From 77e6c4989accc29f7344d29fcb2c9f57dcb8f2bd Mon Sep 17 00:00:00 2001 From: Stuart Olivera Date: Tue, 28 May 2019 11:50:00 -0400 Subject: [PATCH 1/2] feat: Track history of model changes --- Gemfile | 3 +- Gemfile.lock | 3 + app/helpers/audit_helper.rb | 12 ++++ app/helpers/hackathon_manager_helper.rb | 4 +- app/models/bus_list.rb | 2 + app/models/message.rb | 2 + app/models/questionnaire.rb | 2 + app/models/school.rb | 2 + app/models/trackable_tag.rb | 2 + app/models/user.rb | 2 + app/views/manage/admins/show.html.haml | 59 ++++++++++-------- .../application/_model_history.html.haml | 43 +++++++++++++ app/views/manage/bus_lists/show.html.haml | 8 ++- app/views/manage/messages/show.html.haml | 40 +++++++----- .../manage/questionnaires/_history.html.haml | 8 ++- app/views/manage/schools/show.html.haml | 5 ++ .../manage/trackable_tags/show.html.haml | 5 ++ db/migrate/20190528155025_install_audited.rb | 30 +++++++++ db/schema.rb | 24 ++++++- test/helpers/audit_helper_test.rb | 32 ++++++++++ vendor/cache/audited-4.8.0.gem | Bin 0 -> 35328 bytes 21 files changed, 239 insertions(+), 49 deletions(-) create mode 100644 app/helpers/audit_helper.rb create mode 100644 app/views/manage/application/_model_history.html.haml create mode 100644 db/migrate/20190528155025_install_audited.rb create mode 100644 test/helpers/audit_helper_test.rb create mode 100644 vendor/cache/audited-4.8.0.gem diff --git a/Gemfile b/Gemfile index e26166aac..e671a1216 100644 --- a/Gemfile +++ b/Gemfile @@ -68,9 +68,10 @@ gem 'bootstrap', '~> 4.3.1' # Markdown parsing gem 'redcarpet' -# Model validation +# Model extensions gem 'strip_attributes' gem 'validate_url' +gem 'audited', '~> 4.7' # Background job processing gem 'sidekiq', '< 6' diff --git a/Gemfile.lock b/Gemfile.lock index 8cee5b29a..8ace4f5cf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,6 +50,8 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) arel (9.0.0) + audited (4.8.0) + activerecord (>= 4.0, < 5.3) autoprefixer-rails (9.5.1.1) execjs aws-eventstream (1.0.3) @@ -457,6 +459,7 @@ PLATFORMS DEPENDENCIES ajax-datatables-rails (~> 0.4.0) + audited (~> 4.7) aws-sdk-s3 better_errors binding_of_caller diff --git a/app/helpers/audit_helper.rb b/app/helpers/audit_helper.rb new file mode 100644 index 000000000..0eb913dfa --- /dev/null +++ b/app/helpers/audit_helper.rb @@ -0,0 +1,12 @@ +module AuditHelper + def display_audit_value(value, field) + return "(none)" if value.blank? + return Questionnaire::POSSIBLE_ACC_STATUS[value] if field == "acc_status" + return BusList.find(value)&.name || value if field == "bus_list_id" + return User.find(value)&.full_name || value if field == "checked_in_by_id" + return value.join(", ") if value.is_a? Array + return display_datetime(value, relative: false) if value.is_a? Time + + value + end +end diff --git a/app/helpers/hackathon_manager_helper.rb b/app/helpers/hackathon_manager_helper.rb index 1c3396761..d8abdece4 100644 --- a/app/helpers/hackathon_manager_helper.rb +++ b/app/helpers/hackathon_manager_helper.rb @@ -92,8 +92,10 @@ def acc_status_class(acc_status) end def display_datetime(datetime, opts = {}) + opts[:relative] = true if opts[:relative].nil? + formatted = "" - if Time.now - datetime < 5.hours + if Time.now - datetime < 5.hours && opts[:relative] formatted << "#{time_ago_in_words(datetime, include_seconds: true)} ago" else format = datetime.year == Time.now.year ? "%b %-d at %I:%M %P" : "%b %-d, %Y at %I:%M %P" diff --git a/app/models/bus_list.rb b/app/models/bus_list.rb index c9e9528ba..c5d8c6036 100644 --- a/app/models/bus_list.rb +++ b/app/models/bus_list.rb @@ -1,4 +1,6 @@ class BusList < ApplicationRecord + audited + validates_presence_of :name, :capacity validates_uniqueness_of :name diff --git a/app/models/message.rb b/app/models/message.rb index cf6fcd1c3..f98ee83bf 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -1,4 +1,6 @@ class Message < ApplicationRecord + audited + self.inheritance_column = nil # To enable using "type" field validates_presence_of :name, :subject, :template diff --git a/app/models/questionnaire.rb b/app/models/questionnaire.rb index 75b3dacd2..ef6d88dd9 100644 --- a/app/models/questionnaire.rb +++ b/app/models/questionnaire.rb @@ -1,4 +1,6 @@ class Questionnaire < ApplicationRecord + audited + include ActiveModel::Dirty include DeletableAttachment diff --git a/app/models/school.rb b/app/models/school.rb index 9ec30cdb5..8af7b6c3f 100644 --- a/app/models/school.rb +++ b/app/models/school.rb @@ -1,4 +1,6 @@ class School < ApplicationRecord + audited + validates_presence_of :name validates_uniqueness_of :name diff --git a/app/models/trackable_tag.rb b/app/models/trackable_tag.rb index 50eebe466..5898689cb 100644 --- a/app/models/trackable_tag.rb +++ b/app/models/trackable_tag.rb @@ -1,4 +1,6 @@ class TrackableTag < ApplicationRecord + audited + validates_presence_of :name validates_uniqueness_of :name strip_attributes diff --git a/app/models/user.rb b/app/models/user.rb index 2c10f85c2..378df208d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,6 @@ class User < ApplicationRecord + audited only: [:email, :role, :is_active, :receive_weekly_report] + devise :database_authenticatable, :registerable, :timeoutable, :recoverable, :rememberable, :trackable, :validatable, :doorkeeper, :omniauthable, omniauth_providers: [:mlh] diff --git a/app/views/manage/admins/show.html.haml b/app/views/manage/admins/show.html.haml index df6a6794e..7565d0f50 100644 --- a/app/views/manage/admins/show.html.haml +++ b/app/views/manage/admins/show.html.haml @@ -3,34 +3,39 @@ = link_to 'Edit', edit_manage_admin_path(@user), class: 'btn btn-sm btn-outline-secondary' = link_to 'Delete', manage_admin_path(@user), method: :delete, data: { confirm: "Are you sure? #{@user.email} will be permanently deleted. This action is irreversible." }, class: 'btn btn-sm btn-outline-secondary' -%div - %p - %b Email address: - = @user.email +.row.mt-2.mb-4 + .col-lg-6 + %p + %b Email address: + = @user.email - %p - %b Role: - = @user.role.titleize + %p + %b Role: + = @user.role.titleize - %p - %b Login access: - - if @user.is_active - %span.badge.badge-success Active - - else - %span.badge.badge-danger Inactive + %p + %b Login access: + - if @user.is_active + %span.badge.badge-success Active + - else + %span.badge.badge-danger Inactive - %p - %b Receive weekly report: - - if @user.receive_weekly_report - %span.badge.badge-success Yes - - if !@user.is_active - %br - %small - %span.fa.fa-info-circle.icon-space-r-half - Will not receive while user is inactive - - else - %span.badge.badge-secondary No + %p + %b Receive weekly report: + - if @user.receive_weekly_report + %span.badge.badge-success Yes + - if !@user.is_active + %br + %small + %span.fa.fa-info-circle.icon-space-r-half + Will not receive while user is inactive + - else + %span.badge.badge-secondary No - %p - %b Registered: - = display_datetime(@user.created_at) + %p + %b Registered: + = display_datetime(@user.created_at) + + .col-lg-6 + %h4.border-bottom.pb-2.mb-3 Change History + = render "model_history", model: @user diff --git a/app/views/manage/application/_model_history.html.haml b/app/views/manage/application/_model_history.html.haml new file mode 100644 index 000000000..55f42a63d --- /dev/null +++ b/app/views/manage/application/_model_history.html.haml @@ -0,0 +1,43 @@ +- ignore_fields = ['acc_status_author_id', 'acc_status_date'] + +- audits ||= model.audits if defined?(model) +- audits = audits.sort_by(&:created_at).reverse +- audits.each_with_index do |audit, index| + .d-xl-flex.justify-content-between + %div + - if audit.action == 'create' + %p.mb-1 + = audit.auditable.model_name.human + created + - else + - audit.audited_changes.each do |field, value_pairs| + - next if ignore_fields.include? field + %p.mb-1 + = t("simple_form.labels.#{audit.auditable.class.name.downcase}.#{field}") + - if audit.auditable.class.columns_hash[field].type == :text + changed + - else + changed to + %strong= display_audit_value(value_pairs[1], field) + %br + %small.text-secondary + Previously: + %strong= display_audit_value(value_pairs[0], field) + .text-secondary.d-flex.justify-content-between.flex-xl-column.justify-content-xl-start.text-xl-right + %p.mb-0 + %small + %span.fa.fa-clock-o.icon-space-r-half + = display_datetime(audit.created_at) + %p.mb-2 + - if audit.user + %small{"data-toggle" => "popover", "data-content" => audit.user.email, "data-trigger" => "hover"} + %span.fa.fa-user-o.icon-space-r-half + = audit.user.full_name + - else +   + - unless (index + 1) == audits.count + %hr.mt-1.mb-2 + +- if audits.empty? + %p.alert.alert-info + No history recorded. diff --git a/app/views/manage/bus_lists/show.html.haml b/app/views/manage/bus_lists/show.html.haml index 2d6ad8796..2a8e3d1f3 100644 --- a/app/views/manage/bus_lists/show.html.haml +++ b/app/views/manage/bus_lists/show.html.haml @@ -116,6 +116,10 @@ .row.mt-2.mb-4 .col - %h4.border-bottom.pb-2.mb-4 - Passenger Distribution + %h4.border-bottom.pb-2.mb-4 Passenger Distribution = render partial: 'bus_list_stats', locals: { bus_list: @bus_list } + +.row.mt-2.mb-4 + .col-lg-6 + %h4.border-bottom.pb-2.mb-3 Change History + = render "model_history", model: @bus_list diff --git a/app/views/manage/messages/show.html.haml b/app/views/manage/messages/show.html.haml index eff294b05..bad3228ad 100644 --- a/app/views/manage/messages/show.html.haml +++ b/app/views/manage/messages/show.html.haml @@ -59,20 +59,28 @@ %iframe.email-preview{src: preview_manage_message_path(@message)} +.row.mt-3 + .col-lg-6 + .card.mb-3 + .card-body.pb-1 + %h5.card-title Change history + = render "model_history", model: @message + - if @message.bulk? - .card.mt-3.mb-3 - .card-body - %h5.card-title Bulk delivery details - %p.card-text - %b - Status: - = @message.status.titleize - %p.card-text - %b Queued At: - = @message.queued_at || "(n/a)" - %p.card-text - %b Started At: - = @message.started_at || "(n/a)" - %p.card-text - %b Delivered At: - = @message.delivered_at || "(n/a)" + .col-lg-6 + .card.mb-3 + .card-body + %h5.card-title Bulk delivery details + %p.card-text + %b + Status: + = @message.status.titleize + %p.card-text + %b Queued At: + = @message.queued_at || "(n/a)" + %p.card-text + %b Started At: + = @message.started_at || "(n/a)" + %p.card-text + %b Delivered At: + = @message.delivered_at || "(n/a)" diff --git a/app/views/manage/questionnaires/_history.html.haml b/app/views/manage/questionnaires/_history.html.haml index 384673860..ef3a9aa63 100644 --- a/app/views/manage/questionnaires/_history.html.haml +++ b/app/views/manage/questionnaires/_history.html.haml @@ -1,5 +1,11 @@ .row - .col-md-6 + .col-lg-6 + .card.mb-3 + .card-header Recent Changes + .card-body.pb-2 + = render "model_history", model: @questionnaire, audits: @questionnaire.audits + @questionnaire.user.audits + + .col-lg-6 .card.mb-3 .card-header Recent Email Events .card-body diff --git a/app/views/manage/schools/show.html.haml b/app/views/manage/schools/show.html.haml index a40928938..eb071ca54 100644 --- a/app/views/manage/schools/show.html.haml +++ b/app/views/manage/schools/show.html.haml @@ -98,3 +98,8 @@ %td= q.email %td= "#{Questionnaire::POSSIBLE_ACC_STATUS[q.acc_status]}".html_safe %td= q.checked_in? ? "Yes" : "No" + +.row.mt-2.mb-4 + .col-lg-6 + %h4.border-bottom.pb-2.mb-3 Change History + = render "model_history", model: @school diff --git a/app/views/manage/trackable_tags/show.html.haml b/app/views/manage/trackable_tags/show.html.haml index df13afd99..c9ad2ece3 100644 --- a/app/views/manage/trackable_tags/show.html.haml +++ b/app/views/manage/trackable_tags/show.html.haml @@ -36,3 +36,8 @@ %td - if current_user.admin? || current_user == trackable_event.user = link_to 'Edit', edit_manage_trackable_event_path(trackable_event) + +.row.mt-2.mb-4 + .col-lg-6 + %h4.border-bottom.pb-2.mb-3 Change History + = render "model_history", model: @trackable_tag diff --git a/db/migrate/20190528155025_install_audited.rb b/db/migrate/20190528155025_install_audited.rb new file mode 100644 index 000000000..ef5487ec3 --- /dev/null +++ b/db/migrate/20190528155025_install_audited.rb @@ -0,0 +1,30 @@ +class InstallAudited < ActiveRecord::Migration[5.2] + def self.up + create_table :audits, :force => true do |t| + t.column :auditable_id, :integer + t.column :auditable_type, :string + t.column :associated_id, :integer + t.column :associated_type, :string + t.column :user_id, :integer + t.column :user_type, :string + t.column :username, :string + t.column :action, :string + t.column :audited_changes, :text + t.column :version, :integer, :default => 0 + t.column :comment, :string + t.column :remote_address, :string + t.column :request_uuid, :string + t.column :created_at, :datetime + end + + add_index :audits, [:auditable_type, :auditable_id, :version], :name => 'auditable_index' + add_index :audits, [:associated_type, :associated_id], :name => 'associated_index' + add_index :audits, [:user_id, :user_type], :name => 'user_index' + add_index :audits, :request_uuid + add_index :audits, :created_at + end + + def self.down + drop_table :audits + end +end diff --git a/db/schema.rb b/db/schema.rb index 7e1f6475f..4efd716b1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_05_27_163723) do +ActiveRecord::Schema.define(version: 2019_05_28_155025) do create_table "active_storage_attachments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.string "name", null: false @@ -33,6 +33,28 @@ t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true end + create_table "audits", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + t.integer "auditable_id" + t.string "auditable_type" + t.integer "associated_id" + t.string "associated_type" + t.integer "user_id" + t.string "user_type" + t.string "username" + t.string "action" + t.text "audited_changes" + t.integer "version", default: 0 + t.string "comment" + t.string "remote_address" + t.string "request_uuid" + t.datetime "created_at" + t.index ["associated_type", "associated_id"], name: "associated_index" + t.index ["auditable_type", "auditable_id", "version"], name: "auditable_index" + t.index ["created_at"], name: "index_audits_on_created_at" + t.index ["request_uuid"], name: "index_audits_on_request_uuid" + t.index ["user_id", "user_type"], name: "user_index" + end + create_table "blazer_audits", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.integer "user_id" t.integer "query_id" diff --git a/test/helpers/audit_helper_test.rb b/test/helpers/audit_helper_test.rb new file mode 100644 index 000000000..26c780b0f --- /dev/null +++ b/test/helpers/audit_helper_test.rb @@ -0,0 +1,32 @@ +require "test_helper" + +class AuditHelperTest < ActiveSupport::TestCase + include AuditHelper + + context "display_audit_value" do + should "show (none) for empty values" do + assert_equal "(none)", display_audit_value(nil, "foo") + assert_equal "(none)", display_audit_value("", "foo") + assert_equal "(none)", display_audit_value([], "foo") + end + + should "use human name for acc_status" do + assert_equal "RSVP Confirmed", display_audit_value("rsvp_confirmed", "acc_status") + end + + should "model values for related fields" do + bus_list = create(:bus_list, name: "Foo bus list") + assert_equal "Foo bus list", display_audit_value(bus_list.id, "bus_list_id") + user = create(:user, email: "abc@example.com") + assert_equal "abc@example.com", display_audit_value(user.id, "checked_in_by_id") + end + + should "use human description for arrays" do + assert_equal "foo, bar, baz", display_audit_value(["foo", "bar", "baz"], "foo") + end + + should "default to regular value" do + assert_equal "Hello world", display_audit_value("Hello world", "foo") + end + end +end diff --git a/vendor/cache/audited-4.8.0.gem b/vendor/cache/audited-4.8.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..a0c6fc693074dfb20d2603877a1f4303176fa5ad GIT binary patch literal 35328 zcmeFYQ*bU$5HA?pKCx||nF)P5)nYNE8hN zvbEx+0|vf>Gi7(gc~@Jf=)93ku@Q$IIM0}67vz#?0#7c6%m5ciImXI`R+*53*J9Dv zBO=}S_pNjW%TZJ zDx(dg6cyLr=(AGXv$v0&2XQuNoQ~DlO!=h2-V>ml)uGDs0`=n_1w$F?kElqDEL{;jXNdo@G>-jnpsk45BQs4j)C4dfN<2l*~h%6|ve-lIPQ7=JV$2xkxd@ zI*DNCWFe~#r%akM`cw^QDfg{W7@KFMH+Az+W;q zC~;G8z8XWw2ELt_5fXCo^-BKBE1RWbe>q=IiwkmOj?&Ms#Ov|i?39crTu@>Lc*m0H zUCjupjKCimaEcAJ)?;d~JwY{+Pv~8sHCsEHc>xO#&njqek{~h zZUAr4#KLJu$fF9L>9fnCtXAC|t^WEl~! z<=odCAA^d(YUAIUa7zx>urCdlt^H~8H}S&Z@7&8NO^OKxUx`yVWNxnpKlXa7Sqp5OPNSP_*6(hpJ6_k0-k#Bxe$l;cZ+BJz`C?p7R4wGd*0Ttfqk* z#j~x3CKoW+By^c_WD*N0yT&K4B$6P(X4Q9*;FAc2>ypgQOEGUWXIx6o%on%Oa;rb- z!0pb0*Q1-jr;`A%f#lZ(wR@g8L3@rL_*&=i)8@>LruKCgZ#z3FE3c;J(1{}Ay1JN)NjV_{+cpYflK>;K39|5vuj|G@w2o-3~{@kQp0z3wQ^9$2aHAjwM% z=OXT?zvNkKOnZiID&xa2~xsIU$o^Q>bpuRgE!8Vzj?>5UqVYAet#;D{(Crd0QI z@}s1I{Oay%8ft3;9Z%>$Rv5C|YK4~z7v9|Oot-+KujKEoi+`?tmp9kf*SG(kk=)!0 zzGmfL_vu#OFWG#s91q2rQ?lviveQy@p80t@`o_-!kLJoa-rNZf`nXuWcoCTn_TJ3& zox`FH0nb+Q$NJu9c0L3{YaU!R^pF-Mupey+C06uTasm{h8)~2w{ z&-!u*^C$M^ejsnHZ#?j!SkyDa9i4u83W9&s{LF9sT?^ZVK&lEP>d%rZ*F5F#l1}p6 z-rEgxzP4g<5kIiWw!iqBSm*nAb`PIg4l_BTB zmeKzSDTtRp4>!1IJvE;3>c*}Y!*|5DhxL}INR4-iyV9AhcC}G`|E;C$*w$n@5)|kJ zST7h`!Tig23E$#Yr$%?hr?AcaOZKZjzV3rQ5=-9}rvnrPc~j7cSi4a&$DUefM;**KHq$+C-cuL6%rsY^wshgf$V9Jt0RG#+y7#9x$b%uc zAmKiOLQj8gBmpRTR5!P-C>e5Z_kHEkTG8v8tkRVWaqyEVv)LbeLQk@g^injU^PAZZ z@SPpdgs4^b#w=&C05Q;AATLnYYKvh0Ub5q&VU9VfTd(2}hWS4rg6Ao8TclT0U8!_9*#S zkCh4~9@nvDcB0KN_iwH!P|8HC0cF@t2x*|Noj=Skugapo;92AUIgfXXZxb?b3yGq@ zs2;vO4v|P=f<@5lLq&e3As-ulll{8f7nC<6CK=!_2G0v!SdVrnOjyeZUpk?WIn@C1 z_WCyh_JJq+$!oiLeGe;-XetiXgwTygoRh>(d@NT*!n3niu=Jf)(GBX;%bSqew^hK( z5@-H{@Um)B$VgZHiQ`Pb0=7y{1i$tUP4_@t;sL9 zP#f0(C-GY&H=($SP!(imKUrKBlzaepVi0NrtTPiBB|e9p@nsKU*{;mk;zW$;&c7_O zA*;S0LNd2MzrHwC@o?3jDY$$Ey$)aZFI-<$XkWA|JU@ItNW)Q?!un59F2Yo> zIG>06bmt41=(u%XN|bZPwzU*wlkhU(rFm@5O`yTZM&ufdd&0BX_q;7^d(W=@Y^pu^ z6BD!C=FsNPo*Lz_EleQa%uV>asM`+j0rlUzgGMTWC8p^ak zPTq1j+9po!s9elIET*>7!-@l%k64FFkkl)|Yy(39Yu3*XF8grYsWEQNv zqNQ>;CNO2(T&gfx;#T9=1w^IXASgEWE&0Vx!KMMWDXHVn+MNXSUepzNmr+#oIK{?blx4hhZNmIlsiJ{-F zAlbo=&y1Gn4g2&6j6<2c;b2vDwbxexDvn4Q2Zu@dyC!vmUpV8eLAcuBAhKgfDd=WK z7I#tjRB%NN<*x%g^6t=Zqg;960^rC{G0Y&Ni8N@51nXGdPyq7!YBo(nt|VM1U5ZMM z!P^N;QtxYd00c6<&+vww7>;BEgf&rg5yDg>7o!6t42IX=f`0dX!aP%6nENy4NeU1L z{5T5@A@3p^iIkm@ohYlchemn!%gG059p2oe2i~fGgsrinb=~yMJIN;pIDVRiJ{oCz z4E6?Cmu@Aif&G(*sMm~f#$+J01yVZK!I~A>e++-pSiCtpqrTqE9$ti7!=;hVo5kS) zP)b=gSI_WcDV+ykJyAWxnpP{QyT}(6B*NWC-Koa@ryer)d?86JkNiQ!aGW<2GKP?2 ziP+8*R z#nW~91Eq|Ir@V8-U~&lzt>l@a2;VLqW@_p{KwPh*)N>w?Vk zK-C~4W?^eI&2WVIrg#MP#9%whW^fkVlLGjW^HDS6BfW{0vqWV`b%_aL#M`eNR=@YDyC9 z-4UWC7$8xVphmK3L|HM$P>uQ-@QKHS$r0*V!#mbPh7@%%t>S(r4h6+Qv?gXqR%huO zC03l%{-tn9dUKHO`RL+>3%{m*kH=pB5S;g-ku-X8!7<6AP!^*j3W*8_(Lcdv%8@0t zpZK{L+nsKCA%4@8a~WJgF*8sRkYD7<^)=L3%#zlsI7{<#q8a87xt(J|Tf~nvFR(@DlgZWiHoa7pcmwtv6-% zDc9s4Xr@ns8njWSKY*13#ILhK{Fw89h5YsA?9>iGkmvoO1al!gZ*yiR-`2!O#)x8Z z2LmvGFM>(*%^#p44N5(KlFHY!Yj1ogvsHo%Tr9M(B00veFUoPi{plZmleRt-EWp*<3^XKuKjNk9?7NZh zF!f#JSKkEQ5Sd*2dwurse&)|Tpo(K7(rgwnflTtq&v$GKZ?usKgME#8odvs_U$J9@`WZlP%ql8kTiy`*-m zx&;_m#p_YF1;o+22;5NbS@iD1e7w?@Fp2G>seHD$=6GV5{z3kHS*t!Q5aRDuu~~Qn zcP&c!{Ld2l0WF4vTm9vuyDr+nSUyZ?!UgzxI&h|ki$TE=Q#Bg>e{k9Ek2XzE3x_b% zK^JgIO9=h3aXIPvVUkjE2T%I8M z&z-8n;*VWOuL)hFhLMYOiS7SA7xK;n>&C9HN9N9e03JRwD)Z};i)jBGz;D07O9}J4 zu3a-A;5YDj#QqFHI){)?0Eq2<&&KQZ!}MZ6HJ9JKaSwcdczU~z>EZsH3-Eq_I>yP% z1^9nGwNX*c`5Orc^_(%yZY(96Q=QG9zr%+SM3u?M&DA%UkCj_o`}jRAO)Mop`nOmM z@c>X-nJURWh^6wqsJ%em+ zU&wC*vwnPD9~fO#1m94_0webgV@&!#S5L?326G#AOnLmj!@>m!hQ{Okyu7Bnf~5HT zyj&h?X7cd)ct1`uta<{}<*hYi;^V#_*Z%l~d=m`#$ImI~1I8=?e)nHr7=EorY2{~C zmjVj2aa-5tPsa$L504ko=KpYm(5<=)#0z#G|LnpAW&NT96T5r0Hy^7KdO3bOr)h?q zdfe9JKfAdD2Jx4VNhstI_zNEaS6+a;T^(;kJ>NIGJMTcPuf7tvhu!M@`Kh$r0hacN zrLNj_JcfV}It4Eb1US2%oVOX%=(Uh2HLK?OJ*rAH+O6LaM1gpp(OMIF*{jwov<&CZ zj@&Qnf4E-*CnT-og}dj9!d3J4p46^9|8}xJvW5K3r(fc%{VybYAP}Ih>zUc9VguK# zbELcW>mA>Xj>bDnO55{ffmKtQOSK4${x$ej90}}s~!@` z?w;Gmuy{W93;vaJlVD$f;1a@qVjb2BHT?@LK)P5A&VS32&G3o44+2=&dE<0|b|#Z9 zEl|7z+ShKG+=z~-TB3!m4~i}_j+s)o|EfOC#MJTl#ltlX>#(t93D4kH>{^DW^XXAe zA4u}lil4^(q+vl5&eJD@T^G70s*}7zE(34b1iO6-jv{&|%{}SA`Y!}~xuwRxxYER5Qsdfx5Q}=K#NDH!;R*qLFuP;E~j)`Si?s<9p zjwC9;A>BF~xp)cWLcac9b~gGh(+9g6uT_$w6@P-W{e`1#;EiUtVoQ9uEey(OIR!zN zY^SrcYzco`VMNPqR_dJpfgTW86Adyfz&&m5vGx^nlSQD~_(%Y~^-1QgyD1DW2Mtp5 zHK=nNPw6puRN~;Q(ri(HO3Wj z4pkNAKYk8|B1@A7(%Qfg`8%phx}8f9^~J=H@i(2A*B=g6B!i@Xab{%%P#;Qv3&}FG z?^k|y3&g&E6fDMvj@KuE8RG9tXg!_VBkYz-I~2kYFj#tXB$i}P_%hZ}EQH~Qv_$!x zE<&SR9@?8y5~Ba`qhv(9yz6LGm&{?G)a;c|?HIAaS#%&^yXKJm4fTG4UaNPIsz1tQ zxTtG)kC=uvqow~j5aT=MGqIzNvW+6&9mdh6lin`IzR?~g9>s-(axlx*r&&aZe&+5) z9ZAWJ9Cz+|BuZ>6Ly=dPj~IE4KLr-QbNe4eIL?z_b~kkTm~PfRu-;y-`+VPpYk=L@ zE-Z~eBL(@xMg?HsUN$fG@aUStHmKfET986nfE(PQh`TkGF{U=L$=heg=Fiwo`G7E6 z@(acJ+=w@<)i~4DGk$53e<9u<#4_>`kFs@pBq+sT1zvgz``_dsCfiy z&Y$v#&sIG!h9ELtC*vS(j;~)-JKpkZpE>fjWcW#&ln|L`{mTAP&**%1{PvhIXBP5j zoEl9VtgCRzehwvB5R-GA+gV;8kG81R$=atVka$7?MG_;!((0#kes>iFX85(0a-jlz z2NP9^HQuG~SR3&Fjl%a+VC-tX8#n*HIDJG79-VYrmOFNQFVPl*54YWKbdU`VMRmCt z4EgtmgunD0=5v`quha?CMi80kZh^i;AnJ|_YsAIe>eU&P?GNk3(AMY*B;0#xdZV#C!DN-!|~WnYzh zZ)_HdifSqr{7n3QIi}QymM^-4tfBc$MMc)#CGg5|vgf|^&sia>=#%o8=^t_GbX0|a zbOI^yQ;`FjgfilD{~{KoMQ+#AUQEgULe1Nw@o>#JYoy_2V~V3i5LgCY*1eG>_S+ZDBfs;=lc~gItDY8!Ijt} zHw~SioUNKJr=P5Ob1(}Pz#87K2zjJHJJ4wz2^*&n*n4@7T zOnAqL$=>*cxai=9hN3hQOC+{9>K*cuY>+lsUE^qIJ<@q?#i+x5P*MM95G32>8riW| zkPeix>hvL^SFKm*(pEzc5gw>s0}(7ngrRdRw)N^?4Y-K68G7VrMU2ubk$2+B8iOfk`xY=J;0z8~F%lhzw>&Sh>n8zpokt`%RSCQK$>3~5QL=*73LE39~r!l}CeFsxryc~2W$qa8^@pA9j_bvslm)SEBgp;k>5(hB0(x9Jd z;s_E7#}}TK;Y%My`pnE3Yj;=5)*GzEH#r}N+6*m(X6uQ8W*+4K)dDpYGb_aYkkLnP z1zm5+JoM@tVxBX2p~=-J#!W32dM6mCXp-#=v}(Y)?RCyV+|W3Q8+XL^hRBz>&>qfTg2*VPavAgleMC9KX9rk8YX12 zP*b^ckI}GVZlHgYP_@|x zH~oYol-_^l7Hb{-q*$xHyfF|dHM~4t38lk7OfiijLm^Z=G#&2EpYz_%YSD4V7km(- z^#lbv-#TNvJmJGK;VaPsgdZPfYBUhHGNI17v7FXPQN}4xh|$^Kr=$d2d2`UoN*E)$X>ju5yA~- zK&~8u_c23QquOHzM*wb&Lw8QJG2VBPX2=7+2zA{T_}IKTvUl8Cy81yDbQN3zsc$5+ zG|;y!d7r3+BIqws^yQ@l&6i)Nr=yv}=#69hqa%vGc;^LOF>MW#>OM!h6iqae?#P7m z1mrn6$b`h-4?(C2dK&Gmi+4V#$I)9~;v`l5_%GE$Avk4cujAwvFJxOfs24LPBIF&!faah~C!wP6$F{ns}KU`rg* z|FnaS4T;^VCEw%o`-f@wTEl7&b(6@70jo$}gxIlIty(E!(htbuvUQsu)$B43&-uws zNDqqq`R#nJ)mtP&HSkF3SoXtgw&y>0$=%GuH)s!jqv-@AYJSNFxe1IKT(=kSsQ(T) zD~b+_g{MV=u#aes3cui!LzJL@LBNztLOY*gKGy9B6&u|EdrSbbluT9=`33#QgiO(7QGW6o>!{j2{4R z{)-FOM*K6oG5S;<#6)zWg;qIaRnG4%o#!KM|sBm}Ph^p`Ux{`T;UEc1m z{`n`#`cskKPMZ+mnP9a_*`Y^}^H7feUg+fzsf>e4M=8rSRWR296!$x4|5f!A0^U>a z`nLGS^MGBsJ-pvQ^HG1+%wG=RJK}POJ^gm0i%Fn|3BJBdIbp@tnTs0Q zJ%89e527LrPE@Fg^TULqwHX{bCb{FjELi@?#$q`&8*opv!|nFhp1(f6bjZh0#`!uD zHnXjUpO+_F%R{)?Z|9=;lYYzr{oH=)y1KmQr|$hf-JgJui@bl6#Ou~wwZiiQB0Lb*LgOvRl7YBkiMG6h zSacS`z6SBjezGoJ2?AEe;A4NhRDnJ2hr00TC6&cybKBhKl0x52*>V|UAwcFA=J+ip z8C*&KvQ?A^NL3huS3ueNB&fQXKw9cBOA)9LA^jj9122=2AaB2iOcmYN0JGRyMsWNh zFKr$5jaVeqRECAjlt0bp;#q+_+rrE5-v-9n7bTV~D{u>Cin^nHad~`vnK|C}$z#Xd z4ztN#n;9s6gbE_=+X&%(ZNqF%HO=o}@Dd@QjKkGlW|^1RNF7a-2OvlnBJ2uYGMqsV ze+d0>gju6LeeoHHs5VG?3o5`Es01iyqR|EJ7=1BgtS`81&5lNFe$2DA{A5$j(~jap zWd7di*56~RO1v7VVieCjbuR;uy=vLrNsjYZN>%b3TT7d%<0jOh1|5r$BWO0-L6LhG zPLbaa?`|#v<6JILDKBs%`gyv)mBQ-OWg-)B$Jwi66#E;xAqa1$WgG^qigF~+i#RBT zY_w5h*9P$|VB%5fF%)Hx2LBT6g7&JI-IZmyscOS> ziMMj%*)~ViFEUbBp&5d!zDLWnVvW`5s?VYhe4hS+iYC47WgoH#xLIM?kkvc7 z>=Q7FzqB<=VG{~_QnM@JGdc)?Ao0D{DFY$lDGZ-Qbd=+M}oeKxvbq#@4FKyk6K zr}7Uo`?)ke(&i^82dNA!U_dVoKv@RKal6?cJ5m)*%MPIwJ13o$&VFQ5|CfP2WSCC zf@P46%=Yj!@ckpX$y(pnJw;DY?SB%yp|vqMCw@50ZF`832%*pz#3S`3|C&q{y1@HT zgNyMVD>u_iL^sejjJlL|k7+7URkT;JgXRTM02ae2KvQEQp%Xk`3s2ra8Fe0apdTvn z3-Eq_1Qr5jD?Ou$!~TKJSRU@Rp4X=eC+hbN`ZF1>yjhRML*EpiDq(a?VR@71D}%lD z@|&&n+YUkog#zWkP z=!Tvsm3Z~!pF&a$4@+i~W`Ig8xcH#enQ)hRiw`|4FKA;y7YE*7fYE#q?;WRwr55x> z@h52Yrm;{v23`J1qQPK6bkK@#1>w!?W$yJsDW+!Lx8D2;`-CmWsddiqpt~??_JFGv z*`V60xq(((OLu$|#YpxzuC-@UiYvd#-+@hZIyMt zJ)4S%TNGpm^8&G`nZbVHFh1DN&E$oKn0IJ4-Dpf=E3&XU5+ipuLQ-my zEu^AWBrwP1HroG9*bro4)^4(QXwsLupe!2FoS_Gb&aGvL(#j6)idS5z=u#5$o?;i- z7IaUW09T;G?$tHNmxz)RECwlm%A&vM&@K&qXe; zbXHq**>SZCt_S4Pqv<54d~4lOOB%G%KPdJg9n`11XZQ)B88)^vC#z$K3`zGP#V;uN zoY7{_ytvJdAHRrO=j1gkFM^ly(~*^#Je4*fOsDSUS$Geol?b%MOe&URu%5Z9!%EY8 z>P0s{g>Qj_=d1Q0Q@21jH(u!9pLIREx!!%Pml0=RK%6%Dkj%YV|_bjY9F^MD3``h`&QhppEaP1f55gIzS zGn#;!uIG=6SbF(Kk+<)cbOGP6V8n}(O5nA@OMq{*<9e^D&b1gWRz53a;!~aqog!wQ z3J4uRA4PGpX4pabQEarK6;~NaTiHQr@ut!0`~oQqM_So-Ie^fKzKQI~nXP}0jz?d# zK+hzMd4xXnR+z7B-*2;~F#C&rQ#m-q2kA!|(H|FE`%ye&Uh!B8uPo8(LOtsVjq!3= zks7nVKSgNmXS*TJlS9AMR7;8zx<_}?3YU)lSRhir*^XRas$oNrUly{vAEwJ9m=RUs zC2)X_jynY`=ZJ#8#Pli35nA z+5%JHz{*^noraYLnuPz%7BaW#jiXz#rK~TN?bQ8|7^ayv+N2{;?>_BEfXr&U%@sqT zjQD5IN@!5T=>xPiBY85+62Kr2 z8th!TOvsdFt-z2s@LAL3g4^PCs6;ChWdPGn2_3l4$b89iAu|GwNvBz5OjG|opX|8F z!Kix$I_n|3ige9`%-VaLYatuoDVCP5gj2MLy2jGmmHm&{oS27&p76=k{2&dFHD@Yl4piKth}OGk@_N#xT;t6e2AKgcVRx> zMVL0Cc13iG@N7G%d4m;Aj3c|4mRs8;(R9-3zdtiO$%2#2@PUn}vI@|$2PeI-OHV?< zKAFH^n-!#YHcH7hzs|L|LUN2P`n8UVQ*WYWS00a1AnX3|PYGy7?1d%rDWd_zT zGD!1|LL!(-?F@_Av(RKI+}gKOI0AN|5+Qgj#O@cxxyCwOi!*mX-2?O%Ox&Iqneth= zyJT5UWn!_MxGLdRNi-3aktT`;&k3*s1u{cEf75f&MrP(ZZeh8bZW5R6XGF$W#BQ*% zYBL%A1r=mBjGZ&|9#me;8o(49ld}oUJ6R!Ak z+ELH*5&5beC-YO8^ajNxxW|Iuk=m}0BIzmQhEzvYDg^VE%mscQ3J%VU(Yc$SlBqsh zp<_0SSS;?8Y*HDM+ya9(Px9aEfMyY%N2oe|+jNW7S()3V7&>A{)6lLat;K}H1B8TT z?dpm#rg7bp3wRU%2iVus)tSN4LR!UJ`%fpqy{eaEIWB!f;!q8iJf=t%6gLl=Dn%%k zDLW3iQwT>5@7ILN+Iu&OlY6mNSX+r>WDxMO)#An{H%xh;nd#lnb@{~(vr1-AU8h>U zgdffXgz313ok}lBBAfBGreScV6r!`@k^^Phng$r@;%RfitVB?8D#Qw}wJMbb9u$6J(hWC|=G zIv~bG1!@B|twrvU5Y--Val7zH6-GkeE0{frU0ze^np>CLtCEUqi-_2c`PU5uj>K*| z99X_Jbiis{<&bi^#(B3<6!DQM?g|p1EL+J3w}>Z5JW!#Tg#)@+z23R z=<#7hZutA-(}|Xh@{qOn6giEBD0PC(XY%}cdwt9QWdM4HY}!dW%bFkr zZqrLYESg5&z?a+Uc3seu&8(^tlV~bCPP{Yalrvf~qHps;6KO7UJ>1!NPucY-TYdR; z7AFHP+oCHCt_CBZchg{49ZNySn3h;f+pJbe@Yvo$FmW`Z`-|CJi!(QiC&cAv{YBcV z2d-xWZ+{22Lx|b7X*Axl4bkY%MtfSZJ_WQhZyR96Nv&&K+#)0}?g~@>&&>+v!y-8C zw4KHnp=sCbmA{Ijdw9s2z+zmLOx<4i8Hj3&U{{=&iKjOd2F@74)kd7t!fr7K&@yfu z&d(H=(f0P3EF7OekBN2$VZn8{|BIYWjg%_0qulm5b#5o=jb32MyrCNpNDKlDVwf+k z1eoWr0?=k@mWU#XE9I(`f5!$|h_V656q(B2`6SO5Rv2SlDor=!go_K;i$DBG)mU9j zDVE400g@GD1EkEtDAz1Zi!NBBkqam%fB~Dv6x(f0zRu>wke2SDAD>`S*Q+a0p|XgJil;< zBY@+MH+>#Wen6rx8c%TLMgtEQA1}9uL(e{cH$Sh3uXL;&?vA2W%Ge{ZrmIPOs4Syi z3`G^fevopHm~b+}>~rcw&*2aHtvtO3UOjzo-J|?-2*s=INEU2`M0dH^tBRPuJDi>g*iBCgy~L8Mde#Ti$8s@fr1^_XC9^^D+?oBOc5bCI zV^NfZm37jZ*VwV+QP4?+v@Va0BK`%YK9pj3`dRm-(;c*}O*$R+s8O4%EbwJb_PYt` zNHKd>6{{htYts%hJkHZ%d?kwFOtTJ`P-`EjZSuLAB%ZD znmuyrdut!)X+0kV1(?C*_Fl-o(E*8g@!6*g?s!Y(PV;fP%~Ci;tN4ni`g~2wXoXH^ zQU~iAh;-O1XW916BwX1mcFL$HmcO<-PZoNhiDX86=m6O>Du70Fn>au1hYpTDujR~T~k8S-kx$G-o zmJC%~3n9jZWJ^llDQ8G7T=L`0PBv}x21=1;t zME_7TvA@>VRKR~Pq`_uVQjD=z)R47c0BlZ8#)uw0(>v0UU%4sE|28y&q=wE<2VZ(m7+7eU;Ez=eZ$L*gfScxZ?m)q^DN-cEXnV^Wwa;0>}o8e13hl!5< zs&&;t0k5hUN||dbt!iyGZL^@Yo0J#ffHv9L;W`VAAs2GzD}zT}f%0TD*Go7M5EZmT zV5n>Me0W*r-B7ay8Sy=W{Tz&EbQgg=Oj-HYF8NpI zxtCBR^*le>8uP7FQ{%~Ku5l-N*+OxrPDqE~maUv3XsCvn$D=(d* zWGy~^ilx?hLn&WvfbL2WwW)nmqh?qcfz$7$v5`MZ)r4S8Ngn9|R#^$B?L+G+_i*G> zaOGE7AA4m3blprF{}>FFum4@b8S9*ZUAEptcm27A$D>u2)aYMsocDFV-|6E98n8V9 z|8;=YMF6|n(x-qP^BY}Lz=yFn;G_?-I4ktP6uM0IsN)HJR&!V){gLCkw7B`lXVuOPWMzr-DZkg{nW6c_CdtcRO095nIaEqPOGZ=z-*A_sq4ou#DvGm0G8`ld*1&0i0P@+BQY zj$D<1J0$|s*PhbyoTk!BW9o3VN6bj{f+*+6H3`(m^1{ejx0ykYe2 z61@^3pv|kJ%V#O$t>hzNGGr#sHL)AIfVi-hgEheMo5t`Iq$Fm&M>bGJz>k+oDSgNP zwOC?rN7q3_5AKCgPx?xEeIMOl_7ZDXGt_Lx!!y$jx`Kv4vCc#D8UB-t9qOL?;Vjb5 zy@*f5S~nAY_Txu~x?qWpC(@8G^!&Xr&b-QJuGrBOz9p)QH0?E(%yy_tzSL>5_@c9=hFT|&ks$vz*O;X z$2D?)96bz0j5XA-%Pf(A_4umj9zgs3ZqyV~*^lzqbfU#F$P_#BD8RdvVsz?9E_O*% zRwFsg#&0|rgchIm0TACd=t6)(77`;kaS_RZ+i*s^Hun!h@i(J{xJVl^G+iMx@HX50 zI}lw!JY;60yDus-f*GNzw*l97XSh7=M=%|pe&2LSB6|CqUPI+AOGPb0RuU!*ZiK@+ zZ)-0K?m`a7S5YeNW*i^2L18olP8@m);?_K*8cjp*Vofot{mQbN=pwW>{l@6B#8lfn zQiQLXSs*E{#X=-wgvlzUMNcy(Y?QZZwuWP&htyq~y|bU~h8u7@PhT}B1B&Lwg?qEq z_jg%c!nI`SF@_J>zMpwPa4h{dz`ek0ps1z;)hf+-WE5LE8cW)XQXTGl_l*ZY8zO8F zCz0*r_!KAXtrtwgz$LEBF{oBy#xmmt^vl&YqmJH=o$i#>FtuF8(PJ!=vKujh{i{6s zazU0(LzjVIf|L%}pzi9E$_<89a!Kiti!fcNhgqT+<;2Px?z3aQ|{FPFk4<72B|Ir9yzP7?VuPO(Pp=0e?zPur8X z@VRWCcvo~jwuo0mB=BK%KBnMCl`_^~^-${xII8)?VYK96svzp4#o6h^Y^T+<74_jU4h_t!wVyR}6tJ=(# z!BvU@Udkmh8I_uIHQ3~Yfc0(if{9B#A>}E=D|xcV7pq5Vr>g6(M#?Z(svMa;sj)kD z#KIHqYj5k_j1PB-ddGS89z)EI%x7AhTi8US*KcPDCCM8_T0#}2g(n=1h788~Q{01$ zA0Cb4kMFwi$xXjC$AO*?FTTGX^q537*mOVI-vFhWxs`aJvQLzyx|- z);YB`X4t_JZb^h8zmmFWMqA6opw0Z&vu0gmZBolRElVG}1bN~$t@HYFN7s95`Quaj ziCmbSz0Q=&jPQXzL=*Rn@n7QONs^zIa(G)vYA=1AHNQ+%rqX*%V5J_h2B$3`GEJ`I zgW+8!#co4;vJ{8f9s$0!hGuI9b5`_AVb35%jsI9`?0;+T9b2NC7H4ovq3n z)T9@ur-$MaVpqk^Z1&Y!?$2Lzk9O|c=Z&)~g5xP*M(6v5@8lDGALn+%W%X_5Z0V-% zNoo`zMbD2A%Mgi5ndeTtc*fuTj!{qt0_g07>?HdR60UO^1^A`Lb&*=jhojk0vsi}I zwwQgBzP!%E+~on7P*fz23j$Mh%r8o-*7hc{KuYJ!mLsP${S=!2_^d+jUY_HA7OTbs^=ZDUVYyA`nD^~?%f#K#M>8}g+zgp8hoD+V$p`r4EH==( zbo;2v<&An~6>rFI`%LWsLj!-e8A9^99n?J%w*Rw7jM0}1HW=`IF3maY&NfmWY0uLB za}nE^?cT`I;W#umqJR4^zIfQ5XR;GLn--)2@fuyMCDhV~71#nSBE*$>Cx3}Ahsa|x z!tvwXzD59l)a$=uP48Fv+!aU#T=YZNxrqS);vWFGd=$CHr7K=80U`YymM9_v$Hx)* zd|eg?F+7n}>cXVh{20HiB5@idPS#Q1A(`fztQUkSUAzLSpi`u0?C7D0=YOm1iq_=hXsrI?j!i9IS z>gwJ~caW@123>jU=SF`BSl!&b+Svz~z1c(m`=~|u11EdKv%bpb&tTkh{0eVpsVVvo zeD&eb6tO)=C9SS`$56D&swrqp?B~|E)q}*V@afADMVboz0z^L&>6y{Mxt%63)SKd$V_ zz^tx5PKA*8D42Gi(bCOMe*9yRArqdHkG#IHFu^OQp!!%vT2EvCM+Hk0dVa)-?&^(s zx@X~U^Cb;;W~4$>0wHt^SH%bEJm9hAQ)wIUc>mbj+3SZ6xS|&agdngefX0w#1<#KS zhLfQv<7ICun{E#=vbQC(oJ$&d)mNFaE6L9O)mX{N@M&xlFt`T+|BYvn9%UGn4*QEl zin-G3z=9i=oLt)xcJ~zNkJhL)BXUEm296RX$~bvum6yE=S33+^O0GtpI(a;;8VMK1 zc6n0?JHu<_%WVlFK#U2(Cnxe7^1?!G$HHTvEEz5R8AP5@XR%kO}g z(VfzSCQ6Zw&`98KYAE1@8uHckk+S)HF`@F1oOAt`IvZ)-7B-+D7b)d-C3GmYJ+zW|I;rp`{9Upt4 zsFgTKa#vb~2lf09IQB=ZFJtdM!Cq(8bj-dgxFD+r0Nr0S-#2b(+||~VK|NSm1&TI_?`3r%oTKy*@w2Kf(@wp$AJcnpI%r2+_v`_n*J+Mt z><#d8ec8)9c{&5&Gwr>b{!V)Y^pehcs8HQ-$Z_IJ)3W5sF*YOX?#?`#7op*MNekTq zi$gqWtm0fAFW&1nY$T*T&`rUSW%Vl$`8!ce*LSTv20@d7{y6|C@`z^sGu<@OLHf%m z@TOS>1_Y5?G1M0>6J0PXx6~aSG&d7wb=^i{r6T5z29PbHyFXI|J7llbRH!^% z^=Ht!21P@EP2XAe3|)>`A}{&}obm_NF58g&GnnbSq-idt^HL5WCdDvt=ly2A#R%^R zKi*GLfWcBz7?q<%jaZHguEb(S^xrc2Z#PF2ZB0MUm>LZKTD!#GkF~u1Q#I;KdGPC= z5ilc12H5zS-NXVusy_9y9eW+W%XKU7_7;Tbofhuwla=TbpwV~h%`nb5W+3KXX-|Oh zL-y48AT2K;(_HZSRhnm*y&PDpX0XkeEUk7AH6XNx9K!JvZ=i?)3kX|h{IDZaRfL%_ z{1TUpG;ZvNPH()-96WA7*a`xOr^<1o4h!iKX)mg`j9sHndl68gbGfur;R#8yhsgS@ zJ}~QeuPsHVAb7G(@>O{-OIQ%dfW&*6xz?9xfQz)chQMpS>2WEFS00N{eYBL88gi9X zARtf-t~9UF=eQJc$UM7PQjM~zT9qu1I#e8-H)EMnB7s^p*kTj8+Os3vS|>~s(>6?nxe;Cv zT6YO?Mje?iGD(_+q&lA3|$RC-?446M1YUlbw)-87e+au(G-gnw0 zI2IpArOBj2Ex4tFuC$L-8t*u$Ka zr@~*9j{8kZ?l7=4C4^8w4q6J$4NToMgCsyt6>bTE0qCjz|C(VcoM9`Sqbi(XDxD>v zz8quCJUFpmkM$r>s_)4hPYKR#;dXBVPCxT?8MJ+wHe1EMvMlb|%08z}?pu+b&&i@| zC|$|W8%LNFu5I=rLVA;hP+9u)JCC@WYF5UJwTrsz4x}Ig+=y%Z@4JK{XycEdoehbG z$h{Apl=jMCqP>u?%;xU-gezyuRes@R$U4HV9>re~|36~NH)2+@Ao(4Li>KeX=3 z<|qes_^Qo0`d{GR@^Jp`=x_cqC;k#{!XO2O&7UD+G#ME=3w<5ZDM$ov9NEkG;$ql* z{H0=&Oe;EQ=YZ&(-n-TCwCkNh2_eJEyvphGTvKDYG#}qR!}T@SF{WRY*Qt32E7I?t zt(x&$pCX!N&;D$pr%0PC09LDnDk;poIduk2$Y8&zq3oAS?Q32tdIwdAyJ@IMS!w_j zuu_u>(O8RWEHN7MCyCG)XoK@|LRp%T@DXVgl*u(UTaTbL18XlYcw;p;+FEPtrde%A zU$u7A`tP3WruFOLuv8;fQ;>0QayAYE7(#J`ve)>YD_@FiF8voWC$WO~tj_fnv6*e_ zslT0XbX+ernIE!mTifYdxmQVK#}M<5bXyn5)3)+EztVPHuAtR|>0#x9Mn8Q*_c?lz z%&|lrcs5gshX|=$NFbv+v(lmcNIoN<~7%VPV_<8gOycYIMJ>I@SVhf}pSgn2o5 z+1Y-Y;?+BDv9=z!uvPGxP8~@!E}*65D&PCcVi@ zjM>r)BFhZTVr&&7JvFhw(Zfo!SymnhO^nJKjU_FnCzegp0_7Okl5moVJEo0OH$!ph zXgzo08L6_jXN#jP&^2omlwDjiy2Wp9*}FnEP9!{Etu32#-$RL2g3JO=qu1PbM7~kp zH}QXFzCS4aYZa*V#l?F>(SmJ}ETgMo8eWM>H>=Ejfk~ zuz;~J_y;RdCCIH7e4pI*9Kh&KJ8W=G%Rn_Puw$$)jyILCUtiPxtig z?C7lkL4Mble&5c|d}VQPGCO*@2^|mv8el3gBxupxBeiI>2bS%W3Kd*kBNvzU3sdm2 z#s0jAK0Jpy)u{#TiTXha)yx&6YY`YolhJ1?#PF>_7UOM_3g3x01N?rYeuQ^PB|)#7 z_=mk^Z#@E_A5qC)`)H9j536hL%hR>#H@$};Qwns|8 zB(JEuguB}B4SwB1dGb@+pNL9=CiPw!-t3W}i)@#3UmL(eQxjJ}m45cY);&2;cY`p= zfGUR>n&oNu*U7T&8C|`Q(zmI;j1kH10gXY?Z#h?&ovDPHxE?lyGSOKrMHeX6AIrUC zw9|SU_nu&|1rxDW>!2It@-9KBJ@!DLF+q)s?Xw$?DK!nAVT+tg@N{w=N- zO#%AAB;eG8EB&SbRR$|@ziX}dO}$ou!)A|peqsy`w8QAe32z6%FdaZLF5Yr4PXGq- zHV4YUa@-bx`fIKSk7KkX=Szo{*q4gtn6r`aB1!Hi{IKNSyUf{@H>LG#k^*O02H3Ok zcnXS_DW6h)8{?#X#8N$4Q?epgr-JDCgKlQ7fs=G>(!`7lxqu=NA z83BY1-kG$^W^d+~2Y8#Bpcgok_oD$m3(};AUCn{vAu>NdXt+qzXOkF^+kSu%5N3%7 zitOi*BZ@gaH9ll}^Rk%|YL@Mrbba(t(ZGf<8=rcW*G&>G4fd=>_u{Z*kLq7KB;b?W zd+YVzYOIBBNIEQ;FTRgCF*tGywPGg*1dJ3uxgHk#@{P(3_ZiK+1;?r1%(nmd(v|9H zOqvfbSl2=ycFV!a2BYlI5QeuT_ru(X1kK@0KMaUy+gh7omOp7)b(5{N0*!wU`5@B~ zx$|NS%8TxZ(7K(D6HlH_-#5%t)OMSkr^9AZkJHbCc7~Y!~oMKsG)tb zt6gBz6WJ;K#;HIp{BFFXxAVmd?%pwVM07RalJ(v1lR$=A$=i{RqC~MM*%w zqrft#FbwBmw^i<2AwHuLtixZm40RJHQVWM=XK`2u{q>K{DiR0I_VY}c=Cj+BN2zv) z>I@eMs5+HdjYX>+^%hUlm+jL00e6*n<@L4byyR9IIM4|8}9Ik>HgbBIT zx-<#_ztwjz2CeR;RHJVny){sUTje7&JE3K+=-Ghz9!K&kWB|Gch|)DAX$5JTxv)Me z)m{hkoAcU4UF*!?k()cQy88&X&u}u!&Y)nak1xhmHecZ}!Bo;G2ibIbeBvc zL)a>z@H(ld*mL;jiYLiHrrMP&*ystm#Z?uzmf|wAVAI0R;PkDfu~>uR*j|7{RZ#|_ zv_mZ|ILLB0nY>UM>l@TV^TYR%YkHy4eH~e~b8tAO<@iJ95e&u9 zT@B;SY+)Ik@^3CBz#w83qqguFs#ab9v)G&+H4+y_aQRZ|hH7w2{-#KUNn}3RreXy~ z`}d6Uzhvd#vZl{is^$eD*oaEaI+5WPjLKJ#!kTmPnblZPYx^pkXd=s=yeq4X;@YPa z!1o^K1Y@XLeSG!?(KXL3j57I@#0c_%b=UYH-h87s^ zWd@o9tiFzgB%MN1UR7oB9^}i6!g5N>Fb&GA&64HMp!pK|;BEN@gJ5{O!=S`oU`CxjaiRaJ!+dAC}vq?ALc@rSC ziW#9`C`uqI@udoHmuC6r;6ZD5HsWjSwunU}x7s!>QS{8ATts(y+tlgCjj#sTk%m#EZm5QVM@feqC9MK0ToN+C@nqZx zgbGcnv=T?dZzmeqtDtq0i-5{@Rh1p*FUpHxp%N`zRCk&|#Zoh}Y`iA7>7KW-?l3%S z7rDL?7#s0TrlB?1wYPCtcIT$;FELwDWzQea)AE+npowqhp-Nj-rmTXmR$dP}MA>rW zC~@5b5NLrBjMX8GEn1{wa&oq2*eVd$LwpGBr6f=e`BQos78c59gUXS8+8K3T<7O2 zdaF$70y2|>5y@Dd0=gLuoWgfIcxaE~S?~de);j>-&p<@pC!?5`?CooHv~8}Eava;0 zL?%_Kv7b@?J}g%qLGU=4nWyOYnbj5$S9Ah70|ZG|7Ez&BTasjlrE7q-WsR)=j=TV~ z`j#)~@xQh{TC7;3-XI>pM#80Fj$bI0Wjs?lo<13G;Jyx4d?AFI;#ed?lhfQ~RD4iS zY#^K-Q{GH&3Yg-P`oPG#9(gg=>$u>e;f!gS9m?ZFc{@Yymo=MS-9X}^RN4ARJWXM# z%;kuDze64Fxk7j(kv#8a@Tj|;&t2-)0H2%trXZ-H z7~Hb67Wsrb2YlGIvgp}THfqwaec$e{g_6u|Su37Zsc|(2r<_+6J{#$f%X8O?VUT^H z94{u*b8^fl<`>$0FKv%kFBQ>Q4Q`k+k{QIrof@7!n!WjGS@R`LFQY|^CEmguMnWZ4 zBr-+^rOtuXA)5#ojAcy(`1oGsbUF0G3sb$&X{9Ot+G$rhP1I^&Y8f0@)!fe+d=8Ij z0~MF=jjirhiK8Dvmf?7Opm98U(SK-+PiCQInhXzpxf>@voKObLr4g&wyI}|UsD_@u z`4qlSe~+N5(D^za=BH$=lUMtp)Y_61f=-UAIV!#aQMgv5w>v6*0!^!y5L6>DsrNWa zYeeb%HD-tv^qbPv4GAcnmV}qy)cRx9wKIi#EIX+S6EwX+qG6HvCA<13D#fxi%Kwc! zWf_Q`MH+R%Q3WmtweaOyBtNw?KeZwOtA8&OwRMHsg4PTzn>91Qb;B2vspGJIAwlM= zukf|`Rv&8j0sa1BZu|V-=xUG)cJYuz^0~(Kq_1d8pYp4UrPb)d3g$W8NJxxIhe=NR z_`iyF8_d*)YJAuy%Hd;Za%%{`ueYVm9Ml^0;=bk}-mi@bcL+E*n0Rv7^#hbO?x2U` z$#lxgXc5uNN$EMF$cHh~n>8=S?1=mC^Wq=B z>Dshws=@cA3hPB>+LhEmgNi2kZpOGamew?G41*MDGKmT6y9g*>d?}~i+B3)qsTZS) zDr@5?RaHk>a-)28-L-mi)|uVYM3iRxFR2yY?jFKz+8uMS{G&NaSf7#YvRmJh$4>^- z!S;0Bqd%34ZATL_?8~^Gx&%s8C~zUAnG;vB-d!fd?o5}6s1xmXgkG3-vV%3hdxwcT z+s%}kr?un5_5o9)UTAz8HS9I}P?f3j(2G&?^^VXKIBUNWtv#Wahi4{)5hIl-I5uIi z5Yca1ioh!AZWU{K2AWa;RheWuV~@uVRQ~cItC^EEG(Ni!d=`k6oa;8IEjh3tIn`%X z9(G=o>M`8*LLz%)lkOZe)Q3jjP$6(dL}2ADsZxZjyEfF$8eRj>nBx>{?U&?ip{qU zs~-Mk5CX5BzlEkgzHStg7+awz=r^)#P_$QXgT4I$DP$l7e#%Ec!YSb1xH7}UQ}(D= z>@?+xPx(0AOVJ&(*PqA;!|eFylM2M0Uu2h>F=%U;U=rRGlQJeWtx?%SmZC$|YA!qm zh`4_EyUw4hAe#hZ;I6RCPEDfAXNlIFEVTXu;)a4|bHG;5fab3$vpGh&IYG7cE1riI ze|tB@xQ3<)bDReK5F6I%IZF*{s0>VbUoKMOT`<*U;%}mZdPa)*=rKIj`pCi+m6?BP zul7AA+o`k^ZqOIM#*~JSuZ0-XI7AkglAXmrrju_(v65u)Q^rqA%%WZX=rId8cl>(9 zOc<@u71e8ZWcEcAEmiF*|`&NBl4Z$5C%h?l{m4avv|fb_Aj3S2X5}#}`{| zzw5H%4UdGy+TmCEE#U|OZbIqDK0R0+0UScHA&}8MSX$@8%xrWUlGsZ2G`jD6u0Vci zeA!;k#SWfTyrO-Tex17{Zmp`Hns^+P z5hCDdf<1lCLwazd^QN$$F8|iBV%ul5t5O20xoKl0YlFLS?3%Jrpgxk&xbL##ng)3Y z8Vf#q_wi~=fQ5C0)sUS^ZD?040OUK7fmHPCs72R??lgBuhP;6S{2zgN|Wlnn~#RIL)AcGcL&1$)v;Ub}H2v=`3fBXghwZ4Afe#mf{_u$zI; z23M)BPSd6%>2fZ57+6JxnG~1~Gd|7_-I|q#4{pB(^b4DP?U7+eiEUbh=?Ho%Fxlj? zq6ADI{Fknh$Q3*6ATlROu4;$9c|}Ias16{3z#957)#TWSy~*W<)f+G8XVZJ6 z7weLsW9*B>oVdkHStaJnPvL=D{fPT_kg8vTY!AC_TJ=u%dl{9_d9rf{;`m&~Q85!Y zYxujK{XkOoPwRECzXwGhjLhqvkGXHkakt8vqXKAS3_<0==Uf@jL&>>cQo!Ntx;<^A&o0X+$}))n2Pf zfo5<*R}J?lH`zNPq@9P!3)k3q+=fQeSl@#8$;>7@E@AoaaNW&W9P*0)$vGWmCp85JIDb6;(xO zobsgDzpIxaY#ALq0}g5wUW9xEKhN5Eswi=J+vU13jX&xoY$c5DMu%hz1!Ql7C#G5s z13;~FEzZRw(H4*-)=i=gk06#wom->SPy2CCS%et)Z07p3%=IZ3pXzw)m3dqN$o*S7`n7)@em3)J0*KZjGevm>6XCmD-p1|Y^mJ0qVYVoAM}IC(fzwtDT-?VsTS4lqjWWunOu^`2r)Fm4 zByZAy8McsAnQ$nP3ryaFRHKd4Q*K*!!z`B_*pbJ_#Bt@@b3LuP7iaTShS5P$|3!f` z38b!Et0-ODVO^pF0L!^IL5O@U;8_j0`?bL9EA9&1eR{GipZ|C{w`I-z++Hew0gM6H zSC=K674ECjY%I--b2|4@_5?s z)OMUN1)kL<;wp^eCwGG;1q`xb6zr+A#khZgi98CsURsX?h$H2oLpd;U?CTX%o#t}u zENs4lG!$xw;2AP~Qfdgb*f*p6#jAn`5=Vqg@W9a z{FJRBEuU_K_-%pI;y|NySJTS-bi=01xLtIgc|M3#HSNF{u<713HCkTicuRP;?q$)r z&mW}JxcAd(wC`a?elKs2QUQk9j>|XM$Cj7R)f^=_Wzdt~a`EppY!_K^M z3^9h!P|CJnk`-9t7R0FhID79f!rNB9JlOT5Q?gBBPS0@js_9u4(LJ$iP_h_kvyb8~ z%5%$SP&X=G2CZ}!SrJ=!l=Yj!i3q?&M$j}X2B9^HP+2(RD4ugN;d5(1ts$JhOCE*JB$9);vzZ5EbFy>#4WB-eRnQ5Eq;Pv(%pS^Lq)-$eo1nH`3;VHm zJM+WCy(2PxluM~odRZ)%PZ{`!?ZP8#FPFe5qVo|&Z}-FN?P!Y=c<;E>Sf0`x zxQOL4_ydG5dh|==hN^liYzs-YXl*(%{b*b3z8*#~xC9M^4?O%v=)V4cmqw0})v(E# zZ&IR6FWY*-ikg5<6WCxGrKa3*3`i*9q;McUV^IatPBNK5DnGq|!@3T^?R5Xh#^rXi z^Wov}csOpf@f$_dEIPUV-G0~9sxk#$(o8yizzFv!+XFUah)JolU$^Vc=2md(xeIm7 zT-F!Nu!dx)2$)#Flg<1a$air#9>A>Ws z@^s(&P?b?NZDGvr5_Hi;{-C)@f)FQ?SYa|`@e+5q*qDSq`|)Ka=I7@SX>sAUPW(I* zwusF-47p-Nd9X-87AqIn6T_0wsaUiZsYQ#8Ns5M{Ux&= zZI&g{4?*12jlAEd21)FxMmnRinPZ((4F>|~&+tH;bHG9$Zdp9)-5+?QPTe zcm}jKTiG@Z^g+ji`TLeJJ7T3Gza|nh_?qg>H@#ro?j3ep7FUlxqcWHoX!DQO^_`D zRF+GY2l9E_Wu{LK1Qh0Y{-n^ z?-t~n#3&W)Cf%*Pzn|5PxvrmKM*X-Q^`|sui*hr7{!ZCY02e#^zyAQJ_5mESQ+t>C zyM3nI9DF+-uAgwtYu-}N85Dt#scUFHsy9M044Tgu&6)1C=d~5o#qdp0j>5oZ+*Ql+ zUk=clfL$eXSe4QL=r5dA7lT_$A5I(@EzL{yRMm;OGd=|H+#ReHv+sLZ$Dxx5Pe$00hjAEUt7J>_W-^>c)f1FR>OW+F!^-<EG-& zigrN2KR+SlYELyC_M&&)6*A;~EXw(PzqoR?Ki~@waD4*caz8F9>+ZC#VmtjUs&YBC zs>9k;=h&yLUe+UEE*0kLj%eVn`y~zowmLft0Ds?enLguM1zsWUjC(j3)r$e^+mi=? zUrRrLui3kLBcfdhSbiVHlN~cNZbb8{W3t}+y{8zy?7%!P8HaDNoi(8=*VoX%>(Khq zPk)WL}ZSOH70Fg&UN#lxwUj0+V&qz5GT>sO7S! zHs~Xt4Dy2^y0K-qYZ2rw`#x9}8@MI?%R^~>Ft|U;L|#za5c|FoMFCuG3CBSmco(7Pa z)%l%qBIpficN?}$OR;ZZyI#upY*B5|uBd}6OoILs1KrX&KTfk|QVsZ?r3^b4`xmG> z2hgp}S_VA+a{Uh&D)&2A$rq!&6K(_H$m674fGCj+%-1{Q4&yw$$AufkQ1%5c3N!#` z=Qy9?F%dhC3DKcIMLI|c>8&w@^WamY4-(H;dX8kOvppQdqxHfAZHYz zBRDQFH%Ez`EAwY}8~&2V(AY&FGmzp#$s5v-JjLFCK-4+8`U)k4*AGpKKv$SqxkXx* zcE)+HZ$r-eB#-j=YY~4@IFo8WqRU&Hdk?|2O9z}i3@s|`FHlNd(>kseiXLb%!~F~N zPCVYvL3zFe+!mo{m8BH8uPIQ9&wY}unrj&QkW@Dkh`pIs z@Cwd-5!8~?NgY2)i{dG4^0#a{-ym@({Go;{&srItsdgXyL+8hcNMQhns9)Rw=J3i? zY>Pd;{5bGA)?DZrmBh){l?^XZ{K(i60zCIQnf(#sC>t}JF_c(FSZQ8Uncy{u0K=nj zO;f!Ij!K*iID#)Y!Uwq0=mq>ex;d0X?Z3a>KHVqVrz@ZZVHk6Q9jx4Pzka#rnX>8$J85^v*W82R0dR$6 zrQfP>U77Y9ERsjU}nH;t-0XFKv zVkqdmMZSL<1NyN>Ft9IgAy@WPHq!UJVe{I z)^TyPs-n&Y6b)$M0~-@y_P;}^0+jGvq)Rly$FC85*eE8EIr;TbpYT}0Z)MUY$H(jU zjSP^lh8WfZR*K4lemAC+tT8l68Mg|HGhYrOI4VzT^q(h`x0qYz{V{R&xd#4h|6=tT zLB$sb1u_8(8hPWE?3sc;1D@gkE-?~I*yJs>OO!y71-&+JN>6ZM9x)fwE*(Y18X3M7#6T)qTd%Ef0OJNw%G+gFp9Dd>o+p& zV|#Mn1733WdoOSO>aW%ve+T<^;oLgVw9ZS&V85~a8b5?$)+1o{DvsOD9lI-007wLZ zz#+(6utS=9t1<)bVcG=Pb=vayBDONb{*pJC$X1)*cAcU$^1e))fq%XPjVI@d-jTNh zgh2Z)zw}P&z86p5>|vXkeV3j-$i1rv$L3YDv41`6-rOv)06-u4AihT_Mh$rrt?U}H z^Hg3DN`24(UT&uVvn2q#t?bL;zslIaqEp_js~FeL-7A+7uk4*7w)dKs?by{#{8%wB z$lWJASyzOPL4%i0T{}1K9BEG57sBM+%SX|}@o)3C(~j&rx9^k_*iIo??+OGfXd;%9FvWga6CvtUJc|t_gP>f$29e{3S$H$^tL8Zv+pKF* zX2(siyzFjnUv74vy8|4cw*{FRie6gILk*iUm%%gD>gS<2-ExRAj_&ezFQD{wa~*k_ zPq!QL8`OVfWwUwV{3Fe{UbBAPa!;8|-toihYAG5+c&kE=GR0iD(x0u+EagpmWyt%b zp|>>7;ugXYr3U40xSDGNC$GiPE2&o-#d#YB7uWyZNFIBQ<@`JWae&cGsqD=J7@ z%({)dxO48f7cW|5004thAM0a)4|l#cS8saT88CkTTd^O{k`WJuB1+*3VN>KDSaO?~ zGwc1ULTvim9An`ov_Py7TE01vpUy6{K)OgfQpF69Igs>tYjn7}qpyjUM(es`N{OUt z;rH^TA=5FMuFT`VWkGAK@MQ>%@3N8DAg0nW+Awk`FO@=|_tIHimajc;_d`BDpRY)^ za&l6ageu10%SxE2uWI;Nuz1*$N^RT&*4P4cydzy&K~Q>U)6~(wU9j|}m^*MFhczL3 zp;(rX%i}*5qU;_C;GaBvcq|xB9{+@wiMJ;9N38D9f;%!URHMLcH@`&f=^b*W=9pJT z*OVWKjiZSs7SJ1tV>=FvPLiy*M5>nR%UX7ePF(h8;~mIy?{_A0XAjMy){ zUa~bJ6WZ^DwvtKWc3>Ekn^9}dk^mpcXQV|qsE>1?9GpuCE7prqwigY^M7jwq1WpcV zdX`c!;g%K^X)H)k@)$JrNPkv3yq`RKzG4E)NNHWK4$iJM=G{0WvqJqM&Jx=cx2QE` zG;I1;st)bOMf+_-2ViA$rPKZe+UCp4l?(S)k0E2%aEa9+EZ%|K<}>rLZ@}$|+QE!= zmWCC}UP!-CoWD_V+ZwEcxC>gwx)=q-wEkk&my^yrQ;EqG%BEfVqXtPfh}j}{BfY6( z!K{@nqIi79WtJcf5yUcVB;&&{|Mc((jJnEp8@S+!Y+1vOa6QL?Q_*|}329Y_ZP9b> z_>EqN1xbq#q+x;u9BuPNfQ_RSx5Fo3X|137!=u3b*((;7O?&}pPdhbb9}Qk8zpa3F zH<#rrKdM@^Mt~Cerp%=^b{^6TRAP0KHKPapMH1pez|Yb{#Npj8wA%0wj*;|o!|&Df{v@dA>MqY z5I#vL1PLBCjK7WPsE>F*YbB%o&X%7Hh1&_930|Rw@hN5$LL|QM8PV7o*1kJ_uK} z;)V`i15J#So@CdfB8Kj_n>#`9<9({lY#n@C>Q_&P$%+Gq7&=aS0y2R8O+VhqY zN;+7y8q_fua+%43p=oA_;#ojK1NagYGK$E{l1G%&t)g?_sgJxo*b0uc8TRDmvI~Yq z8NiZv!L;AAisZb^@}L7_rr&ys)g_Q(>M$pRUVU<8T{sYE!i2OQFr>lli=M_Pla z5^c1cVf?*RAP?t(WmsyPLt*nYUic8=3Sao*Xuco1xxxSZV$9&+<$7ORrF&$fDV~Vne*Oo29^Lp1O-$wA~jr!N_gr8OE zo9qj4C*o!N=Z!W0cdM37B|z)V?%2;(O|5};_ZsP0L*(0y%>cmmz!&h@de^J^t@Wm- z{yqBEZ=iE(pC;7YMh&gX3E;o)ZH4}jtHo~q8O!dtHw92U2H@IFop4LfQ#}ta#UZOQ z)BiZ)E0XqygGc{f%0)nLY;Sd($pyLZby_;lc#X?W9ro)?Bkww$MW!Iw%82|zla1K( z2QzSPse8vbdjOHji3n60JGhk(Mho#XMnG z2Gy`7F=L>?OnjL_&neO}fkFR13ELuRu%1@|_uLG;LIOk(7#9irwiSqp#Ez}3&*@pO zHe;RK*xTwrT>m>wfv4#rCdC_lJbe>Uw0M+0i)-(-YFS zz_QRjIe8M~Z!p?NQvHYoNhfw!@;M7*Av^khqSF~SSV8BAz)bkSr;%AT#}O`{M`^M? z++{~=g7Py*x)skoz>!zjyI|jp7uRn=)Q~8oR!HAC&)G0-ji z_-?RKal~o(ZMeK5b-BA%@H@bM2Q7bi6>uMVXK-ov?{n8G;|@@LSZHJg*j{oAqvJ&!MFo<3Y!h7Cl5q^0#nL(^eE7 zRak_Aqgt|SK!!L)tWuN&c}QMo3d)8-sI@25xV$+?{Wr?un9rPjczA$r<_2}i1!D%) zU8pG;SOSrx46C8mh(y&m#~If2wz_LeRGkwi^~8Kb50{rQSjO01@Thr^^%e!G+ydcd z{vR>no^?;<8S7;|orxkD`%09<$jZ)bogAX|KiQXW>dTa2DjSnhdrAw#AV~@#5f;D7 zKCRKEwvV{=?kbRJY#6i$5z*+eJ1XO#swJJ|2U=@eT8NDb840X{@8wayd9!uE(Ic?v zbM0s!Cy=o3he@GhFouG;sR`i)^9b0^j0rI*d1@|>irF`ySSMOfPD}ek5HNF&MgLg= z7{>aGRHW^*mg-z5W!;$YkZS;EZ~;Bl)ib=$^>IEepKtg;KmY(JkijED6wnOF{}#R4 z{~F|ftp$wCO^mFZTx^`^JPd5C|Nl{eX81`gEG$6($$!%Sm@}|2GW`$w&n&Er%s>PT z|7(}}Kkv=O=|}zgXG(77CMMSZ^CtgS>Hk;#|Gl>VzPSIFuKrJ|`tSPBCbQitpbT)L z^SnyN0rn&sezIa>vtSLz3iI}gj67tdaQ07U+qSKfADh%W^s5)AzQV)Ay1YF%t13W0 zwEkC1noh-R3pW)6Uz;ux z*)!_w*2M{UeFx0;ce2|oM>tq9Wa%RDgC6>os^z4UEX&R%tPT^A8TFhMv6TsJ=J3d_ z5C~Y|x?`~9qxm17o!`&;hW@a2Dpwv0r3wH3$#9s{g5C_AP%sIf2+G4KNfhXpNichp z!t*o5@#xbkQ+du@6F{us44lNo7t9-9cE<3_3TXQRWpF7<76AXB^iBS2F8^hL|FXb; KS>S(%1^yc;kj9Jv literal 0 HcmV?d00001 From 4b0644b50d32ba5cb45c085e566f8674ea702b95 Mon Sep 17 00:00:00 2001 From: Stuart Olivera Date: Tue, 28 May 2019 23:00:23 -0400 Subject: [PATCH 2/2] Hound fixes --- .rubocop-shared.yml | 4 ++++ app/views/manage/application/_model_history.html.haml | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.rubocop-shared.yml b/.rubocop-shared.yml index ebda19232..992bd02aa 100644 --- a/.rubocop-shared.yml +++ b/.rubocop-shared.yml @@ -51,6 +51,10 @@ Style/Documentation: Style/GuardClause: Enabled: false +Style/HashSyntax: + Exclude: + - db/migrate/* + Style/PercentLiteralDelimiters: Enabled: false diff --git a/app/views/manage/application/_model_history.html.haml b/app/views/manage/application/_model_history.html.haml index 55f42a63d..2377bc78b 100644 --- a/app/views/manage/application/_model_history.html.haml +++ b/app/views/manage/application/_model_history.html.haml @@ -1,7 +1,8 @@ -- ignore_fields = ['acc_status_author_id', 'acc_status_date'] +:ruby + ignore_fields = ['acc_status_author_id', 'acc_status_date'] + audits ||= model.audits if defined?(model) + audits = audits.sort_by(&:created_at).reverse -- audits ||= model.audits if defined?(model) -- audits = audits.sort_by(&:created_at).reverse - audits.each_with_index do |audit, index| .d-xl-flex.justify-content-between %div