diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000000..e94f8140cc --- /dev/null +++ b/.browserslistrc @@ -0,0 +1 @@ +defaults diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..d51205ca9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep + +/public/assets +.byebug_history + +# Ignore master key for decrypting credentials and more. +/config/master.key + +/public/packs +/public/packs-test +/node_modules +/yarn-error.log +yarn-debug.log* +.yarn-integrity + +.env + +#Ignore test related files +/coverage.data +/coverage/ \ No newline at end of file diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000000..57cf282ebb --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.6.5 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..6117eb5a5b --- /dev/null +++ b/Gemfile @@ -0,0 +1,88 @@ +source 'https://rubygems.org' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby '2.6.5' + +# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' +gem 'rails', '~> 6.0.3', '>= 6.0.3.1' +# Use postgresql as the database for Active Record +gem 'pg', '>= 0.18', '< 2.0' +# Use Puma as the app server +gem 'puma', '~> 4.1' +# Use SCSS for stylesheets +gem 'sass-rails', '>= 6' +# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker +gem 'webpacker', '~> 4.0' +# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks +gem 'turbolinks', '~> 5' +# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder +gem 'jbuilder', '~> 2.7' +# Use Redis adapter to run Action Cable in production +# gem 'redis', '~> 4.0' +# Use Active Model has_secure_password +# gem 'bcrypt', '~> 3.1.7' + +# Use Active Storage variant +# gem 'image_processing', '~> 1.2' + +# Reduces boot times through caching; required in config/boot.rb +gem 'bootsnap', '>= 1.4.2', require: false + +gem 'faker', :git => 'https://github.com/faker-ruby/faker.git', :branch => 'master' + +group :development, :test do + # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] +end + +group :development do + # Access an interactive console on exception pages or by calling 'console' anywhere in the code. + gem 'web-console', '>= 3.3.0' + gem 'listen', '~> 3.2' + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'spring' + gem 'spring-watcher-listen', '~> 2.0.0' +end + +group :test do + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '>= 2.15' + gem 'selenium-webdriver' + # Easy installation and use of web drivers to run system tests with browsers + gem 'webdrivers' +end + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] + +gem 'jquery-rails' +gem 'jquery-turbolinks' +gem 'bootstrap' +group :development, :test do + gem 'pry-rails' +end + +group :development do + gem 'guard' + gem 'guard-minitest' + gem 'debase', '>= 0.2.4.1' + gem 'ruby-debug-ide', '>= 0.7.0' +end + +group :development do + gem 'better_errors' + gem 'binding_of_caller' + gem 'dotenv-rails' +end + +group :test do + gem 'minitest-rails' + gem 'minitest-reporters' + gem 'simplecov', require: false + gem 'rails-controller-testing' +end + +gem "omniauth" +gem "omniauth-github" +gem 'will_paginate', '~> 3.0' +gem 'pg_search' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..978785cf99 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,353 @@ +GIT + remote: https://github.com/faker-ruby/faker.git + revision: aa4174a4e72807674e8f044ecf1234a1e7dfabbd + branch: master + specs: + faker (2.12.0) + i18n (>= 1.6, < 2) + +GEM + remote: https://rubygems.org/ + specs: + actioncable (6.0.3.1) + actionpack (= 6.0.3.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.0.3.1) + actionpack (= 6.0.3.1) + activejob (= 6.0.3.1) + activerecord (= 6.0.3.1) + activestorage (= 6.0.3.1) + activesupport (= 6.0.3.1) + mail (>= 2.7.1) + actionmailer (6.0.3.1) + actionpack (= 6.0.3.1) + actionview (= 6.0.3.1) + activejob (= 6.0.3.1) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.0.3.1) + actionview (= 6.0.3.1) + activesupport (= 6.0.3.1) + rack (~> 2.0, >= 2.0.8) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.0.3.1) + actionpack (= 6.0.3.1) + activerecord (= 6.0.3.1) + activestorage (= 6.0.3.1) + activesupport (= 6.0.3.1) + nokogiri (>= 1.8.5) + actionview (6.0.3.1) + activesupport (= 6.0.3.1) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.0.3.1) + activesupport (= 6.0.3.1) + globalid (>= 0.3.6) + activemodel (6.0.3.1) + activesupport (= 6.0.3.1) + activerecord (6.0.3.1) + activemodel (= 6.0.3.1) + activesupport (= 6.0.3.1) + activestorage (6.0.3.1) + actionpack (= 6.0.3.1) + activejob (= 6.0.3.1) + activerecord (= 6.0.3.1) + marcel (~> 0.3.1) + activesupport (6.0.3.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2, >= 2.2.2) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + ansi (1.5.0) + autoprefixer-rails (9.7.6) + execjs + better_errors (2.7.1) + coderay (>= 1.0.0) + erubi (>= 1.0.0) + rack (>= 0.9.0) + bindex (0.8.1) + binding_of_caller (0.8.0) + debug_inspector (>= 0.0.1) + bootsnap (1.4.6) + msgpack (~> 1.0) + bootstrap (4.5.0) + autoprefixer-rails (>= 9.1.0) + popper_js (>= 1.14.3, < 2) + sassc-rails (>= 2.0.0) + builder (3.2.4) + byebug (11.1.3) + capybara (3.32.2) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.5) + xpath (~> 3.2) + childprocess (3.0.0) + coderay (1.1.3) + concurrent-ruby (1.1.6) + crass (1.0.6) + debase (0.2.4.1) + debase-ruby_core_source (>= 0.10.2) + debase-ruby_core_source (0.10.9) + debug_inspector (0.0.3) + docile (1.3.2) + dotenv (2.7.5) + dotenv-rails (2.7.5) + dotenv (= 2.7.5) + railties (>= 3.2, < 6.1) + erubi (1.9.0) + execjs (2.7.0) + faraday (1.0.1) + multipart-post (>= 1.2, < 3) + ffi (1.13.1) + formatador (0.2.5) + globalid (0.4.2) + activesupport (>= 4.2.0) + guard (2.16.2) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.9.12) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-minitest (2.4.6) + guard-compat (~> 1.2) + minitest (>= 3.0) + hashie (4.1.0) + i18n (1.8.3) + concurrent-ruby (~> 1.0) + jbuilder (2.10.0) + activesupport (>= 5.0.0) + jquery-rails (4.4.0) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + jquery-turbolinks (2.1.0) + railties (>= 3.1.0) + turbolinks + jwt (2.2.1) + listen (3.2.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + loofah (2.5.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + lumberjack (1.2.5) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) + method_source (1.0.0) + mimemagic (0.3.5) + mini_mime (1.0.2) + mini_portile2 (2.4.0) + minitest (5.14.1) + minitest-rails (6.0.1) + minitest (~> 5.10) + railties (~> 6.0.0) + minitest-reporters (1.4.2) + ansi + builder + minitest (>= 5.0) + ruby-progressbar + msgpack (1.3.3) + multi_json (1.14.1) + multi_xml (0.6.0) + multipart-post (2.1.1) + nenv (0.3.0) + nio4r (2.5.2) + nokogiri (1.10.9) + mini_portile2 (~> 2.4.0) + notiffany (0.1.3) + nenv (~> 0.1) + shellany (~> 0.0) + oauth2 (1.4.4) + faraday (>= 0.8, < 2.0) + jwt (>= 1.0, < 3.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + omniauth (1.9.1) + hashie (>= 3.4.6) + rack (>= 1.6.2, < 3) + omniauth-github (1.4.0) + omniauth (~> 1.5) + omniauth-oauth2 (>= 1.4.0, < 2.0) + omniauth-oauth2 (1.6.0) + oauth2 (~> 1.1) + omniauth (~> 1.9) + pg (1.2.3) + pg_search (2.3.2) + activerecord (>= 5.2) + activesupport (>= 5.2) + popper_js (1.16.0) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-rails (0.3.9) + pry (>= 0.10.4) + public_suffix (4.0.5) + puma (4.3.5) + nio4r (~> 2.0) + rack (2.2.2) + rack-proxy (0.6.5) + rack + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (6.0.3.1) + actioncable (= 6.0.3.1) + actionmailbox (= 6.0.3.1) + actionmailer (= 6.0.3.1) + actionpack (= 6.0.3.1) + actiontext (= 6.0.3.1) + actionview (= 6.0.3.1) + activejob (= 6.0.3.1) + activemodel (= 6.0.3.1) + activerecord (= 6.0.3.1) + activestorage (= 6.0.3.1) + activesupport (= 6.0.3.1) + bundler (>= 1.3.0) + railties (= 6.0.3.1) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.4) + actionpack (>= 5.0.1.x) + actionview (>= 5.0.1.x) + activesupport (>= 5.0.1.x) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (6.0.3.1) + actionpack (= 6.0.3.1) + activesupport (= 6.0.3.1) + method_source + rake (>= 0.8.7) + thor (>= 0.20.3, < 2.0) + rake (13.0.1) + rb-fsevent (0.10.4) + rb-inotify (0.10.1) + ffi (~> 1.0) + regexp_parser (1.7.1) + ruby-debug-ide (0.7.2) + rake (>= 0.8.1) + ruby-progressbar (1.10.1) + rubyzip (2.3.0) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt + selenium-webdriver (3.142.7) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) + shellany (0.0.1) + simplecov (0.18.5) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov-html (0.12.2) + spring (2.1.0) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (4.0.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + thor (1.0.1) + thread_safe (0.3.6) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (1.2.7) + thread_safe (~> 0.1) + web-console (4.0.2) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) + bindex (>= 0.4.0) + railties (>= 6.0.0) + webdrivers (4.4.1) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (>= 3.0, < 4.0) + webpacker (4.2.2) + activesupport (>= 4.2) + rack-proxy (>= 0.6.1) + railties (>= 4.2) + websocket-driver (0.7.2) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + will_paginate (3.3.0) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.3.0) + +PLATFORMS + ruby + +DEPENDENCIES + better_errors + binding_of_caller + bootsnap (>= 1.4.2) + bootstrap + byebug + capybara (>= 2.15) + debase (>= 0.2.4.1) + dotenv-rails + faker! + guard + guard-minitest + jbuilder (~> 2.7) + jquery-rails + jquery-turbolinks + listen (~> 3.2) + minitest-rails + minitest-reporters + omniauth + omniauth-github + pg (>= 0.18, < 2.0) + pg_search + pry-rails + puma (~> 4.1) + rails (~> 6.0.3, >= 6.0.3.1) + rails-controller-testing + ruby-debug-ide (>= 0.7.0) + sass-rails (>= 6) + selenium-webdriver + simplecov + spring + spring-watcher-listen (~> 2.0.0) + turbolinks (~> 5) + tzinfo-data + web-console (>= 3.3.0) + webdrivers + webpacker (~> 4.0) + will_paginate (~> 3.0) + +RUBY VERSION + ruby 2.6.5p114 + +BUNDLED WITH + 2.1.4 diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000000..e34f706f4a --- /dev/null +++ b/Guardfile @@ -0,0 +1,9 @@ +guard :minitest, autorun: false, spring: true do + watch(%r{^app/(.+).rb$}) { |m| "test/#{m[1]}_test.rb" } + watch(%r{^app/controllers/application_controller.rb$}) { 'test/controllers' } + watch(%r{^app/controllers/(.+)_controller.rb$}) { |m| "test/integration/#{m[1]}_test.rb" } + watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" } + watch(%r{^lib/(.+).rb$}) { |m| "test/lib/#{m[1]}_test.rb" } + watch(%r{^test/.+_test.rb$}) + watch(%r{^test/test_helper.rb$}) { 'test' } +end diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000000..e85f913914 --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000000..44599c02ef --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,4 @@ +//= link_tree ../images +//= link_directory ../stylesheets .css +//= link AnimalCrossing.mp4 + diff --git a/app/assets/fonts/Arvo-Regular.ttf b/app/assets/fonts/Arvo-Regular.ttf new file mode 100644 index 0000000000..d8d0ec8901 Binary files /dev/null and b/app/assets/fonts/Arvo-Regular.ttf differ diff --git a/app/assets/images/.keep b/app/assets/images/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/images/dialogue.png b/app/assets/images/dialogue.png new file mode 100644 index 0000000000..5ed99b854d Binary files /dev/null and b/app/assets/images/dialogue.png differ diff --git a/app/assets/images/enter.png b/app/assets/images/enter.png new file mode 100644 index 0000000000..5ebd5d5110 Binary files /dev/null and b/app/assets/images/enter.png differ diff --git a/app/assets/images/pointer.png b/app/assets/images/pointer.png new file mode 100644 index 0000000000..bc5b0d6860 Binary files /dev/null and b/app/assets/images/pointer.png differ diff --git a/app/assets/images/timmytommy.png b/app/assets/images/timmytommy.png new file mode 100644 index 0000000000..1aebe880fb Binary files /dev/null and b/app/assets/images/timmytommy.png differ diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss new file mode 100644 index 0000000000..8992a6dc59 --- /dev/null +++ b/app/assets/stylesheets/application.scss @@ -0,0 +1,498 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + */ +/* Custom bootstrap variables must be set or imported *before* bootstrap. */ + +*, *::before, *::after { + box-sizing: border-box; + margin: 0; +} + +* { + font-family: 'Balsamiq Sans', cursive; +} + +.app-header__header { + width: 100%; + overflow: visible; + background-color: #f3f1d6; + box-shadow: -2px 2px 10px -4px rgba(26,26,26,1); + z-index: 1039; + box-sizing: border-box; +} + +.header-nav { + box-sizing: border-box; + z-index: 1039; + width: 100%; + background-color: #f3f1d6; + border-radius: 10px; +} + +.navbar-light .navbar-nav .nav-link { + color: rgba(0,0,0,.5); +} + +li { + display: list-item; + text-align: -webkit-match-parent; +} + +.nav-link { + color: #676764; + font-weight: 700; + padding: 0; +} + +.nav-link { + outline: none; + text-decoration: none; +} + +a { + background-color: transparent; +} + +//BACKGROUND SOURCE: https://codepen.io/damsenviet/pen/NBzLKN +.body { + margin: 20px; + min-height: 1em; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + + background-color: #FFE0AF; + background-image: + linear-gradient(45deg, #FFDD88 25%, transparent 25%, transparent 75%, #FFDD88 75%, #FFDD88), + linear-gradient(45deg, #FFDD88 25%, transparent 25%, transparent 75%, #FFDD88 75%, #FFDD88), + linear-gradient(45deg, transparent, transparent 50%, #FFC87F 50%, #FFC87F); + background-size: 100px 100px; + background-position: 0 0, 50px 50px, 50px 0px; + -webkit-animation: scroll 5s linear infinite; +} + +@-webkit-keyframes scroll { + from { background-position: 0 0, 50px 50px, 50px 0; } + to { background-position: -100px -100px, -50px -50px, -50px -100px; } +} + +// See application.js for resources used for scrolling pause +.body.paused{ + -webkit-animation-play-state: paused; + animation-play-state: paused; +} + +a.pause { + // background: url(/images/pointer.png) no-repeat; + background: url('https://i.ibb.co/MRT2wDL/pointer.png') no-repeat; + cursor:pointer; + border: none; +} + +// a.btn{position:absolute;z-index:999999999999;white-space:nowrap;outline:0;text-decoration:none;cursor:pointer; :hidden;font:600 12px/18px "Helvetica Neue","HelveticaNeue",Helvetica,Arial,sans-serif;height:20px;padding:0 5px;-webkit-font-smoothing:antialiased;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;-o-box-sizing:border-box;box-sizing:border-box;-webkit-transition-property:padding;-moz-transition-property:padding;-ms-transition-property:padding;-o-transition-property:padding;transition-property:padding;-webkit-transition-duration:.1s;-moz-transition-duration:.1s;-ms-transition-duration:.1s;-o-transition-duration:.1s;transition-duration:.1s;-webkit-transition-timing-function:ease;-moz-transition-timing-function:ease;-ms-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.btn{color:#fff;border:1px solid rgba(0,0,0,0.18);background:rgba(0,0,0,0.38);text-shadow:1px 1px 0 rgba(0,0,0,0.08)}a.btn,a.btn:hover{color:white!important}.btn{margin-bottom:5px;color:#fff;border:1px solid rgba(0,0,0,0.18);background:rgba(0,0,0,0.38);text-shadow:1px 1px 0 rgba(0,0,0,0.08);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.btn:hover::after,.btn:focus::after{background:rgba(255,255,255,0.09);color:white}.btn:active::after{background:rgba(255,255,255,0.18); color:white}.btn_label.show{display:block}.btn::after{position:absolute;top:0;right:0;bottom:0;left:0;content:'';-webkit-border-radius:inherit;-moz-border-radius:inherit;border-radius:inherit}.btn.icon::before{display:block;content:'';position:absolute;top:0;left:0;bottom:0;width:20px;border-radius:inherit;background:url('http://static.tumblr.com/tpqedpr/cQ1mbwb60/de.png') 0 0 no-repeat}.btn.theme::before{background-position:0 -0px}.btn img{width:15px}.btn.icon{padding-left:20px}.btn:active::after {background:rgba(255,255,255,0.18)}.clear {clear: both;} #pagination {display: all;} + +@import "bootstrap"; +@import "**/*"; + +nav > ul > li { + list-style-type: none; +} + +.dropdown-menu { + height: 200px; + overflow: auto; + border: 0; +} + +.right-btn { + position: absolute; + right: 10px; + font-size: 18px; +} + + +.app-header { + position: fixed; + top: 0; + left: 0; + margin-bottom: 50px; + color: #fff; +} + + +.navbar { + background-color: #fff; + background-size: 25%; + height: 175px; +} + +.nav-back { + background-color: rgba(255,255,255, 0.9); + border-radius: 25px; +} + +.pause-button { + position: fixed; + top: 180px; + left: 50px; + z-index: 5; + background-image: url('https://i.ibb.co/MRT2wDL/pointer.png'); + height: 60px; + width: 180px; + background-size: 100%; + margin-bottom: 50px; +} + +.top-container { + display: flex; + flex-direction: row; + align-items: center; +} + +.flash-msg__section { + position: absolute; + top: 130px; + width: 100%; + text-align: center; + z-index: 6; +} + +.alert { + position: relative; + padding: 0.75rem 1.25rem; + margin-top: 100px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 0.25rem; + text-align: center; + z-index: 2; +} + +.alert-success { + color: #155724; + background-color: #d4edda; + border-color: #c3e6cb; +} + +.alert-error { + color: #856404; + background-color: #fff3cd; + border-color: #ffeeba; +} + +img:hover { + /* Start the shake animation and make the animation last for 0.5 seconds */ + animation: shake 0.5s; + + /* When the animation is finished, start again */ + animation-iteration-count: 0.5; +} + +@keyframes shake { + 0% { transform: translate(1px, 1px) rotate(0deg); } + 10% { transform: translate(-1px, -2px) rotate(-1deg); } + 20% { transform: translate(-3px, 0px) rotate(1deg); } + 30% { transform: translate(3px, 2px) rotate(0deg); } + 40% { transform: translate(1px, -1px) rotate(1deg); } + 50% { transform: translate(-1px, 2px) rotate(-1deg); } + 60% { transform: translate(-3px, 1px) rotate(0deg); } + 70% { transform: translate(3px, 1px) rotate(-1deg); } + 80% { transform: translate(-1px, -1px) rotate(1deg); } + 90% { transform: translate(1px, 2px) rotate(0deg); } + 100% { transform: translate(1px, -2px) rotate(-1deg); } +} + +.pointer { cursor: pointer; } + +.form-control-review { + width: 50%; + opacity: 0.7; + display: flex; + justify-content: center; + align-items: center; + margin-left: auto; + margin-right: auto; + border: 0; + border-radius: 10px; + outline: none; +} + +.form-control { + opacity: 0.8; + display: flex; + justify-content: center; + align-items: center; + border: 0; +} + +.form-control-category { + align-items: flex-start; + width: 50%; + opacity: 0.8; + border: 0; +} + +// search - reference: https://codepen.io/code-district/pen/YzyvKPg +input[type="search"] { + -webkit-appearance: none !important; + background-clip: padding-box; + background-color: white; + vertical-align: middle; + border-radius: 0.25rem; + border: 1px solid #e0e0e5; + font-size: 1rem; + width: 100%; + line-height: 2; + padding: 0.375rem 1.25rem; + -webkit-transition: border-color 0.2s; + -moz-transition: border-color 0.2s; + transition: border-color 0.2s; +} + +input[type="search"]:focus { + transition: all 0.5s; + box-shadow: 0 0 40px #f9d442b9; + border-color: #f9d342; + outline: none; +} + +form.search-form { + display: flex; + justify-content: center; +} + +.search-label { + flex-grow: 1; + flex-shrink: 0; + flex-basis: auto; + margin-bottom: 0; + margin-right: 20px; + margin-left: 30px; + max-width: 180px; +} + +input.search-field { + margin-bottom: 0; + flex-grow: 1; + flex-shrink: 0; + flex-basis: auto; + align-self: center; + height: 45px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + opacity: 0.8; +} + +button.search-submit { + height: 45px; + margin: 0; + padding: 1rem 1.3rem; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + font-family: "Font Awesome 5 Free"; + font-size: 1rem; +} + +.screen-reader-text { + clip: rect(1px, 1px, 1px, 1px); + position: absolute !important; + height: 1px; + width: 1px; + overflow: hidden; +} + +.button { + display: inline-block; + font-weight: 600; + font-size: 0.8rem; + line-height: 1.15; + letter-spacing: 0.1rem; + text-transform: uppercase; + background: #ffdd88; + color: #292826; + border: 1px solid transparent; + vertical-align: middle; + text-shadow: none; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + transition: all 0.2s; +} + +.button:hover, +.button:active, +.button:focus { + cursor: pointer; + background: #d4b743; + color: #292826; + outline: 0; +} + +.btn-primary:hover { + background-color: #947339; + border: 0; +} + +.cart_img { + height: 60px; +} + +.cart-container { + position: relative; + display: inline-block; +} + +@media only screen and (min-width: 990px) { + .navbar-right { + position: fixed; + top: 10px; + right: 20px; + } + + .search-label { + // position: fixed; + position: absolute; + right: 20px; + top: 100px; + } + + .fixed-navbar { + // position: fixed; + position: absolute; + // top: 50px; + top: 30px; + display: flex; + flex-direction: column; + z-index: 1; + } +} + +@media only screen and (max-width: 989px) { + .dropdown-menu { + border: 0; + width: 100%; + left: 0; + right: 0; + } + + .navbar-collapse { + padding: 20px; + z-index: -1; + } + + .navbar { + margin: 0; + padding: 0; + height: 150px; + } + + .nooksy { + padding-left: 15px; + } +} + +.notify-badge { + position: absolute; + margin-left: 45px; + margin-bottom: 50px; + background: red; + text-align: center; + border-radius: 30px; + color:white; + padding: 5px 10px; + font-size: 9px; + font-weight: bold; +} + +image { + cursor: pointer; +} + +.nooksy { + position: absolute; + top: 0; +} + +button.navbar-toggler { + border: solid red; + position: absolute; + top: 10px; + right: 10px; +} + +.margin-top { + margin-top: 100px; +} + +.content_container { + padding-top: 250px; + min-height: 5em; + padding-left: 50px; + padding-right: 50px; + padding-bottom: 50px; +} + +.footer { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + height: 170px; + color: white; + text-align: center; + background-color: rgb(58, 222, 178); + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + padding-top: 30px; +} + +.social_footer_img { + height: 30px; + width: auto; + margin: 5px; +} + +.social_media_section { + display: flex; + flex-direction: column; + width: 300px; + grid-column-start: 3; + padding-right: 35px; + align-items: center; +} + +.social_imgs_row { + display: flex; + flex-direction: row; +} + +.footer_headline_font { + font-size: 20px; + text-align: center; + padding-bottom: 20px; +} + +.learn_more_section { + grid-column-start: 2; +} + + +.nooksy-logo { + position: absolute; + top: 0px; + width: 200px; + z-index: 2; +} \ No newline at end of file diff --git a/app/assets/stylesheets/categories.scss b/app/assets/stylesheets/categories.scss new file mode 100644 index 0000000000..01d6df8a00 --- /dev/null +++ b/app/assets/stylesheets/categories.scss @@ -0,0 +1,31 @@ +// Place all the styles related to the Categories controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ + +.category__form-container { + display: flex; + flex-direction: column; + margin-left: auto; + margin-right: auto; + justify-content: center; + width: 500px; +} + +.category__form-title { + text-align: center; + margin-top: 0; + margin-bottom: 50px; +} + +.category_index-container { + margin-top: 50px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + max-width: 65%; + justify-content: center; + align-items: center; + margin-left: auto; + margin-right: auto; + color: #fff; +} diff --git a/app/assets/stylesheets/orderitems.scss b/app/assets/stylesheets/orderitems.scss new file mode 100644 index 0000000000..fe26cd763e --- /dev/null +++ b/app/assets/stylesheets/orderitems.scss @@ -0,0 +1,48 @@ +// Place all the styles related to the orderitems controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ +.qty { + align-items: center; + justify-items: center; +} + +.cart_total { + // background-image: url('dialogue.png'); + background-image: url('https://i.ibb.co/Tqn1TQ3/dialogue.png'); + background-size: 100%; + height: 150px; + width: 450px; + padding: 20px; + // display: flex; + // flex-direction: row-reverse; + // margin-left: 60%; + // margin-right: 50px; + margin-bottom: 50px; + position: absolute; + right: 0px; +} + +.total { + font-size: 40px; + padding-left: 30%; + padding-top: 30px; +} + +.checkout-btn { + justify-self: right; +} + +.empty_cart { + display: flex; + margin-top: 50px; + font-size: 40px; + padding: 15px; + justify-content: center; + align-items: center; + color: white; + text-align: center; + // width: 80vw; + width: 100%; + background-color: rgba(122, 144, 77, 0.6); + border-radius: 25px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/orders.scss b/app/assets/stylesheets/orders.scss new file mode 100644 index 0000000000..99134ffd36 --- /dev/null +++ b/app/assets/stylesheets/orders.scss @@ -0,0 +1,26 @@ +// Place all the styles related to the orders controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ +.checkout { + // text-align: center; + // align-self: center; + background-color: rgba(122, 144, 77,0.6); + border-radius: 25px; + width: fit-content; + padding: 20px; + margin-left: 45%; + margin-bottom: 25px; +} + +.sales_info { + padding: 50px 200px; +} + +.cart_view { + margin-top: 30px; + position: relative; +} + +.ordered_product-img { + width: 50px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/pages.scss b/app/assets/stylesheets/pages.scss new file mode 100644 index 0000000000..0ae0f8bc0a --- /dev/null +++ b/app/assets/stylesheets/pages.scss @@ -0,0 +1,286 @@ +// Place all the styles related to the pages controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ + +.home_video { + width: 100vw; + height: 100vh; + position: absolute; + object-fit: cover; + top: 0; + left: 0; + z-index: -2; +} + + +h1.home { + color: white; + padding-left: 50%; + padding-right: 50%; + align-self: center; +} + +.welcome-link { + position: absolute; + bottom: 10px; + right: 25%; + left: 50%; + margin-left:-150px; +} + +.frontpage { + display: flex; + flex-direction: column; + align-items: center; +} + +.carousel { + padding-bottom: 80px; + // width:80%; + margin-top: 0; + padding-top: 0; + width: 100%; + height:auto; +} + +.phone_app { + display: flex; + align-items: center; + justify-content: center; + // align-items: space-evenly; + padding-top: 40px; + padding-left: 10%; +} + +.frontpage_feature { + max-height: 400px; + // width: 600px; + max-width: 400px; + padding: 100px; + margin: 100px; + background: rgba(131,75,22,0.75); + border-radius: 25px; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.frontpage_feature_title { + color: white; + font-size: 80px; + position: relative; + text-align: center; +} + +.frontpage_feature_img { + border-radius: 25px; + box-sizing: border-box; + max-width: 350px; +} + +.download_img { + height: 50px; + width: 80px; + // padding-left: 25px; +} + + .spotlight { + display: flex; + flex-direction: row; + padding-bottom: 50px; + height: 500px; + } + + .new_product { + background-color: rgba(131,75,22,0.75); + border-radius: 25px; + // margin-right: 10%; + border: solid white 5px; + box-sizing: border-box; + max-height: 255px; + } + + .new_product > img { + width: 150px; + } + + .featured_merchant_spotlight h4 { + padding: 20px; + } + + .merchant_spotlight_card { + display: flex; + flex-direction: row; + padding-left: 80px; + } + + .merchant_img { + // width: 125px; + width: 130px; + } + + .merchant_details { + padding-left: 20px; + width: 300px; + margin-top: 30px; + margin-left: 10px; + } + + .catchphrase { + font-size: 40px; + // margin-top: 40px; + margin-top: 20%; + // padding: 20px; + // background-color:#7a904d; + border-radius: 25px; + position: absolute; + color: #000; + // z-index: 3 + font-size: 30px; + margin-left: 10px; + } + + .slider { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + // width: 80vw; + width: 100%; + max-height: 350px; + overflow: scroll; + background-color: rgba(255,255,255, 0.5); + border-radius: 25px; + } + + .popular_products { + display: flex; + font-size: 40px; + padding: 15px; + justify-content: center; + align-items: center; + color: white; + text-align: center; + // width: 80vw; + width: 100%; + background-color: rgba(122, 144, 77, 0.6); + border-radius: 25px; + } + + .slider_card { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 210px; + background-color: rgb(255,255,255); + padding: 25px; + margin: 25px; + border-radius: 25px; + height: 300px; + } + + + .slider_details { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 200px; + // padding-right: 25px; + padding-top: 25px; + text-align: center; + } + + +.spotlight { + display: flex; + flex-direction: row; + padding-bottom: 50px; + height: 500px; +} + + +.newest_product_spotlight { + // background-color: rgba(84, 212, 252, 0.7); + background-color: #fff; + opacity: 0.9; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: #000; + border-radius: 25px; + // width: 80%; + padding: 60px; + padding-top: 40px; + box-sizing: border-box; + max-width: 500px; + // margin-left: 40px; + text-align: center; +} + +.newest_product_spotlight h4 { + padding: 20px; +} + +.new_product_card { + display: flex; + flex-direction: column; + z-index: 2; +} + + + +.featured_merchant_spotlight { + // background-color: rgba(28, 124, 36, 0.7); + background-color: #fff; + width: 500px; + opacity: 0.9; + color: #000; + display: flex; + flex-direction: column; + align-items: center; + // color: white; + border-radius: 25px; + // width: fit-content; + padding: 60px; + padding-top: 40px; + box-sizing: border-box; + // width: 80%; + margin-left: 30px; + z-index: 1; +} + +// .merchant_spotlight_card { +// display: flex; +// flex-direction: row; +// } + +// .merchant_img { +// height: 200px; +// border-radius: 25px; +// margin-right: 20%; +// } + + +.slider_img { + height: 100px; + width: auto; + // padding-left: 25%; +} + + +.home-video-wrapper { + height: 100vh; + display: flex; +} + +h1.home { + color: white; + padding-left: 50%; + padding-right: 50%; + align-self: center; +} diff --git a/app/assets/stylesheets/products.scss b/app/assets/stylesheets/products.scss new file mode 100644 index 0000000000..00c8036905 --- /dev/null +++ b/app/assets/stylesheets/products.scss @@ -0,0 +1,249 @@ +// Place all the styles related to the Products controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ + +a { + color: #000; +} + +.products__index_container { + display: flex; + flex-direction: row; + justify-content: center; + flex-wrap: wrap; +} + +.products__index_product-container { + display: flex; + flex-direction: column; + margin-left: 20px; + margin-right: 20px; + background-color: rgba(125, 78, 9, 0.5); + border: solid white 7px; + border-radius: 25px; + padding: 20px; + margin: 20px; +} + +.products__index_product-info-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + + +.products__index_product-img { + display: flex; + width: 150px; + flex-direction: column; + margin-left: auto; + margin-right: auto; +} + + +.products__show_product-img { + position: relative; + top: -50px; + display: flex; + width: 150px; + flex-direction: column; + margin-left: auto; + margin-right: auto; +} + +.products__show_container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + max-width: 500px; + min-width: 400px; + margin-bottom: 0; + padding-bottom: 0; +} + +.products__show_detail-container { + margin: 0; + padding: 0; + position: relative; + top: -30px; + display: flex; + flex-direction: column;; + margin-left: auto; + margin-right: auto; + justify-content: center; + align-items: center; +} + +.products__form-container { + margin: 30px; +} + +.products__show-product-name { + font-size: 30px; +} + +body { + background-color: #EDF1F3; +} + +.bar { + color: #FFF; + background-color: #EFD679; + padding: 35px; + width: 400px; + margin: 50px auto 0; + font: 35px/50px 'Bree Serif', Courier, monospaced; + text-align: center; + position: relative; + text-transform: uppercase; + border: 2px transparent solid; + box-shadow: 0 10px 30px -10px gray; +} + +.bar span { + position: absolute; +} + +.bar span:nth-child(1),.bar span:nth-child(3) { + border-style: solid; + border-width: 15px; + z-index: -1; +} +.bar span:nth-child(1) { + border-color: #000 #000 transparent transparent; + top: 120px; + left: -2px; +} +.bar span:nth-child(3) { + border-color: #000 transparent transparent #000 ; + top: 120px; + left: 442px; +} + +.bar span:nth-child(2), .bar span:nth-child(4) { + top: 30px; + border-style: solid; + border-width: 60px; + z-index: -2; +} +.bar span:nth-child(2) { + border-color: #E8BA85 #E8BA85 #E8BA85 transparent; + left: -90px; + box-shadow: 20px 20px 30px -10px grey; +} + +.bar span:nth-child(4) { + border-color: #E8BA85 transparent #E8BA85 #E8BA85; + left: 440px; + box-shadow: -20px 19px 30px -10px grey; +} + +.reviews__container { + margin-top: 25px; + min-height: 500px; + margin-bottom: 200px; +} + +.reviews__form-container { + padding-bottom: 250px; +} + +.review-stars { + font-size: 30px; + color: #fd9b07; +} + +.review-comment { + font-size: 20px; +} + +.average-rating-container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + justify-content: center; +} + +.reviews-average-rating { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + +} + +.average-rating { + color: #fd9b07; + font-size: 50px; +} + +.large-review { + font-size: 50px; +} + +.small-review { + display: flex; + flex-direction: column; + max-width: 50px; + font-size: 15px; +} + +.product__form-container { + display: flex; + flex-direction: column; + margin-left: auto; + margin-right: auto; + justify-content: center; + width: 500px; +} + +.products__form-title { + text-align: center; + margin-top: 0; + margin-bottom: 50px; +} + +.search-result-container { + opacity: 0.5; + background: #fff; + border-radius: 10px; + padding-right: 20px; + list-style: none; + display: flex; + flex-direction: row; + padding: 10px; +} + +.search-result-container > li { + padding-left: 10px; +} + +.search-result-container > li::after { + content: "|"; + padding-left: 10px; +} + +.search-result-container > li:last-child::after { + content: ""; +} + +.small-stars { + color: #fd9b07; +} + +.yellow-font { + color: #FFDD88; + margin-top: 20px; +} + + +.search-result-title { + margin-bottom: 50px; +} + +.review { + padding: 20px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/reviews.scss b/app/assets/stylesheets/reviews.scss new file mode 100644 index 0000000000..8b738f8cdb --- /dev/null +++ b/app/assets/stylesheets/reviews.scss @@ -0,0 +1,15 @@ +// Place all the styles related to the Reviews controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ + +.reviews__container { + padding-top: 25px; + text-align: center; + height: 300px; + // padding: 50px; +} + +.yellow-stars { + color: #fd9b07; + margin-right: 20px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss new file mode 100644 index 0000000000..0856e61ced --- /dev/null +++ b/app/assets/stylesheets/users.scss @@ -0,0 +1,214 @@ +@font-face { + font-family: 'Fink Heavy'; + src: url('assets/fonts/FinkHeavy.ttf') +} + +.merchant_page { + display: grid; + grid-template-rows: 0.5fr 1fr; + align-content: space-between; + margin-bottom: 100px; +} + +.users__index_container { + display: flex; + flex-direction: row; + justify-content: center; + flex-wrap: wrap; + // width: 30%; +} + +// Background resource: https://animalcrossingqrdesigns.tumblr.com/post/180286998342/amiibo-card-background + +.users__show_container { + border-radius: 25px; + margin: 50px; + margin-top: 20px; + display: flex; + flex-direction: column; + align-items: center; + justify-items: center; + // background: rgba(131,75,22,0.75); + background-image: url('https://66.media.tumblr.com/dcd57734b3f15d82e70aa661a10008cc/tumblr_pi7a1r5W3d1ts4uamo1_500.png'); + background-size: 400px auto; + width: 400px; + height: 500px; + padding-top: 50px; + justify-self: center; +} + +.users__show_container h2 { + font-size: 23px; +} + +.user_product-container .show_page { + margin-top: 0; + padding-top: 0; + grid-row-start: 2; +} + +.users__index_user-container { + height: 200px; + width: 175px; + border-radius: 25px; + margin: 50px; + display: flex; + flex-direction: column; + align-items: center; + justify-items: center; + // background: rgba(131,75,22,0.75); + background-image: url('https://66.media.tumblr.com/dcd57734b3f15d82e70aa661a10008cc/tumblr_pi7a1r5W3d1ts4uamo1_500.png'); + background-size: 175px auto; +} + +.user_image { + padding-top: 30px; + height: 170px; +} + +.user_name { + line-height: 1.35; + font-size: 1.5rem; + padding: 15px 45px; + font-weight: 700; + color: white; + text-shadow: 0 3px 2px rgba(0,0,0,0.3); +} + +.pages { + display: flex; + flex-direction: row; + justify-content: center; +} + +.products__show_container { + height: 500px; + width: 40%; + border-radius: 25%; + margin: 50px; + display: flex; + flex-direction: column; + align-items: center; + justify-items: center; + background: rgba(131,75,22,0.75); + // position: fixed; + /* center the element */ + right: 0; + left: 0; + margin-right: auto; + margin-left: auto; + /* give it dimensions */ + min-height: 10em; + +} + +.users__show_detail-container { + display: flex; + flex-direction: column; + justify-content: space-around; + // justify-content: center; + text-align: center; + padding: 15px; + margin: 30px; + // margin-bottom: 0; + background-color: rgba(191, 48, 57, 0.6); + border-radius: 25px; +} + +h2 { + color: white; +} + +.row { + display: flex; + flex-direction: row; + justify-content: space-evenly; +} + +.merchant_dashboard_page { + display: flex; + flex-direction: column; + align-items: center; + margin-top: 0px; +} + +.dashboard_product_image { + height: 100px; + width: 100px; +} + +.product_dashboard { + padding: 30px; + background-image: url("https://bit.ly/3e99t37"); + margin: 15px; + border-radius: 25px; + min-height: 800px; + margin-bottom: 100px; +} + +.table { + font-size: 16px; +} + +.thead { + background-color: #E1D24D; +} + +td, th { + height: fit-content; + text-align: center; +} + +tr:hover { + background-image: url("https://bit.ly/2AxPvjE"); + opacity: 60%; +} + +.btn-primary { + background-color: #7a904d; + border-color: #7a904d; +} + +.btn { + padding: 10px 20px; + text-align: center; + text-decoration: none; + display: inline-block; + margin: 4px 2px; + cursor: pointer; + border-radius: 16px; +} + +.merchant_stats { + display: flex; + flex-direction: row; + justify-content: center; + margin-top: 50px; + background-color: #fff; + opacity: 0.5; + border-radius: 25px; + // width: fit-content; +} + +.total_revenue { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: #000; + padding: 60px; + box-sizing: border-box; + max-width: 500px; + text-align: center; +} + +.revenue_section { + display: flex; + flex-direction: row; +} + +.revenue_callout { + margin: 20px; + padding: 10px; +} + diff --git a/app/assets/videos/AnimalCrossing.mp4 b/app/assets/videos/AnimalCrossing.mp4 new file mode 100644 index 0000000000..89835b6370 Binary files /dev/null and b/app/assets/videos/AnimalCrossing.mp4 differ diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000000..d672697283 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000000..0ff5442f47 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000000..db27768530 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,26 @@ +class ApplicationController < ActionController::Base + before_action :set_users, :current_user + + private + def set_users + @users = User.all + end + + def render_404 + render :file => "#{Rails.root}/public/404.html", layout: false, status: :not_found + return + end + + def current_user + if session[:user_id] + @login_user = User.find_by(id: session[:user_id]) + end + end + + def require_login + if current_user.nil? + flash[:error] = "You must be logged in to do that" + redirect_back(fallback_location: frontpage_path) + end + end +end diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb new file mode 100644 index 0000000000..1415f6a9c0 --- /dev/null +++ b/app/controllers/categories_controller.rb @@ -0,0 +1,55 @@ +class CategoriesController < ApplicationController + helper_method :render_404, :require_login + + around_action :require_login, only: [:new, :update], if: -> { !@login_user } + before_action :find_category, only: [:show, :edit, :update, :destroy] + around_action :render_404, only: [:show, :edit, :update, :destroy], if: -> { @category.nil? } + + def index + @categories = Category.all.order(:name) + end + + def show + end + + def new + @category = Category.new + end + + def create + @category = Category.new(category_params) + + if @category.save + flash[:success] = "#{@category.name} was successfully added! 😄" + redirect_to categories_path + return + else + flash.now[:error] = "A problem occurred: Could not update '#{@category.name}'" + render :new + return + end + end + + def update + if @category.update(category_params) + flash[:success] = "#{@category.name} was successfully edited! 😄" + redirect_to category_path(@category.id) + return + else + flash.now[:error] = "The category was not successfully edited :(" + render :edit + return + end + end + + private + + def category_params + return params.require(:category).permit(:name) + end + + def find_category + category_id = params[:id] + @category = Category.find_by(id: category_id) + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/controllers/orderitems_controller.rb b/app/controllers/orderitems_controller.rb new file mode 100644 index 0000000000..4f5382a467 --- /dev/null +++ b/app/controllers/orderitems_controller.rb @@ -0,0 +1,110 @@ +class OrderitemsController < ApplicationController + before_action :find_order_item, only: [:create] + + def index + end + + def create + if !session[:cart] + session[:cart] = Array.new + end + + product = Product.find_by(id: params["product_id"]) + + quantity = params["quantity"].to_i + + session[:cart].each do |item| + if item['product_id'] == product.id + if item['quantity'] < product.inventory + item["quantity"] += 1 + flash[:success] = "Item added to shopping cart." + redirect_to cart_path + return + elsif item['quantity'] == product.inventory + flash[:error] = "There is no inventory left. Item cannot be added to cart." + redirect_to cart_path + return + end + end + end + + @orderitem = OrderItem.new( + quantity: quantity, + product_id: product.id, + ) + + if @orderitem.save + session[:cart] << @orderitem + flash[:success] = "#{product.name} was successfully added to shopping cart! 😄" + redirect_to product_path(product) + return + else + flash.now[:error] = "A problem occurred: Could not update #{Product.find_by(id: @orderitem.product_id).name} - : #{@orderitem.errors.messages}" + render :new, status: :bad_request + return + end + + flash[:error] = "There is no inventory left. Item cannot be added to cart." + + redirect_to product_path(product) + return + end + + def increase_quantity + return "You have nothing in your cart. :( " if !session[:cart] + + product = Product.find_by(id: params["format"]).inventory + + + session[:cart].each do |item| + if item["product_id"] == params['format'].to_i && item['quantity'] < product + item["quantity"] += 1 + flash[:success] = "Item added to shopping cart." + elsif item["product_id"] == params['format'].to_i && item['quantity'] == product + flash[:error] = "WARNING: There is no inventory left. No additional items can be added to cart." + end + end + + fallback_location = orderitems_path + redirect_back(fallback_location: fallback_location) + return + end + + def decrease_quantity + return "You have nothing in your cart. :( " if !session[:cart] + + session[:cart].each do |item| + curr_product = Product.find(item["product_id"]) + if curr_product.active == false + flash[:error] = "Cart error. Inactive item!" + redirect_back(fallback_location: orderitems_path) + return + + end + + + if curr_product.inventory == 0 + flash[:error] = "Cart error. Quantity cannot fall below 1." + redirect_back(fallback_location: orderitems_path) + return + end + + if item["product_id"] == params['format'].to_i + item["quantity"] > 1 ? item["quantity"] -= 1 : session[:cart].delete(item) + end + + + end + + flash[:success] = "Item removed from shopping cart." + fallback_location = orderitems_path + redirect_back(fallback_location: fallback_location) + return + end + + private + + def find_order_item + @order_item = OrderItem.find_by(id: params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 0000000000..cd26597743 --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,85 @@ +class OrdersController < ApplicationController + before_action :require_login, only: [:ordered, :index] + + def index + @merchant_orders = [] + @merchant_products = [] + + Order.all.each do |order| + order.order_items.each do |item| + merchant_product = Product.find_by(id: item.product_id) + + if session[:user_id] == merchant_product.user_id + if !@merchant_orders.include?(order) + @merchant_orders << order + @merchant_products << merchant_product + end + end + end + end + end + + def new + @order = Order.new + end + + def create + @order = Order.new(order_params) + + if @order.save + if session[:cart] + session[:cart].each do |item| + ordered_item = OrderItem.find_by(id: item['id']) + product = Product.find_by(id: item['product_id']) + product.remove_inventory(item['quantity']) + + ordered_item.order_id = @order.id + @order.order_items << ordered_item + end + + session[:cart] = [] + flash[:success] = "Your order was successfully placed!" + redirect_to order_path(@order) + return + end + else + flash.now[:error] = "A problem occurred: Could not update #{@order.name} - : #{@order.errors.messages}" + render :new, status: :bad_request + return + end + end + + def show + @order = Order.find_by(id: params['id']) + + if @order.nil? + redirect_back(fallback_location: root_path) + return + end + + if @order.status == "pending" + redirect_to cart_path + return + end + end + + def mark_shipped + order = Order.find_by(id: params['format']) + order.mark_shipped + + if order.status == 'shipped' + flash[:success] = "Order was successfully shipped! 😄" + redirect_to orders_path + end + end + + def ordered + @order = Order.find_by(id: params['id']) + end + + private + + def order_params + return params.require(:order).permit(:status, :name, :email_address, :address, :city, :state, :zipcode, :cc_num, :cc_exp_month, :cc_exp_year, :cc_cvv, :order_date, :user_id) + end +end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb new file mode 100644 index 0000000000..6bfc6e9211 --- /dev/null +++ b/app/controllers/pages_controller.rb @@ -0,0 +1,9 @@ +class PagesController < ApplicationController + def home + end + + def frontpage + end + +end + diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 0000000000..7f5cb7592d --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,97 @@ +class ProductsController < ApplicationController + helper_method :current_user, :render_404, :require_login + + before_action :find_product, only: [:show, :edit, :update, :destroy, :toggle_status] + + around_action :require_login, only: [:new, :create, :edit, :update, :destroy, :toggle_status], if: -> { !@login_user } + around_action :render_404, only: [:show, :edit, :update, :destroy, :toggle_status], if: -> { @product.nil? } + around_action :check_authorization, only: [:edit, :update, :destroy, :toggle_status], if: -> { @login_user && @login_user != @product.user } + + + def index + @products = Product.where(active: true).order(:name).paginate(:page=>params[:page],:per_page=>15) + end + + def show + @product.inactivate_product + end + + def new + @product = Product.new + end + + def create + @product = Product.new(product_params) + @product.user_id = @login_user.id + + if @product.save + flash[:success] = "#{@product.name} was successfully added! 😄" + redirect_to product_path(@product) + return + else + flash.now[:error] = "A problem occurred: Could not update #{@product.name} - : #{@product.errors.messages}" + render :new, status: :bad_request + return + end + end + + def edit + end + + def update + + if @product.update(product_params) + + @product.inactivate_product + + flash[:success] = "#{@product.name} was successfully edited! 😄" + redirect_to dashboard_path + return + else + flash.now[:error] = "The product was not successfully edited :( - #{@product.errors.messages}" + render :edit, status: :bad_request + return + end + end + + def toggle_status + + if @product.change_status + flash[:success] = "#{@product.name}'s status was successfully updated! 😄" + redirect_to dashboard_path + return + end + end + + def search + if params[:search].blank? + flash[:error] = "Empty field!" + redirect_to(frontpage_path) + return + end + + @parameter = params[:search].downcase + @products = Product.where("lower(name) LIKE ? ", "%#{@parameter}%") + @categories = Category.where("lower(name) LIKE ? ", "%#{@parameter}%") + @users = User.where("lower(name) LIKE ? ", "%#{@parameter}%") + end + + private + + def product_params + return params.require(:product).permit(:name, :description, :inventory, :price, :photo_url, :active, category_ids: []) + end + + def find_product + product_id = params[:id] + @product = Product.find_by(id: product_id) + end + + def check_authorization + if @login_user && @login_user != @product.user + flash.now[:error] = "A problem occurred: You are not authorized to perform this action. This is not your product." + redirect_to dashboard_path + return + end + end +end diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb new file mode 100644 index 0000000000..cae6c45be0 --- /dev/null +++ b/app/controllers/reviews_controller.rb @@ -0,0 +1,55 @@ +class ReviewsController < ApplicationController + FIELDS = [:rating, :description, :product_id, :reviewer] + + def new + @review = Review.new + @product = find_product + end + + def create + @product = find_product + + + if @login_user && (@login_user.id == @product.user_id) + flash[:error] = "A problem occurred: Cannot add a review for your own product!" + redirect_back(fallback_location: root_path) + return + + else + + if @login_user + @review = Review.new(review_params) + @review.reviewer = @login_user.name + else + @review = Review.new(review_params) + end + + if @review.save + flash[:success] = "The review was successfully added! 😄" + else + messages = [] + + FIELDS.each do |field| + if @review.errors.messages.include?(field) + messages << "'#{field.capitalize}' - #{@review.errors.messages[field].join(", ")}" + end + end + + flash[:error] = "A problem occurred: Could not update the review \n\n#{messages.join(", ")}" + end + + redirect_back(fallback_location: root_path) + return + end + end + + private + + def review_params + return params.permit(*FIELDS) + end + + def find_product + return Product.find_by(id: params[:product_id]) + end +end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000000..03e604abe5 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,76 @@ +class UsersController < ApplicationController + helper_method :render_404 + + before_action :require_login, only: [:destroy, :dashboard] + + def index + @users = User.all.order(:name).paginate(:page=>params[:page],:per_page=>15) + end + + def show + @user = User.find_by(id: params['id']) + + if @user.nil? + return render_404 + end + end + + def create + auth_hash = request.env["omniauth.auth"] + + user = User.find_by(uid: auth_hash[:uid], provider: 'github') + + if user + flash[:success] = "Logged in as returning user #{user.name}" + else + + user = User.build_from_github(auth_hash) + + if user.save + flash[:success] = "Logged in as new user #{user.name}" + else + flash[:error] = "Could not create new user account: #{user.errors.messages}" + end + end + + session[:user_id] = user.id + redirect_back(fallback_location: frontpage_path) + return + end + + def destroy + session[:user_id] = nil + flash[:success] = "Successfully logged out!" + + redirect_back(fallback_location: frontpage_path) + return + end + + def dashboard + @user = User.find_by(id: session[:user_id]) + + @revenue = 0 + @paid_revenue = 0 + @paid_count = 0 + @shipped_revenue = 0 + @shipped_count = 0 + + Order.all.each do |order| + order.order_items.each do |item| + merchant_product = Product.find_by(id: item.product_id) + + if @user.id == merchant_product.user_id + @revenue += (item['quantity'] * merchant_product.price) + + if order.status == 'shipped' + @shipped_revenue += item['quantity'] * merchant_product.price + @shipped_count += 1 + elsif order.status == 'paid' + @paid_revenue += item['quantity'] * merchant_product.price + @paid_count += 1 + end + end + end + end + end +end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000000..de6be7945c --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/helpers/categories_helper.rb b/app/helpers/categories_helper.rb new file mode 100644 index 0000000000..e06f31554c --- /dev/null +++ b/app/helpers/categories_helper.rb @@ -0,0 +1,2 @@ +module CategoriesHelper +end diff --git a/app/helpers/orderitems_helper.rb b/app/helpers/orderitems_helper.rb new file mode 100644 index 0000000000..c74e407d1c --- /dev/null +++ b/app/helpers/orderitems_helper.rb @@ -0,0 +1,2 @@ +module OrderitemsHelper +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb new file mode 100644 index 0000000000..443227fd48 --- /dev/null +++ b/app/helpers/orders_helper.rb @@ -0,0 +1,2 @@ +module OrdersHelper +end diff --git a/app/helpers/pages_helper.rb b/app/helpers/pages_helper.rb new file mode 100644 index 0000000000..2c057fd054 --- /dev/null +++ b/app/helpers/pages_helper.rb @@ -0,0 +1,2 @@ +module PagesHelper +end diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 0000000000..ab5c42b325 --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,2 @@ +module ProductsHelper +end diff --git a/app/helpers/reviews_helper.rb b/app/helpers/reviews_helper.rb new file mode 100644 index 0000000000..682b7b1abc --- /dev/null +++ b/app/helpers/reviews_helper.rb @@ -0,0 +1,2 @@ +module ReviewsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000000..2310a240d7 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/javascript/channels/consumer.js b/app/javascript/channels/consumer.js new file mode 100644 index 0000000000..0eceb59b18 --- /dev/null +++ b/app/javascript/channels/consumer.js @@ -0,0 +1,6 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. + +import { createConsumer } from "@rails/actioncable" + +export default createConsumer() diff --git a/app/javascript/channels/index.js b/app/javascript/channels/index.js new file mode 100644 index 0000000000..0cfcf74919 --- /dev/null +++ b/app/javascript/channels/index.js @@ -0,0 +1,5 @@ +// Load all the channels within this directory and all subdirectories. +// Channel files must be named *_channel.js. + +const channels = require.context('.', true, /_channel\.js$/) +channels.keys().forEach(channels) diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js new file mode 100644 index 0000000000..c2562a487c --- /dev/null +++ b/app/javascript/packs/application.js @@ -0,0 +1,28 @@ +// This file is automatically compiled by Webpack, along with any other files +// present in this directory. You're encouraged to place your actual application logic in +// a relevant structure within app/javascript and only use these pack files to reference +// that code so it'll be compiled. + +require("@rails/ujs").start() +require("turbolinks").start() +require("@rails/activestorage").start() +require("channels") +import "bootstrap" + +// Resources used to make background pause: +// https://www.freecodecamp.org/news/how-to-add-javascript-to-your-rails-6-app/ +// https://codepen.io/dudleystorey/pen/knqyK +// http://jsfiddle.net/469Nw/3/ + +$(document).ready(function(){ + $('.btn').click(function(e){ + $('body').toggleClass('paused'); + }); +}); + +// Uncomment to copy all static images under ../images to the output folder and reference +// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) +// or the `imagePath` JavaScript helper below. +// +// const images = require.context('../images', true) +// const imagePath = (name) => images(name, true) diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000000..d394c3d106 --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,7 @@ +class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000000..286b2239d1 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000000..10a4cba84d --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/category.rb b/app/models/category.rb new file mode 100644 index 0000000000..d3d7e31e08 --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,10 @@ +class Category < ApplicationRecord + validates :name, uniqueness: true, presence: true + has_and_belongs_to_many :products, dependent: :nullify + + def self.search_result(parameter) + categories = self.where("lower(name) LIKE ? ", "%#{parameter}%") + + return categories.reduce(0) { |sum, category| sum + category.products.length } + end +end \ No newline at end of file diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 0000000000..fb9cd84f76 --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,42 @@ +require 'date' +require_relative '../validators/order_validator' + +class Order < ApplicationRecord + include ActiveModel::Validations + validates_with OrderValidator + + has_many :order_items, dependent: :destroy + has_many :products, through: :order_items + + validates :status, presence: true + validates :name, presence: {message: "Name can't be blank"}, :on => :update + validates :email_address, format: {with: /\A.+@.+\..{2,3}\z/, message: "E-mail address must be valid"}, :on => :update + validates :address, presence: {message: "Address can't be blank"}, :on => :update + validates :city, presence: {message: "City can't be blank"}, :on => :update + validates :state, format: {with: /\A[a-zA-Z]{2}\z/, message: "State must be two letters in length"}, :on => :update + validates :zipcode, format: {with: /\A\d{5}\z/, message: "Zip code must be 5 digits"}, :on => :update + validates :cc_cvv, format: {with: /\A\d{3,4}\z/, message: "Credit card CVV must be 3-4 numbers in length"}, :on => :update + + def total + return 0 if self.order_items.length == 0 + + order_total = 0 + + self.order_items.each do |item| + p = Product.find_by(id: item["product_id"]) + order_total += (p.price * item.quantity) + end + + return order_total + end + + def self.get_items(merchant_products) + merchant_products.each do |product| + return product.name + end + end + + def mark_shipped + self.update!(status: 'shipped') + end +end diff --git a/app/models/order_item.rb b/app/models/order_item.rb new file mode 100644 index 0000000000..69b5ebaba4 --- /dev/null +++ b/app/models/order_item.rb @@ -0,0 +1,14 @@ +class OrderItem < ApplicationRecord + validates :product_id, presence: true, numericality: {only_integer: true, greater_than: 0} + validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0 } + + def self.cart_count(session) + count = 0 + + session[:cart].each do |product| + count += product["quantity"] + end + + return count + end +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 0000000000..a6db244cd8 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,66 @@ +class Product < ApplicationRecord + validates :name, presence: true, uniqueness: true + validates :price, presence: true, numericality: {only_integer: true, greater_than: 0} + validates :inventory, numericality: {only_integer: true, greater_than: -1} + + + belongs_to :user + has_many :reviews, dependent: :destroy + has_many :order_items, dependent: :destroy + has_many :orders, :through => :order_items + has_and_belongs_to_many :categories, dependent: :destroy + + def change_status + if self.active + self.update!(active: false) + else + self.update!(active: true) + end + end + + def num_of_ratings + return self.reviews.length + end + + def average_rating + all_reviews = self.reviews + + if all_reviews.empty? + return 0 + else + ratings = all_reviews.sum { |review| review.rating } + avg_rating = (ratings / self.num_of_ratings.to_f) + return avg_rating.round(1) + end + end + + def display_categories + return self.categories.map { |category| category.name }.join(", ") + end + + def self.top_rated_products + result = self.all.sort_by { |product| + product.average_rating + }.reverse! + + return result.first(4) + end + + def self.popular_products + result = self.all.sort_by { |product| + product.num_of_ratings + }.reverse! + + return result.first(4) + end + + def inactivate_product + if self.inventory == 0 + self.update(active: false) + end + end + + def remove_inventory(quantity) + self.update!(inventory: (self.inventory - quantity)) + end +end \ No newline at end of file diff --git a/app/models/review.rb b/app/models/review.rb new file mode 100644 index 0000000000..21d8f62208 --- /dev/null +++ b/app/models/review.rb @@ -0,0 +1,14 @@ +class Review < ApplicationRecord + belongs_to :product + + validates :reviewer, presence: true + validates :product_id, presence: true + validates :description, presence: true + validates :rating, presence: true, numericality: {only_integer: true, greater_than: 0, less_than: 6} + + def self.display_rating(rating) + return "☆" * 5 if rating == 0 + empty_star_count = 5 - rating.to_i + return ("★" * rating) + ("☆" * empty_star_count) + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000000..f2e505e8f6 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,19 @@ +class User < ApplicationRecord + has_many :products + has_many :orders + + validates :name, uniqueness: true, presence: true + validates :email_address, uniqueness: true, presence: true + validates :uid, uniqueness: true, presence: true + + def self.build_from_github(auth_hash) + user = User.new + user.uid = auth_hash[:uid] + user.provider = "github" + user.username = auth_hash["info"]["name"] + user.name = auth_hash["info"]["nickname"] + user.email_address = auth_hash["info"]["email"] + + return user + end +end diff --git a/app/validators/order_validator.rb b/app/validators/order_validator.rb new file mode 100644 index 0000000000..db3bb48b3e --- /dev/null +++ b/app/validators/order_validator.rb @@ -0,0 +1,5 @@ +class OrderValidator < ActiveModel::Validator + def validate(record) + return true + end +end \ No newline at end of file diff --git a/app/views/categories/_form.html.erb b/app/views/categories/_form.html.erb new file mode 100644 index 0000000000..c655d1c38c --- /dev/null +++ b/app/views/categories/_form.html.erb @@ -0,0 +1,12 @@ +
+ <%= form_with model: @category do |f| %> + +
+ <%= f.label :category_name %> + <%= f.text_field :name, class: "form-control" %> +
+ + <%= f.submit action_name, class: "btn btn-primary" %> + + <% end %> +
diff --git a/app/views/categories/edit.html.erb b/app/views/categories/edit.html.erb new file mode 100644 index 0000000000..b87507e100 --- /dev/null +++ b/app/views/categories/edit.html.erb @@ -0,0 +1,4 @@ +
+

Edit this category

+ <%= render partial: "form", locals: { action_name: "Edit" } %> +
\ No newline at end of file diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb new file mode 100644 index 0000000000..b889adcc75 --- /dev/null +++ b/app/views/categories/index.html.erb @@ -0,0 +1,6 @@ +

All Categories

+
+ <% @categories.each do |category| %> +
<%= link_to "#{category.name}", category_path(category.id) %>
+ <% end %> +
diff --git a/app/views/categories/new.html.erb b/app/views/categories/new.html.erb new file mode 100644 index 0000000000..8ea2c21615 --- /dev/null +++ b/app/views/categories/new.html.erb @@ -0,0 +1,4 @@ +
+

Add a new category

+ <%= render partial: "form", locals: { action_name: "Add" } %> +
\ No newline at end of file diff --git a/app/views/categories/show.html.erb b/app/views/categories/show.html.erb new file mode 100644 index 0000000000..8b401cd15d --- /dev/null +++ b/app/views/categories/show.html.erb @@ -0,0 +1,15 @@ +

+ <%= @category.products.length %> results for + <%= @category.name %> +

+ +
+ <% if @category.products.empty? %> + <%= image_tag "https://hytsit.com/assets/frontend/images/noproduct.png" %> + <% else %> + + <% @category.products.each do |product| %> + <%= render partial: "products/search_result", locals: { product: product } %> + <% end %> + <% end %> +
\ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000000..6ec588c271 --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,122 @@ + + + + Nooksy + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> + <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> + <%= favicon_link_tag 'https://i.ibb.co/Fzk7PdR/tom.png' %> + <%= stylesheet_link_tag 'https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'%> + + + + <% +=begin%> + removes navigation and other styling for splash page +<% +=end%> +
+ <% unless action_name == "home" %> + + + <% end %> + + + <% flash.each do |name, message| %> +

+ <%= message %> +

+ <% end %> + + + <% unless action_name == "home" %> + + <% end %> +
+ <%= yield %> +
+
+ + + + +<%# button_tag - reference: https://stackoverflow.com/questions/16429542/how-do-i-add-an-i-to-the-text-of-a-submit-tag %> + +<%# https://stackoverflow.com/questions/22849913/ruby-on-rails-navigation-with-dynamic-content %> diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000000..cbd34d2e9d --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/app/views/orderitems/_cart.html.erb b/app/views/orderitems/_cart.html.erb new file mode 100644 index 0000000000..09414a694a --- /dev/null +++ b/app/views/orderitems/_cart.html.erb @@ -0,0 +1,33 @@ +
+ + + + + + + + + + + + + + <% if session[:cart] %> + <% session[:cart].each_with_index do |product, index| %> + <% p = Product.find_by(id: product["product_id"]) %> + + + + + + + + <% end %> + <% end %> + + +
ProductQuantitySold ByPrice
<%= link_to(image_tag(p.photo_url, :alt => "logo", class: 'dashboard_product_image'), product_path(p)) %><%= p.name %> + <%= button_to '-', subtract_path(p.id), method: :patch, class: 'btn btn-primary' %> + <%= session[:cart][index]["quantity"] %> + <%= button_to '+', add_path(p.id), method: :patch, class: 'btn btn-primary'%> + <%= User.find_by(id: p.user_id).name %><%= p.price %> Bells<%= button_to 'Product Page', product_path(p), method: :get, class: "btn btn-primary" %>
diff --git a/app/views/orderitems/index.html.erb b/app/views/orderitems/index.html.erb new file mode 100644 index 0000000000..bc6f185f37 --- /dev/null +++ b/app/views/orderitems/index.html.erb @@ -0,0 +1,15 @@ +<% if session[:cart].nil? %> +

Your cart is empty

+<% else %> + <%= render "cart" %> + + +
+ <% total = 0 %> + <% session[:cart].each do |product| %> + <% total += (Product.find_by(id: product['product_id']).price * product['quantity']) %> + <% end %> +

<%= total %> Bells

+ <%= button_to 'Checkout', new_order_path, class: 'btn btn-primary checkout-btn', method: :get %> +
+<% end %> \ No newline at end of file diff --git a/app/views/orderitems/new.html.erb b/app/views/orderitems/new.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/orders/_form.html.erb b/app/views/orders/_form.html.erb new file mode 100644 index 0000000000..5f2119037b --- /dev/null +++ b/app/views/orders/_form.html.erb @@ -0,0 +1,53 @@ +
+ + <%= form_with model: @order do |f| %> + +
+ <%= f.label :credit_card_name %> + <%= f.text_field :name, class: "form-control" %> +
+ +
+ <%= f.label :email_address %> + <%= f.text_field :email_address, class: "form-control" %> +
+ +
+ <%= f.label :address %> + <%= f.text_field :address, class: "form-control", placeholder: "e.g. 123 Fake Street" %> +
+ +
+ <%= f.label :city %> + <%= f.text_field :city, class: "form-control", placeholder: "Seattle" %> +
+ +
+ <%= f.label :state %> + <%= f.text_field :state, class: "form-control", placeholder: "WA" %> +
+ +
+ <%= f.label :billing_zip_code %> + <%= f.text_field :zipcode, class: "form-control", placeholder: "e.g. 98112" %> +
+ +
+ <%= f.label :credit_card_number %> + <%= f.text_field :cc_num, class: "form-control" %> +
+ +
+ <%= f.label :credit_card_number %> + <%= f.select :cc_exp_month, (1..12), {}, {:class => "_form__select"} %> + <%= f.select :cc_exp_year, (Date.today.year..Date.today.year + 10), {}, {:class => "_form__select"} %> +
+ +
+ <%= f.label :cvv %> (Card security code) + <%= f.text_field :cc_cvv, class: "form-control" %> +
+ <%= f.hidden_field :status, value: 'paid' %> + <%= f.submit action_name, class: "btn btn-primary" %> + <% end %> +
diff --git a/app/views/orders/edit.html.erb b/app/views/orders/edit.html.erb new file mode 100644 index 0000000000..abdb347702 --- /dev/null +++ b/app/views/orders/edit.html.erb @@ -0,0 +1,4 @@ +
+

Checkout

+ <%= render partial: "form", locals: { action_name: "Edit Order" } %> +
\ No newline at end of file diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb new file mode 100644 index 0000000000..2a96be4a4b --- /dev/null +++ b/app/views/orders/index.html.erb @@ -0,0 +1,50 @@ + + +
+ + + + + + + + + + + + + + + + + + <% @merchant_orders.each do |order| %> + + + <% order_items = order.order_items %> + + + + + + + + + <% end %> + + + <% end %> + +
Customer NameOrder Total AmountPurchase DateCurrent StatusMy Products from Order
<%= order.name %><%= order.total %><%= order.created_at.strftime("%m/%d/%Y") %> <%= order.status %> + <% product_names = order_items.map { |item| Product.find_by(id: item.product_id).name } %> + <%= product_names.join(", ")%> + <%= button_to 'Order Details', ordered_path(order), class: 'btn btn-primary', method: :get%> + + <% if order.status != "shipped"%> + <%= button_to 'Mark Shipped', mark_shipped_path(order), class: 'btn btn-primary', method: :patch %> + <% else %> +
+
+ +<%= button_to 'Back to Dashboard', dashboard_path, class: 'btn btn-primary', method: :get %> + diff --git a/app/views/orders/new.html.erb b/app/views/orders/new.html.erb new file mode 100644 index 0000000000..f7327c79ab --- /dev/null +++ b/app/views/orders/new.html.erb @@ -0,0 +1,8 @@ +
+

Checkout

+ <%= render "orderitems/cart" %> + +
+ <%= render partial: "form", locals: { action_name: "Submit Order" } %> +
+
\ No newline at end of file diff --git a/app/views/orders/ordered.html.erb b/app/views/orders/ordered.html.erb new file mode 100644 index 0000000000..d75b4a20a6 --- /dev/null +++ b/app/views/orders/ordered.html.erb @@ -0,0 +1,71 @@ +

Final Order

+ +<% order = Order.find_by(id: params[:format]) %> + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameEmail AddressAddressCityStateZip codeCard Information (Last Four)Order Total Amount
<%= order.name %><%= order.email_address %> <%= order.address %> <%= order.city %> <%= order.state %> <%= order.zipcode %> ************<%= order.cc_num[-4..-1] %> <%= order.total %> Bells
+

Purchased Items

+ + + + + + + + + + + + + <% order.order_items.each do |order_item| %> + + + + + <% product = Product.find_by(id: order_item.product_id) %> + + + + + + + + <% end %> + +
Product IDProduct ImageNamePriceOrder qty
<%= order_item.product_id %><%= link_to(image_tag(product.photo_url, :alt => "product", class: 'ordered_product-img'), product_path(product.id)) %><%= product.name %><%= product.price %><%= order_item.quantity %>
+ + <%= button_to 'Back to All Orders', orders_path, class: 'btn btn-primary', method: :get %> + <%= button_to 'Back to Dashboard', dashboard_path, class: 'btn btn-primary', method: :get %> +
diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb new file mode 100644 index 0000000000..6694e14d03 --- /dev/null +++ b/app/views/orders/show.html.erb @@ -0,0 +1,91 @@ +

Thank You for Your Order!

+ +<% order = Order.find_by(id: params[:id]) %> + +
+

Order Summary

+ + + + + + + + + + + + + + + + + + + + +
Order Total AmountPurchase DateCurrent Status
<%= order.total %> <%= order.created_at.strftime("%m/%d/%Y") %> <%= order.status %>
+
+ +
+

Billing information

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameAddressCityStateZip codeCredit card numberExpiration Date
<%= order.name %> <%= order.address %> <%= order.city %> <%= order.state %> <%= order.zipcode %> <%= order.cc_num %> <%= order.cc_exp_month %><%= order.cc_exp_year %>
+
+ + +
+

Items information

+ + + + + + + + + + + + + + <% order.order_items.each do |item| %> + <% p = Product.find_by(id: item["product_id"]) %> + + + + + + + + <% end %> + +
NamePriceQuantityItem Total
<%= link_to p.name, product_path(p) %><%= p.price %><%= item.quantity %> <%= p.price * item.quantity %> Bells
+
\ No newline at end of file diff --git a/app/views/pages/frontpage.html.erb b/app/views/pages/frontpage.html.erb new file mode 100644 index 0000000000..2f931c333e --- /dev/null +++ b/app/views/pages/frontpage.html.erb @@ -0,0 +1,112 @@ +
+ + + +
+
+

New Product

+
+ <% p = Product.order("created_at").last %> + <%= link_to(image_tag(p.photo_url), product_path(p), class: "new_product")%> +

<%= p.name %>

+
+
+
+ + +
+ + + + + + +
+ <%= image_tag("https://vignette.wikia.nocookie.net/animalcrossing/images/7/7a/Callmeonmynookphone.PNG/revision/latest?cb=20190611205152", class: 'frontpage_feature_img') %> +
+

+ <%= link_to "Download", root_path, class: "frontpage_feature_title" %> +

+ <%= image_tag("https://www.freeiconspng.com/uploads/white-download-icon-png-32.png", class: 'download_img') %> +
+
+
diff --git a/app/views/pages/home.html.erb b/app/views/pages/home.html.erb new file mode 100644 index 0000000000..b7db9983ff --- /dev/null +++ b/app/views/pages/home.html.erb @@ -0,0 +1,6 @@ +
+ <%= image_tag "https://i.imgur.com/PPbqnwD.gif", autoplay: :autoplay, loop: :loop, muted: :muted, class: "home_video" %> +

+ <%= link_to(image_tag('https://i.ibb.co/ZGrfwSq/enter.png', alt: "welcome image", class: "welcome-link"), frontpage_path) %> +

+
diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb new file mode 100644 index 0000000000..53efc51ea9 --- /dev/null +++ b/app/views/products/_form.html.erb @@ -0,0 +1,44 @@ +
+ <%= form_with model: @product do |f| %> + +
+ <%= f.label :product_name %> + <%= f.text_field :name, class: "form-control" %> +
+ +
+ <%= f.label :categories %> +
+ <%= collection_check_boxes(:product, :category_ids, Category.all, :id, :name) %> +
+ + +
+ <%= f.label :description %> + <%= f.text_area :description, class: "form-control", placeholder: "3D Glasses can be found in New Horizons and New Leaf" %> +
+ +
+ <%= f.label :price %> + <%= f.text_field :price, class: "form-control", placeholder: "e.g. 500" %> +
+ +
+ <%= f.label :inventory %> + <%= f.text_field :inventory, class: "form-control" %> +
+ +
+ <%= f.label :active_status %> + <%= f.select :active, [true, false], {}, {:class => "_form__select"} %> +
+ +
+ <%= f.label :photo_url %> + <%= f.text_area :photo_url, class: "form-control", placeholder: "e.g. https://i.ibb.co/0c4cHmM/leaf.png" %> +
+ + <%= f.submit action_name, class: "btn btn-primary" %> + + <% end %> +
diff --git a/app/views/products/_search_result.html.erb b/app/views/products/_search_result.html.erb new file mode 100644 index 0000000000..c55f7ff610 --- /dev/null +++ b/app/views/products/_search_result.html.erb @@ -0,0 +1,15 @@ +
+ <%= link_to(image_tag(product.photo_url, :alt => "product", class: 'products__index_product-img'), product_path(product.id)) %> + +
+
<%= link_to "#{product.name}", product_path(product) %>
+

🔔 <%= product.price %> Bells

+

<%= Review.display_rating(product.average_rating) %>(<%= product.average_rating %>) | + <%= product.num_of_ratings %> ratings

+

Categories: <%= product.display_categories %>

+

Sold by + <% if User.find_by(id: product.user_id).name %> + <%= link_to "#{User.find_by(id: product.user_id).name}", user_path(product.user_id) %>

+ <% end %> +
+
\ No newline at end of file diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb new file mode 100644 index 0000000000..070db1aa7c --- /dev/null +++ b/app/views/products/edit.html.erb @@ -0,0 +1,4 @@ +
+

Edit this product

+ <%= render partial: "form", locals: { action_name: "Edit" } %> +
\ No newline at end of file diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb new file mode 100644 index 0000000000..55d2d4248b --- /dev/null +++ b/app/views/products/index.html.erb @@ -0,0 +1,19 @@ +
+ <% @products.each do |product| %> + <% unless product.photo_url == "NA" %> +
+ <%= link_to(image_tag(product.photo_url, :alt => "product", class: 'products__index_product-img'), product_path(product.id)) %> + +
+
<%= link_to "#{product.name}", product_path(product) %>
+

🔔 <%= product.price %> Bells

+

<%= Review.display_rating(product.average_rating) %>(<%= product.average_rating %>/ 5)

+
+
+ <% end %> + <% end %> +
+ +
+ <%= will_paginate @products, :style => 'color:white', class: 'user_name' %> +
\ No newline at end of file diff --git a/app/views/products/new.html.erb b/app/views/products/new.html.erb new file mode 100644 index 0000000000..20ce3914cd --- /dev/null +++ b/app/views/products/new.html.erb @@ -0,0 +1,4 @@ +
+

Add a new product

+ <%= render partial: "form", locals: { action_name: "Add" } %> +
diff --git a/app/views/products/search.html.erb b/app/views/products/search.html.erb new file mode 100644 index 0000000000..a799e078e6 --- /dev/null +++ b/app/views/products/search.html.erb @@ -0,0 +1,41 @@ +

Search Result for "<%= @parameter %>"...

+ +
+ <% if @products.empty? && @categories.empty? && @users.empty? %> + <%= image_tag "https://hytsit.com/assets/frontend/images/noproduct.png" %> + <% else %> + +
    +
  • Product name: <%= @products && @products.length %>
  • +
  • Category name: <%= Category.search_result(@parameter) && Category.search_result(@parameter) %>
  • +
  • Merchant name: <%= @users && @users.length %>
  • +
+
+ <% end %> +
+ + +
+ <% if !@products.empty? %> + <% @products.each do |product| %> + <%= render partial: "search_result", locals: { product: product } %> + <% end %> + <% end %> + + + <% if !@categories.empty? %> + <% @categories.each do |category| %> + + <% category.products.each do |product| %> + <%= render partial: "search_result", locals: { product: product } %> + <% end %> + + <% end %> + <% end %> + + <% if !@users.empty? %> + <% @users.each do |user| %> + <%= render partial: "/users/search_result", locals: { user: user } %> + <% end %> + <% end %> +
\ No newline at end of file diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb new file mode 100644 index 0000000000..6c73af0406 --- /dev/null +++ b/app/views/products/show.html.erb @@ -0,0 +1,79 @@ +
+ <%= image_tag @product.photo_url, alt: "product image", class: "products__show_product-img" %> + +
+

<%= @product.name %>

+

+ Sold by + <%= link_to "#{User.find_by(id: @product.user_id).name}", user_path(@product.user_id) %> +

+ +

Price: 🔔<%= @product.price %> Bells

+ +

Description: <%= @product.description %>

+

Categories: <%= @product.display_categories %>

+ +

+ <% if @product.active %> + <%= form_tag orderitems_path, method: :post do %> + <%= label_tag :quantity, "Quantity" %> + <%= select_tag(:quantity, options_for_select((1..@product.inventory), 1))%> + <%= hidden_field_tag :product_id, @product.id %> + <%= submit_tag "Add To Cart", class: "btn btn-lg btn-primary"%> + <% end %> +

Only <%= @product.inventory %> left in stock

+ <% else %> +

currently unavailable

+ <% end %> +

+
+
+ + +
+
+
+

Average rating

+ (<%= @product.num_of_ratings %> ratings) +
+ +
+

<%= @product.average_rating %>

+ out of 5 stars +

<%= Review.display_rating(@product.average_rating) %>

+
+
+
+ <% recent_reviews = @product.reviews.sort_by { |review| review.created_at }.reverse %> + + + +
+
+
+ + +
+

Write a review

+ <%= render partial: "reviews/form", locals: { action_name: "Submit Review" } %> +
+ diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb new file mode 100644 index 0000000000..615042ac44 --- /dev/null +++ b/app/views/reviews/_form.html.erb @@ -0,0 +1,43 @@ +
+ <%= form_with model: @review, url: product_reviews_path(@product.id) do |f| %> +
+
+ <%= f.radio_button :rating, 5 %> + <%= label :rating, '★★★★★', class: 'yellow-stars' %> + + <%= f.radio_button :rating, 4 %> + <%= label :rating, '★★★★', class: 'yellow-stars' %> + + <%= f.radio_button :rating, 3 %> + <%= label :rating, '★★★', class: 'yellow-stars' %> + + <%= f.radio_button :rating, 2 %> + <%= label :rating, '★★', class: 'yellow-stars' %> + + <%= f.radio_button :rating, 1 %> + <%= label :rating, '★', class: 'yellow-stars' %> +
+ + <%if !@login_user%> +
+ <%= f.label :name %> + <%= f.text_field :reviewer, class: "form-control-review" %> +
+ <% end %> + + +
+ <%= f.label :comment %> + <%= f.text_area :description, class: "form-control-review" %> +
+ +
+ <%= f.submit action_name, class: 'btn btn-primary' %> +
+ +
+ <% end %> +
+ + + diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/users/_search_result.html.erb b/app/views/users/_search_result.html.erb new file mode 100644 index 0000000000..8e1a54f877 --- /dev/null +++ b/app/views/users/_search_result.html.erb @@ -0,0 +1,22 @@ +
+
+ <% if user.photo_url.nil? %> + <%= image_tag 'timmytommy.png', alt: "user image", class: 'user_image' %> + <% else %> + <%= image_tag user.photo_url, alt: "user image", class: 'user_image' %> + <% end %> +
+

<%= user.name %>

+

Joined: <%= user.created_at.strftime("%m/%d/%Y") %>

+

Username: <%= user.username %>

+
+
+ +
+ +
+ <% user.products.each do |product| %> + <%= render partial: "/products/search_result", locals: { product: product } %> + <% end %> +
+
\ No newline at end of file diff --git a/app/views/users/dashboard.html.erb b/app/views/users/dashboard.html.erb new file mode 100644 index 0000000000..60dedd5421 --- /dev/null +++ b/app/views/users/dashboard.html.erb @@ -0,0 +1,73 @@ +
+
+ <%= image_tag 'timmytommy.png', alt: "user image", class: 'user_image' %> + +
+

<%= @user.name %>

+

Joined: <%= @user.created_at.strftime("%m/%d/%Y") %>

+

Username: <%= @user.username %>

+
+
+
+ +
+ <%= button_to 'Add Product', new_product_path, method: :get, class: "btn btn-primary" %> + <%= button_to 'Add Category', new_category_path, method: :get, class: "btn btn-primary" %> + <%= button_to 'Account Orders', orders_path, method: :get, class: "btn btn-primary" %> + <%= button_to 'My Merchant Page', user_path(@user), method: :get, class: "btn btn-primary" %> +
+ +
+
+
+

Total Revenue:

+

<%= @revenue %> Bells

+
+
+

Revenue by Order Status

+
+
+
Paid Orders:
+

<%= @paid_revenue %> Bells

+

(<%= @paid_count %> Orders)

+
+
+
Shipped Orders:
+

<%= @shipped_revenue %> Bells

+

(<%= @shipped_count %> Orders)

+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + <% @user.products.each do |product| %> + + + + + + + + + + <% end %> + +
ProductNamePriceInventoryStatus
<%= link_to(image_tag(product.photo_url, :alt => "logo", :title => "Home", class: 'dashboard_product_image'), product_path(product.id)) %><%= product.name %><%= product.price %> Bells<%= product.inventory %><%= product.active ? "active" : "inactive" %><%= button_to "Edit", edit_product_path(product.id), method: :get, class: "btn btn-primary" %> + <%= button_to product.active ? "Inactivate" : "Activate", toggle_status_path(product.id), class: "btn btn-primary", method: :patch, data: { confirm: '❗️ Would you like to update your status?' } %> +
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb new file mode 100644 index 0000000000..0ede9d68a5 --- /dev/null +++ b/app/views/users/index.html.erb @@ -0,0 +1,14 @@ +
+ <% @users.each do |user| %> +
+ <% if user.photo_url %> + <%= image_tag user.photo_url, alt: 'user image', class: 'user_image' %> + <% end %> +
<%= link_to "#{user.name}", user_path(user), class: 'user_name' %>
+
+ <% end %> +
+ +
+ <%= will_paginate @users, :style => 'color:white', class: 'user_name' %> +
\ No newline at end of file diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 0000000000..77791fd2ef --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1,33 @@ +
+
+ <% if @user.photo_url.nil? %> + <%= image_tag 'timmytommy.png', alt: "user image", class: 'user_image' %> + <% else %> + <%= image_tag @user.photo_url, alt: "user image", class: 'user_image' %> + <% end %> +
+

<%= @user.name %>

+

Joined: <%= @user.created_at.strftime("%m/%d/%Y") %>

+

Username: <%= @user.username %>

+
+
+ +
+
+ <% @user.products.each do |product| %> + <% unless product.photo_url == "NA" || product.active == false %> +
+ <%= link_to(image_tag(product.photo_url, alt: "product", class: "products__index_product-img"), product_path(product)) %> + +
+
<%= link_to "#{product.name}", product_path(product) %>
+

<%= product.price %> Bells

+

<%= Review.display_rating(product.average_rating) %>(<%= product.average_rating %>) | <%= product.num_of_ratings %> ratings

+ +

Inventory: <%= product.inventory %>

+
+
+ <% end %> + <% end %> +
+
\ No newline at end of file diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000000..12f98da5af --- /dev/null +++ b/babel.config.js @@ -0,0 +1,72 @@ +module.exports = function(api) { + var validEnv = ['development', 'test', 'production'] + var currentEnv = api.env() + var isDevelopmentEnv = api.env('development') + var isProductionEnv = api.env('production') + var isTestEnv = api.env('test') + + if (!validEnv.includes(currentEnv)) { + throw new Error( + 'Please specify a valid `NODE_ENV` or ' + + '`BABEL_ENV` environment variables. Valid values are "development", ' + + '"test", and "production". Instead, received: ' + + JSON.stringify(currentEnv) + + '.' + ) + } + + return { + presets: [ + isTestEnv && [ + '@babel/preset-env', + { + targets: { + node: 'current' + } + } + ], + (isProductionEnv || isDevelopmentEnv) && [ + '@babel/preset-env', + { + forceAllTransforms: true, + useBuiltIns: 'entry', + corejs: 3, + modules: false, + exclude: ['transform-typeof-symbol'] + } + ] + ].filter(Boolean), + plugins: [ + 'babel-plugin-macros', + '@babel/plugin-syntax-dynamic-import', + isTestEnv && 'babel-plugin-dynamic-import-node', + '@babel/plugin-transform-destructuring', + [ + '@babel/plugin-proposal-class-properties', + { + loose: true + } + ], + [ + '@babel/plugin-proposal-object-rest-spread', + { + useBuiltIns: true + } + ], + [ + '@babel/plugin-transform-runtime', + { + helpers: false, + regenerator: true, + corejs: false + } + ], + [ + '@babel/plugin-transform-regenerator', + { + async: false + } + ] + ].filter(Boolean) + } +} diff --git a/bin/bundle b/bin/bundle new file mode 100755 index 0000000000..a71368e323 --- /dev/null +++ b/bin/bundle @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_version + @bundler_version ||= + env_var_version || cli_arg_version || + lockfile_version + end + + def bundler_requirement + return "#{Gem::Requirement.default}.a" unless bundler_version + + bundler_gem_version = Gem::Version.new(bundler_version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000000..5badb2fde0 --- /dev/null +++ b/bin/rails @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000000..d87d5f5781 --- /dev/null +++ b/bin/rake @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000000..5853b5ea87 --- /dev/null +++ b/bin/setup @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +require 'fileutils' + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to setup or update your development environment automatically. + # This script is idempotent, so that you can run it at anytime and get an expectable outcome. + # Add necessary setup steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies + # system('bin/yarn') + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:prepare' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/bin/spring b/bin/spring new file mode 100755 index 0000000000..d89ee495fa --- /dev/null +++ b/bin/spring @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +# This file loads Spring without using Bundler, in order to be fast. +# It gets overwritten when you run the `spring binstub` command. + +unless defined?(Spring) + require 'rubygems' + require 'bundler' + + lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) + spring = lockfile.specs.detect { |spec| spec.name == 'spring' } + if spring + Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path + gem 'spring', spring.version + require 'spring/binstub' + end +end diff --git a/bin/webpack b/bin/webpack new file mode 100755 index 0000000000..1031168d01 --- /dev/null +++ b/bin/webpack @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "bundler/setup" + +require "webpacker" +require "webpacker/webpack_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::WebpackRunner.run(ARGV) +end diff --git a/bin/webpack-dev-server b/bin/webpack-dev-server new file mode 100755 index 0000000000..dd9662737a --- /dev/null +++ b/bin/webpack-dev-server @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "bundler/setup" + +require "webpacker" +require "webpacker/dev_server_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::DevServerRunner.run(ARGV) +end diff --git a/bin/yarn b/bin/yarn new file mode 100755 index 0000000000..460dd565b4 --- /dev/null +++ b/bin/yarn @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + begin + exec "yarnpkg", *ARGV + rescue Errno::ENOENT + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000000..f7ba0b527b --- /dev/null +++ b/config.ru @@ -0,0 +1,5 @@ +# This file is used by Rack-based servers to start the application. + +require_relative 'config/environment' + +run Rails.application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000000..39167e2e9a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,23 @@ +require_relative 'boot' + +require 'rails/all' + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module Betsy + class Application < Rails::Application + config.generators do |g| + # Force new test files to be generated in the minitest-spec style + g.test_framework :minitest, spec: true + end + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 6.0 + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration can go into files in config/initializers + # -- all .rb files in that directory are automatically loaded after loading + # the framework and any gems in your application. + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000000..b9e460cef3 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) + +require 'bundler/setup' # Set up gems listed in the Gemfile. +require 'bootsnap/setup' # Speed up boot time by caching expensive operations. diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000000..f2a452f546 --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: betsy_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000000..afcc1b7aa1 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +SVDYMKskORWYsNz0LOTdtzV4tX8C/l10ea9M7+qxRLgEG0nmw4obmn/FB1aI5RMXjkrd95dZTsoVKP+4IlBHXPzvLhuPSHasdx/FIlOBrueYf97Pr7uo+eQJagzrSeyFBG46hDxSiFWR+tyyRiQeig6WH6sSm+Jr5E93qWwb/XYyEXqTvHU5lhy6WW3r1pxEWV5zal4diYdNXGDlRMeBV7KXTch7wQP46EcREGMnD7E7Wb79JRZof5XygmKt3ds/radXQsrXwAmWgZ5ZXya8Rg03Dp/w4a4B6JBRSrS0IlEBfjZdMqfLvz7DEtxMAZ0ophcZTwSS0Oq0/LH7zZ2hb8Wm52LFznVMTLrXbgA7YPdx2eccXSWt2nRZEsoO9d32UhYs5pX9E1jQDVHiR0M8htZXhS2lnf9g1yeK--eyfkDIR9400mf7Mo--gTBbeyX3hiJPyqbH5oXjXA== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000000..8b9bc23f0c --- /dev/null +++ b/config/database.yml @@ -0,0 +1,85 @@ +# PostgreSQL. Versions 9.3 and up are supported. +# +# Install the pg driver: +# gem install pg +# On macOS with Homebrew: +# gem install pg -- --with-pg-config=/usr/local/bin/pg_config +# On macOS with MacPorts: +# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config +# On Windows: +# gem install pg +# Choose the win32 build. +# Install PostgreSQL and put its /bin directory on your path. +# +# Configure Using Gemfile +# gem 'pg' +# +default: &default + adapter: postgresql + encoding: unicode + # For details on connection pooling, see Rails configuration guide + # https://guides.rubyonrails.org/configuring.html#database-pooling + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + +development: + <<: *default + database: betsy_development + + # The specified database role being used to connect to postgres. + # To create additional roles in postgres see `$ createuser --help`. + # When left blank, postgres will use the default role. This is + # the same name as the operating system user that initialized the database. + #username: betsy + + # The password associated with the postgres role (username). + #password: + + # Connect on a TCP socket. Omitted by default since the client uses a + # domain socket that doesn't need configuration. Windows does not have + # domain sockets, so uncomment these lines. + #host: localhost + + # The TCP port the server listens on. Defaults to 5432. + # If your server runs on a different port number, change accordingly. + #port: 5432 + + # Schema search path. The server defaults to $user,public + #schema_search_path: myapp,sharedapp,public + + # Minimum log levels, in increasing order: + # debug5, debug4, debug3, debug2, debug1, + # log, notice, warning, error, fatal, and panic + # Defaults to warning. + #min_messages: notice + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: betsy_test + +# As with config/credentials.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%= ENV['DATABASE_URL'] %> +# +production: + <<: *default + database: betsy_production + username: betsy + password: <%= ENV['BETSY_DATABASE_PASSWORD'] %> diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000000..426333bb46 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000000..66df51f6fc --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,62 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join('tmp', 'caching-dev.txt').exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations. + # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + config.file_watcher = ActiveSupport::EventedFileUpdateChecker +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000000..a511873ff5 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,113 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + + # Compress CSS using a preprocessor. + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = 'http://assets.example.com' + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = 'wss://example.com/cable' + # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "betsy_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners. + config.active_support.deprecation = :notify + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + # Inserts middleware to perform automatic connection switching. + # The `database_selector` hash is used to pass options to the DatabaseSelector + # middleware. The `delay` is used to determine how long to wait after a write + # to send a subsequent read to the primary. + # + # The `database_resolver` class is used by the middleware to determine which + # database is appropriate to use based on the time delay. + # + # The `database_resolver_context` class is used by the middleware to set + # timestamps for the last write to the primary. The resolver uses the context + # class timestamps to determine how long to wait before reading from the + # replica. + # + # By default Rails will store a last write timestamp in the session. The + # DatabaseSelector middleware is designed as such you can define your own + # strategy for connection switching and pass that into the middleware through + # these configuration options. + # config.active_record.database_selector = { delay: 2.seconds } + # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver + # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session + +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000000..0cb24249b5 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,49 @@ +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + config.cache_classes = false + config.action_view.cache_template_loading = true + + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations. + # config.action_view.raise_on_missing_translations = true +end diff --git a/config/initializers/action_view.rb b/config/initializers/action_view.rb new file mode 100644 index 0000000000..142d382f87 --- /dev/null +++ b/config/initializers/action_view.rb @@ -0,0 +1 @@ +Rails.application.config.action_view.form_with_generates_remote_forms = false diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb new file mode 100644 index 0000000000..89d2efab2b --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 0000000000..4b828e80cb --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000000..59385cdf37 --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 0000000000..35d0f26fcd --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,30 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # If you are using webpack-dev-server then specify webpack-dev-server host +# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# Set the nonce only to specific directives +# Rails.application.config.content_security_policy_nonce_directives = %w(script-src) + +# Report CSP violations to a specified URI +# For further information see the following documentation: +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# Rails.application.config.content_security_policy_report_only = true diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb new file mode 100644 index 0000000000..5a6a32d371 --- /dev/null +++ b/config/initializers/cookies_serializer.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000000..4a994e1e7b --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure sensitive parameters which will be filtered from the log file. +Rails.application.config.filter_parameters += [:password] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000000..ac033bf9dc --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym 'RESTful' +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000000..dc1899682b --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb new file mode 100644 index 0000000000..e32a45234e --- /dev/null +++ b/config/initializers/omniauth.rb @@ -0,0 +1,3 @@ +Rails.application.config.middleware.use OmniAuth::Builder do + provider :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user:email" +end \ No newline at end of file diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000000..bbfc3961bf --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000000..cf9b342d0a --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# 'true': 'foo' +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000000..5ed4437744 --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,38 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked web server processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000000..de2739952a --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,33 @@ +Rails.application.routes.draw do + get 'pages/home' + # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html + resources :users, except: [:update, :new, :edit, :update] + + get "/auth/github", as: "github_login" + get "/auth/github/callback", to: "users#create", as: "auth_callback" + delete "/logout", to: "users#destroy", as: "logout" + + root to: "pages#home" + get "/search", to: "products#search", as: "search" + get '/frontpage', to: 'pages#frontpage', as: "frontpage" + + patch '/products/:id/toggle_status', to: 'products#toggle_status', as: 'toggle_status' + get '/dashboard', to: "users#dashboard", as: "dashboard" + get '/ordered', to: "orders#ordered", as: "ordered" + get '/cart', to: "orderitems#index", as: 'cart' + patch 'order/mark_shipped', to: 'orders#mark_shipped', as: "mark_shipped" + patch '/orderitems/add', to:"orderitems#increase_quantity", as: "add" + patch '/orderitems/subtract', to:"orderitems#decrease_quantity", as: "subtract" + + resources :products do + resources :reviews, only: [:new, :create] + end + + resources :orders + resources :orderitems, only: [:index, :create] + resources :products + resources :categories +end + + +# review route - reference: https://stackoverflow.com/questions/25107038/ruby-on-rails-settting-up-reviews-functionality \ No newline at end of file diff --git a/config/spring.rb b/config/spring.rb new file mode 100644 index 0000000000..db5bf1307a --- /dev/null +++ b/config/spring.rb @@ -0,0 +1,6 @@ +Spring.watch( + ".ruby-version", + ".rbenv-vars", + "tmp/restart.txt", + "tmp/caching-dev.txt" +) diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000000..d32f76e8fb --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/config/webpack/development.js b/config/webpack/development.js new file mode 100644 index 0000000000..c5edff94ad --- /dev/null +++ b/config/webpack/development.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/config/webpack/environment.js b/config/webpack/environment.js new file mode 100644 index 0000000000..48103041f7 --- /dev/null +++ b/config/webpack/environment.js @@ -0,0 +1,12 @@ +const { environment } = require('@rails/webpacker') + +module.exports = environment +const webpack = require('webpack') +environment.plugins.append( + 'Provide', + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + Popper: ['popper.js', 'default'] + }) +) diff --git a/config/webpack/production.js b/config/webpack/production.js new file mode 100644 index 0000000000..be0f53aacf --- /dev/null +++ b/config/webpack/production.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'production' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/config/webpack/test.js b/config/webpack/test.js new file mode 100644 index 0000000000..c5edff94ad --- /dev/null +++ b/config/webpack/test.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/config/webpacker.yml b/config/webpacker.yml new file mode 100644 index 0000000000..8581ac0472 --- /dev/null +++ b/config/webpacker.yml @@ -0,0 +1,96 @@ +# Note: You must restart bin/webpack-dev-server for changes to take effect + +default: &default + source_path: app/javascript + source_entry_path: packs + public_root_path: public + public_output_path: packs + cache_path: tmp/cache/webpacker + check_yarn_integrity: false + webpack_compile_output: true + + # Additional paths webpack should lookup modules + # ['app/assets', 'engine/foo/app/assets'] + resolved_paths: [] + + # Reload manifest.json on all requests so we reload latest compiled packs + cache_manifest: false + + # Extract and emit a css file + extract_css: false + + static_assets_extensions: + - .jpg + - .jpeg + - .png + - .gif + - .tiff + - .ico + - .svg + - .eot + - .otf + - .ttf + - .woff + - .woff2 + + extensions: + - .mjs + - .js + - .sass + - .scss + - .css + - .module.sass + - .module.scss + - .module.css + - .png + - .svg + - .gif + - .jpeg + - .jpg + +development: + <<: *default + compile: true + + # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules + check_yarn_integrity: true + + # Reference: https://webpack.js.org/configuration/dev-server/ + dev_server: + https: false + host: localhost + port: 3035 + public: localhost:3035 + hmr: false + # Inline should be set to true if using HMR + inline: true + overlay: true + compress: true + disable_host_check: true + use_local_ip: false + quiet: false + pretty: false + headers: + 'Access-Control-Allow-Origin': '*' + watch_options: + ignored: '**/node_modules/**' + + +test: + <<: *default + compile: true + + # Compile test packs to a separate directory + public_output_path: packs-test + +production: + <<: *default + + # Production depends on precompilation of packs prior to booting for performance. + compile: false + + # Extract and emit a css file + extract_css: true + + # Cache manifest.json for performance + cache_manifest: true diff --git a/coverage/.last_run.json b/coverage/.last_run.json new file mode 100644 index 0000000000..16aa008b6e --- /dev/null +++ b/coverage/.last_run.json @@ -0,0 +1,5 @@ +{ + "result": { + "covered_percent": 90.04 + } +} diff --git a/coverage/.resultset.json b/coverage/.resultset.json new file mode 100644 index 0000000000..912eff4de5 --- /dev/null +++ b/coverage/.resultset.json @@ -0,0 +1,1466 @@ +{ + "Minitest": { + "coverage": { + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/environment.rb": { + "lines": [ + null, + 1, + null, + null, + 1 + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/environments/test.rb": { + "lines": [ + null, + null, + null, + null, + null, + 1, + null, + null, + 1, + 1, + null, + null, + null, + null, + 1, + null, + null, + 1, + 1, + null, + null, + null, + null, + 1, + 1, + 1, + null, + null, + 1, + null, + null, + 1, + null, + null, + 1, + null, + 1, + null, + null, + null, + null, + 1, + null, + null, + 1, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/action_view.rb": { + "lines": [ + 1 + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/application_controller_renderer.rb": { + "lines": [ + null, + null, + null, + null, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/assets.rb": { + "lines": [ + null, + null, + null, + 1, + null, + null, + null, + null, + 1, + null, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/backtrace_silencers.rb": { + "lines": [ + null, + null, + null, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/content_security_policy.rb": { + "lines": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/cookies_serializer.rb": { + "lines": [ + null, + null, + null, + null, + 1 + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/filter_parameter_logging.rb": { + "lines": [ + null, + null, + null, + 1 + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/inflections.rb": { + "lines": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/mime_types.rb": { + "lines": [ + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/omniauth.rb": { + "lines": [ + 1, + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/initializers/wrap_parameters.rb": { + "lines": [ + null, + null, + null, + null, + null, + null, + 1, + 2, + null, + null, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/config/routes.rb": { + "lines": [ + 1, + 1, + null, + 1, + null, + 1, + 1, + 1, + null, + 1, + 1, + 1, + null, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + 1, + 1, + null, + null, + 1, + 1, + 1, + 1, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/application_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/categories_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/orderitems_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/orders_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/pages_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/products_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/reviews_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/helpers/users_helper.rb": { + "lines": [ + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/categories_controller.rb": { + "lines": [ + 1, + 1, + null, + 5, + 1, + 4, + null, + 1, + 2, + null, + null, + 1, + null, + null, + 1, + 1, + null, + null, + 1, + 3, + null, + 3, + 1, + 1, + null, + null, + 2, + 2, + null, + null, + null, + null, + 1, + 3, + 1, + 1, + null, + null, + 2, + 2, + null, + null, + null, + null, + 1, + null, + 1, + 6, + null, + null, + 1, + 3, + 3, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/application_controller.rb": { + "lines": [ + 1, + 1, + null, + null, + 1, + 1, + 94, + null, + null, + 1, + null, + 1, + 2, + null, + null, + null, + 1, + 94, + 24, + null, + null, + null, + 1, + 4, + null, + null, + 1, + 4, + 2, + 2, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/orderitems_controller.rb": { + "lines": [ + 1, + 1, + null, + 1, + null, + null, + 1, + 5, + 5, + null, + null, + 5, + null, + 5, + null, + 5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + null, + null, + null, + null, + 5, + null, + null, + null, + null, + 5, + 4, + 4, + 4, + 4, + null, + 1, + 0, + 0, + null, + null, + 0, + null, + 0, + null, + null, + null, + 1, + 2, + null, + 2, + null, + null, + 2, + 2, + 1, + 1, + 1, + 1, + null, + null, + null, + 2, + 2, + null, + null, + null, + 1, + 1, + null, + 1, + 1, + 1, + null, + null, + 1, + 0, + null, + null, + null, + 1, + 1, + 1, + null, + null, + 1, + null, + 1, + 5, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/orders_controller.rb": { + "lines": [ + 1, + 1, + null, + 1, + 0, + 0, + null, + 0, + 0, + 0, + null, + 0, + 0, + 0, + 0, + null, + null, + null, + null, + null, + null, + 1, + 1, + null, + null, + 1, + 2, + null, + 2, + 0, + 0, + 0, + 0, + null, + 0, + 0, + null, + null, + 0, + 0, + 0, + null, + null, + 2, + 2, + null, + null, + null, + null, + 1, + 2, + null, + 2, + 1, + 1, + null, + null, + 1, + 1, + null, + null, + null, + null, + 1, + 1, + 1, + null, + 1, + 1, + 1, + null, + null, + null, + 1, + 0, + null, + null, + 1, + null, + 1, + 2, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/pages_controller.rb": { + "lines": [ + 1, + 1, + null, + null, + 1, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/products_controller.rb": { + "lines": [ + 1, + 1, + null, + 1, + null, + 12, + 10, + 8, + null, + null, + 1, + 2, + null, + null, + 1, + 1, + null, + null, + 1, + 1, + null, + null, + 1, + 2, + 2, + null, + 2, + 1, + 1, + null, + null, + 1, + 1, + null, + null, + null, + null, + 1, + null, + null, + 1, + null, + 3, + null, + 1, + null, + 1, + 1, + null, + null, + 2, + 2, + null, + null, + null, + null, + 1, + null, + 2, + 2, + 2, + null, + null, + null, + null, + 1, + 4, + 2, + 2, + 2, + null, + null, + 2, + 2, + 2, + 2, + null, + null, + 1, + null, + 1, + 5, + null, + null, + 1, + 9, + 9, + null, + null, + 1, + 1, + 1, + 1, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/reviews_controller.rb": { + "lines": [ + 1, + 1, + null, + null, + 1, + 2, + 2, + null, + null, + 1, + 4, + null, + null, + 4, + 1, + 1, + null, + null, + null, + null, + 3, + 1, + 1, + null, + 2, + null, + null, + 3, + 2, + null, + 1, + null, + 1, + 4, + 1, + null, + null, + null, + 1, + null, + null, + 3, + null, + null, + null, + null, + 1, + null, + 1, + 3, + null, + null, + 1, + 6, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/controllers/users_controller.rb": { + "lines": [ + 1, + 1, + null, + 1, + null, + 1, + 2, + null, + null, + 1, + 2, + null, + 2, + 1, + null, + null, + null, + 1, + 37, + null, + 37, + null, + 37, + 25, + null, + null, + 12, + null, + 12, + 1, + null, + 11, + null, + null, + null, + 37, + 37, + null, + null, + null, + 1, + 1, + 1, + null, + 1, + null, + null, + null, + 1, + 1, + null, + 1, + 1, + 1, + 1, + 1, + null, + 1, + 2, + 0, + null, + 0, + 0, + null, + 0, + 0, + 0, + 0, + 0, + 0, + null, + null, + null, + null, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/models/category.rb": { + "lines": [ + 1, + 1, + 1, + null, + 1, + 6, + null, + 12, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/models/application_record.rb": { + "lines": [ + 1, + 1, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/models/order_item.rb": { + "lines": [ + 1, + 1, + 1, + null, + 1, + 1, + null, + 1, + 1, + null, + null, + 1, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/models/order.rb": { + "lines": [ + 1, + 1, + null, + 1, + 1, + 1, + null, + 1, + 1, + null, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + 1, + 3, + null, + 2, + null, + 2, + 3, + 3, + null, + null, + 2, + null, + null, + 1, + 1, + 1, + null, + null, + null, + 1, + 2, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/validators/order_validator.rb": { + "lines": [ + 1, + 1, + 42, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/models/product.rb": { + "lines": [ + 1, + 1, + 1, + 1, + null, + null, + 1, + 1, + 1, + 1, + 1, + null, + 1, + 4, + 2, + null, + 2, + null, + null, + null, + 1, + 36, + null, + null, + 1, + 47, + null, + 47, + 31, + null, + 53, + 16, + 16, + null, + null, + null, + 1, + 19, + null, + null, + 1, + 1, + 10, + null, + null, + 1, + null, + null, + 1, + 1, + 10, + null, + null, + 1, + null, + null, + 1, + 3, + 1, + null, + null, + null, + 1, + 1, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/models/review.rb": { + "lines": [ + 1, + 1, + null, + 1, + 1, + 1, + 1, + null, + 1, + 18, + 7, + 7, + null, + null + ] + }, + "/Users/oliviamulholland/Ada/Developer/Projects/Rails/betsy/app/models/user.rb": { + "lines": [ + 1, + 1, + 1, + null, + 1, + 1, + 1, + null, + 1, + 13, + 13, + 13, + 13, + 13, + 13, + null, + 13, + null, + null + ] + } + }, + "timestamp": 1592586145 + }, + "Unit Tests": { + "coverage": { + "/Users/corinnafabre/Developer/projects/betsy/app/models/order_item.rb": { + "lines": [ + 1, + null, + 1, + null, + null, + null, + null, + null, + 0, + 0, + 0, + null, + null, + null, + 1, + 2, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 2, + 2, + null, + null, + null, + null, + null, + null, + 1, + 1, + null, + 1, + 1, + null, + null, + 1, + null, + null, + null, + null, + null, + 1, + 1, + 1, + null, + null, + null, + null, + null, + null, + null, + 1, + 2, + null, + null + ] + }, + "/Users/corinnafabre/Developer/projects/betsy/app/models/application_record.rb": { + "lines": [ + 1, + 1, + null + ] + }, + "/Users/corinnafabre/Developer/projects/betsy/app/models/review.rb": { + "lines": [ + 1, + 1, + null, + 1, + 1, + 1, + 1, + null, + 1, + 0, + 0, + 0, + null, + null + ] + }, + "/Users/corinnafabre/Developer/projects/betsy/app/models/product.rb": { + "lines": [ + 1, + 1, + 1, + 1, + null, + null, + 1, + 1, + 1, + 1, + 1, + null, + 1, + 0, + 0, + null, + 0, + null, + null, + null, + 1, + 0, + null, + null, + 1, + 0, + null, + 0, + 0, + null, + 0, + 0, + 0, + null, + null, + null, + 1, + 0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 1, + 0, + 0, + null, + null, + 0, + null, + null, + 1, + 0, + 0, + null, + null, + 0, + null, + null, + 1, + 0, + 0, + null, + null, + null, + 1, + 0, + null, + null + ] + }, + "/Users/corinnafabre/Developer/projects/betsy/app/models/category.rb": { + "lines": [ + 1, + 1, + 1, + null, + null, + null, + null, + null, + 1, + 0, + null, + 0, + null, + null + ] + }, + "/Users/corinnafabre/Developer/projects/betsy/app/models/order.rb": { + "lines": [ + 1, + 1, + null, + 1, + 1, + null, + null, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + null, + null, + null, + null, + 1, + null, + null, + 1, + 1, + null, + null, + 1, + null, + null, + null, + null, + 1, + 1, + 1, + 1, + null, + 1, + 1, + null, + null, + null, + null, + null, + null, + 1, + null, + null, + null, + 1, + 0, + null, + 0, + null, + 0, + 0, + 0, + null, + null, + 0, + null, + null, + null, + 1, + 10, + null, + 10, + null, + 10, + 0, + null, + 0, + 0, + null, + null, + 0, + null, + 0, + 0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 1, + 0, + null, + 0, + 0, + 0, + 0, + 0, + null, + null, + null, + 1, + null, + 1, + 0, + null, + null + ] + }, + "/Users/corinnafabre/Developer/projects/betsy/app/validators/order_validator.rb": { + "lines": [ + 1, + 1, + 7, + null, + null + ] + }, + "/Users/corinnafabre/Developer/projects/betsy/app/models/user.rb": { + "lines": [ + 1, + 1, + 1, + null, + 1, + 1, + 1, + null, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + null, + 0, + 0, + 0, + 0, + null, + null, + null, + null, + 0, + null, + null, + null, + null, + 0, + 0, + 0, + 0, + 0, + null, + 0, + 0, + 0, + null, + null, + null, + null, + 0, + 0, + null, + null, + null, + null, + 1, + 0, + null, + null, + 1, + 0, + null, + 0, + null, + 0, + 0, + 0, + null, + null, + 0, + null, + null, + 0, + null, + null, + null, + 0, + 0, + null, + null, + 1, + 0, + null, + 0, + 0, + 0, + null, + null, + 0, + null, + null, + 0, + null, + null, + null, + null, + null, + 0, + 0, + 0, + null, + null + ] + } + }, + "timestamp": 1592510061 + } +} diff --git a/coverage/.resultset.json.lock b/coverage/.resultset.json.lock new file mode 100644 index 0000000000..e69de29bb2 diff --git a/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc.png b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc.png new file mode 100644 index 0000000000..e1ba61a805 Binary files /dev/null and b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc.png differ diff --git a/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc_disabled.png b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc_disabled.png new file mode 100644 index 0000000000..fb11dfe24a Binary files /dev/null and b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc_disabled.png differ diff --git a/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_both.png b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_both.png new file mode 100644 index 0000000000..af5bc7c5a1 Binary files /dev/null and b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_both.png differ diff --git a/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc.png b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc.png new file mode 100644 index 0000000000..0e156deb5f Binary files /dev/null and b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc.png differ diff --git a/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc_disabled.png b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc_disabled.png new file mode 100644 index 0000000000..c9fdd8a150 Binary files /dev/null and b/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc_disabled.png differ diff --git a/coverage/assets/0.12.2/application.css b/coverage/assets/0.12.2/application.css new file mode 100644 index 0000000000..916699ed2a --- /dev/null +++ b/coverage/assets/0.12.2/application.css @@ -0,0 +1 @@ +html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,code,del,dfn,em,img,q,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,dialog,figure,footer,header,hgroup,nav,section{margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline}article,aside,dialog,figure,footer,header,hgroup,nav,section{display:block}body{line-height:1.5}table{border-collapse:separate;border-spacing:0}caption,th,td{text-align:left;font-weight:normal}table,td,th{vertical-align:middle}blockquote:before,blockquote:after,q:before,q:after{content:""}blockquote,q{quotes:"" ""}a img{border:0}html{font-size:100.01%}body{font-size:82%;color:#222;background:#fff;font-family:"Helvetica Neue",Arial,Helvetica,sans-serif}h1,h2,h3,h4,h5,h6{font-weight:normal;color:#111}h1{font-size:3em;line-height:1;margin-bottom:.5em}h2{font-size:2em;margin-bottom:.75em}h3{font-size:1.5em;line-height:1;margin-bottom:1em}h4{font-size:1.2em;line-height:1.25;margin-bottom:1.25em}h5{font-size:1em;font-weight:bold;margin-bottom:1.5em}h6{font-size:1em;font-weight:bold}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0}p{margin:0 0 1.5em}p img.left{float:left;margin:1.5em 1.5em 1.5em 0;padding:0}p img.right{float:right;margin:1.5em 0 1.5em 1.5em}a:focus,a:hover{color:#000}a{color:#009;text-decoration:underline}blockquote{margin:1.5em;color:#666;font-style:italic}strong{font-weight:bold}em,dfn{font-style:italic}dfn{font-weight:bold}sup,sub{line-height:0}abbr,acronym{border-bottom:1px dotted #666}address{margin:0 0 1.5em;font-style:italic}del{color:#666}pre{margin:1.5em 0;white-space:pre}pre,code,tt{font:1em 'andale mono','lucida console',monospace;line-height:1.5}li ul,li ol{margin:0}ul,ol{margin:0 1.5em 1.5em 0;padding-left:3.333em}ul{list-style-type:disc}ol{list-style-type:decimal}dl{margin:0 0 1.5em 0}dl dt{font-weight:bold}dd{margin-left:1.5em}table{margin-bottom:1.4em;width:100%}th{font-weight:bold}thead th{background:#c3d9ff}th,td,caption{padding:4px 10px 4px 5px}tr.even td{background:#efefef}tfoot{font-style:italic}caption{background:#eee}.small{font-size:.8em;margin-bottom:1.875em;line-height:1.875em}.large{font-size:1.2em;line-height:2.5em;margin-bottom:1.25em}.hide{display:none}.quiet{color:#666}.loud{color:#000}.highlight{background:#ff0}.added{background:#060;color:#fff}.removed{background:#900;color:#fff}.first{margin-left:0;padding-left:0}.last{margin-right:0;padding-right:0}.top{margin-top:0;padding-top:0}.bottom{margin-bottom:0;padding-bottom:0}label{font-weight:bold}fieldset{padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc}legend{font-weight:bold;font-size:1.2em}input[type=text],input[type=password],input.text,input.title,textarea,select{background-color:#fff;border:1px solid #bbb}input[type=text]:focus,input[type=password]:focus,input.text:focus,input.title:focus,textarea:focus,select:focus{border-color:#666}input[type=text],input[type=password],input.text,input.title,textarea,select{margin:.5em 0}input.text,input.title{width:300px;padding:5px}input.title{font-size:1.5em}textarea{width:390px;height:250px;padding:5px}input[type=checkbox],input[type=radio],input.checkbox,input.radio{position:relative;top:.25em}form.inline{line-height:3}form.inline p{margin-bottom:0}.error,.notice,.success{padding:.8em;margin-bottom:1em;border:2px solid #ddd}.error{background:#fbe3e4;color:#8a1f11;border-color:#fbc2c4}.notice{background:#fff6bf;color:#514721;border-color:#ffd324}.success{background:#e6efc2;color:#264409;border-color:#c6d880}.error a{color:#8a1f11}.notice a{color:#514721}.success a{color:#264409}.box{padding:1.5em;margin-bottom:1.5em;background:#e5ecf9}hr{background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:0}hr.space{background:#fff;color:#fff;visibility:hidden}.clearfix:after,.container:after{content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden}.clearfix,.container{display:block}.clear{clear:both}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:0}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand;background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("DataTables-1.10.20/images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("DataTables-1.10.20/images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("DataTables-1.10.20/images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("DataTables-1.10.20/images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("DataTables-1.10.20/images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#fff}table.dataTable tbody tr.selected{background-color:#b0bed9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:0}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:0}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,white),color-stop(100%,#dcdcdc));background:-webkit-linear-gradient(top,white 0,#dcdcdc 100%);background:-moz-linear-gradient(top,white 0,#dcdcdc 100%);background:-ms-linear-gradient(top,white 0,#dcdcdc 100%);background:-o-linear-gradient(top,white 0,#dcdcdc 100%);background:linear-gradient(to bottom,white 0,#dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#585858),color-stop(100%,#111));background:-webkit-linear-gradient(top,#585858 0,#111 100%);background:-moz-linear-gradient(top,#585858 0,#111 100%);background:-ms-linear-gradient(top,#585858 0,#111 100%);background:-o-linear-gradient(top,#585858 0,#111 100%);background:linear-gradient(to bottom,#585858 0,#111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:0;background-color:#2b2b2b;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#2b2b2b),color-stop(100%,#0c0c0c));background:-webkit-linear-gradient(top,#2b2b2b 0,#0c0c0c 100%);background:-moz-linear-gradient(top,#2b2b2b 0,#0c0c0c 100%);background:-ms-linear-gradient(top,#2b2b2b 0,#0c0c0c 100%);background:-o-linear-gradient(top,#2b2b2b 0,#0c0c0c 100%);background:linear-gradient(to bottom,#2b2b2b 0,#0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,0)),color-stop(25%,rgba(255,255,255,0.9)),color-stop(75%,rgba(255,255,255,0.9)),color-stop(100%,rgba(255,255,255,0)));background:-webkit-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,0.9) 25%,rgba(255,255,255,0.9) 75%,rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,0.9) 25%,rgba(255,255,255,0.9) 75%,rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,0.9) 25%,rgba(255,255,255,0.9) 75%,rgba(255,255,255,0) 100%);background:-o-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,0.9) 25%,rgba(255,255,255,0.9) 75%,rgba(255,255,255,0) 100%);background:linear-gradient(to right,rgba(255,255,255,0) 0,rgba(255,255,255,0.9) 25%,rgba(255,255,255,0.9) 75%,rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:0}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width:767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width:640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}}pre .comment,pre .template_comment,pre .diff .header,pre .javadoc{color:#998;font-style:italic}pre .keyword,pre .css .rule .keyword,pre .winutils,pre .javascript .title,pre .lisp .title{color:#000;font-weight:bold}pre .number,pre .hexcolor{color:#458}pre .string,pre .tag .value,pre .phpdoc,pre .tex .formula{color:#d14}pre .subst{color:#712}pre .constant,pre .title,pre .id{color:#900;font-weight:bold}pre .javascript .title,pre .lisp .title,pre .subst{font-weight:normal}pre .class .title,pre .haskell .label,pre .tex .command{color:#458;font-weight:bold}pre .tag,pre .tag .title,pre .rules .property,pre .django .tag .keyword{color:navy;font-weight:normal}pre .attribute,pre .variable,pre .instancevar,pre .lisp .body{color:teal}pre .regexp{color:#009926}pre .class{color:#458;font-weight:bold}pre .symbol,pre .ruby .symbol .string,pre .ruby .symbol .keyword,pre .ruby .symbol .keymethods,pre .lisp .keyword,pre .tex .special,pre .input_number{color:#990073}pre .builtin,pre .built_in,pre .lisp .title{color:#0086b3}pre .preprocessor,pre .pi,pre .doctype,pre .shebang,pre .cdata{color:#999;font-weight:bold}pre .deletion{background:#fdd}pre .addition{background:#dfd}pre .diff .change{background:#0086b3}pre .chunk{color:#aaa}pre .tex .formula{opacity:.5}.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{position:absolute;left:-99999999px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ui-helper-clearfix{display:inline-block}/*\*/* html .ui-helper-clearfix{height:1%}.ui-helper-clearfix{display:block}/**/.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default !important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-widget :active{outline:0}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-icon{width:16px;height:16px;background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-off{background-position:-96px -144px}.ui-icon-radio-on{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-tl{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px}.ui-corner-tr{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;border-top-right-radius:4px}.ui-corner-bl{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.ui-corner-br{-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-corner-top{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;border-top-right-radius:4px}.ui-corner-bottom{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-corner-right{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-corner-left{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.ui-corner-all{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.30;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.30;filter:Alpha(Opacity=30);-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}#colorbox,#cboxOverlay,#cboxWrapper{position:absolute;top:0;left:0;z-index:9999;overflow:hidden}#cboxOverlay{position:fixed;width:100%;height:100%}#cboxMiddleLeft,#cboxBottomLeft{clear:left}#cboxContent{position:relative}#cboxLoadedContent{overflow:auto}#cboxTitle{margin:0}#cboxLoadingOverlay,#cboxLoadingGraphic{position:absolute;top:0;left:0;width:100%;height:100%}#cboxPrevious,#cboxNext,#cboxClose,#cboxSlideshow{cursor:pointer}.cboxPhoto{float:left;margin:auto;border:0;display:block;max-width:none}.cboxIframe{width:100%;height:100%;display:block;border:0}#colorbox,#cboxContent,#cboxLoadedContent{box-sizing:content-box}#cboxOverlay{background:#000}#cboxTopLeft{width:14px;height:14px;background:url(colorbox/controls.png) no-repeat 0 0}#cboxTopCenter{height:14px;background:url(colorbox/border.png) repeat-x top left}#cboxTopRight{width:14px;height:14px;background:url(colorbox/controls.png) no-repeat -36px 0}#cboxBottomLeft{width:14px;height:43px;background:url(colorbox/controls.png) no-repeat 0 -32px}#cboxBottomCenter{height:43px;background:url(colorbox/border.png) repeat-x bottom left}#cboxBottomRight{width:14px;height:43px;background:url(colorbox/controls.png) no-repeat -36px -32px}#cboxMiddleLeft{width:14px;background:url(colorbox/controls.png) repeat-y -175px 0}#cboxMiddleRight{width:14px;background:url(colorbox/controls.png) repeat-y -211px 0}#cboxContent{background:#fff;overflow:visible}.cboxIframe{background:#fff}#cboxError{padding:50px;border:1px solid #ccc}#cboxLoadedContent{margin-bottom:5px}#cboxLoadingOverlay{background:url(colorbox/loading_background.png) no-repeat center center}#cboxLoadingGraphic{background:url(colorbox/loading.gif) no-repeat center center}#cboxTitle{position:absolute;bottom:-25px;left:0;text-align:center;width:100%;font-weight:bold;color:#7c7c7c}#cboxCurrent{position:absolute;bottom:-25px;left:58px;font-weight:bold;color:#7c7c7c}#cboxPrevious,#cboxNext,#cboxClose,#cboxSlideshow{position:absolute;bottom:-29px;background:url(colorbox/controls.png) no-repeat 0 0;width:23px;height:23px;text-indent:-9999px}#cboxPrevious{left:0;background-position:-51px -25px}#cboxPrevious:hover{background-position:-51px 0}#cboxNext{left:27px;background-position:-75px -25px}#cboxNext:hover{background-position:-75px 0}#cboxClose{right:0;background-position:-100px -25px}#cboxClose:hover{background-position:-100px 0}.cboxSlideshow_on #cboxSlideshow{background-position:-125px 0;right:27px}.cboxSlideshow_on #cboxSlideshow:hover{background-position:-150px 0}.cboxSlideshow_off #cboxSlideshow{background-position:-150px -25px;right:27px}.cboxSlideshow_off #cboxSlideshow:hover{background-position:-125px 0}#loading{position:fixed;left:40%;top:50%}a{color:#333;text-decoration:none}a:hover{color:#000;text-decoration:underline}body{font-family:"Lucida Grande",Helvetica,"Helvetica Neue",Arial,sans-serif;padding:12px;background-color:#333}h1,h2,h3,h4{color:#1c2324;margin:0;padding:0;margin-bottom:12px}table{width:100%}#content{clear:left;background-color:white;border:2px solid #ddd;border-top:8px solid #ddd;padding:18px;-webkit-border-bottom-left-radius:5px;-webkit-border-bottom-right-radius:5px;-webkit-border-top-right-radius:5px;-moz-border-radius-bottomleft:5px;-moz-border-radius-bottomright:5px;-moz-border-radius-topright:5px;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top-right-radius:5px}.dataTables_filter,.dataTables_info{padding:2px 6px}abbr.timeago{text-decoration:none;border:0;font-weight:bold}.timestamp{float:right;color:#ddd}.group_tabs{list-style:none;float:left;margin:0;padding:0}.group_tabs li{display:inline;float:left}.group_tabs li a{font-family:Helvetica,Arial,sans-serif;display:block;float:left;text-decoration:none;padding:4px 8px;background-color:#aaa;background:-webkit-gradient(linear,0 0,0 bottom,from(#ddd),to(#aaa));background:-moz-linear-gradient(#ddd,#aaa);background:linear-gradient(#ddd,#aaa);text-shadow:#e5e5e5 1px 1px 0;border-bottom:0;color:#333;font-weight:bold;margin-right:8px;border-top:1px solid #efefef;-webkit-border-top-left-radius:2px;-webkit-border-top-right-radius:2px;-moz-border-radius-topleft:2px;-moz-border-radius-topright:2px;border-top-left-radius:2px;border-top-right-radius:2px}.group_tabs li a:hover{background-color:#ccc;background:-webkit-gradient(linear,0 0,0 bottom,from(#eee),to(#aaa));background:-moz-linear-gradient(#eee,#aaa);background:linear-gradient(#eee,#aaa)}.group_tabs li a:active{padding-top:5px;padding-bottom:3px}.group_tabs li.active a{color:black;text-shadow:#fff 1px 1px 0;background-color:#ddd;background:-webkit-gradient(linear,0 0,0 bottom,from(white),to(#ddd));background:-moz-linear-gradient(white,#ddd);background:linear-gradient(white,#ddd)}.file_list{margin-bottom:18px}.file_list--responsive{overflow-x:auto;overflow-y:hidden}a.src_link{background:url("./magnify.png") no-repeat left 50%;padding-left:18px}tr,td{margin:0;padding:0}th{white-space:nowrap}th.ui-state-default{cursor:pointer}th span.ui-icon{float:left}td{padding:4px 8px}td.strong{font-weight:bold}.cell--number{text-align:right}.source_table h3,.source_table h4{padding:0;margin:0;margin-bottom:4px}.source_table .header{padding:10px}.source_table pre{margin:0;padding:0;white-space:normal;color:#000;font-family:"Monaco","Inconsolata","Consolas",monospace}.source_table code{color:#000;font-family:"Monaco","Inconsolata","Consolas",monospace}.source_table pre{background-color:#333}.source_table pre ol{margin:0;padding:0;margin-left:45px;font-size:12px;color:white}.source_table pre li{margin:0;padding:2px 6px;border-left:5px solid white}.source_table pre li code{white-space:pre;white-space:pre-wrap}.source_table pre .hits{float:right;margin-left:10px;padding:2px 4px;background-color:#444;background:-webkit-gradient(linear,0 0,0 bottom,from(#222),to(#666));background:-moz-linear-gradient(#222,#666);background:linear-gradient(#222,#666);color:white;font-family:Helvetica,"Helvetica Neue",Arial,sans-serif;font-size:10px;font-weight:bold;text-align:center;border-radius:6px}#footer{color:#ddd;font-size:12px;font-weight:bold;margin-top:12px;text-align:right}#footer a{color:#eee;text-decoration:underline}#footer a:hover{color:#fff;text-decoration:none}.green{color:#090}.red{color:#900}.yellow{color:#da0}.blue{color:blue}thead th{background:white}.source_table .covered{border-color:#090}.source_table .missed{border-color:#900}.source_table .never{border-color:black}.source_table .skipped{border-color:#fc0}.source_table .missed-branch{border-color:#bf0000}.source_table .covered:nth-child(odd){background-color:#cdf2cd}.source_table .covered:nth-child(even){background-color:#dbf2db}.source_table .missed:nth-child(odd){background-color:#f7c0c0}.source_table .missed:nth-child(even){background-color:#f7cfcf}.source_table .never:nth-child(odd){background-color:#efefef}.source_table .never:nth-child(even){background-color:#f4f4f4}.source_table .skipped:nth-child(odd){background-color:#fbf0c0}.source_table .skipped:nth-child(even){background-color:#fbffcf}.source_table .missed-branch:nth-child(odd){background-color:#cc8e8e}.source_table .missed-branch:nth-child(even){background-color:#cc6e6e} \ No newline at end of file diff --git a/coverage/assets/0.12.2/application.js b/coverage/assets/0.12.2/application.js new file mode 100644 index 0000000000..e1c2ab2346 --- /dev/null +++ b/coverage/assets/0.12.2/application.js @@ -0,0 +1,7 @@ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(T,e){"use strict";function g(e,t,n){var r,a,i=(n=n||le).createElement("script");if(i.text=e,t)for(r in Se)(a=t[r]||t.getAttribute&&t.getAttribute(r))&&i.setAttribute(r,a);n.head.appendChild(i).parentNode.removeChild(i)}function m(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?pe[ge.call(e)]||"object":typeof e}function s(e){var t=!!e&&"length"in e&&e.length,n=m(e);return!we(e)&&!xe(e)&&("array"===n||0===t||"number"==typeof t&&0D.cacheLength&&delete n[r.shift()],n[e+" "]=t}var r=[];return n}function l(e){return e[q]=!0,e}function a(e){var t=E.createElement("fieldset");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function t(e,t){for(var n=e.split("|"),r=n.length;r--;)D.attrHandle[n[r]]=t}function u(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function r(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function i(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function o(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&_e(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function s(o){return l(function(i){return i=+i,l(function(e,t){for(var n,r=o([],e.length,i),a=r.length;a--;)e[n=r[a]]&&(e[n]=!(t[n]=e[n]))})})}function p(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function c(){}function g(e){for(var t=0,n=e.length,r="";t+~]|"+re+")"+re+"*"),fe=new RegExp(re+"|>"),de=new RegExp(oe),he=new RegExp("^"+ae+"$"),pe={ID:new RegExp("^#("+ae+")"),CLASS:new RegExp("^\\.("+ae+")"),TAG:new RegExp("^("+ae+"|[*])"),ATTR:new RegExp("^"+ie),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+re+"*(even|odd|(([+-]|)(\\d*)n|)"+re+"*(?:([+-]|)"+re+"*(\\d+)|))"+re+"*\\)|)","i"),bool:new RegExp("^(?:"+ne+")$","i"),needsContext:new RegExp("^"+re+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+re+"*((?:-\\d)?\\d*)"+re+"*\\)|)(?=[^-]|$)","i")},ge=/HTML$/i,me=/^(?:input|select|textarea|button)$/i,ve=/^h\d$/i,ye=/^[^{]+\{\s*\[native \w/,be=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,we=/[+~]/,xe=new RegExp("\\\\([\\da-f]{1,6}"+re+"?|("+re+")|.)","ig"),Se=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},De=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,Te=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},Ce=function(){L()},_e=f(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{Q.apply(Y=ee.call(W.childNodes),W.childNodes),Y[W.childNodes.length].nodeType}catch(Ae){Q={apply:Y.length?function(e,t){K.apply(e,ee.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}for(v in S=w.support={},C=w.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!ge.test(t||n&&n.nodeName||"HTML")},L=w.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:W;return r!==E&&9===r.nodeType&&r.documentElement&&(R=(E=r).documentElement,F=!C(E),W!==E&&(n=E.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Ce,!1):n.attachEvent&&n.attachEvent("onunload",Ce)),S.attributes=a(function(e){return e.className="i",!e.getAttribute("className")}),S.getElementsByTagName=a(function(e){return e.appendChild(E.createComment("")),!e.getElementsByTagName("*").length}),S.getElementsByClassName=ye.test(E.getElementsByClassName),S.getById=a(function(e){return R.appendChild(e).id=q,!E.getElementsByName||!E.getElementsByName(q).length}),S.getById?(D.filter.ID=function(e){var t=e.replace(xe,Se);return function(e){return e.getAttribute("id")===t}},D.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&F){var n=t.getElementById(e);return n?[n]:[]}}):(D.filter.ID=function(e){var n=e.replace(xe,Se);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},D.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&F){var n,r,a,i=t.getElementById(e);if(i){if((n=i.getAttributeNode("id"))&&n.value===e)return[i];for(a=t.getElementsByName(e),r=0;i=a[r++];)if((n=i.getAttributeNode("id"))&&n.value===e)return[i]}return[]}}),D.find.TAG=S.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):S.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],a=0,i=t.getElementsByTagName(e);if("*"!==e)return i;for(;n=i[a++];)1===n.nodeType&&r.push(n);return r},D.find.CLASS=S.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&F)return t.getElementsByClassName(e)},H=[],P=[],(S.qsa=ye.test(E.querySelectorAll))&&(a(function(e){R.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&P.push("[*^$]="+re+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||P.push("\\["+re+"*(?:value|"+ne+")"),e.querySelectorAll("[id~="+q+"-]").length||P.push("~="),e.querySelectorAll(":checked").length||P.push(":checked"),e.querySelectorAll("a#"+q+"+*").length||P.push(".#.+[+~]")}),a(function(e){e.innerHTML="";var t=E.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&P.push("name"+re+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&P.push(":enabled",":disabled"),R.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&P.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),P.push(",.*:")})),(S.matchesSelector=ye.test(M=R.matches||R.webkitMatchesSelector||R.mozMatchesSelector||R.oMatchesSelector||R.msMatchesSelector))&&a(function(e){S.disconnectedMatch=M.call(e,"*"),M.call(e,"[s!='']:x"),H.push("!=",oe)}),P=P.length&&new RegExp(P.join("|")),H=H.length&&new RegExp(H.join("|")),t=ye.test(R.compareDocumentPosition),O=t||ye.test(R.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},G=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!S.sortDetached&&t.compareDocumentPosition(e)===n?e===E||e.ownerDocument===W&&O(W,e)?-1:t===E||t.ownerDocument===W&&O(W,t)?1:I?te(I,e)-te(I,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,a=e.parentNode,i=t.parentNode,o=[e],s=[t];if(!a||!i)return e===E?-1:t===E?1:a?-1:i?1:I?te(I,e)-te(I,t):0;if(a===i)return u(e,t);for(n=e;n=n.parentNode;)o.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;o[r]===s[r];)r++;return r?u(o[r],s[r]):o[r]===W?-1:s[r]===W?1:0}),E},w.matches=function(e,t){return w(e,null,null,t)},w.matchesSelector=function(e,t){if((e.ownerDocument||e)!==E&&L(e),S.matchesSelector&&F&&!V[t+" "]&&(!H||!H.test(t))&&(!P||!P.test(t)))try{var n=M.call(e,t);if(n||S.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(Ae){V(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(xe,Se),e[3]=(e[3]||e[4]||e[5]||"").replace(xe,Se),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||w.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&w.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&de.test(n)&&(t=_(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(xe,Se).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=U[e+" "];return t||(t=new RegExp("(^|"+re+")"+e+"("+re+"|$)"))&&U(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,a){return function(e){var t=w.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===a:"!="===r?t!==a:"^="===r?a&&0===t.indexOf(a):"*="===r?a&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;Te.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?Te.find.matchesSelector(r,e)?[r]:[]:Te.find.matches(e,Te.grep(t,function(e){return 1===e.nodeType}))},Te.fn.extend({find:function(e){var t,n,r=this.length,a=this;if("string"!=typeof e)return this.pushStack(Te(e).filter(function(){for(t=0;t)[^>]*|#([\w-]+))$/;(Te.fn.init=function(e,t,n){var r,a;if(!e)return this;if(n=n||je,"string"!=typeof e)return e.nodeType?(this[0]=e,this.length=1,this):we(e)?n.ready!==undefined?n.ready(e):e(Te):Te.makeArray(e,this);if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:Le.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof Te?t[0]:t,Te.merge(this,Te.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:le,!0)),Ie.test(r[1])&&Te.isPlainObject(t))for(r in t)we(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(a=le.getElementById(r[2]))&&(this[0]=a,this.length=1),this}).prototype=Te.fn,je=Te(le);var Ee=/^(?:parents|prev(?:Until|All))/,Re={children:!0,contents:!0,next:!0,prev:!0};Te.fn.extend({has:function(e){var t=Te(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,rt=/^$|^module$|\/(?:java|ecma)script/i,at={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};at.optgroup=at.option,at.tbody=at.tfoot=at.colgroup=at.caption=at.thead,at.th=at.td;var it,ot,st=/<|&#?\w+;/;it=le.createDocumentFragment().appendChild(le.createElement("div")),(ot=le.createElement("input")).setAttribute("type","radio"),ot.setAttribute("checked","checked"),ot.setAttribute("name","t"),it.appendChild(ot),be.checkClone=it.cloneNode(!0).cloneNode(!0).lastChild.checked,it.innerHTML="",be.noCloneChecked=!!it.cloneNode(!0).lastChild.defaultValue;var lt=/^key/,ut=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ct=/^([^.]*)(?:\.(.+)|)/;Te.event={global:{},add:function(t,e,n,r,a){var i,o,s,l,u,c,f,d,h,p,g,m=Be.get(t);if(m)for(n.handler&&(n=(i=n).handler,a=i.selector),a&&Te.find.matchesSelector(Je,a),n.guid||(n.guid=Te.guid++),(l=m.events)||(l=m.events={}),(o=m.handle)||(o=m.handle=function(e){return void 0!==Te&&Te.event.triggered!==e.type?Te.event.dispatch.apply(t,arguments):undefined}),u=(e=(e||"").match(Fe)||[""]).length;u--;)h=g=(s=ct.exec(e[u])||[])[1],p=(s[2]||"").split(".").sort(),h&&(f=Te.event.special[h]||{},h=(a?f.delegateType:f.bindType)||h,f=Te.event.special[h]||{},c=Te.extend({type:h,origType:g,data:r,handler:n,guid:n.guid,selector:a,needsContext:a&&Te.expr.match.needsContext.test(a),namespace:p.join(".")},i),(d=l[h])||((d=l[h]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,p,o)||t.addEventListener&&t.addEventListener(h,o)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),a?d.splice(d.delegateCount++,0,c):d.push(c),Te.event.global[h]=!0)},remove:function(e,t,n,r,a){var i,o,s,l,u,c,f,d,h,p,g,m=Be.hasData(e)&&Be.get(e);if(m&&(l=m.events)){for(u=(t=(t||"").match(Fe)||[""]).length;u--;)if(h=g=(s=ct.exec(t[u])||[])[1],p=(s[2]||"").split(".").sort(),h){for(f=Te.event.special[h]||{},d=l[h=(r?f.delegateType:f.bindType)||h]||[],s=s[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),o=i=d.length;i--;)c=d[i],!a&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(d.splice(i,1),c.selector&&d.delegateCount--,f.remove&&f.remove.call(e,c));o&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,p,m.handle)||Te.removeEvent(e,h,m.handle),delete l[h])}else for(h in l)Te.event.remove(e,h+t[u],n,r,!0);Te.isEmptyObject(l)&&Be.remove(e,"handle events")}},dispatch:function(e){var t,n,r,a,i,o,s=Te.event.fix(e),l=new Array(arguments.length),u=(Be.get(this,"events")||{})[s.type]||[],c=Te.event.special[s.type]||{};for(l[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,dt=/\s*$/g;Te.extend({htmlPrefilter:function(e){return e.replace(ft,"<$1>")},clone:function(e,t,n){var r,a,i,o,s=e.cloneNode(!0),l=Ye(e);if(!(be.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||Te.isXMLDoc(e)))for(o=w(s),r=0,a=(i=w(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",a=function(e){r.remove(),a=null,e&&t("error"===e.type?404:200,e.type)}),le.head.appendChild(r[0])},abort:function(){a&&a()}}});var an,on=[],sn=/(=)\?(?=&|$)|\?\?/;Te.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=on.pop()||Te.expando+"_"+Ot++;return this[e]=!0,e}}),Te.ajaxPrefilter("json jsonp",function(e,t,n){var r,a,i,o=!1!==e.jsonp&&(sn.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&sn.test(e.data)&&"data");if(o||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=we(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,o?e[o]=e[o].replace(sn,"$1"+r):!1!==e.jsonp&&(e.url+=(qt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return i||Te.error(r+" was not called"),i[0]},e.dataTypes[0]="json",a=T[r],T[r]=function(){i=arguments},n.always(function(){a===undefined?Te(T).removeProp(r):T[r]=a,e[r]&&(e.jsonpCallback=t.jsonpCallback,on.push(r)),i&&we(a)&&a(i[0]),i=a=undefined}),"script"}),be.createHTMLDocument=((an=le.implementation.createHTMLDocument("").body).innerHTML="
",2===an.childNodes.length),Te.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(be.createHTMLDocument?((r=(t=le.implementation.createHTMLDocument("")).createElement("base")).href=le.location.href,t.head.appendChild(r)):t=le),i=!n&&[],(a=Ie.exec(e))?[t.createElement(a[1])]:(a=S([e],t,i),i&&i.length&&Te(i).remove(),Te.merge([],a.childNodes)));var r,a,i},Te.fn.load=function(e,t,n){var r,a,i,o=this,s=e.indexOf(" ");return-1").append(Te.parseHTML(e)).find(r):e)}).always(n&&function(e,t){o.each(function(){n.apply(this,i||[e.responseText,t,e])})}),this},Te.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){Te.fn[t]=function(e){return this.on(t,e)}}),Te.expr.pseudos.animated=function(t){return Te.grep(Te.timers,function(e){return t===e.elem}).length},Te.offset={setOffset:function(e,t,n){var r,a,i,o,s,l,u=Te.css(e,"position"),c=Te(e),f={};"static"===u&&(e.style.position="relative"),s=c.offset(),i=Te.css(e,"top"),l=Te.css(e,"left"),("absolute"===u||"fixed"===u)&&-1<(i+l).indexOf("auto")?(o=(r=c.position()).top,a=r.left):(o=parseFloat(i)||0,a=parseFloat(l)||0),we(t)&&(t=t.call(e,n,Te.extend({},s))),null!=t.top&&(f.top=t.top-s.top+o),null!=t.left&&(f.left=t.left-s.left+a),"using"in t?t.using.call(e,f):c.css(f)}},Te.fn.extend({offset:function(t){if(arguments.length)return t===undefined?this:this.each(function(e){Te.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],a={top:0,left:0};if("fixed"===Te.css(r,"position"))t=r.getBoundingClientRect();else{for(t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;e&&(e===n.body||e===n.documentElement)&&"static"===Te.css(e,"position");)e=e.parentNode;e&&e!==r&&1===e.nodeType&&((a=Te(e).offset()).top+=Te.css(e,"borderTopWidth",!0),a.left+=Te.css(e,"borderLeftWidth",!0))}return{top:t.top-a.top-Te.css(r,"marginTop",!0),left:t.left-a.left-Te.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent;e&&"static"===Te.css(e,"position");)e=e.offsetParent;return e||Je})}}),Te.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,a){var i="pageYOffset"===a;Te.fn[t]=function(e){return Me(this,function(e,t,n){var r;if(xe(e)?r=e:9===e.nodeType&&(r=e.defaultView),n===undefined)return r?r[a]:e[t];r?r.scrollTo(i?r.pageXOffset:n,i?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),Te.each(["top","left"],function(e,n){Te.cssHooks[n]=M(be.pixelPosition,function(e,t){if(t)return t=H(e,n),gt.test(t)?Te(e).position()[n]+"px":t})}),Te.each({Height:"height",Width:"width"},function(o,s){Te.each({padding:"inner"+o,content:s,"":"outer"+o},function(r,i){Te.fn[i]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),a=r||(!0===e||!0===t?"margin":"border");return Me(this,function(e,t,n){var r;return xe(e)?0===i.indexOf("outer")?e["inner"+o]:e.document.documentElement["client"+o]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+o],r["scroll"+o],e.body["offset"+o],r["offset"+o],r["client"+o])):n===undefined?Te.css(e,t,a):Te.style(e,t,n,a)},s,n?e:undefined,n)}})}),Te.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){Te.fn[n]=function(e,t){return 0"}for(var i=0,o="",s=[];e.length||t.length;){var l=r().splice(0,1)[0];if(o+=x(n.substr(i,l.offset-i)),i=l.offset,"start"==l.event)o+=a(l.node),s.push(l.node);else if("stop"==l.event){var u=s.length;do{var c=s[--u];o+=""}while(c!=l.node);for(s.splice(u,1);u'+x(a[0])+""):n+=x(a[0]),r=t.lR.lastIndex,a=t.lR.exec(e)}return n+=x(e.substr(r,e.length-r))}function f(e,t){if(t.sL&&T[t.sL]){var n=D(t.sL,e);return g+=n.keyword_count,n.value}return r(e,t)}function d(e,t){var n=e.cN?'':"";e.rB?(m+=n,e.buffer=""):e.eB?(m+=x(t)+n,e.buffer=""):(m+=n,e.buffer=t),h.push(e),p+=e.r}function i(e,t,n){var r=h[h.length-1];if(n)return m+=f(r.buffer+e,r),!1;var a=l(t,r);if(a)return m+=f(r.buffer+e,r),d(a,t),a.rB;var i=u(h.length-1,t);if(i){var o=r.cN?"":"";for(r.rE?m+=f(r.buffer+e,r)+o:r.eE?m+=f(r.buffer+e,r)+o+x(t):m+=f(r.buffer+e+t,r)+o;1":"",m+=o,i--,h.length--;var s=h[h.length-1];return h.length--,h[h.length-1].buffer="",s.starts&&d(s.starts,""),r.rE}if(c(t,r))throw"Illegal"}var s=T[e],h=[s.dM],p=0,g=0,m="";try{var v=0;s.dM.buffer="";do{var y=n(t,v),b=i(y[0],y[1],y[2]);v+=y[0].length,b||(v+=y[1].length)}while(!y[2]);if(1o.keyword_count+o.r&&(o=l),l.keyword_count+l.r>i.keyword_count+i.r&&(o=i,i=l)}}var u=e.className;u.match(i.language)||(u=u?u+" "+i.language:i.language);var c=g(e);if(c.length)(f=document.createElement("pre")).innerHTML=i.value,i.value=m(c,g(f),r);if(n&&(i.value=i.value.replace(/^((<[^>]+>|\t)+)/gm,function(e,t){return t.replace(/\t/g,n)})),t&&(i.value=i.value.replace(/\n/g,"
")),/MSIE [678]/.test(navigator.userAgent)&&"CODE"==e.tagName&&"PRE"==e.parentNode.tagName){var f=e.parentNode,d=document.createElement("div");d.innerHTML="
"+i.value+"
",e=d.firstChild.firstChild,d.firstChild.cN=f.cN,f.parentNode.replaceChild(d.firstChild,f)}else e.innerHTML=i.value;e.className=u,e.dataset={},e.dataset.result={language:i.language,kw:i.keyword_count,re:i.r},o&&o.language&&(e.dataset.second_best={language:o.language,kw:o.keyword_count,re:o.r})}}function i(){if(!i.called){i.called=!0,v();for(var e=document.getElementsByTagName("pre"),t=0;t|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",this.BE={b:"\\\\.",r:0},this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0},this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0},this.CLCM={cN:"comment",b:"//",e:"$"},this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"},this.HCM={cN:"comment",b:"#",e:"$"},this.NM={cN:"number",b:this.NR,r:0},this.CNM={cN:"number",b:this.CNR,r:0},this.inherit=function(e,t){var n={};for(var r in e)n[r]=e[r];if(t)for(var r in t)n[r]=t[r];return n}};hljs.LANGUAGES.ruby=function(){var e="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?",t="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",n={keyword:{and:1,"false":1,then:1,defined:1,module:1,"in":1,"return":1,redo:1,"if":1,BEGIN:1,retry:1,end:1,"for":1,"true":1,self:1,when:1,next:1,until:1,"do":1,begin:1,unless:1,END:1,rescue:1,nil:1,"else":1,"break":1,undef:1,not:1,"super":1,"class":1,"case":1,require:1,"yield":1,alias:1,"while":1,ensure:1,elsif:1,or:1,def:1},keymethods:{__id__:1,__send__:1,abort:1,abs:1,"all?":1,allocate:1,ancestors:1,"any?":1,arity:1,assoc:1,at:1,at_exit:1,autoload:1,"autoload?":1,"between?":1,binding:1,binmode:1,"block_given?":1,call:1,callcc:1,caller:1,capitalize:1,"capitalize!":1,casecmp:1,"catch":1,ceil:1,center:1,chomp:1,"chomp!":1,chop:1,"chop!":1,chr:1,"class":1,class_eval:1,"class_variable_defined?":1,class_variables:1,clear:1,clone:1,close:1,close_read:1,close_write:1,"closed?":1,coerce:1,collect:1,"collect!":1,compact:1,"compact!":1,concat:1,"const_defined?":1,const_get:1,const_missing:1,const_set:1,constants:1,count:1,crypt:1,"default":1,default_proc:1,"delete":1,"delete!":1,delete_at:1,delete_if:1,detect:1,display:1,div:1,divmod:1,downcase:1,"downcase!":1,downto:1,dump:1,dup:1,each:1,each_byte:1,each_index:1,each_key:1,each_line:1,each_pair:1,each_value:1,each_with_index:1,"empty?":1,entries:1,eof:1,"eof?":1,"eql?":1,"equal?":1,eval:1,exec:1,exit:1,"exit!":1,extend:1,fail:1,fcntl:1,fetch:1,fileno:1,fill:1,find:1,find_all:1,first:1,flatten:1,"flatten!":1,floor:1,flush:1,for_fd:1,foreach:1,fork:1,format:1,freeze:1,"frozen?":1,fsync:1,getc:1,gets:1,global_variables:1,grep:1,gsub:1,"gsub!":1,"has_key?":1,"has_value?":1,hash:1,hex:1,id:1,include:1,"include?":1,included_modules:1,index:1,indexes:1,indices:1,induced_from:1,inject:1,insert:1,inspect:1,instance_eval:1,instance_method:1,instance_methods:1,"instance_of?":1,"instance_variable_defined?":1,instance_variable_get:1,instance_variable_set:1,instance_variables:1,"integer?":1,intern:1,invert:1,ioctl:1,"is_a?":1,isatty:1,"iterator?":1,join:1,"key?":1,keys:1,"kind_of?":1,lambda:1,last:1,length:1,lineno:1,ljust:1,load:1,local_variables:1,loop:1,lstrip:1,"lstrip!":1,map:1,"map!":1,match:1,max:1,"member?":1,merge:1,"merge!":1,method:1,"method_defined?":1,method_missing:1,methods:1,min:1,module_eval:1,modulo:1,name:1,nesting:1,"new":1,next:1,"next!":1,"nil?":1,nitems:1,"nonzero?":1,object_id:1,oct:1,open:1,pack:1,partition:1,pid:1,pipe:1,pop:1,popen:1,pos:1,prec:1,prec_f:1,prec_i:1,print:1,printf:1,private_class_method:1,private_instance_methods:1,"private_method_defined?":1,private_methods:1,proc:1,protected_instance_methods:1, +"protected_method_defined?":1,protected_methods:1,public_class_method:1,public_instance_methods:1,"public_method_defined?":1,public_methods:1,push:1,putc:1,puts:1,quo:1,raise:1,rand:1,rassoc:1,read:1,read_nonblock:1,readchar:1,readline:1,readlines:1,readpartial:1,rehash:1,reject:1,"reject!":1,remainder:1,reopen:1,replace:1,require:1,"respond_to?":1,reverse:1,"reverse!":1,reverse_each:1,rewind:1,rindex:1,rjust:1,round:1,rstrip:1,"rstrip!":1,scan:1,seek:1,select:1,send:1,set_trace_func:1,shift:1,singleton_method_added:1,singleton_methods:1,size:1,sleep:1,slice:1,"slice!":1,sort:1,"sort!":1,sort_by:1,split:1,sprintf:1,squeeze:1,"squeeze!":1,srand:1,stat:1,step:1,store:1,strip:1,"strip!":1,sub:1,"sub!":1,succ:1,"succ!":1,sum:1,superclass:1,swapcase:1,"swapcase!":1,sync:1,syscall:1,sysopen:1,sysread:1,sysseek:1,system:1,syswrite:1,taint:1,"tainted?":1,tell:1,test:1,"throw":1,times:1,to_a:1,to_ary:1,to_f:1,to_hash:1,to_i:1,to_int:1,to_io:1,to_proc:1,to_s:1,to_str:1,to_sym:1,tr:1,"tr!":1,tr_s:1,"tr_s!":1,trace_var:1,transpose:1,trap:1,truncate:1,"tty?":1,type:1,ungetc:1,uniq:1,"uniq!":1,unpack:1,unshift:1,untaint:1,untrace_var:1,upcase:1,"upcase!":1,update:1,upto:1,"value?":1,values:1,values_at:1,warn:1,write:1,write_nonblock:1,"zero?":1,zip:1}},r={cN:"yardoctag",b:"@[A-Za-z]+"},a={cN:"comment",b:"#",e:"$",c:[r]},i={cN:"comment",b:"^\\=begin",e:"^\\=end",c:[r],r:10},o={cN:"comment",b:"^__END__",e:"\\n$"},s={cN:"subst",b:"#\\{",e:"}",l:e,k:n},l=[hljs.BE,s],u={cN:"string",b:"'",e:"'",c:l,r:0},c={cN:"string",b:'"',e:'"',c:l,r:0},f={cN:"string",b:"%[qw]?\\(",e:"\\)",c:l,r:10},d={cN:"string",b:"%[qw]?\\[",e:"\\]",c:l,r:10},h={cN:"string",b:"%[qw]?{",e:"}",c:l,r:10},p={cN:"string",b:"%[qw]?<",e:">",c:l,r:10},g={cN:"string",b:"%[qw]?/",e:"/",c:l,r:10},m={cN:"string",b:"%[qw]?%",e:"%",c:l,r:10},v={cN:"string",b:"%[qw]?-",e:"-",c:l,r:10},y={cN:"string",b:"%[qw]?\\|",e:"\\|",c:l,r:10},b={cN:"function",b:"\\bdef\\s+",e:" |$|;",l:e,k:n,c:[{cN:"title",b:t,l:e,k:n},{cN:"params",b:"\\(",e:"\\)",l:e,k:n},a,i,o]},w={cN:"identifier",b:e,l:e,k:n,r:0},x=[a,i,o,u,c,f,d,h,p,g,m,v,y,{cN:"class",b:"\\b(class|module)\\b",e:"$|;",k:{"class":1,module:1},c:[{cN:"title",b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?",r:0},{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+hljs.IR+"::)?"+hljs.IR}]},a,i,o]},b,{cN:"constant",b:"(::)?([A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:[u,c,f,d,h,p,g,m,v,y,w],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"number",b:"\\?\\w"},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},w,{b:"("+hljs.RSR+")\\s*",c:[a,i,o,{cN:"regexp",b:"/",e:"/[a-z]*",i:"\\n",c:[hljs.BE]}],r:0}];return s.c=x,{dM:{l:e,k:n,c:b.c[1].c=x}}}(),function(c,s,o){function l(e,t,n){var r=s.createElement(e);return t&&(r.id=te+t),n&&(r.style.cssText=n),c(r)}function f(){return o.innerHeight?o.innerHeight:c(o).height()}function u(e,n){n!==Object(n)&&(n={}),this.cache={},this.el=e,this.value=function(e){var t;return this.cache[e]===undefined&&((t=c(this.el).attr("data-cbox-"+e))!==undefined?this.cache[e]=t:n[e]!==undefined?this.cache[e]=n[e]:Q[e]!==undefined&&(this.cache[e]=Q[e])),this.cache[e]},this.get=function(e){var t=this.value(e);return c.isFunction(t)?t.call(this.el,this):t}}function i(e){var t=k.length,n=(X+e)%t;return n<0?t+n:n}function d(e,t){return Math.round((/%/.test(e)?("x"===t?I.width():f())/100:1)*parseInt(e,10))}function h(e,t){return e.get("photo")||e.get("photoRegex").test(t)}function p(e,t){return e.get("retinaUrl")&&1"),w()}}function a(){S||(t=!1,I=c(o),S=l(ce).attr({id:ee,"class":!1===c.support.opacity?te+"IE":"",role:"dialog",tabindex:"-1"}).hide(),x=l(ce,"Overlay").hide(),E=c([l(ce,"LoadingOverlay")[0],l(ce,"LoadingGraphic")[0]]),D=l(ce,"Wrapper"),T=l(ce,"Content").append(R=l(ce,"Title"),F=l(ce,"Current"),M=c('