generated from CDCgov/template
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathREADME.qmd
706 lines (588 loc) · 22.6 KB
/
README.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
---
title: CFA Forecast Tools (Python)
format: gfm
jupyter: python3
---
<!-- To learn more about using Quarto for
render a GitHub README, see
<https://quarto.org/docs/output-formats/gfm.html>
-->
<!-- ```{python}
#| echo: false
import polars as pl
# format polars dataframe correctly in the
# background
pl.Config.set_tbl_hide_dataframe_shape(False)
pl.Config.set_tbl_formatting("ASCII_MARKDOWN")
pl.Config.set_tbl_hide_column_data_types(False)
``` -->
Summary of `forecasttools-py`:
* A Python package.
* Primarily supports the Short Term Forecast's team.
* Intended to support wider Real Time Monitoring branch operations.
* Has tools for pre- and post-processing.
* Conversion of `az.InferenceData` forecast to Hubverse format.
* Addition of time and or dates to `az.InferenceData`.
Notes:
* This repository is a WORK IN PROGRESS.
* For the R version of this toolkit, see [forecasttools](https://github.com/CDCgov/forecasttools).
* For CDC project expected to use `forecasttools-py`, see [pyrenew-hew](https://github.com/CDCgov/pyrenew-hew).
<details markdown=1>
<summary>
A Tentative Utilities Diagram
</summary>
```mermaid
%%{init: {"theme": "neutral", "themeVariables": { "fontFamily": "Iosevka", "fontSize": "25px", "lineColor": "#808b96", "arrowheadColor": "#808b96", "edgeStrokeWidth": "10px", "arrowheadLength": "20px"}}}%%
flowchart TD
A1[COVID-19 Data _from forecasttools_] --> A4[NumPyro Model]
A2[Influenza Data _from forecasttools_] --> A4[NumPyro Model]
A3[External Dataset] --> A4[NumPyro Model]
A4[NumPyro Model] -->|_arviz.from_numpyro_| A5[Forecast As InferenceData Object wo/ Dates]
A5[Forecast As InferenceData Object wo/ Dates] -->|_Add Dates To InferenceData_ - done| A6[InferenceData Object w/ Dates]
A6[InferenceData Object w/ Dates] -->|_Convert To Tidy-Like Dataframe_ - done| A7[Polars Forecast Dataframe w/ Draws]
A7[Polars Forecast Dataframe w/ Draws] -->|_Convert To Hubverse Formatted Dataframe_ - done| A8[FluSight Submission Dataframe]
A7[Polars Forecast Dataframe w/ Draws] -->|_Convert To ScoringUtils Formatted Dataframe_ - in progress| A9[ScoringUtils DataFrame]
A7[Polars Forecast Dataframe w/ Draws] -->|_Save_| A10[Parquet File]
A8[FluSight Submission Dataframe] -->|_Save_| A11[Parquet File]
A9[ScoringUtils DataFrame] -->|_Save_| A12[Parquet File]
A8[FluSight Submission Dataframe] -->|_Convert To ScoringUtils Formatted Dataframe_ - in progress| A9[ScoringUtils DataFrame]
A12[Parquet File] -->|_Get scores in R_| A13[Forecast Scores]
A11[Parquet File] -->|_Model Forecast Hypothesis Testing_| A14[Model Comparison Report]
B1[Pulled Parquet Hubverse Submissions] -->|_Model Forecast Hypothesis Testing_| A14[Model Comparison Report]
linkStyle default stroke: #808b96
linkStyle default stroke-width: 2.0px
```
</details>
# Installation
Install `forecasttools-py` via:
```
pip3 install git+https://github.com/CDCgov/forecasttools-py@main
```
# Vignettes
* [Format Arviz Forecast Output For FluSight Submission](https://github.com/CDCgov/forecasttools-py/blob/main/notebooks/flusight_from_idata.qmd)
* [Community Meeting Utilities Demonstration (2024-11-19)](https://github.com/CDCgov/forecasttools-py/blob/main/notebooks/forecasttools_community_demo_2024-11-19.qmd)
* [Creating InferenceData Objects and Using Forecasttools Datasets](https://github.com/CDCgov/forecasttools-py/blob/main/notebooks/datasets_and_idata_creation.qmd)
_Coming soon as webpages, once [Issue 26](https://github.com/CDCgov/forecasttools-py/issues/26) is completed_.
# Datasets
Within `forecasttools-py`, one finds several packaged datasets. These datasets can aid with experimentation; some are directly necessary to other utilities provided by `forecasttools-py`.
```{python}
import forecasttools
```
Summary of datasets:
* `forecasttools.location_table`
* A Polars dataframe of location abbreviations, codes, and names for Hubverse formatted forecast submissions.
* `forecasttools.example_flusight_submission`
* An example Hubverse formatted influenza forecast submission (as a Polars dataframe) submitted to the FluSight Hub.
* `forecasttools.nhsn_hosp_COVID`
* A Polars dataframe of NHSN COVID hospital admissions data.
* `forecasttools.nhsn_hosp_flu`
* A Polars dataframe of NHSN influenza hospital admissions data.
* `forecasttools.nhsn_flu_forecast_wo_dates`
* An `az.InferenceData` object containing a forecast made using NSHN influenza data for Texas.
* `forecasttools.nhsn_flu_forecast_w_dates`
* An modified (with dates as coordinates) `az.InferenceData` object containing a forecast made using NSHN influenza data for Texas.
See below for more information on the datasets.
## Location Table
The location table contains abbreviations, codes, and extended names for the US jurisdictions for which the FluSight and COVID forecasting hubs require users to generate forecasts.
The location table is stored in `forecasttools-py` as a `polars` dataframe and is accessed via:
```{python}
loc_table = forecasttools.location_table
print(loc_table)
```
Using `./forecasttools/data.py`, the location table was created by running the following:
```python
make_census_dataset(
file_save_path=os.path.join(
os.getcwd(),
"location_table.csv"
),
)
```
## Example FluSight Hub Submission
The example FluSight submission comes from the [following 2023-24 submission](https://raw.githubusercontent.com/cdcepi/FluSight-forecast-hub/main/model-output/cfa-flumech/2023-10-14-cfa-flumech.csv).
The example FluSight submission is stored in `forecasttools-py` as a `polars` dataframe and is accessed via:
```{python}
submission = forecasttools.example_flusight_submission
print(submission)
```
Using `data.py`, the example FluSight submission was created by running the following:
```python
get_and_save_flusight_submission(
file_save_path=os.path.join(
os.getcwd(),
"example_flusight_submission.csv"
),
)
```
## NHSN COVID And Flu Hospital Admissions
NHSN hospital admissions fitting data for COVID and Flu is included in `forecasttools-py` as well, for user experimentation.
This data:
* Is current as of `2024-04-27`
* Comes from the website [HealthData.gov COVID-19 Reported Patient Impact and Hospital Capacity by State Timeseries](https://healthdata.gov/Hospital/COVID-19-Reported-Patient-Impact-and-Hospital-Capa/g62h-syeh).
For influenza, the `previous_day_admission_influenza_confirmed` column is retained and for COVID the `previous_day_admission_adult_covid_confirmed` column is retained. As can be seen in the example below, some early dates for each jurisdiction do not have data.
The fitting data is stored in `forecasttools-py` as a `polars` dataframe and is accessed via:
```{python}
# access COVID data
covid_nhsn_data = forecasttools.nhsn_hosp_COVID
# access flu data
flu_nhsn_data = forecasttools.nhsn_hosp_flu
# display flu data
print(flu_nhsn_data)
```
The data was created by placing a csv file called `NHSN_RAW_20240926.csv` (the full NHSN dataset) into `./forecasttools/` and running, in `data.py`, the following:
```python
# generate COVID dataset
make_nshn_fitting_dataset(
dataset="COVID",
nhsn_dataset_path="NHSN_RAW_20240926.csv",
file_save_path=os.path.join(
os.getcwd(),
"nhsn_hosp_COVID.csv"
)
)
# generate flu dataset
make_nshn_fitting_dataset(
dataset="flu",
nhsn_dataset_path="NHSN_RAW_20240926.csv",
file_save_path=os.path.join(
os.getcwd(),
"nhsn_hosp_flu.csv"
)
)
```
## Influenza Hospitalizations Forecast(s)
Two example forecasts stored in Arviz `InferenceData` objects are included for vignettes and user experimentation. Both are 28 day influenza hospital admissions forecasts for Texas made using a spline regression model fitted to NHSN data between 2022-08-08 and 2022-12-08. The only difference between the forecasts is that `example_flu_forecast_w_dates.nc` has had dates added as its coordinates (this is not a native Arviz feature).
The forecast `idata`s are accessed via:
```{python}
# idata with dates as coordinates
idata_w_dates = forecasttools.nhsn_flu_forecast_w_dates
print(idata_w_dates)
```
```{python}
# show dates
print(idata_w_dates["observed_data"]["obs"]["obs_dim_0"][:15])
```
```{python}
# idata without dates as coordinates
idata_wo_dates = forecasttools.nhsn_flu_forecast_wo_dates
print(idata_wo_dates["observed_data"]["obs"]["obs_dim_0"][:15])
```
The forecast was generated following the creation of `nhsn_hosp_flu.csv` (see previous section) by running `data.py` with the following added:
```python
make_forecast(
nhsn_data=forecasttools.nhsn_hosp_flu,
start_date="2022-08-08",
end_date="2022-12-08",
juris_subset=["TX"],
forecast_days=28,
save_path="../forecasttools/example_flu_forecast_w_dates.nc",
save_idata=True,
use_log=False,
)
```
(note: `make_forecast` is no longer included in `forecasttools-py`, given the expectation that no one would ever call it; however, for reproducibility's sake, the following is included here)
<details markdown=1>
<summary>
Some Of The Forecast Code
</summary>
```python
"""
Creating a new idata object with
dates to change the functionality
of idata_w_dates_to_df.
"""
# %% IMPORTS
import os
from datetime import datetime, timedelta
import arviz as az
import forecasttools
import jax.numpy as jnp
import jax.random as jr
import matplotlib.pyplot as plt
import numpy as np
import numpyro
import numpyro.distributions as dist
import patsy
import polars as pl
from numpy.typing import NDArray
# %% CHECK FILE PATH
def check_file_save_path(
file_save_path: str,
) -> None:
"""
Checks whether a file path is valid.
file_save_path
The file path to be checked.
"""
directory = os.path.dirname(file_save_path)
if not os.path.exists(directory):
raise FileNotFoundError(f"Directory does not exist: {directory}")
if not os.access(directory, os.W_OK):
raise PermissionError(f"Directory is not writable: {directory}")
if os.path.exists(file_save_path):
raise FileExistsError(f"File already exists at: {file_save_path}")
# %% SPLINE REGRESSION MODEL
def model(basis_matrix, y=None):
# priors
shift = numpyro.sample("shift", dist.Normal(0.0, 2.0))
beta_coeffs = numpyro.sample(
"beta_coeffs",
dist.Normal(jnp.zeros(basis_matrix.shape[1]), 2.0),
)
shift_mu = jnp.dot(basis_matrix, beta_coeffs) + shift
mu_exp = jnp.exp(shift_mu)
alpha = numpyro.sample("alpha", dist.Exponential(1.0))
# likelihood
numpyro.sample(
"obs",
dist.NegativeBinomial2(mu_exp, alpha),
obs=y,
)
# %% SPLINE BASIS MATRIX
def spline_basis(X, degree: int = 4, df: int = 8) -> NDArray:
basis = patsy.dmatrix(
"bs(x, df=df, degree=degree, include_intercept=True) - 1",
{"x": X, "df": df, "degree": degree},
return_type="matrix",
)
return np.array(basis)
# %% PLOT AND OR SAVE FORECAST
def plot_and_or_save_forecast(
idata: az.InferenceData,
X: NDArray,
y: NDArray,
title: str,
start_date: str,
end_date: str,
last_fit: int,
X_act: NDArray,
y_act: NDArray,
save_to_pdf: bool = False,
use_log: bool = False,
):
"""
Includes hard-coded variables. For the
author's testing and no more.
"""
x_data = idata.posterior_predictive["obs_dim_0"]
y_data = idata.posterior_predictive["obs"]
fig, axes = plt.subplots(1, 1, figsize=(8, 6))
az.plot_hdi(
x_data,
y_data,
hdi_prob=0.95,
color="skyblue",
smooth=False,
fill_kwargs={
"alpha": 0.2,
"label": "95% Credible",
},
ax=axes,
)
az.plot_hdi(
x_data,
y_data,
hdi_prob=0.75,
color="skyblue",
smooth=False,
fill_kwargs={
"alpha": 0.4,
"label": "75% Credible",
},
ax=axes,
)
az.plot_hdi(
x_data,
y_data,
hdi_prob=0.5,
color="C0",
smooth=False,
fill_kwargs={
"alpha": 0.6,
"label": "50% Credible",
},
ax=axes,
)
axes.plot(
X,
y,
marker="o",
color="black",
linewidth=1.0,
markersize=3.0,
label="Observed",
)
if (X_act is not None) and (y_act is not None):
axes.plot(
X_act,
y_act,
marker="o",
color="red",
linewidth=1.0,
markersize=3.0,
label="Actual",
)
if use_log:
axes.set_yscale("log")
axes.set_ylabel(
"(Log) Hospital Admissions",
fontsize=17.5,
)
if not use_log:
axes.set_ylabel("Hospital Admissions", fontsize=17.5)
median_ts = y_data.median(dim=["chain", "draw"])
axes.plot(
x_data,
median_ts,
color="blue",
label="Median",
)
axes.legend()
axes.axvline(last_fit, color="black", linestyle="--")
axes.set_title(
f"{title}",
fontsize=20,
)
axes.set_xlabel("Time", fontsize=17.5)
plt.show()
# %% ADD DATES TO AN INFERENCE DATA OBJECT
def add_dates_to_idata_object(
idata: az.InferenceData,
start_date: str,
) -> az.InferenceData:
"""
Takes an InferenceData object w/
observed_data and posterior_predictive
groups and adds date indexing
"""
pass
# %% MAKE A FORECAST
def make_forecast(
nhsn_data: str,
start_date: str,
end_date: str,
juris_subset: list[str],
forecast_days: int,
save_path: str = os.path.join(os.getcwd(), "forecast.nc"),
show_plot: bool = True,
save_idata: bool = False,
use_log: bool = False,
) -> None:
"""
Generates a forecast for specified
dates using a spline regression model.
"""
# check dataset path
check_file_save_path(save_path)
# clean data and organize data, cleaning null values
nhsn_data = nhsn_data.with_columns(
pl.col("hosp").cast(pl.Int64),
pl.col("date").str.strptime(pl.Date, "%Y-%m-%d"),
).filter(
pl.col("hosp").is_not_null(),
pl.col("state").is_in(juris_subset),
)
nhsn_data_ready = nhsn_data.filter(
(
pl.col("date")
>= pl.lit(start_date).str.strptime(pl.Date, "%Y-%m-%d")
)
& (
pl.col("date")
<= pl.lit(end_date).str.strptime(pl.Date, "%Y-%m-%d")
)
)
# get the actual values, if they exist
try:
forecast_end_date = datetime.strptime(
end_date, "%Y-%m-%d"
) + timedelta(days=forecast_days)
nhsn_data_actual = nhsn_data.filter(
(
pl.col("date")
>= pl.lit(end_date).str.strptime(pl.Date, "%Y-%m-%d")
)
& (pl.col("date") <= pl.lit(forecast_end_date))
)
except Exception as e:
nhsn_data_actual = None
print(f"The following error occurred: {e}")
# define some shared inference values
random_seed = 2134312
num_samples = 1000
num_warmup = 500
# get posterior samples and make forecasts for each selected state
for state in juris_subset:
# get the state data
state_nhsn = nhsn_data_ready.filter(pl.col("state") == state)
# get observation (fitting) data y, X
y = state_nhsn["hosp"].to_numpy()
X = np.arange(y.shape[0])
# set up inference, NUTS/MCMC
kernel = numpyro.infer.NUTS(
model=model,
max_tree_depth=12,
target_accept_prob=0.85,
init_strategy=numpyro.infer.init_to_uniform(),
)
mcmc = numpyro.infer.MCMC(
kernel,
num_warmup=num_warmup,
num_samples=num_samples,
)
# create spline basis for obs period and forecast period
last = X[-1]
X_future = np.hstack(
(
X,
np.arange(
last + 1,
last + 1 + forecast_days,
),
)
)
sbm = spline_basis(X_future)
# get posterior samples
mcmc.run(
rng_key=jr.key(random_seed),
basis_matrix=sbm[: len(X)],
y=y,
)
posterior_samples = mcmc.get_samples()
# get prior predictive
prior_pred = numpyro.infer.Predictive(model, num_samples=num_samples)(
rng_key=jr.key(random_seed),
basis_matrix=sbm[: len(X)],
)
# get posterior predictive forecast
posterior_pred_for = numpyro.infer.Predictive(
model,
posterior_samples=posterior_samples,
)(
rng_key=jr.key(random_seed),
basis_matrix=sbm,
)
# create initial inference data object(s) and store
idata = az.from_numpyro(
posterior=mcmc,
posterior_predictive=posterior_pred_for,
prior=prior_pred,
)
# get actual data, if it exists
if isinstance(nhsn_data_actual, pl.DataFrame):
actual_data = nhsn_data_actual.filter(pl.col("state") == state)
y_act = actual_data["hosp"].to_numpy()
X_act = np.arange(last - 1, last + forecast_days)
if not isinstance(nhsn_data_actual, pl.DataFrame):
y_act = None
X_act = None
# add dates to idata object
# save idata object(s)
if save_idata:
idata.to_netcdf(save_path)
# plot forecast (if desired) from idata light
if show_plot:
plot_and_or_save_forecast(
idata=idata,
X=X,
y=y,
title=f"Hospital Admissions ({state}, {start_date}-{end_date})",
start_date=start_date,
end_date=end_date,
last_fit=last,
X_act=X_act,
y_act=y_act,
use_log=use_log,
)
# %% EXECUTE MODE
make_forecast(
nhsn_data=forecasttools.nhsn_hosp_flu,
start_date="2022-08-08",
end_date="2022-12-08",
juris_subset=["TX"],
forecast_days=28,
save_path="../forecasttools/example_flu_forecast_w_dates.nc",
save_idata=False,
use_log=True,
)
```
</details>
The forecast looks like:
![Example NHSN-based Influenza forecast](./assets/example_forecast_w_dates.png){ width=75% }
# CDC Open Source Considerations
**General disclaimer** This repository was created for use by CDC programs to collaborate on public health related projects in support of the [CDC mission](https://www.cdc.gov/about/organization/mission.htm). GitHub is not hosted by the CDC, but is a third party website used by CDC and its partners to share information and collaborate on software. CDC use of GitHub does not imply an endorsement of any one particular service, product, or enterprise.
<details markdown=1>
<summary>Rules, Policy, And Collaboration</summary>
* [Open Practices](./rules-and-policies/open_practices.md)
* [Rules of Behavior](./rules-and-policies/rules_of_behavior.md)
* [Thanks and Acknowledgements](./rules-and-policies/thanks.md)
* [Disclaimer](DISCLAIMER.md)
* [Contribution Notice](CONTRIBUTING.md)
* [Code of Conduct](./rules-and-policies/code-of-conduct.md)
</details>
<details markdown=1>
<summary>
Public Domain Standard Notice
</summary>
This repository constitutes a work of the United States Government and is not
subject to domestic copyright protection under 17 USC § 105. This repository is in
the public domain within the United States, and copyright and related rights in
the work worldwide are waived through the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/).
All contributions to this repository will be released under the CC0 dedication. By
submitting a pull request you are agreeing to comply with this waiver of
copyright interest.
</details>
<details markdown=1>
<summary>
License Standard Notice
</summary>
The repository utilizes code licensed under the terms of the Apache Software
License and therefore is licensed under ASL v2 or later.
This source code in this repository is free: you can redistribute it and/or modify it under
the terms of the Apache Software License version 2, or (at your option) any
later version.
This source code in this repository is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the Apache Software License for more details.
You should have received a copy of the Apache Software License along with this
program. If not, see http://www.apache.org/licenses/LICENSE-2.0.html
The source code forked from other open source projects will inherit its license.
</details>
<details markdown=1>
<summary>
Privacy Standard Notice
</summary>
This repository contains only non-sensitive, publicly available data and
information. All material and community participation is covered by the
[Disclaimer](DISCLAIMER.md)
and [Code of Conduct](code-of-conduct.md).
For more information about CDC's privacy policy, please visit [http://www.cdc.gov/other/privacy.html](https://www.cdc.gov/other/privacy.html).
</details>
<details markdown=1>
<summary>
Contributing Standard Notice
</summary>
Anyone is encouraged to contribute to the repository by [forking](https://help.github.com/articles/fork-a-repo)
and submitting a pull request. (If you are new to GitHub, you might start with a
[basic tutorial](https://help.github.com/articles/set-up-git).) By contributing
to this project, you grant a world-wide, royalty-free, perpetual, irrevocable,
non-exclusive, transferable license to all users under the terms of the
[Apache Software License v2](http://www.apache.org/licenses/LICENSE-2.0.html) or
later.
All comments, messages, pull requests, and other submissions received through
CDC including this GitHub page may be subject to applicable federal law, including but not limited to the Federal Records Act, and may be archived. Learn more at [http://www.cdc.gov/other/privacy.html](http://www.cdc.gov/other/privacy.html).
</details>
<details markdown=1>
<summary>
Records Management Standard Notice
</summary>
This repository is not a source of government records, but is a copy to increase
collaboration and collaborative potential. All government records will be
published through the [CDC web site](http://www.cdc.gov).
</details>
<details markdown=1>
<summary>
Additional Standard Notices
</summary>
Please refer to [CDC's Template Repository](https://github.com/CDCgov/template) for more information about [contributing to this repository](https://github.com/CDCgov/template/blob/main/CONTRIBUTING.md), [public domain notices and disclaimers](https://github.com/CDCgov/template/blob/main/DISCLAIMER.md), and [code of conduct](https://github.com/CDCgov/template/blob/main/code-of-conduct.md).
</details>