diff --git a/.gitignore b/.gitignore
index 0abd85ad..eaa4a86e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,20 +1,4 @@
-*.gem
-*.rbc
-.bundle
.config
-coverage
-InstalledFiles
-lib/bundler/man
-pkg
-rdoc
-spec/reports
-test/tmp
-test/version_tmp
-tmp
-# YARD artifacts
-.yardoc
-_yardoc
-doc/
tests/coverage
config.yml
.DS_Store
@@ -30,8 +14,7 @@ files/map.txt
.sass-cache/*
files/sslsites.zip
.tm_properties
-./black_box.rb
.vagrant
public/banned_sites
public/deleted_sites
-tests/stat_logs/*
+Gemfile.lock
diff --git a/.travis.yml b/.travis.yml
index e029b7a2..07848556 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,10 @@
language: ruby
rvm:
- - "2.1.1"
+ - "2.3.0"
+ - "2.2.3"
addons:
postgresql: "9.3"
before_script:
- psql -c 'create database travis_ci_test;' -U postgres
+sudo: false
+bundler_args: --jobs=1
diff --git a/Gemfile b/Gemfile
index c92b40d4..a98cc309 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,8 +15,8 @@ gem 'mail'
gem 'google-api-client', require: 'google/api_client'
gem 'tilt'
gem 'erubis'
-gem 'stripe' #, source: 'https://code.stripe.com/'
-gem 'screencap'
+gem 'stripe', '1.15.0' #, source: 'https://code.stripe.com/'
+#gem 'screencap', '~> 0.1.4'
gem 'cocaine'
gem 'zipruby'
gem 'sass', require: nil
@@ -32,13 +32,17 @@ gem 'geoip'
gem 'io-extra', require: 'io/extra'
gem 'rye'
gem 'dnsruby'
+gem 'base32'
+gem 'coveralls', require: false
+gem 'sanitize'
+gem 'will_paginate'
platform :mri, :rbx do
gem 'magic' # sudo apt-get install file, For OSX: brew install libmagic
gem 'pg'
gem 'sequel_pg', require: nil
gem 'hiredis'
- gem 'rainbows', require: nil
+ gem 'posix-spawn'
group :development, :test do
gem 'pry'
@@ -77,10 +81,11 @@ group :test do
gem 'capybara_minitest_spec'
gem 'rack_session_access', require: nil
gem 'webmock', require: nil
- gem 'stripe-ruby-mock', '~> 2.0.1', require: 'stripe_mock'
+ gem 'stripe-ruby-mock', '2.0.1', require: 'stripe_mock'
gem 'timecop'
platform :mri, :rbx do
gem 'simplecov', require: nil
+ gem 'm'
end
end
diff --git a/Gemfile.lock b/Gemfile.lock
deleted file mode 100644
index 98f8ed2f..00000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,324 +0,0 @@
-GEM
- remote: https://rubygems.org/
- specs:
- activesupport (4.2.3)
- i18n (~> 0.7)
- json (~> 1.7, >= 1.7.7)
- minitest (~> 5.1)
- thread_safe (~> 0.3, >= 0.3.4)
- tzinfo (~> 1.1)
- addressable (2.3.8)
- ago (0.1.5)
- annoy (0.5.6)
- highline (>= 1.5.0)
- ansi (1.5.0)
- autoparse (0.3.3)
- addressable (>= 2.3.1)
- extlib (>= 0.9.15)
- multi_json (>= 1.0.0)
- bcrypt (3.1.10)
- blankslate (3.1.3)
- builder (3.2.2)
- byebug (4.0.5)
- columnize (= 0.9.0)
- capybara (2.4.4)
- mime-types (>= 1.16)
- nokogiri (>= 1.3.3)
- rack (>= 1.0.0)
- rack-test (>= 0.5.4)
- xpath (~> 2.0)
- capybara_minitest_spec (1.0.5)
- capybara (>= 2)
- minitest (>= 4)
- celluloid (0.16.0)
- timers (~> 4.0.0)
- climate_control (0.0.3)
- activesupport (>= 3.0)
- cliver (0.3.2)
- cocaine (0.5.7)
- climate_control (>= 0.0.3, < 1.0)
- coderay (1.1.0)
- columnize (0.9.0)
- connection_pool (2.2.0)
- crack (0.4.2)
- safe_yaml (~> 1.0.0)
- dante (0.2.0)
- dav4rack (0.3.0)
- nokogiri (>= 1.4.2)
- rack (>= 1.1.0)
- uuidtools (~> 2.1.1)
- dnsruby (1.58.0)
- docile (1.1.5)
- domain_name (0.5.24)
- unf (>= 0.0.5, < 1.0.0)
- drydock (0.6.9)
- erubis (2.7.0)
- extlib (0.9.16)
- fabrication (2.13.2)
- faker (1.4.3)
- i18n (~> 0.5)
- faraday (0.9.1)
- multipart-post (>= 1.2, < 3)
- ffi (1.9.10)
- ffi-compiler (0.1.3)
- ffi (>= 1.0.0)
- rake
- filesize (0.1.0)
- geoip (1.6.1)
- google-api-client (0.8.6)
- activesupport (>= 3.2)
- addressable (~> 2.3)
- autoparse (~> 0.3)
- extlib (~> 0.9)
- faraday (~> 0.9)
- googleauth (~> 0.3)
- launchy (~> 2.4)
- multi_json (~> 1.10)
- retriable (~> 1.4)
- signet (~> 0.6)
- googleauth (0.4.1)
- faraday (~> 0.9)
- jwt (~> 1.4)
- logging (~> 2.0)
- memoist (~> 0.12)
- multi_json (= 1.11)
- signet (~> 0.6)
- highline (1.7.2)
- hiredis (0.6.0)
- hitimes (1.2.2)
- http-cookie (1.0.2)
- domain_name (~> 0.5)
- i18n (0.7.0)
- io-extra (1.2.8)
- jimson-temp (0.9.5)
- blankslate (>= 3.1.2)
- multi_json (~> 1.0)
- rack (~> 1.4)
- rest-client (~> 1.0)
- json (1.8.3)
- jwt (1.5.1)
- kgio (2.9.3)
- launchy (2.4.3)
- addressable (~> 2.3)
- little-plugger (1.1.3)
- logging (2.0.0)
- little-plugger (~> 1.1)
- multi_json (~> 1.10)
- magic (0.2.9)
- ffi (>= 0.6.3)
- mail (2.6.3)
- mime-types (>= 1.16, < 3)
- memoist (0.12.0)
- metaclass (0.0.4)
- method_source (0.8.2)
- mime-types (2.6.1)
- mini_portile (0.6.2)
- minitest (5.7.0)
- minitest-reporters (1.0.18)
- ansi
- builder
- minitest (>= 5.0)
- ruby-progressbar
- mocha (1.1.0)
- metaclass (~> 0.0.1)
- multi_json (1.11.0)
- multipart-post (2.0.0)
- net-scp (1.2.1)
- net-ssh (>= 2.6.5)
- net-ssh (2.9.2)
- netrc (0.10.3)
- nokogiri (1.6.6.2)
- mini_portile (~> 0.6.0)
- paypal-recurring (1.1.0)
- pg (0.18.2)
- phantomjs (1.9.8.0)
- poltergeist (1.6.0)
- capybara (~> 2.1)
- cliver (~> 0.3.1)
- multi_json (~> 1.0)
- websocket-driver (>= 0.2.0)
- pry (0.10.1)
- coderay (~> 1.1.0)
- method_source (~> 0.8.1)
- slop (~> 3.4)
- pry-byebug (3.1.0)
- byebug (~> 4.0)
- pry (~> 0.10)
- puma (2.11.3)
- rack (>= 1.1, < 2.0)
- rack (1.6.4)
- rack-cache (1.2)
- rack (>= 0.4)
- rack-protection (1.5.3)
- rack
- rack-recaptcha (0.6.6)
- json
- rack-test (0.6.3)
- rack (>= 1.0)
- rack_session_access (0.1.1)
- builder (>= 2.0.0)
- rack (>= 1.0.0)
- rainbows (4.6.2)
- kgio (~> 2.5)
- rack (~> 1.1)
- unicorn (~> 4.8)
- raindrops (0.14.0)
- rake (10.4.2)
- redis (3.2.1)
- redis-namespace (1.5.2)
- redis (~> 3.0, >= 3.0.4)
- rest-client (1.8.0)
- http-cookie (>= 1.0.2, < 2.0)
- mime-types (>= 1.16, < 3.0)
- netrc (~> 0.7)
- retriable (1.4.1)
- rmagick (2.15.2)
- ruby-progressbar (1.7.5)
- rye (0.9.13)
- annoy
- docile (>= 1.0.1)
- highline (>= 1.5.1)
- net-scp (>= 1.0.2)
- net-ssh (>= 2.0.13)
- sysinfo (>= 0.8.1)
- safe_yaml (1.0.4)
- sass (3.4.16)
- screencap (0.1.2)
- phantomjs
- scrypt (2.0.2)
- ffi-compiler (>= 0.0.2)
- rake
- sequel (4.8.0)
- sequel_pg (1.6.13)
- pg (>= 0.8.0)
- sequel (>= 3.39.0)
- shotgun (0.9.1)
- rack (>= 1.0)
- sidekiq (3.4.1)
- celluloid (~> 0.16.0)
- connection_pool (>= 2.1.1)
- json
- redis (>= 3.0.6)
- redis-namespace (>= 1.3.1)
- signet (0.6.1)
- addressable (~> 2.3)
- extlib (~> 0.9)
- faraday (~> 0.9)
- jwt (~> 1.5)
- multi_json (~> 1.10)
- simplecov (0.10.0)
- docile (~> 1.1.0)
- json (~> 1.8)
- simplecov-html (~> 0.10.0)
- simplecov-html (0.10.0)
- sinatra (1.4.6)
- rack (~> 1.4)
- rack-protection (~> 1.4)
- tilt (>= 1.3, < 3)
- sinatra-flash (0.3.0)
- sinatra (>= 1.0.0)
- sinatra-xsendfile (0.4.2)
- sinatra (>= 0.9.1)
- slop (3.6.0)
- storable (0.8.9)
- stripe (1.23.0)
- json (~> 1.8.1)
- rest-client (~> 1.4)
- stripe-ruby-mock (2.0.5)
- dante (>= 0.2.0)
- jimson-temp
- stripe (>= 1.15.0)
- sysinfo (0.8.1)
- drydock
- storable
- thread (0.2.1)
- thread_safe (0.3.5)
- tilt (2.0.1)
- timecop (0.7.4)
- timers (4.0.1)
- hitimes
- tzinfo (1.2.2)
- thread_safe (~> 0.1)
- unf (0.1.4)
- unf_ext
- unf_ext (0.0.7.1)
- unicorn (4.9.0)
- kgio (~> 2.6)
- rack
- raindrops (~> 0.7)
- uuidtools (2.1.5)
- webmock (1.21.0)
- addressable (>= 2.3.6)
- crack (>= 0.3.2)
- websocket-driver (0.6.1)
- websocket-extensions (>= 0.1.0)
- websocket-extensions (0.1.2)
- xpath (2.0.0)
- nokogiri (~> 1.3)
- zipruby (0.3.6)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- addressable
- ago
- bcrypt
- capybara_minitest_spec
- cocaine
- dav4rack
- dnsruby
- erubis
- fabrication
- faker
- filesize
- geoip
- google-api-client
- hiredis
- io-extra
- jdbc-postgres
- jruby-openssl
- json
- magic
- mail
- minitest
- minitest-reporters
- mocha
- paypal-recurring
- pg
- poltergeist
- pry
- pry-byebug
- puma
- rack-cache
- rack-recaptcha
- rack-test
- rack_session_access
- rainbows
- rake
- redis
- rest-client
- rmagick
- ruby-debug
- rye
- sass
- screencap
- scrypt
- sequel (= 4.8.0)
- sequel_pg
- shotgun
- sidekiq
- simplecov
- sinatra
- sinatra-flash
- sinatra-xsendfile
- stripe
- stripe-ruby-mock (~> 2.0.1)
- thread
- tilt
- timecop
- webmock
- zipruby
-
-BUNDLED WITH
- 1.10.2
diff --git a/README.md b/README.md
index d69f7d66..e5fc7bbf 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# Neocities.org
[](https://travis-ci.org/neocities/neocities)
+[](https://coveralls.io/github/neocities/neocities?branch=master)
The web site for Neocities! It's open source. Want a feature on the site? Send a pull request!
diff --git a/Rakefile b/Rakefile
index 4ac5badd..49f89cfe 100644
--- a/Rakefile
+++ b/Rakefile
@@ -41,7 +41,7 @@ end
desc 'Update banned IPs list'
task :update_blocked_ips => [:environment] do
uri = URI.parse('http://www.stopforumspam.com/downloads/listed_ip_90.zip')
- blocked_ips_zip = Tempfile.new('blockedipszip', Dir.tmpdir, 'wb')
+ blocked_ips_zip = Tempfile.new('blockedipszip', Dir.tmpdir)
blocked_ips_zip.binmode
Net::HTTP.start(uri.host, uri.port) do |http|
@@ -216,6 +216,73 @@ task :hash_ips => [:environment] do
end
end
+desc 'prime_site_files'
+task :prime_site_files => [:environment] do
+ Site.where(is_banned: false).where(is_deleted: false).select(:id, :username).all.each do |site|
+ Dir.glob(File.join(site.files_path, '**/*')).each do |file|
+ path = file.gsub(site.base_files_path, '').sub(/^\//, '')
+
+ site_file = site.site_files_dataset[path: path]
+
+ if site_file.nil?
+ mtime = File.mtime file
+
+ site_file_opts = {
+ path: path,
+ updated_at: mtime,
+ created_at: mtime
+ }
+
+ if File.directory? file
+ site_file_opts.merge! is_directory: true
+ else
+ site_file_opts.merge!(
+ size: File.size(file),
+ sha1_hash: Digest::SHA1.file(file).hexdigest
+ )
+ end
+
+ site.add_site_file site_file_opts
+ end
+ end
+ end
+end
+
+desc 'dedupe_follows'
+task :dedupe_follows => [:environment] do
+ follows = Follow.all
+ deduped_follows = Follow.all.uniq {|f| "#{f.site_id}_#{f.actioning_site_id}"}
+
+ follows.each do |follow|
+ unless deduped_follows.include?(follow)
+ puts "deleting dedupe: #{follow.inspect}"
+ follow.delete
+ end
+ end
+end
+
+desc 'flush_empty_index_sites'
+task :flush_empty_index_sites => [:environment] do
+ sites = Site.select(:id).all
+
+ counter = 0
+
+ sites.each do |site|
+ if site.empty_index?
+ counter += 1
+ site.site_changed = false
+ site.save_changes validate: false
+ end
+ end
+
+ puts "#{counter} sites set to not changed."
+end
+
+desc 'compute_scores'
+task :compute_scores => [:environment] do
+ Site.compute_scores
+end
+
=begin
desc 'Update screenshots'
task :update_screenshots => [:environment] do
@@ -224,3 +291,33 @@ task :update_screenshots => [:environment] do
}
end
=end
+
+desc 'prime_classifier'
+task :prime_classifier => [:environment] do
+ Site.select(:id, :username).where(is_banned: false, is_deleted: false).all.each do |site|
+ next if site.site_files_dataset.where(classifier: 'spam').count > 0
+ html_files = site.site_files_dataset.where(path: /\.html$/).all
+
+ html_files.each do |html_file|
+ print "training #{site.username}/#{html_file.path}..."
+ site.train html_file.path
+ print "done.\n"
+ end
+ end
+end
+
+desc 'train_spam'
+task :train_spam => [:environment] do
+ paths = File.read('./spam.txt')
+
+ paths.split("\n").each do |path|
+ username, site_file_path = path.match(/^([a-zA-Z0-9_\-]+)\/(.+)$/i).captures
+ site = Site[username: username]
+ next if site.nil?
+ site_file = site.site_files_dataset.where(path: site_file_path).first
+ next if site_file.nil?
+ site.train site_file_path, :spam
+ site.ban!
+ puts "Deleted #{site_file_path}, banned #{site.username}"
+ end
+end
diff --git a/app/admin.rb b/app/admin.rb
index 5f2303af..80f751d8 100644
--- a/app/admin.rb
+++ b/app/admin.rb
@@ -11,6 +11,65 @@ get '/admin/reports' do
erb :'admin/reports'
end
+get '/admin/site/:username' do |username|
+ require_admin
+ @site = Site[username: username]
+ not_found if @site.nil?
+ @title = "Site Inspector - #{@site.username}"
+ erb :'admin/site'
+end
+
+post '/admin/reports' do
+
+end
+
+post '/admin/site_files/train' do
+ require_admin
+ site = Site[params[:site_id]]
+ site_file = site.site_files_dataset.where(path: params[:path]).first
+ not_found if site_file.nil?
+ site.untrain site_file.path
+ site.train site_file.path, params[:classifier]
+ 'ok'
+end
+
+get '/admin/usage' do
+ require_admin
+ today = Date.today
+ current_month = Date.new today.year, today.month, 1
+
+ @monthly_stats = []
+
+ month = current_month
+
+ until month.year == 2015 && month.month == 1 do
+ stats = DB[
+ 'select sum(views) as views, sum(hits) as hits, sum(bandwidth) as bandwidth from stats where created_at >= ? and created_at < ?',
+ month,
+ month.next_month].first
+
+ stats.keys.each do |key|
+ stats[key] ||= 0
+ end
+
+ stats.collect {|s| s == 0}.uniq
+
+ if stats[:views] != 0 && stats[:hits] != 0 && stats[:bandwidth] != 0
+ popular_sites = DB[
+ 'select sum(bandwidth) as bandwidth,username from stats left join sites on sites.id=stats.site_id where stats.created_at >= ? and stats.created_at < ? group by username order by bandwidth desc limit 50',
+ month,
+ month.next_month
+ ].all
+
+ @monthly_stats.push stats.merge(date: month).merge(popular_sites: popular_sites)
+ end
+
+ month = month.prev_month
+ end
+
+ erb :'admin/usage'
+end
+
get '/admin/email' do
require_admin
erb :'admin/email'
@@ -79,6 +138,11 @@ post '/admin/banhammer' do
site = Site[username: params[:username]]
+ if !params[:classifier].empty?
+ site.untrain 'index.html'
+ site.train 'index.html', params[:classifier]
+ end
+
if site.nil?
flash[:error] = 'User not found'
redirect '/admin'
@@ -105,6 +169,7 @@ post '/admin/mark_nsfw' do
end
site.is_nsfw = true
+ site.admin_nsfw = true
site.save_changes validate: false
flash[:success] = 'MISSION ACCOMPLISHED'
diff --git a/app/blog.rb b/app/blog.rb
index 6fa8e715..c2e4df8e 100644
--- a/app/blog.rb
+++ b/app/blog.rb
@@ -1,22 +1,7 @@
-require 'net/http'
-require 'uri'
-
get '/blog/?' do
- expires 60, :public, :must_revalidate
- return Net::HTTP.get_response(URI('http://blog.neocities.org')).body
+ redirect 'https://blog.neocities.org', 301
end
get '/blog/:article' do |article|
- expires 60, :public, :must_revalidate
-
- attempted = false
-
- begin
- return Net::HTTP.get_response(URI("http://blog.neocities.org/#{article}.html")).body
- rescue => e
- raise e if attempted
- attempted = true
- article = article.match(/^[a-zA-Z0-9-]+/).to_s
- retry
- end
+ redirect "https://blog.neocities.org/#{article}.html", 301
end
diff --git a/app/browse.rb b/app/browse.rb
index 744e67e7..3d4717ef 100644
--- a/app/browse.rb
+++ b/app/browse.rb
@@ -1,7 +1,7 @@
get '/browse/?' do
- @current_page = params[:current_page]
- @current_page = @current_page.to_i
- @current_page = 1 if @current_page == 0
+
+ @page = params[:page].to_i
+ @page = 1 if @page == 0
params.delete 'tag' if params[:tag].nil? || params[:tag].strip.empty?
@@ -11,12 +11,14 @@ get '/browse/?' do
site_dataset = browse_sites_dataset
end
- site_dataset = site_dataset.paginate @current_page, Site::BROWSE_PAGINATION_LENGTH
- @page_count = site_dataset.page_count || 1
+ site_dataset = site_dataset.paginate @page, Site::BROWSE_PAGINATION_LENGTH
+ @pagination_dataset = site_dataset
@sites = site_dataset.all
+
if params[:tag]
@title = "Sites tagged #{params[:tag]}"
end
+
erb :browse
end
@@ -28,9 +30,12 @@ def education_sites_dataset
end
def browse_sites_dataset
- site_dataset = Site.filter(is_deleted: false, is_banned: false, is_crashing: false).filter(site_changed: true)
+
+ site_dataset = Site.browse_dataset
if current_site
+ site_dataset.or! sites__id: current_site.id
+
if !current_site.blocking_site_ids.empty?
site_dataset.where!(Sequel.~(Sequel.qualify(:sites, :id) => current_site.blocking_site_ids))
end
@@ -43,6 +48,9 @@ def browse_sites_dataset
end
case params[:sort_by]
+ when 'special_sauce'
+ site_dataset.exclude! score: nil
+ site_dataset.order! :score.desc
when 'followers'
site_dataset = site_dataset.association_left_join :follows
site_dataset.select_all! :sites
@@ -89,8 +97,9 @@ def browse_sites_dataset
site_dataset.where! ['sites.is_nsfw = ?', (params[:is_nsfw] == 'true' ? true : false)]
- if params[:tag] && params[:sort_by] != 'followers'
- site_dataset = site_dataset.association_join(:tags).select_all(:sites)
+ if params[:tag]
+ site_dataset.inner_join! :sites_tags, :site_id => :id
+ site_dataset.inner_join! :tags, :id => :sites_tags__tag_id
site_dataset.where! ['tags.name = ?', params[:tag]]
site_dataset.where! ['tags.is_nsfw = ?', (params[:is_nsfw] == 'true' ? true : false)]
end
diff --git a/app/create.rb b/app/create.rb
index a9df8649..b3f0d3d8 100644
--- a/app/create.rb
+++ b/app/create.rb
@@ -1,5 +1,5 @@
def new_recaptcha_valid?
- return session[:captcha_valid] = true if ENV['RACK_ENV'] == 'test'
+ return session[:captcha_valid] = true if ENV['RACK_ENV'] == 'test' || ENV['TRAVIS']
resp = Net::HTTP.get URI(
'https://www.google.com/recaptcha/api/siteverify?'+
Rack::Utils.build_query(
@@ -54,7 +54,15 @@ end
post '/create' do
content_type :json
- require_unbanned_ip
+
+ if banned?(true)
+ signout
+ session[:banned] = true if !session[:banned]
+
+ flash[:error] = 'There was an error, please contact support to log in.'
+ redirect '/'
+ end
+
dashboard_if_signed_in
@site = Site.new(
diff --git a/app/dmca.rb b/app/dmca.rb
index ae838708..de118f0a 100644
--- a/app/dmca.rb
+++ b/app/dmca.rb
@@ -30,7 +30,7 @@ post '/dmca/contact' do
no_footer: true
})
- flash[:success] = 'Your DCMA notification has been sent.'
+ flash[:success] = 'Your DMCA notification has been sent.'
redirect '/'
end
end
diff --git a/app/index.rb b/app/index.rb
index 17e2ee85..e905414c 100644
--- a/app/index.rb
+++ b/app/index.rb
@@ -6,23 +6,23 @@ get '/?' do
@suggestions = current_site.suggestions
- @current_page = params[:current_page].to_i
- @current_page = 1 if @current_page == 0
+ @page = params[:page].to_i
+ @page = 1 if @page == 0
if params[:activity] == 'mine'
- events_dataset = current_site.latest_events(@current_page, 10)
+ events_dataset = current_site.latest_events(@page, 10)
elsif params[:event_id]
event = Event.select(:id).where(id: params[:event_id]).first
not_found if event.nil?
not_found if event.is_deleted
events_dataset = Event.where(id: params[:event_id]).paginate(1, 1)
elsif params[:activity] == 'global'
- events_dataset = Event.global_dataset @current_page
+ events_dataset = Event.global_dataset @page
else
- events_dataset = current_site.news_feed(@current_page, 10)
+ events_dataset = current_site.news_feed(@page, 10)
end
- @page_count = events_dataset.page_count || 1
+ @pagination_dataset = events_dataset
@events = events_dataset.all
current_site.events_dataset.update notification_seen: true
@@ -50,10 +50,6 @@ get '/education' do
erb :education, layout: :index_layout
end
-get '/tutorials' do
- erb :'tutorials'
-end
-
get '/donate' do
erb :'donate'
end
@@ -82,3 +78,7 @@ end
get '/permanent-web' do
erb :'permanent_web'
end
+
+get '/thankyou' do
+ erb :'thankyou'
+end
diff --git a/app/mockup.rb b/app/mockup.rb
index 3017a565..5aab40b2 100644
--- a/app/mockup.rb
+++ b/app/mockup.rb
@@ -29,4 +29,9 @@ get '/stats_mockup' do
require_login
erb :'stats_mockup', locals: {site: current_site}
end
+
+get '/tutorial_mockup_c1p2' do
+ require_login
+ erb :'tutorial_mockup_c1p2', locals: {site: current_site}
+end
# :nocov:
\ No newline at end of file
diff --git a/app/search.rb b/app/search.rb
deleted file mode 100644
index 8e76e5ad..00000000
--- a/app/search.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-
-get '/search' do
- erb :'search'
-end
diff --git a/app/settings.rb b/app/settings.rb
index fb35e541..8b18ae3b 100644
--- a/app/settings.rb
+++ b/app/settings.rb
@@ -185,7 +185,7 @@ post '/settings/:username/change_name' do
end
old_host = @site.host
- old_file_paths = @site.file_list.collect {|f| f[:path]}
+ old_site_file_paths = @site.site_files.collect {|site_file| site_file.path}
@site.username = params[:name]
@@ -195,11 +195,11 @@ post '/settings/:username/change_name' do
@site.move_files_from old_username
}
- old_file_paths.each do |file_path|
- @site.purge_cache file_path
+ old_site_file_paths.each do |site_file_path|
+ @site.delete_cache site_file_path
end
- flash[:success] = "Site/user name has been changed. You will need to use this name to login, don't forget it ."
+ flash[:success] = "Site/user name has been changed. You will need to use this name to login, don't forget it! "
redirect "/settings/#{@site.username}#username"
else
flash[:error] = @site.errors.first.last.first
@@ -211,6 +211,8 @@ post '/settings/:username/change_nsfw' do
require_login
require_ownership_for_settings
+ redirect "/settings/#{@site.username}" if @site.admin_nsfw == true
+
@site.is_nsfw = params[:is_nsfw]
@site.save_changes validate: false
flash[:success] = @site.is_nsfw ? 'Marked 18+' : 'Unmarked 18+'
@@ -260,7 +262,7 @@ end
post '/settings/change_email' do
require_login
-
+
if params[:email] == parent_site.email
flash[:error] = 'You are already using this email address for this account.'
redirect '/settings#email'
@@ -331,4 +333,30 @@ get '/settings/unsubscribe_email/?' do
@message = 'There was an error unsubscribing your email address. Please contact support.'
end
erb :'settings/account/unsubscribe'
-end
\ No newline at end of file
+end
+
+post '/settings/update_card' do
+ require_login
+
+ customer = Stripe::Customer.retrieve current_site.stripe_customer_id
+
+ old_card_ids = customer.sources.collect {|s| s.id}
+
+ begin
+ customer.sources.create source: params[:stripe_token]
+ rescue Stripe::InvalidRequestError => e
+ if e.message.match /cannot use a.+token more than once/
+ flash[:error] = 'Card is already being used.'
+ redirect '/settings#billing'
+ else
+ raise e
+ end
+ end
+
+ old_card_ids.each do |card_id|
+ customer.sources.retrieve(card_id).delete
+ end
+
+ flash[:success] = 'Card information updated.'
+ redirect '/settings#billing'
+end
diff --git a/app/site.rb b/app/site.rb
index d716ec56..eceaffe5 100644
--- a/app/site.rb
+++ b/app/site.rb
@@ -13,9 +13,9 @@ get '/site/:username/?' do |username|
@title = site.title
- @current_page = params[:current_page]
- @current_page = @current_page.to_i
- @current_page = 1 if @current_page == 0
+ @page = params[:page]
+ @page = @page.to_i
+ @page = 1 if @page == 0
if params[:event_id]
not_found unless params[:event_id].is_integer?
@@ -23,10 +23,11 @@ get '/site/:username/?' do |username|
not_found if event.nil?
events_dataset = Event.where(id: params[:event_id]).paginate(1, 1)
else
- events_dataset = site.latest_events(@current_page, 10)
+ events_dataset = site.latest_events(@page, 10)
end
@page_count = events_dataset.page_count || 1
+ @pagination_dataset = events_dataset
@latest_events = events_dataset.all
erb :'site', locals: {site: site, is_current_site: site == current_site}
@@ -161,7 +162,6 @@ post '/site/create_directory' do
require_login
path = "#{params[:dir] || ''}/#{params[:name]}"
-
result = current_site.create_directory path
if result != true
diff --git a/app/site_files.rb b/app/site_files.rb
index aa7107dc..8fd9789e 100644
--- a/app/site_files.rb
+++ b/app/site_files.rb
@@ -207,6 +207,10 @@ get '/site_files/allowed_types' do
erb :'site_files/allowed_types'
end
+get '/site_files/hotlinking' do
+ erb :'site_files/hotlinking'
+end
+
get '/site_files/mount_info' do
erb :'site_files/mount_info'
end
diff --git a/app/surf.rb b/app/surf.rb
index 95d819db..a96b8995 100644
--- a/app/surf.rb
+++ b/app/surf.rb
@@ -1,8 +1,8 @@
get '/surf/?' do
- @current_page = params[:current_page].to_i || 1
+ @page = params[:page].to_i || 1
params.delete 'tag' if params[:tag].nil? || params[:tag].strip.empty?
site_dataset = browse_sites_dataset
- site_dataset = site_dataset.paginate @current_page, 1
+ site_dataset = site_dataset.paginate @page, 1
@page_count = site_dataset.page_count || 1
@site = site_dataset.first
redirect "/browse?#{Rack::Utils.build_query params}" if @site.nil?
diff --git a/app/tutorial.rb b/app/tutorial.rb
new file mode 100644
index 00000000..cdba092f
--- /dev/null
+++ b/app/tutorial.rb
@@ -0,0 +1,45 @@
+def default_tutorial_html
+ <<-EOT.strip
+
+
+
+
+
+ My web site
+
+
+
+
+ Hello World!
+
+
+
+EOT
+end
+
+get '/tutorials' do
+ erb :'tutorials'
+end
+
+get '/tutorial/?' do
+ require_login
+ erb :'tutorial/index'
+end
+
+get '/tutorial/:section/?' do
+ require_login
+ redirect "/tutorial/#{params[:section]}/1"
+end
+
+get '/tutorial/:section/:page/?' do
+ require_login
+ @page = params[:page]
+ not_found if @page.to_i == 0
+ not_found unless %w{html css js}.include?(params[:section])
+
+ @section = params[:section]
+
+ @title = "#{params[:section].upcase} Tutorial - #{@page}/10"
+
+ erb "tutorial/layout".to_sym
+end
diff --git a/app_helpers.rb b/app_helpers.rb
index 27a0e116..5590c189 100644
--- a/app_helpers.rb
+++ b/app_helpers.rb
@@ -1,20 +1,10 @@
-def kickstarter_days_remaining
- ending = Time.parse('Sat, Jul 25 2015 3:05 PM PDT')
- today = Time.now
-
- remaining = ending - today
- return 0 if remaining < 0
-
- ((ending - today) / 86400).to_i
-end
-
def dashboard_if_signed_in
redirect '/dashboard' if signed_in?
end
def require_login_ajax
halt 'You are not logged in!' unless signed_in?
- halt 'You are banned.' if current_site.is_banned? || parent_site.is_banned?
+ halt 'Please contact support.' if banned?
end
def csrf_safe?
@@ -31,11 +21,7 @@ end
def require_login
redirect '/' unless signed_in?
- if session[:banned] || current_site.is_banned || parent_site.is_banned
- signout
- session[:banned] = true
- redirect '/'
- end
+ enforce_ban if banned?
end
def signed_in?
@@ -52,15 +38,18 @@ def parent_site
current_site.parent? ? current_site : current_site.parent
end
-def require_unbanned_ip
- if session[:banned] || (is_banned_ip = Site.banned_ip?(request.ip))
- signout
- session[:banned] = request.ip if !session[:banned]
+def banned?(ip_check=false)
+ return true if session[:banned]
+ return true if current_site && (current_site.is_banned || parent_site.is_banned)
- flash[:error] = 'Site creation has been banned due to a Terms of Service violation from your location. '+
- 'If you believe this to be in error, contact the site admin .'
- return {result: 'error'}.to_json
- end
+ return true if ip_check && Site.banned_ip?(request.ip)
+ false
+end
+
+def enforce_ban
+ signout
+ session[:banned] = true
+ redirect '/'
end
def title
diff --git a/config.ru b/config.ru
index f664a028..16e3721c 100644
--- a/config.ru
+++ b/config.ru
@@ -1,11 +1,6 @@
require 'rubygems'
require './app.rb'
require 'sidekiq/web'
-require 'unicorn/preread_input'
-
-if defined?(Unicorn)
- use Unicorn::PrereadInput
-end
map('/') do
use(Rack::Cache,
@@ -35,13 +30,18 @@ map '/webdav' do
end
if Site.valid_file_type?(filename: path, tempfile: tmpfile)
- site.store_file path, tmpfile
+ site.store_files [{filename: path, tempfile: tmpfile}]
return [201, {}, ['']]
else
return [415, {}, ['']]
end
end
+ if env['REQUEST_METHOD'] == 'MKCOL'
+ site.create_directory env['PATH_INFO']
+ return [201, {}, ['']]
+ end
+
if env['REQUEST_METHOD'] == 'MOVE'
tmpfile = Tempfile.new 'moved_file'
tmpfile.close
@@ -51,7 +51,7 @@ map '/webdav' do
FileUtils.cp site.files_path(env['PATH_INFO']), tmpfile.path
DB.transaction do
- site.store_file destination, tmpfile
+ site.store_files [{filename: destination, tempfile: tmpfile}]
site.delete_file env['PATH_INFO']
end
diff --git a/environment.rb b/environment.rb
index a5eb50a1..d8a6cb9d 100644
--- a/environment.rb
+++ b/environment.rb
@@ -11,6 +11,8 @@ require 'logger'
Bundler.require
Bundler.require :development if ENV['RACK_ENV'] == 'development'
+require 'tilt/erubis'
+
Dir['./ext/**/*.rb'].each {|f| require f}
# :nocov:
@@ -31,6 +33,8 @@ raise 'hash_ip_salt is required' unless $config['ip_hash_salt']
DB = Sequel.connect $config['database'], sslmode: 'disable', max_connections: $config['database_pool']
DB.extension :pagination
+require 'will_paginate/sequel'
+
# :nocov:
=begin
if defined?(Pry)
@@ -61,6 +65,7 @@ end
# :nocov:
if ENV['RACK_ENV'] == 'development'
# Run async jobs immediately in development.
+=begin
module Sidekiq
module Worker
module ClassMethods
@@ -72,6 +77,7 @@ if ENV['RACK_ENV'] == 'development'
end
end
end
+=end
end
# :nocov:
diff --git a/ext/base58.rb b/ext/base58.rb
new file mode 100644
index 00000000..048f7cb8
--- /dev/null
+++ b/ext/base58.rb
@@ -0,0 +1,41 @@
+module Base58
+ class << self
+ def int_to_base58(int_val, leading_zero_bytes=0)
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
+ base58_val, base = '', alpha.size
+ while int_val > 0
+ int_val, remainder = int_val.divmod(base)
+ base58_val = alpha[remainder] + base58_val
+ end
+ base58_val
+ end
+
+ def base58_to_int(base58_val)
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
+ int_val, base = 0, alpha.size
+ base58_val.reverse.each_char.with_index do |char,index|
+ raise ArgumentError, 'Value not a valid Base58 String.' unless char_index = alpha.index(char)
+ int_val += char_index*(base**index)
+ end
+ int_val
+ end
+
+ def base58_to_bytestring(base58_val)
+ [Base58.decode_base58(base58_val)].pack('H*')
+ end
+
+ def encode_base58(hex)
+ leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2
+ ("1"*leading_zero_bytes) + int_to_base58( hex.to_i(16) )
+ end
+
+ def decode_base58(base58_val)
+ s = base58_to_int(base58_val).to_s(16); s = (s.bytesize.odd? ? '0'+s : s)
+ s = '' if s == '00'
+ leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 : '').size
+ s = ("00"*leading_zero_bytes) + s if leading_zero_bytes > 0
+ s
+ end
+ alias_method :base58_to_hex, :decode_base58
+ end
+end
diff --git a/files/phantomjs_screenshot.js b/files/phantomjs_screenshot.js
new file mode 100644
index 00000000..0ac8e24b
--- /dev/null
+++ b/files/phantomjs_screenshot.js
@@ -0,0 +1,56 @@
+var page = require('webpage').create()
+var system = require('system')
+
+var maxTimeout = 15000
+
+if (system.args.length === 1) {
+ console.log('required args: ');
+ phantom.exit(1)
+}
+
+var address = system.args[1]
+var outputPath = system.args[2]
+
+page.viewportSize = { width: 1280, height: 960 }
+page.clipRect = { top: 0, left: 0, width: 1280, height: 960}
+
+/*
+In development, not working yet.
+
+page.settings.scriptTimeout = 1000
+
+page.onLongRunningScript = function() {
+ page.stopJavaScript()
+ phantom.exit(4)
+}
+*/
+
+var t = Date.now()
+
+console.log('Loading ' + address)
+
+setTimeout(function() {
+ console.log('timeout')
+ phantom.exit(62)
+}, maxTimeout)
+
+page.settings.resourceTimeout = maxTimeout
+
+page.onResourceTimeout = function(e) {
+ console.log(e.errorCode)
+ console.log(e.errorString)
+ console.log(e.url)
+ phantom.exit(3)
+}
+
+page.open(address, function(status) {
+ if(status !== 'success') {
+ console.log('failed')
+ phantom.exit(2)
+ }
+
+ page.render(outputPath)
+ console.log('Loading time ' + (Date.now() - t) + ' msec');
+ phantom.exit()
+})
+
diff --git a/migrations/070_add_admin_nsfw.rb b/migrations/070_add_admin_nsfw.rb
new file mode 100644
index 00000000..e03921d0
--- /dev/null
+++ b/migrations/070_add_admin_nsfw.rb
@@ -0,0 +1,9 @@
+Sequel.migration do
+ up {
+ DB.add_column :sites, :admin_nsfw, :boolean
+ }
+
+ down {
+ DB.drop_column :sites, :admin_nsfw
+ }
+end
diff --git a/migrations/071_banned_referrers.rb b/migrations/071_banned_referrers.rb
new file mode 100644
index 00000000..c23d728a
--- /dev/null
+++ b/migrations/071_banned_referrers.rb
@@ -0,0 +1,12 @@
+Sequel.migration do
+ up {
+ DB.create_table! :banned_referrers do
+ primary_key :id
+ String :name
+ end
+ }
+
+ down {
+ DB.drop_table :banned_referrers
+ }
+end
diff --git a/migrations/072_banned_commenting.rb b/migrations/072_banned_commenting.rb
new file mode 100644
index 00000000..88176fd2
--- /dev/null
+++ b/migrations/072_banned_commenting.rb
@@ -0,0 +1,9 @@
+Sequel.migration do
+ up {
+ DB.add_column :sites, :commenting_banned, :boolean, default: false
+ }
+
+ down {
+ DB.drop_column :sites, :commenting_banned
+ }
+end
diff --git a/migrations/073_add_follow_uniqueness.rb b/migrations/073_add_follow_uniqueness.rb
new file mode 100644
index 00000000..4e80ff28
--- /dev/null
+++ b/migrations/073_add_follow_uniqueness.rb
@@ -0,0 +1,9 @@
+Sequel.migration do
+ up {
+ DB['alter table follows add constraint one_follow_per_site unique (site_id, actioning_site_id)'].first
+ }
+
+ down {
+ DB['alter table follows drop constraint one_follow_per_site'].first
+ }
+end
diff --git a/migrations/074_add_custom_max_space.rb b/migrations/074_add_custom_max_space.rb
new file mode 100644
index 00000000..1bc09b18
--- /dev/null
+++ b/migrations/074_add_custom_max_space.rb
@@ -0,0 +1,9 @@
+Sequel.migration do
+ up {
+ DB.add_column :sites, :custom_max_space, :bigint, default: 0
+ }
+
+ down {
+ DB.drop_column :sites, :custom_max_space
+ }
+end
diff --git a/migrations/075_special_sauce.rb b/migrations/075_special_sauce.rb
new file mode 100644
index 00000000..394f2ded
--- /dev/null
+++ b/migrations/075_special_sauce.rb
@@ -0,0 +1,11 @@
+# IT'S MADE OUT OF FUCKING PEOPLE
+
+Sequel.migration do
+ up {
+ DB.add_column :sites, :score, :integer
+ }
+
+ down {
+ DB.drop_column :sites, :score
+ }
+end
diff --git a/migrations/076_decimal_sauce.rb b/migrations/076_decimal_sauce.rb
new file mode 100644
index 00000000..dcef090c
--- /dev/null
+++ b/migrations/076_decimal_sauce.rb
@@ -0,0 +1,13 @@
+# IT'S MADE OUT OF FUCKING DECIMAL PEOPLE
+
+Sequel.migration do
+ up {
+ DB.drop_column :sites, :score
+ DB.add_column :sites, :score, :decimal, default: 0
+ }
+
+ down {
+ DB.drop_column :sites, :score
+ DB.add_column :sites, :score, :integer
+ }
+end
diff --git a/migrations/077_decimal_sauce_index.rb b/migrations/077_decimal_sauce_index.rb
new file mode 100644
index 00000000..fa242b45
--- /dev/null
+++ b/migrations/077_decimal_sauce_index.rb
@@ -0,0 +1,9 @@
+Sequel.migration do
+ up {
+ DB.add_index :sites, :score
+ }
+
+ down {
+ DB.drop_index :sites, :score
+ }
+end
diff --git a/migrations/078_total_stat.rb b/migrations/078_total_stat.rb
new file mode 100644
index 00000000..6698e2a9
--- /dev/null
+++ b/migrations/078_total_stat.rb
@@ -0,0 +1,17 @@
+Sequel.migration do
+ up {
+ DB.create_table! :daily_site_stats do
+ primary_key :id
+ Date :created_at, index: true
+ Integer :hits, default: 0
+ Integer :views, default: 0
+ Integer :comments, default: 0
+ Integer :follows, default: 0
+ Integer :site_updates, default: 0
+ end
+ }
+
+ down {
+ DB.drop_table :daily_site_stats
+ }
+end
diff --git a/migrations/079_add_total_stat_bandwidth.rb b/migrations/079_add_total_stat_bandwidth.rb
new file mode 100644
index 00000000..a3d30feb
--- /dev/null
+++ b/migrations/079_add_total_stat_bandwidth.rb
@@ -0,0 +1,9 @@
+Sequel.migration do
+ up {
+ DB.add_column :daily_site_stats, :bandwidth, :integer
+ }
+
+ down {
+ DB.drop_column :daily_site_stats, :bandwidth
+ }
+end
diff --git a/migrations/080_fix_total_stat_bandwidth.rb b/migrations/080_fix_total_stat_bandwidth.rb
new file mode 100644
index 00000000..3c87e95a
--- /dev/null
+++ b/migrations/080_fix_total_stat_bandwidth.rb
@@ -0,0 +1,11 @@
+Sequel.migration do
+ up {
+ DB.drop_column :daily_site_stats, :bandwidth
+ DB.add_column :daily_site_stats, :bandwidth, :integer, default: 0
+ }
+
+ down {
+ DB.drop_column :daily_site_stats, :bandwidth
+ DB.add_column :daily_site_stats, :bandwidth, :integer
+ }
+end
diff --git a/migrations/081_stats_bigint.rb b/migrations/081_stats_bigint.rb
new file mode 100644
index 00000000..f8f0081b
--- /dev/null
+++ b/migrations/081_stats_bigint.rb
@@ -0,0 +1,15 @@
+Sequel.migration do
+ up {
+ alter_table(:stats) do
+ set_column_type :hits, Bignum
+ set_column_type :views, Bignum
+ end
+ }
+
+ down {
+ alter_table(:stats) do
+ set_column_type :hits, Integer
+ set_column_type :views, Integer
+ end
+ }
+end
diff --git a/migrations/082_daily_stats_bigint.rb b/migrations/082_daily_stats_bigint.rb
new file mode 100644
index 00000000..5cefebed
--- /dev/null
+++ b/migrations/082_daily_stats_bigint.rb
@@ -0,0 +1,19 @@
+Sequel.migration do
+ up {
+ alter_table(:daily_site_stats) do
+ set_column_type :hits, Bignum
+ set_column_type :views, Bignum
+ set_column_type :bandwidth, Bignum
+ set_column_type :site_updates, Bignum
+ end
+ }
+
+ down {
+ alter_table(:daily_site_stats) do
+ set_column_type :hits, Integer
+ set_column_type :views, Integer
+ set_column_type :bandwidth, Integer
+ set_column_type :site_updates, Integer
+ end
+ }
+end
diff --git a/migrations/083_add_classifiers.rb b/migrations/083_add_classifiers.rb
new file mode 100644
index 00000000..9292780b
--- /dev/null
+++ b/migrations/083_add_classifiers.rb
@@ -0,0 +1,9 @@
+Sequel.migration do
+ up {
+ DB.add_column :site_files, :classifier, :text, default: nil, index: true
+ }
+
+ down {
+ DB.drop_column :site_files, :classifier
+ }
+end
diff --git a/models/archive.rb b/models/archive.rb
index 53731056..93b30b03 100644
--- a/models/archive.rb
+++ b/models/archive.rb
@@ -1,9 +1,19 @@
+require 'base32'
+
class Archive < Sequel::Model
many_to_one :site
set_primary_key [:site_id, :ipfs_hash]
unrestrict_primary_key
+ def self.base58_to_hshca(base58)
+ Base32.encode(Base58.base58_to_bytestring(base58)).gsub('=', '').downcase
+ end
+
+ def hshca_hash
+ self.class.base58_to_hshca ipfs_hash
+ end
+
def url
- "https://#{ipfs_hash}.ipfs.neocities.org"
+ "http://#{hshca_hash}.ipfs.neocitiesops.net"
end
end
diff --git a/models/daily_site_stat.rb b/models/daily_site_stat.rb
new file mode 100644
index 00000000..cdcc3622
--- /dev/null
+++ b/models/daily_site_stat.rb
@@ -0,0 +1,2 @@
+class DailySiteStat < Sequel::Model
+end
diff --git a/models/site.rb b/models/site.rb
index 3da82121..54920fa3 100644
--- a/models/site.rb
+++ b/models/site.rb
@@ -33,11 +33,11 @@ class Site < Sequel::Model
}
VALID_EXTENSIONS = %w{
- html htm txt text css js jpg jpeg png gif svg md markdown eot ttf woff woff2 json geojson csv tsv mf ico pdf asc key pgp xml mid midi manifest otf webapp
+ html htm txt text css js jpg jpeg png gif svg md markdown eot ttf woff woff2 json geojson csv tsv mf ico pdf asc key pgp xml mid midi manifest otf webapp less sass
}
VALID_EDITABLE_EXTENSIONS = %w{
- html htm txt js css md manifest
+ html htm txt js css md manifest less
}
MINIMUM_PASSWORD_LENGTH = 5
@@ -74,6 +74,8 @@ class Site < Sequel::Model
/PHP\.Hide/
]
+ EMPTY_FILE_HASH = Digest::SHA1.hexdigest ''
+
PHISHING_FORM_REGEX = /www.formbuddy.com\/cgi-bin\/form.pl/i
SPAM_MATCH_REGEX = ENV['RACK_ENV'] == 'test' ? /pillz/ : /#{$config['spam_smart_filter'].join('|')}/i
EMAIL_SANITY_REGEX = /.+@.+\..+/i
@@ -103,7 +105,7 @@ class Site < Sequel::Model
custom_ssl_certificates: true,
no_file_restrictions: true,
custom_domains: true,
- maximum_site_files: 25000
+ maximum_site_files: 50000
}
PLAN_FEATURES[:free] = PLAN_FEATURES[:supporter].merge(
@@ -115,7 +117,7 @@ class Site < Sequel::Model
custom_ssl_certificates: false,
no_file_restrictions: false,
custom_domains: false,
- maximum_site_files: 1000
+ maximum_site_files: 2000
)
def self.newsletter_sites
@@ -294,6 +296,7 @@ class Site < Sequel::Model
end
def banned_ip?(ip)
+ return false if ENV['RACK_ENV'] == 'production' && ip == '127.0.0.1'
return true if Site.where(is_banned: true).
where(ip: hash_ip(ip)).
where(['updated_at > ?', Time.now-BANNED_TIME]).
@@ -318,7 +321,7 @@ class Site < Sequel::Model
end
def is_following?(site)
- followings_dataset.select(:id).filter(site_id: site.id).first ? true : false
+ followings_dataset.select(:follows__id).filter(site_id: site.id).first ? true : false
end
def toggle_follow(site)
@@ -417,7 +420,7 @@ class Site < Sequel::Model
end
def get_file(path)
- File.read files_path(path)
+ File.read current_files_path(path)
end
def before_destroy
@@ -456,8 +459,8 @@ class Site < Sequel::Model
FileUtils.mv files_path, File.join(BANNED_SITES_ROOT, username)
}
- file_list.each do |path|
- purge_cache path
+ site_files.each do |site_file|
+ delete_cache site_file.path
end
end
@@ -467,6 +470,16 @@ class Site < Sequel::Model
}
end
+ # Who this site follows
+ def followings_dataset
+ super.select_all(:follows).inner_join(:sites, :id=>:site_id).exclude(:sites__is_deleted => true).exclude(:sites__is_banned => true)
+ end
+
+ # Who this site is following
+ def follows_dataset
+ super.select_all(:follows).inner_join(:sites, :id=>:actioning_site_id).exclude(:sites__is_deleted => true).exclude(:sites__is_banned => true)
+ end
+
=begin
def follows_dataset
super.where(Sequel.~(site_id: blocking_site_ids))
@@ -485,6 +498,7 @@ class Site < Sequel::Model
=end
def commenting_allowed?
+ return false if owner.commenting_banned == true
return true if owner.commenting_allowed
if owner.supporter?
@@ -579,12 +593,32 @@ class Site < Sequel::Model
# We gotta flush the dirname too if it's an index file.
if relative_path != '' && relative_path.match(/\/$|index\.html?$/i)
PurgeCacheOrderWorker.perform_async username, relative_path
- PurgeCacheOrderWorker.perform_async username, Pathname(relative_path).dirname.to_s
+
+ purge_file_path = Pathname(relative_path).dirname.to_s
+
+ PurgeCacheOrderWorker.perform_async username, '/?surf=1' if purge_file_path == '/'
+ PurgeCacheOrderWorker.perform_async username, purge_file_path
else
PurgeCacheOrderWorker.perform_async username, relative_path
end
end
+ # TODO DRY this up
+
+ def delete_cache(path)
+ relative_path = path.gsub base_files_path, ''
+
+ DeleteCacheOrderWorker.perform_async username, relative_path
+
+ # We gotta flush the dirname too if it's an index file.
+ if relative_path != '' && relative_path.match(/\/$|index\.html?$/i)
+ purge_file_path = Pathname(relative_path).dirname.to_s
+
+ DeleteCacheOrderWorker.perform_async username, '/?surf=1' if purge_file_path == '/'
+ DeleteCacheOrderWorker.perform_async username, purge_file_path
+ end
+ end
+
Rye::Cmd.add_command :ipfs, nil, 'add', :r
def add_to_ipfs
@@ -637,6 +671,32 @@ class Site < Sequel::Model
return 'Directory (or file) already exists.'
end
+ path_dirs = path.to_s.split('/').select {|p| ![nil, '.', ''].include?(p) }
+
+ path_site_file = ''
+
+ until path_dirs.empty?
+ if path_site_file == ''
+ path_site_file += path_dirs.shift
+ else
+ path_site_file += '/' + path_dirs.shift
+ end
+
+ raise ArgumentError, 'directory name cannot be empty' if path_site_file == ''
+
+ site_file = SiteFile.where(site_id: self.id, path: path_site_file).first
+
+ if site_file.nil?
+ SiteFile.create(
+ site_id: self.id,
+ path: path_site_file,
+ is_directory: true,
+ created_at: Time.now,
+ updated_at: Time.now
+ )
+ end
+ end
+
FileUtils.mkdir_p relative_path
true
end
@@ -870,6 +930,12 @@ class Site < Sequel::Model
File.join TEMPLATE_ROOT, name
end
+ def current_base_files_path(name=username)
+ raise 'username missing' if name.nil? || name.empty?
+ return File.join BANNED_SITES_ROOT, name if is_banned
+ base_files_path name
+ end
+
def base_files_path(name=username)
raise 'username missing' if name.nil? || name.empty?
File.join SITE_FILES_ROOT, name
@@ -880,7 +946,7 @@ class Site < Sequel::Model
path ||= ''
clean = []
- parts = path.split '/'
+ parts = path.to_s.split '/'
parts.each do |part|
next if part.empty? || part == '.'
@@ -890,6 +956,10 @@ class Site < Sequel::Model
clean.join '/'
end
+ def current_files_path(path='')
+ File.join current_base_files_path, scrubbed_path(path)
+ end
+
def files_path(path='')
File.join base_files_path, scrubbed_path(path)
end
@@ -904,9 +974,17 @@ class Site < Sequel::Model
is_root_index: file_path == "#{base_files_path}/index.html"
}
+ site_file = site_files_dataset.where(path: file_path.gsub(base_files_path, '').sub(/^\//, '')).first
+
+ if site_file
+ file[:size] = site_file.size unless file[:is_directory]
+ file[:updated_at] = site_file.updated_at
+ end
+
file[:is_html] = !(file[:ext].match HTML_REGEX).nil?
file[:is_image] = !(file[:ext].match IMAGE_REGEX).nil?
file[:is_editable] = !(file[:ext].match EDITABLE_FILE_EXT).nil?
+
file
end
@@ -920,8 +998,16 @@ class Site < Sequel::Model
end
def actual_space_used
- space = Dir.glob(File.join(files_path, '*')).collect {|p| File.size(p)}.inject {|sum,x| sum += x}
- space.nil? ? 0 : space
+ space = 0
+
+ files = Dir.glob File.join(files_path, '**', '*')
+
+ files.each do |file|
+ next if File.directory? file
+ space += File.size file
+ end
+
+ space
end
def total_space_used
@@ -936,7 +1022,11 @@ class Site < Sequel::Model
end
def maximum_space
- PLAN_FEATURES[(parent? ? self : parent).plan_type.to_sym][:space]
+ plan_space = PLAN_FEATURES[(parent? ? self : parent).plan_type.to_sym][:space]
+
+ return custom_max_space if custom_max_space > plan_space
+
+ plan_space
end
def space_percentage_used
@@ -956,6 +1046,10 @@ class Site < Sequel::Model
PLAN_FEATURES[plan_type.to_sym][:name]
end
+ def stripe_paying_supporter?
+ stripe_customer_id && !plan_ended && values[:plan_type].match(/free|special/).nil?
+ end
+
def unconverted_legacy_supporter?
stripe_customer_id && !plan_ended && values[:plan_type].nil? && stripe_subscription_id.nil?
end
@@ -1028,13 +1122,70 @@ class Site < Sequel::Model
end
end
+ def self.compute_scores
+ select(:id, :username, :created_at, :updated_at, :views, :featured_at, :changed_count, :api_calls).exclude(is_banned: true).exclude(is_crashing: true).exclude(is_nsfw: true).exclude(updated_at: nil).where(site_changed: true).all.each do |s|
+ s.score = s.compute_score
+ s.save_changes validate: false
+ end
+ end
+
+ SCORE_GRAVITY = 1.8
+
+ def compute_score
+ points = 0
+ points += follows_dataset.count * 30
+ points += profile_comments_dataset.count * 1
+ points += views / 1000
+ points += 20 if !featured_at.nil?
+
+ # penalties
+ points = 0 if changed_count < 2
+ points = 0 if api_calls && api_calls > 1000
+
+ (points / ((Time.now - updated_at) / 7.days)**SCORE_GRAVITY).round(4)
+ end
+
+=begin
+ def compute_score
+ score = 0
+ score += (Time.now - created_at) / 1.day
+ score -= ((Time.now - updated_at) / 1.day) * 2
+ score += 500 if (updated_at > 1.week.ago)
+ score -= 1000 if
+ follow_count = follows_dataset.count
+ score -= 1000 if follow_count == 0
+ score += follow_count * 100
+ score += profile_comments_dataset.count * 5
+ score += profile_commentings_dataset.count
+ score.to_i
+ end
+=end
+
+ def self.browse_dataset
+ dataset.where is_deleted: false, is_banned: false, is_crashing: false, site_changed: true
+ end
+
def suggestions(limit=SUGGESTIONS_LIMIT, offset=0)
suggestions_dataset = Site.exclude(id: id).exclude(is_banned: true).exclude(is_nsfw: true).order(:views.desc, :updated_at.desc)
suggestions = suggestions_dataset.where(tags: tags).limit(limit, offset).all
return suggestions if suggestions.length == limit
- suggestions += suggestions_dataset.where("views >= #{SUGGESTIONS_VIEWS_MIN}").limit(limit-suggestions.length).order(Sequel.lit('RANDOM()')).all
+ # Old.
+ #suggestions += suggestions_dataset.where("views >= #{SUGGESTIONS_VIEWS_MIN}").limit(limit-suggestions.length).order(Sequel.lit('RANDOM()')).all
+
+ # New:
+
+ site_dataset = self.class.browse_dataset.association_left_join :follows
+ site_dataset.select_all! :sites
+ site_dataset.select_append! Sequel.lit("count(follows.site_id) AS follow_count")
+ site_dataset.group! :sites__id
+ site_dataset.order! :follow_count.desc, :updated_at.desc
+ site_dataset.where! "views >= #{SUGGESTIONS_VIEWS_MIN}"
+ site_dataset.limit! limit-suggestions.length
+ #site_dataset.order! Sequel.lit('RANDOM()')
+
+ suggestions += site_dataset.all
end
def screenshot_path(path, resolution)
@@ -1090,11 +1241,53 @@ class Site < Sequel::Model
end
end
+ def empty_index?
+ !site_files_dataset.where(path: /^\/?index.html$/).where(sha1_hash: EMPTY_FILE_HASH).first.nil?
+ end
+
+ def classify(path)
+ return nil unless classification_allowed? path
+ #$classifier.classify process_for_classification(path)
+ end
+
+ def classification_scores(path)
+ return nil unless classification_allowed? path
+ #$classifier.classification_scores process_for_classification(path)
+ end
+
+ def train(path, category='ham')
+ return nil unless classification_allowed? path
+ # $trainer.train(category, process_for_classification(path))
+ site_file = site_files_dataset.where(path: path).first
+ site_file.classifier = category
+ site_file.save_changes validate: false
+ end
+
+ def untrain(path, category='ham')
+ return nil unless classification_allowed? path
+ # $trainer.untrain(category, process_for_classification(path))
+ site_file = site_files_dataset.where(path: path).first
+ site_file.classifier = category
+ site_file.save_changes validate: false
+ end
+
+ def classification_allowed?(path)
+ site_file = site_files_dataset.where(path: path).first
+ return false if site_file.is_directory
+ return false if site_file.size > SiteFile::CLASSIFIER_LIMIT
+ return false if !path.match(/\.html$/)
+ true
+ end
+
+ def process_for_classification(path)
+ sanitized = Sanitize.fragment get_file(path)
+ sanitized.gsub(/(http|https):\/\//, '').gsub(/[^\w\s]/, '').downcase.split.uniq.select{|v| v.length < SiteFile::CLASSIFIER_WORD_LIMIT}.join(' ')
+ end
+
# array of hashes: filename, tempfile, opts.
def store_files(files, opts={})
results = []
new_size = 0
- html_uploaded = false
if too_many_files?(files.length)
results << false
@@ -1102,35 +1295,53 @@ class Site < Sequel::Model
end
files.each do |file|
- html_uploaded = true if file[:filename].match HTML_REGEX
-
existing_size = 0
+
site_file = site_files_dataset.where(path: scrubbed_path(file[:filename])).first
+
if site_file
existing_size = site_file.size
end
res = store_file(file[:filename], file[:tempfile], file[:opts] || opts)
+
if res == true
new_size -= existing_size
new_size += file[:tempfile].size
end
+
results << res
end
- if results.include? true && opts[:new_install] != true
- time = Time.now
- sql = DB["update sites set site_changed=?, site_updated_at=?, updated_at=?, changed_count=changed_count+1, space_used=space_used#{new_size < 0 ? new_size.to_s : '+'+new_size.to_s} where id=?",
- true,
- time,
- time,
- self.id
- ]
- sql.first
+ if results.include? true
+
+ DB["update sites set space_used=space_used#{new_size < 0 ? new_size.to_s : '+'+new_size.to_s} where id=?", self.id].first
+
+ if opts[:new_install] != true
+ if files.select {|f| f[:filename] =~ /^\/?index.html$/}.length > 0 || site_changed == true
+ index_changed = true
+ else
+ index_changed = false
+ end
+
+ index_changed = false if empty_index?
+
+ time = Time.now
+
+ sql = DB["update sites set site_changed=?, site_updated_at=?, updated_at=?, changed_count=changed_count+1 where id=?",
+ index_changed,
+ time,
+ time,
+ self.id
+ ]
+ sql.first
+
+ ArchiveWorker.perform_in 24.hours, self.id
+ end
+
reload
#SiteChange.record self, relative_path unless opts[:new_install]
- ArchiveWorker.perform_async self.id
end
results
@@ -1138,36 +1349,9 @@ class Site < Sequel::Model
def delete_file(path)
return false if files_path(path) == files_path
- begin
- FileUtils.rm files_path(path)
- rescue Errno::EISDIR
- site_files.each do |site_file|
- if site_file.path.match /^#{path}\//
- site_file.destroy
- end
- end
- FileUtils.remove_dir files_path(path), true
- rescue Errno::ENOENT
- end
-
- purge_cache path
-
- ext = File.extname(path).gsub(/^./, '')
-
- screenshots_delete(path) if ext.match HTML_REGEX
- thumbnails_delete(path) if ext.match IMAGE_REGEX
-
- path = path[1..path.length] if path[0] == '/'
-
- DB.transaction do
- site_file = site_files_dataset.where(path: path).first
- if site_file
- DB['update sites set space_used=space_used-? where id=?', site_file.size, self.id].first
- site_file.delete
- end
- SiteChangeFile.filter(site_id: self.id, filename: path).delete
- end
-
+ path = scrubbed_path path
+ site_file = site_files_dataset.where(path: path).first
+ site_file.destroy if site_file
true
end
@@ -1186,6 +1370,15 @@ class Site < Sequel::Model
return false
end
+ if pathname.extname.match HTML_REGEX
+ # SPAM and phishing checking code goes here
+ end
+
+ relative_path_dir = Pathname(relative_path).dirname
+ create_directory relative_path_dir unless relative_path_dir == '.'
+
+ uploaded_size = uploaded.size
+
if relative_path == 'index.html'
begin
new_title = Nokogiri::HTML(File.read(uploaded.path)).css('title').first.text
@@ -1198,18 +1391,6 @@ class Site < Sequel::Model
end
end
- if pathname.extname.match HTML_REGEX
- # SPAM and phishing checking code goes here
- end
-
- dirname = pathname.dirname.to_s
-
- if !File.exists? dirname
- FileUtils.mkdir_p dirname
- end
-
- uploaded_size = uploaded.size
-
FileUtils.cp uploaded.path, path
File.chmod 0640, path
@@ -1227,11 +1408,11 @@ class Site < Sequel::Model
purge_cache path
if pathname.extname.match HTML_REGEX
- ScreenshotWorker.perform_async values[:username], relative_path
+ ScreenshotWorker.perform_in 1.minute, values[:username], relative_path
elsif pathname.extname.match IMAGE_REGEX
ThumbnailWorker.perform_async values[:username], relative_path
end
+
true
end
-
end
diff --git a/models/site_file.rb b/models/site_file.rb
index fa5db8d6..bf81c5e3 100644
--- a/models/site_file.rb
+++ b/models/site_file.rb
@@ -1,5 +1,53 @@
+require 'sanitize'
+
class SiteFile < Sequel::Model
+ CLASSIFIER_LIMIT = 1_000_000.freeze
+ CLASSIFIER_WORD_LIMIT = 25.freeze
unrestrict_primary_key
plugin :update_primary_key
many_to_one :site
+
+ def before_destroy
+ if is_directory
+ site.site_files_dataset.where(path: /^#{path}\//, is_directory: true).all.each do |site_file|
+ begin
+ site_file.destroy
+ rescue Sequel::NoExistingObject
+ end
+ end
+
+ site.site_files_dataset.where(path: /^#{path}\//, is_directory: false).all.each do |site_file|
+ site_file.destroy
+ end
+
+ begin
+ FileUtils.remove_dir site.files_path(path)
+ rescue Errno::ENOENT
+ end
+
+ else
+
+ begin
+ FileUtils.rm site.files_path(path)
+ rescue Errno::ENOENT
+ end
+
+ ext = File.extname(path).gsub(/^./, '')
+ site.screenshots_delete(path) if ext.match Site::HTML_REGEX
+ site.thumbnails_delete(path) if ext.match Site::IMAGE_REGEX
+ end
+
+ super
+ end
+
+ def after_destroy
+ super
+ unless is_directory
+ DB['update sites set space_used=space_used-? where id=?', size, site_id].first
+ end
+
+ site.delete_cache site.files_path(path)
+ SiteChangeFile.filter(site_id: site_id, filename: path).delete
+ end
end
+
diff --git a/models/stat.rb b/models/stat.rb
index 687997ee..fe2ea15c 100644
--- a/models/stat.rb
+++ b/models/stat.rb
@@ -15,8 +15,11 @@ class Stat < Sequel::Model
end
def parse_logfiles(path)
+ total_site_stats = {}
+
Dir["#{path}/*.log"].each do |log_path|
site_logs = {}
+
logfile = File.open log_path, 'r'
while hit = logfile.gets
@@ -26,9 +29,13 @@ class Stat < Sequel::Model
time, username, size, path, ip, referrer = hit_array
+ log_time = Time.parse time
+
next if !referrer.nil? && referrer.match(/bot/i)
- site_logs[username] = {
+ site_logs[log_time] = {} unless site_logs[log_time]
+
+ site_logs[log_time][username] = {
hits: 0,
views: 0,
bandwidth: 0,
@@ -36,78 +43,111 @@ class Stat < Sequel::Model
ips: [],
referrers: {},
paths: {}
- } unless site_logs[username]
+ } unless site_logs[log_time][username]
- site_logs[username][:hits] += 1
- site_logs[username][:bandwidth] += size.to_i
+ total_site_stats[log_time] = {
+ hits: 0,
+ views: 0,
+ bandwidth: 0
+ } unless total_site_stats[log_time]
- unless site_logs[username][:view_ips].include?(ip)
- site_logs[username][:views] += 1
- site_logs[username][:view_ips] << ip
+ site_logs[log_time][username][:hits] += 1
+ site_logs[log_time][username][:bandwidth] += size.to_i
+
+ total_site_stats[log_time][:hits] += 1
+ total_site_stats[log_time][:bandwidth] += size.to_i
+
+ unless site_logs[log_time][username][:view_ips].include?(ip)
+ site_logs[log_time][username][:views] += 1
+
+ total_site_stats[log_time][:views] += 1
+
+ site_logs[log_time][username][:view_ips] << ip
if referrer != '-' && !referrer.nil?
- site_logs[username][:referrers][referrer] ||= 0
- site_logs[username][:referrers][referrer] += 1
+ site_logs[log_time][username][:referrers][referrer] ||= 0
+ site_logs[log_time][username][:referrers][referrer] += 1
end
end
- site_logs[username][:paths][path] ||= 0
- site_logs[username][:paths][path] += 1
+ site_logs[log_time][username][:paths][path] ||= 0
+ site_logs[log_time][username][:paths][path] += 1
end
logfile.close
- current_time = Time.now.utc
- current_day_string = current_time.to_date.to_s
-
- Site.select(:id, :username).where(username: site_logs.keys).all.each do |site|
- site_logs[site.username][:id] = site.id
- end
-
DB.transaction do
- site_logs.each do |username, site_log|
- DB['update sites set hits=hits+?, views=views+? where username=?',
- site_log[:hits],
- site_log[:views],
- username
+ site_logs.each do |log_time, usernames|
+ Site.select(:id, :username).where(username: usernames.keys).all.each do |site|
+ site_logs[log_time][site.username][:id] = site.id
+ end
+
+ usernames.each do |username, site_log|
+ DB['update sites set hits=hits+?, views=views+? where username=?',
+ site_log[:hits],
+ site_log[:views],
+ username
].first
- opts = {site_id: site_log[:id], created_at: current_day_string}
+ opts = {site_id: site_log[:id], created_at: log_time.to_date.to_s}
- stat = Stat.select(:id).where(opts).first
- DB[:stats].lock('EXCLUSIVE') { stat = Stat.create opts } if stat.nil?
+ stat = nil
- DB[
- 'update stats set hits=hits+?, views=views+?, bandwidth=bandwidth+? where id=?',
- site_log[:hits],
- site_log[:views],
- site_log[:bandwidth],
- stat.id
- ].first
+ DB[:stats].lock('EXCLUSIVE') {
+ stat = Stat.select(:id).where(opts).first
+ stat = Stat.create opts if stat.nil?
+ }
+
+ DB[
+ 'update stats set hits=hits+?, views=views+?, bandwidth=bandwidth+? where id=?',
+ site_log[:hits],
+ site_log[:views],
+ site_log[:bandwidth],
+ stat.id
+ ].first
=begin
- site_log[:referrers].each do |referrer, views|
- stat_referrer = StatReferrer.create_or_get site_log[:id], referrer
- DB['update stat_referrers set views=views+? where site_id=?', views, site_log[:id]].first
- end
+ site_log[:referrers].each do |referrer, views|
+ stat_referrer = StatReferrer.create_or_get site_log[:id], referrer
+ DB['update stat_referrers set views=views+? where site_id=?', views, site_log[:id]].first
+ end
- site_log[:view_ips].each do |ip|
- site_location = StatLocation.create_or_get site_log[:id], ip
- next if site_location.nil?
- DB['update stat_locations set views=views+1 where id=?', site_location.id].first
- end
+ site_log[:view_ips].each do |ip|
+ site_location = StatLocation.create_or_get site_log[:id], ip
+ next if site_location.nil?
+ DB['update stat_locations set views=views+1 where id=?', site_location.id].first
+ end
- site_log[:paths].each do |path, views|
- site_path = StatPath.create_or_get site_log[:id], path
- next if site_path.nil?
- DB['update stat_paths set views=views+? where id=?', views, site_path.id].first
- end
+ site_log[:paths].each do |path, views|
+ site_path = StatPath.create_or_get site_log[:id], path
+ next if site_path.nil?
+ DB['update stat_paths set views=views+? where id=?', views, site_path.id].first
+ end
=end
+ end
end
end
FileUtils.rm log_path
end
+
+ total_site_stats.each do |time, stats|
+ opts = {created_at: time.to_date.to_s}
+
+ DB[:stats].lock('EXCLUSIVE') {
+ stat = DailySiteStat.select(:id).where(opts).first
+ stat = DailySiteStat.create opts if stat.nil?
+ }
+
+ DB[
+ 'update daily_site_stats set hits=hits+?, views=views+?, bandwidth=bandwidth+? where created_at=?',
+ stats[:hits],
+ stats[:views],
+ stats[:bandwidth],
+ time.to_date
+ ].first
+ end
+
end
end
end
diff --git a/public/cat.png b/public/cat.png
new file mode 100644
index 00000000..7d8eeadb
Binary files /dev/null and b/public/cat.png differ
diff --git a/public/css/highlight/styles/agate.css b/public/css/highlight/styles/agate.css
new file mode 100644
index 00000000..8d64547c
--- /dev/null
+++ b/public/css/highlight/styles/agate.css
@@ -0,0 +1,108 @@
+/*!
+ * Agate by Taufik Nurrohman
+ * ----------------------------------------------------
+ *
+ * #ade5fc
+ * #a2fca2
+ * #c6b4f0
+ * #d36363
+ * #fcc28c
+ * #fc9b9b
+ * #ffa
+ * #fff
+ * #333
+ * #62c8f3
+ * #888
+ *
+ */
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #333;
+ color: white;
+}
+
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-code,
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-tag {
+ color: #62c8f3;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #ade5fc;
+}
+
+.hljs-string,
+.hljs-bullet {
+ color: #a2fca2;
+}
+
+.hljs-type,
+.hljs-title,
+.hljs-section,
+.hljs-attribute,
+.hljs-quote,
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #ffa;
+}
+
+.hljs-number,
+.hljs-symbol,
+.hljs-bullet {
+ color: #d36363;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal {
+ color: #fcc28c;
+}
+
+.hljs-comment,
+.hljs-deletion,
+.hljs-code {
+ color: #888;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #c6b4f0;
+}
+
+.hljs-meta {
+ color: #fc9b9b;
+}
+
+.hljs-deletion {
+ background-color: #fc9b9b;
+ color: #333;
+}
+
+.hljs-addition {
+ background-color: #a2fca2;
+ color: #333;
+}
+
+.hljs a {
+ color: inherit;
+}
+
+.hljs a:focus,
+.hljs a:hover {
+ color: inherit;
+ text-decoration: underline;
+}
diff --git a/public/css/highlight/styles/androidstudio.css b/public/css/highlight/styles/androidstudio.css
new file mode 100644
index 00000000..bc8e473b
--- /dev/null
+++ b/public/css/highlight/styles/androidstudio.css
@@ -0,0 +1,66 @@
+/*
+Date: 24 Fev 2015
+Author: Pedro Oliveira
+*/
+
+.hljs {
+ color: #a9b7c6;
+ background: #282b2e;
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+}
+
+.hljs-number,
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet {
+ color: #6897BB;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-deletion {
+ color: #cc7832;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-link {
+ color: #629755;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #808080;
+}
+
+.hljs-meta {
+ color: #bbb529;
+}
+
+.hljs-string,
+.hljs-attribute,
+.hljs-addition {
+ color: #6A8759;
+}
+
+.hljs-section,
+.hljs-title,
+.hljs-type {
+ color: #ffc66d;
+}
+
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #e8bf6a;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/arta.css b/public/css/highlight/styles/arta.css
new file mode 100644
index 00000000..75ef3a9e
--- /dev/null
+++ b/public/css/highlight/styles/arta.css
@@ -0,0 +1,73 @@
+/*
+Date: 17.V.2011
+Author: pumbur
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #222;
+}
+
+.hljs,
+.hljs-subst {
+ color: #aaa;
+}
+
+.hljs-section {
+ color: #fff;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-meta {
+ color: #444;
+}
+
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-regexp {
+ color: #ffcc33;
+}
+
+.hljs-number,
+.hljs-addition {
+ color: #00cc66;
+}
+
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-link {
+ color: #32aaee;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #6644aa;
+}
+
+.hljs-title,
+.hljs-variable,
+.hljs-deletion,
+.hljs-template-tag {
+ color: #bb1166;
+}
+
+.hljs-section,
+.hljs-doctag,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/ascetic.css b/public/css/highlight/styles/ascetic.css
new file mode 100644
index 00000000..48397e88
--- /dev/null
+++ b/public/css/highlight/styles/ascetic.css
@@ -0,0 +1,45 @@
+/*
+
+Original style from softwaremaniacs.org (c) Ivan Sagalaev
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: white;
+ color: black;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-section,
+.hljs-addition,
+.hljs-attribute,
+.hljs-link {
+ color: #888;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-meta,
+.hljs-deletion {
+ color: #ccc;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-name,
+.hljs-type,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/atelier-cave-dark.css b/public/css/highlight/styles/atelier-cave-dark.css
new file mode 100644
index 00000000..65428f3b
--- /dev/null
+++ b/public/css/highlight/styles/atelier-cave-dark.css
@@ -0,0 +1,83 @@
+/* Base16 Atelier Cave Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Cave Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #7e7887;
+}
+
+/* Atelier-Cave Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-regexp,
+.hljs-link,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #be4678;
+}
+
+/* Atelier-Cave Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #aa573c;
+}
+
+/* Atelier-Cave Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #2a9292;
+}
+
+/* Atelier-Cave Blue */
+.hljs-title,
+.hljs-section {
+ color: #576ddb;
+}
+
+/* Atelier-Cave Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #955ae7;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #19171c;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #be4678;
+}
+
+.hljs-addition {
+ background-color: #2a9292;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #19171c;
+ color: #8b8792;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-cave-light.css b/public/css/highlight/styles/atelier-cave-light.css
new file mode 100644
index 00000000..b419f9fd
--- /dev/null
+++ b/public/css/highlight/styles/atelier-cave-light.css
@@ -0,0 +1,85 @@
+/* Base16 Atelier Cave Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Cave Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #655f6d;
+}
+
+/* Atelier-Cave Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #be4678;
+}
+
+/* Atelier-Cave Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #aa573c;
+}
+
+/* Atelier-Cave Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #2a9292;
+}
+
+/* Atelier-Cave Blue */
+.hljs-title,
+.hljs-section {
+ color: #576ddb;
+}
+
+/* Atelier-Cave Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #955ae7;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #19171c;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #be4678;
+}
+
+.hljs-addition {
+ background-color: #2a9292;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #efecf4;
+ color: #585260;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-dune-dark.css b/public/css/highlight/styles/atelier-dune-dark.css
new file mode 100644
index 00000000..1684f522
--- /dev/null
+++ b/public/css/highlight/styles/atelier-dune-dark.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Dune Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Dune Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #999580;
+}
+
+/* Atelier-Dune Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #d73737;
+}
+
+/* Atelier-Dune Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #b65611;
+}
+
+/* Atelier-Dune Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #60ac39;
+}
+
+/* Atelier-Dune Blue */
+.hljs-title,
+.hljs-section {
+ color: #6684e1;
+}
+
+/* Atelier-Dune Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #b854d4;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #20201d;
+ color: #a6a28c;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-dune-light.css b/public/css/highlight/styles/atelier-dune-light.css
new file mode 100644
index 00000000..547719de
--- /dev/null
+++ b/public/css/highlight/styles/atelier-dune-light.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Dune Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Dune Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #7d7a68;
+}
+
+/* Atelier-Dune Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #d73737;
+}
+
+/* Atelier-Dune Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #b65611;
+}
+
+/* Atelier-Dune Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #60ac39;
+}
+
+/* Atelier-Dune Blue */
+.hljs-title,
+.hljs-section {
+ color: #6684e1;
+}
+
+/* Atelier-Dune Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #b854d4;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #fefbec;
+ color: #6e6b5e;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-estuary-dark.css b/public/css/highlight/styles/atelier-estuary-dark.css
new file mode 100644
index 00000000..a5e50718
--- /dev/null
+++ b/public/css/highlight/styles/atelier-estuary-dark.css
@@ -0,0 +1,84 @@
+/* Base16 Atelier Estuary Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Estuary Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #878573;
+}
+
+/* Atelier-Estuary Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #ba6236;
+}
+
+/* Atelier-Estuary Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #ae7313;
+}
+
+/* Atelier-Estuary Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #7d9726;
+}
+
+/* Atelier-Estuary Blue */
+.hljs-title,
+.hljs-section {
+ color: #36a166;
+}
+
+/* Atelier-Estuary Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #5f9182;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #22221b;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #ba6236;
+}
+
+.hljs-addition {
+ background-color: #7d9726;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #22221b;
+ color: #929181;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-estuary-light.css b/public/css/highlight/styles/atelier-estuary-light.css
new file mode 100644
index 00000000..1daee5d9
--- /dev/null
+++ b/public/css/highlight/styles/atelier-estuary-light.css
@@ -0,0 +1,84 @@
+/* Base16 Atelier Estuary Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Estuary Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #6c6b5a;
+}
+
+/* Atelier-Estuary Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #ba6236;
+}
+
+/* Atelier-Estuary Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #ae7313;
+}
+
+/* Atelier-Estuary Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #7d9726;
+}
+
+/* Atelier-Estuary Blue */
+.hljs-title,
+.hljs-section {
+ color: #36a166;
+}
+
+/* Atelier-Estuary Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #5f9182;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #22221b;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #ba6236;
+}
+
+.hljs-addition {
+ background-color: #7d9726;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #f4f3ec;
+ color: #5f5e4e;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-forest-dark.css b/public/css/highlight/styles/atelier-forest-dark.css
new file mode 100644
index 00000000..0ef4fae3
--- /dev/null
+++ b/public/css/highlight/styles/atelier-forest-dark.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Forest Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Forest Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #9c9491;
+}
+
+/* Atelier-Forest Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #f22c40;
+}
+
+/* Atelier-Forest Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #df5320;
+}
+
+/* Atelier-Forest Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #7b9726;
+}
+
+/* Atelier-Forest Blue */
+.hljs-title,
+.hljs-section {
+ color: #407ee7;
+}
+
+/* Atelier-Forest Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #6666ea;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #1b1918;
+ color: #a8a19f;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-forest-light.css b/public/css/highlight/styles/atelier-forest-light.css
new file mode 100644
index 00000000..bbedde18
--- /dev/null
+++ b/public/css/highlight/styles/atelier-forest-light.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Forest Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Forest Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #766e6b;
+}
+
+/* Atelier-Forest Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #f22c40;
+}
+
+/* Atelier-Forest Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #df5320;
+}
+
+/* Atelier-Forest Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #7b9726;
+}
+
+/* Atelier-Forest Blue */
+.hljs-title,
+.hljs-section {
+ color: #407ee7;
+}
+
+/* Atelier-Forest Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #6666ea;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #f1efee;
+ color: #68615e;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-heath-dark.css b/public/css/highlight/styles/atelier-heath-dark.css
new file mode 100644
index 00000000..fe01ff72
--- /dev/null
+++ b/public/css/highlight/styles/atelier-heath-dark.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Heath Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Heath Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #9e8f9e;
+}
+
+/* Atelier-Heath Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #ca402b;
+}
+
+/* Atelier-Heath Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #a65926;
+}
+
+/* Atelier-Heath Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #918b3b;
+}
+
+/* Atelier-Heath Blue */
+.hljs-title,
+.hljs-section {
+ color: #516aec;
+}
+
+/* Atelier-Heath Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #7b59c0;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #1b181b;
+ color: #ab9bab;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-heath-light.css b/public/css/highlight/styles/atelier-heath-light.css
new file mode 100644
index 00000000..ee43786d
--- /dev/null
+++ b/public/css/highlight/styles/atelier-heath-light.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Heath Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Heath Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #776977;
+}
+
+/* Atelier-Heath Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #ca402b;
+}
+
+/* Atelier-Heath Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #a65926;
+}
+
+/* Atelier-Heath Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #918b3b;
+}
+
+/* Atelier-Heath Blue */
+.hljs-title,
+.hljs-section {
+ color: #516aec;
+}
+
+/* Atelier-Heath Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #7b59c0;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #f7f3f7;
+ color: #695d69;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-lakeside-dark.css b/public/css/highlight/styles/atelier-lakeside-dark.css
new file mode 100644
index 00000000..a937d3bf
--- /dev/null
+++ b/public/css/highlight/styles/atelier-lakeside-dark.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Lakeside Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Lakeside Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #7195a8;
+}
+
+/* Atelier-Lakeside Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #d22d72;
+}
+
+/* Atelier-Lakeside Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #935c25;
+}
+
+/* Atelier-Lakeside Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #568c3b;
+}
+
+/* Atelier-Lakeside Blue */
+.hljs-title,
+.hljs-section {
+ color: #257fad;
+}
+
+/* Atelier-Lakeside Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #6b6bb8;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #161b1d;
+ color: #7ea2b4;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-lakeside-light.css b/public/css/highlight/styles/atelier-lakeside-light.css
new file mode 100644
index 00000000..6c7e8f9e
--- /dev/null
+++ b/public/css/highlight/styles/atelier-lakeside-light.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Lakeside Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Lakeside Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #5a7b8c;
+}
+
+/* Atelier-Lakeside Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #d22d72;
+}
+
+/* Atelier-Lakeside Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #935c25;
+}
+
+/* Atelier-Lakeside Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #568c3b;
+}
+
+/* Atelier-Lakeside Blue */
+.hljs-title,
+.hljs-section {
+ color: #257fad;
+}
+
+/* Atelier-Lakeside Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #6b6bb8;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #ebf8ff;
+ color: #516d7b;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-plateau-dark.css b/public/css/highlight/styles/atelier-plateau-dark.css
new file mode 100644
index 00000000..3bb05269
--- /dev/null
+++ b/public/css/highlight/styles/atelier-plateau-dark.css
@@ -0,0 +1,84 @@
+/* Base16 Atelier Plateau Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Plateau Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #7e7777;
+}
+
+/* Atelier-Plateau Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #ca4949;
+}
+
+/* Atelier-Plateau Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #b45a3c;
+}
+
+/* Atelier-Plateau Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #4b8b8b;
+}
+
+/* Atelier-Plateau Blue */
+.hljs-title,
+.hljs-section {
+ color: #7272ca;
+}
+
+/* Atelier-Plateau Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #8464c4;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #1b1818;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #ca4949;
+}
+
+.hljs-addition {
+ background-color: #4b8b8b;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #1b1818;
+ color: #8a8585;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-plateau-light.css b/public/css/highlight/styles/atelier-plateau-light.css
new file mode 100644
index 00000000..5f0222be
--- /dev/null
+++ b/public/css/highlight/styles/atelier-plateau-light.css
@@ -0,0 +1,84 @@
+/* Base16 Atelier Plateau Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Plateau Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #655d5d;
+}
+
+/* Atelier-Plateau Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #ca4949;
+}
+
+/* Atelier-Plateau Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #b45a3c;
+}
+
+/* Atelier-Plateau Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #4b8b8b;
+}
+
+/* Atelier-Plateau Blue */
+.hljs-title,
+.hljs-section {
+ color: #7272ca;
+}
+
+/* Atelier-Plateau Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #8464c4;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #1b1818;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #ca4949;
+}
+
+.hljs-addition {
+ background-color: #4b8b8b;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #f4ecec;
+ color: #585050;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-savanna-dark.css b/public/css/highlight/styles/atelier-savanna-dark.css
new file mode 100644
index 00000000..38f83143
--- /dev/null
+++ b/public/css/highlight/styles/atelier-savanna-dark.css
@@ -0,0 +1,84 @@
+/* Base16 Atelier Savanna Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Savanna Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #78877d;
+}
+
+/* Atelier-Savanna Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #b16139;
+}
+
+/* Atelier-Savanna Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #9f713c;
+}
+
+/* Atelier-Savanna Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #489963;
+}
+
+/* Atelier-Savanna Blue */
+.hljs-title,
+.hljs-section {
+ color: #478c90;
+}
+
+/* Atelier-Savanna Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #55859b;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #171c19;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #b16139;
+}
+
+.hljs-addition {
+ background-color: #489963;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #171c19;
+ color: #87928a;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-savanna-light.css b/public/css/highlight/styles/atelier-savanna-light.css
new file mode 100644
index 00000000..1ccd7c68
--- /dev/null
+++ b/public/css/highlight/styles/atelier-savanna-light.css
@@ -0,0 +1,84 @@
+/* Base16 Atelier Savanna Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Savanna Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #5f6d64;
+}
+
+/* Atelier-Savanna Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #b16139;
+}
+
+/* Atelier-Savanna Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #9f713c;
+}
+
+/* Atelier-Savanna Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #489963;
+}
+
+/* Atelier-Savanna Blue */
+.hljs-title,
+.hljs-section {
+ color: #478c90;
+}
+
+/* Atelier-Savanna Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #55859b;
+}
+
+.hljs-deletion,
+.hljs-addition {
+ color: #171c19;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #b16139;
+}
+
+.hljs-addition {
+ background-color: #489963;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #ecf4ee;
+ color: #526057;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-seaside-dark.css b/public/css/highlight/styles/atelier-seaside-dark.css
new file mode 100644
index 00000000..df29949c
--- /dev/null
+++ b/public/css/highlight/styles/atelier-seaside-dark.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Seaside Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Seaside Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #809980;
+}
+
+/* Atelier-Seaside Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #e6193c;
+}
+
+/* Atelier-Seaside Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #87711d;
+}
+
+/* Atelier-Seaside Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #29a329;
+}
+
+/* Atelier-Seaside Blue */
+.hljs-title,
+.hljs-section {
+ color: #3d62f5;
+}
+
+/* Atelier-Seaside Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #ad2bee;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #131513;
+ color: #8ca68c;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-seaside-light.css b/public/css/highlight/styles/atelier-seaside-light.css
new file mode 100644
index 00000000..9d960f29
--- /dev/null
+++ b/public/css/highlight/styles/atelier-seaside-light.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Seaside Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Seaside Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #687d68;
+}
+
+/* Atelier-Seaside Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #e6193c;
+}
+
+/* Atelier-Seaside Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #87711d;
+}
+
+/* Atelier-Seaside Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #29a329;
+}
+
+/* Atelier-Seaside Blue */
+.hljs-title,
+.hljs-section {
+ color: #3d62f5;
+}
+
+/* Atelier-Seaside Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #ad2bee;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #f4fbf4;
+ color: #5e6e5e;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-sulphurpool-dark.css b/public/css/highlight/styles/atelier-sulphurpool-dark.css
new file mode 100644
index 00000000..c2ab7938
--- /dev/null
+++ b/public/css/highlight/styles/atelier-sulphurpool-dark.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Sulphurpool Dark - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Sulphurpool Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #898ea4;
+}
+
+/* Atelier-Sulphurpool Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #c94922;
+}
+
+/* Atelier-Sulphurpool Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #c76b29;
+}
+
+/* Atelier-Sulphurpool Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #ac9739;
+}
+
+/* Atelier-Sulphurpool Blue */
+.hljs-title,
+.hljs-section {
+ color: #3d8fd1;
+}
+
+/* Atelier-Sulphurpool Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #6679cc;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #202746;
+ color: #979db4;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/atelier-sulphurpool-light.css b/public/css/highlight/styles/atelier-sulphurpool-light.css
new file mode 100644
index 00000000..96c47d08
--- /dev/null
+++ b/public/css/highlight/styles/atelier-sulphurpool-light.css
@@ -0,0 +1,69 @@
+/* Base16 Atelier Sulphurpool Light - Theme */
+/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) */
+/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
+
+/* Atelier-Sulphurpool Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #6b7394;
+}
+
+/* Atelier-Sulphurpool Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-regexp,
+.hljs-link,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #c94922;
+}
+
+/* Atelier-Sulphurpool Orange */
+.hljs-number,
+.hljs-meta,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #c76b29;
+}
+
+/* Atelier-Sulphurpool Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet {
+ color: #ac9739;
+}
+
+/* Atelier-Sulphurpool Blue */
+.hljs-title,
+.hljs-section {
+ color: #3d8fd1;
+}
+
+/* Atelier-Sulphurpool Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #6679cc;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #f5f7ff;
+ color: #5e6687;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/brown-paper.css b/public/css/highlight/styles/brown-paper.css
new file mode 100644
index 00000000..f0197b92
--- /dev/null
+++ b/public/css/highlight/styles/brown-paper.css
@@ -0,0 +1,64 @@
+/*
+
+Brown Paper style from goldblog.com.ua (c) Zaripov Yura
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background:#b7a68e url(./brown-papersq.png);
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal {
+ color:#005599;
+ font-weight:bold;
+}
+
+.hljs,
+.hljs-subst {
+ color: #363c69;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-attribute,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-built_in,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable,
+.hljs-link,
+.hljs-name {
+ color: #2c009f;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-meta,
+.hljs-deletion {
+ color: #802022;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/brown-papersq.png b/public/css/highlight/styles/brown-papersq.png
new file mode 100644
index 00000000..3813903d
Binary files /dev/null and b/public/css/highlight/styles/brown-papersq.png differ
diff --git a/public/css/highlight/styles/codepen-embed.css b/public/css/highlight/styles/codepen-embed.css
new file mode 100644
index 00000000..195c4a07
--- /dev/null
+++ b/public/css/highlight/styles/codepen-embed.css
@@ -0,0 +1,60 @@
+/*
+ codepen.io Embed Theme
+ Author: Justin Perry
+ Original theme - https://github.com/chriskempson/tomorrow-theme
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #222;
+ color: #fff;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #777;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-regexp,
+.hljs-meta,
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-params,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-deletion {
+ color: #ab875d;
+}
+
+.hljs-section,
+.hljs-title,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-type,
+.hljs-attribute {
+ color: #9b869b;
+}
+
+.hljs-string,
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-addition {
+ color: #8f9c6c;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/color-brewer.css b/public/css/highlight/styles/color-brewer.css
new file mode 100644
index 00000000..7934d986
--- /dev/null
+++ b/public/css/highlight/styles/color-brewer.css
@@ -0,0 +1,71 @@
+/*
+
+Colorbrewer theme
+Original: https://github.com/mbostock/colorbrewer-theme (c) Mike Bostock
+Ported by Fabrício Tavares de Oliveira
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #fff;
+}
+
+.hljs,
+.hljs-subst {
+ color: #000;
+}
+
+.hljs-string,
+.hljs-meta,
+.hljs-symbol,
+.hljs-template-tag,
+.hljs-template-variable,
+.hljs-addition {
+ color: #756bb1;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #636363;
+}
+
+.hljs-number,
+.hljs-regexp,
+.hljs-literal,
+.hljs-bullet,
+.hljs-link {
+ color: #31a354;
+}
+
+.hljs-deletion,
+.hljs-variable {
+ color: #88f;
+}
+
+
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-title,
+.hljs-section,
+.hljs-built_in,
+.hljs-doctag,
+.hljs-type,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-strong {
+ color: #3182bd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-attribute {
+ color: #e6550d;
+}
diff --git a/public/css/highlight/styles/dark.css b/public/css/highlight/styles/dark.css
new file mode 100644
index 00000000..b4724f5f
--- /dev/null
+++ b/public/css/highlight/styles/dark.css
@@ -0,0 +1,63 @@
+/*
+
+Dark style from softwaremaniacs.org (c) Ivan Sagalaev
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #444;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-section,
+.hljs-link {
+ color: white;
+}
+
+.hljs,
+.hljs-subst {
+ color: #ddd;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-name,
+.hljs-type,
+.hljs-attribute,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-built_in,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #d88;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion,
+.hljs-meta {
+ color: #777;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-title,
+.hljs-section,
+.hljs-doctag,
+.hljs-type,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/darkula.css b/public/css/highlight/styles/darkula.css
new file mode 100644
index 00000000..c01f9a7f
--- /dev/null
+++ b/public/css/highlight/styles/darkula.css
@@ -0,0 +1,74 @@
+/*
+
+Darkula color scheme from the JetBrains family of IDEs
+
+*/
+
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #2b2b2b;
+}
+
+.hljs {
+ color: #bababa;
+}
+
+.hljs-strong,
+.hljs-emphasis {
+ color: #a8a8a2;
+}
+
+.hljs-bullet,
+.hljs-quote,
+.hljs-link,
+.hljs-number,
+.hljs-regexp,
+.hljs-literal {
+ color: #6896ba;
+}
+
+.hljs-code,
+.hljs-selector-class {
+ color: #a6e22e;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-attribute,
+.hljs-name,
+.hljs-variable {
+ color: #cb7832;
+}
+
+.hljs-params {
+ color: #b9b9b9;
+}
+
+.hljs-string,
+.hljs-subst,
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-symbol,
+.hljs-selector-id,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-template-tag,
+.hljs-template-variable,
+.hljs-addition {
+ color: #e0c46c;
+}
+
+.hljs-comment,
+.hljs-deletion,
+.hljs-meta {
+ color: #7f7f7f;
+}
diff --git a/public/css/highlight/styles/default.css b/public/css/highlight/styles/default.css
new file mode 100644
index 00000000..aee40746
--- /dev/null
+++ b/public/css/highlight/styles/default.css
@@ -0,0 +1,77 @@
+/*
+
+Original highlight.js style (c) Ivan Sagalaev
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #F0F0F0;
+}
+
+.hljs,
+.hljs-subst {
+ color: #444;
+}
+
+.hljs-keyword,
+.hljs-attribute,
+.hljs-selector-tag,
+.hljs-meta-keyword,
+.hljs-doctag,
+.hljs-name {
+ font-weight: bold;
+}
+
+.hljs-built_in,
+.hljs-literal,
+.hljs-bullet,
+.hljs-code,
+.hljs-addition {
+ color: #1F811F;
+}
+
+.hljs-regexp,
+.hljs-symbol,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-link,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #BC6060;
+}
+
+.hljs-type,
+.hljs-string,
+.hljs-number,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-quote,
+.hljs-template-tag,
+.hljs-deletion {
+ color: #880000;
+}
+
+.hljs-title,
+.hljs-section {
+ color: #880000;
+ font-weight: bold;
+}
+
+.hljs-comment {
+ color: #888888;
+}
+
+.hljs-meta {
+ color: #2B6EA1;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/docco.css b/public/css/highlight/styles/docco.css
new file mode 100644
index 00000000..db366be3
--- /dev/null
+++ b/public/css/highlight/styles/docco.css
@@ -0,0 +1,97 @@
+/*
+Docco style used in http://jashkenas.github.com/docco/ converted by Simon Madine (@thingsinjars)
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #000;
+ background: #f8f8ff;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #408080;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-subst {
+ color: #954121;
+}
+
+.hljs-number {
+ color: #40a070;
+}
+
+.hljs-string,
+.hljs-doctag {
+ color: #219161;
+}
+
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-section,
+.hljs-type {
+ color: #19469d;
+}
+
+.hljs-params {
+ color: #00f;
+}
+
+.hljs-title {
+ color: #458;
+ font-weight: bold;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-attribute {
+ color: #000080;
+ font-weight: normal;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #008080;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #b68;
+}
+
+.hljs-symbol,
+.hljs-bullet {
+ color: #990073;
+}
+
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #0086b3;
+}
+
+.hljs-meta {
+ color: #999;
+ font-weight: bold;
+}
+
+.hljs-deletion {
+ background: #fdd;
+}
+
+.hljs-addition {
+ background: #dfd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/far.css b/public/css/highlight/styles/far.css
new file mode 100644
index 00000000..2b3f87b5
--- /dev/null
+++ b/public/css/highlight/styles/far.css
@@ -0,0 +1,71 @@
+/*
+
+FAR Style (c) MajestiC
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #000080;
+}
+
+.hljs,
+.hljs-subst {
+ color: #0ff;
+}
+
+.hljs-string,
+.hljs-attribute,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-template-tag,
+.hljs-template-variable,
+.hljs-addition {
+ color: #ff0;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-type,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-variable {
+ color: #fff;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-doctag,
+.hljs-deletion {
+ color: #888;
+}
+
+.hljs-number,
+.hljs-regexp,
+.hljs-literal,
+.hljs-link {
+ color: #0f0;
+}
+
+.hljs-meta {
+ color: #008080;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-title,
+.hljs-section,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/foundation.css b/public/css/highlight/styles/foundation.css
new file mode 100644
index 00000000..f1fe64b3
--- /dev/null
+++ b/public/css/highlight/styles/foundation.css
@@ -0,0 +1,88 @@
+/*
+Description: Foundation 4 docs style for highlight.js
+Author: Dan Allen
+Website: http://foundation.zurb.com/docs/
+Version: 1.0
+Date: 2013-04-02
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #eee; color: black;
+}
+
+.hljs-link,
+.hljs-emphasis,
+.hljs-attribute,
+.hljs-addition {
+ color: #070;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong,
+.hljs-string,
+.hljs-deletion {
+ color: #d14;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-quote,
+.hljs-comment {
+ color: #998;
+ font-style: italic;
+}
+
+.hljs-section,
+.hljs-title {
+ color: #900;
+}
+
+.hljs-class .hljs-title,
+.hljs-type {
+ color: #458;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #336699;
+}
+
+.hljs-bullet {
+ color: #997700;
+}
+
+.hljs-meta {
+ color: #3344bb;
+}
+
+.hljs-code,
+.hljs-number,
+.hljs-literal,
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #099;
+}
+
+.hljs-regexp {
+ background-color: #fff0ff;
+ color: #880088;
+}
+
+.hljs-symbol {
+ color: #990073;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #007700;
+}
diff --git a/public/css/highlight/styles/github-gist.css b/public/css/highlight/styles/github-gist.css
new file mode 100644
index 00000000..155f0b91
--- /dev/null
+++ b/public/css/highlight/styles/github-gist.css
@@ -0,0 +1,71 @@
+/**
+ * GitHub Gist Theme
+ * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
+ */
+
+.hljs {
+ display: block;
+ background: white;
+ padding: 0.5em;
+ color: #333333;
+ overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+ color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+ color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+ color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+ color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+ color: #63a35c;
+}
+
+.hljs-tag {
+ color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #795da3;
+}
+
+.hljs-addition {
+ color: #55a532;
+ background-color: #eaffea;
+}
+
+.hljs-deletion {
+ color: #bd2c00;
+ background-color: #ffecec;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/public/css/highlight/styles/github.css b/public/css/highlight/styles/github.css
new file mode 100644
index 00000000..791932b8
--- /dev/null
+++ b/public/css/highlight/styles/github.css
@@ -0,0 +1,99 @@
+/*
+
+github.com style (c) Vasily Polovnyov
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #333;
+ background: #f8f8f8;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #998;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-subst {
+ color: #333;
+ font-weight: bold;
+}
+
+.hljs-number,
+.hljs-literal,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag .hljs-attr {
+ color: #008080;
+}
+
+.hljs-string,
+.hljs-doctag {
+ color: #d14;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-selector-id {
+ color: #900;
+ font-weight: bold;
+}
+
+.hljs-subst {
+ font-weight: normal;
+}
+
+.hljs-type,
+.hljs-class .hljs-title {
+ color: #458;
+ font-weight: bold;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-attribute {
+ color: #000080;
+ font-weight: normal;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #009926;
+}
+
+.hljs-symbol,
+.hljs-bullet {
+ color: #990073;
+}
+
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #0086b3;
+}
+
+.hljs-meta {
+ color: #999;
+ font-weight: bold;
+}
+
+.hljs-deletion {
+ background: #fdd;
+}
+
+.hljs-addition {
+ background: #dfd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/googlecode.css b/public/css/highlight/styles/googlecode.css
new file mode 100644
index 00000000..884ad635
--- /dev/null
+++ b/public/css/highlight/styles/googlecode.css
@@ -0,0 +1,89 @@
+/*
+
+Google Code style (c) Aahan Krish
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: white;
+ color: black;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #800;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-section,
+.hljs-title,
+.hljs-name {
+ color: #008;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #660;
+}
+
+.hljs-string,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-regexp {
+ color: #080;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-meta,
+.hljs-number,
+.hljs-link {
+ color: #066;
+}
+
+.hljs-title,
+.hljs-doctag,
+.hljs-type,
+.hljs-attr,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-params {
+ color: #606;
+}
+
+.hljs-attribute,
+.hljs-subst {
+ color: #000;
+}
+
+.hljs-formula {
+ background-color: #eee;
+ font-style: italic;
+}
+
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #9B703F
+}
+
+.hljs-addition {
+ background-color: #baeeba;
+}
+
+.hljs-deletion {
+ background-color: #ffc8bd;
+}
+
+.hljs-doctag,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/grayscale.css b/public/css/highlight/styles/grayscale.css
new file mode 100644
index 00000000..5376f340
--- /dev/null
+++ b/public/css/highlight/styles/grayscale.css
@@ -0,0 +1,101 @@
+/*
+
+grayscale style (c) MY Sun
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #333;
+ background: #fff;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #777;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-subst {
+ color: #333;
+ font-weight: bold;
+}
+
+.hljs-number,
+.hljs-literal {
+ color: #777;
+}
+
+.hljs-string,
+.hljs-doctag,
+.hljs-formula {
+ color: #333;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAJ0lEQVQIW2O8e/fufwYGBgZBQUEQxcCIIfDu3Tuwivfv30NUoAsAALHpFMMLqZlPAAAAAElFTkSuQmCC) repeat;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-selector-id {
+ color: #000;
+ font-weight: bold;
+}
+
+.hljs-subst {
+ font-weight: normal;
+}
+
+.hljs-class .hljs-title,
+.hljs-type,
+.hljs-name {
+ color: #333;
+ font-weight: bold;
+}
+
+.hljs-tag {
+ color: #333;
+}
+
+.hljs-regexp {
+ color: #333;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==) repeat;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link {
+ color: #000;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAKElEQVQIW2NkQAO7d+/+z4gsBhJwdXVlhAvCBECKwIIwAbhKZBUwBQA6hBpm5efZsgAAAABJRU5ErkJggg==) repeat;
+}
+
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #000;
+ text-decoration: underline;
+}
+
+.hljs-meta {
+ color: #999;
+ font-weight: bold;
+}
+
+.hljs-deletion {
+ color: #fff;
+ background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==) repeat;
+}
+
+.hljs-addition {
+ color: #000;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAALUlEQVQYV2N89+7dfwYk8P79ewZBQUFkIQZGOiu6e/cuiptQHAPl0NtNxAQBAM97Oejj3Dg7AAAAAElFTkSuQmCC) repeat;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/hopscotch.css b/public/css/highlight/styles/hopscotch.css
new file mode 100644
index 00000000..32e60d23
--- /dev/null
+++ b/public/css/highlight/styles/hopscotch.css
@@ -0,0 +1,83 @@
+/*
+ * Hopscotch
+ * by Jan T. Sott
+ * https://github.com/idleberg/Hopscotch
+ *
+ * This work is licensed under the Creative Commons CC0 1.0 Universal License
+ */
+
+/* Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #989498;
+}
+
+/* Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-link,
+.hljs-deletion {
+ color: #dd464c;
+}
+
+/* Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params {
+ color: #fd8b19;
+}
+
+/* Yellow */
+.hljs-class .hljs-title {
+ color: #fdcc59;
+}
+
+/* Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #8fc13e;
+}
+
+/* Aqua */
+.hljs-meta {
+ color: #149b93;
+}
+
+/* Blue */
+.hljs-function,
+.hljs-section,
+.hljs-title {
+ color: #1290bf;
+}
+
+/* Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #c85e7c;
+}
+
+.hljs {
+ display: block;
+ background: #322931;
+ color: #b9b5b8;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/hybrid.css b/public/css/highlight/styles/hybrid.css
new file mode 100644
index 00000000..29735a18
--- /dev/null
+++ b/public/css/highlight/styles/hybrid.css
@@ -0,0 +1,102 @@
+/*
+
+vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
+
+*/
+
+/*background color*/
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #1d1f21;
+}
+
+/*selection color*/
+.hljs::selection,
+.hljs span::selection {
+ background: #373b41;
+}
+
+.hljs::-moz-selection,
+.hljs span::-moz-selection {
+ background: #373b41;
+}
+
+/*foreground color*/
+.hljs {
+ color: #c5c8c6;
+}
+
+/*color: fg_yellow*/
+.hljs-title,
+.hljs-name {
+ color: #f0c674;
+}
+
+/*color: fg_comment*/
+.hljs-comment,
+.hljs-meta,
+.hljs-meta .hljs-keyword {
+ color: #707880;
+}
+
+/*color: fg_red*/
+.hljs-number,
+.hljs-symbol,
+.hljs-literal,
+.hljs-deletion,
+.hljs-link {
+ color: #cc6666
+}
+
+/*color: fg_green*/
+.hljs-string,
+.hljs-doctag,
+.hljs-addition,
+.hljs-regexp,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #b5bd68;
+}
+
+/*color: fg_purple*/
+.hljs-attribute,
+.hljs-code,
+.hljs-selector-id {
+ color: #b294bb;
+}
+
+/*color: fg_blue*/
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-bullet,
+.hljs-tag {
+ color: #81a2be;
+}
+
+/*color: fg_aqua*/
+.hljs-subst,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #8abeb7;
+}
+
+/*color: fg_orange*/
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-quote,
+.hljs-section,
+.hljs-selector-class {
+ color: #de935f;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/idea.css b/public/css/highlight/styles/idea.css
new file mode 100644
index 00000000..3bf1892b
--- /dev/null
+++ b/public/css/highlight/styles/idea.css
@@ -0,0 +1,97 @@
+/*
+
+Intellij Idea-like styling (c) Vasily Polovnyov
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #000;
+ background: #fff;
+}
+
+.hljs-subst,
+.hljs-title {
+ font-weight: normal;
+ color: #000;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #808080;
+ font-style: italic;
+}
+
+.hljs-meta {
+ color: #808000;
+}
+
+.hljs-tag {
+ background: #efefef;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-literal,
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type,
+.hljs-selector-id,
+.hljs-selector-class {
+ font-weight: bold;
+ color: #000080;
+}
+
+.hljs-attribute,
+.hljs-number,
+.hljs-regexp,
+.hljs-link {
+ font-weight: bold;
+ color: #0000ff;
+}
+
+.hljs-number,
+.hljs-regexp,
+.hljs-link {
+ font-weight: normal;
+}
+
+.hljs-string {
+ color: #008000;
+ font-weight: bold;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-formula {
+ color: #000;
+ background: #d0eded;
+ font-style: italic;
+}
+
+.hljs-doctag {
+ text-decoration: underline;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #660e7a;
+}
+
+.hljs-addition {
+ background: #baeeba;
+}
+
+.hljs-deletion {
+ background: #ffc8bd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/ir-black.css b/public/css/highlight/styles/ir-black.css
new file mode 100644
index 00000000..bd4c755e
--- /dev/null
+++ b/public/css/highlight/styles/ir-black.css
@@ -0,0 +1,73 @@
+/*
+ IR_Black style (c) Vasily Mikhailitchenko
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #000;
+ color: #f8f8f8;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-meta {
+ color: #7c7c7c;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-tag,
+.hljs-name {
+ color: #96cbfe;
+}
+
+.hljs-attribute,
+.hljs-selector-id {
+ color: #ffffb6;
+}
+
+.hljs-string,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition {
+ color: #a8ff60;
+}
+
+.hljs-subst {
+ color: #daefa3;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #e9c062;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-doctag {
+ color: #ffffb6;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-literal {
+ color: #c6c5fe;
+}
+
+.hljs-number,
+.hljs-deletion {
+ color:#ff73fd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/kimbie.dark.css b/public/css/highlight/styles/kimbie.dark.css
new file mode 100644
index 00000000..d139cb5d
--- /dev/null
+++ b/public/css/highlight/styles/kimbie.dark.css
@@ -0,0 +1,74 @@
+/*
+ Name: Kimbie (dark)
+ Author: Jan T. Sott
+ License: Creative Commons Attribution-ShareAlike 4.0 Unported License
+ URL: https://github.com/idleberg/Kimbie-highlight.js
+*/
+
+/* Kimbie Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #d6baad;
+}
+
+/* Kimbie Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-meta {
+ color: #dc3958;
+}
+
+/* Kimbie Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-deletion,
+.hljs-link {
+ color: #f79a32;
+}
+
+/* Kimbie Yellow */
+.hljs-title,
+.hljs-section,
+.hljs-attribute {
+ color: #f06431;
+}
+
+/* Kimbie Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #889b4a;
+}
+
+/* Kimbie Purple */
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-function {
+ color: #98676a;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #221a0f;
+ color: #d3af86;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/kimbie.light.css b/public/css/highlight/styles/kimbie.light.css
new file mode 100644
index 00000000..04ff6ed3
--- /dev/null
+++ b/public/css/highlight/styles/kimbie.light.css
@@ -0,0 +1,74 @@
+/*
+ Name: Kimbie (light)
+ Author: Jan T. Sott
+ License: Creative Commons Attribution-ShareAlike 4.0 Unported License
+ URL: https://github.com/idleberg/Kimbie-highlight.js
+*/
+
+/* Kimbie Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #a57a4c;
+}
+
+/* Kimbie Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-meta {
+ color: #dc3958;
+}
+
+/* Kimbie Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-deletion,
+.hljs-link {
+ color: #f79a32;
+}
+
+/* Kimbie Yellow */
+.hljs-title,
+.hljs-section,
+.hljs-attribute {
+ color: #f06431;
+}
+
+/* Kimbie Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #889b4a;
+}
+
+/* Kimbie Purple */
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-function {
+ color: #98676a;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #fbebd4;
+ color: #84613d;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/magula.css b/public/css/highlight/styles/magula.css
new file mode 100644
index 00000000..44dee5e8
--- /dev/null
+++ b/public/css/highlight/styles/magula.css
@@ -0,0 +1,70 @@
+/*
+Description: Magula style for highligh.js
+Author: Ruslan Keba
+Website: http://rukeba.com/
+Version: 1.0
+Date: 2009-01-03
+Music: Aphex Twin / Xtal
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background-color: #f4f4f4;
+}
+
+.hljs,
+.hljs-subst {
+ color: black;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #050;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #777;
+}
+
+.hljs-number,
+.hljs-regexp,
+.hljs-literal,
+.hljs-type,
+.hljs-link {
+ color: #800;
+}
+
+.hljs-deletion,
+.hljs-meta {
+ color: #00e;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-built_in,
+.hljs-tag,
+.hljs-name {
+ font-weight: bold;
+ color: navy;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/mono-blue.css b/public/css/highlight/styles/mono-blue.css
new file mode 100644
index 00000000..884c97c7
--- /dev/null
+++ b/public/css/highlight/styles/mono-blue.css
@@ -0,0 +1,59 @@
+/*
+ Five-color theme from a single blue hue.
+*/
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #eaeef3;
+}
+
+.hljs {
+ color: #00193a;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-title,
+.hljs-section,
+.hljs-doctag,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-comment {
+ color: #738191;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-section,
+.hljs-built_in,
+.hljs-literal,
+.hljs-type,
+.hljs-addition,
+.hljs-tag,
+.hljs-quote,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #0048ab;
+}
+
+.hljs-meta,
+.hljs-subst,
+.hljs-symbol,
+.hljs-regexp,
+.hljs-attribute,
+.hljs-deletion,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-link,
+.hljs-bullet {
+ color: #4c81c9;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/monokai-sublime.css b/public/css/highlight/styles/monokai-sublime.css
new file mode 100644
index 00000000..2864170d
--- /dev/null
+++ b/public/css/highlight/styles/monokai-sublime.css
@@ -0,0 +1,83 @@
+/*
+
+Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #23241f;
+}
+
+.hljs,
+.hljs-tag,
+.hljs-subst {
+ color: #f8f8f2;
+}
+
+.hljs-strong,
+.hljs-emphasis {
+ color: #a8a8a2;
+}
+
+.hljs-bullet,
+.hljs-quote,
+.hljs-number,
+.hljs-regexp,
+.hljs-literal,
+.hljs-link {
+ color: #ae81ff;
+}
+
+.hljs-code,
+.hljs-title,
+.hljs-section,
+.hljs-selector-class {
+ color: #a6e22e;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-name,
+.hljs-attr {
+ color: #f92672;
+}
+
+.hljs-symbol,
+.hljs-attribute {
+ color: #66d9ef;
+}
+
+.hljs-params,
+.hljs-class .hljs-title {
+ color: #f8f8f2;
+}
+
+.hljs-string,
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-selector-id,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-variable {
+ color: #e6db74;
+}
+
+.hljs-comment,
+.hljs-deletion,
+.hljs-meta {
+ color: #75715e;
+}
diff --git a/public/css/highlight/styles/monokai.css b/public/css/highlight/styles/monokai.css
new file mode 100644
index 00000000..775d53f9
--- /dev/null
+++ b/public/css/highlight/styles/monokai.css
@@ -0,0 +1,70 @@
+/*
+Monokai style - ported by Luigi Maselli - http://grigio.org
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #272822; color: #ddd;
+}
+
+.hljs-tag,
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-strong,
+.hljs-name {
+ color: #f92672;
+}
+
+.hljs-code {
+ color: #66d9ef;
+}
+
+.hljs-class .hljs-title {
+ color: white;
+}
+
+.hljs-attribute,
+.hljs-symbol,
+.hljs-regexp,
+.hljs-link {
+ color: #bf79db;
+}
+
+.hljs-string,
+.hljs-bullet,
+.hljs-subst,
+.hljs-title,
+.hljs-section,
+.hljs-emphasis,
+.hljs-type,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #a6e22e;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion,
+.hljs-meta {
+ color: #75715e;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-selector-id {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/obsidian.css b/public/css/highlight/styles/obsidian.css
new file mode 100644
index 00000000..356630fa
--- /dev/null
+++ b/public/css/highlight/styles/obsidian.css
@@ -0,0 +1,88 @@
+/**
+ * Obsidian style
+ * ported by Alexander Marenin (http://github.com/ioncreature)
+ */
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #282b2e;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-selector-id {
+ color: #93c763;
+}
+
+.hljs-number {
+ color: #ffcd22;
+}
+
+.hljs {
+ color: #e0e2e4;
+}
+
+.hljs-attribute {
+ color: #668bb0;
+}
+
+.hljs-code,
+.hljs-class .hljs-title,
+.hljs-section {
+ color: white;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #d39745;
+}
+
+.hljs-meta {
+ color: #557182;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-bullet,
+.hljs-subst,
+.hljs-emphasis,
+.hljs-type,
+.hljs-built_in,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable {
+ color: #8cbbad;
+}
+
+.hljs-string,
+.hljs-symbol {
+ color: #ec7600;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion {
+ color: #818e96;
+}
+
+.hljs-selector-class {
+ color: #A082BD
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/paraiso-dark.css b/public/css/highlight/styles/paraiso-dark.css
new file mode 100644
index 00000000..e7292401
--- /dev/null
+++ b/public/css/highlight/styles/paraiso-dark.css
@@ -0,0 +1,72 @@
+/*
+ Paraíso (dark)
+ Created by Jan T. Sott (http://github.com/idleberg)
+ Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
+*/
+
+/* Paraíso Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #8d8687;
+}
+
+/* Paraíso Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-link,
+.hljs-meta {
+ color: #ef6155;
+}
+
+/* Paraíso Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-deletion {
+ color: #f99b15;
+}
+
+/* Paraíso Yellow */
+.hljs-title,
+.hljs-section,
+.hljs-attribute {
+ color: #fec418;
+}
+
+/* Paraíso Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #48b685;
+}
+
+/* Paraíso Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #815ba4;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #2f1e2e;
+ color: #a39e9b;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/paraiso-light.css b/public/css/highlight/styles/paraiso-light.css
new file mode 100644
index 00000000..944857cd
--- /dev/null
+++ b/public/css/highlight/styles/paraiso-light.css
@@ -0,0 +1,72 @@
+/*
+ Paraíso (light)
+ Created by Jan T. Sott (http://github.com/idleberg)
+ Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
+*/
+
+/* Paraíso Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #776e71;
+}
+
+/* Paraíso Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-link,
+.hljs-meta {
+ color: #ef6155;
+}
+
+/* Paraíso Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-deletion {
+ color: #f99b15;
+}
+
+/* Paraíso Yellow */
+.hljs-title,
+.hljs-section,
+.hljs-attribute {
+ color: #fec418;
+}
+
+/* Paraíso Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #48b685;
+}
+
+/* Paraíso Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #815ba4;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #e7e9db;
+ color: #4f424c;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/pojoaque.css b/public/css/highlight/styles/pojoaque.css
new file mode 100644
index 00000000..2e07847b
--- /dev/null
+++ b/public/css/highlight/styles/pojoaque.css
@@ -0,0 +1,83 @@
+/*
+
+Pojoaque Style by Jason Tate
+http://web-cms-designs.com/ftopict-10-pojoaque-style-for-highlight-js-code-highlighter.html
+Based on Solarized Style from http://ethanschoonover.com/solarized
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #dccf8f;
+ background: url(./pojoaque.jpg) repeat scroll left top #181914;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #586e75;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-addition {
+ color: #b64926;
+}
+
+.hljs-number,
+.hljs-string,
+.hljs-doctag,
+.hljs-regexp {
+ color: #468966;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-built_in,
+.hljs-name {
+ color: #ffb03b;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-class .hljs-title,
+.hljs-type,
+.hljs-tag {
+ color: #b58900;
+}
+
+.hljs-attribute {
+ color: #b89859;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-subst,
+.hljs-meta {
+ color: #cb4b16;
+}
+
+.hljs-deletion {
+ color: #dc322f;
+}
+
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #d3a60c;
+}
+
+.hljs-formula {
+ background: #073642;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/pojoaque.jpg b/public/css/highlight/styles/pojoaque.jpg
new file mode 100644
index 00000000..9c07d4ab
Binary files /dev/null and b/public/css/highlight/styles/pojoaque.jpg differ
diff --git a/public/css/highlight/styles/railscasts.css b/public/css/highlight/styles/railscasts.css
new file mode 100644
index 00000000..008cdc5b
--- /dev/null
+++ b/public/css/highlight/styles/railscasts.css
@@ -0,0 +1,106 @@
+/*
+
+Railscasts-like style (c) Visoft, Inc. (Damien White)
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #232323;
+ color: #e6e1dc;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #bc9458;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #c26230;
+}
+
+.hljs-string,
+.hljs-number,
+.hljs-regexp,
+.hljs-variable,
+.hljs-template-variable {
+ color: #a5c261;
+}
+
+.hljs-subst {
+ color: #519f50;
+}
+
+.hljs-tag,
+.hljs-name {
+ color: #e8bf6a;
+}
+
+.hljs-type {
+ color: #da4939;
+}
+
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-attr,
+.hljs-link {
+ color: #6d9cbe;
+}
+
+.hljs-params {
+ color: #d0d0ff;
+}
+
+.hljs-attribute {
+ color: #cda869;
+}
+
+.hljs-meta {
+ color: #9b859d;
+}
+
+.hljs-title,
+.hljs-section {
+ color: #ffc66d;
+}
+
+.hljs-addition {
+ background-color: #144212;
+ color: #e6e1dc;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-deletion {
+ background-color: #600;
+ color: #e6e1dc;
+ display: inline-block;
+ width: 100%;
+}
+
+.hljs-selector-class {
+ color: #9b703f;
+}
+
+.hljs-selector-id {
+ color: #8b98ab;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/public/css/highlight/styles/rainbow.css b/public/css/highlight/styles/rainbow.css
new file mode 100644
index 00000000..905eb8ef
--- /dev/null
+++ b/public/css/highlight/styles/rainbow.css
@@ -0,0 +1,85 @@
+/*
+
+Style with support for rainbow parens
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #474949;
+ color: #d1d9e1;
+}
+
+
+.hljs-comment,
+.hljs-quote {
+ color: #969896;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-type,
+.hljs-addition {
+ color: #cc99cc;
+}
+
+.hljs-number,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+ color: #f99157;
+}
+
+.hljs-string,
+.hljs-doctag,
+.hljs-regexp {
+ color: #8abeb7;
+}
+
+.hljs-title,
+.hljs-name,
+.hljs-section,
+.hljs-built_in {
+ color: #b5bd68;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-selector-id,
+.hljs-class .hljs-title {
+ color: #ffcc66;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-subst,
+.hljs-meta,
+.hljs-link {
+ color: #f99157;
+}
+
+.hljs-deletion {
+ color: #dc322f;
+}
+
+.hljs-formula {
+ background: #eee8d5;
+}
+
+.hljs-attr,
+.hljs-attribute {
+ color: #81a2be;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/school-book.css b/public/css/highlight/styles/school-book.css
new file mode 100644
index 00000000..964b51d8
--- /dev/null
+++ b/public/css/highlight/styles/school-book.css
@@ -0,0 +1,72 @@
+/*
+
+School Book style from goldblog.com.ua (c) Zaripov Yura
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 15px 0.5em 0.5em 30px;
+ font-size: 11px;
+ line-height:16px;
+}
+
+pre{
+ background:#f6f6ae url(./school-book.png);
+ border-top: solid 2px #d2e8b9;
+ border-bottom: solid 1px #d2e8b9;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal {
+ color:#005599;
+ font-weight:bold;
+}
+
+.hljs,
+.hljs-subst {
+ color: #3e5915;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable,
+.hljs-link {
+ color: #2c009f;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-deletion,
+.hljs-meta {
+ color: #e60415;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-name,
+.hljs-selector-id,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/school-book.png b/public/css/highlight/styles/school-book.png
new file mode 100644
index 00000000..956e9790
Binary files /dev/null and b/public/css/highlight/styles/school-book.png differ
diff --git a/public/css/highlight/styles/solarized-dark.css b/public/css/highlight/styles/solarized-dark.css
new file mode 100644
index 00000000..b4c0da1f
--- /dev/null
+++ b/public/css/highlight/styles/solarized-dark.css
@@ -0,0 +1,84 @@
+/*
+
+Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #002b36;
+ color: #839496;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #586e75;
+}
+
+/* Solarized Green */
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-addition {
+ color: #859900;
+}
+
+/* Solarized Cyan */
+.hljs-number,
+.hljs-string,
+.hljs-meta .hljs-meta-string,
+.hljs-literal,
+.hljs-doctag,
+.hljs-regexp {
+ color: #2aa198;
+}
+
+/* Solarized Blue */
+.hljs-title,
+.hljs-section,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #268bd2;
+}
+
+/* Solarized Yellow */
+.hljs-attribute,
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-class .hljs-title,
+.hljs-type {
+ color: #b58900;
+}
+
+/* Solarized Orange */
+.hljs-symbol,
+.hljs-bullet,
+.hljs-subst,
+.hljs-meta,
+.hljs-meta .hljs-keyword,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-link {
+ color: #cb4b16;
+}
+
+/* Solarized Red */
+.hljs-built_in,
+.hljs-deletion {
+ color: #dc322f;
+}
+
+.hljs-formula {
+ background: #073642;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/solarized-light.css b/public/css/highlight/styles/solarized-light.css
new file mode 100644
index 00000000..fdcfcc72
--- /dev/null
+++ b/public/css/highlight/styles/solarized-light.css
@@ -0,0 +1,84 @@
+/*
+
+Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #fdf6e3;
+ color: #657b83;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #93a1a1;
+}
+
+/* Solarized Green */
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-addition {
+ color: #859900;
+}
+
+/* Solarized Cyan */
+.hljs-number,
+.hljs-string,
+.hljs-meta .hljs-meta-string,
+.hljs-literal,
+.hljs-doctag,
+.hljs-regexp {
+ color: #2aa198;
+}
+
+/* Solarized Blue */
+.hljs-title,
+.hljs-section,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #268bd2;
+}
+
+/* Solarized Yellow */
+.hljs-attribute,
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-class .hljs-title,
+.hljs-type {
+ color: #b58900;
+}
+
+/* Solarized Orange */
+.hljs-symbol,
+.hljs-bullet,
+.hljs-subst,
+.hljs-meta,
+.hljs-meta .hljs-keyword,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-link {
+ color: #cb4b16;
+}
+
+/* Solarized Red */
+.hljs-built_in,
+.hljs-deletion {
+ color: #dc322f;
+}
+
+.hljs-formula {
+ background: #eee8d5;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/sunburst.css b/public/css/highlight/styles/sunburst.css
new file mode 100644
index 00000000..f56dd5e9
--- /dev/null
+++ b/public/css/highlight/styles/sunburst.css
@@ -0,0 +1,102 @@
+/*
+
+Sunburst-like style (c) Vasily Polovnyov
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #000;
+ color: #f8f8f8;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #aeaeae;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+ color: #e28964;
+}
+
+.hljs-string {
+ color: #65b042;
+}
+
+.hljs-subst {
+ color: #daefa3;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #e9c062;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-tag,
+.hljs-name {
+ color: #89bdff;
+}
+
+.hljs-class .hljs-title,
+.hljs-doctag {
+ text-decoration: underline;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-number {
+ color: #3387cc;
+}
+
+.hljs-params,
+.hljs-variable,
+.hljs-template-variable {
+ color: #3e87e3;
+}
+
+.hljs-attribute {
+ color: #cda869;
+}
+
+.hljs-meta {
+ color: #8996a8;
+}
+
+.hljs-formula {
+ background-color: #0e2231;
+ color: #f8f8f8;
+ font-style: italic;
+}
+
+.hljs-addition {
+ background-color: #253b22;
+ color: #f8f8f8;
+}
+
+.hljs-deletion {
+ background-color: #420e09;
+ color: #f8f8f8;
+}
+
+.hljs-selector-class {
+ color: #9b703f;
+}
+
+.hljs-selector-id {
+ color: #8b98ab;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/tomorrow-night-blue.css b/public/css/highlight/styles/tomorrow-night-blue.css
new file mode 100644
index 00000000..78e59cc8
--- /dev/null
+++ b/public/css/highlight/styles/tomorrow-night-blue.css
@@ -0,0 +1,75 @@
+/* Tomorrow Night Blue Theme */
+/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
+/* Original theme - https://github.com/chriskempson/tomorrow-theme */
+/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
+
+/* Tomorrow Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #7285b7;
+}
+
+/* Tomorrow Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion {
+ color: #ff9da4;
+}
+
+/* Tomorrow Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link {
+ color: #ffc58f;
+}
+
+/* Tomorrow Yellow */
+.hljs-attribute {
+ color: #ffeead;
+}
+
+/* Tomorrow Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #d1f1a9;
+}
+
+/* Tomorrow Blue */
+.hljs-title,
+.hljs-section {
+ color: #bbdaff;
+}
+
+/* Tomorrow Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #ebbbff;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #002451;
+ color: white;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/tomorrow-night-bright.css b/public/css/highlight/styles/tomorrow-night-bright.css
new file mode 100644
index 00000000..e05af8ae
--- /dev/null
+++ b/public/css/highlight/styles/tomorrow-night-bright.css
@@ -0,0 +1,74 @@
+/* Tomorrow Night Bright Theme */
+/* Original theme - https://github.com/chriskempson/tomorrow-theme */
+/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
+
+/* Tomorrow Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #969896;
+}
+
+/* Tomorrow Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion {
+ color: #d54e53;
+}
+
+/* Tomorrow Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link {
+ color: #e78c45;
+}
+
+/* Tomorrow Yellow */
+.hljs-attribute {
+ color: #e7c547;
+}
+
+/* Tomorrow Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #b9ca4a;
+}
+
+/* Tomorrow Blue */
+.hljs-title,
+.hljs-section {
+ color: #7aa6da;
+}
+
+/* Tomorrow Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #c397d8;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: black;
+ color: #eaeaea;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/tomorrow-night-eighties.css b/public/css/highlight/styles/tomorrow-night-eighties.css
new file mode 100644
index 00000000..08fd51c7
--- /dev/null
+++ b/public/css/highlight/styles/tomorrow-night-eighties.css
@@ -0,0 +1,74 @@
+/* Tomorrow Night Eighties Theme */
+/* Original theme - https://github.com/chriskempson/tomorrow-theme */
+/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
+
+/* Tomorrow Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #999999;
+}
+
+/* Tomorrow Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion {
+ color: #f2777a;
+}
+
+/* Tomorrow Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link {
+ color: #f99157;
+}
+
+/* Tomorrow Yellow */
+.hljs-attribute {
+ color: #ffcc66;
+}
+
+/* Tomorrow Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #99cc99;
+}
+
+/* Tomorrow Blue */
+.hljs-title,
+.hljs-section {
+ color: #6699cc;
+}
+
+/* Tomorrow Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #cc99cc;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #2d2d2d;
+ color: #cccccc;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/tomorrow-night.css b/public/css/highlight/styles/tomorrow-night.css
new file mode 100644
index 00000000..ddd270a4
--- /dev/null
+++ b/public/css/highlight/styles/tomorrow-night.css
@@ -0,0 +1,75 @@
+/* Tomorrow Night Theme */
+/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
+/* Original theme - https://github.com/chriskempson/tomorrow-theme */
+/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
+
+/* Tomorrow Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #969896;
+}
+
+/* Tomorrow Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion {
+ color: #cc6666;
+}
+
+/* Tomorrow Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link {
+ color: #de935f;
+}
+
+/* Tomorrow Yellow */
+.hljs-attribute {
+ color: #f0c674;
+}
+
+/* Tomorrow Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #b5bd68;
+}
+
+/* Tomorrow Blue */
+.hljs-title,
+.hljs-section {
+ color: #81a2be;
+}
+
+/* Tomorrow Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #b294bb;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: #1d1f21;
+ color: #c5c8c6;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/tomorrow.css b/public/css/highlight/styles/tomorrow.css
new file mode 100644
index 00000000..026a62fe
--- /dev/null
+++ b/public/css/highlight/styles/tomorrow.css
@@ -0,0 +1,72 @@
+/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
+
+/* Tomorrow Comment */
+.hljs-comment,
+.hljs-quote {
+ color: #8e908c;
+}
+
+/* Tomorrow Red */
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-regexp,
+.hljs-deletion {
+ color: #c82829;
+}
+
+/* Tomorrow Orange */
+.hljs-number,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-literal,
+.hljs-type,
+.hljs-params,
+.hljs-meta,
+.hljs-link {
+ color: #f5871f;
+}
+
+/* Tomorrow Yellow */
+.hljs-attribute {
+ color: #eab700;
+}
+
+/* Tomorrow Green */
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition {
+ color: #718c00;
+}
+
+/* Tomorrow Blue */
+.hljs-title,
+.hljs-section {
+ color: #4271ae;
+}
+
+/* Tomorrow Purple */
+.hljs-keyword,
+.hljs-selector-tag {
+ color: #8959a8;
+}
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ background: white;
+ color: #4d4d4c;
+ padding: 0.5em;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/vs.css b/public/css/highlight/styles/vs.css
new file mode 100644
index 00000000..c5d07d31
--- /dev/null
+++ b/public/css/highlight/styles/vs.css
@@ -0,0 +1,68 @@
+/*
+
+Visual Studio-like style based on original C# coloring by Jason Diamond
+
+*/
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: white;
+ color: black;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-variable {
+ color: #008000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-built_in,
+.hljs-name,
+.hljs-tag {
+ color: #00f;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-section,
+.hljs-attribute,
+.hljs-literal,
+.hljs-template-tag,
+.hljs-template-variable,
+.hljs-type,
+.hljs-addition {
+ color: #a31515;
+}
+
+.hljs-deletion,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-meta {
+ color: #2b91af;
+}
+
+.hljs-doctag {
+ color: #808080;
+}
+
+.hljs-attr {
+ color: #f00;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link {
+ color: #00b0e8;
+}
+
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/highlight/styles/xcode.css b/public/css/highlight/styles/xcode.css
new file mode 100644
index 00000000..43dddad8
--- /dev/null
+++ b/public/css/highlight/styles/xcode.css
@@ -0,0 +1,93 @@
+/*
+
+XCode style (c) Angel Garcia
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #fff;
+ color: black;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #006a00;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal {
+ color: #aa0d91;
+}
+
+.hljs-name {
+ color: #008;
+}
+
+.hljs-variable,
+.hljs-template-variable {
+ color: #660;
+}
+
+.hljs-string {
+ color: #c41a16;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #080;
+}
+
+.hljs-title,
+.hljs-tag,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-number,
+.hljs-meta {
+ color: #1c00cf;
+}
+
+.hljs-section,
+.hljs-class .hljs-title,
+.hljs-type,
+.hljs-attr,
+.hljs-built_in,
+.hljs-builtin-name,
+.hljs-params {
+ color: #5c2699;
+}
+
+.hljs-attribute,
+.hljs-subst {
+ color: #000;
+}
+
+.hljs-formula {
+ background-color: #eee;
+ font-style: italic;
+}
+
+.hljs-addition {
+ background-color: #baeeba;
+}
+
+.hljs-deletion {
+ background-color: #ffc8bd;
+}
+
+.hljs-selector-id,
+.hljs-selector-class {
+ color: #9b703f;
+}
+
+.hljs-doctag,
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
diff --git a/public/css/highlight/styles/zenburn.css b/public/css/highlight/styles/zenburn.css
new file mode 100644
index 00000000..07be5020
--- /dev/null
+++ b/public/css/highlight/styles/zenburn.css
@@ -0,0 +1,80 @@
+/*
+
+Zenburn style from voldmar.ru (c) Vladimir Epifanov
+based on dark.css by Ivan Sagalaev
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ background: #3f3f3f;
+ color: #dcdcdc;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-tag {
+ color: #e3ceab;
+}
+
+.hljs-template-tag {
+ color: #dcdcdc;
+}
+
+.hljs-number {
+ color: #8cd0d3;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-attribute {
+ color: #efdcbc;
+}
+
+.hljs-literal {
+ color: #efefaf;
+}
+
+.hljs-subst {
+ color: #8f8f8f;
+}
+
+.hljs-title,
+.hljs-name,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-section,
+.hljs-type {
+ color: #efef8f;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link {
+ color: #dca3a3;
+}
+
+.hljs-deletion,
+.hljs-string,
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #cc9393;
+}
+
+.hljs-addition,
+.hljs-comment,
+.hljs-quote,
+.hljs-meta {
+ color: #7f9f7f;
+}
+
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
diff --git a/public/css/neo.css.map b/public/css/neo.css.map
new file mode 100644
index 00000000..c77f028a
--- /dev/null
+++ b/public/css/neo.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "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",
+"sources": ["../../sass/neo.scss","../../sass/_base-sass/_basic.scss","../../sass/_helper-sass/_mixins.scss","../../sass/_base-sass/_base-HTML5.scss","../../sass/_base-sass/_base-Media.scss","../../sass/_project-sass/_project-Vars.scss","../../sass/_base-sass/_typography.scss","../../sass/_base-sass/_type-Code.scss","../../sass/_base-sass/_type-Lists.scss","../../sass/_base-sass/_base-Form.scss","../../sass/_base-sass/_tables.scss","../../sass/_helper-sass/_layout.scss","../../sass/_base-sass/_navs.scss","../../sass/_base-sass/_forms.scss","../../sass/_helper-sass/_buttons.scss","../../sass/_helper-sass/_navs.scss","../../sass/_helper-sass/_helper.scss","../../sass/_helper-sass/_type.scss","../../sass/_project-sass/_project-Type.scss","../../sass/_project-sass/_project-Base.scss","../../sass/_project-sass/_project-Header.scss","../../sass/_project-sass/_project-Main.scss","../../sass/_project-sass/_project-Footer.scss","../../sass/_project-sass/_project-Website-Gallery.scss","../../sass/_project-sass/_project-Tutorial.scss","../../sass/_tidy.scss"],
+"names": [],
+"file": "neo.css"
+}
\ No newline at end of file
diff --git a/public/img/discourse-logo.png b/public/img/discourse-logo.png
new file mode 100644
index 00000000..a0e952f1
Binary files /dev/null and b/public/img/discourse-logo.png differ
diff --git a/public/img/front-browse-screenshot.jpg b/public/img/front-browse-screenshot.jpg
new file mode 100644
index 00000000..5df8119c
Binary files /dev/null and b/public/img/front-browse-screenshot.jpg differ
diff --git a/public/img/front-follow-screenshot.jpg b/public/img/front-follow-screenshot.jpg
new file mode 100644
index 00000000..231dd63f
Binary files /dev/null and b/public/img/front-follow-screenshot.jpg differ
diff --git a/public/img/kickstarterendpenelope.png b/public/img/kickstarterendpenelope.png
new file mode 100644
index 00000000..c2f61c64
Binary files /dev/null and b/public/img/kickstarterendpenelope.png differ
diff --git a/public/img/tutorial/ch1pg1.png b/public/img/tutorial/ch1pg1.png
new file mode 100644
index 00000000..09be5c38
Binary files /dev/null and b/public/img/tutorial/ch1pg1.png differ
diff --git a/public/img/tutorial/ch1pg10.png b/public/img/tutorial/ch1pg10.png
new file mode 100644
index 00000000..485fb02f
Binary files /dev/null and b/public/img/tutorial/ch1pg10.png differ
diff --git a/public/img/tutorial/ch1pg1_2.png b/public/img/tutorial/ch1pg1_2.png
new file mode 100644
index 00000000..62404533
Binary files /dev/null and b/public/img/tutorial/ch1pg1_2.png differ
diff --git a/public/img/tutorial/ch1pg2.png b/public/img/tutorial/ch1pg2.png
new file mode 100644
index 00000000..64b0e3a1
Binary files /dev/null and b/public/img/tutorial/ch1pg2.png differ
diff --git a/public/img/tutorial/ch1pg2_2.png b/public/img/tutorial/ch1pg2_2.png
new file mode 100644
index 00000000..3fbaa935
Binary files /dev/null and b/public/img/tutorial/ch1pg2_2.png differ
diff --git a/public/img/tutorial/ch1pg3.png b/public/img/tutorial/ch1pg3.png
new file mode 100644
index 00000000..5df04e0a
Binary files /dev/null and b/public/img/tutorial/ch1pg3.png differ
diff --git a/public/img/tutorial/ch1pg4.png b/public/img/tutorial/ch1pg4.png
new file mode 100644
index 00000000..dfe9fa81
Binary files /dev/null and b/public/img/tutorial/ch1pg4.png differ
diff --git a/public/img/tutorial/ch1pg5.png b/public/img/tutorial/ch1pg5.png
new file mode 100644
index 00000000..0f369db2
Binary files /dev/null and b/public/img/tutorial/ch1pg5.png differ
diff --git a/public/img/tutorial/ch1pg6.png b/public/img/tutorial/ch1pg6.png
new file mode 100644
index 00000000..71ef3165
Binary files /dev/null and b/public/img/tutorial/ch1pg6.png differ
diff --git a/public/img/tutorial/ch1pg7.png b/public/img/tutorial/ch1pg7.png
new file mode 100644
index 00000000..6620a4e3
Binary files /dev/null and b/public/img/tutorial/ch1pg7.png differ
diff --git a/public/img/tutorial/ch1pg8.png b/public/img/tutorial/ch1pg8.png
new file mode 100644
index 00000000..c20fd57a
Binary files /dev/null and b/public/img/tutorial/ch1pg8.png differ
diff --git a/public/img/tutorial/ch1pg9.png b/public/img/tutorial/ch1pg9.png
new file mode 100644
index 00000000..54d661a3
Binary files /dev/null and b/public/img/tutorial/ch1pg9.png differ
diff --git a/public/js/highlight.pack.js b/public/js/highlight.pack.js
new file mode 100644
index 00000000..6daf8698
--- /dev/null
+++ b/public/js/highlight.pack.js
@@ -0,0 +1,2 @@
+/*! highlight.js v9.0.0 | BSD3 License | git.io/hljslicense */
+!function(e){"undefined"!=typeof exports?e(exports):(self.hljs=e({}),"function"==typeof define&&define.amd&&define("hljs",[],function(){return self.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&").replace(//gm,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){return/^(no-?highlight|plain|text)$/i.test(e)}function i(e){var n,t,r,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=/\blang(?:uage)?-([\w-]+)\b/i.exec(i))return E(t[1])?t[1]:"no-highlight";for(i=i.split(/\s+/),n=0,r=i.length;r>n;n++)if(E(i[n])||a(i[n]))return i[n]}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset"}function u(e){l+=""+t(e)+">"}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);f.reverse().forEach(o)}else"start"==g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\b\w+\b/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function l(e,t,a,i){function o(e,n){for(var t=0;t";return i+=e+'">',i+n+o}function p(){if(!L.k)return n(M);var e="",t=0;L.lR.lastIndex=0;for(var r=L.lR.exec(M);r;){e+=n(M.substr(t,r.index-t));var a=g(L,r);a?(B+=a[1],e+=h(a[0],n(r[0]))):e+=n(r[0]),t=L.lR.lastIndex,r=L.lR.exec(M)}return e+n(M.substr(t))}function d(){var e="string"==typeof L.sL;if(e&&!R[L.sL])return n(M);var t=e?l(L.sL,M,!0,y[L.sL]):f(M,L.sL.length?L.sL:void 0);return L.r>0&&(B+=t.r),e&&(y[L.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){return void 0!==L.sL?d():p()}function v(e,t){var r=e.cN?h(e.cN,"",!0):"";e.rB?(k+=r,M=""):e.eB?(k+=n(t)+r,M=""):(k+=r,M=t),L=Object.create(e,{parent:{value:L}})}function m(e,t){if(M+=e,void 0===t)return k+=b(),0;var r=o(t,L);if(r)return k+=b(),v(r,t),r.rB?0:t.length;var a=u(L,t);if(a){var i=L;i.rE||i.eE||(M+=t),k+=b();do L.cN&&(k+=""),B+=L.r,L=L.parent;while(L!=a.parent);return i.eE&&(k+=n(t)),M="",a.starts&&v(a.starts,""),i.rE?0:t.length}if(c(t,L))throw new Error('Illegal lexeme "'+t+'" for mode "'+(L.cN||"")+'"');return M+=t,t.length||1}var N=E(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var w,L=i||N,y={},k="";for(w=L;w!=N;w=w.parent)w.cN&&(k=h(w.cN,"",!0)+k);var M="",B=0;try{for(var C,j,I=0;;){if(L.t.lastIndex=I,C=L.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),w=L;w.parent;w=w.parent)w.cN&&(k+="");return{r:B,value:k,language:e,top:L}}catch(O){if(-1!=O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function f(e,t){t=t||x.languages||Object.keys(R);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(E(n)){var t=l(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function g(e){return x.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,x.tabReplace)})),x.useBR&&(e=e.replace(/\n/g," ")),e}function h(e,n,t){var r=n?w[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n=i(e);if(!a(n)){var t;x.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/ /g,"\n")):t=e;var r=t.textContent,o=n?l(n,r,!0):f(r),s=u(t);if(s.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=o.value,o.value=c(s,u(p),r)}o.value=g(o.value),e.innerHTML=o.value,e.className=h(e.className,n,o.language),e.result={language:o.language,re:o.r},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.r})}}function d(e){x=o(x,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=R[n]=t(e);r.aliases&&r.aliases.forEach(function(e){w[e]=n})}function N(){return Object.keys(R)}function E(e){return e=(e||"").toLowerCase(),R[e]||R[w[e]]}var x={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},R={},w={};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=E,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e});hljs.registerLanguage("xml",function(s){var t="[A-Za-z0-9\\._:-]+",e={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php"},r={eW:!0,i:/,r:0,c:[e,{cN:"attr",b:t,r:0},{b:"=",r:0,c:[{cN:"string",c:[e],v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s\/>]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},e,{cN:"meta",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},r]}]}});hljs.registerLanguage("php",function(e){var c={b:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},a={cN:"meta",b:/<\?(php)?|\?>/},i={cN:"string",c:[e.BE,a],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},t={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.CLCM,e.HCM,e.C("/\\*","\\*/",{c:[{cN:"doctag",b:"@[A-Za-z]+"},a]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:/<<<['"]?\w+['"]?$/,e:/^\w+;?$/,c:[e.BE,{cN:"subst",v:[{b:/\$\w+/},{b:/\{\$/,e:/\}/}]}]},a,c,{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",c,e.CBCM,i,t]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},i,t]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\s*\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"']+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("python",function(e){var r={cN:"meta",b:/^(>>>|\.\.\.) /},b={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[r],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[r],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},e.ASM,e.QSM]},a={cN:"number",r:0,v:[{b:e.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:e.CNR+"[lLjJ]?"}]},l={cN:"params",b:/\(/,e:/\)/,c:["self",r,a,b]};return{aliases:["py","gyp"],k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[r,a,b,e.HCM,{v:[{cN:"function",bK:"def",r:10},{cN:"class",bK:"class"}],e:/:/,i:/[${=;\n,]/,c:[e.UTM,l]},{cN:"meta",b:/^[\t ]*@/,e:/$/},{b:/\b(print|exec)\(/}]}});hljs.registerLanguage("http",function(e){var t="HTTP/[0-9\\.]+";return{aliases:["https"],i:"\\S",c:[{b:"^"+t,e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{b:"^[A-Z]+ (.*?) "+t+"$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0},{b:t},{cN:"keyword",b:"[A-Z]+"}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{e:"$",r:0}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("json",function(e){var t={literal:"true false null"},i=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:i,k:t},s={b:"{",e:"}",c:[{cN:"attr",b:'\\s*"',e:'"\\s*:\\s*',eB:!0,eE:!0,c:[e.BE],i:"\\n",starts:r}],i:"\\S"},n={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return i.splice(i.length,0,s,n),{c:i,k:t,i:"\\S"}});hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/,e:/>\s*[);\]]/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#/}});hljs.registerLanguage("ruby",function(e){var b="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",c="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",r={cN:"doctag",b:"@[A-Za-z]+"},a={b:"#<",e:">"},s=[e.C("#","$",{c:[r]}),e.C("^\\=begin","^\\=end",{c:[r],r:10}),e.C("^__END__","\\n$")],n={cN:"subst",b:"#\\{",e:"}",k:c},t={cN:"string",c:[e.BE,n],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]},i={cN:"params",b:"\\(",e:"\\)",endsParent:!0,k:c},d=[t,a,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{b:"<\\s*",c:[{b:"("+e.IR+"::)?"+e.IR}]}].concat(s)},{cN:"function",bK:"def",e:"$|;",c:[e.inherit(e.TM,{b:b}),i].concat(s)},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":",c:[t,{b:b}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[a,{cN:"regexp",c:[e.BE,n],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(s),r:0}].concat(s);n.c=d,i.c=d;var o="[>?]>",l="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",w=[{b:/^\s*=>/,starts:{e:"$",c:d}},{cN:"meta",b:"^("+o+"|"+l+"|"+u+")",starts:{e:"$",c:d}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:c,i:/\/\*/,c:s.concat(w).concat(d)}});
\ No newline at end of file
diff --git a/public/js/keyboard.js b/public/js/keyboard.js
deleted file mode 100644
index 5a518d7d..00000000
--- a/public/js/keyboard.js
+++ /dev/null
@@ -1,961 +0,0 @@
-/**
- * Title: KeyboardJS
- * Version: v0.4.1
- * Description: KeyboardJS is a flexible and easy to use keyboard binding
- * library.
- * Author: Robert Hurst.
- *
- * Copyright 2011, Robert William Hurst
- * Licenced under the BSD License.
- * See https://raw.github.com/RobertWHurst/KeyboardJS/master/license.txt
- */
-(function(context, factory) {
-
- //INDEXOF POLLYFILL
- [].indexOf||(Array.prototype.indexOf=function(a,b,c){for(c=this.length,b=(c+~~b)%c;b"]],
- ['shift + /', ["questionmark", "?"]]
- ]
- };
- //a-z and A-Z
- for (aI = 65; aI <= 90; aI += 1) {
- usLocale.map[aI] = String.fromCharCode(aI + 32);
- usLocale.macros.push(['shift + ' + String.fromCharCode(aI + 32) + ', capslock + ' + String.fromCharCode(aI + 32), [String.fromCharCode(aI)]]);
- }
- registerLocale('us', usLocale);
- getSetLocale('us');
-
-
- //////////
- // INIT //
- //////////
-
- //enable the library
- enable();
-
-
- /////////
- // API //
- /////////
-
- //assemble the library and return it
- KeyboardJS.enable = enable;
- KeyboardJS.disable = disable;
- KeyboardJS.activeKeys = getActiveKeys;
- KeyboardJS.releaseKey = removeActiveKey;
- KeyboardJS.pressKey = addActiveKey;
- KeyboardJS.on = createBinding;
- KeyboardJS.clear = removeBindingByKeyCombo;
- KeyboardJS.clear.key = removeBindingByKeyName;
- KeyboardJS.locale = getSetLocale;
- KeyboardJS.locale.register = registerLocale;
- KeyboardJS.macro = createMacro;
- KeyboardJS.macro.remove = removeMacro;
- KeyboardJS.key = {};
- KeyboardJS.key.name = getKeyName;
- KeyboardJS.key.code = getKeyCode;
- KeyboardJS.combo = {};
- KeyboardJS.combo.active = isSatisfiedCombo;
- KeyboardJS.combo.parse = parseKeyCombo;
- KeyboardJS.combo.stringify = stringifyKeyCombo;
- return KeyboardJS;
-
-
- //////////////////////
- // INSTANCE METHODS //
- //////////////////////
-
- /**
- * Enables KeyboardJS
- */
- function enable() {
- if(targetWindow.addEventListener) {
- targetWindow.document.addEventListener('keydown', keydown, false);
- targetWindow.document.addEventListener('keyup', keyup, false);
- targetWindow.addEventListener('blur', reset, false);
- targetWindow.addEventListener('webkitfullscreenchange', reset, false);
- targetWindow.addEventListener('mozfullscreenchange', reset, false);
- } else if(targetWindow.attachEvent) {
- targetWindow.document.attachEvent('onkeydown', keydown);
- targetWindow.document.attachEvent('onkeyup', keyup);
- targetWindow.attachEvent('onblur', reset);
- }
- }
-
- /**
- * Exits all active bindings and disables KeyboardJS
- */
- function disable() {
- reset();
- if(targetWindow.removeEventListener) {
- targetWindow.document.removeEventListener('keydown', keydown, false);
- targetWindow.document.removeEventListener('keyup', keyup, false);
- targetWindow.removeEventListener('blur', reset, false);
- targetWindow.removeEventListener('webkitfullscreenchange', reset, false);
- targetWindow.removeEventListener('mozfullscreenchange', reset, false);
- } else if(targetWindow.detachEvent) {
- targetWindow.document.detachEvent('onkeydown', keydown);
- targetWindow.document.detachEvent('onkeyup', keyup);
- targetWindow.detachEvent('onblur', reset);
- }
- }
-
-
- ////////////////////
- // EVENT HANDLERS //
- ////////////////////
-
- /**
- * Exits all active bindings. Optionally passes an event to all binding
- * handlers.
- * @param {KeyboardEvent} event [Optional]
- */
- function reset(event) {
- activeKeys = [];
- pruneMacros();
- pruneBindings(event);
- }
-
- /**
- * Key down event handler.
- * @param {KeyboardEvent} event
- */
- function keydown(event) {
- var keyNames, keyName, kI;
- keyNames = getKeyName(event.keyCode);
- if(keyNames.length < 1) { return; }
- event.isRepeat = false;
- for(kI = 0; kI < keyNames.length; kI += 1) {
- keyName = keyNames[kI];
- if (getActiveKeys().indexOf(keyName) != -1)
- event.isRepeat = true;
- addActiveKey(keyName);
- }
- executeMacros();
- executeBindings(event);
- }
-
- /**
- * Key up event handler.
- * @param {KeyboardEvent} event
- */
- function keyup(event) {
- var keyNames, kI;
- keyNames = getKeyName(event.keyCode);
- if(keyNames.length < 1) { return; }
- for(kI = 0; kI < keyNames.length; kI += 1) {
- removeActiveKey(keyNames[kI]);
- }
- pruneMacros();
- pruneBindings(event);
- }
-
- /**
- * Accepts a key code and returns the key names defined by the current
- * locale.
- * @param {Number} keyCode
- * @return {Array} keyNames An array of key names defined for the key
- * code as defined by the current locale.
- */
- function getKeyName(keyCode) {
- return map[keyCode] || [];
- }
-
- /**
- * Accepts a key name and returns the key code defined by the current
- * locale.
- * @param {Number} keyName
- * @return {Number|false}
- */
- function getKeyCode(keyName) {
- var keyCode;
- for(keyCode in map) {
- if(!map.hasOwnProperty(keyCode)) { continue; }
- if(map[keyCode].indexOf(keyName) > -1) { return keyCode; }
- }
- return false;
- }
-
-
- ////////////
- // MACROS //
- ////////////
-
- /**
- * Accepts a key combo and an array of key names to inject once the key
- * combo is satisfied.
- * @param {String} combo
- * @param {Array} injectedKeys
- */
- function createMacro(combo, injectedKeys) {
- if(typeof combo !== 'string' && (typeof combo !== 'object' || typeof combo.push !== 'function')) {
- throw new Error("Cannot create macro. The combo must be a string or array.");
- }
- if(typeof injectedKeys !== 'object' || typeof injectedKeys.push !== 'function') {
- throw new Error("Cannot create macro. The injectedKeys must be an array.");
- }
- macros.push([combo, injectedKeys]);
- }
-
- /**
- * Accepts a key combo and clears any and all macros bound to that key
- * combo.
- * @param {String} combo
- */
- function removeMacro(combo) {
- var macro;
- if(typeof combo !== 'string' && (typeof combo !== 'object' || typeof combo.push !== 'function')) { throw new Error("Cannot remove macro. The combo must be a string or array."); }
- for(mI = 0; mI < macros.length; mI += 1) {
- macro = macros[mI];
- if(compareCombos(combo, macro[0])) {
- removeActiveKey(macro[1]);
- macros.splice(mI, 1);
- break;
- }
- }
- }
-
- /**
- * Executes macros against the active keys. Each macro's key combo is
- * checked and if found to be satisfied, the macro's key names are injected
- * into active keys.
- */
- function executeMacros() {
- var mI, combo, kI;
- for(mI = 0; mI < macros.length; mI += 1) {
- combo = parseKeyCombo(macros[mI][0]);
- if(activeMacros.indexOf(macros[mI]) === -1 && isSatisfiedCombo(combo)) {
- activeMacros.push(macros[mI]);
- for(kI = 0; kI < macros[mI][1].length; kI += 1) {
- addActiveKey(macros[mI][1][kI]);
- }
- }
- }
- }
-
- /**
- * Prunes active macros. Checks each active macro's key combo and if found
- * to no longer to be satisfied, each of the macro's key names are removed
- * from active keys.
- */
- function pruneMacros() {
- var mI, combo, kI;
- for(mI = 0; mI < activeMacros.length; mI += 1) {
- combo = parseKeyCombo(activeMacros[mI][0]);
- if(isSatisfiedCombo(combo) === false) {
- for(kI = 0; kI < activeMacros[mI][1].length; kI += 1) {
- removeActiveKey(activeMacros[mI][1][kI]);
- }
- activeMacros.splice(mI, 1);
- mI -= 1;
- }
- }
- }
-
-
- //////////////
- // BINDINGS //
- //////////////
-
- /**
- * Creates a binding object, and, if provided, binds a key down hander and
- * a key up handler. Returns a binding object that emits keyup and
- * keydown events.
- * @param {String} keyCombo
- * @param {Function} keyDownCallback [Optional]
- * @param {Function} keyUpCallback [Optional]
- * @return {Object} binding
- */
- function createBinding(keyCombo, keyDownCallback, keyUpCallback) {
- var api = {}, binding, subBindings = [], bindingApi = {}, kI,
- subCombo;
-
- //break the combo down into a combo array
- if(typeof keyCombo === 'string') {
- keyCombo = parseKeyCombo(keyCombo);
- }
-
- //bind each sub combo contained within the combo string
- for(kI = 0; kI < keyCombo.length; kI += 1) {
- binding = {};
-
- //stringify the combo again
- subCombo = stringifyKeyCombo([keyCombo[kI]]);
-
- //validate the sub combo
- if(typeof subCombo !== 'string') { throw new Error('Failed to bind key combo. The key combo must be string.'); }
-
- //create the binding
- binding.keyCombo = subCombo;
- binding.keyDownCallback = [];
- binding.keyUpCallback = [];
-
- //inject the key down and key up callbacks if given
- if(keyDownCallback) { binding.keyDownCallback.push(keyDownCallback); }
- if(keyUpCallback) { binding.keyUpCallback.push(keyUpCallback); }
-
- //stash the new binding
- bindings.push(binding);
- subBindings.push(binding);
- }
-
- //build the binding api
- api.clear = clear;
- api.on = on;
- return api;
-
- /**
- * Clears the binding
- */
- function clear() {
- var bI;
- for(bI = 0; bI < subBindings.length; bI += 1) {
- bindings.splice(bindings.indexOf(subBindings[bI]), 1);
- }
- }
-
- /**
- * Accepts an event name. and any number of callbacks. When the event is
- * emitted, all callbacks are executed. Available events are key up and
- * key down.
- * @param {String} eventName
- * @return {Object} subBinding
- */
- function on(eventName ) {
- var api = {}, callbacks, cI, bI;
-
- //validate event name
- if(typeof eventName !== 'string') { throw new Error('Cannot bind callback. The event name must be a string.'); }
- if(eventName !== 'keyup' && eventName !== 'keydown') { throw new Error('Cannot bind callback. The event name must be a "keyup" or "keydown".'); }
-
- //gather the callbacks
- callbacks = Array.prototype.slice.apply(arguments, [1]);
-
- //stash each the new binding
- for(cI = 0; cI < callbacks.length; cI += 1) {
- if(typeof callbacks[cI] === 'function') {
- if(eventName === 'keyup') {
- for(bI = 0; bI < subBindings.length; bI += 1) {
- subBindings[bI].keyUpCallback.push(callbacks[cI]);
- }
- } else if(eventName === 'keydown') {
- for(bI = 0; bI < subBindings.length; bI += 1) {
- subBindings[bI].keyDownCallback.push(callbacks[cI]);
- }
- }
- }
- }
-
- //construct and return the sub binding api
- api.clear = clear;
- return api;
-
- /**
- * Clears the binding
- */
- function clear() {
- var cI, bI;
- for(cI = 0; cI < callbacks.length; cI += 1) {
- if(typeof callbacks[cI] === 'function') {
- if(eventName === 'keyup') {
- for(bI = 0; bI < subBindings.length; bI += 1) {
- subBindings[bI].keyUpCallback.splice(subBindings[bI].keyUpCallback.indexOf(callbacks[cI]), 1);
- }
- } else {
- for(bI = 0; bI < subBindings.length; bI += 1) {
- subBindings[bI].keyDownCallback.splice(subBindings[bI].keyDownCallback.indexOf(callbacks[cI]), 1);
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Clears all binding attached to a given key combo. Key name order does not
- * matter as long as the key combos equate.
- * @param {String} keyCombo
- */
- function removeBindingByKeyCombo(keyCombo) {
- var bI, binding, keyName;
- for(bI = 0; bI < bindings.length; bI += 1) {
- binding = bindings[bI];
- if(compareCombos(keyCombo, binding.keyCombo)) {
- bindings.splice(bI, 1); bI -= 1;
- }
- }
- }
-
- /**
- * Clears all binding attached to key combos containing a given key name.
- * @param {String} keyName
- */
- function removeBindingByKeyName(keyName) {
- var bI, kI, binding;
- if(keyName) {
- for(bI = 0; bI < bindings.length; bI += 1) {
- binding = bindings[bI];
- for(kI = 0; kI < binding.keyCombo.length; kI += 1) {
- if(binding.keyCombo[kI].indexOf(keyName) > -1) {
- bindings.splice(bI, 1); bI -= 1;
- break;
- }
- }
- }
- } else {
- bindings = [];
- }
- }
-
- /**
- * Executes bindings that are active. Only allows the keys to be used once
- * as to prevent binding overlap.
- * @param {KeyboardEvent} event The keyboard event.
- */
- function executeBindings(event) {
- var bI, sBI, binding, bindingKeys, remainingKeys, cI, killEventBubble, kI, bindingKeysSatisfied,
- index, sortedBindings = [], bindingWeight;
-
- remainingKeys = [].concat(activeKeys);
- for(bI = 0; bI < bindings.length; bI += 1) {
- bindingWeight = extractComboKeys(bindings[bI].keyCombo).length;
- if(!sortedBindings[bindingWeight]) { sortedBindings[bindingWeight] = []; }
- sortedBindings[bindingWeight].push(bindings[bI]);
- }
- for(sBI = sortedBindings.length - 1; sBI >= 0; sBI -= 1) {
- if(!sortedBindings[sBI]) { continue; }
- for(bI = 0; bI < sortedBindings[sBI].length; bI += 1) {
- binding = sortedBindings[sBI][bI];
- bindingKeys = extractComboKeys(binding.keyCombo);
- bindingKeysSatisfied = true;
- for(kI = 0; kI < bindingKeys.length; kI += 1) {
- if(remainingKeys.indexOf(bindingKeys[kI]) === -1) {
- bindingKeysSatisfied = false;
- break;
- }
- }
- if(bindingKeysSatisfied && isSatisfiedCombo(binding.keyCombo)) {
- activeBindings.push(binding);
- for(kI = 0; kI < bindingKeys.length; kI += 1) {
- index = remainingKeys.indexOf(bindingKeys[kI]);
- if(index > -1) {
- remainingKeys.splice(index, 1);
- kI -= 1;
- }
- }
- for(cI = 0; cI < binding.keyDownCallback.length; cI += 1) {
- if (binding.keyDownCallback[cI](event, getActiveKeys(), binding.keyCombo) === false) {
- killEventBubble = true;
- }
- }
- if(killEventBubble === true) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- }
- }
-
- /**
- * Removes bindings that are no longer satisfied by the active keys. Also
- * fires the key up callbacks.
- * @param {KeyboardEvent} event
- */
- function pruneBindings(event) {
- var bI, cI, binding, killEventBubble;
- for(bI = 0; bI < activeBindings.length; bI += 1) {
- binding = activeBindings[bI];
- if(isSatisfiedCombo(binding.keyCombo) === false) {
- for(cI = 0; cI < binding.keyUpCallback.length; cI += 1) {
- if (binding.keyUpCallback[cI](event, getActiveKeys(), binding.keyCombo) === false) {
- killEventBubble = true;
- }
- }
- if(killEventBubble === true) {
- event.preventDefault();
- event.stopPropagation();
- }
- activeBindings.splice(bI, 1);
- bI -= 1;
- }
- }
- }
-
-
- ///////////////////
- // COMBO STRINGS //
- ///////////////////
-
- /**
- * Compares two key combos returning true when they are functionally
- * equivalent.
- * @param {String} keyComboArrayA keyCombo A key combo string or array.
- * @param {String} keyComboArrayB keyCombo A key combo string or array.
- * @return {Boolean}
- */
- function compareCombos(keyComboArrayA, keyComboArrayB) {
- var cI, sI, kI;
- keyComboArrayA = parseKeyCombo(keyComboArrayA);
- keyComboArrayB = parseKeyCombo(keyComboArrayB);
- if(keyComboArrayA.length !== keyComboArrayB.length) { return false; }
- for(cI = 0; cI < keyComboArrayA.length; cI += 1) {
- if(keyComboArrayA[cI].length !== keyComboArrayB[cI].length) { return false; }
- for(sI = 0; sI < keyComboArrayA[cI].length; sI += 1) {
- if(keyComboArrayA[cI][sI].length !== keyComboArrayB[cI][sI].length) { return false; }
- for(kI = 0; kI < keyComboArrayA[cI][sI].length; kI += 1) {
- if(keyComboArrayB[cI][sI].indexOf(keyComboArrayA[cI][sI][kI]) === -1) { return false; }
- }
- }
- }
- return true;
- }
-
- /**
- * Checks to see if a key combo string or key array is satisfied by the
- * currently active keys. It does not take into account spent keys.
- * @param {String} keyCombo A key combo string or array.
- * @return {Boolean}
- */
- function isSatisfiedCombo(keyCombo) {
- var cI, sI, stage, kI, stageOffset = 0, index, comboMatches;
- keyCombo = parseKeyCombo(keyCombo);
- for(cI = 0; cI < keyCombo.length; cI += 1) {
- comboMatches = true;
- stageOffset = 0;
- for(sI = 0; sI < keyCombo[cI].length; sI += 1) {
- stage = [].concat(keyCombo[cI][sI]);
- for(kI = stageOffset; kI < activeKeys.length; kI += 1) {
- index = stage.indexOf(activeKeys[kI]);
- if(index > -1) {
- stage.splice(index, 1);
- stageOffset = kI;
- }
- }
- if(stage.length !== 0) { comboMatches = false; break; }
- }
- if(comboMatches) { return true; }
- }
- return false;
- }
-
- /**
- * Accepts a key combo array or string and returns a flat array containing all keys referenced by
- * the key combo.
- * @param {String} keyCombo A key combo string or array.
- * @return {Array}
- */
- function extractComboKeys(keyCombo) {
- var cI, sI, kI, keys = [];
- keyCombo = parseKeyCombo(keyCombo);
- for(cI = 0; cI < keyCombo.length; cI += 1) {
- for(sI = 0; sI < keyCombo[cI].length; sI += 1) {
- keys = keys.concat(keyCombo[cI][sI]);
- }
- }
- return keys;
- }
-
- /**
- * Parses a key combo string into a 3 dimensional array.
- * - Level 1 - sub combos.
- * - Level 2 - combo stages. A stage is a set of key name pairs that must
- * be satisfied in the order they are defined.
- * - Level 3 - each key name to the stage.
- * @param {String|Array} keyCombo A key combo string.
- * @return {Array}
- */
- function parseKeyCombo(keyCombo) {
- var s = keyCombo, i = 0, op = 0, ws = false, nc = false, combos = [], combo = [], stage = [], key = '';
-
- if(typeof keyCombo === 'object' && typeof keyCombo.push === 'function') { return keyCombo; }
- if(typeof keyCombo !== 'string') { throw new Error('Cannot parse "keyCombo" because its type is "' + (typeof keyCombo) + '". It must be a "string".'); }
-
- //remove leading whitespace
- while(s.charAt(i) === ' ') { i += 1; }
- while(true) {
- if(s.charAt(i) === ' ') {
- //white space & next combo op
- while(s.charAt(i) === ' ') { i += 1; }
- ws = true;
- } else if(s.charAt(i) === ',') {
- if(op || nc) { throw new Error('Failed to parse key combo. Unexpected , at character index ' + i + '.'); }
- nc = true;
- i += 1;
- } else if(s.charAt(i) === '+') {
- //next key
- if(key.length) { stage.push(key); key = ''; }
- if(op || nc) { throw new Error('Failed to parse key combo. Unexpected + at character index ' + i + '.'); }
- op = true;
- i += 1;
- } else if(s.charAt(i) === '>') {
- //next stage op
- if(key.length) { stage.push(key); key = ''; }
- if(stage.length) { combo.push(stage); stage = []; }
- if(op || nc) { throw new Error('Failed to parse key combo. Unexpected > at character index ' + i + '.'); }
- op = true;
- i += 1;
- } else if(i < s.length - 1 && s.charAt(i) === '!' && (s.charAt(i + 1) === '>' || s.charAt(i + 1) === ',' || s.charAt(i + 1) === '+')) {
- key += s.charAt(i + 1);
- op = false;
- ws = false;
- nc = false;
- i += 2;
- } else if(i < s.length && s.charAt(i) !== '+' && s.charAt(i) !== '>' && s.charAt(i) !== ',' && s.charAt(i) !== ' ') {
- //end combo
- if(op === false && ws === true || nc === true) {
- if(key.length) { stage.push(key); key = ''; }
- if(stage.length) { combo.push(stage); stage = []; }
- if(combo.length) { combos.push(combo); combo = []; }
- }
- op = false;
- ws = false;
- nc = false;
- //key
- while(i < s.length && s.charAt(i) !== '+' && s.charAt(i) !== '>' && s.charAt(i) !== ',' && s.charAt(i) !== ' ') {
- key += s.charAt(i);
- i += 1;
- }
- } else {
- //unknown char
- i += 1;
- continue;
- }
- //end of combos string
- if(i >= s.length) {
- if(key.length) { stage.push(key); key = ''; }
- if(stage.length) { combo.push(stage); stage = []; }
- if(combo.length) { combos.push(combo); combo = []; }
- break;
- }
- }
- return combos;
- }
-
- /**
- * Stringifys a key combo.
- * @param {Array|String} keyComboArray A key combo array. If a key
- * combo string is given it will be returned.
- * @return {String}
- */
- function stringifyKeyCombo(keyComboArray) {
- var cI, ccI, output = [];
- if(typeof keyComboArray === 'string') { return keyComboArray; }
- if(typeof keyComboArray !== 'object' || typeof keyComboArray.push !== 'function') { throw new Error('Cannot stringify key combo.'); }
- for(cI = 0; cI < keyComboArray.length; cI += 1) {
- output[cI] = [];
- for(ccI = 0; ccI < keyComboArray[cI].length; ccI += 1) {
- output[cI][ccI] = keyComboArray[cI][ccI].join(' + ');
- }
- output[cI] = output[cI].join(' > ');
- }
- return output.join(' ');
- }
-
-
- /////////////////
- // ACTIVE KEYS //
- /////////////////
-
- /**
- * Returns the a copy of the active keys array.
- * @return {Array}
- */
- function getActiveKeys() {
- return [].concat(activeKeys);
- }
-
- /**
- * Adds a key to the active keys array, but only if it has not already been
- * added.
- * @param {String} keyName The key name string.
- */
- function addActiveKey(keyName) {
- if(keyName.match(/\s/)) { throw new Error('Cannot add key name ' + keyName + ' to active keys because it contains whitespace.'); }
- if(activeKeys.indexOf(keyName) > -1) { return; }
- activeKeys.push(keyName);
- }
-
- /**
- * Removes a key from the active keys array.
- * @param {String} keyNames The key name string.
- */
- function removeActiveKey(keyName) {
- var keyCode = getKeyCode(keyName);
- if(keyCode === '91' || keyCode === '92') { activeKeys = []; } //remove all key on release of super.
- else { activeKeys.splice(activeKeys.indexOf(keyName), 1); }
- }
-
-
- /////////////
- // LOCALES //
- /////////////
-
- /**
- * Registers a new locale. This is useful if you would like to add support for a new keyboard layout. It could also be useful for
- * alternative key names. For example if you program games you could create a locale for your key mappings. Instead of key 65 mapped
- * to 'a' you could map it to 'jump'.
- * @param {String} localeName The name of the new locale.
- * @param {Object} localeMap The locale map.
- */
- function registerLocale(localeName, localeMap) {
-
- //validate arguments
- if(typeof localeName !== 'string') { throw new Error('Cannot register new locale. The locale name must be a string.'); }
- if(typeof localeMap !== 'object') { throw new Error('Cannot register ' + localeName + ' locale. The locale map must be an object.'); }
- if(typeof localeMap.map !== 'object') { throw new Error('Cannot register ' + localeName + ' locale. The locale map is invalid.'); }
-
- //stash the locale
- if(!localeMap.macros) { localeMap.macros = []; }
- locales[localeName] = localeMap;
- }
-
- /**
- * Swaps the current locale.
- * @param {String} localeName The locale to activate.
- * @return {Object}
- */
- function getSetLocale(localeName) {
-
- //if a new locale is given then set it
- if(localeName) {
- if(typeof localeName !== 'string') { throw new Error('Cannot set locale. The locale name must be a string.'); }
- if(!locales[localeName]) { throw new Error('Cannot set locale to ' + localeName + ' because it does not exist. If you would like to submit a ' + localeName + ' locale map for KeyboardJS please submit it at https://github.com/RobertWHurst/KeyboardJS/issues.'); }
-
- //set the current map and macros
- map = locales[localeName].map;
- macros = locales[localeName].macros;
-
- //set the current locale
- locale = localeName;
- }
-
- //return the current locale
- return locale;
- }
-});
diff --git a/public/js/xregexp-min.js b/public/js/xregexp-min.js
new file mode 100644
index 00000000..ade6f9a3
--- /dev/null
+++ b/public/js/xregexp-min.js
@@ -0,0 +1,2 @@
+//XRegExp 3.0.0 MIT License
+var XRegExp=function(a){"use strict";function u(a,d,e,f,g){var h;if(a[c]={captureNames:d},g)return a;if(a.__proto__)a.__proto__=b.prototype;else for(h in b.prototype)a[h]=b.prototype[h];return a[c].source=e,a[c].flags=f?f.split("").sort().join(""):f,a}function v(a){return e.replace.call(a,/([\s\S])(?=[\s\S]*\1)/g,"")}function w(d,f){if(!b.isRegExp(d))throw new TypeError("Type RegExp expected");var g=d[c]||{},h=y(d),i="",j="",k=null,l=null;return f=f||{},f.removeG&&(j+="g"),f.removeY&&(j+="y"),j&&(h=e.replace.call(h,new RegExp("["+j+"]+","g"),"")),f.addG&&(i+="g"),f.addY&&(i+="y"),i&&(h=v(h+i)),f.isInternalOnly||(g.source!==a&&(k=g.source),null!=g.flags&&(l=i?v(g.flags+i):g.flags)),d=u(new RegExp(d.source,h),z(d)?g.captureNames.slice(0):null,k,l,f.isInternalOnly)}function x(a){return parseInt(a,16)}function y(a){return q?a.flags:e.exec.call(/\/([a-z]*)$/i,RegExp.prototype.toString.call(a))[1]}function z(a){return!(!a[c]||!a[c].captureNames)}function A(a){return parseInt(a,10).toString(16)}function B(a,b){var d,c=a.length;for(d=0;c>d;++d)if(a[d]===b)return d;return-1}function C(a,b){return s.call(a)==="[object "+b+"]"}function D(a,b,c){return e.test.call(c.indexOf("x")>-1?/^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/:/^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,a.slice(b))}function E(a){for(;a.length<4;)a="0"+a;return a}function F(a,b){var c;if(v(b)!==b)throw new SyntaxError("Invalid duplicate regex flag "+b);for(a=e.replace.call(a,/^\(\?([\w$]+)\)/,function(a,c){if(e.test.call(/[gy]/,c))throw new SyntaxError("Cannot use flag g or y in mode modifier "+a);return b=v(b+c),""}),c=0;c"}else if(c)return"\\"+(+c+i);return a};if(!C(a,"Array")||!a.length)throw new TypeError("Must provide a nonempty array of patterns to merge");for(m=0;m1&&B(f,"")>-1&&(h=w(this,{removeG:!0,isInternalOnly:!0}),e.replace.call(String(b).slice(f.index),h,function(){var c,b=arguments.length;for(c=1;b-2>c;++c)arguments[c]===a&&(f[c]=a)})),this[c]&&this[c].captureNames)for(i=1;if.index&&(this.lastIndex=f.index)}return this.global||(this.lastIndex=d),f},f.test=function(a){return!!f.exec.call(this,a)},f.match=function(a){var c;if(b.isRegExp(a)){if(a.global)return c=e.match.apply(this,arguments),a.lastIndex=0,c}else a=new RegExp(a);return f.exec.call(a,L(this))},f.replace=function(d,f){var h,i,j,g=b.isRegExp(d);return g?(d[c]&&(i=d[c].captureNames),h=d.lastIndex):d+="",j=C(f,"Function")?e.replace.call(String(this),d,function(){var c,b=arguments;if(i)for(b[0]=new String(b[0]),c=0;ce)throw new SyntaxError("Backreference to undefined group "+b);return a[e+1]||""}if("$"===d)return"$";if("&"===d||0===+d)return a[0];if("`"===d)return a[a.length-1].slice(0,a[a.length-2]);if("'"===d)return a[a.length-1].slice(a[a.length-2]+a[0].length);if(d=+d,!isNaN(d)){if(d>a.length-3)throw new SyntaxError("Backreference to undefined group "+b);return a[d]||""}throw new SyntaxError("Invalid token "+b)})}),g&&(d.global?d.lastIndex=0:d.lastIndex=h),j},f.split=function(c,d){if(!b.isRegExp(c))return e.split.apply(this,arguments);var j,f=String(this),g=[],h=c.lastIndex,i=0;return d=(d===a?-1:d)>>>0,b.forEach(f,c,function(a){a.index+a[0].length>i&&(g.push(f.slice(i,a.index)),a.length>1&&a.indexd?g.slice(0,d):g},t=b.addToken,t(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/,function(a,b){if("B"===a[1]&&b===j)return a[0];throw new SyntaxError("Invalid escape "+a[0])},{scope:"all",leadChar:"\\"}),t(/\\u{([\dA-Fa-f]+)}/,function(a,b,c){var d=x(a[1]);if(d>1114111)throw new SyntaxError("Invalid Unicode code point "+a[0]);if(65535>=d)return"\\u"+E(A(d));if(o&&c.indexOf("u")>-1)return a[0];throw new SyntaxError("Cannot use Unicode code point above \\u{FFFF} without flag u")},{scope:"all",leadChar:"\\"}),t(/\[(\^?)]/,function(a){return a[1]?"[\\s\\S]":"\\b\\B"},{leadChar:"["}),t(/\(\?#[^)]*\)/,function(a,b,c){return D(a.input,a.index+a[0].length,c)?"":"(?:)"},{leadChar:"("}),t(/\s+|#.*/,function(a,b,c){return D(a.input,a.index+a[0].length,c)?"":"(?:)"},{flag:"x"}),t(/\./,function(){return"[\\s\\S]"},{flag:"s",leadChar:"."}),t(/\\k<([\w$]+)>/,function(a){var b=isNaN(a[1])?B(this.captureNames,a[1])+1:+a[1],c=a.index+a[0].length;if(!b||b>this.captureNames.length)throw new SyntaxError("Backreference to undefined group "+a[0]);return"\\"+b+(c===a.input.length||isNaN(a.input.charAt(c))?"":"(?:)")},{leadChar:"\\"}),t(/\\(\d+)/,function(a,b){if(!(b===j&&/^[1-9]/.test(a[1])&&+a[1]<=this.captureNames.length)&&"0"!==a[1])throw new SyntaxError("Cannot use octal escape or backreference to undefined group "+a[0]);return a[0]},{scope:"all",leadChar:"\\"}),t(/\(\?P?<([\w$]+)>/,function(a){if(!isNaN(a[1]))throw new SyntaxError("Cannot use integer as capture name "+a[0]);if("length"===a[1]||"__proto__"===a[1])throw new SyntaxError("Cannot use reserved word as capture name "+a[0]);if(B(this.captureNames,a[1])>-1)throw new SyntaxError("Cannot use same name for multiple groups "+a[0]);return this.captureNames.push(a[1]),this.hasNamedCapture=!0,"("},{leadChar:"("}),t(/\((?!\?)/,function(a,b,c){return c.indexOf("n")>-1?"(?:":(this.captureNames.push(null),"(")},{optionalFlags:"n",leadChar:"("}),b}();
\ No newline at end of file
diff --git a/puma_config.rb b/puma_config.rb
new file mode 100644
index 00000000..5fb01d68
--- /dev/null
+++ b/puma_config.rb
@@ -0,0 +1,28 @@
+def processor_count
+ case RbConfig::CONFIG['host_os']
+ when /darwin9/
+ `hwprefs cpu_count`.to_i
+ when /darwin/
+ ((`which hwprefs` != '') ? `hwprefs thread_count` : `sysctl -n hw.ncpu`).to_i
+ when /linux/
+ `cat /proc/cpuinfo | grep processor | wc -l`.to_i
+ when /freebsd/
+ `sysctl -n hw.ncpu`.to_i
+ when /mswin|mingw/
+ require 'win32ole'
+ wmi = WIN32OLE.connect("winmgmts://")
+ cpu = wmi.ExecQuery("select NumberOfCores from Win32_Processor") # TODO count hyper-threaded in this
+ cpu.to_enum.first.NumberOfCores
+ end
+end
+
+environment 'production'
+daemonize
+pidfile '/var/run/neocities/neocities.pid'
+stdout_redirect '/var/log/neocities/neocities.log', '/var/log/neocities/neocities-errors.log', true
+quiet
+workers processor_count
+worker_timeout 600
+preload_app!
+on_worker_boot { DB.disconnect }
+bind 'unix:/var/run/neocities/neocities.sock?backlog=2048'
diff --git a/sass/_project-sass/_project-Main.scss b/sass/_project-sass/_project-Main.scss
index 9054be9a..8bc6a24f 100644
--- a/sass/_project-sass/_project-Main.scss
+++ b/sass/_project-sass/_project-Main.scss
@@ -42,6 +42,10 @@
.interior .header-Outro h1 {
font-size: 2.5em;
margin-top: 15px;
+
+ a {
+ color: white;
+ }
}
.news-site-info {
@media (max-device-width:480px), screen and (max-width:800px) {
@@ -127,15 +131,30 @@
font-weight: normal;
font-size: 12px;
padding: 7px 15px;
-
- @media (max-device-width:480px), screen and (max-width:800px) {
- margin: 6px 0px 8px;
- }
}
.row.content {
margin-left: 6%;
margin-right: 6%;
}
+ @media (max-device-width:480px), screen and (max-width:800px) {
+ .signup-Area {
+ display: none;
+ }
+ ul {
+ display: none;
+ }
+ .row.content.wide {
+ margin: 0;
+ padding-top: 13px;
+ padding-bottom: 10px;
+ }
+ .btn-Action {
+ margin: 6px 4px 8px;
+ }
+ .site-url {
+ margin-top: -13px;
+ }
+ }
}
.interior .header-Outro a {color:#E93250}
.interior .header-Outro .btn-Action {color:#fff}
@@ -168,7 +187,7 @@
@media (max-device-width:480px), screen and (max-width:800px) {
width: 100%;
- height: 300px;
+ height: 200px;
}
}
.interior .header-Outro .screenshot.dashboard {
@@ -205,8 +224,8 @@
float: left;
@media (max-device-width: 480px), screen and (max-width: 800px) {
- margin-left: 22px;
- margin-top: 18px;
+ margin-left: 0px;
+ margin-top: 16px;
}
}
.welcome {
@@ -237,6 +256,48 @@
width: 100%;
position: relative;
margin-top: 7px;
+
+ .column, input[type='checkbox'] {
+ display: none;
+ }
+
+ .btn-group {
+ float: left;
+ margin-right: 15px;
+ margin-left: -3px;
+
+ >.btn+.btn {
+ margin-left: 0px;
+ border-left: 1px solid rgba(0, 0, 0, 0.1);
+ }
+ .btn {
+ padding: 7px 11px;
+ margin-top: 1px;
+ background: #77ABB8;
+ @include box-shadow(0 0 5px rgba(0, 0, 0, 0.2));
+
+ &:focus, &.active {
+ outline: 0;
+ background: #4F727B;
+ }
+ }
+ }
+}
+.files {
+ .btn.iconview-button {
+ background: #4F727B;
+ }
+ .btn.listview-button {
+ background: #77ABB8;
+ }
+}
+.files.list-view {
+ .btn.listview-button {
+ background: #4F727B;
+ }
+ .btn.iconview-button {
+ background: #77ABB8;
+ }
}
.files .header {
background: #5E95A1;
@@ -259,12 +320,22 @@
}
.files .actions {
float: right;
+
+ @media (max-device-width:480px), screen and (max-width:800px) {
+ float: left;
+ margin-top: 7px;
+
+ .fa {
+ display: none;
+ }
+ }
}
.files .btn-Action {
margin-left: 8px;
@media (max-device-width:480px), screen and (max-width:800px) {
- margin: 4px 8px 4px 0;
+ margin: 4px 3px 4px 0;
+ padding: 8px 17px;
}
}
.files .list {
@@ -360,6 +431,7 @@
white-space: nowrap;
overflow: hidden;
display: block;
+ text-overflow: ellipsis;
}
.html-thumbnail {
font-size: 11px;
@@ -448,6 +520,112 @@
.html-thumbnail.misc.fileimagehover .overlay {
margin: 1px 0 0 2px;
}
+@mixin dashboard-list-view {
+ padding: 0;
+
+ .upload-Boundary {
+ padding: 0;
+ border: 0;
+ margin: 0;
+ }
+ .file {
+ padding: 10px 20px;
+ margin: 0;
+ width: 100%;
+
+ &:nth-child(even) {
+ background: #EFE8DC;
+ }
+ .title {
+ margin: 0;
+ margin-left: 9px;
+ margin-top: 2px;
+ float: left;
+ font-size: 14px;
+ text-align: left;
+ width: 30%;
+ text-overflow: ellipsis;
+
+ @media (max-device-width:480px), screen and (max-width:800px) {
+ width: 33%;
+ }
+ }
+ input[type='checkbox'] {
+ display: block;
+ float: left;
+ margin-top: 5px;
+ margin-right: 6px;
+ }
+ }
+ .html-thumbnail, .misc-icon {
+ margin: 0;
+ float: left;
+ width: 23px;
+ height: 23px;
+ background-size: 23px;
+ padding: 0;
+ font-size: 8px;
+
+ img {
+ max-width: 23px;
+ max-height: 23px;
+ }
+ }
+ .misc-icon {
+ padding-top: 8px;
+ }
+ .folder-icon {
+ background-position: 0 4px;
+ background-size: 23px;
+ height: 23px;
+ }
+ .file > .overlay {
+ padding-top: 11px;
+ margin-left: 20px;
+ text-align: right;
+ background-color: transparent;
+ display: block;
+ width: 94%;
+
+ a {
+ color: #e93250;
+ display: inline;
+ margin-right: 5px;
+ }
+ .link-overlay {
+ width: 30%;
+ }
+
+ @media (max-device-width:480px), screen and (max-width:800px) {
+ width: 84%;
+ }
+ }
+ .html-thumbnail > .overlay {
+ display: none;
+ }
+ .column {
+ float: left;
+ width: 13%;
+ font-size: 13px;
+ display: block;
+ padding-top: 4px;
+
+ @media (max-device-width:480px), screen and (max-width:800px) {
+ display: none;
+ }
+ }
+}
+@media (max-device-width:480px), screen and (max-width:800px) {
+ .files .list {
+ @include dashboard-list-view;
+ }
+ .files .btn-group {
+ display: none;
+ }
+}
+.files.list-view .list {
+ @include dashboard-list-view;
+}
.site-actions {
float: left;
margin-top: 20px;
@@ -574,10 +752,9 @@
}
}
@media (max-device-width:480px), screen and (max-width:800px) {
- width: 10em!important;
- float: right;
- padding: 0 0 18px 0;
- margin-top: -77px;
+ position: absolute;
+ top: 46px;
+ right: -8px;
}
}
.interior .header-Outro.with-columns .col-66 {
@@ -638,6 +815,7 @@
@media (max-device-width:480px), screen and (max-width:800px) {
width: 60%;
+ height: 160px;
}
}
.site-portrait {
@@ -1664,7 +1842,7 @@ a.tag:hover {
padding-top: 0;
background: #4F7E89;
- padding-bottom: 7em;
+ padding-bottom: 5em;
a {
color: white;
@@ -1730,8 +1908,20 @@ a.tag:hover {
.browse-page h1 {
margin-top: 0;
}
-.browse-page .tags {
- padding: 0 30px 40px 30px;
+.browse-page .row.content.misc {
+ form {
+ padding: 0;
+ }
+ input {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+ &:last-child {
+ padding-bottom: 68px;
+ }
+ p {
+ margin-top: 1em;
+ }
}
.misc-page .pagination {
width: 100%;
@@ -1781,6 +1971,12 @@ a.tag:hover {
.filename {
font-weight: bold;
}
+ @media (max-device-width:480px), screen and (max-width:800px) {
+ width: 70%;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
}
.row.content {
padding: 15px 20px;
@@ -1916,39 +2112,33 @@ table#latest-visitors {
width: 100%;
}
}
-.intro-List.kickstarter .col {
- padding-top: 1em;
- padding-bottom: .8em;
- margin-left: 0;
-
- &:first-child{
- padding-left: 2px;
+.section.thankyou {
+ text-align: center;
+ color: #4F7E89;
+ padding: 6.5em 8% 7em;
+
+ a {
+ color: #4F7E89;
+ text-decoration: underline;
}
-
- .title {
- margin-top: 1%;
- }
- .title a {
- color: white;
- font-weight: bold;
- text-decoration: none;
+ img {
+ margin-bottom: 1em;
}
p {
- margin-top: 15px;
+ font-size: 1em;
+ }
+ p:first-child {
+ font-size: 120%;
+ margin-bottom: .2em;
}
}
-.welcome.kickstarter {
- background: #daeea5 url(/img/tutorialthumbnail.png) no-repeat;
- background-position: right center;
- background-size: auto 100%;
- padding: 15px 100px 4px 23px;
- margin-bottom: 13px;
- font-size: 95%;
+ul.thankyou {
+ list-style: none;
+ margin-top: 1.5em;
+ clear: both;
- h4 {
- margin-bottom: .2em;
- a {
- color: #2c3e50!important;
- }
+ li {
+ display: inline-block;
+ width: 32%;
}
}
\ No newline at end of file
diff --git a/sass/_project-sass/_project-Tutorial.scss b/sass/_project-sass/_project-Tutorial.scss
new file mode 100644
index 00000000..4b68c506
--- /dev/null
+++ b/sass/_project-sass/_project-Tutorial.scss
@@ -0,0 +1,73 @@
+// ----------------------------------------------------------------
+// Project Specific: Tutorial
+// ----------------------------------------------------------------
+
+.tutorial {
+ p {
+ font-size: 1em;
+ }
+ .interact {
+ textarea.editor {
+ height: 350px!important;
+ width: 100%;
+ background-color: #1D1F21;
+ color: white;
+ font: 16px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
+ margin-bottom: 0;
+ border: 0;
+ }
+ h3 {
+ margin-top: 10px;
+ }
+ .preview {
+ height: 300px;
+ width: 100%;
+ background-color: gray;
+ }
+ .btn {
+ float: right;
+ }
+ .error {
+ background: #93771b;
+ color: #fff;
+ padding: 5px 10px;
+ font-size: 14px;
+ }
+ }
+ .lesson {
+ h1, .subtitle {
+ color: #5e95a1;
+ }
+ .subtitle {
+ font-size: 14px;
+ margin-top: 0;
+ text-align: left;
+ }
+ .comic {
+ position: relative;
+ background-repeat: no-repeat;
+ }
+ .dialogue {
+ width: 180px;
+ position: absolute;
+ text-align: center;
+
+ &:nth-child(1) {
+ left: 30px;
+ top: 30px;
+ }
+ &:nth-child(2) {
+ left: 250px;
+ top: 30px;
+ }
+ &:nth-child(3) {
+ left: 30px;
+ top: 250px;
+ }
+ &:nth-child(4) {
+ left: 250px;
+ top: 250px;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/sass/_project-sass/_project-Website-Gallery.scss b/sass/_project-sass/_project-Website-Gallery.scss
index 45306414..8653cb88 100644
--- a/sass/_project-sass/_project-Website-Gallery.scss
+++ b/sass/_project-sass/_project-Website-Gallery.scss
@@ -11,7 +11,7 @@
float:left;
margin-bottom:$spacing*2;
color: #666;
- @include box-shadow(1px 1px 2px 0px rgba(0, 0, 0, 0.18));
+ @include box-shadow(0px 1px 3px 0px rgba(0, 0, 0, 0.18));
@media (max-device-width:480px), screen and (max-width:800px){
width:50%
diff --git a/sass/neo.scss b/sass/neo.scss
index fd821dc3..b0ab7f7e 100644
--- a/sass/neo.scss
+++ b/sass/neo.scss
@@ -29,6 +29,7 @@
// Specific Modules
@import '_project-sass/project-Website-Gallery'; // Browse website specific styling
+ @import '_project-sass/project-Tutorial'; // Tutorial specific styling
// FIXITFIXITFIXITFIXIT
// Only import tidyUp if you actually need to make some quick fix hacks that you don't
diff --git a/tests/acceptance/browse_tests.rb b/tests/acceptance/browse_tests.rb
new file mode 100644
index 00000000..af8c390a
--- /dev/null
+++ b/tests/acceptance/browse_tests.rb
@@ -0,0 +1,46 @@
+require_relative './environment.rb'
+
+describe '/browse' do
+ include Capybara::DSL
+
+ describe 'as admin' do
+ before do
+ DB[:sites_tags].delete
+ DB[:sites].delete
+ Capybara.reset_sessions!
+ @admin = Fabricate :site, is_admin: true
+ @site = Fabricate :site, site_changed: true
+ page.set_rack_session id: @admin.id
+ end
+
+ it 'bans from browse for admin' do
+ visit '/browse?sort_by=newest'
+ within(".website-Gallery li#username_#{@site.username}") do
+ click_button 'Ban'
+ end
+
+ @site.reload.is_banned.must_equal true
+ @admin.reload.is_banned.must_equal false
+ end
+
+ it 'bans for spam' do
+ visit '/browse?sort_by=newest'
+ within(".website-Gallery li#username_#{@site.username}") do
+ click_button 'Spam'
+ end
+
+ @site.reload.is_banned.must_equal true
+ @site.site_files_dataset.where(path: 'index.html').first.classifier.must_equal 'spam'
+ end
+
+ it 'bans for phishing' do
+ visit '/browse?sort_by=newest'
+ within(".website-Gallery li#username_#{@site.username}") do
+ click_button 'Phishing'
+ end
+
+ @site.reload.is_banned.must_equal true
+ @site.site_files_dataset.where(path: 'index.html').first.classifier.must_equal 'phishing'
+ end
+ end
+end
diff --git a/tests/acceptance/settings/site_tests.rb b/tests/acceptance/settings/site_tests.rb
index 968037ff..dbb4d999 100644
--- a/tests/acceptance/settings/site_tests.rb
+++ b/tests/acceptance/settings/site_tests.rb
@@ -320,6 +320,12 @@ describe 'delete' do
someone_elses_site.is_deleted.must_equal false
end
+ it 'should not show NSFW tab for admin NSFW flag' do
+ owned_site = Fabricate :site, parent_site_id: @site.id, admin_nsfw: true
+ visit "/settings/#{owned_site.username}"
+ page.body.wont_match /18\+/
+ end
+
it 'should succeed if you own the site' do
owned_site = Fabricate :site, parent_site_id: @site.id
visit "/settings/#{owned_site.username}#delete"
@@ -341,4 +347,4 @@ describe 'delete' do
visit "/settings/#{@site.username}#delete"
page.body.must_match /You cannot delete the parent site without deleting the children sites first/i
end
-end
\ No newline at end of file
+end
diff --git a/tests/acceptance/signup_tests.rb b/tests/acceptance/signup_tests.rb
index d5018b26..08cb5176 100644
--- a/tests/acceptance/signup_tests.rb
+++ b/tests/acceptance/signup_tests.rb
@@ -9,9 +9,19 @@ describe 'signup' do
def fill_in_valid
@site = Fabricate.attributes_for(:site)
- fill_in 'username', with: @site[:username]
- fill_in 'password', with: @site[:password]
- fill_in 'email', with: @site[:email]
+
+ time = Time.now
+ begin
+ fill_in 'username', with: @site[:username]
+ fill_in 'password', with: @site[:password]
+ fill_in 'email', with: @site[:email]
+ rescue Capybara::ElementNotFound
+ puts "Waiting on fill_in #{Time.now - time} seconds"
+ raise if Time.now - time > 30
+ visit_signup
+ sleep 0.5
+ retry
+ end
end
def click_signup_button
@@ -35,12 +45,14 @@ describe 'signup' do
after do
Capybara.default_driver = :rack_test
+ BlockedIp.where(ip: '127.0.0.1').delete
+ DB[:sites].where(is_banned: true).delete
end
it 'succeeds with valid data' do
fill_in_valid
click_signup_button
- site_created?.must_equal true
+ site_created?
index_file_path = File.join Site::SITE_FILES_ROOT, @site[:username], 'index.html'
File.exist?(index_file_path).must_equal true
@@ -54,6 +66,27 @@ describe 'signup' do
site.ip.must_equal Site.hash_ip('127.0.0.1')
end
+ it 'fails if site with same ip has been banned' do
+ @banned_site = Fabricate :site
+ @banned_site.is_banned = true
+ @banned_site.save_changes
+
+ fill_in_valid
+ click_signup_button
+ Site[username: @site[:username]].must_be_nil
+ current_path.must_equal '/'
+ page.wont_have_content 'Welcome to Neocities'
+ end
+
+ it 'fails if IP is banned from blocked ips list' do
+ DB[:blocked_ips].insert(ip: '127.0.0.1', created_at: Time.now)
+ fill_in_valid
+ click_signup_button
+ Site[username: @site[:username]].must_be_nil
+ current_path.must_equal '/'
+ page.wont_have_content 'Welcome to Neocities'
+ end
+
it 'fails to create for existing site' do
@existing_site = Fabricate :site
fill_in_valid
diff --git a/tests/environment.rb b/tests/environment.rb
index 3247bc9f..d8d148bb 100644
--- a/tests/environment.rb
+++ b/tests/environment.rb
@@ -1,10 +1,17 @@
ENV['RACK_ENV'] = 'test'
raise 'Forget it.' if ENV['RACK_ENV'] == 'production'
+require 'coveralls'
require 'simplecov'
+
+SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
+ SimpleCov::Formatter::HTMLFormatter,
+ Coveralls::SimpleCov::Formatter
+]
SimpleCov.coverage_dir File.join('tests', 'coverage')
SimpleCov.start do
add_filter "/migrations/"
+ add_filter "/tests/"
end
SimpleCov.command_name 'minitest'
diff --git a/tests/files/blankindex/index.html b/tests/files/blankindex/index.html
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/files/classifier/ham.html b/tests/files/classifier/ham.html
new file mode 100644
index 00000000..fb2e3f75
--- /dev/null
+++ b/tests/files/classifier/ham.html
@@ -0,0 +1 @@
+I am a piece of ham.
diff --git a/tests/files/classifier/phishing.html b/tests/files/classifier/phishing.html
new file mode 100644
index 00000000..b7a57acd
--- /dev/null
+++ b/tests/files/classifier/phishing.html
@@ -0,0 +1 @@
+Facebook login enter your password derrp
diff --git a/tests/files/classifier/spam.html b/tests/files/classifier/spam.html
new file mode 100644
index 00000000..bea343a8
--- /dev/null
+++ b/tests/files/classifier/spam.html
@@ -0,0 +1 @@
+Ham sucks. How would you like to buy some spam?
diff --git a/tests/site_file_tests.rb b/tests/site_file_tests.rb
index f2aee5ee..fbf6ccff 100644
--- a/tests/site_file_tests.rb
+++ b/tests/site_file_tests.rb
@@ -24,16 +24,43 @@ describe 'site_files' do
end
describe 'delete' do
+ before do
+ DeleteCacheWorker.jobs.clear
+ DeleteCacheOrderWorker.jobs.clear
+ end
+
it 'works' do
+ initial_space_used = @site.space_used
uploaded_file = Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
upload 'files[]' => uploaded_file
- @site.reload.space_used.must_equal uploaded_file.size
+
+ PurgeCacheOrderWorker.jobs.clear
+
+ @site.reload.space_used.must_equal initial_space_used + uploaded_file.size
+ @site.actual_space_used.must_equal @site.space_used
file_path = @site.files_path 'test.jpg'
File.exists?(file_path).must_equal true
delete_file filename: 'test.jpg'
+
File.exists?(file_path).must_equal false
SiteFile[site_id: @site.id, path: 'test.jpg'].must_be_nil
- @site.reload.space_used.must_equal 0
+ @site.reload.space_used.must_equal initial_space_used
+ @site.actual_space_used.must_equal @site.space_used
+
+ PurgeCacheOrderWorker.jobs.length.must_equal 0
+ DeleteCacheOrderWorker.jobs.length.must_equal 1
+ args = DeleteCacheOrderWorker.jobs.first['args']
+ args[0].must_equal @site.username
+ args[1].must_equal '/test.jpg'
+ end
+
+ it 'flushes surf for index.html' do
+ uploaded_file = Rack::Test::UploadedFile.new('./tests/files/index.html', 'text/html')
+ upload 'files[]' => uploaded_file
+ delete_file filename: '/index.html'
+
+ DeleteCacheOrderWorker.jobs.length.must_equal 3
+ DeleteCacheOrderWorker.jobs.collect {|j| j['args'].last}.must_equal ['/index.html', '/?surf=1', '/']
end
it 'deletes a directory and all files in it' do
@@ -45,9 +72,36 @@ describe 'site_files' do
'dir' => '',
'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
)
+
+ space_used = @site.reload.space_used
delete_file filename: 'test'
+
+ @site.reload.space_used.must_equal(space_used - File.size('./tests/files/test.jpg'))
+
+ @site.site_files.select {|f| f.path == 'test'}.length.must_equal 0
@site.site_files.select {|f| f.path =~ /^test\//}.length.must_equal 0
- @site.site_files.select {|f| f.path =~ /^test/}.length.must_equal 1
+ @site.site_files.select {|f| f.path =~ /^test.jpg/}.length.must_equal 1
+ end
+
+ it 'deletes records for nested directories' do
+ upload(
+ 'dir' => 'derp/ing/tons',
+ 'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
+ )
+
+ expected_site_file_paths = ['derp', 'derp/ing', 'derp/ing/tons', 'derp/ing/tons/test.jpg']
+
+ expected_site_file_paths.each do |path|
+ @site.site_files.select {|f| f.path == path}.length.must_equal 1
+ end
+
+ delete_file filename: 'derp'
+
+ @site.reload
+
+ expected_site_file_paths.each do |path|
+ @site.site_files.select {|f| f.path == path}.length.must_equal 0
+ end
end
it 'goes back to deleting directory' do
@@ -107,25 +161,35 @@ describe 'site_files' do
@site.title.must_equal 'Hello?'
# Purge cache needs to flush / and index.html for either scenario.
- PurgeCacheOrderWorker.jobs.length.must_equal 2
+ PurgeCacheOrderWorker.jobs.length.must_equal 3
first_purge = PurgeCacheOrderWorker.jobs.first
+ surf_purge = PurgeCacheOrderWorker.jobs[1]
dirname_purge = PurgeCacheOrderWorker.jobs.last
username, pathname = first_purge['args']
username.must_equal @site.username
pathname.must_equal '/index.html'
+
+ surf_purge['args'].last.must_equal '/?surf=1'
+
username, pathame = nil
username, pathname = dirname_purge['args']
username.must_equal @site.username
pathname.must_equal '/'
+
+ @site.space_used.must_equal @site.actual_space_used
+
+ (@site.space_used > 0).must_equal true
end
it 'provides the correct space used after overwriting an existing file' do
+ initial_space_used = @site.space_used
uploaded_file = Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
upload 'files[]' => uploaded_file
second_uploaded_file = Rack::Test::UploadedFile.new('./tests/files/img/test.jpg', 'image/jpeg')
upload 'files[]' => second_uploaded_file
- @site.reload.space_used.must_equal second_uploaded_file.size
+ @site.reload.space_used.must_equal initial_space_used + second_uploaded_file.size
+ @site.space_used.must_equal @site.actual_space_used
end
it 'does not change title for subdir index.html' do
@@ -138,6 +202,7 @@ describe 'site_files' do
end
it 'succeeds with valid file' do
+ initial_space_used = @site.space_used
uploaded_file = Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
upload 'files[]' => uploaded_file
last_response.body.must_match /successfully uploaded/i
@@ -149,7 +214,8 @@ describe 'site_files' do
@site.reload
@site.space_used.wont_equal 0
- @site.space_used.must_equal uploaded_file.size
+ @site.space_used.must_equal initial_space_used + uploaded_file.size
+ @site.space_used.must_equal @site.actual_space_used
ThumbnailWorker.jobs.length.must_equal 1
ThumbnailWorker.drain
@@ -158,7 +224,15 @@ describe 'site_files' do
File.exists?(@site.thumbnail_path('test.jpg', resolution)).must_equal true
end
- @site.site_changed.must_equal true
+ @site.site_changed.must_equal false
+ end
+
+ it 'sets site changed to false if index is empty' do
+ uploaded_file = Rack::Test::UploadedFile.new('./tests/files/blankindex/index.html', 'text/html')
+ upload 'files[]' => uploaded_file
+ last_response.body.must_match /successfully uploaded/i
+ @site.empty_index?.must_equal true
+ @site.site_changed.must_equal false
end
it 'fails with unsupported file' do
@@ -213,6 +287,10 @@ describe 'site_files' do
ThumbnailWorker.jobs.length.must_equal 1
ThumbnailWorker.drain
+ @site.site_files_dataset.where(path: 'derpie').count.must_equal 1
+ @site.site_files_dataset.where(path: 'derpie/derptest').count.must_equal 1
+ @site.site_files_dataset.where(path: 'derpie/derptest/test.jpg').count.must_equal 1
+
Site::THUMBNAIL_RESOLUTIONS.each do |resolution|
File.exists?(@site.thumbnail_path('derpie/derptest/test.jpg', resolution)).must_equal true
@site.thumbnail_url('derpie/derptest/test.jpg', resolution).must_equal(
@@ -221,6 +299,20 @@ describe 'site_files' do
end
end
+ it 'does not register site changing until root index.html is changed' do
+ upload(
+ 'dir' => 'derpie/derptest',
+ 'files[]' => Rack::Test::UploadedFile.new('./tests/files/test.jpg', 'image/jpeg')
+ )
+ @site.reload.site_changed.must_equal false
+
+ upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/index.html', 'text/html')
+ @site.reload.site_changed.must_equal true
+
+ upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/chunkfive.otf', 'application/vnd.ms-opentype')
+ @site.reload.site_changed.must_equal true
+ end
+
it 'does not store new file if hash matches' do
upload(
'dir' => 'derpie/derptest',
@@ -237,5 +329,27 @@ describe 'site_files' do
upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/index.html', 'text/html')
@site.reload.changed_count.must_equal 2
end
+
+ describe 'classification' do
+ before do
+ puts "TODO FINISH CLASSIFIER"
+ #$trainer.instance_variable_get('@db').redis.flushall
+ end
+=begin
+ it 'trains files' do
+ upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/classifier/ham.html', 'text/html')
+ upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/classifier/spam.html', 'text/html')
+ upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/classifier/phishing.html', 'text/html')
+
+ @site.train 'ham.html'
+ @site.train 'spam.html', 'spam'
+ @site.train 'phishing.html', 'phishing'
+
+ @site.classify('ham.html').must_equal 'ham'
+ @site.classify('spam.html').must_equal 'spam'
+ @site.classify('phishing.html').must_equal 'phishing'
+ end
+=end
+ end
end
end
diff --git a/tests/site_tests.rb b/tests/site_tests.rb
index e72a685e..5cf387cb 100644
--- a/tests/site_tests.rb
+++ b/tests/site_tests.rb
@@ -5,6 +5,38 @@ def app
end
describe Site do
+ describe 'banning' do
+ it 'still makes files available' do
+ site = Fabricate :site
+ site.ban!
+ File.exist?(site.current_files_path('index.html')).must_equal true
+ site.current_files_path('index.html').must_equal File.join(Site::BANNED_SITES_ROOT, site.username, 'index.html')
+ end
+ end
+
+ describe 'directory create' do
+ it 'handles wacky pathnames' do
+ ['/derp', '/derp/'].each do |path|
+ site = Fabricate :site
+ site_file_count = site.site_files_dataset.count
+ site.create_directory path
+ site.site_files.select {|s| s.path == '' || s.path == '.'}.length.must_equal 0
+ site.site_files.select {|s| s.path == path.gsub('/', '')}.first.wont_be_nil
+ site.site_files_dataset.count.must_equal site_file_count+1
+ end
+ end
+ end
+
+ describe 'custom_max_space' do
+ it 'should use the custom max space if it is more' do
+ site = Fabricate :site
+ site.maximum_space.must_equal Site::PLAN_FEATURES[:free][:space]
+ site.custom_max_space = 10**9
+ site.save_changes
+ site.maximum_space.must_equal 10**9
+ end
+ end
+
describe 'can_email' do
it 'should fail if send_emails is false' do
site = Fabricate :site
@@ -76,7 +108,7 @@ describe Site do
Fabricate :site, new_tags_string: 'gardening', views: Site::SUGGESTIONS_VIEWS_MIN
}
- site.suggestions.length.must_equal Site::SUGGESTIONS_LIMIT
+ site.suggestions.length.must_equal(Site::SUGGESTIONS_LIMIT - 5)
end
end
end
diff --git a/tests/stat_logs/.gitignore b/tests/stat_logs/.gitignore
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/tests/stat_logs/.gitignore
@@ -0,0 +1 @@
+*
diff --git a/tests/stat_tests.rb b/tests/stat_tests.rb
index 4216d39e..3c22fdeb 100644
--- a/tests/stat_tests.rb
+++ b/tests/stat_tests.rb
@@ -35,11 +35,34 @@ describe 'stats' do
end
Stat.parse_logfiles STAT_LOGS_PATH
+
@site.stats.first.bandwidth.must_equal 612917*2
#@site.stat_referrers.first.url.must_equal 'http://derp.com'
#@site.stat_locations.first.city_name.must_equal 'Menlo Park'
end
+ it 'takes accout for log hit time' do
+ @site = Fabricate :site
+ File.open("tests/stat_logs/#{SecureRandom.uuid}.log", 'w') do |file|
+ file.write "2015-05-01T21:16:35+00:00\t#{@site.username}\t612917\t/images/derpie space.png\t67.180.75.140\thttp://derp.com\n"
+ file.write "2015-05-02T21:16:35+00:00\t#{@site.username}\t612917\t/images/derpie space.png\t67.180.75.140\thttp://derp.com\n"
+ end
+
+ Stat.parse_logfiles STAT_LOGS_PATH
+
+ @site.stats.length.must_equal 2
+
+ [Date.new(2015, 5, 2), Date.new(2015, 5, 1)].each do |date|
+ stats = @site.stats.select {|stat| stat.created_at == date}
+ stats.length.must_equal 1
+ stat = stats.first
+ stat.hits.must_equal 1
+ stat.views.must_equal 1
+ stat.bandwidth.must_equal 612917
+ end
+
+ end
+
it 'deals with spaces in referrer' do
@site = Fabricate :site
File.open("tests/stat_logs/#{SecureRandom.uuid}.log", 'w') do |file|
@@ -103,6 +126,7 @@ describe 'stats' do
end
it 'parses logfile' do
+ DB[:daily_site_stats].delete
Stat.parse_logfiles STAT_LOGS_PATH
@site_one.reload
@@ -149,5 +173,14 @@ describe 'stats' do
#stat_paths.last.name.must_equal '/derp.html'
# [geoip.city('67.180.75.140'), geoip.city('172.56.16.152')]
+
+ # Saves to daily_site_stats
+
+ DailySiteStat.count.must_equal 1
+ d = DailySiteStat.first
+ d.created_at.must_equal Date.new(@time.year, @time.month, @time.day)
+ d.hits.must_equal 7
+ d.views.must_equal 5
+ d.bandwidth.must_equal 35000
end
end
diff --git a/tests/workers/delete_cache_order_worker_tests.rb b/tests/workers/delete_cache_order_worker_tests.rb
new file mode 100644
index 00000000..9810fcd8
--- /dev/null
+++ b/tests/workers/delete_cache_order_worker_tests.rb
@@ -0,0 +1,21 @@
+require_relative '../environment.rb'
+
+describe DeleteCacheWorker do
+ before do
+ PurgeCacheOrderWorker.jobs.clear
+ PurgeCacheWorker.jobs.clear
+ end
+
+ it 'queues up purges' do
+ DeleteCacheOrderWorker.new.perform('kyledrake', '/test.jpg')
+
+ job_one_args = DeleteCacheWorker.jobs.first['args']
+ job_two_args = DeleteCacheWorker.jobs.last['args']
+ job_one_args[0].must_equal '10.0.0.1'
+ job_one_args[1].must_equal 'kyledrake'
+ job_one_args[2].must_equal '/test.jpg'
+ job_two_args[0].must_equal '10.0.0.2'
+ job_two_args[1].must_equal 'kyledrake'
+ job_two_args[2].must_equal '/test.jpg'
+ end
+end
diff --git a/tests/workers/delete_cache_worker_tests.rb b/tests/workers/delete_cache_worker_tests.rb
new file mode 100644
index 00000000..70f6f690
--- /dev/null
+++ b/tests/workers/delete_cache_worker_tests.rb
@@ -0,0 +1,64 @@
+require_relative '../environment.rb'
+
+describe DeleteCacheWorker do
+ before do
+ @test_ip = '10.0.0.1'
+ end
+
+ it 'throws exception without 200 or 404 http status' do
+ stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org'})
+ .to_return(status: 503)
+
+ worker = DeleteCacheWorker.new
+
+ proc {
+ worker.perform @test_ip, 'kyledrake', '/test.jpg'
+ }.must_raise RestClient::ServiceUnavailable
+ end
+
+ it 'handles 404 without exception' do
+ stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org'})
+ .to_return(status: 404)
+
+ worker = DeleteCacheWorker.new
+ worker.perform @test_ip, 'kyledrake', '/test.jpg'
+ end
+
+ it 'sends a purge request' do
+ stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org'})
+ .to_return(status: 200)
+
+ worker = DeleteCacheWorker.new
+ worker.perform @test_ip, 'kyledrake', '/test.jpg'
+
+ assert_requested :get, "http://#{@test_ip}/:cache/purge/test.jpg"
+ end
+
+ it 'handles spaces correctly' do
+ stub_request(:get, "http://#{@test_ip}/:cache/purge/te st.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org'})
+ .to_return(status: 200)
+
+ url = Addressable::URI.encode_component(
+ "http://#{@test_ip}/:cache/purge/te st.jpg",
+ Addressable::URI::CharacterClasses::QUERY
+ )
+
+ worker = DeleteCacheWorker.new
+ worker.perform @test_ip, 'kyledrake', '/te st.jpg'
+
+ assert_requested :get, url
+ end
+
+ it 'works without forward slash' do
+ stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org'})
+ .to_return(status: 200)
+
+ worker = DeleteCacheWorker.new
+ worker.perform @test_ip, 'kyledrake', 'test.jpg'
+ end
+end
diff --git a/tests/workers/purge_cache_worker_tests.rb b/tests/workers/purge_cache_worker_tests.rb
index 90be0da8..b07bc3c7 100644
--- a/tests/workers/purge_cache_worker_tests.rb
+++ b/tests/workers/purge_cache_worker_tests.rb
@@ -6,8 +6,8 @@ describe PurgeCacheWorker do
end
it 'throws exception without 200 or 404 http status' do
- stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
- with(headers: {'Host' => 'kyledrake.neocities.org'})
+ stub_request(:head, "http://#{@test_ip}/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org', 'Cache-Purge' => '1'})
.to_return(status: 503)
worker = PurgeCacheWorker.new
@@ -18,8 +18,8 @@ describe PurgeCacheWorker do
end
it 'handles 404 without exception' do
- stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
- with(headers: {'Host' => 'kyledrake.neocities.org'})
+ stub_request(:head, "http://#{@test_ip}/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org', 'Cache-Purge' => '1'})
.to_return(status: 404)
worker = PurgeCacheWorker.new
@@ -27,35 +27,35 @@ describe PurgeCacheWorker do
end
it 'sends a purge request' do
- stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
- with(headers: {'Host' => 'kyledrake.neocities.org'})
+ stub_request(:head, "http://#{@test_ip}/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org', 'Cache-Purge' => '1'})
.to_return(status: 200)
worker = PurgeCacheWorker.new
worker.perform @test_ip, 'kyledrake', '/test.jpg'
- assert_requested :get, "http://#{@test_ip}/:cache/purge/test.jpg"
+ assert_requested :head, "http://#{@test_ip}/test.jpg"
end
it 'handles spaces correctly' do
- stub_request(:get, "http://#{@test_ip}/:cache/purge/te st.jpg").
- with(headers: {'Host' => 'kyledrake.neocities.org'})
+ stub_request(:head, "http://#{@test_ip}/te st.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org', 'Cache-Purge' => '1'})
.to_return(status: 200)
url = Addressable::URI.encode_component(
- "http://#{@test_ip}/:cache/purge/te st.jpg",
+ "http://#{@test_ip}/te st.jpg",
Addressable::URI::CharacterClasses::QUERY
)
worker = PurgeCacheWorker.new
worker.perform @test_ip, 'kyledrake', '/te st.jpg'
- assert_requested :get, url
+ assert_requested :head, url
end
it 'works without forward slash' do
- stub_request(:get, "http://#{@test_ip}/:cache/purge/test.jpg").
- with(headers: {'Host' => 'kyledrake.neocities.org'})
+ stub_request(:head, "http://#{@test_ip}/test.jpg").
+ with(headers: {'Host' => 'kyledrake.neocities.org', 'Cache-Purge' => '1'})
.to_return(status: 200)
worker = PurgeCacheWorker.new
diff --git a/views/_footer.erb b/views/_footer.erb
index cd67fe04..e1ab4b83 100644
--- a/views/_footer.erb
+++ b/views/_footer.erb
@@ -11,7 +11,7 @@
About
Donate
<% unless is_education? %>
- Blog
+ Blog
API
Press
<% end %>
diff --git a/views/_header_links.erb b/views/_header_links.erb
index 265f3616..ec317af4 100644
--- a/views/_header_links.erb
+++ b/views/_header_links.erb
@@ -7,9 +7,6 @@
Websites
<% unless is_education? %>
-
- Search
-
Activity
@@ -17,8 +14,6 @@
Learn
- <% unless is_education? %>
- Support Our Kickstarter
-
- <% end %>
+ Support Us
+
\ No newline at end of file
diff --git a/views/_news.erb b/views/_news.erb
index 2641c68d..7ca1b3c5 100644
--- a/views/_news.erb
+++ b/views/_news.erb
@@ -126,26 +126,7 @@
<% if params[:activity] != 'global' %>
- <% if @page_count > 1 %>
-
- <% end %>
+ <%== erb :_pagination, layout: false %>
<% end %>
diff --git a/views/_news_profile_comment.erb b/views/_news_profile_comment.erb
index f2ccde95..9d9716a9 100644
--- a/views/_news_profile_comment.erb
+++ b/views/_news_profile_comment.erb
@@ -10,13 +10,11 @@
<% if actioning_site.supporter? %> <% end %> <%= actioning_site.username %>
<% end %>
-
+ <% if actioning_site.id != profile_comment.site_id %>
+
+ <% if profile_comment.site.supporter? %> <% end %> <%= profile_comment.site.username %>
+ <% end %>
- <% if current_site && current_site.id == profile_comment.site_id %>
- You
- <% else %>
- <% if profile_comment.site.supporter? %> <% end %> <%= profile_comment.site.username %>
- <% end %>
<%= profile_comment.created_at.ago %>
diff --git a/views/_pagination.erb b/views/_pagination.erb
new file mode 100644
index 00000000..b568d5f9
--- /dev/null
+++ b/views/_pagination.erb
@@ -0,0 +1,5 @@
+<% if @pagination_dataset.total_pages > 1 %>
+
+<% end %>
diff --git a/views/admin.erb b/views/admin.erb
index f2ac59b1..394e617a 100644
--- a/views/admin.erb
+++ b/views/admin.erb
@@ -9,7 +9,8 @@
@@ -28,6 +29,13 @@
<%== csrf_token_input_html %>
Site Name:
+
+
+
+ Spam
+ Phishing
+
+
diff --git a/views/admin/reports.erb b/views/admin/reports.erb
index 3b6c0801..2de772a6 100644
--- a/views/admin/reports.erb
+++ b/views/admin/reports.erb
@@ -5,7 +5,8 @@
diff --git a/workers/delete_cache_order_worker.rb b/workers/delete_cache_order_worker.rb
new file mode 100644
index 00000000..0e19b13c
--- /dev/null
+++ b/workers/delete_cache_order_worker.rb
@@ -0,0 +1,23 @@
+class DeleteCacheOrderWorker
+ include Sidekiq::Worker
+ sidekiq_options queue: :deletecacheorder, retry: 1000, backtrace: true, average_scheduled_poll_interval: 1
+
+ sidekiq_retry_in do |count|
+ return 10 if count < 10
+ 180
+ end
+
+ RESOLVER = Dnsruby::Resolver.new
+
+ def perform(username, path)
+ if ENV['RACK_ENV'] == 'test'
+ proxy_ips = ['10.0.0.1', '10.0.0.2']
+ else
+ proxy_ips = RESOLVER.query($config['cache_purge_ips_uri']).answer.collect {|a| a.address.to_s}
+ end
+
+ proxy_ips.each do |proxy_ip|
+ DeleteCacheWorker.perform_async proxy_ip, username, path
+ end
+ end
+end
diff --git a/workers/delete_cache_worker.rb b/workers/delete_cache_worker.rb
new file mode 100644
index 00000000..3b0dc35e
--- /dev/null
+++ b/workers/delete_cache_worker.rb
@@ -0,0 +1,34 @@
+require 'open-uri'
+
+# PurgeCacheWorker refreshes the cache, this actually deletes it.
+# This is because when the file is 404ing the PurgeCacheWorker
+# will just sit on the stale cache, even though it's not supposed to.
+# It's some nginx bug. I'm not going to deal with it.
+
+class DeleteCacheWorker
+ HTTP_TIMEOUT = 5
+ include Sidekiq::Worker
+ sidekiq_options queue: :deletecache, retry: 1000, backtrace: false, average_scheduled_poll_interval: 1
+
+ sidekiq_retry_in do |count|
+ return 10 if count < 10
+ 180
+ end
+
+ def perform(proxy_ip, username, path)
+ # Must always have a forward slash
+ path = '/' + path if path[0] != '/'
+
+ url = Addressable::URI.encode_component(
+ "http://#{proxy_ip}/:cache/purge#{path}",
+ Addressable::URI::CharacterClasses::QUERY
+ )
+ begin
+ RestClient::Request.execute method: :get, url: url, timeout: HTTP_TIMEOUT, headers: {
+ host: URI::encode("#{username}.neocities.org")
+ }
+ rescue RestClient::ResourceNotFound
+ rescue RestClient::Forbidden
+ end
+ end
+end
diff --git a/workers/email_worker.rb b/workers/email_worker.rb
index b86a3829..078f4861 100644
--- a/workers/email_worker.rb
+++ b/workers/email_worker.rb
@@ -3,7 +3,7 @@ class EmailWorker
sidekiq_options queue: :emails, retry: 10, backtrace: true
def perform(args={})
- raise 'no' if ENV['RACK_ENV'].nil? || ENV['RACK_ENV'] == 'development'
+ return if ENV['RACK_ENV'].nil? || ENV['RACK_ENV'] == 'development'
unsubscribe_token = Site.email_unsubscribe_token args['to']
if args['no_footer']
diff --git a/workers/purge_cache_worker.rb b/workers/purge_cache_worker.rb
index 836b8a81..1ce5a260 100644
--- a/workers/purge_cache_worker.rb
+++ b/workers/purge_cache_worker.rb
@@ -1,6 +1,7 @@
require 'open-uri'
class PurgeCacheWorker
+ HTTP_TIMEOUT = 5
include Sidekiq::Worker
sidekiq_options queue: :purgecache, retry: 1000, backtrace: false, average_scheduled_poll_interval: 1
@@ -14,12 +15,24 @@ class PurgeCacheWorker
path = '/' + path if path[0] != '/'
url = Addressable::URI.encode_component(
- "http://#{proxy_ip}/:cache/purge#{path}",
+ "http://#{proxy_ip}#{path}",
Addressable::URI::CharacterClasses::QUERY
)
+
+ retry_encoded = false
+
begin
- RestClient.get(url, host: URI::encode("#{username}.neocities.org"))
+ RestClient::Request.execute method: :head, url: url, timeout: HTTP_TIMEOUT, headers: {
+ host: URI::encode("#{username}.neocities.org"),
+ cache_purge: '1'
+ }
+ rescue URI::InvalidURIError
+ raise if retry_encoded == true
+ url = URI.encode url
+ retry_encoded = true
+ retry
rescue RestClient::ResourceNotFound
+ rescue RestClient::Forbidden
end
end
end
diff --git a/workers/screenshot_worker.rb b/workers/screenshot_worker.rb
index 8831a1d4..53e84c10 100644
--- a/workers/screenshot_worker.rb
+++ b/workers/screenshot_worker.rb
@@ -4,32 +4,9 @@ require 'securerandom'
require 'thread'
require 'open3'
-# Don't judge - Ruby handling of timeouts is a joke..
-module Phantomjs
- def self.run(*args, &block)
- pid = nil
- stdin, stdout, stderr, wait_thr = nil
- begin
- Timeout::timeout(50) do
- stdin, stdout, stderr, wait_thr = Open3.popen3(path, *args)
- pid = wait_thr.pid
- wait_thr.join
- return stdout.read
- end
- # :nocov:
- rescue Timeout::Error
- stdin.close
- stdout.close
- stderr.close
- Process.kill 'QUIT', pid
- raise Timeout::Error
- end
- # :nocov:
- end
-end
-
class ScreenshotWorker
SCREENSHOTS_PATH = Site::SCREENSHOTS_ROOT
+ HARD_TIMEOUT = 30.freeze
include Sidekiq::Worker
sidekiq_options queue: :screenshots, retry: 3, backtrace: true
@@ -39,40 +16,31 @@ class ScreenshotWorker
screenshot.close
screenshot_output_path = screenshot.path+'.png'
- begin
- f = Screencap::Fetcher.new("http://#{username}.neocities.org#{path}")
- f.fetch(
- output: screenshot_output_path,
- width: 1280,
- height: 960
- )
- rescue Timeout::Error
- # :nocov:
- puts "#{username}/#{path} is timing out, discontinuing"
- site = Site[username: username]
- site.is_crashing = true
- site.save_changes validate: false
+ line = Cocaine::CommandLine.new(
+ "timeout #{HARD_TIMEOUT} phantomjs #{File.join DIR_ROOT, 'files', 'phantomjs_screenshot.js'}", ":url :output",
+ expected_outcodes: [0]
+ )
- # Don't enable until we know it works well.
-=begin
- if site.email
- EmailWorker.perform_async({
- from: 'web@neocities.org',
- to: site.email,
- subject: "[NeoCities] The web page \"#{path}\" on your site (#{username}.neocities.org) is slow",
- body: "Hi there! This is an automated email to inform you that we're having issues loading your site to take a "+
- "screenshot. It is possible that this is an error specific to our screenshot program, but it is much more "+
- "likely that your site is too slow to be used with browsers. We don't want Neocities sites crashing browsers, "+
- "so we're taking steps to inform you and see if you can resolve the issue. "+
- "We may have to de-list your web site from being viewable in our browse page if it is not resolved shortly. "+
- "We will review the site manually before taking this step, so don't worry if your site is fine and we made "+
- "a mistake."+
- "\n\nOur best,\n- Neocities"
- })
- end
-=end
- return
- # :nocov:
+ begin
+ output = line.run(
+ url: "http://#{username}.neocities.org#{path}",
+ output: screenshot_output_path
+ )
+ rescue Cocaine::ExitStatusError => e
+ raise e
+
+ # We set is_crashing after retries now, but use this code to go back to instant:
+
+ #if e.message && e.message.match(/returned 124/)
+ # puts "#{username}/#{path} is timing out, discontinuing"
+ # site = Site[username: username]
+ # site.is_crashing = true
+ # site.save_changes validate: false
+ # return true
+ #
+ #else
+ # raise
+ #end
end
img_list = Magick::ImageList.new
@@ -97,10 +65,34 @@ class ScreenshotWorker
else
new_img = img.scale width, height
end
-
new_img.write(File.join(user_screenshots_path, "#{path}.#{res}.jpg")) {
self.quality = 90
}
end
end
+
+ sidekiq_retries_exhausted do |msg|
+ username, path = msg['args']
+ site = Site[username: username]
+ site.is_crashing = true
+ site.save_changes validate: false
+
+=begin
+ if site.email
+ EmailWorker.perform_async({
+ from: 'web@neocities.org',
+ to: site.email,
+ subject: "[NeoCities] The web page \"#{path}\" on your site (#{username}.neocities.org) is slow",
+ body: "Hi there! This is an automated email to inform you that we're having issues loading your site to take a "+
+ "screenshot. It is possible that this is an error specific to our screenshot program, but it is much more "+
+ "likely that your site is too slow to be used with browsers. We don't want Neocities sites crashing browsers, "+
+ "so we're taking steps to inform you and see if you can resolve the issue. "+
+ "We may have to de-list your web site from being viewable in our browse page if it is not resolved shortly. "+
+ "We will review the site manually before taking this step, so don't worry if your site is fine and we made "+
+ "a mistake."+
+ "\n\nOur best,\n- Neocities"
+ })
+ end
+=end
+ end
end
diff --git a/workers/thumbnail_worker.rb b/workers/thumbnail_worker.rb
index 181b2183..ad6a3e06 100644
--- a/workers/thumbnail_worker.rb
+++ b/workers/thumbnail_worker.rb
@@ -7,7 +7,13 @@ class ThumbnailWorker
def perform(username, path)
img_list = Magick::ImageList.new
- img_list.from_blob File.read(File.join(Site::SITE_FILES_ROOT, username, path))
+
+ begin
+ img_list.from_blob File.read(File.join(Site::SITE_FILES_ROOT, username, path))
+ rescue Errno::ENOENT => e # Not found, skip
+ return
+ end
+
img = img_list.first
user_thumbnails_path = File.join THUMBNAILS_PATH, username