From 6031e69928a949974c0a5c13046cbd556a4b690b Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 23 Dec 2024 13:28:53 -0600 Subject: [PATCH] Update to Rails 8.0 (#199) --- Gemfile | 9 +- Gemfile.lock | 146 +++++++------ bin/setup | 12 +- config/application.rb | 2 +- config/environments/development.rb | 20 +- config/environments/production.rb | 9 +- config/environments/test.rb | 5 +- .../initializers/filter_parameter_logging.rb | 2 +- config/puma.rb | 66 +++--- public/400.html | 147 +++++++++++++ public/404.html | 206 ++++++++++++------ public/406-unsupported-browser.html | 178 +++++++++------ public/422.html | 206 ++++++++++++------ public/500.html | 206 ++++++++++++------ public/icon.png | Bin 5599 -> 4166 bytes public/icon.svg | 4 +- 16 files changed, 821 insertions(+), 397 deletions(-) create mode 100644 public/400.html diff --git a/Gemfile b/Gemfile index fd050349..1a6c9c0d 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'omniauth-shibboleth', "~> 1.1" gem 'omniauth-shibboleth-passive', "~> 0.1" # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.1' +gem 'rails', '~> 8.0' # Use mysql2 as the database for Active Record gem 'mysql2', "~> 0.5" # Use sqlite also @@ -45,7 +45,7 @@ gem 'twitter-typeahead-rails', git: 'https://github.com/pgate/twitter-typeahead- gem 'net-ldap', "~> 0.16" # Use bootstrap for styling -gem 'twitter-bootstrap-rails', git: 'https://github.com/seyhunak/twitter-bootstrap-rails.git' +gem 'twitter-bootstrap-rails', git: 'https://github.com/UMN-LATIS/twitter-bootstrap-rails.git' # Use special bootstrap select gem 'bootstrap-select-rails', "~> 1.13" @@ -73,7 +73,7 @@ gem 'starburst', github: 'UMN-LATIS/starburst', branch: 'feature/rails-7' # notify someone when exceptions occur # and notify slack channel -gem 'exception_notification', "~> 4.4" +gem 'exception_notification', git: "https://github.com/smartinez87/exception_notification.git" gem 'slack-notifier', "~> 2.3" # For URL migration @@ -148,7 +148,8 @@ group :development do gem "rubocop-rspec", "~> 2.4", require: false # Use annotate to list the attributes of models - gem 'annotate', "~> 3.1" + # gem 'annotate', "~> 3.2" + # TODO: fix to work with Rails 8 or move to annotaterb? gem 'bcrypt_pbkdf', "~> 1.1" gem 'capistrano', "~> 3.19" diff --git a/Gemfile.lock b/Gemfile.lock index 53a41431..50cdd981 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,6 +6,16 @@ GIT starburst (2.0.0.rc0) rails (>= 4.2.0) +GIT + remote: https://github.com/UMN-LATIS/twitter-bootstrap-rails.git + revision: 441803d95edc44291eb8526fac8338f0d469547a + specs: + twitter-bootstrap-rails (5.0.0) + actionpack (>= 5.0, < 9.0) + execjs (~> 2.7) + less-rails (>= 3.0, < 5.0) + railties (>= 5.0, < 9.0) + GIT remote: https://github.com/pgate/twitter-typeahead-rails.git revision: 105a036048eb4c19a1d5c0bb7aec55346c8b506d @@ -16,78 +26,75 @@ GIT railties (>= 3.1) GIT - remote: https://github.com/seyhunak/twitter-bootstrap-rails.git - revision: 6e0fbcb0b200f2dac8a40a5cfec54e7c7b35f442 + remote: https://github.com/smartinez87/exception_notification.git + revision: 60e158888bbff96f7a9ae00ae97305cdd33726e9 specs: - twitter-bootstrap-rails (5.0.0) - actionpack (>= 5.0, < 8.0) - execjs (~> 2.7) - less-rails (>= 3.0, < 5.0) - railties (>= 5.0, < 8.0) + exception_notification (4.5.0) + actionmailer (>= 5.2, < 9) + activesupport (>= 5.2, < 9) GEM remote: https://rubygems.org/ specs: - actioncable (7.2.2.1) - actionpack (= 7.2.2.1) - activesupport (= 7.2.2.1) + actioncable (8.0.1) + actionpack (= 8.0.1) + activesupport (= 8.0.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.2.1) - actionpack (= 7.2.2.1) - activejob (= 7.2.2.1) - activerecord (= 7.2.2.1) - activestorage (= 7.2.2.1) - activesupport (= 7.2.2.1) + actionmailbox (8.0.1) + actionpack (= 8.0.1) + activejob (= 8.0.1) + activerecord (= 8.0.1) + activestorage (= 8.0.1) + activesupport (= 8.0.1) mail (>= 2.8.0) - actionmailer (7.2.2.1) - actionpack (= 7.2.2.1) - actionview (= 7.2.2.1) - activejob (= 7.2.2.1) - activesupport (= 7.2.2.1) + actionmailer (8.0.1) + actionpack (= 8.0.1) + actionview (= 8.0.1) + activejob (= 8.0.1) + activesupport (= 8.0.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.2.1) - actionview (= 7.2.2.1) - activesupport (= 7.2.2.1) + actionpack (8.0.1) + actionview (= 8.0.1) + activesupport (= 8.0.1) nokogiri (>= 1.8.5) - racc - rack (>= 2.2.4, < 3.2) + rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.2.1) - actionpack (= 7.2.2.1) - activerecord (= 7.2.2.1) - activestorage (= 7.2.2.1) - activesupport (= 7.2.2.1) + actiontext (8.0.1) + actionpack (= 8.0.1) + activerecord (= 8.0.1) + activestorage (= 8.0.1) + activesupport (= 8.0.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.2.1) - activesupport (= 7.2.2.1) + actionview (8.0.1) + activesupport (= 8.0.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.2.2.1) - activesupport (= 7.2.2.1) + activejob (8.0.1) + activesupport (= 8.0.1) globalid (>= 0.3.6) - activemodel (7.2.2.1) - activesupport (= 7.2.2.1) - activerecord (7.2.2.1) - activemodel (= 7.2.2.1) - activesupport (= 7.2.2.1) + activemodel (8.0.1) + activesupport (= 8.0.1) + activerecord (8.0.1) + activemodel (= 8.0.1) + activesupport (= 8.0.1) timeout (>= 0.4.0) - activestorage (7.2.2.1) - actionpack (= 7.2.2.1) - activejob (= 7.2.2.1) - activerecord (= 7.2.2.1) - activesupport (= 7.2.2.1) + activestorage (8.0.1) + actionpack (= 8.0.1) + activejob (= 8.0.1) + activerecord (= 8.0.1) + activesupport (= 8.0.1) marcel (~> 1.0) - activesupport (7.2.2.1) + activesupport (8.0.1) base64 benchmark (>= 0.3) bigdecimal @@ -99,6 +106,7 @@ GEM minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) airbrussh (1.5.3) @@ -106,9 +114,6 @@ GEM ajax-datatables-rails (1.5.0) rails (>= 6.0) zeitwerk - annotate (3.2.0) - activerecord (>= 3.2, < 8.0) - rake (>= 10.4, < 14.0) ast (2.4.2) awesome_print (1.9.2) base64 (0.1.1) @@ -175,9 +180,6 @@ GEM dry-cli (1.2.0) ed25519 (1.3.0) erubi (1.13.1) - exception_notification (4.5.0) - actionmailer (>= 5.2, < 8) - activesupport (>= 5.2, < 8) execjs (2.10.0) factory_bot (6.5.0) activesupport (>= 5.0.0) @@ -287,7 +289,7 @@ GEM mutex_m (0.3.0) mysql2 (0.5.6) nenv (0.3.0) - net-imap (0.5.3) + net-imap (0.5.4) date net-protocol net-ldap (0.19.0) @@ -360,20 +362,20 @@ GEM rackup (1.0.1) rack (< 3) webrick - rails (7.2.2.1) - actioncable (= 7.2.2.1) - actionmailbox (= 7.2.2.1) - actionmailer (= 7.2.2.1) - actionpack (= 7.2.2.1) - actiontext (= 7.2.2.1) - actionview (= 7.2.2.1) - activejob (= 7.2.2.1) - activemodel (= 7.2.2.1) - activerecord (= 7.2.2.1) - activestorage (= 7.2.2.1) - activesupport (= 7.2.2.1) + rails (8.0.1) + actioncable (= 8.0.1) + actionmailbox (= 8.0.1) + actionmailer (= 8.0.1) + actionpack (= 8.0.1) + actiontext (= 8.0.1) + actionview (= 8.0.1) + activejob (= 8.0.1) + activemodel (= 8.0.1) + activerecord (= 8.0.1) + activestorage (= 8.0.1) + activesupport (= 8.0.1) bundler (>= 1.15.0) - railties (= 7.2.2.1) + railties (= 8.0.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -381,9 +383,9 @@ GEM rails-html-sanitizer (1.6.2) loofah (~> 2.21) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (7.2.2.1) - actionpack (= 7.2.2.1) - activesupport (= 7.2.2.1) + railties (8.0.1) + actionpack (= 8.0.1) + activesupport (= 8.0.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -523,6 +525,7 @@ GEM unicode-display_width (3.1.2) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) + uri (1.0.2) useragent (0.16.11) vite_rails (3.0.19) railties (>= 5.1, < 9) @@ -554,7 +557,6 @@ PLATFORMS DEPENDENCIES addressable (~> 2.8) ajax-datatables-rails (~> 1.4) - annotate (~> 3.1) awesome_print (~> 1.8) bcrypt_pbkdf (~> 1.1) better_errors (~> 2.7) @@ -574,7 +576,7 @@ DEPENDENCIES database_cleaner-active_record (~> 2.2) dotenv-rails (~> 2.7) ed25519 (~> 1.2) - exception_notification (~> 4.4) + exception_notification! factory_bot_rails (~> 6.2) font-awesome-rails (~> 4.7) foreman @@ -601,7 +603,7 @@ DEPENDENCIES puma (~> 6.0) pundit (~> 2.1) rack-utf8_sanitizer (~> 1.7) - rails (~> 7.1) + rails (~> 8.0) rqrcode (~> 2.2) rspec-rails (~> 6.1, >= 6.1.2) rspec-retry (~> 0.6) diff --git a/bin/setup b/bin/setup index 811e0f1e..5ac96be7 100755 --- a/bin/setup +++ b/bin/setup @@ -15,7 +15,6 @@ FileUtils.chdir APP_ROOT do # 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 ==" @@ -29,10 +28,9 @@ FileUtils.chdir APP_ROOT do puts "\n== Removing old logs and tempfiles ==" system! "bin/rails log:clear tmp:clear" - puts "\n== Restarting application server ==" - system! "bin/rails restart" - - # puts "\n== Configuring puma-dev ==" - # system "ln -nfs #{APP_ROOT} ~/.puma-dev/#{APP_NAME}" - # system "curl -Is https://#{APP_NAME}.test/up | head -n 1" + unless ARGV.include?("--skip-server") + puts "\n== Starting development server ==" + STDOUT.flush # flush the output before exec(2) so that it displays + exec "bin/dev" + end end diff --git a/config/application.rb b/config/application.rb index 598b764a..319514ea 100644 --- a/config/application.rb +++ b/config/application.rb @@ -14,7 +14,7 @@ module Z class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 7.2 + config.load_defaults 8.0 # continue to use `config/secrets.yml` for secrets (removed in 7.2 in lieu of `credentials.yml.enc`) config.secret_key_base = config_for(:secrets).fetch(:secret_key_base) diff --git a/config/environments/development.rb b/config/environments/development.rb index c22d02b8..bf7de1db 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -3,9 +3,7 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # In the development environment your application's code is reloaded 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. + # Make code changes take effect immediately without server restart. config.enable_reloading = true # Do not eager load code on boot. @@ -14,11 +12,11 @@ # Show full error reports. config.consider_all_requests_local = true - # Enable server timing + # Enable server timing. config.server_timing = true - # Enable/disable caching. By default caching is disabled. - # Run rails dev:cache to toggle caching. + # Enable/disable Action Controller caching. By default Action Controller caching is disabled. + # Run rails dev:cache to toggle Action Controller caching. if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true @@ -39,8 +37,10 @@ # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + # Make template changes take effect immediately. config.action_mailer.perform_caching = false + # Set localhost to be used by links generated in mailer templates. config.action_mailer.default_url_options = { host: "localhost", port: 3000 } # Print deprecation notices to the Rails logger. @@ -58,6 +58,9 @@ # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true + # Append comments with runtime information tags to SQL queries in logs. + config.active_record.query_log_tags_enabled = true + # Highlight code that enqueued background job in logs. config.active_job.verbose_enqueue_logs = true @@ -73,8 +76,11 @@ # 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 + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true config.omniauth_provider = 'developer' + + # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. + # config.generators.apply_rubocop_autocorrect_after_generate! end diff --git a/config/environments/production.rb b/config/environments/production.rb index e78c5872..24dd29fa 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -6,14 +6,13 @@ # 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. + # Eager load code on boot for better performance and memory savings (ignored by Rake tasks). config.eager_load = true - # Full error reports are disabled and caching is turned on. + # Full error reports are disabled. config.consider_all_requests_local = false + + # Turn on fragment caching in view templates. 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 diff --git a/config/environments/test.rb b/config/environments/test.rb index 43d63bf6..54c8c476 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -45,9 +45,8 @@ # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Unlike controllers, the mailer instance doesn't have any context about the - # incoming request so you'll need to provide the :host parameter yourself. - config.action_mailer.default_url_options = { host: "www.example.com" } + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = { host: "example.com" } # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index fa40e0ad..912b1594 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -4,5 +4,5 @@ # Use this to limit dissemination of sensitive information. # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. Rails.application.config.filter_parameters += %i[ - password passw secret token _key crypt salt certificate otp ssn + password passw secret token _key crypt salt certificate otp ssn cvv cvc ] diff --git a/config/puma.rb b/config/puma.rb index e074d7a0..63d385b5 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,47 +1,47 @@ -# 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. +# 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. # -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } -threads min_threads_count, max_threads_count - -# Specifies the `worker_timeout` threshold that Puma will use to wait before -# terminating a worker in development environments. +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. +# +# You can control the number of workers using ENV["WEB_CONCURRENCY"]. You +# should only set this value when you want to run 2 or more workers. The +# default is already 1. +# +# The ideal number of threads per worker depends both on how much time the +# application spends waiting for IO operations and on how much you wish to +# prioritize throughput over latency. # -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" +# As a rule of thumb, increasing the number of threads will increase how much +# traffic a given process can handle (throughput), but due to CRuby's +# Global VM Lock (GVL) it has diminishing returns and will degrade the +# response time (latency) of the application. +# +# The default is set to 3 threads as it's deemed a decent compromise between +# throughput and latency for the average Rails application. +# +# Any libraries that use a connection pool or another resource pool should +# be configured to provide at least as many connections as the number of +# threads. This includes Active Record's `pool` parameter in `database.yml`. +threads_count = ENV.fetch("RAILS_MAX_THREADS", 5) +threads threads_count, threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. -# -port ENV.fetch("PORT") { 3000 } +port ENV.fetch("PORT", 3000) # Specifies the `environment` that Puma will run in. -# -environment ENV.fetch("RAILS_ENV") { "development" } +environment ENV.fetch("RAILS_ENV", "development") # Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } - -# Specifies the number of `workers` to boot in clustered mode. -# Workers are forked web server processes. If using threads and workers together -# the concurrency of the application would be max `threads` * `workers`. -# Workers do not work on JRuby or Windows (both of which do not support -# processes). -# -# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +pidfile ENV.fetch("PIDFILE", "tmp/pids/server.pid") -# Use the `preload_app!` method when specifying a `workers` number. -# This directive tells Puma to first boot the application and load code -# before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. -# -# preload_app! - -# Allow puma to be restarted by `rails restart` command. +# Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart +# Run the Solid Queue supervisor inside of Puma for single-server deployments +plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"] + # Specify the PID file. Defaults to tmp/pids/server.pid in development. # In other environments, only set the PID file if requested. pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/public/400.html b/public/400.html new file mode 100644 index 00000000..515c404f --- /dev/null +++ b/public/400.html @@ -0,0 +1,147 @@ + + + + + + The server cannot process the request due to a client error (400 Bad + Request) + + + + + + + + + + + + +
+
+ + + + +
+
+

+ The server cannot process the request due to a client + error. + Please check the request and try again. If you’re the application + owner check the logs for more information. +

+
+
+ + diff --git a/public/404.html b/public/404.html index 2be3af26..8dfb0798 100644 --- a/public/404.html +++ b/public/404.html @@ -1,67 +1,141 @@ - - - - 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.

-
- + + + + + The page you were looking for doesn’t exist (404 Not found) + + + + + + + + + + + +
+
+ + + + +
+
+

+ The page you were looking for doesn’t exist. You may + have mistyped the address or the page may have moved. If you’re the + application owner check the logs for more information. +

+
+
+ diff --git a/public/406-unsupported-browser.html b/public/406-unsupported-browser.html index 7cf1e168..9532a9cc 100644 --- a/public/406-unsupported-browser.html +++ b/public/406-unsupported-browser.html @@ -1,66 +1,114 @@ - - - - Your browser is not supported (406) - - - - - - -
-
-

Your browser is not supported.

-

Please upgrade your browser to continue.

-
-
- + + + + + + + Your browser is not supported (406 Not Acceptable) + + + + + + + + + + + + + +
+
+ +
+
+

Your browser is not supported.
Please upgrade your browser to continue.

+
+
+ + + diff --git a/public/422.html b/public/422.html index c08eac0d..ab2741da 100644 --- a/public/422.html +++ b/public/422.html @@ -1,67 +1,141 @@ - - - - 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.

-
- + + + + + The change you wanted was rejected (422 Unprocessable Entity) + + + + + + + + + + + +
+
+ + + + +
+
+

+ The change you wanted was rejected. Maybe you tried + to change something you didn’t have access to. If you’re the + application owner check the logs for more information. +

+
+
+ diff --git a/public/500.html b/public/500.html index 78a030af..3c0c9c05 100644 --- a/public/500.html +++ b/public/500.html @@ -1,66 +1,142 @@ - - - - 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.

-
- + + + + + + We’re sorry, but something went wrong (500 Internal Server Error) + + + + + + + + + + + + +
+
+ + + + +
+
+

+ We’re sorry, but something went wrong.
+ If you’re the application owner check the logs for more information. +

+
+
+ diff --git a/public/icon.png b/public/icon.png index f3b5abcbde91cf6d7a6a26e514eb7e30f476f950..c4c9dbfbbd2f7c1421ffd5727188146213abbcef 100644 GIT binary patch literal 4166 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 literal 5599 zcmeHL-D}fO6hCR_taXJlzs3}~RuB=Iujyo=i*=1|1FN%E=zNfMTjru|Q<6v{J{U!C zBEE}?j6I3sz>fzN!6}L_BKjcuASk~1;Dg|U_@d{g?V8mM`~#9U+>>*Ezw>c(PjYWA z4(;!cgge6k5E&d$G5`S-0}!Ik>CV(0Y#1}s-v_gAHhja2=W1?nBAte9D2HG<(+)uj z!5=W4u*{VKMw#{V@^NNs4TClr!FAA%ID-*gc{R%CFKEzG<6gm*9s_uy)oMGW*=nJf zw{(Mau|2FHfXIv6C0@Wk5k)F=3jo1srV-C{pl&k&)4_&JjYrnbJiul}d0^NCSh(#7h=F;3{|>EU>h z6U8_p;^wK6mAB(1b92>5-HxJ~V}@3?G`&Qq-TbJ2(&~-HsH6F#8mFaAG(45eT3VPO zM|(Jd<+;UZs;w>0Qw}0>D%{~r{uo_Fl5_Bo3ABWi zWo^j^_T3dxG6J6fH8X)$a^%TJ#PU!=LxF=#Fd9EvKx_x>q<(KY%+y-08?kN9dXjXK z**Q=yt-FTU*13ouhCdqq-0&;Ke{T3sQU9IdzhV9LhQIpq*P{N)+}|Mh+a-VV=x?R} c>%+pvTcMWshj-umO}|qP?%A)*_KlqT3uEqhU;qFB diff --git a/public/icon.svg b/public/icon.svg index 78307ccd..04b34bf8 100644 --- a/public/icon.svg +++ b/public/icon.svg @@ -1,3 +1,3 @@ - - + +