From ffe08471bfd5988fb931358c089a47bcff8a3bbe Mon Sep 17 00:00:00 2001
From: Connor <78193645+Connor-Bernard@users.noreply.github.com>
Date: Wed, 14 Feb 2024 17:41:54 -0800
Subject: [PATCH 001/155] feat: initialize repo (#1)
---
Dockerfile | 62 +++
Gemfile | 71 ++++
Gemfile.lock | 376 ++++++++++++++++++
Guardfile | 70 ++++
Rakefile | 6 +
app/assets/config/manifest.js | 4 +
app/assets/images/.keep | 0
app/assets/stylesheets/application.css | 15 +
app/channels/application_cable/channel.rb | 4 +
app/channels/application_cable/connection.rb | 4 +
app/controllers/application_controller.rb | 2 +
app/controllers/concerns/.keep | 0
app/helpers/application_helper.rb | 2 +
app/javascript/application.js | 3 +
app/javascript/controllers/application.js | 9 +
.../controllers/hello_controller.js | 7 +
app/javascript/controllers/index.js | 11 +
app/jobs/application_job.rb | 7 +
app/mailers/application_mailer.rb | 4 +
app/models/application_record.rb | 3 +
app/models/concerns/.keep | 0
app/views/layouts/application.html.erb | 16 +
app/views/layouts/mailer.html.erb | 13 +
app/views/layouts/mailer.text.erb | 1 +
bin/bundle | 109 +++++
bin/cucumber | 11 +
bin/docker-entrypoint | 8 +
bin/importmap | 4 +
bin/rails | 4 +
bin/rake | 4 +
bin/setup | 33 ++
config.ru | 6 +
config/application.rb | 42 ++
config/boot.rb | 4 +
config/cable.yml | 10 +
config/credentials.yml.enc | 1 +
config/cucumber.yml | 8 +
config/database.yml | 25 ++
config/environment.rb | 5 +
config/environments/development.rb | 80 ++++
config/environments/production.rb | 97 +++++
config/environments/test.rb | 68 ++++
config/importmap.rb | 7 +
config/initializers/assets.rb | 12 +
.../initializers/content_security_policy.rb | 25 ++
.../initializers/filter_parameter_logging.rb | 8 +
config/initializers/inflections.rb | 16 +
config/initializers/permissions_policy.rb | 13 +
config/locales/en.yml | 31 ++
config/puma.rb | 35 ++
config/routes.rb | 10 +
config/storage.yml | 34 ++
db/seeds.rb | 9 +
features/step_definitions/.keep | 0
features/step_definitions/web_steps.rb | 254 ++++++++++++
features/support/env.rb | 53 +++
features/support/paths.rb | 38 ++
features/support/selectors.rb | 44 ++
lib/assets/.keep | 0
lib/tasks/.keep | 0
lib/tasks/cucumber.rake | 69 ++++
log/.keep | 0
public/404.html | 67 ++++
public/422.html | 67 ++++
public/500.html | 66 +++
public/apple-touch-icon-precomposed.png | 0
public/apple-touch-icon.png | 0
public/favicon.ico | 0
public/robots.txt | 1 +
spec/rails_helper.rb | 65 +++
spec/spec_helper.rb | 94 +++++
storage/.keep | 0
tmp/.keep | 0
vendor/.keep | 0
vendor/javascript/.keep | 0
75 files changed, 2227 insertions(+)
create mode 100644 Dockerfile
create mode 100644 Gemfile
create mode 100644 Gemfile.lock
create mode 100644 Guardfile
create mode 100644 Rakefile
create mode 100644 app/assets/config/manifest.js
create mode 100644 app/assets/images/.keep
create mode 100644 app/assets/stylesheets/application.css
create mode 100644 app/channels/application_cable/channel.rb
create mode 100644 app/channels/application_cable/connection.rb
create mode 100644 app/controllers/application_controller.rb
create mode 100644 app/controllers/concerns/.keep
create mode 100644 app/helpers/application_helper.rb
create mode 100644 app/javascript/application.js
create mode 100644 app/javascript/controllers/application.js
create mode 100644 app/javascript/controllers/hello_controller.js
create mode 100644 app/javascript/controllers/index.js
create mode 100644 app/jobs/application_job.rb
create mode 100644 app/mailers/application_mailer.rb
create mode 100644 app/models/application_record.rb
create mode 100644 app/models/concerns/.keep
create mode 100644 app/views/layouts/application.html.erb
create mode 100644 app/views/layouts/mailer.html.erb
create mode 100644 app/views/layouts/mailer.text.erb
create mode 100755 bin/bundle
create mode 100755 bin/cucumber
create mode 100755 bin/docker-entrypoint
create mode 100755 bin/importmap
create mode 100755 bin/rails
create mode 100755 bin/rake
create mode 100755 bin/setup
create mode 100644 config.ru
create mode 100644 config/application.rb
create mode 100644 config/boot.rb
create mode 100644 config/cable.yml
create mode 100644 config/credentials.yml.enc
create mode 100644 config/cucumber.yml
create mode 100644 config/database.yml
create mode 100644 config/environment.rb
create mode 100644 config/environments/development.rb
create mode 100644 config/environments/production.rb
create mode 100644 config/environments/test.rb
create mode 100644 config/importmap.rb
create mode 100644 config/initializers/assets.rb
create mode 100644 config/initializers/content_security_policy.rb
create mode 100644 config/initializers/filter_parameter_logging.rb
create mode 100644 config/initializers/inflections.rb
create mode 100644 config/initializers/permissions_policy.rb
create mode 100644 config/locales/en.yml
create mode 100644 config/puma.rb
create mode 100644 config/routes.rb
create mode 100644 config/storage.yml
create mode 100644 db/seeds.rb
create mode 100644 features/step_definitions/.keep
create mode 100644 features/step_definitions/web_steps.rb
create mode 100644 features/support/env.rb
create mode 100644 features/support/paths.rb
create mode 100644 features/support/selectors.rb
create mode 100644 lib/assets/.keep
create mode 100644 lib/tasks/.keep
create mode 100644 lib/tasks/cucumber.rake
create mode 100644 log/.keep
create mode 100644 public/404.html
create mode 100644 public/422.html
create mode 100644 public/500.html
create mode 100644 public/apple-touch-icon-precomposed.png
create mode 100644 public/apple-touch-icon.png
create mode 100644 public/favicon.ico
create mode 100644 public/robots.txt
create mode 100644 spec/rails_helper.rb
create mode 100644 spec/spec_helper.rb
create mode 100644 storage/.keep
create mode 100644 tmp/.keep
create mode 100644 vendor/.keep
create mode 100644 vendor/javascript/.keep
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..d18898b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,62 @@
+# syntax = docker/dockerfile:1
+
+# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
+ARG RUBY_VERSION=3.3.0
+FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
+
+# Rails app lives here
+WORKDIR /rails
+
+# Set production environment
+ENV RAILS_ENV="production" \
+ BUNDLE_DEPLOYMENT="1" \
+ BUNDLE_PATH="/usr/local/bundle" \
+ BUNDLE_WITHOUT="development"
+
+
+# Throw-away build stage to reduce size of final image
+FROM base as build
+
+# Install packages needed to build gems
+RUN apt-get update -qq && \
+ apt-get install --no-install-recommends -y build-essential git libvips pkg-config
+
+# Install application gems
+COPY Gemfile Gemfile.lock ./
+RUN bundle install && \
+ rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
+ bundle exec bootsnap precompile --gemfile
+
+# Copy application code
+COPY . .
+
+# Precompile bootsnap code for faster boot times
+RUN bundle exec bootsnap precompile app/ lib/
+
+# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
+RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
+
+
+# Final stage for app image
+FROM base
+
+# Install packages needed for deployment
+RUN apt-get update -qq && \
+ apt-get install --no-install-recommends -y curl libsqlite3-0 libvips && \
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
+
+# Copy built artifacts: gems, application
+COPY --from=build /usr/local/bundle /usr/local/bundle
+COPY --from=build /rails /rails
+
+# Run and own only the runtime files as a non-root user for security
+RUN useradd rails --create-home --shell /bin/bash && \
+ chown -R rails:rails db log storage tmp
+USER rails:rails
+
+# Entrypoint prepares the database.
+ENTRYPOINT ["/rails/bin/docker-entrypoint"]
+
+# Start the server by default, this can be overwritten at runtime
+EXPOSE 3000
+CMD ["./bin/rails", "server"]
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..a6a72fc
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,71 @@
+source "https://rubygems.org"
+
+ruby "3.3.0"
+
+# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
+gem "rails", "~> 7.1.3"
+
+# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
+gem "sprockets-rails"
+
+# Use sqlite3 as the database for Active Record
+gem "sqlite3", "~> 1.4"
+
+# Use the Puma web server [https://github.com/puma/puma]
+gem "puma", ">= 5.0"
+
+# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
+gem "importmap-rails"
+
+# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
+gem "turbo-rails"
+
+# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
+gem "stimulus-rails"
+
+# Build JSON APIs with ease [https://github.com/rails/jbuilder]
+gem "jbuilder"
+
+# Use Redis adapter to run Action Cable in production
+# gem "redis", ">= 4.0.1"
+
+# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
+# gem "kredis"
+
+# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
+# gem "bcrypt", "~> 3.1.7"
+
+# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
+gem "tzinfo-data", platforms: %i[ windows jruby ]
+
+# Reduces boot times through caching; required in config/boot.rb
+gem "bootsnap", require: false
+
+# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
+# gem "image_processing", "~> 1.2"
+
+group :development, :test do
+ # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
+ gem "debug", platforms: %i[ mri windows ]
+end
+
+group :test do
+ gem 'rspec-rails'
+ gem 'guard-rspec'
+ gem 'simplecov', :require => false
+ gem 'cucumber-rails', :require => false
+ gem 'cucumber-rails-training-wheels'
+ gem 'database_cleaner'
+end
+
+group :development do
+ # Use console on exceptions pages [https://github.com/rails/web-console]
+ gem "web-console"
+
+ # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
+ # gem "rack-mini-profiler"
+
+ # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
+ # gem "spring"
+end
+
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..6daf496
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,376 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actioncable (7.1.3)
+ actionpack (= 7.1.3)
+ activesupport (= 7.1.3)
+ nio4r (~> 2.0)
+ websocket-driver (>= 0.6.1)
+ zeitwerk (~> 2.6)
+ actionmailbox (7.1.3)
+ actionpack (= 7.1.3)
+ activejob (= 7.1.3)
+ activerecord (= 7.1.3)
+ activestorage (= 7.1.3)
+ activesupport (= 7.1.3)
+ mail (>= 2.7.1)
+ net-imap
+ net-pop
+ net-smtp
+ actionmailer (7.1.3)
+ actionpack (= 7.1.3)
+ actionview (= 7.1.3)
+ activejob (= 7.1.3)
+ activesupport (= 7.1.3)
+ mail (~> 2.5, >= 2.5.4)
+ net-imap
+ net-pop
+ net-smtp
+ rails-dom-testing (~> 2.2)
+ actionpack (7.1.3)
+ actionview (= 7.1.3)
+ activesupport (= 7.1.3)
+ nokogiri (>= 1.8.5)
+ racc
+ rack (>= 2.2.4)
+ rack-session (>= 1.0.1)
+ rack-test (>= 0.6.3)
+ rails-dom-testing (~> 2.2)
+ rails-html-sanitizer (~> 1.6)
+ actiontext (7.1.3)
+ actionpack (= 7.1.3)
+ activerecord (= 7.1.3)
+ activestorage (= 7.1.3)
+ activesupport (= 7.1.3)
+ globalid (>= 0.6.0)
+ nokogiri (>= 1.8.5)
+ actionview (7.1.3)
+ activesupport (= 7.1.3)
+ builder (~> 3.1)
+ erubi (~> 1.11)
+ rails-dom-testing (~> 2.2)
+ rails-html-sanitizer (~> 1.6)
+ activejob (7.1.3)
+ activesupport (= 7.1.3)
+ globalid (>= 0.3.6)
+ activemodel (7.1.3)
+ activesupport (= 7.1.3)
+ activerecord (7.1.3)
+ activemodel (= 7.1.3)
+ activesupport (= 7.1.3)
+ timeout (>= 0.4.0)
+ activestorage (7.1.3)
+ actionpack (= 7.1.3)
+ activejob (= 7.1.3)
+ activerecord (= 7.1.3)
+ activesupport (= 7.1.3)
+ marcel (~> 1.0)
+ activesupport (7.1.3)
+ base64
+ bigdecimal
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ connection_pool (>= 2.2.5)
+ drb
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ mutex_m
+ tzinfo (~> 2.0)
+ addressable (2.8.6)
+ public_suffix (>= 2.0.2, < 6.0)
+ base64 (0.2.0)
+ bigdecimal (3.1.6)
+ bindex (0.8.1)
+ bootsnap (1.18.3)
+ msgpack (~> 1.2)
+ builder (3.2.4)
+ 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)
+ coderay (1.1.3)
+ concurrent-ruby (1.2.3)
+ connection_pool (2.4.1)
+ crass (1.0.6)
+ cucumber (9.1.2)
+ builder (~> 3.2, >= 3.2.4)
+ cucumber-ci-environment (~> 9.2, >= 9.2.0)
+ cucumber-core (~> 12.0)
+ cucumber-cucumber-expressions (~> 17.0)
+ cucumber-gherkin (> 24, < 27)
+ cucumber-html-formatter (> 20.3, < 22)
+ cucumber-messages (> 19, < 25)
+ diff-lcs (~> 1.5)
+ mini_mime (~> 1.1, >= 1.1.5)
+ multi_test (~> 1.1, >= 1.1.0)
+ sys-uname (~> 1.2, >= 1.2.3)
+ cucumber-ci-environment (9.2.0)
+ cucumber-core (12.0.0)
+ cucumber-gherkin (>= 25, < 27)
+ cucumber-messages (>= 20, < 23)
+ cucumber-tag-expressions (~> 5.0, >= 5.0.4)
+ cucumber-cucumber-expressions (17.0.1)
+ cucumber-gherkin (26.2.0)
+ cucumber-messages (>= 19.1.4, < 22.1)
+ cucumber-html-formatter (21.2.0)
+ cucumber-messages (> 19, < 25)
+ cucumber-messages (22.0.0)
+ cucumber-rails (3.0.0)
+ capybara (>= 3.11, < 4)
+ cucumber (>= 5, < 10)
+ railties (>= 5.2, < 8)
+ cucumber-rails-training-wheels (1.0.0)
+ cucumber-rails (>= 1.1.1)
+ cucumber-tag-expressions (5.0.6)
+ database_cleaner (2.0.2)
+ database_cleaner-active_record (>= 2, < 3)
+ database_cleaner-active_record (2.1.0)
+ activerecord (>= 5.a)
+ database_cleaner-core (~> 2.0.0)
+ database_cleaner-core (2.0.1)
+ date (3.3.4)
+ debug (1.9.1)
+ irb (~> 1.10)
+ reline (>= 0.3.8)
+ diff-lcs (1.5.1)
+ docile (1.4.0)
+ drb (2.2.0)
+ ruby2_keywords
+ erubi (1.12.0)
+ ffi (1.16.3)
+ formatador (1.1.0)
+ globalid (1.2.1)
+ activesupport (>= 6.1)
+ guard (2.18.1)
+ formatador (>= 0.2.4)
+ listen (>= 2.7, < 4.0)
+ 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-rspec (4.7.3)
+ guard (~> 2.1)
+ guard-compat (~> 1.1)
+ rspec (>= 2.99.0, < 4.0)
+ i18n (1.14.1)
+ concurrent-ruby (~> 1.0)
+ importmap-rails (2.0.1)
+ actionpack (>= 6.0.0)
+ activesupport (>= 6.0.0)
+ railties (>= 6.0.0)
+ io-console (0.7.2)
+ irb (1.11.2)
+ rdoc
+ reline (>= 0.4.2)
+ jbuilder (2.11.5)
+ actionview (>= 5.0.0)
+ activesupport (>= 5.0.0)
+ listen (3.8.0)
+ rb-fsevent (~> 0.10, >= 0.10.3)
+ rb-inotify (~> 0.9, >= 0.9.10)
+ loofah (2.22.0)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.12.0)
+ lumberjack (1.2.10)
+ mail (2.8.1)
+ mini_mime (>= 0.1.1)
+ net-imap
+ net-pop
+ net-smtp
+ marcel (1.0.2)
+ matrix (0.4.2)
+ method_source (1.0.0)
+ mini_mime (1.1.5)
+ minitest (5.22.2)
+ msgpack (1.7.2)
+ multi_test (1.1.0)
+ mutex_m (0.2.0)
+ nenv (0.3.0)
+ net-imap (0.4.10)
+ date
+ net-protocol
+ net-pop (0.1.2)
+ net-protocol
+ net-protocol (0.2.2)
+ timeout
+ net-smtp (0.4.0.1)
+ net-protocol
+ nio4r (2.7.0)
+ nokogiri (1.16.2-aarch64-linux)
+ racc (~> 1.4)
+ nokogiri (1.16.2-arm-linux)
+ racc (~> 1.4)
+ nokogiri (1.16.2-arm64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.16.2-x86-linux)
+ racc (~> 1.4)
+ nokogiri (1.16.2-x86_64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.16.2-x86_64-linux)
+ racc (~> 1.4)
+ notiffany (0.1.3)
+ nenv (~> 0.1)
+ shellany (~> 0.0)
+ pry (0.14.2)
+ coderay (~> 1.1)
+ method_source (~> 1.0)
+ psych (5.1.2)
+ stringio
+ public_suffix (5.0.4)
+ puma (6.4.2)
+ nio4r (~> 2.0)
+ racc (1.7.3)
+ rack (3.0.9)
+ rack-session (2.0.0)
+ rack (>= 3.0.0)
+ rack-test (2.1.0)
+ rack (>= 1.3)
+ rackup (2.1.0)
+ rack (>= 3)
+ webrick (~> 1.8)
+ rails (7.1.3)
+ actioncable (= 7.1.3)
+ actionmailbox (= 7.1.3)
+ actionmailer (= 7.1.3)
+ actionpack (= 7.1.3)
+ actiontext (= 7.1.3)
+ actionview (= 7.1.3)
+ activejob (= 7.1.3)
+ activemodel (= 7.1.3)
+ activerecord (= 7.1.3)
+ activestorage (= 7.1.3)
+ activesupport (= 7.1.3)
+ bundler (>= 1.15.0)
+ railties (= 7.1.3)
+ rails-dom-testing (2.2.0)
+ activesupport (>= 5.0.0)
+ minitest
+ nokogiri (>= 1.6)
+ rails-html-sanitizer (1.6.0)
+ loofah (~> 2.21)
+ nokogiri (~> 1.14)
+ railties (7.1.3)
+ actionpack (= 7.1.3)
+ activesupport (= 7.1.3)
+ irb
+ rackup (>= 1.0.0)
+ rake (>= 12.2)
+ thor (~> 1.0, >= 1.2.2)
+ zeitwerk (~> 2.6)
+ rake (13.1.0)
+ rb-fsevent (0.11.2)
+ rb-inotify (0.10.1)
+ ffi (~> 1.0)
+ rdoc (6.6.2)
+ psych (>= 4.0.0)
+ regexp_parser (2.9.0)
+ reline (0.4.2)
+ io-console (~> 0.5)
+ rspec (3.13.0)
+ rspec-core (~> 3.13.0)
+ rspec-expectations (~> 3.13.0)
+ rspec-mocks (~> 3.13.0)
+ rspec-core (3.13.0)
+ rspec-support (~> 3.13.0)
+ rspec-expectations (3.13.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.13.0)
+ rspec-mocks (3.13.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.13.0)
+ rspec-rails (6.1.1)
+ actionpack (>= 6.1)
+ activesupport (>= 6.1)
+ railties (>= 6.1)
+ rspec-core (~> 3.12)
+ rspec-expectations (~> 3.12)
+ rspec-mocks (~> 3.12)
+ rspec-support (~> 3.12)
+ rspec-support (3.13.0)
+ ruby2_keywords (0.0.5)
+ shellany (0.0.1)
+ simplecov (0.22.0)
+ docile (~> 1.1)
+ simplecov-html (~> 0.11)
+ simplecov_json_formatter (~> 0.1)
+ simplecov-html (0.12.3)
+ simplecov_json_formatter (0.1.4)
+ sprockets (4.2.1)
+ concurrent-ruby (~> 1.0)
+ rack (>= 2.2.4, < 4)
+ sprockets-rails (3.4.2)
+ actionpack (>= 5.2)
+ activesupport (>= 5.2)
+ sprockets (>= 3.0.0)
+ sqlite3 (1.7.2-aarch64-linux)
+ sqlite3 (1.7.2-arm-linux)
+ sqlite3 (1.7.2-arm64-darwin)
+ sqlite3 (1.7.2-x86-linux)
+ sqlite3 (1.7.2-x86_64-darwin)
+ sqlite3 (1.7.2-x86_64-linux)
+ stimulus-rails (1.3.3)
+ railties (>= 6.0.0)
+ stringio (3.1.0)
+ sys-uname (1.2.3)
+ ffi (~> 1.1)
+ thor (1.3.0)
+ timeout (0.4.1)
+ turbo-rails (2.0.0)
+ actionpack (>= 6.0.0)
+ activejob (>= 6.0.0)
+ railties (>= 6.0.0)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ web-console (4.2.1)
+ actionview (>= 6.0.0)
+ activemodel (>= 6.0.0)
+ bindex (>= 0.4.0)
+ railties (>= 6.0.0)
+ webrick (1.8.1)
+ websocket-driver (0.7.6)
+ websocket-extensions (>= 0.1.0)
+ websocket-extensions (0.1.5)
+ xpath (3.2.0)
+ nokogiri (~> 1.8)
+ zeitwerk (2.6.13)
+
+PLATFORMS
+ aarch64-linux
+ arm-linux
+ arm64-darwin
+ x86-linux
+ x86_64-darwin
+ x86_64-linux
+
+DEPENDENCIES
+ bootsnap
+ cucumber-rails
+ cucumber-rails-training-wheels
+ database_cleaner
+ debug
+ guard-rspec
+ importmap-rails
+ jbuilder
+ puma (>= 5.0)
+ rails (~> 7.1.3)
+ rspec-rails
+ simplecov
+ sprockets-rails
+ sqlite3 (~> 1.4)
+ stimulus-rails
+ turbo-rails
+ tzinfo-data
+ web-console
+
+RUBY VERSION
+ ruby 3.3.0p0
+
+BUNDLED WITH
+ 2.5.6
diff --git a/Guardfile b/Guardfile
new file mode 100644
index 0000000..23074cd
--- /dev/null
+++ b/Guardfile
@@ -0,0 +1,70 @@
+# A sample Guardfile
+# More info at https://github.com/guard/guard#readme
+
+## Uncomment and set this to only include directories you want to watch
+# directories %w(app lib config test spec features) \
+# .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
+
+## Note: if you are using the `directories` clause above and you are not
+## watching the project directory ('.'), then you will want to move
+## the Guardfile to a watched dir and symlink it back, e.g.
+#
+# $ mkdir config
+# $ mv Guardfile config/
+# $ ln -s config/Guardfile .
+#
+# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
+
+# Note: The cmd option is now required due to the increasing number of ways
+# rspec may be run, below are examples of the most common uses.
+# * bundler: 'bundle exec rspec'
+# * bundler binstubs: 'bin/rspec'
+# * spring: 'bin/rspec' (This will use spring if running and you have
+# installed the spring binstubs per the docs)
+# * zeus: 'zeus rspec' (requires the server to be started separately)
+# * 'just' rspec: 'rspec'
+
+guard :rspec, cmd: "bundle exec rspec" do
+ require "guard/rspec/dsl"
+ dsl = Guard::RSpec::Dsl.new(self)
+
+ # Feel free to open issues for suggestions and improvements
+
+ # RSpec files
+ rspec = dsl.rspec
+ watch(rspec.spec_helper) { rspec.spec_dir }
+ watch(rspec.spec_support) { rspec.spec_dir }
+ watch(rspec.spec_files)
+
+ # Ruby files
+ ruby = dsl.ruby
+ dsl.watch_spec_files_for(ruby.lib_files)
+
+ # Rails files
+ rails = dsl.rails(view_extensions: %w(erb haml slim))
+ dsl.watch_spec_files_for(rails.app_files)
+ dsl.watch_spec_files_for(rails.views)
+
+ watch(rails.controllers) do |m|
+ [
+ rspec.spec.call("routing/#{m[1]}_routing"),
+ rspec.spec.call("controllers/#{m[1]}_controller"),
+ rspec.spec.call("acceptance/#{m[1]}")
+ ]
+ end
+
+ # Rails config changes
+ watch(rails.spec_helper) { rspec.spec_dir }
+ watch(rails.routes) { "#{rspec.spec_dir}/routing" }
+ watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
+
+ # Capybara features specs
+ watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
+ watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }
+
+ # Turnip features and steps
+ watch(%r{^spec/acceptance/(.+)\.feature$})
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
+ Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
+ end
+end
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..9a5ea73
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,6 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require_relative "config/application"
+
+Rails.application.load_tasks
diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js
new file mode 100644
index 0000000..ddd546a
--- /dev/null
+++ b/app/assets/config/manifest.js
@@ -0,0 +1,4 @@
+//= link_tree ../images
+//= link_directory ../stylesheets .css
+//= link_tree ../../javascript .js
+//= link_tree ../../../vendor/javascript .js
diff --git a/app/assets/images/.keep b/app/assets/images/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
new file mode 100644
index 0000000..288b9ab
--- /dev/null
+++ b/app/assets/stylesheets/application.css
@@ -0,0 +1,15 @@
+/*
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
+ * listed below.
+ *
+ * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's
+ * vendor/assets/stylesheets directory can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS
+ * files in this directory. Styles in this file should be added after the last require_* statement.
+ * It is generally better to create a new file per style scope.
+ *
+ *= require_tree .
+ *= require_self
+ */
diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb
new file mode 100644
index 0000000..d672697
--- /dev/null
+++ b/app/channels/application_cable/channel.rb
@@ -0,0 +1,4 @@
+module ApplicationCable
+ class Channel < ActionCable::Channel::Base
+ end
+end
diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb
new file mode 100644
index 0000000..0ff5442
--- /dev/null
+++ b/app/channels/application_cable/connection.rb
@@ -0,0 +1,4 @@
+module ApplicationCable
+ class Connection < ActionCable::Connection::Base
+ end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
new file mode 100644
index 0000000..09705d1
--- /dev/null
+++ b/app/controllers/application_controller.rb
@@ -0,0 +1,2 @@
+class ApplicationController < ActionController::Base
+end
diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
new file mode 100644
index 0000000..de6be79
--- /dev/null
+++ b/app/helpers/application_helper.rb
@@ -0,0 +1,2 @@
+module ApplicationHelper
+end
diff --git a/app/javascript/application.js b/app/javascript/application.js
new file mode 100644
index 0000000..0d7b494
--- /dev/null
+++ b/app/javascript/application.js
@@ -0,0 +1,3 @@
+// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
+import "@hotwired/turbo-rails"
+import "controllers"
diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js
new file mode 100644
index 0000000..1213e85
--- /dev/null
+++ b/app/javascript/controllers/application.js
@@ -0,0 +1,9 @@
+import { Application } from "@hotwired/stimulus"
+
+const application = Application.start()
+
+// Configure Stimulus development experience
+application.debug = false
+window.Stimulus = application
+
+export { application }
diff --git a/app/javascript/controllers/hello_controller.js b/app/javascript/controllers/hello_controller.js
new file mode 100644
index 0000000..5975c07
--- /dev/null
+++ b/app/javascript/controllers/hello_controller.js
@@ -0,0 +1,7 @@
+import { Controller } from "@hotwired/stimulus"
+
+export default class extends Controller {
+ connect() {
+ this.element.textContent = "Hello World!"
+ }
+}
diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js
new file mode 100644
index 0000000..54ad4ca
--- /dev/null
+++ b/app/javascript/controllers/index.js
@@ -0,0 +1,11 @@
+// Import and register all your controllers from the importmap under controllers/*
+
+import { application } from "controllers/application"
+
+// Eager load all controllers defined in the import map under controllers/**/*_controller
+import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
+eagerLoadControllersFrom("controllers", application)
+
+// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
+// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
+// lazyLoadControllersFrom("controllers", application)
diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb
new file mode 100644
index 0000000..d394c3d
--- /dev/null
+++ b/app/jobs/application_job.rb
@@ -0,0 +1,7 @@
+class ApplicationJob < ActiveJob::Base
+ # Automatically retry jobs that encountered a deadlock
+ # retry_on ActiveRecord::Deadlocked
+
+ # Most jobs are safe to ignore if the underlying records are no longer available
+ # discard_on ActiveJob::DeserializationError
+end
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
new file mode 100644
index 0000000..3c34c81
--- /dev/null
+++ b/app/mailers/application_mailer.rb
@@ -0,0 +1,4 @@
+class ApplicationMailer < ActionMailer::Base
+ default from: "from@example.com"
+ layout "mailer"
+end
diff --git a/app/models/application_record.rb b/app/models/application_record.rb
new file mode 100644
index 0000000..b63caeb
--- /dev/null
+++ b/app/models/application_record.rb
@@ -0,0 +1,3 @@
+class ApplicationRecord < ActiveRecord::Base
+ primary_abstract_class
+end
diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
new file mode 100644
index 0000000..b0e6526
--- /dev/null
+++ b/app/views/layouts/application.html.erb
@@ -0,0 +1,16 @@
+
+
+
+ Flextentions
+
+ <%= csrf_meta_tags %>
+ <%= csp_meta_tag %>
+
+ <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
+ <%= javascript_importmap_tags %>
+
+
+
+ <%= yield %>
+
+
diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb
new file mode 100644
index 0000000..3aac900
--- /dev/null
+++ b/app/views/layouts/mailer.html.erb
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+ <%= yield %>
+
+
diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb
new file mode 100644
index 0000000..37f0bdd
--- /dev/null
+++ b/app/views/layouts/mailer.text.erb
@@ -0,0 +1 @@
+<%= yield %>
diff --git a/bin/bundle b/bin/bundle
new file mode 100755
index 0000000..50da5fd
--- /dev/null
+++ b/bin/bundle
@@ -0,0 +1,109 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'bundle' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "rubygems"
+
+m = Module.new do
+ module_function
+
+ def invoked_as_script?
+ File.expand_path($0) == File.expand_path(__FILE__)
+ end
+
+ def env_var_version
+ ENV["BUNDLER_VERSION"]
+ end
+
+ def cli_arg_version
+ return unless invoked_as_script? # don't want to hijack other binstubs
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
+ bundler_version = nil
+ update_index = nil
+ ARGV.each_with_index do |a, i|
+ if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
+ bundler_version = a
+ end
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
+ bundler_version = $1
+ update_index = i
+ end
+ bundler_version
+ end
+
+ def gemfile
+ gemfile = ENV["BUNDLE_GEMFILE"]
+ return gemfile if gemfile && !gemfile.empty?
+
+ File.expand_path("../Gemfile", __dir__)
+ end
+
+ def lockfile
+ lockfile =
+ case File.basename(gemfile)
+ when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
+ else "#{gemfile}.lock"
+ end
+ File.expand_path(lockfile)
+ end
+
+ def lockfile_version
+ return unless File.file?(lockfile)
+ lockfile_contents = File.read(lockfile)
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
+ Regexp.last_match(1)
+ end
+
+ def bundler_requirement
+ @bundler_requirement ||=
+ env_var_version ||
+ cli_arg_version ||
+ bundler_requirement_for(lockfile_version)
+ end
+
+ def bundler_requirement_for(version)
+ return "#{Gem::Requirement.default}.a" unless version
+
+ bundler_gem_version = Gem::Version.new(version)
+
+ bundler_gem_version.approximate_recommendation
+ end
+
+ def load_bundler!
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
+
+ activate_bundler
+ end
+
+ def activate_bundler
+ gem_error = activation_error_handling do
+ gem "bundler", bundler_requirement
+ end
+ return if gem_error.nil?
+ require_error = activation_error_handling do
+ require "bundler/version"
+ end
+ return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
+ warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
+ exit 42
+ end
+
+ def activation_error_handling
+ yield
+ nil
+ rescue StandardError, LoadError => e
+ e
+ end
+end
+
+m.load_bundler!
+
+if m.invoked_as_script?
+ load Gem.bin_path("bundler", "bundle")
+end
diff --git a/bin/cucumber b/bin/cucumber
new file mode 100755
index 0000000..eb5e962
--- /dev/null
+++ b/bin/cucumber
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
+if vendored_cucumber_bin
+ load File.expand_path(vendored_cucumber_bin)
+else
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
+ require 'cucumber'
+ load Cucumber::BINARY
+end
diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint
new file mode 100755
index 0000000..67ef493
--- /dev/null
+++ b/bin/docker-entrypoint
@@ -0,0 +1,8 @@
+#!/bin/bash -e
+
+# If running the rails server then create or migrate existing database
+if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then
+ ./bin/rails db:prepare
+fi
+
+exec "${@}"
diff --git a/bin/importmap b/bin/importmap
new file mode 100755
index 0000000..36502ab
--- /dev/null
+++ b/bin/importmap
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+
+require_relative "../config/application"
+require "importmap/commands"
diff --git a/bin/rails b/bin/rails
new file mode 100755
index 0000000..efc0377
--- /dev/null
+++ b/bin/rails
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+APP_PATH = File.expand_path("../config/application", __dir__)
+require_relative "../config/boot"
+require "rails/commands"
diff --git a/bin/rake b/bin/rake
new file mode 100755
index 0000000..4fbf10b
--- /dev/null
+++ b/bin/rake
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+require_relative "../config/boot"
+require "rake"
+Rake.application.run
diff --git a/bin/setup b/bin/setup
new file mode 100755
index 0000000..3cd5a9d
--- /dev/null
+++ b/bin/setup
@@ -0,0 +1,33 @@
+#!/usr/bin/env ruby
+require "fileutils"
+
+# path to your application root.
+APP_ROOT = File.expand_path("..", __dir__)
+
+def system!(*args)
+ system(*args, exception: true)
+end
+
+FileUtils.chdir APP_ROOT do
+ # This script is a way to set up or update your development environment automatically.
+ # This script is idempotent, so that you can run it at any time and get an expectable outcome.
+ # Add necessary setup steps to this file.
+
+ puts "== Installing dependencies =="
+ system! "gem install bundler --conservative"
+ system("bundle check") || system!("bundle install")
+
+ # puts "\n== Copying sample files =="
+ # unless File.exist?("config/database.yml")
+ # FileUtils.cp "config/database.yml.sample", "config/database.yml"
+ # end
+
+ puts "\n== Preparing database =="
+ system! "bin/rails db:prepare"
+
+ puts "\n== Removing old logs and tempfiles =="
+ system! "bin/rails log:clear tmp:clear"
+
+ puts "\n== Restarting application server =="
+ system! "bin/rails restart"
+end
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..4a3c09a
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,6 @@
+# This file is used by Rack-based servers to start the application.
+
+require_relative "config/environment"
+
+run Rails.application
+Rails.application.load_server
diff --git a/config/application.rb b/config/application.rb
new file mode 100644
index 0000000..b1b8b31
--- /dev/null
+++ b/config/application.rb
@@ -0,0 +1,42 @@
+require_relative "boot"
+
+require "rails"
+# Pick the frameworks you want:
+require "active_model/railtie"
+require "active_job/railtie"
+require "active_record/railtie"
+require "active_storage/engine"
+require "action_controller/railtie"
+require "action_mailer/railtie"
+require "action_mailbox/engine"
+require "action_text/engine"
+require "action_view/railtie"
+require "action_cable/engine"
+# require "rails/test_unit/railtie"
+
+# Require the gems listed in Gemfile, including any gems
+# you've limited to :test, :development, or :production.
+Bundler.require(*Rails.groups)
+
+module Flextentions
+ class Application < Rails::Application
+ # Initialize configuration defaults for originally generated Rails version.
+ config.load_defaults 7.1
+
+ # Please, add to the `ignore` list any other `lib` subdirectories that do
+ # not contain `.rb` files, or that should not be reloaded or eager loaded.
+ # Common ones are `templates`, `generators`, or `middleware`, for example.
+ config.autoload_lib(ignore: %w(assets tasks))
+
+ # Configuration for the application, engines, and railties goes here.
+ #
+ # These settings can be overridden in specific environments using the files
+ # in config/environments, which are processed later.
+ #
+ # config.time_zone = "Central Time (US & Canada)"
+ # config.eager_load_paths << Rails.root.join("extras")
+
+ # Don't generate system test files.
+ config.generators.system_tests = nil
+ end
+end
diff --git a/config/boot.rb b/config/boot.rb
new file mode 100644
index 0000000..988a5dd
--- /dev/null
+++ b/config/boot.rb
@@ -0,0 +1,4 @@
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+require "bundler/setup" # Set up gems listed in the Gemfile.
+require "bootsnap/setup" # Speed up boot time by caching expensive operations.
diff --git a/config/cable.yml b/config/cable.yml
new file mode 100644
index 0000000..c4e8350
--- /dev/null
+++ b/config/cable.yml
@@ -0,0 +1,10 @@
+development:
+ adapter: async
+
+test:
+ adapter: test
+
+production:
+ adapter: redis
+ url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
+ channel_prefix: flextentions_production
diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc
new file mode 100644
index 0000000..67fde49
--- /dev/null
+++ b/config/credentials.yml.enc
@@ -0,0 +1 @@
+3vroDXUwhiW0QKwPi+aCGnT/dpgAcHNKuimTpEYLpuA2f5Qrl9jO6CVb+rfhR/nqJ+vCAoJlkUyspQRuoI9pbPcHbYUuwSrr1sU6C1FMDToCwcMM7Eiciw+groww/b0L89PiQCrD/MhQZMArgNEhKD2wIRls33uMGUNYq2iw1H+G2156W3lgpAr9y96cdQBtY6a8e1WPa74TSdNZ6NmrVmhl2WMQ5WHZoZPMKdGVlolWKQH+FRVLJrxO/cuVXg4cP5AcxeDbJJqRYJ31grzKYa52WTvHp3DqKLdm2uaFxa2NpxtQEf3Kzr10X0Vcskhk5ZQl/RIoo0CQW/4WO22eqvLanHXnETr32FfKbuBxuUC4J72ph88W+IUjoTh/MkHi9ixrEWmBio6S3BOFU2fieUwypUre--ZvlZOImv6FGhJFMV--YjAJhG+nrWIhnihrxgT3tw==
\ No newline at end of file
diff --git a/config/cucumber.yml b/config/cucumber.yml
new file mode 100644
index 0000000..47a4663
--- /dev/null
+++ b/config/cucumber.yml
@@ -0,0 +1,8 @@
+<%
+rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
+rerun = rerun.strip.gsub /\s/, ' '
+rerun_opts = rerun.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
+std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags 'not @wip'"
+%>
+default: <%= std_opts %> features
+rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags 'not @wip'
diff --git a/config/database.yml b/config/database.yml
new file mode 100644
index 0000000..796466b
--- /dev/null
+++ b/config/database.yml
@@ -0,0 +1,25 @@
+# SQLite. Versions 3.8.0 and up are supported.
+# gem install sqlite3
+#
+# Ensure the SQLite 3 gem is defined in your Gemfile
+# gem "sqlite3"
+#
+default: &default
+ adapter: sqlite3
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ timeout: 5000
+
+development:
+ <<: *default
+ database: storage/development.sqlite3
+
+# Warning: The database defined as "test" will be erased and
+# re-generated from your development database when you run "rake".
+# Do not set this db to the same as development or production.
+test:
+ <<: *default
+ database: storage/test.sqlite3
+
+production:
+ <<: *default
+ database: storage/production.sqlite3
diff --git a/config/environment.rb b/config/environment.rb
new file mode 100644
index 0000000..cac5315
--- /dev/null
+++ b/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the Rails application.
+require_relative "application"
+
+# Initialize the Rails application.
+Rails.application.initialize!
diff --git a/config/environments/development.rb b/config/environments/development.rb
new file mode 100644
index 0000000..f4a7fc5
--- /dev/null
+++ b/config/environments/development.rb
@@ -0,0 +1,80 @@
+require "active_support/core_ext/integer/time"
+
+Rails.application.configure do
+ # Configure 'rails notes' to inspect Cucumber files
+ config.annotations.register_directories('features')
+ config.annotations.register_extensions('feature') { |tag| /#\s*(#{tag}):?\s*(.*)$/ }
+
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # In the development environment your application's code is reloaded any time
+ # it changes. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.enable_reloading = true
+
+ # Do not eager load code on boot.
+ config.eager_load = false
+
+ # Show full error reports.
+ config.consider_all_requests_local = true
+
+ # Enable server timing
+ config.server_timing = true
+
+ # Enable/disable caching. By default caching is disabled.
+ # Run rails dev:cache to toggle caching.
+ if Rails.root.join("tmp/caching-dev.txt").exist?
+ config.action_controller.perform_caching = true
+ config.action_controller.enable_fragment_cache_logging = true
+
+ config.cache_store = :memory_store
+ config.public_file_server.headers = {
+ "Cache-Control" => "public, max-age=#{2.days.to_i}"
+ }
+ else
+ config.action_controller.perform_caching = false
+
+ config.cache_store = :null_store
+ end
+
+ # Store uploaded files on the local file system (see config/storage.yml for options).
+ config.active_storage.service = :local
+
+ # Don't care if the mailer can't send.
+ config.action_mailer.raise_delivery_errors = false
+
+ config.action_mailer.perform_caching = false
+
+ # Print deprecation notices to the Rails logger.
+ config.active_support.deprecation = :log
+
+ # Raise exceptions for disallowed deprecations.
+ config.active_support.disallowed_deprecation = :raise
+
+ # Tell Active Support which deprecation messages to disallow.
+ config.active_support.disallowed_deprecation_warnings = []
+
+ # Raise an error on page load if there are pending migrations.
+ config.active_record.migration_error = :page_load
+
+ # Highlight code that triggered database queries in logs.
+ config.active_record.verbose_query_logs = true
+
+ # Highlight code that enqueued background job in logs.
+ config.active_job.verbose_enqueue_logs = true
+
+ # Suppress logger output for asset requests.
+ config.assets.quiet = true
+
+ # Raises error for missing translations.
+ # config.i18n.raise_on_missing_translations = true
+
+ # Annotate rendered view with file names.
+ # config.action_view.annotate_rendered_view_with_filenames = true
+
+ # Uncomment if you wish to allow Action Cable access from any origin.
+ # config.action_cable.disable_request_forgery_protection = true
+
+ # Raise error when a before_action's only/except options reference missing actions
+ config.action_controller.raise_on_missing_callback_actions = true
+end
diff --git a/config/environments/production.rb b/config/environments/production.rb
new file mode 100644
index 0000000..5c2f34c
--- /dev/null
+++ b/config/environments/production.rb
@@ -0,0 +1,97 @@
+require "active_support/core_ext/integer/time"
+
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # Code is not reloaded between requests.
+ config.enable_reloading = false
+
+ # Eager load code on boot. This eager loads most of Rails and
+ # your application in memory, allowing both threaded web servers
+ # and those relying on copy on write to perform better.
+ # Rake tasks automatically ignore this option for performance.
+ config.eager_load = true
+
+ # Full error reports are disabled and caching is turned on.
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
+ # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
+ # config.require_master_key = true
+
+ # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
+ # config.public_file_server.enabled = false
+
+ # Compress CSS using a preprocessor.
+ # config.assets.css_compressor = :sass
+
+ # Do not fall back to assets pipeline if a precompiled asset is missed.
+ config.assets.compile = false
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
+ # config.asset_host = "http://assets.example.com"
+
+ # Specifies the header that your server uses for sending files.
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
+ # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
+
+ # Store uploaded files on the local file system (see config/storage.yml for options).
+ config.active_storage.service = :local
+
+ # Mount Action Cable outside main process or domain.
+ # config.action_cable.mount_path = nil
+ # config.action_cable.url = "wss://example.com/cable"
+ # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ]
+
+ # Assume all access to the app is happening through a SSL-terminating reverse proxy.
+ # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
+ # config.assume_ssl = true
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ config.force_ssl = true
+
+ # Log to STDOUT by default
+ config.logger = ActiveSupport::Logger.new(STDOUT)
+ .tap { |logger| logger.formatter = ::Logger::Formatter.new }
+ .then { |logger| ActiveSupport::TaggedLogging.new(logger) }
+
+ # Prepend all log lines with the following tags.
+ config.log_tags = [ :request_id ]
+
+ # "info" includes generic and useful information about system operation, but avoids logging too much
+ # information to avoid inadvertent exposure of personally identifiable information (PII). If you
+ # want to log everything, set the level to "debug".
+ config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
+
+ # Use a different cache store in production.
+ # config.cache_store = :mem_cache_store
+
+ # Use a real queuing backend for Active Job (and separate queues per environment).
+ # config.active_job.queue_adapter = :resque
+ # config.active_job.queue_name_prefix = "flextentions_production"
+
+ config.action_mailer.perform_caching = false
+
+ # Ignore bad email addresses and do not raise email delivery errors.
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation cannot be found).
+ config.i18n.fallbacks = true
+
+ # Don't log any deprecations.
+ config.active_support.report_deprecations = false
+
+ # Do not dump schema after migrations.
+ config.active_record.dump_schema_after_migration = false
+
+ # Enable DNS rebinding protection and other `Host` header attacks.
+ # config.hosts = [
+ # "example.com", # Allow requests from example.com
+ # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
+ # ]
+ # Skip DNS rebinding protection for the default health check endpoint.
+ # config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
+end
diff --git a/config/environments/test.rb b/config/environments/test.rb
new file mode 100644
index 0000000..fdf88c0
--- /dev/null
+++ b/config/environments/test.rb
@@ -0,0 +1,68 @@
+require "active_support/core_ext/integer/time"
+
+# The test environment is used exclusively to run your application's
+# test suite. You never need to work with it otherwise. Remember that
+# your test database is "scratch space" for the test suite and is wiped
+# and recreated between test runs. Don't rely on the data there!
+
+Rails.application.configure do
+ # Configure 'rails notes' to inspect Cucumber files
+ config.annotations.register_directories('features')
+ config.annotations.register_extensions('feature') { |tag| /#\s*(#{tag}):?\s*(.*)$/ }
+
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # While tests run files are not watched, reloading is not necessary.
+ config.enable_reloading = false
+
+ # Eager loading loads your entire application. When running a single test locally,
+ # this is usually not necessary, and can slow down your test suite. However, it's
+ # recommended that you enable it in continuous integration systems to ensure eager
+ # loading is working properly before deploying your code.
+ config.eager_load = ENV["CI"].present?
+
+ # Configure public file server for tests with Cache-Control for performance.
+ config.public_file_server.enabled = true
+ config.public_file_server.headers = {
+ "Cache-Control" => "public, max-age=#{1.hour.to_i}"
+ }
+
+ # Show full error reports and disable caching.
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+ config.cache_store = :null_store
+
+ # Render exception templates for rescuable exceptions and raise for other exceptions.
+ config.action_dispatch.show_exceptions = :rescuable
+
+ # Disable request forgery protection in test environment.
+ config.action_controller.allow_forgery_protection = false
+
+ # Store uploaded files on the local file system in a temporary directory.
+ config.active_storage.service = :test
+
+ config.action_mailer.perform_caching = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Print deprecation notices to the stderr.
+ config.active_support.deprecation = :stderr
+
+ # Raise exceptions for disallowed deprecations.
+ config.active_support.disallowed_deprecation = :raise
+
+ # Tell Active Support which deprecation messages to disallow.
+ config.active_support.disallowed_deprecation_warnings = []
+
+ # Raises error for missing translations.
+ # config.i18n.raise_on_missing_translations = true
+
+ # Annotate rendered view with file names.
+ # config.action_view.annotate_rendered_view_with_filenames = true
+
+ # Raise error when a before_action's only/except options reference missing actions
+ config.action_controller.raise_on_missing_callback_actions = true
+end
diff --git a/config/importmap.rb b/config/importmap.rb
new file mode 100644
index 0000000..909dfc5
--- /dev/null
+++ b/config/importmap.rb
@@ -0,0 +1,7 @@
+# Pin npm packages by running ./bin/importmap
+
+pin "application"
+pin "@hotwired/turbo-rails", to: "turbo.min.js"
+pin "@hotwired/stimulus", to: "stimulus.min.js"
+pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
+pin_all_from "app/javascript/controllers", under: "controllers"
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
new file mode 100644
index 0000000..2eeef96
--- /dev/null
+++ b/config/initializers/assets.rb
@@ -0,0 +1,12 @@
+# Be sure to restart your server when you modify this file.
+
+# Version of your assets, change this if you want to expire all your assets.
+Rails.application.config.assets.version = "1.0"
+
+# Add additional assets to the asset load path.
+# Rails.application.config.assets.paths << Emoji.images_path
+
+# Precompile additional assets.
+# application.js, application.css, and all non-JS/CSS in the app/assets
+# folder are already added.
+# Rails.application.config.assets.precompile += %w( admin.js admin.css )
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
new file mode 100644
index 0000000..b3076b3
--- /dev/null
+++ b/config/initializers/content_security_policy.rb
@@ -0,0 +1,25 @@
+# Be sure to restart your server when you modify this file.
+
+# Define an application-wide content security policy.
+# See the Securing Rails Applications Guide for more information:
+# https://guides.rubyonrails.org/security.html#content-security-policy-header
+
+# Rails.application.configure do
+# config.content_security_policy do |policy|
+# policy.default_src :self, :https
+# policy.font_src :self, :https, :data
+# policy.img_src :self, :https, :data
+# policy.object_src :none
+# policy.script_src :self, :https
+# policy.style_src :self, :https
+# # Specify URI for violation reports
+# # policy.report_uri "/csp-violation-report-endpoint"
+# end
+#
+# # Generate session nonces for permitted importmap, inline scripts, and inline styles.
+# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
+# config.content_security_policy_nonce_directives = %w(script-src style-src)
+#
+# # Report violations without enforcing the policy.
+# # config.content_security_policy_report_only = true
+# end
diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb
new file mode 100644
index 0000000..c2d89e2
--- /dev/null
+++ b/config/initializers/filter_parameter_logging.rb
@@ -0,0 +1,8 @@
+# Be sure to restart your server when you modify this file.
+
+# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
+# Use this to limit dissemination of sensitive information.
+# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
+Rails.application.config.filter_parameters += [
+ :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
+]
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
new file mode 100644
index 0000000..3860f65
--- /dev/null
+++ b/config/initializers/inflections.rb
@@ -0,0 +1,16 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format. Inflections
+# are locale specific, and you may define rules for as many different
+# locales as you wish. All of these examples are active by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.plural /^(ox)$/i, "\\1en"
+# inflect.singular /^(ox)en/i, "\\1"
+# inflect.irregular "person", "people"
+# inflect.uncountable %w( fish sheep )
+# end
+
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.acronym "RESTful"
+# end
diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb
new file mode 100644
index 0000000..7db3b95
--- /dev/null
+++ b/config/initializers/permissions_policy.rb
@@ -0,0 +1,13 @@
+# Be sure to restart your server when you modify this file.
+
+# Define an application-wide HTTP permissions policy. For further
+# information see: https://developers.google.com/web/updates/2018/06/feature-policy
+
+# Rails.application.config.permissions_policy do |policy|
+# policy.camera :none
+# policy.gyroscope :none
+# policy.microphone :none
+# policy.usb :none
+# policy.fullscreen :self
+# policy.payment :self, "https://secure.example.com"
+# end
diff --git a/config/locales/en.yml b/config/locales/en.yml
new file mode 100644
index 0000000..6c349ae
--- /dev/null
+++ b/config/locales/en.yml
@@ -0,0 +1,31 @@
+# Files in the config/locales directory are used for internationalization and
+# are automatically loaded by Rails. If you want to use locales other than
+# English, add the necessary files in this directory.
+#
+# To use the locales, use `I18n.t`:
+#
+# I18n.t "hello"
+#
+# In views, this is aliased to just `t`:
+#
+# <%= t("hello") %>
+#
+# To use a different locale, set it with `I18n.locale`:
+#
+# I18n.locale = :es
+#
+# This would use the information in config/locales/es.yml.
+#
+# To learn more about the API, please read the Rails Internationalization guide
+# at https://guides.rubyonrails.org/i18n.html.
+#
+# Be aware that YAML interprets the following case-insensitive strings as
+# booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings
+# must be quoted to be interpreted as strings. For example:
+#
+# en:
+# "yes": yup
+# enabled: "ON"
+
+en:
+ hello: "Hello world"
diff --git a/config/puma.rb b/config/puma.rb
new file mode 100644
index 0000000..afa809b
--- /dev/null
+++ b/config/puma.rb
@@ -0,0 +1,35 @@
+# This configuration file will be evaluated by Puma. The top-level methods that
+# are invoked here are part of Puma's configuration DSL. For more information
+# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html.
+
+# Puma can serve each request in a thread from an internal thread pool.
+# The `threads` method setting takes two numbers: a minimum and maximum.
+# Any libraries that use thread pools should be configured to match
+# the maximum value specified for Puma. Default is set to 5 threads for minimum
+# and maximum; this matches the default thread size of Active Record.
+max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
+min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
+threads min_threads_count, max_threads_count
+
+# Specifies that the worker count should equal the number of processors in production.
+if ENV["RAILS_ENV"] == "production"
+ require "concurrent-ruby"
+ worker_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count })
+ workers worker_count if worker_count > 1
+end
+
+# Specifies the `worker_timeout` threshold that Puma will use to wait before
+# terminating a worker in development environments.
+worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
+
+# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
+port ENV.fetch("PORT") { 3000 }
+
+# Specifies the `environment` that Puma will run in.
+environment ENV.fetch("RAILS_ENV") { "development" }
+
+# Specifies the `pidfile` that Puma will use.
+pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
+
+# Allow puma to be restarted by `bin/rails restart` command.
+plugin :tmp_restart
diff --git a/config/routes.rb b/config/routes.rb
new file mode 100644
index 0000000..a125ef0
--- /dev/null
+++ b/config/routes.rb
@@ -0,0 +1,10 @@
+Rails.application.routes.draw do
+ # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
+
+ # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
+ # Can be used by load balancers and uptime monitors to verify that the app is live.
+ get "up" => "rails/health#show", as: :rails_health_check
+
+ # Defines the root path route ("/")
+ # root "posts#index"
+end
diff --git a/config/storage.yml b/config/storage.yml
new file mode 100644
index 0000000..4942ab6
--- /dev/null
+++ b/config/storage.yml
@@ -0,0 +1,34 @@
+test:
+ service: Disk
+ root: <%= Rails.root.join("tmp/storage") %>
+
+local:
+ service: Disk
+ root: <%= Rails.root.join("storage") %>
+
+# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
+# amazon:
+# service: S3
+# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
+# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
+# region: us-east-1
+# bucket: your_own_bucket-<%= Rails.env %>
+
+# Remember not to checkin your GCS keyfile to a repository
+# google:
+# service: GCS
+# project: your_project
+# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
+# bucket: your_own_bucket-<%= Rails.env %>
+
+# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
+# microsoft:
+# service: AzureStorage
+# storage_account_name: your_account_name
+# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
+# container: your_container_name-<%= Rails.env %>
+
+# mirror:
+# service: Mirror
+# primary: local
+# mirrors: [ amazon, google, microsoft ]
diff --git a/db/seeds.rb b/db/seeds.rb
new file mode 100644
index 0000000..4fbd6ed
--- /dev/null
+++ b/db/seeds.rb
@@ -0,0 +1,9 @@
+# This file should ensure the existence of records required to run the application in every environment (production,
+# development, test). The code here should be idempotent so that it can be executed at any point in every environment.
+# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).
+#
+# Example:
+#
+# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name|
+# MovieGenre.find_or_create_by!(name: genre_name)
+# end
diff --git a/features/step_definitions/.keep b/features/step_definitions/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/features/step_definitions/web_steps.rb b/features/step_definitions/web_steps.rb
new file mode 100644
index 0000000..4d9aab6
--- /dev/null
+++ b/features/step_definitions/web_steps.rb
@@ -0,0 +1,254 @@
+# TL;DR: YOU SHOULD DELETE THIS FILE
+#
+# This file was generated by Cucumber-Rails and is only here to get you a head start
+# These step definitions are thin wrappers around the Capybara/Webrat API that lets you
+# visit pages, interact with widgets and make assertions about page content.
+#
+# If you use these step definitions as basis for your features you will quickly end up
+# with features that are:
+#
+# * Hard to maintain
+# * Verbose to read
+#
+# A much better approach is to write your own higher level step definitions, following
+# the advice in the following blog posts:
+#
+# * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
+# * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
+# * http://elabs.se/blog/15-you-re-cuking-it-wrong
+#
+
+
+require 'uri'
+require 'cgi'
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "selectors"))
+
+module WithinHelpers
+ def with_scope(locator)
+ locator ? within(*selector_for(locator)) { yield } : yield
+ end
+end
+World(WithinHelpers)
+
+# Single-line step scoper
+When /^(.*) within (.*[^:])$/ do |step, parent|
+ with_scope(parent) { When step }
+end
+
+# Multi-line step scoper
+When /^(.*) within (.*[^:]):$/ do |step, parent, table_or_string|
+ with_scope(parent) { When "#{step}:", table_or_string }
+end
+
+Given /^(?:|I )am on (.+)$/ do |page_name|
+ visit path_to(page_name)
+end
+
+When /^(?:|I )go to (.+)$/ do |page_name|
+ visit path_to(page_name)
+end
+
+When /^(?:|I )press "([^"]*)"$/ do |button|
+ click_button(button)
+end
+
+When /^(?:|I )follow "([^"]*)"$/ do |link|
+ click_link(link)
+end
+
+When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
+ fill_in(field, :with => value)
+end
+
+When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
+ fill_in(field, :with => value)
+end
+
+# Use this to fill in an entire form with data from a table. Example:
+#
+# When I fill in the following:
+# | Account Number | 5002 |
+# | Expiry date | 2009-11-01 |
+# | Note | Nice guy |
+# | Wants Email? | |
+#
+# TODO: Add support for checkbox, select or option
+# based on naming conventions.
+#
+When /^(?:|I )fill in the following:$/ do |fields|
+ fields.rows_hash.each do |name, value|
+ When %{I fill in "#{name}" with "#{value}"}
+ end
+end
+
+When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
+ select(value, :from => field)
+end
+
+When /^(?:|I )check "([^"]*)"$/ do |field|
+ check(field)
+end
+
+When /^(?:|I )uncheck "([^"]*)"$/ do |field|
+ uncheck(field)
+end
+
+When /^(?:|I )choose "([^"]*)"$/ do |field|
+ choose(field)
+end
+
+When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
+ attach_file(field, File.expand_path(path))
+end
+
+Then /^(?:|I )should see "([^"]*)"$/ do |text|
+ if page.respond_to? :should
+ page.should have_content(text)
+ else
+ assert page.has_content?(text)
+ end
+end
+
+Then /^(?:|I )should see \/([^\/]*)\/$/ do |regexp|
+ regexp = Regexp.new(regexp)
+
+ if page.respond_to? :should
+ page.should have_xpath('//*', :text => regexp)
+ else
+ assert page.has_xpath?('//*', :text => regexp)
+ end
+end
+
+Then /^(?:|I )should not see "([^"]*)"$/ do |text|
+ if page.respond_to? :should
+ page.should have_no_content(text)
+ else
+ assert page.has_no_content?(text)
+ end
+end
+
+Then /^(?:|I )should not see \/([^\/]*)\/$/ do |regexp|
+ regexp = Regexp.new(regexp)
+
+ if page.respond_to? :should
+ page.should have_no_xpath('//*', :text => regexp)
+ else
+ assert page.has_no_xpath?('//*', :text => regexp)
+ end
+end
+
+Then /^the "([^"]*)" field(?: within (.*))? should contain "([^"]*)"$/ do |field, parent, value|
+ with_scope(parent) do
+ field = find_field(field)
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
+ if field_value.respond_to? :should
+ field_value.should =~ /#{value}/
+ else
+ assert_match(/#{value}/, field_value)
+ end
+ end
+end
+
+Then /^the "([^"]*)" field(?: within (.*))? should not contain "([^"]*)"$/ do |field, parent, value|
+ with_scope(parent) do
+ field = find_field(field)
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
+ if field_value.respond_to? :should_not
+ field_value.should_not =~ /#{value}/
+ else
+ assert_no_match(/#{value}/, field_value)
+ end
+ end
+end
+
+Then /^the "([^"]*)" field should have the error "([^"]*)"$/ do |field, error_message|
+ element = find_field(field)
+ classes = element.find(:xpath, '..')[:class].split(' ')
+
+ form_for_input = element.find(:xpath, 'ancestor::form[1]')
+ using_formtastic = form_for_input[:class].include?('formtastic')
+ error_class = using_formtastic ? 'error' : 'field_with_errors'
+
+ if classes.respond_to? :should
+ classes.should include(error_class)
+ else
+ assert classes.include?(error_class)
+ end
+
+ if page.respond_to?(:should)
+ if using_formtastic
+ error_paragraph = element.find(:xpath, '../*[@class="inline-errors"][1]')
+ error_paragraph.should have_content(error_message)
+ else
+ page.should have_content("#{field.titlecase} #{error_message}")
+ end
+ else
+ if using_formtastic
+ error_paragraph = element.find(:xpath, '../*[@class="inline-errors"][1]')
+ assert error_paragraph.has_content?(error_message)
+ else
+ assert page.has_content?("#{field.titlecase} #{error_message}")
+ end
+ end
+end
+
+Then /^the "([^"]*)" field should have no error$/ do |field|
+ element = find_field(field)
+ classes = element.find(:xpath, '..')[:class].split(' ')
+ if classes.respond_to? :should
+ classes.should_not include('field_with_errors')
+ classes.should_not include('error')
+ else
+ assert !classes.include?('field_with_errors')
+ assert !classes.include?('error')
+ end
+end
+
+Then /^the "([^"]*)" checkbox(?: within (.*))? should be checked$/ do |label, parent|
+ with_scope(parent) do
+ field_checked = find_field(label)['checked']
+ if field_checked.respond_to? :should
+ field_checked.should be_true
+ else
+ assert field_checked
+ end
+ end
+end
+
+Then /^the "([^"]*)" checkbox(?: within (.*))? should not be checked$/ do |label, parent|
+ with_scope(parent) do
+ field_checked = find_field(label)['checked']
+ if field_checked.respond_to? :should
+ field_checked.should be_false
+ else
+ assert !field_checked
+ end
+ end
+end
+
+Then /^(?:|I )should be on (.+)$/ do |page_name|
+ current_path = URI.parse(current_url).path
+ if current_path.respond_to? :should
+ current_path.should == path_to(page_name)
+ else
+ assert_equal path_to(page_name), current_path
+ end
+end
+
+Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
+ query = URI.parse(current_url).query
+ actual_params = query ? CGI.parse(query) : {}
+ expected_params = {}
+ expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
+
+ if actual_params.respond_to? :should
+ actual_params.should == expected_params
+ else
+ assert_equal expected_params, actual_params
+ end
+end
+
+Then /^show me the page$/ do
+ save_and_open_page
+end
diff --git a/features/support/env.rb b/features/support/env.rb
new file mode 100644
index 0000000..3b97d14
--- /dev/null
+++ b/features/support/env.rb
@@ -0,0 +1,53 @@
+# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
+# It is recommended to regenerate this file in the future when you upgrade to a
+# newer version of cucumber-rails. Consider adding your own code to a new file
+# instead of editing this one. Cucumber will automatically load all features/**/*.rb
+# files.
+
+
+require 'cucumber/rails'
+
+# By default, any exception happening in your Rails application will bubble up
+# to Cucumber so that your scenario will fail. This is a different from how
+# your application behaves in the production environment, where an error page will
+# be rendered instead.
+#
+# Sometimes we want to override this default behaviour and allow Rails to rescue
+# exceptions and display an error page (just like when the app is running in production).
+# Typical scenarios where you want to do this is when you test your error pages.
+# There are two ways to allow Rails to rescue exceptions:
+#
+# 1) Tag your scenario (or feature) with @allow-rescue
+#
+# 2) Set the value below to true. Beware that doing this globally is not
+# recommended as it will mask a lot of errors for you!
+#
+ActionController::Base.allow_rescue = false
+
+# Remove/comment out the lines below if your app doesn't have a database.
+# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
+begin
+ DatabaseCleaner.strategy = :transaction
+rescue NameError
+ raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
+end
+
+# You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios.
+# See the DatabaseCleaner documentation for details. Example:
+#
+# Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do
+# # { except: [:widgets] } may not do what you expect here
+# # as Cucumber::Rails::Database.javascript_strategy overrides
+# # this setting.
+# DatabaseCleaner.strategy = :truncation
+# end
+#
+# Before('not @no-txn', 'not @selenium', 'not @culerity', 'not @celerity', 'not @javascript') do
+# DatabaseCleaner.strategy = :transaction
+# end
+#
+
+# Possible values are :truncation and :transaction
+# The :transaction strategy is faster, but might give you threading problems.
+# See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature
+Cucumber::Rails::Database.javascript_strategy = :truncation
diff --git a/features/support/paths.rb b/features/support/paths.rb
new file mode 100644
index 0000000..290543c
--- /dev/null
+++ b/features/support/paths.rb
@@ -0,0 +1,38 @@
+# TL;DR: YOU SHOULD DELETE THIS FILE
+#
+# This file is used by web_steps.rb, which you should also delete
+#
+# You have been warned
+module NavigationHelpers
+ # Maps a name to a path. Used by the
+ #
+ # When /^I go to (.+)$/ do |page_name|
+ #
+ # step definition in web_steps.rb
+ #
+ def path_to(page_name)
+ case page_name
+
+ when /^the home\s?page$/
+ '/'
+
+ # Add more mappings here.
+ # Here is an example that pulls values out of the Regexp:
+ #
+ # when /^(.*)'s profile page$/i
+ # user_profile_path(User.find_by_login($1))
+
+ else
+ begin
+ page_name =~ /^the (.*) page$/
+ path_components = $1.split(/\s+/)
+ self.send(path_components.push('path').join('_').to_sym)
+ rescue NoMethodError, ArgumentError
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
+ "Now, go and add a mapping in #{__FILE__}"
+ end
+ end
+ end
+end
+
+World(NavigationHelpers)
diff --git a/features/support/selectors.rb b/features/support/selectors.rb
new file mode 100644
index 0000000..33bebc1
--- /dev/null
+++ b/features/support/selectors.rb
@@ -0,0 +1,44 @@
+# TL;DR: YOU SHOULD DELETE THIS FILE
+#
+# This file is used by web_steps.rb, which you should also delete
+#
+# You have been warned
+module HtmlSelectorsHelpers
+ # Maps a name to a selector. Used primarily by the
+ #
+ # When /^(.+) within (.+)$/ do |step, scope|
+ #
+ # step definitions in web_steps.rb
+ #
+ def selector_for(locator)
+ case locator
+
+ when "the page"
+ "html > body"
+
+ # Add more mappings here.
+ # Here is an example that pulls values out of the Regexp:
+ #
+ # when /^the (notice|error|info) flash$/
+ # ".flash.#{$1}"
+
+ # You can also return an array to use a different selector
+ # type, like:
+ #
+ # when /the header/
+ # [:xpath, "//header"]
+
+ # This allows you to provide a quoted selector as the scope
+ # for "within" steps as was previously the default for the
+ # web steps:
+ when /^"(.+)"$/
+ $1
+
+ else
+ raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
+ "Now, go and add a mapping in #{__FILE__}"
+ end
+ end
+end
+
+World(HtmlSelectorsHelpers)
diff --git a/lib/assets/.keep b/lib/assets/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/lib/tasks/.keep b/lib/tasks/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake
new file mode 100644
index 0000000..0caa4d2
--- /dev/null
+++ b/lib/tasks/cucumber.rake
@@ -0,0 +1,69 @@
+# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
+# It is recommended to regenerate this file in the future when you upgrade to a
+# newer version of cucumber-rails. Consider adding your own code to a new file
+# instead of editing this one. Cucumber will automatically load all features/**/*.rb
+# files.
+
+
+unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
+
+vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
+$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
+
+begin
+ require 'cucumber/rake/task'
+
+ namespace :cucumber do
+ Cucumber::Rake::Task.new({ok: 'test:prepare'}, 'Run features that should pass') do |t|
+ t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'default'
+ end
+
+ Cucumber::Rake::Task.new({wip: 'test:prepare'}, 'Run features that are being worked on') do |t|
+ t.binary = vendored_cucumber_bin
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'wip'
+ end
+
+ Cucumber::Rake::Task.new({rerun: 'test:prepare'}, 'Record failing features and run only them if any exist') do |t|
+ t.binary = vendored_cucumber_bin
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'rerun'
+ end
+
+ desc 'Run all features'
+ task all: [:ok, :wip]
+
+ task :statsetup do
+ require 'rails/code_statistics'
+ ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features')
+ ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features')
+ end
+
+ end
+
+ desc 'Alias for cucumber:ok'
+ task cucumber: 'cucumber:ok'
+
+ task default: :cucumber
+
+ task features: :cucumber do
+ STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
+ end
+
+ # In case we don't have the generic Rails test:prepare hook, append a no-op task that we can depend upon.
+ task 'test:prepare' do
+ end
+
+ task stats: 'cucumber:statsetup'
+
+
+rescue LoadError
+ desc 'cucumber rake task not available (cucumber not installed)'
+ task :cucumber do
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
+ end
+end
+
+end
diff --git a/log/.keep b/log/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/public/404.html b/public/404.html
new file mode 100644
index 0000000..2be3af2
--- /dev/null
+++ b/public/404.html
@@ -0,0 +1,67 @@
+
+
+
+ The page you were looking for doesn't exist (404)
+
+
+
+
+
+
+
+
+
The page you were looking for doesn't exist.
+
You may have mistyped the address or the page may have moved.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/public/422.html b/public/422.html
new file mode 100644
index 0000000..c08eac0
--- /dev/null
+++ b/public/422.html
@@ -0,0 +1,67 @@
+
+
+
+ The change you wanted was rejected (422)
+
+
+
+
+
+
+
+
+
The change you wanted was rejected.
+
Maybe you tried to change something you didn't have access to.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/public/500.html b/public/500.html
new file mode 100644
index 0000000..78a030a
--- /dev/null
+++ b/public/500.html
@@ -0,0 +1,66 @@
+
+
+
+ We're sorry, but something went wrong (500)
+
+
+
+
+
+
+
+
+
We're sorry, but something went wrong.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png
new file mode 100644
index 0000000..e69de29
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
new file mode 100644
index 0000000..e69de29
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..e69de29
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..c19f78a
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1 @@
+# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
new file mode 100644
index 0000000..a15455f
--- /dev/null
+++ b/spec/rails_helper.rb
@@ -0,0 +1,65 @@
+# This file is copied to spec/ when you run 'rails generate rspec:install'
+require 'spec_helper'
+ENV['RAILS_ENV'] ||= 'test'
+require_relative '../config/environment'
+# Prevent database truncation if the environment is production
+abort("The Rails environment is running in production mode!") if Rails.env.production?
+require 'rspec/rails'
+# Add additional requires below this line. Rails is not loaded until this point!
+
+# Requires supporting ruby files with custom matchers and macros, etc, in
+# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
+# run as spec files by default. This means that files in spec/support that end
+# in _spec.rb will both be required and run as specs, causing the specs to be
+# run twice. It is recommended that you do not name files matching this glob to
+# end with _spec.rb. You can configure this pattern with the --pattern
+# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
+#
+# The following line is provided for convenience purposes. It has the downside
+# of increasing the boot-up time by auto-requiring all files in the support
+# directory. Alternatively, in the individual `*_spec.rb` files, manually
+# require only the support files necessary.
+#
+# Rails.root.glob('spec/support/**/*.rb').sort.each { |f| require f }
+
+# Checks for pending migrations and applies them before tests are run.
+# If you are not using ActiveRecord, you can remove these lines.
+begin
+ ActiveRecord::Migration.maintain_test_schema!
+rescue ActiveRecord::PendingMigrationError => e
+ abort e.to_s.strip
+end
+RSpec.configure do |config|
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
+ config.fixture_paths = [
+ Rails.root.join('spec/fixtures')
+ ]
+
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, remove the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = true
+
+ # You can uncomment this line to turn off ActiveRecord support entirely.
+ # config.use_active_record = false
+
+ # RSpec Rails can automatically mix in different behaviours to your tests
+ # based on their file location, for example enabling you to call `get` and
+ # `post` in specs under `spec/controllers`.
+ #
+ # You can disable this behaviour by removing the line below, and instead
+ # explicitly tag your specs with their type, e.g.:
+ #
+ # RSpec.describe UsersController, type: :controller do
+ # # ...
+ # end
+ #
+ # The different available types are documented in the features, such as in
+ # https://rspec.info/features/6-0/rspec-rails
+ config.infer_spec_type_from_file_location!
+
+ # Filter lines from Rails gems in backtraces.
+ config.filter_rails_from_backtrace!
+ # arbitrary gems may also be filtered via:
+ # config.filter_gems_from_backtrace("gem name")
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..327b58e
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,94 @@
+# This file was generated by the `rails generate rspec:install` command. Conventionally, all
+# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
+# The generated `.rspec` file contains `--require spec_helper` which will cause
+# this file to always be loaded, without a need to explicitly require it in any
+# files.
+#
+# Given that it is always loaded, you are encouraged to keep this file as
+# light-weight as possible. Requiring heavyweight dependencies from this file
+# will add to the boot time of your test suite on EVERY test run, even for an
+# individual file that may not need all of that loaded. Instead, consider making
+# a separate helper file that requires the additional dependencies and performs
+# the additional setup, and require it from the spec files that actually need
+# it.
+#
+# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+ # rspec-expectations config goes here. You can use an alternate
+ # assertion/expectation library such as wrong or the stdlib/minitest
+ # assertions if you prefer.
+ config.expect_with :rspec do |expectations|
+ # This option will default to `true` in RSpec 4. It makes the `description`
+ # and `failure_message` of custom matchers include text for helper methods
+ # defined using `chain`, e.g.:
+ # be_bigger_than(2).and_smaller_than(4).description
+ # # => "be bigger than 2 and smaller than 4"
+ # ...rather than:
+ # # => "be bigger than 2"
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ # rspec-mocks config goes here. You can use an alternate test double
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
+ config.mock_with :rspec do |mocks|
+ # Prevents you from mocking or stubbing a method that does not exist on
+ # a real object. This is generally recommended, and will default to
+ # `true` in RSpec 4.
+ mocks.verify_partial_doubles = true
+ end
+
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
+ # have no way to turn it off -- the option exists only for backwards
+ # compatibility in RSpec 3). It causes shared context metadata to be
+ # inherited by the metadata hash of host groups and examples, rather than
+ # triggering implicit auto-inclusion in groups with matching metadata.
+ config.shared_context_metadata_behavior = :apply_to_host_groups
+
+# The settings below are suggested to provide a good initial experience
+# with RSpec, but feel free to customize to your heart's content.
+=begin
+ # This allows you to limit a spec run to individual examples or groups
+ # you care about by tagging them with `:focus` metadata. When nothing
+ # is tagged with `:focus`, all examples get run. RSpec also provides
+ # aliases for `it`, `describe`, and `context` that include `:focus`
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
+ config.filter_run_when_matching :focus
+
+ # Allows RSpec to persist some state between runs in order to support
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
+ # you configure your source control system to ignore this file.
+ config.example_status_persistence_file_path = "spec/examples.txt"
+
+ # Limits the available syntax to the non-monkey patched syntax that is
+ # recommended. For more details, see:
+ # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/
+ config.disable_monkey_patching!
+
+ # Many RSpec users commonly either run the entire suite or an individual
+ # file, and it's useful to allow more verbose output when running an
+ # individual spec file.
+ if config.files_to_run.one?
+ # Use the documentation formatter for detailed output,
+ # unless a formatter has already been configured
+ # (e.g. via a command-line flag).
+ config.default_formatter = "doc"
+ end
+
+ # Print the 10 slowest examples and example groups at the
+ # end of the spec run, to help surface which specs are running
+ # particularly slow.
+ config.profile_examples = 10
+
+ # Run specs in random order to surface order dependencies. If you find an
+ # order dependency and want to debug it, you can fix the order by providing
+ # the seed, which is printed after each run.
+ # --seed 1234
+ config.order = :random
+
+ # Seed global randomization in this process using the `--seed` CLI option.
+ # Setting this allows you to use `--seed` to deterministically reproduce
+ # test failures related to randomization by passing the same `--seed` value
+ # as the one that triggered the failure.
+ Kernel.srand config.seed
+=end
+end
diff --git a/storage/.keep b/storage/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/tmp/.keep b/tmp/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/.keep b/vendor/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/javascript/.keep b/vendor/javascript/.keep
new file mode 100644
index 0000000..e69de29
From d9b08aeb59c7e4de0960b8dd25adfa66875fd795 Mon Sep 17 00:00:00 2001
From: Cynthia Xinyi Li <76521916+cynthia-lixinyi@users.noreply.github.com>
Date: Wed, 14 Feb 2024 23:28:10 -0800
Subject: [PATCH 002/155] Set CI workflow by creating main.yml
---
.github/workflows/main.yml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 .github/workflows/main.yml
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..17ad560
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,18 @@
+name: build
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - name: Install Ruby (3.3)
+ uses: actions/setup-ruby@v1
+ with:
+ ruby-version: 3.3.0
+ - name: Build and test with RSpec
+ run: |
+ gem install bundler
+ bundle install --jobs 4 --retry 3
+ bundle exec rspec
From a17a8fcf9ebec9640dd14658f803770a5a717432 Mon Sep 17 00:00:00 2001
From: Zzz212zzZ <2120020201@qq.com>
Date: Thu, 15 Feb 2024 10:37:20 -0800
Subject: [PATCH 003/155] feat: integrate Bootstrap for UI enhancements
---
Gemfile | 5 +++
Gemfile.lock | 31 +++++++++++++++++++
.../{application.css => application.scss} | 2 ++
3 files changed, 38 insertions(+)
rename app/assets/stylesheets/{application.css => application.scss} (97%)
diff --git a/Gemfile b/Gemfile
index a6a72fc..c613a41 100644
--- a/Gemfile
+++ b/Gemfile
@@ -44,6 +44,11 @@ gem "bootsnap", require: false
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"
+gem 'bootstrap', '~> 5.3.2'
+gem 'jquery-rails'
+gem 'sassc-rails', '~> 2.1' #dependency for bootstrap
+
+
group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ]
diff --git a/Gemfile.lock b/Gemfile.lock
index 6daf496..20147a8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -77,11 +77,16 @@ GEM
tzinfo (~> 2.0)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
+ autoprefixer-rails (10.4.16.0)
+ execjs (~> 2)
base64 (0.2.0)
bigdecimal (3.1.6)
bindex (0.8.1)
bootsnap (1.18.3)
msgpack (~> 1.2)
+ bootstrap (5.3.2)
+ autoprefixer-rails (>= 9.1.0)
+ popper_js (>= 2.11.8, < 3)
builder (3.2.4)
capybara (3.40.0)
addressable
@@ -141,6 +146,7 @@ GEM
drb (2.2.0)
ruby2_keywords
erubi (1.12.0)
+ execjs (2.9.1)
ffi (1.16.3)
formatador (1.1.0)
globalid (1.2.1)
@@ -172,6 +178,10 @@ GEM
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
+ jquery-rails (4.6.0)
+ rails-dom-testing (>= 1, < 3)
+ railties (>= 4.2.0)
+ thor (>= 0.14, < 2.0)
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
@@ -188,6 +198,7 @@ GEM
matrix (0.4.2)
method_source (1.0.0)
mini_mime (1.1.5)
+ mini_portile2 (2.8.5)
minitest (5.22.2)
msgpack (1.7.2)
multi_test (1.1.0)
@@ -211,6 +222,8 @@ GEM
racc (~> 1.4)
nokogiri (1.16.2-x86-linux)
racc (~> 1.4)
+ nokogiri (1.16.2-x86-mingw32)
+ racc (~> 1.4)
nokogiri (1.16.2-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.16.2-x86_64-linux)
@@ -218,6 +231,7 @@ GEM
notiffany (0.1.3)
nenv (~> 0.1)
shellany (~> 0.0)
+ popper_js (2.11.8)
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
@@ -295,6 +309,14 @@ GEM
rspec-support (~> 3.12)
rspec-support (3.13.0)
ruby2_keywords (0.0.5)
+ 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
shellany (0.0.1)
simplecov (0.22.0)
docile (~> 1.1)
@@ -309,6 +331,8 @@ GEM
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
+ sqlite3 (1.7.2)
+ mini_portile2 (~> 2.8.0)
sqlite3 (1.7.2-aarch64-linux)
sqlite3 (1.7.2-arm-linux)
sqlite3 (1.7.2-arm64-darwin)
@@ -321,6 +345,7 @@ GEM
sys-uname (1.2.3)
ffi (~> 1.1)
thor (1.3.0)
+ tilt (2.3.0)
timeout (0.4.1)
turbo-rails (2.0.0)
actionpack (>= 6.0.0)
@@ -328,6 +353,8 @@ GEM
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
+ tzinfo-data (1.2024.1)
+ tzinfo (>= 1.0.0)
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
@@ -346,11 +373,13 @@ PLATFORMS
arm-linux
arm64-darwin
x86-linux
+ x86-mingw32
x86_64-darwin
x86_64-linux
DEPENDENCIES
bootsnap
+ bootstrap (~> 5.3.2)
cucumber-rails
cucumber-rails-training-wheels
database_cleaner
@@ -358,9 +387,11 @@ DEPENDENCIES
guard-rspec
importmap-rails
jbuilder
+ jquery-rails
puma (>= 5.0)
rails (~> 7.1.3)
rspec-rails
+ sassc-rails (~> 2.1)
simplecov
sprockets-rails
sqlite3 (~> 1.4)
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.scss
similarity index 97%
rename from app/assets/stylesheets/application.css
rename to app/assets/stylesheets/application.scss
index 288b9ab..05c538d 100644
--- a/app/assets/stylesheets/application.css
+++ b/app/assets/stylesheets/application.scss
@@ -13,3 +13,5 @@
*= require_tree .
*= require_self
*/
+
+ @import "bootstrap";
\ No newline at end of file
From 4bee37f95b0fd87961f2e21fb464650de2b93c5c Mon Sep 17 00:00:00 2001
From: Cynthia Li
Date: Thu, 15 Feb 2024 13:19:05 -0800
Subject: [PATCH 004/155] Add CodeClimate maintainability and test coverage
badges to README.md file
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index a5c055e..6bb9bc4 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,4 @@
# flextensions
Back end/API for UC Berkeley EECS "Flextensions" software
+
+[](https://codeclimate.com/github/cs169/flextensions/maintainability) [](https://codeclimate.com/github/cs169/flextensions/test_coverage)
\ No newline at end of file
From 5494d8f9afb835a9587c26639fb58f1a87b591d0 Mon Sep 17 00:00:00 2001
From: Zzz212zzZ <2120020201@qq.com>
Date: Thu, 15 Feb 2024 19:10:51 -0800
Subject: [PATCH 005/155] feat: Integrate LMS API wrapper for Canvas
interaction
---
Gemfile | 13 +++++++++
Gemfile.lock | 28 +++++++++++++++++++
app/models/authentication.rb | 5 ++++
.../20240216023813_create_authentications.rb | 9 ++++++
db/schema.rb | 20 +++++++++++++
5 files changed, 75 insertions(+)
create mode 100644 app/models/authentication.rb
create mode 100644 db/migrate/20240216023813_create_authentications.rb
create mode 100644 db/schema.rb
diff --git a/Gemfile b/Gemfile
index a6a72fc..90b651a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -41,6 +41,16 @@ gem "tzinfo-data", platforms: %i[ windows jruby ]
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false
+gem 'sassc-rails', '~> 2.1'
+gem "lms-api"
+
+
+
+# Use Active Storage for file uploads [https://guides.rubyonrails.org/active_storage_overview.html]
+# gem "activestorage", "~> 7.0.0"
+
+# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible [
+
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"
@@ -61,6 +71,9 @@ end
group :development do
# Use console on exceptions pages [https://github.com/rails/web-console]
gem "web-console"
+
+ #for debug
+ gem 'byebug'
# Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
# gem "rack-mini-profiler"
diff --git a/Gemfile.lock b/Gemfile.lock
index 6daf496..a1ea65e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -83,6 +83,7 @@ GEM
bootsnap (1.18.3)
msgpack (~> 1.2)
builder (3.2.4)
+ byebug (11.1.3)
capybara (3.40.0)
addressable
matrix
@@ -159,6 +160,9 @@ GEM
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
+ httparty (0.21.0)
+ mini_mime (>= 1.0.0)
+ multi_xml (>= 0.5.2)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
importmap-rails (2.0.1)
@@ -175,6 +179,9 @@ GEM
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
+ lms-api (1.24.0)
+ activesupport (>= 3.0)
+ httparty
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
@@ -188,9 +195,11 @@ GEM
matrix (0.4.2)
method_source (1.0.0)
mini_mime (1.1.5)
+ mini_portile2 (2.8.5)
minitest (5.22.2)
msgpack (1.7.2)
multi_test (1.1.0)
+ multi_xml (0.6.0)
mutex_m (0.2.0)
nenv (0.3.0)
net-imap (0.4.10)
@@ -211,6 +220,8 @@ GEM
racc (~> 1.4)
nokogiri (1.16.2-x86-linux)
racc (~> 1.4)
+ nokogiri (1.16.2-x86-mingw32)
+ racc (~> 1.4)
nokogiri (1.16.2-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.16.2-x86_64-linux)
@@ -295,6 +306,14 @@ GEM
rspec-support (~> 3.12)
rspec-support (3.13.0)
ruby2_keywords (0.0.5)
+ 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
shellany (0.0.1)
simplecov (0.22.0)
docile (~> 1.1)
@@ -309,6 +328,8 @@ GEM
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
+ sqlite3 (1.7.2)
+ mini_portile2 (~> 2.8.0)
sqlite3 (1.7.2-aarch64-linux)
sqlite3 (1.7.2-arm-linux)
sqlite3 (1.7.2-arm64-darwin)
@@ -321,6 +342,7 @@ GEM
sys-uname (1.2.3)
ffi (~> 1.1)
thor (1.3.0)
+ tilt (2.3.0)
timeout (0.4.1)
turbo-rails (2.0.0)
actionpack (>= 6.0.0)
@@ -328,6 +350,8 @@ GEM
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
+ tzinfo-data (1.2024.1)
+ tzinfo (>= 1.0.0)
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
@@ -346,11 +370,13 @@ PLATFORMS
arm-linux
arm64-darwin
x86-linux
+ x86-mingw32
x86_64-darwin
x86_64-linux
DEPENDENCIES
bootsnap
+ byebug
cucumber-rails
cucumber-rails-training-wheels
database_cleaner
@@ -358,9 +384,11 @@ DEPENDENCIES
guard-rspec
importmap-rails
jbuilder
+ lms-api
puma (>= 5.0)
rails (~> 7.1.3)
rspec-rails
+ sassc-rails (~> 2.1)
simplecov
sprockets-rails
sqlite3 (~> 1.4)
diff --git a/app/models/authentication.rb b/app/models/authentication.rb
new file mode 100644
index 0000000..ec84c12
--- /dev/null
+++ b/app/models/authentication.rb
@@ -0,0 +1,5 @@
+class Authentication < ApplicationRecord
+ def access_token
+ self.bcourse_token
+ end
+end
\ No newline at end of file
diff --git a/db/migrate/20240216023813_create_authentications.rb b/db/migrate/20240216023813_create_authentications.rb
new file mode 100644
index 0000000..fe5eea6
--- /dev/null
+++ b/db/migrate/20240216023813_create_authentications.rb
@@ -0,0 +1,9 @@
+class CreateAuthentications < ActiveRecord::Migration[7.1]
+ def change
+ create_table :authentications do |t|
+ t.string :bcourse_token
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000..eb77018
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,20 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `bin/rails
+# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema[7.1].define(version: 2024_02_16_023813) do
+ create_table "authentications", force: :cascade do |t|
+ t.string "bcourse_token"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+end
From 4f54d663c8693400ece0c24aa3f4eacd3cfe2446 Mon Sep 17 00:00:00 2001
From: Zzz212zzZ <2120020201@qq.com>
Date: Thu, 15 Feb 2024 19:13:02 -0800
Subject: [PATCH 006/155] feat: Add BCourses controller and view for course
listing (/bcourses)
---
app/controllers/bcourses_controller.rb | 18 ++++++++++++++++++
app/helpers/bcourses_helper.rb | 2 ++
app/views/bcourses/index.html.erb | 11 +++++++++++
config/routes.rb | 2 ++
4 files changed, 33 insertions(+)
create mode 100644 app/controllers/bcourses_controller.rb
create mode 100644 app/helpers/bcourses_helper.rb
create mode 100644 app/views/bcourses/index.html.erb
diff --git a/app/controllers/bcourses_controller.rb b/app/controllers/bcourses_controller.rb
new file mode 100644
index 0000000..acdd0bb
--- /dev/null
+++ b/app/controllers/bcourses_controller.rb
@@ -0,0 +1,18 @@
+class BcoursesController < ApplicationController
+ require 'lms_api'
+
+ def index
+ auth = Authentication.first
+ canvas_url = "https://bcourses.berkeley.edu"
+
+ # Assuming LMS::Canvas.new expects a token directly. Adjust as needed for actual API wrapper usage.
+ api = LMS::Canvas.new(canvas_url, auth.access_token)
+
+ # byebug
+ # Fetch courses list
+ courses_url = "#{canvas_url}/api/v1/courses"
+ @courses = api.api_get_request(courses_url)
+ rescue StandardError => e
+ @error = "Failed to fetch courses: #{e.message}"
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/bcourses_helper.rb b/app/helpers/bcourses_helper.rb
new file mode 100644
index 0000000..cf1ce1c
--- /dev/null
+++ b/app/helpers/bcourses_helper.rb
@@ -0,0 +1,2 @@
+module BcoursesHelper
+end
diff --git a/app/views/bcourses/index.html.erb b/app/views/bcourses/index.html.erb
new file mode 100644
index 0000000..889b529
--- /dev/null
+++ b/app/views/bcourses/index.html.erb
@@ -0,0 +1,11 @@
+Canvas Courses
+
+<% if @error %>
+ Error: <%= @error %>
+<% else %>
+
+ <% @courses.each do |course| %>
+ - <%= course['name'] %>
+ <% end %>
+
+<% end %>
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index a125ef0..97ece4d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,4 +1,6 @@
Rails.application.routes.draw do
+ get 'bcourses/index'
+ get 'bcourses', to: 'bcourses#index'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
From cb18cb12895e7660d4530b5d6dfcf3d93bc07d82 Mon Sep 17 00:00:00 2001
From: Zzz212zzZ <2120020201@qq.com>
Date: Thu, 15 Feb 2024 22:46:04 -0800
Subject: [PATCH 007/155] feat: Securely store BCourse Dev API Token using
Rails credentials
---
.gitignore | 4 ++++
app/controllers/bcourses_controller.rb | 3 ++-
config/credentials.yml.enc | 2 +-
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
index c55bb71..1cb38ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,3 +67,7 @@ yarn-debug.log*
/storage/*
!/storage/.keep
/public/uploads
+
+/config/master.key
+
+/config/credentials/production.key
diff --git a/app/controllers/bcourses_controller.rb b/app/controllers/bcourses_controller.rb
index acdd0bb..08fa642 100644
--- a/app/controllers/bcourses_controller.rb
+++ b/app/controllers/bcourses_controller.rb
@@ -6,7 +6,8 @@ def index
canvas_url = "https://bcourses.berkeley.edu"
# Assuming LMS::Canvas.new expects a token directly. Adjust as needed for actual API wrapper usage.
- api = LMS::Canvas.new(canvas_url, auth.access_token)
+ canvas_api_key = Rails.application.credentials.dig(:development, :canvas, :dev_api_key) # this will be obtained from omniauth in later iterations
+ api = LMS::Canvas.new(canvas_url, canvas_api_key)
# byebug
# Fetch courses list
diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc
index 67fde49..060d058 100644
--- a/config/credentials.yml.enc
+++ b/config/credentials.yml.enc
@@ -1 +1 @@
-3vroDXUwhiW0QKwPi+aCGnT/dpgAcHNKuimTpEYLpuA2f5Qrl9jO6CVb+rfhR/nqJ+vCAoJlkUyspQRuoI9pbPcHbYUuwSrr1sU6C1FMDToCwcMM7Eiciw+groww/b0L89PiQCrD/MhQZMArgNEhKD2wIRls33uMGUNYq2iw1H+G2156W3lgpAr9y96cdQBtY6a8e1WPa74TSdNZ6NmrVmhl2WMQ5WHZoZPMKdGVlolWKQH+FRVLJrxO/cuVXg4cP5AcxeDbJJqRYJ31grzKYa52WTvHp3DqKLdm2uaFxa2NpxtQEf3Kzr10X0Vcskhk5ZQl/RIoo0CQW/4WO22eqvLanHXnETr32FfKbuBxuUC4J72ph88W+IUjoTh/MkHi9ixrEWmBio6S3BOFU2fieUwypUre--ZvlZOImv6FGhJFMV--YjAJhG+nrWIhnihrxgT3tw==
\ No newline at end of file
+3mXBTuTQTuce/izO1v4GA6xZPNt9wtlU83nGqRHUnQDlURF44/7D9pKoBc9OLr2pW1/oBH8Qk71TQUG5t3XAqLDH4OTbbQy49KCg12EHyhg9lUhPeMbGp17nvKA3YSAhMUYhztkTwU4/+Ox7qJAxbNblmHxj9f+w+BML4pCMQTSUM31m3SQLvsi+6Ab8mY888XWOoBK3qxW58KAgnFbXr1/gyVyEntrI6M+OUtBYx9t17s108KJy72K0+sgU+/ZWvLXDqjigWLv0Y68lziUX0jgiF8MR13LEH/qfJfsLTAti3geSP9m311GsxUYem70DJ2HMXWFM9DNfcNTx4yv8RaW+5RTS03DS6Z+ElZjR6aoOztY4j4Dgae+VMlarVdoxbHf2yc74ljvL2lHn5nvemodT0mYN6/T71aw0+41utodTKhA79DwhBiPJgbKc1AIbaJU54QXBVIdpZ6CF0A4JB4G6PofKbNNEn67RfDXKPprfRV4MsjN9KouiRHCaZOQZn8cfGeqBklXV1BY6dKZUh0wMCXa1ZmoGLBasNdtFVGUeZwh4SJk=--MgSOib34au1Sef7j--VdjSl9KhoDYmTQ/Xedzdug==
\ No newline at end of file
From f0faef050b02cd5c336c1249325c05c5862c9bc0 Mon Sep 17 00:00:00 2001
From: Cynthia Xinyi Li <76521916+cynthia-lixinyi@users.noreply.github.com>
Date: Fri, 16 Feb 2024 10:28:52 -0800
Subject: [PATCH 008/155] Update main.yml
---
.github/workflows/main.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 17ad560..dbbcff7 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- - name: Install Ruby (3.3)
+ - name: Install Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: 3.3.0
From 392eaa670bbdd8d4dee85af346ccffa9d267621e Mon Sep 17 00:00:00 2001
From: Cynthia Xinyi Li <76521916+cynthia-lixinyi@users.noreply.github.com>
Date: Fri, 16 Feb 2024 10:31:51 -0800
Subject: [PATCH 009/155] Update main.yml
Try 3.2 and 3.2.3
---
.github/workflows/main.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index dbbcff7..3c784c8 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- - name: Install Ruby
+ - name: Install Ruby (3.2)
uses: actions/setup-ruby@v1
with:
- ruby-version: 3.3.0
+ ruby-version: 3.2.3
- name: Build and test with RSpec
run: |
gem install bundler
From e9ac65022bf0d4245ea9ea8b20bb01a0492f6ab9 Mon Sep 17 00:00:00 2001
From: Cynthia Xinyi Li <76521916+cynthia-lixinyi@users.noreply.github.com>
Date: Fri, 16 Feb 2024 10:32:36 -0800
Subject: [PATCH 010/155] Update main.yml
---
.github/workflows/main.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 3c784c8..3934406 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- - name: Install Ruby (3.2)
+ - name: Install Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: 3.2.3
From 9bd2705e07452477d16fa59b53b1bf1ab9d443bf Mon Sep 17 00:00:00 2001
From: Jeffro <87971517+Zzz212zzZ@users.noreply.github.com>
Date: Fri, 16 Feb 2024 19:31:34 -0800
Subject: [PATCH 011/155] fix: Set up CI
---
.github/workflows/main.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 3934406..1826cf5 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -8,9 +8,9 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Install Ruby
- uses: actions/setup-ruby@v1
+ uses: ruby/setup-ruby@v1
with:
- ruby-version: 3.2.3
+ ruby-version: 3.3.0
- name: Build and test with RSpec
run: |
gem install bundler
From 39ae8946a69a8b0b543862ad8853a0c4e2a67e83 Mon Sep 17 00:00:00 2001
From: Sepehr Behmanesh Fard
Date: Sat, 17 Feb 2024 19:03:37 -0800
Subject: [PATCH 012/155] Chore: removed actioncable and mailer
---
config/application.rb | 2 +-
config/environments/development.rb | 4 ++--
config/environments/production.rb | 2 +-
config/environments/test.rb | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/config/application.rb b/config/application.rb
index b1b8b31..041c362 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -7,7 +7,7 @@
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
-require "action_mailer/railtie"
+# require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
diff --git a/config/environments/development.rb b/config/environments/development.rb
index f4a7fc5..8f64d3a 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -41,9 +41,9 @@
config.active_storage.service = :local
# Don't care if the mailer can't send.
- config.action_mailer.raise_delivery_errors = false
+ # config.action_mailer.raise_delivery_errors = false
- config.action_mailer.perform_caching = false
+ # config.action_mailer.perform_caching = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 5c2f34c..0f626a2 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -71,7 +71,7 @@
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "flextentions_production"
- config.action_mailer.perform_caching = false
+ # config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
diff --git a/config/environments/test.rb b/config/environments/test.rb
index fdf88c0..9da3cdf 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -41,12 +41,12 @@
# Store uploaded files on the local file system in a temporary directory.
config.active_storage.service = :test
- config.action_mailer.perform_caching = false
+ # config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
- config.action_mailer.delivery_method = :test
+ # config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
From eca7c34a357da7849d61a1d67fe52b534129086a Mon Sep 17 00:00:00 2001
From: Sepehr Behmanesh Fard
Date: Sat, 17 Feb 2024 19:19:09 -0800
Subject: [PATCH 013/155] Revert "Chore: removed actioncable and mailer"
This reverts commit 39ae8946a69a8b0b543862ad8853a0c4e2a67e83.
---
config/application.rb | 2 +-
config/environments/development.rb | 4 ++--
config/environments/production.rb | 2 +-
config/environments/test.rb | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/config/application.rb b/config/application.rb
index 041c362..b1b8b31 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -7,7 +7,7 @@
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
-# require "action_mailer/railtie"
+require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 8f64d3a..f4a7fc5 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -41,9 +41,9 @@
config.active_storage.service = :local
# Don't care if the mailer can't send.
- # config.action_mailer.raise_delivery_errors = false
+ config.action_mailer.raise_delivery_errors = false
- # config.action_mailer.perform_caching = false
+ config.action_mailer.perform_caching = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 0f626a2..5c2f34c 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -71,7 +71,7 @@
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "flextentions_production"
- # config.action_mailer.perform_caching = false
+ config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 9da3cdf..fdf88c0 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -41,12 +41,12 @@
# Store uploaded files on the local file system in a temporary directory.
config.active_storage.service = :test
- # config.action_mailer.perform_caching = false
+ config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
- # config.action_mailer.delivery_method = :test
+ config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
From e1609e9f93c78a127010c2ca9dfc85df7926ecde Mon Sep 17 00:00:00 2001
From: Sepehr Behmanesh Fard
Date: Sat, 17 Feb 2024 19:33:56 -0800
Subject: [PATCH 014/155] Chore: turned off action mailer
---
config/application.rb | 2 +-
config/environments/development.rb | 4 ++--
config/environments/production.rb | 2 +-
config/environments/test.rb | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/config/application.rb b/config/application.rb
index b1b8b31..041c362 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -7,7 +7,7 @@
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
-require "action_mailer/railtie"
+# require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
diff --git a/config/environments/development.rb b/config/environments/development.rb
index f4a7fc5..8f64d3a 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -41,9 +41,9 @@
config.active_storage.service = :local
# Don't care if the mailer can't send.
- config.action_mailer.raise_delivery_errors = false
+ # config.action_mailer.raise_delivery_errors = false
- config.action_mailer.perform_caching = false
+ # config.action_mailer.perform_caching = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 5c2f34c..0f626a2 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -71,7 +71,7 @@
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "flextentions_production"
- config.action_mailer.perform_caching = false
+ # config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
diff --git a/config/environments/test.rb b/config/environments/test.rb
index fdf88c0..9da3cdf 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -41,12 +41,12 @@
# Store uploaded files on the local file system in a temporary directory.
config.active_storage.service = :test
- config.action_mailer.perform_caching = false
+ # config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
- config.action_mailer.delivery_method = :test
+ # config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
From 4ee789e15efa866b9fd3ba95e4bddb6b3294fe2d Mon Sep 17 00:00:00 2001
From: Connor Bernard
Date: Tue, 20 Feb 2024 00:45:51 +0000
Subject: [PATCH 015/155] chore: add pr template
---
.github/pull_request_template.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 .github/pull_request_template.md
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..03584b3
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,20 @@
+# General Info
+
+- [Pivotal Tracker Story](https://www.pivotaltracker.com/story/show/########)
+- [ ] Breaking?
+
+# Changes
+
+Explain your changes here (in such a way that you would understand why you made them a year from now).
+
+# Testing
+
+Explain how you tested your changes. If testing is not necessary, explain why.
+
+# Documentation
+
+Does this PR require documentation. If so, explain where it can be found.
+
+# Checklist
+
+- [ ] Name of branch corresponds to story
From 46e28b83b1b448c8ef73a5719e4e8e8633525c56 Mon Sep 17 00:00:00 2001
From: Connor Bernard
Date: Tue, 20 Feb 2024 04:12:44 +0000
Subject: [PATCH 016/155] feat!: configure app to use pg in all environments
---
Gemfile | 5 ++---
Gemfile.lock | 13 +++----------
config/database.yml | 32 ++++++++++++++++++++------------
db/schema.rb | 17 +++++++++++++++++
4 files changed, 42 insertions(+), 25 deletions(-)
create mode 100644 db/schema.rb
diff --git a/Gemfile b/Gemfile
index c613a41..bb5f50e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -8,8 +8,8 @@ gem "rails", "~> 7.1.3"
# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"
-# Use sqlite3 as the database for Active Record
-gem "sqlite3", "~> 1.4"
+# Use postgres for all env dbs
+gem "pg"
# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"
@@ -73,4 +73,3 @@ group :development do
# Speed up commands on slow machines / big apps [https://github.com/rails/spring]
# gem "spring"
end
-
diff --git a/Gemfile.lock b/Gemfile.lock
index 20147a8..bcf2447 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -198,7 +198,6 @@ GEM
matrix (0.4.2)
method_source (1.0.0)
mini_mime (1.1.5)
- mini_portile2 (2.8.5)
minitest (5.22.2)
msgpack (1.7.2)
multi_test (1.1.0)
@@ -231,6 +230,8 @@ GEM
notiffany (0.1.3)
nenv (~> 0.1)
shellany (~> 0.0)
+ pg (1.5.5)
+ pg (1.5.5-x86-mingw32)
popper_js (2.11.8)
pry (0.14.2)
coderay (~> 1.1)
@@ -331,14 +332,6 @@ GEM
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
- sqlite3 (1.7.2)
- mini_portile2 (~> 2.8.0)
- sqlite3 (1.7.2-aarch64-linux)
- sqlite3 (1.7.2-arm-linux)
- sqlite3 (1.7.2-arm64-darwin)
- sqlite3 (1.7.2-x86-linux)
- sqlite3 (1.7.2-x86_64-darwin)
- sqlite3 (1.7.2-x86_64-linux)
stimulus-rails (1.3.3)
railties (>= 6.0.0)
stringio (3.1.0)
@@ -388,13 +381,13 @@ DEPENDENCIES
importmap-rails
jbuilder
jquery-rails
+ pg
puma (>= 5.0)
rails (~> 7.1.3)
rspec-rails
sassc-rails (~> 2.1)
simplecov
sprockets-rails
- sqlite3 (~> 1.4)
stimulus-rails
turbo-rails
tzinfo-data
diff --git a/config/database.yml b/config/database.yml
index 796466b..660574a 100644
--- a/config/database.yml
+++ b/config/database.yml
@@ -1,25 +1,33 @@
-# SQLite. Versions 3.8.0 and up are supported.
-# gem install sqlite3
-#
-# Ensure the SQLite 3 gem is defined in your Gemfile
-# gem "sqlite3"
-#
default: &default
- adapter: sqlite3
- pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ adapter: postgresql
+ pool: 5
timeout: 5000
+ host: localhost
+ port: <%= ENV['DB_PORT'] || '5432' %>
+ username: <%= ENV['DB_USER'] || ENV['USER'] || 'postgres' %>
+ password: <%= ENV['DB_PASSWORD'] || 'password' %>
+ database: <%= ENV['DB_NAME'] || 'postgres' %>
development:
<<: *default
- database: storage/development.sqlite3
+ database: flextentions_dev
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
- database: storage/test.sqlite3
+ database: flextentions_test
+staging:
+ adapter: postgresql
+ pool: 5
+ timeout: 5000
+ database: flextentions_stage
+
+# MAKE SURE THE ENVIRONMENT CONFIG IS SET UP FOR PROD
production:
- <<: *default
- database: storage/production.sqlite3
+ adapter: postgresql
+ pool: 5
+ timeout: 5000
+ database: flextentions_prod
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000..f913998
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,17 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `bin/rails
+# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema[7.1].define(version: 0) do
+ # These are extensions that must be enabled in order to support this database
+ enable_extension "plpgsql"
+
+end
From a1ef43c612e1bb3d29a4ec7cffc72a3f313e4192 Mon Sep 17 00:00:00 2001
From: Connor Bernard
Date: Tue, 20 Feb 2024 04:17:22 +0000
Subject: [PATCH 017/155] chore: make standing up with env through overmind
easy
---
Makefile | 2 ++
Procfile.dev | 1 +
bin.lock | 1 +
bin/overmind | Bin 0 -> 3837952 bytes
package.json | 13 +++++++++++++
yarn.lock | 4 ++++
6 files changed, 21 insertions(+)
create mode 100644 Makefile
create mode 100644 Procfile.dev
create mode 100644 bin.lock
create mode 100755 bin/overmind
create mode 100644 package.json
create mode 100644 yarn.lock
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2c23972
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+dev:
+ @yarn run dev
diff --git a/Procfile.dev b/Procfile.dev
new file mode 100644
index 0000000..f6a9573
--- /dev/null
+++ b/Procfile.dev
@@ -0,0 +1 @@
+web: bundle exec rails s -p 3000
diff --git a/bin.lock b/bin.lock
new file mode 100644
index 0000000..8092b78
--- /dev/null
+++ b/bin.lock
@@ -0,0 +1 @@
+overmind (= 2.4.0)
diff --git a/bin/overmind b/bin/overmind
new file mode 100755
index 0000000000000000000000000000000000000000..4c7319fcaf8c2f8af16b3c020888bbbd1b35bb95
GIT binary patch
literal 3837952
zcmeFad3;k<`ahnOL{dn-K?4L0kV?=L3$|Ldk)i>LR;^BTilTND6&V~+8Eiluz(QK+
z^>Uq#intFt&WziPejG(`?E;j=g@P!HY_2B;1!1IRk^bKAb8nV5MQ1+W&+GS>eZ88y
zoO7P@Z09-8dCqe08B=<`)oQiG|1vDyEPUG2(!)`JtJ_Q}u=p(9Edk51NIwSenO0C`
zbMSu$?)h)Szr|%-A6G1v$Ny+^@P7hc^PlPbPt=C87W@y+@mlzAM;gn^^gOS{^0Lpt
z|BcUiE&ONMMEZ_Gi)H)>2mcp6W3|+uYT(86%f75+b!mUZn=q<++iprrWdvy%KqS=G|FlK1mB@1X-0y;Taj?eCeK&Z~TN2j`3eWrsv0N
zvsipacFS?8`JO-5F@DH7meAE^A}&7j)`P19|EzbB?L5b#>T@im=cU8zpOVi~9CBEe
z4Y$-^fS2Z<&%74nN*u{Dsmsvm31%8EDI}%5{pI!-4*bG_UpVj!2Y%teFC6%V1HW+K
z7Y_WwfnPZA-*bTDi(liP*9&g9Sc=2r#uQ$5dimtZXWe$na9lb;G3-PaAsKS+|V4
zVOq)c)6YNa?(1#|UoiTj8&3QEog+t2nRrQI*)3;|F1#Q-^p-pByz8_xZolZ)rGhLFUw78o)AR3`dirR~OaAfey3{l#!)d1dYfpc~m$tX23+w8{R`m`#0O-BkYzEOZ~ZOr9V`&PMLopMts3WWuA|S9JDEOdJ^#O4y%*>
zo_SjVZEM4i10!GB^nz3MyRE@CWzJ5F7?BzPgo2#4`lNO|xD#2kck8*s@g^_Q)-9Yh
zarR8h?YD&|;vv=#_=GFun~C9aea7&Ns`Dm>FGkY5t;&N<^R`9~b`NJyoPF-~lfx%y
zGyDO)0$GMn4rgioi+h~s05?uV)eCBi{l_oRdh?Z9?hk-<9wcoC9pbIY-7LEOnRf;|
zAd6IFwPGxC=&PH!sLI7%?(GRC*##9
zsGmMTrXe(C(Q}WlnrRsk7SXYIr;o8JizoY!2a5{;QGW)NY9q)1Z77)mxRLMiPF>!x
z!=_bsw`oP)gWJL@p@Dv&?Nf``CJRUb^wlB0IniQK7NfCN*N2ajvNKf(t07wGtXNLgx(bJEyhz0mjqvAeX=DlBA+AV9|`}+A-
zb$xK-%wgJ@k^;%1;GR43)D>XNisJ4-eFRg~&6=bxcw}l*EK_Q(3c%_f^?(>bxZjJj
zcxh1EgpQjfFb5X3Ma<^Q7PV0n8mViA!kaz7W1{iq8_}OPQL#V&7)zZf8*q#z+7qBn
z+s8|~{Tq&uQDoOR-R|pm5}Ts9>aWt6+L}W)MyB+v`+7s;9C}vv#UY1U;%E-JjrV`z
z`x2L)<&z1X=8&JL>RF$izyzP3b+SwdG=~Z@Wx`))Ga*mU%8?0$&7oojBlWBoMlvC!
zXPqh&N}6RmV}P~UUIL!+4wnCdkfUZ**rD2~9kHIeF8)RM^l89Z*&$TBJ)j-?XtIxgm288j@G-&2n0A
zS@pWKs**OHob;of@hZ1T$8Q|~>5yejYMhxsKmsf!K&FYU!z92G-Odc+13XF$3*rEaIs&}M0GOxu
zKFt7FC;=7|Ak)Nr17JwEGlQ5J2Ur{jSlSU_wE-}s_a15hEQ$F*VUgOP+nFYY6GE$Q
zXR;W^hn46b75%iI(5YV?U7y}U>-{hE>FuGYu&J{yvAG>pm-aw2s7ZymQj@4z(lfx7
znncZ_CgtHuO`>L*n)DYoU~1Ay1}{ua;%jjRF@YvANu11wpVFk$+2W-p4KhG^pp?zJ
zo$rOnl|nDn?MxJ#@CenBwxSCiy2tOQfE7w$rMjId;!*=xo^EHdIL`o99OrjO-LbDFyNY{4*G?g@;+`cjFEA_C
zWs0z(G&P5b;@_u&NShym1Fe!&i`ap_6}sSvv{{uo^>~0O@*A0|5}DpKGpY6fLj6d^
za}vZ8Myl&MzEu`9)Ml|^K1YX0KGCi|#|Z%WL>+#Pa}4r{Ee=mELS60SMh*M&gVEmBGI6@pYs_{%HneW
zAmT!Wdd`B%WflrCNj*Cs)Jy8?Ywhg3I`jHhfHr%E-+}T~ci1A!#x)uIPD*1aasUmt
z$qm3^2gRK6fALKp^s;|#GkaNNwxREEC{KegPINCWbT4jnEuJRX3oivgi(*}iR2$wp
zjJL@Snhc<9~aw!t;B}@$)la11%emZ!u{0TL}w=EVeAukv26MEu~S$e
zQqK+#cOKrM8dT+AFD1ssv%|0VMwYpnL?6%;tM1xgcpOC{yF38o1EF4czX}EbF8$Zm
z_^Zf4`^+iqO&dP5X_I@|w1Nz+sE6)#1#hv1FGYe|E%L(>+0g4c#AZy$naEb=1B4e)
z-FmqdmdOtaeR^px2Y8r7_qk+&aLo!R5{7x6Cf-%{b<=_AsA|qzw3CAzdAvFntwU1WBFS#MC(xg#s8{2
ziW-Cau~1w|{^b8%`N8q>xj$EanAzT>{87IglH$s-Bm5b36;gR2R9}QmXUlP5$kGHu
z()8h{;k};*Px~2ogCo0~WJ?@BV{px&2Hvurdm_u6O`@1!8q@v%j`ATO6tRid;66$I
zI$7>NmT#i`P4V*Y_4=9eUE}{6_|O6WYQp(h{KXUW(o*%a^yljDsGnOgTIx{V`CpY!
z&_5P>6QooC*CLPJln5pIysifx*|LKK)xc
ziafe5KNfg^xMcZPk5=B=BpznkS4I;`Yd=W8^QY3iuvfZ$(amx!tJ`bu9U?nBF(}v#
zL*fxEx+c*&|AYPk14JT@PRY4P`JbN3gJ>f0&KYo`Z=yR)ffrq4c0A_0=$oCMwNB4}
z===;$rNW~>nEHH8r)RBG{ik+<*E#j&JlqW%jnLlh_;=^m?>Ez)`=LsN?fu4O@hR*mZb00-E
z#`tfzfk!6nXMecP7(!Gu(R16HYpZ$r8`a3y|<@feZ*Uk`Yj=O>h+Gyc;?(tm=g
zA+kTslVX?(=b47--hytHnst?5=vTMbYz}W_+pEq1HLmOTF;Xd5h&8hwMQ@8H%Fv$y=HytJ<7+gVwy%lV>mxAM~7
z*f;R_U4WQ})?SdmE`J>wAV&|``qfq#0q@QG2|-!x9%9{#XSPo-LZv_>*fJ|K_{sE7
zqBX3EE*M{XgH7SNfFz`u+r&4>S*U(5^C3_0L*>3tkgCjW!!O5jH*YcUEXc9$WAHZTd*qqh!aR$M
za)`O|(vh4)FkK7|xb^AQ;6|lp4$=X$Ft|^d!x5BzGbfJb)#5hi!<;o2w{B@TG%!1+
zMv0s?hSHo?2?Y;T+Vb0D!@)bw7WhC)Kt*n3lfIBipI>bzL22FPe%+yYh!2`2G)Z0Efy5P9}`5ybdj-7NNdW2n7~A00lcZ{p08uQ^6oOZ?HLhU9d%&musq)87US+;x2lM
zYH`k`KtiK_8>;1v`M})}1Z=2QDHIO5z})SLdRHs={SE2L+;{LRm8;!Qu8J&+^$@Tq
z$~h2Rt;~IhnHHC4S(KMP&RGvIZhb1$D*Qb4M8C=!+&BH!oYiVe>*j`o1G6_Pje~D;uFJ
zd-_QgX%X|{H?wdf9^q3PCM>2HucP9(xTzBjb|}cMP70!K$k{wAL){uYqEx>}R{dz3
zIwSIuAHcRvT63d_I8UU+%vMm6=`-wzIDYmDsOGcUw5x_z&Xx=
z%ECt7J(lRHt|kDPcDyz~Q-W*4eIqMuk!D-uTU$(M6~hi|rKcSZuBp6HS);7V-=w^~
zYJDv7xmEZ6Mwaz7>CSI~hNX2=W$2-*w!;riw`pg^j?pTI9bW(4`mYw^)k3^F53gpN
zc6j~n^_oD`FIaT=JTA5M@ZNt`W};QO$>FA)*2r!v
zS~=Xf#GkCs$nQ+%cXi00>c2;J1<){ZVN-F*WBb6Bla&nmu)T0_U4$!xZXsOVxEAB;
z5!qk~9vH8p>E&c+3EFTejB{CJS-?OF84P)2{D4d@;O9m=^PtUn->({B-P7JatuH9@
z5kp-4lFu6fE6{`=AAoThJ;2w5*tx%+cB&blP>t9g%E(9=jFv?VL~I8LIPubm>z$hc
zzu>I|v;GTsuoo8bA%Z0x;C*NPS$MhecqLs<)#(SfJm3-|NSOaAmn=*o_yhsInSx+v
zdX>40fr$xopMqfam8+Ct4dG)HZ7vd&VfEpRKU{N@M#s&fRdJPw7V>DdFY~dEQDwD`
z_v)I4oxSomsq6DsH$=PVx2T&NVy^r(>ch;U+fE>w`76(S?!J4Tzq$VXX>T;fdDw~1
z=zrmVB1n?T7uG_ygNGH_W(hT{<&{kMD{ZU!F{6v>ygD4nk*=3YgB1
z!*cvo2+E3-#U;-D4GyK|H;^PAl*rD3RR>(kT+Vt`9dJ({Uv;2YxM%(<^bEz(#VClE
zO3j}s_fVjwKI{XO5X6K_u@uV8q{6~~FXYOD4(XR98;ne^I^d~1wdz1WrRE|6EeU8L
zKXg`sE@0gfI^^OgSNsruwAQ%k0Pn{v+3wjuOnApmzqIN=R%K4rfn$}L9}J;%C^Ezd
zp(cuSMsWz75WGvIR~=B&>0JIZK4KM&9C^;_0Gy)*a
zA$~x>1Mt`pb;;M>onWY#3;LgX{~KM~_hGuOefXQMbnPyGH?~&;kIDXm$a1IJh`||_
zN#S(?+;P9=&?a%sicg!uMOAqqM@(I4moB}ny1w!lNY)=a85EgI?l@H!lF>M6ktEF{
zsVi{FkSh>EdTy}cob7R@=_FeLe{OQO-@*f9)^l}^%5)8R=P*Q
zlEC!Uz)zwqHXT4K`2qrBE9u-mrX6E=cH&>i72BDf-W%xHFe3+q9EDcIq>PAEHM6hl
z0$v}P|8<#vVlY|Y*DTPI4xj!TW&{a7CHG+FUf&hI*~sqzzvJ<;;3ylAk|DErv`n<2
z@Cw5wq|rNEmY0*YHcZrFD4?AX^kB7R_8P1S?4w=e43;?g_HswC%pqfNoHjS8zK@V!
zG$0=ZzK`_K5n?^KI^Zk-obp(Gb^|8X5zM=gK#sQlbsFij(a~UeTpjc_Is$O~6n$sM
z>qp(7(m(>k6xTSLG7K?A0~2K!VvLPMsxiC8KOK!GuX4zXagTp#PLqC<=i^G9R2DM!eVgyB3}3I3&y
z;M4Uh0pC;^4@Nb?9wvOFYegLnaU-m4NBB?e|G$Jk2&TCs{E`0&d}Zz%C>Yr#{Tr-s
z9ix@ewYfl998&hz`zqNy186*4mnqw3uJm9s_)3*VH9(`^5*JvySZ>&S9WvcK=#qs`~d57a>4`ctY6C9w>!{R!iN2S
zPU1t={|$*7SEZBq>XluQc>bo%B?`kcyQJD2gGGYH|9D}iu(CT@or
zw?pby*pJ5wBdcx?m0&fK5mOJLFnvZ|Mc&>FO9Ye0Sl@JhA_v!VGY7BYSmwxLsx^}J
zk#X5*Tt1Z-loqS@0o`&_B8W$)4bDQ9TJ4>gpqJgr2^bl>)bG@O>diLeb)>oCsbV|y{A#s~Z8f9G
zgK5zXQaM~Js-DH8707wmav1K0$By`7!sT)j@fEX~&C;$Cka*81Oh?5RS>}dp&U`2_
zThWs_?jFQBj3u8Y-g2kCn1Hv8{Bu44OhL;Y4aSInU|AzuDx8LJj&A?Rj^)XCz5g@G
zCmXVLmwjIh_EEa2&ipO0-e}G)G-pQ>Z=?uDs|SM{XPvC&KB9#utDgkNPMU5D?w#t?
z!j-|XQ>O0-?!DvF^imQZ3dze#uZM6M}BPVFt=Ztb_7s=o&;fe=`Q%X09gp}OKCa%TOLmtg_nH;YiDS3dG4Jj|dMi&PkZqzFa0cl))Chz=`M#fo~FaFO8jg@0wtX@NX
z=b(rm5X8h3&~!+Ae0f>&Wf)se&=&l$F%hirivLqEXx37JG#84njmKq+w&WDU3_iL-
zDD2gG!IO1cH>)jZYk^?nJ?|1w2k8;Na@0T0SY014M=DC0nEujp9!66bFjS%0W(f(`cYnfqA0)RAS6l
zG)bE|87;^bJUG>*g{NpUEAg~3c<_#oVg>4+oR2mAFtY-#bsr&v^qfYZK3=XZqypzk
zAq+QbG0Jdl;m?=pZkEyPU(7tuQEjQKQ(GFo>7&`|8lqXVceWGAe6%u~rP^9;(MJvk
z@5L({+uN&V_-z@LW8>vWl)Ao7-Cz`kH90~3uHjqTY?xde+p@gjyNt+J-RyjbIWQ%-
zA4cX|L`TO%T*N*PQ<_i)(2^Ic&}VQmQY=OYQ_sq4Mmxoj1{ufUT8wK2t|hpR$F)=f
zD8<5cEqL9CEh>Or4i(#`u4Xo}1J8cl8w9?-;ASPV2%J?G{{|Cb>tmRB
z9M#%H%UyX6#y|`O7ovs$kgCv}E&_iRBigtTos9Q|02?4I&Tpw7kf6wcZgy2@?S+~O08to7z~Ovpp*?(%!$Drt&i*?`*YQX24Pnl
z8+O?1>T()@R-SbYvb%v~!1@h-{Z;`mp8Rj~_s6ID0}K)|Ir1LWtp14(|yCvQ1-#`!wd=zs{Fu}34z
zd|hzh58e(O=tRF$nL8hKM|OokRk2}(rUG;+TKYuU(#txw^wT4s53D+bAPwp+$^SO`
zH7Ke&gm}tw+-T#_w*56*D$f8f0>G>U)SqrN_Y$>JbAJV)o5->dntRHBy%VK!wL5LW
zzSBzNWF2Q4Fuwp_#c(jb3iOMhGMspzabe}0c=SU{3bpf4%4Pi#
zQ<@p-Cn%bWR9DWAIR}H$Y0mR=qQQOl)I?`UB?^Ise|a*|x3D`Dh1ldb1{05y0?OPg
zSl1L^u+OwY0HTz9ptS%fdej1Aw1id6caHw@
zGH*QYP@li`Go`ACncJF`d1sg}xxw-j+yg^5y}0KnwySJ4Tf*l@>I+rF>%}|E3iR++
z@%C?#j22jJ?l#iP3gw2QGDq|UWYX_+VBy1B(FcJ*b!GHnyn@!dbo=-sFabue{}fr?
z#xTe-ZLFx-<}XAQagV@&
za6)Gk@8q5+yLu-!M9Dp4cd_(JR;%@zsFpbsJAUkHi92?zey1DZq?O`wSqZZF)e_2gRQ%|ni}A_Vkm%`BqVT7|
zPr7lq(51poI4~LyT&U_4R5&_Qaf6jE|8p^wW42cc@HRL{%3_#!%ux@OBe(F$TA2-7
zqq4LzAH=<&F|yYhvj<%WI8?8z%tU?Vs3O#a4Xb0Ye{7wyut^&l;_bKC_PP+;Uh(e1
z#_SE5Tjlo5W6%?AiMhp72zzL9@L*F{%S~Rz(okWyt6q`^h4R;_uvX__7XiqDF>%$b
zQfejvKfT1qls#Cejud#&c#Ty9GM6J*VpHZFBNq`ERP?Q@LyGi+wv|amH1O@<a8q?TTCk
zFV4~WOBA<+d#Ys)b(Bp#KR0&0KF)zvAZx`%D5~Eny;pHAYyME2O=y4=D@rg-X~wx*
z_*2ghu=F4ufQX`#rDxF_@Cl1i`T*iYEUk~ZRkit{em1KZ1LsJ$d!CW41)2Sjr)?q{
zwnOQIUnd+ci>MkYm$CUE(LiuE`J&WxLrMY(XR~}uJh16v2FPp#3M%ST*RB{j8SSEM
zaDvv%=8*v~DFIvGiZvNh;exm%jF?(O;X0)0d;OId|
zk2c$Hx$JzLoQ8HtJjeYdLyCnvZ~LYSr67S>fy8V#B2HK;1iKi9=F&y#%Te`yWMiwe
zvQ^e;C2r;QGN=X?UsW{p&POWS31F
zWvjMC>htO-s;dDivdq>bX77Xp_+i{Io7Z&v{1LD*Mv)$^#EDVeC~(=WUFeQ88AC5A
z$_8XKx<1gK1>Sp_Lp1-Em^s(niHEQqb(kFlvllouC)vi
z75gz#fGETeNKZPzy+D7|39FgPg3k0$`<2ndd9@H@GIUev_ItFjMTKJzfKX@YKU*K2tz>;BG&kia(?29x#O
z7_V>0Pu8c*^>HvL_j`HS|8ljb(fzq)_cy#mQiTz{?Ee0RWp
zXB_Hf=St#{on-ajQA#pV>Jg&@UaicnVuS*^#B4-vJLr!qRexND
z{>*@kp+C~REojinyiyS|SHq@x#D{xQ6~JXEfVx(5R9h1^)}f9pj$RC@>vt84VSpAr
z7Y_ynAV?jVN`V}%WF{!6oR(@04c&&n<&?(vv+s|JnG7|F{0`VTkB;5#CU$jz7`*`x
z(he{bBc6aXVtt!K7me8#0E!cGj$8UCbT*TYtOv~-5oXvnkT(>X`AXY-`LS&Ujr
zsFS_$NPn}edKD&d*1<&qihaOzLc>HQQVf>~8g{K-!gekGj%|V{FLk;JT?ApV*mk(Y
zvKRu9>|skGhvU&IOOn=7Jcjv~73>`GGZrKjGt5>Z>(P2kuN4k#BhF)?1G`0@+9G|}
z?Dd(k>Mh~8^ZLcNQ1uSZYYF@!4;@&e^#)|?oe39#@MY_*9Ki)G;mf5mNHJY{zD({4
z&wbd*+7VB^L^g+m$H+3$>%|Eg26(`oHoZ=H9aEhzm3X^hVh>|(xMl;Pf~j-3#9vP;E>5E7hhbbHHj2SWs}wK_w8
zVv*h9z*u
zn@2&yun9i(h`O8X6IZh!edfz>gExM)Rpw=&0jmw_5*4R-*^_MQZj=~kmViUa7+9Wu
zn_s(>>q$~Q>=M{Wc-Vf!!{$osmEtRe-wYqyFE-;|-7VJh(h3hdeyT^(!}hWCART~+
z=JPB&%STMblSbKvxDW?@RMNx#{JoAIc7V1)dS=IReWl@<4LD0$LH2~XaSxk;goO3)
z>|qy5KlT(>D?MzjjGjd&zj-&tTz|%xD|=h!4|3EM0J0t#jrI0x#?Xa9HsD}*&nG-A
zy=RF79d_xC#|J1b(`mJpUzoPB
zRCrV+{a#!{go1TlpGyCi5hJ?QAs8vL2WXb!O8=K}O(zN%{_n>qm1x{n!sJu3wXnJ}
zxWvbHeBG5_+%4%BFTzfjbia7Dqbv9JRlKbe_kDtHrd#`>&6VH2v3xkN+e8
zwHWfJ4+r1T2n-FzK-ve>S{(rww2|yr!6+HKfC+VooA+ZY#qVIuM#7kl^mZFbV}{5B
zj2U>SU6n9q;H=p7inLms$@6HJF;wT(Zjm#X;6K`%L##G(zpu|-K
z<2u8$=wWy~_eP-@R#Z(x<2U_fYzIy>Ec(lUlj1LX#aI-QF(U6z_{)nB#sTG~zwAx;
z%PxZ>0mENDcn1AtIIcT4Kv<8PalE7Yucw>-z>3ghYotEjel23qD$|c4bg|()seo?i
z9`?A;1LW9i5@ecxk>7QMiHI8!rsuykI$iF&_en$x32w20VH!N(M-Rh{SP_KuFf3wS
zs{scy>!pSpQCsToPoG14{n1hJQ|4}h7Mc1L8i7dkx^Yu~T=QrL
zUR%_D&7)}>`sTkJbnnc*d}UbKIng<%oLEH`Q8aGleyP%XJ3i~K__
z+3QMP?phC_cSnw+v`=O3iL!m=#q44&VhXRqc!FPyE_E=gv1D=h;~ZG(nkpAG2^kX~GK
zaj}S57)EOLKwq5rgb{~^fro7S3=YsY;Y0n8R6)=i;?9T^P=24=4eelydiwjeOy
zqJCrD2n*#2HdXco<*;_PhR-rcv?%xvoPizD?5s{Nc34$;hvRhYYw;#hkAvAh!i{P?
zwpdj8m_~(o6mn*(SxOW|>6i8nI}$s$M`i8}a{O5i>Pt;oAxH{#SNO+a%~mB?9MCQX
zadND~6y%f!lKkQ`<^W3}yflF&nDIgDCXh*9tkz49=dvTOehIh8@i-;FcqCIU&*6T&
zaaw7_X#4#INNrvh4@K9T(YWmIGCz2zy8a=hT1NrMfXak(vn+pcV4?PoryUMzS%E&1roT`d
z-KkA=#BC&n}`we^BUsV
zQt6+%RQsoZD6TUe30f8qvpxWlHz%!adOS~=`#GuI<;P&LC+tH1V*Ikd;gWMSXlca}
zFv6fCW({G*fgVAEUeKsrYSYdNzCZI)ea4xVs`Ex*u-hIRjhcD37{gR245b==`;48VkK)k_n%fSz$uc!hN;7Hq8F;G(cEZvta|{Rk@|wj
zGJg|vFAtbd2c_%Fcj7*T;B>pPFTtfg$RQp+k^zBDeILB|F>W{GQtNC#rs2GZ66Eai
zJPDZc!^1~njuEG4T4wL625_y~U&{*z!dXkP+zgv3o~s({i1mYo5${x(9uXvoQNNKF
zydf3E8YUFHe(@;tm{5#mzu*hNDby~&+o$XT-t)&e;>WG}$F
zhjO?8uagy7za=Y5{j`ST$P2K(7|#{Baz<*rp7qZ@GRFku;8YaBOa_=Kde#qT$&^Z@
z+=($d%hE2+fXE8f7yVUuWjgRWPLYGuZOAE4h{6@?}EA5WrtZsEWa_Ba+yoJkR8?x)LVu3aREX_@HSn5mteyIOYLdekK|`mkR|iHv9dtnpir
z-`Sw`(=M~cx|?~_$FcQ9YF3HqDgyOg1!?N+4>{$)ka=
z5*QBx&>ojhaXbLMf^Ql4d<&sg)KKkzMnVUNilz5}oAMk
zdp?Y0F;u?Xgdc~CZB<;$cRhL)W$vBb$)bW2u$z1^ytyY)5@xepA8UmL9UokO$F&b(
zWIE^}9KbtSF1-NitcC5D{Vd>f+~E?xpODlg*ii3Cf>9P%`UfS6kOetmR)WQCCJWw@
z;2x^Ao%T?I0S49RsEPh~b-l?axj9w8!y4S9%zYgepY$n@WBe`7}?aZW~@
z4)PiJB#D)fL2CZ~oFl+A5A5fw6}ACGc`B2o-x^6E&Fp0K6YQ@LO-rf-1s~@~Y^ZvO
z@<6T%QiN+6q$>IOxIu%VLjOj}_2SIaxQdvVnVVG-+`IIK
zbnc-N5LD2SbrQ5>9k|Q3kn;gJ$ZokDTx9AB+p$9taR(PSNiI%CmsF0$mTThTFj`iE
ze`6tPc7V{ma*$t&-i2KtAdZJ7k3-oR;JoDLgR%k;RB7@Ax49rx7B`DAJ2HUBF9Hg9
z{LV(njWi(t(wbgDy
z*GILRN)e|KfA
z1wWXYi3Uf7h+T|UGyxX55D%%E$V5mmG0_cxF0t&ogeH1{Q7I(NazJ|mrZ1>$<5j~j
z>9%;Rf!0o}!8{-BSJ!HmqQz1J?nZ1_ZCmOFNy3V-p1Rh!{{a!X+6TS$c&}d^mo9K%
zlb6D629{`|YBVl#n6n3)BJDje4u614!mv7~F?(w!W_Fb7#{dT64J5^@d+%@gJZF=X
zq`JO!C#6eys>_W$UsK|1p#s(odO=moS2?YE!G(Ik^rU>hGIU~+`ki%yA>S{-r+^{f
z1`C9x3UF((^+$@j*H(}_2_KZ$KzkdC9D;ngqAO|#L6PP>6b(`6ktk4I2)!odJP*H2
zU6a!im-6p+86SyIF=JtVS0eix{Xv--wNwP($69m4VxzsVt;Whg_XIeXTv(YD`h(IU
zf@m8AZycUZp?~mvIB_>F
z?d}Ldsv8Z-A3`_{-uND|*SOgzqPQ^*8*30-aW6-8VmGt
z;qzHc&*E`}*f3Y)Vc}xfJuF*8cu5{iJ4w`L%2EF$RgRkIz}iIlaoEPO9SPABP{x2;
zv&kll1EB8)17Nf9rc!yAeNL$uVSp;ddhIq&N7%q%;lQMhc!01zK=u&@-)tTo=B^IF
z*lDY!%JV0THfR_^a
z0#GUX91BQRLMkGpgGJxoqRjgfxmJ|*IOx$iFs6_;>e1(C~qEZ8)%S~M-#YIqM8f?9PnK9E2Dxv
zP%Bc*eZBiwGEdwHsCdNfKIQ6q30WvT0PPJVM1P@z3KsF-a>M8
z%h2V2jO*bJlcRMee7Vlb!}BLFHWC&zHT6b8a?q4CSB(>tq!5dE8p%VF+E23(&h`YVzs!fQWXyl3wQ9};)9z-=G|D~1r%O$ksn
zexn4LWx_blgaL7euyq^U^5Yhpx1m06aW^1JLAw)zmXF9ImcpSTC1i7u^_;&=Myl#kN
z2bL0b7Dp*DIU68i;Srx7I3*e`H2Ag1C_f~DLZNu7WAQ>29Lr+yHYCK(VmZ8G0g6YQ
z4wPa(aSIahH3mktQkFBF$@X54q{y<#P2#spVZ}#vxxP`EdoG5T=B_S45Qj=+FM~)v
zj3bxca9J9{S=``Uh2iMDXVDs~+OS6ZLx`ygpA(t)IWVbevsO;$Q_YPS7Xir%)4Z+e
zCK+pnyySeLSO}HEYTx7sivYembXncmT~&8dm(@90-9kW)o{s9O+Ky4?
zeJ#al58p;wr4;joy^FeAq-Z)z@lCu;>QK+-3t$X;^1epObpo<#6k$me+=0|v&($)j4
zaXc(rI+f2Or#O=}t~EM->Z-K1FI&>-o6%)$6Fb%>>D$|-$`-M@pjrn
znYTjZ2B&&}C&4SlMm>j^2yPs@jf?
zo87GN?@2DYK*JOAimSS)esGu7D|jpWPH&@#E7XBB!9Z>7%@GJKxfx~%L@R@RM`Jt?~wMX9FKR@LTGsy~%F?5VtwL_QjJ%%(4HGH=Moq7zLRzF!!y*-kBRIUOGt|{mE3fDT
z^;Nt@&Qd_dr9k%Bi)7BvI_12Vb@pbRF9RK9u1K;LcO{0~Tqx#rQTL@No5D|dTPXcY
zhqxRjN4$+fF>drvQ4mPHgl-i=?qX;cKo39xJ86Y{^rSdgKR|F|JPLE(Sakm%_!m#h
zQDTSr3cc9BOa{ZxM$4SN>n+k(?dJt-5r2A7j)uAB$AM=wSDTpmFZqsvc+T!{>c(fL
zt$}5JmrxONX5pYR-QW^3zMW_Qr>G1asIh^l=%%&G(#}m;focO-@V636Ok)y^{gk
z2pCt@B!=VkVM<
zQ9vJc1TcMSL+eI#@7Wuz0+0072$5*#h?*CZXxBlP^^y#UcFT+;uG=RhaWyyQGiGAo
z`cZW{t}pKZuJagqz~ErsX}BVqFh$Sp#xGdr3=97i_51Z1@E5ras%{x4+15M@N3ql|
zCpkGO1tw3%^9)?Q2>w;!m7X<#Dry88n~j-Tz_uW?#R#N1gNJkmUXjj4G)xDG0AneK
zxq1dO*oY(fv%j})Le9ro?nVD1T=c90DZHCY>y|>)|WA2tXV`GLz
zT-s>2h)n!IQ)%gS`vcohExZUqCR!RLY0M7!aCM1`Bk6)TWqXDN3r;tQBMk_yY!a{I
zB3{7{z|sO>kxx2UsfPe>fc^KJbg*l;aUTEqf1q*wm2-jo>(IV9-*-ON7vU%wEH2_N
zob~+GT7RA~lfN;t$JY88)YqonYRMP*8}e7?Z{<4#;Z7@gOKVEOn`gln>9##flBAD4D+ljY6(_
zmYWbbwGwG}scrMNGl051dw1rcYA&KhuE;^F+@l~fM!vKf8*M9lsxA3j-u8h%F$Wf(
ztwA&X7V$(kg6!Lwf4lk}qOtrg?d*ec)As{S*)c+`?9=d#JR3pXPI@*s>~`t5xp*Wq
zTE!0tCc10d0U)(Fut*}dU9L$15FW$qRu46N?a4gY5Oe6aIbz4CKR^V)L8+nTLCqvH
z!v0e4zvGn=I9|woyk0Tnu)3|`bKC4gYhgmCDob)f#XFpRG&Y69H0U#i90KUw_DH+6
z9}gq<>E%PVKpDM}gT8*>A`a?l-OStlkwdEvP>UG*I2Y*!xc4L%>qM)t
z0-&pG!^~_;2~5
z%%NMY`4T0ug6l=D*+Q|qX+G^HkhFrOiGr10wvCj6`LLhJ?~bycU_qdNVZ+W0M%$CC
z5wRd_0xBXBWoIDY4D4m>p4i5w$O^lYRP|T3*ok};OWuTK{gq8UsD6m&fOrrA?gl!cHFK##dky$y}6!?U_zJt3Cq|
zjGYGJnHG4l+zAJYJmTXwK+($Br`QuB-vq=mywUG+81x&df75!Xrq?ntD1$aqUPDI8
z`=em{I6Mmg`G3TAKlC|?Z6FQXJ}KDtFtOF`;lXflj35;cJ`sC9VgI)JZ!o0x_`<@@
z{f{ztE*050B|&psNJT*_^=el;(6jl@_>Cibjqz0t9vSY`!&YdJOZT3JCr5S+q;h?p
z{Lr9Y`Y_oof(wmyfX!vukcBts!09FQAEI>l?nw(A}5gIQcm>NJ7o7me2Lk
z8CZX8atm*{w*=>Ji~usAi3?!3X2zxUYWYm%3Q!O8;Oga7?_IUI2cvdeQ{&Zng`&>x
zDa)E)Ms)G3h`D-}Y}lp}ZvP)}rgKvl7XqSTNvgF%<~J>eBTIU#Ee5%E85Pa&Q+y
zyd3~G>2gzEO&pssk*Lj%wV2=k2uFPwLQ9STqCbt=GSfx1iw=vj}mAl
z`dplm4}<2>i}&IfPSuppd4&=^O1_M1fp|6w#mqCBLMpZhatL+xnWil;d{1%0h=e^T
zMnPIH9zRn`dcVWrAwYyS%7#tneQ_VsjD5$S7a<9+nT#S_Y0Qc0LR6K9wiO^nQBFxA
zgC805v|=k;Ciy63a{oCA*lxKi9jhavQ78m5jnik`>q_j*I7ThLm#g}Bye3POM4On4
zJmSKLkyP&rR7CY2&nw5A=&e2aEUpbnVnhsqX>hlq4*^$|$Y}hMiw$3M2Gy@QhZ8w6
z=}be=2IA#bxv&%hECpqSDx5=(8(Pki=;U%KC06^cij4qHbmv9$aG632?+b#Z^7PVv
zNI`~TN&Mg^lWTu5FvNTGFiJJQgM@ntWU3*TIPW(K0Zav0T9YIpG38cdOl5m3jdilS{q8(R_jA
zb@K&IAPmx_BY>_P1;t~lWQfTv*1aOV99a^cj%eib-422fi*c`h5_?_fe+Gh+QV{Hn
zpYd%R^P2+beX6TaqY=)+HVKI~y2QCBcY(G?qU|uycK;08U#yg9d&G$ev>kNNM9&1;
zZqbf75z)rduNlBue2BFJ(Th^BPuG`e*dOl(%^uil!wRl|xU8a}ztmNBgf0rtOvJ5m
zn8t&5%XAmgeX{Sq5p{JnzAfnrzD0b5j#RSVgs)|)Xx?Z%G!4*2hZqIFhQdhHU}X(|
zPPztN`Uj-Pg<@`eWeMYpp4fYO8Wwii8e)SrdmD}yMd%8iD|;4mU)@C}CLqnNGB$w^
zmSU0W15b2G56*8xY1RR4HV0?-OKVxP-yAGv%VV4>Pe2FCUeLtkyd);Mn*FeW3BBng
zCiN#8JdymC{;h$KJpS1j*8JmT$rQKo^ef1_PDCGvl;h{ycGk~n6$U?WglyQMkFfkY
z>|B>s|c}vj1PdchgunLV{8*>WB7a*uHw;`pkx>eNG{!qx?@_3Ow#JV&Xh+=
z{lz$+(Wsy8Gfux%)Sr;3pItBwh8Lp}^-4rvWOH8?wgC;h=xd+=#e<-}c?>Aj#!*PC
z|AGYlm3b5~yip2SqR)1kRC=s;`Q9*E@$|UAC+nHRdKRU@|7{XJ`%}QLl+*o5xK=UG
zgbR}^)fs%`U=9wjs|j`Zzy)@`rX$?-JCVWqtJ3Pnejw^Qi{*KYCkHu||LiK)fKhU)C
zN&H5VKPmWG#clZf5Rk{P`2T@1(MN#GJW~PE_%ocg+3>m9yRC{@M+O}@b-tn&$5&MD
zV-F5J!**2ockOF|jC2@cnp-;>Ir9ci1J1_Z|ic_a41|Wv&K%xnGM5Z&2S0_&_Y~;U4g#0PueiYBN3-5auFU
z>Mc+4@KtBjsqk=T7}=BP;X`i*HV#}pz={qMkNt59R|STe~B+;xVp%zYgFMpxs@
zTE^iK8=5}>8Aht|5k&aqhp$-`UR%Vcsv$0Dv?ns69x)#4tnN#R2KJ(@0vp`1d-r|}VUR;yE;6W=vIU{I6UD{0FPO8U(+q0>ImN#u
zkUl*VK+u_6#I4JT{sj*L{ZT}}3;aKk_H@vTNHTW91G8i*(^!#(I;6V9;%KTwQyO7JPaWC)MT_&HWJL&
zK*JeuaEQb6&<^bq1q7EWp9B};Oc54FK;}o}v8Bgy0?J6^w3etuM_DH>eE@`K0?mZY
zfu-$0De(6JhrF6qGlz6VDh;a)n@igZdmrTowLwF`pzN(kg0hpvc^EosaHA1#mEYQ-
z(csWKuh(W2=inYt@>TgR&`CkCX6~)-7FJ^P2uALUM}?)h7mG9R$PK}nt!bI5gu3<9Zb8~qZ5;}EaR?ZC-+OQN8}
z;-{q<@}bu?Z0F`1_s=ill^m}=JjJZ=?ZSewupzY`#ZQ2NMgoj
zd-jpckB$8iy}^F+3(^tyC7|KhFRY)GJAWnmsY+wA_WDF-sWeICs5C?_t_Yx*I!L8q
zH|!A22=^aNY1TYNrAY{(vpt%2J=$^y4FON^eSsd@Y=-&KmU(a&+cGZfj2*ag;BFI7
zA;!xEcTN!IW8>EC7k)K3u9a@`d0PXua!DOfm}{tHTK&Jnc&&^2i^RH#a>WH_@=+!G
zZdOecY~tjUs*e}X-eG(R>Uba`gS@)^A8QhbV7deII}(x8fJpT2)aH?9AEr$*`*SqD
zk@CC)Y~aiK_hOiY-h1#HTzN+bb4c3C0&b!4r<4b|69;lDBZyl{wGB7tqVvYZ@_Yh+ECR2ieUR
zt6(rtB4nA?qglQO*=7!g%T*-nb_)*Lhh#M
z7b3H{_(N*HZ;(r01jgd2W8LwOz?MgmmbI1Yd29QWZn!AcNX&0afC(t;~B;Ysb8IA+NAud4_J!v?aQ0>0rI{Hj?g=H9Y)r
zq7&h^1jBZT`
zOn#v_P7;xaCzPR|b4R&2Ok)|$BcL1(Ty7A3kWz*Z5XkQFd9=3>906p&_f=;aop1C$VN6GVxBz<%RR0M!%_Fq{KcS6rPj!h&Xj2_O{H3g+nUIW_y0nrQ?AH1&ue0KP4)p`igZxiAC>nYnBoa^bu+V^W?I{nebQlt{e5NvPlpF8nGr
z3s@73S;LpzFoHTp8_G7t)fku;p-OiG_*e?S$57M&=p^WW5ul0#fpE`RnB5ubn{vAA
zO}Jab~WSzU)K4n$TK&$P*vHyJtGKtrBhG$43n8o#`k3x;rdpg=8<
zr%s92oPP(Z7T7<5>CvHFB_cnc0)>X=!SAz)cb^AGlL{_NMR|OgiqFxF
zwN|j6>R1u7;Y_R!y$*^LspuG1q-ITVdpN2@UbjvwVvA(-|fhHhuy3`
z;ylmE4t$LZ6S0VI4{wzgB-|gTtZ#~b4`T!k9*2BvKoz`FM|AsZ`3YHPOz{p4R&z7CngigcIr#j{=V9qR=bInN!m~vsn
zbmRoALgc_DS6ZkW@lHIs4nI*YzOet#ghUxG78QS4Ortxq21fT`jN#)(x3m9@a|=kd
zabC3n-v@E{;X^>MoOiZ~aZek{r8dC5m<|>5>sPneY^!Fo?YbTaR4w8WAile9>mgK%V!8E
z08A+;Gxp|b5>Hlxyqr`QIGw(jq|XOfSa5`KpLCvpw7Bd}X?q=!wveJPMJ`gNUG33x
zJ=#<+X5Z(cQCai~kF~YwJlus{!EKe!I35v1e4q}-N|Gto$PuhbgKFRl3p=q!a1+q?
z(k=Qn(&p>8MZ24=)uUaGxnH$y{cdo@yM9OZ_H2PqCVd0uxU)BBuFY&C2I?r{>cQH!
zjp``M+og{3D6fwy3{6x=6>6hG$c}?FH+H+4b>k}}zNS>1#Jv&lNZs0Hm{AU20SUX5*DowoUf+bz
zKh^NWLX_e>4Aq_Mr~I{yzHgr|i*k_^Xqrt~awI5DiGySy8`L1(9m`Ogf+M|#K593I
zl$Vxw!-1i%-&{CmqIxr``a!$P8*H808$bfUEf+P*Lc-10tK!>unT
zT##cynK%`lDoAwZ%(-cAIzJ;eI=nEpYhQcrB?8n3}!;&ppU?l@kDV1>j(
zAK+)FtYHgRxEqc^J~4Rg6?9XSuIPoJT%EXOHq_%QjDHP_kltRt!Z0(kt2i=Z5&HQI
zrTSewLs?1?SFi4mdu4Hd+lBbtBi0r!2UxAY3s0Du;0}yZ7>I(_M&z=DyURV~u_3LE
z95Q%#WSe+6ZmoV+J3c###mY5>DZ$hVzBP;tU_gAufeD0G6}5%_b^o=PN5_iR
zOK!q)5&UV7VRb>fc1u}s=toE~r!=)|%7gtk;+azcIOe-@fY$$0JVu(V+Rz=iQH@6&
z2q7P}{tts#5K-0%tVg?bGQ6G)b*uISU9Oz<+H1Rrs(gxUv#9bBXY+WVfkkkM#2Z;w
z$uAhYBE-PhI=mhl%(dp6YJelavfQ)X@n2cE}mLHczSUi?_{lnTJf%uB`-$
zcI}!xtV-+us>E2S-U@#i?o??_JLaT>cDqe}riZJ5W8GEpHVdM=;#XdL3lQMwvjEHt
zVJ5f=qMSDxQebRMsXhrABL`hdq#tgyi=Czv9g&9ak)3U^A(4a5aQvaaDN{Umi|jlc
z%QA&(uNxWJc|^DMinO_=U#|VZ0h}(j9#BU++ef<$I)IG@i?Dz*YN?X4LqrZ{_Ud-^
zN#0=XGXv0NH{pozcmNs=NQz$@&F+B_9pOfw2F>8A5C_bM2g^YC=`-3N#Hws|(aroK
zIudaLEeuUFtHie!qzz~eIgBSKFR(!+5SK6b8|U=y@Y&!g^iWr*V;t&loUltPq;^K>
zTFyS$25p}1Q@_`zc5nEu+w3E=QC^9Z0;)cu>M1UFE;u`ujr3RU0d)=Eb)S9YfXvcg
zX4&zQkp)K!wLKJRFIF(LN73H(h@B{}yYH@R`Dy`@7GxfgIcB$0_)26YGV$0W_d~F~
z=ojClEtQPui5N{MMx10af`-^F4e@>>6FFrtgLc0R?IIrwhKq2`0l322a({2I+7BKg
zBaN(0JdPPCfGflc7Sz7QY-q-i10>bnpSJ*1!y6pIE0CpzNS8!M#`4V7Ue
z6qWGQ9;X;{nyQN)y
zRyMUmvZ;-{3A3-=n@7sI9tLFl;yIf)eR!NPkfUV=Mr5c>Y{oMy!e@VFKTuzJmu7dc
z52(jV0>ewCGJw2N;OG#~!N`~er17q=Ea_+fO3H#+G~S%R4V4G&hT*QyUI{$3o-ecjsHhi$#J);2!swF!}@RY8h^7E!2rhEY(g1m%(6ckMGXnLMDj
zxA*@4ek5}q`|Q2;+H0-7_F8MNtz?19FD``x6psF*!s7@wOJhb!D9am`bj|7M%JN=u
zOaIxp@YgIP_B!)%v*nfRS{k<#a{d03A}Q?KoNEy*_AOjlb)vrXCck2F`?tdw<|&ilW_0RjAHep{$c>$qHmIVU)^{Zv6=FI?z+N1eV2UCs2`
z<67`5RB(?g^`I_6GAnKcvblWRkA7u;(@AOH;lTJWdLf|Dx)TqjQ$wn2kp8>i_H=)Q
z&BXGU(<^*0#R3s4Cq%rV*^Yez8|hqAq9l}z@^u+8mxW}%1){bP4R0#J{pw>|?M
z9YcZ)gtIxo$I94IwE1ydEyK#ieJWnu(%Z9yP$7h{=pg~@^8(mc1+anm))tF~roUT3
zU6oknUBmAj{)GIblyzSjq-d<)XXb?=^IN|akiH9hxQy@0HHX@68(Fr)*iuG(`*3!K
zrMlh=u#f7OQpBns=juuhtCqfe4}-PZxav_GSDEZs@p7DM@Wfv9N@Ka#4N)1-btN_Z
z&Et&cIY|5&YH;ZkXPx?R&)bN6@6h?E4q!JNLE_3jJGj?r>H2@*XqGY&r*>(}4r9+%YzL5aTK~S_(;A`Bx=2N@-b~+F@&4t-L`8
zH*fY>b0$bmd2m{%lD%jdT91Iod{K7y)(WMX@zb-8uT2h!6YrnK>aa)D_S>^Z7DV
zv|7IBY#N@4M?Xv|!y^Rx@?vAY2gTw{Fy%5kM8umD+JCrI
zW=D{5?h2L0YzOgDM=4R#ZySJyb6FWnU5|wIV%j6o$V_e)R+TS
z6N8xAYzc{?7^Pbie8Ovod0>0az9G>=Y;-2v)`~;
z&?AcHP1Yz=9$OTJhQ9ot&wF1jGi)1
zP9I+Ok#UgSuIvQkw&?nwsAVaHNxwJMdG>=bdY7E}-sDow#osLrvvl^C1giwJ{g>r4`v@)vsW7AUh`d$wDN
z80id~om~w#h{oe}i2{zmM;6J(qY@5>REIK`Sht5b!|Hf|kP3<6yDVfLg`d&i6Px`tY2_1jTyZJMWsRFW
zP64aZ1Z3%0#0Z+H(F%@;T`$Gi1+Erb5lCess3hn75&K()_Z_$^ofyvX3FDqS3akjI)EE@s5Xg6^Q@
z&A@pjaPmfix6lQ1XU@w*=C2g2zf-XO?r=Q%l!7&QE~gHo-MXvweZD(KsfGQ9ZR>Yf
zC6`;lU&S^oe5b9>E4!zD2;)G$vgnK&9%XVy#wcd7?-d?IW@c%NlUCJ9sA1zWf9fc3
z80I)Aqnkmx?duHECS>m=R2J%^^5zc*PxJ@RThSycOpfCBs0J75Qib{0B9yH!f&V_(N^uGZ$8dF`ys
zx5|}zwnDC&>6rZ-SMB!bn;75-13ZwQwZ#vER%bqrh(7ulAIWJMTFWoFBGT5gr^^!`
zOPEG!R-Y)6ihuWgrMN_dRL#pukbARz>~f5XxoS?-qmKEN4o5KId5MVJtW3Qd-jbtu
zo-68N<_XKpqdoG1d3zxLB0sj+30lWZo~3&_eM=L0>r+MD+9Mw_`)M5|XXz^rE+wDc
zQlgnQ%a>htsA;cve!kx6#dxNvt&U9hiV2dAZHk6ooG#)jSV&>tYt9PB{mHj%P
z5fp})N3WSkPL2KM5$N6`e1aHhwf<#l^iO>AU)DOpBPuq`v%$3&Uo~9M>3XB&LIWxZ`c~WaQa=)w1<9po
z5M_K6kV^f}@t*a|2%lM1E|F-eYG>q8O)i|xSeB>POoPYs$^PRh)a{JtFSt6)cy9ad
zzkNJU9yFe>TP4SV&Exd$gH8ML8O`KSqgf+Z`6osby`e;@Z9@(z(?Dj}vjx?-uJ1Rl
zoBx-`b%W(!d#G_0xZFzboHL8TJvlwN%z%T(caa)jHK_={wr9t8v0TA#Im}o*kQuR&
zAA%Xt75+tLj0|MP@yv2cljgS+pctC)U~Uta$mpR;syvB>yc(*f{(38)baH$88SR
zjea+46csJRp0iAGT_XcGEob0n^cy%NmS|NZVw~>LKlHRs_n6cDXw?@2+qA(7^y+On
ziUE;R=oLhdkivt5**Olu`kEj0_XJF8xFXUu^L$!rykJgNuU8!jB}vt^3CcpK{JhsX
zZWKA5Oi%UJmwSs=nDYXyd*UMS!|9K?^x1EdSV2|ISq<{3BkboR?04qh0B9(_U?XR~-nVzoBKno5db{{UAe{oKG{9
zRo+r&7S`?{ALWP3)XCc8^Cwz!&fJfVgVS|W@(VN|XNCl^)m5mkcF|TPS3&)tZ~i(S
zm$IhPIyi#M{n3)G6`Pi9jbDEsxo7Xgl)ENTrFERoH1a-GK#X4~lMl5=Ubn~+)u^h8
zSn=^3&KHusU(<{vxsb4>2r#3hC^|mNH;KT~TGj$Q3y6y39AE-RAhKMVQ;iH4%qrSr#ubG&
zew>qrfl?*3E*66s{QB&tFRwaG)8GSoB-S$tnDtuLCa`#Bx
zaEiy!SQxFgy_oR&RSdo>jOQukRIMiEYO3bUyXb(bFLbJ|I7HRInva6$@B|-6439!R
zotmLKYF74Pqr6R`s~dYW%vd4a)H<&A?CJI-PNJU;mUo~)IriI1pa}0aWQyzC_qAQ^
z8K6welvD{hzJS>oU%(neOhVhQL&}XG7!Etce6#@fo@5b2){DIB6!um6V+U7pD=a8PW=IT4rm=;gOd+h^_nQD
z;Xcy#m@&NnFXk|^K#0)EVdP_libdy?{feshFmVKG4x|j8l$cj%wAUgyI}FWc&Lz%R
zekNei*@K-a6)~?C>o7~7qgizWi8LlA%n&3ibwQbQ>?RRo=&?Jk#x0VJGHTe?qEmgU
zA;mUDLo`yY&cwclW-wipn-@jZ(amu&3RgOfJa#s#tRwsGA9Q?l(k(flFtE~7N|4)d
zGK)Qa^+aQZ)tJBEJQm78b{~t)urM_e@BA<~D!k8F0To12jY6{I=eexc2#CjOaz9<`
zUvLunPnGQm%ai-Dp&<5UP%m9siy4}D4PR_a{2pUd>V!+uZ;o`%Wpu|kCgUQq-&aO{
zI}8f6$LCFybbsUNL2OIneXIZno)I%#ioIn{v5&qYtGe?V;nABga67gd`P;7#_)oOO
z1t4Aa{7j7obFFruz;9gbOC9Ot=AhiatFuZR+O)(Cp{z9?&1>zI5)>U+)-JBLe
zd&x1_b>wO+8G~IQW3UT2HjJ-IRqLc5d@p00sOU4;#ia(ZryRy$SL(o$u0VB(YNS(F
zV;Pi22+puaIHhR9DFNK7NLY%5RgrgYkxn(;>J2Zf{hwNV!{?>~_8ty-HraY79RNI}
zrZ=t8TwJupxG5qJ#4!BchE!2X-#)zUY63wc#?=HlO!Mg5^I1#9gL_-I
zPNHJ=wtzvpJr;9kBp>=%aq@@+r-ld5v&9C^4S6Od+wT@fT#sT-|`m71p
z^cH=nJw6+OzNOtrS|wvyIE-?Zm-7oTF63VtQ2tZSL*9)B^&En$BBhZji!WZ!zs`9{
zFDtDtyS0vmCmA24jqkBkV%W+lC%VhtlTVBd#!iG;W!X!JWZ9LdG{jU{Hj{?t7|K^o
zQMQJZhScoDs-~~<*iXpsvsK+S$fO48ji2e_
zXgT+?1?%|nEQ_y^BjJwWHDg^$!%^S{%Mq&)p*p*~NBC0=1jn`!JH&f5ziDMyP8gJ^
z6@HyIDLP4fdm<-8*wM9?5BWr<)ji!lt#unWJu3w4_;A&CdPN{IM^TQTj&g%V0h(AZ
zt7Q~1!G(%alDcHf9m_OgmB-he^tmQ-Uy}LK_;AC{qK_z3jJ*cr5_L97f7>0~8NX3#
z;E|-it90^fVXGNy-YCYSoXMZ6wT??q67Rli!y9!cIBkbwUGcF>ZfD`hRP~>t0VB~J
z=tO^Z8dAMRRhItGAxx{77Y0iVs)Zmbysc)4_!Efi$x;Ta9Hq8U`3K7F5-Gb{DK}~|
zhHkQDy~cH(R6sISZsJ6|7j2i6-AV;yjVX>T45H*0s(D}yB6DF-iU!&2EJZhBlVZxM
zakou5nNE@J2A5h@xBbH_5jXeeXpw{E&CeL&OwNu#jYv9dZg-ANbK&}wRl-4Pzvf)U
z;bPgs(n=AJzQ)&9M~F#Vee@W!K~heKAbYP;H%g-J=h~oHYzvO9y*Qbk8yxE^Ja)Cm
z*rIRWk5F?jjpysn<)OA9U*I$MM@(o;YN*Q@MM(A`hYXzm7x`0TWnPnH6CryWK2s(_
z77LrWGB&NM2?8F`gf+tuV;61oQ>uc?(+pCUZaZxJzm9`3AEUmKuf6u(8JV#t19DW
z^5S`6N+$_TfcN4Ku)N3oJ!_>y(X@=}UbfD@oZkDKSF!
zg@AF${50C)i`4uzg9c}cq7PflK^awvc4y~*IUtkLwO(Vl*0I2|3{&&6g!^;t9ALNE
z=t&zkm}^{V`{a#8oKzXz$Z|gf4kyesY(oB-I#OcCU}Xu>Un8=$4slwF#w*wL&JxX+
zK>nWV6yM_PhG?*EmKkyyrW6X}YQP+W)DNakj@1Mc0qHKuB5CVvRk&1TJ+-#rKxJm5Uj+sIhKhe}2XZexG$v@S_WMtx#GqlI6CmNX3SGDKY
z5I-RlZ0`g@J3G`l6abVW9%!yw`q~2EM7HMAYKB(RcLwu-8
zs~N?oS(1T7)7gbC3GJAI!lh07+zW@Hm3vZ8Htq9jcS+of`PK5Cm1@57;!0uhvXj1+
zfDu_YIFoyPc-ebNFW!Sh&PtGPeshgX2VeOG$vKUep0}(AEYVE>-j}i&`BJ!UD!nYYkG~<
zOo?{;wM!6s%d#`r;Q8wZd`GW6=4C0KOB&Zidw9+tVtYcR{23RtG?tnqzZ|zNn3R+aBnyqoaJ9WJA@;Gom>4K
z5yawO?%A{4*XI-T;1dj#LlCSVnK^l)RqIyqEE3)BYqzQ;
z5$93;i`B4V693*hGZce;61%MM$fmR13*ON>CZj>Gvua0(T}f4GZ>R^0&-9=ChFot;
z)LVKE{HO4F{hf!x=RN;ke4c-Jd`7`%qz_Rmag?Ze_fSYZW{9#G%sw|XW|v#FK80DS
z+^r_{_~$_HBZJU8NWah)%N*mx`x08OwcxePrP6^0H~$?9t5wirWez>o_M=AzSqy|#
zGN%mmuT&29ugqSPqikjTD^-qvMK-@HrLg-NRJwJ-AW}2jUx|MONk4}YejFd9<_lDy(@{tyASFt-H?aU!*0{tQDq5`y
zX)J1tyqB#c0YI6*xh0=fV!m4YE*ymd>_I16wXCIcS>naynN)7PZZ+yYOk$1E+PKH~
zF!hA-p|LV`MFvVf8E=$0re8tQ2b)w6B;cY_5L6~JYcOYmZ*dz3^>>E1d1A(MR_&uc
z2_~yGe7%z)s2T*o`^W*0RX@I1jJd~yzLLQP-G^_7zQlqpBS3L6>P{BZbDd7$v(*=B
zpEa-FG*5KtmOAMDxIQ~fMx`D+zr3pGy&Tvpl{`5-y@v%JiULzb4!u_mMejm!{pfu%
zUsepJ_ghyEqIXa#%b_C$w+_8;z_29vRq9AZ>UhXi;9!(J_HZZsMU;a|zHsQBMenDk
z_hmAn3aw1-vmK=AJ)A@DaU;bzR4S%%>>4s?(0nP{<^^Iy!X|s?iCNR)4m9NJjYLSA-G1HW@}3mSu#&^xvlFKO65LQAv(|
z@*}Qt^pk;-|0o9_3IEN8M4*Wj_u~X!N=QVS3lv56i&P@W{GtFFgd?q}$zUlVz9muC
zT|frX#AK^lk)@jUNOyjX?D7d3D^eqL$z>O3@ivTA7+T0&A5uByEYODZ4_&hWEK;2m
z$@quD-Ba|H;_40J@Sgu$E{bEPC$NhQZ@RHLSjP$`Y9ZSo`823}F8E9T{XUn6
zP#s!^i#B)3O3yKp<;EA=8vmAfTrP5+7h2_?Z93N--<%|`f*dt2#v%LR&x4l@+T&MF
zWO|u8YQK3@?3Kh$JT5&?r9Cd`f;t7;?dNNt)@fO49qe!Uzp#G*!(r?nb;=(*4RklA
z?H@BU_Kz9=to`FZuzyrI_7CU>W@#K?|EMrtv@RC6WR-PsF+a6h$3-j{e2EjRlJUj|
z+T#o12o>`&Ct7FWdW%OJ^cBTO!>QO@SXQS_8D#nRF0+OH>@>9auMllfydQmq&dfAk
zfQQCIzoqT%)@&a;nCFTP>BwF&eMD0K;c%9iKBn}UKBi1Gx?sy3(?_*q`j|mLC`7GH
zMaXC|eKZ=Ik|MLwkr$TfDD^@edI_pa$Pwn)
zJVKt-Gu(KWX?NYndol2jT1KC-JZ7vMp0f8+XPZ+>OdO*=VQB*y&Vm{f$9noAX4_zE
z7g-h40Ak*Z6XqZgDigDHWnNn_gn?n*QvDMQ3@35XsFnnWR#gx5UIgh!;wdnC{d8#!gece%2h~2*sAwb>2AcArxrjP
zwT{cm+%gMiz?P8}u;uWNMzzfhwnu2Y?4Qx>;MKo2m(~9!M=yc-DMD_^S|^N;yLt^WEPzK&o47XI$@qQw(yVIV+cvf%+Ok^waBWQ6ooRivSs5
ziN2;<5q%ArOFUXyXA3zx8y=8>I$QN&bhcm4Q92uN_33O8(b**Cq8NIWyk#NL-5xT(
z%zidf1Ks4wP|J9Tr9_BD9deOaV}*x{391W%4J$qEvWR)P2YX)_Jgj0drL>lxhg46(
z3Rj}dT_##A&HaIb?RIYkl>FHoZSMaQeeO1(IE+3w`F};9tGxIh>T`9U
zTA!;stUkAf+2zyeb9GSt|3IH>C!!jbJB&UjYSrQOxwZd5pS$<}NS}-RGy2?cG0+@N
zp98Uh$UUo1x;w`I1
zjjKoUm7xzBr3NSO46V#PAfF9T=7@IwRLb0`NQjIww+UO?U}dgmR-ZCQPyy^7I1_f4
zd|Vl0+mQBqzv8!20IOiZ(I|6QoSnyq^n?70cBC*x*!9QKqfYX(%lux&L9llm;rJes
zr!e`n6S7?P(la8$lM@+WE914mMp7!<;mdO-zRH0UpJOoVXP!uJq$(fiG9f$80GCM+
zmr3}n?6#ZrIR+tFouo)OcO~&zBlnvl=&$skxZS$U$LSb-P7?*?`TBAn>!0~AqRv;v
z=6Mo3t;!=Rh9}-JKMNKrV|(MZvQ%Or5;2_6O_oPK``I(HyZ95>1|(!#NQ6={lQ2P+
zr+%iMr0*OT%qFXLj0gqQa*e*i#{yr|o55e~8c$+Gi`%Lk*>s+J;gK!)sVhgQsM$@a
zndTibA_7YdXD@0bdl$PVgOd6q!SwsB`s4PSE|mm6^ZY>!g9(XSP{oXwQ{R^BImK$Tpk_EnBDMYr&iO`3A0hnxh%-`TAAORO>VvYwjGZO&{o(CQtYp}4Cal+@)+CJp^2
z6GTOb0)$6oR#MJ>GV%Y^4dMTJ7%7+uE_3{yl7}ws|EW*=f2x!rC#3v8bs7IpJx$^N
z5l@^{O`Av{*-yrbmDUgA?+hC`{?4D1VSox`2S**_7-qhx7ypmr`x$aSSt>z6aktc`
z-9cYRfH199eHvHLd9t<_SCHTl&+1`aK}S(IIhxwxYdN5+k_olAZ{JvP>UaS)VEe2!Wj)^n}4jBOMrXvw4{Ti7bLB|etuRQJ+_XducN+M|L>S0qms=2z{?Gh`@7#X`&1a@uKy|WX
zTtl0K+*F4%dhBmh{2@jU$Un#EF-`KfT0{72pPDL0kH4G(vtBoVS%=gglgj>40=(tI
zuboI+$NupT_CsCoKvoVyN^>~3q95l9!uz;ZaZo>nFn2$cq^lISS*d{;Ku|7Glr-XS
zlDs1R>6498W6|$t0{ZONfWa>zrWKGUiC-y#`j%`6gAJGpJ|Hz&7%`bp$
zTFEtylsKl5`e?*4iC_qgUE)dXu!3h);Rv`dW7BQpIswYeI3d>HK4d7zS@Xbv7Y!
zjPk$VAvWt@G@*PS>)xj_q0FOTyZ!XZ@I_A_UktPd{vY_mVt{ZM`^gz<{!~VR|8YF9
z_`{rd;QjO-W*i(3oc4#+Sr?1_1Q~Nke^`U#51Xd15c^5vA^l;-D`G#9NZ?$5*qkB!
zVWPqR59}umV#Rl2N$1Ff1Ut>_?++VnKbZp+=la8bFSG1n{9$+U{(tHZQ^BqoPt?qz
z{b3_$2Y(p8uv(Do_`;?m1rdnKIx*YG@rSMYz0yx4>Q?+=1EX&BP7tetZA;l^kzJrV
zp0JsGgiA%axf+ADS#MZXkf6VBy?q;
zrQ~i(wA*i=09QXMTP4KRC3CzS8A+W%%w(!RYdBL)NQpYc3?dpA
zq#&rF6#0~K9np?B;*p#oaRIno<3WyDXUcwmB^f4;|H+R1=&8}=hU
z4`e>ieJA>mRLzH_x|~vx{soKaOdO&98T$I+PmaP1I3_>I(H%6LJpJ@eG-sbJ2~MSm
zLQ}vL0Vs%~5sy8JnN$#zV_TC;ClWT0Qe?A7*x9wqSJ1<7c?v!;OQKzG`3iQZdb-{S6>RERXH-XZ*+2Q`2%K>P
z3V6Do1L4yaCy+ep^M6UQZ8n5sYvU8OyQYX>godF8fB$nnZVW1N5ZNlRip7vZASGuP
zvxSONCBZi%Oztd&=69VXb#ebHP8y;LjtxnSw$888-{_2WEqsE#K$$A7lKfawTl_1B
zYGos%L^lMi^eG|M>^FH7(GPHF8f}J`Z0UJz$ribN&E&uj&IsX5kfKl6Ou2$HLN*nw
z1MrBkW5atw!$n&PY<`Q4^E1V+kkOTuTfnN#bN})@T1}iFePt`(v8s3BZ10YAdKYkN
zkf08sWCss9@O#hv=tPkfP_;+xPx^d==;)=#F*Y|-MGg%P9-lI$pNH*jH*zM$7XDb?
z|Ne8fI!w|o`xk_0O5I!wy+>)v9`#jvk#mL#gD6oB5OPyu#<1IBj4?
zyp>Jlj&|i)-rddF&9mpq=l@CaPkXw8;YUT;SL6Z*qYEHKoe~{z>)=
zweh07eUhc?@3@O=)h$yF=#>S
ze78C(ZvL0e`tOM|X*?B4M(2nEs+LX4&Aq+(f(){<`MP-%mN%Ia{3`JIEtcn>wv2Q1
z+4I=g+H=H#g3pO(3b0TY@bf@0*-$idmHg6Z`t>73r{4bvoCi4Cz@Dx!CR$(h8$T>l^ezc5%dd|2=
zwi01E@agMzfQ<|U7QhF}uLWOma;;RbpO?WfHcVJo)%8Xm*Ojs53-ie92)+zb36SkW
zDIP4R`SsD7uwTI5=ZILLED_2Q*(LN+MS)rhijrCn4aub5pi5fNSI0p4iOh_b&TPfk
z(~RW>tND6H!KPob#Ns5r7x~F5V_HiXy3g{4@q7+nkomT-`7MVp9!m4YPT`9L5%z!a
za;zs@S~EgTi?V-lI8ky{9#Gp^wg#A|mA#haz%#*SIbcT8JmmKD_BJiz+<2{3GH=p}
zX%vpcYW&)gyLk|+snr(iTntJ8dU;$jV<;xhXS~bJ@UKy6!(vzTU}ng7xi=X-T|4t2
zk>+kS$|HJw7@^UBvEN#BJgfP$m2H>Q{L(%;cd`mu>CkXb+y#bSVHxg-#|V
zv87Do?3ejRNYYu!(pN`-9)Dvi;)U&1j020jRQ?c=~%CRIs%t&LQIJRQ}TXqAYbU4TO#Ba8y
zo+C#JHJFd6&L3r5=~^{eb!h1BPn51J%+k$)DELNC9}0l0E{z7D$)Lb%UFJ^tV%@6a
zFVUwG=McgH9Y>hh2b^Pn0(79SCUswlJA;{*|FX8K8Rg8XTiH>
z>wZSVV9SJr*vhIeoj+^BZph1F+=-&MsFY0^4v8>nfaRe%B<1dFXs**xTpIESH6FGh
zIo~)#pO$y*rP+B=TPs
z%$a8@wj0)tuD;`FvwRtG=*Jo#ckS{tzoR&>rz@GKznR}mhy&6U_c`*F!x9MmC!y6{o@o>FMb|6GKv~=o{d;%O+0k`fow1Og*UoZH>_*tdbaeey5thO{3j7
zebogH<36P1)(W4YE@BTUwBIoh)muJPsFvAF)=I4Xs8nD~T~3(x6X{yb&lqPI3q9tL
zb)Gn|PUBE@O8?hyPr4Pt)9Yqu_AL<=?gTNV<5Y=}L*;Ts>UG+lt}3ndc{+_LKp7?0
z#82rrg-cqg3*$mfghe-q`B-Ju6OsnW%(rayh|TqAi(9CqXC)Ept^}*q&(@^!*6&JZ
z@cXO#Blm}9bEdP$8pXymk8`iHw_m-8H7f*`3ROY3vg`~G?0EZbkm=BDn7;ZI;lW86
zpwt030+YdX{GA_rWTx;yIuSk+g(77CC+-Bx`@PHhi-_5TiBdGeXZ(ct!edY6ndRO5
z=!r77qsw_@SCxG(Pwh3Tl8UNqB~f{$*I<;Q-D8Jnmys`FzC*^^;UOV-d*)yWUgDYM
z-E~hE0y4w7?5BAu;BYN4t93`+7p3IW&u2?Y>IwVX{YzE|aN{XyKY0y*JVSQknQE!&
zxvAN%O^})%;%P>N_9G6Juj@^UaK0hHOf#zjU2hb2*?DP!`iKCDQCYIzTh6se-UfBj
z*wj=4OpCf%Wu(nqqW3W!^EhBX_K}(_M6VO;m8hSx7f%9p#0exRjl?M?N61PlOW80;
z!)oj*@O=SJF`t!8Sj}Jg(AgL&Hq6e2OB~GEYlHZu!s?%F3fR%UCDfAf!C5zUYN5>%=l=PF~gjLe!Xk`dtGlI
zSFp4B?JN1O`5pOd9B}s-m7>u2*6&I`5)sS2b4O~6Inlt#UGRzDEQuPZr+HoPj4z<@
zB>roDTmBj!xetO9;S)5$^fU6#$ph!keLz(sDJ@hrySm=vZ0K;oPW5TJXxC1UD(4^h
zQS)0G|AB8&e*(>Kt2@+8U)Niq0?vhS?{c8_V48AE@+r^A12UXuc~rE~K-XIVitThC
zFiN7l^>bbk={ab8v~bmb`ZJ2hnG_$IzBK+6;b=<=t_DC=YtPD99VL3i5KfXWx~d
zHRLX(Br{mxq}KSr{C#wt)XC|(zmKZC3BQl7<^gdaTFW;?zd7jFTCQPSt@yc|O?Y(d
zL$*F1U_Dh!Qj&Odw&-x?)2b3S=xF3`samGBZW6d2jEKmni)!6yi9R5o)<@^6?6Xs$v0EYUxyeU;z|uXuE0u5E+}qCb
zki*3%>@XizpIMFLdefI>?=c`1>Th}aQStz0O=@PnJ#)J9kIhc$i6aYup`uICERB
z9@bM{edZKQUWZgNr+Cb>7+`>um4Z4zo{j{-Mv&stRc=FE3L?1-n|G^5nXvgLVt=2m
z(62iBH9NLCxm}pX0ZZ#}r3XYm*OTx*0o*QvKUwv>;VF3ESgEfL=x@UlVA%*p*z%cZBQl?a1|S7pz>?Hrcf-`3D|~pJ&1{{o}mE
z70&xf#s~V_lQ=IuT`IOQKCIoE?B+bm5;ZA^5|-(u{pc=d5g{iJkQqLpZ`;`^y5Puy
z^=-b?RcKa;%bj``8a?{kBfH+tA6W0W0hqI|$=10@>h$Sv{`tOj_I>(0lL}s3vb8O=
zWNY)YodD4dj)YY83QwXTjb}UwiIe2a||tdh<$jI~dxrnePspy}=n?=ZSEidGeDy${6Smu@0`_HCbGYK~)*I>EfxVdITm
zJ3N@CgmsrIfv3Nf?^PSBuz}!z$ff4K*Q&AYiD7EE1#uU8`m>mlQGKuz7@fGT1%m!jqF8~(;
zLQ>48=^h#PMt>@mO8q!PkcN=Asuak&w&(F8V80+o$2i6dXOg=+`UD@*qRex$pq6>A
z5osAgVEkTQ{obh-$^QH3{n9`@Dx(9mvcB-yN1VvyN263*GNHSjpGr7PN?PUaG@Kw+
zH6v^G7N=TS$2k@1`#hR{uIP~a@)Eae9b@(Fe-^|sUU~Pm>jz|gaE&`v9$Oyw)(~%d
z>VWRqzkD~1GpuP0zgWcuX99vw4*la|>k`MxH{#gJ;5i}RIAt=(B&kznbizvMpFQh%
zW`GBo0T|o|s0V9DMC&-U{ruR=h^{7{sKb##Km{F=`_!=5%b=~Cn4haW2*lLsa^AAU
zN*h0j{+0qHg4@6u8XsB>z2tY!SA~Fd4lT%QDUIRQg#f8GcIt0w&Cd%_>z{ZQj)K^c
zbRw1>;wSl_h^VL4_0qQCOWT<;X}LmQv46^wQZ6+Qk)pL0Qk&G2-}P3Wu}goxij#R4
z_?lnrlp;Jq9!qr+4KgO`+{YuNS-z
zA=X>vW0)`JADy0WBwHD_k?jSWgo-pPK4x$F4MruIaiu|JRVhtHrO`092o|W)D!=ts
zNm)+Yw9KGSB{zDZ>dIGrvEAB|e5iK{`Pk_#S?cOR%nHn;FE2RN_;A9@*5~*4ysCc!
zpvL+?flJqhcZzzft9mi3Zu1oEF50L*cpV;5GZZ$}yx7YN3zuv`+HPsLzU-+=ovknD
zSz??L@_#Pa=)42fqTSAptxKNf*po81l9qZU#IwTFUKQK8;P1vxM9&{BZ&_JZ)hq%K
z`@GMvhNz6%uiTqnyRMUQT*;{eHSl$N)oO%AsX)GR`l7?ErOamnz``bLWpTCSh
zp$7SE=JnaePLsx7I+Iu9#?s=$(Fb?{UntZQDoHP7-*8=;B$JErtSk3gdhayUE?;OJ
zX9+bFtrQ|Fc)#6RD2d9d_*a|$l7j1`>fbvpP>iB;7-Z1{V3MlXmU%xHvvrL9ygo`Q*I7LuXdSDinD)q8na_BYPViT>{33>57-_B4muj*P
zghcsYl8^Ygiv`J0`u@YB2Vzx1f>P-;oZ~Y@c-+Hd3;R5|4DJl6^++SWl$UxwP!PtGc-f+VP8pX0|nEX@)drtbad0c=fsVaw&P)FSDyp4r6fH!Tu$u0lvNfWMpQ-LHEL2I^5lCXTVgR!3pjWnOtLwk!T(8Tyem3X&3AtYF
zlz&*Rw>Cf5L`7|l{t(@-Hug2|llytY!PdMtQ^)c%e}ufPPChN|roWw=Q_oDU?K6%R
zYJSoMHJ7JdgZiq_XD$6yIQtU5Q8At5PZf1uwSer0pCBuwVBKl+AJ
zWc#e@_9?{uRwiUG^3H0lg}i#Vx*~KvV3;
z2{FW#P>$db$@6*T$SlRkIi~iJWr(kJ_L5OvmpCY^?Em7b-F~Il<4PWnxEP9G^H?|N
z&o*($<=xR1Y4l#T%wgWYn>z%vkI1(5#;a_E{=Hh>B*kzB9CNjf7)$QbcKw~Nb6}oI
z6kOWV-NaXkQ(AiyeqsBwDT`9{bl0wY%8I^MuGVm34=7JQ?xm(VAfZ0Gh%XB8$Mhyi
z)Zr477dNkoQiQ1hMv-#23K}?JN&jTb!g{Lmry7s6q}^1hn1R_TFt`*1+kw+&|wjzG-ZSRt;
zgjH4E=!&il+qjArywVQPVfQ-RvKU=zz~*jwPFZo>ZDxr|
zM`RjU#P4i=rzV5+*1A2vYgeAWEx%v;7o^({S-0;W+`hg|J2VKP!+;>#a$_2Vnfx{;
zr$U2R?UBSM$~xyYt>dV4TC+=vUdA}z#WeSNK@Z2KJ2U|$&op)*#pfCal7EJm^v=B`
z1;cP5*9^}QOWX2M1>f_XpZXixUPgbEr^W%i1^PQ$^NXUg+}C!#`#veCcju*^gc#d-
zh-#RS^I`8*G&y0t7l)
zimjjgf#kbJofpIkAv2Y}Q?#pKpA+9-+OtxKA@OwbPU#1jK$~Ob#K|+vxE~elYBvsK
zA%{+8-q$wlzRv-@r{)4$5nu64G+Cis2T!f9Eqqcb?wPu>6;WumQgHcvm#=2Be4hRY
z%AYND@bPNw{Qu0L%uY%iu_*yjgijr*zo`{G-%i@ZOJH_Etf5R#x5n1Zd(AA5#?~zu
zJ7JxG_8xHUEZUhaC5;6So)t39pV|}i90n4OOa*;8KE%?ha1b2$3Qp+i!rt^
zKvZG{_48ZGZ*6L<^l3sD4XFw-STbx59I;IcPZ5UTMX8EZQi{~;1-q@V58X-8zyV@b
z?xEq-ZLO~@n8JX?*`I0HW8PzAON9@6c~)X<&M2|FtgrOa1r+lQZ&Pnc(awV1?o5L$
z3#foVIDul5BHWMF65`fmA=;_&GR)MxRtU1~7+JyS-TS8)yIBj)|C>r?Cr@`kqkE^w
zX37teMWT$wqs0nyZ__O9!h)S{5vl^bbQruY_$xvrrqE|>loJaH7!-7i1SvJT(rT9=
zp=ifNMK9-kocsmjXy2)!+N$U_22+isZ}3RI4uX?q6t`|0PVW_|8!rnBC}E{_oDM-j
z>~DP?arIWwj)D!==OqNcv}Z*VpeAI6kp75ZRz6F98Lw!~1;EIW0P;YP#&0n8$^2O`
z)Eup2JoK`?V2fB8)mZK0bY@D;>Err8(P&AQ??FEAhA*Yr61XM%d?{UMy9mo=&^ZF+XtK^AS_?L|yEk2cy7(gERHV+w$gxWo*tiC+^TjwcXm(YKZO_CriBHm5MssbRgy6l_p|3f^7l%zC~
ziX0PoJOHJd2DYy)UZ(mGMCtHJCH(r+zXACrr})!eWmiE-lV8I2;6c>Qu00-CS!e19
zYh2_))Re}%f>r0V@x>h)p!r(z)D7y>X{NW9vzvw8iP*pn%(s)96m%jweTE!rBsGV0
ztkF+O753;OM9=t24>*)Ge22l`WfD-=o(OeP?=`=+voB
z*VMJ?oy!vt=`q|!p~rz4f$*y!7y8$^K@qe^DYYaNy{v)^Eaw^1XRWFtkdrSW()-b>_v>iXz8C8fkBQCDTD}9&oWxuas|&~Dd>%FxMe1Go1_u!G
zf@8hO6JN&yn${ZvUE2yL$bz{zw-R|r%R0Z0;7nScO
zHe{C##ZvYao;rMdF<-UYzxWV7zDuo$2J(}ZK949W;97022-dLG+LA3Y+Fgjho-UDt
zad#DX;yfPQpMo$js_5z9aqb)rp$g?(R)deP!DpWvb3~?KT@esN*++j>>mB-|#z>3H
zs;hveGSmUe!m5c=-%=D3(L1YXHS?NZwM4W1yzZ-UCpE&cictCr1DAwidhD%#Q*|M|
z1J-CYj!Jkda_oAuP}<83Bfm-v+a~T5)ggja`9IB=63_;PIfUcT8PU|`>y!GMZp(k6
z3{%ejiJCXjnYI^Ve?g@7!q92I*~-YO>kuxL?Ww#31l)c|E_U#HUcH1Wd5MVOuWwJmS<%gmjgRUC*0`
zl{w$yTZ)A-8~{cnc2Q}ZBiWFnH&skXnKxBAF}tiHiYKfT4QR~9)Clsro<7|B=1KtTvek;cvX!e**ozcMujQ)Uj_!i4hKSc5ERQ6*QhzsKdSy4W=+UH>%vA>~ezu`Z#wacK`wZ{o}jo%3t3UU>y!ToQ+
zej)kPi6F)~wJxPS)2)tU|02(=!lw3fd|HRcErPhuLTV?*x{*@ex^Cj$JL6t^<0OxC
zrj(|!G)Bu^4m#J{`WtTWP-6L^Cl!iUX*I6(AW`hQIJgQdO7tQz)2X?ZH(uzdZ+qR&
z8*%)~bX(entA!1{M**V*CsjT%lV*~`gtHwOWKV*E8})IzDWnt4RCf=eRNbx
z6uBw^Q71Py6-U_0rn>M_ypYsA1@@87=P)E})lh-$`Riswhz&fqQlY-Bvuj7bQX^(P
zr>KE)A^pws=vmY;d;^~~{SAW+Gb}B~?2(mduh|eat0Eh0vYBt#u#H_aTR6mRYte4u
zsG`*c%h_)PBt`=Mc&})qF
zU+~VlsW-D(hm@fAibR4;ty*$i*Ai$9P70sRBE3-%fZkdv&%Gd1W*t8uh@=XG&F}G2
zW?shAGd%j=W=Z$nWEFV@;<(#PKWAZU(xPHUzk^?*MQ&^CSn{
zaslgF4pyg5r9~}u-e*C++}j`I5FjrD9Os%72w{sDQP=O#
zx4Et0^tJ#i`bAU!DX#?=k!IEe^RFjGr9}KcfG#)9)x_!@3>XGs~4kTfv)*MDvUBJ#3Bc
z{0Z{yaZe54gqZYYq3B?vjbIyl=jn?6$a#Vwpgc;O*-%b)=+!;jxMx|gHve;e<8yu5
z)fH%0>$2L_SYt(Y3&H9km8(vMNhTGBsZYU@P=@X7`UX#;(6KKj(!Gjb;0HyKZii~#
z+$U6XHrDCno-A4h<6}b_AEW&&&5&MUb6h~KAP-jOY2GB0FVw=z*rq!cnx`pMak9%S
zzpMG6iy2DOo2Ug)2tfFQ3ljKcr_aL~*zuzbCvb<|Z7w^&%$s@yyarUHY2Wl_dEXbu
zhG^*Fd8%82(Xm2E#$8fVasf=Y(i_BV;Fbw{!S&Opx
zi%Ez6f|dXYfj%`Uid?s=Dk#2hB7ZKB57(EG$WElGpa*OzEtkgBD${lFuD|O$QL!KWdKJ#!N!Upx{dVHx0
zg5tyB>r3g%g$QY*SUQ^-P=5Ur!7sl7p&ou^)2hpMsm3GS_B-3?c&qC8p!P3ze7T3J
z`1qkJ{)N}8XqHh9A^7rCv?m+?Xlju(^}RkE4{Gl$v3Cm2`jMQo&cBq|ly?E%@#8!@
zRgE4N$m6Bv-?9@uE&V8wMT0PrpkYX8Klb#4c7eXPFi{QyBlaUD!p)&^S$-NPXuC}U
zUp%KFUp&}>cu;{uoYo@x-Xjtv_U-DUzulSrh=aUYpU6iq@+$LDJ|6*62``}l_PrxV
z<+l$tLym{Gm>q1$-xAaNKC_1ye!8duOp~j_n%3L8nH1bBdNviUX74QrVXzb~w$$@oMrF98VQ6B%q-B?F&N?OV9OL6K63U;#N@
zt~@1#yncJXa^t03=6yNlmQpsor$I%8XQ)!uxtpMvY*|@>t6E8wR`_>1c46yUt#uDQ
zYkfg$-6=gR{F`h5UK1bg1jTU}Xy{AlsI}qVbxIORSb4cR_O+CL6iXk7{o|7Jqoggy
zA2b!~ANvxYp|caS70^wO2xI$CFR6-Tg+NK!1Eo-)-kmR1c=xMK$ah{qWdlo5fugY?
zS#2q*0^dk$3ndgG5bWbyUGGrgtyR&@=>3jY0lNhsT
zY;C41qQ%tD$aX~t+x`vyH_Q9s-?Lp&M%DXy+HTK#ovxgNJnBdB1N*ap`2t&oL+f!d
zbE|z~?zL9EyB9L=Dq0>}yCB5Lz}U-|%VJfCR)r9K3wXsYVf$$5Q1gYh_)Nu5#bBev
zP~$GtqiQ)UHo6_Amk||gXe}?(VZIb17iGMp4>N2k{!+0Z;wbmY=I6ZkVxf%wHa*%1`uhW&2gP$T#!G}aniEE?P$3$oxe4{a|8-a
zmtZD{N~W5CRg+;zszIN7UI~kU3<
z)N=f4#J(RZl}ZU2<#8x`_NA;3ig^+i>fu+Y2$x24knI9n`LNi&PCj&wDV-{pJv