diff --git a/.github/dependencies.txt b/.github/dependencies.txt
index 2a90f95f2..8cc0e2b73 100644
--- a/.github/dependencies.txt
+++ b/.github/dependencies.txt
@@ -20,6 +20,7 @@ icu-dev
imagemagick
lftp
libcurl
+libffi-dev
libgcc
libintl
libmagic
diff --git a/.github/workflows/asset_compilation.yml b/.github/workflows/asset_compilation.yml
index 886d19772..6129424bc 100644
--- a/.github/workflows/asset_compilation.yml
+++ b/.github/workflows/asset_compilation.yml
@@ -33,7 +33,7 @@ jobs:
- gha_production_load_6
runs-on: ubuntu-22.04
- container: ruby:3.1.6-alpine3.20
+ container: ruby:3.3.7-alpine3.20
steps:
- name: Checkout
@@ -84,7 +84,7 @@ jobs:
- name: Install gems
if: always()
run: |
- gem install bundler --version=2.5.17
+ gem install bundler --version=2.6.3
bundle config set --local without 'production staging development'
bundle install --jobs 10 --retry 3
diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml
index eaef8697a..890dc1e44 100644
--- a/.github/workflows/audit.yml
+++ b/.github/workflows/audit.yml
@@ -13,7 +13,7 @@ jobs:
audit:
runs-on: ubuntu-22.04
# Docker Hub image that the job executes in
- container: ruby:3.1.6-alpine3.20
+ container: ruby:3.3.7-alpine3.20
steps:
- name: Checkout
@@ -25,7 +25,7 @@ jobs:
- name: 'Install gems'
run: |
- gem install bundler --version=2.5.17
+ gem install bundler --version=2.6.3
bundle config set --local without 'production staging development'
bundle install --jobs 4 --retry 3
diff --git a/.github/workflows/build_images.yml b/.github/workflows/build_images.yml
index 67942f4a6..66dab16cc 100644
--- a/.github/workflows/build_images.yml
+++ b/.github/workflows/build_images.yml
@@ -41,8 +41,8 @@ jobs:
trivy_skip_files: /app/config/key.pem,/app/docker/sftp/ssh_host_ed25519_key,/app/docker/sftp/ssh_host_rsa_key
target: prod-build
build-args: |
- BUILD_TAG=3.1.6-alpine3.20
- BUNDLER_VERSION=2.5.17
+ BUILD_TAG=3.3.7-alpine3.20
+ BUNDLER_VERSION=2.6.3
USER_ID=10000
GROUP_ID=10000
tags: |
@@ -51,6 +51,12 @@ jobs:
type=raw,event=branch,value=branch-{{branch}}-{{sha}}
steps:
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
- name: Checkout
uses: actions/checkout@v4
diff --git a/.github/workflows/rails_tests.yml b/.github/workflows/rails_tests.yml
index db693fcac..3fa843ca0 100644
--- a/.github/workflows/rails_tests.yml
+++ b/.github/workflows/rails_tests.yml
@@ -12,7 +12,7 @@ jobs:
build:
runs-on: ubuntu-22.04
# Docker Hub image that the job executes in
- container: ruby:3.1.6-alpine3.20
+ container: ruby:3.3.7-alpine3.20
# Service containers to run with job
services:
@@ -67,7 +67,7 @@ jobs:
- name: Install gems
run: |
- gem install bundler --version=2.5.17
+ gem install bundler --version=2.6.3
bundle config set --local without 'production staging development'
bundle install --jobs 4 --retry 3
diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml
index 88d436fcb..095eb816a 100644
--- a/.github/workflows/rubocop.yml
+++ b/.github/workflows/rubocop.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-22.04
# Docker Hub image that the job executes in
- container: ruby:3.1.6-alpine3.20
+ container: ruby:3.3.7-alpine3.20
steps:
- name: Install git
run: |
@@ -46,7 +46,7 @@ jobs:
- id: gems
name: Install gems
run: |
- gem install bundler --version=2.5.17
+ gem install bundler --version=2.6.3
bundle config set --local without 'production staging'
bundle install --jobs 4 --retry 3
diff --git a/.gitignore b/.gitignore
index 7d0489b08..a980d6ae9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,6 +72,7 @@ docker-compose.override.yml
*.sublime-workspace
.env.local
+.pgpass
# Ignore themes
app/assets/stylesheets/theme/styles
diff --git a/.irbrc b/.irbrc
index 6e1a1c2c1..3c62002d5 100644
--- a/.irbrc
+++ b/.irbrc
@@ -1,4 +1,3 @@
-require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1_000
IRB.conf[:HISTORY_FILE] = File.join(__dir__, '.pry_history')
IRB.conf[:USE_AUTOCOMPLETE] = false
diff --git a/.rubocop.yml b/.rubocop.yml
index b431550b1..7660ecef5 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -4,22 +4,22 @@ require:
AllCops:
Exclude:
- - 'db/**/*'
- - 'config/*'
- - 'config/environments/**/*.rb'
- - 'config/initializers/**/*.rb'
- - 'config/locales/**/*.rb'
- - 'script/**/*'
- - 'bin/{rails,rake,bundle}'
- - 'app/assets/**/*'
- - 'bin/db_prep'
+ - "db/**/*"
+ - "config/*"
+ - "config/environments/**/*.rb"
+ - "config/initializers/**/*.rb"
+ - "config/locales/**/*.rb"
+ - "script/**/*"
+ - "bin/{rails,rake,bundle}"
+ - "app/assets/**/*"
+ - "bin/db_prep"
Include:
- - '**/Rakefile'
- - 'app/**/*.rb'
- - 'spec/**/*.rb'
- - 'drivers/**/*.rb'
- - 'lib/**/*.rb'
+ - "**/Rakefile"
+ - "app/**/*.rb"
+ - "spec/**/*.rb"
+ - "drivers/**/*.rb"
+ - "lib/**/*.rb"
NewCops: disable
@@ -62,15 +62,14 @@ Style/PercentLiteralDelimiters:
PreferredDelimiters:
# Using `[]` for string arrays instead of `()`, since normal arrays are
# indicated with `[]` not `()`.
- '%w': '[]'
- '%W': '[]'
+ "%w": "[]"
+ "%W": "[]"
Style/AndOr:
Enabled: true
Style/ClassAndModuleChildren:
- Enabled:
- false
+ Enabled: false
Style/ConditionalAssignment:
Enabled: false
@@ -88,7 +87,7 @@ Style/RescueStandardError:
Enabled: true
Style/FrozenStringLiteralComment:
- Enabled: false
+ Enabled: true
Style/CommentedKeyword:
Enabled: false
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index e595e1e33..199403f64 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -94,7 +94,6 @@ Layout/EmptyLineBetweenDefs:
# Cop supports --auto-correct.
Layout/EmptyLines:
Exclude:
- - 'bin/setup'
- 'spec/factories/match_decisions/match_recommendation_shelter_agency.rb'
- 'spec/models/rules/interested_in_neighborhood_spec.rb'
- 'spec/models/rules/rank_below_spec.rb'
@@ -164,7 +163,6 @@ Layout/EmptyLinesAroundBlockBody:
- 'spec/models/rules/tagged_with_spec.rb'
- 'spec/models/rules/vispdat_scores_spec.rb'
- 'spec/models/user_spec.rb'
- - 'spec/spec_helper.rb'
- 'spec/support/tasks.rb'
- 'spec/tasks/update_clients_spec.rb'
@@ -710,7 +708,6 @@ Style/Alias:
# Cop supports --auto-correct.
Style/BlockComments:
Exclude:
- - 'spec/spec_helper.rb'
# Offense count: 61
# Cop supports --auto-correct.
@@ -797,7 +794,6 @@ Style/IfInsideElse:
# Cop supports --auto-correct.
Style/IfUnlessModifier:
Exclude:
- - 'bin/setup'
# Offense count: 3
# Cop supports --auto-correct.
@@ -882,7 +878,6 @@ Style/ParenthesesAroundCondition:
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
Exclude:
- - 'bin/setup'
# Offense count: 90
# Cop supports --auto-correct.
@@ -983,7 +978,6 @@ Style/StringLiterals:
- 'bin/deploy'
- 'bin/guard'
- 'bin/rspec'
- - 'bin/setup'
- 'bin/update'
- 'spec/controllers/account_emails_controller_spec.rb'
- 'spec/controllers/account_passwords_controller_spec.rb'
@@ -1034,7 +1028,6 @@ Style/TrailingCommaInArguments:
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArrayLiteral:
Exclude:
- - 'bin/setup'
# Offense count: 21
# Cop supports --auto-correct.
diff --git a/.ruby-version b/.ruby-version
index 24576239a..91b31213a 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-ruby-3.1.6
+ruby-3.3.7
diff --git a/Gemfile b/Gemfile
index 325154f6e..69586565c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,21 +2,29 @@
source 'https://rubygems.org'
gem 'activerecord-import'
-gem 'rack', '>= 2.2.8.1'
+gem 'rack', '>= 2.2.11'
gem 'pg', '~> 1.1'
gem 'rails', '~> 7.0.8.5'
-gem "sprockets-rails"
-gem 'rails-html-sanitizer', '>= 1.4.4' # >= 1.4.4 due to CVE-2022-23519
-gem 'loofah', '>= 2.19.1' # >= 2.19.1 due to GHSA-228g-948r-83gx
+gem 'sprockets-rails'
+gem 'rails-html-sanitizer'
+gem 'loofah'
gem 'tzinfo', '>= 1.2.10' # CVE-2022-31163
+# No longer default gems
+gem 'irb'
+gem 'reline'
+gem 'benchmark'
+gem 'rdoc'
+gem 'mutex_m'
+gem 'drb'
+
gem 'bcrypt'
gem 'bootsnap'
gem 'composite_primary_keys', '~> 14.0.9'
-gem 'csv', '>= 1.0.2' # support for bom|utf-8 in ruby 2.5
+gem 'csv'
gem 'order_as_specified'
gem 'with_advisory_lock'
-gem 'nokogiri', '>= 1.16.4' # GHSA-r95h-9x8f-r3f7
+gem 'nokogiri'
gem 'autoprefixer-rails'
gem 'haml-rails'
@@ -68,14 +76,14 @@ gem 'aws-sdk-cloudwatchlogs', require: false
gem 'json'
gem 'amazing_print'
-gem 'puma', '>= 6.4.2'
+gem 'puma', '~> 6'
gem 'redis'
gem 'activerecord-session_store'
gem 'lograge'
gem 'logstop'
-gem 'paper_trail'
-gem 'paranoia', '~> 2.0'
+gem 'paper_trail'#, '~> 15' # 16 breaks models with inherited has_paper_trail, need to update significant code
+gem 'paranoia'
gem 'validate_url'
gem 'StreetAddress', require: false
gem 'marginalia'
@@ -117,9 +125,6 @@ gem 'auto-session-timeout'
gem 'ruby_parser', require: false
-# gem 'axlsx', git: 'https://github.com/randym/axlsx.git'
-# gem 'axlsx_rails'
-# gem 'spreadsheet', require: false
gem 'caxlsx'
gem 'caxlsx_rails'
gem 'xlsxtream', require: false
@@ -140,10 +145,11 @@ gem 'yabeda-puma-plugin'
gem 'yabeda-http_requests'
gem 'roda'
-gem 'k8s-ruby'
+# Once 0.17 is released we should be able to unpin this
+# https://github.com/k8s-ruby/k8s-ruby/pull/57
+gem 'k8s-ruby', github: 'k8s-ruby/k8s-ruby', branch: 'master'
group :development do
- # gem 'spring'
gem 'capistrano'
gem 'capistrano-bundler'
gem 'capistrano-passenger'
@@ -157,7 +163,6 @@ group :development do
gem 'rails-erd'
gem 'ruby-prof'
gem 'web-console'
- # gem 'rb-readline'
gem 'active_record_query_trace'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 64c70d27e..b56c1d0c0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,3 +1,20 @@
+GIT
+ remote: https://github.com/k8s-ruby/k8s-ruby.git
+ revision: b034ac3e1d3c431d1c0db41c56c0736f8367dc30
+ branch: master
+ specs:
+ k8s-ruby (0.16.0)
+ base64
+ dry-configurable
+ dry-struct
+ dry-types
+ excon (~> 0.71)
+ hashdiff (~> 1.0)
+ jsonpath (~> 1.1)
+ recursive-open-struct (~> 1.1, >= 1.1.3)
+ yajl-ruby (~> 1.4)
+ yaml-safe_load_stream3
+
GEM
remote: https://rubygems.org/
specs:
@@ -49,7 +66,7 @@ GEM
rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_record_distinct_on (1.6.0)
activerecord (>= 6.1, < 7.2)
- active_record_query_trace (1.8.2)
+ active_record_query_trace (1.8.3)
activerecord (>= 6.0.0)
activejob (7.0.8.7)
activesupport (= 7.0.8.7)
@@ -193,6 +210,7 @@ GEM
execjs (~> 2.0)
base64 (0.2.0)
bcrypt (3.1.20)
+ benchmark (0.4.0)
bigdecimal (3.1.7)
bindex (0.8.1)
bootsnap (1.18.3)
@@ -268,10 +286,10 @@ GEM
coffee-script-source (1.12.2)
composite_primary_keys (14.0.9)
activerecord (~> 7.0.2)
- concurrent-ruby (1.3.4)
+ concurrent-ruby (1.3.5)
connection_pool (2.4.1)
crass (1.0.6)
- csv (3.3.0)
+ csv (3.3.2)
daemons (1.4.1)
date (3.4.1)
delayed_job (4.1.11)
@@ -302,24 +320,27 @@ GEM
dotenv-rails (3.1.0)
dotenv (= 3.1.0)
railties (>= 6.1)
- dry-configurable (1.2.0)
- dry-core (~> 1.0, < 2)
+ drb (2.2.1)
+ dry-configurable (1.3.0)
+ dry-core (~> 1.1)
zeitwerk (~> 2.6)
- dry-core (1.0.1)
+ dry-core (1.1.0)
concurrent-ruby (~> 1.0)
+ logger
zeitwerk (~> 2.6)
- dry-inflector (1.1.0)
+ dry-inflector (1.2.0)
dry-initializer (3.1.1)
- dry-logic (1.5.0)
+ dry-logic (1.6.0)
+ bigdecimal
concurrent-ruby (~> 1.0)
- dry-core (~> 1.0, < 2)
+ dry-core (~> 1.1)
zeitwerk (~> 2.6)
- dry-struct (1.6.0)
- dry-core (~> 1.0, < 2)
- dry-types (>= 1.7, < 2)
+ dry-struct (1.7.1)
+ dry-core (~> 1.1)
+ dry-types (~> 1.8, >= 1.8.2)
ice_nine (~> 0.11)
zeitwerk (~> 2.6)
- dry-types (1.7.2)
+ dry-types (1.8.2)
bigdecimal (~> 3.0)
concurrent-ruby (~> 1.0)
dry-core (~> 1.0)
@@ -328,7 +349,7 @@ GEM
zeitwerk (~> 2.6)
erubi (1.13.1)
erubis (2.7.0)
- excon (0.111.0)
+ excon (0.112.0)
execjs (2.9.1)
factory_bot (6.4.6)
activesupport (>= 5.0.0)
@@ -373,20 +394,25 @@ GEM
execjs (~> 2.0)
sprockets (>= 2.0.0)
tilt (>= 1.2)
- hashdiff (1.0.1)
+ hashdiff (1.1.2)
html2haml (2.3.0)
erubis (~> 2.7.0)
haml (>= 4.0)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
htmlentities (4.3.4)
- i18n (1.14.6)
+ i18n (1.14.7)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
iniparse (1.5.0)
+ io-console (0.8.0)
+ irb (1.15.1)
+ pp (>= 0.6.0)
+ rdoc (>= 4.0.0)
+ reline (>= 0.4.2)
jmespath (1.6.2)
jquery-rails (4.6.0)
rails-dom-testing (>= 1, < 3)
@@ -395,16 +421,6 @@ GEM
json (2.7.4)
jsonpath (1.1.5)
multi_json
- k8s-ruby (0.16.0)
- dry-configurable
- dry-struct
- dry-types
- excon (~> 0.71)
- hashdiff (~> 1.0.0)
- jsonpath (~> 1.1)
- recursive-open-struct (~> 1.1.3)
- yajl-ruby (~> 1.4.0)
- yaml-safe_load_stream3
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2)
@@ -426,13 +442,14 @@ GEM
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
+ logger (1.6.5)
lograge (0.14.0)
actionpack (>= 4)
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
logstop (0.3.1)
- loofah (2.23.1)
+ loofah (2.24.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
lumberjack (1.2.10)
@@ -491,25 +508,29 @@ GEM
order_as_specified (1.7)
activerecord (>= 5.0.0)
orm_adapter (0.5.0)
+ ostruct (0.6.1)
overcommit (0.63.0)
childprocess (>= 0.6.3, < 6)
iniparse (~> 1.4)
rexml (~> 3.2)
pagy (8.2.2)
- paper_trail (15.1.0)
+ paper_trail (16.0.0)
activerecord (>= 6.1)
request_store (~> 1.4)
parallel (1.26.3)
- paranoia (2.6.3)
- activerecord (>= 5.1, < 7.2)
+ paranoia (3.0.1)
+ activerecord (>= 6, < 8.1)
parser (3.3.5.0)
ast (~> 2.4.1)
racc
pg (1.5.6)
popper_js (1.16.1)
power_assert (2.0.3)
+ pp (0.6.2)
+ prettyprint
pretender (0.5.0)
actionpack (>= 6.1)
+ prettyprint (0.2.0)
prometheus-client (4.2.2)
pry (0.14.2)
coderay (~> 1.1)
@@ -519,6 +540,9 @@ GEM
pry (>= 0.13, < 0.15)
pry-rails (0.3.9)
pry (>= 0.10.4)
+ psych (5.2.3)
+ date
+ stringio
public_suffix (5.0.5)
puma (6.4.3)
nio4r (~> 2.0)
@@ -573,14 +597,19 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
- recursive-open-struct (1.1.3)
+ rdoc (6.12.0)
+ psych (>= 4.0.0)
+ recursive-open-struct (1.3.1)
+ ostruct
redcarpet (3.6.0)
redis (5.2.0)
redis-client (>= 0.22.0)
redis-client (0.22.1)
connection_pool
regexp_parser (2.9.2)
- request_store (1.6.0)
+ reline (0.6.0)
+ io-console (~> 0.5)
+ request_store (1.7.0)
rack (>= 1.4)
responders (3.1.1)
actionpack (>= 5.2)
@@ -701,12 +730,13 @@ GEM
net-sftp (>= 2.1.2)
net-ssh (>= 2.8.0)
ssrf_filter (1.1.2)
+ stringio (3.1.2)
temple (0.10.3)
terser (1.2.2)
execjs (>= 0.3.0, < 3)
test-unit (3.6.2)
power_assert
- thor (1.3.1)
+ thor (1.3.2)
thread_safe (0.3.6)
tilt (2.3.0)
timecop (0.9.8)
@@ -771,7 +801,7 @@ GEM
yabeda (~> 0.8)
yajl-ruby (1.4.3)
yaml-safe_load_stream3 (0.1.2)
- zeitwerk (2.6.15)
+ zeitwerk (2.7.2)
zip_tricks (5.6.0)
PLATFORMS
@@ -808,6 +838,7 @@ DEPENDENCIES
aws-sdk-ssm (~> 1)
babel-transpiler
bcrypt
+ benchmark
bootsnap
bootstrap (~> 4.3.1)
bootstrap3-datetimepicker-rails (~> 4.17.42)
@@ -826,7 +857,7 @@ DEPENDENCIES
caxlsx_rails
coffee-rails
composite_primary_keys (~> 14.0.9)
- csv (>= 1.0.2)
+ csv
daemons
delayed_job_active_record
deprecation_toolkit
@@ -835,6 +866,7 @@ DEPENDENCIES
devise-security
devise_invitable (>= 2.0.9)
dotenv-rails
+ drb
execjs
factory_bot_rails
faker
@@ -846,16 +878,17 @@ DEPENDENCIES
haml-rails
handlebars_assets
html2haml
+ irb
jquery-rails
json
- k8s-ruby
+ k8s-ruby!
kaminari
launchy
letter_opener
listen
lograge
logstop
- loofah (>= 2.19.1)
+ loofah
marginalia
maxminddb
memery
@@ -863,26 +896,29 @@ DEPENDENCIES
mini_portile2
minitest-reporters
momentjs-rails (>= 2.9.0)
+ mutex_m
net-http
- nokogiri (>= 1.16.4)
+ nokogiri
order_as_specified
overcommit
pagy
paper_trail
- paranoia (~> 2.0)
+ paranoia
pg (~> 1.1)
pretender
pry-byebug
pry-rails
- puma (>= 6.4.2)
- rack (>= 2.2.8.1)
+ puma (~> 6)
+ rack (>= 2.2.11)
rack-mini-profiler
rails (~> 7.0.8.5)
rails-controller-testing
rails-erd
- rails-html-sanitizer (>= 1.4.4)
+ rails-html-sanitizer
+ rdoc
redcarpet
redis
+ reline
responders
roda
roo
@@ -918,5 +954,323 @@ DEPENDENCIES
yabeda-puma-plugin
yabeda-rails
+CHECKSUMS
+ StreetAddress (1.0.6) sha256=f20ae18894af4263be479cad7de4307d7babb6ac3a89607ed55bcca67c33cd6f
+ actioncable (7.0.8.7) sha256=4034513841df2fd09dbbf38f37c1a00fc6c841122a8714e5d6916b8d6ce2f162
+ actionmailbox (7.0.8.7) sha256=940eeaa3d8e85dcd9fc6069e39571e13c5a4bdb0db52c7ab96d14da81d6ac1c2
+ actionmailer (7.0.8.7) sha256=8be8f9a2f8774af89822bc92e1ab6df10b3a2be59c75486a34e86a1f10d88d14
+ actionpack (7.0.8.7) sha256=40e6b1d687904a4fd2285d1fa3aad3d9a9d9ba8fd8858dd0faa9f4673c3f5e2c
+ actiontext (7.0.8.7) sha256=cb75d2db97d5b2c8caccdc0f643541df36c2c53f076a2d49b226f971d8d528a0
+ actionview (7.0.8.7) sha256=be975bc9c61903fe5da80a97c345271159033bcbba63988c7f27b6b8b98f7fed
+ active_record_distinct_on (1.6.0) sha256=fca6b290a7202f887b1840b265db7f5fd19c935d4ec3b2aac7ca9cdc68bdb9ad
+ active_record_query_trace (1.8.3) sha256=e48859e6f1cfe54f8dad000f25ea7e3ec15b169a365c32c09b76f7765f160b7b
+ activejob (7.0.8.7) sha256=eff4db3aeaee34863a47570089d11d5577ed0ea42b1475dc9be6a413be182a20
+ activemodel (7.0.8.7) sha256=f13b04bb055c1e85b965ce40b0a2e671b8d97835083597bc7fbc04cde0f40a83
+ activerecord (7.0.8.7) sha256=f94fc8510e58a18e462c5ee8862c9be75e2bfad0688e8d022b86a6e05df2a45a
+ activerecord-import (1.6.0) sha256=b1704a8bcd47888d1adb249a302ba21fd0ec8e28123d8d66b6552ea8c4d94fb9
+ activerecord-session_store (2.1.0) sha256=f8453b1d618d0c8744683f0808fda4c01c9a93508301316299dd1b9756662374
+ activestorage (7.0.8.7) sha256=ca411e73733a50983f44b0945bfd0612313beb3a8f914cd3a88e4fcd99399ef5
+ activesupport (7.0.8.7) sha256=df4702375de924aae81709c831605317c5417f0bd9e502a0373ff84a067204ff
+ addressable (2.8.6) sha256=798f6af3556641a7619bad1dce04cdb6eb44b0216a991b0396ea7339276f2b47
+ airbrussh (1.5.2) sha256=96dc392771df52411d6014e0a18ed4ad60b2bbfbaf2265ddca9bc15f44fd6a08
+ ajax_modal_rails (1.0.12) sha256=d386142f420d83d6d2fc2253ff98e3e80233caf0613a5235e989af679afb436d
+ amazing_print (1.6.0) sha256=9903e93daadc15411c854239f8ca1ca6ce78be279ed99d43fec2bd3b0aa37397
+ ansi (1.5.0) sha256=5408253274e33d9d27d4a98c46d2998266fd51cba58a7eb9d08f50e57ed23592
+ anyway_config (2.6.4) sha256=f2682e72bc3fb4aa19eecf91efdd5905ca3371eb60479b82b8e2e4a88ef4562d
+ ast (2.4.2) sha256=1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12
+ attribute_normalizer (1.2.0) sha256=580df3f316d7f0a2cc068fd655377f4769848643328d0c6c6c685ea98ac181c4
+ authtrail (0.5.0) sha256=adeab5e6480f2bffe7532e952d4dc088569bf7a4c42d97c7737b7ebda59a768b
+ auto-session-timeout (1.1) sha256=c6e83ae904bc8ade0b74d448674a4478b52903501f0a63dc50c98289e77c45d3
+ autoprefixer-rails (10.4.16.0) sha256=40c4b14d6f26f66026cd0d4631baf18d6c56aab425b36059c8abbda17f19a706
+ aws-eventstream (1.3.0) sha256=f1434cc03ab2248756eb02cfa45e900e59a061d7fbdc4a9fd82a5dd23d796d3f
+ aws-partitions (1.916.0) sha256=9ffa41e8563da988310100df5fca5f2a4e3c46331440256a37a784e512cc34be
+ aws-record (2.13.0) sha256=53879371db0865b452a047c30c63ee443a22a068c801c49955b27b7ef4cc2ef9
+ aws-sdk-autoscaling (1.106.0) sha256=e2f367a77a99bb161aeb8712a28c2b36084cf2d1ff65a161a79b6c941d29df00
+ aws-sdk-cloudwatch (1.89.0) sha256=d5414b3725a1a6e872477a0a26d82152cedf84407933e090cef806baac7da477
+ aws-sdk-cloudwatchevents (1.70.0) sha256=c037aacb28793df1b9713481c2f47e1516a0fa7386758401381312b38d06efa4
+ aws-sdk-cloudwatchlogs (1.80.0) sha256=cf55753e298f92d109e44ea3e7b5906eee8d6698c4199ebedb7a68cf536f5022
+ aws-sdk-core (3.192.1) sha256=c02612fe14a4a5a79d58d173d0f5d67f9ecd162c9f2dd5cfaa73509e66cfe8c2
+ aws-sdk-dynamodb (1.106.0) sha256=affb32367b5ebdaf4ec86f366a36ae44a440a07e225ac7c66315f1bfeaab177d
+ aws-sdk-ec2 (1.450.0) sha256=c4654f28cf1896d9b2a8edc15a1b7dc24d6a238906ed1482625c8a901c963280
+ aws-sdk-ecr (1.69.0) sha256=6d99e2a67621fce65e17d26dca93866ea3cb6314cb4fcdf59ce942df25349204
+ aws-sdk-ecs (1.145.0) sha256=b33d5790deffb408b97a1c8e123ca8e97d8da9570861944c8d41356a9821e288
+ aws-sdk-elasticloadbalancingv2 (1.100.0) sha256=d6e0fb51a36640ef97ba7443771ca3499fa4d53b8e89add63cd3b8ff5e13a322
+ aws-sdk-glacier (1.59.0) sha256=98f4c97018d02b60992cd4fc2b23747bfce2460190a66de3cc0aed248417df0d
+ aws-sdk-iam (1.96.0) sha256=f48454d10ac57dd7800996e8374925c78d4e7df263b1f02f41994395a89a9b7d
+ aws-sdk-kms (1.79.0) sha256=5c21460bc50fbde3a9c745b29f47370801f1bb697bf2965bc13a16d70d0060b1
+ aws-sdk-rails (3.12.0) sha256=cfe2a80dcd69325512aaea3f2ebabf9ffb2e1824032121e7213231ef82ffc2d2
+ aws-sdk-rds (1.226.0) sha256=8dca3406eee8ece60b4051367303991f510230b1dd0ac9dac4b7feb2af9ec558
+ aws-sdk-s3 (1.147.0) sha256=367753c25d98b8019932d403d3ec56def51e70be917a2612d762a369ca167c45
+ aws-sdk-secretsmanager (1.91.0) sha256=c3ce1fbdffee9a523cbd376493f9f1a7dd2b6337e6e18084c578b787570955c7
+ aws-sdk-ses (1.60.0) sha256=ef0d0d2c5f72ff0c98f736c0dd63de65f615ca2c0a5f8d66daeb4ed7222aaf1e
+ aws-sdk-sesv2 (1.45.0) sha256=b5e5e4f56b4b1403d612c607ae9f8eec3ab60d5f5cc92bb29a9a0a386f6f13c2
+ aws-sdk-sns (1.73.0) sha256=fd9cd206bd2cb92d27ac7e14f9574e8d8dbee2d0a289df43677f08f6206de280
+ aws-sdk-sqs (1.70.0) sha256=56067fc1fbca504ab038ce3c15808ef59824b6782d36278c8adb50c919d9ac3a
+ aws-sdk-ssm (1.166.0) sha256=48276867d61d71a43cb39da8f7f819d25cd70a653b9ce4a3577202353f682a37
+ aws-sessionstore-dynamodb (2.2.0) sha256=def51891ea61061596b8fcafb78dc1f8cd08610a3fb0d4df5256bcc7ff5bcd0c
+ aws-sigv4 (1.8.0) sha256=84dd99768b91b93b63d1d8e53ee837cfd06ab402812772a7899a78f9f9117cbc
+ axiom-types (0.1.1) sha256=c1ff113f3de516fa195b2db7e0a9a95fd1b08475a502ff660d04507a09980383
+ babel-source (5.8.35) sha256=79ef222a9dcb867ac2efa3b0da35b4bcb15a4bfa67b6b2dcbf1e9a29104498d9
+ babel-transpiler (0.7.0) sha256=4c06f4ad9e8e1cabe94f99e11df2f140bb72aca9ba067dbb49dc14d9b98d1570
+ base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
+ bcrypt (3.1.20) sha256=8410f8c7b3ed54a3c00cd2456bf13917d695117f033218e2483b2e40b0784099
+ benchmark (0.4.0) sha256=0f12f8c495545e3710c3e4f0480f63f06b4c842cc94cec7f33a956f5180e874a
+ bigdecimal (3.1.7) sha256=e799b369a0005fc6d62eed7ef19139ac9bc319cc51470c637b9dcdf593600133
+ bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e
+ bootsnap (1.18.3) sha256=d7b70de761e2fb1d63d21dd941b393c881c5cab5575211369cede788dfc034eb
+ bootstrap (4.3.1) sha256=f0ec38008cdc2c8e1d1be06cc273560e2554e93d7040b8757499fdf87f4c47c1
+ bootstrap3-datetimepicker-rails (4.17.47) sha256=ee87a9bad74c140729f6a1ea2a7f3f2d9aaefa7e9defbe31b4edd27ff64689a2
+ brakeman (6.1.2) sha256=7716769c18f2c4a52d7a74d2cb5a614be0c46d8aad3fbe7ca089dbb7c98bd4d3
+ browser (5.3.1) sha256=62745301701ff2c6c5d32d077bb12532b20be261929dcb52c6781ed0d5658b3c
+ builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
+ bundler-audit (0.9.1) sha256=bdc716fc21cd8652a6507b137e5bc51f5e0e4f6f106a114ab004c89d0200bd3d
+ byebug (11.1.3) sha256=2485944d2bb21283c593d562f9ae1019bf80002143cc3a255aaffd4e9cf4a35b
+ capistrano (3.18.1) sha256=348593cff0a81cff4a4ddfef025a16b284f697ed6daa985083b4ca4f9664ba5f
+ capistrano-bundler (2.1.0) sha256=249473398f0cacf643dbd54db02b7a302b76c11cd7302d16ac2727e5c26a3627
+ capistrano-passenger (0.2.1) sha256=07a1d25edd5c1d909c19d4fe45fe2ea5f11200569f6967f6bff1d605ade98e13
+ capistrano-rails (1.6.3) sha256=a7cfb325e5618c8afae4c1147b70a4f83d00fa730f7a09f5ff4d7d8f893f9316
+ capistrano-rvm (0.1.2) sha256=4adb7ffd98d2c1335b597b063e1e6cafd9dd2d6ecc9d358bf78100aad8475e97
+ capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef
+ carrierwave (3.0.7) sha256=feaf484453f7bbb8655b45042224738d5356a331b16d4df293511e8b0f8ef06e
+ carrierwave-i18n (3.0.0) sha256=0919a1ddf294700b28097c433a6496fc874dd0a8c36b35b85b1f2e18236ba641
+ caxlsx (4.1.0) sha256=47d0f6d8d72c570c02bbc5c0dd74d47a420bf3b202d020e105bf9d6cda298f1a
+ caxlsx_rails (0.6.3) sha256=fe84fc69e6e578e6dcfde9de5219877075b3e64334c294a44605e69166deb36c
+ cgi (0.4.1) sha256=4349e1e2025c9cc73534c52c93cffc0dafc93e0a81edc0830d851a3b2c49a430
+ childprocess (5.0.0) sha256=0746b7ab1d6c68156e64a3767631d7124121516192c0492929a7f0af7310d835
+ choice (0.2.0) sha256=a19617f7dfd4921b38a85d0616446620de685a113ec6d1ecc85bdb67bf38c974
+ chronic (0.10.2) sha256=766f2fcce6ac3cc152249ed0f2b827770d3e517e2e87c5fba7ed74f4889d2dc3
+ coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
+ coercible (1.0.0) sha256=5081ad24352cc8435ce5472bc2faa30260c7ea7f2102cc6a9f167c4d9bffaadc
+ coffee-rails (5.0.0) sha256=5daaa1ba51fd4907c98a333b6a9e7c1a99b1fff57fcef999b6c62d813cb91a9c
+ coffee-script (2.4.1) sha256=82fe281e11b93c8117b98c5ea8063e71741870f1c4fbb27177d7d6333dd38765
+ coffee-script-source (1.12.2) sha256=e12b16fd8927fbbf8b87cb2e9a85a6cf457c6881cc7ff8b1af15b31f70da07a4
+ composite_primary_keys (14.0.9) sha256=eb04ab8e3194a04b26bd160ab4cc8486aa2416a96c83477e3f275e906ff63563
+ concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6
+ connection_pool (2.4.1) sha256=0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4
+ crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
+ csv (3.3.2) sha256=6ff0c135e65e485d1864dde6c1703b60d34cc9e19bed8452834a0b28a519bd4e
+ daemons (1.4.1) sha256=8fc76d76faec669feb5e455d72f35bd4c46dc6735e28c420afb822fac1fa9a1d
+ date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f
+ delayed_job (4.1.11) sha256=9861510f1ad86bd872cdc7edfd0c59f1a3efd93e26fe0272e58c3c49c5795d68
+ delayed_job_active_record (4.1.8) sha256=aea9ffee50b07d95ef11a0e07ebb8c136d3cfe69d9b1895afb0ac66656d100ad
+ deprecation_toolkit (2.2.0) sha256=858055baa699d9efc7bb407f621a5c1f350cd4f6c782577500a6b671ac370653
+ descendants_tracker (0.0.4) sha256=e9c41dd4cfbb85829a9301ea7e7c48c2a03b26f09319db230e6479ccdc780897
+ devise (4.9.4) sha256=920042fe5e704c548aa4eb65ebdd65980b83ffae67feb32c697206bfd975a7f8
+ devise-pwned_password (0.1.11) sha256=f3984ad4855f1a315107262abfe5f1ba35fe9622151ccdd4b36ae8da4457daa4
+ devise-security (0.18.0) sha256=fc06be1624b5151044ff9c5d8e61abdfa7d56eb16bfdaec16a11235d54708513
+ devise_invitable (2.0.9) sha256=d726c724ecc3481211f73752ed5020088e080c7fe9ef0b3899ece5b15056902e
+ diff-lcs (1.5.1) sha256=273223dfb40685548436d32b4733aa67351769c7dea621da7d9dd4813e63ddfe
+ dotenv (3.1.0) sha256=8b7e682e197dbaa69bd5660cc18bc821e8152e1bb2b3c02e32f2be718fd8b2b4
+ dotenv-rails (3.1.0) sha256=d2e1bc7bf39acf7f135920c81306b1eb7dbfa27a4577fce7665488d77d7fe719
+ drb (2.2.1) sha256=e9d472bf785f558b96b25358bae115646da0dbfd45107ad858b0bc0d935cb340
+ dry-configurable (1.3.0) sha256=882d862858567fc1210d2549d4c090f34370fc1bb7c5c1933de3fe792e18afa8
+ dry-core (1.1.0) sha256=0903821a9707649a7da545a2cd88e20f3a663ab1c5288abd7f914fa7751ab195
+ dry-inflector (1.2.0) sha256=22f5d0b50fd57074ae57e2ca17e3b300e57564c218269dcf82ff3e42d3f38f2e
+ dry-initializer (3.1.1) sha256=4d267dea367ccabe498b259c62b909b99d577d6db547d9510561999403546dec
+ dry-logic (1.6.0) sha256=da6fedbc0f90fc41f9b0cc7e6f05f5d529d1efaef6c8dcc8e0733f685745cea2
+ dry-struct (1.7.1) sha256=4200913a24a36932d531d726a00067f727b4bd03d511d267f58ba3a86bee53ae
+ dry-types (1.8.2) sha256=c84e9ada69419c727c3b12e191e0ed7d2c6d58d040d55e79ea16e0ebf8b3ec0f
+ erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
+ erubis (2.7.0) sha256=63653f5174a7997f6f1d6f465fbe1494dcc4bdab1fb8e635f6216989fb1148ba
+ excon (0.112.0) sha256=daf9ac3a4c2fc9aa48383a33da77ecb44fa395111e973084d5c52f6f214ae0f0
+ execjs (2.9.1) sha256=e8fd066f6df60c8e8fbebc32c6fb356b5212c77374e8416a9019ca4bb154dcfb
+ factory_bot (6.4.6) sha256=1a9486ce98d318d740d8f5804b885a8265a28f326ecf2bcd4ce9fb27a71a6e04
+ factory_bot_rails (6.4.3) sha256=ea73ceac1c0ff3dc11fff390bf2ea8a2604066525ed8ecd3b3bc2c267226dcc8
+ faker (3.3.1) sha256=a42b9b0aca7a6d3c1741dc7713ac5a5491a8bf51af26e45a8687cf4e36665d47
+ ffi (1.16.3) sha256=6d3242ff10c87271b0675c58d68d3f10148fabc2ad6da52a18123f06078871fb
+ font-awesome-sass (6.5.2) sha256=ff93d432dae13498a63a4a1062e93c75b668459b2ded35223ff6cbcd88ffedde
+ foreman (0.88.1) sha256=59c022125b6a328a2ce63da8d70b731f5dd13519e8d9a4184c696538088ea00a
+ formatador (1.1.0) sha256=54e23e2af4d60bb9327c7fac62b29968e4cf28cee0111f726d0bdeadc85e06d0
+ fuzzy_match (2.1.0) sha256=e97e25d0eaee48a5f77ed970d007c7b6ff3c6a6858303fead2d1986859204dfc
+ geocoder (1.8.2) sha256=4cba205c9ac2367465742eb9f2d2479389392e3b8dabe9d183082330b0c71488
+ globalid (1.2.1) sha256=70bf76711871f843dbba72beb8613229a49429d1866828476f9c9d6ccc327ce9
+ guard (2.18.1) sha256=a3893d3b23d538a9b2d6f05a27713e0ed53ea881df0f0550b21a3393c6d87c09
+ guard-compat (1.2.1) sha256=3ad21ab0070107f92edfd82610b5cdc2fb8e368851e72362ada9703443d646fe
+ guard-rspec (4.7.3) sha256=a47ba03cbd1e3c71e6ae8645cea97e203098a248aede507461a43e906e2f75ca
+ haml (6.3.0) sha256=8e6eb87d869639e348852009e74a2a1663d79663ed7e7dbcb38beb1f12bcdd97
+ haml-rails (2.1.0) sha256=273ba0189e2f82ce4b2385019dd9138884017e3103cc2eaebeee7f45186f59ea
+ handlebars_assets (0.23.9) sha256=d6bb35289e6166c01839a4d866cdf90ec33d901a16a86b97be1189c4de38c062
+ hashdiff (1.1.2) sha256=2c30eeded6ed3dce8401d2b5b99e6963fe5f14ed85e60dd9e33c545a44b71a77
+ html2haml (2.3.0) sha256=b587eaf532609642fc3b5c2b35861e8c9e15e72e0355b93bbcfee1e3ae088127
+ htmlentities (4.3.4) sha256=125a73c6c9f2d1b62100b7c3c401e3624441b663762afa7fe428476435a673da
+ i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
+ ice_nine (0.11.2) sha256=5d506a7d2723d5592dc121b9928e4931742730131f22a1a37649df1c1e2e63db
+ image_processing (1.12.2) sha256=d3b9e9c5a1cc2607a5214cc28b90d317a03bdd06239584c97535dd73e46f62b8
+ iniparse (1.5.0) sha256=36a165e98d8a250b7631c4a7f9afba32af78f089970cd6446a39771189c761f1
+ io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2
+ irb (1.15.1) sha256=d9bca745ac4207a8b728a52b98b766ca909b86ff1a504bcde3d6f8c84faae890
+ jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1
+ jquery-rails (4.6.0) sha256=3c4e6bf47274340b44d836b8aa1b5472c6d451e2739af5ec094421f39025a7e2
+ json (2.7.4) sha256=9ea6258b4add3abd25df965515be8b19be417f58b8c42619c7f2d3e86c158ece
+ jsonpath (1.1.5) sha256=29f70467193a2dc93ab864ec3d3326d54267961acc623f487340eb9c34931dbe
+ k8s-ruby (0.16.0)
+ kaminari (1.2.2) sha256=c4076ff9adccc6109408333f87b5c4abbda5e39dc464bd4c66d06d9f73442a3e
+ kaminari-actionview (1.2.2) sha256=1330f6fc8b59a4a4ef6a549ff8a224797289ebf7a3a503e8c1652535287cc909
+ kaminari-activerecord (1.2.2) sha256=0dd3a67bab356a356f36b3b7236bcb81cef313095365befe8e98057dd2472430
+ kaminari-core (1.2.2) sha256=3bd26fec7370645af40ca73b9426a448d09b8a8ba7afa9ba3c3e0d39cdbb83ff
+ language_server-protocol (3.17.0.3) sha256=3d5c58c02f44a20d972957a9febe386d7e7468ab3900ce6bd2b563dd910c6b3f
+ launchy (3.0.0) sha256=4abcdab659689550ceca6ec0630cd9efd9940b51dc14cb4ebceee8f7aedc791b
+ letter_opener (1.10.0) sha256=2ff33f2e3b5c3c26d1959be54b395c086ca6d44826e8bf41a14ff96fdf1bdbb2
+ listen (3.9.0) sha256=db9e4424e0e5834480385197c139cb6b0ae0ef28cc13310cfd1ca78377d59c67
+ logger (1.6.5) sha256=c3cfe56d01656490ddd103d38b8993d73d86296adebc5f58cefc9ec03741e56b
+ lograge (0.14.0) sha256=42371a75823775f166f727639f5ddce73dd149452a55fc94b90c303213dc9ae1
+ logstop (0.3.1) sha256=962055e109a74375c68f2bd2cbfe0b7b326939463242dc6c591235610c9b32a3
+ loofah (2.24.0) sha256=61e6a710883abb8210887f3dc868cf3ed66594c509d9ff6987621efa6651ee1e
+ lumberjack (1.2.10) sha256=bbfe951629341095028ecbf1ad496b58bec3f8bcad6fe35a203a377839c42b6c
+ mail (2.8.1) sha256=ec3b9fadcf2b3755c78785cb17bc9a0ca9ee9857108a64b6f5cfc9c0b5bfc9ad
+ marcel (1.0.4) sha256=0d5649feb64b8f19f3d3468b96c680bae9746335d02194270287868a661516a4
+ marginalia (1.11.1) sha256=cb63212ab63e42746e27595e912cb20408a1a28bcd0edde55d15b7c45fa289cf
+ matrix (0.4.2) sha256=71083ccbd67a14a43bfa78d3e4dc0f4b503b9cc18e5b4b1d686dc0f9ef7c4cc0
+ maxminddb (0.1.22) sha256=50933be438fbed9dceabef4163eab41884bd8830d171fdb8f739bee769c4907e
+ memery (1.5.0) sha256=a088ea778afbc25cba652e73db7389fe3b3ec210d137cd303d0e48690543618e
+ method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
+ mini_magick (4.12.0) sha256=67302fa84e63f1002b71416a8466968ed0f33d22f5d42962a0c09a9f1c3a906a
+ mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
+ mini_portile2 (2.8.8) sha256=8e47136cdac04ce81750bb6c09733b37895bf06962554e4b4056d78168d70a75
+ minitest (5.25.4) sha256=9cf2cae25ac4dfc90c988ebc3b917f53c054978b673273da1bd20bcb0778f947
+ minitest-reporters (1.6.1) sha256=f8fe74e46ab40dada29402f55ca236368d0af65afc410db4219189b7a1c0fc38
+ momentjs-rails (2.29.4.1) sha256=c7f9bc583872b628f8723319f4ae12a646c858c1c3ddb352bc75d5a7aa0b9e01
+ msgpack (1.7.2) sha256=59ab62fd8a4d0dfbde45009f87eb6f158ab2628a7c48886b0256f175166baaa8
+ multi_json (1.15.0) sha256=1fd04138b6e4a90017e8d1b804c039031399866ff3fbabb7822aea367c78615d
+ mutex_m (0.2.0) sha256=b6ef0c6c842ede846f2ec0ade9e266b1a9dac0bc151682b04835e8ebd54840d5
+ nenv (0.3.0) sha256=d9de6d8fb7072228463bf61843159419c969edb34b3cef51832b516ae7972765
+ net-http (0.4.1) sha256=a96efc5ea18bcb9715e24dda4159d10f67ff0345c8a980d04630028055b2c282
+ net-imap (0.5.6) sha256=1ede8048ee688a14206060bf37a716d18cb6ea00855f6c9b15daee97ee51fbe5
+ net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
+ net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
+ net-scp (4.0.0) sha256=b32ded0d48c88ce70844a063e4e14efb44a95e51a9e0c0bfb0c54b4313b622ea
+ net-sftp (4.0.0) sha256=65bb91c859c2f93b09826757af11b69af931a3a9155050f50d1b06d384526364
+ net-smtp (0.5.0) sha256=5fc0415e6ea1cc0b3dfea7270438ec22b278ca8d524986a3ae4e5ae8d087b42a
+ net-ssh (7.2.3) sha256=1605f672d14630294f0614a3a432fba9347b3d101e8ab61ab5bd273d55c10b6b
+ nio4r (2.7.3) sha256=54b94cdd4b8f9dc39aaad5f699e97afae13efb44f2b180a6e724df76105ff604
+ nokogiri (1.18.3) sha256=6b9fc3b14fd0cedd21f6cad8cf565123ba7401e56b5d0aec180c23cdca28fd5a
+ notiffany (0.1.3) sha256=d37669605b7f8dcb04e004e6373e2a780b98c776f8eb503ac9578557d7808738
+ order_as_specified (1.7) sha256=5e4016542f0bda13bc21821021199192567c32823a22f6962bc16b3dc254ce13
+ orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
+ ostruct (0.6.1) sha256=09a3fb7ecc1fa4039f25418cc05ae9c82bd520472c5c6a6f515f03e4988cb817
+ overcommit (0.63.0) sha256=d42e63eb8bfbca0dbcf5adef5264c77dd5f1981f128fed7f9bd7f668252ec414
+ pagy (8.2.2) sha256=67d2d8650c9d0455ec62dc783e76c53fb9ff25f48dc460e35b607bba40afb046
+ paper_trail (16.0.0) sha256=e9b9f0fb1b8b590c8231cfa931b282ba92f90e066e393930a5e1c61ae4c5019d
+ parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
+ paranoia (3.0.1) sha256=cdb50c4c5c66f61fd1354f26371a8f0ca6d60156215bebffff42e135c495d083
+ parser (3.3.5.0) sha256=f30ebb71b7830c2e7cdc4b2b0e0ec2234900e3fca3fe2fba47f78be759181ab3
+ pg (1.5.6) sha256=4bc3ad2438825eea68457373555e3fd4ea1a82027b8a6be98ef57c0d57292b1c
+ popper_js (1.16.1) sha256=6b102fb5ee86c5fa68a0c865547e66d9bf7e80a951053b21c72c3c92a587d692
+ power_assert (2.0.3) sha256=cd5e13c267370427c9804ce6a57925d6030613e341cb48e02eec1f3c772d4cf8
+ pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff
+ pretender (0.5.0) sha256=02120f25bc1c2b98468e136cec9e841360935dcc291158195b0cd073ff8fad77
+ prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
+ prometheus-client (4.2.2) sha256=95e195e33a669ceef69928adae23a51bbf4953083bbe7144aa509a356e4e83ff
+ pry (0.14.2) sha256=c4fe54efedaca1d351280b45b8849af363184696fcac1c72e0415f9bdac4334d
+ pry-byebug (3.10.1) sha256=c8f975c32255bfdb29e151f5532130be64ff3d0042dc858d0907e849125581f8
+ pry-rails (0.3.9) sha256=468662575abb6b67f4a9831219f99290d5eae7bf186e64dd810d0a3e4a8cc4b1
+ psych (5.2.3) sha256=84a54bb952d14604fea22d99938348814678782f58b12648fcdfa4d2fce859ee
+ public_suffix (5.0.5) sha256=72c340218bb384610536919988705cc29e09749c0021fd7005f715c7e5dfc493
+ puma (6.4.3) sha256=24a4645c006811d83f2480057d1f54a96e7627b6b90e1c99b260b9dc630eb43e
+ pwned (2.4.1) sha256=e375b45e1cd78aded2c923737f75e09e64bc66582142c144bd85f4ce1fa0955d
+ racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
+ rack (2.2.11) sha256=424c49affa19081e9255d65d861f2d7bc7d8388edc0cb608b5e6caf1dd49bb8a
+ rack-mini-profiler (3.3.1) sha256=2bf0de7d5795f54581e453b248e42cc50e8d0529efac73828653a9ad2407a801
+ rack-session (1.0.2) sha256=a02115e5420b4de036839b9811e3f7967d73446a554b42aa45106af335851d76
+ rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
+ rails (7.0.8.7) sha256=5e67ed4dd915746349bfb8c7ae2f531d3a36eb68fbe2f60ede02a0500715cded
+ rails-controller-testing (1.0.5) sha256=741448db59366073e86fc965ba403f881c636b79a2c39a48d0486f2607182e94
+ rails-dom-testing (2.2.0) sha256=e515712e48df1f687a1d7c380fd7b07b8558faa26464474da64183a7426fa93b
+ rails-erd (1.7.2) sha256=0b17d0fba25d319d8da8af7a3e5e2149d02d6187cc7351e8be43423f07c48bcd
+ rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560
+ railties (7.0.8.7) sha256=1ab985280b02bc4b176d36e1011148db600b763c646e3de88c02a665d864505f
+ rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
+ rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
+ rb-fsevent (0.11.2) sha256=43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe
+ rb-inotify (0.10.1) sha256=050062d4f31d307cca52c3f6a7f4b946df8de25fc4bd373e1a5142e41034a7ca
+ rdoc (6.12.0) sha256=7d6f706e070bffa5d18a448f24076cbfb34923a99c1eab842aa18e6ca69f56e0
+ recursive-open-struct (1.3.1) sha256=141b4a9c8817bb30f4275c5adb1b5bebaba41bf9b7dd6d6a75ad394390ad8720
+ redcarpet (3.6.0) sha256=8ad1889c0355ff4c47174af14edd06d62f45a326da1da6e8a121d59bdcd2e9e9
+ redis (5.2.0) sha256=336b975a56b166c6af4d4a1026c71dbed429ba5dc949aac373ef2fded07936b4
+ redis-client (0.22.1) sha256=b411b3812e83f817069dc20651dd3b01d4d417a0cab0f04fbaf143d6de19107e
+ regexp_parser (2.9.2) sha256=5a27e767ad634f8a4b544520d5cd28a0db7aa1198a5d7c9d7e11d7b3d9066446
+ reline (0.6.0) sha256=57620375dcbe56ec09bac7192bfb7460c716bbf0054dc94345ecaa5438e539d2
+ request_store (1.7.0) sha256=e1b75d5346a315f452242a68c937ef8e48b215b9453a77a6c0acdca2934c88cb
+ responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a
+ rexml (3.3.9) sha256=d71875b85299f341edf47d44df0212e7658cbdf35aeb69cefdb63f57af3137c9
+ roda (3.85.0) sha256=1e6461b8ef90dfa05271d2bde30f0fc1f4aaafaff6ad7604fadf992eb85951a5
+ roo (2.10.1) sha256=cbb43bc955f9c110e74b721c835fb9bd3515b63af88ec709ac87fbf30f8be70e
+ rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
+ rspec-core (3.13.0) sha256=557792b4e88da883d580342b263d9652b6a10a12d5bda9ef967b01a48f15454c
+ rspec-expectations (3.13.0) sha256=621d48c62262f955421eaa418130744760802cad47e781df70dba4d9f897102e
+ rspec-mocks (3.13.0) sha256=735a891215758d77cdb5f4721fffc21078793959d1f0ee4a961874311d9b7f66
+ rspec-rails (4.0.2) sha256=e135edfe510f8f04ce8800f3f0e2a2a55c1318ae6ceea123ff330819a59d852b
+ rspec-support (3.13.1) sha256=48877d4f15b772b7538f3693c22225f2eda490ba65a0515c4e7cf6f2f17de70f
+ rubocop (1.67.0) sha256=8ccca7226e76d0a9974af960ea446d1fb38adf0c491214294e2fed75a85c378c
+ rubocop-ast (1.33.0) sha256=6235809347985fc9019e44180de1be56885004a4f51a74512d0b70fe0c533ed5
+ rubocop-capybara (2.20.0) sha256=2a6844b942921f230ee3ab8c94fe77f41a9406096a140245270c0e11624bb938
+ rubocop-factory_bot (2.25.1) sha256=62751bde7af789878b8a31cbd2a82e69515ce7b23a2ad1820cb0fcc3e0150134
+ rubocop-faker (1.1.0) sha256=bfdd208f79cb96f124b1ceb2b4a9399fc1b61f2c078ea203eca0e08ee2ada215
+ rubocop-rails (2.24.1) sha256=03edf766954947468f3686cedb69142fae4f10e2007287f89cc0ea7072eeac19
+ rubocop-rspec (2.29.1) sha256=534ee81a3006e7379ec6203687ef7c06ca1d137b7d6d67c2777b680b1ce82e13
+ rubocop-rspec_rails (2.28.3) sha256=9769f2077cca8af2269193ba0450e0317ae1827a132c19149fdbeecaaca32818
+ ruby-filemagic (0.7.3) sha256=9dedfac69c737be29efb4542a280e345a70ba2b6ba905a518abd9998c8f3a7d9
+ ruby-graphviz (1.2.5) sha256=1c2bb44e3f6da9e2b829f5e7fd8d75a521485fb6b4d1fc66ff0f93f906121504
+ ruby-next-core (1.0.3) sha256=0450af2d48c198701ce7d8bc865e6a41c17afd8701b58a038c44319d161405dc
+ ruby-prof (1.7.0) sha256=059687d7566a2d74ce93988ca996babb8c3d2e920b58321e22c244ba6da7ca42
+ ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
+ ruby-vips (2.2.1) sha256=a29841d601c5cfcad9b152964fe83ac8fc60dd94cf8d1fc5e69cfb90fe57cc7b
+ ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef
+ ruby_parser (3.21.0) sha256=3842893d2f4602dcd93c0a79d77f9ce8e1ce197d41ac533d8e25c684f8f1c56b
+ rubyzip (2.3.2) sha256=3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f
+ sassc (2.4.0) sha256=4c60a2b0a3b36685c83b80d5789401c2f678c1652e3288315a1551d811d9f83e
+ sassc-rails (2.1.2) sha256=5f4fdf3881fc9bdc8e856ffbd9850d70a2878866feae8114aa45996179952db5
+ sentry-rails (5.17.3) sha256=017771c42d739c0ad2213a581ca9d005cf543227bc13662cd1ca9909f2429459
+ sentry-ruby (5.17.3) sha256=61791a4b0bb0f95cd87aceeaa1efa6d4ab34d64236c9d5df820478adfe2fbbfc
+ sexp_processor (4.17.1) sha256=91110946720307f30bf1d549e90d9a529fef40d1fc471c069c8cca7667015da0
+ shellany (0.0.1) sha256=0e127a9132698766d7e752e82cdac8250b6adbd09e6c0a7fbbb6f61964fedee7
+ shoulda (4.0.0) sha256=e677218c432eaa102a173e7047fbcf396ebc8ccea467725ba4e6053bc9e09c0a
+ shoulda-context (2.0.0) sha256=7adf45342cd800f507d2a053658cb1cce2884b616b26004d39684b912ea32c34
+ shoulda-matchers (4.5.1) sha256=8d06e2bbb5b22aa170333905fcf23b7388d1baa9485895b0a2b80210e97f27e2
+ simple_form (5.3.0) sha256=628b4b2eb5ded0ca960c6df2f91a672259146b974cd5422e02a90eb95b68e000
+ simpleidn (0.2.1) sha256=35dda985b761dff5751fefa7fba02e477427c975d47b11c4c4ffaf01afe1c719
+ slack-notifier (2.4.0) sha256=cd9aba3f5f3e6227f73df1f6a33ac6c127c5fac35b513b86b7ba900cd98d2b00
+ sniffer (0.5.0) sha256=cd040cc51929c04749b20baa4dd8f5985174210e13437491f4923b8de27e1359
+ sprockets (4.2.1) sha256=951b13dd2f2fcae840a7184722689a803e0ff9d2702d902bd844b196da773f97
+ sprockets-rails (3.4.2) sha256=36d6327757ccf7460a00d1d52b2d5ef0019a4670503046a129fa1fb1300931ad
+ sshkit (1.22.1) sha256=cc9d6904bdd3f47278d519d4ceb42999de8bffe3c00852bdc3856591a290c509
+ ssrf_filter (1.1.2) sha256=263209ed236f9a3fbd76b4d2473a388518ab747f409170cdb2f49d6ef578ff5e
+ stringio (3.1.2) sha256=204f1828f85cdb39d57cac4abc6dc44b04505a223f131587f2e20ae3729ba131
+ temple (0.10.3) sha256=df3145fe6577af1e25387eb7f7122d32ed51bdb6f2e7bb0f4fbf07b66151913b
+ terser (1.2.2) sha256=86ddfa0de7fa8f6c8fd34ad611596f787a77e21bed3db08b90e7c30942d20288
+ test-unit (3.6.2) sha256=3ce480c23990ca504a3f0d6619be2a560e21326cefd1b86d0f9433c387f26039
+ thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda
+ thread_safe (0.3.6) sha256=9ed7072821b51c57e8d6b7011a8e282e25aeea3a4065eab326e43f66f063b05a
+ tilt (2.3.0) sha256=82dd903d61213c63679d28e404ee8e10d1b0fdf5270f1ad0898ec314cc3e745c
+ timecop (0.9.8) sha256=89996da54eafb25c007d309099ae18a1cb1c6a59fe42f7f1ab4148e21e98f563
+ timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e
+ todo_or_die (0.1.1) sha256=0a3d51b664367e48d8c6c49c21aa111bc1bbea13a0cdfd9dd5fc2e2066df948b
+ tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
+ unf (0.1.4) sha256=4999517a531f2a955750f8831941891f6158498ec9b6cb1c81ce89388e63022e
+ unf_ext (0.0.9.1) sha256=926114a858934126c6bbfd3254347dadb5dae354711869368c0f75e3765fc6e9
+ unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a
+ uri (0.13.0) sha256=26553c2a9399762e1e8bebd4444b4361c4b21298cf1c864b22eeabc9c4998f24
+ validate_url (1.0.15) sha256=72fe164c0713d63a9970bd6700bea948babbfbdcec392f2342b6704042f57451
+ validates_email_format_of (1.8.2) sha256=e2dfcf3e933547d06c41dacf066c7b07614819439c8780c3a2521ce047052577
+ virtus (2.0.0) sha256=8841dae4eb7fcc097320ba5ea516bf1839e5d056c61ee27138aa4bddd6e3d1c2
+ warden (1.2.9) sha256=46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0
+ warning (1.3.0) sha256=23695a5d8e50bd5c46068931b529bee0b28e4982cbcefbe77d867800dde8069e
+ web-console (4.2.1) sha256=e7bcf37a10ea2b4ec4281649d1cee461b32232d0a447e82c786e6841fd22fe20
+ websocket-driver (0.7.6) sha256=f69400be7bc197879726ad8e6f5869a61823147372fd8928836a53c2c741d0db
+ websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
+ whenever (1.0.0) sha256=d9b71417c43960f5eb125b77207174cba4691091cedae0d282a29cfc72eaa246
+ with_advisory_lock (5.1.0) sha256=0692cd82013b271c59aa5e1f603b741ab94926dbce098990fbace5dd5412fed7
+ xlsxtream (2.4.0) sha256=cec4b4266412e3c65bb9283c7c1ae506b2bdac1b1841ead6ab9814a4619fbce8
+ xpath (3.2.0) sha256=6dfda79d91bb3b949b947ecc5919f042ef2f399b904013eb3ef6d20dd3a4082e
+ yabeda (0.12.0) sha256=1d8f75807d4608e9f82586875e6899d7aa9c7b258278a38feeed7ef920ae0585
+ yabeda-http_requests (0.2.1) sha256=f1204340cd57317c8a87cf8fee8af52c150d6f622ee66276a7d27a19ee67b90a
+ yabeda-prometheus (0.9.1) sha256=b87d80cae8cffbeb527c25d288eafa8eed9c1fb56cf49616db5c8611768cd5fd
+ yabeda-puma-plugin (0.7.1) sha256=a41d72053b8eb5b9db92c59bfb4a95f1988bafd2fdc9f4f13836849af073b17b
+ yabeda-rails (0.9.0) sha256=6011bfa1e282456dbb4f0d6571267ad57108b54fab0de37ae3b70653fa9582da
+ yajl-ruby (1.4.3) sha256=8c974d9c11ae07b0a3b6d26efea8407269b02e4138118fbe3ef0d2ec9724d1d2
+ yaml-safe_load_stream3 (0.1.2) sha256=fd4f63ffe57e65ec8fd5a314064151f843e83239ff87bfc6b2fdbdba81e7e481
+ zeitwerk (2.7.2) sha256=842e067cb11eb923d747249badfb5fcdc9652d6f20a1f06453317920fdcd4673
+ zip_tricks (5.6.0) sha256=ea644925d97bceee6f86ce0e1ec5a3f0cb84eabf5e56f740ff5d4b518a5aea19
+
BUNDLED WITH
- 2.5.17
+ 2.6.5
diff --git a/app/assets/javascripts/role_table.es6 b/app/assets/javascripts/role_table.es6
index 7f8aefa1c..e524ade50 100644
--- a/app/assets/javascripts/role_table.es6
+++ b/app/assets/javascripts/role_table.es6
@@ -1,5 +1,5 @@
window.App.RoleTable = class RoleTable {
- constructor({props, patch_url} = {props, patch_url:'/admin/roles'}) {
+ constructor({ props, patch_url } = { props, patch_url: '/admin/roles' }) {
this.isDirty = false
this.props = Object.assign({
tableContainerSelector: '.j-table',
@@ -20,10 +20,10 @@ window.App.RoleTable = class RoleTable {
init() {
// Declare variables with defaults
const {
- tableSelector='.j-table__table',
- tableSearchInputSelector='.j-table__search',
- tableRowSelector='.j-table__row',
- submitActionSelector= '.j-table__submit-changes',
+ tableSelector = '.j-table__table',
+ tableSearchInputSelector = '.j-table__search',
+ tableRowSelector = '.j-table__row',
+ submitActionSelector = '.j-table__submit-changes',
tableCancelChange
} = this.props
@@ -31,12 +31,12 @@ window.App.RoleTable = class RoleTable {
this.table = $(tableSelector).DataTable({
// scrollY: '55vh',
scrollCollapse: true,
- scrollX: true,
+ // scrollX: 'true',
searching: false,
ordering: false,
paging: false,
bInfo: false,
- // fixedHeader: true,
+ fixedHeader: true,
fixedColumns: {
leftColumns: 1
}
@@ -96,7 +96,7 @@ window.App.RoleTable = class RoleTable {
})
}
- changeDirtyState(isDirty=true, event) {
+ changeDirtyState(isDirty = true, event) {
this.isDirty = isDirty
if (event) {
event.target.classList.add('dirty')
@@ -135,7 +135,7 @@ window.App.RoleTable = class RoleTable {
`)
}
- confirmSaved(error=null) {
+ confirmSaved(error = null) {
this.isSaving = false
const $loading = this.$tableContainer.find('.j-table__loading')
$(this.submitActionSelector).attr('disabled', false)
@@ -159,4 +159,4 @@ window.App.RoleTable = class RoleTable {
}
setTimeout(() => { $loading.fadeOut() }, 500)
}
-}
\ No newline at end of file
+}
diff --git a/app/assets/stylesheets/elements/_label.scss b/app/assets/stylesheets/elements/_label.scss
index eb53ec2ec..c77f4a534 100644
--- a/app/assets/stylesheets/elements/_label.scss
+++ b/app/assets/stylesheets/elements/_label.scss
@@ -7,14 +7,44 @@ label {
font-style: italic;
font-size: 95%;
font-weight: normal;
+
&--optional {
color: $brand-primary;
}
+
&--required {
color: $brand-danger;
}
}
+.label {
+ color: rgba(0, 0, 0, .9);
+}
+
.label--minor {
font-weight: normal;
}
+
+.label-info {
+ background: $brand-info;
+}
+
+.label-default {
+ background: $gray-030;
+}
+
+.label-primary {
+ background: $brand-primary-l;
+}
+
+.label-danger {
+ background: $brand-danger-l;
+}
+
+.label-success {
+ background: $brand-success-l;
+}
+
+.label-warning {
+ background: $brand-warning-l;
+}
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 612bc7da9..8adc8d41c 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -11,7 +11,7 @@ class UsersController < ApplicationController
before_action :authenticate_user!
before_action :require_can_edit_users!, except: [:stop_impersonating]
- before_action :set_user, only: [:edit, :confirm, :update, :destroy, :impersonate]
+ before_action :set_user, only: [:edit, :confirm, :update, :destroy, :impersonate, :expire_password]
before_action :require_can_become_other_users!, only: [:impersonate]
helper_method :sort_column, :sort_direction
@@ -103,6 +103,15 @@ def reactivate
redirect_to({ action: :index }, notice: "User #{@user.name} re-activated")
end
+ def expire_password
+ msg = if @user.force_password_reset!
+ { notice: "User #{@user.email} has been logged out and will need to change their password on next login." }
+ else
+ { warn: "Unable to expire password for #{@user.email}, password expiration is disabled" }
+ end
+ redirect_to({ action: :index }, **msg)
+ end
+
private
def adding_admin?
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 8f1409b9e..d0b7dfa2e 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -4,6 +4,8 @@
# License detail: https://github.com/greenriver/boston-cas/blob/production/LICENSE.md
###
+# frozen_string_literal: false
+
require_relative '../../lib/util/git'
module ApplicationHelper
@@ -18,11 +20,11 @@ module ApplicationHelper
# END Permissions
#
def yn(boolean)
- boolean ? 'Y': 'N'
+ boolean ? 'Y' : 'N'
end
def checkmark(boolean)
- boolean ? '✓': ''
+ boolean ? '✓' : ''
end
def yes_no(bool)
@@ -48,7 +50,7 @@ def masked_ssn(number)
def date_format(dob)
dob ? l(dob, format: :default) : ''
- #dob.try(:strftime, '%m/%d/%Y')
+ # dob.try(:strftime, '%m/%d/%Y')
end
def impersonating?
@@ -61,11 +63,11 @@ def current_sort_order(columns)
return columns
end
- #returns a link appropriate for re-sorting a table
+ # returns a link appropriate for re-sorting a table
def manual_sort_link(link_text, column, directions)
direction = directions[column]
- sort_direction = (direction.nil? || direction == 'asc') ? 'desc' : 'asc'
- sort = {'sort' => column, 'direction' => sort_direction}
+ sort_direction = direction.nil? || direction == 'asc' ? 'desc' : 'asc'
+ sort = { 'sort' => column, 'direction' => sort_direction }
params.merge!(sort)
# FIXME: un-safe params
link_to(link_text, params.permit!)
@@ -74,18 +76,18 @@ def manual_sort_link(link_text, column, directions)
def client_data_quality(model, fld)
content_tag :span, class: 'cas-dq' do
case model.send("#{fld}_quality")
- #when 'F'; icon('check-circle', class: 'text-success', data: {toggle: :tooltip}, title: 'Full')
- when 'P'; icon('exclamation-triangle', class: 'text-warning', data: {toggle: :tooltip}, title: 'Partial/Approximate')
- when 'N'; icon('question-circle', class: 'text-muted', data: {toggle: :tooltip}, title: 'Client didn\'t know')
- when 'R'; icon('eye-slash', class: 'text-muted', data: {toggle: :tooltip}, title: 'Client refused')
+ # when 'F'; icon('check-circle', class: 'text-success', data: {toggle: :tooltip}, title: 'Full')
+ when 'P' then icon('exclamation-triangle', class: 'text-warning', data: { toggle: :tooltip }, title: 'Partial/Approximate')
+ when 'N' then icon('question-circle', class: 'text-muted', data: { toggle: :tooltip }, title: 'Client didn\'t know')
+ when 'R' then icon('eye-slash', class: 'text-muted', data: { toggle: :tooltip }, title: 'Client refused')
end
end
end
- #returns a link appropriate for sorting a table as described
- def sort_as_link(link_text, column, direction='asc')
- sort_direction = (direction.nil? || direction == 'asc') ? 'asc' : 'desc'
- sort = {'sort' => column, 'direction' => sort_direction}
+ # returns a link appropriate for sorting a table as described
+ def sort_as_link(link_text, column, direction = 'asc')
+ sort_direction = direction.nil? || direction == 'asc' ? 'asc' : 'desc'
+ sort = { 'sort' => column, 'direction' => sort_direction }
params_copy = params.dup
params_copy.merge!(sort)
# FIXME: un-safe params
@@ -94,20 +96,20 @@ def sort_as_link(link_text, column, direction='asc')
def fake_partner
short, long = * [
- ['DND','Department of Neighborhood Development'],
- ['PHC','Public Health Commission'],
- ['Hope','Project Hope'],
- ['CH','MA Coalition for the Homeless'],
- ['DHCD','MA Dept. of Housing and Community Development'],
- ['Camb.','City of Cambridge'],
- ['VofA','Volunteers of America'],
- ['NECHV','New England Center for the Homeless Veterns']
+ ['DND', 'Department of Neighborhood Development'],
+ ['PHC', 'Public Health Commission'],
+ ['Hope', 'Project Hope'],
+ ['CH', 'MA Coalition for the Homeless'],
+ ['DHCD', 'MA Dept. of Housing and Community Development'],
+ ['Camb.', 'City of Cambridge'],
+ ['VofA', 'Volunteers of America'],
+ ['NECHV', 'New England Center for the Homeless Veterns'],
].sample
"#{short}".html_safe
end
def enable_responsive?
- @enable_responsive = true
+ @enable_responsive = true
end
def body_classes
@@ -138,7 +140,7 @@ def modal_size
def human_locale(locale)
translations = {
- en: 'Text adjustments'
+ en: 'Text adjustments',
}
translations[locale.to_sym].presence || locale
end
@@ -152,9 +154,8 @@ def match_step_types
end
def branch_info
- branch_name = `git rev-parse --abbrev-ref HEAD`
- content_tag :div, :class => "navbar-text" do
- content_tag :span, branch_name, :class => "badge badge-warning p-2"
+ content_tag :div, class: 'navbar-text' do
+ content_tag :span, Git.branch, class: 'badge badge-warning p-2'
end
end
@@ -181,6 +182,16 @@ def help_for_path
)
end
+ # Provides a generic mechanism to show an action menu if there is more than one item, button, if only one
+ # Expects an array of objects called items in the following format
+ # [{ link_to: { path: '/hud_reports/aprs/new?filter%5Bactive_roi%5D=false...'}, icon: :copy, label: 'Clone report' }, { link_to: { path: '/hud_reports/aprs/111', method: :delete }, icon: :cross, label: 'Delete' }]
+ def action_menu_or_button(items:)
+ return if items.empty?
+ return render('/common/action_menu', items: items) if items.many?
+
+ render('/common/action_button', item: items.sole)
+ end
+
# def pretty_check_box key, label, form, attrs
# checked = form.object[key]
# value = form.object[key] ? 1 : 0
@@ -190,5 +201,4 @@ def help_for_path
# content_tag(:label, content_tag(:span, label), for: id)
# end
# end
-
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 28e8b0a5a..bf94192c7 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -23,6 +23,8 @@ class User < ApplicationRecord
:confirmable,
:pwned_password,
:session_limitable,
+ :password_expirable,
+ :password_archivable,
password_length: 10..128
# has_secure_password # not needed with devise
# Connect users to login attempts
@@ -165,6 +167,19 @@ def in_app_messages?
true
end
+ # Dependent on devise expire_password_after being set to a value other than false
+ def force_password_reset!
+ return false unless password_expiration_enabled?
+
+ # Immediately logout the user
+ self.unique_session_id = nil
+ # Force a password change on next login
+ need_change_password! # calls save internally
+
+ # Return true to indicate success
+ true
+ end
+
def self.describe_changes(_version, changes)
changes.slice(*whitelist_for_changes_display).map do |name, values|
"Changed #{humanize_attribute_name(name)}: from \"#{values.first}\" to \"#{values.last}\"."
diff --git a/app/views/admin/roles/index.html.haml b/app/views/admin/roles/index.html.haml
index 97dd508bd..6f5e592ed 100644
--- a/app/views/admin/roles/index.html.haml
+++ b/app/views/admin/roles/index.html.haml
@@ -53,4 +53,4 @@
- content_for :page_js do
:javascript
- new App.RoleTable()
\ No newline at end of file
+ new App.RoleTable()
diff --git a/app/views/admin/users/_user_links.haml b/app/views/admin/users/_user_links.haml
new file mode 100644
index 000000000..6174fbe97
--- /dev/null
+++ b/app/views/admin/users/_user_links.haml
@@ -0,0 +1,18 @@
+:ruby
+ items = []
+ items << { link_to: { path: edit_admin_user_path(id: user) }, icon: 'pencil', label: 'Edit Account' }
+
+ if can_audit_users?
+ items << { link_to: { path: admin_user_audit_path(user) }, icon: 'eye', label: 'Audit' }
+ end
+
+ if can_become_other_users? && user.impersonateable_by?(true_user)
+ items << { link_to: { path: impersonate_admin_user_path(true_user, become_id: user.id), method: :post }, icon: 'enter', label: 'Become' }
+ end
+
+ items << { link_to: { path: expire_password_admin_user_path(user), method: :patch, class: ['label-warning'], data: {confirm: "Would you really like to force a password reset for the account? #{user.name} will be immediately logged out and will need to choose a new password on next login." } }, icon: 'lock', label: 'Force Password Reset' }
+
+ if user.valid?
+ items << { link_to: { path: admin_user_path(user), method: :delete, class: ['label-danger'], data: { confirm: "Would you really like to de-activate the account? #{user.name} will no longer be able to login." } }, icon: 'cross', label: 'De-Activate' }
+ end
+= action_menu_or_button(items: items)
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index eff0a3868..f887d2557 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -70,29 +70,7 @@
%td= render 'user_invitation_status', user: user
%td.text-center= @active_matches[user.id] || 0
%td.text-center= @closed_matches[user.id] || 0
- %td
- .w-100
- = link_to(edit_admin_user_path(id: user), class: 'btn btn-sm btn-secondary mb-2 text-nowrap') do
- %i.icon-pencil
- Edit
-
- - if can_audit_users?
- .w-100
- = link_to admin_user_audit_path(user), class: 'btn btn-sm btn-secondary mb-2' do
- %i.icon-eye{data: {toggle: :tooltip, title: 'Audit'}}
- Audit
-
- - if can_become_other_users? && user.impersonateable_by?(true_user)
- .w-100
- = link_to impersonate_admin_user_path(true_user, become_id: user.id), method: :post, class: 'btn btn-sm btn-secondary mb-2' do
- %i.icon-enter
- Become
-
- - if user.valid?
- .w-100
- = link_to admin_user_path(user), method: :delete, data: {confirm: "Would you really like to de-activate the account? #{user.name} will no longer be able to login."}, class: 'btn btn-sm btn-danger mb-2 text-nowrap' do
- %i.icon-cross
- De-Activate
+ %td= render 'user_links', user: user
%p= paginate @users, params: {sort: directions.compact.keys.first, direction: directions.compact.values.first}
.tab-pane#inactive{class: inactive_selected}
diff --git a/app/views/common/_action_button.haml b/app/views/common/_action_button.haml
new file mode 100644
index 000000000..86dd71c4f
--- /dev/null
+++ b/app/views/common/_action_button.haml
@@ -0,0 +1,13 @@
+- classes = ['btn', 'btn-sm']
+- if item.dig(:link_to, :method) == :delete
+ - classes << 'btn-danger'
+ - item[:icon] ||= :cross
+- else
+ - classes << 'btn-secondary'
+- if item[:label].blank?
+ - classes << 'btn-icon-only'
+- path = item.dig(:link_to, :path)
+= link_to(path, **item[:link_to].reverse_merge({class: classes})) do
+ - if item[:icon].present?
+ %i{class: "icon-#{item[:icon]}"}
+ = item[:label]
diff --git a/app/views/common/_action_menu.haml b/app/views/common/_action_menu.haml
new file mode 100644
index 000000000..04a3510c3
--- /dev/null
+++ b/app/views/common/_action_menu.haml
@@ -0,0 +1,19 @@
+.dropdown.ml-auto
+ %button.btn.btn-sm.btn-outline-secondary.dropdown-toggle{ type: :button, data: { toggle: :dropdown}, aria: { expanded: false }}
+ Actions
+ %i.ml-2.icon-angle-down
+ .dropdown-menu.options(aria-label="Actions")
+ %ul.list-unstyled.m-0
+ - items.each do |item|
+ -# Populate classes with a drop-down item
+ - item[:link_to][:class] ||= []
+ - item[:link_to][:class] += ['dropdown-item']
+
+ - if item.dig(:link_to, :method) == :delete
+ - item[:icon] ||= :cross
+ - path = item.dig(:link_to, :path)
+ %li
+ = link_to(path, **item[:link_to]) do
+ - if item[:icon].present?
+ %i{class: "icon-#{item[:icon]} mr-2"}
+ = item[:label]
diff --git a/app/views/devise/password_expired/show.haml b/app/views/devise/password_expired/show.haml
new file mode 100644
index 000000000..b154dde0c
--- /dev/null
+++ b/app/views/devise/password_expired/show.haml
@@ -0,0 +1,13 @@
+%h1 Password Expired
+.row
+ .col-sm-6
+ = simple_form_for(resource, as: resource_name, url: [resource_name, :password_expired], html: { method: :put }, wrapper: :vertical_form_hint_first) do |f|
+ = render 'users/password_rules'
+ = f.error_notification
+ = f.input :current_password, required: true, autofocus: true
+ .form-inputs
+ = f.input :password, label: "New password", required: true
+ = f.input :password_confirmation, label: "Confirm your new password", required: true
+ .form-actions
+ = f.button :submit, "Update my password"
+
diff --git a/app/views/layouts/_header_warnings.haml b/app/views/layouts/_header_warnings.haml
index 62c53886c..1fae7f46b 100644
--- a/app/views/layouts/_header_warnings.haml
+++ b/app/views/layouts/_header_warnings.haml
@@ -11,34 +11,28 @@
= link_to stop_impersonating_admin_users_path, method: :post do
Switch Back
%i.icon-exit.ml-2
-- unless Rails.env.production?
+- if !Rails.env.production? && !ENV['HIDE_NON_PRODUCTION_WARNING']
#non-production-warning
.d-flex.pt-2.pb-2
- - if Rails.env.development?
- .git-branch.ml-auto
- = branch_info
- .git-branch.ml-4
- .navbar-text
- .badge.badge-info.p-2
- = Rails.version
- on
- = ENV['RUBY_VERSION']
- .rails-env.ml-4.mr-6
- .navbar-text
- %span.badge.badge-success.p-2
- = Rails.env
- - else
- .git-revision.ml-auto
- .navbar-text
- .badge.badge-info.p-2
- = git_revision
- .git-branch.ml-4
- .navbar-text
- .badge.badge-info.p-2
- = Rails.version
- on
- = ENV['RUBY_VERSION']
- .rails-env.ml-4.mr-6
- .navbar-text
- %span.badge.badge-success.p-2
- = Rails.env
+ .git-branch.ml-auto
+ .navbar-text
+ .badge.badge-info.p-2
+ = ENV['CLIENT']
+ - if ENV['EKS']
+ (EKS)
+ .git-branch.ml-4
+ = branch_info
+ .git-revision.ml-4
+ .navbar-text
+ .badge.badge-danger.p-2
+ = git_revision
+ .git-branch.ml-4
+ .navbar-text
+ .badge.badge-info.p-2
+ = Rails.version
+ on
+ = ENV['RUBY_VERSION']
+ .rails-env.ml-4.mr-6
+ .navbar-text
+ %span.badge.badge-success.p-2
+ = Rails.env
diff --git a/bin/setup b/bin/setup
index 7005b6a77..bf9c4fd85 100755
--- a/bin/setup
+++ b/bin/setup
@@ -30,6 +30,10 @@ FileUtils.chdir APP_ROOT do
FileUtils.cp "#{file}.sample", file
end
end
+ unless File.exist?('.pgpass')
+ puts "\n== Creating .pgpass"
+ FileUtils.cp 'sample.pgpass', '.pgpass'
+ end
unless File.exist?('.env.local')
puts "\n== Creating .env.local"
FileUtils.cp ".env.sample", ".env.local"
diff --git a/bin/sync_app_assets.rb b/bin/sync_app_assets.rb
index 36c04aa89..34124de63 100755
--- a/bin/sync_app_assets.rb
+++ b/bin/sync_app_assets.rb
@@ -16,13 +16,11 @@
{
bucket: bucket,
prefix: prefix,
- }
+ },
)
- #resp = client.list_objects({ bucket: bucket, prefix: '', })
+ # resp = client.list_objects({ bucket: bucket, prefix: '', })
- if resp.is_truncated
- puts "Result is truncated. Too many keys. Continuing with what we can get"
- end
+ puts 'Result is truncated. Too many keys. Continuing with what we can get' if resp.is_truncated
keys = resp.to_h[:contents]&.map { |r| r[:key] }
@@ -33,10 +31,10 @@
keys.each do |key|
target = if prefix == ''
- key.sub(/#{prefix}/, './')
- else
- key.sub(/#{prefix}/, '.')
- end
+ key.sub(/#{prefix}/, './')
+ else
+ key.sub(/#{prefix}/, '.')
+ end
puts "#{key} -> #{target}"
if target.end_with?('/')
@@ -47,16 +45,16 @@
FileUtils.mkdir_p(target[0..i])
end
- if File.exists?(target) && ENV['UPDATE_ONLY']=='true'
+ if File.exist?(target) && ENV['UPDATE_ONLY'] == 'true'
puts "Skipping #{target} which already exists locally"
next
end
resp = client.get_object({
- bucket: bucket,
- key: key,
- response_target: target,
- })
+ bucket: bucket,
+ key: key,
+ response_target: target,
+ })
end
rescue Aws::S3::Errors::NoSuchBucket
puts "[#{__FILE__}] Cannot find the bucket: #{bucket}"
diff --git a/config/boot.rb b/config/boot.rb
index b9e460cef..81451a9a9 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -1,4 +1,7 @@
+# frozen_string_literal: false
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
+require 'logger' # required before bootsnap setup or ActiveSupport::LoggerThreadSafeLevel::Logger can't be found
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 50221d591..03d06769a 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -247,6 +247,22 @@
# reset. Defaults to true, so a user is signed in automatically after a reset.
# config.sign_in_after_reset_password = true
+ # Password expires after a configurable time (in seconds).
+ # Or expire passwords on demand by setting this configuration to `true`
+ # Use `user.need_change_password!` to expire a password.
+ # Setting the configuration to `false` will completely disable expiration checks.
+ # config.expire_password_after = 3.months | true | false
+ # We use the password expiration feature to handle forced password resets.
+ # If no ENV is provided, use true, which expires on demand
+ expire_password_after = ENV.fetch('PASSWORD_EXPIRATION_DAYS') { 'true' }
+ if expire_password_after == 'true'
+ config.expire_password_after = true
+ elsif expire_password_after == 'false'
+ config.expire_password_after = false
+ else
+ config.expire_password_after = expire_password_after.to_i
+ end
+
# ==> Configuration for :encryptable
# Allow you to use another encryption algorithm besides bcrypt (default). You can use
# :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
diff --git a/config/initializers/yabeda.rb b/config/initializers/yabeda.rb
new file mode 100644
index 000000000..3ce8d0f02
--- /dev/null
+++ b/config/initializers/yabeda.rb
@@ -0,0 +1,6 @@
+Yabeda.configure do
+ default_tag :rails_env, Rails.env
+ default_tag :app, 'cas'
+ default_tag :tenant, ENV.fetch('CLIENT', 'unknown-client-set-CLIENT-env-var')
+ default_tag :fqdn, ENV.fetch('FQDN', 'unknown-instance-set-FQDN-env-var')
+end
diff --git a/config/locales/devise.security_extension.en.yml b/config/locales/devise.security_extension.en.yml
new file mode 100644
index 000000000..af34b46d6
--- /dev/null
+++ b/config/locales/devise.security_extension.en.yml
@@ -0,0 +1,42 @@
+en:
+ errors:
+ messages:
+ taken_in_past: 'was used previously.'
+ equal_to_current_password: 'must be different than the current password.'
+ equal_to_email: 'must be different than the email.'
+ password_complexity:
+ digit:
+ one: must contain at least one digit
+ other: must contain at least %{count} digits
+ lower:
+ one: must contain at least one lower-case letter
+ other: must contain at least %{count} lower-case letters
+ symbol:
+ one: must contain at least one punctuation mark or symbol
+ other: must contain at least %{count} punctuation marks or symbols
+ upper:
+ one: must contain at least one upper-case letter
+ other: must contain at least %{count} upper-case letters
+ devise:
+ invalid_captcha: 'The captcha input was invalid.'
+ invalid_security_question: 'The security question answer was invalid.'
+ paranoid_verify:
+ code_required: 'Please enter the code our support team provided'
+ paranoid_verification_code:
+ updated: Verification code accepted
+ show:
+ submit_verification_code: Submit verification code
+ verification_code: Verification code
+ submit: Submit
+ password_expired:
+ updated: 'Your new password is saved.'
+ change_required: 'Your password is expired. Please renew your password.'
+ show:
+ renew_your_password: Renew your password
+ current_password: Current password
+ new_password: New password
+ new_password_confirmation: Confirm new password
+ change_my_password: Change my password
+ failure:
+ session_limited: 'Your login credentials were used in another browser. Please sign in again to continue in this browser.'
+ expired: 'Your account has expired due to inactivity. Please contact the site administrator.'
diff --git a/config/routes.rb b/config/routes.rb
index 4300a6a2d..4baf5c29a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -165,6 +165,7 @@ def manage_matches
member do
post :confirm
post :impersonate
+ patch :expire_password
end
collection do
post :stop_impersonating
diff --git a/db/migrate/20250208210918_devise_security_fields.rb b/db/migrate/20250208210918_devise_security_fields.rb
new file mode 100644
index 000000000..fa0cee843
--- /dev/null
+++ b/db/migrate/20250208210918_devise_security_fields.rb
@@ -0,0 +1,17 @@
+class DeviseSecurityFields < ActiveRecord::Migration[7.0]
+ def change
+ add_column :users, :password_changed_at, :datetime, index: true
+ # Ensure everyone has a timestamp so they aren't forced to change their passwords on next login
+ User.update_all(password_changed_at: Time.current)
+ add_column :users, :last_activity_at, :datetime, index: true
+ add_column :users, :expired_at, :datetime, index: true
+ create_table :old_passwords do |t|
+ t.string :encrypted_password, null: false
+ t.string :password_archivable_type, null: false
+ t.integer :password_archivable_id, null: false
+ t.string :password_salt # Optional. bcrypt stores the salt in the encrypted password field so this column may not be necessary.
+ t.datetime :created_at
+ end
+ add_index :old_passwords, [:password_archivable_type, :password_archivable_id], name: 'index_password_archivable'
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 9f220114c..fbeca9db8 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -2378,6 +2378,39 @@ CREATE SEQUENCE public.notifications_id_seq
ALTER SEQUENCE public.notifications_id_seq OWNED BY public.notifications.id;
+--
+-- Name: old_passwords; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.old_passwords (
+ id bigint NOT NULL,
+ encrypted_password character varying NOT NULL,
+ password_archivable_type character varying NOT NULL,
+ password_archivable_id integer NOT NULL,
+ password_salt character varying,
+ created_at timestamp(6) without time zone
+);
+
+
+--
+-- Name: old_passwords_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE public.old_passwords_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: old_passwords_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE public.old_passwords_id_seq OWNED BY public.old_passwords.id;
+
+
--
-- Name: opportunities; Type: TABLE; Schema: public; Owner: -
--
@@ -3963,7 +3996,10 @@ CREATE TABLE public.users (
exclude_from_directory boolean DEFAULT false,
exclude_phone_from_directory boolean DEFAULT false,
unique_session_id character varying,
- receive_weekly_match_summary_email boolean DEFAULT true
+ receive_weekly_match_summary_email boolean DEFAULT true,
+ password_changed_at timestamp(6) without time zone,
+ last_activity_at timestamp(6) without time zone,
+ expired_at timestamp(6) without time zone
);
@@ -4491,6 +4527,13 @@ ALTER TABLE ONLY public.non_hmis_clients ALTER COLUMN id SET DEFAULT nextval('pu
ALTER TABLE ONLY public.notifications ALTER COLUMN id SET DEFAULT nextval('public.notifications_id_seq'::regclass);
+--
+-- Name: old_passwords id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.old_passwords ALTER COLUMN id SET DEFAULT nextval('public.old_passwords_id_seq'::regclass);
+
+
--
-- Name: opportunities id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -5187,6 +5230,14 @@ ALTER TABLE ONLY public.notifications
ADD CONSTRAINT notifications_pkey PRIMARY KEY (id);
+--
+-- Name: old_passwords old_passwords_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.old_passwords
+ ADD CONSTRAINT old_passwords_pkey PRIMARY KEY (id);
+
+
--
-- Name: opportunities opportunities_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -6173,6 +6224,13 @@ CREATE INDEX index_outreach_histories_on_non_hmis_client_id ON public.outreach_h
CREATE INDEX index_outreach_histories_on_user_id ON public.outreach_histories USING btree (user_id);
+--
+-- Name: index_password_archivable; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_password_archivable ON public.old_passwords USING btree (password_archivable_type, password_archivable_id);
+
+
--
-- Name: index_program_contacts_on_contact_id; Type: INDEX; Schema: public; Owner: -
--
@@ -7304,6 +7362,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20250113131532'),
('20250113184426'),
('20250118142954'),
-('20250206162624');
+('20250206162624'),
+('20250208210918');
diff --git a/docker/app/Dockerfile b/docker/app/Dockerfile
index 86c7a93a5..67bb7581e 100644
--- a/docker/app/Dockerfile
+++ b/docker/app/Dockerfile
@@ -24,10 +24,10 @@ ARG BUILD_TAG
FROM ruby:${BUILD_TAG} AS base
ARG USER_ID=10000
ARG GROUP_ID=10000
-ARG BUNDLER_VERSION=2.5.17
+ARG BUNDLER_VERSION=2.6.3
LABEL "app"=open-path-cas
-LABEL "ruby-version"=3.1.6
+LABEL "ruby-version"=3.3.7
ENV LANG=C.UTF-8
ENV GEM_HOME=/bundle
@@ -74,7 +74,7 @@ RUN apk update \
linux-headers \
icu icu-dev \
curl libcurl curl-dev \
- libmagic file-dev file \
+ libmagic file-dev file libffi-dev yaml-dev \
build-base libxml2-dev libxslt-dev postgresql-dev tmux postgresql shared-mime-info \
tar xz \
&& git config --global --add safe.directory /app
diff --git a/docker/app/database.open-path-cas.yml b/docker/app/database.open-path-cas.yml
index 8b13f39cc..16a2ded7a 100644
--- a/docker/app/database.open-path-cas.yml
+++ b/docker/app/database.open-path-cas.yml
@@ -6,7 +6,7 @@ default: &default
password: <%= ENV['DATABASE_PASS'] %>
host: <%= ENV['DATABASE_HOST'] %>
sslmode: <%= ENV.fetch('SSLMODE', 'verify-full') %>
- sslrootcert: /etc/ssl/certs/us-east-1-bundle.pem
+ sslrootcert: <%= ENV.fetch('SSLROOTCERT', '/etc/ssl/certs/us-east-1-bundle.pem') %>
<%= ENV.fetch('RAILS_ENV') { 'unknown' } %>:
<<: *default
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index f80869be9..4e8ce466d 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -1,17 +1,15 @@
-version: '3.8'
-
x-app: &app
- image: cas:${TARGET:-dev-build}-1.0
+ image: cas:${TARGET:-dev-build}-1.1
build:
context: .
target: ${TARGET:-dev-build}
dockerfile: docker/app/Dockerfile
args:
- BUILD_TAG: 3.1.6-alpine3.20
+ BUILD_TAG: 3.3.7-alpine3.20
PG_MAJOR: '12'
NODE_MAJOR: '12'
YARN_VERSION: '1.17.3'
- BUNDLER_VERSION: '2.5.17'
+ BUNDLER_VERSION: '2.6.3'
USER_ID: ${USER_ID:-10000}
GROUP_ID: ${GROUP_ID:-10000}
environment: &env
@@ -21,7 +19,6 @@ x-app: &app
AWS_SECURITY_TOKEN: ${AWS_SECURITY_TOKEN:-}
AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN:-}
NODE_ENV: ${NODE_ENV:-development}
- RAILS_ENV: ${RAILS_ENV:-development}
REDIS_URL: redis://redis:6379/
BOOTSNAP_CACHE_DIR: /bundle/bootsnap
K8S_API_HOST_AND_PORT: ${K8S_API_HOST_AND_PORT:-}
@@ -60,7 +57,7 @@ services:
profiles:
- manual
command: /bin/bash
- entrypoint: ''
+ entrypoint: '/usr/bin/entrypoint.spec.sh'
depends_on:
- db
- redis
diff --git a/sample.irbrc b/sample.irbrc
index 6e1a1c2c1..8429bde97 100644
--- a/sample.irbrc
+++ b/sample.irbrc
@@ -1,4 +1,3 @@
-require 'irb/ext/save-history'
-IRB.conf[:SAVE_HISTORY] = 1_000
+IRB.conf[:EVAL_HISTORY] = 1_000
IRB.conf[:HISTORY_FILE] = File.join(__dir__, '.pry_history')
IRB.conf[:USE_AUTOCOMPLETE] = false
diff --git a/sample.pgpass b/sample.pgpass
new file mode 100644
index 000000000..cec9372d4
--- /dev/null
+++ b/sample.pgpass
@@ -0,0 +1 @@
+db:5432:*:postgres:postgres
diff --git a/setenv.rb b/setenv.rb
index 4130de12e..6d49d956a 100755
--- a/setenv.rb
+++ b/setenv.rb
@@ -5,30 +5,24 @@
target = '.env.local'
env_files =
- Dir.glob(".env.*").reject do |env_file|
- env_file == '.env' ||
- env_file == '.env.local' ||
- env_file == '.env.test' ||
- env_file == '.env.development'
+ Dir.glob('.env.*').reject do |env_file|
+ ['.env', '.env.local', '.env.test', '.env.development'].include?(env_file)
end
bad = true
-while (bad)
- puts "Select an environment:"
+while bad
+ puts 'Select an environment:'
env_files.each.with_index do |env_file, index|
- puts "#{"%2d" % index}: #{env_file}"
+ puts "#{'%2d' % index}: #{env_file}" # rubocop:disable Style/FormatString
end
@response = gets.chomp.to_i
- if @response < env_files.length && @response >= 0
- bad=false
- end
+ bad = false if @response < env_files.length && @response >= 0
end
env_file = env_files[@response]
-
-if File.exists?(target) && !File.symlink?(target)
+if File.exist?(target) && !File.symlink?(target)
puts "Refusing to link to #{target} because it's a regular file."
else
puts "Linking .env.local to #{env_file}"
@@ -36,9 +30,9 @@
FileUtils.rm_f(target)
FileUtils.ln_s(env_file, target)
-
if !ENV['TMUX'].nil?
- system("tmux send-keys 'source .env.local
'")
+ system("tmux send-keys 'source .env.local
+'")
else
puts "Type this:\nsource .env.local"
end
diff --git a/spec/features/accounts_spec.rb b/spec/features/accounts_spec.rb
index c78c65ffa..689e81996 100644
--- a/spec/features/accounts_spec.rb
+++ b/spec/features/accounts_spec.rb
@@ -69,5 +69,60 @@
end
end
end
+
+ feature 'Devise expireable password' do
+ scenario 'after expiring password with password expiration disabled' do
+ Rails.configuration.devise.expire_password_after = false
+ user.force_password_reset!
+ fill_in 'Email', with: user.email
+ fill_in 'Password', with: user.password
+ click_button 'Log in'
+ expect(page).to have_content 'Sign Out'
+ end
+
+ scenario 'without expiring password with password expiration enabled manual' do
+ Rails.configuration.devise.expire_password_after = true
+ fill_in 'Email', with: user.email
+ fill_in 'Password', with: user.password
+ click_button 'Log in'
+ expect(page).to have_content 'Sign Out'
+ end
+
+ scenario 'after expiring password with password expiration enabled manual' do
+ Rails.configuration.devise.expire_password_after = true
+ user.force_password_reset!
+ fill_in 'Email', with: user.email
+ fill_in 'Password', with: user.password
+ click_button 'Log in'
+ expect(page).to have_content 'Password Expired'
+ end
+
+ scenario 'without expiring password with password expiration enabled time-based' do
+ Rails.configuration.devise.expire_password_after = 1.weeks
+ fill_in 'Email', with: user.email
+ fill_in 'Password', with: user.password
+ click_button 'Log in'
+ expect(page).to have_content 'Sign Out'
+ end
+
+ scenario 'time-expiring password with password expiration enabled time-based' do
+ Rails.configuration.devise.expire_password_after = 1.weeks
+ fill_in 'Email', with: user.email
+ fill_in 'Password', with: user.password
+ travel_to Time.current + 2.weeks do
+ click_button 'Log in'
+ expect(page).to have_content 'Password Expired'
+ end
+ end
+
+ scenario 'after expiring password with password expiration enabled time-based' do
+ Rails.configuration.devise.expire_password_after = 1.weeks
+ user.force_password_reset!
+ fill_in 'Email', with: user.email
+ fill_in 'Password', with: user.password
+ click_button 'Log in'
+ expect(page).to have_content 'Password Expired'
+ end
+ end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 39402c9c9..f0196e198 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -47,58 +47,59 @@
# 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
+ # # 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"
+ # # 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:
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
- config.disable_monkey_patching!
+ # # Limits the available syntax to the non-monkey patched syntax that is
+ # # recommended. For more details, see:
+ # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
+ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
+ # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#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
+ # # 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
- # 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
- # 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
- # 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
+ config.include ActiveSupport::Testing::TimeHelpers
config.before(:suite) do
Rails.application.load_seed # loading seeds
end
-
end
diff --git a/vendor/assets/javascripts/DataTables/datatables.min.js b/vendor/assets/javascripts/DataTables/datatables.min.js
index e5d55c089..82b18950c 100644
--- a/vendor/assets/javascripts/DataTables/datatables.min.js
+++ b/vendor/assets/javascripts/DataTables/datatables.min.js
@@ -4,386 +4,49 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
- * https://datatables.net/download/#bs4-4.1.1/dt-1.10.18/b-1.5.6/fc-3.2.5/fh-3.1.4/sc-2.0.0/sl-1.3.0
+ * https://datatables.net/download/#dt/dt-2.2.2/b-3.2.2/fc-5.0.4/fh-4.0.1/sc-2.4.3/sl-3.0.0
*
* Included libraries:
- * Bootstrap 4 4.1.1, DataTables 1.10.18, Buttons 1.5.6, FixedColumns 3.2.5, FixedHeader 3.1.4, Scroller 2.0.0, Select 1.3.0
+ * DataTables 2.2.2, Buttons 3.2.2, FixedColumns 5.0.4, FixedHeader 4.0.1, Scroller 2.4.3, Select 3.0.0
*/
-/*!
- * Bootstrap v4.1.1 (https://getbootstrap.com/)
- * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e(t.bootstrap={},t.jQuery,t.Popper)}(this,function(t,e,c){"use strict";function i(t,e){for(var n=0;nthis._items.length-1||t<0))if(this._isSliding)P(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right',trigger:"hover focus",title:"",delay:0,html:!(_e={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"}),selector:!(de={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)"}),placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},pe="out",ve={HIDE:"hide"+he,HIDDEN:"hidden"+he,SHOW:(me="show")+he,SHOWN:"shown"+he,INSERTED:"inserted"+he,CLICK:"click"+he,FOCUSIN:"focusin"+he,FOCUSOUT:"focusout"+he,MOUSEENTER:"mouseenter"+he,MOUSELEAVE:"mouseleave"+he},Ee="fade",ye="show",Te=".tooltip-inner",Ce=".arrow",Ie="hover",Ae="focus",De="click",be="manual",Se=function(){function i(t,e){if("undefined"==typeof c)throw new TypeError("Bootstrap tooltips require Popper.js (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=oe(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),oe(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(oe(this.getTipElement()).hasClass(ye))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),oe.removeData(this.element,this.constructor.DATA_KEY),oe(this.element).off(this.constructor.EVENT_KEY),oe(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&oe(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===oe(this.element).css("display"))throw new Error("Please use show on visible elements");var t=oe.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){oe(this.element).trigger(t);var n=oe.contains(this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!n)return;var i=this.getTipElement(),r=Cn.getUID(this.constructor.NAME);i.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&oe(i).addClass(Ee);var s="function"==typeof this.config.placement?this.config.placement.call(this,i,this.element):this.config.placement,o=this._getAttachment(s);this.addAttachmentClass(o);var a=!1===this.config.container?document.body:oe(this.config.container);oe(i).data(this.constructor.DATA_KEY,this),oe.contains(this.element.ownerDocument.documentElement,this.tip)||oe(i).appendTo(a),oe(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new c(this.element,i,{placement:o,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:Ce},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),oe(i).addClass(ye),"ontouchstart"in document.documentElement&&oe(document.body).children().on("mouseover",null,oe.noop);var l=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,oe(e.element).trigger(e.constructor.Event.SHOWN),t===pe&&e._leave(null,e)};if(oe(this.tip).hasClass(Ee)){var h=Cn.getTransitionDurationFromElement(this.tip);oe(this.tip).one(Cn.TRANSITION_END,l).emulateTransitionEnd(h)}else l()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=oe.Event(this.constructor.Event.HIDE),r=function(){e._hoverState!==me&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),oe(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(oe(this.element).trigger(i),!i.isDefaultPrevented()){if(oe(n).removeClass(ye),"ontouchstart"in document.documentElement&&oe(document.body).children().off("mouseover",null,oe.noop),this._activeTrigger[De]=!1,this._activeTrigger[Ae]=!1,this._activeTrigger[Ie]=!1,oe(this.tip).hasClass(Ee)){var s=Cn.getTransitionDurationFromElement(n);oe(n).one(Cn.TRANSITION_END,r).emulateTransitionEnd(s)}else r();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){oe(this.getTipElement()).addClass(ue+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||oe(this.config.template)[0],this.tip},t.setContent=function(){var t=oe(this.getTipElement());this.setElementContent(t.find(Te),this.getTitle()),t.removeClass(Ee+" "+ye)},t.setElementContent=function(t,e){var n=this.config.html;"object"==typeof e&&(e.nodeType||e.jquery)?n?oe(e).parent().is(t)||t.empty().append(e):t.text(oe(e).text()):t[n?"html":"text"](e)},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getAttachment=function(t){return _e[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)oe(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==be){var e=t===Ie?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===Ie?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;oe(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}oe(i.element).closest(".modal").on("hide.bs.modal",function(){return i.hide()})}),this.config.selector?this.config=h({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||oe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),oe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Ae:Ie]=!0),oe(e.getTipElement()).hasClass(ye)||e._hoverState===me?e._hoverState=me:(clearTimeout(e._timeout),e._hoverState=me,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===me&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||oe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),oe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Ae:Ie]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=pe,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===pe&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){return"number"==typeof(t=h({},this.constructor.Default,oe(this.element).data(),"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),Cn.typeCheckConfig(ae,t,this.constructor.DefaultType),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=oe(this.getTipElement()),e=t.attr("class").match(fe);null!==e&&0'}),He=h({},Nn.DefaultType,{content:"(string|element|function)"}),We="fade",xe=".popover-header",Ue=".popover-body",Ke={HIDE:"hide"+ke,HIDDEN:"hidden"+ke,SHOW:(Me="show")+ke,SHOWN:"shown"+ke,INSERTED:"inserted"+ke,CLICK:"click"+ke,FOCUSIN:"focusin"+ke,FOCUSOUT:"focusout"+ke,MOUSEENTER:"mouseenter"+ke,MOUSELEAVE:"mouseleave"+ke},Fe=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(t){we(this.getTipElement()).addClass(Le+"-"+t)},r.getTipElement=function(){return this.tip=this.tip||we(this.config.template)[0],this.tip},r.setContent=function(){var t=we(this.getTipElement());this.setElementContent(t.find(xe),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(Ue),e),t.removeClass(We+" "+Me)},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var t=we(this.getTipElement()),e=t.attr("class").match(je);null!==e&&0=this._offsets[r]&&("undefined"==typeof this._offsets[r+1]||t li > .active",vn='[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',En=".dropdown-toggle",yn="> .dropdown-menu .active",Tn=function(){function i(t){this._element=t}var t=i.prototype;return t.show=function(){var n=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&rn(this._element).hasClass(cn)||rn(this._element).hasClass(un))){var t,i,e=rn(this._element).closest(gn)[0],r=Cn.getSelectorFromElement(this._element);if(e){var s="UL"===e.nodeName?pn:mn;i=(i=rn.makeArray(rn(e).find(s)))[i.length-1]}var o=rn.Event(ln.HIDE,{relatedTarget:this._element}),a=rn.Event(ln.SHOW,{relatedTarget:i});if(i&&rn(i).trigger(o),rn(this._element).trigger(a),!a.isDefaultPrevented()&&!o.isDefaultPrevented()){r&&(t=rn(r)[0]),this._activate(this._element,e);var l=function(){var t=rn.Event(ln.HIDDEN,{relatedTarget:n._element}),e=rn.Event(ln.SHOWN,{relatedTarget:i});rn(i).trigger(t),rn(n._element).trigger(e)};t?this._activate(t,t.parentNode,l):l()}}},t.dispose=function(){rn.removeData(this._element,sn),this._element=null},t._activate=function(t,e,n){var i=this,r=("UL"===e.nodeName?rn(e).find(pn):rn(e).children(mn))[0],s=n&&r&&rn(r).hasClass(fn),o=function(){return i._transitionComplete(t,r,n)};if(r&&s){var a=Cn.getTransitionDurationFromElement(r);rn(r).one(Cn.TRANSITION_END,o).emulateTransitionEnd(a)}else o()},t._transitionComplete=function(t,e,n){if(e){rn(e).removeClass(dn+" "+cn);var i=rn(e.parentNode).find(yn)[0];i&&rn(i).removeClass(cn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}if(rn(t).addClass(cn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),Cn.reflow(t),rn(t).addClass(dn),t.parentNode&&rn(t.parentNode).hasClass(hn)){var r=rn(t).closest(_n)[0];r&&rn(r).find(En).addClass(cn),t.setAttribute("aria-expanded",!0)}n&&n()},i._jQueryInterface=function(n){return this.each(function(){var t=rn(this),e=t.data(sn);if(e||(e=new i(this),t.data(sn,e)),"string"==typeof n){if("undefined"==typeof e[n])throw new TypeError('No method named "'+n+'"');e[n]()}})},o(i,null,[{key:"VERSION",get:function(){return"4.1.1"}}]),i}(),rn(document).on(ln.CLICK_DATA_API,vn,function(t){t.preventDefault(),Tn._jQueryInterface.call(rn(this),"show")}),rn.fn.tab=Tn._jQueryInterface,rn.fn.tab.Constructor=Tn,rn.fn.tab.noConflict=function(){return rn.fn.tab=an,Tn._jQueryInterface},Tn);!function(t){if("undefined"==typeof t)throw new TypeError("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1===e[0]&&9===e[1]&&e[2]<1||4<=e[0])throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(e),t.Util=Cn,t.Alert=In,t.Button=An,t.Carousel=Dn,t.Collapse=bn,t.Dropdown=Sn,t.Modal=wn,t.Popover=On,t.Scrollspy=kn,t.Tab=Pn,t.Tooltip=Nn,Object.defineProperty(t,"__esModule",{value:!0})});
-//# sourceMappingURL=bootstrap.min.js.map
-
-/*!
- DataTables 1.10.18
- ©2008-2018 SpryMedia Ltd - datatables.net/license
-*/
-(function(h){"function"===typeof define&&define.amd?define(["jquery"],function(E){return h(E,window,document)}):"object"===typeof exports?module.exports=function(E,H){E||(E=window);H||(H="undefined"!==typeof window?require("jquery"):require("jquery")(E));return h(H,E,E.document)}:h(jQuery,window,document)})(function(h,E,H,k){function Z(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),
-d[c]=e,"o"===b[1]&&Z(a[e])});a._hungarianMap=d}function J(a,b,c){a._hungarianMap||Z(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),J(a[d],b[d],c)):b[d]=b[e]})}function Ca(a){var b=n.defaults.oLanguage,c=b.sDecimal;c&&Da(c);if(a){var d=a.sZeroRecords;!a.sEmptyTable&&(d&&"No data available in table"===b.sEmptyTable)&&F(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(d&&"Loading..."===b.sLoadingRecords)&&F(a,
-a,"sZeroRecords","sLoadingRecords");a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&c!==a&&Da(a)}}function eb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":
-"");"boolean"===typeof a.scrollX&&(a.scrollX=a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b").css({position:"fixed",top:0,left:-1*h(E).scrollLeft(),height:1,width:1,
-overflow:"hidden"}).append(h("").css({position:"absolute",top:1,left:1,width:100,overflow:"scroll"}).append(h("").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}h.extend(a.oBrowser,n.__browser);a.oScroll.iBarWidth=n.__browser.barWidth}
-function hb(a,b,c,d,e,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;d!==e;)a.hasOwnProperty(d)&&(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Ea(a,b){var c=n.defaults.column,d=a.aoColumns.length,c=h.extend({},n.models.oColumn,c,{nTh:b?b:H.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},n.models.oSearch,c[d]);ka(a,d,h(b).data())}function ka(a,b,c){var b=a.aoColumns[b],
-d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=e.attr("width")||null;var f=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(fb(c),J(n.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),c.sClass&&e.addClass(c.sClass),h.extend(b,c),F(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),F(b,c,"aDataSort"));var g=b.mData,j=S(g),i=b.mRender?
-S(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b._setter=null;b.fnGetData=function(a,b,c){var d=j(a,b,k,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return N(g)(a,b,c)};"number"!==typeof g&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,
-b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function $(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Fa(a);for(var c=0,d=b.length;cq[f])d(l.length+q[f],m);else if("string"===
-typeof q[f]){j=0;for(i=l.length;jb&&a[e]--; -1!=d&&c===k&&a.splice(d,
-1)}function da(a,b,c,d){var e=a.aoData[b],f,g=function(c,d){for(;c.childNodes.length;)c.removeChild(c.firstChild);c.innerHTML=B(a,b,d,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=Ia(a,e,d,d===k?k:e._aData).data;else{var j=e.anCells;if(j)if(d!==k)g(j[d],d);else{c=0;for(f=j.length;c").appendTo(g));b=0;for(c=l.length;btr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(m.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(m.sFooterTH);if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=-1);var g=a._iDisplayStart,m=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!lb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:m;for(j=j?0:g;j",{"class":e?d[0]:""}).append(h(" | ",{valign:"top",colSpan:V(a),"class":a.oClasses.sRowEmpty}).html(c))[0];r(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ka(a),g,m,i]);r(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ka(a),g,m,i]);d=h(a.nTBody);d.children().detach();
-d.append(h(b));r(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function T(a,b){var c=a.oFeatures,d=c.bFilter;c.bSort&&mb(a);d?ga(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;P(a);a._drawHold=!1}function nb(a){var b=a.oClasses,c=h(a.nTable),c=h("").insertBefore(c),d=a.oFeatures,e=h("",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=
-a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,m,l,q,k=0;k")[0];m=f[k+1];if("'"==m||'"'==m){l="";for(q=2;f[k+q]!=m;)l+=f[k+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(m=l.split("."),i.id=m[0].substr(1,m[0].length-1),i.className=m[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;k+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=ob(a);else if("f"==j&&
-d.bFilter)g=pb(a);else if("r"==j&&d.bProcessing)g=qb(a);else if("t"==j)g=rb(a);else if("i"==j&&d.bInfo)g=sb(a);else if("p"==j&&d.bPaginate)g=tb(a);else if(0!==n.ext.feature.length){i=n.ext.feature;q=0;for(m=i.length;q',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",
-g):j+g,b=h("",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("").append(j)),f=function(){var b=!this.value?"":this.value;b!=e.sSearch&&(ga(a,{sSearch:b,bRegex:e.bRegex,bSmart:e.bSmart,bCaseInsensitive:e.bCaseInsensitive}),a._iDisplayStart=0,P(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===y(a)?400:0,i=h("input",b).val(e.sSearch).attr("placeholder",d.sSearchPlaceholder).on("keyup.DT search.DT input.DT paste.DT cut.DT",g?Oa(f,g):f).on("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",
-c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==H.activeElement&&i.val(e.sSearch)}catch(d){}});return b[0]}function ga(a,b,c){var d=a.oPreviousSearch,e=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};Ga(a);if("ssp"!=y(a)){wb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b=b.length)a.aiDisplay=g.slice();else{if(j||c||f.length>b.length||0!==b.indexOf(f)||a.bSorted)a.aiDisplay=g.slice();b=a.aiDisplay;for(c=0;c",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Cb,sName:"information"}),d.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",
-b+"_info"));return d[0]}function Cb(a){var b=a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,d=a._iDisplayStart+1,e=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Db(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,d,e,f,g,j));h(b).html(j)}}function Db(a,b){var c=a.fnFormatNumber,d=a._iDisplayStart+1,e=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===e;return b.replace(/_START_/g,c.call(a,d)).replace(/_END_/g,
-c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(d/e))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/e)))}function ha(a){var b,c,d=a.iInitDisplayStart,e=a.aoColumns,f;c=a.oFeatures;var g=a.bDeferLoading;if(a.bInitialised){nb(a);kb(a);fa(a,a.aoHeader);fa(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Fa(a);b=0;for(c=e.length;b",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).on("change.DT",function(){Ra(a,h(this).val());P(a)});h(a.nTable).on("length.dt.DT",function(b,c,d){a===
-c&&h("select",i).val(d)});return i[0]}function tb(a){var b=a.sPaginationType,c=n.ext.pager[b],d="function"===typeof c,e=function(a){P(a)},b=h("").addClass(a.oClasses.sPaging+b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;lf&&(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}
-function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none");r(a,null,"processing",[a,b])}function rb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),m=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("",{"class":f.sScrollWrapper}).append(h("",{"class":f.sScrollHead}).css({overflow:"hidden",
-position:"relative",border:0,width:d?!d?null:v(d):"100%"}).append(h("",{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:v(d)}).append(b));l&&i.append(h("",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:v(d):"100%"}).append(h("",
-{"class":f.sScrollFootInner}).append(m.removeAttr("id").css("margin-left",0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=i.children(),k=b[0],f=b[1],t=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(t.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=t;a.aoDrawCallback.push({fn:la,sName:"scrolling"});return i[0]}function la(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,
-f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,m=j.children("table"),j=a.nScrollBody,l=h(j),q=j.style,t=h(a.nScrollFoot).children("div"),n=t.children("table"),o=h(a.nTHead),p=h(a.nTable),s=p[0],r=s.style,u=a.nTFoot?h(a.nTFoot):null,x=a.oBrowser,U=x.bScrollOversize,Xb=D(a.aoColumns,"nTh"),Q,L,R,w,Ua=[],y=[],z=[],A=[],B,C=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};L=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==
-L&&a.scrollBarVis!==k)a.scrollBarVis=L,$(a);else{a.scrollBarVis=L;p.children("thead, tfoot").remove();u&&(R=u.clone().prependTo(p),Q=u.find("tr"),R=R.find("tr"));w=o.clone().prependTo(p);o=o.find("tr");L=w.find("tr");w.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(ra(a,w),function(b,c){B=aa(a,b);c.style.width=a.aoColumns[B].sWidth});u&&I(function(a){a.style.width=""},R);f=p.outerWidth();if(""===c){r.width="100%";if(U&&(p.find("tbody").height()>j.offsetHeight||
-"scroll"==l.css("overflow-y")))r.width=v(p.outerWidth()-b);f=p.outerWidth()}else""!==d&&(r.width=v(d),f=p.outerWidth());I(C,L);I(function(a){z.push(a.innerHTML);Ua.push(v(h(a).css("width")))},L);I(function(a,b){if(h.inArray(a,Xb)!==-1)a.style.width=Ua[b]},o);h(L).height(0);u&&(I(C,R),I(function(a){A.push(a.innerHTML);y.push(v(h(a).css("width")))},R),I(function(a,b){a.style.width=y[b]},Q),h(R).height(0));I(function(a,b){a.innerHTML=''+z[b]+"
";a.childNodes[0].style.height=
-"0";a.childNodes[0].style.overflow="hidden";a.style.width=Ua[b]},L);u&&I(function(a,b){a.innerHTML=''+A[b]+"
";a.childNodes[0].style.height="0";a.childNodes[0].style.overflow="hidden";a.style.width=y[b]},R);if(p.outerWidth()j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(U&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=v(Q-b);(""===c||""!==d)&&K(a,1,"Possible column misalignment",6)}else Q="100%";q.width=v(Q);
-g.width=v(Q);u&&(a.nScrollFoot.style.width=v(Q));!e&&U&&(q.height=v(s.offsetHeight+b));c=p.outerWidth();m[0].style.width=v(c);i.width=v(c);d=p.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+(x.bScrollbarLeft?"Left":"Right");i[e]=d?b+"px":"0px";u&&(n[0].style.width=v(c),t[0].style.width=v(c),t[0].style[e]=d?b+"px":"0px");p.children("colgroup").insertBefore(p.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function I(a,b,c){for(var d=0,e=0,
-f=b.length,g,j;e").appendTo(j.find("tbody"));j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");m=ra(a,j.find("thead")[0]);for(n=0;n").css({width:o.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(n=0;n").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()").css("width",v(a)).appendTo(b||H.body),d=c[0].offsetWidth;c.remove();return d}function Fb(a,
-b){var c=Gb(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h(" | ").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Gb(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;fd&&(d=c.length,e=f);return e}function v(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function X(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var m=[];f=function(a){a.length&&
-!h.isArray(a[0])?m.push(a):h.merge(m,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;ae?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return ce?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,n=f[a]._aSortData,o=f[b]._aSortData;for(j=0;jg?1:0})}a.bSorted=!0}function Ib(a){for(var b,c,d=a.aoColumns,e=X(a),a=a.oLanguage.oAria,f=0,g=d.length;f/g,"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0e?e+1:3));e=0;for(f=d.length;ee?e+1:3))}a.aLastSort=d}function Hb(a,b){var c=a.aoColumns[b],d=n.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,ba(a,b)));for(var f,g=n.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j=f.length?[0,c[1]]:c)}));b.search!==k&&h.extend(a.oPreviousSearch,Bb(b.search));if(b.columns){d=0;for(e=b.columns.length;d=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Na(a,b){var c=a.renderer,d=n.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===
-typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ia(a,b){var c=[],c=Kb.numbers_length,d=Math.floor(c/2);b<=c?c=Y(0,b):a<=d?(c=Y(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=Y(b-(c-2),b):(c=Y(a-d+2,a+d-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function Da(a){h.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Ya)},"html-num":function(b){return za(b,
-a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Ya)}},function(b,c){x.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(x.type.search[b+a]=x.type.search.html)})}function Lb(a){return function(){var b=[ya(this[n.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return n.ext.internal[a].apply(this,b)}}var n=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new s(ya(this[x.iApiIndex])):new s(this)};
-this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&la(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,
-b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():
-c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};
-this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return ya(this[x.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();
-(d===k||d)&&h.draw();return 0};this.fnVersionCheck=x.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=x.internal;for(var e in n.ext.internal)e&&(this[e]=Lb(e));this.each(function(){var e={},g=1").appendTo(q));
-p.nTHead=b[0];b=q.children("tbody");b.length===0&&(b=h("").appendTo(q));p.nTBody=b[0];b=q.children("tfoot");if(b.length===0&&a.length>0&&(p.oScroll.sX!==""||p.oScroll.sY!==""))b=h("").appendTo(q);if(b.length===0||b.children().length===0)q.addClass(u.sNoFooter);else if(b.length>0){p.nTFoot=b[0];ea(p.aoFooter,p.nTFoot)}if(g.aaData)for(j=0;j/g,Zb=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,$b=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Ya=/[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi,M=function(a){return!a||!0===a||"-"===a?!0:!1},Nb=function(a){var b=parseInt(a,10);return!isNaN(b)&&
-isFinite(a)?b:null},Ob=function(a,b){Za[b]||(Za[b]=RegExp(Qa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Za[b],"."):a},$a=function(a,b,c){var d="string"===typeof a;if(M(a))return!0;b&&d&&(a=Ob(a,b));c&&d&&(a=a.replace(Ya,""));return!isNaN(parseFloat(a))&&isFinite(a)},Pb=function(a,b,c){return M(a)?!0:!(M(a)||"string"===typeof a)?null:$a(a.replace(Aa,""),b,c)?!0:null},D=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;ea.length)){b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d")[0],Wb=va.textContent!==k,Yb=
-/<.*?>/g,Oa=n.util.throttle,Rb=[],w=Array.prototype,ac=function(a){var b,c,d=n.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};s=function(a,b){if(!(this instanceof
-s))return new s(a,b);var c=[],d=function(a){(a=ac(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;ea?new s(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);else for(var c=0,d=this.length;c | ").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=V(d),e.push(c[0]))};f(a,b);c._details&&c._details.detach();c._details=h(e);
-c._detailsShow&&c._details.insertAfter(c.nTr)}return this});o(["row().child.show()","row().child().show()"],function(){Tb(this,!0);return this});o(["row().child.hide()","row().child().hide()"],function(){Tb(this,!1);return this});o(["row().child.remove()","row().child().remove()"],function(){db(this);return this});o("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var bc=/^([^:]+):(name|visIdx|visible)$/,Ub=function(a,b,
-c,d,e){for(var c=[],d=0,f=e.length;d=0?b:g.length+b];if(typeof a==="function"){var e=Ba(c,f);return h.map(g,function(b,f){return a(f,Ub(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(bc):
-"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],10);if(b<0){var n=h.map(g,function(a,b){return a.bVisible?b:null});return[n[n.length+b]]}return[aa(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},
-1);c.selector.cols=a;c.selector.opts=b;return c});u("columns().header()","column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});u("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});u("columns().data()","column().data()",function(){return this.iterator("column-rows",Ub,1)});u("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},
-1)});u("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ja(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});u("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ja(a.aoData,e,"anCells",b)},1)});u("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,
-i,m,l;if(a!==k&&g.bVisible!==a){if(a){var n=h.inArray(!0,D(f,"bVisible"),c+1);i=0;for(m=j.length;id;return!0};n.isDataTable=
-n.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;if(a instanceof n.Api)return!0;h.each(n.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot?h("table",e.nScrollFoot)[0]:null;if(e.nTable===b||f===b||g===b)c=!0});return c};n.tables=n.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(n.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new s(c):c};n.camelToHungarian=J;o("$()",function(a,b){var c=
-this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){o(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0]=h.map(a[0].split(/\s/),function(a){return!a.match(/\.dt\b/)?a+".dt":a}).join(" ");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});o("clear()",function(){return this.iterator("table",function(a){oa(a)})});o("settings()",function(){return new s(this.context,this.context)});o("init()",function(){var a=
-this.context;return a.length?a[0].oInit:null});o("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});o("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),o;b.bDestroying=!0;r(b,"aoDestroyCallback","destroy",[b]);a||(new s(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");
-h(E).off(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));b.aaSorting=[];b.aaSortingFixed=[];wa(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",b.sDestroyWidth).removeClass(d.sTable),
-(o=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%o])}));c=h.inArray(b,n.settings);-1!==c&&n.settings.splice(c,1)})});h.each(["column","row","cell"],function(a,b){o(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,m){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,m)})})});o("i18n()",function(a,b,c){var d=this.context[0],a=S(a)(d.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:
-a._);return a.replace("%d",c)});n.version="1.10.18";n.settings=[];n.models={};n.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};n.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};n.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,
-sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};n.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,
-bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+
-a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},
-oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},
-n.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};Z(n.defaults);n.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};
-Z(n.defaults.column);n.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],
-aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",
-iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:
-this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};n.ext=x={buttons:{},
-classes:{},build:"bs4-4.1.1/dt-1.10.18/b-1.5.6/fc-3.2.5/fh-3.1.4/sc-2.0.0/sl-1.3.0",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:n.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:n.version};h.extend(x,{afnFiltering:x.search,aTypes:x.type.detect,ofnSearch:x.type.search,oSort:x.type.order,afnSortData:x.order,aoFeatures:x.feature,oApi:x.internal,oStdClasses:x.classes,oPagination:x.pager});
-h.extend(n.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",
-sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",
-sJUIHeader:"",sJUIFooter:""});var Kb=n.ext.pager;h.extend(Kb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ia(a,b)]},simple_numbers:function(a,b){return["previous",ia(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ia(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ia(a,b),"last"]},_numbers:ia,numbers_length:7});h.extend(!0,n.ext.renderer,{pageButton:{_:function(a,b,c,d,e,
-f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},m,l,n=0,o=function(b,d){var k,s,u,r,v=function(b){Ta(a,b.data.action,true)};k=0;for(s=d.length;k").appendTo(b);o(u,r)}else{m=null;l="";switch(r){case "ellipsis":b.append('…');break;case "first":m=j.sFirst;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":m=j.sPrevious;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":m=
-j.sNext;l=r+(e",{"class":g.sPageButton+" "+l,"aria-controls":a.sTableId,"aria-label":i[r],"data-dt-idx":n,tabindex:a.iTabIndex,id:c===0&&typeof r==="string"?a.sTableId+"_"+r:null}).html(m).appendTo(b);Wa(u,{action:r},v);n++}}}},s;try{s=h(b).find(H.activeElement).data("dt-idx")}catch(u){}o(h(b).empty(),d);s!==k&&h(b).find("[data-dt-idx="+
-s+"]").focus()}}});h.extend(n.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return $a(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&!Zb.test(a))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||M(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return $a(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c,!0)?"html-num-fmt"+c:null},function(a){return M(a)||
-"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(n.ext.type.search,{html:function(a){return M(a)?a:"string"===typeof a?a.replace(Mb," ").replace(Aa,""):""},string:function(a){return M(a)?a:"string"===typeof a?a.replace(Mb," "):a}});var za=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Ob(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(x.type.order,{"date-pre":function(a){a=Date.parse(a);return isNaN(a)?-Infinity:a},"html-pre":function(a){return M(a)?
-"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return M(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return ab?1:0},"string-desc":function(a,b){return ab?-1:0}});Da("");h.extend(!0,n.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:
-c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]==
-"asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Vb=function(a){return"string"===typeof a?a.replace(//g,">").replace(/"/g,"""):a};n.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Vb(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
-a)+f+(e||"")}}},text:function(){return{display:Vb}}};h.extend(n.ext.internal,{_fnExternApiFunc:Lb,_fnBuildAjax:sa,_fnAjaxUpdate:lb,_fnAjaxParameters:ub,_fnAjaxUpdateDraw:vb,_fnAjaxDataSrc:ta,_fnAddColumn:Ea,_fnColumnOptions:ka,_fnAdjustColumnSizing:$,_fnVisibleToColumnIndex:aa,_fnColumnIndexToVisible:ba,_fnVisbleColumns:V,_fnGetColumns:ma,_fnColumnTypes:Ga,_fnApplyColumnDefs:ib,_fnHungarianMap:Z,_fnCamelToHungarian:J,_fnLanguageCompat:Ca,_fnBrowserDetect:gb,_fnAddData:O,_fnAddTr:na,_fnNodeToDataIndex:function(a,
-b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:jb,_fnSplitObjNotation:Ja,_fnGetObjectDataFn:S,_fnSetObjectDataFn:N,_fnGetDataMaster:Ka,_fnClearTable:oa,_fnDeleteIndex:pa,_fnInvalidate:da,_fnGetRowElements:Ia,_fnCreateTr:Ha,_fnBuildHead:kb,_fnDrawHead:fa,_fnDraw:P,_fnReDraw:T,_fnAddOptionsHtml:nb,_fnDetectHeader:ea,_fnGetUniqueThs:ra,_fnFeatureHtmlFilter:pb,_fnFilterComplete:ga,_fnFilterCustom:yb,
-_fnFilterColumn:xb,_fnFilter:wb,_fnFilterCreateSearch:Pa,_fnEscapeRegex:Qa,_fnFilterData:zb,_fnFeatureHtmlInfo:sb,_fnUpdateInfo:Cb,_fnInfoMacros:Db,_fnInitialise:ha,_fnInitComplete:ua,_fnLengthChange:Ra,_fnFeatureHtmlLength:ob,_fnFeatureHtmlPaginate:tb,_fnPageChange:Ta,_fnFeatureHtmlProcessing:qb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:rb,_fnScrollDraw:la,_fnApplyToChildren:I,_fnCalculateColumnWidths:Fa,_fnThrottle:Oa,_fnConvertToWidth:Eb,_fnGetWidestNode:Fb,_fnGetMaxLenString:Gb,_fnStringToCss:v,
-_fnSortFlatten:X,_fnSort:mb,_fnSortAria:Ib,_fnSortListener:Va,_fnSortAttachListener:Ma,_fnSortingClasses:wa,_fnSortData:Hb,_fnSaveState:xa,_fnLoadState:Jb,_fnSettingsFromNode:ya,_fnLog:K,_fnMap:F,_fnBindAction:Wa,_fnCallbackReg:z,_fnCallbackFire:r,_fnLengthOverflow:Sa,_fnRenderer:Na,_fnDataSource:y,_fnRowAttributes:La,_fnExtend:Xa,_fnCalculateEnd:function(){}});h.fn.dataTable=n;n.$=h;h.fn.dataTableSettings=n.settings;h.fn.dataTableExt=n.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};
-h.each(n,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable});
-
-
-/*!
- DataTables Bootstrap 4 integration
- ©2011-2017 SpryMedia Ltd - datatables.net/license
-*/
-(function(b){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return b(a,window,document)}):"object"===typeof exports?module.exports=function(a,d){a||(a=window);if(!d||!d.fn.dataTable)d=require("datatables.net")(a,d).$;return b(d,a,a.document)}:b(jQuery,window,document)})(function(b,a,d,m){var f=b.fn.dataTable;b.extend(!0,f.defaults,{dom:"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
-renderer:"bootstrap"});b.extend(f.ext.classes,{sWrapper:"dataTables_wrapper dt-bootstrap4",sFilterInput:"form-control form-control-sm",sLengthSelect:"custom-select custom-select-sm form-control form-control-sm",sProcessing:"dataTables_processing card",sPageButton:"paginate_button page-item"});f.ext.renderer.pageButton.bootstrap=function(a,h,r,s,j,n){var o=new f.Api(a),t=a.oClasses,k=a.oLanguage.oPaginate,u=a.oLanguage.oAria.paginate||{},e,g,p=0,q=function(d,f){var l,h,i,c,m=function(a){a.preventDefault();
-!b(a.currentTarget).hasClass("disabled")&&o.page()!=a.data.action&&o.page(a.data.action).draw("page")};l=0;for(h=f.length;l",
-{"class":t.sPageButton+" "+g,id:0===r&&"string"===typeof c?a.sTableId+"_"+c:null}).append(b("",{href:"#","aria-controls":a.sTableId,"aria-label":u[c],"data-dt-idx":p,tabindex:a.iTabIndex,"class":"page-link"}).html(e)).appendTo(d),a.oApi._fnBindAction(i,{action:c},m),p++)}},i;try{i=b(h).find(d.activeElement).data("dt-idx")}catch(v){}q(b(h).empty().html('').children("ul"),s);i!==m&&b(h).find("[data-dt-idx="+i+"]").focus()};return f});
-
-
-/*!
- Buttons for DataTables 1.5.6
- ©2016-2019 SpryMedia Ltd - datatables.net/license
-*/
-var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(d,q,n){d instanceof String&&(d=String(d));for(var l=d.length,u=0;u").addClass(this.c.dom.container.className)};this._constructor()};d.extend(t.prototype,{action:function(a,b){a=this._nodeToButton(a);if(b===l)return a.conf.action;a.conf.action=
-b;return this},active:function(a,b){var c=this._nodeToButton(a);a=this.c.dom.button.active;c=d(c.node);if(b===l)return c.hasClass(a);c.toggleClass(a,b===l?!0:b);return this},add:function(a,b){var c=this.s.buttons;if("string"===typeof b){b=b.split("-");c=this.s;for(var d=0,f=b.length-1;d").addClass(y.className).attr("role","menu");m.conf._collection=m.collection;
-this._expandButton(m.buttons,m.conf.buttons,!0,e)}v.init&&v.init.call(f.button(m.node),f,d(m.node),v);g++}}}},_buildButton:function(a,b){var c=this.c.dom.button,e=this.c.dom.buttonLiner,f=this.c.dom.collection,g=this.s.dt,h=function(b){return"function"===typeof b?b(g,m,a):b};b&&f.button&&(c=f.button);b&&f.buttonLiner&&(e=f.buttonLiner);if(a.available&&!a.available(g,a))return!1;var k=function(a,b,c,e){e.action.call(b.button(c),a,b,c,e);d(b.table().node()).triggerHandler("buttons-action.dt",[b.button(c),
-b,c,e])};f=a.tag||c.tag;var v=a.clickBlurs===l?!0:a.clickBlurs,m=d("<"+f+"/>").addClass(c.className).attr("tabindex",this.s.dt.settings()[0].iTabIndex).attr("aria-controls",this.s.dt.table().node().id).on("click.dtb",function(b){b.preventDefault();!m.hasClass(c.disabled)&&a.action&&k(b,g,m,a);v&&m.blur()}).on("keyup.dtb",function(b){13===b.keyCode&&!m.hasClass(c.disabled)&&a.action&&k(b,g,m,a)});"a"===f.toLowerCase()&&m.attr("href","#");"button"===f.toLowerCase()&&m.attr("type","button");e.tag?(f=
-d("<"+e.tag+"/>").html(h(a.text)).addClass(e.className),"a"===e.tag.toLowerCase()&&f.attr("href","#"),m.append(f)):m.html(h(a.text));!1===a.enabled&&m.addClass(c.disabled);a.className&&m.addClass(a.className);a.titleAttr&&m.attr("title",h(a.titleAttr));a.attr&&m.attr(a.attr);a.namespace||(a.namespace=".dt-button-"+C++);e=(e=this.c.dom.buttonContainer)&&e.tag?d("<"+e.tag+"/>").addClass(e.className).append(m):m;this._addKey(a);this.c.buttonCreated&&(e=this.c.buttonCreated(a,e));return{conf:a,node:m.get(0),
-inserter:e,buttons:[],inCollection:b,collection:null}},_nodeToButton:function(a,b){b||(b=this.s.buttons);for(var c=0,d=b.length;c").addClass(b).css("display","none").insertAfter(e).stop().fadeIn(c):
-d("div."+b).stop().fadeOut(c,function(){d(this).removeClass(b).remove()})};t.instanceSelector=function(a,b){if(!a)return d.map(b,function(a){return a.inst});var c=[],e=d.map(b,function(a){return a.name}),f=function(a){if(d.isArray(a))for(var g=0,k=a.length;g'+e.collectionTitle+"");e._collection.addClass(e.collectionLayout).css("display","none").insertAfter(l).stop().fadeIn(e.fade);
-g=e._collection.css("position");if(k&&"absolute"===g)e._collection.css({top:k.top,left:k.left});else if("absolute"===g){e._collection.css({top:a.top+c.outerHeight(),left:a.left});k=h.offset().top+h.height();k=a.top+c.outerHeight()+e._collection.outerHeight()-k;g=a.top-e._collection.outerHeight();var m=h.offset().top;(k>m-g||e.dropup)&&e._collection.css("top",a.top-e._collection.outerHeight()-5);e._collection.hasClass(e.rightAlignClassName)&&e._collection.css("left",a.left+c.outerWidth()-e._collection.outerWidth());
-k=a.left+e._collection.outerWidth();h=h.offset().left+h.width();k>h&&e._collection.css("left",a.left-(k-h));c=c.offset().left+e._collection.outerWidth();c>d(q).width()&&e._collection.css("left",a.left-(c-d(q).width()))}else c=e._collection.height()/2,c>d(q).height()/2&&(c=d(q).height()/2),e._collection.css("marginTop",-1*c);e.background&&t.background(!0,e.backgroundClassName,e.fade,l);setTimeout(function(){d("div.dt-button-background").on("click.dtb-collection",function(){});d("body").on("click.dtb-collection",
-function(a){var b=d.fn.addBack?"addBack":"andSelf";d(a.target).parents()[b]().filter(e._collection).length||f()}).on("keyup.dtb-collection",function(a){27===a.keyCode&&f()});if(e.autoClose)b.on("buttons-action.b-internal",function(){f()})},10)}},background:!0,collectionLayout:"",collectionTitle:"",backgroundClassName:"dt-button-background",rightAlignClassName:"dt-button-right",autoClose:!1,fade:400,attr:{"aria-haspopup":!0}},copy:function(a,b){if(r.copyHtml5)return"copyHtml5";if(r.copyFlash&&r.copyFlash.available(a,
-b))return"copyFlash"},csv:function(a,b){if(r.csvHtml5&&r.csvHtml5.available(a,b))return"csvHtml5";if(r.csvFlash&&r.csvFlash.available(a,b))return"csvFlash"},excel:function(a,b){if(r.excelHtml5&&r.excelHtml5.available(a,b))return"excelHtml5";if(r.excelFlash&&r.excelFlash.available(a,b))return"excelFlash"},pdf:function(a,b){if(r.pdfHtml5&&r.pdfHtml5.available(a,b))return"pdfHtml5";if(r.pdfFlash&&r.pdfFlash.available(a,b))return"pdfFlash"},pageLength:function(a){a=a.settings()[0].aLengthMenu;var b=d.isArray(a[0])?
-a[0]:a,c=d.isArray(a[0])?a[1]:a;return{extend:"collection",text:function(a){return a.i18n("buttons.pageLength",{"-1":"Show all rows",_:"Show %d rows"},a.page.len())},className:"buttons-page-length",autoClose:!0,buttons:d.map(b,function(a,b){return{text:c[b],className:"button-page-length",action:function(b,c){c.page.len(a).draw()},init:function(b,c,d){var e=this;c=function(){e.active(b.page.len()===a)};b.on("length.dt"+d.namespace,c);c()},destroy:function(a,b,c){a.off("length.dt"+c.namespace)}}}),
-init:function(a,b,c){var d=this;a.on("length.dt"+c.namespace,function(){d.text(c.text)})},destroy:function(a,b,c){a.off("length.dt"+c.namespace)}}}});p.Api.register("buttons()",function(a,b){b===l&&(b=a,a=l);this.selector.buttonGroup=a;var c=this.iterator(!0,"table",function(c){if(c._buttons)return t.buttonSelector(t.instanceSelector(a,c._buttons),b)},!0);c._groupSelector=a;return c});p.Api.register("button()",function(a,b){a=this.buttons(a,b);1"+a+"":"";d('').html(a).append(d("")["string"===typeof b?"html":"append"](b)).css("display","none").appendTo("body").fadeIn();c!==l&&0!==c&&(w=setTimeout(function(){e.buttons.info(!1)},c));
-return this});p.Api.register("buttons.exportData()",function(a){if(this.context.length)return D(new p.Api(this.context[0]),a)});p.Api.register("buttons.exportInfo()",function(a){a||(a={});var b=a;var c="*"===b.filename&&"*"!==b.title&&b.title!==l&&null!==b.title&&""!==b.title?b.title:b.filename;"function"===typeof c&&(c=c());c===l||null===c?c=null:(-1!==c.indexOf("*")&&(c=d.trim(c.replace("*",d("head > title").text()))),c=c.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g,""),(b=x(b.extension))||
-(b=""),c+=b);b=x(a.title);b=null===b?null:-1!==b.indexOf("*")?b.replace("*",d("head > title").text()||"Exported data"):b;return{filename:c,title:b,messageTop:z(this,a.message||a.messageTop,"top"),messageBottom:z(this,a.messageBottom,"bottom")}});var x=function(a){return null===a||a===l?null:"function"===typeof a?a():a},z=function(a,b,c){b=x(b);if(null===b)return null;a=d("caption",a.table().container()).eq(0);return"*"===b?a.css("caption-side")!==c?null:a.length?a.text():"":b},A=d("")[0],
-D=function(a,b){var c=d.extend(!0,{},{rows:null,columns:"",modifier:{search:"applied",order:"applied"},orthogonal:"display",stripHtml:!0,stripNewlines:!0,decodeEntities:!0,trim:!0,format:{header:function(a){return e(a)},footer:function(a){return e(a)},body:function(a){return e(a)}},customizeData:null},b),e=function(a){if("string"!==typeof a)return a;a=a.replace(/