aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Legler <alex@a3li.li>2016-07-20 14:37:49 +0200
committerAlex Legler <alex@a3li.li>2016-07-20 14:37:49 +0200
commitb145840323316610dd5a958cad89bbb84712ca5b (patch)
treeddfd7996d65feeccf927900131482842df3253f1
downloadpackages-5-b145840323316610dd5a958cad89bbb84712ca5b.tar.gz
packages-5-b145840323316610dd5a958cad89bbb84712ca5b.tar.bz2
packages-5-b145840323316610dd5a958cad89bbb84712ca5b.zip
Initial commit w/currently running code
-rw-r--r--.gitignore16
-rw-r--r--.rubocop.yml20
-rw-r--r--CHANGES.md10
-rw-r--r--Gemfile59
-rw-r--r--Gemfile.lock224
-rw-r--r--LICENSE661
-rw-r--r--README.md13
-rw-r--r--Rakefile6
-rw-r--r--app/assets/images/.keep0
-rw-r--r--app/assets/javascripts/application.js18
-rw-r--r--app/assets/javascripts/arches.js2
-rw-r--r--app/assets/javascripts/index/typeahead.js26
-rw-r--r--app/assets/javascripts/kkuleomi.js9
-rw-r--r--app/assets/javascripts/packages/show.js24
-rw-r--r--app/assets/javascripts/useflags/render-bubbles.js70
-rw-r--r--app/assets/javascripts/useflags/typeahead.js25
-rw-r--r--app/assets/stylesheets/about.scss0
-rw-r--r--app/assets/stylesheets/application.css16
-rw-r--r--app/assets/stylesheets/arches.scss3
-rw-r--r--app/assets/stylesheets/categories.scss1
-rw-r--r--app/assets/stylesheets/index.scss9
-rw-r--r--app/assets/stylesheets/keywords.scss24
-rw-r--r--app/assets/stylesheets/misc.scss158
-rw-r--r--app/assets/stylesheets/packages.scss232
-rwxr-xr-xapp/assets/stylesheets/sprockets-octicons.scss217
-rw-r--r--app/assets/stylesheets/useflags.scss20
-rw-r--r--app/controllers/about_controller.rb27
-rw-r--r--app/controllers/application_controller.rb13
-rw-r--r--app/controllers/arches_controller.rb63
-rw-r--r--app/controllers/categories_controller.rb39
-rw-r--r--app/controllers/concerns/.keep0
-rw-r--r--app/controllers/concerns/package_update_feeds.rb35
-rw-r--r--app/controllers/index_controller.rb10
-rw-r--r--app/controllers/packages_controller.rb84
-rw-r--r--app/controllers/useflags_controller.rb50
-rw-r--r--app/helpers/application_helper.rb51
-rw-r--r--app/helpers/arches_helper.rb2
-rw-r--r--app/helpers/keywords_helper.rb90
-rw-r--r--app/helpers/links_helper.rb56
-rw-r--r--app/helpers/packages_helper.rb81
-rw-r--r--app/helpers/portage_helper.rb8
-rw-r--r--app/helpers/useflags_helper.rb5
-rw-r--r--app/jobs/category_update_job.rb39
-rw-r--r--app/jobs/masks_update_job.rb7
-rw-r--r--app/jobs/package_removal_job.rb16
-rw-r--r--app/jobs/package_update_job.rb13
-rw-r--r--app/jobs/record_change_job.rb30
-rw-r--r--app/jobs/useflags_update_job.rb78
-rw-r--r--app/mailers/.keep0
-rw-r--r--app/mailers/application_mailer.rb4
-rw-r--r--app/mailers/feedback_mailer.rb8
-rw-r--r--app/models/.keep0
-rw-r--r--app/models/category.rb39
-rw-r--r--app/models/change.rb13
-rw-r--r--app/models/concerns/.keep0
-rw-r--r--app/models/package.rb74
-rw-r--r--app/models/useflag.rb99
-rw-r--r--app/models/version.rb165
-rw-r--r--app/views/about/changelog.html.md9
-rw-r--r--app/views/about/feedback.html.erb64
-rw-r--r--app/views/about/feeds.html.erb23
-rw-r--r--app/views/about/help.html.erb11
-rw-r--r--app/views/about/index.html.erb23
-rw-r--r--app/views/about/legacy.atom.builder18
-rw-r--r--app/views/arches/index.html.erb36
-rw-r--r--app/views/arches/keyworded.html.erb23
-rw-r--r--app/views/arches/show.html.erb0
-rw-r--r--app/views/arches/stable.html.erb23
-rw-r--r--app/views/categories/_category_header.html.erb21
-rw-r--r--app/views/categories/_package_line.html.erb4
-rw-r--r--app/views/categories/index.html.erb52
-rw-r--r--app/views/categories/index.json.jbuilder5
-rw-r--r--app/views/categories/show.html.erb28
-rw-r--r--app/views/categories/show.json.jbuilder10
-rw-r--r--app/views/feedback_mailer/feedback_email.text.erb5
-rw-r--r--app/views/feeds/changes.atom.builder60
-rw-r--r--app/views/index/_package.html.erb8
-rw-r--r--app/views/index/index.html.erb53
-rw-r--r--app/views/layouts/application.html.erb153
-rw-r--r--app/views/layouts/mailer.html.erb5
-rw-r--r--app/views/layouts/mailer.text.erb1
-rw-r--r--app/views/packages/_changed_package.html.erb71
-rw-r--r--app/views/packages/_changelog.html.erb19
-rw-r--r--app/views/packages/_changelog_entry.html.erb31
-rw-r--r--app/views/packages/_herd.html.erb1
-rw-r--r--app/views/packages/_keyword_legend.html.erb17
-rw-r--r--app/views/packages/_maintainer.html.erb1
-rw-r--r--app/views/packages/_maintainer_needed_notice.html.erb7
-rw-r--r--app/views/packages/_maintainer_spacer.html.erb1
-rw-r--r--app/views/packages/_mask.html.erb30
-rw-r--r--app/views/packages/_masks.html.erb10
-rw-r--r--app/views/packages/_metadata.html.erb87
-rw-r--r--app/views/packages/_metadata_use.html.erb14
-rw-r--r--app/views/packages/_package_header.html.erb31
-rw-r--r--app/views/packages/_package_result_row.html.erb4
-rw-r--r--app/views/packages/_removal_notice.html.erb5
-rw-r--r--app/views/packages/_resources.html.erb35
-rw-r--r--app/views/packages/_useflag.html.erb5
-rw-r--r--app/views/packages/_version_card.html.erb14
-rw-r--r--app/views/packages/_version_row.html.erb12
-rw-r--r--app/views/packages/_versions.html.erb38
-rw-r--r--app/views/packages/added.html.erb23
-rw-r--r--app/views/packages/changelog.html.erb12
-rw-r--r--app/views/packages/changelog.json.jbuilder1
-rw-r--r--app/views/packages/keyworded.html.erb23
-rw-r--r--app/views/packages/resolve.json.jbuilder4
-rw-r--r--app/views/packages/search.html.erb38
-rw-r--r--app/views/packages/show.html.erb28
-rw-r--r--app/views/packages/show.json.jbuilder43
-rw-r--r--app/views/packages/stable.html.erb23
-rw-r--r--app/views/packages/suggest.json.jbuilder1
-rw-r--r--app/views/packages/updated.html.erb23
-rw-r--r--app/views/useflags/_useflag_header.html.erb5
-rw-r--r--app/views/useflags/_useflag_result_row.html.erb4
-rw-r--r--app/views/useflags/index.html.erb45
-rw-r--r--app/views/useflags/popular.json.jbuilder10
-rw-r--r--app/views/useflags/search.html.erb16
-rw-r--r--app/views/useflags/show.html.erb61
-rw-r--r--app/views/useflags/show_use_expand.html.erb57
-rw-r--r--app/views/useflags/suggest.json.jbuilder1
-rwxr-xr-xbin/bundle3
-rwxr-xr-xbin/rails8
-rwxr-xr-xbin/rake8
-rwxr-xr-xbin/setup29
-rwxr-xr-xbin/spring15
-rw-r--r--config.ru4
-rw-r--r--config/application.rb46
-rw-r--r--config/boot.rb3
-rw-r--r--config/environment.rb5
-rw-r--r--config/environments/development.rb41
-rw-r--r--config/environments/production.rb79
-rw-r--r--config/environments/test.rb42
-rw-r--r--config/initializers/assets.rb11
-rw-r--r--config/initializers/backtrace_silencers.rb7
-rw-r--r--config/initializers/cookies_serializer.rb3
-rw-r--r--config/initializers/core_ext.rb1
-rw-r--r--config/initializers/elasticsearch.rb10
-rw-r--r--config/initializers/filter_parameter_logging.rb4
-rw-r--r--config/initializers/inflections.rb16
-rw-r--r--config/initializers/kkuleomi_config.rb.dist23
-rw-r--r--config/initializers/kkuleomi_constants.rb1
-rw-r--r--config/initializers/kkuleomi_data.rb23
-rw-r--r--config/initializers/mime_types.rb4
-rw-r--r--config/initializers/session_store.rb3
-rw-r--r--config/initializers/wrap_parameters.rb14
-rw-r--r--config/locales/de.yml31
-rw-r--r--config/locales/en.yml112
-rw-r--r--config/routes.rb55
-rw-r--r--config/secrets.yml.dist22
-rw-r--r--db/seeds.rb7
-rw-r--r--lib/assets/.keep0
-rw-r--r--lib/core_ext/markdown_handler.rb14
-rw-r--r--lib/core_ext/string.rb5
-rw-r--r--lib/kkuleomi.rb2
-rw-r--r--lib/kkuleomi/store.rb53
-rw-r--r--lib/kkuleomi/store/model.rb80
-rw-r--r--lib/kkuleomi/store/models.rb2
-rw-r--r--lib/kkuleomi/store/models/package_import.rb154
-rw-r--r--lib/kkuleomi/store/models/package_search.rb158
-rw-r--r--lib/kkuleomi/store/models/version_import.rb120
-rw-r--r--lib/kkuleomi/store/suggester.rb23
-rw-r--r--lib/kkuleomi/util.rb2
-rw-r--r--lib/kkuleomi/util/exec.rb65
-rw-r--r--lib/portage.rb2
-rw-r--r--lib/portage/ebuild.rb9
-rw-r--r--lib/portage/repository.rb2
-rw-r--r--lib/portage/repository/category.rb91
-rw-r--r--lib/portage/repository/ebuild.rb54
-rw-r--r--lib/portage/repository/model.rb72
-rw-r--r--lib/portage/repository/package.rb59
-rw-r--r--lib/portage/util.rb2
-rw-r--r--lib/portage/util/atoms.rb107
-rw-r--r--lib/portage/util/history.rb74
-rw-r--r--lib/portage/util/mask.rb28
-rw-r--r--lib/portage/util/maskfile.rb43
-rw-r--r--lib/portage/util/masks.rb105
-rw-r--r--lib/portage/util/metadata.rb69
-rw-r--r--lib/portage/util/metadata_cache.rb72
-rw-r--r--lib/portage/util/projects.rb93
-rw-r--r--lib/portage/util/versions.rb129
-rw-r--r--lib/tasks/.keep0
-rw-r--r--lib/tasks/kkuleomi.rake53
-rw-r--r--log/.keep0
-rw-r--r--public/404.html67
-rw-r--r--public/422.html67
-rw-r--r--public/500.html66
-rw-r--r--public/favicon.ico0
-rw-r--r--public/robots.txt9
-rw-r--r--test/controllers/.keep0
-rw-r--r--test/controllers/about_controller_test.rb14
-rw-r--r--test/controllers/arches_controller_test.rb7
-rw-r--r--test/controllers/categories_controller_test.rb49
-rw-r--r--test/controllers/index_controller_test.rb9
-rw-r--r--test/controllers/packages_controller_test.rb7
-rw-r--r--test/controllers/useflags_controller_test.rb19
-rw-r--r--test/fixtures/.keep0
-rw-r--r--test/helpers/.keep0
-rw-r--r--test/integration/.keep0
-rw-r--r--test/jobs/category_update_job_test.rb7
-rw-r--r--test/jobs/masks_update_job_test.rb7
-rw-r--r--test/jobs/package_removal_job_test.rb7
-rw-r--r--test/jobs/package_update_job_test.rb7
-rw-r--r--test/jobs/record_change_job_test.rb7
-rw-r--r--test/jobs/useflags_update_job_test.rb7
-rw-r--r--test/lib/portage/util/atoms_test.rb70
-rw-r--r--test/lib/portage/util/versions_test.rb72
-rw-r--r--test/mailers/.keep0
-rw-r--r--test/mailers/feedback_mailer_test.rb7
-rw-r--r--test/mailers/previews/feedback_mailer_preview.rb4
-rw-r--r--test/models/.keep0
-rw-r--r--test/test_helper.rb10
-rwxr-xr-xvendor/assets/fonts/octicons.eotbin0 -> 29160 bytes
-rwxr-xr-xvendor/assets/fonts/octicons.svg183
-rwxr-xr-xvendor/assets/fonts/octicons.ttfbin0 -> 28992 bytes
-rwxr-xr-xvendor/assets/fonts/octicons.woffbin0 -> 16060 bytes
-rw-r--r--vendor/assets/javascripts/.keep0
-rw-r--r--vendor/assets/javascripts/d3.min.js5
-rw-r--r--vendor/assets/javascripts/jquery.typeahead.min.js10
-rw-r--r--vendor/assets/javascripts/moment.min.js7
-rw-r--r--vendor/assets/stylesheets/.keep0
-rw-r--r--vendor/assets/stylesheets/jquery.typeahead.min.css1
221 files changed, 7645 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..74055cf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+# Ignore bundler config.
+/.bundle
+
+# Ignore all logfiles and tempfiles.
+/log/*
+!/log/.keep
+/tmp
+
+# Development
+.idea
+
+# Deployment
+/vendor/bundle
+/config/secrets.yml
+/config/initializers/kkuleomi_config.rb
+/public/assets
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..e0f780d
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,20 @@
+Style/FormatString:
+ Enabled: false
+
+Style/Documentation:
+ Enabled: false
+
+Style/PerlBackrefs:
+ Enabled: false
+
+Metrics/LineLength:
+ Max: 120
+
+Metrics/MethodLength:
+ Max: 20
+
+Metrics/ModuleLength:
+ Max: 200
+
+Metrics/ClassLength:
+ Max: 200
diff --git a/CHANGES.md b/CHANGES.md
new file mode 100644
index 0000000..e269ddb
--- /dev/null
+++ b/CHANGES.md
@@ -0,0 +1,10 @@
+## 10 Oct 2015
+
+* Categories list: Condense output, display descriptions as tooltip instead of in a table
+* Front page: Use the detailed updated package view
+* Changed Packages: Now displays the resources
+* Search: - counts as wildcard now
+* Searching names is now case-insensitive
+* Keyword table legend is now displayed in a popup or on the help page, freeing the space for the "Resources" box.
+* Dates are displayed in the browser's local timezone. [JS]
+* We have a Changelog!
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..dab377d
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,59 @@
+source 'https://rubygems.org'
+
+# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
+gem 'rails', '4.2.5.1'
+# Use mysql as the database for Active Record
+# gem 'mysql2'
+# Use SCSS for stylesheets
+gem 'sass-rails', '~> 5.0'
+# Use Uglifier as compressor for JavaScript assets
+gem 'uglifier', '>= 1.3.0'
+# Use CoffeeScript for .coffee assets and views
+# gem 'coffee-rails', '~> 4.1.0'
+# See https://github.com/rails/execjs#readme for more supported runtimes
+# gem 'therubyracer', platforms: :ruby
+
+# Use jquery as the JavaScript library
+gem 'jquery-rails'
+# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
+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
+
+# packages stuff
+
+gem 'elasticsearch-rails'
+gem 'elasticsearch-persistence'
+
+gem 'nokogiri'
+gem 'parallel'
+gem 'ruby-progressbar'
+gem 'git'
+gem 'thin'
+
+gem 'sinatra', require: false
+gem 'sidekiq', require: false
+
+gem 'rdiscount'
+
+# Use ActiveModel has_secure_password
+# gem 'bcrypt', '~> 3.1.7'
+
+# Use Unicorn as the app server
+# gem 'unicorn'
+
+# Use Capistrano for deployment
+# gem 'capistrano-rails', group: :development
+
+group :development, :test do
+ # Call 'byebug' anywhere in the code to stop execution and get a debugger console
+ gem 'byebug'
+
+ # Access an IRB console on exception pages or by using <%= console %> in views
+ gem 'web-console', '~> 2.0'
+
+ # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
+ gem 'spring'
+end
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..241e5ae
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,224 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actionmailer (4.2.5.1)
+ actionpack (= 4.2.5.1)
+ actionview (= 4.2.5.1)
+ activejob (= 4.2.5.1)
+ mail (~> 2.5, >= 2.5.4)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ actionpack (4.2.5.1)
+ actionview (= 4.2.5.1)
+ activesupport (= 4.2.5.1)
+ rack (~> 1.6)
+ rack-test (~> 0.6.2)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ actionview (4.2.5.1)
+ activesupport (= 4.2.5.1)
+ builder (~> 3.1)
+ erubis (~> 2.7.0)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ activejob (4.2.5.1)
+ activesupport (= 4.2.5.1)
+ globalid (>= 0.3.0)
+ activemodel (4.2.5.1)
+ activesupport (= 4.2.5.1)
+ builder (~> 3.1)
+ activerecord (4.2.5.1)
+ activemodel (= 4.2.5.1)
+ activesupport (= 4.2.5.1)
+ arel (~> 6.0)
+ activesupport (4.2.5.1)
+ i18n (~> 0.7)
+ json (~> 1.7, >= 1.7.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.3, >= 0.3.4)
+ tzinfo (~> 1.1)
+ arel (6.0.3)
+ axiom-types (0.1.1)
+ descendants_tracker (~> 0.0.4)
+ ice_nine (~> 0.11.0)
+ thread_safe (~> 0.3, >= 0.3.1)
+ binding_of_caller (0.7.2)
+ debug_inspector (>= 0.0.1)
+ builder (3.2.2)
+ byebug (8.2.1)
+ coercible (1.0.0)
+ descendants_tracker (~> 0.0.1)
+ coffee-rails (4.1.1)
+ coffee-script (>= 2.2.0)
+ railties (>= 4.0.0, < 5.1.x)
+ coffee-script (2.4.1)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.10.0)
+ concurrent-ruby (1.0.0)
+ connection_pool (2.2.0)
+ daemons (1.2.3)
+ debug_inspector (0.0.2)
+ descendants_tracker (0.0.4)
+ thread_safe (~> 0.3, >= 0.3.1)
+ elasticsearch (1.0.15)
+ elasticsearch-api (= 1.0.15)
+ elasticsearch-transport (= 1.0.15)
+ elasticsearch-api (1.0.15)
+ multi_json
+ elasticsearch-model (0.1.8)
+ activesupport (> 3)
+ elasticsearch (> 0.4)
+ hashie
+ elasticsearch-persistence (0.1.8)
+ activemodel (> 3)
+ activesupport (> 3)
+ elasticsearch (> 0.4)
+ elasticsearch-model (>= 0.1)
+ hashie
+ virtus
+ elasticsearch-rails (0.1.8)
+ elasticsearch-transport (1.0.15)
+ faraday
+ multi_json
+ equalizer (0.0.11)
+ erubis (2.7.0)
+ eventmachine (1.0.9.1)
+ execjs (2.6.0)
+ faraday (0.9.2)
+ multipart-post (>= 1.2, < 3)
+ git (1.2.9.1)
+ globalid (0.3.6)
+ activesupport (>= 4.1.0)
+ hashie (3.4.3)
+ i18n (0.7.0)
+ ice_nine (0.11.1)
+ jbuilder (2.4.0)
+ activesupport (>= 3.0.0, < 5.1)
+ multi_json (~> 1.2)
+ jquery-rails (4.1.0)
+ rails-dom-testing (~> 1.0)
+ railties (>= 4.2.0)
+ thor (>= 0.14, < 2.0)
+ json (1.8.3)
+ loofah (2.0.3)
+ nokogiri (>= 1.5.9)
+ mail (2.6.3)
+ mime-types (>= 1.16, < 3)
+ mime-types (2.99)
+ mini_portile2 (2.0.0)
+ minitest (5.8.4)
+ multi_json (1.11.2)
+ multipart-post (2.0.0)
+ nokogiri (1.6.7.2)
+ mini_portile2 (~> 2.0.0.rc2)
+ parallel (1.6.1)
+ rack (1.6.4)
+ rack-protection (1.5.3)
+ rack
+ rack-test (0.6.3)
+ rack (>= 1.0)
+ rails (4.2.5.1)
+ actionmailer (= 4.2.5.1)
+ actionpack (= 4.2.5.1)
+ actionview (= 4.2.5.1)
+ activejob (= 4.2.5.1)
+ activemodel (= 4.2.5.1)
+ activerecord (= 4.2.5.1)
+ activesupport (= 4.2.5.1)
+ bundler (>= 1.3.0, < 2.0)
+ railties (= 4.2.5.1)
+ sprockets-rails
+ rails-deprecated_sanitizer (1.0.3)
+ activesupport (>= 4.2.0.alpha)
+ rails-dom-testing (1.0.7)
+ activesupport (>= 4.2.0.beta, < 5.0)
+ nokogiri (~> 1.6.0)
+ rails-deprecated_sanitizer (>= 1.0.1)
+ rails-html-sanitizer (1.0.3)
+ loofah (~> 2.0)
+ railties (4.2.5.1)
+ actionpack (= 4.2.5.1)
+ activesupport (= 4.2.5.1)
+ rake (>= 0.8.7)
+ thor (>= 0.18.1, < 2.0)
+ rake (10.5.0)
+ rdiscount (2.1.8)
+ rdoc (4.2.1)
+ json (~> 1.4)
+ redis (3.2.2)
+ ruby-progressbar (1.7.5)
+ sass (3.4.21)
+ sass-rails (5.0.4)
+ railties (>= 4.0.0, < 5.0)
+ sass (~> 3.1)
+ sprockets (>= 2.8, < 4.0)
+ sprockets-rails (>= 2.0, < 4.0)
+ tilt (>= 1.1, < 3)
+ sdoc (0.4.1)
+ json (~> 1.7, >= 1.7.7)
+ rdoc (~> 4.0)
+ sidekiq (4.0.2)
+ concurrent-ruby (~> 1.0)
+ connection_pool (~> 2.2, >= 2.2.0)
+ redis (~> 3.2, >= 3.2.1)
+ sinatra (1.4.7)
+ rack (~> 1.5)
+ rack-protection (~> 1.4)
+ tilt (>= 1.3, < 3)
+ spring (1.6.2)
+ sprockets (3.5.2)
+ concurrent-ruby (~> 1.0)
+ rack (> 1, < 3)
+ sprockets-rails (3.0.0)
+ actionpack (>= 4.0)
+ activesupport (>= 4.0)
+ sprockets (>= 3.0.0)
+ thin (1.6.4)
+ daemons (~> 1.0, >= 1.0.9)
+ eventmachine (~> 1.0, >= 1.0.4)
+ rack (~> 1.0)
+ thor (0.19.1)
+ thread_safe (0.3.5)
+ tilt (2.0.2)
+ turbolinks (2.5.3)
+ coffee-rails
+ tzinfo (1.2.2)
+ thread_safe (~> 0.1)
+ uglifier (2.7.2)
+ execjs (>= 0.3.0)
+ json (>= 1.8.0)
+ virtus (1.0.5)
+ axiom-types (~> 0.1)
+ coercible (~> 1.0)
+ descendants_tracker (~> 0.0, >= 0.0.3)
+ equalizer (~> 0.0, >= 0.0.9)
+ web-console (2.2.1)
+ activemodel (>= 4.0)
+ binding_of_caller (>= 0.7.2)
+ railties (>= 4.0)
+ sprockets-rails (>= 2.0, < 4.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ byebug
+ elasticsearch-persistence
+ elasticsearch-rails
+ git
+ jbuilder (~> 2.0)
+ jquery-rails
+ nokogiri
+ parallel
+ rails (= 4.2.5.1)
+ rdiscount
+ ruby-progressbar
+ sass-rails (~> 5.0)
+ sdoc (~> 0.4.0)
+ sidekiq
+ sinatra
+ spring
+ thin
+ turbolinks
+ uglifier (>= 1.3.0)
+ web-console (~> 2.0)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..dba13ed
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..260e264
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+This is the code that powers [packages.gentoo.org](https://packages.gentoo.org/),
+internally codenamed kkuleomi/꾸러미 which is Korean for package (who would have thought!)
+
+Copyright © 2015–16 [Alex Legler](mailto:a3li@gentoo.org)
+
+## Installation instructions
+
+soon
+
+## Contributions
+
+Email [gpackages@gentoo.org](mailto:gpackages.gentoo.org) or
+file a bug on [bugs.gentoo.org](https://bugs.gentoo.org/) (Websites → Packages).
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..ba6b733
--- /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/assets/images/.keep b/app/assets/images/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/assets/images/.keep
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
new file mode 100644
index 0000000..9bca50a
--- /dev/null
+++ b/app/assets/javascripts/application.js
@@ -0,0 +1,18 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
+// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// compiled file.
+//
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
+// about supported directives.
+//
+//= require jquery
+//= require jquery_ujs
+//= require turbolinks
+//= require jquery.typeahead.min
+//= require moment.min
+//= require_directory .
diff --git a/app/assets/javascripts/arches.js b/app/assets/javascripts/arches.js
new file mode 100644
index 0000000..dee720f
--- /dev/null
+++ b/app/assets/javascripts/arches.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/index/typeahead.js b/app/assets/javascripts/index/typeahead.js
new file mode 100644
index 0000000..3232fe8
--- /dev/null
+++ b/app/assets/javascripts/index/typeahead.js
@@ -0,0 +1,26 @@
+$(function() {
+ $('#q').typeahead({
+ order: 'asc',
+ dynamic: true,
+ delay: 500,
+ source: {
+ packages: {
+ display: 'name',
+ href: function(item) { return '/packages/' + item.category + '/' + item.name; },
+ url: [{
+ type: 'GET',
+ url: "/packages/suggest.json",
+ data: {
+ q: "{{query}}"
+ }
+ }, 'results'],
+ template: '<span class="kk-suggest-cat">{{category}}</span>/<span class="kk-suggest-pkg">{{name}}</span> <span class="kk-suggest-detail">{{description}}</span>'
+ }
+ },
+ callback: {
+ onClick: function(node, a, item, event) {
+ window.location = item.href;
+ }
+ }
+ });
+});
diff --git a/app/assets/javascripts/kkuleomi.js b/app/assets/javascripts/kkuleomi.js
new file mode 100644
index 0000000..3a01529
--- /dev/null
+++ b/app/assets/javascripts/kkuleomi.js
@@ -0,0 +1,9 @@
+$(document).on('ready page:load kkuleomi:ajax', function(event) {
+ $('[data-toggle="tooltip"]').tooltip();
+
+ $('.kk-i18n-date').each(function(idx) {
+ // TODO: Support different date formats
+ var me = $(this);
+ me.text(moment.unix(me.data('utcts')).local().format('ddd, D MMM YYYY HH:mm'));
+ });
+});
diff --git a/app/assets/javascripts/packages/show.js b/app/assets/javascripts/packages/show.js
new file mode 100644
index 0000000..01f5300
--- /dev/null
+++ b/app/assets/javascripts/packages/show.js
@@ -0,0 +1,24 @@
+$(function() {
+ var atom = $('#package-title').data('atom');
+
+ $.ajax({
+ url: '/packages/' + atom + '/changelog'
+ }).done(function(data) {
+ $('#changelog-container').html(data);
+ $(document).trigger('kkuleomi:ajax');
+ }).fail(function() {
+ $('#changelog-container > li').html('<span class="fa fa-fw fa-3x fa-ban text-danger"></span><br><br>Changelog currently not available. Please check back later.');
+ });
+
+ $('#kk-keyword-legend-btn').popover({
+ content: function(btn) {
+ return $('#kk-keyword-legend-text').html();
+ },
+ html: true,
+ trigger: 'toggle'
+ });
+
+ $('#kk-keyword-legend-btn').click(function() {
+ return false;
+ });
+});
diff --git a/app/assets/javascripts/useflags/render-bubbles.js b/app/assets/javascripts/useflags/render-bubbles.js
new file mode 100644
index 0000000..6c99e43
--- /dev/null
+++ b/app/assets/javascripts/useflags/render-bubbles.js
@@ -0,0 +1,70 @@
+$('#bubble-placeholder').show();
+
+var width = 600;
+ height = 600;
+
+var diameter = 960,
+ format = d3.format(",d"),
+ color = d3.scale.category20c();
+
+var bubble = d3.layout.pack()
+ .sort(null)
+ .size([width, height])
+ .padding(1.5);
+
+var svg = d3.select("#bubble-placeholder").append("svg")
+ .attr("width", width)
+ .attr("height", height)
+ .attr("class", "bubble");
+
+d3.json("/useflags/popular.json", function(error, root) {
+ if (error) throw error;
+
+ var node = svg.selectAll(".node")
+ .data(bubble.nodes(classes(root))
+ .filter(function(d) { return !d.children; }))
+ .enter().append("g")
+ .attr("class", "node")
+ .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
+
+ node.append("title")
+ .text(function(d) { return d.className + ": " + format(d.value); });
+
+ node.append("circle")
+ .attr("r", function(d) { return d.r; })
+ .attr("class", "kk-useflag-circle")
+ .attr("onclick", function(d) { return "location.href='/useflags/" + d.className + "';"; })
+ .style("fill", function(d) { return color(d.className); });
+
+ node.append("text")
+ .attr("dy", ".3em")
+ .attr('class', 'kk-useflag-circle')
+ .attr("onclick", function(d) { return "location.href='/useflags/" + d.className + "';"; })
+ .style("text-anchor", "middle")
+ .style("font-size", function(d) {
+ var len = d.className.substring(0, d.r / 3).length;
+ var size = d.r/3;
+ size *= 8 / len;
+ if (len == 1) {
+ size -= 60;
+ }
+ size += 1;
+ return Math.round(size)+'px';
+ })
+ .text(function(d) { return d.className.substring(0, d.r / 3); });
+});
+
+// Returns a flattened hierarchy containing all leaf nodes under the root.
+function classes(root) {
+ var classes = [];
+
+ function recurse(name, node) {
+ if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
+ else classes.push({packageName: name, className: node.name, value: node.size});
+ }
+
+ recurse(null, root);
+ return {children: classes};
+}
+
+d3.select(self.frameElement).style("height", height + "px");
diff --git a/app/assets/javascripts/useflags/typeahead.js b/app/assets/javascripts/useflags/typeahead.js
new file mode 100644
index 0000000..3912380
--- /dev/null
+++ b/app/assets/javascripts/useflags/typeahead.js
@@ -0,0 +1,25 @@
+$(function() {
+ $('#q').typeahead({
+ order: "asc",
+ dynamic: true,
+ source: {
+ use: {
+ display: 'name',
+ href: function(item) { return '/useflags/' + item.name; },
+ url: [{
+ type: 'GET',
+ url: "/useflags/suggest.json",
+ data: {
+ q: "{{query}}"
+ }
+ }, 'results'],
+ template: '<span>{{name}}</span> <span class="kk-suggest-detail">{{description}}</span>'
+ }
+ },
+ callback: {
+ onClick: function(node, a, item, event) {
+ window.location = item.href;
+ }
+ }
+ });
+});
diff --git a/app/assets/stylesheets/about.scss b/app/assets/stylesheets/about.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/assets/stylesheets/about.scss
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
new file mode 100644
index 0000000..6b38ea1
--- /dev/null
+++ b/app/assets/stylesheets/application.css
@@ -0,0 +1,16 @@
+/*
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
+ * listed below.
+ *
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
+ * compiled file so the styles you add here take precedence over styles defined in any styles
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
+ * file per style scope.
+ *
+ *= require_tree .
+ *= require jquery.typeahead.min
+ *= require_self
+ */
diff --git a/app/assets/stylesheets/arches.scss b/app/assets/stylesheets/arches.scss
new file mode 100644
index 0000000..f0daf89
--- /dev/null
+++ b/app/assets/stylesheets/arches.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Arches controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/categories.scss b/app/assets/stylesheets/categories.scss
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/app/assets/stylesheets/categories.scss
@@ -0,0 +1 @@
+
diff --git a/app/assets/stylesheets/index.scss b/app/assets/stylesheets/index.scss
new file mode 100644
index 0000000..00db929
--- /dev/null
+++ b/app/assets/stylesheets/index.scss
@@ -0,0 +1,9 @@
+.site-welcome {
+ font-size: 2.5em;
+ text-align: center;
+ margin-bottom: 1em;
+
+ @media screen and (max-width: 767px) {
+ font-size: 1.75em;
+ }
+}
diff --git a/app/assets/stylesheets/keywords.scss b/app/assets/stylesheets/keywords.scss
new file mode 100644
index 0000000..e860d2f
--- /dev/null
+++ b/app/assets/stylesheets/keywords.scss
@@ -0,0 +1,24 @@
+.kk-keyword-stable {
+ background-color: #81C784;
+ color: #2E7D32;
+}
+
+.kk-keyword-testing {
+ background-color: #FFF176;
+ color: #a08700;
+}
+
+.kk-keyword-unavailable {
+ background-color: #d5d5d5;
+ color: #666;
+}
+
+.kk-keyword-masked {
+ background-color: #EF9A9A;
+ color: #B71C1C;
+}
+
+.kk-keyword-unknown {
+ background-color: #fafafa;
+ color: #333;
+}
diff --git a/app/assets/stylesheets/misc.scss b/app/assets/stylesheets/misc.scss
new file mode 100644
index 0000000..f3c557d
--- /dev/null
+++ b/app/assets/stylesheets/misc.scss
@@ -0,0 +1,158 @@
+h1 {
+ a.kk-feed-icon {
+ font-size: 65%;
+ }
+}
+
+.label {
+ cursor: default;
+}
+
+.kk-cell-sep-right {
+ border-right-width: 3px !important;
+}
+
+.panel {
+ table.table {
+ tr {
+ th:first-child,
+ td:first-child {
+ padding-left: 1em;
+ }
+ }
+ }
+}
+
+.black {
+ color: #333;
+}
+
+td .alert {
+ margin-bottom: 0;
+}
+
+.kk-nobreak-cell {
+ white-space: nowrap;
+}
+
+.kk-panel-content-sorry {
+ background-color: #f0f0f0;
+ text-align: center;
+ padding-top: 2em;
+ padding-bottom: 2em;
+ color: #666;
+}
+
+.kk-3col-list {
+ columns: 3;
+ -webkit-columns: 3;
+ -moz-columns: 3;
+}
+
+.kk-4col-list {
+ columns: 4;
+ -webkit-columns: 4;
+ -moz-columns: 4;
+}
+
+.kk-5col-list {
+ columns: 5;
+ -webkit-columns: 5;
+ -moz-columns: 5;
+}
+
+.kk-6col-list {
+ columns: 6;
+ -webkit-columns: 6;
+ -moz-columns: 6;
+}
+
+.kk-col-list {
+ @media screen and (max-width: 767px) {
+ columns: 1;
+ -webkit-columns: 1;
+ -moz-columns: 1;
+ }
+
+ padding: 0;
+
+ li {
+ list-style-type: none;
+
+ a:link,
+ a:hover,
+ a:active,
+ a:visited {
+ display: block;
+ padding: .2em;
+ }
+
+ a:hover {
+ background-color: #eee;
+ border-radius: 2px;
+ text-decoration: none;
+ }
+ }
+}
+
+.kk-col-list-header {
+ margin-top: 1em;
+
+ .kk-group-header {
+ display: block;
+ border-bottom: 1px solid #eee;
+ }
+}
+
+.kk-col-list .kk-col-list-header:first-of-type {
+ margin-top: 0;
+}
+
+.kk-group-header {
+ color: #8a8a8a;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ font-size: 90%;
+}
+
+.kk-suggest-cat {
+ color: #8a8a8a;
+}
+
+.kk-suggest-pkg {
+}
+
+.kk-suggest-detail {
+ float: right;
+ color: #8a8a8a;
+ font-size: 90%;
+
+ @media screen and (max-width: 767px) {
+ display: block;
+ float: none;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+}
+
+body.kk .typeahead-list > li > a {
+ // Firefox workaround again
+ white-space: normal;
+}
+
+.kk-site-notice {
+ font-size: 90%;
+ padding-top: .5em;
+ padding-bottom: .5em;
+ text-align: center;
+}
+
+a.kk-box-meta-link:link,
+a.kk-box-meta-link:active,
+a.kk-box-meta-link:visited {
+ color: #aaa;
+}
+
+a.kk-box-meta-link:hover {
+ color: #555;
+}
diff --git a/app/assets/stylesheets/packages.scss b/app/assets/stylesheets/packages.scss
new file mode 100644
index 0000000..1c2811a
--- /dev/null
+++ b/app/assets/stylesheets/packages.scss
@@ -0,0 +1,232 @@
+.kk-keyword-header {
+ width: 5em;
+ font-size: 85%;
+ white-space: normal !important;
+}
+
+@media screen and (max-width: 767px) {
+ .kk-keyword-header {
+ min-width: 5em;
+ max-width: 5em;
+ }
+}
+
+.kk-version {
+ // Only set on small screens due to:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=488725
+ @media screen and (max-width: 767px) {
+ white-space: nowrap;
+ }
+}
+
+.kk-slot {
+ color: #888;
+}
+
+.kk-keyword {
+ text-align: center;
+ white-space: normal !important;
+}
+
+.kk-search-result-header {
+ margin-top: 0;
+}
+
+.kk-metadata-key {
+ font-weight: bold;
+}
+
+.kk-package-title .kk-package-icon {
+ float: left;
+}
+
+.kk-package-title .kk-package-name {
+ margin-left: 1.3em;
+ word-wrap: break-word;
+}
+
+.kk-package-title .kk-package-cat {
+ padding-left: 2.05em;
+}
+
+.kk-package-maindesc {
+ margin-top: 1.75em;
+}
+
+.kk-package-homepage {
+ margin: 0;
+ font-size: 125%;
+}
+
+.kk-byline {
+ padding-left: 1em;
+ font-style: italic;
+}
+
+.kk-commit {
+ font-family: monospace;
+}
+
+.kk-changelog-diffstat {
+ margin-top: 1em;
+ margin-bottom: 0;
+ border: 1px solid #ddd;
+ border-top: none;
+}
+
+.kk-changelog-diffstat {
+ a:link, a:visited, a:active {
+ color: #333;
+ }
+}
+
+.kk-changelog-diffstat-icon {
+ width: 20px;
+}
+
+.kk-octicon-spacer {
+ padding-left: 18px;
+}
+
+.kk-useflag a:link,
+.kk-useflag a:visited {
+ padding: 0.2em;
+ padding-top: 0.1em;
+ padding-bottom: 0.1em;
+ background-color: #f0f0f0;
+ border: 1px solid #eaeaea;
+ border-radius: 2px;
+ color: #333;
+ font-family: monospace;
+ font-size: 90%;
+}
+
+.kk-useflag a:hover {
+ background-color: #e9e9e9;
+ color: #305d8c;
+}
+
+.kk-useflag a:hover {
+ text-decoration: none;
+}
+
+.kk-useflag {
+ list-style-type: none;
+ margin-bottom: 0.4em;
+ margin-right: 0.2em;
+}
+
+.kk-useflag-container {
+ padding: 0;
+ margin-top: .4em;
+
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.kk-useflag-container-many {
+ justify-content: space-between;
+}
+
+.kk-useflag-container-few {
+ justify-content: flex-start;
+}
+
+.kk-useflag-group {
+ color: #8a8a8a;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ font-size: 90%;
+}
+
+.kk-versions-table {
+ .kk-restrict-label,
+ .kk-properties-label {
+ float: right;
+
+ @media screen and (max-width: 767px) {
+ float: none;
+ }
+ }
+}
+
+.kk-version-card > p:last-of-type {
+ margin-bottom: 0;
+}
+
+@media screen and (max-width: 767px) {
+ .kk-version-card > p:first-of-type {
+ margin-top: .5em;
+ }
+}
+
+.kk-mask {
+ background-color: #f2dede;
+}
+
+.kk-mask-details {
+ font-size: 90%;
+
+ .row {
+ margin-bottom: 1em;
+ }
+
+ margin-top: 1em;
+ margin-bottom: -1em;
+}
+
+.kk-mask-reason {
+ a:link,
+ a:visited {
+ color: inherit;
+ text-decoration: underline;
+ }
+}
+
+.kk-mask-atoms {
+ max-height: 3.6em;
+ overflow-x: scroll;
+ line-height: 1.2em;
+}
+
+.popover .kk-keyword-legend {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ width: 240px;
+}
+
+.kk-package-detailed {
+ h4 {
+ margin-bottom: 5px;
+ }
+}
+
+.kk-package-detailed-toolbox {
+ float:right;
+ margin-top: -1.75em;
+}
+
+.kk-inline-changelog-entry {
+ font-size: 90%;
+ border-radius: 2px;
+ border: 1px solid #ddd;
+ background-color: #f5f5f5;
+ margin-top: 5px;
+
+ a:link,
+ a:active,
+ a:visited,
+ a:hover {
+ display: block;
+ padding: 5px;
+ color: #333;
+ }
+
+ .kk-commit-message {
+ margin-left: .5em;
+ }
+
+ .kk-commit {
+ color: #999;
+ }
+}
diff --git a/app/assets/stylesheets/sprockets-octicons.scss b/app/assets/stylesheets/sprockets-octicons.scss
new file mode 100755
index 0000000..cef21ae
--- /dev/null
+++ b/app/assets/stylesheets/sprockets-octicons.scss
@@ -0,0 +1,217 @@
+@font-face {
+ font-family: 'octicons';
+ src: font-url('octicons.eot?#iefix') format('embedded-opentype'),
+ font-url('octicons.woff') format('woff'),
+ font-url('octicons.ttf') format('truetype'),
+ font-url('octicons.svg#octicons') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+// .octicon is optimized for 16px.
+// .mega-octicon is optimized for 32px but can be used larger.
+.octicon, .mega-octicon {
+ font: normal normal normal 16px/1 octicons;
+ display: inline-block;
+ text-decoration: none;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.mega-octicon { font-size: 32px; }
+
+.octicon-alert:before { content: '\f02d'} /*  */
+.octicon-arrow-down:before { content: '\f03f'} /*  */
+.octicon-arrow-left:before { content: '\f040'} /*  */
+.octicon-arrow-right:before { content: '\f03e'} /*  */
+.octicon-arrow-small-down:before { content: '\f0a0'} /*  */
+.octicon-arrow-small-left:before { content: '\f0a1'} /*  */
+.octicon-arrow-small-right:before { content: '\f071'} /*  */
+.octicon-arrow-small-up:before { content: '\f09f'} /*  */
+.octicon-arrow-up:before { content: '\f03d'} /*  */
+.octicon-microscope:before,
+.octicon-beaker:before { content: '\f0dd'} /*  */
+.octicon-bell:before { content: '\f0de'} /*  */
+.octicon-book:before { content: '\f007'} /*  */
+.octicon-bookmark:before { content: '\f07b'} /*  */
+.octicon-briefcase:before { content: '\f0d3'} /*  */
+.octicon-broadcast:before { content: '\f048'} /*  */
+.octicon-browser:before { content: '\f0c5'} /*  */
+.octicon-bug:before { content: '\f091'} /*  */
+.octicon-calendar:before { content: '\f068'} /*  */
+.octicon-check:before { content: '\f03a'} /*  */
+.octicon-checklist:before { content: '\f076'} /*  */
+.octicon-chevron-down:before { content: '\f0a3'} /*  */
+.octicon-chevron-left:before { content: '\f0a4'} /*  */
+.octicon-chevron-right:before { content: '\f078'} /*  */
+.octicon-chevron-up:before { content: '\f0a2'} /*  */
+.octicon-circle-slash:before { content: '\f084'} /*  */
+.octicon-circuit-board:before { content: '\f0d6'} /*  */
+.octicon-clippy:before { content: '\f035'} /*  */
+.octicon-clock:before { content: '\f046'} /*  */
+.octicon-cloud-download:before { content: '\f00b'} /*  */
+.octicon-cloud-upload:before { content: '\f00c'} /*  */
+.octicon-code:before { content: '\f05f'} /*  */
+.octicon-color-mode:before { content: '\f065'} /*  */
+.octicon-comment-add:before,
+.octicon-comment:before { content: '\f02b'} /*  */
+.octicon-comment-discussion:before { content: '\f04f'} /*  */
+.octicon-credit-card:before { content: '\f045'} /*  */
+.octicon-dash:before { content: '\f0ca'} /*  */
+.octicon-dashboard:before { content: '\f07d'} /*  */
+.octicon-database:before { content: '\f096'} /*  */
+.octicon-clone:before,
+.octicon-desktop-download:before { content: '\f0dc'} /*  */
+.octicon-device-camera:before { content: '\f056'} /*  */
+.octicon-device-camera-video:before { content: '\f057'} /*  */
+.octicon-device-desktop:before { content: '\f27c'} /*  */
+.octicon-device-mobile:before { content: '\f038'} /*  */
+.octicon-diff:before { content: '\f04d'} /*  */
+.octicon-diff-added:before { content: '\f06b'} /*  */
+.octicon-diff-ignored:before { content: '\f099'} /*  */
+.octicon-diff-modified:before { content: '\f06d'} /*  */
+.octicon-diff-removed:before { content: '\f06c'} /*  */
+.octicon-diff-renamed:before { content: '\f06e'} /*  */
+.octicon-ellipsis:before { content: '\f09a'} /*  */
+.octicon-eye-unwatch:before,
+.octicon-eye-watch:before,
+.octicon-eye:before { content: '\f04e'} /*  */
+.octicon-file-binary:before { content: '\f094'} /*  */
+.octicon-file-code:before { content: '\f010'} /*  */
+.octicon-file-directory:before { content: '\f016'} /*  */
+.octicon-file-media:before { content: '\f012'} /*  */
+.octicon-file-pdf:before { content: '\f014'} /*  */
+.octicon-file-submodule:before { content: '\f017'} /*  */
+.octicon-file-symlink-directory:before { content: '\f0b1'} /*  */
+.octicon-file-symlink-file:before { content: '\f0b0'} /*  */
+.octicon-file-text:before { content: '\f011'} /*  */
+.octicon-file-zip:before { content: '\f013'} /*  */
+.octicon-flame:before { content: '\f0d2'} /*  */
+.octicon-fold:before { content: '\f0cc'} /*  */
+.octicon-gear:before { content: '\f02f'} /*  */
+.octicon-gift:before { content: '\f042'} /*  */
+.octicon-gist:before { content: '\f00e'} /*  */
+.octicon-gist-secret:before { content: '\f08c'} /*  */
+.octicon-git-branch-create:before,
+.octicon-git-branch-delete:before,
+.octicon-git-branch:before { content: '\f020'} /*  */
+.octicon-git-commit:before { content: '\f01f'} /*  */
+.octicon-git-compare:before { content: '\f0ac'} /*  */
+.octicon-git-merge:before { content: '\f023'} /*  */
+.octicon-git-pull-request-abandoned:before,
+.octicon-git-pull-request:before { content: '\f009'} /*  */
+.octicon-globe:before { content: '\f0b6'} /*  */
+.octicon-graph:before { content: '\f043'} /*  */
+.octicon-heart:before { content: '\2665'} /* ♥ */
+.octicon-history:before { content: '\f07e'} /*  */
+.octicon-home:before { content: '\f08d'} /*  */
+.octicon-horizontal-rule:before { content: '\f070'} /*  */
+.octicon-hubot:before { content: '\f09d'} /*  */
+.octicon-inbox:before { content: '\f0cf'} /*  */
+.octicon-info:before { content: '\f059'} /*  */
+.octicon-issue-closed:before { content: '\f028'} /*  */
+.octicon-issue-opened:before { content: '\f026'} /*  */
+.octicon-issue-reopened:before { content: '\f027'} /*  */
+.octicon-jersey:before { content: '\f019'} /*  */
+.octicon-key:before { content: '\f049'} /*  */
+.octicon-keyboard:before { content: '\f00d'} /*  */
+.octicon-law:before { content: '\f0d8'} /*  */
+.octicon-light-bulb:before { content: '\f000'} /*  */
+.octicon-link:before { content: '\f05c'} /*  */
+.octicon-link-external:before { content: '\f07f'} /*  */
+.octicon-list-ordered:before { content: '\f062'} /*  */
+.octicon-list-unordered:before { content: '\f061'} /*  */
+.octicon-location:before { content: '\f060'} /*  */
+.octicon-gist-private:before,
+.octicon-mirror-private:before,
+.octicon-git-fork-private:before,
+.octicon-lock:before { content: '\f06a'} /*  */
+.octicon-logo-github:before { content: '\f092'} /*  */
+.octicon-mail:before { content: '\f03b'} /*  */
+.octicon-mail-read:before { content: '\f03c'} /*  */
+.octicon-mail-reply:before { content: '\f051'} /*  */
+.octicon-mark-github:before { content: '\f00a'} /*  */
+.octicon-markdown:before { content: '\f0c9'} /*  */
+.octicon-megaphone:before { content: '\f077'} /*  */
+.octicon-mention:before { content: '\f0be'} /*  */
+.octicon-milestone:before { content: '\f075'} /*  */
+.octicon-mirror-public:before,
+.octicon-mirror:before { content: '\f024'} /*  */
+.octicon-mortar-board:before { content: '\f0d7'} /*  */
+.octicon-mute:before { content: '\f080'} /*  */
+.octicon-no-newline:before { content: '\f09c'} /*  */
+.octicon-octoface:before { content: '\f008'} /*  */
+.octicon-organization:before { content: '\f037'} /*  */
+.octicon-package:before { content: '\f0c4'} /*  */
+.octicon-paintcan:before { content: '\f0d1'} /*  */
+.octicon-pencil:before { content: '\f058'} /*  */
+.octicon-person-add:before,
+.octicon-person-follow:before,
+.octicon-person:before { content: '\f018'} /*  */
+.octicon-pin:before { content: '\f041'} /*  */
+.octicon-plug:before { content: '\f0d4'} /*  */
+.octicon-repo-create:before,
+.octicon-gist-new:before,
+.octicon-file-directory-create:before,
+.octicon-file-add:before,
+.octicon-plus:before { content: '\f05d'} /*  */
+.octicon-primitive-dot:before { content: '\f052'} /*  */
+.octicon-primitive-square:before { content: '\f053'} /*  */
+.octicon-pulse:before { content: '\f085'} /*  */
+.octicon-question:before { content: '\f02c'} /*  */
+.octicon-quote:before { content: '\f063'} /*  */
+.octicon-radio-tower:before { content: '\f030'} /*  */
+.octicon-repo-delete:before,
+.octicon-repo:before { content: '\f001'} /*  */
+.octicon-repo-clone:before { content: '\f04c'} /*  */
+.octicon-repo-force-push:before { content: '\f04a'} /*  */
+.octicon-gist-fork:before,
+.octicon-repo-forked:before { content: '\f002'} /*  */
+.octicon-repo-pull:before { content: '\f006'} /*  */
+.octicon-repo-push:before { content: '\f005'} /*  */
+.octicon-rocket:before { content: '\f033'} /*  */
+.octicon-rss:before { content: '\f034'} /*  */
+.octicon-ruby:before { content: '\f047'} /*  */
+.octicon-screen-full:before { content: '\f066'} /*  */
+.octicon-screen-normal:before { content: '\f067'} /*  */
+.octicon-search-save:before,
+.octicon-search:before { content: '\f02e'} /*  */
+.octicon-server:before { content: '\f097'} /*  */
+.octicon-settings:before { content: '\f07c'} /*  */
+.octicon-shield:before { content: '\f0e1'} /*  */
+.octicon-log-in:before,
+.octicon-sign-in:before { content: '\f036'} /*  */
+.octicon-log-out:before,
+.octicon-sign-out:before { content: '\f032'} /*  */
+.octicon-squirrel:before { content: '\f0b2'} /*  */
+.octicon-star-add:before,
+.octicon-star-delete:before,
+.octicon-star:before { content: '\f02a'} /*  */
+.octicon-stop:before { content: '\f08f'} /*  */
+.octicon-repo-sync:before,
+.octicon-sync:before { content: '\f087'} /*  */
+.octicon-tag-remove:before,
+.octicon-tag-add:before,
+.octicon-tag:before { content: '\f015'} /*  */
+.octicon-telescope:before { content: '\f088'} /*  */
+.octicon-terminal:before { content: '\f0c8'} /*  */
+.octicon-three-bars:before { content: '\f05e'} /*  */
+.octicon-thumbsdown:before { content: '\f0db'} /*  */
+.octicon-thumbsup:before { content: '\f0da'} /*  */
+.octicon-tools:before { content: '\f031'} /*  */
+.octicon-trashcan:before { content: '\f0d0'} /*  */
+.octicon-triangle-down:before { content: '\f05b'} /*  */
+.octicon-triangle-left:before { content: '\f044'} /*  */
+.octicon-triangle-right:before { content: '\f05a'} /*  */
+.octicon-triangle-up:before { content: '\f0aa'} /*  */
+.octicon-unfold:before { content: '\f039'} /*  */
+.octicon-unmute:before { content: '\f0ba'} /*  */
+.octicon-versions:before { content: '\f064'} /*  */
+.octicon-watch:before { content: '\f0e0'} /*  */
+.octicon-remove-close:before,
+.octicon-x:before { content: '\f081'} /*  */
+.octicon-zap:before { content: '\26A1'} /* ⚡ */
diff --git a/app/assets/stylesheets/useflags.scss b/app/assets/stylesheets/useflags.scss
new file mode 100644
index 0000000..90f667d
--- /dev/null
+++ b/app/assets/stylesheets/useflags.scss
@@ -0,0 +1,20 @@
+.kk-useflag-circle {
+ cursor: pointer;
+}
+
+.kk-useflag-bubble-container {
+ text-align: center;
+ overflow: scroll;
+}
+
+.kk-useflag-listing {
+ a:link,
+ a:visited {
+ color: #333;
+ }
+}
+
+form.useflag-search {
+ margin-top: 2.5em;
+ margin-bottom: 1em;
+}
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
new file mode 100644
index 0000000..e41c3b5
--- /dev/null
+++ b/app/controllers/about_controller.rb
@@ -0,0 +1,27 @@
+class AboutController < ApplicationController
+ before_action :set_nav
+
+ def feedback
+ if params.key? :feedback
+ FeedbackMailer.feedback_email(params[:feedback], params[:contact]).deliver_now
+ render text: 'Thank you for your feedback!', layout: 'application'
+ end
+ end
+
+ def index
+ end
+
+ def feeds
+ end
+
+ def legacy
+ @feed_type = 'legacy'
+ @feed_title = 'packages.gentoo.org Legacy Feed'
+ end
+
+ private
+
+ def set_nav
+ @nav = :about
+ end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
new file mode 100644
index 0000000..9e8e1ca
--- /dev/null
+++ b/app/controllers/application_controller.rb
@@ -0,0 +1,13 @@
+class ApplicationController < ActionController::Base
+ before_action :set_locale, :set_caching
+
+ def set_locale
+ I18n.locale = params[:hl] || I18n.default_locale
+ rescue
+ I18n.default_locale
+ end
+
+ def set_caching
+ expires_in 10.minutes, public: true
+ end
+end
diff --git a/app/controllers/arches_controller.rb b/app/controllers/arches_controller.rb
new file mode 100644
index 0000000..cbbcb65
--- /dev/null
+++ b/app/controllers/arches_controller.rb
@@ -0,0 +1,63 @@
+class ArchesController < ApplicationController
+ before_action :set_nav
+ before_action :set_arch, only: [:show, :added, :updated, :stable, :keyworded]
+
+ def index
+ end
+
+ def show
+ end
+
+ def stable
+ @changes = stabled_packages @arch
+ render_changes_feed :stable, t(:feed_stable_arch, arch: @arch)
+ end
+
+ def keyworded
+ @changes = keyworded_packages @arch
+ render_changes_feed :keyworded, t(:feed_keyworded, arch: @arch)
+ end
+
+ private
+
+ def set_nav
+ @nav = :arches
+ end
+
+ def set_arch
+ fail ActionController::RoutingError, 'No such architecture' unless ::KKULEOMI_ARCHES.include? params[:id]
+ @arch = params[:id]
+ @feed_id = @arch
+ end
+
+ def render_changes_feed(type, title)
+ respond_to do |wants|
+ wants.html {}
+ wants.atom do
+ @feed_type = type
+ @feed_title = title
+ render template: 'feeds/changes'
+ end
+ end
+ end
+
+ def keyworded_packages(arch)
+ Rails.cache.fetch("keyworded_packages/#{arch}", expires_in: 10.minutes) do
+ Change.filter_all({ change_type: 'keyword', arches: arch },
+ size: 50,
+ sort: { created_at: { order: 'desc' } }).map do |change|
+ change.to_os(:change_type, :package, :category, :version, :arches, :created_at)
+ end
+ end
+ end
+
+ def stabled_packages(arch)
+ Rails.cache.fetch("stabled_packages/#{arch}", expires_in: 10.minutes) do
+ Change.filter_all({ change_type: 'stable', arches: arch },
+ size: 50,
+ sort: { created_at: { order: 'desc' } }).map do |change|
+ change.to_os(:change_type, :package, :category, :version, :arches, :created_at)
+ end
+ end
+ end
+end
diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb
new file mode 100644
index 0000000..e144df7
--- /dev/null
+++ b/app/controllers/categories_controller.rb
@@ -0,0 +1,39 @@
+class CategoriesController < ApplicationController
+ before_action :set_category, only: [:show, :search]
+ before_action :set_nav
+
+ def index
+ @categories = Category.all_sorted_by(:name, :asc)
+ end
+
+ def show
+ @packages = Rails.cache.fetch("category/#{@category.name}/packages",
+ expires_in: 10.minutes) do
+ Package.find_all_by(:category,
+ @category.name,
+ sort: { name_sort: { order: 'asc' } }).map do |pkg|
+ pkg.to_os(:name, :atom, :description)
+ end
+ end
+
+ @description = t(:desc_categories_show,
+ category: @category.name,
+ description: @category.description)
+ end
+
+ def search
+ end
+
+ private
+
+ def set_category
+ @category = Category.find_by(:name, params[:id])
+ fail ActionController::RoutingError, 'No such category' unless @category
+
+ @title = @category.name
+ end
+
+ def set_nav
+ @nav = :packages
+ end
+end
diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/controllers/concerns/.keep
diff --git a/app/controllers/concerns/package_update_feeds.rb b/app/controllers/concerns/package_update_feeds.rb
new file mode 100644
index 0000000..2d20672
--- /dev/null
+++ b/app/controllers/concerns/package_update_feeds.rb
@@ -0,0 +1,35 @@
+module PackageUpdateFeeds
+ extend ActiveSupport::Concern
+
+ def new_packages
+ Rails.cache.fetch('new_packages', expires_in: 10.minutes) do
+ Change.find_all_by(:change_type, 'new_package', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change|
+ change.to_os(:change_type, :package, :category, :created_at)
+ end
+ end
+ end
+
+ def version_bumps
+ Rails.cache.fetch('version_bumps', expires_in: 10.minutes) do
+ Change.find_all_by(:change_type, 'version_bump', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change|
+ change.to_os(:change_type, :package, :category, :version, :created_at)
+ end
+ end
+ end
+
+ def keyworded_packages
+ Rails.cache.fetch('keyworded_packages', expires_in: 10.minutes) do
+ Change.find_all_by(:change_type, 'keyword', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change|
+ change.to_os(:change_type, :package, :category, :version, :arches, :created_at)
+ end
+ end
+ end
+
+ def stabled_packages
+ Rails.cache.fetch('stabled_packages', expires_in: 10.minutes) do
+ Change.find_all_by(:change_type, 'stable', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change|
+ change.to_os(:change_type, :package, :category, :version, :arches, :created_at)
+ end
+ end
+ end
+end
diff --git a/app/controllers/index_controller.rb b/app/controllers/index_controller.rb
new file mode 100644
index 0000000..ba866c6
--- /dev/null
+++ b/app/controllers/index_controller.rb
@@ -0,0 +1,10 @@
+class IndexController < ApplicationController
+ include PackageUpdateFeeds
+
+ def index
+ @nav = :index
+
+ @new_packages = new_packages[0..9]
+ @version_bumps = version_bumps[0..9]
+ end
+end
diff --git a/app/controllers/packages_controller.rb b/app/controllers/packages_controller.rb
new file mode 100644
index 0000000..ee098ae
--- /dev/null
+++ b/app/controllers/packages_controller.rb
@@ -0,0 +1,84 @@
+class PackagesController < ApplicationController
+ include PackageUpdateFeeds
+ before_action :set_nav
+
+ def index
+ redirect_to categories_path
+ end
+
+ def search
+ @offset = params[:o].to_i || 0
+ @packages = Package.default_search(params[:q], @offset)
+
+ redirect_to package_path(@packages.first).gsub('%2F', '/') if @packages.size == 1
+ end
+
+ def suggest
+ @packages = Package.suggest(params[:q])
+ end
+
+ def resolve
+ @packages = Package.resolve(params[:atom])
+ end
+
+ def show
+ @package = Package.find_by(:atom, params[:id])
+ fail ActionController::RoutingError, 'No such package' unless @package
+
+ # Enable this in 2024 (when we have full-color emojis on a Linux desktop)
+ # @title = ' &#x1F4E6; %s' % @package.atom
+ @title = @package.atom
+ @description = 'Gentoo package %s: %s' % [@package.atom, @package.description]
+ end
+
+ def changelog
+ @package = Package.find_by(:atom, params[:id])
+ fail ActionController::RoutingError, 'No such package' unless @package
+
+ @changelog = Rails.cache.fetch("changelog/#{@package.atom}", expires_in: 10.minutes) do
+ Portage::Util::History.for(@package.category, @package.name, 5)
+ end
+
+ respond_to do |wants|
+ wants.html { render layout: false }
+ wants.json {}
+ end
+ end
+
+ def added
+ @changes = new_packages
+ render_changes_feed :added, t(:feed_added)
+ end
+
+ def updated
+ @changes = version_bumps
+ render_changes_feed :updated, t(:feed_updated)
+ end
+
+ def stable
+ @changes = stabled_packages
+ render_changes_feed :stable, t(:feed_stable)
+ end
+
+ def keyworded
+ @changes = keyworded_packages
+ render_changes_feed :keyworded, t(:feed_keyworded)
+ end
+
+ private
+
+ def render_changes_feed(type, title)
+ respond_to do |wants|
+ wants.html {}
+ wants.atom do
+ @feed_type = type
+ @feed_title = title
+ render template: 'feeds/changes'
+ end
+ end
+ end
+
+ def set_nav
+ @nav = :packages
+ end
+end
diff --git a/app/controllers/useflags_controller.rb b/app/controllers/useflags_controller.rb
new file mode 100644
index 0000000..0fa74f4
--- /dev/null
+++ b/app/controllers/useflags_controller.rb
@@ -0,0 +1,50 @@
+class UseflagsController < ApplicationController
+ before_action :set_nav
+
+ def index
+ @title = t :use_flags
+ end
+
+ def show
+ @useflags = Useflag.get_flags(params[:id])
+
+ if @useflags.empty? || (@useflags[:use_expand].empty? && @useflags[:local].empty? && @useflags[:global].empty?)
+ fail ActionController::RoutingError, 'No such useflag'
+ end
+
+ @packages = Package.find_atoms_by_useflag(params[:id])
+ @title = '%s – %s' % [params[:id], t(:use_flags)]
+
+ unless @useflags[:use_expand].empty?
+ @useflag = @useflags[:use_expand].first
+ @use_expand_flags = Useflag.find_all_by(:use_expand_prefix, @useflag.use_expand_prefix)
+ @use_expand_flag_name = @useflag.use_expand_prefix.upcase
+
+ render template: 'useflags/show_use_expand'
+ return
+ else
+ render template: 'useflags/show'
+ end
+ end
+
+ def search
+ # TODO: Different search?
+ @flags = Useflag.suggest(params[:q])
+ end
+
+ def suggest
+ @flags = Useflag.suggest(params[:q])
+ end
+
+ def popular
+ @popular_useflags = Rails.cache.fetch('popular_useflags', expires_in: 24.hours) do
+ Version.get_popular_useflags(100)
+ end
+ end
+
+ private
+
+ def set_nav
+ @nav = :use
+ end
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
new file mode 100644
index 0000000..619582c
--- /dev/null
+++ b/app/helpers/application_helper.rb
@@ -0,0 +1,51 @@
+module ApplicationHelper
+ def cp_to_atom(category, package)
+ '%s/%s' % [category, package]
+ end
+
+ def atom_add_version(atom, version)
+ '%s-%s' % [atom, version]
+ end
+
+ # Generates a somewhat sensible atom ID
+ def atom_id(*args)
+ ['tag:packages.gentoo.org,2015-10-03', args].flatten.compact.join ':'
+ end
+
+ def alternate_feed_link(url, description, mime = 'application/atom+xml')
+ tag :link,
+ rel: 'alternate',
+ href: url,
+ title: description,
+ type: mime
+ end
+
+ # Renders a label displaying the first letters of the components of a string
+ def abbreviated_label(items, css_class, message_id)
+ return '' if items.nil? || items.empty?
+
+ letters = strip_conditionals(items).map { |r| r[0].upcase }.uniq
+
+ content_tag :span,
+ letters.join(', '),
+ class: 'label %s' % css_class,
+ title: t(message_id, list: items.join(' '))
+ end
+
+ def last_import_start
+ Rails.cache.fetch(::KK_CACHE_LAST_IMPORT)
+ end
+
+ def i18n_date(date, format = '%a, %e %b %Y %H:%M')
+ content_tag :span,
+ l(date, format: format),
+ class: 'kk-i18n-date',
+ :'data-utcts' => date.strftime('%s'),
+ :'data-format' => format.to_s,
+ title: date.to_formatted_s(:rfc822)
+ end
+
+ def kk_changelog
+ File.read('CHANGES.md')
+ end
+end
diff --git a/app/helpers/arches_helper.rb b/app/helpers/arches_helper.rb
new file mode 100644
index 0000000..670d125
--- /dev/null
+++ b/app/helpers/arches_helper.rb
@@ -0,0 +1,2 @@
+module ArchesHelper
+end
diff --git a/app/helpers/keywords_helper.rb b/app/helpers/keywords_helper.rb
new file mode 100644
index 0000000..2444a6b
--- /dev/null
+++ b/app/helpers/keywords_helper.rb
@@ -0,0 +1,90 @@
+# Helper methods for dealing with package version KEYWORDS
+module KeywordsHelper
+ # Renders an icon for a keyword status
+ def keyword_icon_tag(keyword)
+ css_class = KK_KEYWORD_ICON[keyword]
+
+ if css_class
+ content_tag :span,
+ '',
+ class: ['octicon', css_class]
+ else
+ ''
+ end
+ end
+
+ # Retrieves the CSS class for a keyword
+ def keyword_class(keyword)
+ KK_KEYWORD_CLASS[keyword] || nil
+ end
+
+ # Displays a keyword icon plus text-mdoe browser fallback
+ def keyword_icon(keyword, arch)
+ capture do
+ concat keyword_icon_tag(keyword)
+ concat keyword_fallback_tag(keyword, arch)
+ end
+ end
+
+ # Renders a keyword as a familiar string
+ def keyword_string(keyword, arch)
+ case keyword
+ when :stable
+ arch
+ when :testing
+ '~%s' % arch
+ when :unavailable
+ '-%s' % arch
+ when :masked
+ '[M]%s' % arch
+ else
+ '?%s' % arch
+ end
+ end
+
+ def keyword_fallback_tag(keyword, arch)
+ content_tag :span,
+ keyword_string(keyword, arch),
+ class: 'sr-only'
+ end
+
+ def verbalize_version_visibility(version, arch)
+ keyword = t(KK_KEYWORD_VERBALIZATION[version.keyword(arch)])
+
+ keyword_str = keyword
+ keyword_str = '%s (%s)' % [
+ t(KK_KEYWORD_VERBALIZATION[:masked]),
+ keyword
+ ] if version.is_masked?
+
+ t 'keyword_tooltip',
+ version: version.version,
+ keyword: keyword_str,
+ arch: arch
+ end
+
+ def keyword_cell(version, arch, large_separator = false)
+ effective_keyword = version.effective_keyword arch
+
+ css_class = ['kk-keyword']
+ css_class << 'kk-cell-sep-right' if large_separator
+ css_class << keyword_class(effective_keyword)
+
+ content_tag :td,
+ keyword_icon(effective_keyword, arch),
+ class: css_class,
+ title: verbalize_version_visibility(version, arch)
+ end
+
+ def keyword_label(version, arch)
+ effective_keyword = version.effective_keyword arch
+
+ css_class = ['label']
+ css_class << keyword_class(effective_keyword)
+
+ content_tag :span,
+ keyword_string(effective_keyword, arch),
+ class: css_class,
+ title: verbalize_version_visibility(version, arch)
+ end
+end
diff --git a/app/helpers/links_helper.rb b/app/helpers/links_helper.rb
new file mode 100644
index 0000000..5a28fb0
--- /dev/null
+++ b/app/helpers/links_helper.rb
@@ -0,0 +1,56 @@
+module LinksHelper
+ # Slash-in-Link-Fix
+ # Replaces the URLencoded slash with a proper slash
+ def slf(input)
+ input.gsub('%2F', '/')
+ end
+
+ def link_to_gitweb_commit(commitid)
+ link_to commitid[0...8],
+ gitweb_commit_url(commitid),
+ title: commitid,
+ class: 'kk-commit'
+ end
+
+ def gitweb_commit_url(commitid)
+ 'https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=%s' % commitid
+ end
+
+ def link_to_gitweb_ebuild_diff(name, commitid, cat, pkg)
+ link_to name, 'https://gitweb.gentoo.org/repo/gentoo.git/diff/%s/%s/%s?id=%s' % [cat, pkg, name, commitid]
+ end
+
+ def link_to_license_text(license)
+ link_to license, 'https://gitweb.gentoo.org/repo/gentoo.git/plain/licenses/%s' % license
+ end
+
+ def link_to_category(category)
+ link_to category.name,
+ category_path(category),
+ title: category.description,
+ 'data-toggle' => 'tooltip',
+ 'data-placement' => 'right'
+ end
+
+ def link_to_package(atom)
+ link_to atom, slf(package_path(atom))
+ end
+
+ def link_to_herd(herd)
+ link_to herd, 'https://www.gentoo.org/inside-gentoo/developers/herds.html#%s' % herd
+ end
+
+ def link_to_bug(str, bugid)
+ link_to str, 'https://bugs.gentoo.org/show_bug.cgi?id=%s' % bugid
+ end
+
+ def absolute_link_to_package(atom)
+ slf package_url(atom)
+ end
+
+ def feed_icon(url)
+ content_tag :a,
+ content_tag(:span, '', class: 'fa fa-fw fa-rss-square'),
+ title: t(:atom_feed), href: url, class: 'kk-feed-icon'
+ end
+end
diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb
new file mode 100644
index 0000000..ed90f5d
--- /dev/null
+++ b/app/helpers/packages_helper.rb
@@ -0,0 +1,81 @@
+# Helpers for displaying package models
+module PackagesHelper
+ def restrict_label(version)
+ abbreviated_label version.restrict,
+ 'label-danger kk-restrict-label',
+ :restrict_tooltip
+ end
+
+ def properties_label(version)
+ abbreviated_label version.properties,
+ 'label-info kk-properties-label',
+ :properties_tooltip
+ end
+
+ def version_labels(version)
+ capture do
+ concat restrict_label(version)
+ concat properties_label(version)
+ end
+ end
+
+ def annotate_license_str(str)
+ str.split(/\s/).map do |license|
+ if license[0] =~ /[[:alpha:]]/ && !license.end_with?('?')
+ link_to_license_text license
+ else
+ h license
+ end
+ end.join(' ').html_safe
+ end
+
+ def annotate_bugs(str)
+ annotated_str = str.gsub(/([bB]ug\s+|[bB]ug\s+#|#)(\d+)/) do
+ link_to_bug("#{$1}#{$2}", $2)
+ end
+
+ sanitize(annotated_str, tags: ['a'], attributes: ['href'])
+ end
+
+ # Filters duplicate masks
+ def filter_masks(versions)
+ masks = {}
+
+ versions.each do |version|
+ version.masks.each do |mask|
+ masks[mask['reason']] = mask
+ end
+ end
+
+ masks.values
+ end
+
+ def version_slot(slot, subslot = nil)
+ title = "subslot #{subslot}" if subslot && !subslot.empty?
+
+ content_tag :span,
+ sanitize('&#x2008;:&#x2008;%s' % slot),
+ class: 'kk-slot',
+ title: title
+ end
+
+ # Returns a list of members belonging to a project
+ def project_members(project)
+ Portage::Util::Projects.cached_instance.inherited_members(project)
+ end
+
+ # Tries to find a matching changelog entry for a change object
+ def matching_changelog_entry(change)
+ changelog = Rails.cache.fetch("changelog/#{cp_to_atom(change.category, change.package)}", expires_in: 10.minutes) do
+ Portage::Util::History.for(change.category, change.package, 5)
+ end
+
+ changelog.each do |changelog_entry|
+ if changelog_entry[:files][:added].include?('%s-%s.ebuild' % [change.package, change.version])
+ return changelog_entry
+ end
+ end
+
+ nil
+ end
+end
diff --git a/app/helpers/portage_helper.rb b/app/helpers/portage_helper.rb
new file mode 100644
index 0000000..3e1b9e6
--- /dev/null
+++ b/app/helpers/portage_helper.rb
@@ -0,0 +1,8 @@
+module PortageHelper
+ # Strips condition constructs ("foo? ()") from a Portage definition
+ def strip_conditionals(ary)
+ ary.reject do |item|
+ (not item[0] =~ /[[:alpha:]]/) or item.end_with? '?'
+ end
+ end
+end
diff --git a/app/helpers/useflags_helper.rb b/app/helpers/useflags_helper.rb
new file mode 100644
index 0000000..258cec2
--- /dev/null
+++ b/app/helpers/useflags_helper.rb
@@ -0,0 +1,5 @@
+module UseflagsHelper
+ def annotate_useflag_description(str)
+ sanitize(str.gsub(/<pkg>([^<]+)<\/pkg>/) { pkg=$~[1] ; link_to(pkg, slf(package_path(pkg))) }, tags: ['a'], attributes: ['href'])
+ end
+end
diff --git a/app/jobs/category_update_job.rb b/app/jobs/category_update_job.rb
new file mode 100644
index 0000000..6418bb4
--- /dev/null
+++ b/app/jobs/category_update_job.rb
@@ -0,0 +1,39 @@
+class CategoryUpdateJob < ActiveJob::Base
+ queue_as :default
+
+ def perform(*args)
+ category_path, options = args
+
+ model = Portage::Repository::Category.new(category_path)
+ category = Category.find_by(:name, model.name) || Category.new
+ idx_packages = Package.find_all_by(:category, model.name) || []
+
+ if category.needs_import? model
+ category.import! model
+ end
+
+ idx_package_map = Hash[idx_packages.map { |p| [p.name, p] }]
+ model_package_map = Hash[model.packages.map { |p| [p.name, p] }]
+
+ idx_keys = idx_package_map.keys
+ model_keys = model_package_map.keys
+
+ new_p = model_keys - idx_keys
+ eql_p = model_keys & idx_keys
+ del_p = idx_keys - model_keys
+
+ new_p.each do |pkg_name|
+ PackageUpdateJob.perform_later model_package_map[pkg_name].path, options.merge(package_state: 'new')
+ end
+
+ eql_p.each do |pkg_name|
+ if idx_package_map[pkg_name].needs_import? model_package_map[pkg_name]
+ PackageUpdateJob.perform_later model_package_map[pkg_name].path, options.merge(package_state: 'existing')
+ end
+ end
+
+ del_p.each do |pkg_name|
+ PackageRemovalJob.perform_later '%s/%s' % [category.name, pkg_name]
+ end
+ end
+end
diff --git a/app/jobs/masks_update_job.rb b/app/jobs/masks_update_job.rb
new file mode 100644
index 0000000..a6574a0
--- /dev/null
+++ b/app/jobs/masks_update_job.rb
@@ -0,0 +1,7 @@
+class MasksUpdateJob < ActiveJob::Base
+ queue_as :default
+
+ def perform(*_args)
+ Portage::Util::Masks.update!
+ end
+end
diff --git a/app/jobs/package_removal_job.rb b/app/jobs/package_removal_job.rb
new file mode 100644
index 0000000..1041f05
--- /dev/null
+++ b/app/jobs/package_removal_job.rb
@@ -0,0 +1,16 @@
+class PackageRemovalJob < ActiveJob::Base
+ queue_as :default
+
+ def perform(*args)
+ atom, _options = args
+
+ package_doc = Package.find_by(:atom, atom)
+ return if package_doc.nil?
+
+ package_doc.versions.each(&:delete)
+ package_doc.delete
+
+ Rails.logger.warn { "Package deleted: #{atom}" }
+ # USE flags are cleaned up by the UseflagsUpdateJob
+ end
+end
diff --git a/app/jobs/package_update_job.rb b/app/jobs/package_update_job.rb
new file mode 100644
index 0000000..8c4fd43
--- /dev/null
+++ b/app/jobs/package_update_job.rb
@@ -0,0 +1,13 @@
+class PackageUpdateJob < ActiveJob::Base
+ queue_as :default
+
+ def perform(*args)
+ path, options = args
+ package_model = Portage::Repository::Package.new(path)
+ package_doc = Package.find_by(:atom, package_model.to_cp) || Package.new
+
+ if package_doc.needs_import? package_model
+ package_doc.import!(package_model, options)
+ end
+ end
+end
diff --git a/app/jobs/record_change_job.rb b/app/jobs/record_change_job.rb
new file mode 100644
index 0000000..b2b4b10
--- /dev/null
+++ b/app/jobs/record_change_job.rb
@@ -0,0 +1,30 @@
+class RecordChangeJob < ActiveJob::Base
+ queue_as :default
+
+ # Creates a Change object for the given data
+ def perform(args)
+ c = Change.new
+ c.package = args[:package]
+ c.category = args[:category]
+ c.actor = args[:actor] if args.has_key? :actor
+
+ if args[:type] == 'new_package'
+ c.change_type = 'new_package'
+ elsif args[:type] == 'version_bump'
+ c.change_type = 'version_bump'
+ c.version = args[:version]
+ elsif args[:type] == 'stable'
+ c.change_type = 'stable'
+ c.version = args[:version]
+ c.arches = args[:arches]
+ elsif args[:type] == 'keyword'
+ c.change_type = 'keyword'
+ c.version = args[:version]
+ c.arches = args[:arches]
+ elsif args[:type] == 'package_removed'
+ c.change_type = 'removal'
+ end
+
+ c.save
+ end
+end
diff --git a/app/jobs/useflags_update_job.rb b/app/jobs/useflags_update_job.rb
new file mode 100644
index 0000000..d6f9e9b
--- /dev/null
+++ b/app/jobs/useflags_update_job.rb
@@ -0,0 +1,78 @@
+class UseflagsUpdateJob < ActiveJob::Base
+ queue_as :default
+
+ def perform(*args)
+ repo = Portage::Repository::Model.new KKULEOMI_PORTDIR
+
+ update_global repo
+ update_use_expand repo
+ end
+
+ def update_global(repo)
+ model_flags = repo.global_useflags
+ index_flags = Useflag.global
+
+ new_flags = model_flags.keys - index_flags.keys
+ del_flags = index_flags.keys - model_flags.keys
+ eql_flags = model_flags.keys & index_flags.keys
+
+ new_flags.each do |flag|
+ flag_doc = Useflag.new
+ flag_doc.name = flag
+ flag_doc.description = model_flags[flag]
+ flag_doc.scope = 'global'
+ flag_doc.save
+ end
+
+ eql_flags.each do |flag|
+ unless index_flags[flag].description == model_flags[flag]
+ index_flags[flag].description = model_flags[flag]
+ index_flags[flag].save
+ end
+ end
+
+ del_flags.each do |flag|
+ index_flags[flag].delete
+ end
+ end
+
+ def update_use_expand(repo)
+ model_flags = repo.use_expand_flags
+ index_flags = Useflag.use_expand
+
+ # Calculate keys only once
+ index_flag_keys = index_flags.keys
+
+ # Record processed flags to find deletion candidates
+ flag_status = Hash[index_flag_keys.map {|key| [key, false] }]
+
+ model_flags.each_pair do |variable, values_hsh|
+ values_hsh.each_pair do |flag, desc|
+ _flag = '%s_%s' % [variable, flag]
+ flag_status[_flag] = true
+
+ # Already present ones
+ if index_flag_keys.include? _flag
+ unless index_flags[_flag].description == desc
+ index_flags[_flag].description = desc
+ index_flags[_flag].save
+ end
+ else
+ # New flag
+ flag_doc = Useflag.new
+ flag_doc.name = _flag
+ flag_doc.description = desc
+ flag_doc.scope = 'use_expand'
+ flag_doc.use_expand_prefix = variable
+ flag_doc.save
+ end
+ end
+ end
+
+ # Find and process removed flags
+ flag_status.each_pair do |flag, status|
+ index_flags[flag].delete unless status
+ end
+ end
+
+end
diff --git a/app/mailers/.keep b/app/mailers/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/mailers/.keep
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
new file mode 100644
index 0000000..28eebce
--- /dev/null
+++ b/app/mailers/application_mailer.rb
@@ -0,0 +1,4 @@
+class ApplicationMailer < ActionMailer::Base
+ default from: 'gpackages@gentoo.org'
+ layout 'mailer'
+end
diff --git a/app/mailers/feedback_mailer.rb b/app/mailers/feedback_mailer.rb
new file mode 100644
index 0000000..3ec045c
--- /dev/null
+++ b/app/mailers/feedback_mailer.rb
@@ -0,0 +1,8 @@
+class FeedbackMailer < ApplicationMailer
+ def feedback_email(feedback, contact)
+ @feedback = feedback
+ @contact = contact
+
+ mail(to: KKULEOMI_FEEDBACK_RECIPIENT, subject: 'Feedback')
+ end
+end
diff --git a/app/models/.keep b/app/models/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/models/.keep
diff --git a/app/models/category.rb b/app/models/category.rb
new file mode 100644
index 0000000..5fa31ea
--- /dev/null
+++ b/app/models/category.rb
@@ -0,0 +1,39 @@
+class Category
+ include Elasticsearch::Persistence::Model
+ include Kkuleomi::Store::Model
+
+ index_name "packages-#{Rails.env}"
+
+ attribute :name, String, mapping: { index: 'not_analyzed' }
+ attribute :description, String
+ attribute :metadata_hash, String, mapping: { index: 'not_analyzed' }
+
+ # Determines if the document model needs an update from the repository model
+ #
+ # @param [Portage::Repository::Category] category_model
+ def needs_import?(category_model)
+ metadata_hash != category_model.metadata_hash
+ end
+
+ # Populates values from a repository category model
+ #
+ # @param [Portage::Repository::Category] category_model Input category model
+ def import(category_model)
+ self.name = category_model.name
+ self.description = category_model.description
+ self.metadata_hash = category_model.metadata_hash
+ end
+
+ # Populates values from a repository category model and saves
+ #
+ # @param [Portage::Repository::Category] category_model Input category model
+ def import!(category_model)
+ import(category_model)
+ save
+ end
+
+ # Returns the URL parameter for referencing this package (Rails internal stuff)
+ def to_param
+ name
+ end
+end
diff --git a/app/models/change.rb b/app/models/change.rb
new file mode 100644
index 0000000..9ffe258
--- /dev/null
+++ b/app/models/change.rb
@@ -0,0 +1,13 @@
+class Change
+ include Elasticsearch::Persistence::Model
+ include Kkuleomi::Store::Model
+
+ index_name "packages-#{Rails.env}"
+
+ attribute :package, String, mapping: { index: 'not_analyzed' }
+ attribute :category, String, mapping: { index: 'not_analyzed' }
+ attribute :change_type, String, mapping: { index: 'not_analyzed' }
+ attribute :version, String, mapping: { index: 'not_analyzed' }
+ attribute :arches, String, mapping: { index: 'not_analyzed' }
+ attribute :commit, Hash, default: {}, mapping: { type: 'object' }
+end
diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/models/concerns/.keep
diff --git a/app/models/package.rb b/app/models/package.rb
new file mode 100644
index 0000000..24cbd8b
--- /dev/null
+++ b/app/models/package.rb
@@ -0,0 +1,74 @@
+class Package
+ include Elasticsearch::Persistence::Model
+ include Kkuleomi::Store::Model
+ include Kkuleomi::Store::Models::PackageImport
+ include Kkuleomi::Store::Models::PackageSearch
+
+ index_name "packages-#{Rails.env}"
+
+ attribute :category, String, mapping: { index: 'not_analyzed' }
+ attribute :name, String, mapping: { index: 'not_analyzed' }
+ attribute :name_sort, String, mapping: { index: 'not_analyzed' }
+ attribute :atom, String, mapping: { index: 'not_analyzed' }
+ attribute :description, String
+ attribute :longdescription, String
+ attribute :homepage, String, default: [], mapping: { index: 'not_analyzed' }
+ attribute :license, String, mapping: { index: 'not_analyzed' }
+ attribute :licenses, String, default: [], mapping: { index: 'not_analyzed' }
+ attribute :herds, String, default: [], mapping: { index: 'not_analyzed' }
+ attribute :maintainers, Array, default: [], mapping: { type: 'object' }
+ attribute :useflags, Hash, default: {}, mapping: { type: 'object' }
+ attribute :metadata_hash, String, mapping: { index: 'not_analyzed' }
+
+ def category_model
+ @category_model ||= Category.find_by(:name, category)
+ end
+
+ def to_param
+ atom
+ end
+
+ # Are all of the versions of this package pending for removal?
+ #
+ # @return [Boolean] true, if all of the versions' masks look like a removal mask
+ def removal_pending?
+ versions.map(&:removal_pending?).uniq == [true]
+ end
+
+ def has_useflags?
+ useflags && !(useflags['local'].empty? && useflags['global'].empty? && useflags['use_expand'])
+ end
+
+ def versions
+ @versions ||= Version.find_all_by_parent(self, sort: { sort_key: { order: 'asc' } })
+ end
+
+ def latest_version
+ versions.first
+ end
+
+ def version(version_str)
+ versions.each { |version| return version if version.version == version_str }
+
+ nil
+ end
+
+ # Does this package need a maintainer?
+ #
+ # @return [Boolean] true, if it is assigned to maintainer-needed or has no maintainers
+ def needs_maintainer?
+ (maintainers.size == 1 && maintainers.first['email'] == 'maintainer-needed@gentoo.org') ||
+ maintainers.empty? && herds.empty?
+ end
+
+ private
+
+ # Splits a license string into single licenses, stripping the permitted logic constructs
+ def split_license_str(str)
+ return [] unless str
+
+ str.split(/\s/).reject do |license|
+ (not license[0] =~ /[[:alpha:]]/) or license.end_with? '?'
+ end
+ end
+end
diff --git a/app/models/useflag.rb b/app/models/useflag.rb
new file mode 100644
index 0000000..1139c97
--- /dev/null
+++ b/app/models/useflag.rb
@@ -0,0 +1,99 @@
+class Useflag
+ include Elasticsearch::Persistence::Model
+ include Kkuleomi::Store::Model
+
+ index_name "packages-#{Rails.env}"
+
+ attribute :name, String, mapping: { index: 'not_analyzed' }
+ attribute :description, String
+ attribute :atom, String, mapping: { index: 'not_analyzed' }
+ attribute :scope, String, mapping: { index: 'not_analyzed' }
+ attribute :use_expand_prefix, String, mapping: { index: 'not_analyzed' }
+
+ def all_fields
+ [:name, :description, :atom, :scope, :use_expand_prefix]
+ end
+
+ def to_param
+ name
+ end
+
+ def strip_use_expand
+ name.gsub(use_expand_prefix + '_', '')
+ end
+
+ class << self
+ # Retrieves all flags sorted by their state
+ def get_flags(name)
+ result = { local: {}, global: [], use_expand: [] }
+
+ find_all_by(:name, name).each do |flag|
+ case flag.scope
+ when 'local'
+ result[:local][flag.atom] = flag
+ when 'global'
+ result[:global] << flag
+ when 'use_expand'
+ result[:use_expand] << flag
+ end
+ end
+
+ result
+ end
+
+ def suggest(q)
+ results = Useflag.search(
+ size: 20,
+ query: { match_phrase_prefix: { name: q } }
+ )
+
+ processed_results = {}
+ results.each do |result|
+ if processed_results.key? result.name
+ processed_results[result.name] = {
+ name: result.name,
+ description: '(multiple definitions)',
+ scope: 'multi'
+ }
+ else
+ processed_results[result.name] = result
+ end
+ end
+
+ processed_results.values.sort { |a, b| a[:name].length <=> b[:name].length }
+ end
+
+ # Loads the local USE flags for a given package in a name -> model hash
+ #
+ # @param [String] atom Package to find flags for
+ # @return [Hash]
+ def local_for(atom)
+ map_by_name find_all_by(:atom, atom)
+ end
+
+ # Maps the global USE flags in the index by their name
+ # This is expensive!
+ #
+ def global
+ map_by_name find_all_by(:scope, 'global')
+ end
+
+ # Maps the USE_EXPAND variables in the index by their name
+ #
+ def use_expand
+ map_by_name find_all_by(:scope, 'use_expand')
+ end
+
+ private
+
+ def map_by_name(collection)
+ map = {}
+
+ collection.each do |item|
+ map[item.name] = item
+ end
+
+ map
+ end
+ end
+end
diff --git a/app/models/version.rb b/app/models/version.rb
new file mode 100644
index 0000000..1dc28f8
--- /dev/null
+++ b/app/models/version.rb
@@ -0,0 +1,165 @@
+class Version
+ include Elasticsearch::Persistence::Model
+ include Kkuleomi::Store::Model
+ include Kkuleomi::Store::Models::VersionImport
+
+ index_name "packages-#{Rails.env}"
+
+ attribute :version, String, mapping: { index: 'not_analyzed' }
+ attribute :package, String, mapping: { index: 'not_analyzed' }
+ attribute :atom, String, mapping: { index: 'not_analyzed' }
+ attribute :sort_key, Integer, mapping: { index: 'not_analyzed' }
+ attribute :slot, String, mapping: { index: 'not_analyzed' }
+ attribute :subslot, String, mapping: { index: 'not_analyzed' }
+ attribute :eapi, String, mapping: { index: 'not_analyzed' }
+ attribute :keywords, String, mapping: { index: 'not_analyzed' }
+ attribute :masks, Array, default: [], mapping: { type: 'object' }
+ attribute :use, String, default: [], mapping: { index: 'not_analyzed' }
+ attribute :restrict, String, default: [], mapping: { index: 'not_analyzed' }
+ attribute :properties, String, default: [], mapping: { index: 'not_analyzed' }
+ attribute :metadata_hash, String, mapping: { index: 'not_analyzed' }
+
+ # Returns the keywording state on a given architecture
+ #
+ # @param [String] arch Architecture to query
+ # @return [Symbol] :stable, :testing, :unavailable, :unknown
+ def keyword(arch)
+ @keyword_info_cache ||= parse_keywords keywords
+
+ if @keyword_info_cache[:arches].key? arch
+ @keyword_info_cache[:arches][arch]
+ else
+ if @keyword_info_cache[:exclude_all]
+ :unavailable
+ else
+ :unknown
+ end
+ end
+ end
+
+ # Returns the effective keyword on a given architecture, accounting for masks
+ #
+ # @param [String] arch Architecture to query
+ # @return [Symbol] Keyword status
+ def effective_keyword(arch)
+ if is_masked?(arch)
+ :masked
+ else
+ keyword(arch)
+ end
+ end
+
+ # Returns the masks that apply to the given architecture
+ #
+ def mask(arch)
+ masks.reject do |m|
+ if m['arch'] == '*'
+ false
+ else
+ m['arch'] != arch
+ end
+ end
+ end
+
+ # Checks the masks whether one sounds like a package removal.
+ def removal_pending?
+ return false if masks.empty?
+
+ masks.each do |m|
+ if m['reason'].include?('removal') || m['reason'].include?('Removal')
+ return true
+ end
+ end
+
+ false
+ end
+
+ def is_masked?(arch = nil)
+ !mask(arch).empty?
+ end
+
+ # Returns supported USE flags categorized by local, global, and USE_EXPAND
+ # Typically called in the import phase, not live
+ #
+ # @return [Hash]
+ def useflags
+ @useflags ||= calc_useflags
+ end
+
+ # Retrieves the most widely used USE flags by all versions
+ # Note that packages with many versions are over-represented
+ def self.get_popular_useflags(n = 50)
+ search(
+ query: { match_all: {} },
+ aggs: {
+ group_by_flag: {
+ terms: {
+ field: 'use',
+ size: n
+ }
+ }
+ },
+ size: 0
+ ).response.aggregations['group_by_flag'].buckets
+ end
+
+ # Parses a keyword array and assigns tags for each arch
+ #
+ # @param [Array<String>] keywords Input keywords
+ # @return [Hash] Parsed keywords
+ def parse_keywords(keywords)
+ res = { exclude_all: false, arches: {} }
+ return res unless keywords
+
+ keywords.each do |kw|
+ if kw == '-*'
+ res[:exclude_all] = true
+ next
+ end
+
+ if kw.start_with? '-'
+ res[:arches][kw[1..-1]] = :unavailable
+ next
+ end
+
+ if kw.start_with? '~'
+ res[:arches][kw[1..-1]] = :testing
+ next
+ end
+
+ res[:arches][kw] = :stable
+ end
+
+ res
+ end
+
+ private
+
+ def calc_useflags
+ result = { local: {}, global: {}, use_expand: {} }
+
+ local_flag_map = Useflag.local_for(atom.gsub("-#{version}", ''))
+ local_flags = local_flag_map.keys
+
+ use.sort.each do |flag|
+ if local_flags.include? flag
+ result[:local][flag] = local_flag_map[flag].to_hsh
+ else
+ useflag = Useflag.find_by(:name, flag)
+
+ # This should not happen, but let's be sure
+ next unless useflag
+
+ if useflag.scope == 'global'
+ result[:global][useflag.name] = useflag.to_hsh
+ elsif useflag.scope == 'use_expand'
+ prefix = useflag.use_expand_prefix.upcase
+ result[:use_expand][prefix] ||= {}
+ result[:use_expand][prefix][useflag.name.gsub(useflag.use_expand_prefix + '_', '')] = useflag.to_hsh
+ end
+ end
+ end
+
+ result
+ end
+end
diff --git a/app/views/about/changelog.html.md b/app/views/about/changelog.html.md
new file mode 100644
index 0000000..070d979
--- /dev/null
+++ b/app/views/about/changelog.html.md
@@ -0,0 +1,9 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li><a href="/about"><%= t :about %></a></li>
+ <li class="active"><%= t :changelog %></li>
+</ol>
+
+# <%= t :changelog %>
+
+<%= kk_changelog %>
diff --git a/app/views/about/feedback.html.erb b/app/views/about/feedback.html.erb
new file mode 100644
index 0000000..4a1f1f3
--- /dev/null
+++ b/app/views/about/feedback.html.erb
@@ -0,0 +1,64 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li><a href="/about"><%= t :about %></a></li>
+ <li class="active"><%= t :feedback %></li>
+</ol>
+
+<h1>Feedback</h1>
+
+<p class="lead">
+ Thanks for checking out the new packages.gentoo.org!
+</p>
+<p>
+ This site is currently in an <abbr title="minimum viable product">MVP</abbr> state and will be extended further to provide more useful features.
+ To help us prioritize new features and learn about your use case for the site, please share your ideas below.
+ <br><br>
+</p>
+
+<div class="row">
+ <div class="col-md-8">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Send Feedback</h3>
+ </div>
+ <div class="panel-body">
+ <form class="form-horizontal" method="post" action="/about/feedback">
+ <div class="form-group">
+ <label for="feedback" class="col-sm-2 control-label">Your Feedback:</label>
+ <div class="col-sm-10">
+ <textarea name="feedback" id="feedback" class="form-control" rows="10" placeholder="Please be sure to explain issues in detail and with exact URL references."></textarea>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="contact" class="col-sm-2 control-label">Contact (optional):</label>
+ <div class="col-sm-10">
+ <input type="text" name="contact" class="form-control" id="contact" placeholder="How can we reach you to follow up on your feedback?">
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button type="submit" class="btn btn-default">Send</button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-4">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Other ways to get in touch</h3>
+ </div>
+ <div class="list-group">
+ <a href="mailto:gpackages@gentoo.org" class="list-group-item">
+ <span class="fa fa-fw fa-envelope"></span>
+ E-Mail: gpackages@gentoo.org
+ </a>
+ <a href="irc://irc.gentoo.org/gentoo-www" class="list-group-item">
+ <span class="fa fa-fw fa-comments-o"></span>
+ IRC: #gentoo-www
+ </a>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/app/views/about/feeds.html.erb b/app/views/about/feeds.html.erb
new file mode 100644
index 0000000..5a9c1cd
--- /dev/null
+++ b/app/views/about/feeds.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li><a href="/about"><%= t :about %></a></li>
+ <li class="active"><%= t :update_feeds %></li>
+</ol>
+
+<h1><%= t :update_feeds %></h1>
+
+<p>
+ You can find Atom feeds here:
+</p>
+
+<ul>
+ <li>
+ For all packages: Right column on the <a href="/categories">category listing</a>.
+ </li>
+ <li>
+ For specific architectures: In the <a href="/arches">architectures section</a>.
+ </li>
+ <li>
+ For specific packages: In the <em>Resources</em> box on the respective package pages.
+ </li>
+</ul>
diff --git a/app/views/about/help.html.erb b/app/views/about/help.html.erb
new file mode 100644
index 0000000..77ddf5b
--- /dev/null
+++ b/app/views/about/help.html.erb
@@ -0,0 +1,11 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li><a href="/about"><%= t :about %></a></li>
+ <li class="active"><%= t :help %></li>
+</ol>
+
+<h1><%= t :help %></h1>
+
+<h2 id="keyword-legend"><%= t :keyword_table_legend %></h2>
+
+<%= render partial: 'packages/keyword_legend' %>
diff --git a/app/views/about/index.html.erb b/app/views/about/index.html.erb
new file mode 100644
index 0000000..5d9ed0f
--- /dev/null
+++ b/app/views/about/index.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li class="active"><%= t :about %></li>
+</ol>
+
+<h1>About packages.gentoo.org</h1>
+
+<p>Welcome to the new packages.gentoo.org!</p>
+
+<p>
+ This section will be extended with further information as the site continues to develop.
+ Feel free to <a href="/about/feedback">get in touch</a> if you have any questions that are not answered on this page.
+</p>
+
+<h2>FAQ</h2>
+
+<dl>
+ <dt>How often is the site updated?</dt>
+ <dd>
+ Updates are scheduled <strong>every 10 minutes</strong> and are processed using delayed jobs.
+ You can find the last time an import task was started in the footer.
+ </dd>
+</dl>
diff --git a/app/views/about/legacy.atom.builder b/app/views/about/legacy.atom.builder
new file mode 100644
index 0000000..91c0928
--- /dev/null
+++ b/app/views/about/legacy.atom.builder
@@ -0,0 +1,18 @@
+atom_feed(id: atom_id(@feed_type, 'feed')) do |feed|
+ feed.title @feed_title
+ feed.updated Time.now
+
+ feed.entry('', id: atom_id(@feed_type, 'deprecated'), url: about_feeds_url) do |entry|
+ entry.title 'This feed is deprecated'
+ entry.content <<END_CONTENT.strip
+This is a legacy feed from the previous version of packages.gentoo.org
+
+With our recent site relaunch, the feed setup has changed as well.
+To continue receiving updates about Gentoo packages, please visit the Feeds section of our new packages website at:
+
+ https://packages.gentoo.org/about/feeds
+
+Thank you for your interest in our packages site.
+END_CONTENT
+ end
+end
diff --git a/app/views/arches/index.html.erb b/app/views/arches/index.html.erb
new file mode 100644
index 0000000..8684eb1
--- /dev/null
+++ b/app/views/arches/index.html.erb
@@ -0,0 +1,36 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li class="active"><%= t :architectures %></li>
+</ol>
+
+<h1><%= t :architectures %></h1>
+
+<p><%= t :arches_intro %></p>
+
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :architectures %></h3>
+ </div>
+ <div class="table-responsive">
+ <table class="table table-striped">
+ <col>
+ <col style="width: 20em;">
+ <col style="width: 20em;">
+ <tbody>
+ <% ::KKULEOMI_ARCHES.sort.each do |arch| %>
+ <tr>
+ <th class="kk-nobreak-cell"><%= arch %></th>
+ <td>
+ <%= link_to t(:keyworded_packages), keyworded_arch_path(id: arch) %>
+ <%= feed_icon keyworded_arch_path(id: arch, format: :atom) %>
+ </td>
+ <td>
+ <%= link_to t(:stable_packages), stable_arch_path(id: arch) %>
+ <%= feed_icon stable_arch_path(id: arch, format: :atom) %>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/app/views/arches/keyworded.html.erb b/app/views/arches/keyworded.html.erb
new file mode 100644
index 0000000..b7ae03d
--- /dev/null
+++ b/app/views/arches/keyworded.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:architectures), arches_path %></li>
+ <li class="active"><%= t :keyworded_packages %></li>
+</ol>
+
+<h1>
+ <%= t :keyworded_packages %> (<%= @arch %>)
+ <%= feed_icon keyworded_arch_path(id: @arch, format: :atom) %>
+</h1>
+
+<% cache("keyworded-full-#{@arch}-#{@changes.hash}") do %>
+ <ul class="list-group">
+ <% @changes.each do |change|
+ _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %>
+ <%= render partial: 'packages/changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %>
+ <% end %>
+ </ul>
+<% end %>
+
+<% content_for :head do %>
+ <%= alternate_feed_link(keyworded_arch_url(id: @arch, format: :atom), t(:atom_feed)) %>
+<% end %>
diff --git a/app/views/arches/show.html.erb b/app/views/arches/show.html.erb
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/views/arches/show.html.erb
diff --git a/app/views/arches/stable.html.erb b/app/views/arches/stable.html.erb
new file mode 100644
index 0000000..b1a4548
--- /dev/null
+++ b/app/views/arches/stable.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:architectures), arches_path %></li>
+ <li class="active"><%= t :stable_packages %></li>
+</ol>
+
+<h1>
+ <%= t :stable_packages %> (<%= @arch %>)
+ <%= feed_icon stable_arch_path(id: @arch, format: :atom) %>
+</h1>
+
+<% cache("stable-full-#{@arch}-#{@changes.hash}") do %>
+ <ul class="list-group">
+ <% @changes.each do |change|
+ _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %>
+ <%= render partial: 'packages/changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %>
+ <% end %>
+ </ul>
+<% end %>
+
+<% content_for :head do %>
+ <%= alternate_feed_link(stable_arch_url(id: @arch, format: :atom), t(:atom_feed)) %>
+<% end %>
diff --git a/app/views/categories/_category_header.html.erb b/app/views/categories/_category_header.html.erb
new file mode 100644
index 0000000..b52cecf
--- /dev/null
+++ b/app/views/categories/_category_header.html.erb
@@ -0,0 +1,21 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:packages), categories_path %></li>
+ <li class="active"><%= category.name %></li>
+</ol>
+
+<div class="row">
+ <div class="col-md-4">
+ <h1 class="stick-top">
+ <span class="fa fa-fw fa-cubes"></span>
+ <%= category.name %>
+ </h1>
+ </div>
+ <div class="col-md-8">
+ <p class="lead" style="margin: 0;">
+ <%= category.description %>
+ </p>
+ </div>
+</div>
+
+<hr> \ No newline at end of file
diff --git a/app/views/categories/_package_line.html.erb b/app/views/categories/_package_line.html.erb
new file mode 100644
index 0000000..7ac4a43
--- /dev/null
+++ b/app/views/categories/_package_line.html.erb
@@ -0,0 +1,4 @@
+<tr>
+ <th class="kk-nobreak-cell"><%= link_to package.name, slf(package_path(package.atom)) %></th>
+ <td><%= package.description %></td>
+</tr>
diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb
new file mode 100644
index 0000000..9c19c9c
--- /dev/null
+++ b/app/views/categories/index.html.erb
@@ -0,0 +1,52 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li class="active"><%= t :packages %></li>
+</ol>
+
+<h1><%= t :packages %></h1>
+
+<div class="row">
+ <div class="col-md-9">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :browse_categories %></h3>
+ </div>
+ <div class="panel-body">
+ <ul class="kk-col-list kk-4col-list kk-category-listing">
+ <%- prev_letter = 'z' -%>
+ <% @categories.each do |category| %>
+ <%- unless category.name[0].upcase == prev_letter ; prev_letter = category.name[0].upcase -%>
+ <li class="kk-col-list-header"><span class="kk-group-header"><%= prev_letter %></span></li>
+ <%- end -%>
+ <li><%= link_to_category category %></li>
+ <% end %>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-3">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :update_feeds %></h3>
+ </div>
+ <div class="list-group">
+ <a href="<%= added_packages_path %>" class="list-group-item">
+ <span class="fa fa-fw fa-history"></span>
+ <%= t :added_packages %>
+ </a>
+ <a href="<%= updated_packages_path %>" class="list-group-item">
+ <span class="fa fa-fw fa-asterisk"></span>
+ <%= t :updated_packages %>
+ </a>
+ <a href="<%= stable_packages_path %>" class="list-group-item">
+ <span class="fa fa-fw fa-check-circle-o"></span>
+ <%= t :stable_packages %>
+ </a>
+ <a href="<%= keyworded_packages_path %>" class="list-group-item">
+ <span class="fa fa-fw fa-circle-o"></span>
+ <%= t :keyworded_packages %>
+ </a>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/app/views/categories/index.json.jbuilder b/app/views/categories/index.json.jbuilder
new file mode 100644
index 0000000..12cc02e
--- /dev/null
+++ b/app/views/categories/index.json.jbuilder
@@ -0,0 +1,5 @@
+json.array!(@categories) do |category|
+ json.extract! category, :name
+ json.extract! category, :description
+ json.url category_url(category, format: :json)
+end
diff --git a/app/views/categories/show.html.erb b/app/views/categories/show.html.erb
new file mode 100644
index 0000000..41cceef
--- /dev/null
+++ b/app/views/categories/show.html.erb
@@ -0,0 +1,28 @@
+<%= render partial: 'category_header', object: @category, as: 'category' %>
+
+<div class="row">
+ <div class="col-md-9">
+ <!--<p>
+ <input type="text" class="form-control form-control-xl" placeholder="Search packages in <%= @category.name %>">
+ </p>-->
+
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">All packages</h3>
+ </div>
+ <table class="table">
+ <%= render partial: 'package_line', collection: @packages, as: 'package' %>
+ </table>
+ </div>
+ </div>
+ <div class="col-md-3">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Statistics</h3>
+ </div>
+ <div class="panel-body">
+ <%= @packages.count %> <%= t :packages %>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/app/views/categories/show.json.jbuilder b/app/views/categories/show.json.jbuilder
new file mode 100644
index 0000000..fcf3811
--- /dev/null
+++ b/app/views/categories/show.json.jbuilder
@@ -0,0 +1,10 @@
+json.extract! @category, :name
+json.href slf category_url(id: @category.name)
+
+json.packages @packages do |package|
+ json.name package.name
+ json.description package.description
+ json.href slf(package_url(id: package.atom))
+end
+
+json.extract! @category, :updated_at \ No newline at end of file
diff --git a/app/views/feedback_mailer/feedback_email.text.erb b/app/views/feedback_mailer/feedback_email.text.erb
new file mode 100644
index 0000000..40b0b98
--- /dev/null
+++ b/app/views/feedback_mailer/feedback_email.text.erb
@@ -0,0 +1,5 @@
+Feedback:
+-------------------------------------------------------------------------------
+<%= @feedback %>
+-------------------------------------------------------------------------------
+Contact: <%= @contact %>
diff --git a/app/views/feeds/changes.atom.builder b/app/views/feeds/changes.atom.builder
new file mode 100644
index 0000000..5991f45
--- /dev/null
+++ b/app/views/feeds/changes.atom.builder
@@ -0,0 +1,60 @@
+@feed_id ||= nil
+
+atom_feed(id: atom_id(@feed_type, @feed_id, 'feed')) do |feed|
+ feed.title @feed_title
+ feed.updated !@changes.empty? ? @changes.first.created_at : Time.now
+
+ feed.author do |author|
+ author.name 'Gentoo Packages Database'
+ end
+
+ @changes.each do |change|
+ atom = cp_to_atom change.category, change.package
+ package = Package.find_by :atom, atom
+ if package.nil?
+ logger.warn "Package for change (#{change}) nil!"
+ next
+ end
+
+ id = atom
+ id += '-%s' % change.version if change[:version]
+ id += '-%s' % change.arches.join(',') if change[:arches]
+
+ feed.entry(
+ change,
+ id: atom_id(@feed_type, @feed_id, id),
+ url: absolute_link_to_package(atom)) do |entry|
+ entry.updated change.created_at.to_datetime.rfc3339
+
+ case @feed_type
+ when :added
+ entry.title(t :feed_added_title,
+ atom: atom,
+ description: package.description)
+ entry.content(t :feed_added_content,
+ atom: atom,
+ arches: package.latest_version.keywords.join(', '))
+ when :updated
+ entry.title(t :feed_updated_title,
+ atom: atom_add_version(atom, change.version),
+ description: package.description)
+ entry.content(t :feed_updated_content,
+ atom: change.version)
+ when :stable
+ entry.title(t :feed_stable_title,
+ atom: atom_add_version(atom, change.version),
+ description: package.description)
+ entry.content(t :feed_stable_content,
+ atom: atom,
+ arches: change.arches.join(', '))
+ when :keyworded
+ entry.title(t :feed_keyworded_title,
+ atom: atom_add_version(atom, change.version),
+ description: package.description)
+ entry.content(t :feed_keyworded_content,
+ atom: atom,
+ arches: change.arches.join(', '))
+ end
+ end
+ end
+end
diff --git a/app/views/index/_package.html.erb b/app/views/index/_package.html.erb
new file mode 100644
index 0000000..431142a
--- /dev/null
+++ b/app/views/index/_package.html.erb
@@ -0,0 +1,8 @@
+<tr>
+ <td>
+ <a href="<%= slf(package_path(cp_to_atom(change.category, change.package))) %>">
+ <span class="text-muted"><%= change.category %></span>/<strong><%= change.package %><%= "-#{change.version}" if change[:version] %></strong>
+ </a>
+ </td>
+ <td><%= Package.find_by(:atom, cp_to_atom(change.category, change.package)).description %></td>
+</tr> \ No newline at end of file
diff --git a/app/views/index/index.html.erb b/app/views/index/index.html.erb
new file mode 100644
index 0000000..890a5f3
--- /dev/null
+++ b/app/views/index/index.html.erb
@@ -0,0 +1,53 @@
+<div class="jumbotron">
+ <h2 class="site-welcome stick-top">Welcome to the Home of <span class="text-primary"><%= number_with_delimiter Package.count %></span> Gentoo Packages</h2>
+
+ <form action="<%= search_packages_path %>" method="get">
+ <div class="typeahead-container">
+ <div class="typeahead-field">
+ <span class="typeahead-query">
+ <input id="q" name="q" type="search" autocomplete="off" placeholder="<%= t :find_packages %>" aria-label="<%= t :find_packages %>" autofocus>
+ </span>
+ <span class="typeahead-button">
+ <button type="submit" title="<%= t :find %>" aria-label="<%= t :find %>">
+ <span class="typeahead-search-icon"></span><span class="sr-only"><%= t :find %></span>
+ </button>
+ </span>
+ </div>
+ </div>
+ </form>
+</div>
+
+<% cache("added-#{@new_packages.hash}") do %>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">
+ <span class="fa fa-fw fa-history"></span>
+ <%= link_to t(:added_packages), added_packages_path %>
+ </h3>
+ </div>
+ <div class="table-responsive">
+ <table class="table table-striped">
+ <%= render partial: 'package', collection: @new_packages, as: 'change' %>
+ </table>
+ </div>
+</div>
+<% end %>
+
+<% cache("updated-#{@version_bumps.hash}") do %>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">
+ <span class="fa fa-fw fa-asterisk"></span>
+ <%= link_to t(:updated_packages), updated_packages_path %>
+ </h3>
+ </div>
+ <ul class="list-group">
+ <% @version_bumps.each do |change|
+ _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %>
+ <%= render partial: 'packages/changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %>
+ <% end %>
+ </ul>
+</div>
+<% end %>
+
+<%= javascript_include_tag 'index/typeahead.js' %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
new file mode 100644
index 0000000..72fb8fa
--- /dev/null
+++ b/app/views/layouts/application.html.erb
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title><%= "#{@title} – " if @title %>Gentoo Packages</title>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="theme-color" content="#54487a">
+ <meta name="description" content="<%= "#{@description} in the " if @description %>Gentoo Packages Database">
+ <link href="https://assets.gentoo.org/tyrian/bootstrap.min.css" rel="stylesheet" media="screen">
+ <link href="https://assets.gentoo.org/tyrian/tyrian.min.css" rel="stylesheet" media="screen">
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
+ <script src="https://assets.gentoo.org/tyrian/bootstrap.min.js"></script>
+ <link rel="icon" href="https://www.gentoo.org/favicon.ico" type="image/x-icon">
+ <% if content_for? :head -%>
+ <%= yield :head %>
+ <% end -%>
+</head>
+<body class="kk">
+<header>
+ <div class="site-title">
+ <div class="container">
+ <div class="row">
+ <div class="site-title-buttons">
+ <div class="btn-group btn-group-sm">
+ <a href="https://get.gentoo.org/" role="button" class="btn get-gentoo"><span class="fa fa-fw fa-download"></span> <strong>Get Gentoo!</strong></a>
+ <div class="btn-group btn-group-sm">
+ <a class="btn gentoo-org-sites dropdown-toggle" data-toggle="dropdown" data-target="#" href="#">
+ <span class="fa fa-fw fa-map-o"></span> <span class="hidden-xs">gentoo.org sites</span> <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu dropdown-menu-right">
+ <li><a href="https://www.gentoo.org/" title="Main Gentoo website"><span class="fa fa-home fa-fw"></span> gentoo.org</a></li>
+ <li><a href="https://wiki.gentoo.org/" title="Find and contribute documentation"><span class="fa fa-file-text-o fa-fw"></span> Wiki</a></li>
+ <li><a href="https://bugs.gentoo.org/" title="Report issues and find common issues"><span class="fa fa-bug fa-fw"></span> Bugs</a></li>
+ <li><a href="https://forums.gentoo.org/" title="Discuss with the community"><span class="fa fa-comments-o fa-fw"></span> Forums</a></li>
+ <li><a href="https://packages.gentoo.org/" title="Find software for your Gentoo"><span class="fa fa-hdd-o fa-fw"></span> Packages</a></li>
+ <li class="divider"></li>
+ <li><a href="https://planet.gentoo.org/" title="Find out what's going on in the developer community"><span class="fa fa-rss fa-fw"></span> Planet</a></li>
+ <li><a href="https://archives.gentoo.org/" title="Read up on past discussions"><span class="fa fa-archive fa-fw"></span> Archives</a></li>
+ <li><a href="https://sources.gentoo.org/" title="Browse our source code"><span class="fa fa-code fa-fw"></span> Sources</a></li>
+ <li class="divider"></li>
+ <li><a href="https://infra-status.gentoo.org/" title="Get updates on the services provided by Gentoo"><span class="fa fa-server fa-fw"></span> Infra Status</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <div class="logo">
+ <a href="/" title="Back to the homepage" class="site-logo">
+ <object data="https://assets.gentoo.org/tyrian/site-logo.svg" type="image/svg+xml">
+ <img src="https://assets.gentoo.org/tyrian/site-logo.png" alt="Gentoo Linux Logo">
+ </object>
+ </a>
+ <span class="site-label">Packages</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <nav class="tyrian-navbar" role="navigation">
+ <div class="container">
+ <div class="row">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main-collapse">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ </div>
+ <div class="collapse navbar-collapse navbar-main-collapse">
+ <ul class="nav navbar-nav">
+ <li class="<%= 'active' if @nav == :index %>"><%= link_to t(:home), '/' %></li>
+ <li class="<%= 'active' if @nav == :packages %>"><%= link_to t(:packages), categories_path %></li>
+ <li class="<%= 'active' if @nav == :use %>"><%= link_to t(:use_flags), useflags_path %></li>
+ <li class="<%= 'active' if @nav == :arches %>"><%= link_to t(:architectures), arches_path %></li>
+ <li class="<%= 'active' if @nav == :about %>"><%= link_to t(:about), about_path %></li>
+ </ul>
+ <% unless @nav == :index %>
+ <form class="navbar-form navbar-right" role="search" action="<%= search_packages_path %>" method="get">
+ <div class="form-group">
+ <input type="text" class="form-control" placeholder="Find Packages" name="q">
+ </div>
+ </form>
+ <% end %>
+ </div>
+ </div>
+ </div>
+ </nav>
+</header>
+
+<div class="container">
+ <div class="row">
+ <div class="col-xs-12">
+ <%= yield %>
+ </div>
+ </div>
+</div>
+
+<footer>
+ <div class="container">
+ <div class="row">
+ <div class="col-xs-12 col-md-offset-2 col-md-7">
+ <h3 class="footerhead"><%= t :app_name %></h3>
+ <div class="row">
+ <div class="col-xs-12 col-md-4">
+ <span class="kk-group-header"><%= t :data_current_as_of %></span><br><%= last_import_start ? i18n_date(last_import_start) : 'unknown' %>
+ </div>
+ <div class="col-xs-12 col-md-4">
+ </div>
+ <div class="col-xs-12 col-md-4">
+ </div>
+ </div>
+ </div>
+ <div class="col-xs-12 col-md-3">
+ <h3 class="footerhead">Questions or comments?</h3>
+ Please feel free to <a href="https://www.gentoo.org/inside-gentoo/contact/">contact us</a>.
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-xs-2 col-sm-3 col-md-2">
+ <ul class="footerlinks three-icons">
+ <li><a href="https://twitter.com/gentoo" title="@Gentoo on Twitter"><span class="fa fa-twitter fa-fw"></span></a></li>
+ <li><a href="https://plus.google.com/+Gentoo" title="+Gentoo on Google+"><span class="fa fa-google-plus fa-fw"></span></a></li>
+ <li><a href="https://www.facebook.com/gentoo.org" title="Gentoo on Facebook"><span class="fa fa-facebook fa-fw"></span></a></li>
+ </ul>
+ </div>
+ <div class="col-xs-10 col-sm-9 col-md-10">
+ <strong>&copy; 2001&ndash;2016 Gentoo Foundation, Inc.</strong><br>
+ <small>
+ Gentoo is a trademark of the Gentoo Foundation, Inc.
+ The contents of this document, unless otherwise expressly stated, are licensed under the
+ <a href="https://creativecommons.org/licenses/by-sa/3.0/" rel="license">CC-BY-SA-3.0</a> license.
+ The <a href="https://www.gentoo.org/inside-gentoo/foundation/name-logo-guidelines.html">Gentoo Name and Logo Usage Guidelines</a> apply.
+ </small>
+ </div>
+ </div>
+ </div>
+</footer>
+<script type="text/javascript">
+ var _paq = _paq || [];
+ _paq.push(['disableCookies']);
+ _paq.push(['trackPageView']);
+ _paq.push(['enableLinkTracking']);
+ (function() {
+ var u="//piwik.gentoo.org/";
+ _paq.push(['setTrackerUrl', u+'piwik.php']);
+ _paq.push(['setSiteId', 8]);
+ var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
+ g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
+ })();
+</script>
+<noscript><p><img src="//piwik.gentoo.org/piwik.php?idsite=8" style="border:0;" alt="" /></p></noscript>
+</body>
+</html>
diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb
new file mode 100644
index 0000000..991cf0f
--- /dev/null
+++ b/app/views/layouts/mailer.html.erb
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <%= yield %>
+ </body>
+</html>
diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb
new file mode 100644
index 0000000..37f0bdd
--- /dev/null
+++ b/app/views/layouts/mailer.text.erb
@@ -0,0 +1 @@
+<%= yield %>
diff --git a/app/views/packages/_changed_package.html.erb b/app/views/packages/_changed_package.html.erb
new file mode 100644
index 0000000..2e917e7
--- /dev/null
+++ b/app/views/packages/_changed_package.html.erb
@@ -0,0 +1,71 @@
+<% unless version.nil? %>
+<li class="list-group-item kk-package-detailed">
+ <div class="row">
+ <div class="col-xs-12 col-md-6">
+ <h4 class="stick-top"><%= link_to package.atom, slf(package_path(package.atom)) %></h4>
+ <div class="kk-package-detailed-toolbox">
+ <div class="btn-group">
+ <button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ <span class="fa fa-fw fa-navicon"></span>
+ </button>
+ <ul class="dropdown-menu dropdown-menu-right">
+ <li><a href="https://bugs.gentoo.org/buglist.cgi?quicksearch=<%= u package.atom %>" target="_blank">
+ <span class="fa fa-fw fa-bug"></span>
+ <%= t :res_bugs %>
+ </a></li>
+ <li><a href="https://wiki.gentoo.org/index.php?title=Special%3ASearch&fulltext=Search&search=<%= u package.name %>" target="_blank">
+ <span class="fa fa-fw fa-book"></span>
+ <%= t :res_docs %>
+ </a></li>
+ <li><a href="https://forums.gentoo.org/search.php?search_terms=all&show_results=topics&search_keywords=<%= u package.name %>&mode=results" target="_blank">
+ <span class="fa fa-fw fa-comments-o"></span>
+ <%= t :res_forums %>
+ </a></li>
+ <li role="separator" class="divider"></li>
+ <li><a href="https://gitweb.gentoo.org/repo/gentoo.git/tree/<%= package.atom %>" target="_blank">
+ <span class="fa fa-fw fa-code-fork"></span>
+ <%= t :res_repo %>
+ </a></li>
+ <li><a href="https://gitweb.gentoo.org/repo/gentoo.git/log/<%= package.atom %>?showmsg=1" target="_blank">
+ <span class="fa fa-fw fa-history"></span>
+ <%= t :res_log %>
+ </a></li>
+ <li><a href="https://gitweb.gentoo.org/repo/gentoo.git/atom/<%= package.atom %>?h=master" target="_blank">
+ <span class="fa fa-fw fa-rss"></span>
+ <%= t :res_feed %>
+ </a></li>
+ <li role="separator" class="divider"></li>
+ <li><a href="http://www.portagefilelist.de/site/query/listPackageVersions/?category=<%= package.category %>&package=<%= package.name %>&do#result" target="_blank">
+ <span class="fa fa-fw fa-files-o"></span>
+ <%= t :res_installed_files %> <small>(via PFL<span class="fa fa-fw fa-external-link-square"></span>)</small>
+ </a></li>
+ </ul>
+ </div>
+ </div>
+ <%= package.description %>
+ <br>
+ <small class="text-muted">
+ <% unless change.arches == nil or change.arches.empty? %>
+ <%= t :added_keywords, keywords: change.arches.join(', ') %>
+ <% end %>
+ </small>
+ <% unless (changelog_entry = matching_changelog_entry(change)).nil? %>
+ <div class="kk-inline-changelog-entry">
+ <a href="<%= gitweb_commit_url(changelog_entry[:id]) %>" title="<%= t :git_commit %>">
+ <span class="octicon octicon-git-pull-request"></span>
+ <span class="kk-commit-message">
+ <%= changelog_entry[:message].lines.first %>
+ </span>
+ </a>
+ </div>
+ <% end %>
+ </div>
+ <div class="col-xs-12 col-md-6">
+ <small class="text-muted pull-right">
+ <%= i18n_date(change.created_at) %>
+ </small>
+ <%= render partial: 'packages/version_card', object: version, as: 'version' %>
+ </div>
+ </div>
+</li>
+<% end %>
diff --git a/app/views/packages/_changelog.html.erb b/app/views/packages/_changelog.html.erb
new file mode 100644
index 0000000..c469a50
--- /dev/null
+++ b/app/views/packages/_changelog.html.erb
@@ -0,0 +1,19 @@
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Changelog</h3>
+ </div>
+ <ul class="list-group" id="changelog-container">
+ <li class="list-group-item kk-panel-content-sorry">
+ <span class="fa fa-refresh fa-spin fa-3x"></span>
+ <noscript>
+ <br><br>
+ <%= t :changelog_error %>
+ <br><br>
+ <a href="https://gitweb.gentoo.org/repo/gentoo.git/log/<%= @package.atom %>?showmsg=1" class="btn btn-default">
+ <span class="fa fa-fw fa-history"></span>
+ <%= t :view_git_changelog %>
+ </a>
+ </noscript>
+ </li>
+ </ul>
+</div>
diff --git a/app/views/packages/_changelog_entry.html.erb b/app/views/packages/_changelog_entry.html.erb
new file mode 100644
index 0000000..6b7b1da
--- /dev/null
+++ b/app/views/packages/_changelog_entry.html.erb
@@ -0,0 +1,31 @@
+<li class="list-group-item">
+ <strong><%= annotate_bugs changelog[:message].lines.first %></strong>
+ <br>
+ <div class="kk-byline">
+ <%= mail_to changelog[:email], changelog[:author] %>,
+ <%= i18n_date(changelog[:date]) %>,
+ commit&nbsp;<%= link_to_gitweb_commit changelog[:id]%>
+ </div>
+
+ <table class="table table-condensed kk-changelog-diffstat">
+ <% unless changelog[:files][:added].empty? %>
+ <tr class="success">
+ <td class="kk-changelog-diffstat-icon"><span class="octicon octicon-diff-added"></span></td>
+ <td><%= safe_join(changelog[:files][:added].map {|f| link_to_gitweb_ebuild_diff(f, changelog[:id], @package.category, @package.name) }, ', ') %></td>
+ </tr>
+ <% end %>
+ <% unless changelog[:files][:modified].empty? %>
+ <tr class="warning">
+ <td class="kk-changelog-diffstat-icon"><span class="octicon octicon-diff-modified"></span></td>
+ <td><%= safe_join(changelog[:files][:modified].map {|f| link_to_gitweb_ebuild_diff(f, changelog[:id], @package.category, @package.name) }, ', ') %></td>
+ </tr>
+ <% end %>
+ <% unless changelog[:files][:deleted].empty? %>
+ <tr class="danger">
+ <td class="kk-changelog-diffstat-icon"><span class="octicon octicon-diff-removed"></span></td>
+ <td><%= safe_join(changelog[:files][:deleted].map {|f| link_to_gitweb_ebuild_diff(f, changelog[:id], @package.category, @package.name) }, ', ') %></td>
+ </tr>
+ <% end %>
+
+ </table>
+</li>
diff --git a/app/views/packages/_herd.html.erb b/app/views/packages/_herd.html.erb
new file mode 100644
index 0000000..3e0db76
--- /dev/null
+++ b/app/views/packages/_herd.html.erb
@@ -0,0 +1 @@
+<%= link_to_herd herd %>
diff --git a/app/views/packages/_keyword_legend.html.erb b/app/views/packages/_keyword_legend.html.erb
new file mode 100644
index 0000000..8c45e36
--- /dev/null
+++ b/app/views/packages/_keyword_legend.html.erb
@@ -0,0 +1,17 @@
+<ul class="list-group kk-keyword-legend">
+ <li class="list-group-item kk-keyword-stable">
+ <%= keyword_icon_tag :stable %> &nbsp;<%= t :legend_stable %>
+ </li>
+ <li class="list-group-item kk-keyword-testing">
+ <%= keyword_icon_tag :testing %> &nbsp;<%= t :legend_testing %>
+ </li>
+ <li class="list-group-item kk-keyword-unavailable">
+ <%= keyword_icon_tag :unavailable %> &nbsp;<%= t :legend_unavailable %>
+ </li>
+ <li class="list-group-item kk-keyword-masked">
+ <%= keyword_icon_tag :masked %> &nbsp;<%= t :legend_masked %>
+ </li>
+ <li class="list-group-item kk-keyword-unknown">
+ <span class="kk-octicon-spacer"></span>&nbsp;<%= t :legend_unknown %>
+ </li>
+</ul>
diff --git a/app/views/packages/_maintainer.html.erb b/app/views/packages/_maintainer.html.erb
new file mode 100644
index 0000000..9f89c7c
--- /dev/null
+++ b/app/views/packages/_maintainer.html.erb
@@ -0,0 +1 @@
+<%= mail_to maintainer['email'], maintainer['name'], title: maintainer['email'] %> \ No newline at end of file
diff --git a/app/views/packages/_maintainer_needed_notice.html.erb b/app/views/packages/_maintainer_needed_notice.html.erb
new file mode 100644
index 0000000..8359547
--- /dev/null
+++ b/app/views/packages/_maintainer_needed_notice.html.erb
@@ -0,0 +1,7 @@
+<% if package.needs_maintainer? %>
+ <div class="alert alert-info">
+ <strong><span class="fa fa-fw fa-wrench"></span> This package needs a new maintainer!</strong><br>
+ If you are interested in helping with the maintenance of <%= package.name %>, please get in touch with our
+ <a href="https://wiki.gentoo.org/wiki/Project:Proxy_Maintainers" class="alert-link">Proxy Maintainers team</a>.
+ </div>
+<% end %> \ No newline at end of file
diff --git a/app/views/packages/_maintainer_spacer.html.erb b/app/views/packages/_maintainer_spacer.html.erb
new file mode 100644
index 0000000..4bb959b
--- /dev/null
+++ b/app/views/packages/_maintainer_spacer.html.erb
@@ -0,0 +1 @@
+<%= ', ' %> \ No newline at end of file
diff --git a/app/views/packages/_mask.html.erb b/app/views/packages/_mask.html.erb
new file mode 100644
index 0000000..b76a103
--- /dev/null
+++ b/app/views/packages/_mask.html.erb
@@ -0,0 +1,30 @@
+<li class="list-group-item kk-mask">
+ <strong class="kk-mask-reason text-danger"><%= annotate_bugs(mask['reason']) %></strong>
+
+ <div class="kk-mask-details">
+ <!--<div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ Affected architectures
+ </div>
+ <div class="col-xs-12 col-md-9 kk-mask-atoms">
+ <%# mask['arch'] %>
+ </div>
+ </div>-->
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <%= t :mask_packages %>
+ </div>
+ <div class="col-xs-12 col-md-9 kk-mask-atoms">
+ <%= mask['atoms'].join ', ' %>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <%= t :mask_author %>
+ </div>
+ <div class="col-xs-12 col-md-9">
+ <%= mask['author'] %> <span class="text-muted">(<%= mask['date'] %>)</span>
+ </div>
+ </div>
+ </div>
+</li>
diff --git a/app/views/packages/_masks.html.erb b/app/views/packages/_masks.html.erb
new file mode 100644
index 0000000..89bf166
--- /dev/null
+++ b/app/views/packages/_masks.html.erb
@@ -0,0 +1,10 @@
+<% unless (_masks = filter_masks(versions)).empty? %>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :box_masks %></h3>
+ </div>
+ <ul class="list-group">
+ <%= render partial: 'mask', collection: _masks.to_a, as: 'mask' %>
+ </ul>
+</div>
+<% end %>
diff --git a/app/views/packages/_metadata.html.erb b/app/views/packages/_metadata.html.erb
new file mode 100644
index 0000000..426afd9
--- /dev/null
+++ b/app/views/packages/_metadata.html.erb
@@ -0,0 +1,87 @@
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :box_metadata %></h3>
+ </div>
+ <ul class="list-group kk-metadata-list">
+ <% if package.homepage.size > 1 %>
+ <li class="kk-metadata-item list-group-item">
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <span class="fa fa-fw fa-home"></span>
+ <%= t :other_homepages %>
+ </div>
+ <div class="col-xs-12 col-md-9">
+ <% package.homepage[1..-1].each do |hp| %>
+ <%= link_to hp, hp, rel: 'nofollow' %>
+ <% end %>
+ </div>
+ </div>
+ </li>
+ <% end %>
+ <% if package.longdescription %>
+ <li class="kk-metadata-item list-group-item">
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <span class="fa fa-fw fa-info"></span>
+ <%= t :longdescription %>
+ </div>
+ <div class="col-xs-12 col-md-9">
+ <%= package.longdescription %>
+ </div>
+ </div>
+ </li>
+ <% end %>
+ <% if package.has_useflags? %>
+ <li class="kk-metadata-item list-group-item">
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <span class="fa fa-fw fa-sliders"></span>
+ <%= t :use_flags %>
+ </div>
+ <div class="col-xs-12 col-md-9">
+ <%= render partial: 'metadata_use', object: package.useflags, as: 'useflags' %>
+ </div>
+ </div>
+ </li>
+ <% end %>
+ <% if package.license %>
+ <li class="kk-metadata-item list-group-item">
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <span class="fa fa-fw fa-legal"></span>
+ <%= t :license %>
+ </div>
+ <div class="col-xs-12 col-md-9">
+ <%= annotate_license_str package.license %>
+ </div>
+ </div>
+ </li>
+ <% end %>
+ <% if package.herds and package.herds.size > 0 %>
+ <li class="kk-metadata-item list-group-item">
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <span class="fa fa-fw fa-group"></span>
+ <%= t :herds %>
+ </div>
+ <div class="col-xs-12 col-md-9">
+ <%= render partial: 'herd', collection: package.herds.sort, as: 'herd', spacer_template: 'maintainer_spacer' %>
+ </div>
+ </div>
+ </li>
+ <% end %>
+ <% if package.maintainers and package.maintainers.size > 0 %>
+ <li class="kk-metadata-item list-group-item">
+ <div class="row">
+ <div class="col-xs-12 col-md-3 kk-metadata-key">
+ <span class="fa fa-fw fa-user"></span>
+ <%= t :maintainers %>
+ </div>
+ <div class="col-xs-12 col-md-9">
+ <%= render partial: 'maintainer', collection: package.maintainers, as: 'maintainer', spacer_template: 'maintainer_spacer' %>
+ </div>
+ </div>
+ </li>
+ <% end %>
+ </ul>
+</div>
diff --git a/app/views/packages/_metadata_use.html.erb b/app/views/packages/_metadata_use.html.erb
new file mode 100644
index 0000000..d33b751
--- /dev/null
+++ b/app/views/packages/_metadata_use.html.erb
@@ -0,0 +1,14 @@
+<% unless useflags['local'].empty? %>
+ <span class="kk-useflag-group"><%= t :local_use_flags %></span>
+ <%= render partial: 'useflag', object: useflags['local'], as: 'useflags' %>
+<% end %>
+<% unless useflags['global'].empty? %>
+ <span class="kk-useflag-group"><%= t :global_use_flags %></span>
+ <%= render partial: 'useflag', object: useflags['global'], as: 'useflags' %>
+<% end %>
+<% unless useflags['use_expand'].empty? %>
+ <% useflags['use_expand'].each_pair do |flag, values| %>
+ <span class="kk-useflag-group"><%= t :use_expand_flag, flag: flag %></span>
+ <%= render partial: 'useflag', object: values, as: 'useflags' %>
+ <% end %>
+<% end %>
diff --git a/app/views/packages/_package_header.html.erb b/app/views/packages/_package_header.html.erb
new file mode 100644
index 0000000..5b8ae08
--- /dev/null
+++ b/app/views/packages/_package_header.html.erb
@@ -0,0 +1,31 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:packages), categories_path %></li>
+ <li><%= link_to package.category_model.name, category_path(package.category_model) %></li>
+ <li class="active"><%= package.name %></li>
+</ol>
+
+<div class="row">
+ <div class="col-md-4">
+ <h1 class="stick-top kk-package-title" id="package-title" data-atom="<%= package.atom %>" data-category="<%= package.category %>" data-name="<%= package.name %>">
+ <small class="kk-package-cat"><%= package.category_model.name %>/</small>
+ <div>
+ <span class="mega-octicon octicon-package kk-package-icon"></span>
+ <div class="kk-package-name"><%= package.name %></div>
+ </div>
+ </h1>
+ </div>
+ <div class="col-md-8">
+ <p class="lead kk-package-maindesc">
+ <%= package.description %>
+ </p>
+
+ <p class="kk-package-homepage">
+ <% if '' != package.homepage.first %>
+ <span class="fa fa-fw fa-home"></span> <%= link_to package.homepage.first, package.homepage.first, rel: 'nofollow' %>
+ <% end %>
+ </p>
+ </div>
+</div>
+
+<hr>
diff --git a/app/views/packages/_package_result_row.html.erb b/app/views/packages/_package_result_row.html.erb
new file mode 100644
index 0000000..fd6c903
--- /dev/null
+++ b/app/views/packages/_package_result_row.html.erb
@@ -0,0 +1,4 @@
+<a class="list-group-item" href="<%= slf package_path package %>">
+ <h3 class="kk-search-result-header"><span class="text-muted"><%= package.category %>/</span><%= package.name %></h3>
+ <%= package.description %>
+</a> \ No newline at end of file
diff --git a/app/views/packages/_removal_notice.html.erb b/app/views/packages/_removal_notice.html.erb
new file mode 100644
index 0000000..20d226b
--- /dev/null
+++ b/app/views/packages/_removal_notice.html.erb
@@ -0,0 +1,5 @@
+<div class="alert alert-danger">
+ <strong><span class="fa fa-fw fa-warning"></span> This package is masked and could be removed soon!</strong><br>
+ The mask comment indicates that this package is scheduled for removal from our package repository.<br>
+ Please review the mask information below for more details.
+</div> \ No newline at end of file
diff --git a/app/views/packages/_resources.html.erb b/app/views/packages/_resources.html.erb
new file mode 100644
index 0000000..51576a9
--- /dev/null
+++ b/app/views/packages/_resources.html.erb
@@ -0,0 +1,35 @@
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t(:resources) %></h3>
+ </div>
+ <div class="list-group">
+ <a href="https://bugs.gentoo.org/buglist.cgi?quicksearch=<%= u package.atom %>" class="list-group-item" target="_blank">
+ <span class="fa fa-fw fa-bug"></span>
+ <%= t :res_bugs %>
+ </a>
+ <a href="https://wiki.gentoo.org/index.php?title=Special%3ASearch&fulltext=Search&search=<%= u package.name %>" class="list-group-item" target="_blank">
+ <span class="fa fa-fw fa-book"></span>
+ <%= t :res_docs %>
+ </a>
+ <a href="https://forums.gentoo.org/search.php?search_terms=all&show_results=topics&search_keywords=<%= u package.name %>&mode=results" class="list-group-item" target="_blank">
+ <span class="fa fa-fw fa-comments-o"></span>
+ <%= t :res_forums %>
+ </a>
+ <a href="https://gitweb.gentoo.org/repo/gentoo.git/tree/<%= package.atom %>" class="list-group-item" target="_blank">
+ <span class="fa fa-fw fa-code-fork"></span>
+ <%= t :res_repo %>
+ </a>
+ <a href="https://gitweb.gentoo.org/repo/gentoo.git/log/<%= package.atom %>?showmsg=1" class="list-group-item" target="_blank">
+ <span class="fa fa-fw fa-history"></span>
+ <%= t :res_log %>
+ </a>
+ <a href="https://gitweb.gentoo.org/repo/gentoo.git/atom/<%= package.atom %>?h=master" class="list-group-item" target="_blank">
+ <span class="fa fa-fw fa-rss"></span>
+ <%= t :res_feed %>
+ </a>
+ <a href="http://www.portagefilelist.de/site/query/listPackageVersions/?category=<%= package.category %>&package=<%= package.name %>&do#result" class="list-group-item" target="_blank">
+ <span class="fa fa-fw fa-files-o"></span>
+ <%= t :res_installed_files %> <small>(via PFL<span class="fa fa-fw fa-external-link-square"></span>)</small>
+ </a>
+ </div>
+</div>
diff --git a/app/views/packages/_useflag.html.erb b/app/views/packages/_useflag.html.erb
new file mode 100644
index 0000000..a60e589
--- /dev/null
+++ b/app/views/packages/_useflag.html.erb
@@ -0,0 +1,5 @@
+<ul class="kk-useflag-container <%= useflags.size > 10 ? 'kk-useflag-container-many' : 'kk-useflag-container-few' %>">
+<% useflags.each_pair do |flag, flag_data| %>
+ <li class="kk-useflag"><%= link_to flag, useflag_path(id: flag_data['name']), :title => strip_tags(flag_data['description']), 'data-toggle' => 'tooltip' %></li>
+<% end %>
+</ul>
diff --git a/app/views/packages/_version_card.html.erb b/app/views/packages/_version_card.html.erb
new file mode 100644
index 0000000..7045617
--- /dev/null
+++ b/app/views/packages/_version_card.html.erb
@@ -0,0 +1,14 @@
+<div class="kk-version-card">
+ <p><strong><%= version.version %></strong><%= version_slot version.slot %> <%= version_labels version %></p>
+ <p>
+ <%= keyword_label version, 'amd64' %>
+ <%= keyword_label version, 'x86' %>
+ <%= keyword_label version, 'alpha' %>
+ <%= keyword_label version, 'arm' %>
+ <%= keyword_label version, 'hppa' %>
+ <%= keyword_label version, 'ia64' %>
+ <%= keyword_label version, 'ppc' %>
+ <%= keyword_label version, 'ppc64' %>
+ <%= keyword_label version, 'sparc' %>
+ </p>
+</div>
diff --git a/app/views/packages/_version_row.html.erb b/app/views/packages/_version_row.html.erb
new file mode 100644
index 0000000..d30d974
--- /dev/null
+++ b/app/views/packages/_version_row.html.erb
@@ -0,0 +1,12 @@
+<tr>
+ <td class="kk-version kk-cell-sep-right"><strong><%= version.version %></strong><%= version_slot version.slot, version.subslot %> <%= version_labels version %></td>
+ <%= keyword_cell version, 'amd64' %>
+ <%= keyword_cell version, 'x86', true %>
+ <%= keyword_cell version, 'alpha' %>
+ <%= keyword_cell version, 'arm' %>
+ <%= keyword_cell version, 'hppa' %>
+ <%= keyword_cell version, 'ia64' %>
+ <%= keyword_cell version, 'ppc' %>
+ <%= keyword_cell version, 'ppc64' %>
+ <%= keyword_cell version, 'sparc' %>
+</tr>
diff --git a/app/views/packages/_versions.html.erb b/app/views/packages/_versions.html.erb
new file mode 100644
index 0000000..3484dc4
--- /dev/null
+++ b/app/views/packages/_versions.html.erb
@@ -0,0 +1,38 @@
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">
+ <%= t :box_versions %>
+ <span class="pull-right">
+ <a href="<%= about_help_path(anchor: 'keyword-legend') %>" aria-label="<%= t :show_table_legend %>" title="<%= t :legend %>" class="kk-box-meta-link" tabindex="0" role="button" id="kk-keyword-legend-btn">
+ <span class="fa fa-fw fa-question-circle"></span>
+ </a>
+ </span>
+ </h3>
+ </div>
+ <div class="table-responsive">
+ <table class="table table-bordered kk-versions-table">
+ <thead>
+ <tr>
+ <th class="kk-version kk-cell-sep-right"><%= t :version %></th>
+ <th class="kk-keyword-header kk-keyword">amd64</th>
+ <th class="kk-keyword-header kk-keyword kk-cell-sep-right">x86</th>
+ <th class="kk-keyword-header kk-keyword">alpha</th>
+ <th class="kk-keyword-header kk-keyword">arm</th>
+ <th class="kk-keyword-header kk-keyword">hppa</th>
+ <th class="kk-keyword-header kk-keyword">ia64</th>
+ <th class="kk-keyword-header kk-keyword">ppc</th>
+ <th class="kk-keyword-header kk-keyword">ppc64</th>
+ <th class="kk-keyword-header kk-keyword">sparc</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <%= render partial: 'version_row', collection: versions, as: 'version' %>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<script id="kk-keyword-legend-text" type="text/template">
+<%= render partial: 'keyword_legend' %>
+</script>
diff --git a/app/views/packages/added.html.erb b/app/views/packages/added.html.erb
new file mode 100644
index 0000000..97d5cb6
--- /dev/null
+++ b/app/views/packages/added.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:packages), categories_path %></li>
+ <li class="active"><%= t :added_packages %></li>
+</ol>
+
+<h1>
+ <%= t :added_packages %>
+ <%= feed_icon added_packages_path(format: :atom) %>
+</h1>
+
+<% cache("added-full-#{@changes.hash}") do %>
+ <ul class="list-group">
+ <% @changes.each do |change|
+ _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %>
+ <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.latest_version } %>
+ <% end %>
+ </ul>
+<% end %>
+
+<% content_for :head do %>
+ <%= alternate_feed_link(added_packages_url(format: :atom), t(:atom_feed)) %>
+<% end %>
diff --git a/app/views/packages/changelog.html.erb b/app/views/packages/changelog.html.erb
new file mode 100644
index 0000000..df9242e
--- /dev/null
+++ b/app/views/packages/changelog.html.erb
@@ -0,0 +1,12 @@
+<% if @changelog.empty? -%>
+ <li class="list-group-item kk-panel-content-sorry">
+ <%= t :changelog_empty %>
+ <br><br>
+ <a href="https://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/<%= @package.atom %>/ChangeLog?view=markup" class="btn btn-default">
+ <span class="fa fa-fw fa-history"></span>
+ <%= t :view_cvs_changelog %>
+ </a>
+ </li>
+<% else %>
+ <%= render partial: 'changelog_entry', collection: @changelog, as: 'changelog' %>
+<% end %>
diff --git a/app/views/packages/changelog.json.jbuilder b/app/views/packages/changelog.json.jbuilder
new file mode 100644
index 0000000..a88a2db
--- /dev/null
+++ b/app/views/packages/changelog.json.jbuilder
@@ -0,0 +1 @@
+json.changes @changelog
diff --git a/app/views/packages/keyworded.html.erb b/app/views/packages/keyworded.html.erb
new file mode 100644
index 0000000..ff5b60c
--- /dev/null
+++ b/app/views/packages/keyworded.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:packages), categories_path %></li>
+ <li class="active"><%= t :keyworded_packages %></li>
+</ol>
+
+<h1>
+ <%= t :keyworded_packages %>
+ <%= feed_icon keyworded_packages_path(format: :atom) %>
+</h1>
+
+<% cache("keyworded-full-#{@changes.hash}") do %>
+ <ul class="list-group">
+ <% @changes.each do |change|
+ _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %>
+ <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %>
+ <% end %>
+ </ul>
+<% end %>
+
+<% content_for :head do %>
+ <%= alternate_feed_link(keyworded_packages_url(format: :atom), t(:atom_feed)) %>
+<% end %>
diff --git a/app/views/packages/resolve.json.jbuilder b/app/views/packages/resolve.json.jbuilder
new file mode 100644
index 0000000..73ffdbb
--- /dev/null
+++ b/app/views/packages/resolve.json.jbuilder
@@ -0,0 +1,4 @@
+json.packages @packages do |package|
+ json.extract! package, :atom, :description
+ json.href slf package_url(id: package.atom)
+end
diff --git a/app/views/packages/search.html.erb b/app/views/packages/search.html.erb
new file mode 100644
index 0000000..fe77dd3
--- /dev/null
+++ b/app/views/packages/search.html.erb
@@ -0,0 +1,38 @@
+<h1 class="first-header">Search Results <small>for <%= params[:q] %></small></h1>
+
+<% if @packages.size > 0 %>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ Results <%= @offset + 1 %>—<%= [@offset + Package.default_search_size, @packages.total].min %> of <%= @packages.total %>
+ </div>
+ <div class="list-group">
+ <%= render partial: 'package_result_row', collection: @packages, as: 'package' %>
+ </div>
+ <div class="panel-footer">
+ <div class="btn-group" role="group" aria-label="Result navigation">
+ <%= link_to '< Prev', search_packages_path(q: params[:q], o: [@offset - Package.default_search_size, 0].max), class: 'btn btn-default' + (@offset > 0 ? '' : ' disabled') %>
+ <%= link_to 'Next >', search_packages_path(q: params[:q], o: @offset + Package.default_search_size), class: 'btn btn-default ' + ((@offset + Package.default_search_size) > @packages.total ? 'disabled' : '') %>
+ </div>
+ </div>
+</div>
+<% else %>
+<div class="jumbotron">
+ <h2 class="site-welcome stick-top">Nothing found. :( Try again?</h2>
+
+ <form action="<%= search_packages_path %>" method="get">
+ <div class="typeahead-container">
+ <div class="typeahead-field">
+ <span class="typeahead-query">
+ <input id="q" name="q" type="search" autocomplete="off" placeholder="<%= t :find_packages %>" aria-label="<%= t :find_packages %>" value="<%= params[:q] %>">
+ </span>
+ <span class="typeahead-button">
+ <button type="submit" title="<%= t :find %>" aria-label="<%= t :find %>">
+ <span class="typeahead-search-icon"></span><span class="sr-only"><%= t :find %></span>
+ </button>
+ </span>
+ </div>
+ </div>
+ </form>
+</div>
+<%= javascript_include_tag 'index/typeahead.js' %>
+<% end %>
diff --git a/app/views/packages/show.html.erb b/app/views/packages/show.html.erb
new file mode 100644
index 0000000..bc649ba
--- /dev/null
+++ b/app/views/packages/show.html.erb
@@ -0,0 +1,28 @@
+<% cache "#{@package.atom}-#{@package.metadata_hash}" do %>
+<%= render partial: 'package_header', object: @package, as: 'package' %>
+
+<div class="row">
+ <div class="col-md-9">
+ <%= render partial: 'versions', object: @package.versions, as: 'versions' %>
+
+ <% if @package.removal_pending? %>
+ <%= render partial: 'removal_notice', object: @package, as: 'package' %>
+ <% end %>
+
+ <%= render partial: 'maintainer_needed_notice', object: @package, as: 'package' %>
+ <%= render partial: 'metadata', object: @package, as: 'package', locals: { latest_version: @package.versions.first} %>
+
+ <%= render partial: 'masks', object: @package.versions, as: 'versions' %>
+
+ <%= render partial: 'changelog', object: @changelog, as: 'changelog' %>
+ </div>
+ <div class="col-md-3">
+ <%= render partial: 'resources', object: @package, as: 'package' %>
+ </div>
+</div>
+
+<%= javascript_include_tag 'packages/show' %>
+<% content_for :head do %>
+ <%= alternate_feed_link('https://gitweb.gentoo.org/repo/gentoo.git/atom/%s?h=master' % @package.atom, t(:raw_git_feed)) %>
+<% end %>
+<% end %>
diff --git a/app/views/packages/show.json.jbuilder b/app/views/packages/show.json.jbuilder
new file mode 100644
index 0000000..3b8a012
--- /dev/null
+++ b/app/views/packages/show.json.jbuilder
@@ -0,0 +1,43 @@
+json.extract! @package, :atom, :description
+json.href slf package_url(id: @package.atom)
+
+json.versions @package.versions do |version|
+ json.version version.version
+ json.keywords version.keywords
+ json.masks version.masks
+end
+
+json.herds @package.herds
+json.maintainers @package.maintainers do |maintainer|
+ json.email maintainer['email']
+ json.name maintainer['name']
+ json.description maintainer['description']
+ json.type maintainer['type']
+
+ if maintainer['type'] == 'project'
+ json.members project_members(maintainer['email'])
+ end
+end
+
+json.use do
+ json.local @package.versions.first.useflags[:local] do |flag|
+ json.name flag[1][:name]
+ json.description strip_tags flag[1][:description]
+ end
+
+ json.global @package.versions.first.useflags[:global] do |flag|
+ json.name flag[1][:name]
+ json.description strip_tags flag[1][:description]
+ end
+
+ json.use_expand @package.versions.first.useflags[:use_expand] do |flag|
+ json.set! flag[0] do
+ json.array! flag[1] do |expand_flag|
+ json.name expand_flag[0]
+ json.description strip_tags expand_flag[1][:description]
+ end
+ end
+ end
+end
+
+json.extract! @package, :updated_at
diff --git a/app/views/packages/stable.html.erb b/app/views/packages/stable.html.erb
new file mode 100644
index 0000000..7b230fe
--- /dev/null
+++ b/app/views/packages/stable.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:packages), categories_path %></li>
+ <li class="active"><%= t :stable_packages %></li>
+</ol>
+
+<h1>
+ <%= t :stable_packages %>
+ <%= feed_icon stable_packages_path(format: :atom) %>
+</h1>
+
+<% cache("stable-full-#{@changes.hash}") do %>
+ <ul class="list-group">
+ <% @changes.each do |change|
+ _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %>
+ <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %>
+ <% end %>
+ </ul>
+<% end %>
+
+<% content_for :head do %>
+ <%= alternate_feed_link(stable_packages_url(format: :atom), t(:atom_feed)) %>
+<% end %>
diff --git a/app/views/packages/suggest.json.jbuilder b/app/views/packages/suggest.json.jbuilder
new file mode 100644
index 0000000..fcd8ba5
--- /dev/null
+++ b/app/views/packages/suggest.json.jbuilder
@@ -0,0 +1 @@
+json.results @packages, :name, :category, :description
diff --git a/app/views/packages/updated.html.erb b/app/views/packages/updated.html.erb
new file mode 100644
index 0000000..b774c58
--- /dev/null
+++ b/app/views/packages/updated.html.erb
@@ -0,0 +1,23 @@
+<ol class="breadcrumb">
+ <li><a href="/">Home</a></li>
+ <li><%= link_to t(:packages), categories_path %></li>
+ <li class="active"><%= t :updated_packages %></li>
+</ol>
+
+<h1>
+ <%= t :updated_packages %>
+ <%= feed_icon updated_packages_path(format: :atom) %>
+</h1>
+
+<% cache("updated-full-#{@changes.hash}") do %>
+ <ul class="list-group">
+ <% @changes.each do |change|
+ _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %>
+ <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %>
+ <% end %>
+ </ul>
+<% end %>
+
+<% content_for :head do %>
+ <%= alternate_feed_link(updated_packages_url(format: :atom), t(:atom_feed)) %>
+<% end %>
diff --git a/app/views/useflags/_useflag_header.html.erb b/app/views/useflags/_useflag_header.html.erb
new file mode 100644
index 0000000..9422fac
--- /dev/null
+++ b/app/views/useflags/_useflag_header.html.erb
@@ -0,0 +1,5 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li><%= link_to t(:use_flags), useflags_path %></li>
+ <li class="active"><%= params[:id] %></li>
+</ol>
diff --git a/app/views/useflags/_useflag_result_row.html.erb b/app/views/useflags/_useflag_result_row.html.erb
new file mode 100644
index 0000000..084669f
--- /dev/null
+++ b/app/views/useflags/_useflag_result_row.html.erb
@@ -0,0 +1,4 @@
+<a class="list-group-item" href="<%= slf useflag_path useflag[:name] %>">
+ <h3 class="kk-search-result-header"><%= useflag[:name] %></h3>
+ <%= useflag[:description] %>
+</a>
diff --git a/app/views/useflags/index.html.erb b/app/views/useflags/index.html.erb
new file mode 100644
index 0000000..ac006f2
--- /dev/null
+++ b/app/views/useflags/index.html.erb
@@ -0,0 +1,45 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li class="active"><%= t :use_flags %></li>
+</ol>
+
+<h1><%= t :use_flags %></h1>
+
+<div class="alert alert-info">
+ Looking for the full USE flag index?
+ You can find it on our <a href="https://www.gentoo.org/support/use-flags/" class="alert-link">main website</a>.
+</div>
+
+<form action="<%= search_useflags_path %>" method="get" class="useflag-search">
+ <div class="typeahead-container">
+ <div class="typeahead-field">
+ <span class="typeahead-query">
+ <input id="q" name="q" type="search" autocomplete="off" placeholder="Find USE flags">
+ </span>
+ <span class="typeahead-button">
+ <button type="submit">
+ <span class="typeahead-search-icon"></span>
+ </button>
+ </span>
+ </div>
+ </div>
+</form>
+
+<br>
+
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Most widely used USE flags</h3>
+ </div>
+ <noscript>
+ <div class="panel-body kk-panel-content-sorry">
+ This feature requires JavaScript to work.
+ </div>
+ </noscript>
+ <div class="panel-body kk-useflag-bubble-container" id="bubble-placeholder" style="display: none;">
+ </div>
+</div>
+
+<%= javascript_include_tag 'useflags/typeahead.js' %>
+<%= javascript_include_tag 'd3.min.js' %>
+<%= javascript_include_tag 'useflags/render-bubbles.js' %>
diff --git a/app/views/useflags/popular.json.jbuilder b/app/views/useflags/popular.json.jbuilder
new file mode 100644
index 0000000..d174c9e
--- /dev/null
+++ b/app/views/useflags/popular.json.jbuilder
@@ -0,0 +1,10 @@
+json.name 'flags'
+json.children @popular_useflags do |flag|
+ # Very cheap filter for USE_EXPAND flags
+ next if flag['key'].include? '_'
+ next if flag['key'] =~ /^(doc|test|debug)$/
+
+ json.name flag['key']
+ json.size flag['doc_count']
+ json.children nil
+end
diff --git a/app/views/useflags/search.html.erb b/app/views/useflags/search.html.erb
new file mode 100644
index 0000000..061405b
--- /dev/null
+++ b/app/views/useflags/search.html.erb
@@ -0,0 +1,16 @@
+<ol class="breadcrumb">
+ <li><a href="/"><%= t :home %></a></li>
+ <li><%= link_to t(:use_flags), useflags_path %></li>
+ <li class="active">Search</li>
+</ol>
+
+<h1>USE Flag Search Results <small>for <%= params[:q] %></small></h1>
+
+<div class="panel panel-default">
+ <div class="panel-heading">
+ Results
+ </div>
+ <div class="list-group">
+ <%= render partial: 'useflag_result_row', collection: @flags, as: 'useflag' %>
+ </div>
+</div>
diff --git a/app/views/useflags/show.html.erb b/app/views/useflags/show.html.erb
new file mode 100644
index 0000000..b5b8bb6
--- /dev/null
+++ b/app/views/useflags/show.html.erb
@@ -0,0 +1,61 @@
+<%= render partial: 'useflag_header' %>
+
+<div class="row">
+ <div class="col-md-4">
+ <h1 class="stick-top">
+ <span class="fa fa-fw fa-sliders"></span>
+ <%= params[:id] %>
+ </h1>
+ </div>
+ <div class="col-md-8">
+ <% unless @useflags[:global].empty? %>
+ <div class="kk-useflag-group"><%= t :global_use_flag %></div>
+ <p class="lead" style="margin: 0;">
+ <%= @useflags[:global].first.description %>
+ </p>
+ <% else %>
+ <div class="kk-useflag-group"><%= t :local_use_flag %></div>
+ <% end %>
+ </div>
+</div>
+
+<hr>
+
+<% unless @useflags[:local].empty? %>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :local_use_package_list, flag: params[:id] %></h3>
+ </div>
+ <div class="table-responsive">
+ <table class="table">
+ <thead>
+ <th><%= t :package %></th>
+ <th><%= t :flag_description, flag: params[:id] %></th>
+ </thead>
+ <tbody>
+ <% @useflags[:local].keys.sort.each do |package| %>
+ <tr>
+ <th class="kk-nobreak-cell"><%= link_to package, slf(package_path(package)) %></th>
+ <td><%= annotate_useflag_description @useflags[:local][package].description %></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+ </div>
+<% end %>
+
+<% unless @useflags[:global].empty? %>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :providing_packages_list, flag: params[:id], count: @packages.count %></h3>
+ </div>
+ <div class="panel-body">
+ <ul class="kk-col-list kk-3col-list kk-useflag-listing">
+ <% @packages.each do |package| %>
+ <li><%= link_to_package package['key'] %></li>
+ <% end %>
+ </ul>
+ </div>
+ </div>
+<% end %>
diff --git a/app/views/useflags/show_use_expand.html.erb b/app/views/useflags/show_use_expand.html.erb
new file mode 100644
index 0000000..45c2779
--- /dev/null
+++ b/app/views/useflags/show_use_expand.html.erb
@@ -0,0 +1,57 @@
+<%= render partial: 'useflag_header' %>
+
+<div class="row">
+ <div class="col-md-4">
+ <h1 class="stick-top">
+ <span class="fa fa-fw fa-sliders"></span>
+ <%= @useflag.strip_use_expand %>
+ </h1>
+ </div>
+ <div class="col-md-8">
+ <div class="kk-useflag-group"><%= t :named_use_expand_flag, name: @use_expand_flag_name %></div>
+ <p class="lead" style="margin: 0;">
+ <%= @useflags[:use_expand].first.description %>
+ </p>
+ </div>
+</div>
+
+<hr>
+
+<% unless @use_expand_flags.empty? %>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :other_use_expand_list, flag: @use_expand_flag_name %></h3>
+ </div>
+ <div class="table-responsive">
+ <table class="table">
+ <thead>
+ <th><%= t :use_flag %></th>
+ <th><%= t :description %></th>
+ </thead>
+ <tbody>
+ <% @use_expand_flags.each do |flag| %>
+ <tr>
+ <th class="kk-nobreak-cell"><%= link_to flag.name, slf(useflag_path(flag.name)) %></th>
+ <td><%= flag.description %></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+ </div>
+<% end %>
+
+<% unless @packages.empty? %>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><%= t :providing_packages_list, flag: params[:id], count: @packages.count %></h3>
+ </div>
+ <div class="panel-body">
+ <ul class="kk-3col-list kk-useflag-listing">
+ <% @packages.each do |package| %>
+ <li><%= link_to_package package['key'] %></li>
+ <% end %>
+ </ul>
+ </div>
+ </div>
+<% end %>
diff --git a/app/views/useflags/suggest.json.jbuilder b/app/views/useflags/suggest.json.jbuilder
new file mode 100644
index 0000000..5e1571f
--- /dev/null
+++ b/app/views/useflags/suggest.json.jbuilder
@@ -0,0 +1 @@
+json.results @flags
diff --git a/bin/bundle b/bin/bundle
new file mode 100755
index 0000000..66e9889
--- /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 0000000..4d608ed
--- /dev/null
+++ b/bin/rails
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path("../spring", __FILE__)
+rescue LoadError
+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 0000000..8017a02
--- /dev/null
+++ b/bin/rake
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path("../spring", __FILE__)
+rescue LoadError
+end
+require_relative '../config/boot'
+require 'rake'
+Rake.application.run
diff --git a/bin/setup b/bin/setup
new file mode 100755
index 0000000..acdb2c1
--- /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 0000000..7b45d37
--- /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 }
+ gem "spring", match[1]
+ require "spring/binstub"
+ end
+end
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..bd83b25
--- /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 0000000..dea7c05
--- /dev/null
+++ b/config/application.rb
@@ -0,0 +1,46 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails'
+
+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)
+
+module Packages
+ class Application < Rails::Application
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+
+ # 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 = 'Central Time (US & Canada)'
+
+ # 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 = :en
+
+ # Do not swallow errors in after_commit/after_rollback callbacks.
+ #config.active_record.raise_in_transactional_callbacks = true
+
+ config.assets.precompile += %w(*.svg *.eot *.woff *.ttf *.css *.js)
+
+ config.autoload_paths << Rails.root.join('lib')
+
+ config.active_job.queue_adapter = :sidekiq
+ end
+end
+
+require 'elasticsearch/persistence'
+require 'digest'
+require 'set'
+require 'core_ext/markdown_handler'
diff --git a/config/boot.rb b/config/boot.rb
new file mode 100644
index 0000000..6b750f0
--- /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/environment.rb b/config/environment.rb
new file mode 100644
index 0000000..052dd73
--- /dev/null
+++ b/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the Rails application.
+require File.expand_path('../application', __FILE__)
+
+# Initialize the Rails application.
+Rails.application.initialize! \ No newline at end of file
diff --git a/config/environments/development.rb b/config/environments/development.rb
new file mode 100644
index 0000000..a2355b1
--- /dev/null
+++ b/config/environments/development.rb
@@ -0,0 +1,41 @@
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
+
+ # Do not eager load code on boot.
+ config.eager_load = false
+
+ # Show full error reports 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
+
+ # Raise an error on page load if there are pending migrations.
+ #config.active_record.migration_error = :page_load
+
+ # 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 0000000..22e330d
--- /dev/null
+++ b/config/environments/production.rb
@@ -0,0 +1,79 @@
+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
+ # 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
+
+ # `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 = :warn
+
+ # 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
+
+ # Do not dump schema after migrations.
+ # config.active_record.dump_schema_after_migration = false
+end
diff --git a/config/environments/test.rb b/config/environments/test.rb
new file mode 100644
index 0000000..1c19f08
--- /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 0000000..01ef3e6
--- /dev/null
+++ b/config/initializers/assets.rb
@@ -0,0 +1,11 @@
+# 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 )
diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb
new file mode 100644
index 0000000..59385cd
--- /dev/null
+++ b/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb
new file mode 100644
index 0000000..7f70458
--- /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_ext.rb b/config/initializers/core_ext.rb
new file mode 100644
index 0000000..e4271e7
--- /dev/null
+++ b/config/initializers/core_ext.rb
@@ -0,0 +1 @@
+Dir[File.join(Rails.root, 'lib', 'core_ext', '*.rb')].each {|l| require l } \ No newline at end of file
diff --git a/config/initializers/elasticsearch.rb b/config/initializers/elasticsearch.rb
new file mode 100644
index 0000000..9be3660
--- /dev/null
+++ b/config/initializers/elasticsearch.rb
@@ -0,0 +1,10 @@
+require 'elasticsearch/persistence/model'
+
+Elasticsearch::Persistence.client = Elasticsearch::Client.new host: ENV['ELASTICSEARCH_URL'] || 'localhost:9200'
+
+if Rails.env.development?
+ logger = ActiveSupport::Logger.new(STDERR)
+ logger.level = Logger::INFO
+ logger.formatter = proc { |s, d, p, m| "\e[2m#{m}\n\e[0m" }
+ Elasticsearch::Persistence.client.transport.logger = logger
+end \ No newline at end of file
diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb
new file mode 100644
index 0000000..4a994e1
--- /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 0000000..ac033bf
--- /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/kkuleomi_config.rb.dist b/config/initializers/kkuleomi_config.rb.dist
new file mode 100644
index 0000000..3982107
--- /dev/null
+++ b/config/initializers/kkuleomi_config.rb.dist
@@ -0,0 +1,23 @@
+# The location of the repository used for the indexer
+KKULEOMI_PORTDIR='/usr/portage'
+
+# The location of the repository used for gathering runtime information
+KKULEOMI_RUNTIME_PORTDIR='/usr/portage'
+
+# The first actual git commit
+# Set this to the second commit in the repo to avoid long changelog generation times
+KKULEOMI_FIRST_COMMIT='c1de71edb35b118c3244c0d9d1b3f97c93d41969'
+
+# Where does git(1) live?
+KKULEOMI_GIT='git'
+
+# Who gets feedback
+KKULEOMI_FEEDBACK_RECIPIENT='a3li@gentoo.org'
+
+# Cache settings
+# deployment:
+# Rails.application.config.cache_store = :mem_cache_store, '127.0.0.1'
+
+# development:
+# Rails.application.config.cache_store = :memory_store, { size: 64.megabytes }
+# Rails.application.config.action_controller.perform_caching = true
diff --git a/config/initializers/kkuleomi_constants.rb b/config/initializers/kkuleomi_constants.rb
new file mode 100644
index 0000000..bf1a8b7
--- /dev/null
+++ b/config/initializers/kkuleomi_constants.rb
@@ -0,0 +1 @@
+KK_CACHE_LAST_IMPORT = 'kk/last-import'
diff --git a/config/initializers/kkuleomi_data.rb b/config/initializers/kkuleomi_data.rb
new file mode 100644
index 0000000..a00b0f9
--- /dev/null
+++ b/config/initializers/kkuleomi_data.rb
@@ -0,0 +1,23 @@
+KK_KEYWORD_ICON = {
+ stable: 'octicon-diff-added',
+ testing: 'octicon-diff-modified',
+ unavailable: 'octicon-diff-removed',
+ masked: 'octicon-diff-ignored'
+}
+
+KK_KEYWORD_CLASS = {
+ stable: 'kk-keyword-stable',
+ testing: 'kk-keyword-testing',
+ unavailable: 'kk-keyword-unavailable',
+ masked: 'kk-keyword-masked',
+ unknown: 'kk-keyword-unknown'
+}
+
+KK_KEYWORD_VERBALIZATION = {
+ stable: :keyword_stable,
+ testing: :keyword_testing,
+ unavailable: :keyword_unavailable,
+ unknown: :keyword_unknown,
+ masked: :keyword_masked,
+ invalid: :keyword_invalid
+}
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
new file mode 100644
index 0000000..dc18996
--- /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/session_store.rb b/config/initializers/session_store.rb
new file mode 100644
index 0000000..1e567f0
--- /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 :disabled
diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb
new file mode 100644
index 0000000..33725e9
--- /dev/null
+++ b/config/initializers/wrap_parameters.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+
+# This file contains settings for ActionController::ParamsWrapper which
+# is enabled by default.
+
+# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
+ActiveSupport.on_load(:action_controller) do
+ wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
+end
+
+# To enable root element in JSON for ActiveRecord objects.
+# ActiveSupport.on_load(:active_record) do
+# self.include_root_in_json = true
+# end
diff --git a/config/locales/de.yml b/config/locales/de.yml
new file mode 100644
index 0000000..0d9d2ee
--- /dev/null
+++ b/config/locales/de.yml
@@ -0,0 +1,31 @@
+# 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.
+
+de:
+ hello: "Hello world"
+ description: "Beschreibung"
+ categories: "Kategorien"
+ category: "Kategorie"
+ resources: "Ressourcen"
+ restrict_tooltip: "Die folgenden Features sind nicht verfügbar: %{list}"
+ keyword_tooltip: "%{version} ist %{keyword} für %{arch}"
+ properties_tooltip: "Dieses Ebuild setzt die folgenden Properties: %{list}"
+ packages: "Pakete"
diff --git a/config/locales/en.yml b/config/locales/en.yml
new file mode 100644
index 0000000..a9aa69f
--- /dev/null
+++ b/config/locales/en.yml
@@ -0,0 +1,112 @@
+en:
+ # Basic phrases
+ app_name: "Gentoo Packages Database"
+ home: "Home"
+ packages: "Packages"
+ description: "Description"
+ categories: "Categories"
+ category: "Category"
+ resources: "Resources"
+ version: "Version"
+ commit: "commit"
+ find: "Find"
+ architectures: "Architectures"
+ about: "About"
+ help: "Help"
+ feedback: "Feedback"
+ find_packages: "Find Packages"
+ atom_feed: "Atom feed"
+ update_feeds: "Update Feeds"
+ more: "more…"
+ global_use_flag: "Global USE flag"
+ local_use_flag: "Local USE flag"
+ use_expand_flag: "USE_EXPAND flag"
+ named_use_expand_flag: "%{name} USE_EXPAND flag"
+ legend: "Legend"
+ show_table_legend: "Show table legend"
+ changelog: "Changelog"
+ data_current_as_of: "Data currrent as of"
+ git_commit: "Git commit"
+ # Keywords
+ keyword_table_legend: "Keyword table legend"
+ keyword_stable: "stable"
+ keyword_testing: "testing"
+ keyword_unavailable: "unavailable"
+ keyword_unknown: "unknown"
+ keyword_masked: "masked"
+ keyword_invalid: "?"
+ # Category view
+ browse_categories: "Browse Categories"
+ # Package view
+ box_versions: "Available Versions"
+ box_metadata: "Package Metadata"
+ box_changelog: "Changelog"
+ box_masks: "Masks"
+ box_legend: "Legend"
+ box_resources: "Resources"
+ other_homepages: "Other homepage(s)"
+ longdescription: "Full description"
+ license: "License"
+ herds: "Herd(s)"
+ use_flags: "USE flags"
+ maintainers: "Maintainer(s)"
+ restrict_tooltip: "The following features are restricted: %{list}"
+ keyword_tooltip: "%{version} is %{keyword} on %{arch}"
+ properties_tooltip: "This ebuild sets the following properties: %{list}"
+ changelog_empty: "This package has not been changed since our repository has moved to Git."
+ view_cvs_changelog: "View old CVS Changelog"
+ changelog_error: "Inline Changelog cannot be displayed."
+ view_git_changelog: "View Git Changelog"
+ res_bugs: "Related bugs"
+ res_docs: "Documentation"
+ res_forums: "Forums posts"
+ res_repo: "Git repository browser"
+ res_log: "Git log"
+ res_feed: "Changes feed"
+ res_installed_files: "Installed files"
+ legend_stable: "Stable"
+ legend_testing: "Testing"
+ legend_unavailable: "Explicitly unavailable"
+ legend_masked: "Masked"
+ legend_unknown: "Unknown"
+ local_use_flags: "Local USE flags"
+ global_use_flags: "Global USE flags"
+ use_expand_flag: "%{flag} (USE_EXPAND)"
+ added_keywords: "added keywords: %{keywords}"
+ raw_git_feed: "Raw Git Changelog (Atom Feed)"
+ mask_packages: "Affected packages"
+ mask_arches: "Affected architectures"
+ mask_all_arches: "(all architectures)"
+ mask_author: "Author/Date"
+ # Other package-related stuff
+ added_packages: "Added Packages"
+ updated_packages: "Updated Packages"
+ stable_packages: "Newly Stable Packages"
+ keyworded_pacakges: "Keyworded Packages"
+ version_not_found: "Version was not found. It has likely been removed already."
+ # USE flag view
+ local_use_package_list: "Packages describing “%{flag}” as local USE flag"
+ flag_description: "“%{flag}” Flag Description"
+ providing_packages_list: "All packages providing a “%{flag}” USE flag (%{count})"
+ other_use_expand_list: "Other “%{flag}” USE_EXPAND flag values"
+ # arches
+ arches_intro: "In this section, you can find updates for specific architectures."
+ # Feeds
+ feed_added: "Gentoo Packages: Added packages"
+ feed_added_arch: "Gentoo Packages: Added packages on %{arch}"
+ feed_added_title: "%{atom} (%{description})"
+ feed_added_content: "%{atom} is now available in Gentoo on these architectures: %{arches}"
+ feed_updated: "Gentoo Packages: Updated packages"
+ feed_updated_arch: "Gentoo Packages: Updated packages on %{arch}"
+ feed_updated_title: "%{atom} (%{description})"
+ feed_updated_content: "%{atom} was added as a new package version to Gentoo."
+ feed_stable: "Gentoo Packages: Newly stable packages"
+ feed_stable_arch: "Gentoo Packages: Newly stable packages on %{arch}"
+ feed_stable_title: "%{atom} (%{description})"
+ feed_stable_content: "%{atom} is now stable on these architectures: %{arches}"
+ feed_keyworded: "Gentoo Packages: Newly keyworded packages"
+ feed_keyworded_arch: "Gentoo Packages: Newly keyworded packages on %{arch}"
+ feed_keyworded_title: "%{atom} (%{description})"
+ feed_keyworded_content: "%{atom} is now keyworded on these architectures: %{arches}"
+ # <meta> descriptions
+ desc_categories_show: "Gentoo package category %{category}: %{description}"
diff --git a/config/routes.rb b/config/routes.rb
new file mode 100644
index 0000000..57ad107
--- /dev/null
+++ b/config/routes.rb
@@ -0,0 +1,55 @@
+require 'sidekiq/web'
+
+Rails.application.routes.draw do
+ get 'about/feedback'
+ post 'about/feedback'
+ get 'about', to: 'about#index'
+ get 'about/feeds'
+ get 'about/help'
+ get 'about/changelog'
+
+ root 'index#index'
+
+ # Catch all old pgo feeds
+ get 'feed(/*stuff)', to: 'about#legacy', defaults: { format: 'atom' }
+
+ resources :categories, only: [:index, :show, :search] do
+ member do
+ get 'search'
+ end
+ end
+
+ resources :packages, only: [:index, :show, :search], constraints: { id: /[^.]*/ } do
+ collection do
+ get 'search'
+ get 'suggest'
+ get 'resolve'
+
+ get 'added'
+ get 'updated'
+ get 'stable'
+ get 'keyworded'
+ end
+
+ member do
+ get 'changelog'
+ end
+ end
+
+ resources :useflags do
+ collection do
+ get 'popular'
+ get 'search'
+ get 'suggest'
+ end
+ end
+
+ resources :arches do
+ member do
+ get 'stable'
+ get 'keyworded'
+ end
+ end
+
+ mount Sidekiq::Web, at: '/sidekiq'
+end
diff --git a/config/secrets.yml.dist b/config/secrets.yml.dist
new file mode 100644
index 0000000..d227190
--- /dev/null
+++ b/config/secrets.yml.dist
@@ -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: <%= set_me %>
+
+test:
+ secret_key_base: <%= set_me %>
+
+# Do not keep production secrets in the repository,
+# instead read values from the environment.
+production:
+ secret_key_base: <%= set_me %>
diff --git a/db/seeds.rb b/db/seeds.rb
new file mode 100644
index 0000000..4edb1e8
--- /dev/null
+++ b/db/seeds.rb
@@ -0,0 +1,7 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
+#
+# Examples:
+#
+# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
+# Mayor.create(name: 'Emanuel', city: cities.first)
diff --git a/lib/assets/.keep b/lib/assets/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/assets/.keep
diff --git a/lib/core_ext/markdown_handler.rb b/lib/core_ext/markdown_handler.rb
new file mode 100644
index 0000000..f5ffa7b
--- /dev/null
+++ b/lib/core_ext/markdown_handler.rb
@@ -0,0 +1,14 @@
+require 'rdiscount'
+
+module MarkdownHandler
+ def self.erb
+ @erb ||= ActionView::Template.registered_template_handler(:erb)
+ end
+
+ def self.call(template)
+ compiled_source = erb.call(template)
+ "RDiscount.new(begin;#{compiled_source};end).to_html"
+ end
+end
+
+ActionView::Template.register_template_handler :md, MarkdownHandler
diff --git a/lib/core_ext/string.rb b/lib/core_ext/string.rb
new file mode 100644
index 0000000..a5fa002
--- /dev/null
+++ b/lib/core_ext/string.rb
@@ -0,0 +1,5 @@
+class String
+ def is_i?
+ /\A[-+]?\d+\z/ === self
+ end
+end \ No newline at end of file
diff --git a/lib/kkuleomi.rb b/lib/kkuleomi.rb
new file mode 100644
index 0000000..2de5955
--- /dev/null
+++ b/lib/kkuleomi.rb
@@ -0,0 +1,2 @@
+module Kkuleomi
+end
diff --git a/lib/kkuleomi/store.rb b/lib/kkuleomi/store.rb
new file mode 100644
index 0000000..4baf2c4
--- /dev/null
+++ b/lib/kkuleomi/store.rb
@@ -0,0 +1,53 @@
+module Kkuleomi::Store
+ def self.refresh_index
+ Category.gateway.refresh_index!
+ end
+
+ def self.create_index(force = false)
+ client = Category.gateway.client
+ index_name = Category.index_name
+
+ settings_list = [
+ Category.settings.to_hash,
+ Package.settings.to_hash,
+ Version.settings.to_hash,
+ Change.settings.to_hash,
+ Useflag.settings.to_hash
+ ]
+
+ mappings_list = [
+ Category.mappings.to_hash,
+ Package.mappings.to_hash,
+ Version.mappings.to_hash,
+ Change.mappings.to_hash,
+ Useflag.mappings.to_hash
+ ]
+
+ settings = {
+ analysis: {
+ filter: {
+ autocomplete_filter: {
+ type: 'edge_ngram',
+ min_gram: 1,
+ max_gram: 20,
+ }
+ },
+ analyzer: {
+ autocomplete: {
+ type: 'custom',
+ tokenizer: 'standard',
+ filter: %w(lowercase autocomplete_filter)
+ }
+ }
+ }
+ }
+ settings_list.each { |setting| settings.merge! setting }
+
+ mappings = {}
+ mappings_list.each { |mapping| mappings.merge! mapping }
+
+ client.indices.delete(index: index_name) rescue nil if force
+
+ client.indices.create(index: index_name, body: { settings: settings, mappings: mappings })
+ end
+end
diff --git a/lib/kkuleomi/store/model.rb b/lib/kkuleomi/store/model.rb
new file mode 100644
index 0000000..8d406bf
--- /dev/null
+++ b/lib/kkuleomi/store/model.rb
@@ -0,0 +1,80 @@
+module Kkuleomi::Store::Model
+ def self.included(base)
+ base.send :include, InstanceMethods
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ # Finds instances by exact IDs using the 'term' filter
+ def find_all_by(field, value, opts = {})
+ search({
+ size: 10_000,
+ query: {
+ filtered: { filter: { term: { field => value } } }
+ }
+ }.merge(opts))
+ end
+
+ # Filter all instances by the given parameters
+ def filter_all(filters, opts = {})
+ filter_args = []
+ filters.each_pair { |field, value| filter_args << { term: { field => value } } }
+
+ search({
+ query: {
+ filtered: { filter: { bool: { must: filter_args } } }
+ },
+ size: 10_000
+ }.merge(opts))
+ end
+
+ def find_by(field, value, opts = {})
+ find_all_by(field, value, opts).first
+ end
+
+ def find_all_by_parent(parent, opts = {})
+ search(opts.merge(
+ size: 10_000,
+ query: {
+ filtered: {
+ filter: {
+ has_parent: {
+ type: parent.class.document_type,
+ filter: { term: { _id: parent.id } }
+ }
+ },
+ query: { match_all: {} }
+ }
+ }
+ ))
+ end
+
+ # Returns all (by default 10k) records of this class sorted by a field.
+ def all_sorted_by(field, order, options = {})
+ all({
+ query: { match_all: {} },
+ sort: { field => { order: order } }
+ }, options)
+ end
+ end
+
+ module InstanceMethods
+ # Converts the model to an OpenStruct instance
+ #
+ # @param [Array<Symbol>] fields Fields to export into the OpenStruct, or all fields if nil
+ # @return [OpenStruct] OpenStruct containing the selected fields
+ def to_os(*fields)
+ fields = all_fields if fields.empty?
+ OpenStruct.new(Hash[fields.map { |field| [field, send(field)] }])
+ end
+
+ # Converts the model to a Hash
+ #
+ # @param [Array<Symbol>] fields Fields to export into the Hash, or all fields if nil
+ # @return [Hash] Hash containing the selected fields
+ def to_hsh(*fields)
+ fields = all_fields if fields.empty?
+ Hash[fields.map { |field| [field, send(field)] }]
+ end
+ end
+end
diff --git a/lib/kkuleomi/store/models.rb b/lib/kkuleomi/store/models.rb
new file mode 100644
index 0000000..6b0c4e3
--- /dev/null
+++ b/lib/kkuleomi/store/models.rb
@@ -0,0 +1,2 @@
+module Kkuleomi::Store::Models
+end
diff --git a/lib/kkuleomi/store/models/package_import.rb b/lib/kkuleomi/store/models/package_import.rb
new file mode 100644
index 0000000..caea415
--- /dev/null
+++ b/lib/kkuleomi/store/models/package_import.rb
@@ -0,0 +1,154 @@
+# Contains the import logic for packages
+module Kkuleomi::Store::Models::PackageImport
+ def self.included(base)
+ base.send :include, InstanceMethods
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ end
+
+ module InstanceMethods
+ # Determines if the current package document needs an update from the model
+ #
+ # @param [Portage::Repository::Package] package_model Package model
+ def needs_import?(package_model)
+ metadata_hash != package_model.metadata_hash
+ end
+
+ # Imports data from this model. Saving is not optional here as we might need the package's ID as parent.
+ #
+ # @param [Portage::Repository::Package] package_model Package model
+ # @param [Hash] options Import options
+ def import!(package_model, options)
+ # Fetch ebuilds, newest-first
+ ebuilds = package_model.ebuilds_sorted.reverse
+ latest_ebuild = ebuilds.first
+
+ fail "No ebuilds found for #{package_model.name}. Skipping import." unless latest_ebuild
+
+ set_basic_metadata(package_model, latest_ebuild)
+
+ # Be sure to have an ID now
+ save
+
+ import_useflags!(package_model)
+ Kkuleomi::Store.refresh_index
+ import_versions!(package_model, ebuilds, options)
+
+ # Do this last, so that any exceptions before this point skip this step
+ self.metadata_hash = package_model.metadata_hash
+ save
+
+ if options[:package_state] == 'new' && !options[:suppress_change_objects]
+ RecordChangeJob.perform_later(
+ type: 'new_package',
+ category: category,
+ package: name
+ )
+ end
+ end
+
+ def set_basic_metadata(package_model, latest_ebuild)
+ self.name = package_model.name
+ self.name_sort = package_model.name.downcase
+ self.category = package_model.category
+ self.atom = package_model.to_cp
+
+ self.description = latest_ebuild.metadata[:description]
+
+ if (homepage = latest_ebuild.metadata[:homepage])
+ self.homepage = homepage.split ' '
+ end
+
+ self.license = latest_ebuild.metadata[:license]
+ self.licenses = split_license_str latest_ebuild.metadata[:license]
+
+ self.herds = package_model.metadata[:herds]
+ self.maintainers = package_model.metadata[:maintainer]
+
+ self.longdescription = package_model.metadata[:longdescription][:en]
+ end
+
+ def import_useflags!(package_model)
+ index_flags = Useflag.local_for(package_model.to_cp)
+ model_flags = package_model.metadata[:use]
+
+ new_flags = model_flags.keys - index_flags.keys
+ del_flags = index_flags.keys - model_flags.keys
+ eql_flags = model_flags.keys & index_flags.keys
+
+ new_flags.each do |flag|
+ flag_doc = Useflag.new
+ # TODO: import! method?
+ flag_doc.name = flag
+ flag_doc.description = model_flags[flag]
+ flag_doc.atom = package_model.to_cp
+ flag_doc.scope = 'local'
+ flag_doc.save
+ end
+
+ eql_flags.each do |flag|
+ unless index_flags[flag].description == model_flags[flag]
+ index_flags[flag].description = model_flags[flag]
+ index_flags[flag].save
+ end
+ end
+
+ del_flags.each do |flag|
+ index_flags[flag].delete
+ end
+ end
+
+ def import_versions!(package_model, ebuilds, options)
+ index_v = Hash[Version.find_all_by_parent(self).map { |v| [v.version, v] }]
+ model_v = Hash[ebuilds.map { |v| [v.version, v] }]
+
+ index_keys = index_v.keys
+ model_keys = model_v.keys
+
+ new_v = model_keys - index_keys
+ del_v = index_keys - model_keys
+ eql_v = model_keys & index_keys
+
+ Rails.logger.debug { "#{package_model.to_cp} new: " + new_v.inspect }
+ Rails.logger.debug { "#{package_model.to_cp} del: " + del_v.inspect }
+ Rails.logger.debug { "#{package_model.to_cp} eql: " + eql_v.inspect }
+
+ ebuild_order = Hash[ebuilds.each_with_index.map { |e, i| [e.version, i] }]
+
+ new_v.each do |v|
+ version_doc = Version.new
+ version_doc.import!(model_v[v], self, options.merge(version_state: 'new'))
+
+ sort_key = ebuild_order[v]
+ version_doc.set_sort_key!(sort_key, self)
+
+ if sort_key == 0
+ self.useflags = version_doc.useflags
+ save
+ end
+ end
+
+ eql_v.each do |v|
+ version_doc = index_v[v]
+
+ if version_doc.needs_import? model_v[v]
+ version_doc.import!(model_v[v], self, options)
+ end
+
+ sort_key = ebuild_order[v]
+ version_doc.set_sort_key!(sort_key, self)
+
+ if sort_key == 0
+ self.useflags = version_doc.useflags
+ save
+ end
+ end
+
+ del_v.each do |v|
+ index_v[v].delete
+ end
+ end
+ end
+end
diff --git a/lib/kkuleomi/store/models/package_search.rb b/lib/kkuleomi/store/models/package_search.rb
new file mode 100644
index 0000000..150b0e9
--- /dev/null
+++ b/lib/kkuleomi/store/models/package_search.rb
@@ -0,0 +1,158 @@
+# Contains the search logic for packages
+module Kkuleomi::Store::Models::PackageSearch
+ def self.included(base)
+ base.send :include, InstanceMethods
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ def suggest(q)
+ Package.search(
+ size: 20,
+ query: {
+ wildcard: {
+ name_sort: {
+ wildcard: q.downcase + '*'
+ }
+ }
+ }
+ )
+ end
+
+ # Tries to resolve a query atom to one or more packages
+ def resolve(atom)
+ [] if atom.nil? || atom.empty?
+
+ Package.find_all_by(:atom, atom) + Package.find_all_by(:name, atom)
+ end
+
+ # Searches the versions index for versions using a certain USE flag.
+ # Results are aggregated by package atoms.
+ def find_atoms_by_useflag(useflag)
+ Version.search(
+ query: {
+ filtered: {
+ query: { match_all: {} },
+ filter: { term: { use: useflag } }
+ }
+ },
+ aggs: {
+ group_by_package: {
+ terms: {
+ field: 'package',
+ size: 0,
+ order: { '_term' => 'asc' }
+ }
+ }
+ },
+ size: 0
+ ).response.aggregations['group_by_package'].buckets
+ end
+
+ def default_search_size
+ 25
+ end
+
+ def default_search(q, offset)
+ return [] if q.nil? || q.empty?
+
+ part1, part2 = q.split('/', 2)
+
+ if part2.nil?
+ search(build_query(part1, nil, default_search_size, offset))
+ else
+ search(build_query(part2, part1, default_search_size, offset))
+ end
+ end
+
+ def build_query(q, category, size, offset)
+ {
+ size: size,
+ from: offset,
+ query: {
+ function_score: {
+ query: { bool: bool_query_parts(q, category) },
+ functions: scoring_functions
+ }
+ }
+ }
+ end
+
+ def bool_query_parts(q, category = nil)
+ q_dwncsd = q.downcase
+
+ query = {
+ must: [
+ match_wildcard(q_dwncsd)
+ ],
+ should: [
+ match_phrase(q_dwncsd),
+ match_description(q)
+ ]
+ }
+
+ query[:must] << [match_category(category)] if category
+
+ query
+ end
+
+ def match_wildcard(q)
+ q = ('*' + q + '*') unless q.include? '*'
+ q.tr!(' ', '*')
+
+ {
+ wildcard: {
+ name_sort: {
+ wildcard: q,
+ boost: 4
+ }
+ }
+ }
+ end
+
+ def match_phrase(q)
+ {
+ match_phrase: {
+ name: {
+ query: q,
+ boost: 5
+ }
+ }
+ }
+ end
+
+ def match_description(q)
+ {
+ match: {
+ description: {
+ query: q,
+ boost: 0.1
+ }
+ }
+ }
+ end
+
+ def match_category(cat)
+ {
+ match: {
+ category: {
+ query: cat,
+ boost: 2
+ }
+ }
+ }
+ end
+
+ def scoring_functions
+ [
+ {
+ filter: { term: { category: 'virtual' } },
+ boost_factor: 0.6
+ }
+ ]
+ end
+ end
+
+ module InstanceMethods
+ end
+end
diff --git a/lib/kkuleomi/store/models/version_import.rb b/lib/kkuleomi/store/models/version_import.rb
new file mode 100644
index 0000000..c18344e
--- /dev/null
+++ b/lib/kkuleomi/store/models/version_import.rb
@@ -0,0 +1,120 @@
+# Contains the import logic for versions
+module Kkuleomi::Store::Models::VersionImport
+ def self.included(base)
+ base.send :include, InstanceMethods
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ end
+
+ module InstanceMethods
+ # Determines if the current version document needs an update from the model
+ #
+ # @param [Portage::Repository::Ebuild] ebuild_model Ebuild model
+ def needs_import?(ebuild_model)
+ metadata_hash != ebuild_model.metadata_hash
+ end
+
+ # Imports data from an ebuild model and saves the object
+ #
+ # @param [Portrage::Repository::Ebuild] ebuild_model
+ def import!(ebuild_model, parent_package, options)
+ self.version = ebuild_model.version
+ self.atom = ebuild_model.to_cpv
+ self.package = parent_package.atom
+
+ raw_slot = nil
+ raw_subslot = nil
+ raw_slot, raw_subslot = ebuild_model.metadata[:slot].split '/' if ebuild_model.metadata[:slot]
+ self.slot = raw_slot || ''
+ self.subslot = raw_subslot || ''
+
+ old_keywords = keywords
+ self.keywords = ebuild_model.metadata[:keywords] || []
+ self.use = strip_useflag_defaults(ebuild_model.metadata[:iuse] || []).uniq
+ self.restrict = ebuild_model.metadata[:restrict] || []
+ self.properties = ebuild_model.metadata[:properties] || []
+ self.masks = Portage::Util::Masks.for(ebuild_model)
+ self.metadata_hash = ebuild_model.metadata_hash
+
+ save(parent: parent_package.id)
+
+ # If keywords changed, calculate changes and record as needed (but only do that if we should)
+ unless options[:suppress_change_objects]
+ RecordChangeJob.perform_later(
+ type: 'version_bump',
+ category: parent_package.category,
+ package: parent_package.name,
+ version: version
+ ) if options[:package_state] != 'new' && options[:version_state] == 'new'
+
+ process_keyword_diff(old_keywords, keywords, parent_package) unless old_keywords == keywords
+ end
+ end
+
+ # Convenience method to set the sort key and save the model
+ #
+ # @param [Integer] sort_key Sort key to set
+ # @param [Package] parent Parent package model
+ def set_sort_key!(key, parent)
+ self.sort_key = key
+ save(parent: parent.id)
+ end
+
+ def strip_useflag_defaults(flags)
+ flags.map { |flag| flag.start_with?('+', '-') ? flag[1..-1] : flag }
+ end
+
+ def process_keyword_diff(old_kws_raw, new_kws_raw, package)
+ stabled = []
+ keyworded = []
+
+ old_kws = parse_keywords old_kws_raw
+ new_kws = parse_keywords new_kws_raw
+
+ (old_kws[:arches].keys | new_kws[:arches].keys).each do |arch|
+ old = old_kws[:arches][arch]
+ new = new_kws[:arches][arch]
+
+ if old && new
+ next if old == new
+
+ if old == :unavailable && new == :testing
+ keyworded << arch
+ elsif old == :unavailable && new == :stable
+ stabled << arch
+ elsif old == :testing && new == :stable
+ stabled << arch
+ end
+ elsif new && !old
+ if new == :testing
+ keyworded << arch
+ elsif new == :stable
+ stabled << arch
+ end
+ end
+ end
+
+ unless stabled.empty?
+ RecordChangeJob.perform_later(
+ type: 'stable',
+ category: package.category,
+ package: package.name,
+ version: version,
+ arches: stabled
+ )
+ end
+
+ unless keyworded.empty?
+ RecordChangeJob.perform_later(
+ type: 'keyword',
+ category: package.category,
+ package: package.name,
+ version: version,
+ arches: keyworded
+ )
+ end
+ end
+ end
+end
diff --git a/lib/kkuleomi/store/suggester.rb b/lib/kkuleomi/store/suggester.rb
new file mode 100644
index 0000000..1da59ab
--- /dev/null
+++ b/lib/kkuleomi/store/suggester.rb
@@ -0,0 +1,23 @@
+class Kkuleomi::Store::Suggester
+ def initialize(q)
+ @q = q
+ end
+
+ def response
+ @response ||= begin
+ Elasticsearch::Persistence.client.suggest(
+ index: "packages-#{Rails.env}",
+ body: {
+ name: {
+ text: @q,
+ completion: { field: 'suggest_name', size: 25 }
+ },
+ description: {
+ text: @q,
+ completion: { field: 'suggest_description', size: 25 }
+ }
+ }
+ )
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/kkuleomi/util.rb b/lib/kkuleomi/util.rb
new file mode 100644
index 0000000..e9ea9be
--- /dev/null
+++ b/lib/kkuleomi/util.rb
@@ -0,0 +1,2 @@
+module Kkuleomi::Util
+end
diff --git a/lib/kkuleomi/util/exec.rb b/lib/kkuleomi/util/exec.rb
new file mode 100644
index 0000000..704d651
--- /dev/null
+++ b/lib/kkuleomi/util/exec.rb
@@ -0,0 +1,65 @@
+require 'open3'
+
+class Kkuleomi::Util::Exec
+ def initialize(command)
+ @cmd = command
+ end
+
+ def env(key, value)
+ @env ||= {}
+ @env[key] = value
+
+ self
+ end
+
+ def args(*arguments)
+ @args = arguments
+
+ self
+ end
+
+ def in(chdir)
+ @chdir = chdir
+
+ self
+ end
+
+ def run
+ args = nil
+
+ if @env.is_a?(Hash) && !@env.empty?
+ args = [@env, @cmd]
+ else
+ args = @cmd
+ end
+
+ opts = {}
+ opts[:chdir] = @chdir if @chdir
+
+ @stdin, @stdout, @stderr, @wait_thr = Open3.popen3(args, *(@args || []), opts)
+
+ @ran = true
+ self
+ end
+
+ def exit_status
+ run unless @ran
+ @wait_thr.value
+ end
+
+ def stdout
+ run unless @ran
+ @stdout.read
+ end
+
+ def stderr
+ run unless @ran
+ @stderr.read
+ end
+
+ class << self
+ def cmd(command)
+ new(command)
+ end
+ end
+end
diff --git a/lib/portage.rb b/lib/portage.rb
new file mode 100644
index 0000000..09c3ee7
--- /dev/null
+++ b/lib/portage.rb
@@ -0,0 +1,2 @@
+module Portage
+end
diff --git a/lib/portage/ebuild.rb b/lib/portage/ebuild.rb
new file mode 100644
index 0000000..1b3035d
--- /dev/null
+++ b/lib/portage/ebuild.rb
@@ -0,0 +1,9 @@
+module Portage::Ebuild
+ # Exception thrown when an atom is invalid
+ class InvalidAtomError < StandardError
+ end
+
+ # Exception thrown when a version string is invalid
+ class InvalidVersionError < StandardError
+ end
+end
diff --git a/lib/portage/repository.rb b/lib/portage/repository.rb
new file mode 100644
index 0000000..49c34db
--- /dev/null
+++ b/lib/portage/repository.rb
@@ -0,0 +1,2 @@
+module Portage::Repository
+end
diff --git a/lib/portage/repository/category.rb b/lib/portage/repository/category.rb
new file mode 100644
index 0000000..1f70a97
--- /dev/null
+++ b/lib/portage/repository/category.rb
@@ -0,0 +1,91 @@
+class Portage::Repository::Category
+ attr_reader :name, :path
+
+ # Creates a new Category model
+ #
+ # @param [String] path Category base directory path
+ def initialize(path)
+ unless File.directory? path
+ raise ArgumentError, "#{path} does not look like a valid category for repository."
+ end
+
+ @path = path
+ @name = path.split('/').last
+ end
+
+ # Returns the description of the category in English, or the requested language
+ #
+ # @param [Symbol] lang Requested description language
+ # @return [String] Description, or nil if no description for this language is included in the metadata
+ def description(lang = :en)
+ metadata[lang.to_sym]
+ end
+
+ # Returns a list of available description languages
+ #
+ # @return [Array] Available language symbols
+ def description_languages
+ metadata.keys.sort
+ end
+
+ # Returns a list of packages in this category
+ #
+ # @return [Array] List of packages in this category
+ def packages
+ @packages ||= package_dirs.map {|p| Portage::Repository::Package.new(p) }
+ end
+
+
+ # Returns a given package, or nil
+ #
+ # TODO: Hash categories internally?
+ def package(name)
+ packages.each do |package|
+ return package if package.name == name
+ end
+
+ nil
+ end
+
+
+ # Returns the hash of the metadata for this category
+ #
+ # @return [String] MD5 hash of the category metadata
+ def metadata_hash
+ Digest::MD5.file(File.join(@path, 'metadata.xml')).hexdigest
+ end
+
+ private
+ def metadata
+ @metadata ||= parse_metadata
+ end
+
+ def parse_metadata
+ f = File.open(File.join(@path, 'metadata.xml'))
+ xml = Nokogiri::XML(f)
+ f.close
+
+ res = {}
+
+ xml.xpath('/catmetadata/longdescription').each do |desc_tag|
+ lang = :en
+ lang = desc_tag['lang'].downcase.to_sym if desc_tag.has_attribute? 'lang'
+
+ res[lang] = desc_tag.text.strip.gsub(/\s+/, ' ')
+ end
+
+ res
+ rescue Errno::ENOENT
+ Rails.logger.warn "Cannot find metadata for category #{@name}."
+ {}
+ end
+
+ # Filters the subdirectories of the category to find packages
+ #
+ # @return [Array] Package directories in this category
+ def package_dirs
+ Dir.glob("#{@path}/*").select do |d|
+ File.directory?(d) and File.file?(File.join(d, 'metadata.xml'))
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/portage/repository/ebuild.rb b/lib/portage/repository/ebuild.rb
new file mode 100644
index 0000000..fff3f4b
--- /dev/null
+++ b/lib/portage/repository/ebuild.rb
@@ -0,0 +1,54 @@
+class Portage::Repository::Ebuild
+ attr_reader :package, :name, :path, :version, :category, :repo_root
+
+ # Creates a new ebuild model instance
+ #
+ # @param [String] path File path to the ebuild
+ def initialize(path)
+ unless File.file? path
+ fail ArgumentError, "#{name} does not look like a valid ebuild."
+ end
+
+ @path = path
+ path_parts = path.split '/'
+
+ @repo_root = File.join(File.dirname(path), '..', '..')
+ @category = path_parts[-3]
+ @package = path_parts[-2]
+ @name = path_parts.last
+
+ if @name =~ /^#{Regexp.escape @package}-(.*)\.ebuild$/
+ @version = $1
+ else
+ fail ArgumentError, "#{name} does not look like a valid ebuild name for package #{package}."
+ end
+ end
+
+ def to_s
+ "#{@category}/#{@name}"
+ end
+
+ def to_cp
+ "#{@category}/#{@package}"
+ end
+
+ def to_cpv
+ "#{@category}/#{to_pv}"
+ end
+
+ def to_pv
+ @name.gsub(/\.ebuild$/, '')
+ end
+
+ def metadata
+ @metadata ||= Portage::Util::MetadataCache.new self
+ end
+
+ def metadata_hash
+ Digest::MD5.hexdigest("#{metadata.hash}#{Portage::Util::Masks.for(self).hash}")
+ end
+
+ def inspect
+ "#<Ebuild '#{@name}' @package='#{@package}' @path='#{@path}'>"
+ end
+end
diff --git a/lib/portage/repository/model.rb b/lib/portage/repository/model.rb
new file mode 100644
index 0000000..135f7e5
--- /dev/null
+++ b/lib/portage/repository/model.rb
@@ -0,0 +1,72 @@
+# Describes a portage repository identified by its base path
+class Portage::Repository::Model
+ attr_reader :repo_name, :path
+
+ def initialize(path)
+ @path = path
+ @repo_name = File.read(File.join(path, 'profiles', 'repo_name')).strip
+ end
+
+ # Returns the categories contained within this repository
+ #
+ # @return [Array[Portage::Repository::Category]] List of categories
+ def categories
+ @categories ||= category_dirs.map {|c| Portage::Repository::Category.new(File.join(@path, c)) }
+ end
+
+ # Returns a given category, or nil
+ #
+ # TODO: Hash categories internally?
+ def category(name)
+ categories.each do |category|
+ return category if category.name == name
+ end
+
+ nil
+ end
+
+ # Returns the global USE flags described in this repositorie's use.desc file
+ #
+ # @return [Hash{String => String}] Hash of USE flags mapped to their description.
+ def global_useflags
+ @useflags ||= parse_useflags(File.join(@path, 'profiles', 'use.desc'))
+ end
+
+ # Returns the USE_EXPAND flags described in the repository
+ #
+ # @return [Hash{String => Hash{String => String}}] Hash of USE_EXPAND variables mapped to possible values mapped to their description.
+ def use_expand_flags
+ @use_expand_flags ||= parse_use_expand_flags
+ end
+
+ private
+ # Filters the subdirectories of the repository to find categories
+ #
+ # @return [Array] Category directories in this repository
+ def category_dirs
+ File.read(File.join(@path, 'profiles', 'categories')).lines.map {|line| line.strip}
+ end
+
+ def parse_use_expand_flags
+ flags = {}
+
+ Dir.glob(File.join(@path, 'profiles', 'desc', '*.desc')) do |desc_file|
+ flags[desc_file.split('/').last.gsub('.desc', '')] = parse_useflags(desc_file)
+ end
+
+ flags
+ end
+
+ def parse_useflags(file)
+ flags = {}
+
+ File.readlines(file).each do |line|
+ next if line =~ /^(|#.*)$/
+
+ flag, desc = line.strip.split(' - ', 2)
+ flags[flag] = desc
+ end
+
+ flags
+ end
+end \ No newline at end of file
diff --git a/lib/portage/repository/package.rb b/lib/portage/repository/package.rb
new file mode 100644
index 0000000..55c443f
--- /dev/null
+++ b/lib/portage/repository/package.rb
@@ -0,0 +1,59 @@
+class Portage::Repository::Package
+ attr_reader :category, :name, :path
+
+ # Creates a new Package model
+ #
+ # @param [String] path Path of the package base directory
+ def initialize(path)
+ unless File.directory? path
+ fail ArgumentError, "'#{path}' is not a directory, and thus can't be a package directory."
+ end
+
+ @path = path
+ path_parts = path.split '/'
+ @name = path_parts.last
+ @category = path_parts[-2]
+ end
+
+ # Renders the package name as 'cp' string (category + package)
+ #
+ # @return [String] CP string
+ def to_cp
+ "#{@category}/#{@name}"
+ end
+
+ # Returns the available ebuilds (versions) for this package *unsorted*
+ #
+ # @return [Array<Portage::Repository::Ebuild>] Available ebuilds
+ def ebuilds
+ @ebuilds ||= ebuild_files.map { |e| Portage::Repository::Ebuild.new(e) }
+ end
+
+ # Returns the available ebuilds sorted by their version string.
+ #
+ # @return [Array<Portage::Repository::Ebuild] Available ebuilds in a sorted array
+ def ebuilds_sorted
+ @ebuilds_sorted ||= ebuilds.sort { |a, b| Portage::Util::Versions.compare(a.version, b.version) }
+ end
+
+ def metadata
+ @metadata ||= Portage::Util::Metadata.new(File.join(@path, 'metadata.xml'))
+ end
+
+ def metadata_hash
+ Digest::MD5.hexdigest("#{metadata.hash}" + ebuilds.map(&:metadata_hash).join(' '))
+ end
+
+ def inspect
+ "#<Package '#{@name}' @category='#{@category}' @path='#{@path}'>"
+ end
+
+ private
+
+ # Filters the files of the package to find ebuilds
+ #
+ # @return [Array<String>] Ebuild files in this category
+ def ebuild_files
+ Dir.glob(File.join(@path, '*.ebuild'))
+ end
+end
diff --git a/lib/portage/util.rb b/lib/portage/util.rb
new file mode 100644
index 0000000..0c0fb3c
--- /dev/null
+++ b/lib/portage/util.rb
@@ -0,0 +1,2 @@
+module Portage::Util
+end \ No newline at end of file
diff --git a/lib/portage/util/atoms.rb b/lib/portage/util/atoms.rb
new file mode 100644
index 0000000..ce1ba81
--- /dev/null
+++ b/lib/portage/util/atoms.rb
@@ -0,0 +1,107 @@
+class Portage::Util::Atoms
+ class << self
+ # Parses an atom into its parts.
+ # TODO: This is very resilient to malformed version strings
+ #
+ # @param [String] str
+ # @return [Hash]
+ # @raise [Portage::Ebuild::InvalidAtomError]
+ def parse(str)
+ result = { prefix: nil, cmp: nil, category: nil, package: nil, version: nil, postfix: nil, slot: nil, subslot: nil }
+
+ if str.start_with? '~'
+ result[:prefix] = '~'
+ str = str[1..-1]
+ end
+
+ if str =~ /^(>|>=|=|<=|<)[A-Za-z0-9]/
+ result[:cmp] = $1
+ str = str[$1.length..-1]
+ end
+
+ if str =~ /^([A-Za-z0-9][A-Za-z0-9+_.-]+)\/([^:]*)(:.*)?$/
+ result[:category] = $1
+ result[:package] = $2
+ package_parts = $2.split('-')
+ result[:slot], result[:subslot] = $3[1..-1].split('/') if $3
+
+ revision = ''
+ if package_parts.last =~ /^r\d+$/
+ revision = '-%s' % package_parts.last
+ package_parts.pop
+ end
+
+ if package_parts.last =~ /^[0-9]/
+ ver = package_parts.last
+
+ if ver.last.end_with? '*'
+ result[:postfix] = '*'
+ ver = ver[0..-2]
+ end
+
+ result[:version] = ver + revision
+ result[:package] = package_parts[0..-2].join('-')
+ end
+
+ else
+ raise Portage::Ebuild::InvalidAtomError, "Cannot parse atom #{str}."
+ end
+
+ result
+ end
+
+ # Ascertains whether a version matches a given dependency atom.
+ # Package names are NOT considered.
+ #
+ # @param [String] atom Atom to match against
+ # @param [String] version Version that should match
+ # @return [Boolean] true if the version is matched by the atom
+ def matches?(atom, version, slot = '0')
+ _atom = parse(atom)
+
+ # 'foo-bar/baz', i.e. match all versions
+ return true if _atom[:slot].nil? and _atom[:cmp].nil? and _atom[:prefix].nil?
+
+ # Check for mismatched slots early
+ if _atom[:slot]
+ return false unless _atom[:slot] == slot
+
+ # No further filtering needed?
+ return true if _atom[:cmp].nil? and _atom[:version].nil? and _atom[:prefix].nil?
+ end
+
+ # Now, the slot matches, match the version
+ if _atom[:postfix] and _atom[:postfix].include? '*'
+ return version.match(_atom[:version].gsub(/\*$/, '.*'))
+ end
+
+ # Real version comparing starts now
+ _version = Portage::Util::Versions.parse(version)
+ _atom_version = Portage::Util::Versions.parse(_atom[:version])
+
+ # '~' Operator?
+ if _atom[:prefix] and _atom[:prefix].include? '~'
+ _cmp = _atom_version[:num] == _version[:num] &&
+ _atom_version[:alph] == _version[:alph] &&
+ _atom_version[:suffixes] == _version[:suffixes]
+ return _cmp
+ end
+
+ # Okay, let's compare.
+ _cmp = Portage::Util::Versions.compare(_atom[:version], version)
+
+ # version higher than atom
+ if _cmp == 0
+ return _atom[:cmp].include? '='
+ elsif _cmp == -1
+ return _atom[:cmp][0] == '>'
+ elsif _cmp == 1
+ return _atom[:cmp][0] == '<'
+ end
+
+ # This should technically not happen
+ false
+ end
+
+ end
+end
diff --git a/lib/portage/util/history.rb b/lib/portage/util/history.rb
new file mode 100644
index 0000000..13db8e5
--- /dev/null
+++ b/lib/portage/util/history.rb
@@ -0,0 +1,74 @@
+require 'time'
+
+class Portage::Util::History
+ class << self
+ def for(category, package, limit = 20)
+ return [] if KKULEOMI_DISABLE_GIT == true
+
+ files = "#{category}/#{package}/*.ebuild"
+ git = Kkuleomi::Util::Exec
+ .cmd(KKULEOMI_GIT)
+ .in(KKULEOMI_RUNTIME_PORTDIR)
+ .args(
+ 'log', '--name-status', '--no-merges', '--date=iso8601', "-n #{limit.to_i}",
+ "#{KKULEOMI_FIRST_COMMIT}..HEAD", files)
+ .run
+
+ raw_log, stderr, status = git.stdout, git.stderr, git.exit_status
+ fail "Cannot get git log: #{stderr}" unless status == 0
+
+ parse raw_log
+ end
+
+ private
+
+ def parse(raw_log)
+ log_items = []
+
+ raw_log.split("\n\ncommit ").each do |raw_commit|
+ commit_lines = raw_commit.lines
+
+ _id = commit_lines.shift.gsub('commit ', '').strip
+
+ commit_lines.shift =~ /^Author:\s+(.*) <([^>]*)>$/
+ _author = $1
+ _email = $2
+
+ _date = Time.parse(commit_lines.shift[/^Date:\s+(.*)$/, 1]).utc
+
+ commit_lines.shift
+ _raw_message = []
+ while (line = commit_lines.shift) != "\n"
+ _raw_message << line
+ end
+
+ _raw_files = commit_lines
+ _files = {added: [], modified: [], deleted: []}
+ _raw_files.each do |file|
+ mode, file = file.split "\t"
+ filename = file.strip.split('/').last
+
+ case mode
+ when 'M'
+ _files[:modified] << filename
+ when 'D'
+ _files[:deleted] << filename
+ when 'A'
+ _files[:added] << filename
+ end
+ end
+
+ log_items << {
+ id: _id,
+ author: _author,
+ email: _email,
+ date: _date,
+ message: _raw_message.map { |l| l.strip }.join("\n"),
+ files: _files
+ }
+ end
+
+ log_items
+ end
+ end
+end
diff --git a/lib/portage/util/mask.rb b/lib/portage/util/mask.rb
new file mode 100644
index 0000000..234a17a
--- /dev/null
+++ b/lib/portage/util/mask.rb
@@ -0,0 +1,28 @@
+class Portage::Util::Mask
+ attr_accessor :author, :date, :reason
+ attr_reader :atoms
+
+ def initialize(author, date, reason, atoms)
+ @author = author
+ @date = date
+ @reason = reason
+ @atoms = atoms
+ end
+
+ def add_atom(atom)
+ @atoms << atom
+ end
+
+ def to_s
+ "<Mask @author='#{@author}' @reason='#{@reason[0..50]}' @atoms=[#{@atoms.join ','}]>"
+ end
+
+ def to_hash
+ {
+ author: author,
+ date: date,
+ reason: reason,
+ atoms: atoms
+ }
+ end
+end
diff --git a/lib/portage/util/maskfile.rb b/lib/portage/util/maskfile.rb
new file mode 100644
index 0000000..44b9d89
--- /dev/null
+++ b/lib/portage/util/maskfile.rb
@@ -0,0 +1,43 @@
+# Provides low-level access to a mask file
+class Portage::Util::Maskfile
+ attr_reader :masks
+
+ def initialize(path)
+ @path = path
+ @masks = []
+ parse!
+ end
+
+ def parse!
+ File.read(@path).split("\n\n").each do |raw_mask|
+ comments = []
+ atoms = []
+
+ raw_mask.each_line do |line|
+ line.strip!
+
+ if line.start_with? '#'
+ comments << line
+ else
+ atoms << line unless line == ''
+ end
+ end
+
+ # Skip examples or other comment-only entries
+ next if atoms.empty?
+
+ author = nil
+ date = nil
+
+ if comments.first =~ /^#\s+(.*)\s+<([^>]+)>\s\(([^)]+)\)/
+ author = '%s <%s>' % [$1, $2]
+ date = $3
+ end
+
+ # Strip the newlines, we don't want to carry over the ASCII art
+ reason = comments[1..-1].map { |l| l.gsub(/^# /, '') }.join ' '
+
+ @masks << Portage::Util::Mask.new(author, date, reason, atoms)
+ end
+ end
+end
diff --git a/lib/portage/util/masks.rb b/lib/portage/util/masks.rb
new file mode 100644
index 0000000..08ec12a
--- /dev/null
+++ b/lib/portage/util/masks.rb
@@ -0,0 +1,105 @@
+module Portage
+ module Util
+ class Masks
+ class << self
+ # Updates the mask cache
+ def update!
+ mask_hash = {}
+ profiles_base_dir = File.join(KKULEOMI_PORTDIR, 'profiles')
+
+ add_global_masks(mask_hash, profiles_base_dir)
+ add_arch_masks(mask_hash, profiles_base_dir)
+
+ @masks = mask_hash
+ end
+
+ def masks
+ @masks || update!
+ end
+
+ # Filters all masks for masks applying to this ebuild
+ #
+ # @param [Portage::Repository::Ebuild] ebuild Ebuild model
+ def for(ebuild)
+ ebuild_masks = masks[ebuild.to_cp]
+ result = []
+ return result unless ebuild_masks
+
+ ebuild_masks.each do |mask|
+ matches = false
+
+ mask[:atoms].each do |atom|
+ matches = true if Portage::Util::Atoms.matches?(atom, ebuild.version, ebuild.metadata[:slot])
+ end
+
+ result << mask if matches
+ end
+
+ result
+ end
+
+ private
+
+ # Adds the globally set masks (profiles{,base}/package.mask) to the new mask hash
+ def add_global_masks(mask_hash, profiles_base_dir)
+ mask_files = [
+ File.join(profiles_base_dir, 'package.mask'),
+ File.join(profiles_base_dir, 'base', 'package.mask')
+ ]
+
+ mask_files.each do |mask_file|
+ Portage::Util::Maskfile.new(mask_file).masks.each do |mask|
+ add_mask(mask_hash, mask, '*')
+ end
+ end
+ end
+
+ # Adds all arch-specific masks to the new mask hash
+ def add_arch_masks(mask_hash, profiles_base_dir)
+ Dir.glob(File.join(profiles_base_dir, 'arch', '*', 'package.mask')) do |mask_file|
+ arch = mask_file.split('/')[-2]
+
+ Portage::Util::Maskfile.new(mask_file).masks.each do |mask|
+ add_mask(mask_hash, mask, arch)
+ end
+ end
+ end
+
+ # Adds a single mask entry
+ def add_mask(mask_list, mask, arch = '*')
+ mask_hash = mask.to_hash.merge(arches: [arch])
+
+ mask.atoms.each do |atom|
+ atom = Portage::Util::Atoms.parse(atom)
+ insert_or_append_mask(mask_list, atom, mask_hash)
+ end
+ rescue => e
+ Rails.logger.warn { "Parsing mask #{mask.inspect} on arch #{arch} failed: #{e.message}" }
+ end
+
+ def insert_or_append_mask(mask_list, atom, mask)
+ key = atom[:category] + '/' + atom[:package]
+
+ if mask_list.key? key
+ append_mask(mask_list, key, mask)
+ else
+ mask_list[key] = [mask]
+ end
+ end
+
+ def append_mask(mask_list, key, mask)
+ mask_list[key].each do |existing_mask|
+ next unless existing_mask[:reason] == mask[:reason]
+
+ if existing_mask[:arches] == ['*'] || mask[:arches] == ['*']
+ existing_mask[:arches] = ['*']
+ else
+ existing_mask[:arches] += mask[:arches]
+ existing_mask[:arches].uniq!
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/portage/util/metadata.rb b/lib/portage/util/metadata.rb
new file mode 100644
index 0000000..fd44041
--- /dev/null
+++ b/lib/portage/util/metadata.rb
@@ -0,0 +1,69 @@
+class Portage::Util::Metadata
+ def initialize(file)
+ @metadata = {}
+ @file = file
+
+ f = File.open(file)
+ parse! Nokogiri::XML(f)
+ f.close
+ end
+
+ def [](key)
+ @metadata[key]
+ end
+
+ def hash
+ Digest::MD5.file(@file).hexdigest
+ end
+
+ private
+
+ def parse!(xml)
+ # <herd>
+ @metadata[:herds] = xml.xpath('/pkgmetadata/herd').map(&:text)
+
+ # <maintainer>
+ @metadata[:maintainer] = []
+ xml.xpath('/pkgmetadata/maintainer').each do |maintainer_tag|
+ @metadata[:maintainer] << {
+ email: single_xpath(maintainer_tag, './email/text()'),
+ name: single_xpath(maintainer_tag, './name/text()'),
+ type: maintainer_tag['type'],
+ description: single_xpath(maintainer_tag, './description/text()'),
+ restrict: maintainer_tag['restrict']
+ }
+ end
+
+ # <use>/<flag>
+ @metadata[:use] = {}
+ xml.xpath('/pkgmetadata/use/flag').each do |flag_tag|
+ # inner_html as there are <pkg> and <cat> links
+ @metadata[:use][flag_tag['name']] = clean_xml_str(flag_tag.inner_html)
+ end
+
+ # <natural-name>
+ @metadata[:natural_name] = single_xpath(xml, '/pkgmetadata/natural-name/text()')
+
+ # <longdescription>
+ @metadata[:longdescription] = { en: nil }
+ xml.xpath('/pkgmetadata/longdescription').each do |desc_tag|
+ if desc_tag.has_attribute? 'lang'
+ @metadata[:longdescription][desc_tag['lang'].downcase.to_sym] = clean_xml_str(desc_tag.text)
+ else
+ @metadata[:longdescription][:en] = clean_xml_str(desc_tag.text)
+ end
+ end
+ end
+
+ def single_xpath(xml, path)
+ if (res = xml.xpath(path)).empty?
+ nil
+ else
+ res.to_s
+ end
+ end
+
+ def clean_xml_str(input)
+ input.strip.gsub(/\s+/, ' ')
+ end
+end
diff --git a/lib/portage/util/metadata_cache.rb b/lib/portage/util/metadata_cache.rb
new file mode 100644
index 0000000..945fc3a
--- /dev/null
+++ b/lib/portage/util/metadata_cache.rb
@@ -0,0 +1,72 @@
+class Portage::Util::MetadataCache
+ # Parses the metadata cache entries for the given ebuild
+ #
+ # @param [Portage::Repository::Ebuild] ebuild Ebuild to parse metadata for
+ def initialize(ebuild)
+ @file = File.join(ebuild.repo_root, 'metadata', 'md5-cache', ebuild.category, ebuild.to_pv)
+ cache_f = File.open(@file)
+ @metadata = parse(cache_f)
+ cache_f.close
+ end
+
+ def hash
+ Digest::MD5.file(@file).hexdigest
+ end
+
+ # Returns information from the portage metadata cache
+ # Values: :depend, :rdepend, :slot, :src_uri, :restrict, :homepage,
+ # :license, :description, :keywords, :iuse, :required_use,
+ # :pdepend, :provide, :eapi, :properties, :defined_phases
+ # as per portage/pym/portage/cache/metadata.py (database.auxdbkey_order)
+ #
+ # @param [String] key Requested information key as above
+ # @return [String, Array] Requested information
+ def [](key)
+ @metadata[key]
+ end
+
+ # Based on a function I wrote for GLSAMaker.
+ #
+ # @param [File] f File to read metadata cache from
+ # @return [Hash{Symbol => String, Array}] A hash with all available metadata (see above for keys)
+ def parse(f)
+ # noinspection RubyStringKeysInHashInspection
+ items = {
+ 'DEFINED_PHASES' => :defined_phases,
+ 'DEPEND' => :depend,
+ 'DESCRIPTION' => :description,
+ 'EAPI' => :eapi,
+ 'HOMEPAGE' => :homepage,
+ 'IUSE' => :iuse,
+ 'KEYWORDS' => :keywords,
+ 'LICENSE' => :license,
+ 'PDEPEND' => :pdepend,
+ 'PROPERTIES' => :properties,
+ 'RDEPEND' => :rdepend,
+ 'RESTRICT' => :restrict,
+ 'REQUIRED_USE' => :required_use,
+ 'SLOT' => :slot,
+ 'SRC_URI' => :src_uri
+ }
+
+ valid_keys = items.keys
+
+ # List of metadata items to split at space
+ split_keys = %w[ SRC_URI IUSE KEYWORDS PROPERTIES RESTRICT DEFINED_PHASES ]
+
+ r = Regexp.compile('^(\\w+)=([^\n]*)')
+ result = {}
+
+ while f.gets
+ if (match = r.match($_)) != nil and valid_keys.include? match[1]
+ if split_keys.include? match[1]
+ result[items[match[1]]] = match[2].split(' ')
+ else
+ result[items[match[1]]] = match[2]
+ end
+ end
+ end
+
+ result
+ end
+end
diff --git a/lib/portage/util/projects.rb b/lib/portage/util/projects.rb
new file mode 100644
index 0000000..595c6b5
--- /dev/null
+++ b/lib/portage/util/projects.rb
@@ -0,0 +1,93 @@
+require 'nokogiri'
+require 'net/http'
+require 'time'
+
+module Portage
+ module Util
+ class Projects
+ PROJECTS_XML = URI('https://api.gentoo.org/metastructure/projects.xml')
+
+ CACHE_DURATION = 3600
+ @instance_ts = Time.at(0)
+ @instance = nil
+
+ def self.cached_instance
+ if (Time.now - @instance_ts) > CACHE_DURATION
+ @instance = new
+ @instance_ts = Time.now
+ end
+
+ @instance
+ end
+
+ def initialize
+ @xml = Nokogiri::XML(Net::HTTP.get(PROJECTS_XML))
+ end
+
+ def projects
+ @xml.xpath('/projects/project/email/text()').map(&:to_s)
+ end
+
+ def project(project)
+ project_tag = @xml.xpath('/projects/project/email[text()="%s"]/..' % project).first
+ return nil if project_tag.nil?
+
+ project_hash = {
+ email: single_xpath(project_tag, './email/text()'),
+ name: single_xpath(project_tag, './name/text()'),
+ url: single_xpath(project_tag, './url/text()'),
+ description: single_xpath(project_tag, './description/text()'),
+ members: [],
+ subprojects: []
+ }
+
+ project_tag.xpath('./member').each do |member_tag|
+ project_hash[:members] << {
+ email: single_xpath(member_tag, './email/text()'),
+ name: single_xpath(member_tag, './name/text()'),
+ role: single_xpath(member_tag, './role/text()'),
+ is_lead: member_tag['is-lead'] == '1'
+ }
+ end
+
+ project_tag.xpath('./subproject').each do |subproject_tag|
+ project_hash[:subprojects] << {
+ ref: subproject_tag[:ref],
+ inherit_members: subproject_tag['inherit-members'] == '1'
+ }
+ end
+
+ project_hash
+ end
+
+ # This inherits one level down only
+ def inherited_members(project)
+ p = project(project)
+ return [] if p.nil?
+
+ members = {}
+ p[:members].each { |m| members[m[:email]] = m[:name] }
+
+ p[:subprojects].each do |subp|
+ next unless subp[:inherit_members]
+
+ project(subp[:ref])[:members].each { |m| members[m[:email]] = m[:name] }
+ end
+
+ result = []
+ members.each_pair { |k, v| result << { email: k, name: v } }
+ result
+ end
+
+ private
+
+ def single_xpath(xml, path)
+ if (res = xml.xpath(path)).empty?
+ nil
+ else
+ res.to_s
+ end
+ end
+ end
+ end
+end
diff --git a/lib/portage/util/versions.rb b/lib/portage/util/versions.rb
new file mode 100644
index 0000000..146d748
--- /dev/null
+++ b/lib/portage/util/versions.rb
@@ -0,0 +1,129 @@
+class Portage::Util::Versions
+ class << self
+ # Compares an two ebuild version strings with each other as per PMS.
+ #
+ # @param [String] a_ver
+ # @param [String] b_ver
+ # @return [Integer] -1 if b > a; 0 if a == b; 1 if b < a
+ def compare(a_ver, b_ver)
+ a = parse a_ver
+ b = parse b_ver
+
+ comparison_1 = compare_numbers(a, b)
+ return comparison_1 unless comparison_1 == 0
+
+ comparison_2 = compare_letters(a, b)
+ return comparison_2 unless comparison_2 == 0
+
+ comparison_3 = compare_suffixes(a, b)
+ return comparison_3 unless comparison_3 == 0
+
+ comparison_4 = compare_revisions(a, b)
+ return comparison_4 unless comparison_4 == 0
+
+ # Give up: they're equal
+ 0
+ end
+
+ # Parses a version string into its parts.
+ # TODO: This is very resilient to malformed version strings
+ #
+ # @param [String] str
+ # @return [Hash]
+ # @raise [Portage::Ebuild::InvalidVersionError]
+ def parse(str)
+ def number_conv(num)
+ if num.start_with? '0'
+ num
+ else
+ num.to_i
+ end
+ end
+
+ raw_parts = str.split(/[\._-]/)
+ result = { num: [], num_count: 0, alph: nil, suffixes: [], suffix_count: 0, revision: 0 }
+
+ raw_parts.each do |raw_part|
+ if raw_part.is_i?
+ result[:num] << number_conv(raw_part)
+ result[:num_count] += 1
+ elsif raw_part =~ /^(\d+)([a-z])$/
+ result[:num] << number_conv($1)
+ result[:num_count] += 1
+ result[:alph] = $2
+ elsif raw_part =~ /^(alpha|beta|pre|rc|p)(\d+)?$/
+ result[:suffixes] << [$1, $2 == nil ? nil : $2.to_i]
+ result[:suffix_count] += 1
+ elsif raw_part =~ /^r(\d+)$/
+ result[:revision] = $1.to_i
+ else
+ raise Portage::Ebuild::InvalidVersionError, "Unknown version component: #{raw_part}"
+ end
+ end
+
+ result
+ end
+
+ private
+ # Algorithm 2
+ def compare_numbers(a, b)
+ return 1 if a[:num].first.to_i > b[:num].first.to_i
+ return -1 if a[:num].first.to_i < b[:num].first.to_i
+
+ (0...[a[:num_count], b[:num_count]].min).each do |i|
+ # Algorithm 3
+ if a[:num][i].is_a? String or b[:num][i].is_a? String
+ cmp = a[:num][i].to_s <=> b[:num][i].to_s
+ return cmp unless cmp == 0
+ else
+ cmp = a[:num][i].to_i <=> b[:num][i].to_i
+ return cmp unless cmp == 0
+ end
+ end
+
+ return 1 if a[:num_count] > b[:num_count]
+ return -1 if a[:num_count] < b[:num_count]
+
+ 0
+ end
+
+ def compare_letters(a, b)
+ a_letter = a[:alph] || ''
+ b_letter = b[:alph] || ''
+
+ a_letter <=> b_letter
+ end
+
+ # Algorithm 5
+ def compare_suffixes(a, b)
+ suffix_order = %w[ alpha beta pre rc p ]
+
+ (0...[a[:suffix_count], b[:suffix_count]].min).each do |i|
+ # Algorithm 6
+ if a[:suffixes][i].first == b[:suffixes][i].first
+ suffix_cmp = (a[:suffixes][i].last || 0) <=> (b[:suffixes][i].last || 0)
+ return suffix_cmp unless suffix_cmp == 0
+ else
+ a_order = suffix_order.find_index a[:suffixes][i].first
+ b_order = suffix_order.find_index b[:suffixes][i].first
+
+ order_cmp = a_order <=> b_order
+ return order_cmp unless order_cmp == 0
+ end
+ end
+
+ if a[:suffix_count] > b[:suffix_count]
+ return a[:suffixes].last[0] == 'p' ? 1 : -1
+ elsif a[:suffix_count] < b[:suffix_count]
+ return b[:suffixes].last[0] == 'p' ? -1 : 1
+ end
+
+ 0
+ end
+
+ # Algorithm 7
+ def compare_revisions(a, b)
+ a[:revision] <=> b[:revision]
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/tasks/.keep b/lib/tasks/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/tasks/.keep
diff --git a/lib/tasks/kkuleomi.rake b/lib/tasks/kkuleomi.rake
new file mode 100644
index 0000000..9b8bca0
--- /dev/null
+++ b/lib/tasks/kkuleomi.rake
@@ -0,0 +1,53 @@
+namespace :kkuleomi do
+ namespace :index do
+ desc '(Re-)Initializes the ElasticSearch index'
+ task init: :environment do
+ Kkuleomi::Store.create_index true
+ end
+ end
+
+ namespace :update do
+ desc 'Updates all data'
+ task all: :environment do
+ run_update(false)
+ end
+
+ desc 'Update global USE and USE_EXPAND flags'
+ task use: :environment do
+ UseflagsUpdateJob.perform_later
+ end
+
+ desc 'Update internal mask cache in the delayed job runner process'
+ task masks: :environment do
+ MasksUpdateJob.perform_later
+ end
+ end
+
+ namespace :seed do
+ desc 'Initially seeds all data'
+ task all: :environment do
+ run_update(true)
+ end
+ end
+end
+
+def run_update(no_change_objects)
+ initialize_caches
+
+ fail 'Invalid work dir!' unless File.directory? KKULEOMI_PORTDIR
+ repo = Portage::Repository::Model.new KKULEOMI_PORTDIR
+
+ options = {
+ suppress_change_objects: no_change_objects
+ }
+
+ Rails.cache.write(KK_CACHE_LAST_IMPORT, Time.now)
+ repo.categories.each do |category|
+ CategoryUpdateJob.perform_later(category.path, options)
+ end
+end
+
+def initialize_caches
+ MasksUpdateJob.perform_later
+ UseflagsUpdateJob.perform_later
+end
diff --git a/log/.keep b/log/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/log/.keep
diff --git a/public/404.html b/public/404.html
new file mode 100644
index 0000000..b612547
--- /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 0000000..a21f82b
--- /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 0000000..061abc5
--- /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 0000000..e69de29
--- /dev/null
+++ b/public/favicon.ico
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..ba47d79
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,9 @@
+User-agent: *
+Disallow: /packages/search
+Disallow: /packages/suggest
+Disallow: /categories/search
+Disallow: /categories/suggest
+Disallow: /useflags/suggest
+
+User-agent: AhrefsBot
+Disallow: /
diff --git a/test/controllers/.keep b/test/controllers/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/controllers/.keep
diff --git a/test/controllers/about_controller_test.rb b/test/controllers/about_controller_test.rb
new file mode 100644
index 0000000..da08918
--- /dev/null
+++ b/test/controllers/about_controller_test.rb
@@ -0,0 +1,14 @@
+require 'test_helper'
+
+class AboutControllerTest < ActionController::TestCase
+ test "should get feedback" do
+ get :feedback
+ assert_response :success
+ end
+
+ test "should get index" do
+ get :index
+ assert_response :success
+ end
+
+end
diff --git a/test/controllers/arches_controller_test.rb b/test/controllers/arches_controller_test.rb
new file mode 100644
index 0000000..4846b5e
--- /dev/null
+++ b/test/controllers/arches_controller_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class ArchesControllerTest < ActionController::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/controllers/categories_controller_test.rb b/test/controllers/categories_controller_test.rb
new file mode 100644
index 0000000..d74df38
--- /dev/null
+++ b/test/controllers/categories_controller_test.rb
@@ -0,0 +1,49 @@
+require 'test_helper'
+
+class CategoriesControllerTest < ActionController::TestCase
+ setup do
+ @category = categories(:one)
+ end
+
+ test "should get index" do
+ get :index
+ assert_response :success
+ assert_not_nil assigns(:categories)
+ end
+
+ test "should get new" do
+ get :new
+ assert_response :success
+ end
+
+ test "should create category" do
+ assert_difference('Category.count') do
+ post :create, category: { }
+ end
+
+ assert_redirected_to category_path(assigns(:category))
+ end
+
+ test "should show category" do
+ get :show, id: @category
+ assert_response :success
+ end
+
+ test "should get edit" do
+ get :edit, id: @category
+ assert_response :success
+ end
+
+ test "should update category" do
+ patch :update, id: @category, category: { }
+ assert_redirected_to category_path(assigns(:category))
+ end
+
+ test "should destroy category" do
+ assert_difference('Category.count', -1) do
+ delete :destroy, id: @category
+ end
+
+ assert_redirected_to categories_path
+ end
+end
diff --git a/test/controllers/index_controller_test.rb b/test/controllers/index_controller_test.rb
new file mode 100644
index 0000000..a12b212
--- /dev/null
+++ b/test/controllers/index_controller_test.rb
@@ -0,0 +1,9 @@
+require 'test_helper'
+
+class IndexControllerTest < ActionController::TestCase
+ test "should get index" do
+ get :index
+ assert_response :success
+ end
+
+end
diff --git a/test/controllers/packages_controller_test.rb b/test/controllers/packages_controller_test.rb
new file mode 100644
index 0000000..736532c
--- /dev/null
+++ b/test/controllers/packages_controller_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class PackagesControllerTest < ActionController::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/controllers/useflags_controller_test.rb b/test/controllers/useflags_controller_test.rb
new file mode 100644
index 0000000..aa9e42d
--- /dev/null
+++ b/test/controllers/useflags_controller_test.rb
@@ -0,0 +1,19 @@
+require 'test_helper'
+
+class UseflagsControllerTest < ActionController::TestCase
+ test "should get index" do
+ get :index
+ assert_response :success
+ end
+
+ test "should get show" do
+ get :show
+ assert_response :success
+ end
+
+ test "should get search" do
+ get :search
+ assert_response :success
+ end
+
+end
diff --git a/test/fixtures/.keep b/test/fixtures/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fixtures/.keep
diff --git a/test/helpers/.keep b/test/helpers/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/helpers/.keep
diff --git a/test/integration/.keep b/test/integration/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/integration/.keep
diff --git a/test/jobs/category_update_job_test.rb b/test/jobs/category_update_job_test.rb
new file mode 100644
index 0000000..9b9e877
--- /dev/null
+++ b/test/jobs/category_update_job_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class CategoryUpdateJobTest < ActiveJob::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/jobs/masks_update_job_test.rb b/test/jobs/masks_update_job_test.rb
new file mode 100644
index 0000000..539539f
--- /dev/null
+++ b/test/jobs/masks_update_job_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class MasksUpdateJobTest < ActiveJob::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/jobs/package_removal_job_test.rb b/test/jobs/package_removal_job_test.rb
new file mode 100644
index 0000000..e972425
--- /dev/null
+++ b/test/jobs/package_removal_job_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class PackageRemovalJobTest < ActiveJob::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/jobs/package_update_job_test.rb b/test/jobs/package_update_job_test.rb
new file mode 100644
index 0000000..429907b
--- /dev/null
+++ b/test/jobs/package_update_job_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class PackageUpdateJobTest < ActiveJob::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/jobs/record_change_job_test.rb b/test/jobs/record_change_job_test.rb
new file mode 100644
index 0000000..74b58a2
--- /dev/null
+++ b/test/jobs/record_change_job_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class RecordChangeJobTest < ActiveJob::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/jobs/useflags_update_job_test.rb b/test/jobs/useflags_update_job_test.rb
new file mode 100644
index 0000000..54162cb
--- /dev/null
+++ b/test/jobs/useflags_update_job_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class UseflagsUpdateJobTest < ActiveJob::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/lib/portage/util/atoms_test.rb b/test/lib/portage/util/atoms_test.rb
new file mode 100644
index 0000000..97ef092
--- /dev/null
+++ b/test/lib/portage/util/atoms_test.rb
@@ -0,0 +1,70 @@
+require 'test_helper'
+
+class AtomsTest < ActiveSupport::TestCase
+ def matches?(atom, version, slot = '0')
+ Portage::Util::Atoms.matches?(atom, version, slot)
+ end
+
+ def parse(atom)
+ Portage::Util::Atoms.parse(atom)
+ end
+
+ test 'parsing' do
+ assert_equal({
+ prefix: nil,
+ cmp: '>=',
+ category: 'games-emulation',
+ package: 'mupen64plus',
+ version: '2-r2',
+ postfix: nil,
+ slot: nil,
+ subslot: nil
+ },
+ parse('>=games-emulation/mupen64plus-2-r2'))
+ end
+
+ test 'matching plain versions' do
+ assert matches?('dev-lang/ruby', '0.0.9')
+ assert matches?('dev-lang/ruby', '1.2.3')
+ assert matches?('dev-lang/ruby', '0.0.9', 'slotfoo')
+ end
+
+ test 'version wildcards' do
+ assert matches?('=dev-lang/ruby-2*', '2.1.2')
+ assert_not matches?('=dev-lang/ruby-2*', '3.3')
+
+ # Known as not working. But do we need this?
+ # assert matches?('>=dev-lang/ruby-2*', '3.3')
+ end
+
+ test 'revision wildcards' do
+ assert matches?('~dev-lang/ruby-2.0.4', '2.0.4-r0')
+ assert matches?('~dev-lang/ruby-2.0.4', '2.0.4-r12')
+ assert matches?('~dev-lang/ruby-2.0.4', '2.0.4')
+ assert_not matches?('~dev-lang/ruby-2.0.4', '2.0.5')
+ assert_not matches?('~dev-lang/ruby-2.0.4', '2.0')
+ end
+
+ test 'plain slots' do
+ assert matches?('dev-lang/ruby:3', '1.2.3', '3')
+ assert_not matches?('dev-lang/ruby:3', '1.2.3')
+ assert_not matches?('dev-lang/ruby:3', '1.2.3', '4')
+
+ assert matches?('dev-lang/ruby', '1.2.3', '4')
+ end
+
+ test 'slots and other stuff' do
+
+ end
+
+ test 'good ol comparing' do
+ assert matches?('=dev-lang/ruby-2.0.4', '2.0.4')
+ assert matches?('>=dev-lang/ruby-2.0.4', '2.0.4')
+ assert matches?('<=dev-lang/ruby-2.0.4', '2.0.4')
+
+ assert_not matches?('=dev-lang/ruby-2.0.4', '2')
+ assert_not matches?('<=dev-lang/ruby-2.0.4', '3')
+ assert_not matches?('>=dev-lang/ruby-2.0.4', '1')
+ end
+
+end \ No newline at end of file
diff --git a/test/lib/portage/util/versions_test.rb b/test/lib/portage/util/versions_test.rb
new file mode 100644
index 0000000..386e5a7
--- /dev/null
+++ b/test/lib/portage/util/versions_test.rb
@@ -0,0 +1,72 @@
+require 'test_helper'
+
+class VersionsTest < ActiveSupport::TestCase
+ def compare(a, b)
+ Portage::Util::Versions.compare(a, b)
+ end
+
+ test 'parsing versions' do
+ ver1 = '1.2.3z_p2-r0'
+ res1 = {
+ num: [1, 2, 3],
+ num_count: 3,
+ alph: 'z',
+ suffixes: [['p', 2]],
+ suffix_count: 1,
+ revision: 0
+ }
+
+ assert_equal(res1, Portage::Util::Versions.parse(ver1))
+ end
+
+ test 'parsing malformed versions' do
+ assert_raises Portage::Ebuild::InvalidVersionError do
+ Portage::Util::Versions.parse('1.2-ra')
+ end
+ end
+
+ test 'comparing numeric components' do
+ assert_equal -1, compare('1.0', '2.0')
+ assert_equal 1, compare('2', '1')
+ assert_equal 0, compare('2.2', '2.2')
+
+ assert_equal 0, compare('2.2.2', '2.2.2')
+ assert_equal 1, compare('2.2.3', '2.2.2')
+ assert_equal -1, compare('2.2', '2.2.2')
+ end
+
+ test 'comparing letter suffixes' do
+ assert_equal -1, compare('1.0a', '2.0b')
+ assert_equal 1, compare('2a', '1b')
+ assert_equal 0, compare('2.2a', '2.2a')
+
+ assert_equal -1, compare('2.2a', '2.2b')
+ assert_equal 1, compare('2.2e', '2.2b')
+ end
+
+ test 'comparing suffixes' do
+ assert_equal 0, compare('1_alpha', '1_alpha')
+ assert_equal -1, compare('1_alpha', '1_alpha1')
+ assert_equal 1, compare('1_alpha2', '1_alpha1')
+
+ assert_equal 0, compare('1_beta12', '1_beta12')
+ assert_equal -1, compare('1_alpha34', '1_p')
+
+ assert_equal -1, compare('1_alpha', '1')
+ assert_equal 1, compare('1', '1_beta')
+ assert_equal 1, compare('1', '1_pre')
+ assert_equal -1, compare('1', '1_p42')
+
+ assert_equal 0, compare('1_alpha_alpha', '1_alpha_alpha')
+ assert_equal -1, compare('1_alpha_alpha', '1_alpha_beta')
+ assert_equal 1, compare('1_p12_alpha', '1_alpha_beta')
+ assert_equal 1, compare('1_alpha_beta1', '1_alpha_beta')
+ end
+
+ test 'comparing revisions' do
+ assert_equal 0, compare('1-r1', '1-r1')
+ assert_equal 0, compare('1', '1-r0')
+ assert_equal 1, compare('1-r2', '1-r1')
+ assert_equal -1, compare('1', '1-r1')
+ end
+end
diff --git a/test/mailers/.keep b/test/mailers/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/mailers/.keep
diff --git a/test/mailers/feedback_mailer_test.rb b/test/mailers/feedback_mailer_test.rb
new file mode 100644
index 0000000..5d661b7
--- /dev/null
+++ b/test/mailers/feedback_mailer_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class FeedbackMailerTest < ActionMailer::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/mailers/previews/feedback_mailer_preview.rb b/test/mailers/previews/feedback_mailer_preview.rb
new file mode 100644
index 0000000..9fcbe21
--- /dev/null
+++ b/test/mailers/previews/feedback_mailer_preview.rb
@@ -0,0 +1,4 @@
+# Preview all emails at http://localhost:3000/rails/mailers/feedback_mailer
+class FeedbackMailerPreview < ActionMailer::Preview
+
+end
diff --git a/test/models/.keep b/test/models/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/models/.keep
diff --git a/test/test_helper.rb b/test/test_helper.rb
new file mode 100644
index 0000000..9962fe4
--- /dev/null
+++ b/test/test_helper.rb
@@ -0,0 +1,10 @@
+ENV['RAILS_ENV'] ||= 'test'
+require File.expand_path('../../config/environment', __FILE__)
+require 'rails/test_help'
+
+class ActiveSupport::TestCase
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
+ # fixtures :all
+
+ # Add more helper methods to be used by all tests here...
+end \ No newline at end of file
diff --git a/vendor/assets/fonts/octicons.eot b/vendor/assets/fonts/octicons.eot
new file mode 100755
index 0000000..2bf20bc
--- /dev/null
+++ b/vendor/assets/fonts/octicons.eot
Binary files differ
diff --git a/vendor/assets/fonts/octicons.svg b/vendor/assets/fonts/octicons.svg
new file mode 100755
index 0000000..d932988
--- /dev/null
+++ b/vendor/assets/fonts/octicons.svg
@@ -0,0 +1,183 @@
+<?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>
+(c) 2012-2015 GitHub
+
+When using the GitHub logos, be sure to follow the GitHub logo guidelines (https://github.com/logos)
+
+Font License: SIL OFL 1.1 (http://scripts.sil.org/OFL)
+Applies to all font files
+
+Code License: MIT (http://choosealicense.com/licenses/mit/)
+Applies to all other files
+</metadata>
+<defs>
+<font id="octicons" horiz-adv-x="1024" >
+<font-face font-family="octicons" font-weight="400" font-stretch="normal" units-per-em="1024" ascent="832" descent="-192" />
+<missing-glyph d="M512 832C229.25 832 0 602.75 0 320c0-226.25 146.688-418.125 350.156-485.812 25.594-4.688 34.938 11.125 34.938 24.625 0 12.188-0.469 52.562-0.719 95.312C242-76.81200000000001 211.906 14.5 211.906 14.5c-23.312 59.125-56.844 74.875-56.844 74.875-46.531 31.75 3.53 31.125 3.53 31.125 51.406-3.562 78.47-52.75 78.47-52.75 45.688-78.25 119.875-55.625 149-42.5 4.654 33 17.904 55.625 32.5 68.375C304.906 106.56200000000001 185.344 150.5 185.344 346.688c0 55.938 19.969 101.562 52.656 137.406-5.219 13-22.844 65.094 5.062 135.562 0 0 42.938 13.75 140.812-52.5 40.812 11.406 84.594 17.031 128.125 17.219 43.5-0.188 87.312-5.875 128.188-17.281 97.688 66.312 140.688 52.5 140.688 52.5 28-70.531 10.375-122.562 5.125-135.5 32.812-35.844 52.625-81.469 52.625-137.406 0-196.688-119.75-240-233.812-252.688 18.438-15.875 34.75-47 34.75-94.75 0-68.438-0.688-123.625-0.688-140.5 0-13.625 9.312-29.562 35.25-24.562C877.438-98 1024 93.875 1024 320 1024 602.75 794.75 832 512 832z" horiz-adv-x="1024" />
+<glyph glyph-name="alert" unicode="&#xf02d;" d="M1005.854 31.753000000000043l-438.286 767C556.173 818.694 534.967 831 512 831s-44.173-12.306-55.567-32.247l-438.286-767c-11.319-19.809-11.238-44.144 0.213-63.876C29.811-51.85500000000002 50.899-64 73.714-64h876.572c22.814 0 43.903 12.145 55.354 31.877S1017.173 11.94399999999996 1005.854 31.753000000000043zM576 64H448V192h128V64zM576 256H448V512h128V256z" horiz-adv-x="1024" />
+<glyph glyph-name="arrow-down" unicode="&#xf03f;" d="M448 384V640H192v-256H0l320-384 320 384H448z" horiz-adv-x="640" />
+<glyph glyph-name="arrow-left" unicode="&#xf040;" d="M384 448V640L0 320l384-320V192h256V448H384z" horiz-adv-x="640" />
+<glyph glyph-name="arrow-right" unicode="&#xf03e;" d="M640 320L256 640v-192H0v-256h256v-192L640 320z" horiz-adv-x="640" />
+<glyph glyph-name="arrow-small-down" unicode="&#xf0a0;" d="M256 384V512H128v-128H0l192-256 192 256H256z" horiz-adv-x="384" />
+<glyph glyph-name="arrow-small-left" unicode="&#xf0a1;" d="M256 384V512L0 320l256-192V256h128V384H256z" horiz-adv-x="384" />
+<glyph glyph-name="arrow-small-right" unicode="&#xf071;" d="M384 320L128 512v-128H0v-128h128v-128L384 320z" horiz-adv-x="384" />
+<glyph glyph-name="arrow-small-up" unicode="&#xf09f;" d="M192 512L0 256h128v-128h128V256h128L192 512z" horiz-adv-x="384" />
+<glyph glyph-name="arrow-up" unicode="&#xf03d;" d="M320 640L0 256h192v-256h256V256h192L320 640z" horiz-adv-x="640" />
+<glyph glyph-name="beaker" unicode="&#xf0dd;" d="M920-102L704 384V640h64v64H192v-64h64v-256L40-102c-19-42 12-90 58-90h764c46 0 77 48 58 90zM240 192l80 192V640h320v-256l80-192H240z m272 128h64v-64h-64v64z m-64 64h-64v64h64v-64z m0 192h64v-64h-64v64z m0 192h-64V832h64v-64z" horiz-adv-x="1024" />
+<glyph glyph-name="bell" unicode="&#xf0de;" d="M896 64v-64H0v64l47 37c49 49 52 163 76 283 49 241 261 320 261 320 0 35 29 64 64 64s64-29 64-64c0 0 217-79 266-320 24-120 27-234 76-283l42-37z m-448-256c71 0 128 57 128 128H320c0-71 57-128 128-128z" horiz-adv-x="896" />
+<glyph glyph-name="book" unicode="&#xf007;" d="M128 512h256v-64H128v64z m0-192h256v64H128v-64z m0-128h256v64H128v-64z m704 320H576v-64h256v64z m0-128H576v-64h256v64z m0-128H576v-64h256v64z m128 384v-576c0-35-29-64-64-64H544l-64-64-64 64H64c-35 0-64 29-64 64V640c0 35 29 64 64 64h352l64-64 64 64h352c35 0 64-29 64-64z m-512-32l-32 32H64v-576h384V608z m448 32H544l-32-32v-544h384V640z" horiz-adv-x="1024" />
+<glyph glyph-name="bookmark" unicode="&#xf07b;" d="M0-64l192 128 192-128V640c0 35-29 64-64 64H64c-35 0-64-29-64-64v-704z m72 580l88 1 27 83c3 9 7 9 10 0l27-83 88-1c9 0 11-3 4-9l-72-52 28-83c2-9-1-11-8-7l-72 52-72-52c-7-4-10-2-8 7l28 83-72 52c-7 6-5 9 4 9z" horiz-adv-x="384" />
+<glyph glyph-name="briefcase" unicode="&#xf0d3;" d="M576 576v64c0 35-29 64-64 64H384c-35 0-64-29-64-64v-64H64c-35 0-64-29-64-64v-512c0-35 29-64 64-64h768c35 0 64 29 64 64V512c0 35-29 64-64 64H576z m-192 64h128v-64H384v64z m448-384H512v-64H384v64H64V512h64v-192h640V512h64v-256z" horiz-adv-x="896" />
+<glyph glyph-name="broadcast" unicode="&#xf048;" d="M576 256h-64c35 0 64 29 64 64v64c0 35-29 64-64 64h-64c-35 0-64-29-64-64v-64c0-35 29-64 64-64h-64c-35 0-64-29-64-64v-128h64v-192c0-35 29-64 64-64h64c35 0 64 29 64 64V64h64V192c0 35-29 64-64 64zM448 384h64v-64h-64v64z m128-256h-64v-256h-64V128h-64v64h192v-64z m134 224c0 127-103 230-230 230S250 479 250 352c0-18 2-35 6-52v-127c-39 49-64 111-64 179 0 159 129 288 288 288s288-129 288-288c0-68-25-130-64-179V300c4 17 6 34 6 52z m250 0c0-184-104-344-256-424v67c119 74 198 206 198 357 0 233-189 422-422 422S58 585 58 352c0-151 79-283 198-357v-67C104 8 0 168 0 352 0 617 215 832 480 832s480-215 480-480z" horiz-adv-x="1024" />
+<glyph glyph-name="browser" unicode="&#xf0c5;" d="M320 640h64v-64h-64V640zM192 640h64v-64h-64V640zM64 640h64v-64H64V640zM832 0H64V512h768V0zM832 576H448v64h384V576zM896 640c0 35.35-28.65 64-64 64H64c-35.35 0-64-28.65-64-64v-640c0-35.35 28.65-64 64-64h768c35.35 0 64 28.65 64 64V640z" horiz-adv-x="896" />
+<glyph glyph-name="bug" unicode="&#xf091;" d="M704 192h192v64H704v64l203 66-22 60-181-62v64c0 35-29 64-64 64v64c0 31-23 56-53 62l66 66h115V768H627L499 640h-38L333 768H192v-64h115l66-66c-30-6-53-31-53-62v-64c-35 0-64-29-64-64v-64L75 446l-22-60 203-66v-64H64v-64h192v-64L53 62l22-60 181 62v-64c0-35 29-64 64-64h64l64 64V448h64v-448l64-64h64c35 0 64 29 64 64v64l181-62 22 60-203 66v64zM576 512H384v64h192v-64z" horiz-adv-x="1024" />
+<glyph glyph-name="calendar" unicode="&#xf068;" d="M768 704h-64v-96c0-18-14-32-32-32H544c-18 0-32 14-32 32v96H320v-96c0-18-14-32-32-32H160c-18 0-32 14-32 32v96H64c-35 0-64-29-64-64v-704c0-35 29-64 64-64h704c35 0 64 29 64 64V640c0 35-29 64-64 64z m0-768H64V512h704v-576zM256 640h-64V768h64v-128z m384 0h-64V768h64v-128zM320 384h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64zM192 256h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64zM192 128h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64zM192 0h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64z m128 0h-64v64h64v-64z" horiz-adv-x="896" />
+<glyph glyph-name="check" unicode="&#xf03a;" d="M768 512L256 0 0 256l96 96 160-160 416 416 96-96z" horiz-adv-x="768" />
+<glyph glyph-name="checklist" unicode="&#xf076;" d="M208 166c1 21 10 42 25 56l64 60c16 15 35 22 55 22s41-8 57-23l39-40 128 128V640c0 35-29 64-64 64H64c-35 0-64-29-64-64v-576c0-35 29-64 64-64h272L231 108c-15 16-23 36-23 58z m-16 474h320v-64H192v64z m-64-192H64v64h64v-64z m0 128H64v64h64v-64z m64-64h320v-64H192v64z m544-224L448 0 288 164l64 60 96-96 224 224 64-64z" horiz-adv-x="768" />
+<glyph glyph-name="chevron-down" unicode="&#xf0a3;" d="M320 128L0 448l96 96 224-240 224 240 96-96-320-320z" horiz-adv-x="640" />
+<glyph glyph-name="chevron-left" unicode="&#xf0a4;" d="M352 640l96-96-240-224 240-224-96-96L32 320l320 320z" horiz-adv-x="512" />
+<glyph glyph-name="chevron-right" unicode="&#xf078;" d="M480 320L160 0l-96 96 240 224L64 544l96 96 320-320z" horiz-adv-x="512" />
+<glyph glyph-name="chevron-up" unicode="&#xf0a2;" d="M640 256l-96-96-224 240L96 160 0 256l320 320 320-320z" horiz-adv-x="640" />
+<glyph glyph-name="circle-slash" unicode="&#xf084;" d="M448 768C201 768 0 567 0 320s201-448 448-448 448 201 448 448S695 768 448 768z m0-83c83 0 160-28 222-75L158 98c-47 62-75 139-75 222 0 201 164 365 365 365z m0-730c-83 0-160 28-222 75l512 512c47-62 75-139 75-222 0-201-164-365-365-365z" horiz-adv-x="896" />
+<glyph glyph-name="circuit-board" unicode="&#xf0d6;" d="M192 512c0 35 29 64 64 64s64-29 64-64-29-64-64-64-64 29-64 64z m512 0c0 35-29 64-64 64s-64-29-64-64 29-64 64-64 64 29 64 64z m0-384c0 35-29 64-64 64s-64-29-64-64 29-64 64-64 64 29 64 64zM832 768H320v-139c23-12 41-30 53-53h150c27 50 85 82 150 67 48-12 87-51 98-99 20-88-46-166-131-166-51 0-95 28-117 70H373c-27-51-85-82-150-66-47 11-86 50-97 97-16 65 15 123 66 150V768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64l320 320h139c27 50 85 82 150 67 48-12 87-51 98-99 20-88-46-166-131-166-51 0-95 28-117 70h-75L256-128h576c35 0 64 29 64 64V704c0 35-29 64-64 64z" horiz-adv-x="896" />
+<glyph glyph-name="clippy" unicode="&#xf035;" d="M128 64h256v-64H128v64z m320 384H128v-64h320v64z m128-192V384L384 192l192-192V128h320V256H576z m-288 64H128v-64h160v64zM128 128h160v64H128v-64z m576-64h64v-128c-1-18-7-33-19-45s-27-18-45-19H64c-35 0-64 29-64 64V640c0 35 29 64 64 64h192C256 775 313 832 384 832s128-57 128-128h192c35 0 64-29 64-64v-320h-64V512H64v-576h640V64zM128 576h512c0 35-29 64-64 64h-64c-35 0-64 29-64 64s-29 64-64 64-64-29-64-64-29-64-64-64h-64c-35 0-64-29-64-64z" horiz-adv-x="896" />
+<glyph glyph-name="clock" unicode="&#xf046;" d="M512 320h192v-128H448c-35 0-64 29-64 64V576h128v-256z m-64 365c201 0 365-164 365-365S649-45 448-45 83 119 83 320s164 365 365 365m0 83C201 768 0 567 0 320s201-448 448-448 448 201 448 448S695 768 448 768z" horiz-adv-x="896" />
+<glyph glyph-name="cloud-download" unicode="&#xf00b;" d="M576 0h128l-192-192-192 192h128V320h128v-320z m192 512c0 28-58 192-288 192-155 0-288-123-288-256C65 448 0 351 0 256c0-98 64-192 192-192 28 0 170 0 192 0v83H192C88 147 83 238 83 256c0 11 3 109 109 109h83v83c0 89 100 173 205 173 163 0 200-99 205-115v-77h83c52 0 173-14 173-141 0-134-144-141-173-141H640v-83c24 0 127 0 128 0 133 0 256 74 256 224 0 156-123 224-256 224z" horiz-adv-x="1024" />
+<glyph glyph-name="cloud-upload" unicode="&#xf00c;" d="M448 256H320l192 192 192-192H576v-320H448V256z m320 256c0 28-58 192-288 192-155 0-288-123-288-256C65 448 0 351 0 256c0-98 64-192 192-192 28 0 170 0 192 0v83H192C88 147 83 238 83 256c0 11 3 109 109 109h83v83c0 89 100 173 205 173 163 0 200-99 205-115v-77h83c52 0 173-14 173-141 0-134-144-141-173-141H640v-83c24 0 127 0 128 0 133 0 256 74 256 224 0 156-123 224-256 224z" horiz-adv-x="1024" />
+<glyph glyph-name="code" unicode="&#xf05f;" d="M608 640l-96-96 224-224L512 96l96-96 288 320L608 640zM288 640L0 320l288-320 96 96L160 320l224 224L288 640z" horiz-adv-x="896" />
+<glyph glyph-name="color-mode" unicode="&#xf065;" d="M704 704H64c-35 0-64-29-64-64v-640c0-35 29-64 64-64h640c35 0 64 29 64 64V640c0 35-29 64-64 64zM64 0V640h640L64 0z" horiz-adv-x="768" />
+<glyph glyph-name="comment" unicode="&#xf02b;" d="M832 704H64c-35 0-64-29-64-64v-512c0-35 29-64 64-64h128v-224l224 224h416c35 0 64 29 64 64V640c0 35-29 64-64 64z m0-576H384L256 0V128H64V640h768v-512z" horiz-adv-x="896" />
+<glyph glyph-name="comment-discussion" unicode="&#xf04f;" d="M256 256c0-35 29-64 64-64h256v-64c0-35-29-64-64-64H320L128-128V64H64c-35 0-64 29-64 64V448c0 35 29 64 64 64h192v-256z m640 448H384c-35 0-64-29-64-64v-320c0-35 29-64 64-64h256l192-192V256h64c35 0 64 29 64 64V640c0 35-29 64-64 64z" horiz-adv-x="1024" />
+<glyph glyph-name="credit-card" unicode="&#xf045;" d="M768 256H128v64h640v-64z m256 384v-576c0-35-29-64-64-64H64c-35 0-64 29-64 64V640c0 35 29 64 64 64h896c35 0 64-29 64-64z m-64-192H64v-384h896V448z m0 192H64v-64h896v64zM384 192H128v-64h256v64z" horiz-adv-x="1024" />
+<glyph glyph-name="dash" unicode="&#xf0ca;" d="M0 384v-128h512V384H0z" horiz-adv-x="512" />
+<glyph glyph-name="dashboard" unicode="&#xf07d;" d="M512 512h-64v64h64v-64z m256-192h-64v-64h64v64zM320 512h-64v-64h64v64z m-64-192h-64v-64h64v64z m704 352l-32 32-416-320c-4 1-64 0-64 0-35 0-64-29-64-64v-64c0-35 29-64 64-64h64c35 0 64 29 64 64v59l384 357zM858 410c12-39 19-80 19-122 0-219-178-397-397-397S83 69 83 288s178 397 397 397c77 0 148-22 209-60l60 60c-76 52-169 83-269 83C215 768 0 553 0 288s215-480 480-480 480 215 480 480c0 66-13 129-38 186l-64-64z" horiz-adv-x="1024" />
+<glyph glyph-name="database" unicode="&#xf096;" d="M384-128C171.969-128 0-70.625 0 0c0 38.625 0 80.875 0 128 0 11.125 5.562 21.688 13.562 32C56.375 104.875 205.25 64 384 64s327.625 40.875 370.438 96c8-10.312 13.562-20.875 13.562-32 0-37.062 0-76.375 0-128C768-70.625 596-128 384-128zM384 128C171.969 128 0 185.375 0 256c0 38.656 0 80.844 0 128 0 6.781 2.562 13.375 6 19.906l0 0C7.938 408 10.5 412.031 13.562 416 56.375 360.906 205.25 320 384 320s327.625 40.906 370.438 96c3.062-3.969 5.625-8 7.562-12.094l0 0c3.438-6.531 6-13.125 6-19.906 0-37.062 0-76.344 0-128C768 185.375 596 128 384 128zM384 384C171.969 384 0 441.344 0 512c0 20.219 0 41.594 0 64 0 20.344 0 41.469 0 64C0 710.656 171.969 768 384 768c212 0 384-57.344 384-128 0-19.969 0-41.156 0-64 0-19.594 0-40.25 0-64C768 441.344 596 384 384 384zM384 704c-141.375 0-256-28.594-256-64s114.625-64 256-64 256 28.594 256 64S525.375 704 384 704z" horiz-adv-x="768" />
+<glyph glyph-name="desktop-download" unicode="&#xf0dc;" d="M256 448h192V832h128v-384h192L512 192 256 448z m704 256H704v-64h256v-512H64V640h256v64H64c-35 0-64-29-64-64v-576c0-35 29-64 64-64h342c-16-39-55-89-150-128h512c-95 39-134 89-150 128h342c35 0 64 29 64 64V640c0 35-29 64-64 64z" horiz-adv-x="1024" />
+<glyph glyph-name="device-camera" unicode="&#xf056;" d="M960 640H448c0 35-29 64-64 64H128c-35 0-64-29-64-64-35 0-64-29-64-64v-576c0-35 29-64 64-64h896c35 0 64 29 64 64V576c0 35-29 64-64 64zM384 512H128v64h256v-64z m288-448c-124 0-224 100-224 224s100 224 224 224 224-100 224-224-100-224-224-224z m160 224c0-88-72-160-160-160s-160 72-160 160 72 160 160 160 160-72 160-160z" horiz-adv-x="1024" />
+<glyph glyph-name="device-camera-video" unicode="&#xf057;" d="M973 634L640 402V576c0 35-29 64-64 64H64c-35 0-64-29-64-64v-576c0-35 29-64 64-64h512c35 0 64 29 64 64V174l333-232c21-15 51 0 51 26V608c0 26-30 41-51 26z" horiz-adv-x="1024" />
+<glyph glyph-name="device-desktop" unicode="&#xf27c;" d="M960 704H64c-35 0-64-29-64-64v-576c0-35 29-64 64-64h342c-16-39-55-89-150-128h512c-95 39-134 89-150 128h342c35 0 64 29 64 64V640c0 35-29 64-64 64z m0-576H64V640h896v-512z" horiz-adv-x="1024" />
+<glyph glyph-name="device-mobile" unicode="&#xf038;" d="M576 832H64C29 832 0 803 0 768v-896c0-35 29-64 64-64h512c35 0 64 29 64 64V768c0 35-29 64-64 64zM320-147c-46 0-83 37-83 83s37 83 83 83 83-37 83-83-37-83-83-83z m256 211H64V704h512v-640z" horiz-adv-x="640" />
+<glyph glyph-name="diff" unicode="&#xf04d;" d="M384 384h128v-64H384v-128h-64V320H192v64h128V512h64v-128zM192 0h320v64H192v-64z m288 704l224-224v-608c0-35-29-64-64-64H64c-35 0-64 29-64 64V640c0 35 29 64 64 64h416z m160-256L448 640H64v-768h576V448zM544 832S192 832 192 832v-64h320l256-256v-512h64V544L544 832z" horiz-adv-x="896" />
+<glyph glyph-name="diff-added" unicode="&#xf06b;" d="M832 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h768c35 0 64 29 64 64V704c0 35-29 64-64 64z m0-832H64V704h768v-768zM384 256H192V384h192V576h128v-192h192v-128H512v-192H384V256z" horiz-adv-x="896" />
+<glyph glyph-name="diff-ignored" unicode="&#xf099;" d="M832 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h768c35 0 64 29 64 64V704c0 35-29 64-64 64z m0-832H64V704h768v-768zM288 64h-96v96l416 416h96v-96L288 64z" horiz-adv-x="896" />
+<glyph glyph-name="diff-modified" unicode="&#xf06d;" d="M832 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h768c35 0 64 29 64 64V704c0 35-29 64-64 64z m0-832H64V704h768v-768zM256 320c0 106 86 192 192 192s192-86 192-192-86-192-192-192-192 86-192 192z" horiz-adv-x="896" />
+<glyph glyph-name="diff-removed" unicode="&#xf06c;" d="M832 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h768c35 0 64 29 64 64V704c0 35-29 64-64 64z m0-832H64V704h768v-768zM704 256H192V384h512v-128z" horiz-adv-x="896" />
+<glyph glyph-name="diff-renamed" unicode="&#xf06e;" d="M384 256H192V384h192V576l320-256-320-256V256z m512 448v-768c0-35-29-64-64-64H64c-35 0-64 29-64 64V704c0 35 29 64 64 64h768c35 0 64-29 64-64z m-64 0H64v-768h768V704z" horiz-adv-x="896" />
+<glyph glyph-name="ellipsis" unicode="&#xf09a;" d="M704 512H64c-35 0-64-29-64-64v-256c0-35 29-64 64-64h640c35 0 64 29 64 64V448c0 35-29 64-64 64zM256 256H128V384h128v-128z m192 0H320V384h128v-128z m192 0H512V384h128v-128z" horiz-adv-x="768" />
+<glyph glyph-name="eye" unicode="&#xf04e;" d="M516 704C192 704 0 320 0 320s192-384 516-384c316 0 508 384 508 384S832 704 516 704z m-4-640c-141 0-256 114-256 256 0 141 115 256 256 256 142 0 256-115 256-256 0-142-114-256-256-256z m128 256c0-71-57-128-128-128s-128 57-128 128 57 128 128 128 128-57 128-128z" horiz-adv-x="1024" />
+<glyph glyph-name="file-binary" unicode="&#xf094;" d="M256 64h64v-64H128v64h64V192h-64v64h128v-192z m512 480v-608c0-35-29-64-64-64H64c-35 0-64 29-64 64V704c0 35 29 64 64 64h480l224-224z m-64-32L512 704H64v-768h640V512z m-192 64H384v-64h64v-128h-64v-64h192v64h-64V576z m-384 0h192v-256H128V576z m64-192h64V512h-64v-128z m192-128h192v-256H384V256z m64-192h64V192h-64v-128z" horiz-adv-x="768" />
+<glyph glyph-name="file-code" unicode="&#xf010;" d="M544 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h640c35 0 64 29 64 64V544L544 768z m160-832H64V704h448l192-192v-576zM320 385l-96-97 96-96-32-64-160 160 160 160 32-63z m160 63l160-160-160-160-32 63 96 97-96 96 32 64z" horiz-adv-x="768" />
+<glyph glyph-name="file-directory" unicode="&#xf016;" d="M832 576H448v64c0 42-20 64-64 64H64c-35 0-64-29-64-64v-640c0-35 29-64 64-64h768c35 0 64 29 64 64V512c0 35-29 64-64 64z m-448 0H64v64h320v-64z" horiz-adv-x="896" />
+<glyph glyph-name="file-media" unicode="&#xf012;" d="M384 512h128v-128H384V512z m384 32v-608c0-35-29-64-64-64H64c-35 0-64 29-64 64V704c0 35 29 64 64 64h480l224-224z m-64-32L512 704H64v-704l192 320 128-256 128 128 192-192V512z" horiz-adv-x="768" />
+<glyph glyph-name="file-pdf" unicode="&#xf014;" d="M544 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h640c35 0 64 29 64 64V544L544 768zM64 704h256c-7-2-13-6-20-13-6-6-11-16-15-30-7-25-9-57-6-94s11-75 22-115c-15-47-39-103-71-170s-51-106-58-118c-9-3-23-9-44-19-21-9-42-23-64-41V704z m283-307c29-72 54-117 75-134s41-29 60-34c-41-6-79-13-116-21-36-8-75-21-116-38 1 1 14 28 39 80s45 101 58 147z m357-461H96c-4 0-8 1-11 2 13 4 29 13 47 28 29 24 67 74 114 152 20 8 37 15 52 20l27 9c29 8 60 15 92 21 32 5 64 10 95 13 29-14 58-25 89-34 31-8 58-13 79-15 9 0 17 1 24 2v-198z m0 311c-12 7-26 13-41 18-15 4-31 6-48 7-25 0-51-2-79-5-15 4-36 18-63 41s-55 73-84 149c8 53 12 95 13 126s1 47 0 48c3 26-2 45-13 56s-24 17-39 17h162l192-192v-265z" horiz-adv-x="768" />
+<glyph glyph-name="file-submodule" unicode="&#xf017;" d="M640 384H256v-448h576c35 0 64 29 64 64V320H640v64z m-64-128H320v64h256v-64z m256 320H448v64c0 42-20 64-64 64H64c-35 0-64-29-64-64v-640c0-35 29-64 64-64h128V384c0 35 29 64 64 64h384c35 0 64-29 64-64h192V512c0 35-29 64-64 64z m-448 0H64v64h320v-64z" horiz-adv-x="896" />
+<glyph glyph-name="file-symlink-directory" unicode="&#xf0b1;" d="M832 576H448v64c0 42-20 64-64 64H64c-35 0-64-29-64-64v-640c0-35 29-64 64-64h768c35 0 64 29 64 64V512c0 35-29 64-64 64zM64 640h320v-64H64v64z m384-576V192c-63 1-118-14-163-45s-76-80-93-147c1 105 25 184 72 239 47 54 108 81 184 81V448l256-192-256-192z" horiz-adv-x="896" />
+<glyph glyph-name="file-symlink-file" unicode="&#xf0b0;" d="M544 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h640c35 0 64 29 64 64V544L544 768z m160-832H64V704h448l192-192v-576zM384 544l256-192-256-192V288c-63 1-118-14-163-45s-76-80-93-147c1 105 25 184 72 239 47 54 108 81 184 81V544z" horiz-adv-x="768" />
+<glyph glyph-name="file-text" unicode="&#xf011;" d="M384 512H128v64h256v-64zM128 320h448v64H128v-64z m0-128h448v64H128v-64z m0-128h448v64H128v-64z m640 480v-608c0-35-29-64-64-64H64c-35 0-64 29-64 64V704c0 35 29 64 64 64h480l224-224z m-64-32L512 704H64v-768h640V512z" horiz-adv-x="768" />
+<glyph glyph-name="file-zip" unicode="&#xf013;" d="M544 768H64C29 768 0 739 0 704v-768c0-35 29-64 64-64h640c35 0 64 29 64 64V544L544 768z m160-832H64V704h192v-64h64v64h192l192-192v-576zM320 576v64h64v-64h-64z m-64 0h64v-64h-64v64z m64-128v64h64v-64h-64z m-64 0h64v-64h-64v64z m64-128v64h64v-64h-64z m-64-82c-38-22-64-63-64-110v-64h256v64c0 71-57 128-128 128v64h-64v-82z m128-46v-64H256v64h128z" horiz-adv-x="768" />
+<glyph glyph-name="flame" unicode="&#xf0d2;" d="M433 787c50-134 24-207-32-265-61-64-156-112-223-206-89-125-104-400 217-472-135 71-164 277-18 406-38-125 32-205 119-176 85 29 141-32 139-102-1-48-20-89-69-112 209 37 293 210 293 342 0 174-155 198-77 344-93-8-125-69-116-169 6-66-63-111-114-81-41 25-40 73-4 109 77 76 107 251-115 382z" horiz-adv-x="1024" />
+<glyph glyph-name="fold" unicode="&#xf0cc;" d="M448 256l192-192H512v-192H384V64H256l192 192z m192 384H512V832H384v-192H256l192-192 192 192z m256-128c0 35-29 64-64 64H672l-64-64h192L672 384H224L96 512h192l-64 64H64c-35 0-64-29-64-64l160-160L0 192c0-35 29-64 64-64h160l64 64H96l128 128h448l128-128H608l64-64h160c35 0 64 29 64 64L736 352l160 160z" horiz-adv-x="896" />
+<glyph glyph-name="gear" unicode="&#xf02f;" d="M896 271V373l-124 41-29 70 56 118-72 72-116-58-70 29-44 123H395l-40-124-71-29-118 56-72-72 58-116-29-70L0 369v-102l124-41 29-70-56-118 72-72 116 58 70-29 44-123h102l40 124 71 29 118-56 72 72-59 116 30 70 123 44zM448 128c-106 0-192 86-192 192s86 192 192 192 192-86 192-192-86-192-192-192z" horiz-adv-x="896" />
+<glyph glyph-name="gift" unicode="&#xf042;" d="M832 576h-88c12 21 21 43 23 58 4 43-7 78-33 103-23 24-52 31-87 31-3 0-5 0-7 0-34-1-71-16-98-37s-47-46-62-77c-15 31-35 56-62 77s-64 37-98 37c-1 0-2 0-2 0-36 0-68-6-92-31-26-25-37-60-33-103 2-15 11-37 23-58h-88c-35 0-64-29-64-64v-192h64v-320c0-35 29-64 64-64h576c35 0 64 29 64 64V320h64V512c0 35-29 64-64 64z m-306 56c11 23 27 43 48 59 19 15 46 25 67 26h6c29 0 42-7 51-16s21-25 19-61c-3-12-16-39-32-64H500l26 56z m-264 69c8 8 20 16 58 16 20 0 46-11 66-26 21-16 37-35 48-59l27-56H275c-16 25-29 52-32 64-2 36 10 52 19 61z m186-701H192V320h256v-320z m0 384H128V512h320v-128z m320-384H512V320h256v-320z m64 384H512V512h320v-128z" horiz-adv-x="896" />
+<glyph glyph-name="gist" unicode="&#xf00e;" d="M480 512l160-160-160-160-48 48 112 112-112 112 48 48z m-192 0L128 352l160-160 48 48-112 112 112 112-48 48zM0 0V704c0 35 29 64 64 64h640c35 0 64-29 64-64v-704c0-35-29-64-64-64H64c-35 0-64 29-64 64z m64 0h640V704H64v-704z" horiz-adv-x="768" />
+<glyph glyph-name="gist-secret" unicode="&#xf08c;" d="M512 160l64-224H320l64 224-48 96h224l-48-96z m128 288H256l-128-64h640l-128 64z m-64 256l-128-64-128 64-64-192h384l-64 192z m258-496l-194 48 64-128-128-192h206c29 0 55 20 62 48l36 146c9 34-12 69-46 78z m-578 48L62 208c-34-9-55-44-46-78l36-146c7-28 33-48 62-48h206L192 128l64 128z" horiz-adv-x="896" />
+<glyph glyph-name="git-branch" unicode="&#xf020;" d="M640 512c0 71-57 128-128 128s-128-57-128-128c0-47 26-88 64-110v-19c-1-33-15-63-40-88s-55-39-88-40c-53-1-95-10-128-29V530c38 22 64 63 64 110 0 71-57 128-128 128S0 711 0 640c0-47 26-88 64-110v-420C26 88 0 47 0 0c0-71 57-128 128-128s128 57 128 128c0 34-13 64-34 87 6 4 31 26 38 30 16 7 36 11 60 11 67 3 125 29 176 80s77 127 80 193h-1c39 23 65 64 65 111zM128 717c42 0 77-35 77-77s-35-77-77-77-77 35-77 77 35 77 77 77z m0-794c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z m384 512c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z" horiz-adv-x="640" />
+<glyph glyph-name="git-commit" unicode="&#xf01f;" d="M695 384c-29 110-128 192-247 192s-218-82-247-192H0v-128h201c29-110 128-192 247-192s218 82 247 192h201V384H695zM448 179c-78 0-141 63-141 141s63 141 141 141 141-63 141-141-63-141-141-141z" horiz-adv-x="896" />
+<glyph glyph-name="git-compare" unicode="&#xf0ac;" d="M320 64h-64c-17 1-31 7-44 20s-19 27-20 44V530c38 22 64 63 64 110 0 71-57 128-128 128S0 711 0 640c0-47 26-88 64-110 0-111 0-402 0-402 2-50 22-94 60-132s82-58 132-60c0 0 65 0 64 0v-128l192 192-192 192v-128zM128 717c42 0 77-35 77-77s-35-77-77-77-77 35-77 77 35 77 77 77z m704-607c0 111 0 402 0 402-2 50-22 94-60 132s-82 58-132 60c0 0-65 0-64 0V832L384 640l192-192V576h64c17-1 31-7 44-20s19-27 20-44v-402c-38-22-64-63-64-110 0-71 57-128 128-128s128 57 128 128c0 47-26 88-64 110z m-64-187c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z" horiz-adv-x="896" />
+<glyph glyph-name="git-merge" unicode="&#xf023;" d="M640 384c-47 0-88-26-111-65v1c-67 1-145 23-200 65-48 37-96 103-121 156 29 23 48 59 48 99 0 71-57 128-128 128S0 711 0 640c0-47 26-88 64-110v-420C26 88 0 47 0 0c0-71 57-128 128-128s128 57 128 128c0 47-26 88-64 110V341c43-45 92-81 147-108s130-40 190-41v1c23-39 64-65 111-65 71 0 128 57 128 128s-57 128-128 128zM205 0c0-42-35-77-77-77s-77 35-77 77 35 77 77 77 77-35 77-77z m-77 563c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z m512-384c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z" horiz-adv-x="768" />
+<glyph glyph-name="git-pull-request" unicode="&#xf009;" d="M704 110c0 111 0 402 0 402-2 50-22 94-60 132s-82 58-132 60c0 0-65 0-64 0V832L256 640l192-192V576h64c17-1 31-7 44-20s19-27 20-44v-402c-38-22-64-63-64-110 0-71 57-128 128-128s128 57 128 128c0 47-26 88-64 110z m-64-187c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77zM256 640c0 71-57 128-128 128S0 711 0 640c0-47 26-88 64-110 0-99 0-356 0-420-38-22-64-63-64-110 0-71 57-128 128-128s128 57 128 128c0 47-26 88-64 110V530c38 22 64 63 64 110z m-51-640c0-42-35-77-77-77s-77 35-77 77 35 77 77 77 77-35 77-77z m-77 563c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z" horiz-adv-x="768" />
+<glyph glyph-name="globe" unicode="&#xf0b6;" d="M512 704c-212.077 0-384-171.923-384-384s171.923-384 384-384c25.953 0 51.303 2.582 75.812 7.49-9.879 4.725-10.957 40.174-1.188 60.385 10.875 22.5 45 79.5 11.25 98.625s-24.375 27.75-45 49.875-12.19 25.451-13.5 31.125c-4.5 19.5 19.875 48.75 21 51.75s1.125 14.25 0.75 17.625S545.75 265.25 542 265.625s-5.625-6-10.875-6.375-28.125 13.875-33 17.625-7.125 12.75-13.875 19.5-7.5 1.5-18 5.625-44.25 16.5-70.125 27-28.125 25.219-28.5 35.625-15.75 25.5-22.961 36.375c-7.209 10.875-8.539 25.875-11.164 22.5s13.5-42.75 10.875-43.875-8.25 10.875-15.75 20.625 7.875 4.5-16.125 51.75 7.5 71.344 9 96 20.25-9 10.5 6.75 0.75 48.75-6.75 60.75S275 602 275 602c1.125 11.625 37.5 31.5 63.75 49.875s42.281 4.125 63.375-2.625 22.5-4.5 15.375 2.25 3 10.125 19.5 7.5 21-22.5 46.125-20.625 2.625-4.875 6-11.25-3.75-5.625-20.25-16.875S469.25 599 498.5 577.625s20.25 14.25 17.25 30S537.125 611 537.125 611c18-12 14.674-0.66 27.799-4.785S613.625 572 613.625 572c-44.625-24.375-16.5-27-9-32.625s-15.375-16.5-15.375-16.5c-9.375 9.375-10.875-0.375-16.875-3.75s-0.375-12-0.375-12c-31.031-4.875-24-37.5-23.625-45.375s-19.875-19.875-25.125-31.125S536.75 395 527 393.5s-19.5 36.75-72 22.5c-15.828-4.297-51-22.5-32.25-59.625s49.875 10.5 60.375 5.25-3-28.875-0.75-29.25 29.625-1.031 31.125-33 41.625-29.25 50.25-30 37.5 23.625 41.625 24.75S626 309.125 662 288.5s54.375-17.625 66.75-26.25 3.75-25.875 15.375-31.5 58.125 1.875 69.75-17.25-48-115.125-66.75-125.625S719.75 53.375 701 38s-45-34.406-69.75-49.125c-21.908-13.027-25.85-36.365-35.609-43.732C767.496-16.67999999999995 896 136.64999999999998 896 320 896 532.077 724.077 704 512 704zM602 343.625c-5.25-1.5-16.125-11.25-42.75 4.5s-45 12.75-47.25 15.375c0 0-2.25 6.375 9.375 7.5 23.871 2.311 54-22.125 60.75-22.5s10.125 6.75 22.125 2.883C616.25 347.52 607.25 345.125 602 343.625zM476.375 665.75c-2.615 1.902 2.166 4.092 5.016 7.875 1.645 2.186 0.425 5.815 2.484 7.875 5.625 5.625 33.375 13.5 27.949-1.875C506.4 664.25 480.5 662.75 476.375 665.75zM543.5 617c-9.375 0.375-31.443 2.707-27.375 6.75 15.844 15.75-6 20.25-19.5 21.375S477.5 653.75 484.25 654.5s33.75-0.375 38.25-4.125 28.875-13.5 30.375-20.625S552.875 616.625 543.5 617zM624.875 619.625c-7.5-6-45.24 21.529-52.5 27.75-31.5 27-48.375 18-54.99 22.5-6.617 4.5-4.26 10.5 5.865 19.5s38.625-3 55.125-4.875 35.625-14.625 36-29.781C614.75 639.564 632.375 625.625 624.875 619.625z" horiz-adv-x="1024" />
+<glyph glyph-name="graph" unicode="&#xf043;" d="M1024-64v-64H0V832h64v-896h960z m-704 64H192V320h128v-320z m256 0H448V640h128v-640z m256 0H704V448h128v-448z" horiz-adv-x="1024" />
+<glyph glyph-name="heart" unicode="&#x2665;" d="M717 576c-33 40-80 61-141 64-62 0-108-27-141-64s-50-59-51-64c-1 5-18 27-51 64s-75 64-141 64c-61-3-108-24-141-64-33-39-50-82-51-128 0-33 6-97 43-171s150-188 341-341c191 153 305 267 342 341s42 139 42 171c-1 46-18 89-51 129z" horiz-adv-x="768" />
+<glyph glyph-name="history" unicode="&#xf07e;" d="M512 0H384V448h320v-128H512v-320zM448 768c-140 0-264-65-346-166L0 704v-256h256l-96 96c67 85 171 141 288 141 201 0 365-164 365-365S649-45 448-45 83 119 83 320c0 22 2 43 6 64H5c-3-21-5-42-5-64 0-247 201-448 448-448s448 201 448 448S695 768 448 768z" horiz-adv-x="896" />
+<glyph glyph-name="home" unicode="&#xf08d;" d="M1024 256L832 448V704H704v-128L512 768 0 256h128l64-320c0-35 29-64 64-64h512c35 0 64 29 64 64l64 320h128zM768-64H576V192H448v-256H256l-76 404 332 332 332-332-76-404z" horiz-adv-x="1024" />
+<glyph glyph-name="horizontal-rule" unicode="&#xf070;" d="M63.938 384h128v-128h64V639.938h-64V448h-128V639.938H0V256h63.938V384zM639.875 256V384h-63.938v-128H639.875zM639.875 448V575.938h-63.938V448H639.875zM447.938 448V575.938h128v64h-192V256h64V384h128v64H447.938zM0 0h639.875V128H0V0z" horiz-adv-x="639.875" />
+<glyph glyph-name="hubot" unicode="&#xf09d;" d="M192 448c-35 0-64-29-64-64v-128c0-35 29-64 64-64h512c35 0 64 29 64 64V384c0 35-29 64-64 64H192z m512-112l-80-80h-96l-80 80-80-80h-96l-80 80v48h48l80-80 80 80h96l80-80 80 80h48v-48zM320 128h256v-64H320v64z m128 576C201 704 0 518 0 288v-288c0-35 29-64 64-64h768c35 0 64 29 64 64V288c0 230-201 416-448 416z m384-704H64V288c0 198 169 358 384 358s384-160 384-358v-288z" horiz-adv-x="896" />
+<glyph glyph-name="inbox" unicode="&#xf0cf;" d="M896 256l-72 457c-5 31-32 55-64 55H136c-32 0-59-24-64-55L0 256v-320c0-35 29-64 64-64h768c35 0 64 29 64 64V256z m-210-35l-28-57c-11-22-33-36-58-36H295c-24 0-46 14-57 35l-28 58c-11 21-33 35-57 35H64l64 448h640l64-448h-88c-25 0-47-14-58-35z" horiz-adv-x="896" />
+<glyph glyph-name="info" unicode="&#xf059;" d="M403 468c-12 12-18 27-18 45s6 33 18 45 27 18 45 18 33-6 45-18 18-27 18-45-6-33-18-45-27-19-45-19-33 7-45 19z m109-147c-1 16-7 31-20 44-13 12-27 19-44 20h-64c-17-1-31-8-44-20-13-13-19-28-20-44h64v-192c1-17 7-32 20-44 13-13 27-20 44-20h64c17 0 31 7 44 20 13 12 19 27 20 44h-64V321z m-64 364C247 685 83 522 83 321s164-365 365-365 365 163 365 365-164 364-365 364m0 84c247 0 448-201 448-448S695-127 448-127 0 73 0 321 201 769 448 769z" horiz-adv-x="896" />
+<glyph glyph-name="issue-closed" unicode="&#xf028;" d="M448 192h128v-128H448V192z m128 384H448v-320h128V576z m96-96l-64-64 160-160 256 288-64 64-192-224-96 96zM512-45c-201 0-365 164-365 365s164 365 365 365c117 0 221-56 288-141l59 59C777 704 652 768 512 768 265 768 64 567 64 320s201-448 448-448 448 201 448 448l-97-97c-42-154-183-268-351-268z" horiz-adv-x="1024" />
+<glyph glyph-name="issue-opened" unicode="&#xf026;" d="M448 685c201 0 365-164 365-365S649-45 448-45 83 119 83 320s164 365 365 365m0 83C201 768 0 567 0 320s201-448 448-448 448 201 448 448S695 768 448 768z m64-192H384v-320h128V576z m0-384H384v-128h128V192z" horiz-adv-x="896" />
+<glyph glyph-name="issue-reopened" unicode="&#xf027;" d="M512 256H384V576h128v-320zM384 64h128V192H384v-128z m405 128H640l96-96c-67-85-171-141-288-141-201 0-365 164-365 365 0 22 2 43 6 64H5c-3-21-5-42-5-64 0-247 201-448 448-448 140 0 264 65 346 166l102-102V192H789zM107 448h149l-96 96c67 85 171 141 288 141 201 0 365-164 365-365 0-22-2-43-6-64h84c3 21 5 42 5 64 0 247-201 448-448 448-140 0-264-65-346-166L0 704v-256h107z" horiz-adv-x="896" />
+<glyph glyph-name="jersey" unicode="&#xf019;" d="M224 448l-32-32v-320l32-32h128l32 32V416l-32 32H224z m96-320h-64V384h64v-256z m401 464c-14 88-20 168-17 240H513c0-17-8-31-25-44-16-13-40-19-72-19s-56 6-72 19c-15 13-23 27-23 44H128c3-72-2-152-16-240-13-88-51-136-112-144v-576c1-17 7-31 20-44s27-19 44-20h704c17 1 31 7 44 20s19 27 20 44V448c-61 8-98 56-112 144z m47-720H64V384c57 32 95 80 110 144s20 144 18 240h64c-1-50 10-94 33-132 23-37 65-57 128-60 63 1 105 21 128 60 23 38 32 82 31 132h64c1-91 8-163 21-216 13-52 44-128 107-168v-512zM480 448l-32-32v-320l32-32h128l32 32V416l-32 32H480z m96-320h-64V384h64v-256z" horiz-adv-x="896" />
+<glyph glyph-name="key" unicode="&#xf049;" d="M821 693c-48 48-108 73-181 75-72-2-133-27-181-75s-72-108-74-181c0-19 2-38 6-57L0 64v-64l64-64h128l64 64v64h64v64h64v64h128l70 71c19-5 38-7 58-7 73 2 133 27 181 75s73 108 75 181c-2 73-27 133-75 181zM704 488c-49 0-88 39-88 88s39 88 88 88 88-39 88-88-39-88-88-88z" horiz-adv-x="896" />
+<glyph glyph-name="keyboard" unicode="&#xf00d;" d="M640 512h-64v64h64v-64z m-448-64h-64v-64h64v64z m320 128h-64v-64h64v64z m-256 0H128v-64h128v64z m512-448h128v64H768v-64zM512 384h64v64h-64v-64zM256 192H128v-64h128v64z m512 384h-64v-64h64v64z m128 0h-64v-64h64v64zM768 256h128V448H768v-192z m256 384v-576c0-35-29-64-64-64H64c-35 0-64 29-64 64V640c0 35 29 64 64 64h896c35 0 64-29 64-64z m-64 0H64v-576h896V640zM384 384h64v64h-64v-64z m0 192h-64v-64h64v64zM256 384h64v64h-64v-64z m64-256h384v64H320v-64z m320 256h64v64h-64v-64z m-448-64h-64v-64h64v64z m320 0v-64h64v64h-64z m-128 0v-64h64v64h-64z m-64 0h-64v-64h64v64z m320-64h64v64h-64v-64z" horiz-adv-x="1024" />
+<glyph glyph-name="law" unicode="&#xf0d8;" d="M448 576c-53 0-96 43-96 96s43 96 96 96 96-43 96-96-43-96-96-96z m448-384c0-71-57-128-128-128h-64c-71 0-128 57-128 128l128 256h-64c-35 0-64 29-64 64h-64v-512c27 0 64-29 64-64h64c27 0 64-29 64-64H192c0 35 37 64 64 64h64c0 35 37 64 64 64h2l-2 512h-64c0-35-29-64-64-64h-64l128-256c0-71-57-128-128-128h-64C57 64 0 121 0 192l128 256H64v64h192c0 35 29 64 64 64h256c35 0 64-29 64-64h192v-64h-64l128-256zM160 384L64 192h192l-96 192z m672-192l-96 192-96-192h192z" horiz-adv-x="896" />
+<glyph glyph-name="light-bulb" unicode="&#xf000;" d="M352 832C159 832 0 692 0 512c0-59 35-144 64-192 86-144 114-178 128-256v-64h320v64c14 78 42 112 128 256 29 48 64 133 64 192C704 692 545 832 352 832z m233-479c-16-28-30-51-43-71-55-90-80-132-93-207-1-3-1-7-1-11H256c0 4 0 8-1 11-13 75-38 117-93 207-13 20-27 43-43 71-27 45-55 117-55 159C64 653 193 768 352 768c78 0 151-27 206-76 53-48 82-112 82-180 0-42-28-114-55-159zM192-64h320c-15-73-83-128-160-128s-145 55-160 128z" horiz-adv-x="768" />
+<glyph glyph-name="link" unicode="&#xf05c;" d="M256 256h64v-64h-64c-96 0-192 108-192 224s99 224 192 224h256c93 0 192-108 192-224 0-90-58-174-128-208v74c37 29 64 81 64 134 0 82-65 160-128 160H256c-63 0-128-78-128-160s64-160 128-160z m576 192h-64v-64h64c64 0 128-78 128-160s-65-160-128-160H576c-63 0-128 78-128 160 0 53 27 105 64 134v74c-70-34-128-118-128-208 0-116 99-224 192-224h256c93 0 192 108 192 224s-96 224-192 224z" horiz-adv-x="1024" />
+<glyph glyph-name="link-external" unicode="&#xf07f;" d="M704 192h64v-192c0-35-29-64-64-64H64c-35 0-64 29-64 64V640c0 35 29 64 64 64h192v-64H64v-640h640V192zM384 704l144-144-208-208 96-96 208 208 144-144V704H384z" horiz-adv-x="768" />
+<glyph glyph-name="list-ordered" unicode="&#xf062;" d="M320 256h448v128h-448v-128z m0-256h448v128h-448v-128z m0 640v-128h448v128h-448z m-241-256h78v256h-36l-85-23v-50l43 2v-185z m110-206c0 36-12 78-96 78-33 0-64-6-83-16l1-66c21 10 42 15 67 15s32-11 32-28c0-26-30-58-110-112v-50h192v67l-91-2c49 30 87 66 87 113l1 1z" horiz-adv-x="768" />
+<glyph glyph-name="list-unordered" unicode="&#xf061;" d="M0 256h128v128h-128v-128z m0 256h128v128h-128v-128z m0-512h128v128h-128v-128z m256 256h512v128h-512v-128z m0 256h512v128h-512v-128z m0-512h512v128h-512v-128z" horiz-adv-x="768" />
+<glyph glyph-name="location" unicode="&#xf060;" d="M384 832C172 832 0 672 0 480c0-289 384-672 384-672s384 383 384 672C768 672 596 832 384 832z m0-931C265 31 64 292 64 480 64 639 208 768 384 768c86 0 167-31 228-87 59-55 92-126 92-201 0-188-201-449-320-579z m128 579c0-71-57-128-128-128s-128 57-128 128 57 128 128 128 128-57 128-128z" horiz-adv-x="768" />
+<glyph glyph-name="lock" unicode="&#xf06a;" d="M256 0h-64v64h64v-64z m512 384v-448c0-35-29-64-64-64H64c-35 0-64 29-64 64V384c0 35 29 64 64 64h64V576C128 717 243 832 384 832s256-115 256-256v-128h64c35 0 64-29 64-64z m-525 64h282V576c0 78-63 141-141 141s-141-63-141-141v-128z m461-64H128v-448h576V384z m-448-64h-64v-64h64v64z m0-128h-64v-64h64v64z" horiz-adv-x="768" />
+<glyph glyph-name="logo-github" unicode="&#xf092;" d="M552.73 499.865H311.557c-6.205 0-11.25-5.045-11.25-11.297v-117.887c0-6.252 5.045-11.272 11.25-11.272h94.109v-146.542c0 0-21.145-7.057-79.496-7.057-68.914 0-165.156 25.244-165.156 236.795 0 211.642 100.197 239.491 194.307 239.491 81.465 0 116.514-14.304 138.869-21.241 7.01-2.203 13.404 4.831 13.404 11.105L534.543 785.87c0 2.912-1.041 6.417-4.262 8.785C521.186 801.048 465.865 832 326.168 832 165.133 832 0 763.513 0 434.243 0 105.02099999999996 189.051 56 348.381 56c131.883 0 212.021 56.314 212.021 56.314 3.268 1.801 3.6 6.395 3.6 8.479V488.568C563.955 494.773 558.887 499.865 552.73 499.865zM1772.381 803.866h-135.695c-6.252 0-11.271-5.044-11.271-11.296v-262.393h-211.619V792.57c0 6.252-5.068 11.296-11.178 11.296h-135.838c-6.111 0-11.084-5.044-11.084-11.296v-710.473c0-6.299 5.021-11.32 11.084-11.32h135.838c6.203 0 11.178 5.068 11.178 11.32V385.933h211.619l-0.475-303.883c0-6.3 5.021-11.272 11.084-11.272h135.885c6.252 0 11.131 5.068 11.131 11.272l0.473 710.521C1783.607 798.822 1778.539 803.866 1772.381 803.866zM714.949 787.763c-48.357 0-87.574-39.572-87.574-88.403 0-48.855 39.217-88.428 87.574-88.428s87.527 39.572 87.527 88.428C802.477 748.19 763.307 787.763 714.949 787.763zM792.861 559.874c0 6.205-5.02 11.344-11.131 11.344H646.32c-6.348 0-11.746-6.394-11.746-12.67 0 0 0-394.654 0-469.867 0-13.735 8.572-17.903 19.703-17.903 0 0 57.688 0 121.959 0 13.311 0 16.814 6.536 16.814 18.188-0.094 25.197-0.094 123.808-0.094 142.942C792.861 250.09500000000003 792.861 559.874 792.861 559.874zM2297.973 570.152h-134.701c-6.158 0-11.084-5.092-11.084-11.344v-348.31c0 0-34.244-25.197-82.934-25.197-48.547 0-61.525 22.024-61.525 69.719 0 47.553 0 303.835 0 303.835 0 6.252-5.068 11.345-11.131 11.345h-136.643c-6.252 0-11.178-5.093-11.178-11.345 0 0 0-185.521 0-326.807 0-141.284 78.766-175.906 186.99-175.906 88.854 0 160.609 49.115 160.609 49.115s3.363-25.766 5.068-28.844c1.422-3.078 5.447-6.158 9.852-6.158h86.58c6.158 0 11.178 5.069 11.178 11.321l0.379 477.278C2309.15 565.0609999999999 2304.129 570.152 2297.973 570.152zM2666.932 586.1610000000001c-76.539 0-128.592-34.148-128.592-34.148V792.57c0 6.252-5.068 11.296-11.131 11.296h-136.264c-6.109 0-11.131-5.044-11.131-11.296l-0.379-710.521c0-6.3 5.068-11.272 11.225-11.272 0 0 94.773 0 94.869 0 4.215 0 7.389 2.179 9.805 5.968 2.369 3.837 5.73 32.775 5.73 32.775s55.557-52.763 161.035-52.763c123.807 0 194.758 62.804 194.758 281.906C2856.859 557.482 2743.471 586.1610000000001 2666.932 586.1610000000001zM2613.791 185.77499999999998c-46.701 1.421-78.34 22.64-78.34 22.64v225.07c0 0 31.307 19.206 69.672 22.593 48.547 4.31 95.438-10.326 95.438-126.13C2700.322 207.94100000000003 2679.199 183.83399999999995 2613.791 185.77499999999998zM1185.125 188.33299999999997c-5.969 0-21.219-2.368-36.85-2.368-49.92 0-66.971 23.256-66.971 53.331 0 30.218 0 199.85 0 199.85h101.926c6.252 0 11.178 5.044 11.178 11.343v109.48c0.094 6.299-4.926 11.344-11.178 11.344h-101.926l-0.143 134.535c0 5.092-2.699 7.625-8.572 7.625H933.861c-5.352 0-8.336-2.391-8.336-7.578v-139.035c0 0-69.576-16.79-74.266-18.188-4.641-1.326-8.051-5.684-8.051-10.822v-87.408c0-6.252 5.068-11.344 11.178-11.344h71.139c0 0 0-91.34 0-210.222 0-156.109 109.553-171.455 183.439-171.455 33.723 0 74.076 10.988 80.848 13.356 4.074 1.421 6.395 5.637 6.395 10.136l0.047 96.101C1196.254 183.312 1190.998 188.428 1185.125 188.33299999999997z" horiz-adv-x="2856.857" />
+<glyph glyph-name="mail" unicode="&#xf03b;" d="M0 576v-512c0-35 29-64 64-64h768c35 0 64 29 64 64V576c0 35-29 64-64 64H64c-35 0-64-29-64-64z m832 0L448 256 64 576h768zM64 480l256-192L64 96V480z m64-416l224 192 96-96 96 96 224-192H128z m704 32L576 288l256 192v-384z" horiz-adv-x="896" />
+<glyph glyph-name="mail-read" unicode="&#xf03c;" d="M384 512H256v64h128v-64z m192-64H256v-64h320v64z m320 31v-543c0-35-29-64-64-64H64c-35 0-64 29-64 64V479c0 21 10 40 27 52l101 72v37c0 35 29 64 64 64h77L448 832l179-128h77c35 0 64-29 64-64v-37l101-72c17-12 27-31 27-52zM192 352l256-160 256 160V640H192v-288zM64-32l288 192L64 352v-384z m704-32L448 128 128-64h640z m64 416L544 160l288-192V352z" horiz-adv-x="896" />
+<glyph glyph-name="mail-reply" unicode="&#xf051;" d="M384 672l-384-288 384-288v192c111 0 329-61 384-280 0 291-196 451-384 472v192z" horiz-adv-x="768" />
+<glyph glyph-name="mark-github" unicode="&#xf00a;" d="M512 832C229.252 832 0 602.748 0 320c0-226.251 146.688-418.126 350.155-485.813 25.593-4.686 34.937 11.125 34.937 24.626 0 12.188-0.469 52.562-0.718 95.314-128.708-23.46-161.707 31.541-172.469 60.373-5.525 14.809-30.407 60.249-52.398 72.263-17.988 9.828-43.26 33.237-0.917 33.735 40.434 0.476 69.348-37.308 78.471-52.75 45.938-77.749 119.876-55.627 148.999-42.5 4.654 32.999 17.902 55.627 32.501 68.373-113.657 12.939-233.22 56.875-233.22 253.063 0 55.94 19.968 101.561 52.658 137.404-5.22 12.999-22.844 65.095 5.063 135.563 0 0 42.937 13.749 140.811-52.501 40.811 11.406 84.594 17.031 128.124 17.22 43.499-0.188 87.314-5.874 128.188-17.28 97.689 66.311 140.686 52.501 140.686 52.501 28-70.532 10.375-122.564 5.124-135.499 32.811-35.844 52.626-81.468 52.626-137.404 0-196.686-119.751-240-233.813-252.686 18.439-15.876 34.748-47.001 34.748-94.748 0-68.437-0.686-123.627-0.686-140.501 0-13.625 9.312-29.561 35.25-24.562C877.436-97.99800000000005 1024 93.87400000000002 1024 320 1024 602.748 794.748 832 512 832z" horiz-adv-x="1024" />
+<glyph glyph-name="markdown" unicode="&#xf0c9;" d="M950.154 640H73.846C33.127 640 0 606.873 0 566.154v-492.308C0 33.125 33.127 0 73.846 0h876.308c40.721 0 73.846 33.125 73.846 73.846V566.154C1024 606.873 990.875 640 950.154 640zM576 128.125L448 128V320l-96-123.077L256 320v-192H128V512h128l96-128 96 128 128 0.125V128.125zM767.091 96.125L608 320h96V512h128v-192h96L767.091 96.125z" horiz-adv-x="1024" />
+<glyph glyph-name="megaphone" unicode="&#xf077;" d="M640 768c-11 0-23-3-33-9-92-56-319-220-415-247-88 0-192-43-192-160s104-160 192-160c19-5 41-15 64-26v-294h128V93c86-55 172-117 223-148 10-6 22-9 33-9 33 0 64 27 64 64V704c0 37-31 64-64 64z m0-768c-24 15-57 37-96 64-10 7-21 14-32 22V620c10 7 20 13 30 20 39 26 74 49 98 64v-704z m128 384h256v-64H768v64z m0-128l256-128v-64L768 192v64z m256 384v-64L768 448v64l256 128z" horiz-adv-x="1024" />
+<glyph glyph-name="mention" unicode="&#xf0be;" d="M466.697 732.899C238.66 760.898 31.1 598.735 3.102 370.698c-28-228.038 134.163-435.598 362.2-463.597 71.429-8.756 145.115 0.913 213.325 29.946l-0.016 0.032c24.404 10.357 35.788 38.538 25.431 62.939-10.359 24.403-38.538 35.787-62.94 25.43l-0.001 0.004c-52.472-22.339-109.15-29.799-164.1-23.067-175.413 21.538-300.153 181.2-278.616 356.613 21.538 175.413 181.199 300.154 356.613 278.616 175.412-21.538 300.154-181.199 278.617-356.612-4.309-35.083-21.542-55.725-61.6-55.725-42.5 0-64 45.889-64 81.222V432c0 26.51-21.49 48-48 48-9.699 0-18.72-2.887-26.269-7.833-25.684 20.259-57.437 33.87-94.349 38.402-105.246 12.923-201.045-61.924-213.967-167.17C212.508 238.15200000000004 287.354 142.35400000000004 392.6 129.43200000000002c57.379-7.045 116.216 14.707 157.871 53.13 24.959-28.124 59.866-47.624 100.121-52.567 87.707-10.769 167.537 51.602 178.307 139.309C856.898 497.34 694.734 704.899 466.697 732.899zM511.285 308.30100000000004c-6.462-52.623-54.361-90.047-106.985-83.585-52.623 6.461-90.046 54.36-83.585 106.984 6.461 52.623 54.361 90.046 106.984 83.585C480.322 408.823 517.746 360.924 511.285 308.30100000000004z" horiz-adv-x="832" />
+<glyph glyph-name="milestone" unicode="&#xf075;" d="M512 704H384V832h128v-128z m256-320H128c-35 0-64 29-64 64V576c0 35 29 64 64 64h640l128-128-128-128zM512 576H384v-128h128V576z m-128-768h128V320H384v-512z" horiz-adv-x="896" />
+<glyph glyph-name="mirror" unicode="&#xf024;" d="M992 531L544 832 96 531c-19-12-32-29-32-51v-672l480 256 480-256V480c0 22-13 39-32 51z m-32-627L576 112v80h-64v-80L128-96V480L512 736v-288h64V736l384-256v-576zM384 384h320V512l192-192-192-192V256H384v-128L192 320l192 192v-128z" horiz-adv-x="1024" />
+<glyph glyph-name="mortar-board" unicode="&#xf0d7;" d="M501 244l-245 76s0-96 0-160 115-96 256-96 256 32 256 96 0 160 0 160l-245-76c-7-2-15-2-23 0h1z m18 409c-4 1-9 1-13 0l-489-152c-21-7-21-36 0-43l111-35v-113c-19-11-32-32-32-55 0-12 3-23 9-32-5-9-9-20-9-32v-165c0-35 128-35 128 0v165c0 12-3 23-9 32 5 9 9 20 9 32 0 24-13 44-32 55v93l313-98c4-1 9-1 13 0l489 152c21 7 21 36 0 43l-488 153z m-6-205c-35 0-64 14-64 32s29 32 64 32 64-14 64-32-29-32-64-32z" horiz-adv-x="1024" />
+<glyph glyph-name="mute" unicode="&#xf080;" d="M512 652v-664c0-43-52-64-82-34L192 192H64c-35 0-64 29-64 64V384c0 35 29 64 64 64h128l238 238c30 30 82 9 82-34z m482-206l-68 68-126-126-126 126-68-68 126-126-126-126 68-68 126 126 126-126 68 68-126 126 126 126z" horiz-adv-x="1024" />
+<glyph glyph-name="no-newline" unicode="&#xf09c;" d="M1024 512v-192c0-35-29-64-64-64H768v-128L576 320l192 192v-128h128V512h128zM512 320c0-141-115-256-256-256S0 179 0 320s115 256 256 256 256-115 256-256zM96 214l266 266c-31 20-67 32-106 32-106 0-192-86-192-192 0-39 12-75 32-106z m352 106c0 39-12 75-32 106L150 160c31-20 67-32 106-32 106 0 192 86 192 192z" horiz-adv-x="1024" />
+<glyph glyph-name="octoface" unicode="&#xf008;" d="M940.812 554.312c8.25 20.219 35.375 101.75-8.562 211.906 0 0-67.375 21.312-219.875-82.906C648.5 700.875 579.875 703.5 512 703.5c-67.906 0-136.438-2.625-200.5-20.25C159.031 787.531 91.719 766.219 91.719 766.219 47.812 656 74.938 574.531 83.188 554.312 31.5 498.438 0 427.125 0 339.656 0 10.437999999999988 213.25-64 510.844-64 808.562-64 1024 10.437999999999988 1024 339.656 1024 427.125 992.5 498.438 940.812 554.312zM512-1c-211.406 0-382.781 9.875-382.781 214.688 0 48.938 24.062 94.595 65.344 132.312 68.75 62.969 185.281 29.688 317.438 29.688 132.25 0 248.625 33.281 317.438-29.625 41.312-37.78 65.438-83.312 65.438-132.312C894.875 8.875 723.375-1 512-1zM351.156 319.562c-42.469 0-76.906-51.062-76.906-114.188s34.438-114.312 76.906-114.312c42.375 0 76.812 51.188 76.812 114.312S393.531 319.562 351.156 319.562zM672.875 319.562C630.5 319.562 596 268.5 596 205.375s34.5-114.312 76.875-114.312 76.812 51.188 76.812 114.312C749.75 268.5 715.312 319.562 672.875 319.562z" horiz-adv-x="1024" />
+<glyph glyph-name="organization" unicode="&#xf037;" d="M304 515c35-41 86-67 144-67s109 26 144 67c22-40 64-67 112-67 71 0 128 57 128 128s-57 128-128 128c-26 0-49-8-69-21C615 768 539 832 448 832S281 768 261 683c-20 13-43 21-69 21-71 0-128-57-128-128s57-128 128-128c48 0 90 27 112 67z m333 97c13 24 38 41 67 41 42 0 77-35 77-77s-35-77-77-77-75 34-76 75c4 12 7 25 9 38zM448 769c71 0 129-58 129-129s-58-129-129-129-129 58-129 129S377 769 448 769zM192 499c-42 0-77 35-77 77s35 77 77 77c29 0 54-17 67-41 2-13 5-26 9-38-1-41-34-75-76-75z m640-51H64c-35 0-64-29-64-64v-192c0-35 29-64 64-64v-128c0-35 29-64 64-64h64c35 0 64 29 64 64v64h64v-192c0-35 29-64 64-64h128c35 0 64 29 64 64V64h64v-64c0-35 29-64 64-64h64c35 0 64 29 64 64V128c35 0 64 29 64 64V384c0 35-29 64-64 64zM192 0h-64V192H64V384h128v-384z m448 128h-64V256h-64v-384H384V256h-64v-128h-64V384h384v-256z m192 64h-64v-192h-64V384h128v-192z" horiz-adv-x="896" />
+<glyph glyph-name="package" unicode="&#xf0c4;" d="M0 559v-478c0-29 19-54 48-62l416-111c10-3 22-3 32 0l416 111c29 8 48 33 48 62V559c0 29-19 54-48 62L496 732c-10 2-22 2-32 0L48 621c-29-8-48-33-48-62z m448-582L64 79V512l384-103v-432zM64 576l160 43 416-111-160-43L64 576z m832-497L512-23V409l128 35v-156l128 34V478l128 34v-433zM768 542L352 653l128 34 416-111-128-34z" horiz-adv-x="1024" />
+<glyph glyph-name="paintcan" unicode="&#xf0d1;" d="M384 832C171.923 832 0 660.077 0 448v-64c0-35.346 28.654-64 64-64v-320c0-70.692 143.269-128 320-128s320 57.308 320 128V320c35.346 0 64 28.654 64 64v64C768 660.077 596.077 832 384 832zM576 192v-32c0-17.673-14.327-32-32-32s-32 14.327-32 32v32c0 17.673-14.327 32-32 32s-32-14.327-32-32v-160c0-17.673-14.327-32-32-32s-32 14.327-32 32V160c0 17.673-14.327 32-32 32s-32-14.327-32-32v-32c0-35.346-28.654-64-64-64s-64 28.654-64 64v64c-35.346 0-64 28.654-64 64V371.193C186.382 340.108 279.318 320 384 320s197.618 20.108 256 51.193V256C640 220.654 611.346 192 576 192zM384 384c-107.433 0-199.393 26.474-237.372 64 37.979 37.526 129.939 64 237.372 64s199.393-26.474 237.372-64C583.393 410.474 491.433 384 384 384zM384 576c-176.62 0-319.816-57.236-319.996-127.867-0.001 0.001-0.002 0.001-0.003 0.002C64.075 624.804 207.314 768 384 768c176.731 0 320-143.269 320-320C704 518.692 560.731 576 384 576z" horiz-adv-x="768" />
+<glyph glyph-name="pencil" unicode="&#xf058;" d="M0 64v-192h192l512 512-192 192L0 64z m192-128H64V64h64v-64h64v-64z m659 595l-83-83-192 192 83 83c25 25 65 25 90 0l102-102c25-25 25-65 0-90z" horiz-adv-x="896" />
+<glyph glyph-name="person" unicode="&#xf018;" d="M448 448H64c-35 0-64-29-64-64v-320h128v-192c0-35 29-64 64-64h128c35 0 64 29 64 64V64h128V384c0 35-29 64-64 64z m0-320h-64V256h-64v-384H192V256h-64v-128H64V384h384v-256z m0 512C448 746 362 832 256 832S64 746 64 640s86-192 192-192 192 86 192 192zM256 512c-71 0-128 57-128 128S185 768 256 768s128-57 128-128-57-128-128-128z" horiz-adv-x="512" />
+<glyph glyph-name="pin" unicode="&#xf041;" d="M640 755v-51l32-64-288-192H141c-28 0-43-34-22-55l201-201L64-128l320 256 201-201c21-21 55-6 55 22V192l192 288 64-32h51c28 0 43 34 22 55L695 777c-21 21-55 6-55-22z" horiz-adv-x="1024" />
+<glyph glyph-name="plug" unicode="&#xf0d4;" d="M960 448v64H704V640H576v-64H448c-66 0-113-52-128-128l-64-64c-106 0-192-86-192-192v-128h64V192c0 71 57 128 128 128l64-64c16-74 63-128 128-128h128v-64h128V192h256v64H704V448h256z" horiz-adv-x="1024" />
+<glyph glyph-name="plus" unicode="&#xf05d;" d="M768 256H448v-320H320V256H0V384h320V704h128v-320h320v-128z" horiz-adv-x="768" />
+<glyph glyph-name="primitive-dot" unicode="&#xf052;" d="M-0.088 320c0 141.5 114.5 256 256 256 141.438 0 256-114.5 256-256s-114.562-256-256-256C114.413 64-0.088 178.5-0.088 320z" horiz-adv-x="511.825" />
+<glyph glyph-name="primitive-square" unicode="&#xf053;" d="M512 64H0V576h512V64z" horiz-adv-x="512" />
+<glyph glyph-name="pulse" unicode="&#xf085;" d="M736 320.062L563.188 486.406 422.406 288 352 729.594 152.438 320.062H0V192h230.406L288 307.188l57.594-345.562L576 288l102.375-96H896V320.062H736z" horiz-adv-x="896" />
+<glyph glyph-name="question" unicode="&#xf02c;" d="M384 192h128v-128H384V192z m256 224c0-137-128-160-128-160H384c0 35 29 64 64 64h32c18 0 32 14 32 32v64c0 18-14 32-32 32h-64c-18 0-32-14-32-32v-32H256c0 96 96 192 192 192s192-64 192-160zM448 685c201 0 365-164 365-365S649-45 448-45 83 119 83 320s164 365 365 365m0 83C201 768 0 567 0 320s201-448 448-448 448 201 448 448S695 768 448 768z" horiz-adv-x="896" />
+<glyph glyph-name="quote" unicode="&#xf063;" d="M0 320v-256h256V320H128c0 0 0 128 128 128V576C256 576 0 576 0 320zM640 448V576c0 0-256 0-256-256v-256h256V320H512C512 320 512 448 640 448z" horiz-adv-x="640" />
+<glyph glyph-name="radio-tower" unicode="&#xf030;" d="M306.838 441.261c15.868 16.306 15.868 42.731 0 59.037-20.521 21.116-30.643 48.417-30.705 76.124 0.062 27.77 10.183 55.039 30.705 76.186 15.868 16.337 15.868 42.764 0 59.069-7.934 8.184-18.272 12.275-28.706 12.275-10.371 0-20.804-4.029-28.738-12.213-36.266-37.297-54.633-86.433-54.57-135.317-0.062-48.792 18.305-97.927 54.57-135.161C265.262 424.955 290.97 424.955 306.838 441.261zM149.093 798.858c-8.121 8.309-18.68 12.463-29.3 12.463-10.558 0-21.179-4.154-29.237-12.463C30.8 737.509 0.751 656.856 0.813 576.422 0.751 496.081 30.8 415.272 90.494 353.985c16.181-16.618 42.356-16.618 58.537 0 16.118 16.587 16.118 43.513 0 60.067-43.7 44.98-65.44 103.456-65.44 162.368s21.74 117.449 65.44 162.368C165.149 755.439 165.149 782.365 149.093 798.858zM513.031 472.153c57.351 0 103.956 46.574 103.956 103.956 0 57.382-46.605 103.955-103.956 103.955-57.381 0-103.956-46.573-103.956-103.955C409.076 518.727 455.65 472.153 513.031 472.153zM933.539 798.233c-16.181 16.618-42.355 16.618-58.475 0-16.181-16.587-16.181-43.513 0-60.068 43.668-44.918 65.409-103.456 65.409-162.368 0-58.85-21.805-117.387-65.473-162.306-16.117-16.618-16.117-43.575 0.062-60.068 8.059-8.309 18.616-12.463 29.237-12.463 10.558 0 21.178 4.154 29.236 12.463 59.726 61.287 89.774 142.096 89.649 222.437C1023.313 656.138 993.264 736.947 933.539 798.233zM513.281 389.127L513.281 389.127c-26.489-0.062-53.04 6.466-77.091 19.429L235.057-127.59000000000003h95.209l54.819 63.973h255.891l53.977-63.973h95.272L589.124 408.431C565.384 395.655 539.395 389.127 513.281 389.127zM512.656 358.483L577.004 128.29999999999995H449.059L512.656 358.483zM385.086 0.3550000000000182l63.974 63.973h127.944l63.974-63.973H385.086zM717.194 710.958c-15.868-16.306-15.868-42.731 0-59.037 20.491-21.116 30.611-48.511 30.674-76.124-0.062-27.77-10.183-55.102-30.674-76.187-15.868-16.336-15.868-42.763 0-59.068 7.871-8.184 18.242-12.213 28.737-12.213 10.309 0 20.741 4.029 28.675 12.213 36.298 37.234 54.665 86.433 54.54 135.255 0.125 48.792-18.181 97.927-54.54 135.161C758.801 727.264 733.062 727.264 717.194 710.958z" horiz-adv-x="1024" />
+<glyph glyph-name="repo" unicode="&#xf001;" d="M256 256h-64v64h64v-64z m0 192h-64v-64h64v64z m0 128h-64v-64h64v64z m0 128h-64v-64h64v64z m512 64v-768c0-35-29-64-64-64H384v-128l-96 96-96-96V-64H64c-35 0-64 29-64 64V768C0 803 29 832 64 832h640c35 0 64-29 64-64z m-64-640H64v-128h128v64h192v-64h320V128z m0 640H128v-576h576V768z" horiz-adv-x="768" />
+<glyph glyph-name="repo-clone" unicode="&#xf04c;" d="M960 832H576v-448c0-35 29-64 64-64h64v-64h64v64h192c35 0 64 29 64 64V768c0 35-29 64-64 64zM704 384h-64v64h64v-64z m256 0H768v64h192v-64z m0 128H704V768h256v-256z m-704 0h-64v64h64v-64z m0 128h-64v64h64v-64zM128 768h384V832H64C29 832 0 803 0 768v-768c0-35 29-64 64-64h128v-128l96 96 96-96V-64h320c35 0 64 29 64 64V192H128V768z m576-640v-128H384v64H192v-64H64V128h640zM192 320h64v-64h-64v64z m64 64h-64v64h64v-64z" horiz-adv-x="1024" />
+<glyph glyph-name="repo-force-push" unicode="&#xf04a;" d="M640 256H512v-448H384V256H256l144 192H256l192 256 192-256H496l144-192zM704 832H64C29 832 0 803 0 768v-768c0-35 29-64 64-64h256v64H64V128h256v64H128V768h576v-576H576v-64h128v-128H576v-64h128c35 0 64 29 64 64V768c0 35-29 64-64 64z" horiz-adv-x="767.896" />
+<glyph glyph-name="repo-forked" unicode="&#xf002;" d="M512 768c-71 0-128-57-128-128 0-47 26-88 64-110v-82L320 320 192 448v82c38 22 64 63 64 110 0 71-57 128-128 128S0 711 0 640c0-47 26-88 64-110v-114l192-192v-114c-38-22-64-63-64-110 0-71 57-128 128-128s128 57 128 128c0 47-26 88-64 110V224l192 192V530c38 22 64 63 64 110 0 71-57 128-128 128zM128 563c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z m192-640c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z m192 640c-42 0-77 35-77 77s35 77 77 77 77-35 77-77-35-77-77-77z" horiz-adv-x="640" />
+<glyph glyph-name="repo-pull" unicode="&#xf006;" d="M832 320V448H448V576h384V704l192-192-192-192zM256 704h-64v-64h64v64z m448-320h64v-384c0-35-29-64-64-64H384v-128l-96 96-96-96V-64H64c-35 0-64 29-64 64V768C0 803 29 832 64 832h640c35 0 64-29 64-64v-128h-64V768H128v-576h576V384z m0-256H64v-128h128v64h192v-64h320V128zM256 448h-64v-64h64v64z m0 128h-64v-64h64v64z m-64-320h64v64h-64v-64z" horiz-adv-x="1024" />
+<glyph glyph-name="repo-push" unicode="&#xf005;" d="M256 640h-64v64h64v-64z m-64-128h64v64h-64v-64z m256 0L256 256h128v-448h128V256h128L448 512zM704 832H64C29 832 0 803 0 768v-768c0-35 29-64 64-64h256v64H64V128h256v64H128V768h577l-1-576H576v-64h128v-128H576v-64h128c35 0 64 29 64 64V768c0 35-29 64-64 64z" horiz-adv-x="768" />
+<glyph glyph-name="rocket" unicode="&#xf033;" d="M1024 832s-6-24-19-68c-13-45-35-101-68-170-45 5-81 21-106 46s-40 60-45 105c69 33 125 56 169 69 45 13 69 18 69 18zM779 587c-17 17-30 35-40 56-10 20-17 42-22 65-37-21-74-45-111-72-37-28-73-60-108-95-45-45-85-116-114-157H192L0 192h192l128 128c-22-49-65-191-64-192l64-64c1-1 143 41 192 64L384 0v-192l192 192V192c41 29 112 70 157 114 35 35 67 72 94 109 28 37 52 74 73 110-23 5-45 12-66 22-20 10-38 23-55 40z" horiz-adv-x="1024" />
+<glyph glyph-name="rss" unicode="&#xf034;" d="M128 0H0V128c71 0 128-57 128-128zM0 640v-64c318 0 576-258 576-576h64c0 353-287 640-640 640z m0-256v-64c176 0 320-144 320-320h64c0 212-172 384-384 384z" horiz-adv-x="640" />
+<glyph glyph-name="ruby" unicode="&#xf047;" d="M832 448L512 128V576h192l128-128z m192 0L512-64 0 448l256 256h512l256-256zM512 32l416 416-192 192H288L96 448l416-416z" horiz-adv-x="1024" />
+<glyph glyph-name="screen-full" unicode="&#xf066;" d="M832 192h64v-192c0-35-29-64-64-64H640v64h192V192z m-768 0H0v-192c0-35 29-64 64-64h192v64H64V192z m0 448h192v64H64c-35 0-64-29-64-64v-192h64V640z m64-64h640v-512H128V576z m128-384h384V448H256v-256z m576 512H640v-64h192v-192h64V640c0 35-29 64-64 64z" horiz-adv-x="896" />
+<glyph glyph-name="screen-normal" unicode="&#xf067;" d="M128 576H0v64h128V768h64v-128c0-35-29-64-64-64z m0-512H0v-64h128v-128h64V0c0 35-29 64-64 64z m576 128c0-35-29-64-64-64H256c-35 0-64 29-64 64V448c0 35 29 64 64 64h384c35 0 64-29 64-64v-256zM576 384H320v-128h256V384z m128-384v-128h64V0h128v64H768c-35 0-64-29-64-64z m64 640V768h-64v-128c0-35 29-64 64-64h128v64H768z" horiz-adv-x="896" />
+<glyph glyph-name="search" unicode="&#xf02e;" d="M1005-83L761 162c45 63 71 139 71 222 0 212-172 384-384 384S64 596 64 384s172-384 384-384c83 0 159 26 222 71l245-244c12-13 29-19 45-19s33 6 45 19c25 25 25 65 0 90zM448 83c-166 0-301 135-301 301s135 301 301 301 301-135 301-301-135-301-301-301z" horiz-adv-x="1024" />
+<glyph glyph-name="server" unicode="&#xf097;" d="M704 448H64c-35 0-64-29-64-64v-128c0-35 29-64 64-64h640c35 0 64 29 64 64V384c0 35-29 64-64 64zM128 256H64V384h64v-128z m128 0h-64V384h64v-128z m128 0h-64V384h64v-128z m128 0h-64V384h64v-128zM704 768H64C29 768 0 739 0 704v-128c0-35 29-64 64-64h640c35 0 64 29 64 64V704c0 35-29 64-64 64zM128 576H64V704h64v-128z m128 0h-64V704h64v-128z m128 0h-64V704h64v-128z m128 0h-64V704h64v-128z m192 64h-64v64h64v-64z m0-512H64c-35 0-64-29-64-64v-128c0-35 29-64 64-64h640c35 0 64 29 64 64V64c0 35-29 64-64 64zM128-64H64V64h64v-128z m128 0h-64V64h64v-128z m128 0h-64V64h64v-128z m128 0h-64V64h64v-128z" horiz-adv-x="768" />
+<glyph glyph-name="settings" unicode="&#xf07c;" d="M192 384h-64V704h64v-320z m-64-448h64V128h-64v-192z m320 0h64V320h-64v-384z m320 0h64V64h-64v-128z m64 768h-64v-384h64V704z m-320 0h-64v-128h64V704zM256 320H64c-35 0-64-29-64-64s29-64 64-64h192c35 0 64 29 64 64s-29 64-64 64z m320 192H384c-35 0-64-29-64-64s29-64 64-64h192c35 0 64 29 64 64s-29 64-64 64z m320-256H704c-35 0-64-29-64-64s29-64 64-64h192c35 0 64 29 64 64s-29 64-64 64z" horiz-adv-x="1024" />
+<glyph glyph-name="shield" unicode="&#xf0e1;" d="M448 832L0 704v-385c0-299 340-511 448-511s448 212 448 511V704L448 832zM320 128l73 179c3 15-4 30-16 38-36 23-57 61-57 103 0 70 57 128 127 128 69 0 129-58 129-128 0-42-21-80-57-103-12-8-19-23-16-38l73-179H320z" horiz-adv-x="896" />
+<glyph glyph-name="sign-in" unicode="&#xf036;" d="M384 400v-336h256V320h64v-256c0-35-29-64-64-64H384v-192L35-18c-21 11-35 33-35 58V768C0 803 29 832 64 832h576c35 0 64-29 64-64v-192h-64V768H128l256-128v-144l192 144v-128h256v-128H576v-128L384 400z" horiz-adv-x="896" />
+<glyph glyph-name="sign-out" unicode="&#xf032;" d="M768 256V384H512V512h256V640l256-192-256-192zM640 64H384V640L128 768h512v-192h64V768c0 35-29 64-64 64H64C29 832 0 803 0 768v-728c0-25 14-47 35-58l349-174V0h256c35 0 64 29 64 64V320h-64v-256z" horiz-adv-x="1024" />
+<glyph glyph-name="squirrel" unicode="&#xf0b2;" d="M768 768c-141.385 0-256-83.75-256-186.875C512 457.25 544 387 512 192c0 288-177 405.783-256 405.783 3.266 32.17-30.955 42.217-30.955 42.217s-14-7.124-19.354-21.583c-17.231 20.053-36.154 17.54-36.154 17.54l-8.491-37.081c0 0-117.045-40.876-118.635-206.292C56 371 141.311 353.898 201.887 364.882c57.157-2.956 42.991-50.648 30.193-63.446C178.083 247.438 128 320 64 320s-64-64 0-64 64-64 192-64c-198-77 0-256 0-256h-64c-64 0-64-64-64-64s256 0 384 0c192 0 320 64 320 222.182 0 54.34-27.699 114.629-64 162.228C697.057 349.433 782.453 427.566 832 384s192-64 192 128C1024 653.385 909.385 768 768 768zM160 448c-17.674 0-32 14.327-32 32 0 17.674 14.326 32 32 32 17.673 0 32-14.326 32-32C192 462.327 177.673 448 160 448z" horiz-adv-x="1024" />
+<glyph glyph-name="star" unicode="&#xf02a;" d="M896 448l-313.5 40.781L448 768 313.469 488.781 0 448l230.469-208.875L171-63.93799999999999l277 148.812 277.062-148.812L665.5 239.125 896 448z" horiz-adv-x="896" />
+<glyph glyph-name="stop" unicode="&#xf08f;" d="M640 768H256L0 512v-384l256-256h384l256 256V512L640 768z m192-608L608-64H288L64 160V480l224 224h320l224-224v-320zM384 576h128v-320H384V576z m0-384h128v-128H384V192z" horiz-adv-x="896" />
+<glyph glyph-name="sync" unicode="&#xf087;" d="M655.461 358.531c11.875-81.719-13.062-167.781-76.812-230.594-94.188-92.938-239.5-104.375-346.375-34.562l74.875 73L31.96 204.75 70.367-64l84.031 80.5c150.907-111.25 364.938-100.75 502.063 34.562 79.5 78.438 115.75 182.562 111.25 285.312L655.461 358.531zM189.46 511.938c94.156 92.938 239.438 104.438 346.313 34.562l-75-72.969 275.188-38.406L697.586 704l-83.938-80.688C462.711 734.656 248.742 724.031 111.585 588.75 32.085 510.344-4.133 406.219 0.335 303.5l112.25-22.125C100.71 363.125 125.71 449.094 189.46 511.938z" horiz-adv-x="768.051" />
+<glyph glyph-name="tag" unicode="&#xf015;" d="M431 657c-30 30-71 47-113 47H160C72 704 0 632 0 544v-158c0-42 17-83 47-113l388-388c25-25 65-25 90 0l294 294c25 25 25 65 0 90L431 657zM88 314c-20 19-30 45-30 72V544c0 56 46 102 102 102h158c27 0 53-10 72-30l393-392-303-303L88 314z m40 262h128v-128H128V576z" horiz-adv-x="896" />
+<glyph glyph-name="telescope" unicode="&#xf088;" d="M512 256l192-384h-64L512 128v-320h-64V192L320-128h-64l128 320 128 64zM448 832h-64v-64h64V832zM320 640h-64v-64h64v64zM128 768H64v-64h64V768zM40 256c-14-10-18-28-10-43l35-59c8-15 26-20 41-13l89 42-74 128-81-55z m505 345L174 348l79-137 405 194-113 196z m270-82l-94 161c-9 16-30 21-46 11l-77-53 118-205 85 41c17 8 23 28 14 45z" horiz-adv-x="896" />
+<glyph glyph-name="terminal" unicode="&#xf0c8;" d="M448 192h256v-64H448v64z m-192-64l192 192-192 192-48-48 144-144-144-144 48-48z m640 512v-640c0-35-29-64-64-64H64c-35 0-64 29-64 64V640c0 35 29 64 64 64h768c35 0 64-29 64-64z m-64 0H64v-640h768V640z" horiz-adv-x="896" />
+<glyph glyph-name="three-bars" unicode="&#xf05e;" d="M0 640v-128h768v128h-768z m0-384h768v128h-768v-128z m0-256h768v128h-768v-128z" horiz-adv-x="768" />
+<glyph glyph-name="thumbsdown" unicode="&#xf0db;" d="M871 347c9 19 15 40 15 62 0 51-28 96-69 120 4 13 6 27 6 41 0 50-26 93-65 118 2 8 10 19 10 27C768 781 709 832 640 832c0 0-212 0-222 0-88 0-170-43-242-81-42-22-89-47-113-47H0v-576h64c37-2 155-69 206-112 12-10 173-168 173-168 26-26 60-40 96-40 35 0 68 13 92 38 51 51 50 135-2 188-20 20-94 115-117 138l256-44c76 0 128 59 128 131 0 34-3 64-25 88zM768 192l-384 64c-7 0 200-266 200-266 28-29 29-73 3-100-13-13-30-19-48-19s-37 7-52 21L347 34c-86 71-216 158-283 158V642c87 0 221 126 352 126h224c34 0 64-20 64-53 0-34-30-75-64-75h48c45 0 72-25 72-70 0-44-36-90-81-90h63c45 0 81-26 81-71 0-44-36-80-81-80h27c42 0 63-32 63-70 0-39-23-67-64-67z" horiz-adv-x="896" />
+<glyph glyph-name="thumbsup" unicode="&#xf0da;" d="M896 381c0 72-52 131-128 131l-256-44c23 23 97 118 117 138 52 53 53 137 2 188-24 25-57 38-92 38-36 0-70-14-96-40 0 0-161-158-173-168-51-43-169-110-206-112H0v-576h63c24 0 71-25 113-47 72-38 154-81 242-81 10 0 222 0 222 0 69 0 128 51 128 117 0 8-8 19-10 27 39 25 65 68 65 118 0 14-2 28-6 41 41 24 69 69 69 120 0 22-6 43-15 62 22 24 25 54 25 88z m-64 0c0-38-21-70-63-70h-27c45 0 81-36 81-80 0-45-36-71-81-71h-63c45 0 81-46 81-90 0-45-27-70-72-70h-48c34 0 64-41 64-75 0-33-30-53-64-53H416c-131 0-265 126-352 126V448c67 0 197 87 283 158L487 748c15 14 34 21 52 21s35-6 48-19c26-27 25-71-3-100 0 0-207-266-200-266l384 64c41 0 64-28 64-67z" horiz-adv-x="896" />
+<glyph glyph-name="tools" unicode="&#xf031;" d="M286.547 366.984c16.843-16.812 81.716-85.279 81.716-85.279l35.968 37.093-56.373 58.248L456.072 491.98c0 0-48.842 47.623-27.468 28.655 20.438 75.903 1.812 160.589-55.842 220.243C315.608 800.064 234.392 819.47 161.425 799.096l123.653-127.715-32.53-125.309-121.06-33.438L7.898 640.3820000000001c-19.718-75.436-0.969-159.339 56.311-218.556C124.302 359.703 210.83 341.453 286.547 366.984zM698.815 242.769L549.694 95.46100000000001l245.932-254.805c20.062-20.812 46.498-31.188 72.872-31.188 26.25 0 52.624 10.375 72.811 31.188 40.249 41.624 40.249 108.997 0 150.62L698.815 242.769zM1023.681 670.162L867.06 832.001 405.387 354.703l56.373-58.248L185.425 10.839000000000055l-63.154-33.749-89.217-145.559 22.719-23.562 140.839 92.247 32.655 65.312 276.336 285.554 56.404-58.248L1023.681 670.162z" horiz-adv-x="1024" />
+<glyph glyph-name="trashcan" unicode="&#xf0d0;" d="M640 704H512c0 35-29 64-64 64H256c-35 0-64-29-64-64H64c-35 0-64-29-64-64v-64c0-35 29-64 64-64v-576c0-35 29-64 64-64h448c35 0 64 29 64 64V512c35 0 64 29 64 64v64c0 35-29 64-64 64z m-64-768H128V512h64v-512h64V512h64v-512h64V512h64v-512h64V512h64v-576z m64 640H64v64h576v-64z" horiz-adv-x="768" />
+<glyph glyph-name="triangle-down" unicode="&#xf05b;" d="M0 448l383.75-383.75L767.5 448H0z" horiz-adv-x="767.5" />
+<glyph glyph-name="triangle-left" unicode="&#xf044;" d="M0 320.125l383.75-383.75v767.5L0 320.125z" horiz-adv-x="383.75" />
+<glyph glyph-name="triangle-right" unicode="&#xf05a;" d="M0.062 703.75L383.812 320 0.062-63.75V703.75z" horiz-adv-x="383.875" />
+<glyph glyph-name="triangle-up" unicode="&#xf0aa;" d="M383.75 576L0 192.25h767.5L383.75 576z" horiz-adv-x="767.5" />
+<glyph glyph-name="unfold" unicode="&#xf039;" d="M736 288l160-160c0-35-29-64-64-64H576v64h224L672 256H224L96 128h224v-64H64c-35 0-64 29-64 64l160 160L0 448c0 35 29 64 64 64h256v-64H96l128-128h448l128 128H576v64h256c35 0 64-29 64-64L736 288z m-352 96h128V576h128L448 768 256 576h128v-192z m128-192H384v-192H256l192-192 192 192H512V192z" horiz-adv-x="896" />
+<glyph glyph-name="unmute" unicode="&#xf0ba;" d="M704 319c0-70-29-134-75-181l-43 43c35 36 57 84 57 138s-22 103-57 138l43 43c46-46 75-110 75-181zM430 686L192 448H64c-35 0-64-29-64-64v-128c0-35 29-64 64-64h128l238-238c30-30 82-9 82 34V652c0 43-52 64-82 34z m380-5l-43-43c82-82 132-194 132-319 0-124-50-237-132-319l43-43c93 93 150 221 150 362 0 142-57 270-150 362z m-90-90l-44-43c59-59 95-140 95-229s-36-170-95-228l44-43c69 69 112 165 112 271s-43 202-112 272z" horiz-adv-x="1024" />
+<glyph glyph-name="versions" unicode="&#xf064;" d="M832 640H448c-35 0-64-29-64-64v-512c0-35 29-64 64-64h384c35 0 64 29 64 64V576c0 35-29 64-64 64z m-64-512H512V512h256v-384zM256 576h64v-64h-64v-384h64v-64h-64c-35 0-64 29-64 64V512c0 35 29 64 64 64zM64 512h64v-64H64v-256h64v-64H64c-35 0-64 29-64 64V448c0 35 29 64 64 64z" horiz-adv-x="896" />
+<glyph glyph-name="watch" unicode="&#xf0e0;" d="M384 320h128v-64H320V512h64v-192z m384 0c0-142-77-266-192-332v-116c0-35-29-64-64-64H256c-35 0-64 29-64 64V-12C77 54 0 178 0 320s77 266 192 332V768c0 35 29 64 64 64h256c35 0 64-29 64-64v-116c115-66 192-190 192-332z m-64 0c0 177-143 320-320 320S64 497 64 320s143-320 320-320 320 143 320 320z" horiz-adv-x="768" />
+<glyph glyph-name="x" unicode="&#xf081;" d="M479 320l240-240-95-95-240 240-240-240-95 95 240 240L49 560l95 95 240-240 240 240 95-95-240-240z" horiz-adv-x="768" />
+<glyph glyph-name="zap" unicode="&#x26A1;" d="M640 384H384L576 832 0 256h256L64-192 640 384z" horiz-adv-x="640" />
+</font>
+</defs>
+</svg>
diff --git a/vendor/assets/fonts/octicons.ttf b/vendor/assets/fonts/octicons.ttf
new file mode 100755
index 0000000..32e6720
--- /dev/null
+++ b/vendor/assets/fonts/octicons.ttf
Binary files differ
diff --git a/vendor/assets/fonts/octicons.woff b/vendor/assets/fonts/octicons.woff
new file mode 100755
index 0000000..cbf9f62
--- /dev/null
+++ b/vendor/assets/fonts/octicons.woff
Binary files differ
diff --git a/vendor/assets/javascripts/.keep b/vendor/assets/javascripts/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vendor/assets/javascripts/.keep
diff --git a/vendor/assets/javascripts/d3.min.js b/vendor/assets/javascripts/d3.min.js
new file mode 100644
index 0000000..1984d17
--- /dev/null
+++ b/vendor/assets/javascripts/d3.min.js
@@ -0,0 +1,5 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function r(n){return null===n?0/0:+n}function u(n){return!isNaN(n)}function i(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function l(){this._=Object.create(null)}function s(n){return(n+="")===pa||n[0]===va?va+n:n}function f(n){return(n+="")[0]===va?n.slice(1):n}function h(n){return s(n)in this._}function g(n){return(n=s(n))in this._&&delete this._[n]}function p(){var n=[];for(var t in this._)n.push(f(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function m(){this._=Object.create(null)}function y(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=da.length;r>e;++e){var u=da[e]+t;if(u in n)return u}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new l;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function S(){ta.event.preventDefault()}function k(){for(var n,t=ta.event;n=t.sourceEvent;)t=n;return t}function E(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=ta.event;u.target=n,ta.event=u,t[u.type].apply(e,r)}finally{ta.event=i}}},t}function A(n){return ya(n,_a),n}function N(n){return"function"==typeof n?n:function(){return Ma(n,this)}}function C(n){return"function"==typeof n?n:function(){return xa(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ta.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function q(n){return n.trim().replace(/\s+/g," ")}function L(n){return new RegExp("(?:^|\\s+)"+ta.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=T(n).map(D);var u=n.length;return"function"==typeof t?r:e}function D(n){var t=L(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",q(u+" "+n))):e.setAttribute("class",q(u.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e?t.createElementNS(e,n):t.createElement(n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ta.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return ba(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function Z(n){return ya(n,Sa),n}function V(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,ra(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+ta.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=$;a>0&&(n=n.slice(0,a));var l=ka.get(n);return l&&(n=l,c=B),a?t?u:r:t?b:i}function $(n,t){return function(e){var r=ta.event;ta.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ta.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Aa,u="click"+r,i=ta.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ea&&(Ea="onselectstart"in e?!1:x(e.style,"userSelect")),Ea){var o=n(e).style,a=o[Ea];o[Ea]="none"}return function(n){if(i.on(r,null),Ea&&(o[Ea]=a),n){var t=function(){i.on(u,null)};i.on(u,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var u=r.createSVGPoint();if(0>Na){var i=t(n);if(i.scrollX||i.scrollY){r=ta.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Na=!(o.f||o.e),r.remove()}}return Na?(u.x=e.pageX,u.y=e.pageY):(u.x=e.clientX,u.y=e.clientY),u=u.matrixTransform(n.getScreenCTM().inverse()),[u.x,u.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ta.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nt(n){return n>1?0:-1>n?qa:Math.acos(n)}function tt(n){return n>1?Ra:-1>n?-Ra:Math.asin(n)}function et(n){return((n=Math.exp(n))-1/n)/2}function rt(n){return((n=Math.exp(n))+1/n)/2}function ut(n){return((n=Math.exp(2*n))-1)/(n+1)}function it(n){return(n=Math.sin(n/2))*n}function ot(){}function at(n,t,e){return this instanceof at?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof at?new at(n.h,n.s,n.l):bt(""+n,_t,at):new at(n,t,e)}function ct(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new mt(u(n+120),u(n),u(n-120))}function lt(n,t,e){return this instanceof lt?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof lt?new lt(n.h,n.c,n.l):n instanceof ft?gt(n.l,n.a,n.b):gt((n=wt((n=ta.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new lt(n,t,e)}function st(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new ft(e,Math.cos(n*=Da)*t,Math.sin(n)*t)}function ft(n,t,e){return this instanceof ft?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof ft?new ft(n.l,n.a,n.b):n instanceof lt?st(n.h,n.c,n.l):wt((n=mt(n)).r,n.g,n.b):new ft(n,t,e)}function ht(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=pt(u)*Xa,r=pt(r)*$a,i=pt(i)*Ba,new mt(dt(3.2404542*u-1.5371385*r-.4985314*i),dt(-.969266*u+1.8760108*r+.041556*i),dt(.0556434*u-.2040259*r+1.0572252*i))}function gt(n,t,e){return n>0?new lt(Math.atan2(e,t)*Pa,Math.sqrt(t*t+e*e),n):new lt(0/0,0/0,n)}function pt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function vt(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function dt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mt(n,t,e){return this instanceof mt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mt?new mt(n.r,n.g,n.b):bt(""+n,mt,ct):new mt(n,t,e)}function yt(n){return new mt(n>>16,n>>8&255,255&n)}function Mt(n){return yt(n)+""}function xt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(kt(u[0]),kt(u[1]),kt(u[2]))}return(i=Ga.get(n))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function _t(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new at(r,u,c)}function wt(n,t,e){n=St(n),t=St(t),e=St(e);var r=vt((.4124564*n+.3575761*t+.1804375*e)/Xa),u=vt((.2126729*n+.7151522*t+.072175*e)/$a),i=vt((.0193339*n+.119192*t+.9503041*e)/Ba);return ft(116*u-16,500*(r-u),200*(u-i))}function St(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function kt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Et(n){return"function"==typeof n?n:function(){return n}}function At(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Nt(t,e,n,r)}}function Nt(n,t,e,r){function u(){var n,t=c.status;if(!t&&zt(c)||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return void o.error.call(i,r)}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=ta.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=ta.event;ta.event=n;try{o.progress.call(i,c)}finally{ta.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(ra(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},ta.rebind(i,o,"on"),null==r?i:i.get(Ct(r))}function Ct(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function zt(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qt(){var n=Lt(),t=Tt()-n;t>24?(isFinite(t)&&(clearTimeout(tc),tc=setTimeout(qt,t)),nc=0):(nc=1,rc(qt))}function Lt(){var n=Date.now();for(ec=Ka;ec;)n>=ec.t&&(ec.f=ec.c(n-ec.t)),ec=ec.n;return n}function Tt(){for(var n,t=Ka,e=1/0;t;)t.f?t=n?n.n=t.n:Ka=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Qa=n,e}function Rt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Dt(n,t){var e=Math.pow(10,3*ga(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Pt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],o=0,a=r[0],c=0;u>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),i.push(n.substring(u-=a,u+a)),!((c+=a+1)>t));)a=r[o=(o+1)%r.length];return i.reverse().join(e)}:y;return function(n){var e=ic.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",c=e[4]||"",l=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===o)&&(l=r="0",o="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=oc.get(g)||Ut;var M=l&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>p){var c=ta.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=y?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!l&&f&&(x=i(x,1/0));var S=v.length+x.length+b.length+(M?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return M&&(x=i(k+x,k.length?s-b.length:1/0)),u+=v,n=x+b,("<"===o?u+n+k:">"===o?k+u+n:"^"===o?k.substring(0,S>>=1)+u+n+k.substring(S):u+(M?n:k+n))+e}}}function Ut(n){return n+""}function jt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ft(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new cc(e-1)),1),e}function i(n,e){return t(n=new cc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{cc=jt;var r=new jt;return r._=n,o(r,t,e)}finally{cc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Ht(n);return c.floor=c,c.round=Ht(r),c.ceil=Ht(u),c.offset=Ht(i),c.range=a,n}function Ht(n){return function(t,e){try{cc=jt;var r=new jt;return r._=t,n(r,e)._}finally{cc=Date}}}function Ot(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(u=sc[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=N[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.slice(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&cc!==jt,o=new(i?jt:cc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=C[o in sc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.slice(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,N.c.toString(),t,r)}function c(n,t,r){return e(n,N.x.toString(),t,r)}function l(n,t,r){return e(n,N.X.toString(),t,r)}function s(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{cc=jt;var t=new cc;return t._=n,r(t)}finally{cc=Date}}var r=t(n);return e.parse=function(n){try{cc=jt;var t=r.parse(n);return t&&t._}finally{cc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ae;var M=ta.map(),x=Yt(v),b=Zt(v),_=Yt(d),w=Zt(d),S=Yt(m),k=Zt(m),E=Yt(y),A=Zt(y);p.forEach(function(n,t){M.set(n.toLowerCase(),t)});var N={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return It(n.getDate(),t,2)},e:function(n,t){return It(n.getDate(),t,2)},H:function(n,t){return It(n.getHours(),t,2)},I:function(n,t){return It(n.getHours()%12||12,t,2)},j:function(n,t){return It(1+ac.dayOfYear(n),t,3)},L:function(n,t){return It(n.getMilliseconds(),t,3)},m:function(n,t){return It(n.getMonth()+1,t,2)},M:function(n,t){return It(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return It(n.getSeconds(),t,2)},U:function(n,t){return It(ac.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return It(ac.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return It(n.getFullYear()%100,t,2)},Y:function(n,t){return It(n.getFullYear()%1e4,t,4)},Z:ie,"%":function(){return"%"}},C={a:r,A:u,b:i,B:o,c:a,d:Qt,e:Qt,H:te,I:te,j:ne,L:ue,m:Kt,M:ee,p:s,S:re,U:Xt,w:Vt,W:$t,x:c,X:l,y:Wt,Y:Bt,Z:Jt,"%":oe};return t}function It(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Yt(n){return new RegExp("^(?:"+n.map(ta.requote).join("|")+")","i")}function Zt(n){for(var t=new l,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Vt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Xt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function $t(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Bt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Wt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.y=Gt(+r[0]),e+r[0].length):-1}function Jt(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Gt(n){return n+(n>68?1900:2e3)}function Kt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function ne(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function te(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ee(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function re(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ue(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ie(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=ga(t)/60|0,u=ga(t)%60;return e+It(r,"0",2)+It(u,"0",2)}function oe(n,t,e){hc.lastIndex=0;var r=hc.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ae(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ce(){}function le(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function se(n,t){n&&dc.hasOwnProperty(n.type)&&dc[n.type](n,t)}function fe(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function he(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)fe(n[e],t,1);t.polygonEnd()}function ge(){function n(n,t){n*=Da,t=t*Da/2+qa/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),l=Math.sin(t),s=i*l,f=u*c+s*Math.cos(a),h=s*o*Math.sin(a);yc.add(Math.atan2(h,f)),r=n,u=c,i=l}var t,e,r,u,i;Mc.point=function(o,a){Mc.point=n,r=(t=o)*Da,u=Math.cos(a=(e=a)*Da/2+qa/4),i=Math.sin(a)},Mc.lineEnd=function(){n(t,e)}}function pe(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function ve(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function de(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function me(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function ye(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Me(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function xe(n){return[Math.atan2(n[1],n[0]),tt(n[2])]}function be(n,t){return ga(n[0]-t[0])<Ca&&ga(n[1]-t[1])<Ca}function _e(n,t){n*=Da;var e=Math.cos(t*=Da);we(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function we(n,t,e){++xc,_c+=(n-_c)/xc,wc+=(t-wc)/xc,Sc+=(e-Sc)/xc}function Se(){function n(n,u){n*=Da;var i=Math.cos(u*=Da),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),l=Math.atan2(Math.sqrt((l=e*c-r*a)*l+(l=r*o-t*c)*l+(l=t*a-e*o)*l),t*o+e*a+r*c);bc+=l,kc+=l*(t+(t=o)),Ec+=l*(e+(e=a)),Ac+=l*(r+(r=c)),we(t,e,r)}var t,e,r;qc.point=function(u,i){u*=Da;var o=Math.cos(i*=Da);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),qc.point=n,we(t,e,r)}}function ke(){qc.point=_e}function Ee(){function n(n,t){n*=Da;var e=Math.cos(t*=Da),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),l=u*c-i*a,s=i*o-r*c,f=r*a-u*o,h=Math.sqrt(l*l+s*s+f*f),g=r*o+u*a+i*c,p=h&&-nt(g)/h,v=Math.atan2(h,g);Nc+=p*l,Cc+=p*s,zc+=p*f,bc+=v,kc+=v*(r+(r=o)),Ec+=v*(u+(u=a)),Ac+=v*(i+(i=c)),we(r,u,i)}var t,e,r,u,i;qc.point=function(o,a){t=o,e=a,qc.point=n,o*=Da;var c=Math.cos(a*=Da);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),we(r,u,i)},qc.lineEnd=function(){n(t,e),qc.lineEnd=ke,qc.point=_e}}function Ae(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function Ne(){return!0}function Ce(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(be(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return void u.lineEnd()}var c=new qe(e,n,null,!0),l=new qe(e,null,c,!1);c.o=l,i.push(c),o.push(l),c=new qe(r,n,null,!1),l=new qe(r,null,c,!0),c.o=l,i.push(c),o.push(l)}}),o.sort(t),ze(i),ze(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].e=c=!c;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,l=s.length;l>a;++a)u.point((f=s[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var a=s.length-1;a>=0;--a)u.point((f=s[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ze(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function qe(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Le(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function l(){y.point=o,d.lineEnd()}function s(n,t){v.push([n,t]);var e=u(n,t);x.point(e[0],e[1])}function f(){x.lineStart(),v=[]}function h(){s(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(b||(i.polygonStart(),b=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Te))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=ta.merge(g);var n=Fe(m,p);g.length?(b||(i.polygonStart(),b=!0),Ce(g,De,n,e,i)):n&&(b||(i.polygonStart(),b=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),b&&(i.polygonEnd(),b=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Re(),x=t(M),b=!1;return y}}function Te(n){return n.length>1}function Re(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function De(n,t){return((n=n.x)[0]<0?n[1]-Ra-Ca:Ra-n[1])-((t=t.x)[0]<0?t[1]-Ra-Ca:Ra-t[1])}function Pe(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?qa:-qa,c=ga(i-e);ga(c-qa)<Ca?(n.point(e,r=(r+o)/2>0?Ra:-Ra),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=qa&&(ga(e-u)<Ca&&(e-=u*Ca),ga(i-a)<Ca&&(i-=a*Ca),r=Ue(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function Ue(n,t,e,r){var u,i,o=Math.sin(n-e);return ga(o)>Ca?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function je(n,t,e,r){var u;if(null==n)u=e*Ra,r.point(-qa,u),r.point(0,u),r.point(qa,u),r.point(qa,0),r.point(qa,-u),r.point(0,-u),r.point(-qa,-u),r.point(-qa,0),r.point(-qa,u);else if(ga(n[0]-t[0])>Ca){var i=n[0]<t[0]?qa:-qa;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function Fe(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;yc.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+qa/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=l[d];var m=n[0],y=n[1]/2+qa/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=b>=0?1:-1,w=_*b,S=w>qa,k=p*M;if(yc.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),i+=S?b+_*La:b,S^h>=e^m>=e){var E=de(pe(f),pe(n));Me(E);var A=de(u,E);Me(A);var N=(S^b>=0?-1:1)*tt(A[2]);(r>N||r===N&&(E[0]||E[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=m,p=M,v=x,f=n}}return(-Ca>i||Ca>i&&0>yc)^1&o}function He(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?qa:-qa),h):0;if(!e&&(l=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(be(e,g)||be(p,g))&&(p[0]+=Ca,p[1]+=Ca,v=t(p[0],p[1]))),v!==c)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&be(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=pe(n),u=pe(t),o=[1,0,0],a=de(r,u),c=ve(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=de(o,a),p=ye(o,f),v=ye(a,h);me(p,v);var d=g,m=ve(p,d),y=ve(d,d),M=m*m-y*(ve(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=ye(d,(-m-x)/y);if(me(b,p),b=xe(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=ga(A-qa)<Ca,C=N||Ca>A;if(!N&&k>E&&(_=k,k=E,E=_),C?N?k+E>0^b[1]<(ga(b[0]-w)<Ca?k:E):k<=b[1]&&b[1]<=E:A>qa^(w<=b[0]&&b[0]<=S)){var z=ye(d,(-m+x)/y);return me(z,p),[b,xe(z)]}}}function u(t,e){var r=o?n:qa-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ga(i)>Ca,c=gr(n,6*Da);return Le(t,e,c,o?[0,-n]:[-qa,n-qa])}function Oe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,l=o.y,s=a.x,f=a.y,h=0,g=1,p=s-c,v=f-l;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-l,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-l,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:l+h*v}),1>g&&(u.b={x:c+g*p,y:l+g*v}),u}}}}}}function Ie(n,t,e,r){function u(r,u){return ga(r[0]-n)<Ca?u>0?0:3:ga(r[0]-e)<Ca?u>0?2:1:ga(r[1]-t)<Ca?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&Q(l,i,n)>0&&++t:i[1]<=r&&Q(l,i,n)<0&&--t,l=i;return 0!==t}function l(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&a.point(n,t)}function h(){C.point=p,d&&d.push(m=[]),S=!0,w=!1,b=_=0/0}function g(){v&&(p(y,M),x&&w&&A.rejoin(),v.push(A.buffer())),C.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Tc,Math.min(Tc,n)),t=Math.max(-Tc,Math.min(Tc,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};N(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,m,y,M,x,b,_,w,S,k,E=a,A=Re(),N=Oe(n,t,e,r),C={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=ta.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Ce(v,i,t,l,a),a.polygonEnd()),v=d=m=null}};return C}}function Ye(n){var t=0,e=qa/3,r=ir(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*qa/180,e=n[1]*qa/180):[t/qa*180,e/qa*180]},u}function Ze(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,tt((i-(n*n+e*e)*u*u)/(2*u))]},e}function Ve(){function n(n,t){Dc+=u*n-r*t,r=n,u=t}var t,e,r,u;Hc.point=function(i,o){Hc.point=n,t=r=i,e=u=o},Hc.lineEnd=function(){n(t,e)}}function Xe(n,t){Pc>n&&(Pc=n),n>jc&&(jc=n),Uc>t&&(Uc=t),t>Fc&&(Fc=t)}function $e(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Be(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Be(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Be(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function We(n,t){_c+=n,wc+=t,++Sc}function Je(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);kc+=o*(t+n)/2,Ec+=o*(e+r)/2,Ac+=o,We(t=n,e=r)}var t,e;Ic.point=function(r,u){Ic.point=n,We(t=r,e=u)}}function Ge(){Ic.point=We}function Ke(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);kc+=o*(r+n)/2,Ec+=o*(u+t)/2,Ac+=o,o=u*n-r*t,Nc+=o*(r+n),Cc+=o*(u+t),zc+=3*o,We(r=n,u=t)}var t,e,r,u;Ic.point=function(i,o){Ic.point=n,We(t=r=i,e=u=o)},Ic.lineEnd=function(){n(t,e)}}function Qe(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,La)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function nr(n){function t(n){return(a?r:e)(n)}function e(t){return rr(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=0/0,S.point=i,t.lineStart()}function i(e,r){var i=pe([e,r]),o=n(e,r);u(M,x,y,b,_,w,M=o[0],x=o[1],y=e,b=i[0],_=i[1],w=i[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=l,S.lineEnd=s}function l(n,t){i(f=n,h=t),g=M,p=x,v=b,d=_,m=w,S.point=i}function s(){u(M,x,y,b,_,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c
+},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,l,s,f,h,g,p,v,d,m){var y=s-t,M=f-e,x=y*y+M*M;if(x>4*i&&d--){var b=a+g,_=c+p,w=l+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),E=ga(ga(w)-1)<Ca||ga(r-h)<Ca?(r+h)/2:Math.atan2(_,b),A=n(E,k),N=A[0],C=A[1],z=N-t,q=C-e,L=M*z-y*q;(L*L/x>i||ga((y*z+M*q)/x-.5)>.3||o>a*g+c*p+l*v)&&(u(t,e,r,a,c,l,N,C,E,b/=S,_/=S,w,d,m),m.point(N,C),u(N,C,E,b,_,w,s,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Da),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function tr(n){var t=nr(function(t,e){return n([t*Pa,e*Pa])});return function(n){return or(t(n))}}function er(n){this.stream=n}function rr(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function ur(n){return ir(function(){return n})()}function ir(n){function t(n){return n=a(n[0]*Da,n[1]*Da),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Pa,n[1]*Pa]}function r(){a=Ae(o=lr(m,M,x),i);var n=i(v,d);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=nr(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,M=0,x=0,b=Lc,_=y,w=null,S=null;return t.stream=function(n){return s&&(s.valid=!1),s=or(b(o,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Lc):He((w=+n)*Da),u()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Ie(n[0][0],n[0][1],n[1][0],n[1][1]):y,u()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Da,d=n[1]%360*Da,r()):[v*Pa,d*Pa]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Da,M=n[1]%360*Da,x=n.length>2?n[2]%360*Da:0,r()):[m*Pa,M*Pa,x*Pa]},ta.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function or(n){return rr(n,function(t,e){n.point(t*Da,e*Da)})}function ar(n,t){return[n,t]}function cr(n,t){return[n>qa?n-La:-qa>n?n+La:n,t]}function lr(n,t,e){return n?t||e?Ae(fr(n),hr(t,e)):fr(n):t||e?hr(t,e):cr}function sr(n){return function(t,e){return t+=n,[t>qa?t-La:-qa>t?t+La:t,e]}}function fr(n){var t=sr(n);return t.invert=sr(-n),t}function hr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),tt(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),tt(s*r-a*u)]},e}function gr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=pr(e,u),i=pr(e,i),(o>0?i>u:u>i)&&(u+=o*La)):(u=n+o*La,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=xe([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function pr(n,t){var e=pe(t);e[0]-=n,Me(e);var r=nt(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Ca)%(2*Math.PI)}function vr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function dr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function mr(n){return n.source}function yr(n){return n.target}function Mr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(it(r-t)+u*o*it(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Pa,Math.atan2(o,Math.sqrt(r*r+u*u))*Pa]}:function(){return[n*Pa,t*Pa]};return p.distance=h,p}function xr(){function n(n,u){var i=Math.sin(u*=Da),o=Math.cos(u),a=ga((n*=Da)-t),c=Math.cos(a);Yc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Zc.point=function(u,i){t=u*Da,e=Math.sin(i*=Da),r=Math.cos(i),Zc.point=n},Zc.lineEnd=function(){Zc.point=Zc.lineEnd=b}}function br(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function _r(n,t){function e(n,t){o>0?-Ra+Ca>t&&(t=-Ra+Ca):t>Ra-Ca&&(t=Ra-Ca);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(qa/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=K(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ra]},e):Sr}function wr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ga(u)<Ca?ar:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-K(u)*Math.sqrt(n*n+e*e)]},e)}function Sr(n,t){return[n,Math.log(Math.tan(qa/4+t/2))]}function kr(n){var t,e=ur(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=qa*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(qa/4+t/2)),-n]}function Ar(n){return n[0]}function Nr(n){return n[1]}function Cr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function zr(n,t){return n[0]-t[0]||n[1]-t[1]}function qr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Lr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function Tr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Rr(){tu(this),this.edge=this.site=this.circle=null}function Dr(n){var t=el.pop()||new Rr;return t.site=n,t}function Pr(n){Xr(n),Qc.remove(n),el.push(n),tu(n)}function Ur(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Pr(n);for(var c=i;c.circle&&ga(e-c.circle.x)<Ca&&ga(r-c.circle.cy)<Ca;)i=c.P,a.unshift(c),Pr(c),c=i;a.unshift(c),Xr(c);for(var l=o;l.circle&&ga(e-l.circle.x)<Ca&&ga(r-l.circle.cy)<Ca;)o=l.N,a.push(l),Pr(l),l=o;a.push(l),Xr(l);var s,f=a.length;for(s=1;f>s;++s)l=a[s],c=a[s-1],Kr(l.edge,c.site,l.site,u);c=a[0],l=a[f-1],l.edge=Jr(c.site,l.site,null,u),Vr(c),Vr(l)}function jr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Qc._;a;)if(r=Fr(a,o)-i,r>Ca)a=a.L;else{if(u=i-Hr(a,o),!(u>Ca)){r>-Ca?(t=a.P,e=a):u>-Ca?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Dr(n);if(Qc.insert(t,c),t||e){if(t===e)return Xr(t),e=Dr(t.site),Qc.insert(c,e),c.edge=e.edge=Jr(t.site,c.site),Vr(t),void Vr(e);if(!e)return void(c.edge=Jr(t.site,c.site));Xr(t),Xr(e);var l=t.site,s=l.x,f=l.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,M=v*v+d*d,x={x:(d*y-g*M)/m+s,y:(h*M-v*y)/m+f};Kr(e.edge,l,p,x),c.edge=Jr(l,n,null,x),e.edge=Jr(n,p,null,x),Vr(t),Vr(e)}}function Fr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,l=c-t;if(!l)return a;var s=a-r,f=1/i-1/l,h=s/l;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*l)-c+l/2+u-i/2)))/f+r:(r+a)/2}function Hr(n,t){var e=n.N;if(e)return Fr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Or(n){this.site=n,this.edges=[]}function Ir(n){for(var t,e,r,u,i,o,a,c,l,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Kc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)s=a[o].end(),r=s.x,u=s.y,l=a[++o%c].start(),t=l.x,e=l.y,(ga(r-t)>Ca||ga(u-e)>Ca)&&(a.splice(o,0,new Qr(Gr(i.site,s,ga(r-f)<Ca&&p-u>Ca?{x:f,y:ga(t-f)<Ca?e:p}:ga(u-p)<Ca&&h-r>Ca?{x:ga(e-p)<Ca?t:h,y:p}:ga(r-h)<Ca&&u-g>Ca?{x:h,y:ga(t-h)<Ca?e:g}:ga(u-g)<Ca&&r-f>Ca?{x:ga(e-g)<Ca?t:f,y:g}:null),i.site,null)),++c)}function Yr(n,t){return t.angle-n.angle}function Zr(){tu(this),this.x=this.y=this.arc=this.site=this.cy=null}function Vr(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,l=r.y-a,s=i.x-o,f=i.y-a,h=2*(c*f-l*s);if(!(h>=-za)){var g=c*c+l*l,p=s*s+f*f,v=(f*g-l*p)/h,d=(c*p-s*g)/h,f=d+a,m=rl.pop()||new Zr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,M=tl._;M;)if(m.y<M.y||m.y===M.y&&m.x<=M.x){if(!M.L){y=M.P;break}M=M.L}else{if(!M.R){y=M;break}M=M.R}tl.insert(y,m),y||(nl=m)}}}}function Xr(n){var t=n.circle;t&&(t.P||(nl=t.N),tl.remove(t),rl.push(t),tu(t),n.circle=null)}function $r(n){for(var t,e=Gc,r=Oe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Br(t,n)||!r(t)||ga(t.a.x-t.b.x)<Ca&&ga(t.a.y-t.b.y)<Ca)&&(t.a=t.b=null,e.splice(u,1))}function Br(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],s=n.l,f=n.r,h=s.x,g=s.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=l)return}else i={x:d,y:c};e={x:d,y:l}}else{if(i){if(i.y<c)return}else i={x:d,y:l};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=l)return}else i={x:(c-u)/r,y:c};e={x:(l-u)/r,y:l}}else{if(i){if(i.y<c)return}else i={x:(l-u)/r,y:l};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Wr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Jr(n,t,e,r){var u=new Wr(n,t);return Gc.push(u),e&&Kr(u,n,t,e),r&&Kr(u,t,n,r),Kc[n.i].edges.push(new Qr(u,n,t)),Kc[t.i].edges.push(new Qr(u,t,n)),u}function Gr(n,t,e){var r=new Wr(n,null);return r.a=t,r.b=e,Gc.push(r),r}function Kr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Qr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function nu(){this._=null}function tu(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function eu(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ru(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function uu(n){for(;n.L;)n=n.L;return n}function iu(n,t){var e,r,u,i=n.sort(ou).pop();for(Gc=[],Kc=new Array(n.length),Qc=new nu,tl=new nu;;)if(u=nl,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Kc[i.i]=new Or(i),jr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;Ur(u.arc)}t&&($r(t),Ir(t));var o={cells:Kc,edges:Gc};return Qc=tl=Gc=Kc=null,o}function ou(n,t){return t.y-n.y||t.x-n.x}function au(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function cu(n){return n.x}function lu(n){return n.y}function su(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function fu(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&fu(n,c[0],e,r,o,a),c[1]&&fu(n,c[1],o,r,u,a),c[2]&&fu(n,c[2],e,a,o,i),c[3]&&fu(n,c[3],o,a,u,i)}}function hu(n,t,e,r,u,i,o){var a,c=1/0;return function l(n,s,f,h,g){if(!(s>i||f>o||r>h||u>g)){if(p=n.point){var p,v=t-n.x,d=e-n.y,m=v*v+d*d;if(c>m){var y=Math.sqrt(c=m);r=t-y,u=e-y,i=t+y,o=e+y,a=p}}for(var M=n.nodes,x=.5*(s+h),b=.5*(f+g),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:l(n,s,f,x,b);break;case 1:l(n,x,f,h,b);break;case 2:l(n,s,b,x,g);break;case 3:l(n,x,b,h,g)}}}(n,r,u,i,o),a}function gu(n,t){n=ta.rgb(n),t=ta.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+xt(Math.round(e+i*n))+xt(Math.round(r+o*n))+xt(Math.round(u+a*n))}}function pu(n,t){var e,r={},u={};for(e in n)e in t?r[e]=mu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function vu(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function du(n,t){var e,r,u,i=il.lastIndex=ol.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=il.exec(n))&&(r=ol.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:vu(e,r)})),i=ol.lastIndex;return i<t.length&&(u=t.slice(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function mu(n,t){for(var e,r=ta.interpolators.length;--r>=0&&!(e=ta.interpolators[r](n,t)););return e}function yu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(mu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Mu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function xu(n){return function(t){return 1-n(1-t)}}function bu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function _u(n){return n*n}function wu(n){return n*n*n}function Su(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function ku(n){return function(t){return Math.pow(t,n)}}function Eu(n){return 1-Math.cos(n*Ra)}function Au(n){return Math.pow(2,10*(n-1))}function Nu(n){return 1-Math.sqrt(1-n*n)}function Cu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/La*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*La/t)}}function zu(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function qu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Lu(n,t){n=ta.hcl(n),t=ta.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return st(e+i*n,r+o*n,u+a*n)+""}}function Tu(n,t){n=ta.hsl(n),t=ta.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function Ru(n,t){n=ta.lab(n),t=ta.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ht(e+i*n,r+o*n,u+a*n)+""}}function Du(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Pu(n){var t=[n.a,n.b],e=[n.c,n.d],r=ju(t),u=Uu(t,e),i=ju(Fu(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Pa,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Pa:0}function Uu(n,t){return n[0]*t[0]+n[1]*t[1]}function ju(n){var t=Math.sqrt(Uu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Fu(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Hu(n,t){var e,r=[],u=[],i=ta.transform(n),o=ta.transform(t),a=i.translate,c=o.translate,l=i.rotate,s=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:vu(a[0],c[0])},{i:3,x:vu(a[1],c[1])})):r.push(c[0]||c[1]?"translate("+c+")":""),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:vu(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:vu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:vu(g[0],p[0])},{i:e-2,x:vu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Ou(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Iu(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Yu(n){for(var t=n.source,e=n.target,r=Vu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Zu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Vu(n,t){if(n===t)return n;for(var e=Zu(n),r=Zu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Xu(n){n.fixed|=2}function $u(n){n.fixed&=-7}function Bu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Wu(n){n.fixed&=-5}function Ju(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Ju(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,u+=l*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Gu(n,t){return ta.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=ri,n}function Ku(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Qu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function ni(n){return n.children}function ti(n){return n.value}function ei(n,t){return t.value-n.value}function ri(n){return ta.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function ui(n){return n.x}function ii(n){return n.y}function oi(n,t,e){n.y0=t,n.y=e}function ai(n){return ta.range(n.length)}function ci(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function li(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function si(n){return n.reduce(fi,0)}function fi(n,t){return n+t[1]}function hi(n,t){return gi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function gi(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function pi(n){return[ta.min(n),ta.max(n)]}function vi(n,t){return n.value-t.value}function di(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function mi(n,t){n._pack_next=t,t._pack_prev=n}function yi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Mi(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(xi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],wi(r,u,i),t(i),di(r,i),r._pack_prev=i,di(i,u),u=r._pack_next,o=3;l>o;o++){wi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(yi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!yi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?mi(r,u=a):mi(r=c,u),o--):(di(r,i),u=i,t(i))}var m=(s+f)/2,y=(h+g)/2,M=0;for(o=0;l>o;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(bi)}}function xi(n){n._pack_next=n._pack_prev=n}function bi(n){delete n._pack_next,delete n._pack_prev}function _i(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)_i(u[i],t,e,r)}function wi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+l*i,e.y=n.y+c*i-l*u}else e.x=n.x+r,e.y=n.y}function Si(n,t){return n.parent==t.parent?1:2}function ki(n){var t=n.children;return t.length?t[0]:n.t}function Ei(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ai(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Ni(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Ci(n,t,e){return n.a.parent===t.parent?n.a:e}function zi(n){return 1+ta.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Li(n){var t=n.children;return t&&t.length?Li(t[0]):n}function Ti(n){var t,e=n.children;return e&&(t=e.length)?Ti(e[t-1]):n}function Ri(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Di(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Pi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ui(n){return n.rangeExtent?n.rangeExtent():Pi(n.range())}function ji(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Fi(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Hi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ml}function Oi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=ta.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ii(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Oi:ji,c=r?Iu:Ou;return o=u(n,t,c,e),a=u(t,n,c,mu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Du)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Xi(n,t)},i.tickFormat=function(t,e){return $i(n,t,e)},i.nice=function(t){return Zi(n,t),u()},i.copy=function(){return Ii(n,t,e,r)},u()}function Yi(n,t){return ta.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Zi(n,t){return Fi(n,Hi(Vi(n,t)[2]))}function Vi(n,t){null==t&&(t=10);var e=Pi(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Xi(n,t){return ta.range.apply(ta,Vi(n,t))}function $i(n,t,e){var r=Vi(n,t);if(e){var u=ic.exec(e);if(u.shift(),"s"===u[8]){var i=ta.formatPrefix(Math.max(ga(r[0]),ga(r[1])));return u[7]||(u[7]="."+Bi(i.scale(r[2]))),u[8]="f",e=ta.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Wi(u[8],r)),e=u.join("")}else e=",."+Bi(r[2])+"f";return ta.format(e)}function Bi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Wi(n,t){var e=Bi(t[2]);return n in yl?Math.abs(e-Bi(Math.max(ga(t[0]),ga(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Ji(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Fi(r.map(u),e?Math:xl);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Pi(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++<s;)for(var h=f-1;h>0;h--)o.push(i(l)*h);for(l=0;o[l]<a;l++);for(s=o.length;o[s-1]>c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return Ml;arguments.length<2?t=Ml:"function"!=typeof t&&(t=ta.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Ji(n.copy(),t,e,r)},Yi(o,n)}function Gi(n,t,e){function r(t){return n(u(t))}var u=Ki(t),i=Ki(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Xi(e,n)},r.tickFormat=function(n,t){return $i(e,n,t)},r.nice=function(n){return r.domain(Zi(e,n))},r.exponent=function(o){return arguments.length?(u=Ki(t=o),i=Ki(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Gi(n.copy(),t,e)},Yi(r,n)}function Ki(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Qi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return ta.range(n.length).map(function(n){return t+e*n})}var u,i,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new l;for(var i,o=-1,a=r.length;++o<a;)u.has(i=r[o])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,o=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=(c+l)/2,0):(l-c)/(n.length-1+a);return i=r(c+s*a/2,s),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=l=Math.round((c+l)/2),0):(l-c)/(n.length-1+a)|0;return i=r(c+Math.round(s*a/2+(l-c-(n.length-1+a)*s)/2),s),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=(f-s)/(n.length-a+2*c);return i=r(s+h*c,h),l&&i.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=Math.floor((f-s)/(n.length-a+2*c));return i=r(s+Math.round((f-s-(n.length-a)*h)/2),h),l&&i.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Pi(t.a[0])},e.copy=function(){return Qi(n,t)},e.domain(n)}function no(n,t){function i(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ta.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ta.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(u).sort(e),i()):n},o.range=function(n){return arguments.length?(t=n,i()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[0/0,0/0]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return no(n,t)},i()}function to(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return to(n,t,e)},u()}function eo(n,t){function e(e){return e>=e?t[ta.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return eo(n,t)},e}function ro(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Xi(n,t)},t.tickFormat=function(t,e){return $i(n,t,e)},t.copy=function(){return ro(n)},t}function uo(){return 0}function io(n){return n.innerRadius}function oo(n){return n.outerRadius}function ao(n){return n.startAngle}function co(n){return n.endAngle}function lo(n){return n&&n.padAngle}function so(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function fo(n,t,e,r,u){var i=n[0]-t[0],o=n[1]-t[1],a=(u?r:-r)/Math.sqrt(i*i+o*o),c=a*o,l=-a*i,s=n[0]+c,f=n[1]+l,h=t[0]+c,g=t[1]+l,p=(s+h)/2,v=(f+g)/2,d=h-s,m=g-f,y=d*d+m*m,M=e-r,x=s*g-h*f,b=(0>m?-1:1)*Math.sqrt(M*M*y-x*x),_=(x*m-d*b)/y,w=(-x*d-m*b)/y,S=(x*m+d*b)/y,k=(-x*d+m*b)/y,E=_-p,A=w-v,N=S-p,C=k-v;return E*E+A*A>N*N+C*C&&(_=S,w=k),[[_-c,w-l],[_*e/M,w*e/M]]}function ho(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=Et(e),p=Et(r);++f<h;)u.call(this,c=t[f],f)?s.push([+g.call(this,c,f),+p.call(this,c,f)]):s.length&&(o(),s=[]);return s.length&&o(),l.length?l.join(""):null}var e=Ar,r=Nr,u=Ne,i=go,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=El.get(n)||go).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function go(n){return n.join("L")}function po(n){return go(n)+"Z"}function vo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function mo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function yo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function Mo(n,t){return n.length<4?go(n):n[1]+_o(n.slice(1,-1),wo(n,t))}function xo(n,t){return n.length<3?go(n):n[0]+_o((n.push(n[0]),n),wo([n[n.length-2]].concat(n,[n[1]]),t))}function bo(n,t){return n.length<3?go(n):n[0]+_o(n,wo(n,t))}function _o(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return go(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l<t.length;l++,c++)i=n[c],a=t[l],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var s=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+s[0]+","+s[1]}return r}function wo(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function So(n){if(n.length<3)return go(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",No(Cl,o),",",No(Cl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Co(c,o,a);return n.pop(),c.push("L",r),c.join("")}function ko(n){if(n.length<4)return go(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(No(Cl,i)+","+No(Cl,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Co(e,i,o);return e.join("")}function Eo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[No(Cl,o),",",No(Cl,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Co(t,o,a);return t.join("")}function Ao(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,l=-1;++l<=e;)r=n[l],u=l/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return So(n)}function No(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Co(n,t,e){n.push("C",No(Al,t),",",No(Al,e),",",No(Nl,t),",",No(Nl,e),",",No(Cl,t),",",No(Cl,e))}function zo(n,t){return(t[1]-n[1])/(t[0]-n[0])}function qo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=zo(u,i);++t<e;)r[t]=(o+(o=zo(u=i,i=n[t+1])))/2;return r[t]=o,r}function Lo(n){for(var t,e,r,u,i=[],o=qo(n),a=-1,c=n.length-1;++a<c;)t=zo(n[a],n[a+1]),ga(t)<Ca?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function To(n){return n.length<3?go(n):n[0]+_o(n,Lo(n))}function Ro(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]-Ra,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Do(n){function t(t){function c(){v.push("M",a(n(m),f),s,l(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,M=t.length,x=Et(e),b=Et(u),_=e===r?function(){return g}:Et(r),w=u===i?function(){return p}:Et(i);++y<M;)o.call(this,h=t[y],y)?(d.push([g=+x.call(this,h,y),p=+b.call(this,h,y)]),m.push([+_.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=Ar,r=Ar,u=0,i=Nr,o=Ne,a=go,c=a.key,l=a,s="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r
+},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=El.get(n)||go).key,l=a.reverse||a,s=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Po(n){return n.radius}function Uo(n){return[n.x,n.y]}function jo(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Ra;return[e*Math.cos(r),e*Math.sin(r)]}}function Fo(){return 64}function Ho(){return"circle"}function Oo(n){var t=Math.sqrt(n/qa);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Io(n){return function(){var t,e;(t=this[n])&&(e=t[t.active])&&(--t.count?delete t[t.active]:delete this[n],t.active+=.5,e.event&&e.event.interrupt.call(this,this.__data__,e.index))}}function Yo(n,t,e){return ya(n,Pl),n.namespace=t,n.id=e,n}function Zo(n,t,e,r){var u=n.id,i=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[i][u].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[i][u].tween.set(t,e)}))}function Vo(n){return null==n&&(n=""),function(){this.textContent=n}}function Xo(n){return null==n?"__transition__":"__transition_"+n+"__"}function $o(n,t,e,r,u){var i=n[e]||(n[e]={active:0,count:0}),o=i[r];if(!o){var a=u.time;o=i[r]={tween:new l,time:a,delay:u.delay,duration:u.duration,ease:u.ease,index:t},u=null,++i.count,ta.timer(function(u){function c(e){if(i.active>r)return s();var u=i[i.active];u&&(--i.count,delete i[i.active],u.event&&u.event.interrupt.call(n,n.__data__,u.index)),i.active=r,o.event&&o.event.start.call(n,n.__data__,t),o.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&v.push(r)}),h=o.ease,f=o.duration,ta.timer(function(){return p.c=l(e||1)?Ne:l,1},0,a)}function l(e){if(i.active!==r)return 1;for(var u=e/f,a=h(u),c=v.length;c>0;)v[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,n.__data__,t),s()):void 0}function s(){return--i.count?delete i[r]:delete n[e],1}var f,h,g=o.delay,p=ec,v=[];return p.t=g+a,u>=g?c(u-g):void(p.c=c)},0,a)}}function Bo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function Wo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function Jo(n){return n.toISOString()}function Go(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=ta.bisect(Vl,u);return i==Vl.length?[t.year,Vi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Vl[i-1]<Vl[i]/u?i-1:i]:[Bl,Vi(n,e)[2]]}return r.invert=function(t){return Ko(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Ko)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Ko(+e+1),t).length}var i=r.domain(),o=Pi(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Fi(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Ko(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Ko(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Pi(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Ko(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Go(n.copy(),t,e)},Yi(r,n)}function Ko(n){return new Date(n)}function Qo(n){return JSON.parse(n.responseText)}function na(n){var t=ua.createRange();return t.selectNode(ua.body),t.createContextualFragment(n.responseText)}var ta={version:"3.5.6"},ea=[].slice,ra=function(n){return ea.call(n)},ua=this.document;if(ua)try{ra(ua.documentElement.childNodes)[0].nodeType}catch(ia){ra=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),ua)try{ua.createElement("DIV").style.setProperty("opacity",0,"")}catch(oa){var aa=this.Element.prototype,ca=aa.setAttribute,la=aa.setAttributeNS,sa=this.CSSStyleDeclaration.prototype,fa=sa.setProperty;aa.setAttribute=function(n,t){ca.call(this,n,t+"")},aa.setAttributeNS=function(n,t,e){la.call(this,n,t,e+"")},sa.setProperty=function(n,t,e){fa.call(this,n,t+"",e)}}ta.ascending=e,ta.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},ta.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},ta.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},ta.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=n[i])&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},ta.sum=function(n,t){var e,r=0,i=n.length,o=-1;if(1===arguments.length)for(;++o<i;)u(e=+n[o])&&(r+=e);else for(;++o<i;)u(e=+t.call(n,n[o],o))&&(r+=e);return r},ta.mean=function(n,t){var e,i=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)u(e=r(n[a]))?i+=e:--c;else for(;++a<o;)u(e=r(t.call(n,n[a],a)))?i+=e:--c;return c?i/c:void 0},ta.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},ta.median=function(n,t){var i,o=[],a=n.length,c=-1;if(1===arguments.length)for(;++c<a;)u(i=r(n[c]))&&o.push(i);else for(;++c<a;)u(i=r(t.call(n,n[c],c)))&&o.push(i);return o.length?ta.quantile(o.sort(e),.5):void 0},ta.variance=function(n,t){var e,i,o=n.length,a=0,c=0,l=-1,s=0;if(1===arguments.length)for(;++l<o;)u(e=r(n[l]))&&(i=e-a,a+=i/++s,c+=i*(e-a));else for(;++l<o;)u(e=r(t.call(n,n[l],l)))&&(i=e-a,a+=i/++s,c+=i*(e-a));return s>1?c/(s-1):void 0},ta.deviation=function(){var n=ta.variance.apply(this,arguments);return n?Math.sqrt(n):n};var ha=i(e);ta.bisectLeft=ha.left,ta.bisect=ta.bisectRight=ha.right,ta.bisector=function(n){return i(1===n.length?function(t,r){return e(n(t),r)}:n)},ta.shuffle=function(n,t,e){(i=arguments.length)<3&&(e=n.length,2>i&&(t=0));for(var r,u,i=e-t;i;)u=Math.random()*i--|0,r=n[i+t],n[i+t]=n[u+t],n[u+t]=r;return n},ta.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ta.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},ta.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=ta.min(arguments,o),e=new Array(t);++n<t;)for(var r,u=-1,i=e[n]=new Array(r);++u<r;)i[u]=arguments[u][n];return e},ta.transpose=function(n){return ta.zip.apply(ta,n)},ta.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ta.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ta.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ta.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ga=Math.abs;ta.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,u=[],i=a(ga(e)),o=-1;if(n*=i,t*=i,e*=i,0>e)for(;(r=n+e*++o)>t;)u.push(r/i);else for(;(r=n+e*++o)<t;)u.push(r/i);return u},ta.map=function(n,t){var e=new l;if(n instanceof l)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,u=-1,i=n.length;if(1===arguments.length)for(;++u<i;)e.set(u,n[u]);else for(;++u<i;)e.set(t.call(n,r=n[u],u),r)}else for(var o in n)e.set(o,n[o]);return e};var pa="__proto__",va="\x00";c(l,{has:h,get:function(n){return this._[s(n)]},set:function(n,t){return this._[s(n)]=t},remove:g,keys:p,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:f(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t),this._[t])}}),ta.nest=function(){function n(t,o,a){if(a>=i.length)return r?r.call(u,o):e?o.sort(e):o;for(var c,s,f,h,g=-1,p=o.length,v=i[a++],d=new l;++g<p;)(h=d.get(c=v(s=o[g])))?h.push(s):d.set(c,[s]);return t?(s=t(),f=function(e,r){s.set(e,n(t,r,a))}):(s={},f=function(e,r){s[e]=n(t,r,a)}),d.forEach(f),s}function t(n,e){if(e>=i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(ta.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},ta.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},c(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),ta.behavior={},ta.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=M(n,t,t[e]);return n};var da=["webkit","ms","moz","Moz","o","O"];ta.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ta.event=null,ta.requote=function(n){return n.replace(ma,"\\$&")};var ma=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ya={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ma=function(n,t){return t.querySelector(n)},xa=function(n,t){return t.querySelectorAll(n)},ba=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(ba=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ma=function(n,t){return Sizzle(n,t)[0]||null},xa=Sizzle,ba=Sizzle.matchesSelector),ta.selection=function(){return ta.select(ua.documentElement)};var _a=ta.selection.prototype=[];_a.select=function(n){var t,e,r,u,i=[];n=N(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,l=r.length;++c<l;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return A(i)},_a.selectAll=function(n){var t,e,r=[];n=C(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=ra(n.call(e,e.__data__,a,u))),t.parentNode=e);return A(r)};var wa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ta.ns={prefix:wa,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.slice(0,t),n=n.slice(t+1)),wa.hasOwnProperty(e)?{space:wa[e],local:n}:n}},_a.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ta.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},_a.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!L(n[u]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},_a.style=function(n,e,r){var u=arguments.length;if(3>u){if("string"!=typeof n){2>u&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>u){var i=this.node();return t(i).getComputedStyle(i,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},_a.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},_a.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},_a.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},_a.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},_a.insert=function(n,t){return n=j(n),t=N(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},_a.remove=function(){return this.each(F)},_a.data=function(n,t){function e(n,e){var r,u,i,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),v=new Array(o);if(t){var d,m=new l,y=new Array(o);for(r=-1;++r<o;)m.has(d=t.call(u=n[r],u.__data__,r))?v[r]=u:m.set(d,u),y[r]=d;for(r=-1;++r<f;)(u=m.get(d=t.call(e,i=e[r],r)))?u!==!0&&(g[r]=u,u.__data__=i):p[r]=H(i),m.set(d,!0);for(r=-1;++r<o;)m.get(y[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=H(i);for(;f>r;++r)p[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,a.push(p),c.push(g),s.push(v)}var r,u,i=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++i<o;)(u=r[i])&&(n[i]=u.__data__);return n}var a=Z([]),c=A([]),s=A([]);if("function"==typeof n)for(;++i<o;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<o;)e(r=this[i],n);return c.enter=function(){return a},c.exit=function(){return s},c},_a.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},_a.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return A(u)},_a.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},_a.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},_a.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},_a.call=function(n){var t=ra(arguments);return n.apply(t[0]=this,t),this},_a.empty=function(){return!this.node()},_a.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},_a.size=function(){var n=0;return Y(this,function(){++n}),n};var Sa=[];ta.selection.enter=Z,ta.selection.enter.prototype=Sa,Sa.append=_a.append,Sa.empty=_a.empty,Sa.node=_a.node,Sa.call=_a.call,Sa.size=_a.size,Sa.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var l=-1,s=u.length;++l<s;)(i=u[l])?(t.push(r[l]=e=n.call(u.parentNode,i.__data__,l,a)),e.__data__=i.__data__):t.push(null)}return A(o)},Sa.insert=function(n,t){return arguments.length<2&&(t=V(this)),_a.insert.call(this,n,t)},ta.select=function(t){var e;return"string"==typeof t?(e=[Ma(t,ua)],e.parentNode=ua.documentElement):(e=[t],e.parentNode=n(t)),A([e])},ta.selectAll=function(n){var t;return"string"==typeof n?(t=ra(xa(n,ua)),t.parentNode=ua.documentElement):(t=n,t.parentNode=null),A([t])},_a.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var ka=ta.map({mouseenter:"mouseover",mouseleave:"mouseout"});ua&&ka.forEach(function(n){"on"+n in ua&&ka.remove(n)});var Ea,Aa=0;ta.mouse=function(n){return J(n,k())};var Na=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ta.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return J(n,r)},ta.behavior.drag=function(){function n(){this.on("mousedown.drag",i).on("touchstart.drag",o)}function e(n,t,e,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],p|=n|e,M=r,g({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&ta.event.target===f),g({type:"dragend"}))}var l,s=this,f=ta.event.target,h=s.parentNode,g=r.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=ta.select(e(f)).on(i+d,a).on(o+d,c),y=W(f),M=t(h,v);u?(l=u.apply(s,arguments),l=[l.x-M[0],l.y-M[1]]):l=[0,0],g({type:"dragstart"})}}var r=E(n,"drag","dragstart","dragend"),u=null,i=e(b,ta.mouse,t,"mousemove","mouseup"),o=e(G,ta.touch,y,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},ta.rebind(n,r,"on")},ta.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?ra(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Ca=1e-6,za=Ca*Ca,qa=Math.PI,La=2*qa,Ta=La-Ca,Ra=qa/2,Da=qa/180,Pa=180/qa,Ua=Math.SQRT2,ja=2,Fa=4;ta.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=rt(v),o=i/(ja*h)*(e*ut(Ua*t+v)-et(v));return[r+o*l,u+o*s,i*e/rt(Ua*t+v)]}return[r+n*l,u+n*s,i*Math.exp(Ua*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+Fa*f)/(2*i*ja*h),p=(c*c-i*i-Fa*f)/(2*c*ja*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Ua;return e.duration=1e3*y,e},ta.behavior.zoom=function(){function n(n){n.on(q,f).on(Oa+".zoom",g).on("dblclick.zoom",p).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function u(n){k.k=Math.max(N[0],Math.min(N[1],n))}function i(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},u(Math.pow(2,o)),i(d=e,r),t=ta.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function c(n){z++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function s(n){--z||(n({type:"zoomend"}),d=null)}function f(){function n(){f=1,i(ta.mouse(u),g),l(a)}function r(){h.on(L,null).on(T,null),p(f&&ta.event.target===o),s(a)}var u=this,o=ta.event.target,a=D.of(u,arguments),f=0,h=ta.select(t(u)).on(L,n).on(T,r),g=e(ta.mouse(u)),p=W(u);Dl.call(u),c(a)}function h(){function n(){var n=ta.touches(p);return g=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ta.event.target;ta.select(t).on(x,r).on(b,a),_.push(t);for(var e=ta.event.changedTouches,u=0,i=e.length;i>u;++u)d[e[u].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-M){var s=c[0];o(p,s,d[s.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=l}else if(c.length>1){var s=c[0],f=c[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function r(){var n,t,e,r,o=ta.touches(p);Dl.call(p);for(var a=0,c=o.length;c>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],u(f*g)}M=null,i(n,t),l(v)}function a(){if(ta.event.touches.length){for(var t=ta.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in d)return void n()}ta.selectAll(_).on(y,null),w.on(q,f).on(R,h),E(),s(v)}var g,p=this,v=D.of(p,arguments),d={},m=0,y=".zoom-"+ta.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,_=[],w=ta.select(p),E=W(p);t(),c(v),w.on(q,null).on(R,t)}function g(){var n=D.of(this,arguments);y?clearTimeout(y):(Dl.call(this),v=e(d=m||ta.mouse(this)),c(n)),y=setTimeout(function(){y=null,s(n)},50),S(),u(Math.pow(2,.002*Ha())*k.k),i(d,v),l(n)}function p(){var n=ta.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ta.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,m,y,M,x,b,_,w,k={x:0,y:0,k:1},A=[960,500],N=Ia,C=250,z=0,q="mousedown.zoom",L="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=E(n,"zoomstart","zoom","zoomend");return Oa||(Oa="onwheel"in ua?(Ha=function(){return-ta.event.deltaY*(ta.event.deltaMode?120:1)},"wheel"):"onmousewheel"in ua?(Ha=function(){return ta.event.wheelDelta},"mousewheel"):(Ha=function(){return-ta.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Tl?ta.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var e=A[0],r=A[1],u=d?d[0]:e/2,i=d?d[1]:r/2,o=ta.interpolateZoom([(u-k.x)/k.k,(i-k.y)/k.k,e/k.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:u-r[0]*a,y:i-r[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){s(n)}).each("end.zoom",function(){s(n)}):(this.__chart__=k,c(n),l(n),s(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:+t},a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(N=null==t?Ia:[+t[0],+t[1]],n):N},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(A=t&&[+t[0],+t[1]],n):A},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ta.rebind(n,D,"on")};var Ha,Oa,Ia=[0,1/0];ta.color=ot,ot.prototype.toString=function(){return this.rgb()+""},ta.hsl=at;var Ya=at.prototype=new ot;Ya.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,this.l/n)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,n*this.l)},Ya.rgb=function(){return ct(this.h,this.s,this.l)},ta.hcl=lt;var Za=lt.prototype=new ot;Za.brighter=function(n){return new lt(this.h,this.c,Math.min(100,this.l+Va*(arguments.length?n:1)))},Za.darker=function(n){return new lt(this.h,this.c,Math.max(0,this.l-Va*(arguments.length?n:1)))},Za.rgb=function(){return st(this.h,this.c,this.l).rgb()},ta.lab=ft;var Va=18,Xa=.95047,$a=1,Ba=1.08883,Wa=ft.prototype=new ot;Wa.brighter=function(n){return new ft(Math.min(100,this.l+Va*(arguments.length?n:1)),this.a,this.b)},Wa.darker=function(n){return new ft(Math.max(0,this.l-Va*(arguments.length?n:1)),this.a,this.b)},Wa.rgb=function(){return ht(this.l,this.a,this.b)},ta.rgb=mt;var Ja=mt.prototype=new ot;Ja.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new mt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mt(u,u,u)},Ja.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mt(n*this.r,n*this.g,n*this.b)},Ja.hsl=function(){return _t(this.r,this.g,this.b)},Ja.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var Ga=ta.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ga.forEach(function(n,t){Ga.set(n,yt(t))}),ta.functor=Et,ta.xhr=At(y),ta.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=Nt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=l)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++<l;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}s=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++s):10===r&&(u=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;l>s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==c)continue;return n.slice(t,s-a)}return n.slice(t)}for(var r,u,i={},o={},a=[],l=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,f++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new m,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},ta.csv=ta.dsv(",","text/csv"),ta.tsv=ta.dsv(" ","text/tab-separated-values");var Ka,Qa,nc,tc,ec,rc=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ta.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Qa?Qa.n=i:Ka=i,Qa=i,nc||(tc=clearTimeout(tc),nc=1,rc(qt))},ta.timer.flush=function(){Lt(),Tt()},ta.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var uc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Dt);ta.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=ta.round(n,Rt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),uc[8+e/3]};var ic=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,oc=ta.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ta.round(n,Rt(n,t))).toFixed(Math.max(0,Math.min(20,Rt(n*(1+1e-15),t))))}}),ac=ta.time={},cc=Date;jt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){lc.setUTCDate.apply(this._,arguments)},setDay:function(){lc.setUTCDay.apply(this._,arguments)},setFullYear:function(){lc.setUTCFullYear.apply(this._,arguments)},setHours:function(){lc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){lc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){lc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){lc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){lc.setUTCSeconds.apply(this._,arguments)},setTime:function(){lc.setTime.apply(this._,arguments)}};var lc=Date.prototype;ac.year=Ft(function(n){return n=ac.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ac.years=ac.year.range,ac.years.utc=ac.year.utc.range,ac.day=Ft(function(n){var t=new cc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ac.days=ac.day.range,ac.days.utc=ac.day.utc.range,ac.dayOfYear=function(n){var t=ac.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ac[n]=Ft(function(n){return(n=ac.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ac[n+"s"]=e.range,ac[n+"s"].utc=e.utc.range,ac[n+"OfYear"]=function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)}}),ac.week=ac.sunday,ac.weeks=ac.sunday.range,ac.weeks.utc=ac.sunday.utc.range,ac.weekOfYear=ac.sundayOfYear;var sc={"-":"",_:" ",0:"0"},fc=/^\s*\d+/,hc=/^%/;ta.locale=function(n){return{numberFormat:Pt(n),timeFormat:Ot(n)}};var gc=ta.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ta.format=gc.numberFormat,ta.geo={},ce.prototype={s:0,t:0,add:function(n){le(n,this.t,pc),le(pc.s,this.s,this),this.s?this.t+=pc.t:this.s=pc.t
+},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var pc=new ce;ta.geo.stream=function(n,t){n&&vc.hasOwnProperty(n.type)?vc[n.type](n,t):se(n,t)};var vc={Feature:function(n,t){se(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)se(e[r].geometry,t)}},dc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){fe(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)fe(e[r],t,0)},Polygon:function(n,t){he(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)he(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)se(e[r],t)}};ta.geo.area=function(n){return mc=0,ta.geo.stream(n,Mc),mc};var mc,yc=new ce,Mc={sphere:function(){mc+=4*qa},point:b,lineStart:b,lineEnd:b,polygonStart:function(){yc.reset(),Mc.lineStart=ge},polygonEnd:function(){var n=2*yc;mc+=0>n?4*qa+n:n,Mc.lineStart=Mc.lineEnd=Mc.point=b}};ta.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=pe([t*Da,e*Da]);if(m){var u=de(m,r),i=[u[1],-u[0],0],o=de(i,u);Me(o),o=xe(o);var c=t-p,l=c>0?1:-1,v=o[0]*Pa*l,d=ga(c)>180;if(d^(v>l*p&&l*t>v)){var y=o[1]*Pa;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>l*p&&l*t>v)){var y=-o[1]*Pa;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ga(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Mc.point(n,e),t(n,e)}function i(){Mc.lineStart()}function o(){u(v,d),Mc.lineEnd(),ga(y)>Ca&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var s,f,h,g,p,v,d,m,y,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=u,b.lineStart=i,b.lineEnd=o,y=0,Mc.polygonStart()},polygonEnd:function(){Mc.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>yc?(s=-(h=180),f=-(g=90)):y>Ca?g=90:-Ca>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],ta.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),ta.geo.centroid=function(n){xc=bc=_c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,qc);var t=Nc,e=Cc,r=zc,u=t*t+e*e+r*r;return za>u&&(t=kc,e=Ec,r=Ac,Ca>bc&&(t=_c,e=wc,r=Sc),u=t*t+e*e+r*r,za>u)?[0/0,0/0]:[Math.atan2(e,t)*Pa,tt(r/Math.sqrt(u))*Pa]};var xc,bc,_c,wc,Sc,kc,Ec,Ac,Nc,Cc,zc,qc={sphere:b,point:_e,lineStart:Se,lineEnd:ke,polygonStart:function(){qc.lineStart=Ee},polygonEnd:function(){qc.lineStart=Se}},Lc=Le(Ne,Pe,je,[-qa,-qa/2]),Tc=1e9;ta.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ie(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ta.geo.conicEqualArea=function(){return Ye(Ze)}).raw=Ze,ta.geo.albers=function(){return ta.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ta.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=ta.geo.albers(),o=ta.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ta.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Ca,f+.12*l+Ca],[s-.214*l-Ca,f+.234*l-Ca]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Ca,f+.166*l+Ca],[s-.115*l-Ca,f+.234*l-Ca]]).stream(c).point,n},n.scale(1070)};var Rc,Dc,Pc,Uc,jc,Fc,Hc={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Dc=0,Hc.lineStart=Ve},polygonEnd:function(){Hc.lineStart=Hc.lineEnd=Hc.point=b,Rc+=ga(Dc/2)}},Oc={point:Xe,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Ic={point:We,lineStart:Je,lineEnd:Ge,polygonStart:function(){Ic.lineStart=Ke},polygonEnd:function(){Ic.point=We,Ic.lineStart=Je,Ic.lineEnd=Ge}};ta.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),ta.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Rc=0,ta.geo.stream(n,u(Hc)),Rc},n.centroid=function(n){return _c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,u(Ic)),zc?[Nc/zc,Cc/zc]:Ac?[kc/Ac,Ec/Ac]:Sc?[_c/Sc,wc/Sc]:[0/0,0/0]},n.bounds=function(n){return jc=Fc=-(Pc=Uc=1/0),ta.geo.stream(n,u(Oc)),[[Pc,Uc],[jc,Fc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||tr(n):y,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new $e:new Qe(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(ta.geo.albersUsa()).context(null)},ta.geo.transform=function(n){return{stream:function(t){var e=new er(t);for(var r in n)e[r]=n[r];return e}}},er.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ta.geo.projection=ur,ta.geo.projectionMutator=ir,(ta.geo.equirectangular=function(){return ur(ar)}).raw=ar.invert=ar,ta.geo.rotation=function(n){function t(t){return t=n(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t}return n=lr(n[0]%360*Da,n[1]*Da,n.length>2?n[2]*Da:0),t.invert=function(t){return t=n.invert(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t},t},cr.invert=ar,ta.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=lr(-n[0]*Da,-n[1]*Da,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Pa,n[1]*=Pa}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=gr((t=+r)*Da,u*Da),n):t},n.precision=function(r){return arguments.length?(e=gr(t*Da,(u=+r)*Da),n):u},n.angle(90)},ta.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Da,u=n[1]*Da,i=t[1]*Da,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},ta.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ta.range(Math.ceil(i/d)*d,u,d).map(h).concat(ta.range(Math.ceil(l/m)*m,c,m).map(g)).concat(ta.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ga(n%d)>Ca}).map(s)).concat(ta.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ga(n%m)>Ca}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=vr(a,o,90),f=dr(r,e,y),h=vr(l,c,90),g=dr(i,u,y),n):y},n.majorExtent([[-180,-90+Ca],[180,90-Ca]]).minorExtent([[-180,-80-Ca],[180,80+Ca]])},ta.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=mr,u=yr;return n.distance=function(){return ta.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},ta.geo.interpolate=function(n,t){return Mr(n[0]*Da,n[1]*Da,t[0]*Da,t[1]*Da)},ta.geo.length=function(n){return Yc=0,ta.geo.stream(n,Zc),Yc};var Yc,Zc={sphere:b,point:b,lineStart:xr,lineEnd:b,polygonStart:b,polygonEnd:b},Vc=br(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ta.geo.azimuthalEqualArea=function(){return ur(Vc)}).raw=Vc;var Xc=br(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},y);(ta.geo.azimuthalEquidistant=function(){return ur(Xc)}).raw=Xc,(ta.geo.conicConformal=function(){return Ye(_r)}).raw=_r,(ta.geo.conicEquidistant=function(){return Ye(wr)}).raw=wr;var $c=br(function(n){return 1/n},Math.atan);(ta.geo.gnomonic=function(){return ur($c)}).raw=$c,Sr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ra]},(ta.geo.mercator=function(){return kr(Sr)}).raw=Sr;var Bc=br(function(){return 1},Math.asin);(ta.geo.orthographic=function(){return ur(Bc)}).raw=Bc;var Wc=br(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ta.geo.stereographic=function(){return ur(Wc)}).raw=Wc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ra]},(ta.geo.transverseMercator=function(){var n=kr(Er),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Er,ta.geom={},ta.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=Et(e),i=Et(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(zr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=Cr(a),s=Cr(c),f=s[0]===l[0],h=s[s.length-1]===l[l.length-1],g=[];for(t=l.length-1;t>=0;--t)g.push(n[a[l[t]][2]]);for(t=+f;t<s.length-h;++t)g.push(n[a[s[t]][2]]);return g}var e=Ar,r=Nr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ta.geom.polygon=function(n){return ya(n,Jc),n};var Jc=ta.geom.polygon.prototype=[];Jc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Jc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Jc.clip=function(n){for(var t,e,r,u,i,o,a=Tr(n),c=-1,l=this.length-Tr(this),s=this[l-1];++c<l;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],qr(o,s,u)?(qr(i,s,u)||n.push(Lr(i,o,s,u)),n.push(o)):qr(i,s,u)&&n.push(Lr(i,o,s,u)),i=o;a&&n.push(n[0]),s=u}return n};var Gc,Kc,Qc,nl,tl,el=[],rl=[];Or.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Yr),t.length},Qr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},nu.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=uu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(eu(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ru(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(ru(this,e),n=e,e=n.U),e.C=!1,r.C=!0,eu(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?uu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,eu(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ru(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,eu(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,ru(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,eu(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,ru(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},ta.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return iu(e(n),a).cells.forEach(function(e,a){var c=e.edges,l=e.site,s=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=r&&l.x<=i&&l.y>=u&&l.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];s.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Ca)*Ca,y:Math.round(o(n,t)/Ca)*Ca,i:t}})}var r=Ar,u=Nr,i=r,o=u,a=ul;return n?t(n):(t.links=function(n){return iu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return iu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Yr),c=-1,l=a.length,s=a[l-1].edge,f=s.l===o?s.r:s.l;++c<l;)u=s,i=f,s=a[c].edge,f=s.l===o?s.r:s.l,r<i.i&&r<f.i&&au(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=Et(r=n),t):r},t.y=function(n){return arguments.length?(o=Et(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?ul:n,t):a===ul?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===ul?null:a&&a[1]},t)};var ul=[[-1e6,-1e6],[1e6,1e6]];ta.geom.delaunay=function(n){return ta.geom.voronoi().triangles(n)},ta.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,s=n.y;if(null!=c)if(ga(c-e)+ga(s-r)<.01)l(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,l(n,f,c,s,u,i,o,a),l(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else l(n,t,e,r,u,i,o,a)}function l(n,t,e,r,u,o,a,c){var l=.5*(u+a),s=.5*(o+c),f=e>=l,h=r>=s,g=h<<1|f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=su()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,v,d,m,y,M=Et(a),x=Et(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.x<v&&(v=s.x),s.y<d&&(d=s.y),s.x>m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},k.find=function(n){return hu(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=s=null,k}var o,a=Ar,c=Nr;return(o=arguments.length)?(a=cu,c=lu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},ta.interpolateRgb=gu,ta.interpolateObject=pu,ta.interpolateNumber=vu,ta.interpolateString=du;var il=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ol=new RegExp(il.source,"g");ta.interpolate=mu,ta.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ga.has(t.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(t)?gu:du:t instanceof ot?gu:Array.isArray(t)?yu:"object"===e&&isNaN(t)?pu:vu)(n,t)}],ta.interpolateArray=yu;var al=function(){return y},cl=ta.map({linear:al,poly:ku,quad:function(){return _u},cubic:function(){return wu},sin:function(){return Eu},exp:function(){return Au},circle:function(){return Nu},elastic:Cu,back:zu,bounce:function(){return qu}}),ll=ta.map({"in":y,out:xu,"in-out":bu,"out-in":function(n){return bu(xu(n))}});ta.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=cl.get(e)||al,r=ll.get(r)||y,Mu(r(e.apply(null,ea.call(arguments,1))))},ta.interpolateHcl=Lu,ta.interpolateHsl=Tu,ta.interpolateLab=Ru,ta.interpolateRound=Du,ta.transform=function(n){var t=ua.createElementNS(ta.ns.prefix.svg,"g");return(ta.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:sl)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var sl={a:1,b:0,c:0,d:1,e:0,f:0};ta.interpolateTransform=Hu,ta.layout={},ta.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Yu(n[e]));return t}},ta.layout.chord=function(){function n(){var n,l,f,h,g,p={},v=[],d=ta.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(l=0,g=-1;++g<i;)l+=u[h][g];v.push(l),m.push(ta.range(i)),n+=l}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(La-s*i)/n,l=0,h=-1;++h<i;){for(f=l,g=-1;++g<i;){var y=d[h],M=m[y][g],x=u[y][M],b=l,_=l+=x*n;p[y+"-"+M]={index:y,subindex:M,startAngle:b,endAngle:_,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/n},l+=s}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,l={},s=0;return l.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,l):u},l.padding=function(n){return arguments.length?(s=n,e=r=null,l):s},l.sortGroups=function(n){return arguments.length?(o=n,e=r=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,e=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return e||n(),e},l.groups=function(){return r||n(),r},l},ta.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ta.event.x,n.py=ta.event.y,a.resume()}var e,r,u,i,o,a={},c=ta.dispatch("start","tick","end"),l=[1,1],s=.9,f=fl,h=hl,g=-30,p=gl,v=.1,d=.64,m=[],M=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,y,x,b=m.length,_=M.length;for(e=0;_>e;++e)a=M[e],f=a.source,h=a.target,y=h.x-f.x,x=h.y-f.y,(p=y*y+x*x)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,y*=p,x*=p,h.x-=y*(d=f.weight/(h.weight+f.weight)),h.y-=x*d,f.x+=y*(d=1-d),f.y+=x*d);if((d=r*v)&&(y=l[0]/2,x=l[1]/2,e=-1,d))for(;++e<b;)a=m[e],a.x+=(y-a.x)*d,a.y+=(x-a.y)*d;if(g)for(Ju(t=ta.geom.quadtree(m),r,o),e=-1;++e<b;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<b;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*s,a.y-=(a.py-(a.py=a.y))*s);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(M=n,a):M},a.size=function(n){return arguments.length?(l=n,a):l},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(s=+n,a):s},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ta.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++a<l;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,s=M.length,p=l[0],v=l[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=M[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;s>t;++t)u[t]=+f.call(this,M[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,M[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=ta.behavior.drag().origin(y).on("dragstart.force",Xu).on("drag.force",t).on("dragend.force",$u)),arguments.length?void this.on("mouseover.force",Bu).on("mouseout.force",Wu).call(e):e},ta.rebind(a,c,"on")};var fl=20,hl=1,gl=1/0;ta.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Qu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ei,e=ni,r=ti;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(Ku(t,function(n){n.children&&(n.value=0)}),Qu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ta.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++l<o;)n(a=i[l],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=ta.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Gu(e,r)},ta.layout.pie=function(){function n(o){var a,c=o.length,l=o.map(function(e,r){return+t.call(n,e,r)}),s=+("function"==typeof r?r.apply(this,arguments):r),f=("function"==typeof u?u.apply(this,arguments):u)-s,h=Math.min(Math.abs(f)/c,+("function"==typeof i?i.apply(this,arguments):i)),g=h*(0>f?-1:1),p=(f-c*g)/ta.sum(l),v=ta.range(c),d=[];return null!=e&&v.sort(e===pl?function(n,t){return l[t]-l[n]}:function(n,t){return e(o[n],o[t])}),v.forEach(function(n){d[n]={data:o[n],value:a=l[n],startAngle:s,endAngle:s+=a*p+g,padAngle:h}}),d}var t=Number,e=pl,r=0,u=La,i=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var pl={};ta.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=ta.permute(l,f),s=ta.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=y,e=ai,r=ci,u=oi,i=ui,o=ii;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:vl.get(t)||ai,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:dl.get(t)||ci,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var vl=ta.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(li),i=n.map(si),o=ta.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ta.range(n.length).reverse()},"default":ai}),dl=ta.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ci});ta.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=l[i],a>=s[0]&&a<=s[1]&&(o=c[ta.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=pi,u=hi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=Et(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return gi(n,t)}:Et(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ta.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Qu(a,function(n){n.r=+s(n.value)}),Qu(a,Mi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Qu(a,function(n){n.r+=f}),Qu(a,Mi),Qu(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=ta.layout.hierarchy().sort(vi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Gu(n,e)},ta.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Qu(h,e),h.parent.m=-h.z,Ku(h,r),l)Ku(f,i);else{var g=f,p=f,v=f;Ku(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Ku(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Ni(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=Ei(o),u=ki(u),o&&u;)c=ki(c),i=Ei(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ai(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!Ei(i)&&(i.t=o,i.m+=f-s),u&&!ki(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ta.layout.hierarchy().sort(null).value(null),a=Si,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Gu(n,o)},ta.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Qu(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Qu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=ta.layout.hierarchy().sort(null).value(null),e=Si,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Gu(n,t)},ta.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++i<o;)u=n[i],u.x=a,u.y=l,u.dy=s,a+=u.dx=Math.min(e.x+e.dx-a,s?c(u.area/s):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);++i<o;)u=n[i],u.x=a,u.y=l,u.dx=s,l+=u.dy=Math.min(e.y+e.dy-l,s?c(u.area/s):0);u.z=!1,u.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=ta.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=Ri,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));
+return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ri(t):Di(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Di(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?Ri:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Gu(i,a)},ta.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++a<c;){i.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(e=l[s])&&$o(e,s,u,r,o),t.push(e)}return Yo(i,u,r)},_a.interrupt=function(n){return this.each(null==n?Dl:Io(Xo(n)))};var Tl,Rl,Dl=Io(Xo()),Pl=[],Ul=0;Pl.call=_a.call,Pl.empty=_a.empty,Pl.node=_a.node,Pl.size=_a.size,ta.transition=function(n,t){return n&&n.transition?Tl?n.transition(t):n:ta.selection().transition(n)},ta.transition.prototype=Pl,Pl.select=function(n){var t,e,r,u=this.id,i=this.namespace,o=[];n=N(n);for(var a=-1,c=this.length;++a<c;){o.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(r=l[s])&&(e=n.call(r,r.__data__,s,a))?("__data__"in r&&(e.__data__=r.__data__),$o(e,s,i,u,r[i][u]),t.push(e)):t.push(null)}return Yo(o,i,u)},Pl.selectAll=function(n){var t,e,r,u,i,o=this.id,a=this.namespace,c=[];n=C(n);for(var l=-1,s=this.length;++l<s;)for(var f=this[l],h=-1,g=f.length;++h<g;)if(r=f[h]){i=r[a][o],e=n.call(r,r.__data__,h,l),c.push(t=[]);for(var p=-1,v=e.length;++p<v;)(u=e[p])&&$o(u,p,a,o,i),t.push(u)}return Yo(c,a,o)},Pl.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]<M[0])],q[1]=h[+(n[1]<M[1])]):M=null),A&&m(n,l,0)&&(r(k),t=!0),N&&m(n,s,1)&&(u(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function m(n,t,e){var r,u,i=Ui(t),c=i[0],l=i[1],s=q[e],v=e?h:f,d=v[1]-v[0];return C&&(c-=s,l-=d+s),r=(e?p:g)?Math.max(c,Math.min(l,n[e])):n[e],C?u=(r+=s)+d:(M&&(s=Math.max(c,Math.min(l,2*M[e]-r))),r>s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}(); \ No newline at end of file
diff --git a/vendor/assets/javascripts/jquery.typeahead.min.js b/vendor/assets/javascripts/jquery.typeahead.min.js
new file mode 100644
index 0000000..884de9e
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.typeahead.min.js
@@ -0,0 +1,10 @@
+/*!
+ * jQuery Typeahead
+ * Copyright (C) 2015 RunningCoder.org
+ * Licensed under the MIT license
+ *
+ * @author Tom Bertrand
+ * @version 2.1.2 (2015-09-28)
+ * @link http://www.runningcoder.org/jquerytypeahead/
+*/
+!function(a,b,c,d){a.Typeahead={version:"2.1.2"};var e={input:null,minLength:2,maxItem:8,dynamic:!1,delay:300,order:null,offset:!1,hint:!1,accent:!1,highlight:!0,group:!1,maxItemPerGroup:null,dropdownFilter:!1,dynamicFilter:null,backdrop:!1,cache:!1,ttl:36e5,compression:!1,suggestion:!1,searchOnFocus:!1,resultContainer:null,generateOnLoad:null,mustSelectItem:!1,href:null,display:["display"],template:null,correlativeTemplate:!1,emptyTemplate:!1,source:null,callback:{onInit:null,onReady:null,onSearch:null,onResult:null,onLayoutBuiltBefore:null,onLayoutBuiltAfter:null,onNavigate:null,onMouseEnter:null,onMouseLeave:null,onClickBefore:null,onClickAfter:null,onSendRequest:null,onReceiveRequest:null,onSubmit:null},selector:{container:"typeahead-container",group:"typeahead-group",result:"typeahead-result",list:"typeahead-list",display:"typeahead-display",query:"typeahead-query",filter:"typeahead-filter",filterButton:"typeahead-filter-button",filterValue:"typeahead-filter-value",dropdown:"typeahead-dropdown",dropdownCarret:"typeahead-caret",button:"typeahead-button",backdrop:"typeahead-backdrop",hint:"typeahead-hint"},debug:!1},f=".typeahead",g={from:"ãàáäâẽèéëêìíïîõòóöôùúüûñç",to:"aaaaaeeeeeiiiiooooouuuunc"},h=~navigator.appVersion.indexOf("MSIE 9."),i=function(a,b){this.rawQuery="",this.query="",this.source={},this.isGenerated=null,this.generatedGroupCount=0,this.groupCount=0,this.groupBy="group",this.result=[],this.resultCount=0,this.options=b,this.node=a,this.container=null,this.resultContainer=null,this.item=null,this.xhr={},this.hintIndex=null,this.filters={dropdown:{},dynamic:{}},this.requests={},this.backdrop={},this.hint={},this.__construct()};i.prototype={extendOptions:function(){this.options.dynamic&&(this.options.cache=!1,this.options.compression=!1),this.options.cache&&(this.options.cache=function(){var b="undefined"!=typeof a.localStorage;if(b)try{a.localStorage.setItem("typeahead","typeahead"),a.localStorage.removeItem("typeahead")}catch(c){b=!1}return b}()),this.options.compression&&("object"==typeof LZString&&this.options.cache||(this.options.compression=!1)),"undefined"==typeof this.options.maxItem||/^\d+$/.test(this.options.maxItem)&&0!==this.options.maxItem||(this.options.maxItem=1/0),this.options.maxItemPerGroup&&!/^\d+$/.test(this.options.maxItemPerGroup)&&(this.options.maxItemPerGroup=null),!this.options.display||this.options.display instanceof Array||(this.options.display=[this.options.display]),!this.options.group||this.options.group instanceof Array||(this.options.group=[this.options.group]),!this.options.dynamicFilter||this.options.dynamicFilter instanceof Array||(this.options.dynamicFilter=[this.options.dynamicFilter]),this.options.resultContainer&&("string"==typeof this.options.resultContainer&&(this.options.resultContainer=c(this.options.resultContainer)),this.options.resultContainer instanceof jQuery&&this.options.resultContainer[0]&&(this.resultContainer=this.options.resultContainer)),this.options.group&&"string"==typeof this.options.group[0]&&this.options.maxItemPerGroup&&(this.groupBy=this.options.group[0]),this.options.callback&&this.options.callback.onClick&&(this.options.callback.onClickBefore=this.options.callback.onClick,delete this.options.callback.onClick),this.options=c.extend(!0,{},e,this.options)},unifySourceFormat:function(){if(this.options.source instanceof Array)return this.options.source={group:{data:this.options.source}},this.groupCount+=1,!0;("undefined"!=typeof this.options.source.data||"undefined"!=typeof this.options.source.url)&&(this.options.source={group:this.options.source});for(var a in this.options.source)if(this.options.source.hasOwnProperty(a)){if(("string"==typeof this.options.source[a]||this.options.source[a]instanceof Array)&&(this.options.source[a]={url:this.options.source[a]}),!this.options.source[a].data&&!this.options.source[a].url)return!1;!this.options.source[a].display||this.options.source[a].display instanceof Array||(this.options.source[a].display=[this.options.source[a].display]),this.options.source[a].ignore&&(this.options.source[a].ignore instanceof RegExp||delete this.options.source[a].ignore),this.groupCount+=1}return!0},init:function(){this.helper.executeCallback(this.options.callback.onInit,[this.node]),this.container=this.node.closest("."+this.options.selector.container)},delegateEvents:function(){var a=this,b=["focus"+f,"input"+f,"propertychange"+f,"keydown"+f,"keyup"+f,"dynamic"+f,"generateOnLoad"+f];this.container.off(f).on("click"+f+" touchstart"+f,function(b){b.stopPropagation(),a.options.dropdownFilter&&a.container.find("."+a.options.selector.dropdown.replace(" ",".")).hide()}),this.node.closest("form").on("submit",function(b){return a.options.mustSelectItem&&a.helper.isEmpty(a.item)?void b.preventDefault():(a.hideLayout(),a.rawQuery="",a.query="",a.helper.executeCallback(a.options.callback.onSubmit,[a.node,this,a.item,b])?!1:void 0)});var c=!1;this.node.off(f).on(b.join(" "),function(b){switch(b.type){case"generateOnLoad":case"focus":a.isGenerated&&a.options.searchOnFocus&&a.query.length>=a.options.minLength&&a.showLayout(),null!==a.isGenerated||a.options.dynamic||a.generateSource();break;case"keydown":a.isGenerated&&a.result.length&&b.keyCode&&~[13,27,38,39,40].indexOf(b.keyCode)&&(c=!0,a.navigate(b));break;case"keyup":h&&a.node[0].value.replace(/^\s+/,"").toString().length<a.query.length&&a.node.trigger("input"+f);break;case"propertychange":if(c){c=!1;break}case"input":if(a.rawQuery=a.node[0].value.toString(),a.query=a.node[0].value.replace(/^\s+/,"").toString(),a.options.hint&&a.hint.container&&""!==a.hint.container.val()&&0!==a.hint.container.val().indexOf(a.rawQuery)&&a.hint.container.val(""),a.options.dynamic)return a.isGenerated=null,void a.helper.typeWatch(function(){a.query.length>=a.options.minLength?a.generateSource():a.hideLayout()},a.options.delay);case"dynamic":if(!a.isGenerated)break;if(a.query.length<a.options.minLength){a.hideLayout();break}a.searchResult(),a.buildLayout(),a.result.length>0||a.options.emptyTemplate?a.showLayout():a.hideLayout()}}),this.options.generateOnLoad&&this.node.trigger("generateOnLoad"+f)},generateSource:function(){if(!this.isGenerated||this.options.dynamic){if(this.generatedGroupCount=0,this.isGenerated=!1,!this.helper.isEmpty(this.xhr)){for(var b in this.xhr)this.xhr.hasOwnProperty(b)&&this.xhr[b].abort();this.xhr={}}var c,d,e;for(c in this.options.source)if(this.options.source.hasOwnProperty(c)){if(this.options.cache&&(d=a.localStorage.getItem(this.node.selector+":"+c))){this.options.compression&&(d=LZString.decompressFromUTF16(d)),e=!1;try{d=JSON.parse(d+""),d.data&&d.ttl>(new Date).getTime()?(this.populateSource(d.data,c),e=!0):a.localStorage.removeItem(this.node.selector+":"+c)}catch(f){}if(e)continue}!this.options.source[c].data||this.options.source[c].url?this.options.source[c].url&&(this.requests[c]||(this.requests[c]=this.generateRequestObject(c))):this.populateSource("function"==typeof this.options.source[c].data&&this.options.source[c].data()||this.options.source[c].data,c)}this.handleRequests()}},generateRequestObject:function(a){var b={request:{url:null,dataType:"json"},extra:{path:null,group:a,callback:{done:null,fail:null,complete:null,always:null}},validForGroup:[a]};!(this.options.source[a].url instanceof Array)&&this.options.source[a].url instanceof Object&&(this.options.source[a].url=[this.options.source[a].url]),this.options.source[a].url instanceof Array?(this.options.source[a].url[0]instanceof Object?(this.options.source[a].url[0].callback&&(b.extra.callback=this.options.source[a].url[0].callback,delete this.options.source[a].url[0].callback),b.request=c.extend(!0,b.request,this.options.source[a].url[0])):"string"==typeof this.options.source[a].url[0]&&(b.request.url=this.options.source[a].url[0]),this.options.source[a].url[1]&&"string"==typeof this.options.source[a].url[1]&&(b.extra.path=this.options.source[a].url[1])):"string"==typeof this.options.source[a].url&&(b.request.url=this.options.source[a].url),"jsonp"===b.request.dataType.toLowerCase()&&(b.request.jsonpCallback="callback_"+a);var d;for(var e in this.requests)if(this.requests.hasOwnProperty(e)&&(d=JSON.stringify(this.requests[e].request),d===JSON.stringify(b.request))){this.requests[e].validForGroup.push(a),b.isDuplicated=!0,delete b.validForGroup;break}return b},handleRequests:function(){var a=this,b=Object.keys(this.requests).length;b&&this.helper.executeCallback(this.options.callback.onSendRequest,[this.node,this.query]);for(var d in this.requests)this.requests.hasOwnProperty(d)&&(this.requests[d].isDuplicated||!function(d,e){var f;if(~e.request.url.indexOf("{{query}}")&&(e.request.url=e.request.url.replace("{{query}}",a.query)),e.request.data)for(var g in e.request.data)if(e.request.data.hasOwnProperty(g)&&~String(e.request.data[g]).indexOf("{{query}}")){e=c.extend(!0,{},e),e.request.data[g]=e.request.data[g].replace("{{query}}",a.query);break}a.xhr[d]=c.ajax(e.request).done(function(c,d,g){for(var h,i=0;i<e.validForGroup.length;i++)f=a.requests[e.validForGroup[i]],f.extra.callback.done instanceof Function&&(h=f.extra.callback.done(c,d,g),c=h instanceof Array&&h||c),a.populateSource(c,f.extra.group,f.extra.path),b-=1,0===b&&a.helper.executeCallback(a.options.callback.onReceiveRequest,[a.node,a.query])}).fail(function(b,c,d){for(var g=0;g<e.validForGroup.length;g++)f=a.requests[e.validForGroup[g]],f.extra.callback.fail instanceof Function&&f.extra.callback.fail(b,c,d)}).complete(function(b,c){for(var d=0;d<e.validForGroup.length;d++)f=a.requests[e.validForGroup[d]],f.extra.callback.complete instanceof Function&&f.extra.callback.complete(b,c)}).always(function(b,c,d){for(var g=0;g<e.validForGroup.length;g++)f=a.requests[e.validForGroup[g]],f.extra.callback.always instanceof Function&&f.extra.callback.always(b,c,d)})}(d,this.requests[d]))},populateSource:function(a,b,c){var d=this,e=this.options.source[b].url&&this.options.source[b].data;a="string"==typeof c?this.helper.namespace(c,a):a,a instanceof Array||(a=[]),e&&("function"==typeof e&&(e=e()),e instanceof Array&&(a=a.concat(e)));for(var f,g=this.options.source[b].display?"compiled"===this.options.source[b].display[0]?this.options.source[b].display[1]:this.options.source[b].display[0]:"compiled"===this.options.display[0]?this.options.display[1]:this.options.display[0],h=0;h<a.length;h++)"string"==typeof a[h]&&(f={},f[g]=a[h],a[h]=f),a[h].group=b;if(this.options.correlativeTemplate){var i=this.options.source[b].template||this.options.template;if(i){i=i.replace(/<.+?>/g,"");for(var h=0;h<a.length;h++)a[h].compiled=i.replace(/\{\{([\w\-\.]+)(?:\|(\w+))?}}/g,function(b,c){return d.helper.namespace(c,a[h],"get","")}).trim();this.options.source[b].display?~this.options.source[b].display.indexOf("compiled")||this.options.source[b].display.unshift("compiled"):~this.options.display.indexOf("compiled")||this.options.display.unshift("compiled")}else;}if(this.source[b]=a,this.options.cache&&!localStorage.getItem(this.node.selector+":"+b)){var j=JSON.stringify({data:a,ttl:(new Date).getTime()+this.options.ttl});this.options.compression&&(j=LZString.compressToUTF16(j)),localStorage.setItem(this.node.selector+":"+b,j)}this.incrementGeneratedGroup()},incrementGeneratedGroup:function(){this.generatedGroupCount+=1,this.groupCount===this.generatedGroupCount&&(this.isGenerated=!0,this.node.trigger("dynamic"+f))},navigate:function(a){this.helper.executeCallback(this.options.callback.onNavigate,[this.node,this.query,a]);var b=this.resultContainer.find("> ul > li:not([data-search-group])"),c=b.filter(".active"),d=c[0]&&b.index(c)||null;if(27===a.keyCode)return void(this.container.hasClass("result")&&(a.preventDefault(),this.hideLayout()));if(13===a.keyCode){if(c.length>0)return a.preventDefault(),a.stopPropagation(),void c.find("a:first").trigger("click");if(this.options.mustSelectItem&&this.helper.isEmpty(this.item))return;return void this.hideLayout()}if(39===a.keyCode)return void(d?b.eq(d).find("a:first").trigger("click"):this.options.hint&&""!==this.hint.container.val()&&this.helper.getCaret(this.node[0])>=this.query.length&&b.find('a[data-index="'+this.hintIndex+'"]').trigger("click"));if(b.length>0&&c.removeClass("active"),38===a.keyCode?(a.preventDefault(),c.length>0?d-1>=0&&b.eq(d-1).addClass("active"):b.last().addClass("active")):40===a.keyCode&&(a.preventDefault(),c.length>0?d+1<b.length&&b.eq(d+1).addClass("active"):b.first().addClass("active")),c=b.filter(".active"),this.options.hint&&this.hint.container&&(c.length>0?this.hint.container.css("color",this.hint.container.css("background-color")||"fff"):this.hint.container.css("color",this.hint.css.color)),c.length>0){var e=c.find("a:first").attr("data-index");e&&this.node.val(this.result[e][this.result[e].matchedKey])}else this.node.val(this.rawQuery)},searchResult:function(a){a||(this.item={}),this.helper.executeCallback(this.options.callback.onSearch,[this.node,this.query]),this.result=[],this.resultCount=0;var b,c,d,e,f,g,h,i,j,k=this,l=this.query.toLowerCase(),m={},n=this.filters.dropdown&&this.filters.dropdown.key||this.groupBy,o=this.filters.dynamic&&!this.helper.isEmpty(this.filters.dynamic);this.options.accent&&(l=this.helper.removeAccent(l));for(b in this.source)if(this.source.hasOwnProperty(b)&&(!this.filters.dropdown||"group"!==this.filters.dropdown.key||this.filters.dropdown.value===b)){if(this.options.maxItemPerGroup&&"group"===n)if(m[b]){if(m[b]>=this.options.maxItemPerGroup&&!this.options.callback.onResult)break}else m[b]=0;g="undefined"==typeof this.options.source[b].filter||this.options.source[b].filter===!0;for(var p=0;p<this.source[b].length&&(!(this.result.length>=this.options.maxItem)||this.options.callback.onResult);p++)if(!o||this.dynamicFilter.validate.apply(this,[this.source[b][p]])){if(c=this.source[b][p],this.options.maxItemPerGroup&&"group"!==n)if(m[c[n]]){if(m[c[n]]>=this.options.maxItemPerGroup&&!this.options.callback.onResult)continue}else m[c[n]]=0;f=this.options.source[b].display||this.options.display;for(var q=0;q<f.length;q++){if(g){if(e=c[f[q]],!e)continue;if(e=e.toString().toLowerCase(),this.options.accent&&(e=this.helper.removeAccent(e)),d=e.indexOf(l),this.options.correlativeTemplate&&"compiled"===f[q]&&0>d&&/\s/.test(l)){h=!0,i=l.split(" "),j=e;for(var r=0;r<i.length;r++)if(""!==i[r]){if(!~j.indexOf(i[r])){h=!1;break}j=j.replace(i[r],"")}}if(0>d&&!h)continue;if(this.options.offset&&0!==d)continue;if(this.options.source[b].ignore&&this.options.source[b].ignore.test(e))continue}if(!this.filters.dropdown||this.filters.dropdown.value==c[this.filters.dropdown.key]){if(this.resultCount+=1,this.options.callback.onResult&&this.result.length>=this.options.maxItem||this.options.maxItemPerGroup&&m[c[n]]>=this.options.maxItemPerGroup)break;c.matchedKey=f[q],this.result.push(c),this.options.maxItemPerGroup&&(m[c[n]]+=1);break}}}}if(this.options.order){for(var s,f=[],q=0;q<this.result.length;q++)s=this.options.source[this.result[q].group].display||this.options.display,~f.indexOf(s[0])||f.push(s[0]);this.result.sort(k.helper.sort(f,"asc"===k.options.order,function(a){return a.toString().toUpperCase()}))}this.helper.executeCallback(this.options.callback.onResult,[this.node,this.query,this.result,this.resultCount])},buildLayout:function(){this.resultContainer||(this.resultContainer=c("<div/>",{"class":this.options.selector.result}),this.container.append(this.resultContainer));var a=this.query.toLowerCase();this.options.accent&&(a=this.helper.removeAccent(a));var b=this,d=c("<ul/>",{"class":this.options.selector.list+(b.helper.isEmpty(b.result)?" empty":""),html:function(){if(b.options.emptyTemplate&&b.helper.isEmpty(b.result))return c("<li/>",{html:c("<a/>",{href:"javascript:;",html:"function"==typeof b.options.emptyTemplate&&b.options.emptyTemplate(b.query)||b.options.emptyTemplate.replace(/\{\{query}}/gi,b.query)})});for(var d in b.result)b.result.hasOwnProperty(d)&&!function(d,e,f){var g,h,i,j,k,l=e.group,m={},n=b.options.source[e.group].display||b.options.display,o=b.options.source[e.group].href||b.options.href;b.options.group&&("boolean"!=typeof b.options.group[0]&&e[b.options.group[0]]&&(l=e[b.options.group[0]]),c(f).find('li[data-search-group="'+l+'"]')[0]||c(f).append(c("<li/>",{"class":b.options.selector.group,html:c("<a/>",{href:"javascript:;",html:b.options.group[1]&&b.options.group[1].replace(/(\{\{group}})/gi,e[b.options.group[0]]||l)||l}),"data-search-group":l})));for(var p=0;p<n.length;p++)i=n[p],m[i]=e[i];g=c("<li/>",{html:c("<a/>",{href:function(){return o&&("string"==typeof o?o=o.replace(/\{\{([\w\-\.]+)(?:\|(\w+))?}}/g,function(a,c,d){var f=b.helper.namespace(c,e,"get","");return d&&"raw"===d?f:b.helper.slugify(f)}):"function"==typeof o&&(o=o(e)),e.href=o),o||"javascript:;"},"data-group":l,"data-index":d,html:function(){k=e.group&&b.options.source[e.group].template||b.options.template,h=k?k.replace(/\{\{([\w\-\.]+)(?:\|(\w+))?}}/g,function(a,c,d){var f=b.helper.namespace(c,e,"get","");return d&&"raw"===d?f:b.helper.namespace(c,m,"get","")||f}):'<span class="'+b.options.selector.display+'">'+b.helper.joinObject(m," ")+"</span>",b.options.highlight&&(h=b.helper.highlight(h,a.split(" "),b.options.accent)),c(this).append(h)},click:function(a){return b.options.mustSelectItem&&b.helper.isEmpty(e)?void a.preventDefault():(b.item=e,b.helper.executeCallback(b.options.callback.onClickBefore,[b.node,this,e,a]),void(a.isDefaultPrevented()||(a.preventDefault(),b.query=b.rawQuery=e[e.matchedKey].toString(),b.node.val(b.query).focus(),b.searchResult(!0),b.buildLayout(),b.hideLayout(),b.helper.executeCallback(b.options.callback.onClickAfter,[b.node,this,e,a]))))},mouseenter:function(a){c(this).closest("ul").find("li.active").removeClass("active"),c(this).closest("li").addClass("active"),b.helper.executeCallback(b.options.callback.onMouseEnter,[b.node,this,e,a])},mouseleave:function(a){c(this).closest("li").removeClass("active"),b.helper.executeCallback(b.options.callback.onMouseLeave,[b.node,this,e,a])}})}),b.options.group?(j=c(f).find('a[data-group="'+l+'"]:last').closest("li"),j[0]||(j=c(f).find('li[data-search-group="'+l+'"]')),c(g).insertAfter(j)):c(f).append(g)}(d,b.result[d],this)}});if(this.options.callback.onLayoutBuiltBefore){var f=this.helper.executeCallback(this.options.callback.onLayoutBuiltBefore,[this.node,this.query,this.result,d]);f instanceof jQuery&&(d=f)}if(this.container.addClass("result"),this.resultContainer.html(d),this.options.callback.onLayoutBuiltAfter&&this.helper.executeCallback(this.options.callback.onLayoutBuiltAfter,[this.node,this.query,this.result]),this.options.backdrop&&(this.backdrop.container?this.backdrop.container.show():(this.backdrop.css=c.extend({opacity:.6,filter:"alpha(opacity=60)",position:"fixed",top:0,right:0,bottom:0,left:0,"z-index":1040,"background-color":"#000"},this.options.backdrop),this.backdrop.container=c("<div/>",{"class":this.options.selector.backdrop,css:this.backdrop.css,click:function(){b.hideLayout()}}).insertAfter(this.container)),this.container.addClass("backdrop").css({"z-index":this.backdrop.css["z-index"]+1,position:"relative"})),this.options.hint){var g="";if(this.result.length>0&&this.query.length>0){this.hint.container||(this.hint.css=c.extend({"border-color":"transparent",position:"absolute",top:0,display:"inline","z-index":-1,"float":"none",color:"silver","box-shadow":"none",cursor:"default","-webkit-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none"},this.options.hint),this.hint.container=c("<input/>",{type:this.node.attr("type"),"class":this.node.attr("class"),readonly:!0,unselectable:"on",tabindex:-1,click:function(){b.node.focus()}}).addClass(e.selector.hint).css(this.hint.css).insertAfter(this.node),this.node.parent().css({position:"relative"})),this.hint.container.css("color",this.hint.css.color);var h,i,j;this.hintIndex=null;for(var k=0;k<this.result.length;k++){i=this.result[k].group,h=b.options.source[i].display||b.options.display;for(var l=0;l<h.length;l++)if(j=String(this.result[k][h[l]]).toLowerCase(),this.options.accent&&(j=this.helper.removeAccent(j)),0===j.indexOf(a)){g=String(this.result[k][h[l]]),this.hintIndex=k;break}if(null!==this.hintIndex)break}}this.hint.container&&this.hint.container.val(g.length>0&&this.rawQuery+g.substring(this.query.length)||"").show()}},buildDropdownLayout:function(){function a(a){"*"===a.value?delete this.filters.dropdown:this.filters.dropdown=a,this.container.removeClass("filter").find("."+this.options.selector.filterValue).html(a.display||a.value),this.node.trigger("dynamic"+f),this.node.focus()}if(this.options.dropdownFilter){var b,d=this;if("boolean"==typeof this.options.dropdownFilter)b="all";else if("string"==typeof this.options.dropdownFilter)b=this.options.dropdownFilter;else if(this.options.dropdownFilter instanceof Array)for(var e=0;e<this.options.dropdownFilter.length;e++)if("*"===this.options.dropdownFilter[e].value&&this.options.dropdownFilter[e].display){b=this.options.dropdownFilter[e].display;break}c("<span/>",{"class":this.options.selector.filter,html:function(){c(this).append(c("<button/>",{type:"button","class":d.options.selector.filterButton,html:"<span class='"+d.options.selector.filterValue+"'>"+b+"</span> <span class='"+d.options.selector.dropdownCarret+"'></span>",click:function(a){a.stopPropagation();var b=d.container.find("."+d.options.selector.dropdown.replace(" ","."));b.is(":visible")?(d.container.removeClass("filter"),b.hide(),c("html").off(f+".dropdownFilter")):(d.container.addClass("filter"),b.show(),c("html").off(f+".dropdownFilter").on("click"+f+".dropdownFilter touchstart"+f+".dropdownFilter",function(){d.container.removeClass("filter"),b.hide(),c(this).off(f+".dropdownFilter")}))}})),c(this).append(c("<ul/>",{"class":d.options.selector.dropdown,html:function(){var b=d.options.dropdownFilter;if(~["string","boolean"].indexOf(typeof d.options.dropdownFilter)){b=[];for(var e in d.options.source)d.options.source.hasOwnProperty(e)&&b.push({key:"group",value:e});b.push({key:"group",value:"*",display:"string"==typeof d.options.dropdownFilter&&d.options.dropdownFilter||"All"})}for(var f=0;f<b.length;f++)!function(b,e,f){(e.key||"*"===e.value)&&e.value&&("*"===e.value&&c(f).append(c("<li/>",{"class":"divider"})),c(f).append(c("<li/>",{html:c("<a/>",{href:"javascript:;",html:e.display||e.value,click:function(b){b.preventDefault(),a.apply(d,[e])}})})))}(f,b[f],this)}}))}}).insertAfter(d.container.find("."+d.options.selector.query))}},dynamicFilter:{validate:function(a){var b,c,d=null,e=null;for(var f in this.filters.dynamic)if(this.filters.dynamic.hasOwnProperty(f)&&(c=~f.indexOf(".")?this.helper.namespace(f,a,"get"):a[f],"|"!==this.filters.dynamic[f].modifier||d||(d=c==this.filters.dynamic[f].value||!1),"&"===this.filters.dynamic[f].modifier)){if(c!=this.filters.dynamic[f].value){e=!1;break}e=!0}return b=d,null!==e&&(b=e,e===!0&&null!==d&&(b=d)),!!b},set:function(a,b){var c=a.match(/^([|&])?(.+)/);b?this.filters.dynamic[c[2]]={modifier:c[1]||"|",value:b}:delete this.filters.dynamic[c[2]],this.searchResult(),this.buildLayout()},bind:function(){if(this.options.dynamicFilter)for(var a,b=this,d=0;d<this.options.dynamicFilter.length;d++)a=this.options.dynamicFilter[d],"string"==typeof a.selector&&(a.selector=c(a.selector)),a.selector instanceof jQuery&&a.selector[0]&&a.key&&!function(a){a.selector.off(f).on("change"+f,function(){b.dynamicFilter.set.apply(b,[a.key,b.dynamicFilter.getValue(this)])}).trigger("change"+f)}(a)},getValue:function(a){var b;return"SELECT"===a.tagName?b=a.value:"INPUT"===a.tagName&&("checkbox"===a.type?b=a.checked||null:"radio"===a.type&&a.checked&&(b=a.value)),b}},showLayout:function(){var a=this;c("html").off(f).on("click"+f+" touchstart"+f,function(){a.hideLayout(),c(this).off(f)}),(this.result.length||this.options.emptyTemplate)&&this.container.addClass("result hint backdrop")},hideLayout:function(){this.container.removeClass("result hint backdrop filter")},__construct:function(){this.extendOptions(),this.unifySourceFormat()&&(this.init(),this.delegateEvents(),this.buildDropdownLayout(),this.dynamicFilter.bind.apply(this),this.helper.executeCallback(this.options.callback.onReady,[this.node]))},helper:{isEmpty:function(a){for(var b in a)if(a.hasOwnProperty(b))return!1;return!0},removeAccent:function(a){return"string"==typeof a?a=a.toLowerCase().replace(new RegExp("["+g.from+"]","g"),function(a){return g.to[g.from.indexOf(a)]}):void 0},slugify:function(a){return a=String(a),""!==a&&(a=this.removeAccent(a),a=a.replace(/[^-a-z0-9]+/g,"-").replace(/-+/g,"-").trim("-")),a},sort:function(a,b,c){var d=function(b){for(var d=0;d<a.length;d++)if("undefined"!=typeof b[a[d]])return c(b[a[d]])};return b=[-1,1][+!!b],function(a,c){return a=d(a),c=d(c),b*((a>c)-(c>a))}},replaceAt:function(a,b,c,d){return a.substring(0,b)+d+a.substring(b+c)},highlight:function(a,b,c){a=String(a);var d=c&&this.removeAccent(a)||a,e=[];b instanceof Array||(b=[b]),b.sort(function(a,b){return b.length-a.length});for(var f=b.length-1;f>=0;f--)""!==b[f].trim()?b[f]=b[f].replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"):b.splice(f,1);d.replace(new RegExp("(?:"+b.join("|")+")(?!([^<]+)?>)","gi"),function(a,b,c){e.push({offset:c,length:a.length})});for(var f=e.length-1;f>=0;f--)a=this.replaceAt(a,e[f].offset,e[f].length,"<strong>"+a.substr(e[f].offset,e[f].length)+"</strong>");return a},joinObject:function(a,b){var c="",d=0;for(var e in a)a.hasOwnProperty(e)&&(0!==d&&(c+=b),c+=a[e],d++);return c},getCaret:function(a){if(a.selectionStart)return a.selectionStart;if(b.selection){a.focus();var c=b.selection.createRange();if(null==c)return 0;var d=a.createTextRange(),e=d.duplicate();return d.moveToBookmark(c.getBookmark()),e.setEndPoint("EndToStart",d),e.text.length}return 0},executeCallback:function(b,d){if(!b)return!1;var e;d[0];if("function"==typeof b)e=b;else if(("string"==typeof b||b instanceof Array)&&("string"==typeof b&&(b=[b,[]]),e=this.helper.namespace(b[0],a),"function"!=typeof e))return!1;return e.apply(this,c.merge(b[1]||[],d?d:[]))||!0},namespace:function(b,c,e,f){if("string"!=typeof b||""===b)return!1;for(var g=b.split("."),h=c||a,e=e||"get",i=f||{},j="",k=0,l=g.length;l>k;k++){if(j=g[k],"undefined"==typeof h[j]){if(~["get","delete"].indexOf(e))return"undefined"!=typeof f?f:d;h[j]={}}if(~["set","create","delete"].indexOf(e)&&k===l-1){if("set"!==e&&"create"!==e)return delete h[j],!0;h[j]=i}h=h[j]}return h},typeWatch:function(){var a=0;return function(b,c){clearTimeout(a),a=setTimeout(b,c)}}()}},c.fn.typeahead=c.typeahead=function(a){return j.typeahead(this,a)};var j={typeahead:function(b,d){if(d&&d.source&&"object"==typeof d.source){if("function"==typeof b){if(!d.input)return;b=c(d.input)}if(b.length)for(var e,f=0;f<b.length;f++)e=1===b.length?b:c(b.selector.split(",")[f].trim()),a.Typeahead[e.selector]=new i(e,d)}}};a.console=a.console||{log:function(){}},"trim"in String.prototype||(String.prototype.trim=function(){return this.replace(/^\s+/,"").replace(/\s+$/,"")}),"indexOf"in Array.prototype||(Array.prototype.indexOf=function(a,b){b===d&&(b=0),0>b&&(b+=this.length),0>b&&(b=0);for(var c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1}),Object.keys||(Object.keys=function(a){var b,c=[];for(b in a)Object.prototype.hasOwnProperty.call(a,b)&&c.push(b);return c})}(window,document,window.jQuery); \ No newline at end of file
diff --git a/vendor/assets/javascripts/moment.min.js b/vendor/assets/javascripts/moment.min.js
new file mode 100644
index 0000000..8e6866a
--- /dev/null
+++ b/vendor/assets/javascripts/moment.min.js
@@ -0,0 +1,7 @@
+//! moment.js
+//! version : 2.10.6
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Hc.apply(null,arguments)}function b(a){Hc=a}function c(a){return"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function f(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function g(a,b){for(var c in b)f(b,c)&&(a[c]=b[c]);return f(b,"toString")&&(a.toString=b.toString),f(b,"valueOf")&&(a.valueOf=b.valueOf),a}function h(a,b,c,d){return Ca(a,b,c,d,!0).utc()}function i(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function j(a){return null==a._pf&&(a._pf=i()),a._pf}function k(a){if(null==a._isValid){var b=j(a);a._isValid=!(isNaN(a._d.getTime())||!(b.overflow<0)||b.empty||b.invalidMonth||b.invalidWeekday||b.nullInput||b.invalidFormat||b.userInvalidated),a._strict&&(a._isValid=a._isValid&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour)}return a._isValid}function l(a){var b=h(NaN);return null!=a?g(j(b),a):j(b).userInvalidated=!0,b}function m(a,b){var c,d,e;if("undefined"!=typeof b._isAMomentObject&&(a._isAMomentObject=b._isAMomentObject),"undefined"!=typeof b._i&&(a._i=b._i),"undefined"!=typeof b._f&&(a._f=b._f),"undefined"!=typeof b._l&&(a._l=b._l),"undefined"!=typeof b._strict&&(a._strict=b._strict),"undefined"!=typeof b._tzm&&(a._tzm=b._tzm),"undefined"!=typeof b._isUTC&&(a._isUTC=b._isUTC),"undefined"!=typeof b._offset&&(a._offset=b._offset),"undefined"!=typeof b._pf&&(a._pf=j(b)),"undefined"!=typeof b._locale&&(a._locale=b._locale),Jc.length>0)for(c in Jc)d=Jc[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function n(b){m(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),Kc===!1&&(Kc=!0,a.updateOffset(this),Kc=!1)}function o(a){return a instanceof n||null!=a&&null!=a._isAMomentObject}function p(a){return 0>a?Math.ceil(a):Math.floor(a)}function q(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=p(b)),c}function r(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&q(a[d])!==q(b[d]))&&g++;return g+f}function s(){}function t(a){return a?a.toLowerCase().replace("_","-"):a}function u(a){for(var b,c,d,e,f=0;f<a.length;){for(e=t(a[f]).split("-"),b=e.length,c=t(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=v(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&r(e,c,!0)>=b-1)break;b--}f++}return null}function v(a){var b=null;if(!Lc[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Ic._abbr,require("./locale/"+a),w(b)}catch(c){}return Lc[a]}function w(a,b){var c;return a&&(c="undefined"==typeof b?y(a):x(a,b),c&&(Ic=c)),Ic._abbr}function x(a,b){return null!==b?(b.abbr=a,Lc[a]=Lc[a]||new s,Lc[a].set(b),w(a),Lc[a]):(delete Lc[a],null)}function y(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Ic;if(!c(a)){if(b=v(a))return b;a=[a]}return u(a)}function z(a,b){var c=a.toLowerCase();Mc[c]=Mc[c+"s"]=Mc[b]=a}function A(a){return"string"==typeof a?Mc[a]||Mc[a.toLowerCase()]:void 0}function B(a){var b,c,d={};for(c in a)f(a,c)&&(b=A(c),b&&(d[b]=a[c]));return d}function C(b,c){return function(d){return null!=d?(E(this,b,d),a.updateOffset(this,c),this):D(this,b)}}function D(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function E(a,b,c){return a._d["set"+(a._isUTC?"UTC":"")+b](c)}function F(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=A(a),"function"==typeof this[a])return this[a](b);return this}function G(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function H(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Qc[a]=e),b&&(Qc[b[0]]=function(){return G(e.apply(this,arguments),b[1],b[2])}),c&&(Qc[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function I(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function J(a){var b,c,d=a.match(Nc);for(b=0,c=d.length;c>b;b++)Qc[d[b]]?d[b]=Qc[d[b]]:d[b]=I(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function K(a,b){return a.isValid()?(b=L(b,a.localeData()),Pc[b]=Pc[b]||J(b),Pc[b](a)):a.localeData().invalidDate()}function L(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Oc.lastIndex=0;d>=0&&Oc.test(a);)a=a.replace(Oc,c),Oc.lastIndex=0,d-=1;return a}function M(a){return"function"==typeof a&&"[object Function]"===Object.prototype.toString.call(a)}function N(a,b,c){dd[a]=M(b)?b:function(a){return a&&c?c:b}}function O(a,b){return f(dd,a)?dd[a](b._strict,b._locale):new RegExp(P(a))}function P(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function Q(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=q(a)}),c=0;c<a.length;c++)ed[a[c]]=d}function R(a,b){Q(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function S(a,b,c){null!=b&&f(ed,a)&&ed[a](b,c._a,c,a)}function T(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function U(a){return this._months[a.month()]}function V(a){return this._monthsShort[a.month()]}function W(a,b,c){var d,e,f;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;12>d;d++){if(e=h([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function X(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),T(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function Y(b){return null!=b?(X(this,b),a.updateOffset(this,!0),this):D(this,"Month")}function Z(){return T(this.year(),this.month())}function $(a){var b,c=a._a;return c&&-2===j(a).overflow&&(b=c[gd]<0||c[gd]>11?gd:c[hd]<1||c[hd]>T(c[fd],c[gd])?hd:c[id]<0||c[id]>24||24===c[id]&&(0!==c[jd]||0!==c[kd]||0!==c[ld])?id:c[jd]<0||c[jd]>59?jd:c[kd]<0||c[kd]>59?kd:c[ld]<0||c[ld]>999?ld:-1,j(a)._overflowDayOfYear&&(fd>b||b>hd)&&(b=hd),j(a).overflow=b),a}function _(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function aa(a,b){var c=!0;return g(function(){return c&&(_(a+"\n"+(new Error).stack),c=!1),b.apply(this,arguments)},b)}function ba(a,b){od[a]||(_(b),od[a]=!0)}function ca(a){var b,c,d=a._i,e=pd.exec(d);if(e){for(j(a).iso=!0,b=0,c=qd.length;c>b;b++)if(qd[b][1].exec(d)){a._f=qd[b][0];break}for(b=0,c=rd.length;c>b;b++)if(rd[b][1].exec(d)){a._f+=(e[6]||" ")+rd[b][0];break}d.match(ad)&&(a._f+="Z"),va(a)}else a._isValid=!1}function da(b){var c=sd.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(ca(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ea(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function fa(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function ga(a){return ha(a)?366:365}function ha(a){return a%4===0&&a%100!==0||a%400===0}function ia(){return ha(this.year())}function ja(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=Da(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ka(a){return ja(a,this._week.dow,this._week.doy).week}function la(){return this._week.dow}function ma(){return this._week.doy}function na(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function oa(a){var b=ja(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function pa(a,b,c,d,e){var f,g=6+e-d,h=fa(a,0,1+g),i=h.getUTCDay();return e>i&&(i+=7),c=null!=c?1*c:e,f=1+g+7*(b-1)-i+c,{year:f>0?a:a-1,dayOfYear:f>0?f:ga(a-1)+f}}function qa(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function ra(a,b,c){return null!=a?a:null!=b?b:c}function sa(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function ta(a){var b,c,d,e,f=[];if(!a._d){for(d=sa(a),a._w&&null==a._a[hd]&&null==a._a[gd]&&ua(a),a._dayOfYear&&(e=ra(a._a[fd],d[fd]),a._dayOfYear>ga(e)&&(j(a)._overflowDayOfYear=!0),c=fa(e,0,a._dayOfYear),a._a[gd]=c.getUTCMonth(),a._a[hd]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[id]&&0===a._a[jd]&&0===a._a[kd]&&0===a._a[ld]&&(a._nextDay=!0,a._a[id]=0),a._d=(a._useUTC?fa:ea).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[id]=24)}}function ua(a){var b,c,d,e,f,g,h;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=ra(b.GG,a._a[fd],ja(Da(),1,4).year),d=ra(b.W,1),e=ra(b.E,1)):(f=a._locale._week.dow,g=a._locale._week.doy,c=ra(b.gg,a._a[fd],ja(Da(),f,g).year),d=ra(b.w,1),null!=b.d?(e=b.d,f>e&&++d):e=null!=b.e?b.e+f:f),h=pa(c,d,e,g,f),a._a[fd]=h.year,a._dayOfYear=h.dayOfYear}function va(b){if(b._f===a.ISO_8601)return void ca(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=L(b._f,b._locale).match(Nc)||[],c=0;c<e.length;c++)f=e[c],d=(h.match(O(f,b))||[])[0],d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),Qc[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),S(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[id]<=12&&b._a[id]>0&&(j(b).bigHour=void 0),b._a[id]=wa(b._locale,b._a[id],b._meridiem),ta(b),$(b)}function wa(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function xa(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=m({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],va(b),k(b)&&(f+=j(b).charsLeftOver,f+=10*j(b).unusedTokens.length,j(b).score=f,(null==d||d>f)&&(d=f,c=b));g(a,c||b)}function ya(a){if(!a._d){var b=B(a._i);a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],ta(a)}}function za(a){var b=new n($(Aa(a)));return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function Aa(a){var b=a._i,e=a._f;return a._locale=a._locale||y(a._l),null===b||void 0===e&&""===b?l({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),o(b)?new n($(b)):(c(e)?xa(a):e?va(a):d(b)?a._d=b:Ba(a),a))}function Ba(b){var f=b._i;void 0===f?b._d=new Date:d(f)?b._d=new Date(+f):"string"==typeof f?da(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),ta(b)):"object"==typeof f?ya(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function Ca(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,za(f)}function Da(a,b,c,d){return Ca(a,b,c,d,!1)}function Ea(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Da();for(d=b[0],e=1;e<b.length;++e)(!b[e].isValid()||b[e][a](d))&&(d=b[e]);return d}function Fa(){var a=[].slice.call(arguments,0);return Ea("isBefore",a)}function Ga(){var a=[].slice.call(arguments,0);return Ea("isAfter",a)}function Ha(a){var b=B(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+36e5*h,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=y(),this._bubble()}function Ia(a){return a instanceof Ha}function Ja(a,b){H(a,0,0,function(){var a=this.utcOffset(),c="+";return 0>a&&(a=-a,c="-"),c+G(~~(a/60),2)+b+G(~~a%60,2)})}function Ka(a){var b=(a||"").match(ad)||[],c=b[b.length-1]||[],d=(c+"").match(xd)||["-",0,0],e=+(60*d[1])+q(d[2]);return"+"===d[0]?e:-e}function La(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(o(b)||d(b)?+b:+Da(b))-+e,e._d.setTime(+e._d+f),a.updateOffset(e,!1),e):Da(b).local()}function Ma(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Na(b,c){var d,e=this._offset||0;return null!=b?("string"==typeof b&&(b=Ka(b)),Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ma(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?bb(this,Ya(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ma(this)}function Oa(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Pa(a){return this.utcOffset(0,a)}function Qa(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ma(this),"m")),this}function Ra(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ka(this._i)),this}function Sa(a){return a=a?Da(a).utcOffset():0,(this.utcOffset()-a)%60===0}function Ta(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ua(){if("undefined"!=typeof this._isDSTShifted)return this._isDSTShifted;var a={};if(m(a,this),a=Aa(a),a._a){var b=a._isUTC?h(a._a):Da(a._a);this._isDSTShifted=this.isValid()&&r(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Va(){return!this._isUTC}function Wa(){return this._isUTC}function Xa(){return this._isUTC&&0===this._offset}function Ya(a,b){var c,d,e,g=a,h=null;return Ia(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=yd.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:q(h[hd])*c,h:q(h[id])*c,m:q(h[jd])*c,s:q(h[kd])*c,ms:q(h[ld])*c}):(h=zd.exec(a))?(c="-"===h[1]?-1:1,g={y:Za(h[2],c),M:Za(h[3],c),d:Za(h[4],c),h:Za(h[5],c),m:Za(h[6],c),s:Za(h[7],c),w:Za(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=_a(Da(g.from),Da(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Ha(g),Ia(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function Za(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function $a(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function _a(a,b){var c;return b=La(b,a),a.isBefore(b)?c=$a(a,b):(c=$a(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function ab(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(ba(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ya(c,d),bb(this,e,a),this}}function bb(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&E(b,"Date",D(b,"Date")+g*d),h&&X(b,D(b,"Month")+h*d),e&&a.updateOffset(b,g||h)}function cb(a,b){var c=a||Da(),d=La(c,this).startOf("day"),e=this.diff(d,"days",!0),f=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(b&&b[f]||this.localeData().calendar(f,this,Da(c)))}function db(){return new n(this)}function eb(a,b){var c;return b=A("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+this>+a):(c=o(a)?+a:+Da(a),c<+this.clone().startOf(b))}function fb(a,b){var c;return b=A("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+a>+this):(c=o(a)?+a:+Da(a),+this.clone().endOf(b)<c)}function gb(a,b,c){return this.isAfter(a,c)&&this.isBefore(b,c)}function hb(a,b){var c;return b=A(b||"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+this===+a):(c=+Da(a),+this.clone().startOf(b)<=c&&c<=+this.clone().endOf(b))}function ib(a,b,c){var d,e,f=La(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=A(b),"year"===b||"month"===b||"quarter"===b?(e=jb(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:p(e)}function jb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function kb(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function lb(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?"function"==typeof Date.prototype.toISOString?this.toDate().toISOString():K(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):K(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function mb(b){var c=K(this,b||a.defaultFormat);return this.localeData().postformat(c)}function nb(a,b){return this.isValid()?Ya({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ob(a){return this.from(Da(),a)}function pb(a,b){return this.isValid()?Ya({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function qb(a){return this.to(Da(),a)}function rb(a){var b;return void 0===a?this._locale._abbr:(b=y(a),null!=b&&(this._locale=b),this)}function sb(){return this._locale}function tb(a){switch(a=A(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function ub(a){return a=A(a),void 0===a||"millisecond"===a?this:this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms")}function vb(){return+this._d-6e4*(this._offset||0)}function wb(){return Math.floor(+this/1e3)}function xb(){return this._offset?new Date(+this):this._d}function yb(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function zb(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function Ab(){return k(this)}function Bb(){return g({},j(this))}function Cb(){return j(this).overflow}function Db(a,b){H(0,[a,a.length],0,b)}function Eb(a,b,c){return ja(Da([a,11,31+b-c]),b,c).week}function Fb(a){var b=ja(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")}function Gb(a){var b=ja(this,1,4).year;return null==a?b:this.add(a-b,"y")}function Hb(){return Eb(this.year(),1,4)}function Ib(){var a=this.localeData()._week;return Eb(this.year(),a.dow,a.doy)}function Jb(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}function Kb(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Lb(a){return this._weekdays[a.day()]}function Mb(a){return this._weekdaysShort[a.day()]}function Nb(a){return this._weekdaysMin[a.day()]}function Ob(a){var b,c,d;for(this._weekdaysParse=this._weekdaysParse||[],b=0;7>b;b++)if(this._weekdaysParse[b]||(c=Da([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b}function Pb(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Kb(a,this.localeData()),this.add(a-b,"d")):b}function Qb(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Rb(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)}function Sb(a,b){H(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Tb(a,b){return b._meridiemParse}function Ub(a){return"p"===(a+"").toLowerCase().charAt(0)}function Vb(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Wb(a,b){b[ld]=q(1e3*("0."+a))}function Xb(){return this._isUTC?"UTC":""}function Yb(){return this._isUTC?"Coordinated Universal Time":""}function Zb(a){return Da(1e3*a)}function $b(){return Da.apply(null,arguments).parseZone()}function _b(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.call(b,c):d}function ac(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function bc(){return this._invalidDate}function cc(a){return this._ordinal.replace("%d",a)}function dc(a){return a}function ec(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)}function fc(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)}function gc(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function hc(a,b,c,d){var e=y(),f=h().set(d,b);return e[c](f,a)}function ic(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return hc(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=hc(a,f,c,e);return g}function jc(a,b){return ic(a,b,"months",12,"month")}function kc(a,b){return ic(a,b,"monthsShort",12,"month")}function lc(a,b){return ic(a,b,"weekdays",7,"day")}function mc(a,b){return ic(a,b,"weekdaysShort",7,"day")}function nc(a,b){return ic(a,b,"weekdaysMin",7,"day")}function oc(){var a=this._data;return this._milliseconds=Wd(this._milliseconds),this._days=Wd(this._days),this._months=Wd(this._months),a.milliseconds=Wd(a.milliseconds),a.seconds=Wd(a.seconds),a.minutes=Wd(a.minutes),a.hours=Wd(a.hours),a.months=Wd(a.months),a.years=Wd(a.years),this}function pc(a,b,c,d){var e=Ya(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function qc(a,b){return pc(this,a,b,1)}function rc(a,b){return pc(this,a,b,-1)}function sc(a){return 0>a?Math.floor(a):Math.ceil(a)}function tc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||0>=f&&0>=g&&0>=h||(f+=864e5*sc(vc(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=p(f/1e3),i.seconds=a%60,b=p(a/60),i.minutes=b%60,c=p(b/60),i.hours=c%24,g+=p(c/24),e=p(uc(g)),h+=e,g-=sc(vc(e)),d=p(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function uc(a){return 4800*a/146097}function vc(a){return 146097*a/4800}function wc(a){var b,c,d=this._milliseconds;if(a=A(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+uc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(vc(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function xc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*q(this._months/12)}function yc(a){return function(){return this.as(a)}}function zc(a){return a=A(a),this[a+"s"]()}function Ac(a){return function(){return this._data[a]}}function Bc(){return p(this.days()/7)}function Cc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function Dc(a,b,c){var d=Ya(a).abs(),e=ke(d.as("s")),f=ke(d.as("m")),g=ke(d.as("h")),h=ke(d.as("d")),i=ke(d.as("M")),j=ke(d.as("y")),k=e<le.s&&["s",e]||1===f&&["m"]||f<le.m&&["mm",f]||1===g&&["h"]||g<le.h&&["hh",g]||1===h&&["d"]||h<le.d&&["dd",h]||1===i&&["M"]||i<le.M&&["MM",i]||1===j&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,Cc.apply(null,k)}function Ec(a,b){return void 0===le[a]?!1:void 0===b?le[a]:(le[a]=b,!0)}function Fc(a){var b=this.localeData(),c=Dc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function Gc(){var a,b,c,d=me(this._milliseconds)/1e3,e=me(this._days),f=me(this._months);a=p(d/60),b=p(a/60),d%=60,a%=60,c=p(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(0>m?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var Hc,Ic,Jc=a.momentProperties=[],Kc=!1,Lc={},Mc={},Nc=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Oc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Pc={},Qc={},Rc=/\d/,Sc=/\d\d/,Tc=/\d{3}/,Uc=/\d{4}/,Vc=/[+-]?\d{6}/,Wc=/\d\d?/,Xc=/\d{1,3}/,Yc=/\d{1,4}/,Zc=/[+-]?\d{1,6}/,$c=/\d+/,_c=/[+-]?\d+/,ad=/Z|[+-]\d\d:?\d\d/gi,bd=/[+-]?\d+(\.\d{1,3})?/,cd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,dd={},ed={},fd=0,gd=1,hd=2,id=3,jd=4,kd=5,ld=6;H("M",["MM",2],"Mo",function(){return this.month()+1}),H("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),H("MMMM",0,0,function(a){return this.localeData().months(this,a)}),z("month","M"),N("M",Wc),N("MM",Wc,Sc),N("MMM",cd),N("MMMM",cd),Q(["M","MM"],function(a,b){b[gd]=q(a)-1}),Q(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[gd]=e:j(c).invalidMonth=a});var md="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),nd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),od={};a.suppressDeprecationWarnings=!1;var pd=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,qd=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],rd=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],sd=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=aa("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),H(0,["YY",2],0,function(){return this.year()%100}),H(0,["YYYY",4],0,"year"),H(0,["YYYYY",5],0,"year"),H(0,["YYYYYY",6,!0],0,"year"),z("year","y"),N("Y",_c),N("YY",Wc,Sc),N("YYYY",Yc,Uc),N("YYYYY",Zc,Vc),N("YYYYYY",Zc,Vc),Q(["YYYYY","YYYYYY"],fd),Q("YYYY",function(b,c){c[fd]=2===b.length?a.parseTwoDigitYear(b):q(b)}),Q("YY",function(b,c){c[fd]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return q(a)+(q(a)>68?1900:2e3)};var td=C("FullYear",!1);H("w",["ww",2],"wo","week"),H("W",["WW",2],"Wo","isoWeek"),z("week","w"),z("isoWeek","W"),N("w",Wc),N("ww",Wc,Sc),N("W",Wc),N("WW",Wc,Sc),R(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=q(a)});var ud={dow:0,doy:6};H("DDD",["DDDD",3],"DDDo","dayOfYear"),z("dayOfYear","DDD"),N("DDD",Xc),N("DDDD",Tc),Q(["DDD","DDDD"],function(a,b,c){c._dayOfYear=q(a)}),a.ISO_8601=function(){};var vd=aa("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Da.apply(null,arguments);return this>a?this:a}),wd=aa("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Da.apply(null,arguments);return a>this?this:a});Ja("Z",":"),Ja("ZZ",""),N("Z",ad),N("ZZ",ad),Q(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ka(a)});var xd=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var yd=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,zd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Ya.fn=Ha.prototype;var Ad=ab(1,"add"),Bd=ab(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Cd=aa("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});H(0,["gg",2],0,function(){return this.weekYear()%100}),H(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Db("gggg","weekYear"),Db("ggggg","weekYear"),Db("GGGG","isoWeekYear"),Db("GGGGG","isoWeekYear"),z("weekYear","gg"),z("isoWeekYear","GG"),N("G",_c),N("g",_c),N("GG",Wc,Sc),N("gg",Wc,Sc),N("GGGG",Yc,Uc),N("gggg",Yc,Uc),N("GGGGG",Zc,Vc),N("ggggg",Zc,Vc),R(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=q(a)}),R(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),H("Q",0,0,"quarter"),z("quarter","Q"),N("Q",Rc),Q("Q",function(a,b){b[gd]=3*(q(a)-1)}),H("D",["DD",2],"Do","date"),z("date","D"),N("D",Wc),N("DD",Wc,Sc),N("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),Q(["D","DD"],hd),Q("Do",function(a,b){b[hd]=q(a.match(Wc)[0],10)});var Dd=C("Date",!0);H("d",0,"do","day"),H("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),H("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),H("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),H("e",0,0,"weekday"),H("E",0,0,"isoWeekday"),z("day","d"),z("weekday","e"),z("isoWeekday","E"),N("d",Wc),N("e",Wc),N("E",Wc),N("dd",cd),N("ddd",cd),N("dddd",cd),R(["dd","ddd","dddd"],function(a,b,c){var d=c._locale.weekdaysParse(a);null!=d?b.d=d:j(c).invalidWeekday=a}),R(["d","e","E"],function(a,b,c,d){b[d]=q(a)});var Ed="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Fd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Gd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");H("H",["HH",2],0,"hour"),H("h",["hh",2],0,function(){return this.hours()%12||12}),Sb("a",!0),Sb("A",!1),z("hour","h"),N("a",Tb),N("A",Tb),N("H",Wc),N("h",Wc),N("HH",Wc,Sc),N("hh",Wc,Sc),Q(["H","HH"],id),Q(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),Q(["h","hh"],function(a,b,c){b[id]=q(a),j(c).bigHour=!0});var Hd=/[ap]\.?m?\.?/i,Id=C("Hours",!0);H("m",["mm",2],0,"minute"),z("minute","m"),N("m",Wc),N("mm",Wc,Sc),Q(["m","mm"],jd);var Jd=C("Minutes",!1);H("s",["ss",2],0,"second"),z("second","s"),N("s",Wc),N("ss",Wc,Sc),Q(["s","ss"],kd);var Kd=C("Seconds",!1);H("S",0,0,function(){return~~(this.millisecond()/100)}),H(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),H(0,["SSS",3],0,"millisecond"),H(0,["SSSS",4],0,function(){return 10*this.millisecond()}),H(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),H(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),H(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),H(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),H(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),z("millisecond","ms"),N("S",Xc,Rc),N("SS",Xc,Sc),N("SSS",Xc,Tc);var Ld;for(Ld="SSSS";Ld.length<=9;Ld+="S")N(Ld,$c);for(Ld="S";Ld.length<=9;Ld+="S")Q(Ld,Wb);var Md=C("Milliseconds",!1);H("z",0,0,"zoneAbbr"),H("zz",0,0,"zoneName");var Nd=n.prototype;Nd.add=Ad,Nd.calendar=cb,Nd.clone=db,Nd.diff=ib,Nd.endOf=ub,Nd.format=mb,Nd.from=nb,Nd.fromNow=ob,Nd.to=pb,Nd.toNow=qb,Nd.get=F,Nd.invalidAt=Cb,Nd.isAfter=eb,Nd.isBefore=fb,Nd.isBetween=gb,Nd.isSame=hb,Nd.isValid=Ab,Nd.lang=Cd,Nd.locale=rb,Nd.localeData=sb,Nd.max=wd,Nd.min=vd,Nd.parsingFlags=Bb,Nd.set=F,Nd.startOf=tb,Nd.subtract=Bd,Nd.toArray=yb,Nd.toObject=zb,Nd.toDate=xb,Nd.toISOString=lb,Nd.toJSON=lb,Nd.toString=kb,Nd.unix=wb,Nd.valueOf=vb,Nd.year=td,Nd.isLeapYear=ia,Nd.weekYear=Fb,Nd.isoWeekYear=Gb,Nd.quarter=Nd.quarters=Jb,Nd.month=Y,Nd.daysInMonth=Z,Nd.week=Nd.weeks=na,Nd.isoWeek=Nd.isoWeeks=oa,Nd.weeksInYear=Ib,Nd.isoWeeksInYear=Hb,Nd.date=Dd,Nd.day=Nd.days=Pb,Nd.weekday=Qb,Nd.isoWeekday=Rb,Nd.dayOfYear=qa,Nd.hour=Nd.hours=Id,Nd.minute=Nd.minutes=Jd,Nd.second=Nd.seconds=Kd,
+Nd.millisecond=Nd.milliseconds=Md,Nd.utcOffset=Na,Nd.utc=Pa,Nd.local=Qa,Nd.parseZone=Ra,Nd.hasAlignedHourOffset=Sa,Nd.isDST=Ta,Nd.isDSTShifted=Ua,Nd.isLocal=Va,Nd.isUtcOffset=Wa,Nd.isUtc=Xa,Nd.isUTC=Xa,Nd.zoneAbbr=Xb,Nd.zoneName=Yb,Nd.dates=aa("dates accessor is deprecated. Use date instead.",Dd),Nd.months=aa("months accessor is deprecated. Use month instead",Y),Nd.years=aa("years accessor is deprecated. Use year instead",td),Nd.zone=aa("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Oa);var Od=Nd,Pd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Qd={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Rd="Invalid date",Sd="%d",Td=/\d{1,2}/,Ud={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Vd=s.prototype;Vd._calendar=Pd,Vd.calendar=_b,Vd._longDateFormat=Qd,Vd.longDateFormat=ac,Vd._invalidDate=Rd,Vd.invalidDate=bc,Vd._ordinal=Sd,Vd.ordinal=cc,Vd._ordinalParse=Td,Vd.preparse=dc,Vd.postformat=dc,Vd._relativeTime=Ud,Vd.relativeTime=ec,Vd.pastFuture=fc,Vd.set=gc,Vd.months=U,Vd._months=md,Vd.monthsShort=V,Vd._monthsShort=nd,Vd.monthsParse=W,Vd.week=ka,Vd._week=ud,Vd.firstDayOfYear=ma,Vd.firstDayOfWeek=la,Vd.weekdays=Lb,Vd._weekdays=Ed,Vd.weekdaysMin=Nb,Vd._weekdaysMin=Gd,Vd.weekdaysShort=Mb,Vd._weekdaysShort=Fd,Vd.weekdaysParse=Ob,Vd.isPM=Ub,Vd._meridiemParse=Hd,Vd.meridiem=Vb,w("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===q(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=aa("moment.lang is deprecated. Use moment.locale instead.",w),a.langData=aa("moment.langData is deprecated. Use moment.localeData instead.",y);var Wd=Math.abs,Xd=yc("ms"),Yd=yc("s"),Zd=yc("m"),$d=yc("h"),_d=yc("d"),ae=yc("w"),be=yc("M"),ce=yc("y"),de=Ac("milliseconds"),ee=Ac("seconds"),fe=Ac("minutes"),ge=Ac("hours"),he=Ac("days"),ie=Ac("months"),je=Ac("years"),ke=Math.round,le={s:45,m:45,h:22,d:26,M:11},me=Math.abs,ne=Ha.prototype;ne.abs=oc,ne.add=qc,ne.subtract=rc,ne.as=wc,ne.asMilliseconds=Xd,ne.asSeconds=Yd,ne.asMinutes=Zd,ne.asHours=$d,ne.asDays=_d,ne.asWeeks=ae,ne.asMonths=be,ne.asYears=ce,ne.valueOf=xc,ne._bubble=tc,ne.get=zc,ne.milliseconds=de,ne.seconds=ee,ne.minutes=fe,ne.hours=ge,ne.days=he,ne.weeks=Bc,ne.months=ie,ne.years=je,ne.humanize=Fc,ne.toISOString=Gc,ne.toString=Gc,ne.toJSON=Gc,ne.locale=rb,ne.localeData=sb,ne.toIsoString=aa("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Gc),ne.lang=Cd,H("X",0,0,"unix"),H("x",0,0,"valueOf"),N("x",_c),N("X",bd),Q("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),Q("x",function(a,b,c){c._d=new Date(q(a))}),a.version="2.10.6",b(Da),a.fn=Od,a.min=Fa,a.max=Ga,a.utc=h,a.unix=Zb,a.months=jc,a.isDate=d,a.locale=w,a.invalid=l,a.duration=Ya,a.isMoment=o,a.weekdays=lc,a.parseZone=$b,a.localeData=y,a.isDuration=Ia,a.monthsShort=kc,a.weekdaysMin=nc,a.defineLocale=x,a.weekdaysShort=mc,a.normalizeUnits=A,a.relativeTimeThreshold=Ec;var oe=a;return oe}); \ No newline at end of file
diff --git a/vendor/assets/stylesheets/.keep b/vendor/assets/stylesheets/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vendor/assets/stylesheets/.keep
diff --git a/vendor/assets/stylesheets/jquery.typeahead.min.css b/vendor/assets/stylesheets/jquery.typeahead.min.css
new file mode 100644
index 0000000..d455fc3
--- /dev/null
+++ b/vendor/assets/stylesheets/jquery.typeahead.min.css
@@ -0,0 +1 @@
+.typeahead-field,.typeahead-query{position:relative;width:100%}.typeahead-button,.typeahead-container,.typeahead-field,.typeahead-filter,.typeahead-query{position:relative}.typeahead-container button,.typeahead-field input,.typeahead-select{border:1px solid #ccc;line-height:1.42857143;padding:6px 12px;height:32px}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}.typeahead-container,.typeahead-result.detached .typeahead-list{font-family:"Open Sans",Arial,Helvetica,Sans-Serif}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}.typeahead-container *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.typeahead-query{z-index:2}.typeahead-filter button{min-width:66px}.typeahead-field{display:table;border-collapse:separate}.typeahead-button{font-size:0;white-space:nowrap;width:1%;vertical-align:middle}.typeahead-field>span{display:table-cell;vertical-align:top}.typeahead-button button{border-top-right-radius:2px;border-bottom-right-radius:2px}.typeahead-field input,.typeahead-select{display:block;width:100%;font-size:13px;color:#555;background:0 0;border-radius:2px 0 0 2px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.typeahead-field input{-webkit-appearance:none;background:0 0}.typeahead-field input:last-child,.typeahead-hint{background:#fff}.typeahead-container button{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;touch-action:manipulation;cursor:pointer;background-color:#fff;white-space:nowrap;font-size:13px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#333;box-shadow:inset 0 -2px 0 rgba(0,0,0,.05);-moz-box-shadow:inset 0 -2px 0 rgba(0,0,0,.05);-webkit-box-shadow:inset 0 -2px 0 rgba(0,0,0,.05)}.typeahead-container button:active,.typeahead-container button:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.typeahead-container button:focus,.typeahead-container button:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.typeahead-container button.active,.typeahead-container button:active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.typeahead-container button.disabled,.typeahead-container button[disabled],.typeahead-field input.disabled,.typeahead-field input[disabled]{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;background-color:#fff;border-color:#ccc}.typeahead-button button,.typeahead-filter button{margin-left:-1px;border-bottom-left-radius:0;border-top-left-radius:0}.typeahead-button,.typeahead-filter{z-index:1}.typeahead-button:active,.typeahead-button:active button:active,.typeahead-button:focus,.typeahead-button:focus button:focus,.typeahead-button:hover,.typeahead-container.filter .typeahead-filter,.typeahead-filter:active,.typeahead-filter:focus,.typeahead-filter:hover{z-index:1001}.typeahead-dropdown,.typeahead-list{position:absolute;top:100%;left:0;z-index:1000;width:100%;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:13px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:2px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.typeahead-result.detached .typeahead-list{position:relative;z-index:1041;top:auto;left:auto}.typeahead-dropdown{right:0;left:auto;z-index:1001}.typeahead-list>li:first-child{border-top:none}.typeahead-list>li{position:relative;border-top:solid 1px rgba(0,0,0,.15)}.typeahead-dropdown>li>a,.typeahead-list>li>a{display:block;padding:6px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap;text-decoration:none}.typeahead-dropdown>li.active>a,.typeahead-dropdown>li>a:focus,.typeahead-dropdown>li>a:hover,.typeahead-list>li.active>a,.typeahead-list>li>a:focus,.typeahead-list>li>a:hover{background-color:#ebebeb;color:#333}.typeahead-list.empty>li.active>a,.typeahead-list.empty>li>a:focus,.typeahead-list.empty>li>a:hover{background-color:transparent}.typeahead-list.empty>li>a{cursor:default}.typeahead-list>li.typeahead-group.active>a,.typeahead-list>li.typeahead-group>a,.typeahead-list>li.typeahead-group>a:focus,.typeahead-list>li.typeahead-group>a:hover{border-color:#9cb4c5;color:#305d8c;background-color:#d6dde7;cursor:default}.typeahead-container.backdrop+.typeahead-backdrop,.typeahead-container.filter .typeahead-dropdown,.typeahead-container.hint .typeahead-hint,.typeahead-container.result .typeahead-list{display:block!important}.typeahead-container .typeahead-dropdown,.typeahead-container .typeahead-hint,.typeahead-container .typeahead-list,.typeahead-container+.typeahead-backdrop{display:none!important}.typeahead-dropdown .divider{height:1px;margin:5px 0;overflow:hidden;background-color:#e5e5e5}.typeahead-caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.typeahead-search-icon{min-width:40px;height:18px;font-size:13px;display:block;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABH0lEQVR4nJ3SvyvFYRTH8deVkkJ3UUZJIbJ8bzJjMtyMym6w2Njs/gCDP0AGCyWjxYDF5GdJYpS6xaIUw/d8771dT7qc+vZ8vs95zvuc5zmnlGWZsG6sYBGjsXeNHWzjQ8JKARjCEUZSh3CJeTy3OjoicxF8hwX0oi/0HSZwiK4UYKUpeBoHeMdb6OnwTWI5BVgMvYZaovwa1kMvpQBjoY8TwVp84ylAO/YV62cKcBt65hfAbKwPKcBu6E2UE8Hl8MF+CrCFG/nwnKKKnviqONOYj6NWQDFIg/I+/3ikFnuUX6d+lY4mR4ZVnMvnoIYLbKCCp0h0otG5egXt2HAED+BFPmAP7bYR7jGHV/RjCjr/AICryFzB3n8ARSX3xc83qRk4q9rDNWcAAAAASUVORK5CYII=) center center no-repeat} \ No newline at end of file