home_care_cost_model 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/home-care-cost-model +39 -0
- data/lib/home_care_cost_model.rb +250 -0
- metadata +48 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 716517c40320a0ed76c334a26fef5cf72a9534972887e730631d2e2f88a1e474
|
|
4
|
+
data.tar.gz: dd9841247a970e010e71978237b2706620e8190fca2f7348f5275b2669aed48d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ceb31de0cef84981656e648a6320720a499acf7b773e2c574b7ecfd9e1c74480719711b1091af5a6e9774470fe0dcc722e6b444f2117ae78bd5e2714757af340
|
|
7
|
+
data.tar.gz: bf88e68c8a03e2c28b59cf70f69c4c73ec14b6a32fb3cd5d51bf16fb1724c0a3fbb9e9bc7ecc59938a476037f939797600ec85662282f31f33334589604537a1
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
|
3
|
+
require "home_care_cost_model"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
result = HomeCareCostModel.calculate(
|
|
7
|
+
adl_katz_score: 2,
|
|
8
|
+
iadl_lawton_score: 1,
|
|
9
|
+
province: "BC",
|
|
10
|
+
household_composition: "with_spouse",
|
|
11
|
+
cognitive_status: "moderate",
|
|
12
|
+
mobility_status: "walker",
|
|
13
|
+
primary_diagnosis_category: "dementia",
|
|
14
|
+
informal_caregiver_hours_per_week: 20.0,
|
|
15
|
+
net_family_income_cad: 72000.0,
|
|
16
|
+
has_dtc: true,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if ARGV.include?("--json")
|
|
20
|
+
puts JSON.pretty_generate(result)
|
|
21
|
+
else
|
|
22
|
+
puts "Home Care Cost Model — Ruby Engine v#{HomeCareCostModel::VERSION}"
|
|
23
|
+
puts "======================================================"
|
|
24
|
+
puts "Jurisdiction: #{result[:province]} Tax year: #{result[:tax_year]}"
|
|
25
|
+
puts "Recommended PSW hours/week: #{result[:recommended_psw_hours_per_week]}"
|
|
26
|
+
puts "Recommended housekeeping h/w: #{result[:recommended_housekeeping_hours_per_week]}"
|
|
27
|
+
puts "Recommended nursing h/w: #{result[:recommended_nursing_hours_per_week]}"
|
|
28
|
+
puts "Service mix: #{result[:recommended_service_mix]}"
|
|
29
|
+
puts "Private pay monthly CAD: $#{'%.2f' % result[:private_pay_monthly_cad]}"
|
|
30
|
+
puts "Subsidy value monthly CAD: $#{'%.2f' % result[:subsidy_value_monthly_cad]}"
|
|
31
|
+
puts "OoP before credits monthly CAD: $#{'%.2f' % result[:out_of_pocket_before_credits_monthly_cad]}"
|
|
32
|
+
puts "Tax credits annual CAD: $#{'%.2f' % result[:total_credits_value_cad]}"
|
|
33
|
+
puts "OoP after credits monthly CAD: $#{'%.2f' % result[:out_of_pocket_after_credits_monthly_cad]}"
|
|
34
|
+
puts "OoP after credits annual CAD: $#{'%.2f' % result[:out_of_pocket_after_credits_annual_cad]}"
|
|
35
|
+
puts "All-PSW comparison monthly CAD: $#{'%.2f' % result[:all_psw_cost_comparison_monthly_cad]}"
|
|
36
|
+
puts "Hybrid savings monthly CAD: $#{'%.2f' % result[:hybrid_savings_vs_all_psw_monthly_cad]}"
|
|
37
|
+
puts
|
|
38
|
+
puts "Disclaimer: #{result[:disclaimer]}"
|
|
39
|
+
end
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Home Care Cost Model — Ruby reference port
|
|
2
|
+
#
|
|
3
|
+
# Reference cost model for Canadian home care service-mix decisions.
|
|
4
|
+
# Port of the Python reference implementation.
|
|
5
|
+
#
|
|
6
|
+
# Working paper: https://www.binx.ca/guides/home-care-cost-model-guide.pdf
|
|
7
|
+
# This reference model is not clinical or financial advice.
|
|
8
|
+
|
|
9
|
+
require "csv"
|
|
10
|
+
require "json"
|
|
11
|
+
|
|
12
|
+
module HomeCareCostModel
|
|
13
|
+
VERSION = "0.1.0"
|
|
14
|
+
WEEKS_PER_MONTH = 4.345
|
|
15
|
+
DISCLAIMER = "Reference model only. Not clinical or financial advice; consult a regulated health professional or registered tax practitioner for individual decisions."
|
|
16
|
+
|
|
17
|
+
METC_FEDERAL_RATE = 0.15
|
|
18
|
+
METC_FLOOR_FRAC = 0.03
|
|
19
|
+
METC_ABS_FLOOR = 2759.0
|
|
20
|
+
DTC_BASE = 9872.0
|
|
21
|
+
CCC_CAREGIVER_BASE = 8375.0
|
|
22
|
+
CCC_PHASE_START = 19666.0
|
|
23
|
+
CCC_PHASE_END = 28041.0
|
|
24
|
+
VIP_HOUSEKEEPING = 3072.0
|
|
25
|
+
VIP_PERSONAL_CARE = 9324.0
|
|
26
|
+
|
|
27
|
+
PROVINCIAL_FACTORS = {
|
|
28
|
+
"ON" => { metc_rate: 0.0505, metc_floor: 2923, dtc_base: 10250, ccc_base: 5933 },
|
|
29
|
+
"QC" => { metc_rate: 0.1400, metc_floor: 2759, dtc_base: 3494, ccc_base: 1311 },
|
|
30
|
+
"BC" => { metc_rate: 0.0506, metc_floor: 2605, dtc_base: 9428, ccc_base: 5014 },
|
|
31
|
+
"AB" => { metc_rate: 0.1000, metc_floor: 2824, dtc_base: 16066, ccc_base: 12307 },
|
|
32
|
+
"SK" => { metc_rate: 0.1050, metc_floor: 2837, dtc_base: 10405, ccc_base: 10405 },
|
|
33
|
+
"MB" => { metc_rate: 0.1080, metc_floor: 1728, dtc_base: 6180, ccc_base: 3605 },
|
|
34
|
+
"NS" => { metc_rate: 0.0879, metc_floor: 1637, dtc_base: 7341, ccc_base: 4898 },
|
|
35
|
+
"NB" => { metc_rate: 0.0940, metc_floor: 2344, dtc_base: 8552, ccc_base: 5197 },
|
|
36
|
+
"NL" => { metc_rate: 0.0870, metc_floor: 2116, dtc_base: 7064, ccc_base: 3497 },
|
|
37
|
+
"PE" => { metc_rate: 0.0980, metc_floor: 1768, dtc_base: 6890, ccc_base: 2446 },
|
|
38
|
+
"YT" => { metc_rate: 0.0640, metc_floor: 2759, dtc_base: 9872, ccc_base: 8375 },
|
|
39
|
+
"NT" => { metc_rate: 0.0590, metc_floor: 2759, dtc_base: 14160, ccc_base: 5167 },
|
|
40
|
+
"NU" => { metc_rate: 0.0400, metc_floor: 2759, dtc_base: 15440, ccc_base: 5560 },
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
def self.personal_care_category_for(province)
|
|
44
|
+
case province
|
|
45
|
+
when "ON", "QC" then "PSW"
|
|
46
|
+
when "BC", "AB", "SK", "MB" then "HCA"
|
|
47
|
+
else "HSW"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.cognitive_bump(c)
|
|
52
|
+
{ "intact" => 0, "mild" => 3, "moderate" => 8, "severe" => 14 }[c] || 0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.mobility_bump(m)
|
|
56
|
+
{ "independent" => 0, "cane" => 0.5, "walker" => 2, "wheelchair" => 5, "bedbound" => 12 }[m] || 0
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.household_mod(h)
|
|
60
|
+
{ "alone" => 3, "with_spouse" => 1.5, "with_adult_child" => 1, "multigen" => 0.5 }[h] || 2
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.diagnosis_nursing(d)
|
|
64
|
+
{ "stroke" => 4, "parkinson" => 1, "post_surgical" => 6, "chronic_mixed" => 2 }[d] || 0
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.derive_psw_hours(adl, cognitive, mobility, informal)
|
|
68
|
+
base = 7.0 * [0, 6 - adl].max + cognitive_bump(cognitive) + mobility_bump(mobility)
|
|
69
|
+
credited = [informal * 0.5, base * 0.6].min
|
|
70
|
+
[(base - credited), 0.0].max.round(1)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.derive_housekeeping_hours(iadl, household)
|
|
74
|
+
base = 2.0 * [0, 8 - iadl].max + household_mod(household)
|
|
75
|
+
[base, 0.0].max.round(1)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.derive_nursing_hours(diagnosis, cognitive)
|
|
79
|
+
base = diagnosis_nursing(diagnosis)
|
|
80
|
+
base += 1 if cognitive == "severe"
|
|
81
|
+
[base, 0.0].max.round(1)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.datasets_dir
|
|
85
|
+
candidates = [
|
|
86
|
+
File.expand_path("../../datasets", __dir__),
|
|
87
|
+
File.expand_path("../../../datasets", __dir__),
|
|
88
|
+
File.expand_path("./datasets"),
|
|
89
|
+
]
|
|
90
|
+
candidates.find { |d| File.exist?(File.join(d, "home_care_services_canada.csv")) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.load_services
|
|
94
|
+
path = File.join(datasets_dir, "home_care_services_canada.csv") rescue nil
|
|
95
|
+
return {} unless path && File.exist?(path)
|
|
96
|
+
result = {}
|
|
97
|
+
CSV.foreach(path, headers: true) do |row|
|
|
98
|
+
result["#{row["jurisdiction_code"]}|#{row["service_category"]}"] = row.to_h
|
|
99
|
+
end
|
|
100
|
+
result
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.load_subsidies
|
|
104
|
+
path = File.join(datasets_dir, "home_care_subsidy_programs.csv") rescue nil
|
|
105
|
+
return {} unless path && File.exist?(path)
|
|
106
|
+
result = {}
|
|
107
|
+
CSV.foreach(path, headers: true) do |row|
|
|
108
|
+
code = row["jurisdiction_code"]
|
|
109
|
+
result[code] ||= row.to_h
|
|
110
|
+
end
|
|
111
|
+
result
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.service_rate(services, prov, category)
|
|
115
|
+
row = services["#{prov}|#{category}"]
|
|
116
|
+
return 0.0 unless row
|
|
117
|
+
(row["private_pay_rate_cad_median"] || "0").to_f
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.subsidy_hours_awarded(subsidies, prov, adl)
|
|
121
|
+
row = subsidies[prov]
|
|
122
|
+
return 0.0 unless row
|
|
123
|
+
moderate = (row["typical_psw_hours_per_week_moderate"] || "0").to_f
|
|
124
|
+
high = (row["typical_psw_hours_per_week_high"] || "0").to_f
|
|
125
|
+
return 0.0 if adl >= 5
|
|
126
|
+
return high.round(1) if adl <= 1
|
|
127
|
+
alpha = (4 - adl) / 3.0
|
|
128
|
+
(moderate + alpha * (high - moderate)).round(1)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def self.calculate(input)
|
|
132
|
+
input = {
|
|
133
|
+
household_composition: "alone",
|
|
134
|
+
cognitive_status: "intact",
|
|
135
|
+
mobility_status: "independent",
|
|
136
|
+
primary_diagnosis_category: "frailty",
|
|
137
|
+
informal_caregiver_hours_per_week: 0.0,
|
|
138
|
+
net_family_income_cad: 60000.0,
|
|
139
|
+
is_veteran: false,
|
|
140
|
+
has_dtc: false,
|
|
141
|
+
agency_vs_private: "private",
|
|
142
|
+
include_subsidy: true,
|
|
143
|
+
tax_year: 2026,
|
|
144
|
+
}.merge(input)
|
|
145
|
+
|
|
146
|
+
services = load_services
|
|
147
|
+
subsidies = load_subsidies
|
|
148
|
+
|
|
149
|
+
psw_hours = derive_psw_hours(
|
|
150
|
+
input[:adl_katz_score], input[:cognitive_status],
|
|
151
|
+
input[:mobility_status], input[:informal_caregiver_hours_per_week]
|
|
152
|
+
)
|
|
153
|
+
housekeeping_hours = derive_housekeeping_hours(input[:iadl_lawton_score], input[:household_composition])
|
|
154
|
+
nursing_hours = derive_nursing_hours(input[:primary_diagnosis_category], input[:cognitive_status])
|
|
155
|
+
|
|
156
|
+
mix = if nursing_hours > 0 && psw_hours > 0
|
|
157
|
+
housekeeping_hours > 0 ? "nursing+psw+housekeeping" : "nursing+psw"
|
|
158
|
+
elsif psw_hours > 0 && housekeeping_hours > 0
|
|
159
|
+
"psw+housekeeping"
|
|
160
|
+
elsif psw_hours > 0
|
|
161
|
+
"psw_only"
|
|
162
|
+
elsif housekeeping_hours > 0
|
|
163
|
+
"housekeeping_only"
|
|
164
|
+
else
|
|
165
|
+
"no_formal_services"
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
pc_cat = personal_care_category_for(input[:province])
|
|
169
|
+
psw_rate = service_rate(services, input[:province], pc_cat)
|
|
170
|
+
house_cat = input[:agency_vs_private] == "agency" ? "Cleaning_Service_Agency" : "Housekeeper_Private"
|
|
171
|
+
housekeeping_rate = service_rate(services, input[:province], house_cat)
|
|
172
|
+
nursing_rate = service_rate(services, input[:province], "LPN_RPN")
|
|
173
|
+
|
|
174
|
+
private_monthly = (psw_hours * psw_rate + housekeeping_hours * housekeeping_rate + nursing_hours * nursing_rate) * WEEKS_PER_MONTH
|
|
175
|
+
|
|
176
|
+
subsidy_hours = input[:include_subsidy] ? [subsidy_hours_awarded(subsidies, input[:province], input[:adl_katz_score]), psw_hours].min : 0.0
|
|
177
|
+
subsidy_value = subsidy_hours * psw_rate * WEEKS_PER_MONTH
|
|
178
|
+
oop_monthly = [private_monthly - subsidy_value, 0.0].max
|
|
179
|
+
oop_annual = oop_monthly * 12.0
|
|
180
|
+
|
|
181
|
+
pp = PROVINCIAL_FACTORS[input[:province]] || PROVINCIAL_FACTORS["ON"]
|
|
182
|
+
fed_threshold = [input[:net_family_income_cad] * METC_FLOOR_FRAC, METC_ABS_FLOOR].min
|
|
183
|
+
metc_fed = [(oop_annual - fed_threshold), 0.0].max * METC_FEDERAL_RATE
|
|
184
|
+
prov_threshold = [input[:net_family_income_cad] * METC_FLOOR_FRAC, pp[:metc_floor]].min
|
|
185
|
+
metc_prov = [(oop_annual - prov_threshold), 0.0].max * pp[:metc_rate]
|
|
186
|
+
metc_credit = metc_fed + metc_prov
|
|
187
|
+
|
|
188
|
+
dtc_credit = (input[:has_dtc] || input[:cognitive_status] == "severe") ? (DTC_BASE * METC_FEDERAL_RATE + pp[:dtc_base] * pp[:metc_rate]) : 0.0
|
|
189
|
+
|
|
190
|
+
ccc_credit = 0.0
|
|
191
|
+
if %w[with_spouse with_adult_child multigen].include?(input[:household_composition]) && psw_hours >= 10
|
|
192
|
+
phase_factor = if input[:net_family_income_cad] <= CCC_PHASE_START
|
|
193
|
+
1.0
|
|
194
|
+
elsif input[:net_family_income_cad] >= CCC_PHASE_END
|
|
195
|
+
0.0
|
|
196
|
+
else
|
|
197
|
+
1.0 - (input[:net_family_income_cad] - CCC_PHASE_START) / (CCC_PHASE_END - CCC_PHASE_START)
|
|
198
|
+
end
|
|
199
|
+
ccc_credit = (CCC_CAREGIVER_BASE * METC_FEDERAL_RATE + pp[:ccc_base] * pp[:metc_rate]) * phase_factor
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
vip_credit = input[:is_veteran] ? (VIP_HOUSEKEEPING + VIP_PERSONAL_CARE) : 0.0
|
|
203
|
+
total_credits = metc_credit + dtc_credit + ccc_credit + vip_credit
|
|
204
|
+
oop_after_annual = [oop_annual - total_credits, 0.0].max
|
|
205
|
+
oop_after_monthly = oop_after_annual / 12.0
|
|
206
|
+
|
|
207
|
+
total_hours = psw_hours + housekeeping_hours + nursing_hours
|
|
208
|
+
all_psw_monthly = total_hours * psw_rate * WEEKS_PER_MONTH
|
|
209
|
+
hybrid_savings = all_psw_monthly - private_monthly
|
|
210
|
+
|
|
211
|
+
scope_warnings = []
|
|
212
|
+
if input[:adl_katz_score] <= 4 || %w[moderate severe].include?(input[:cognitive_status])
|
|
213
|
+
scope_warnings << "Personal care required: the recipient's ADL score or cognitive status indicates that personal care tasks (bathing, toileting, transfers) are needed. A housekeeper or cleaning service cannot legally substitute for a PSW/HCA in this scope. If a cleaning service is part of the plan, it must be in addition to, not instead of, personal support."
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
employment_warnings = []
|
|
217
|
+
if input[:agency_vs_private] == "private" && (total_hours - subsidy_hours) >= 20
|
|
218
|
+
employment_warnings << "At #{(total_hours - subsidy_hours).round(0)} hours per week of privately-hired care in #{input[:province]}, the CRA employer-determination test is likely to classify the family as an employer."
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
{
|
|
222
|
+
province: input[:province],
|
|
223
|
+
tax_year: input[:tax_year],
|
|
224
|
+
recommended_psw_hours_per_week: psw_hours,
|
|
225
|
+
recommended_housekeeping_hours_per_week: housekeeping_hours,
|
|
226
|
+
recommended_nursing_hours_per_week: nursing_hours,
|
|
227
|
+
recommended_service_mix: mix,
|
|
228
|
+
psw_hourly_rate_cad: psw_rate.round(2),
|
|
229
|
+
housekeeping_hourly_rate_cad: housekeeping_rate.round(2),
|
|
230
|
+
nursing_hourly_rate_cad: nursing_rate.round(2),
|
|
231
|
+
private_pay_monthly_cad: private_monthly.round(2),
|
|
232
|
+
subsidy_hours_per_week_allocated: subsidy_hours.round(1),
|
|
233
|
+
subsidy_value_monthly_cad: subsidy_value.round(2),
|
|
234
|
+
out_of_pocket_before_credits_monthly_cad: oop_monthly.round(2),
|
|
235
|
+
metc_credit_value_cad: metc_credit.round(2),
|
|
236
|
+
dtc_credit_value_cad: dtc_credit.round(2),
|
|
237
|
+
ccc_credit_value_cad: ccc_credit.round(2),
|
|
238
|
+
vac_vip_credit_value_cad: vip_credit.round(2),
|
|
239
|
+
total_credits_value_cad: total_credits.round(2),
|
|
240
|
+
out_of_pocket_after_credits_monthly_cad: oop_after_monthly.round(2),
|
|
241
|
+
out_of_pocket_after_credits_annual_cad: oop_after_annual.round(2),
|
|
242
|
+
all_psw_cost_comparison_monthly_cad: all_psw_monthly.round(2),
|
|
243
|
+
hybrid_savings_vs_all_psw_monthly_cad: hybrid_savings.round(2),
|
|
244
|
+
scope_warnings: scope_warnings,
|
|
245
|
+
employment_law_warnings: employment_warnings,
|
|
246
|
+
currency: "CAD",
|
|
247
|
+
disclaimer: DISCLAIMER,
|
|
248
|
+
}
|
|
249
|
+
end
|
|
250
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: home_care_cost_model
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Dave Cook
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-04-10 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Ruby port of the Home Care Cost Model reference implementation. Calculates
|
|
13
|
+
recommended PSW, housekeeping, and nursing hours, private-pay cost, subsidised hours,
|
|
14
|
+
and the 2026 federal/provincial tax relief stack for Canadian households.
|
|
15
|
+
email:
|
|
16
|
+
- dave@binx.ca
|
|
17
|
+
executables:
|
|
18
|
+
- home-care-cost-model
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- bin/home-care-cost-model
|
|
23
|
+
- lib/home_care_cost_model.rb
|
|
24
|
+
homepage: https://github.com/DaveCookVectorLabs/home-care-cost-model
|
|
25
|
+
licenses:
|
|
26
|
+
- MIT
|
|
27
|
+
metadata:
|
|
28
|
+
homepage_uri: https://github.com/DaveCookVectorLabs/home-care-cost-model
|
|
29
|
+
source_code_uri: https://github.com/DaveCookVectorLabs/home-care-cost-model
|
|
30
|
+
documentation_uri: https://www.binx.ca/guides/home-care-cost-model-guide.pdf
|
|
31
|
+
rdoc_options: []
|
|
32
|
+
require_paths:
|
|
33
|
+
- lib
|
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: 2.7.0
|
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
requirements: []
|
|
45
|
+
rubygems_version: 3.6.3
|
|
46
|
+
specification_version: 4
|
|
47
|
+
summary: Reference cost model for Canadian home care service-mix decisions.
|
|
48
|
+
test_files: []
|