commit 298610b5f6b508a1b5f209f84ee9a565360a0ff4 Author: Robbie Paul Date: Wed Apr 29 11:21:39 2026 +0100 Initial commit (history cleared) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fa13bee --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + matrix: + ruby-version: ['3.4.1'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + + - name: Install dependencies + run: bundle install + + - name: Setup database + run: | + RAILS_ENV=test bundle exec rails db:create + RAILS_ENV=test bundle exec rails db:migrate + + - name: Run tests + env: + RAILSGOAT_MAINTAINER: true + run: bundle exec rspec + + - name: Run security audit + run: bundle exec bundle-audit check --update + continue-on-error: true diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..cc92eae --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +.rvmrc +/.bundle +/bin +/db/*.sqlite3 +/log/*.log +/tmp +.elasticbeanstalk/ +.DS_Store +/public/data +/public/assets +*.png +coverage +.tags +/.vagrant +/vendor/ruby diff --git a/.overcommit.yml b/.overcommit.yml new file mode 100644 index 0000000..beb8964 --- /dev/null +++ b/.overcommit.yml @@ -0,0 +1,30 @@ +# Use this file to configure the Overcommit hooks you wish to use. This will +# extend the default configuration defined in: +# https://github.com/brigade/overcommit/blob/master/config/default.yml +# +# At the topmost level of this YAML file is a key representing type of hook +# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can +# customize each hook, such as whether to only run it on certain files (via +# `include`), whether to only display output if it fails (via `quiet`), etc. +# +# For a complete list of hooks, see: +# https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook +# +# For a complete list of options that you can use to customize hooks, see: +# https://github.com/brigade/overcommit#configuration +# +# Uncomment the following lines to make the configuration take effect. + +PreCommit: + TrailingWhitespace: + enabled: true + exclude: + - '**/db/structure.sql' # Ignore trailing whitespace in generated files + + PostCheckout: + enabled: true + ALL: # Special hook name that customizes all hooks of this type + quiet: true # Change all post-checkout hooks to only display output on failure + +# IndexTags: +# enabled: true # Generate a tags file with `ctags` each time HEAD changes diff --git a/.powrc b/.powrc new file mode 100644 index 0000000..80850f5 --- /dev/null +++ b/.powrc @@ -0,0 +1,9 @@ +if [ -f "${rvm_path}/scripts/rvm" ]; then + source "${rvm_path}/scripts/rvm" + + if [ -f ".rvmrc" ]; then + source ".rvmrc" + elif [ -f ".ruby-version" ] && [ -f ".ruby-gemset" ]; then + rvm use `cat .ruby-version`@`cat .ruby-gemset` + fi +fi diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..9fc14ad --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--backtrace \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..77b4529 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,9 @@ +inherit_gem: + rubocop-github: + - config/default.yml + - config/rails.yml + + +Rails/OutputSafety: + Exclude: + - 'app/controllers/password_resets_controller.rb' diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 0000000..b546338 --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +railsgoat diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..47b322c --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.4.1 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..00c1c76 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. +Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. +Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at railsgoat@gmail.com. +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. +The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a0ee2be --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,66 @@ +# Ways to Contribute to RailsGoat + +Thanks for your interest on contributing to RailsGoat! +Here are a few general guidelines on contributing and reporting +bugs to RailsGoat that we ask you to take a look first. +Notice that all of your interactions in the project are +expected to follow our [Code of Conduct](./CODE_OF_CONDUCT.md). + +## Reporting Issues + +Before reporting a new issue, please be sure that the issue wasn't +already reported or fixed by searching on GitHub through our +[issues](https://github.com/OWASP/railsgoat/issues). + +When creating a new issue, be sure to include a **title and clear description**, +as much relevant information as possible, and either a test case example or +even better a **sample Rails app that replicates the issue** - +RailsGoat has a lot of moving parts and it's functionality can be affected +by third party gems, so we need as much context and details as possible +to identify what might be broken for you. + +Avoid opening new issues to ask questions in our issues tracker. +Please go through the project wiki, documentation and source code first, +or try to ask your question in our +[Slack Channel](https://owasp.slack.com/messages/C04THC44W). + +## Sending Pull Requests + +Before sending a new Pull Request, take a look on existing Pull Requests +and Issues to see if the proposed change or fix has been discussed in +the past, or if the change was already implemented but not yet released. + +We expect new Pull Requests to include enough tests for new or changed +behavior, and we aim to maintain everything as most backwards compatible +as possible, reserving breaking changes to be ship in major releases +when necessary + +If your Pull Request includes new or changed behavior, be sure that the +changes are beneficial to a wide range of use cases or it's an application +specific change that might not be so valuable to other applications. + +We also welcome Pull Requests that improve our existing documentation +(both our `README.md` and the doc sections in the source code). + +## Other Ways to Contribute + +We welcome anyone that wants to contribute to RailsGoat to triage +and reply to open issues to help troubleshoot and fix existing bugs +on RailsGoat. Here is what you can do: + +* Help ensure that existing issues follows the recommendations from the +[Reporting Issues template](./ISSUE_TEMPLATE.md), +providing feeback to the issue's author on what might be missing. +* Review and update the existing content of our +[Wiki](https://github.com/OWASP/railsgoat/wiki) +with up to date instructions and code samples - the wiki was grown +with several different tutorials and references that we can't keep +track of everything, so if there is a page that showcases an integration +or customization that you are familiar with feel free to update it +as necessary. +* Review existing Pull Requests, and testing patches against real +existing applications that use RailsGoat. + +Thanks again for your interest on contributing to the project! + +:heart: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a6e13b6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM --platform=linux/amd64 ruby:3.4.1 +RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs +RUN mkdir /myapp +WORKDIR /myapp +ADD Gemfile /myapp/Gemfile +ADD Gemfile.lock /myapp/Gemfile.lock +RUN gem install bundler +RUN bundle install +ADD . /myapp diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..d7b16d5 --- /dev/null +++ b/Gemfile @@ -0,0 +1,62 @@ +# frozen_string_literal: true +source "https://rubygems.org" + +gem "rails", "~> 8.0.0" + +ruby "3.4.1" + +gem "aruba" +gem "bcrypt" +gem "foreman" +gem "jquery-fileupload-rails" +gem "jquery-rails" +gem "minitest" +gem "pry-rails" # not in dev group in case running via prod/staging @ a training +gem "puma", "~> 6.0" +gem "rake" +gem "responders" +gem "ruby-prof" +gem "sassc-rails" +gem "simplecov", require: false, group: :test +gem "sqlite3", "~> 2.0" +gem "turbolinks" + +# Asset pipeline +gem "sprockets-rails" +gem "importmap-rails" +gem "stimulus-rails" +gem "turbo-rails" + +# Add SMTP server support using MailCatcher +# NOTE: https://github.com/sj26/mailcatcher#bundler +# gem 'mailcatcher' + +group :development, :mysql do + gem "better_errors" + gem "binding_of_caller" + gem "bundler-audit" + gem "guard-livereload" + gem "guard-rspec" + gem "guard-shell" + gem "pry" + gem "rack-livereload" + gem "rb-fsevent" + gem "rubocop" +end + +group :development, :test, :mysql do + gem "capybara" + gem "database_cleaner" + gem "launchy" + gem "selenium-webdriver" + gem "rspec-rails" + gem "test-unit" +end + +group :openshift do + gem "pg" +end + +group :mysql do + gem "mysql2" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..a5b0674 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,737 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (8.0.4) + actionpack (= 8.0.4) + activesupport (= 8.0.4) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + zeitwerk (~> 2.6) + actionmailbox (8.0.4) + actionpack (= 8.0.4) + activejob (= 8.0.4) + activerecord (= 8.0.4) + activestorage (= 8.0.4) + activesupport (= 8.0.4) + mail (>= 2.8.0) + actionmailer (8.0.4) + actionpack (= 8.0.4) + actionview (= 8.0.4) + activejob (= 8.0.4) + activesupport (= 8.0.4) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (8.0.4) + actionview (= 8.0.4) + activesupport (= 8.0.4) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (8.0.4) + actionpack (= 8.0.4) + activerecord (= 8.0.4) + activestorage (= 8.0.4) + activesupport (= 8.0.4) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (8.0.4) + activesupport (= 8.0.4) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (8.0.4) + activesupport (= 8.0.4) + globalid (>= 0.3.6) + activemodel (8.0.4) + activesupport (= 8.0.4) + activerecord (8.0.4) + activemodel (= 8.0.4) + activesupport (= 8.0.4) + timeout (>= 0.4.0) + activestorage (8.0.4) + actionpack (= 8.0.4) + activejob (= 8.0.4) + activerecord (= 8.0.4) + activesupport (= 8.0.4) + marcel (~> 1.0) + activesupport (8.0.4) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.8) + public_suffix (>= 2.0.2, < 8.0) + aruba (2.3.3) + bundler (>= 1.17) + contracts (>= 0.16.0, < 0.18.0) + cucumber (>= 8.0, < 11.0) + rspec-expectations (>= 3.4, < 5.0) + thor (~> 1.0) + ast (2.4.3) + base64 (0.3.0) + bcrypt (3.1.21) + benchmark (0.5.0) + better_errors (2.10.1) + erubi (>= 1.0.0) + rack (>= 0.9.0) + rouge (>= 1.0.0) + bigdecimal (4.0.1) + binding_of_caller (1.0.1) + debug_inspector (>= 1.2.0) + builder (3.3.0) + bundler-audit (0.9.3) + bundler (>= 1.2.0) + thor (~> 1.0) + capybara (3.40.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.11) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + childprocess (5.1.0) + logger (~> 1.5) + coderay (1.1.3) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) + contracts (0.17.3) + crass (1.0.6) + cucumber (10.2.0) + base64 (~> 0.2) + builder (~> 3.2) + cucumber-ci-environment (> 9, < 12) + cucumber-core (> 15, < 17) + cucumber-cucumber-expressions (> 17, < 20) + cucumber-html-formatter (> 21, < 23) + diff-lcs (~> 1.5) + logger (~> 1.6) + mini_mime (~> 1.1) + multi_test (~> 1.1) + sys-uname (~> 1.3) + cucumber-ci-environment (11.0.0) + cucumber-core (16.1.1) + cucumber-gherkin (> 36, < 40) + cucumber-messages (> 31, < 33) + cucumber-tag-expressions (> 6, < 9) + cucumber-cucumber-expressions (18.1.0) + bigdecimal + cucumber-gherkin (38.0.0) + cucumber-messages (>= 31, < 33) + cucumber-html-formatter (22.3.0) + cucumber-messages (> 23, < 33) + cucumber-messages (32.0.0) + cucumber-tag-expressions (8.1.0) + database_cleaner (2.1.0) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.2.2) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0) + database_cleaner-core (2.0.1) + date (3.5.1) + debug_inspector (1.2.0) + diff-lcs (1.6.2) + docile (1.4.1) + drb (2.2.3) + em-websocket (0.5.3) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0) + erb (6.0.1) + erubi (1.13.1) + eventmachine (1.2.7) + ffi (1.17.3) + ffi (1.17.3-aarch64-linux-gnu) + ffi (1.17.3-aarch64-linux-musl) + ffi (1.17.3-arm-linux-gnu) + ffi (1.17.3-arm-linux-musl) + ffi (1.17.3-arm64-darwin) + ffi (1.17.3-x86_64-darwin) + ffi (1.17.3-x86_64-linux-gnu) + ffi (1.17.3-x86_64-linux-musl) + foreman (0.90.0) + thor (~> 1.4) + formatador (1.2.3) + reline + globalid (1.3.0) + activesupport (>= 6.1) + guard (2.20.0) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + logger (~> 1.6) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.13.0) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-livereload (2.5.2) + em-websocket (~> 0.5) + guard (~> 2.8) + guard-compat (~> 1.0) + multi_json (~> 1.8) + guard-rspec (4.7.3) + guard (~> 2.1) + guard-compat (~> 1.1) + rspec (>= 2.99.0, < 4.0) + guard-shell (0.7.2) + guard (>= 2.0.0) + guard-compat (~> 1.0) + http_parser.rb (0.8.1) + i18n (1.14.8) + concurrent-ruby (~> 1.0) + importmap-rails (2.2.3) + actionpack (>= 6.0.0) + activesupport (>= 6.0.0) + railties (>= 6.0.0) + io-console (0.8.2) + irb (1.16.0) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jquery-fileupload-rails (1.0.0) + actionpack (>= 3.1) + railties (>= 3.1) + sassc + jquery-rails (4.6.1) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + json (2.18.0) + language_server-protocol (3.17.0.5) + launchy (3.1.1) + addressable (~> 2.8) + childprocess (~> 5.0) + logger (~> 1.6) + lint_roller (1.1.0) + listen (3.10.0) + logger + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.7.0) + loofah (2.25.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + lumberjack (1.4.2) + mail (2.9.0) + logger + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.1.0) + matrix (0.4.3) + memoist3 (1.0.0) + method_source (1.1.0) + mini_mime (1.1.5) + mini_portile2 (2.8.9) + minitest (6.0.1) + prism (~> 1.5) + multi_json (1.19.1) + multi_test (1.1.0) + mysql2 (0.5.7) + bigdecimal + nenv (0.3.0) + net-imap (0.6.2) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.1) + net-protocol + nio4r (2.7.5) + nokogiri (1.19.0) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) + nokogiri (1.19.0-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.0-aarch64-linux-musl) + racc (~> 1.4) + nokogiri (1.19.0-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.0-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.19.0-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.0-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.19.0-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.0-x86_64-linux-musl) + racc (~> 1.4) + notiffany (0.1.3) + nenv (~> 0.1) + shellany (~> 0.0) + parallel (1.27.0) + parser (3.3.10.1) + ast (~> 2.4.1) + racc + pg (1.6.3) + pg (1.6.3-aarch64-linux) + pg (1.6.3-aarch64-linux-musl) + pg (1.6.3-arm64-darwin) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) + pg (1.6.3-x86_64-linux-musl) + power_assert (3.0.1) + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + prism (1.8.0) + pry (0.16.0) + coderay (~> 1.1) + method_source (~> 1.0) + reline (>= 0.6.0) + pry-rails (0.3.11) + pry (>= 0.13.0) + psych (5.3.1) + date + stringio + public_suffix (7.0.2) + puma (6.6.1) + nio4r (~> 2.0) + racc (1.8.1) + rack (3.1.19) + rack-livereload (0.6.1) + rack (>= 3.0, < 3.2) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.3.1) + rack (>= 3) + rails (8.0.4) + actioncable (= 8.0.4) + actionmailbox (= 8.0.4) + actionmailer (= 8.0.4) + actionpack (= 8.0.4) + actiontext (= 8.0.4) + actionview (= 8.0.4) + activejob (= 8.0.4) + activemodel (= 8.0.4) + activerecord (= 8.0.4) + activestorage (= 8.0.4) + activesupport (= 8.0.4) + bundler (>= 1.15.0) + railties (= 8.0.4) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.2) + loofah (~> 2.21) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (8.0.4) + actionpack (= 8.0.4) + activesupport (= 8.0.4) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) + rainbow (3.1.1) + rake (13.3.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rdoc (7.1.0) + erb + psych (>= 4.0.0) + tsort + regexp_parser (2.11.3) + reline (0.6.3) + io-console (~> 0.5) + responders (3.2.0) + actionpack (>= 7.0) + railties (>= 7.0) + rexml (3.4.4) + rouge (4.7.0) + rspec (3.13.2) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.6) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.7) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-rails (8.0.2) + actionpack (>= 7.2) + activesupport (>= 7.2) + railties (>= 7.2) + rspec-core (~> 3.13) + rspec-expectations (~> 3.13) + rspec-mocks (~> 3.13) + rspec-support (~> 3.13) + rspec-support (3.13.6) + rubocop (1.82.1) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.48.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.49.0) + parser (>= 3.3.7.2) + prism (~> 1.7) + ruby-prof (1.7.2) + base64 + ruby-progressbar (1.13.0) + rubyzip (3.2.2) + 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 + securerandom (0.4.1) + selenium-webdriver (4.40.0) + base64 (~> 0.2) + logger (~> 1.4) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 4.0) + websocket (~> 1.0) + shellany (0.0.1) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.13.2) + simplecov_json_formatter (0.1.4) + sprockets (4.2.2) + concurrent-ruby (~> 1.0) + logger + rack (>= 2.2.4, < 4) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) + sprockets (>= 3.0.0) + sqlite3 (2.9.0) + mini_portile2 (~> 2.8.0) + sqlite3 (2.9.0-aarch64-linux-gnu) + sqlite3 (2.9.0-aarch64-linux-musl) + sqlite3 (2.9.0-arm-linux-gnu) + sqlite3 (2.9.0-arm-linux-musl) + sqlite3 (2.9.0-arm64-darwin) + sqlite3 (2.9.0-x86_64-darwin) + sqlite3 (2.9.0-x86_64-linux-gnu) + sqlite3 (2.9.0-x86_64-linux-musl) + stimulus-rails (1.3.4) + railties (>= 6.0.0) + stringio (3.2.0) + sys-uname (1.4.1) + ffi (~> 1.1) + memoist3 (~> 1.0.0) + test-unit (3.7.7) + power_assert + thor (1.5.0) + tilt (2.7.0) + timeout (0.6.0) + tsort (0.2.0) + turbo-rails (2.0.21) + actionpack (>= 7.1.0) + railties (>= 7.1.0) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + uri (1.1.1) + useragent (0.16.11) + websocket (1.2.11) + websocket-driver (0.8.0) + base64 + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.7.4) + +PLATFORMS + aarch64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + universal-darwin + x86_64-darwin + x86_64-linux + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + aruba + bcrypt + better_errors + binding_of_caller + bundler-audit + capybara + database_cleaner + foreman + guard-livereload + guard-rspec + guard-shell + importmap-rails + jquery-fileupload-rails + jquery-rails + launchy + minitest + mysql2 + pg + pry + pry-rails + puma (~> 6.0) + rack-livereload + rails (~> 8.0.0) + rake + rb-fsevent + responders + rspec-rails + rubocop + ruby-prof + sassc-rails + selenium-webdriver + simplecov + sprockets-rails + sqlite3 (~> 2.0) + stimulus-rails + test-unit + turbo-rails + turbolinks + +CHECKSUMS + actioncable (8.0.4) sha256=aadb2bf2977b666cfeaa7dee66fd50e147559f78a8d55f6169e913502475e09f + actionmailbox (8.0.4) sha256=ed0b634a502fb63d1ba01ae025772e9d0261b7ba12e66389c736fcf4635cd80f + actionmailer (8.0.4) sha256=3b9270d8e19f0afb534b11c52f439937dc30028adcbbae2b244f3383ce75de4b + actionpack (8.0.4) sha256=0364c7582f32c8f404725fa30d3f6853f834c5f4964afd4a072b848c8a23cddb + actiontext (8.0.4) sha256=40b3970268ac29b865685456b2586df5052d068fd0cb04acb2291e737cea2340 + actionview (8.0.4) sha256=5bd3c41ee7a59e14cf062bb5e4ee53c9a253d12fc13c8754cae368012e1a1648 + activejob (8.0.4) sha256=cbc8a85d0e168cb90a5629c8a36fe2d08ba840103d3aed3eee0c7beb784fccce + activemodel (8.0.4) sha256=8f4e4fac3cd104b1bf30419c3745206f6f724c0e2902a939b4113f4c90730dfd + activerecord (8.0.4) sha256=bda32c171799e5ca5460447d3b7272ed14447244e2497abf2107f87fc44cbf32 + activestorage (8.0.4) sha256=47f312962fc898c1669f20cf7448d19668a5547f4a5f64e59a837d9d3f64a043 + activesupport (8.0.4) sha256=894a3a6c7733b5fae5a7df3acd76c4b563f38687df8a04fa3cbd25360f3fe95a + addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057 + aruba (2.3.3) sha256=837a2f023368a75a38ad9be227e9738ab9af7df3b3f35afd8fb5fc5f7a93f1d4 + ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + bcrypt (3.1.21) sha256=5964613d750a42c7ee5dc61f7b9336fb6caca429ba4ac9f2011609946e4a2dcf + benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c + better_errors (2.10.1) sha256=f798f1bac93f3e775925b7fcb24cffbcf0bb62ee2210f5350f161a6b75fc0a73 + bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7 + binding_of_caller (1.0.1) sha256=2b2902abff4246ddcfbc4da9b69bc4a019e22aeb300c2ff6289a173d4b90b29a + builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f + bundler-audit (0.9.3) sha256=81c8766c71e47d0d28a0f98c7eed028539f21a6ea3cd8f685eb6f42333c9b4e9 + capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef + childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec + coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b + concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab + connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a + contracts (0.17.3) sha256=e72e626413ea47099becb7b5683beb1c2ea902c69f5bad55c9258fe2b48314d7 + crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d + cucumber (10.2.0) sha256=fdedbd31ecf40858b60f04853f2aa15c44f5c30bbac29c6a227fa1e7005a8158 + cucumber-ci-environment (11.0.0) sha256=0df79a9e1d0b015b3d9def680f989200d96fef206f4d19ccf86a338c4f71d1e2 + cucumber-core (16.1.1) sha256=d3aaa80a1ee2865f63f1a21ef496129f675af9099993b9af9608c4ef8ae26b89 + cucumber-cucumber-expressions (18.1.0) sha256=181c64ef7596e7d61d33fb723929a63f06426e9724d78ec3a5c1c3c242208ce9 + cucumber-gherkin (38.0.0) sha256=3e5846badf646eaec482b07067520e4494f370a0cfa5474d63522ca2ace800c4 + cucumber-html-formatter (22.3.0) sha256=f9768ed05588dbd73a5f3824c2cc648bd86b00206e6972d743af8051281d0729 + cucumber-messages (32.0.0) sha256=eb64fa67c9499ab40126823046be6d6f63c2d1444d6ba61434f305d25a11722c + cucumber-tag-expressions (8.1.0) sha256=9bd8c4b6654f8e5bf2a9c99329b6f32136a75e50cd39d4cfb3927d0fa9f52e21 + database_cleaner (2.1.0) sha256=1dcba26e3b1576da692fc6bac10136a4744da5bcc293d248aae19640c65d89cd + database_cleaner-active_record (2.2.2) sha256=88296b9f3088c31f7c0d4fcec10f68e4b71c96698043916de59b04debec10388 + database_cleaner-core (2.0.1) sha256=8646574c32162e59ed7b5258a97a208d3c44551b854e510994f24683865d846c + date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0 + debug_inspector (1.2.0) sha256=9bdfa02eebc3da163833e6a89b154084232f5766087e59573b70521c77ea68a2 + diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 + docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e + drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 + em-websocket (0.5.3) sha256=f56a92bde4e6cb879256d58ee31f124181f68f8887bd14d53d5d9a292758c6a8 + erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5 + erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 + eventmachine (1.2.7) sha256=994016e42aa041477ba9cff45cbe50de2047f25dd418eba003e84f0d16560972 + ffi (1.17.3) sha256=0e9f39f7bb3934f77ad6feab49662be77e87eedcdeb2a3f5c0234c2938563d4c + ffi (1.17.3-aarch64-linux-gnu) sha256=28ad573df26560f0aedd8a90c3371279a0b2bd0b4e834b16a2baa10bd7a97068 + ffi (1.17.3-aarch64-linux-musl) sha256=020b33b76775b1abacc3b7d86b287cef3251f66d747092deec592c7f5df764b2 + ffi (1.17.3-arm-linux-gnu) sha256=5bd4cea83b68b5ec0037f99c57d5ce2dd5aa438f35decc5ef68a7d085c785668 + ffi (1.17.3-arm-linux-musl) sha256=0d7626bb96265f9af78afa33e267d71cfef9d9a8eb8f5525344f8da6c7d76053 + ffi (1.17.3-arm64-darwin) sha256=0c690555d4cee17a7f07c04d59df39b2fba74ec440b19da1f685c6579bb0717f + ffi (1.17.3-x86_64-darwin) sha256=1f211811eb5cfaa25998322cdd92ab104bfbd26d1c4c08471599c511f2c00bb5 + ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f + ffi (1.17.3-x86_64-linux-musl) sha256=086b221c3a68320b7564066f46fed23449a44f7a1935f1fe5a245bd89d9aea56 + foreman (0.90.0) sha256=ff675e2d47b607ac58714a6d4ac3e1ee8f06f41d8db084531c31961e2c3f117c + formatador (1.2.3) sha256=19fa898133c2c26cdbb5d09f6998c1e137ad9427a046663e55adfe18b950d894 + globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11 + guard (2.20.0) sha256=66829ac0154080f20c6b1d8e6b65c6d5b3f3064ff46f85beb56c82f27b306040 + guard-compat (1.2.1) sha256=3ad21ab0070107f92edfd82610b5cdc2fb8e368851e72362ada9703443d646fe + guard-livereload (2.5.2) sha256=124dd33cb08a232e5b46971b427c69ae34c4ff56fa72ac98f85eecb5da23a779 + guard-rspec (4.7.3) sha256=a47ba03cbd1e3c71e6ae8645cea97e203098a248aede507461a43e906e2f75ca + guard-shell (0.7.2) sha256=c9cd104c597c51465f7bed623753f7f4cfb87cfbd0ff28bdda9a02f6605e436d + http_parser.rb (0.8.1) sha256=9ae8df145b39aa5398b2f90090d651c67bd8e2ebfe4507c966579f641e11097a + i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5 + importmap-rails (2.2.3) sha256=7101be2a4dc97cf1558fb8f573a718404c5f6bcfe94f304bf1f39e444feeb16a + io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc + irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806 + jquery-fileupload-rails (1.0.0) sha256=487834a12eb51731977f70b8b10153e10a1013f86610aaef02ee027fe7fc7350 + jquery-rails (4.6.1) sha256=619f3496cdcdeaae1fd6dafa52dbac3fc45b745d4e09712da4184a16b3a8d9c0 + json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505 + language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc + launchy (3.1.1) sha256=72b847b5cc961589dde2c395af0108c86ff0119f42d4648d25b5440ebb10059e + lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 + listen (3.10.0) sha256=c6e182db62143aeccc2e1960033bebe7445309c7272061979bb098d03760c9d2 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + loofah (2.25.0) sha256=df5ed7ac3bac6a4ec802df3877ee5cc86d027299f8952e6243b3dac446b060e6 + lumberjack (1.4.2) sha256=40de5ae46321380c835031bcc1370f13bba304d29f2b5f5bb152061a5a191b95 + mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941 + marcel (1.1.0) sha256=fdcfcfa33cc52e93c4308d40e4090a5d4ea279e160a7f6af988260fa970e0bee + matrix (0.4.3) sha256=a0d5ab7ddcc1973ff690ab361b67f359acbb16958d1dc072b8b956a286564c5b + memoist3 (1.0.0) sha256=686e42402cf150a362050c23143dc57b0ef88f8c344943ff8b7845792b50d56f + method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5 + mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef + mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289 + minitest (6.0.1) sha256=7854c74f48e2e975969062833adc4013f249a4b212f5e7b9d5c040bf838d54bb + multi_json (1.19.1) sha256=7aefeff8f2c854bf739931a238e4aea64592845e0c0395c8a7d2eea7fdd631b7 + multi_test (1.1.0) sha256=e9e550cdd863fb72becfe344aefdcd4cbd26ebf307847f4a6c039a4082324d10 + mysql2 (0.5.7) sha256=ba09ede515a0ae8a7192040a1b778c0fb0f025fa5877e9be895cd325fa5e9d7b + nenv (0.3.0) sha256=d9de6d8fb7072228463bf61843159419c969edb34b3cef51832b516ae7972765 + net-imap (0.6.2) sha256=08caacad486853c61676cca0c0c47df93db02abc4a8239a8b67eb0981428acc6 + net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 + net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 + net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 + nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 + nokogiri (1.19.0) sha256=e304d21865f62518e04f2bf59f93bd3a97ca7b07e7f03952946d8e1c05f45695 + nokogiri (1.19.0-aarch64-linux-gnu) sha256=11a97ecc3c0e7e5edcf395720b10860ef493b768f6aa80c539573530bc933767 + nokogiri (1.19.0-aarch64-linux-musl) sha256=eb70507f5e01bc23dad9b8dbec2b36ad0e61d227b42d292835020ff754fb7ba9 + nokogiri (1.19.0-arm-linux-gnu) sha256=572a259026b2c8b7c161fdb6469fa2d0edd2b61cd599db4bbda93289abefbfe5 + nokogiri (1.19.0-arm-linux-musl) sha256=23ed90922f1a38aed555d3de4d058e90850c731c5b756d191b3dc8055948e73c + nokogiri (1.19.0-arm64-darwin) sha256=0811dfd936d5f6dd3f6d32ef790568bf29b2b7bead9ba68866847b33c9cf5810 + nokogiri (1.19.0-x86_64-darwin) sha256=1dad56220b603a8edb9750cd95798bffa2b8dd9dd9aa47f664009ee5b43e3067 + nokogiri (1.19.0-x86_64-linux-gnu) sha256=f482b95c713d60031d48c44ce14562f8d2ce31e3a9e8dd0ccb131e9e5a68b58c + nokogiri (1.19.0-x86_64-linux-musl) sha256=1c4ca6b381622420073ce6043443af1d321e8ed93cc18b08e2666e5bd02ffae4 + notiffany (0.1.3) sha256=d37669605b7f8dcb04e004e6373e2a780b98c776f8eb503ac9578557d7808738 + parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130 + parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688 + pg (1.6.3) sha256=1388d0563e13d2758c1089e35e973a3249e955c659592d10e5b77c468f628a99 + pg (1.6.3-aarch64-linux) sha256=0698ad563e02383c27510b76bf7d4cd2de19cd1d16a5013f375dd473e4be72ea + pg (1.6.3-aarch64-linux-musl) sha256=06a75f4ea04b05140146f2a10550b8e0d9f006a79cdaf8b5b130cde40e3ecc2c + pg (1.6.3-arm64-darwin) sha256=7240330b572e6355d7c75a7de535edb5dfcbd6295d9c7777df4d9dddfb8c0e5f + pg (1.6.3-x86_64-darwin) sha256=ee2e04a17c0627225054ffeb43e31a95be9d7e93abda2737ea3ce4a62f2729d6 + pg (1.6.3-x86_64-linux) sha256=5d9e188c8f7a0295d162b7b88a768d8452a899977d44f3274d1946d67920ae8d + pg (1.6.3-x86_64-linux-musl) sha256=9c9c90d98c72f78eb04c0f55e9618fe55d1512128e411035fe229ff427864009 + power_assert (3.0.1) sha256=8ce9876716cc74e863fcd4cdcdc52d792bd983598d1af3447083a3a9a4d34103 + pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6 + prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 + prism (1.8.0) sha256=84453a16ef5530ea62c5f03ec16b52a459575ad4e7b9c2b360fd8ce2c39c1254 + pry (0.16.0) sha256=d76c69065698ed1f85e717bd33d7942c38a50868f6b0673c636192b3d1b6054e + pry-rails (0.3.11) sha256=a69e28e24a34d75d1f60bcf241192a54253f8f7ef8a62cba1e75750a9653593d + psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974 + public_suffix (7.0.2) sha256=9114090c8e4e7135c1fd0e7acfea33afaab38101884320c65aaa0ffb8e26a857 + puma (6.6.1) sha256=b9b56e4a4ea75d1bfa6d9e1972ee2c9f43d0883f011826d914e8e37b3694ea1e + racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f + rack (3.1.19) sha256=52b7e200d7454a86add861abf552d306079516b887d48c33f4311634de030faf + rack-livereload (0.6.1) sha256=34337d2bdbea44327b9f7bd99f2595b04f90d8b2cf5305648c0e4860f3a30539 + rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9 + rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 + rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868 + rails (8.0.4) sha256=364494a32d2dc3f9d5c135d036ce47e7776684bc6add73f1037ac2b1007962db + rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d + rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560 + railties (8.0.4) sha256=8203d853dcffab4abcdd05c193f101676a92068075464694790f6d8f72d5cb47 + rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a + rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c + rb-fsevent (0.11.2) sha256=43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe + rb-inotify (0.11.1) sha256=a0a700441239b0ff18eb65e3866236cd78613d6b9f78fea1f9ac47a85e47be6e + rdoc (7.1.0) sha256=494899df0706c178596ca6e1d50f1b7eb285a9b2aae715be5abd742734f17363 + regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4 + reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835 + responders (3.2.0) sha256=89c2d6ac0ae16f6458a11524cae4a8efdceba1a3baea164d28ee9046bd3df55a + rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 + rouge (4.7.0) sha256=dba5896715c0325c362e895460a6d350803dbf6427454f49a47500f3193ea739 + rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587 + rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d + rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836 + rspec-mocks (3.13.7) sha256=0979034e64b1d7a838aaaddf12bf065ea4dc40ef3d4c39f01f93ae2c66c62b1c + rspec-rails (8.0.2) sha256=113139a53f5d068d4f48d1c29ad5f982013ed9b0daa69d7f7b266eda5d433ace + rspec-support (3.13.6) sha256=2e8de3702427eab064c9352fe74488cc12a1bfae887ad8b91cba480ec9f8afb2 + rubocop (1.82.1) sha256=09f1a6a654a960eda767aebea33e47603080f8e9c9a3f019bf9b94c9cab5e273 + rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd + ruby-prof (1.7.2) sha256=270424fcac37e611f2d15a55226c4628e234f8434e1d7c25ca8a2155b9fc4340 + ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 + rubyzip (3.2.2) sha256=c0ed99385f0625415c8f05bcae33fe649ed2952894a95ff8b08f26ca57ea5b3c + sassc (2.4.0) sha256=4c60a2b0a3b36685c83b80d5789401c2f678c1652e3288315a1551d811d9f83e + sassc-rails (2.1.2) sha256=5f4fdf3881fc9bdc8e856ffbd9850d70a2878866feae8114aa45996179952db5 + securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 + selenium-webdriver (4.40.0) sha256=16ef7aa9853c1d4b9d52eac45aafa916e3934c5c83cb4facb03f250adfd15e5b + shellany (0.0.1) sha256=0e127a9132698766d7e752e82cdac8250b6adbd09e6c0a7fbbb6f61964fedee7 + simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5 + simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246 + simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428 + sprockets (4.2.2) sha256=761e5a49f1c288704763f73139763564c845a8f856d52fba013458f8af1b59b1 + sprockets-rails (3.5.2) sha256=a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e + sqlite3 (2.9.0) sha256=ece9c00b32ec5f550d3a4a35c41ea8d738563589f090b9dfd0d510b7ae5f296c + sqlite3 (2.9.0-aarch64-linux-gnu) sha256=cfe1e0216f46d7483839719bf827129151e6c680317b99d7b8fc1597a3e13473 + sqlite3 (2.9.0-aarch64-linux-musl) sha256=56a35cb2d70779afc2ac191baf2c2148242285ecfed72f9b021218c5c4917913 + sqlite3 (2.9.0-arm-linux-gnu) sha256=a19a21504b0d7c8c825fbbf37b358ae316b6bd0d0134c619874060b2eef05435 + sqlite3 (2.9.0-arm-linux-musl) sha256=fca5b26197c70e3363115d3faaea34d7b2ad9c7f5fa8d8312e31b64e7556ee07 + sqlite3 (2.9.0-arm64-darwin) sha256=a917bd9b84285766ff3300b7d79cd583f5a067594c8c1263e6441618c04a6ed3 + sqlite3 (2.9.0-x86_64-darwin) sha256=59fe51baa3cb33c36d27ce78b4ed9360cd33ccca09498c2ae63850c97c0a6026 + sqlite3 (2.9.0-x86_64-linux-gnu) sha256=72fff9bd750070ba3af695511ba5f0e0a2d8a9206f84869640b3e99dfaf3d5a5 + sqlite3 (2.9.0-x86_64-linux-musl) sha256=ef716ba7a66d7deb1ccc402ac3a6d7343da17fac862793b7f0be3d2917253c90 + stimulus-rails (1.3.4) sha256=765676ffa1f33af64ce026d26b48e8ffb2e0b94e0f50e9119e11d6107d67cb06 + stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1 + sys-uname (1.4.1) sha256=ed2278ec670ee8af5eb5420d3a98e22188051f6241180db7c779993db2739a16 + test-unit (3.7.7) sha256=3c89d5ff0690a16bef9946156c4624390402b9d54dfcf4ce9cbd5b06bead1e45 + thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 + tilt (2.7.0) sha256=0d5b9ba69f6a36490c64b0eee9f6e9aad517e20dcc848800a06eb116f08c6ab3 + timeout (0.6.0) sha256=6d722ad619f96ee383a0c557ec6eb8c4ecb08af3af62098a0be5057bf00de1af + tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f + turbo-rails (2.0.21) sha256=02070ea29fd11d8c1a07d9d7be980729a20e94e39b8c6c819f690f7959216bc7 + turbolinks (5.2.1) sha256=5fea5889c4e2a78a5bd9abda3860c565342b50c6e2593697d5558a08e15cce9c + turbolinks-source (5.2.0) sha256=362a41fa851a22b0f15cf8f944b6c7c5788f645dc1f61ae25478bb25c3bc85d4 + tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b + unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42 + unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f + uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6 + useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844 + websocket (1.2.11) sha256=b7e7a74e2410b5e85c25858b26b3322f29161e300935f70a0e0d3c35e0462737 + websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962 + websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241 + xpath (3.2.0) sha256=6dfda79d91bb3b949b947ecc5919f042ef2f399b904013eb3ef6d20dd3a4082e + zeitwerk (2.7.4) sha256=2bef90f356bdafe9a6c2bd32bcd804f83a4f9b8bc27f3600fff051eb3edcec8b + +RUBY VERSION + ruby 3.4.1 + +BUNDLED WITH + 4.0.4 diff --git a/Guardfile b/Guardfile new file mode 100755 index 0000000..18b70eb --- /dev/null +++ b/Guardfile @@ -0,0 +1,45 @@ +# frozen_string_literal: true +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard "brakeman", run_on_start: true do + watch(%r{^app/.+\.(erb|haml|rhtml|rb)$}) + watch(%r{^config/.+\.rb$}) + watch(%r{^lib/.+\.rb$}) + watch("Gemfile") +end + +guard :shell do + watch(%r{^Gemfile|Gemfile.lock$}) { system("bundle-audit") } +end + +guard "livereload", host: "railsgoat.dev", port: "35727" do + watch(%r{app/views/.+\.(erb|haml|slim)$}) + watch(%r{app/helpers/.+\.rb}) + watch(%r{public/.+\.(css|js|html)}) + watch(%r{config/locales/.+\.yml}) + # Rails Assets Pipeline + watch(%r{(app|vendor)(/assets/\w+/(.+\.(css|js|html))).*}) { |m| "/assets/#{m[3]}" } +end + + +guard :rspec, cmd: "bundle exec rspec" do + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } + watch("spec/spec_helper.rb") { "spec" } + + # Rails example + watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } + watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } + watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] } + watch(%r{^spec/support/(.+)\.rb$}) { "spec" } + watch("config/routes.rb") { "spec/routing" } + watch("app/controllers/application_controller.rb") { "spec/controllers" } + + # Capybara features specs + watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" } + + # Turnip features and steps + watch(%r{^spec/acceptance/(.+)\.feature$}) + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance" } +end diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..d0c9553 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,20 @@ + + +🐞 **Problem** + + + +🎯 **Goal** + + + +💡 **Possible solutions** + + +📋 **Steps to solve the problem** + + * Comment below about what you've started working on. + * Add, commit, push your changes + * Submit a pull request and add this in comments - `Addresses #` + * Ask for a review in comments section of pull request + * Celebrate your contribution to this project 🎉 diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 0000000..42c7d15 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2018 The Open Worldwide Application Security Project + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Procfile b/Procfile new file mode 100755 index 0000000..c2c566e --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: bundle exec puma -C config/puma.rb diff --git a/README.md b/README.md new file mode 100755 index 0000000..9b04507 --- /dev/null +++ b/README.md @@ -0,0 +1,192 @@ +# RailsGoat + +RailsGoat is a deliberately vulnerable web application built on Ruby on Rails. It demonstrates real-world security vulnerabilities from the OWASP Top 10 and serves as a hands-on training platform for developers and security professionals. + +## What is RailsGoat? + +RailsGoat is an intentionally insecure Rails application designed to teach web application security. By exploring and exploiting its vulnerabilities, you'll learn: + +- How common security flaws manifest in Rails applications +- How to identify vulnerabilities through code review and testing +- How to implement proper security controls and remediation strategies + +**Current Version:** Rails 8.0 with Ruby 3.4.1 + +## Vulnerabilities Included + +RailsGoat demonstrates real-world security vulnerabilities from the OWASP Top 10, including SQL injection, cross-site scripting (XSS), authentication issues, insecure direct object references, and more. + +For a complete list of vulnerabilities with detailed explanations and tutorials, visit the [RailsGoat Wiki](https://github.com/OWASP/railsgoat/wiki). + +## Quick Start + +### Prerequisites + +- Ruby 3.4.1 +- Git +- SQLite3 (included by default) +- MySQL (optional, required for certain SQL injection demos) + +**New to Ruby?** Follow the setup guide at [GoRails](https://gorails.com/setup) for your operating system. + +### Installation + +1. **Clone the repository:** + ```bash + git clone https://github.com/OWASP/railsgoat.git + cd railsgoat + ``` + +2. **Install dependencies:** + ```bash + gem install bundler + bundle install + ``` + +3. **Setup the database:** + ```bash + rails db:setup + ``` + +4. **Start the server:** + ```bash + rails server + ``` + +5. **Open your browser:** + Navigate to `http://localhost:3000` and start exploring! + +### Other Rails Versions + +The `main` branch runs Rails 8. For older versions, switch branches: + +```bash +git checkout rails_3_2 # Rails 3.2 +git checkout rails_4_2 # Rails 4.2 +git checkout rails_5 # Rails 5.x +``` + +## Learning Path + +### 1. Training Mode (Recommended for Learners) + +Run the vulnerability test suite to see which security flaws exist: + +```bash +rails training +``` + +Each failing test indicates a vulnerability. The test output includes a link to a wiki tutorial explaining: +- How the vulnerability works +- How to exploit it +- How to fix it + +To run a specific vulnerability test: + +```bash +rails training SPEC=spec/vulnerabilities/sql_injection_spec.rb +``` + +### 2. Explore the Application + +- Create an account and log in +- Browse the different features +- Try to access other users' data +- Attempt various injection attacks +- Review the source code to understand the vulnerabilities + +### 3. Learn from the Wiki + +Visit the [RailsGoat Wiki](https://github.com/OWASP/railsgoat/wiki) for detailed tutorials on each vulnerability, including: +- Vulnerability explanation +- Exploitation techniques +- Code examples +- Remediation steps + +## Bonus Security Topics + +Additional documentation covering advanced and modern Rails security concepts: + +- [Bonus: Encrypted Secrets and Credentials in Rails 5.1+](docs/bonus_encrypted_secrets.md) + + + +## Docker Installation + +**Requirements:** [Docker](https://docs.docker.com/engine/installation/) and [Docker Compose](https://docs.docker.com/compose/install/) 1.6.0+ + +**For Mac Apple Silicon (ARM64):** Rosetta must be installed + +```bash +docker-compose build +docker-compose run web rails db:setup +docker-compose up +``` + +The application will be available at `http://localhost:3000` + +**Troubleshooting:** If the container exits with "A server is already running", remove `tmp/pids/server.pid` from your working directory and try again. + +## Advanced Configuration + +### MySQL Environment + +Some SQL injection vulnerabilities require MySQL. To run with MySQL: + +```bash +# Create and migrate the database +RAILS_ENV=mysql rails db:create +RAILS_ENV=mysql rails db:migrate + +# Start the server +RAILS_ENV=mysql rails server +``` + +### Email Testing + +RailsGoat uses [MailCatcher](https://mailcatcher.me/) to intercept emails: + +```bash +gem install mailcatcher +mailcatcher +``` + +View emails at `http://localhost:1080` + +## For Contributors and Maintainers + +### Running Tests in Maintainer Mode + +Set the `RAILSGOAT_MAINTAINER` environment variable to verify that vulnerabilities still exist: + +```bash +RAILSGOAT_MAINTAINER="yes" bundle exec rspec +``` + +In maintainer mode, tests pass when vulnerabilities are correctly implemented (opposite of training mode). + +### Contributing + +We welcome contributions! Please see our [contribution guidelines](./CONTRIBUTING.md) for details. + +## Support + +Need help? + +- Join the [OWASP Slack Channel](https://owasp.slack.com/messages/project-railsgoat/) +- Check the [Wiki](https://github.com/OWASP/railsgoat/wiki) for tutorials +- Open an [issue](https://github.com/OWASP/railsgoat/issues) for bugs or questions + +## Project History + +RailsGoat was created to demonstrate security vulnerabilities in Rails applications and teach secure coding practices. It has been continuously updated through Rails versions 3, 4, 5, 6, and now 8, maintaining relevance as the framework evolves. + +Conversion to OWASP Top Ten 2013 completed in November 2013. + +## License + +[The MIT License (MIT)](./LICENSE.md) + +--- + +**Warning:** This application contains serious security vulnerabilities. Never deploy it on a public server or network. Use only in isolated training environments. diff --git a/Rakefile b/Rakefile new file mode 100755 index 0000000..4237d41 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +# frozen_string_literal: true +# 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 0000000..b16e53d --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/app/assets/images/1.jpg b/app/assets/images/1.jpg new file mode 100755 index 0000000..7926830 Binary files /dev/null and b/app/assets/images/1.jpg differ diff --git a/app/assets/images/2.jpg b/app/assets/images/2.jpg new file mode 100755 index 0000000..ed60c05 Binary files /dev/null and b/app/assets/images/2.jpg differ diff --git a/app/assets/images/3.jpg b/app/assets/images/3.jpg new file mode 100755 index 0000000..d852848 Binary files /dev/null and b/app/assets/images/3.jpg differ diff --git a/app/assets/images/4.jpg b/app/assets/images/4.jpg new file mode 100755 index 0000000..1a1a2c6 Binary files /dev/null and b/app/assets/images/4.jpg differ diff --git a/app/assets/images/alpha.png b/app/assets/images/alpha.png new file mode 100755 index 0000000..38043f1 Binary files /dev/null and b/app/assets/images/alpha.png differ diff --git a/app/assets/images/blackforest.png b/app/assets/images/blackforest.png new file mode 100755 index 0000000..6a8ddc2 Binary files /dev/null and b/app/assets/images/blackforest.png differ diff --git a/app/assets/images/clear.png b/app/assets/images/clear.png new file mode 100755 index 0000000..580b52a Binary files /dev/null and b/app/assets/images/clear.png differ diff --git a/app/assets/images/company.png b/app/assets/images/company.png new file mode 100755 index 0000000..0ce67d8 Binary files /dev/null and b/app/assets/images/company.png differ diff --git a/app/assets/images/email.png b/app/assets/images/email.png new file mode 100755 index 0000000..e74af67 Binary files /dev/null and b/app/assets/images/email.png differ diff --git a/app/assets/images/fonts/icomoon.dev.svg b/app/assets/images/fonts/icomoon.dev.svg new file mode 100755 index 0000000..c882486 --- /dev/null +++ b/app/assets/images/fonts/icomoon.dev.svg @@ -0,0 +1,1930 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/images/fonts/icomoon.eot b/app/assets/images/fonts/icomoon.eot new file mode 100755 index 0000000..e016ca0 Binary files /dev/null and b/app/assets/images/fonts/icomoon.eot differ diff --git a/app/assets/images/fonts/icomoon.svg b/app/assets/images/fonts/icomoon.svg new file mode 100755 index 0000000..efb1718 --- /dev/null +++ b/app/assets/images/fonts/icomoon.svg @@ -0,0 +1,1930 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/images/fonts/icomoon.ttf b/app/assets/images/fonts/icomoon.ttf new file mode 100755 index 0000000..6ae9773 Binary files /dev/null and b/app/assets/images/fonts/icomoon.ttf differ diff --git a/app/assets/images/fonts/icomoon.woff b/app/assets/images/fonts/icomoon.woff new file mode 100755 index 0000000..7fef63d Binary files /dev/null and b/app/assets/images/fonts/icomoon.woff differ diff --git a/app/assets/images/fonts/lte-ie7.js b/app/assets/images/fonts/lte-ie7.js new file mode 100755 index 0000000..6e21175 --- /dev/null +++ b/app/assets/images/fonts/lte-ie7.js @@ -0,0 +1,501 @@ +/* Use this script if you need to support IE 7 and IE 6. */ + +window.onload = function() { + function addIcon(el, entity) { + var html = el.innerHTML; + el.innerHTML = '' + entity + '' + html; + } + var icons = { + 'icon-home' : '', + 'icon-home-2' : '', + 'icon-home-3' : '', + 'icon-office' : '', + 'icon-newspaper' : '', + 'icon-pencil' : '', + 'icon-pencil-2' : '', + 'icon-quill' : '', + 'icon-pen' : '', + 'icon-blog' : '', + 'icon-droplet' : '', + 'icon-paint-format' : '', + 'icon-image' : '', + 'icon-image-2' : '', + 'icon-images' : '', + 'icon-camera' : '', + 'icon-music' : '', + 'icon-headphones' : '', + 'icon-play' : '', + 'icon-film' : '', + 'icon-camera-2' : '', + 'icon-dice' : '', + 'icon-pacman' : '', + 'icon-spades' : '', + 'icon-clubs' : '', + 'icon-diamonds' : '', + 'icon-pawn' : '', + 'icon-bullhorn' : '', + 'icon-connection' : '', + 'icon-podcast' : '', + 'icon-feed' : '', + 'icon-book' : '', + 'icon-books' : '', + 'icon-library' : '', + 'icon-file' : '', + 'icon-profile' : '', + 'icon-file-2' : '', + 'icon-file-3' : '', + 'icon-file-4' : '', + 'icon-copy' : '', + 'icon-copy-2' : '', + 'icon-copy-3' : '', + 'icon-paste' : '', + 'icon-paste-2' : '', + 'icon-paste-3' : '', + 'icon-stack' : '', + 'icon-folder' : '', + 'icon-folder-open' : '', + 'icon-tag' : '', + 'icon-tags' : '', + 'icon-barcode' : '', + 'icon-qrcode' : '', + 'icon-ticket' : '', + 'icon-cart' : '', + 'icon-cart-2' : '', + 'icon-cart-3' : '', + 'icon-coin' : '', + 'icon-credit' : '', + 'icon-calculate' : '', + 'icon-support' : '', + 'icon-phone' : '', + 'icon-phone-hang-up' : '', + 'icon-address-book' : '', + 'icon-notebook' : '', + 'icon-envelop' : '', + 'icon-pushpin' : '', + 'icon-location' : '', + 'icon-location-2' : '', + 'icon-compass' : '', + 'icon-map' : '', + 'icon-map-2' : '', + 'icon-history' : '', + 'icon-clock' : '', + 'icon-clock-2' : '', + 'icon-alarm' : '', + 'icon-alarm-2' : '', + 'icon-bell' : '', + 'icon-stopwatch' : '', + 'icon-calendar' : '', + 'icon-calendar-2' : '', + 'icon-print' : '', + 'icon-keyboard' : '', + 'icon-screen' : '', + 'icon-laptop' : '', + 'icon-mobile' : '', + 'icon-mobile-2' : '', + 'icon-tablet' : '', + 'icon-tv' : '', + 'icon-cabinet' : '', + 'icon-drawer' : '', + 'icon-drawer-2' : '', + 'icon-drawer-3' : '', + 'icon-box-add' : '', + 'icon-box-remove' : '', + 'icon-download' : '', + 'icon-upload' : '', + 'icon-disk' : '', + 'icon-storage' : '', + 'icon-undo' : '', + 'icon-redo' : '', + 'icon-flip' : '', + 'icon-flip-2' : '', + 'icon-undo-2' : '', + 'icon-redo-2' : '', + 'icon-forward' : '', + 'icon-reply' : '', + 'icon-bubble' : '', + 'icon-bubbles' : '', + 'icon-bubbles-2' : '', + 'icon-bubble-2' : '', + 'icon-bubbles-3' : '', + 'icon-bubbles-4' : '', + 'icon-user' : '', + 'icon-users' : '', + 'icon-user-2' : '', + 'icon-users-2' : '', + 'icon-user-3' : '', + 'icon-user-4' : '', + 'icon-quotes-left' : '', + 'icon-busy' : '', + 'icon-spinner' : '', + 'icon-spinner-2' : '', + 'icon-spinner-3' : '', + 'icon-spinner-4' : '', + 'icon-spinner-5' : '', + 'icon-spinner-6' : '', + 'icon-binoculars' : '', + 'icon-search' : '', + 'icon-zoom-in' : '', + 'icon-zoom-out' : '', + 'icon-expand' : '', + 'icon-contract' : '', + 'icon-expand-2' : '', + 'icon-contract-2' : '', + 'icon-key' : '', + 'icon-key-2' : '', + 'icon-lock' : '', + 'icon-lock-2' : '', + 'icon-unlocked' : '', + 'icon-wrench' : '', + 'icon-settings' : '', + 'icon-equalizer' : '', + 'icon-cog' : '', + 'icon-cogs' : '', + 'icon-cog-2' : '', + 'icon-hammer' : '', + 'icon-wand' : '', + 'icon-aid' : '', + 'icon-bug' : '', + 'icon-pie' : '', + 'icon-stats' : '', + 'icon-bars' : '', + 'icon-bars-2' : '', + 'icon-gift' : '', + 'icon-trophy' : '', + 'icon-glass' : '', + 'icon-mug' : '', + 'icon-food' : '', + 'icon-leaf' : '', + 'icon-rocket' : '', + 'icon-meter' : '', + 'icon-meter2' : '', + 'icon-dashboard' : '', + 'icon-hammer-2' : '', + 'icon-fire' : '', + 'icon-lab' : '', + 'icon-magnet' : '', + 'icon-remove' : '', + 'icon-remove-2' : '', + 'icon-briefcase' : '', + 'icon-airplane' : '', + 'icon-truck' : '', + 'icon-road' : '', + 'icon-accessibility' : '', + 'icon-target' : '', + 'icon-shield' : '', + 'icon-lightning' : '', + 'icon-switch' : '', + 'icon-power-cord' : '', + 'icon-signup' : '', + 'icon-list' : '', + 'icon-list-2' : '', + 'icon-numbered-list' : '', + 'icon-menu' : '', + 'icon-menu-2' : '', + 'icon-tree' : '', + 'icon-cloud' : '', + 'icon-cloud-download' : '', + 'icon-cloud-upload' : '', + 'icon-download-2' : '', + 'icon-upload-2' : '', + 'icon-download-3' : '', + 'icon-upload-3' : '', + 'icon-globe' : '', + 'icon-earth' : '', + 'icon-link' : '', + 'icon-flag' : '', + 'icon-attachment' : '', + 'icon-eye' : '', + 'icon-eye-blocked' : '', + 'icon-eye-2' : '', + 'icon-bookmark' : '', + 'icon-bookmarks' : '', + 'icon-brightness-medium' : '', + 'icon-brightness-contrast' : '', + 'icon-contrast' : '', + 'icon-star' : '', + 'icon-star-2' : '', + 'icon-star-3' : '', + 'icon-heart' : '', + 'icon-heart-2' : '', + 'icon-heart-broken' : '', + 'icon-thumbs-up' : '', + 'icon-thumbs-up-2' : '', + 'icon-happy' : '', + 'icon-happy-2' : '', + 'icon-smiley' : '', + 'icon-smiley-2' : '', + 'icon-tongue' : '', + 'icon-tongue-2' : '', + 'icon-sad' : '', + 'icon-sad-2' : '', + 'icon-wink' : '', + 'icon-wink-2' : '', + 'icon-grin' : '', + 'icon-grin-2' : '', + 'icon-cool' : '', + 'icon-cool-2' : '', + 'icon-angry' : '', + 'icon-angry-2' : '', + 'icon-evil' : '', + 'icon-evil-2' : '', + 'icon-shocked' : '', + 'icon-shocked-2' : '', + 'icon-confused' : '', + 'icon-confused-2' : '', + 'icon-neutral' : '', + 'icon-neutral-2' : '', + 'icon-wondering' : '', + 'icon-wondering-2' : '', + 'icon-point-up' : '', + 'icon-point-right' : '', + 'icon-point-down' : '', + 'icon-point-left' : '', + 'icon-warning' : '', + 'icon-notification' : '', + 'icon-question' : '', + 'icon-info' : '', + 'icon-info-2' : '', + 'icon-blocked' : '', + 'icon-cancel-circle' : '', + 'icon-checkmark-circle' : '', + 'icon-spam' : '', + 'icon-close' : '', + 'icon-checkmark' : '', + 'icon-checkmark-2' : '', + 'icon-spell-check' : '', + 'icon-minus' : '', + 'icon-plus' : '', + 'icon-enter' : '', + 'icon-exit' : '', + 'icon-play-2' : '', + 'icon-pause' : '', + 'icon-stop' : '', + 'icon-backward' : '', + 'icon-forward-2' : '', + 'icon-play-3' : '', + 'icon-pause-2' : '', + 'icon-stop-2' : '', + 'icon-backward-2' : '', + 'icon-forward-3' : '', + 'icon-first' : '', + 'icon-last' : '', + 'icon-previous' : '', + 'icon-next' : '', + 'icon-eject' : '', + 'icon-volume-high' : '', + 'icon-volume-medium' : '', + 'icon-volume-low' : '', + 'icon-volume-mute' : '', + 'icon-volume-mute-2' : '', + 'icon-volume-increase' : '', + 'icon-volume-decrease' : '', + 'icon-loop' : '', + 'icon-loop-2' : '', + 'icon-loop-3' : '', + 'icon-shuffle' : '', + 'icon-arrow-up-left' : '', + 'icon-arrow-up' : '', + 'icon-arrow-up-right' : '', + 'icon-arrow-right' : '', + 'icon-arrow-down-right' : '', + 'icon-arrow-down' : '', + 'icon-arrow-down-left' : '', + 'icon-arrow-left' : '', + 'icon-arrow-up-left-2' : '', + 'icon-arrow-up-2' : '', + 'icon-arrow-up-right-2' : '', + 'icon-arrow-right-2' : '', + 'icon-arrow-down-right-2' : '', + 'icon-arrow-down-2' : '', + 'icon-arrow-down-left-2' : '', + 'icon-arrow-left-2' : '', + 'icon-arrow-up-left-3' : '', + 'icon-arrow-up-3' : '', + 'icon-arrow-up-right-3' : '', + 'icon-arrow-right-3' : '', + 'icon-arrow-down-right-3' : '', + 'icon-arrow-down-3' : '', + 'icon-arrow-down-left-3' : '', + 'icon-arrow-left-3' : '', + 'icon-tab' : '', + 'icon-checkbox-checked' : '', + 'icon-checkbox-unchecked' : '', + 'icon-checkbox-partial' : '', + 'icon-radio-checked' : '', + 'icon-radio-unchecked' : '', + 'icon-crop' : '', + 'icon-scissors' : '', + 'icon-filter' : '', + 'icon-filter-2' : '', + 'icon-font' : '', + 'icon-text-height' : '', + 'icon-text-width' : '', + 'icon-bold' : '', + 'icon-underline' : '', + 'icon-italic' : '', + 'icon-strikethrough' : '', + 'icon-omega' : '', + 'icon-sigma' : '', + 'icon-table' : '', + 'icon-table-2' : '', + 'icon-insert-template' : '', + 'icon-pilcrow' : '', + 'icon-left-to-right' : '', + 'icon-right-to-left' : '', + 'icon-paragraph-left' : '', + 'icon-paragraph-center' : '', + 'icon-paragraph-right' : '', + 'icon-paragraph-justify' : '', + 'icon-paragraph-left-2' : '', + 'icon-paragraph-center-2' : '', + 'icon-paragraph-right-2' : '', + 'icon-paragraph-justify-2' : '', + 'icon-indent-increase' : '', + 'icon-indent-decrease' : '', + 'icon-new-tab' : '', + 'icon-embed' : '', + 'icon-code' : '', + 'icon-console' : '', + 'icon-share' : '', + 'icon-mail' : '', + 'icon-mail-2' : '', + 'icon-mail-3' : '', + 'icon-mail-4' : '', + 'icon-google' : '', + 'icon-google-plus' : '', + 'icon-google-plus-2' : '', + 'icon-google-plus-3' : '', + 'icon-google-plus-4' : '', + 'icon-google-drive' : '', + 'icon-facebook' : '', + 'icon-facebook-2' : '', + 'icon-facebook-3' : '', + 'icon-instagram' : '', + 'icon-twitter' : '', + 'icon-twitter-2' : '', + 'icon-twitter-3' : '', + 'icon-feed-2' : '', + 'icon-feed-3' : '', + 'icon-feed-4' : '', + 'icon-youtube' : '', + 'icon-youtube-2' : '', + 'icon-vimeo' : '', + 'icon-vimeo2' : '', + 'icon-vimeo-2' : '', + 'icon-lanyrd' : '', + 'icon-flickr' : '', + 'icon-flickr-2' : '', + 'icon-flickr-3' : '', + 'icon-flickr-4' : '', + 'icon-picassa' : '', + 'icon-picassa-2' : '', + 'icon-dribbble' : '', + 'icon-dribbble-2' : '', + 'icon-dribbble-3' : '', + 'icon-forrst' : '', + 'icon-forrst-2' : '', + 'icon-deviantart' : '', + 'icon-deviantart-2' : '', + 'icon-steam' : '', + 'icon-steam-2' : '', + 'icon-github' : '', + 'icon-github-2' : '', + 'icon-github-3' : '', + 'icon-github-4' : '', + 'icon-github-5' : '', + 'icon-wordpress' : '', + 'icon-wordpress-2' : '', + 'icon-joomla' : '', + 'icon-blogger' : '', + 'icon-blogger-2' : '', + 'icon-tumblr' : '', + 'icon-tumblr-2' : '', + 'icon-yahoo' : '', + 'icon-tux' : '', + 'icon-apple' : '', + 'icon-finder' : '', + 'icon-android' : '', + 'icon-windows' : '', + 'icon-windows8' : '', + 'icon-soundcloud' : '', + 'icon-soundcloud-2' : '', + 'icon-skype' : '', + 'icon-reddit' : '', + 'icon-linkedin' : '', + 'icon-lastfm' : '', + 'icon-lastfm-2' : '', + 'icon-delicious' : '', + 'icon-stumbleupon' : '', + 'icon-stumbleupon-2' : '', + 'icon-stackoverflow' : '', + 'icon-pinterest' : '', + 'icon-pinterest-2' : '', + 'icon-xing' : '', + 'icon-xing-2' : '', + 'icon-flattr' : '', + 'icon-foursquare' : '', + 'icon-foursquare-2' : '', + 'icon-paypal' : '', + 'icon-paypal-2' : '', + 'icon-paypal-3' : '', + 'icon-yelp' : '', + 'icon-libreoffice' : '', + 'icon-file-pdf' : '', + 'icon-file-openoffice' : '', + 'icon-file-word' : '', + 'icon-file-excel' : '', + 'icon-file-zip' : '', + 'icon-file-powerpoint' : '', + 'icon-file-xml' : '', + 'icon-file-css' : '', + 'icon-html5' : '', + 'icon-html5-2' : '', + 'icon-css3' : '', + 'icon-chrome' : '', + 'icon-firefox' : '', + 'icon-IE' : '', + 'icon-opera' : '', + 'icon-safari' : '', + 'icon-IcoMoon' : '', + 'icon-comment' : '', + 'icon-mic' : '', + 'icon-envelope' : '', + 'icon-briefcase-2' : '', + 'icon-cart-4' : '', + 'icon-locked' : '', + 'icon-apple-2' : '', + 'icon-chart' : '', + 'icon-warning-2' : '', + 'icon-keyboard-2' : '', + 'icon-stats-2' : '', + 'icon-list-3' : '', + 'icon-grid' : '', + 'icon-address-book-2' : '', + 'icon-left-quote-alt' : '', + 'icon-right-quote-alt' : '', + 'icon-umbrella' : '', + 'icon-left-quote' : '', + 'icon-right-quote' : '', + 'icon-eyedropper' : '', + 'icon-pen-alt-stroke' : '', + 'icon-pen-alt-fill' : '', + 'icon-unlock-fill' : '', + 'icon-cloudy' : '', + 'icon-cloud-2' : '', + 'icon-rainy' : '' + }, + els = document.getElementsByTagName('*'), + i, attr, html, c, el; + for (i = 0; i < els.length; i += 1) { + el = els[i]; + attr = el.getAttribute('data-icon'); + if (attr) { + addIcon(el, attr); + } + c = el.className; + c = c.match(/icon-[^\s'"]+/); + if (c && icons[c[0]]) { + addIcon(el, icons[c[0]]); + } + } +}; \ No newline at end of file diff --git a/app/assets/images/glyphicons-halflings-white.png b/app/assets/images/glyphicons-halflings-white.png new file mode 100755 index 0000000..3bf6484 Binary files /dev/null and b/app/assets/images/glyphicons-halflings-white.png differ diff --git a/app/assets/images/glyphicons-halflings.png b/app/assets/images/glyphicons-halflings.png new file mode 100755 index 0000000..11313fa Binary files /dev/null and b/app/assets/images/glyphicons-halflings.png differ diff --git a/app/assets/images/html-screen.jpg b/app/assets/images/html-screen.jpg new file mode 100755 index 0000000..210c8b4 Binary files /dev/null and b/app/assets/images/html-screen.jpg differ diff --git a/app/assets/images/hue.png b/app/assets/images/hue.png new file mode 100755 index 0000000..d89560e Binary files /dev/null and b/app/assets/images/hue.png differ diff --git a/app/assets/images/key.png b/app/assets/images/key.png new file mode 100755 index 0000000..20dba07 Binary files /dev/null and b/app/assets/images/key.png differ diff --git a/app/assets/images/loading-black.gif b/app/assets/images/loading-black.gif new file mode 100755 index 0000000..2539121 Binary files /dev/null and b/app/assets/images/loading-black.gif differ diff --git a/app/assets/images/loading-blue.gif b/app/assets/images/loading-blue.gif new file mode 100755 index 0000000..fa1760f Binary files /dev/null and b/app/assets/images/loading-blue.gif differ diff --git a/app/assets/images/loading-green.gif b/app/assets/images/loading-green.gif new file mode 100755 index 0000000..3ef707c Binary files /dev/null and b/app/assets/images/loading-green.gif differ diff --git a/app/assets/images/loading-orange.gif b/app/assets/images/loading-orange.gif new file mode 100755 index 0000000..215b29c Binary files /dev/null and b/app/assets/images/loading-orange.gif differ diff --git a/app/assets/images/loading-red.gif b/app/assets/images/loading-red.gif new file mode 100755 index 0000000..5d348e3 Binary files /dev/null and b/app/assets/images/loading-red.gif differ diff --git a/app/assets/images/loading.gif b/app/assets/images/loading.gif new file mode 100755 index 0000000..5b33f7e Binary files /dev/null and b/app/assets/images/loading.gif differ diff --git a/app/assets/images/logo-blue.png b/app/assets/images/logo-blue.png new file mode 100755 index 0000000..6f53e9d Binary files /dev/null and b/app/assets/images/logo-blue.png differ diff --git a/app/assets/images/logo.png b/app/assets/images/logo.png new file mode 100755 index 0000000..1ebf28d Binary files /dev/null and b/app/assets/images/logo.png differ diff --git a/app/assets/images/logo.psd b/app/assets/images/logo.psd new file mode 100755 index 0000000..618c3ae Binary files /dev/null and b/app/assets/images/logo.psd differ diff --git a/app/assets/images/logo1.png b/app/assets/images/logo1.png new file mode 100755 index 0000000..8f06c09 Binary files /dev/null and b/app/assets/images/logo1.png differ diff --git a/app/assets/images/logo2.png b/app/assets/images/logo2.png new file mode 100755 index 0000000..af86f1b Binary files /dev/null and b/app/assets/images/logo2.png differ diff --git a/app/assets/images/logo3.png b/app/assets/images/logo3.png new file mode 100755 index 0000000..bac7ed2 Binary files /dev/null and b/app/assets/images/logo3.png differ diff --git a/app/assets/images/profile.jpg b/app/assets/images/profile.jpg new file mode 100755 index 0000000..ec566fa Binary files /dev/null and b/app/assets/images/profile.jpg differ diff --git a/app/assets/images/profile.png b/app/assets/images/profile.png new file mode 100755 index 0000000..744197a Binary files /dev/null and b/app/assets/images/profile.png differ diff --git a/app/assets/images/profile1.png b/app/assets/images/profile1.png new file mode 100755 index 0000000..2df835e Binary files /dev/null and b/app/assets/images/profile1.png differ diff --git a/app/assets/images/profile_color.jpg b/app/assets/images/profile_color.jpg new file mode 100755 index 0000000..4bf9ca1 Binary files /dev/null and b/app/assets/images/profile_color.jpg differ diff --git a/app/assets/images/railsgoat.png b/app/assets/images/railsgoat.png new file mode 100644 index 0000000..cc1f81e Binary files /dev/null and b/app/assets/images/railsgoat.png differ diff --git a/app/assets/images/saturation.png b/app/assets/images/saturation.png new file mode 100755 index 0000000..594ae50 Binary files /dev/null and b/app/assets/images/saturation.png differ diff --git a/app/assets/images/select2.png b/app/assets/images/select2.png new file mode 100755 index 0000000..28982f2 Binary files /dev/null and b/app/assets/images/select2.png differ diff --git a/app/assets/images/social_icons.png b/app/assets/images/social_icons.png new file mode 100755 index 0000000..4dc28bf Binary files /dev/null and b/app/assets/images/social_icons.png differ diff --git a/app/assets/images/sorting.png b/app/assets/images/sorting.png new file mode 100755 index 0000000..b88c06c Binary files /dev/null and b/app/assets/images/sorting.png differ diff --git a/app/assets/images/sorting_asc.png b/app/assets/images/sorting_asc.png new file mode 100755 index 0000000..c0d72a3 Binary files /dev/null and b/app/assets/images/sorting_asc.png differ diff --git a/app/assets/images/sorting_desc.png b/app/assets/images/sorting_desc.png new file mode 100755 index 0000000..f580b85 Binary files /dev/null and b/app/assets/images/sorting_desc.png differ diff --git a/app/assets/images/step-1.png b/app/assets/images/step-1.png new file mode 100755 index 0000000..d1a6ce2 Binary files /dev/null and b/app/assets/images/step-1.png differ diff --git a/app/assets/images/step-2.png b/app/assets/images/step-2.png new file mode 100755 index 0000000..703959d Binary files /dev/null and b/app/assets/images/step-2.png differ diff --git a/app/assets/images/ui-icons_3d80b3_256x240.png b/app/assets/images/ui-icons_3d80b3_256x240.png new file mode 100755 index 0000000..4f624bb Binary files /dev/null and b/app/assets/images/ui-icons_3d80b3_256x240.png differ diff --git a/app/assets/images/user-display.png b/app/assets/images/user-display.png new file mode 100755 index 0000000..3a9dd90 Binary files /dev/null and b/app/assets/images/user-display.png differ diff --git a/app/assets/javascripts/alertify.min.js b/app/assets/javascripts/alertify.min.js new file mode 100755 index 0000000..88e76de --- /dev/null +++ b/app/assets/javascripts/alertify.min.js @@ -0,0 +1,12 @@ +/** + * alertify + * An unobtrusive customizable JavaScript notification system + * + * @author Fabien Doiron + * @copyright Fabien Doiron 2013 + * @license MIT + * @link http://fabien-d.github.com/alertify.js/ + * @module alertify + * @version 0.3.7 + */ +(function(e,t){"use strict";var n=e.document,r;r=function(){var e={},r={},i=!1,s={ENTER:13,ESC:27,SPACE:32},o=[],u,a,f,l,c,h,p,d,v,m,g,y;return r={buttons:{holder:'',submit:'',ok:'{{ok}}',cancel:'{{cancel}}'},input:'
',message:'

{{message}}

',log:'
{{message}}
'},y=function(){var e,r=n.createElement("fakeelement"),i={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"otransitionend",transition:"transitionend"};for(e in i)if(r.style[e]!==t)return i[e]},u=function(e){return n.getElementById(e)},e={labels:{ok:"OK",cancel:"Cancel"},delay:5e3,buttonReverse:!1,buttonFocus:"ok",transition:t,addListeners:function(e){var t=typeof f!="undefined",r=typeof a!="undefined",i=typeof g!="undefined",o="",u=this,c,h,p,d,v;c=function(t){return typeof t.preventDefault!="undefined"&&t.preventDefault(),p(t),typeof g!="undefined"&&(o=g.value),typeof e=="function"&&(typeof g!="undefined"?e(!0,o):e(!0)),!1},h=function(t){return typeof t.preventDefault!="undefined"&&t.preventDefault(),p(t),typeof e=="function"&&e(!1),!1},p=function(e){u.hide(),u.unbind(n.body,"keyup",d),u.unbind(l,"focus",v),i&&u.unbind(m,"submit",c),t&&u.unbind(f,"click",c),r&&u.unbind(a,"click",h)},d=function(e){var t=e.keyCode;t===s.SPACE&&!i&&c(e),t===s.ESC&&r&&h(e)},v=function(e){i?g.focus():r?a.focus():f.focus()},this.bind(l,"focus",v),t&&this.bind(f,"click",c),r&&this.bind(a,"click",h),this.bind(n.body,"keyup",d),i&&this.bind(m,"submit",c),typeof this.transition=="undefined"&&this.setFocus()},bind:function(e,t,n){typeof e.addEventListener=="function"?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n)},appendButtons:function(e,t){return this.buttonReverse?t+e:e+t},build:function(t){var n="",i=t.type,s=t.message,o=t.cssClass||"";n+='
',e.buttonFocus==="none"&&(n+=''),i==="prompt"&&(n+='
'),n+='
',n+=r.message.replace("{{message}}",s),i==="prompt"&&(n+=r.input),n+=r.buttons.holder,n+="
",i==="prompt"&&(n+="
"),n+='Reset Focus',n+="
";switch(i){case"confirm":n=n.replace("{{buttons}}",this.appendButtons(r.buttons.cancel,r.buttons.ok)),n=n.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"prompt":n=n.replace("{{buttons}}",this.appendButtons(r.buttons.cancel,r.buttons.submit)),n=n.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"alert":n=n.replace("{{buttons}}",r.buttons.ok),n=n.replace("{{ok}}",this.labels.ok);break;default:}return d.className="alertify alertify-show alertify-"+i+" "+o,p.className="alertify-cover",n},close:function(e,t){var n=t&&!isNaN(t)?+t:this.delay,r=this,i,s;this.bind(e,"click",function(){i(e)}),s=function(e){e.stopPropagation(),r.unbind(this,r.transition,s),v.removeChild(this),v.hasChildNodes()||(v.className+=" alertify-logs-hidden")},i=function(e){typeof e!="undefined"&&e.parentNode===v&&(typeof r.transition!="undefined"?(r.bind(e,r.transition,s),e.className+=" alertify-log-hide"):(v.removeChild(e),v.hasChildNodes()||(v.className+=" alertify-logs-hidden")))};if(t===0)return;setTimeout(function(){i(e)},n)},dialog:function(e,t,r,s,u){h=n.activeElement;var a=function(){if(d&&d.scrollTop!==null)return;a()};if(typeof e!="string")throw new Error("message must be a string");if(typeof t!="string")throw new Error("type must be a string");if(typeof r!="undefined"&&typeof r!="function")throw new Error("fn must be a function");return typeof this.init=="function"&&(this.init(),a()),o.push({type:t,message:e,callback:r,placeholder:s,cssClass:u}),i||this.setup(),this},extend:function(e){if(typeof e!="string")throw new Error("extend method must have exactly one paramter");return function(t,n){return this.log(t,e,n),this}},hide:function(){var e,t=this;o.splice(0,1),o.length>0?this.setup():(i=!1,e=function(n){n.stopPropagation(),d.className+=" alertify-isHidden",t.unbind(d,t.transition,e)},typeof this.transition!="undefined"?(this.bind(d,this.transition,e),d.className="alertify alertify-hide alertify-hidden"):d.className="alertify alertify-hide alertify-hidden alertify-isHidden",p.className="alertify-cover alertify-cover-hidden",h.focus())},init:function(){n.createElement("nav"),n.createElement("article"),n.createElement("section"),p=n.createElement("div"),p.setAttribute("id","alertify-cover"),p.className="alertify-cover alertify-cover-hidden",n.body.appendChild(p),d=n.createElement("section"),d.setAttribute("id","alertify"),d.className="alertify alertify-hidden",n.body.appendChild(d),v=n.createElement("section"),v.setAttribute("id","alertify-logs"),v.className="alertify-logs alertify-logs-hidden",n.body.appendChild(v),n.body.setAttribute("tabindex","0"),this.transition=y(),delete this.init},log:function(e,t,n){var r=function(){if(v&&v.scrollTop!==null)return;r()};return typeof this.init=="function"&&(this.init(),r()),v.className="alertify-logs",this.notify(e,t,n),this},notify:function(e,t,r){var i=n.createElement("article");i.className="alertify-log"+(typeof t=="string"&&t!==""?" alertify-log-"+t:""),i.innerHTML=e,v.insertBefore(i,v.firstChild),setTimeout(function(){i.className=i.className+" alertify-log-show"},50),this.close(i,r)},set:function(e){var t;if(typeof e!="object"&&e instanceof Array)throw new Error("args must be an object");for(t in e)e.hasOwnProperty(t)&&(this[t]=e[t])},setFocus:function(){g?(g.focus(),g.select()):c.focus()},setup:function(){var n=o[0],r=this,s;i=!0,s=function(e){e.stopPropagation(),r.setFocus(),r.unbind(d,r.transition,s)},typeof this.transition!="undefined"&&this.bind(d,this.transition,s),d.innerHTML=this.build(n),l=u("alertify-resetFocus"),f=u("alertify-ok")||t,a=u("alertify-cancel")||t,c=e.buttonFocus==="cancel"?a:e.buttonFocus==="none"?u("alertify-noneFocus"):f,g=u("alertify-text")||t,m=u("alertify-form")||t,typeof n.placeholder=="string"&&n.placeholder!==""&&(g.value=n.placeholder),this.addListeners(n.callback)},unbind:function(e,t,n){typeof e.removeEventListener=="function"?e.removeEventListener(t,n,!1):e.detachEvent&&e.detachEvent("on"+t,n)}},{alert:function(t,n,r){return e.dialog(t,"alert",n,"",r),this},confirm:function(t,n,r){return e.dialog(t,"confirm",n,"",r),this},extend:e.extend,init:e.init,log:function(t,n,r){return e.log(t,n,r),this},prompt:function(t,n,r,i){return e.dialog(t,"prompt",n,r,i),this},success:function(t,n){return e.log(t,"success",n),this},error:function(t,n){return e.log(t,"error",n),this},set:function(t){e.set(t)},labels:e.labels}},typeof define=="function"?define([],function(){return new r}):typeof e.alertify=="undefined"&&(e.alertify=new r)})(this); \ No newline at end of file diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100755 index 0000000..282532b --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,60 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD +// GO AFTER THE REQUIRES BELOW. +// +//= require jquery +//= require jquery_ujs +//= require turbolinks +//= require jquery.scrollUp.js +//= require bootstrap.js +//= require bootstrap-colorpicker.js +//= require date-picker/date.js +//= require date-picker/daterangepicker.js +//= require bootstrap-timepicker.js +//= require jquery.bootstrap.wizard.js +//= require tiny-scrollbar.js +//= require jquery.validate.min.js +//= require jquery.snippet.js +//= require jquery.easy-pie-chart.js +//= require jquery-fileupload/basic +//= require jquery-fileupload/vendor/tmpl + +function rubyCodeFormat() { + $("pre.ruby").snippet("ruby",{style:"rand01",transparent:true,showNum:true}); + $("pre.javascript").snippet("javascript",{style:"rand01",transparent:true,showNum:true}); +} + +function coerceToString(val) { + return String((val === null || val === undefined) ? '' : val); +} + +var rAmp = /&/g, + rLt = //g, + rApos = /\'/g, + rQuot = /\"/g, + hChars = /[&<>\"\']/; + +function hoganEscape(str) { + str = coerceToString(str); + return hChars.test(str) ? + str + .replace(rAmp, '&') + .replace(rLt, '<') + .replace(rGt, '>') + .replace(rApos, ''') + .replace(rQuot, '"') : + str; +} + +$(document).ready(function(){ + rubyCodeFormat(); +}); diff --git a/app/assets/javascripts/bootstrap-colorpicker.js b/app/assets/javascripts/bootstrap-colorpicker.js new file mode 100755 index 0000000..6a0fc8a --- /dev/null +++ b/app/assets/javascripts/bootstrap-colorpicker.js @@ -0,0 +1,540 @@ +/* ========================================================= + * bootstrap-colorpicker.js + * http://www.eyecon.ro/bootstrap-colorpicker + * ========================================================= + * Copyright 2012 Stefan Petre + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +!function( $ ) { + + // Color object + + var Color = function(val) { + this.value = { + h: 1, + s: 1, + b: 1, + a: 1 + }; + this.setColor(val); + }; + + Color.prototype = { + constructor: Color, + + //parse a string to HSB + setColor: function(val){ + val = val.toLowerCase(); + var that = this; + $.each( CPGlobal.stringParsers, function( i, parser ) { + var match = parser.re.exec( val ), + values = match && parser.parse( match ), + space = parser.space||'rgba'; + if ( values ) { + if (space === 'hsla') { + that.value = CPGlobal.RGBtoHSB.apply(null, CPGlobal.HSLtoRGB.apply(null, values)); + } else { + that.value = CPGlobal.RGBtoHSB.apply(null, values); + } + return false; + } + }); + }, + + setHue: function(h) { + this.value.h = 1- h; + }, + + setSaturation: function(s) { + this.value.s = s; + }, + + setLightness: function(b) { + this.value.b = 1- b; + }, + + setAlpha: function(a) { + this.value.a = parseInt((1 - a)*100, 10)/100; + }, + + // HSBtoRGB from RaphaelJS + // https://github.com/DmitryBaranovskiy/raphael/ + toRGB: function(h, s, b, a) { + if (!h) { + h = this.value.h; + s = this.value.s; + b = this.value.b; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = b * s; + X = C * (1 - Math.abs(h % 2 - 1)); + R = G = B = b - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return { + r: Math.round(R*255), + g: Math.round(G*255), + b: Math.round(B*255), + a: a||this.value.a + }; + }, + + toHex: function(h, s, b, a){ + var rgb = this.toRGB(h, s, b, a); + return '#'+((1 << 24) | (parseInt(rgb.r) << 16) | (parseInt(rgb.g) << 8) | parseInt(rgb.b)).toString(16).substr(1); + }, + + toHSL: function(h, s, b, a){ + if (!h) { + h = this.value.h; + s = this.value.s; + b = this.value.b; + } + var H = h, + L = (2 - s) * b, + S = s * b; + if (L > 0 && L <= 1) { + S /= L; + } else { + S /= 2 - L; + } + L /= 2; + if (S > 1) { + S = 1; + } + return { + h: H, + s: S, + l: L, + a: a||this.value.a + }; + } + }; + + // Picker object + + var Colorpicker = function(element, options){ + this.element = $(element); + var format = options.format||this.element.data('color-format')||'hex'; + this.format = CPGlobal.translateFormats[format]; + this.isInput = this.element.is('input'); + this.component = this.element.is('.color') ? this.element.find('.add-on') : false; + + this.picker = $(CPGlobal.template) + .appendTo('body') + .on('mousedown', $.proxy(this.mousedown, this)); + + if (this.isInput) { + this.element.on({ + 'focus': $.proxy(this.show, this), + 'keyup': $.proxy(this.update, this) + }); + } else if (this.component){ + this.component.on({ + 'click': $.proxy(this.show, this) + }); + } else { + this.element.on({ + 'click': $.proxy(this.show, this) + }); + } + if (format === 'rgba' || format === 'hsla') { + this.picker.addClass('alpha'); + this.alpha = this.picker.find('.colorpicker-alpha')[0].style; + } + + if (this.component){ + this.picker.find('.colorpicker-color').hide(); + this.preview = this.element.find('i')[0].style; + } else { + this.preview = this.picker.find('div:last')[0].style; + } + + this.base = this.picker.find('div:first')[0].style; + this.update(); + }; + + Colorpicker.prototype = { + constructor: Colorpicker, + + show: function(e) { + this.picker.show(); + this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); + this.place(); + $(window).on('resize', $.proxy(this.place, this)); + if (!this.isInput) { + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + } + $(document).on({ + 'mousedown': $.proxy(this.hide, this) + }); + this.element.trigger({ + type: 'show', + color: this.color + }); + }, + + update: function(){ + this.color = new Color(this.isInput ? this.element.prop('value') : this.element.data('color')); + this.picker.find('i') + .eq(0).css({left: this.color.value.s*100, top: 100 - this.color.value.b*100}).end() + .eq(1).css('top', 100 * (1 - this.color.value.h)).end() + .eq(2).css('top', 100 * (1 - this.color.value.a)); + this.previewColor(); + }, + + setValue: function(newColor) { + this.color = new Color(newColor); + this.picker.find('i') + .eq(0).css({left: this.color.value.s*100, top: 100 - this.color.value.b*100}).end() + .eq(1).css('top', 100 * (1 - this.color.value.h)).end() + .eq(2).css('top', 100 * (1 - this.color.value.a)); + this.previewColor(); + this.element.trigger({ + type: 'changeColor', + color: this.color + }); + }, + + hide: function(){ + this.picker.hide(); + $(window).off('resize', this.place); + if (!this.isInput) { + $(document).off({ + 'mousedown': this.hide + }); + if (this.component){ + this.element.find('input').prop('value', this.format.call(this)); + } + this.element.data('color', this.format.call(this)); + } else { + this.element.prop('value', this.format.call(this)); + } + this.element.trigger({ + type: 'hide', + color: this.color + }); + }, + + place: function(){ + var offset = this.component ? this.component.offset() : this.element.offset(); + this.picker.css({ + top: offset.top + this.height, + left: offset.left + }); + }, + + //preview color change + previewColor: function(){ + try { + this.preview.backgroundColor = this.format.call(this); + } catch(e) { + this.preview.backgroundColor = this.color.toHex(); + } + //set the color for brightness/saturation slider + this.base.backgroundColor = this.color.toHex(this.color.value.h, 1, 1, 1); + //set te color for alpha slider + if (this.alpha) { + this.alpha.backgroundColor = this.color.toHex(); + } + }, + + pointer: null, + + slider: null, + + mousedown: function(e){ + e.stopPropagation(); + e.preventDefault(); + + var target = $(e.target); + + //detect the slider and set the limits and callbacks + var zone = target.closest('div'); + if (!zone.is('.colorpicker')) { + if (zone.is('.colorpicker-saturation')) { + this.slider = $.extend({}, CPGlobal.sliders.saturation); + } + else if (zone.is('.colorpicker-hue')) { + this.slider = $.extend({}, CPGlobal.sliders.hue); + } + else if (zone.is('.colorpicker-alpha')) { + this.slider = $.extend({}, CPGlobal.sliders.alpha); + } else { + return false; + } + var offset = zone.offset(); + //reference to knob's style + this.slider.knob = zone.find('i')[0].style; + this.slider.left = e.pageX - offset.left; + this.slider.top = e.pageY - offset.top; + this.pointer = { + left: e.pageX, + top: e.pageY + }; + //trigger mousemove to move the knob to the current position + $(document).on({ + mousemove: $.proxy(this.mousemove, this), + mouseup: $.proxy(this.mouseup, this) + }).trigger('mousemove'); + } + return false; + }, + + mousemove: function(e){ + e.stopPropagation(); + e.preventDefault(); + var left = Math.max( + 0, + Math.min( + this.slider.maxLeft, + this.slider.left + ((e.pageX||this.pointer.left) - this.pointer.left) + ) + ); + var top = Math.max( + 0, + Math.min( + this.slider.maxTop, + this.slider.top + ((e.pageY||this.pointer.top) - this.pointer.top) + ) + ); + this.slider.knob.left = left + 'px'; + this.slider.knob.top = top + 'px'; + if (this.slider.callLeft) { + this.color[this.slider.callLeft].call(this.color, left/100); + } + if (this.slider.callTop) { + this.color[this.slider.callTop].call(this.color, top/100); + } + this.previewColor(); + this.element.trigger({ + type: 'changeColor', + color: this.color + }); + return false; + }, + + mouseup: function(e){ + e.stopPropagation(); + e.preventDefault(); + $(document).off({ + mousemove: this.mousemove, + mouseup: this.mouseup + }); + return false; + } + } + + $.fn.colorpicker = function ( option ) { + return this.each(function () { + var $this = $(this), + data = $this.data('colorpicker'), + options = typeof option === 'object' && option; + if (!data) { + $this.data('colorpicker', (data = new Colorpicker(this, $.extend({}, $.fn.colorpicker.defaults,options)))); + } + if (typeof option === 'string') data[option](); + }); + }; + + $.fn.colorpicker.defaults = { + }; + + $.fn.colorpicker.Constructor = Colorpicker; + + var CPGlobal = { + + // translate a format from Color object to a string + translateFormats: { + 'rgb': function(){ + var rgb = this.color.toRGB(); + return 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')'; + }, + + 'rgba': function(){ + var rgb = this.color.toRGB(); + return 'rgba('+rgb.r+','+rgb.g+','+rgb.b+','+rgb.a+')'; + }, + + 'hsl': function(){ + var hsl = this.color.toHSL(); + return 'hsl('+Math.round(hsl.h*360)+','+Math.round(hsl.s*100)+'%,'+Math.round(hsl.l*100)+'%)'; + }, + + 'hsla': function(){ + var hsl = this.color.toHSL(); + return 'hsla('+Math.round(hsl.h*360)+','+Math.round(hsl.s*100)+'%,'+Math.round(hsl.l*100)+'%,'+hsl.a+')'; + }, + + 'hex': function(){ + return this.color.toHex(); + } + }, + + sliders: { + saturation: { + maxLeft: 100, + maxTop: 100, + callLeft: 'setSaturation', + callTop: 'setLightness' + }, + + hue: { + maxLeft: 0, + maxTop: 100, + callLeft: false, + callTop: 'setHue' + }, + + alpha: { + maxLeft: 0, + maxTop: 100, + callLeft: false, + callTop: 'setAlpha' + } + }, + + // HSBtoRGB from RaphaelJS + // https://github.com/DmitryBaranovskiy/raphael/ + RGBtoHSB: function (r, g, b, a){ + r /= 255; + g /= 255; + b /= 255; + + var H, S, V, C; + V = Math.max(r, g, b); + C = V - Math.min(r, g, b); + H = (C === 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C === 0 ? 0 : C / V; + return {h: H||1, s: S, b: V, a: a||1}; + }, + + HueToRGB: function (p, q, h) { + if (h < 0) + h += 1; + else if (h > 1) + h -= 1; + + if ((h * 6) < 1) + return p + (q - p) * h * 6; + else if ((h * 2) < 1) + return q; + else if ((h * 3) < 2) + return p + (q - p) * ((2 / 3) - h) * 6; + else + return p; + }, + + HSLtoRGB: function (h, s, l, a) + { + if (s < 0) { + s = 0; + } + var q; + if (l <= 0.5) { + q = l * (1 + s); + } else { + q = l + s - (l * s); + } + + var p = 2 * l - q; + + var tr = h + (1 / 3); + var tg = h; + var tb = h - (1 / 3); + + var r = Math.round(CPGlobal.HueToRGB(p, q, tr) * 255); + var g = Math.round(CPGlobal.HueToRGB(p, q, tg) * 255); + var b = Math.round(CPGlobal.HueToRGB(p, q, tb) * 255); + return [r, g, b, a||1]; + }, + + // a set of RE's that can match strings and generate color tuples. + // from John Resig color plugin + // https://github.com/jquery/jquery-color/ + stringParsers: [ + { + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + 2.55 * execResult[1], + 2.55 * execResult[2], + 2.55 * execResult[3], + execResult[ 4 ] + ]; + } + }, { + re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ) + ]; + } + }, { + re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + space: 'hsla', + parse: function( execResult ) { + return [ + execResult[1]/360, + execResult[2] / 100, + execResult[3] / 100, + execResult[4] + ]; + } + } + ], + template: '