From fca974c68494f07dcaef2077a972950b9ac7d506 Mon Sep 17 00:00:00 2001 From: rachlobay Date: Mon, 10 Jul 2023 04:03:25 -0700 Subject: [PATCH 01/16] Get arx vignette up and running (note had to demote knitr to 1.4.2 for accomodating html widgets) --- .../arx-forecaster/execute-results/html.json | 18 + .../figure-html/unnamed-chunk-12-1.png | Bin 0 -> 144428 bytes .../figure-html/unnamed-chunk-13-1.svg | 759 ++ .../figure-html/unnamed-chunk-14-1.png | Bin 0 -> 137547 bytes .../figure-html/unnamed-chunk-15-1.png | Bin 0 -> 143987 bytes .../figure-html/unnamed-chunk-15-1.svg | 1103 ++ .../figure-html/unnamed-chunk-16-1.svg | 1103 ++ .../crosstalk-1.2.0/css/crosstalk.min.css | 1 + .../site_libs/crosstalk-1.2.0/js/crosstalk.js | 1474 +++ .../crosstalk-1.2.0/js/crosstalk.js.map | 37 + .../crosstalk-1.2.0/js/crosstalk.min.js | 2 + .../crosstalk-1.2.0/js/crosstalk.min.js.map | 1 + .../crosstalk-1.2.0/scss/crosstalk.scss | 75 + .../htmlwidgets-1.6.2/htmlwidgets.js | 901 ++ .../site_libs/jquery-3.5.1/jquery-AUTHORS.txt | 357 + _freeze/site_libs/jquery-3.5.1/jquery.js | 10872 ++++++++++++++++ _freeze/site_libs/jquery-3.5.1/jquery.min.js | 2 + _freeze/site_libs/jquery-3.5.1/jquery.min.map | 1 + .../site_libs/plotly-binding-4.10.2/plotly.js | 941 ++ .../plotly-htmlwidgets.css | 9 + .../plotly-main-2.11.1/plotly-latest.min.js | 69 + .../typedarray-0.1/typedarray.min.js | 1 + _quarto.yml | 1 + arx-forecaster.qmd | 279 + renv.lock | 91 +- 25 files changed, 18094 insertions(+), 3 deletions(-) create mode 100644 _freeze/arx-forecaster/execute-results/html.json create mode 100644 _freeze/arx-forecaster/figure-html/unnamed-chunk-12-1.png create mode 100644 _freeze/arx-forecaster/figure-html/unnamed-chunk-13-1.svg create mode 100644 _freeze/arx-forecaster/figure-html/unnamed-chunk-14-1.png create mode 100644 _freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.png create mode 100644 _freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg create mode 100644 _freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg create mode 100644 _freeze/site_libs/crosstalk-1.2.0/css/crosstalk.min.css create mode 100644 _freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js create mode 100644 _freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js.map create mode 100644 _freeze/site_libs/crosstalk-1.2.0/js/crosstalk.min.js create mode 100644 _freeze/site_libs/crosstalk-1.2.0/js/crosstalk.min.js.map create mode 100644 _freeze/site_libs/crosstalk-1.2.0/scss/crosstalk.scss create mode 100644 _freeze/site_libs/htmlwidgets-1.6.2/htmlwidgets.js create mode 100644 _freeze/site_libs/jquery-3.5.1/jquery-AUTHORS.txt create mode 100644 _freeze/site_libs/jquery-3.5.1/jquery.js create mode 100644 _freeze/site_libs/jquery-3.5.1/jquery.min.js create mode 100644 _freeze/site_libs/jquery-3.5.1/jquery.min.map create mode 100644 _freeze/site_libs/plotly-binding-4.10.2/plotly.js create mode 100644 _freeze/site_libs/plotly-htmlwidgets-css-2.11.1/plotly-htmlwidgets.css create mode 100644 _freeze/site_libs/plotly-main-2.11.1/plotly-latest.min.js create mode 100644 _freeze/site_libs/typedarray-0.1/typedarray.min.js create mode 100644 arx-forecaster.qmd diff --git a/_freeze/arx-forecaster/execute-results/html.json b/_freeze/arx-forecaster/execute-results/html.json new file mode 100644 index 0000000..e091afa --- /dev/null +++ b/_freeze/arx-forecaster/execute-results/html.json @@ -0,0 +1,18 @@ +{ + "hash": "51a1c1c4df5110ac6f4c81d860c61ecb", + "result": { + "markdown": "# Introducing the ARX forecaster\n\nThe ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nIt can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data.\n\nFrom the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `\"death_rate\"`, and predictors of `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" in the raw `jhu` data and the `lag_14_death_rate` is the value from \"2021-09-01\". In this way, we can manually check that the model used the correct predictor data if we're so inclined.\n\nNow that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nLike with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature.\n\nOk. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_623d4d77ac1bb400822d8937f0b1b87e'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done is to not impose an upper bound the data used in `hist` to make the death rate lines (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_579614de5d067c1e3c156707ca8e42ce'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAs our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nRemember the adapted \"Customize choropleth code\" that we introduced at the end of the Regression In Tidymodels chapter (UPDATE THIS REFERENCE/LINK)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). \nThat's all it takes.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
\",\n \"Pred death rate:\", round(.pred, digits = 3), \"
\",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
(Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
\n\n```\n:::\n:::\n\n\nYou can either hit play in the resulting plot and then sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", + "supporting": [], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": { + "include-in-header": [ + "\n\n\n\n\n\n\n\n" + ] + }, + "engineDependencies": {}, + "preserve": {}, + "postProcess": true + } +} \ No newline at end of file diff --git a/_freeze/arx-forecaster/figure-html/unnamed-chunk-12-1.png b/_freeze/arx-forecaster/figure-html/unnamed-chunk-12-1.png new file mode 100644 index 0000000000000000000000000000000000000000..4c1c15b6e2078389487934ba5554e6f84bb6dc2f GIT binary patch literal 144428 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

);Ff`xET1DqY^7jSE}8FBvK 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 LtW*5w&9MIh99xs> literal 0 HcmV?d00001 diff --git a/_freeze/arx-forecaster/figure-html/unnamed-chunk-13-1.svg b/_freeze/arx-forecaster/figure-html/unnamed-chunk-13-1.svg new file mode 100644 index 0000000..a942088 --- /dev/null +++ b/_freeze/arx-forecaster/figure-html/unnamed-chunk-13-1.svg @@ -0,0 +1,759 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_freeze/arx-forecaster/figure-html/unnamed-chunk-14-1.png b/_freeze/arx-forecaster/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6b530491eaadb7155f52daeef347ba91e1316288 GIT binary patch literal 137547 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

puy4%N)$e6dq!V3cZt|Vuh-(l8E?x=@? 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

  • 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�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

    {$XI|CkECiQ2;Il%pMr&-o3={ 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

    w-?}2ehIB*$ImzE&@-H zZ$ferNGc=t#N2LP1YXQMf3;rF(#qJmn}$~Zoxi%-RYB<}BT{ug3N2Dof2NIX{M1}@ zb>R&=^C?MSSO#OviL z>p+*)!C_ab9s@@WuJ)jt%$II$R$aaFxJa2U2HBq)61&Bozp|OWc)UFn>+w^Q#Ae30 z(@*MWYw_&&(|Gn}rGQkjSj5_nP$qX8ePoGtnR@=fzrAA|60$sNGx!CJU&9Zx}+=7;53#!`XlIm~Jez%0c;S7W#`)rqpyfo{S zbxzN+*?d=JppIEyvfUmSewjOPe(JYOgL#zSgGN6LNF4*H4i`S-cMfh(N9MYQ9A?hy z`@a|kuKBXtc!@=AO|zcGDW0SuDpN_!eA^{thBuuEOx7hbmXO@1Ol z!X)<9C6&O0Fhq?)Hn94$azBmHbN>2M7-Id&v8`epZj-&C=e~Xfzy_fV^OF7^OG7~@ zJarccZL6*)bTQsZ;Gh>=y!TV)l-GYhz5eu?c`d3T#!KvJ5|Lv1(*!NG4yzbD(SGH& zzO4Cif8GsLVa9YrT~It#EEyK_fl`S_sQ>*uKzUZ93zH#Miz>v1sSoKWTdi1iF@Ekl zXf~Pd^s|mIbBxkbjz@BR9Z1D(J=qC+l!du3?>6(Oi514vjtnKOWVC|A&yIozVp#Ko zaoOj0mm@$jw`h^h@ZP;DT=Jz&j6RBHK4y(x8D@bb*+Z;`3>!|9NA9W&X_^U=ODRQ6 z#vICyz2t5q++jo@OCa&gv~CbZK30hZrBg9QTHoJGr=Cuz!lZ5ndvh$LDU^opix|{{ zx-Vj%sx7S4Fy_yt>KVX3sa`ZmK9XxYe1C6>1fQ63#pz`=tIbp{J?o6*eB8 z*)C349kmESunsmpzInjvY~<3&`nxk*5S-^Isy-GNr`cd8n(IT+RQVb-r7y2IdfSz7 z%N8PbE@UF$VkYce^O|IR?3~)bJ0d~PndWiu#NLSMsA2gQ+`(1WBcUzirHan#&HQ2p zN*19_R@|GIK^0k4p{JV3j~}E|sA^h$Z8pi~tg2)In#U&CxkKAI?^}=!_Qb~!Y_8D> zgS!hjU-n%@Z{^jBhY%q|kweS1Gfk#{7<{OoiefGPCd+xAF z)EZ4?A65~aHJzN}+(#HNtQiJMQc_x~YYfizMvM1(KkRh02BaoiDT15!wQWCgj?zD0R^&uw8J~*{H=|iWvVL@0+q1QXYt2j3hC1 z`@q2=4qlWZ=^PGqC8?aS27;%(e>7SYp-kF4AERPqu<#A+h7W@UafLf+DXp*{ARONc3!dscqHj&k2=L#MqfYvfg+bzjLq zKCFz^#|qG~^9B7)nC(6DR`OU2-!#irh0M@!Fb& zL?)>gqH}Q}vU`@#-T7I0WK`7IjTz5^CCCfZiB_{l6nq^7Bl-gJS(Is1Xkvx}++X!o z`RAFR9?d%tPP7T0)5zeRQ^~_1p~r|(;a$brhPX5PVD31S1RY(v79!eS^jlsaw^`QM zhPa5^9$LUMj5x;bUl@oQ#C?h?T52$PUO(jIC-uZVD8Tq0^TfrIy)l-h7885y4>!_! z*TuFHYL6GlmyYEfxzp*KMR#paFwpd7(`~rPX>PDx+S&W$*fW%b!jTp8#zoLZq>87~ z6|=jg)>JwtzcnI9q<`dT!MxrPwjA%Q_Pb#{ZLQYGJK<_$6!ly${#@tpq&wqhcxWJ8 zV?;_0V_P*9M;n@})nJq5er9OK!p^RO#;bm6rpk(3`Q z6l8m!RBRfGbQeZdc#`}M3d$};eO;&+J$}5AHI@jeoA~jDkm1k+l@ghwgBO8L!xmfIe6}k+J3ZDkW=jW-2~Xnu zikN))%GWoR=!50#tYVLA@TSvd@r!kok>Wa(&&=n z{Mn6ssD8a3(a%h%OU7tCa`Fm=UE$+M71e{QqDzPNY|NRjF8K0MU7@?}ehI3s^~$Gt z4s=!U@%FI`lmb&!H5lspkvCXmM$do0gjL|$OKV16Z9J>=2+KIT6N}DT)Na91qh8+f zY!doxTkN&H^^n%v4c4i-B-x`Es;nKs#}S;4Hk)KXsUCU&hE5!{`2(5#&wpdl=-pyN zb_1n#zl-F$J@l;?#wGgPY9J@9tg-0ovoPbX#i|H+&<;l@p=N(ey{r(dRp>dN#HjX~ zWYmx@em2i{LIgPydDp{pbBs{kremiLSLfNg!2H`$z*|ROwl)2CqR*B<^1_7q)`9w? z*KTu7tU_apPnM~We8E1Vw0`Thn*4iGj3A%nj&UCWPg!L;n8b~y2!+((^JTmOzPR3Ta| zj9c+hG*%TM=29>Knd@3_AoQJMm!nGCe=EFWx=YWshl@&v8DuYf3d`= zOqunT#}WuR(e<(-iZ#3LfWn`zn1IyWFCz4ms)`^|lU-|Yf0rFoG2sZIWhXxg>e)<; zA>I`*$vcw4QF&Dfan`H6RN(?C3B%|t!Nx_JBh=QxJtlcV5 z@$ca7Fcjv_5+R*tLRfHpi}0H%EUbAvvR(&u__dIQ)J&lb&;1)$Z7+;`GU?Likv6E& z)7{_|u*i;99VJ7;?reW9eoft*c+KtAFjP>3m%-@Bk?GXh7Hs0;5+z`KqC+#CF5Y=3 zr7J*5D@yg)Iq9_esmY&>{*=FoQL9TLb8-YxX_37|ag2<1e5gr*q+_u)cx} zIWwqu_kRBD-B^X{5IXVq6^e(O-})NAws^6r3gzl zp9Hed-LYRoIWY)NsXnJ6jFW%a_B8NXMEA0|K8zhy^N3|l&p|dySxQ6B(KlQ$pt~gG zc4q`84^vM3qA#PtkxWtvF^_KuI{Nu>qM@GBpc+{K1y zyZ7a`$8U~1EAfv7wzOKmPgjh5OC@9Sras{5ZljT6||?fin$L z-h>fen)%<>7>)4?33Dr9@pE*ZH_GY5@8S^}of(wv2IykR88D$xE+jg|v=bZIpvArD zq)copgJ@zc{gAE-zKEAOfF5z=OXZ4N>uY^4c?-p5VX4t^EA6%GXkEG579F%Ntfj{D zZroa5g>t;#5r>2tiPo7_?4$X3RQVk)fdt#`J#1F*<`FB_+x3&T>jwC1OWql%%-Q~V zPb4dv!c=nYfm|%L#LA_A`Oy%9vriRD)4igNtx5Zx@t$QN%|KqIsv>1~J^|kn{PA}` zTF*S9W~7oH&and-!3wy+6JUXiPc<3z5XWB&xH&UGnspXk>(+(Tz?bqnOgf4dcBhTv zo}IH16k}ruIb}xgVec7#9|e@+S*TG}ey?4u)m#=)@rDv#uDIftt`!|CTIh9MXA=!E zzP^pEV2r%@ex5SF9&LXE)ojl|gx1?_1fzkBoLl_3V68IX^dlZIgC#Mb5lGU3v`>V3 z1GT?8r@-QFEH(CiUtkxZ%a8W(ZJm%_e~I;n?2I|b=PZtg8TTx@sGJ-@VLd&XXN0{U zAL-O?a)qdI(`y$_{e&biCLDJ@z#Qs4s(rD&?Ul3|FPp_$PcZ}Ycx;-*-j5O4P#ALO}M|r1o-}>s>GP1Ji3y$YV>AnayjmOz8(P3WM{2L&!rZB;c$u8=!1l zuCygny)=w>h`>|?A%*+q1pX?!hFv=j1`0grPaq+^K_HMJKaESvDeN1)5PbaJaIB^P zO15+ZJ-8dEwN^|**y^08`(BM^6x2E@nC^;biexQKDK#j*;nkh-;0_Z=YEU6)6k*W@fIb^eB?NPt`;r& znEl;ft)Nt30LTp$%Yy=F0Cb^UXrPf2lJ_5@!7ExMX_w2ZuzRQ%JL88IRXm5Xmr4Z} z#bxbsASXwQl1eimG{0I8{)#5iYaf}BQyPm#n@~N1*@l+KqI0uu34$7chstQ@`dv&H zbPfnONCUBS!1VTndi7*I0$khzX8t>d@d8&<4XnZzaZISCO+DqL-3S6#k<)D^`So!k zdz2Z`PB}x3m084>OEy)l&ikga`M6NQqIyYI#d%ZQd5;|L5he6Jg|gIhKD3vwXprXB z{d)4%zw`|D6fXud*8gNOWoV!`ZQBiJ7cM)4X|-xz)$;Ak?7{nj5FpF+Aq}Ghz1yU5 zpi6LlYX=kkgBGiDP1CEJ0M(Z;L#&42qykTU&uB$OqIXM_D&Rnxl9>U8^^K_JuQ|>V z-Lp9X=!pW6UimD`EK1G4<}*-pRSS(KxVytv0aF}2h3n;;1 zXc?nLM(!|+jY?2e`-ejI=BrLPx($i&ues$W)XPuN9fGi z=k2y~0fi5Rwz?g62h@{!^eb996DyI?zBsp(gtwdzbK-`t!YPT<#K1qTTQ~z2f+;oI zTD%U2W}H6OurJ+(v&uGyVWNOu^bFpU^5-RRX%v>Vb~`EuUzqUvzuT9gV!7)t2&OUI z9fNX9m(DQ>ta)xr*dtKP9na|nBd^=SmgVl|FD*^JeR<~98A7BDoDs)i>bw*`7)4}$${bxv{ihlG?6(&zjemoo+*rVR6^{d zn=)(1_E6(c$Vi=GfYMEagBJ*+L7T+ZKX6~4lr$X(XU;jvu|%%e=#NS~ zE+uD9+Ys8lKTfo%-!}D+!2Gt{cg~%xUsLM8xA89A!@}8^bWPVDM<8VNwQ!WCk?Q37 zl@Ve7&S(%rM1VBWRdqwD9qz5GNaMQvt#`YsJ6pHo6!UUQfPzSW;6&afZPGZzXQVg- z8~TR$KHWVP%@_Z^>?%IkK_jja#Bt)1kHgE;*y4nEI4FtphBc%y{T8jOsluoPO@<$t2(&V`=QjXM@pj-S(q z@pMTC(4C6O^Nt$JKqq+fpyPfxbm8dmd2!UurAAR6@`Q>3xHR(PDG%i9X5*k#Ucc|# zXstkE1FyH-WF!`*lssIVy{2Ir zgYMe~-u#(i`E}#Y4yES%obph!ef5cX%S~kL*du^7-E~xdiXPi%ZnvKls)5g2&m_hZ`)GJDm;41XB7zcTAwd_i=(o}fM~GPhI~&6J z%A0Tv1D!a1FXUdb;n(3^*4Z;QWxdB({H;X>Qj7kGp7ahA&flhP&#SHx!s8XOe}JK% z>+7E=^fqjndMGjSXruGCk+&y!rLt>`qGs8pAcvHrok5+Te+q%ea;2rZ^bQ1lQw&wz zYXiMnVY*0?-g4dC*U*@N{d6N6dq*oQ;KD6&_GQlXqx}pdu?-IWL@9OFEL$gVueRc1(UomFDX%kL70IfE&GqwRvsQ0^#)Tc9F`6$Uzzz4;8 zDaX>cf(MPe&>hRmofR0iRa-c-$=Gn$-787XW0%>=G_LKO7li3JrtwzZzjZKQZ9bMF zX|V}SV!Wt*lwqsf+VR*;J}qRQNc^?;67(qFxP}IuylLT7Ss6?=ei%H%6~F5`HkGCM zg|S9|M0`X{m)$h9hWXy#T$O7_`48+E&c2t#Lm zH62v9(Rr0H%fiDkbB}%bhGkGIo5331OjzBR3^TWu{{qbKrF0DaD<*IS;9 z6^*5&z42ECtOR)vTgJ)7c_Lbwi!PSSikmgp&@-+ahetg>i<7ww-e!Ema?T~n?v%6< z<2N4T`Kw#gXofmeMtCjH!&!74PF1?YUQfug>izb`>YQ3lUggt<#1g53rv+M_uB%WS z+{Z&JjMgpdbEO@&_Hmi5oe4p}ghMvu=27+)NS2hP051dW5$C!w6R;x|yH&KI3%cIG%a0 zav+H0uUsX74!wEYgvh#>y5bZchwp^4*G*M*gU^>P;$Az5Ei`u=k<`SW`${z#%jjfD zU#)!@Kg!L}Z$M%j5Q)03wRSeFqDdG_wZf?;|9o3()=tptz{TehmTIJW|1SG=xPPk- znRpJQm*JC$zPrdvt&w)E*WK~A)DFYjCS}TI+`Yl2Hn0{MYBnZh*NHst9TW~rkkKd+ z5v3cO=h|XK&j}P>3cCYI+Mjm6dngh|VwyzwbB+k|y6f%B^mq<38_70)O2RL#o)M0= z21{eiB7O>|5F-u?B*^r-4k240x^7S47zdx(#cdnOHOpD*b3sAZzuYIs1W>2{F1A4WYFP$f| z0MjEA2WcUq$|-1jE9KC)%$T|QorS+O+p{19gGfN=$&8F(TlxXNPBq4<4Z*BdJOcWn z-YxpU+)zZqv!+~0niYQ;^{N*-?Y&i~&#HEdnu$`Gvyc#QxpjxbGl^n$F+C@x99Ug3 zA;jP&a*;yUOpYMq^s?5<=F`p8x-6e-v?kX{?z)fK;txE2`2aM(??X{!Oduc5oRH+N zv~6SkZ$%n9-9;KQGvOe+6GJIPxk-jyQ}5i@rZYUPuUOPSmT{CD%4D92|9CMK*jR+x z6;d{0*1W3~ZJna1`8m#YH|9fD_F%bKx1JVL+M%9fsRwT$MsreqFdSIditioT(` z@;L3BiZfJdv4NDTEC=cK7YVm8{Xhs#*f1@;vgGPE%XgDZ~rZ7Ci!fRk{2yxlV9AscAB&q->=_&CE>&k&atf2%W1U z7v2mD7_IJWudq3!m%k{wLI)j_{y{MPrjjOe9wDau1-cq!uCyUc36X`kUkJ-zH5q}X%Fs7LKqtDjstfrk@PTY&O={++ z*B1N)i`gU7(P$X(=Tuk$jZ4Dg6Y_4`D>6EhXr<9`Qjmt8^0*@wCd;(M0?%;n($W*^&e4I`8EZ- zbBBEWUkt9Dh~?dpYj2gf7kl1pph>h{S7FzD#YlcM$1NLXi!yoVk9YEs*We3^mJQNe zIC>j5J3CISV~d|YWLM)=^E+K*F9O1_w`8mwU!--60&xf$zxKKgXplTevCLk;s(VzJ z(bt1{k2e(WW*5!lPVCf*-nl7a{p4_d$9e?X2_xlxkjvvg$7~XN$%JbDu?e1Vlq$D5 zo8XeVXq4PWSwTVPqsbpoi;xl_0qpJjh8d6D%!)V-3Pb;Qs1n0o$7tptlk3+j+WHk{ z)=S2%9-BK7N};`tFuim3Vl=1)>?kYGOO2;qG5*F9GKFKX9&o*D{Dxl=X_9T&e>caz zHhXeL^|(|nU~NtVPf}e~9>c0-?94D>9WX_zly@Y^m;*3 zC&H@%ZL-4x{`zl=^Bntu(E%wA{xSa=C17F!4B|#wjcZZ`7XaN zIsbKvjCnoHepV_CjKib6oNuwqEnIk!Ojg4Bn@At!A40HfC15TP!u9ijkim3PGJh~U z5II0KfcCWs`6n%S6U?VEZqq07xCdzgrViguFHSU-fL)bJZOSy|(<{q@o8NP)c>-sqqE=fuj`3xwPX7+2=rgT0Dc z)D!$O8;ZQCS1FVD-&i!jwaPt1Q>j4sUsondf{YjN$X|PUhp%oB#XNUG&1iS)GCL}C z2Nz9w@Kw%f_OHV?45*vVyuNs1X90uh#X@HTZ)a9k909pf7K!U0wuYyPYk~a#5AfVC zN}xA@cXOSHVDNGnVchIDo5x>6h#%yEwJm>ZPRJM^!+3g_KNszvbAxysS zc+wlOc9A`r-&p0$^6x48{U@2f@SDR--=pf$z=w0OL^tQNlWxq$$ViksK%Gc@Kgthb zYT3<=wu>OKNad^AW496X-%8q7N6m@9?2~%OxiOxfx=<8_z&Qn*!{(-z+qj2|29V! z%F;?@>zUj_Q}ty^@9W$htp9wl{$mY)rlj{O7A0;dk0ld~M7l8j;7&Zq`sO$#gsT%@d zK7gn)fCmyP({aDWD)D9+)|Tc9caf~`Q2hkBy95w=#d=ux|M5Bg`Zl{0S+aSHfcbIi zOLG*`bc+*Anz5S-!u$ZM?qt>T$kg3wPt&%pr^fA|50gh#)?s(C2dw~Xm84li{=OFo zdSRk!UV7(Wtp6Bz4myEms7wb3(Dyw0kLDkOsPh{4uRokNX_+?ae}oo)6luISh(4RF zPaphcS5NsQyPYbD8{TsOP^Mg_=cdc%OSD{R_V2If)`unrX=F;i(;@w@tKCBGA%2{* zyXgDv60>A>nwB1HT(>lw7QJWO<-z`NuEtBKo%hZ555GsvV*FLoy{$bJZk&vjA@y^O zNTu(tXqu6-o$d$rsuipPYVH{df@Q5g6A%}Ap69rLxn_>R?mtRpy{<3&4^@Z~}0<4jaPYSNxLY72#s z@ft@8UZyNh9$ciCCtXQ|M#bP@RoO{VZ^#Pr$J}MG{6_MJ6gslgG^Qw(%CJtfKW7WN z4tspSY$*6*wkPE2;yVa&pfrcVg2?`ZvxZTYb#9A^ab6oh=Wptc|MZ;yf?ZjUkoL5| zq%FF9T`v5QHWU*q$yQ*dBfc@4A-B;CD#+xZS4g9|aG?#F=tclHcU<;L8ZhjufVJ3f zC$XrUKL$<`P97c*O&STheU~!D;XD_}_ty2aK<2oqB$q4yIb$!Ys(7 zdi35TY|s)(rxES1eZE-zaH~myOH(S<47d@kW`va!(3}r-O+`6YIA{3m7kdD9H5TJq zWmkZ!@Q3=_DRpJdYo3kRxVAJtve*w^vt&9=9yC=BOP~+VOCvAmn-8|G5IVAM{o#;; zzI-w!6K3&b6nv~8H1@<|&O6 z+>$%9+=HGqwY1>3+TpD)F^7Ccf$H7m@Stfs{!p&_5>m(tXg8}|!{A$L^AQ!H|Ok5 z(JP~-T^VRMZB`^hwN6Hod-3@8Aa)MTp4TV3>E8clt%^hh7GFjBMXAy6tZMe5iv3Sd zr5Wt*+iIgvcSVC>v$3_3^-!Nr1XwLq#}=X`l>IJ6yKl{xy1{#^R^E=a7jmK!>cK&gZe;h z4{k{^{DotB9vsu5rCm(snRSPH!wSX%y4~c6*EdG1LJoJ4hs4a9+P|MGI5;lWse%tb z&(3%}l(9;3^s3!0+DQLCemy)ka&guIOu5y&)Tfa>sZ%+9n=c)X>K6enBrhl62f-+F z61Op1^R9kXf# zrpvbwCZVLY?=|d&rnOt<4I32S_{>ZjyyBY^%~_xv@~K~^=gtJ=-xzJrok3(3s9NN3 z0$fEk4p+QtQetLp?Z%WUJ$SG2<1KB4^uuj4g&{$6`{pyq1bm`-JC4;+anJOSYUT(# ztE<^vVf3dKCgz@3e>SQ%U7FwBwdk{1>?lN*Y_3dmP4bA;0zBwG0J+yvTo?gkBFi+Y z6?i;Ne*B~l(5;PV^*J6NusfMOtCr`|>Z{x*w==8UZ+Lw61LBqgr3a1Bh_YMA``P)}=ZB2;+} zQ3O;>CSD$Y8RsVGUyze4dB{wkMP=MH%5ME(%#ktMpo*$I_o1fMBNdprQ#4|h<*GMG zCmmaOT%e1+QWDX)pqCuQPJwF4*rd$01QXiv5VOWG>oS9kh`)>!d5~ZC7F_2gag&ni za46s$(tYzaj`Y48!LsnxHwEu{G3SgN+V}Td2B$gqtY@h+g_&K=f6U#9@ay4fE~@l$ z$hVg(@DRxQQiF9^W`HrPa&{>@O0OTbi@5F+S{Ce?;queZvzaMeeQ3&M#ZI8woIsj2 z@!4(HpVDpqQ=g(Wi>6%LA8fUrmj?slTtf4B!mHj&#zQER?r{9bcfIDCd9g0Hrb&pTlc;FYfpOCWh0mGm*@oG;+ zXE1>C1N^mZXL7$D4^yqORsrrTZcQ(Ie7Q2QDwt84pm$FI@Hv?9cXZ;3*Eaw_nF_IzjT{j^4&c=8knO!SeqJa{jU=N9do0vp@Y)RkjT$Uo$B1k z$_SF}PZWp0jhI*eY;*6u-dlYJ))r{nOlfyM(weVqJKdj;==v67A((mDeE;jq$BB^R zlGhdu?7mmqlJ=3ANtW|=FJvt$%fF8(EY;d(YMlQvm<6g#2N%B{Gfus3EuihMyMH3Z zmAW+6J(I zCR*ihfxyzTFvBB_#Q$QP8<+}q=-mt6`X8<6ddI)Dq6utfT3MvOkaGQZ1Xirc0PW`C z6BA&`Wr#TkaxZiRU}gPPmM{ZOLjJfIiX{NE_5b%{{>Qfpw15yaV=&my@BQ492KRDq zG+^e5ANyV32ITs08K~Pio9NDdEbsbftQ55D<*;Q!Plwk&+utqcqm3?do8L?QH#TP- z^HbQN1 z!7uk+MaX4&AS>Th=w-#@oZRshvgi3;5}W>yH;w`DbM9-@Yp*Bnq0M~M1DO8w+4{EBxK3D@s*n*7vVzu?_bdK_zw;VmRdn1d0DB8R* z)5oS^VFDr}vZ}#nvuC2#RE%)cdaiVL8W$)y-9mo_2B0gz{p~n#2S8XI0lBKLdUA*Y zIO5aFA6QTbmJwOz@T(!fY~TRkvuY09#tIz0qKUEXbNRZ{OYxOUiMZ_}h&P{hMh}71 zYc*(Wqc09Hsd|_JgS8py9+;JW8OPiUuXXFJ&8Pf&;wb}OqlV9%0E7w{YI^VcC zClq`YbJ_NyBx!Lc@CMjx0*ogX%q8HNWz$JCQrXxDHc+;v0nDiT=Y#>}Z8j4?MF)&B zxNzVcvwyh!rl*jn&GM`9KQJY;{dw?>5KwHO;hqfcJe;vUvj5!2{e4qK_1C??fqf0> zc(85RFDVuOdhCDf>wY-Mp$>Wjx%Gr5qt}-tu-k}8n7+T*o zG~-v|LU(hcnbe#S6wiXRXse#g(}g|)wF*b*x|%RhEx|wl^wc{O{&|Ikg&1r&h=5@G z4}!;>IiY^7g(97}wzf70Vc3)KR{xWzv@~F4S`7pa_Ca{ECKL#{k`5HKF8>X03^W(t z(~1&azptb?`>)3yQ|gl|%eXV;e_Ob*-KV8(3m^Djvg&^yB~>4umiB#r(2eiPVHigtL4$38`ABAKOBXCL<=4`1OECV zI)RA%iKZ=7YxR^_uWq0nI4JSG5Dtjo5aOA#`PTsxTiG)T7rTG|_`iQqN8%;cXH-7` zOymL3yypPby(wS^TOEc*I6oS2$+2LS7gGipn$7?YwY&R~zK;N4c>b_)#o@_V7;u># zp3yNyUjTsl<$;e64FE)7M{pStjbOIPdE?+_C#&&0hvj@9v7?>7eSOj)K)#;I77O{Y z&@-oe5sk-5#BG;aUO%IExg+w(cZ+?DEmQXkxK3-}gs5x-uD>F7>}C?MQMFxZZ#%3V z6>b2a1oLu?ESPC>Hcbbt*cCDGS9t-# z421KS>iJf^-}!Oi$dnR zMU!zO^wfwb+D6{yS5=*?3m-zz4;EcV>jB(&qt?yXm7(h}mj~F;bM7eui0_am#0Jdl zcnrzu0mHN3ZGe&KLfigYAK(N*s7>31C<4oiAV*!MtG62Ost?dc^O`0Ba_&s~+F@>y z@|z9$MVMrVWKb?pJDeA?0^OetErq1)?zBp0Pas@;a0G07kE)=7zQD$friY!6imV*9 z919ckI%Sgp{3dU(ekNIuP-U@5vL$_Wr5v`3Y1C8vvAb4MEe5dD7gr=;Fh#XoB^fnq zCnn@nUnidlSz2AdQ_e8t3)T0(H>0OGW!)};Y5^ped>^+Babfk-UPqiVIqShyc3aX7 z1VC(aKyp@$cYs2h32@_8Edd6&M^Jzj z?k1*+$mW+lX}Jo7Q*J{ZvmcQ>-xm0-_&~}lxE25aO}&B>`%%FC1Ky8m#jM~gDg*}E z)lgies*Xq4alx|(IHWhLdQl?Rt0704?xA|@rM*zVGywpT+eqoAb9x>bv^>>U0k{Y& z#P&i%r&Afxq_XW&PaRDjMwePLbHLhhUqe6pN)c6ZUo4c=;|CCpTmqLh3#`wkL!a9S zL(w_#yh`&pD`yQYDPN$~9S+iF9Rz2MZ?#I3Gs6S-OucQ8q3li0L($KPbsa`oQD{&F z#f9sVJ5Z#_0lhe$ER1WZ7=!izk>ZagCRJLh3K?E<1RQ!Sp7$yaOyb|;)LDDyXugfP zJE8uaExKU$NaaUC*RHPPKl9`{)MxA0%c{=Kw3y1kF zsM|<^RjbfHdIFM6CFBC@5_ow~I|?E&dIICw4i?x?xhoTX^r0+As{t(Wtg7XmFE<)B z34IYw@xRbdF^^S_GQ!JZdu@J`J^-F#SGX>~y>J2W-8J;AFDYU0{ESY_?PfT{3fiRv z`>5@Ffsbt0+&%jpp;rl^h#6sZZ&?69EVdqPa~A2%rW5e>{O8O|&=$}-L)G2g%H#6X znf{F$Pe8rV-LPZ8MsStqihrY)JN;2WU3Ej-Nf(--lct1&3gNxg?~Xm3u}9l_Zk5WH z=whlU^he%`FjbWNA+`!DIP`?PwYrPEoC1E2gWZZ@sFUWBjyp+?ExP-tf*f$?%E>yt zL8dY$SNcM(#6+pohG&_+8Qm`;4xfE`s8*k^Cq<7>1gQY*wHq$yZCgY)0PoKQE)%0RN|++#h&$&R>X4sVQtcr!P(dLn=Ftf(dO%ia%KJ4SISW0vwT%;i)cl*$sl* zpQ05LEG-8nfaRR?F-&A172xbFw1`#)XAAev#WhSzEdj;f9ldXRIkWq8LMoTK@#^dRHez@To=sE=0{-UO zal4*~G@5a{g*xO?%zXH6n)1pqjL8{w3Z`%n0j|F4__IPJ3b`k~iEqrqMhd-E$;W4j z>j(XTJFA@`hG=&d!)eW0wau}Ul|zj1NetO+Lesf=J5hbpF$o%&3O{(q4G974JDNOt z|3-&0rl~({HO0Jx0jt#g9{T=r=i!QXhYK13-oOvKh9@$y0IbH3(58kI&t?cqR5jNAiac{RsEX+4t}*h2X?+wXzVwqWnY_8n=W> z;uODx$1fxTGl*!e^?DQNeSj~*5e<11X}rV9w2+pvf1a#qz+Pk}DDwd@11fp#s}8YJ z!;d*02V8}AX}nh;0-Vc*ea{Dz?h%zQToDZu{hT;`1rS9af%`KpxD9YlcO~nei{qYp z;QG~~_o;-doW_!ZLInk$2(>FqAN3P~Jn*oUyB{si844EJ`d#)|gXmPhYIHkDPST{? zt%uL62;~rHw)f`4r|~-`a@K{x1MUDLx=XLNTD;YsO|HDV0f`3b8D7v?rP<=VsDGpB z|ML(}bX+2r_wKa6tU3TsV|qA~l&&~k1SO~rW!GmpuHbzhaDhIJ_jFVy4wow9<-WhZU@M;&E6t@tg8MM5WE;@B}FY> zvgy)|%$_2-vypDF4`_Wg+i`P&@G*GEnChBBaJFwOBW z-2`KTP{tHL>zNiw1AZMTpzQG+1{LQiRcT$oVBH|U4zLFSWp6My zF0O;B_WP_u6iRDMWRr9&R>K<9$GRKWzcd(4>X66@W32~7-fyHx_oK(ulKJP;7~cZ? z&Wv+-<{J5B%CEd|kB`PdgS%1^InOoUsVgf_+Z%OC1t#P;b8=-Cz?VFAXzYP(+l7$6 zCr@e?nIB3jcg`l&3Z}<+Dl*fV_nbAic-QqBDmNl zKPUO;lbwTsVGc2RMg&obctW8S4kfhi^Fz$lO6jeXEG8M+-@8hoDlC!h1_v{osSl|@ z#0&lWLUj7GIHoDIQ3q4Z%{aTGpZ^#iZ~E4!ibxR@*aVzSOI$(Wmuf<}wm8$cs0AfQ zV?W@+aNNZyNQ5QGb>Rd2K2B4o)#-NI6^(ZSeM2%|z*K7SXNhfjeKHKV2@UsuO+zl? z0`K!$j8&`DpcF(qO{v|#Uz^9 zUDW`EfEjQ#dtH3ZW`Vv+7u&Z<<-&p|ZzjU1#joAEsehS1N$ zrItqD)DjBcsgj{bA#f=?1(A<5ruYRxA#_g1F7 zW1VV0l-I^CL==Wxv~UO19=6&InE9r^cG1>f&n%JxcEO%PgD!}o?pYO}F3d=9qvJ}N z{ZvU^;eqPl-?frEQ{y4__v?5Yk3ecLqi^_aF6l&cS~-vs?cyFRb{ z@yyE2Kps&vNh4*q;5}T-LB)m7FXumO{Y{_xK#&Uk9V%3i&7vVm^giFTtniHk`^`RF z`3?l$*z(%G))?)O*4Gd?yb$2(LHz5V-x_E^MZ3YYH)j<{J4{sC~XFG4re|>`E>QsKrA+n%r$}!R%uQ&x-o<_yEa;hdI2+3KWDn>P>i-IIL zulM3aF+~!m(iyeY?z{St?{@;yM}_bHutq`CSl_FFt3QiF)!LuO)hf0hm;Bt4Cr!|v zP<1VX(qylOz+>O4+A=8$X3xCxsVSjZ_qi?U>`?}KoxK4B7F6T{Tb)K6q=wF$qodi%PL;F2?)a@jO?LFt8I>dvCMjV3Pet zigE`3bPVFIZ$y!Ai%*4BDq0M5FCjpiVFtETnFZ53Xf1dcAlUFkSVvRH5?-=D(6`$s z42;Wxc!&(jxM2nuE*W2MRsxRHOajGM5qh6{6{k>~w`MVdZgI!DvCvlt6;VC*{iaU> z_Fq)ukx1}@94@~G-u~fvagLk)9?S~$&v_+g*hd*PE#Dl=Gs4~6UWk)|{j9u4O<$?M z_2Cwh9>7T-5C4p3(J3UoN+RjAp5}E_-%8c)_BN2;uz0xzl%aLR2S?8-yTL5m*T;X- z2hdnN>gH&>w+I1QslgcRWPjniHG0lSxps{*7CLj0 zoA&fAjg3F78B#tGhCSlmWCCE z&yOR7_~_)F{+@tWj+<)DYV3C! zMjRy%jmaA5S&>fk#Jd3(C=EDv(;}By!5NBJ@xFA|1xuC&z?+ez1nQ(6zk-D%?(Ve1 z$#{%{clmFYQ;6Oc*)xgXvF02779QbUFbkBXepGr^7cXBK8*8ZiKGS>qHCRo)bHqTF zIg8UYmw|9tuWWAI|JhV!Wwm&8O!Zd(i;D%k5)D63b&-d#m4dNSmSiR28?&oKodtTV z`5cLeAL)3dZhoRvEyS7aWj|n>i+pI=*oT`3IxK_mX{pmQj&{rs*W`u9r2fnrgo&W6-K$g5pfQB0 z7D>Z3F7Iy^`iB$wL+l6-_fzig+d=QM_M`{F%s!PJSHM({tLdY4>o1_M&@EInZRxBR znCt^oKx9%wMGq0D#>6qX68)ZW-j=5g41lr6x0;vlAn3;0n|g(d=2IwJQPslm^@IcN z%&VqI<9FE1laf||d1cW;F==uMW9v5VtX=J}LJS!IlxzQqMC+dPI}&?}h9GByx!x#h zn|XwL{BZIl^O+TqTy?Uy3Rop(IDaM{WIez$+2XMg5;=bQjz^&NkK*e?Y|1Gsa>XA`-qlzYLea1wg(8+3y-Ut8NRUxMvMZgeVHvqIqJ=af<7P5MJIa-)sn=}qd3OvK z?LW@bZu7oUWl^YregV60f@-k;F}&l&*zBSWdPPS!5hZO4wp6<#SYgygwE}|v_>~e= zL8CUQB1A;cpVd7+TDzi7YZiSX01su%UZ&jdEcS&L;*FtMVGx|plgAXszn@~~3iwU> zAkHk2bl?4L_iB3U&czg={ehl`Ajg!Y(CEzjOKr>ww_>F`;gM2;+z0P*opjWI{Q?P& zDgrqoG!1%whr+Cr%_MCjXF|NWg;MIm7t~r1%oy6VjQgfH<69-7_n>@(lik5MJumv} z;!njEam;x4Q|)-Os%Og4i>yF(2vtp4CNVe3>IdxpBB_;JJ07iXObS_ zQy}$?lVXDOV~H;cy7^s8P&Gh>xj zaj>ynFKu_Pibf)p(|Urvls-FGi%O67)~RR_#&q7xBuf4cu6|~$>||dxHxld;5Bso|AN@K03+MOH!soY@3HjfTS#r__8bE)+LxIB+~?g$Cf0NeF_+~9uJ<6X_fWbuZOzC# zHx|E5>+wg28|%RzJQE>bdUF8uK^*#t%C3OQoFUCX4tYTz7>F8L7JbIqxTc|oNip!q zsDjrh5`IcoLB3bsGo?{~A z>W+Vy*HaEcqDGfmqZOSv=D*?!8f^7GHz4P_#nVdoR*Vmd?|5~Bi?L_YtNdkEi|!SWxc?7v%4Hi%u`_@sPg!|!gva#z^ur{ z?Uf^$p&}D8id7^6CuE?J_k787ckT0t6m|UpsYpPpFB!Vq?F&>Jg>OPr$)ur0nW_w& zYsLCG1dsnwQdCEa>T%Rdiqv9Nx>t4iG$bXO)IF_jd>D*0pA-BU6>B7wty`1#wlX(4 z7uC+~c-g<$bOJZ+sVh3=qRzt$JY0sOGzzJ!7ET&Nao^rbv(#tkMF9C)P%MpNS`&*c zh+H*VC5EDifD|?KR&+p3;LCk(g5Jir+h0;{22}$#N98mUW7np_#e=PBvy20|A4)+@ z3|~urs~LWjjv>5?t~cgm@H%juy0-+XIg)ToWxJ1MBbe0gijy}#$qPv- zci;E0iU1^Zm)O%Q0L?r5l|o{%x#V0QPSw8fT+CgpKbFK0O-*DZMKANI(ir@I+B?&D zsMoiFk10zWr3IZvO&euPCuiL)#Ud-+HyZ7t9=DNPueWiJ2Qb?oJhB3EiU)3>B4;7r` z&S0G{Gz@X2_n;j5zh>w7&*Rm2O)@xKnO<}Z_mon_G2IJ9?UCtsbP*byIjY^+1YKhPp4JPQZjA+j;6N~@1FqHZK`O!Sno zo=)U6*c}=ar#tNr(=YTCmaawIlq%jPLoja*DS+oVK+AF1D z(?=wZ2T@|FhAO@e7|p~(Cklf~???ZRQNDV6kxj&m30X1)Q=fRQ(m#wDAWS!{QnKQ( z(jJ&2dKIh)2&(Z)*p94a4}`>(Y_2fo3>PyTp*hk4KWwqvX6OaTSd$z*$uQo~Zc0bp z&q`e+-P;|tH>9cLLz{*Zxw)hzcKpM+%r(I=2vZR==GAzhcHj@iQ^DP>Z z-OaZM9eOs!j~r6m4qY0fpDbJbDfl_KT&By@%h) z&Yt&5@KnO7JCx-4np~J1(-?V3RX$e@e-bnUeo~2szlPgsC?9rZ8ss)D_f_ovt8Enc zS{z5%fUzef#XTtCsi#$GQV0E5XL8z zj(bj|p?we!+X|zEC(G{(TxX<9eL~UgRM}%9ck=xKP9LgVUKsT^#J=M7wPkdPZs(DA zd@h%oJ8(UIvI#+9(rhB`OmF$4svaDqP0zJoGj?L?kE5-Xu_}@-1IJR|YQUj8CofQ6 z7tsdJbBak+GqS4A1SGJ_M7PSFA2btb7f{o>ETa5wcdF_ATx5>C-skbW?>2;Si_XIp zHkgDHN1L@>1T-s7Z!i)`v&{eenby`Rj8Vo`e=bg7OKVS=Zo~}Y_n%8(jq_|uM6<-tc@}7= zHJ{(JdRJ8hr+oxM@qX5=vD1GFV)X!}e`nME_>%{dxc%w&bX{-T&|j58pci=#Lt;l; zhPwcz!UP<$|Kkr{7kVk+s<47oR+t~lYP-jw7omeXajP#y|8|l7_q9p|&`_oW_T7;# z|9%g6t+p6&8MpEN@jJ+g^Y4E+Y|I434@V=;s{gWd0lHmD$E@-?*DoH0_&WkGZIIEI zQNCZ6wsCMlkl5Xk=l)$QsOt^)VaWg5Xo$pu>LnI%(d@rp&Zg%Fu`0Ns+3?HK3&jwo zrmYTdj{4RNZ;r(Gm2`M(N&j<8ZSCQoWUv30(E3T(anwlL?ZgPK0p4-{{Qc^{#cl@muD+TTlF)nBd+Ii51-b2de z5jE5YOu5~gJ3BhkbxtgbyHEGA*X|Au*;Jp8YvTXYfykOTpRxKPJd0Dnv zE&LF@t<%)Y4&7IfLvk1#F!dN_&cDRelKkRr$jvzHVy5UCNRE_YZ`WZZN3eP6*|IZo z6mK?mI8Qlh`v3?&Tdpq9&tQfjA)1dw{_v#n`DP4jc0iN0o zlD(OuP_ix8Q{IM*^?o=z-uvN}^v#{K@5-ja*GCAM8P;%u&4MK~p;|=t0sHp``42H? zoZ+QvWVPKMhio>P>!gYKw^VTuO!KbG67K!nJt-{T*3#GO^B#1L^Jhc&7-E8bRf(vu z99CQrd|Dj?K~^ZAy}L1EySWB@aNhdJZy$T5;OZE0gNzDvWb`IqYh zXsalKP`hRK z9MuZ{BO9=61oLyR6@FNYg?@FgM=#7Gv!4eRRpf&u%3!EhVe%d?5i7G5wNuI#nx^jk z7&34SzHUs>#7zevYBQgblzIgpQjWG7#pvRSvx+iDRSFjH<>Zkd`k$tyS$b1_g}H#3 zvX03{tgp;Hp|a!d@ZdvueXK%CmOialo?(4vac)7#f|yY)=HmTog@=*SRm!&OGy@hl z#v9D=ss^3cLiYksWI{Pb&NY@{M7A>)n|=e-E34Nx9da?JzcCKcSQ4L)@3N7^Nu#^lVx#}yv6|DZr#Dnv zpvl=G(z!S5opZy4(-@F#Y=8{ADTAy{$vMf*XJSWcHx@oyua?DgpZ&dRB;}^GZC4XX zSAP7N%M>6E^N*+mbpfh%w+XRh#=UsuTC2zN7by-UM&@%qHb{dSDWslZwV{N)c1?zT zd{8?|>eJF*4b#%D`}zHDap(jY?? ztWzM2B?snE)U2>Ft77C(ykJ`sB?t)QZHvApM2GRZ7>h>5^&;Wh6HG;b9kIU)CGA8B zw@~CeCVV`?H>BOdF<=V#=Jb(~zJ;-t@Nc%K_?}5J4PS~oJBL(!krHE8CxmH_=!A*i z3>Cz8B&e`5vb>rMslyg&osDV__$DbFjli}`a-{Xcz!m^a(*0Qvy%Z&Py@R!MZ^o4nY7{!s<2C%>fPAZpCDHF7R!_<}zO05$ZYAcS(BiE&t5W zC&E>S)LM>oUF>8Y0Zj>igvAeO^65-Ifu#(hy#g|w2M`rO%MOwyiE6258kdVE4lQSZRx z@v_|@2_54QRvLoJEew>1_~T|?#vnXellU=cGi-djZBzO-q7!1fWUcH(UCn`I$F{U9 zjO3z)WvRG8Bj(iFkrZlGd~MB_4+183%`0+sK1<0nz){U?}ej!7+ z_ft|34}zVf0CQ^3xyR;H0_e+>i+}Bdpa_~svI`*H3Qv8CeTxN2QtRSyASYpp07SxV zO20L<>*AltGm!`4ds7`Q21_`H7vJXeiQXPX(ng_<5ljst|Kcviq}gDcuLa<0)CwcH z4}wr2dl>W5czvAZ+<0TY(@0ezejV`A5BV#yH`E?2L1-X+PVdiCGME2x1WtKbIT)Sx z^*3?udrY2PzVSLt+Pb6b^6%nx6ncE9c|w)UGdcGx&i$v$vH(imdTFM4^qq=v-i5s_ zA{VK9ia@gZo`AZ{DF%HUcg3qZwfa_mZ%SP6jnZj{6MZh0Da$LbJ~p2guU)c^85&15yUR66ZaR1!L0OiG`N>wI`^-QJ zy`6b!G*Z)zc6u2Uv`~hkYW_V;vFqXvY${+7&ZXR30Sd__~2?8i$JToVcf$ zm61|Rq+B^+BtN5OR5UbMCzIGJjubI6LM73O8DIT%+Z}ILjweKIYr73)R(cl>cPJsq zN5UT;eJA^4evUJYlg_n4$H2uNjQR0r->si-VkGzFjpFfdR&h51{0@xhl-D!T97^?A zCB=>aaqVCSGGaQ3%9FH8h0~WEa0*z4bk9QdNp>2KM4wp2Ng9z}4I@0eXOrPp%!kZS zx7)=<5#mH8q~hcy8+u;~680LH`0ZZQHL=_El1a}IUMb?aqZ@jg5>P8yw41K){oWp6 zdgW=VR9#(O%m+s>xY`MJQ&Ztbiu1-!Z@Et?o_OXMkS;90 zW1~VL#*loBKB)d+QyfR}pZ1)$>U^;X0BU!CEoPN=p*#@X@txw&vu*{6p6%^}7D2#R zR~RqVeHH}BEa#s!8?O^oSoUn-G`On-Wp3jfU{#u2dtL_p@bHI zj6iKyUzTMWud9ez|Y+kv|!app5xMHXmWg!nR;P zLsf!gURC8m5U)bA?QT){HgOEylV^>cdN8xO*gu|B;%NGKw?6Af7k-?}hhv~1?8JR! zkUEh;AkcyD``A)UUE+tdjeZ(|;q1O{`$OVx45{_riGkwR#URL}qXg@v)48aC{gx~m zGRpeBk^bh)6HvHqbEMOz$oN}(Z@f|1q;$WA)D!wzaN)8jb&l`)FvLDYeUue|ir*4gx+GRWF~ literal 0 HcmV?d00001 diff --git a/_freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg b/_freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg new file mode 100644 index 0000000..b868388 --- /dev/null +++ b/_freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg @@ -0,0 +1,1103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg b/_freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg new file mode 100644 index 0000000..fcef859 --- /dev/null +++ b/_freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg @@ -0,0 +1,1103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_freeze/site_libs/crosstalk-1.2.0/css/crosstalk.min.css b/_freeze/site_libs/crosstalk-1.2.0/css/crosstalk.min.css new file mode 100644 index 0000000..6b45382 --- /dev/null +++ b/_freeze/site_libs/crosstalk-1.2.0/css/crosstalk.min.css @@ -0,0 +1 @@ +.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js b/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js new file mode 100644 index 0000000..fd9eb53 --- /dev/null +++ b/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js @@ -0,0 +1,1474 @@ +(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) { + return 1; + } +} + +/** + * @private + */ + +var FilterSet = function () { + function FilterSet() { + _classCallCheck(this, FilterSet); + + this.reset(); + } + + _createClass(FilterSet, [{ + key: "reset", + value: function reset() { + // Key: handle ID, Value: array of selected keys, or null + this._handles = {}; + // Key: key string, Value: count of handles that include it + this._keys = {}; + this._value = null; + this._activeHandles = 0; + } + }, { + key: "update", + value: function update(handleId, keys) { + if (keys !== null) { + keys = keys.slice(0); // clone before sorting + keys.sort(naturalComparator); + } + + var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys), + added = _diffSortedLists.added, + removed = _diffSortedLists.removed; + + this._handles[handleId] = keys; + + for (var i = 0; i < added.length; i++) { + this._keys[added[i]] = (this._keys[added[i]] || 0) + 1; + } + for (var _i = 0; _i < removed.length; _i++) { + this._keys[removed[_i]]--; + } + + this._updateValue(keys); + } + + /** + * @param {string[]} keys Sorted array of strings that indicate + * a superset of possible keys. + * @private + */ + + }, { + key: "_updateValue", + value: function _updateValue() { + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys; + + var handleCount = Object.keys(this._handles).length; + if (handleCount === 0) { + this._value = null; + } else { + this._value = []; + for (var i = 0; i < keys.length; i++) { + var count = this._keys[keys[i]]; + if (count === handleCount) { + this._value.push(keys[i]); + } + } + } + } + }, { + key: "clear", + value: function clear(handleId) { + if (typeof this._handles[handleId] === "undefined") { + return; + } + + var keys = this._handles[handleId]; + if (!keys) { + keys = []; + } + + for (var i = 0; i < keys.length; i++) { + this._keys[keys[i]]--; + } + delete this._handles[handleId]; + + this._updateValue(); + } + }, { + key: "value", + get: function get() { + return this._value; + } + }, { + key: "_allKeys", + get: function get() { + var allKeys = Object.keys(this._keys); + allKeys.sort(naturalComparator); + return allKeys; + } + }]); + + return FilterSet; +}(); + +exports.default = FilterSet; + +},{"./util":11}],4:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.default = group; + +var _var2 = require("./var"); + +var _var3 = _interopRequireDefault(_var2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// Use a global so that multiple copies of crosstalk.js can be loaded and still +// have groups behave as singletons across all copies. +global.__crosstalk_groups = global.__crosstalk_groups || {}; +var groups = global.__crosstalk_groups; + +function group(groupName) { + if (groupName && typeof groupName === "string") { + if (!groups.hasOwnProperty(groupName)) { + groups[groupName] = new Group(groupName); + } + return groups[groupName]; + } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) { + // Appears to already be a group object + return groupName; + } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") { + return group(groupName[0]); + } else { + throw new Error("Invalid groupName argument"); + } +} + +var Group = function () { + function Group(name) { + _classCallCheck(this, Group); + + this.name = name; + this._vars = {}; + } + + _createClass(Group, [{ + key: "var", + value: function _var(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name); + return this._vars[name]; + } + }, { + key: "has", + value: function has(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + return this._vars.hasOwnProperty(name); + } + }]); + + return Group; +}(); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./var":12}],5:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _selection = require("./selection"); + +var _filter = require("./filter"); + +var _input = require("./input"); + +require("./input_selectize"); + +require("./input_checkboxgroup"); + +require("./input_slider"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var defaultGroup = (0, _group2.default)("default"); + +function var_(name) { + return defaultGroup.var(name); +} + +function has(name) { + return defaultGroup.has(name); +} + +if (global.Shiny) { + global.Shiny.addCustomMessageHandler("update-client-value", function (message) { + if (typeof message.group === "string") { + (0, _group2.default)(message.group).var(message.name).set(message.value); + } else { + var_(message.name).set(message.value); + } + }); +} + +var crosstalk = { + group: _group2.default, + var: var_, + has: has, + SelectionHandle: _selection.SelectionHandle, + FilterHandle: _filter.FilterHandle, + bind: _input.bind +}; + +/** + * @namespace crosstalk + */ +exports.default = crosstalk; + +global.crosstalk = crosstalk; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.register = register; +exports.bind = bind; +var $ = global.jQuery; + +var bindings = {}; + +function register(reg) { + bindings[reg.className] = reg; + if (global.document && global.document.readyState !== "complete") { + $(function () { + bind(); + }); + } else if (global.document) { + setTimeout(bind, 100); + } +} + +function bind() { + Object.keys(bindings).forEach(function (className) { + var binding = bindings[className]; + $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) { + bindInstance(binding, el); + }); + }); +} + +// Escape jQuery identifier +function $escape(val) { + return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1"); +} + +function bindEl(el) { + var $el = $(el); + Object.keys(bindings).forEach(function (className) { + if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) { + var binding = bindings[className]; + bindInstance(binding, el); + } + }); +} + +function bindInstance(binding, el) { + var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']"); + var data = JSON.parse(jsonEl[0].innerText); + + var instance = binding.factory(el, data); + $(el).data("crosstalk-instance", instance); + $(el).addClass("crosstalk-input-bound"); +} + +if (global.Shiny) { + var inputBinding = new global.Shiny.InputBinding(); + var _$ = global.jQuery; + _$.extend(inputBinding, { + find: function find(scope) { + return _$(scope).find(".crosstalk-input"); + }, + initialize: function initialize(el) { + if (!_$(el).hasClass("crosstalk-input-bound")) { + bindEl(el); + } + }, + getId: function getId(el) { + return el.id; + }, + getValue: function getValue(el) {}, + setValue: function setValue(el, value) {}, + receiveMessage: function receiveMessage(el, data) {}, + subscribe: function subscribe(el, callback) { + _$(el).data("crosstalk-instance").resume(); + }, + unsubscribe: function unsubscribe(el) { + _$(el).data("crosstalk-instance").suspend(); + } + }); + global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding"); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],7:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-checkboxgroup", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + var $el = $(el); + $el.on("change", "input[type='checkbox']", function () { + var checked = $el.find("input[type='checkbox']:checked"); + if (checked.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + checked.each(function () { + data.map[this.value].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],8:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-select", + + factory: function factory(el, data) { + /* + * items: {value: [...], label: [...]} + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + + var first = [{ value: "", label: "(All)" }]; + var items = util.dataframeToD3(data.items); + var opts = { + options: first.concat(items), + valueField: "value", + labelField: "label", + searchField: "label" + }; + + var select = $(el).find("select")[0]; + + var selectize = $(select).selectize(opts)[0].selectize; + + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + selectize.on("change", function () { + if (selectize.items.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + selectize.items.forEach(function (group) { + data.map[group].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; +var strftime = global.strftime; + +input.register({ + className: "crosstalk-input-slider", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var opts = {}; + var $el = $(el).find("input"); + var dataType = $el.data("data-type"); + var timeFormat = $el.data("time-format"); + var round = $el.data("round"); + var timeFormatter = void 0; + + // Set up formatting functions + if (dataType === "date") { + timeFormatter = strftime.utc(); + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "datetime") { + var timezone = $el.data("timezone"); + if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime; + + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "number") { + if (typeof round !== "undefined") opts.prettify = function (num) { + var factor = Math.pow(10, round); + return Math.round(num * factor) / factor; + }; + } + + $el.ionRangeSlider(opts); + + function getValue() { + var result = $el.data("ionRangeSlider").result; + + // Function for converting numeric value from slider to appropriate type. + var convert = void 0; + var dataType = $el.data("data-type"); + if (dataType === "date") { + convert = function convert(val) { + return formatDateUTC(new Date(+val)); + }; + } else if (dataType === "datetime") { + convert = function convert(val) { + // Convert ms to s + return +val / 1000; + }; + } else { + convert = function convert(val) { + return +val; + }; + } + + if ($el.data("ionRangeSlider").options.type === "double") { + return [convert(result.from), convert(result.to)]; + } else { + return convert(result.from); + } + } + + var lastKnownKeys = null; + + $el.on("change.crosstalkSliderInput", function (event) { + if (!$el.data("updating") && !$el.data("animating")) { + var _getValue = getValue(), + _getValue2 = _slicedToArray(_getValue, 2), + from = _getValue2[0], + to = _getValue2[1]; + + var keys = []; + for (var i = 0; i < data.values.length; i++) { + var val = data.values[i]; + if (val >= from && val <= to) { + keys.push(data.keys[i]); + } + } + keys.sort(); + ctHandle.set(keys); + lastKnownKeys = keys; + } + }); + + // let $el = $(el); + // $el.on("change", "input[type="checkbox"]", function() { + // let checked = $el.find("input[type="checkbox"]:checked"); + // if (checked.length === 0) { + // ctHandle.clear(); + // } else { + // let keys = {}; + // checked.each(function() { + // data.map[this.value].forEach(function(key) { + // keys[key] = true; + // }); + // }); + // let keyArray = Object.keys(keys); + // keyArray.sort(); + // ctHandle.set(keyArray); + // } + // }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +// Convert a number to a string with leading zeros +function padZeros(n, digits) { + var str = n.toString(); + while (str.length < digits) { + str = "0" + str; + }return str; +} + +// Given a Date object, return a string in yyyy-mm-dd format, using the +// UTC date. This may be a day off from the date in the local time zone. +function formatDateUTC(date) { + if (date instanceof Date) { + return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2); + } else { + return null; + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SelectionHandle = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Use this class to read and write (and listen for changes to) the selection + * for a Crosstalk group. This is intended to be used for linked brushing. + * + * If two (or more) `SelectionHandle` instances in the same webpage share the + * same group name, they will share the same state. Setting the selection using + * one `SelectionHandle` instance will result in the `value` property instantly + * changing across the others, and `"change"` event listeners on all instances + * (including the one that initiated the sending) will fire. + * + * @param {string} [group] - The name of the Crosstalk group, or if none, + * null or undefined (or any other falsy value). This can be changed later + * via the [SelectionHandle#setGroup](#setGroup) method. + * @param {Object} [extraInfo] - An object whose properties will be copied to + * the event object whenever an event is emitted. + */ +var SelectionHandle = exports.SelectionHandle = function () { + function SelectionHandle() { + var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, SelectionHandle); + + this._eventRelay = new _events2.default(); + this._emitter = new util.SubscriptionTracker(this._eventRelay); + + // Name of the group we're currently tracking, if any. Can change over time. + this._group = null; + // The Var we're currently tracking, if any. Can change over time. + this._var = null; + // The event handler subscription we currently have on var.on("change"). + this._varOnChangeSub = null; + + this._extraInfo = util.extend({ sender: this }, extraInfo); + + this.setGroup(group); + } + + /** + * Changes the Crosstalk group membership of this SelectionHandle. The group + * being switched away from (if any) will not have its selection value + * modified as a result of calling `setGroup`, even if this handle was the + * most recent handle to set the selection of the group. + * + * The group being switched to (if any) will also not have its selection value + * modified as a result of calling `setGroup`. If you want to set the + * selection value of the new group, call `set` explicitly. + * + * @param {string} group - The name of the Crosstalk group, or null (or + * undefined) to clear the group. + */ + + + _createClass(SelectionHandle, [{ + key: "setGroup", + value: function setGroup(group) { + var _this = this; + + // If group is unchanged, do nothing + if (this._group === group) return; + // Treat null, undefined, and other falsy values the same + if (!this._group && !group) return; + + if (this._var) { + this._var.off("change", this._varOnChangeSub); + this._var = null; + this._varOnChangeSub = null; + } + + this._group = group; + + if (group) { + this._var = (0, _group2.default)(group).var("selection"); + var sub = this._var.on("change", function (e) { + _this._eventRelay.trigger("change", e, _this); + }); + this._varOnChangeSub = sub; + } + } + + /** + * Retrieves the current selection for the group represented by this + * `SelectionHandle`. + * + * - If no selection is active, then this value will be falsy. + * - If a selection is active, but no data points are selected, then this + * value will be an empty array. + * - If a selection is active, and data points are selected, then the keys + * of the selected data points will be present in the array. + */ + + }, { + key: "_mergeExtraInfo", + + + /** + * Combines the given `extraInfo` (if any) with the handle's default + * `_extraInfo` (if any). + * @private + */ + value: function _mergeExtraInfo(extraInfo) { + // Important incidental effect: shallow clone is returned + return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see + * {@link SelectionHandle#value}). + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any options that were + * passed into the `SelectionHandle` constructor). + */ + + }, { + key: "set", + value: function set(selectedKeys, extraInfo) { + if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo)); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any that were passed + * into the `SelectionHandle` constructor). + */ + + }, { + key: "clear", + value: function clear(extraInfo) { + if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo)); + } + + /** + * Subscribes to events on this `SelectionHandle`. + * + * @param {string} eventType - Indicates the type of events to listen to. + * Currently, only `"change"` is supported. + * @param {SelectionHandle~listener} listener - The callback function that + * will be invoked when the event occurs. + * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel + * this subscription. + */ + + }, { + key: "on", + value: function on(eventType, listener) { + return this._emitter.on(eventType, listener); + } + + /** + * Cancels event subscriptions created by {@link SelectionHandle#on}. + * + * @param {string} eventType - The type of event to unsubscribe. + * @param {string|SelectionHandle~listener} listener - Either the callback + * function previously passed into {@link SelectionHandle#on}, or the + * string that was returned from {@link SelectionHandle#on}. + */ + + }, { + key: "off", + value: function off(eventType, listener) { + return this._emitter.off(eventType, listener); + } + + /** + * Shuts down the `SelectionHandle` object. + * + * Removes all event listeners that were added through this handle. + */ + + }, { + key: "close", + value: function close() { + this._emitter.removeAllListeners(); + this.setGroup(null); + } + }, { + key: "value", + get: function get() { + return this._var ? this._var.get() : null; + } + }]); + + return SelectionHandle; +}(); + +/** + * @callback SelectionHandle~listener + * @param {Object} event - An object containing details of the event. For + * `"change"` events, this includes the properties `value` (the new + * value of the selection, or `undefined` if no selection is active), + * `oldValue` (the previous value of the selection), and `sender` (the + * `SelectionHandle` instance that made the change). + */ + +/** + * @event SelectionHandle#change + * @type {object} + * @property {object} value - The new value of the selection, or `undefined` + * if no selection is active. + * @property {object} oldValue - The previous value of the selection. + * @property {SelectionHandle} sender - The `SelectionHandle` instance that + * changed the value. + */ + +},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extend = extend; +exports.checkSorted = checkSorted; +exports.diffSortedLists = diffSortedLists; +exports.dataframeToD3 = dataframeToD3; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function extend(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var src = sources[i]; + if (typeof src === "undefined" || src === null) continue; + + for (var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + } + return target; +} + +function checkSorted(list) { + for (var i = 1; i < list.length; i++) { + if (list[i] <= list[i - 1]) { + throw new Error("List is not sorted or contains duplicate"); + } + } +} + +function diffSortedLists(a, b) { + var i_a = 0; + var i_b = 0; + + if (!a) a = []; + if (!b) b = []; + + var a_only = []; + var b_only = []; + + checkSorted(a); + checkSorted(b); + + while (i_a < a.length && i_b < b.length) { + if (a[i_a] === b[i_b]) { + i_a++; + i_b++; + } else if (a[i_a] < b[i_b]) { + a_only.push(a[i_a++]); + } else { + b_only.push(b[i_b++]); + } + } + + if (i_a < a.length) a_only = a_only.concat(a.slice(i_a)); + if (i_b < b.length) b_only = b_only.concat(b.slice(i_b)); + return { + removed: a_only, + added: b_only + }; +} + +// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... } +// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ] +function dataframeToD3(df) { + var names = []; + var length = void 0; + for (var name in df) { + if (df.hasOwnProperty(name)) names.push(name); + if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof length !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item = void 0; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; +} + +/** + * Keeps track of all event listener additions/removals and lets all active + * listeners be removed with a single operation. + * + * @private + */ + +var SubscriptionTracker = exports.SubscriptionTracker = function () { + function SubscriptionTracker(emitter) { + _classCallCheck(this, SubscriptionTracker); + + this._emitter = emitter; + this._subs = {}; + } + + _createClass(SubscriptionTracker, [{ + key: "on", + value: function on(eventType, listener) { + var sub = this._emitter.on(eventType, listener); + this._subs[sub] = eventType; + return sub; + } + }, { + key: "off", + value: function off(eventType, listener) { + var sub = this._emitter.off(eventType, listener); + if (sub) { + delete this._subs[sub]; + } + return sub; + } + }, { + key: "removeAllListeners", + value: function removeAllListeners() { + var _this = this; + + var current_subs = this._subs; + this._subs = {}; + Object.keys(current_subs).forEach(function (sub) { + _this._emitter.off(current_subs[sub], sub); + }); + } + }]); + + return SubscriptionTracker; +}(); + +},{}],12:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Var = function () { + function Var(group, name, /*optional*/value) { + _classCallCheck(this, Var); + + this._group = group; + this._name = name; + this._value = value; + this._events = new _events2.default(); + } + + _createClass(Var, [{ + key: "get", + value: function get() { + return this._value; + } + }, { + key: "set", + value: function set(value, /*optional*/event) { + if (this._value === value) { + // Do nothing; the value hasn't changed + return; + } + var oldValue = this._value; + this._value = value; + // Alert JavaScript listeners that the value has changed + var evt = {}; + if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") { + for (var k in event) { + if (event.hasOwnProperty(k)) evt[k] = event[k]; + } + } + evt.oldValue = oldValue; + evt.value = value; + this._events.trigger("change", evt, this); + + // TODO: Make this extensible, to let arbitrary back-ends know that + // something has changed + if (global.Shiny && global.Shiny.onInputChange) { + global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value); + } + } + }, { + key: "on", + value: function on(eventType, listener) { + return this._events.on(eventType, listener); + } + }, { + key: "off", + value: function off(eventType, listener) { + return this._events.off(eventType, listener); + } + }]); + + return Var; +}(); + +exports.default = Var; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./events":1}]},{},[5]) +//# sourceMappingURL=crosstalk.js.map diff --git a/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js.map b/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js.map new file mode 100644 index 0000000..cff94f0 --- /dev/null +++ b/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.js.map @@ -0,0 +1,37 @@ +{ + "version": 3, + "sources": [ + "node_modules/browser-pack/_prelude.js", + "javascript/src/events.js", + "javascript/src/filter.js", + "javascript/src/filterset.js", + "javascript/src/group.js", + "javascript/src/index.js", + "javascript/src/input.js", + "javascript/src/input_checkboxgroup.js", + "javascript/src/input_selectize.js", + "javascript/src/input_slider.js", + "javascript/src/selection.js", + "javascript/src/util.js", + "javascript/src/var.js" + ], + "names": [], + "mappings": "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", + "file": "generated.js", + "sourceRoot": "", + "sourcesContent": [ + "(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n", + "import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n", + "import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n", + "import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n", + "let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n", + "import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n", + "export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n", + "import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n" + ] +} \ No newline at end of file diff --git a/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.min.js b/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.min.js new file mode 100644 index 0000000..b7ec0ac --- /dev/null +++ b/_freeze/site_libs/crosstalk-1.2.0/js/crosstalk.min.js @@ -0,0 +1,2 @@ +!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]} \ No newline at end of file diff --git a/_freeze/site_libs/crosstalk-1.2.0/scss/crosstalk.scss b/_freeze/site_libs/crosstalk-1.2.0/scss/crosstalk.scss new file mode 100644 index 0000000..3566561 --- /dev/null +++ b/_freeze/site_libs/crosstalk-1.2.0/scss/crosstalk.scss @@ -0,0 +1,75 @@ +/* Adjust margins outwards, so column contents line up with the edges of the + parent of container-fluid. */ +.container-fluid.crosstalk-bscols { + margin-left: -30px; + margin-right: -30px; + white-space: normal; +} + +/* But don't adjust the margins outwards if we're directly under the body, + i.e. we were the top-level of something at the console. */ +body > .container-fluid.crosstalk-bscols { + margin-left: auto; + margin-right: auto; +} + +.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: inline-block; + padding-right: 12px; + vertical-align: top; +} + +@media only screen and (max-width:480px) { + .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: block; + padding-right: inherit; + } +} + +/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ +.crosstalk-input { + margin-bottom: 15px; /* a la .form-group */ + .control-label { + margin-bottom: 0; + vertical-align: middle; + } + input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px; + line-height: normal; + } + .checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + } + .checkbox > label{ + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + cursor: pointer; + } + .checkbox input[type="checkbox"], + .checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 2px; + margin-left: -20px; + } + .checkbox + .checkbox { + margin-top: -5px; + } + .checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + vertical-align: middle; + cursor: pointer; + } + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; + } +} diff --git a/_freeze/site_libs/htmlwidgets-1.6.2/htmlwidgets.js b/_freeze/site_libs/htmlwidgets-1.6.2/htmlwidgets.js new file mode 100644 index 0000000..1067d02 --- /dev/null +++ b/_freeze/site_libs/htmlwidgets-1.6.2/htmlwidgets.js @@ -0,0 +1,901 @@ +(function() { + // If window.HTMLWidgets is already defined, then use it; otherwise create a + // new object. This allows preceding code to set options that affect the + // initialization process (though none currently exist). + window.HTMLWidgets = window.HTMLWidgets || {}; + + // See if we're running in a viewer pane. If not, we're in a web browser. + var viewerMode = window.HTMLWidgets.viewerMode = + /\bviewer_pane=1\b/.test(window.location); + + // See if we're running in Shiny mode. If not, it's a static document. + // Note that static widgets can appear in both Shiny and static modes, but + // obviously, Shiny widgets can only appear in Shiny apps/documents. + var shinyMode = window.HTMLWidgets.shinyMode = + typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings; + + // We can't count on jQuery being available, so we implement our own + // version if necessary. + function querySelectorAll(scope, selector) { + if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) { + return scope.find(selector); + } + if (scope.querySelectorAll) { + return scope.querySelectorAll(selector); + } + } + + function asArray(value) { + if (value === null) + return []; + if ($.isArray(value)) + return value; + return [value]; + } + + // Implement jQuery's extend + function extend(target /*, ... */) { + if (arguments.length == 1) { + return target; + } + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + } + return target; + } + + // IE8 doesn't support Array.forEach. + function forEach(values, callback, thisArg) { + if (values.forEach) { + values.forEach(callback, thisArg); + } else { + for (var i = 0; i < values.length; i++) { + callback.call(thisArg, values[i], i, values); + } + } + } + + // Replaces the specified method with the return value of funcSource. + // + // Note that funcSource should not BE the new method, it should be a function + // that RETURNS the new method. funcSource receives a single argument that is + // the overridden method, it can be called from the new method. The overridden + // method can be called like a regular function, it has the target permanently + // bound to it so "this" will work correctly. + function overrideMethod(target, methodName, funcSource) { + var superFunc = target[methodName] || function() {}; + var superFuncBound = function() { + return superFunc.apply(target, arguments); + }; + target[methodName] = funcSource(superFuncBound); + } + + // Add a method to delegator that, when invoked, calls + // delegatee.methodName. If there is no such method on + // the delegatee, but there was one on delegator before + // delegateMethod was called, then the original version + // is invoked instead. + // For example: + // + // var a = { + // method1: function() { console.log('a1'); } + // method2: function() { console.log('a2'); } + // }; + // var b = { + // method1: function() { console.log('b1'); } + // }; + // delegateMethod(a, b, "method1"); + // delegateMethod(a, b, "method2"); + // a.method1(); + // a.method2(); + // + // The output would be "b1", "a2". + function delegateMethod(delegator, delegatee, methodName) { + var inherited = delegator[methodName]; + delegator[methodName] = function() { + var target = delegatee; + var method = delegatee[methodName]; + + // The method doesn't exist on the delegatee. Instead, + // call the method on the delegator, if it exists. + if (!method) { + target = delegator; + method = inherited; + } + + if (method) { + return method.apply(target, arguments); + } + }; + } + + // Implement a vague facsimilie of jQuery's data method + function elementData(el, name, value) { + if (arguments.length == 2) { + return el["htmlwidget_data_" + name]; + } else if (arguments.length == 3) { + el["htmlwidget_data_" + name] = value; + return el; + } else { + throw new Error("Wrong number of arguments for elementData: " + + arguments.length); + } + } + + // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex + function escapeRegExp(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + } + + function hasClass(el, className) { + var re = new RegExp("\\b" + escapeRegExp(className) + "\\b"); + return re.test(el.className); + } + + // elements - array (or array-like object) of HTML elements + // className - class name to test for + // include - if true, only return elements with given className; + // if false, only return elements *without* given className + function filterByClass(elements, className, include) { + var results = []; + for (var i = 0; i < elements.length; i++) { + if (hasClass(elements[i], className) == include) + results.push(elements[i]); + } + return results; + } + + function on(obj, eventName, func) { + if (obj.addEventListener) { + obj.addEventListener(eventName, func, false); + } else if (obj.attachEvent) { + obj.attachEvent(eventName, func); + } + } + + function off(obj, eventName, func) { + if (obj.removeEventListener) + obj.removeEventListener(eventName, func, false); + else if (obj.detachEvent) { + obj.detachEvent(eventName, func); + } + } + + // Translate array of values to top/right/bottom/left, as usual with + // the "padding" CSS property + // https://developer.mozilla.org/en-US/docs/Web/CSS/padding + function unpackPadding(value) { + if (typeof(value) === "number") + value = [value]; + if (value.length === 1) { + return {top: value[0], right: value[0], bottom: value[0], left: value[0]}; + } + if (value.length === 2) { + return {top: value[0], right: value[1], bottom: value[0], left: value[1]}; + } + if (value.length === 3) { + return {top: value[0], right: value[1], bottom: value[2], left: value[1]}; + } + if (value.length === 4) { + return {top: value[0], right: value[1], bottom: value[2], left: value[3]}; + } + } + + // Convert an unpacked padding object to a CSS value + function paddingToCss(paddingObj) { + return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px"; + } + + // Makes a number suitable for CSS + function px(x) { + if (typeof(x) === "number") + return x + "px"; + else + return x; + } + + // Retrieves runtime widget sizing information for an element. + // The return value is either null, or an object with fill, padding, + // defaultWidth, defaultHeight fields. + function sizingPolicy(el) { + var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']"); + if (!sizingEl) + return null; + var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}"); + if (viewerMode) { + return sp.viewer; + } else { + return sp.browser; + } + } + + // @param tasks Array of strings (or falsy value, in which case no-op). + // Each element must be a valid JavaScript expression that yields a + // function. Or, can be an array of objects with "code" and "data" + // properties; in this case, the "code" property should be a string + // of JS that's an expr that yields a function, and "data" should be + // an object that will be added as an additional argument when that + // function is called. + // @param target The object that will be "this" for each function + // execution. + // @param args Array of arguments to be passed to the functions. (The + // same arguments will be passed to all functions.) + function evalAndRun(tasks, target, args) { + if (tasks) { + forEach(tasks, function(task) { + var theseArgs = args; + if (typeof(task) === "object") { + theseArgs = theseArgs.concat([task.data]); + task = task.code; + } + var taskFunc = tryEval(task); + if (typeof(taskFunc) !== "function") { + throw new Error("Task must be a function! Source:\n" + task); + } + taskFunc.apply(target, theseArgs); + }); + } + } + + // Attempt eval() both with and without enclosing in parentheses. + // Note that enclosing coerces a function declaration into + // an expression that eval() can parse + // (otherwise, a SyntaxError is thrown) + function tryEval(code) { + var result = null; + try { + result = eval("(" + code + ")"); + } catch(error) { + if (!(error instanceof SyntaxError)) { + throw error; + } + try { + result = eval(code); + } catch(e) { + if (e instanceof SyntaxError) { + throw error; + } else { + throw e; + } + } + } + return result; + } + + function initSizing(el) { + var sizing = sizingPolicy(el); + if (!sizing) + return; + + var cel = document.getElementById("htmlwidget_container"); + if (!cel) + return; + + if (typeof(sizing.padding) !== "undefined") { + document.body.style.margin = "0"; + document.body.style.padding = paddingToCss(unpackPadding(sizing.padding)); + } + + if (sizing.fill) { + document.body.style.overflow = "hidden"; + document.body.style.width = "100%"; + document.body.style.height = "100%"; + document.documentElement.style.width = "100%"; + document.documentElement.style.height = "100%"; + cel.style.position = "absolute"; + var pad = unpackPadding(sizing.padding); + cel.style.top = pad.top + "px"; + cel.style.right = pad.right + "px"; + cel.style.bottom = pad.bottom + "px"; + cel.style.left = pad.left + "px"; + el.style.width = "100%"; + el.style.height = "100%"; + + return { + getWidth: function() { return cel.getBoundingClientRect().width; }, + getHeight: function() { return cel.getBoundingClientRect().height; } + }; + + } else { + el.style.width = px(sizing.width); + el.style.height = px(sizing.height); + + return { + getWidth: function() { return cel.getBoundingClientRect().width; }, + getHeight: function() { return cel.getBoundingClientRect().height; } + }; + } + } + + // Default implementations for methods + var defaults = { + find: function(scope) { + return querySelectorAll(scope, "." + this.name); + }, + renderError: function(el, err) { + var $el = $(el); + + this.clearError(el); + + // Add all these error classes, as Shiny does + var errClass = "shiny-output-error"; + if (err.type !== null) { + // use the classes of the error condition as CSS class names + errClass = errClass + " " + $.map(asArray(err.type), function(type) { + return errClass + "-" + type; + }).join(" "); + } + errClass = errClass + " htmlwidgets-error"; + + // Is el inline or block? If inline or inline-block, just display:none it + // and add an inline error. + var display = $el.css("display"); + $el.data("restore-display-mode", display); + + if (display === "inline" || display === "inline-block") { + $el.hide(); + if (err.message !== "") { + var errorSpan = $("").addClass(errClass); + errorSpan.text(err.message); + $el.after(errorSpan); + } + } else if (display === "block") { + // If block, add an error just after the el, set visibility:none on the + // el, and position the error to be on top of the el. + // Mark it with a unique ID and CSS class so we can remove it later. + $el.css("visibility", "hidden"); + if (err.message !== "") { + var errorDiv = $("

    ").addClass(errClass).css("position", "absolute") + .css("top", el.offsetTop) + .css("left", el.offsetLeft) + // setting width can push out the page size, forcing otherwise + // unnecessary scrollbars to appear and making it impossible for + // the element to shrink; so use max-width instead + .css("maxWidth", el.offsetWidth) + .css("height", el.offsetHeight); + errorDiv.text(err.message); + $el.after(errorDiv); + + // Really dumb way to keep the size/position of the error in sync with + // the parent element as the window is resized or whatever. + var intId = setInterval(function() { + if (!errorDiv[0].parentElement) { + clearInterval(intId); + return; + } + errorDiv + .css("top", el.offsetTop) + .css("left", el.offsetLeft) + .css("maxWidth", el.offsetWidth) + .css("height", el.offsetHeight); + }, 500); + } + } + }, + clearError: function(el) { + var $el = $(el); + var display = $el.data("restore-display-mode"); + $el.data("restore-display-mode", null); + + if (display === "inline" || display === "inline-block") { + if (display) + $el.css("display", display); + $(el.nextSibling).filter(".htmlwidgets-error").remove(); + } else if (display === "block"){ + $el.css("visibility", "inherit"); + $(el.nextSibling).filter(".htmlwidgets-error").remove(); + } + }, + sizing: {} + }; + + // Called by widget bindings to register a new type of widget. The definition + // object can contain the following properties: + // - name (required) - A string indicating the binding name, which will be + // used by default as the CSS classname to look for. + // - initialize (optional) - A function(el) that will be called once per + // widget element; if a value is returned, it will be passed as the third + // value to renderValue. + // - renderValue (required) - A function(el, data, initValue) that will be + // called with data. Static contexts will cause this to be called once per + // element; Shiny apps will cause this to be called multiple times per + // element, as the data changes. + window.HTMLWidgets.widget = function(definition) { + if (!definition.name) { + throw new Error("Widget must have a name"); + } + if (!definition.type) { + throw new Error("Widget must have a type"); + } + // Currently we only support output widgets + if (definition.type !== "output") { + throw new Error("Unrecognized widget type '" + definition.type + "'"); + } + // TODO: Verify that .name is a valid CSS classname + + // Support new-style instance-bound definitions. Old-style class-bound + // definitions have one widget "object" per widget per type/class of + // widget; the renderValue and resize methods on such widget objects + // take el and instance arguments, because the widget object can't + // store them. New-style instance-bound definitions have one widget + // object per widget instance; the definition that's passed in doesn't + // provide renderValue or resize methods at all, just the single method + // factory(el, width, height) + // which returns an object that has renderValue(x) and resize(w, h). + // This enables a far more natural programming style for the widget + // author, who can store per-instance state using either OO-style + // instance fields or functional-style closure variables (I guess this + // is in contrast to what can only be called C-style pseudo-OO which is + // what we required before). + if (definition.factory) { + definition = createLegacyDefinitionAdapter(definition); + } + + if (!definition.renderValue) { + throw new Error("Widget must have a renderValue function"); + } + + // For static rendering (non-Shiny), use a simple widget registration + // scheme. We also use this scheme for Shiny apps/documents that also + // contain static widgets. + window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || []; + // Merge defaults into the definition; don't mutate the original definition. + var staticBinding = extend({}, defaults, definition); + overrideMethod(staticBinding, "find", function(superfunc) { + return function(scope) { + var results = superfunc(scope); + // Filter out Shiny outputs, we only want the static kind + return filterByClass(results, "html-widget-output", false); + }; + }); + window.HTMLWidgets.widgets.push(staticBinding); + + if (shinyMode) { + // Shiny is running. Register the definition with an output binding. + // The definition itself will not be the output binding, instead + // we will make an output binding object that delegates to the + // definition. This is because we foolishly used the same method + // name (renderValue) for htmlwidgets definition and Shiny bindings + // but they actually have quite different semantics (the Shiny + // bindings receive data that includes lots of metadata that it + // strips off before calling htmlwidgets renderValue). We can't + // just ignore the difference because in some widgets it's helpful + // to call this.renderValue() from inside of resize(), and if + // we're not delegating, then that call will go to the Shiny + // version instead of the htmlwidgets version. + + // Merge defaults with definition, without mutating either. + var bindingDef = extend({}, defaults, definition); + + // This object will be our actual Shiny binding. + var shinyBinding = new Shiny.OutputBinding(); + + // With a few exceptions, we'll want to simply use the bindingDef's + // version of methods if they are available, otherwise fall back to + // Shiny's defaults. NOTE: If Shiny's output bindings gain additional + // methods in the future, and we want them to be overrideable by + // HTMLWidget binding definitions, then we'll need to add them to this + // list. + delegateMethod(shinyBinding, bindingDef, "getId"); + delegateMethod(shinyBinding, bindingDef, "onValueChange"); + delegateMethod(shinyBinding, bindingDef, "onValueError"); + delegateMethod(shinyBinding, bindingDef, "renderError"); + delegateMethod(shinyBinding, bindingDef, "clearError"); + delegateMethod(shinyBinding, bindingDef, "showProgress"); + + // The find, renderValue, and resize are handled differently, because we + // want to actually decorate the behavior of the bindingDef methods. + + shinyBinding.find = function(scope) { + var results = bindingDef.find(scope); + + // Only return elements that are Shiny outputs, not static ones + var dynamicResults = results.filter(".html-widget-output"); + + // It's possible that whatever caused Shiny to think there might be + // new dynamic outputs, also caused there to be new static outputs. + // Since there might be lots of different htmlwidgets bindings, we + // schedule execution for later--no need to staticRender multiple + // times. + if (results.length !== dynamicResults.length) + scheduleStaticRender(); + + return dynamicResults; + }; + + // Wrap renderValue to handle initialization, which unfortunately isn't + // supported natively by Shiny at the time of this writing. + + shinyBinding.renderValue = function(el, data) { + Shiny.renderDependencies(data.deps); + // Resolve strings marked as javascript literals to objects + if (!(data.evals instanceof Array)) data.evals = [data.evals]; + for (var i = 0; data.evals && i < data.evals.length; i++) { + window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]); + } + if (!bindingDef.renderOnNullValue) { + if (data.x === null) { + el.style.visibility = "hidden"; + return; + } else { + el.style.visibility = "inherit"; + } + } + if (!elementData(el, "initialized")) { + initSizing(el); + + elementData(el, "initialized", true); + if (bindingDef.initialize) { + var rect = el.getBoundingClientRect(); + var result = bindingDef.initialize(el, rect.width, rect.height); + elementData(el, "init_result", result); + } + } + bindingDef.renderValue(el, data.x, elementData(el, "init_result")); + evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]); + }; + + // Only override resize if bindingDef implements it + if (bindingDef.resize) { + shinyBinding.resize = function(el, width, height) { + // Shiny can call resize before initialize/renderValue have been + // called, which doesn't make sense for widgets. + if (elementData(el, "initialized")) { + bindingDef.resize(el, width, height, elementData(el, "init_result")); + } + }; + } + + Shiny.outputBindings.register(shinyBinding, bindingDef.name); + } + }; + + var scheduleStaticRenderTimerId = null; + function scheduleStaticRender() { + if (!scheduleStaticRenderTimerId) { + scheduleStaticRenderTimerId = setTimeout(function() { + scheduleStaticRenderTimerId = null; + window.HTMLWidgets.staticRender(); + }, 1); + } + } + + // Render static widgets after the document finishes loading + // Statically render all elements that are of this widget's class + window.HTMLWidgets.staticRender = function() { + var bindings = window.HTMLWidgets.widgets || []; + forEach(bindings, function(binding) { + var matches = binding.find(document.documentElement); + forEach(matches, function(el) { + var sizeObj = initSizing(el, binding); + + var getSize = function(el) { + if (sizeObj) { + return {w: sizeObj.getWidth(), h: sizeObj.getHeight()} + } else { + var rect = el.getBoundingClientRect(); + return {w: rect.width, h: rect.height} + } + }; + + if (hasClass(el, "html-widget-static-bound")) + return; + el.className = el.className + " html-widget-static-bound"; + + var initResult; + if (binding.initialize) { + var size = getSize(el); + initResult = binding.initialize(el, size.w, size.h); + elementData(el, "init_result", initResult); + } + + if (binding.resize) { + var lastSize = getSize(el); + var resizeHandler = function(e) { + var size = getSize(el); + if (size.w === 0 && size.h === 0) + return; + if (size.w === lastSize.w && size.h === lastSize.h) + return; + lastSize = size; + binding.resize(el, size.w, size.h, initResult); + }; + + on(window, "resize", resizeHandler); + + // This is needed for cases where we're running in a Shiny + // app, but the widget itself is not a Shiny output, but + // rather a simple static widget. One example of this is + // an rmarkdown document that has runtime:shiny and widget + // that isn't in a render function. Shiny only knows to + // call resize handlers for Shiny outputs, not for static + // widgets, so we do it ourselves. + if (window.jQuery) { + window.jQuery(document).on( + "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets", + resizeHandler + ); + window.jQuery(document).on( + "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets", + resizeHandler + ); + } + + // This is needed for the specific case of ioslides, which + // flips slides between display:none and display:block. + // Ideally we would not have to have ioslide-specific code + // here, but rather have ioslides raise a generic event, + // but the rmarkdown package just went to CRAN so the + // window to getting that fixed may be long. + if (window.addEventListener) { + // It's OK to limit this to window.addEventListener + // browsers because ioslides itself only supports + // such browsers. + on(document, "slideenter", resizeHandler); + on(document, "slideleave", resizeHandler); + } + } + + var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']"); + if (scriptData) { + var data = JSON.parse(scriptData.textContent || scriptData.text); + // Resolve strings marked as javascript literals to objects + if (!(data.evals instanceof Array)) data.evals = [data.evals]; + for (var k = 0; data.evals && k < data.evals.length; k++) { + window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]); + } + binding.renderValue(el, data.x, initResult); + evalAndRun(data.jsHooks.render, initResult, [el, data.x]); + } + }); + }); + + invokePostRenderHandlers(); + } + + + function has_jQuery3() { + if (!window.jQuery) { + return false; + } + var $version = window.jQuery.fn.jquery; + var $major_version = parseInt($version.split(".")[0]); + return $major_version >= 3; + } + + /* + / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's + / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now + / really means $(setTimeout(fn)). + / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous + / + / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny + / one tick later than it did before, which means staticRender() is + / called renderValue() earlier than (advanced) widget authors might be expecting. + / https://github.com/rstudio/shiny/issues/2630 + / + / For a concrete example, leaflet has some methods (e.g., updateBounds) + / which reference Shiny methods registered in initShiny (e.g., setInputValue). + / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to + / delay execution of those methods (until Shiny methods are ready) + / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268 + / + / Ideally widget authors wouldn't need to use this setTimeout() hack that + / leaflet uses to call Shiny methods on a staticRender(). In the long run, + / the logic initShiny should be broken up so that method registration happens + / right away, but binding happens later. + */ + function maybeStaticRenderLater() { + if (shinyMode && has_jQuery3()) { + window.jQuery(window.HTMLWidgets.staticRender); + } else { + window.HTMLWidgets.staticRender(); + } + } + + if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", function() { + document.removeEventListener("DOMContentLoaded", arguments.callee, false); + maybeStaticRenderLater(); + }, false); + } else if (document.attachEvent) { + document.attachEvent("onreadystatechange", function() { + if (document.readyState === "complete") { + document.detachEvent("onreadystatechange", arguments.callee); + maybeStaticRenderLater(); + } + }); + } + + + window.HTMLWidgets.getAttachmentUrl = function(depname, key) { + // If no key, default to the first item + if (typeof(key) === "undefined") + key = 1; + + var link = document.getElementById(depname + "-" + key + "-attachment"); + if (!link) { + throw new Error("Attachment " + depname + "/" + key + " not found in document"); + } + return link.getAttribute("href"); + }; + + window.HTMLWidgets.dataframeToD3 = function(df) { + var names = []; + var length; + for (var name in df) { + if (df.hasOwnProperty(name)) + names.push(name); + if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof(length) !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; + }; + + window.HTMLWidgets.transposeArray2D = function(array) { + if (array.length === 0) return array; + var newArray = array[0].map(function(col, i) { + return array.map(function(row) { + return row[i] + }) + }); + return newArray; + }; + // Split value at splitChar, but allow splitChar to be escaped + // using escapeChar. Any other characters escaped by escapeChar + // will be included as usual (including escapeChar itself). + function splitWithEscape(value, splitChar, escapeChar) { + var results = []; + var escapeMode = false; + var currentResult = ""; + for (var pos = 0; pos < value.length; pos++) { + if (!escapeMode) { + if (value[pos] === splitChar) { + results.push(currentResult); + currentResult = ""; + } else if (value[pos] === escapeChar) { + escapeMode = true; + } else { + currentResult += value[pos]; + } + } else { + currentResult += value[pos]; + escapeMode = false; + } + } + if (currentResult !== "") { + results.push(currentResult); + } + return results; + } + // Function authored by Yihui/JJ Allaire + window.HTMLWidgets.evaluateStringMember = function(o, member) { + var parts = splitWithEscape(member, '.', '\\'); + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i]; + // part may be a character or 'numeric' member name + if (o !== null && typeof o === "object" && part in o) { + if (i == (l - 1)) { // if we are at the end of the line then evalulate + if (typeof o[part] === "string") + o[part] = tryEval(o[part]); + } else { // otherwise continue to next embedded object + o = o[part]; + } + } + } + }; + + // Retrieve the HTMLWidget instance (i.e. the return value of an + // HTMLWidget binding's initialize() or factory() function) + // associated with an element, or null if none. + window.HTMLWidgets.getInstance = function(el) { + return elementData(el, "init_result"); + }; + + // Finds the first element in the scope that matches the selector, + // and returns the HTMLWidget instance (i.e. the return value of + // an HTMLWidget binding's initialize() or factory() function) + // associated with that element, if any. If no element matches the + // selector, or the first matching element has no HTMLWidget + // instance associated with it, then null is returned. + // + // The scope argument is optional, and defaults to window.document. + window.HTMLWidgets.find = function(scope, selector) { + if (arguments.length == 1) { + selector = scope; + scope = document; + } + + var el = scope.querySelector(selector); + if (el === null) { + return null; + } else { + return window.HTMLWidgets.getInstance(el); + } + }; + + // Finds all elements in the scope that match the selector, and + // returns the HTMLWidget instances (i.e. the return values of + // an HTMLWidget binding's initialize() or factory() function) + // associated with the elements, in an array. If elements that + // match the selector don't have an associated HTMLWidget + // instance, the returned array will contain nulls. + // + // The scope argument is optional, and defaults to window.document. + window.HTMLWidgets.findAll = function(scope, selector) { + if (arguments.length == 1) { + selector = scope; + scope = document; + } + + var nodes = scope.querySelectorAll(selector); + var results = []; + for (var i = 0; i < nodes.length; i++) { + results.push(window.HTMLWidgets.getInstance(nodes[i])); + } + return results; + }; + + var postRenderHandlers = []; + function invokePostRenderHandlers() { + while (postRenderHandlers.length) { + var handler = postRenderHandlers.shift(); + if (handler) { + handler(); + } + } + } + + // Register the given callback function to be invoked after the + // next time static widgets are rendered. + window.HTMLWidgets.addPostRenderHandler = function(callback) { + postRenderHandlers.push(callback); + }; + + // Takes a new-style instance-bound definition, and returns an + // old-style class-bound definition. This saves us from having + // to rewrite all the logic in this file to accomodate both + // types of definitions. + function createLegacyDefinitionAdapter(defn) { + var result = { + name: defn.name, + type: defn.type, + initialize: function(el, width, height) { + return defn.factory(el, width, height); + }, + renderValue: function(el, x, instance) { + return instance.renderValue(x); + }, + resize: function(el, width, height, instance) { + return instance.resize(width, height); + } + }; + + if (defn.find) + result.find = defn.find; + if (defn.renderError) + result.renderError = defn.renderError; + if (defn.clearError) + result.clearError = defn.clearError; + + return result; + } +})(); diff --git a/_freeze/site_libs/jquery-3.5.1/jquery-AUTHORS.txt b/_freeze/site_libs/jquery-3.5.1/jquery-AUTHORS.txt new file mode 100644 index 0000000..06df1a5 --- /dev/null +++ b/_freeze/site_libs/jquery-3.5.1/jquery-AUTHORS.txt @@ -0,0 +1,357 @@ +Authors ordered by first contribution. + +John Resig +Gilles van den Hoven +Michael Geary +Stefan Petre +Yehuda Katz +Corey Jewett +Klaus Hartl +Franck Marcia +Jörn Zaefferer +Paul Bakaus +Brandon Aaron +Mike Alsup +Dave Methvin +Ed Engelhardt +Sean Catchpole +Paul Mclanahan +David Serduke +Richard D. Worth +Scott González +Ariel Flesler +Cheah Chu Yeow +Andrew Chalkley +Fabio Buffoni +Stefan Bauckmeier  +Jon Evans +TJ Holowaychuk +Riccardo De Agostini +Michael Bensoussan +Louis-Rémi Babé +Robert Katić +Damian Janowski +Anton Kovalyov +Dušan B. Jovanovic +Earle Castledine +Rich Dougherty +Kim Dalsgaard +Andrea Giammarchi +Fabian Jakobs +Mark Gibson +Karl Swedberg +Justin Meyer +Ben Alman +James Padolsey +David Petersen +Batiste Bieler +Jake Archibald +Alexander Farkas +Filipe Fortes +Rick Waldron +Neeraj Singh +Paul Irish +Iraê Carvalho +Matt Curry +Michael Monteleone +Noah Sloan +Tom Viner +J. Ryan Stinnett +Douglas Neiner +Adam J. Sontag +Heungsub Lee +Dave Reed +Carl Fürstenberg +Jacob Wright +Ralph Whitbeck +unknown +temp01 +Colin Snover +Jared Grippe +Ryan W Tenney +Alex Sexton +Pinhook +Ron Otten +Jephte Clain +Anton Matzneller +Dan Heberden +Henri Wiechers +Russell Holbrook +Julian Aubourg +Gianni Alessandro Chiappetta +Scott Jehl +James Burke +Jonas Pfenniger +Xavi Ramirez +Sylvester Keil +Brandon Sterne +Mathias Bynens +Lee Carpenter +Timmy Willison <4timmywil@gmail.com> +Corey Frang +Digitalxero +David Murdoch +Josh Varner +Charles McNulty +Jordan Boesch +Jess Thrysoee +Michael Murray +Alexis Abril +Rob Morgan +John Firebaugh +Sam Bisbee +Gilmore Davidson +Brian Brennan +Xavier Montillet +Daniel Pihlstrom +Sahab Yazdani +avaly +Scott Hughes +Mike Sherov +Greg Hazel +Schalk Neethling +Denis Knauf +Timo Tijhof +Steen Nielsen +Anton Ryzhov +Shi Chuan +Matt Mueller +Berker Peksag +Toby Brain +Justin +Daniel Herman +Oleg Gaidarenko +Rock Hymas +Richard Gibson +Rafaël Blais Masson +cmc3cn <59194618@qq.com> +Joe Presbrey +Sindre Sorhus +Arne de Bree +Vladislav Zarakovsky +Andrew E Monat +Oskari +Joao Henrique de Andrade Bruni +tsinha +Dominik D. Geyer +Matt Farmer +Trey Hunner +Jason Moon +Jeffery To +Kris Borchers +Vladimir Zhuravlev +Jacob Thornton +Chad Killingsworth +Vitya Muhachev +Nowres Rafid +David Benjamin +Alan Plum +Uri Gilad +Chris Faulkner +Marcel Greter +Elijah Manor +Daniel Chatfield +Daniel Gálvez +Nikita Govorov +Wesley Walser +Mike Pennisi +Matthias Jäggli +Devin Cooper +Markus Staab +Dave Riddle +Callum Macrae +Jonathan Sampson +Benjamin Truyman +Jay Merrifield +James Huston +Sai Lung Wong +Erick Ruiz de Chávez +David Bonner +Allen J Schmidt Jr +Akintayo Akinwunmi +MORGAN +Ismail Khair +Carl Danley +Mike Petrovich +Greg Lavallee +Tom H Fuertes +Roland Eckl +Yiming He +David Fox +Bennett Sorbo +Paul Ramos +Rod Vagg +Sebastian Burkhard +Zachary Adam Kaplan +Adam Coulombe +nanto_vi +nanto +Danil Somsikov +Ryunosuke SATO +Diego Tres +Jean Boussier +Andrew Plummer +Mark Raddatz +Pascal Borreli +Isaac Z. Schlueter +Karl Sieburg +Nguyen Phuc Lam +Dmitry Gusev +Steven Benner +Li Xudong +Michał Gołębiowski-Owczarek +Renato Oliveira dos Santos +Frederic Junod +Tom H Fuertes +Mitch Foley +ros3cin +Kyle Robinson Young +John Paul +Jason Bedard +Chris Talkington +Eddie Monge +Terry Jones +Jason Merino +Dan Burzo +Jeremy Dunck +Chris Price +Guy Bedford +njhamann +Goare Mao +Amey Sakhadeo +Mike Sidorov +Anthony Ryan +Lihan Li +George Kats +Dongseok Paeng +Ronny Springer +Ilya Kantor +Marian Sollmann +Chris Antaki +David Hong +Jakob Stoeck +Christopher Jones +Forbes Lindesay +S. Andrew Sheppard +Leonardo Balter +Rodrigo Rosenfeld Rosas +Daniel Husar +Philip Jägenstedt +John Hoven +Roman Reiß +Benjy Cui +Christian Kosmowski +David Corbacho +Liang Peng +TJ VanToll +Aurelio De Rosa +Senya Pugach +Dan Hart +Nazar Mokrynskyi +Benjamin Tan +Amit Merchant +Jason Bedard +Veaceslav Grimalschi +Richard McDaniel +Arthur Verschaeve +Shivaji Varma +Ben Toews +Bin Xin +Neftaly Hernandez +T.J. Crowder +Nicolas HENRY +Frederic Hemberger +Victor Homyakov +Aditya Raghavan +Anne-Gaelle Colom +Leonardo Braga +George Mauer +Stephen Edgar +Thomas Tortorini +Jörn Wagner +Jon Hester +Colin Frick +Winston Howes +Alexander O'Mara +Chris Rebert +Bastian Buchholz +Mu Haibao +Calvin Metcalf +Arthur Stolyar +Gabriel Schulhof +Gilad Peleg +Julian Alexander Murillo +Kevin Kirsche +Martin Naumann +Yongwoo Jeon +John-David Dalton +Marek Lewandowski +Bruno Pérel +Daniel Nill +Reed Loden +Sean Henderson +Gary Ye +Richard Kraaijenhagen +Connor Atherton +Christian Grete +Tom von Clef +Liza Ramo +Joelle Fleurantin +Steve Mao +Jon Dufresne +Jae Sung Park +Josh Soref +Saptak Sengupta +Henry Wong +Jun Sun +Martijn W. van der Lee +Devin Wilson +Damian Senn +Zack Hall +Vitaliy Terziev +Todor Prikumov +Bernhard M. Wiedemann +Jha Naman +Alexander Lisianoi +William Robinet +Joe Trumbull +Alexander K +Ralin Chimev +Felipe Sateler +Christophe Tafani-Dereeper +Manoj Kumar +David Broder-Rodgers +Alex Louden +Alex Padilla +karan-96 +南漂一卒 +Erik Lax +Boom Lee +Andreas Solleder +Pierre Spring +Shashanka Nataraj +CDAGaming +Matan Kotler-Berkowitz <205matan@gmail.com> +Jordan Beland +Henry Zhu +Nilton Cesar +basil.belokon +Andrey Meshkov +tmybr11 +Luis Emilio Velasco Sanchez +Ed S +Bert Zhang +Sébastien Règne +wartmanm <3869625+wartmanm@users.noreply.github.com> +Siddharth Dungarwal +abnud1 +Andrei Fangli +Marja Hölttä +buddh4 +Hoang +Wonseop Kim +Pat O'Callaghan +JuanMa Ruiz +Ahmed.S.ElAfifi +Sean Robinson +Christian Oliff diff --git a/_freeze/site_libs/jquery-3.5.1/jquery.js b/_freeze/site_libs/jquery-3.5.1/jquery.js new file mode 100644 index 0000000..5093733 --- /dev/null +++ b/_freeze/site_libs/jquery-3.5.1/jquery.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "\n```\n:::\n:::\n\nPretty cool for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, this checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", + "supporting": [], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": { + "include-in-header": [ + "\n\n\n\n\n\n\n\n" + ] + }, + "engineDependencies": {}, + "preserve": {}, + "postProcess": true + } +} \ No newline at end of file diff --git a/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap-icons.css b/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap-icons.css new file mode 100644 index 0000000..f51d04b --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap-icons.css @@ -0,0 +1,1704 @@ +@font-face { + font-family: "bootstrap-icons"; + src: +url("./bootstrap-icons.woff?524846017b983fc8ded9325d94ed40f3") format("woff"); +} + +.bi::before, +[class^="bi-"]::before, +[class*=" bi-"]::before { + display: inline-block; + font-family: bootstrap-icons !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -.125em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bi-123::before { content: "\f67f"; } +.bi-alarm-fill::before { content: "\f101"; } +.bi-alarm::before { content: "\f102"; } +.bi-align-bottom::before { content: "\f103"; } +.bi-align-center::before { content: "\f104"; } +.bi-align-end::before { content: "\f105"; } +.bi-align-middle::before { content: "\f106"; } +.bi-align-start::before { content: "\f107"; } +.bi-align-top::before { content: "\f108"; } +.bi-alt::before { content: "\f109"; } +.bi-app-indicator::before { content: "\f10a"; } +.bi-app::before { content: "\f10b"; } +.bi-archive-fill::before { content: "\f10c"; } +.bi-archive::before { content: "\f10d"; } +.bi-arrow-90deg-down::before { content: "\f10e"; } +.bi-arrow-90deg-left::before { content: "\f10f"; } +.bi-arrow-90deg-right::before { content: "\f110"; } +.bi-arrow-90deg-up::before { content: "\f111"; } +.bi-arrow-bar-down::before { content: "\f112"; } +.bi-arrow-bar-left::before { content: "\f113"; } +.bi-arrow-bar-right::before { content: "\f114"; } +.bi-arrow-bar-up::before { content: "\f115"; } +.bi-arrow-clockwise::before { content: "\f116"; } +.bi-arrow-counterclockwise::before { content: "\f117"; } +.bi-arrow-down-circle-fill::before { content: "\f118"; } +.bi-arrow-down-circle::before { content: "\f119"; } +.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } +.bi-arrow-down-left-circle::before { content: "\f11b"; } +.bi-arrow-down-left-square-fill::before { content: "\f11c"; } +.bi-arrow-down-left-square::before { content: "\f11d"; } +.bi-arrow-down-left::before { content: "\f11e"; } +.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } +.bi-arrow-down-right-circle::before { content: "\f120"; } +.bi-arrow-down-right-square-fill::before { content: "\f121"; } +.bi-arrow-down-right-square::before { content: "\f122"; } +.bi-arrow-down-right::before { content: "\f123"; } +.bi-arrow-down-short::before { content: "\f124"; } +.bi-arrow-down-square-fill::before { content: "\f125"; } +.bi-arrow-down-square::before { content: "\f126"; } +.bi-arrow-down-up::before { content: "\f127"; } +.bi-arrow-down::before { content: "\f128"; } +.bi-arrow-left-circle-fill::before { content: "\f129"; } +.bi-arrow-left-circle::before { content: "\f12a"; } +.bi-arrow-left-right::before { content: "\f12b"; } +.bi-arrow-left-short::before { content: "\f12c"; } +.bi-arrow-left-square-fill::before { content: "\f12d"; } +.bi-arrow-left-square::before { content: "\f12e"; } +.bi-arrow-left::before { content: "\f12f"; } +.bi-arrow-repeat::before { content: "\f130"; } +.bi-arrow-return-left::before { content: "\f131"; } +.bi-arrow-return-right::before { content: "\f132"; } +.bi-arrow-right-circle-fill::before { content: "\f133"; } +.bi-arrow-right-circle::before { content: "\f134"; } +.bi-arrow-right-short::before { content: "\f135"; } +.bi-arrow-right-square-fill::before { content: "\f136"; } +.bi-arrow-right-square::before { content: "\f137"; } +.bi-arrow-right::before { content: "\f138"; } +.bi-arrow-up-circle-fill::before { content: "\f139"; } +.bi-arrow-up-circle::before { content: "\f13a"; } +.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } +.bi-arrow-up-left-circle::before { content: "\f13c"; } +.bi-arrow-up-left-square-fill::before { content: "\f13d"; } +.bi-arrow-up-left-square::before { content: "\f13e"; } +.bi-arrow-up-left::before { content: "\f13f"; } +.bi-arrow-up-right-circle-fill::before { content: "\f140"; } +.bi-arrow-up-right-circle::before { content: "\f141"; } +.bi-arrow-up-right-square-fill::before { content: "\f142"; } +.bi-arrow-up-right-square::before { content: "\f143"; } +.bi-arrow-up-right::before { content: "\f144"; } +.bi-arrow-up-short::before { content: "\f145"; } +.bi-arrow-up-square-fill::before { content: "\f146"; } +.bi-arrow-up-square::before { content: "\f147"; } +.bi-arrow-up::before { content: "\f148"; } +.bi-arrows-angle-contract::before { content: "\f149"; } +.bi-arrows-angle-expand::before { content: "\f14a"; } +.bi-arrows-collapse::before { content: "\f14b"; } +.bi-arrows-expand::before { content: "\f14c"; } +.bi-arrows-fullscreen::before { content: "\f14d"; } +.bi-arrows-move::before { content: "\f14e"; } +.bi-aspect-ratio-fill::before { content: "\f14f"; } +.bi-aspect-ratio::before { content: "\f150"; } +.bi-asterisk::before { content: "\f151"; } +.bi-at::before { content: "\f152"; } +.bi-award-fill::before { content: "\f153"; } +.bi-award::before { content: "\f154"; } +.bi-back::before { content: "\f155"; } +.bi-backspace-fill::before { content: "\f156"; } +.bi-backspace-reverse-fill::before { content: "\f157"; } +.bi-backspace-reverse::before { content: "\f158"; } +.bi-backspace::before { content: "\f159"; } +.bi-badge-3d-fill::before { content: "\f15a"; } +.bi-badge-3d::before { content: "\f15b"; } +.bi-badge-4k-fill::before { content: "\f15c"; } +.bi-badge-4k::before { content: "\f15d"; } +.bi-badge-8k-fill::before { content: "\f15e"; } +.bi-badge-8k::before { content: "\f15f"; } +.bi-badge-ad-fill::before { content: "\f160"; } +.bi-badge-ad::before { content: "\f161"; } +.bi-badge-ar-fill::before { content: "\f162"; } +.bi-badge-ar::before { content: "\f163"; } +.bi-badge-cc-fill::before { content: "\f164"; } +.bi-badge-cc::before { content: "\f165"; } +.bi-badge-hd-fill::before { content: "\f166"; } +.bi-badge-hd::before { content: "\f167"; } +.bi-badge-tm-fill::before { content: "\f168"; } +.bi-badge-tm::before { content: "\f169"; } +.bi-badge-vo-fill::before { content: "\f16a"; } +.bi-badge-vo::before { content: "\f16b"; } +.bi-badge-vr-fill::before { content: "\f16c"; } +.bi-badge-vr::before { content: "\f16d"; } +.bi-badge-wc-fill::before { content: "\f16e"; } +.bi-badge-wc::before { content: "\f16f"; } +.bi-bag-check-fill::before { content: "\f170"; } +.bi-bag-check::before { content: "\f171"; } +.bi-bag-dash-fill::before { content: "\f172"; } +.bi-bag-dash::before { content: "\f173"; } +.bi-bag-fill::before { content: "\f174"; } +.bi-bag-plus-fill::before { content: "\f175"; } +.bi-bag-plus::before { content: "\f176"; } +.bi-bag-x-fill::before { content: "\f177"; } +.bi-bag-x::before { content: "\f178"; } +.bi-bag::before { content: "\f179"; } +.bi-bar-chart-fill::before { content: "\f17a"; } +.bi-bar-chart-line-fill::before { content: "\f17b"; } +.bi-bar-chart-line::before { content: "\f17c"; } +.bi-bar-chart-steps::before { content: "\f17d"; } +.bi-bar-chart::before { content: "\f17e"; } +.bi-basket-fill::before { content: "\f17f"; } +.bi-basket::before { content: "\f180"; } +.bi-basket2-fill::before { content: "\f181"; } +.bi-basket2::before { content: "\f182"; } +.bi-basket3-fill::before { content: "\f183"; } +.bi-basket3::before { content: "\f184"; } +.bi-battery-charging::before { content: "\f185"; } +.bi-battery-full::before { content: "\f186"; } +.bi-battery-half::before { content: "\f187"; } +.bi-battery::before { content: "\f188"; } +.bi-bell-fill::before { content: "\f189"; } +.bi-bell::before { content: "\f18a"; } +.bi-bezier::before { content: "\f18b"; } +.bi-bezier2::before { content: "\f18c"; } +.bi-bicycle::before { content: "\f18d"; } +.bi-binoculars-fill::before { content: "\f18e"; } +.bi-binoculars::before { content: "\f18f"; } +.bi-blockquote-left::before { content: "\f190"; } +.bi-blockquote-right::before { content: "\f191"; } +.bi-book-fill::before { content: "\f192"; } +.bi-book-half::before { content: "\f193"; } +.bi-book::before { content: "\f194"; } +.bi-bookmark-check-fill::before { content: "\f195"; } +.bi-bookmark-check::before { content: "\f196"; } +.bi-bookmark-dash-fill::before { content: "\f197"; } +.bi-bookmark-dash::before { content: "\f198"; } +.bi-bookmark-fill::before { content: "\f199"; } +.bi-bookmark-heart-fill::before { content: "\f19a"; } +.bi-bookmark-heart::before { content: "\f19b"; } +.bi-bookmark-plus-fill::before { content: "\f19c"; } +.bi-bookmark-plus::before { content: "\f19d"; } +.bi-bookmark-star-fill::before { content: "\f19e"; } +.bi-bookmark-star::before { content: "\f19f"; } +.bi-bookmark-x-fill::before { content: "\f1a0"; } +.bi-bookmark-x::before { content: "\f1a1"; } +.bi-bookmark::before { content: "\f1a2"; } +.bi-bookmarks-fill::before { content: "\f1a3"; } +.bi-bookmarks::before { content: "\f1a4"; } +.bi-bookshelf::before { content: "\f1a5"; } +.bi-bootstrap-fill::before { content: "\f1a6"; } +.bi-bootstrap-reboot::before { content: "\f1a7"; } +.bi-bootstrap::before { content: "\f1a8"; } +.bi-border-all::before { content: "\f1a9"; } +.bi-border-bottom::before { content: "\f1aa"; } +.bi-border-center::before { content: "\f1ab"; } +.bi-border-inner::before { content: "\f1ac"; } +.bi-border-left::before { content: "\f1ad"; } +.bi-border-middle::before { content: "\f1ae"; } +.bi-border-outer::before { content: "\f1af"; } +.bi-border-right::before { content: "\f1b0"; } +.bi-border-style::before { content: "\f1b1"; } +.bi-border-top::before { content: "\f1b2"; } +.bi-border-width::before { content: "\f1b3"; } +.bi-border::before { content: "\f1b4"; } +.bi-bounding-box-circles::before { content: "\f1b5"; } +.bi-bounding-box::before { content: "\f1b6"; } +.bi-box-arrow-down-left::before { content: "\f1b7"; } +.bi-box-arrow-down-right::before { content: "\f1b8"; } +.bi-box-arrow-down::before { content: "\f1b9"; } +.bi-box-arrow-in-down-left::before { content: "\f1ba"; } +.bi-box-arrow-in-down-right::before { content: "\f1bb"; } +.bi-box-arrow-in-down::before { content: "\f1bc"; } +.bi-box-arrow-in-left::before { content: "\f1bd"; } +.bi-box-arrow-in-right::before { content: "\f1be"; } +.bi-box-arrow-in-up-left::before { content: "\f1bf"; } +.bi-box-arrow-in-up-right::before { content: "\f1c0"; } +.bi-box-arrow-in-up::before { content: "\f1c1"; } +.bi-box-arrow-left::before { content: "\f1c2"; } +.bi-box-arrow-right::before { content: "\f1c3"; } +.bi-box-arrow-up-left::before { content: "\f1c4"; } +.bi-box-arrow-up-right::before { content: "\f1c5"; } +.bi-box-arrow-up::before { content: "\f1c6"; } +.bi-box-seam::before { content: "\f1c7"; } +.bi-box::before { content: "\f1c8"; } +.bi-braces::before { content: "\f1c9"; } +.bi-bricks::before { content: "\f1ca"; } +.bi-briefcase-fill::before { content: "\f1cb"; } +.bi-briefcase::before { content: "\f1cc"; } +.bi-brightness-alt-high-fill::before { content: "\f1cd"; } +.bi-brightness-alt-high::before { content: "\f1ce"; } +.bi-brightness-alt-low-fill::before { content: "\f1cf"; } +.bi-brightness-alt-low::before { content: "\f1d0"; } +.bi-brightness-high-fill::before { content: "\f1d1"; } +.bi-brightness-high::before { content: "\f1d2"; } +.bi-brightness-low-fill::before { content: "\f1d3"; } +.bi-brightness-low::before { content: "\f1d4"; } +.bi-broadcast-pin::before { content: "\f1d5"; } +.bi-broadcast::before { content: "\f1d6"; } +.bi-brush-fill::before { content: "\f1d7"; } +.bi-brush::before { content: "\f1d8"; } +.bi-bucket-fill::before { content: "\f1d9"; } +.bi-bucket::before { content: "\f1da"; } +.bi-bug-fill::before { content: "\f1db"; } +.bi-bug::before { content: "\f1dc"; } +.bi-building::before { content: "\f1dd"; } +.bi-bullseye::before { content: "\f1de"; } +.bi-calculator-fill::before { content: "\f1df"; } +.bi-calculator::before { content: "\f1e0"; } +.bi-calendar-check-fill::before { content: "\f1e1"; } +.bi-calendar-check::before { content: "\f1e2"; } +.bi-calendar-date-fill::before { content: "\f1e3"; } +.bi-calendar-date::before { content: "\f1e4"; } +.bi-calendar-day-fill::before { content: "\f1e5"; } +.bi-calendar-day::before { content: "\f1e6"; } +.bi-calendar-event-fill::before { content: "\f1e7"; } +.bi-calendar-event::before { content: "\f1e8"; } +.bi-calendar-fill::before { content: "\f1e9"; } +.bi-calendar-minus-fill::before { content: "\f1ea"; } +.bi-calendar-minus::before { content: "\f1eb"; } +.bi-calendar-month-fill::before { content: "\f1ec"; } +.bi-calendar-month::before { content: "\f1ed"; } +.bi-calendar-plus-fill::before { content: "\f1ee"; } +.bi-calendar-plus::before { content: "\f1ef"; } +.bi-calendar-range-fill::before { content: "\f1f0"; } +.bi-calendar-range::before { content: "\f1f1"; } +.bi-calendar-week-fill::before { content: "\f1f2"; } +.bi-calendar-week::before { content: "\f1f3"; } +.bi-calendar-x-fill::before { content: "\f1f4"; } +.bi-calendar-x::before { content: "\f1f5"; } +.bi-calendar::before { content: "\f1f6"; } +.bi-calendar2-check-fill::before { content: "\f1f7"; } +.bi-calendar2-check::before { content: "\f1f8"; } +.bi-calendar2-date-fill::before { content: "\f1f9"; } +.bi-calendar2-date::before { content: "\f1fa"; } +.bi-calendar2-day-fill::before { content: "\f1fb"; } +.bi-calendar2-day::before { content: "\f1fc"; } +.bi-calendar2-event-fill::before { content: "\f1fd"; } +.bi-calendar2-event::before { content: "\f1fe"; } +.bi-calendar2-fill::before { content: "\f1ff"; } +.bi-calendar2-minus-fill::before { content: "\f200"; } +.bi-calendar2-minus::before { content: "\f201"; } +.bi-calendar2-month-fill::before { content: "\f202"; } +.bi-calendar2-month::before { content: "\f203"; } +.bi-calendar2-plus-fill::before { content: "\f204"; } +.bi-calendar2-plus::before { content: "\f205"; } +.bi-calendar2-range-fill::before { content: "\f206"; } +.bi-calendar2-range::before { content: "\f207"; } +.bi-calendar2-week-fill::before { content: "\f208"; } +.bi-calendar2-week::before { content: "\f209"; } +.bi-calendar2-x-fill::before { content: "\f20a"; } +.bi-calendar2-x::before { content: "\f20b"; } +.bi-calendar2::before { content: "\f20c"; } +.bi-calendar3-event-fill::before { content: "\f20d"; } +.bi-calendar3-event::before { content: "\f20e"; } +.bi-calendar3-fill::before { content: "\f20f"; } +.bi-calendar3-range-fill::before { content: "\f210"; } +.bi-calendar3-range::before { content: "\f211"; } +.bi-calendar3-week-fill::before { content: "\f212"; } +.bi-calendar3-week::before { content: "\f213"; } +.bi-calendar3::before { content: "\f214"; } +.bi-calendar4-event::before { content: "\f215"; } +.bi-calendar4-range::before { content: "\f216"; } +.bi-calendar4-week::before { content: "\f217"; } +.bi-calendar4::before { content: "\f218"; } +.bi-camera-fill::before { content: "\f219"; } +.bi-camera-reels-fill::before { content: "\f21a"; } +.bi-camera-reels::before { content: "\f21b"; } +.bi-camera-video-fill::before { content: "\f21c"; } +.bi-camera-video-off-fill::before { content: "\f21d"; } +.bi-camera-video-off::before { content: "\f21e"; } +.bi-camera-video::before { content: "\f21f"; } +.bi-camera::before { content: "\f220"; } +.bi-camera2::before { content: "\f221"; } +.bi-capslock-fill::before { content: "\f222"; } +.bi-capslock::before { content: "\f223"; } +.bi-card-checklist::before { content: "\f224"; } +.bi-card-heading::before { content: "\f225"; } +.bi-card-image::before { content: "\f226"; } +.bi-card-list::before { content: "\f227"; } +.bi-card-text::before { content: "\f228"; } +.bi-caret-down-fill::before { content: "\f229"; } +.bi-caret-down-square-fill::before { content: "\f22a"; } +.bi-caret-down-square::before { content: "\f22b"; } +.bi-caret-down::before { content: "\f22c"; } +.bi-caret-left-fill::before { content: "\f22d"; } +.bi-caret-left-square-fill::before { content: "\f22e"; } +.bi-caret-left-square::before { content: "\f22f"; } +.bi-caret-left::before { content: "\f230"; } +.bi-caret-right-fill::before { content: "\f231"; } +.bi-caret-right-square-fill::before { content: "\f232"; } +.bi-caret-right-square::before { content: "\f233"; } +.bi-caret-right::before { content: "\f234"; } +.bi-caret-up-fill::before { content: "\f235"; } +.bi-caret-up-square-fill::before { content: "\f236"; } +.bi-caret-up-square::before { content: "\f237"; } +.bi-caret-up::before { content: "\f238"; } +.bi-cart-check-fill::before { content: "\f239"; } +.bi-cart-check::before { content: "\f23a"; } +.bi-cart-dash-fill::before { content: "\f23b"; } +.bi-cart-dash::before { content: "\f23c"; } +.bi-cart-fill::before { content: "\f23d"; } +.bi-cart-plus-fill::before { content: "\f23e"; } +.bi-cart-plus::before { content: "\f23f"; } +.bi-cart-x-fill::before { content: "\f240"; } +.bi-cart-x::before { content: "\f241"; } +.bi-cart::before { content: "\f242"; } +.bi-cart2::before { content: "\f243"; } +.bi-cart3::before { content: "\f244"; } +.bi-cart4::before { content: "\f245"; } +.bi-cash-stack::before { content: "\f246"; } +.bi-cash::before { content: "\f247"; } +.bi-cast::before { content: "\f248"; } +.bi-chat-dots-fill::before { content: "\f249"; } +.bi-chat-dots::before { content: "\f24a"; } +.bi-chat-fill::before { content: "\f24b"; } +.bi-chat-left-dots-fill::before { content: "\f24c"; } +.bi-chat-left-dots::before { content: "\f24d"; } +.bi-chat-left-fill::before { content: "\f24e"; } +.bi-chat-left-quote-fill::before { content: "\f24f"; } +.bi-chat-left-quote::before { content: "\f250"; } +.bi-chat-left-text-fill::before { content: "\f251"; } +.bi-chat-left-text::before { content: "\f252"; } +.bi-chat-left::before { content: "\f253"; } +.bi-chat-quote-fill::before { content: "\f254"; } +.bi-chat-quote::before { content: "\f255"; } +.bi-chat-right-dots-fill::before { content: "\f256"; } +.bi-chat-right-dots::before { content: "\f257"; } +.bi-chat-right-fill::before { content: "\f258"; } +.bi-chat-right-quote-fill::before { content: "\f259"; } +.bi-chat-right-quote::before { content: "\f25a"; } +.bi-chat-right-text-fill::before { content: "\f25b"; } +.bi-chat-right-text::before { content: "\f25c"; } +.bi-chat-right::before { content: "\f25d"; } +.bi-chat-square-dots-fill::before { content: "\f25e"; } +.bi-chat-square-dots::before { content: "\f25f"; } +.bi-chat-square-fill::before { content: "\f260"; } +.bi-chat-square-quote-fill::before { content: "\f261"; } +.bi-chat-square-quote::before { content: "\f262"; } +.bi-chat-square-text-fill::before { content: "\f263"; } +.bi-chat-square-text::before { content: "\f264"; } +.bi-chat-square::before { content: "\f265"; } +.bi-chat-text-fill::before { content: "\f266"; } +.bi-chat-text::before { content: "\f267"; } +.bi-chat::before { content: "\f268"; } +.bi-check-all::before { content: "\f269"; } +.bi-check-circle-fill::before { content: "\f26a"; } +.bi-check-circle::before { content: "\f26b"; } +.bi-check-square-fill::before { content: "\f26c"; } +.bi-check-square::before { content: "\f26d"; } +.bi-check::before { content: "\f26e"; } +.bi-check2-all::before { content: "\f26f"; } +.bi-check2-circle::before { content: "\f270"; } +.bi-check2-square::before { content: "\f271"; } +.bi-check2::before { content: "\f272"; } +.bi-chevron-bar-contract::before { content: "\f273"; } +.bi-chevron-bar-down::before { content: "\f274"; } +.bi-chevron-bar-expand::before { content: "\f275"; } +.bi-chevron-bar-left::before { content: "\f276"; } +.bi-chevron-bar-right::before { content: "\f277"; } +.bi-chevron-bar-up::before { content: "\f278"; } +.bi-chevron-compact-down::before { content: "\f279"; } +.bi-chevron-compact-left::before { content: "\f27a"; } +.bi-chevron-compact-right::before { content: "\f27b"; } +.bi-chevron-compact-up::before { content: "\f27c"; } +.bi-chevron-contract::before { content: "\f27d"; } +.bi-chevron-double-down::before { content: "\f27e"; } +.bi-chevron-double-left::before { content: "\f27f"; } +.bi-chevron-double-right::before { content: "\f280"; } +.bi-chevron-double-up::before { content: "\f281"; } +.bi-chevron-down::before { content: "\f282"; } +.bi-chevron-expand::before { content: "\f283"; } +.bi-chevron-left::before { content: "\f284"; } +.bi-chevron-right::before { content: "\f285"; } +.bi-chevron-up::before { content: "\f286"; } +.bi-circle-fill::before { content: "\f287"; } +.bi-circle-half::before { content: "\f288"; } +.bi-circle-square::before { content: "\f289"; } +.bi-circle::before { content: "\f28a"; } +.bi-clipboard-check::before { content: "\f28b"; } +.bi-clipboard-data::before { content: "\f28c"; } +.bi-clipboard-minus::before { content: "\f28d"; } +.bi-clipboard-plus::before { content: "\f28e"; } +.bi-clipboard-x::before { content: "\f28f"; } +.bi-clipboard::before { content: "\f290"; } +.bi-clock-fill::before { content: "\f291"; } +.bi-clock-history::before { content: "\f292"; } +.bi-clock::before { content: "\f293"; } +.bi-cloud-arrow-down-fill::before { content: "\f294"; } +.bi-cloud-arrow-down::before { content: "\f295"; } +.bi-cloud-arrow-up-fill::before { content: "\f296"; } +.bi-cloud-arrow-up::before { content: "\f297"; } +.bi-cloud-check-fill::before { content: "\f298"; } +.bi-cloud-check::before { content: "\f299"; } +.bi-cloud-download-fill::before { content: "\f29a"; } +.bi-cloud-download::before { content: "\f29b"; } +.bi-cloud-drizzle-fill::before { content: "\f29c"; } +.bi-cloud-drizzle::before { content: "\f29d"; } +.bi-cloud-fill::before { content: "\f29e"; } +.bi-cloud-fog-fill::before { content: "\f29f"; } +.bi-cloud-fog::before { content: "\f2a0"; } +.bi-cloud-fog2-fill::before { content: "\f2a1"; } +.bi-cloud-fog2::before { content: "\f2a2"; } +.bi-cloud-hail-fill::before { content: "\f2a3"; } +.bi-cloud-hail::before { content: "\f2a4"; } +.bi-cloud-haze-1::before { content: "\f2a5"; } +.bi-cloud-haze-fill::before { content: "\f2a6"; } +.bi-cloud-haze::before { content: "\f2a7"; } +.bi-cloud-haze2-fill::before { content: "\f2a8"; } +.bi-cloud-lightning-fill::before { content: "\f2a9"; } +.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } +.bi-cloud-lightning-rain::before { content: "\f2ab"; } +.bi-cloud-lightning::before { content: "\f2ac"; } +.bi-cloud-minus-fill::before { content: "\f2ad"; } +.bi-cloud-minus::before { content: "\f2ae"; } +.bi-cloud-moon-fill::before { content: "\f2af"; } +.bi-cloud-moon::before { content: "\f2b0"; } +.bi-cloud-plus-fill::before { content: "\f2b1"; } +.bi-cloud-plus::before { content: "\f2b2"; } +.bi-cloud-rain-fill::before { content: "\f2b3"; } +.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } +.bi-cloud-rain-heavy::before { content: "\f2b5"; } +.bi-cloud-rain::before { content: "\f2b6"; } +.bi-cloud-slash-fill::before { content: "\f2b7"; } +.bi-cloud-slash::before { content: "\f2b8"; } +.bi-cloud-sleet-fill::before { content: "\f2b9"; } +.bi-cloud-sleet::before { content: "\f2ba"; } +.bi-cloud-snow-fill::before { content: "\f2bb"; } +.bi-cloud-snow::before { content: "\f2bc"; } +.bi-cloud-sun-fill::before { content: "\f2bd"; } +.bi-cloud-sun::before { content: "\f2be"; } +.bi-cloud-upload-fill::before { content: "\f2bf"; } +.bi-cloud-upload::before { content: "\f2c0"; } +.bi-cloud::before { content: "\f2c1"; } +.bi-clouds-fill::before { content: "\f2c2"; } +.bi-clouds::before { content: "\f2c3"; } +.bi-cloudy-fill::before { content: "\f2c4"; } +.bi-cloudy::before { content: "\f2c5"; } +.bi-code-slash::before { content: "\f2c6"; } +.bi-code-square::before { content: "\f2c7"; } +.bi-code::before { content: "\f2c8"; } +.bi-collection-fill::before { content: "\f2c9"; } +.bi-collection-play-fill::before { content: "\f2ca"; } +.bi-collection-play::before { content: "\f2cb"; } +.bi-collection::before { content: "\f2cc"; } +.bi-columns-gap::before { content: "\f2cd"; } +.bi-columns::before { content: "\f2ce"; } +.bi-command::before { content: "\f2cf"; } +.bi-compass-fill::before { content: "\f2d0"; } +.bi-compass::before { content: "\f2d1"; } +.bi-cone-striped::before { content: "\f2d2"; } +.bi-cone::before { content: "\f2d3"; } +.bi-controller::before { content: "\f2d4"; } +.bi-cpu-fill::before { content: "\f2d5"; } +.bi-cpu::before { content: "\f2d6"; } +.bi-credit-card-2-back-fill::before { content: "\f2d7"; } +.bi-credit-card-2-back::before { content: "\f2d8"; } +.bi-credit-card-2-front-fill::before { content: "\f2d9"; } +.bi-credit-card-2-front::before { content: "\f2da"; } +.bi-credit-card-fill::before { content: "\f2db"; } +.bi-credit-card::before { content: "\f2dc"; } +.bi-crop::before { content: "\f2dd"; } +.bi-cup-fill::before { content: "\f2de"; } +.bi-cup-straw::before { content: "\f2df"; } +.bi-cup::before { content: "\f2e0"; } +.bi-cursor-fill::before { content: "\f2e1"; } +.bi-cursor-text::before { content: "\f2e2"; } +.bi-cursor::before { content: "\f2e3"; } +.bi-dash-circle-dotted::before { content: "\f2e4"; } +.bi-dash-circle-fill::before { content: "\f2e5"; } +.bi-dash-circle::before { content: "\f2e6"; } +.bi-dash-square-dotted::before { content: "\f2e7"; } +.bi-dash-square-fill::before { content: "\f2e8"; } +.bi-dash-square::before { content: "\f2e9"; } +.bi-dash::before { content: "\f2ea"; } +.bi-diagram-2-fill::before { content: "\f2eb"; } +.bi-diagram-2::before { content: "\f2ec"; } +.bi-diagram-3-fill::before { content: "\f2ed"; } +.bi-diagram-3::before { content: "\f2ee"; } +.bi-diamond-fill::before { content: "\f2ef"; } +.bi-diamond-half::before { content: "\f2f0"; } +.bi-diamond::before { content: "\f2f1"; } +.bi-dice-1-fill::before { content: "\f2f2"; } +.bi-dice-1::before { content: "\f2f3"; } +.bi-dice-2-fill::before { content: "\f2f4"; } +.bi-dice-2::before { content: "\f2f5"; } +.bi-dice-3-fill::before { content: "\f2f6"; } +.bi-dice-3::before { content: "\f2f7"; } +.bi-dice-4-fill::before { content: "\f2f8"; } +.bi-dice-4::before { content: "\f2f9"; } +.bi-dice-5-fill::before { content: "\f2fa"; } +.bi-dice-5::before { content: "\f2fb"; } +.bi-dice-6-fill::before { content: "\f2fc"; } +.bi-dice-6::before { content: "\f2fd"; } +.bi-disc-fill::before { content: "\f2fe"; } +.bi-disc::before { content: "\f2ff"; } +.bi-discord::before { content: "\f300"; } +.bi-display-fill::before { content: "\f301"; } +.bi-display::before { content: "\f302"; } +.bi-distribute-horizontal::before { content: "\f303"; } +.bi-distribute-vertical::before { content: "\f304"; } +.bi-door-closed-fill::before { content: "\f305"; } +.bi-door-closed::before { content: "\f306"; } +.bi-door-open-fill::before { content: "\f307"; } +.bi-door-open::before { content: "\f308"; } +.bi-dot::before { content: "\f309"; } +.bi-download::before { content: "\f30a"; } +.bi-droplet-fill::before { content: "\f30b"; } +.bi-droplet-half::before { content: "\f30c"; } +.bi-droplet::before { content: "\f30d"; } +.bi-earbuds::before { content: "\f30e"; } +.bi-easel-fill::before { content: "\f30f"; } +.bi-easel::before { content: "\f310"; } +.bi-egg-fill::before { content: "\f311"; } +.bi-egg-fried::before { content: "\f312"; } +.bi-egg::before { content: "\f313"; } +.bi-eject-fill::before { content: "\f314"; } +.bi-eject::before { content: "\f315"; } +.bi-emoji-angry-fill::before { content: "\f316"; } +.bi-emoji-angry::before { content: "\f317"; } +.bi-emoji-dizzy-fill::before { content: "\f318"; } +.bi-emoji-dizzy::before { content: "\f319"; } +.bi-emoji-expressionless-fill::before { content: "\f31a"; } +.bi-emoji-expressionless::before { content: "\f31b"; } +.bi-emoji-frown-fill::before { content: "\f31c"; } +.bi-emoji-frown::before { content: "\f31d"; } +.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } +.bi-emoji-heart-eyes::before { content: "\f31f"; } +.bi-emoji-laughing-fill::before { content: "\f320"; } +.bi-emoji-laughing::before { content: "\f321"; } +.bi-emoji-neutral-fill::before { content: "\f322"; } +.bi-emoji-neutral::before { content: "\f323"; } +.bi-emoji-smile-fill::before { content: "\f324"; } +.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } +.bi-emoji-smile-upside-down::before { content: "\f326"; } +.bi-emoji-smile::before { content: "\f327"; } +.bi-emoji-sunglasses-fill::before { content: "\f328"; } +.bi-emoji-sunglasses::before { content: "\f329"; } +.bi-emoji-wink-fill::before { content: "\f32a"; } +.bi-emoji-wink::before { content: "\f32b"; } +.bi-envelope-fill::before { content: "\f32c"; } +.bi-envelope-open-fill::before { content: "\f32d"; } +.bi-envelope-open::before { content: "\f32e"; } +.bi-envelope::before { content: "\f32f"; } +.bi-eraser-fill::before { content: "\f330"; } +.bi-eraser::before { content: "\f331"; } +.bi-exclamation-circle-fill::before { content: "\f332"; } +.bi-exclamation-circle::before { content: "\f333"; } +.bi-exclamation-diamond-fill::before { content: "\f334"; } +.bi-exclamation-diamond::before { content: "\f335"; } +.bi-exclamation-octagon-fill::before { content: "\f336"; } +.bi-exclamation-octagon::before { content: "\f337"; } +.bi-exclamation-square-fill::before { content: "\f338"; } +.bi-exclamation-square::before { content: "\f339"; } +.bi-exclamation-triangle-fill::before { content: "\f33a"; } +.bi-exclamation-triangle::before { content: "\f33b"; } +.bi-exclamation::before { content: "\f33c"; } +.bi-exclude::before { content: "\f33d"; } +.bi-eye-fill::before { content: "\f33e"; } +.bi-eye-slash-fill::before { content: "\f33f"; } +.bi-eye-slash::before { content: "\f340"; } +.bi-eye::before { content: "\f341"; } +.bi-eyedropper::before { content: "\f342"; } +.bi-eyeglasses::before { content: "\f343"; } +.bi-facebook::before { content: "\f344"; } +.bi-file-arrow-down-fill::before { content: "\f345"; } +.bi-file-arrow-down::before { content: "\f346"; } +.bi-file-arrow-up-fill::before { content: "\f347"; } +.bi-file-arrow-up::before { content: "\f348"; } +.bi-file-bar-graph-fill::before { content: "\f349"; } +.bi-file-bar-graph::before { content: "\f34a"; } +.bi-file-binary-fill::before { content: "\f34b"; } +.bi-file-binary::before { content: "\f34c"; } +.bi-file-break-fill::before { content: "\f34d"; } +.bi-file-break::before { content: "\f34e"; } +.bi-file-check-fill::before { content: "\f34f"; } +.bi-file-check::before { content: "\f350"; } +.bi-file-code-fill::before { content: "\f351"; } +.bi-file-code::before { content: "\f352"; } +.bi-file-diff-fill::before { content: "\f353"; } +.bi-file-diff::before { content: "\f354"; } +.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } +.bi-file-earmark-arrow-down::before { content: "\f356"; } +.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } +.bi-file-earmark-arrow-up::before { content: "\f358"; } +.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } +.bi-file-earmark-bar-graph::before { content: "\f35a"; } +.bi-file-earmark-binary-fill::before { content: "\f35b"; } +.bi-file-earmark-binary::before { content: "\f35c"; } +.bi-file-earmark-break-fill::before { content: "\f35d"; } +.bi-file-earmark-break::before { content: "\f35e"; } +.bi-file-earmark-check-fill::before { content: "\f35f"; } +.bi-file-earmark-check::before { content: "\f360"; } +.bi-file-earmark-code-fill::before { content: "\f361"; } +.bi-file-earmark-code::before { content: "\f362"; } +.bi-file-earmark-diff-fill::before { content: "\f363"; } +.bi-file-earmark-diff::before { content: "\f364"; } +.bi-file-earmark-easel-fill::before { content: "\f365"; } +.bi-file-earmark-easel::before { content: "\f366"; } +.bi-file-earmark-excel-fill::before { content: "\f367"; } +.bi-file-earmark-excel::before { content: "\f368"; } +.bi-file-earmark-fill::before { content: "\f369"; } +.bi-file-earmark-font-fill::before { content: "\f36a"; } +.bi-file-earmark-font::before { content: "\f36b"; } +.bi-file-earmark-image-fill::before { content: "\f36c"; } +.bi-file-earmark-image::before { content: "\f36d"; } +.bi-file-earmark-lock-fill::before { content: "\f36e"; } +.bi-file-earmark-lock::before { content: "\f36f"; } +.bi-file-earmark-lock2-fill::before { content: "\f370"; } +.bi-file-earmark-lock2::before { content: "\f371"; } +.bi-file-earmark-medical-fill::before { content: "\f372"; } +.bi-file-earmark-medical::before { content: "\f373"; } +.bi-file-earmark-minus-fill::before { content: "\f374"; } +.bi-file-earmark-minus::before { content: "\f375"; } +.bi-file-earmark-music-fill::before { content: "\f376"; } +.bi-file-earmark-music::before { content: "\f377"; } +.bi-file-earmark-person-fill::before { content: "\f378"; } +.bi-file-earmark-person::before { content: "\f379"; } +.bi-file-earmark-play-fill::before { content: "\f37a"; } +.bi-file-earmark-play::before { content: "\f37b"; } +.bi-file-earmark-plus-fill::before { content: "\f37c"; } +.bi-file-earmark-plus::before { content: "\f37d"; } +.bi-file-earmark-post-fill::before { content: "\f37e"; } +.bi-file-earmark-post::before { content: "\f37f"; } +.bi-file-earmark-ppt-fill::before { content: "\f380"; } +.bi-file-earmark-ppt::before { content: "\f381"; } +.bi-file-earmark-richtext-fill::before { content: "\f382"; } +.bi-file-earmark-richtext::before { content: "\f383"; } +.bi-file-earmark-ruled-fill::before { content: "\f384"; } +.bi-file-earmark-ruled::before { content: "\f385"; } +.bi-file-earmark-slides-fill::before { content: "\f386"; } +.bi-file-earmark-slides::before { content: "\f387"; } +.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } +.bi-file-earmark-spreadsheet::before { content: "\f389"; } +.bi-file-earmark-text-fill::before { content: "\f38a"; } +.bi-file-earmark-text::before { content: "\f38b"; } +.bi-file-earmark-word-fill::before { content: "\f38c"; } +.bi-file-earmark-word::before { content: "\f38d"; } +.bi-file-earmark-x-fill::before { content: "\f38e"; } +.bi-file-earmark-x::before { content: "\f38f"; } +.bi-file-earmark-zip-fill::before { content: "\f390"; } +.bi-file-earmark-zip::before { content: "\f391"; } +.bi-file-earmark::before { content: "\f392"; } +.bi-file-easel-fill::before { content: "\f393"; } +.bi-file-easel::before { content: "\f394"; } +.bi-file-excel-fill::before { content: "\f395"; } +.bi-file-excel::before { content: "\f396"; } +.bi-file-fill::before { content: "\f397"; } +.bi-file-font-fill::before { content: "\f398"; } +.bi-file-font::before { content: "\f399"; } +.bi-file-image-fill::before { content: "\f39a"; } +.bi-file-image::before { content: "\f39b"; } +.bi-file-lock-fill::before { content: "\f39c"; } +.bi-file-lock::before { content: "\f39d"; } +.bi-file-lock2-fill::before { content: "\f39e"; } +.bi-file-lock2::before { content: "\f39f"; } +.bi-file-medical-fill::before { content: "\f3a0"; } +.bi-file-medical::before { content: "\f3a1"; } +.bi-file-minus-fill::before { content: "\f3a2"; } +.bi-file-minus::before { content: "\f3a3"; } +.bi-file-music-fill::before { content: "\f3a4"; } +.bi-file-music::before { content: "\f3a5"; } +.bi-file-person-fill::before { content: "\f3a6"; } +.bi-file-person::before { content: "\f3a7"; } +.bi-file-play-fill::before { content: "\f3a8"; } +.bi-file-play::before { content: "\f3a9"; } +.bi-file-plus-fill::before { content: "\f3aa"; } +.bi-file-plus::before { content: "\f3ab"; } +.bi-file-post-fill::before { content: "\f3ac"; } +.bi-file-post::before { content: "\f3ad"; } +.bi-file-ppt-fill::before { content: "\f3ae"; } +.bi-file-ppt::before { content: "\f3af"; } +.bi-file-richtext-fill::before { content: "\f3b0"; } +.bi-file-richtext::before { content: "\f3b1"; } +.bi-file-ruled-fill::before { content: "\f3b2"; } +.bi-file-ruled::before { content: "\f3b3"; } +.bi-file-slides-fill::before { content: "\f3b4"; } +.bi-file-slides::before { content: "\f3b5"; } +.bi-file-spreadsheet-fill::before { content: "\f3b6"; } +.bi-file-spreadsheet::before { content: "\f3b7"; } +.bi-file-text-fill::before { content: "\f3b8"; } +.bi-file-text::before { content: "\f3b9"; } +.bi-file-word-fill::before { content: "\f3ba"; } +.bi-file-word::before { content: "\f3bb"; } +.bi-file-x-fill::before { content: "\f3bc"; } +.bi-file-x::before { content: "\f3bd"; } +.bi-file-zip-fill::before { content: "\f3be"; } +.bi-file-zip::before { content: "\f3bf"; } +.bi-file::before { content: "\f3c0"; } +.bi-files-alt::before { content: "\f3c1"; } +.bi-files::before { content: "\f3c2"; } +.bi-film::before { content: "\f3c3"; } +.bi-filter-circle-fill::before { content: "\f3c4"; } +.bi-filter-circle::before { content: "\f3c5"; } +.bi-filter-left::before { content: "\f3c6"; } +.bi-filter-right::before { content: "\f3c7"; } +.bi-filter-square-fill::before { content: "\f3c8"; } +.bi-filter-square::before { content: "\f3c9"; } +.bi-filter::before { content: "\f3ca"; } +.bi-flag-fill::before { content: "\f3cb"; } +.bi-flag::before { content: "\f3cc"; } +.bi-flower1::before { content: "\f3cd"; } +.bi-flower2::before { content: "\f3ce"; } +.bi-flower3::before { content: "\f3cf"; } +.bi-folder-check::before { content: "\f3d0"; } +.bi-folder-fill::before { content: "\f3d1"; } +.bi-folder-minus::before { content: "\f3d2"; } +.bi-folder-plus::before { content: "\f3d3"; } +.bi-folder-symlink-fill::before { content: "\f3d4"; } +.bi-folder-symlink::before { content: "\f3d5"; } +.bi-folder-x::before { content: "\f3d6"; } +.bi-folder::before { content: "\f3d7"; } +.bi-folder2-open::before { content: "\f3d8"; } +.bi-folder2::before { content: "\f3d9"; } +.bi-fonts::before { content: "\f3da"; } +.bi-forward-fill::before { content: "\f3db"; } +.bi-forward::before { content: "\f3dc"; } +.bi-front::before { content: "\f3dd"; } +.bi-fullscreen-exit::before { content: "\f3de"; } +.bi-fullscreen::before { content: "\f3df"; } +.bi-funnel-fill::before { content: "\f3e0"; } +.bi-funnel::before { content: "\f3e1"; } +.bi-gear-fill::before { content: "\f3e2"; } +.bi-gear-wide-connected::before { content: "\f3e3"; } +.bi-gear-wide::before { content: "\f3e4"; } +.bi-gear::before { content: "\f3e5"; } +.bi-gem::before { content: "\f3e6"; } +.bi-geo-alt-fill::before { content: "\f3e7"; } +.bi-geo-alt::before { content: "\f3e8"; } +.bi-geo-fill::before { content: "\f3e9"; } +.bi-geo::before { content: "\f3ea"; } +.bi-gift-fill::before { content: "\f3eb"; } +.bi-gift::before { content: "\f3ec"; } +.bi-github::before { content: "\f3ed"; } +.bi-globe::before { content: "\f3ee"; } +.bi-globe2::before { content: "\f3ef"; } +.bi-google::before { content: "\f3f0"; } +.bi-graph-down::before { content: "\f3f1"; } +.bi-graph-up::before { content: "\f3f2"; } +.bi-grid-1x2-fill::before { content: "\f3f3"; } +.bi-grid-1x2::before { content: "\f3f4"; } +.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } +.bi-grid-3x2-gap::before { content: "\f3f6"; } +.bi-grid-3x2::before { content: "\f3f7"; } +.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } +.bi-grid-3x3-gap::before { content: "\f3f9"; } +.bi-grid-3x3::before { content: "\f3fa"; } +.bi-grid-fill::before { content: "\f3fb"; } +.bi-grid::before { content: "\f3fc"; } +.bi-grip-horizontal::before { content: "\f3fd"; } +.bi-grip-vertical::before { content: "\f3fe"; } +.bi-hammer::before { content: "\f3ff"; } +.bi-hand-index-fill::before { content: "\f400"; } +.bi-hand-index-thumb-fill::before { content: "\f401"; } +.bi-hand-index-thumb::before { content: "\f402"; } +.bi-hand-index::before { content: "\f403"; } +.bi-hand-thumbs-down-fill::before { content: "\f404"; } +.bi-hand-thumbs-down::before { content: "\f405"; } +.bi-hand-thumbs-up-fill::before { content: "\f406"; } +.bi-hand-thumbs-up::before { content: "\f407"; } +.bi-handbag-fill::before { content: "\f408"; } +.bi-handbag::before { content: "\f409"; } +.bi-hash::before { content: "\f40a"; } +.bi-hdd-fill::before { content: "\f40b"; } +.bi-hdd-network-fill::before { content: "\f40c"; } +.bi-hdd-network::before { content: "\f40d"; } +.bi-hdd-rack-fill::before { content: "\f40e"; } +.bi-hdd-rack::before { content: "\f40f"; } +.bi-hdd-stack-fill::before { content: "\f410"; } +.bi-hdd-stack::before { content: "\f411"; } +.bi-hdd::before { content: "\f412"; } +.bi-headphones::before { content: "\f413"; } +.bi-headset::before { content: "\f414"; } +.bi-heart-fill::before { content: "\f415"; } +.bi-heart-half::before { content: "\f416"; } +.bi-heart::before { content: "\f417"; } +.bi-heptagon-fill::before { content: "\f418"; } +.bi-heptagon-half::before { content: "\f419"; } +.bi-heptagon::before { content: "\f41a"; } +.bi-hexagon-fill::before { content: "\f41b"; } +.bi-hexagon-half::before { content: "\f41c"; } +.bi-hexagon::before { content: "\f41d"; } +.bi-hourglass-bottom::before { content: "\f41e"; } +.bi-hourglass-split::before { content: "\f41f"; } +.bi-hourglass-top::before { content: "\f420"; } +.bi-hourglass::before { content: "\f421"; } +.bi-house-door-fill::before { content: "\f422"; } +.bi-house-door::before { content: "\f423"; } +.bi-house-fill::before { content: "\f424"; } +.bi-house::before { content: "\f425"; } +.bi-hr::before { content: "\f426"; } +.bi-hurricane::before { content: "\f427"; } +.bi-image-alt::before { content: "\f428"; } +.bi-image-fill::before { content: "\f429"; } +.bi-image::before { content: "\f42a"; } +.bi-images::before { content: "\f42b"; } +.bi-inbox-fill::before { content: "\f42c"; } +.bi-inbox::before { content: "\f42d"; } +.bi-inboxes-fill::before { content: "\f42e"; } +.bi-inboxes::before { content: "\f42f"; } +.bi-info-circle-fill::before { content: "\f430"; } +.bi-info-circle::before { content: "\f431"; } +.bi-info-square-fill::before { content: "\f432"; } +.bi-info-square::before { content: "\f433"; } +.bi-info::before { content: "\f434"; } +.bi-input-cursor-text::before { content: "\f435"; } +.bi-input-cursor::before { content: "\f436"; } +.bi-instagram::before { content: "\f437"; } +.bi-intersect::before { content: "\f438"; } +.bi-journal-album::before { content: "\f439"; } +.bi-journal-arrow-down::before { content: "\f43a"; } +.bi-journal-arrow-up::before { content: "\f43b"; } +.bi-journal-bookmark-fill::before { content: "\f43c"; } +.bi-journal-bookmark::before { content: "\f43d"; } +.bi-journal-check::before { content: "\f43e"; } +.bi-journal-code::before { content: "\f43f"; } +.bi-journal-medical::before { content: "\f440"; } +.bi-journal-minus::before { content: "\f441"; } +.bi-journal-plus::before { content: "\f442"; } +.bi-journal-richtext::before { content: "\f443"; } +.bi-journal-text::before { content: "\f444"; } +.bi-journal-x::before { content: "\f445"; } +.bi-journal::before { content: "\f446"; } +.bi-journals::before { content: "\f447"; } +.bi-joystick::before { content: "\f448"; } +.bi-justify-left::before { content: "\f449"; } +.bi-justify-right::before { content: "\f44a"; } +.bi-justify::before { content: "\f44b"; } +.bi-kanban-fill::before { content: "\f44c"; } +.bi-kanban::before { content: "\f44d"; } +.bi-key-fill::before { content: "\f44e"; } +.bi-key::before { content: "\f44f"; } +.bi-keyboard-fill::before { content: "\f450"; } +.bi-keyboard::before { content: "\f451"; } +.bi-ladder::before { content: "\f452"; } +.bi-lamp-fill::before { content: "\f453"; } +.bi-lamp::before { content: "\f454"; } +.bi-laptop-fill::before { content: "\f455"; } +.bi-laptop::before { content: "\f456"; } +.bi-layer-backward::before { content: "\f457"; } +.bi-layer-forward::before { content: "\f458"; } +.bi-layers-fill::before { content: "\f459"; } +.bi-layers-half::before { content: "\f45a"; } +.bi-layers::before { content: "\f45b"; } +.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } +.bi-layout-sidebar-inset::before { content: "\f45d"; } +.bi-layout-sidebar-reverse::before { content: "\f45e"; } +.bi-layout-sidebar::before { content: "\f45f"; } +.bi-layout-split::before { content: "\f460"; } +.bi-layout-text-sidebar-reverse::before { content: "\f461"; } +.bi-layout-text-sidebar::before { content: "\f462"; } +.bi-layout-text-window-reverse::before { content: "\f463"; } +.bi-layout-text-window::before { content: "\f464"; } +.bi-layout-three-columns::before { content: "\f465"; } +.bi-layout-wtf::before { content: "\f466"; } +.bi-life-preserver::before { content: "\f467"; } +.bi-lightbulb-fill::before { content: "\f468"; } +.bi-lightbulb-off-fill::before { content: "\f469"; } +.bi-lightbulb-off::before { content: "\f46a"; } +.bi-lightbulb::before { content: "\f46b"; } +.bi-lightning-charge-fill::before { content: "\f46c"; } +.bi-lightning-charge::before { content: "\f46d"; } +.bi-lightning-fill::before { content: "\f46e"; } +.bi-lightning::before { content: "\f46f"; } +.bi-link-45deg::before { content: "\f470"; } +.bi-link::before { content: "\f471"; } +.bi-linkedin::before { content: "\f472"; } +.bi-list-check::before { content: "\f473"; } +.bi-list-nested::before { content: "\f474"; } +.bi-list-ol::before { content: "\f475"; } +.bi-list-stars::before { content: "\f476"; } +.bi-list-task::before { content: "\f477"; } +.bi-list-ul::before { content: "\f478"; } +.bi-list::before { content: "\f479"; } +.bi-lock-fill::before { content: "\f47a"; } +.bi-lock::before { content: "\f47b"; } +.bi-mailbox::before { content: "\f47c"; } +.bi-mailbox2::before { content: "\f47d"; } +.bi-map-fill::before { content: "\f47e"; } +.bi-map::before { content: "\f47f"; } +.bi-markdown-fill::before { content: "\f480"; } +.bi-markdown::before { content: "\f481"; } +.bi-mask::before { content: "\f482"; } +.bi-megaphone-fill::before { content: "\f483"; } +.bi-megaphone::before { content: "\f484"; } +.bi-menu-app-fill::before { content: "\f485"; } +.bi-menu-app::before { content: "\f486"; } +.bi-menu-button-fill::before { content: "\f487"; } +.bi-menu-button-wide-fill::before { content: "\f488"; } +.bi-menu-button-wide::before { content: "\f489"; } +.bi-menu-button::before { content: "\f48a"; } +.bi-menu-down::before { content: "\f48b"; } +.bi-menu-up::before { content: "\f48c"; } +.bi-mic-fill::before { content: "\f48d"; } +.bi-mic-mute-fill::before { content: "\f48e"; } +.bi-mic-mute::before { content: "\f48f"; } +.bi-mic::before { content: "\f490"; } +.bi-minecart-loaded::before { content: "\f491"; } +.bi-minecart::before { content: "\f492"; } +.bi-moisture::before { content: "\f493"; } +.bi-moon-fill::before { content: "\f494"; } +.bi-moon-stars-fill::before { content: "\f495"; } +.bi-moon-stars::before { content: "\f496"; } +.bi-moon::before { content: "\f497"; } +.bi-mouse-fill::before { content: "\f498"; } +.bi-mouse::before { content: "\f499"; } +.bi-mouse2-fill::before { content: "\f49a"; } +.bi-mouse2::before { content: "\f49b"; } +.bi-mouse3-fill::before { content: "\f49c"; } +.bi-mouse3::before { content: "\f49d"; } +.bi-music-note-beamed::before { content: "\f49e"; } +.bi-music-note-list::before { content: "\f49f"; } +.bi-music-note::before { content: "\f4a0"; } +.bi-music-player-fill::before { content: "\f4a1"; } +.bi-music-player::before { content: "\f4a2"; } +.bi-newspaper::before { content: "\f4a3"; } +.bi-node-minus-fill::before { content: "\f4a4"; } +.bi-node-minus::before { content: "\f4a5"; } +.bi-node-plus-fill::before { content: "\f4a6"; } +.bi-node-plus::before { content: "\f4a7"; } +.bi-nut-fill::before { content: "\f4a8"; } +.bi-nut::before { content: "\f4a9"; } +.bi-octagon-fill::before { content: "\f4aa"; } +.bi-octagon-half::before { content: "\f4ab"; } +.bi-octagon::before { content: "\f4ac"; } +.bi-option::before { content: "\f4ad"; } +.bi-outlet::before { content: "\f4ae"; } +.bi-paint-bucket::before { content: "\f4af"; } +.bi-palette-fill::before { content: "\f4b0"; } +.bi-palette::before { content: "\f4b1"; } +.bi-palette2::before { content: "\f4b2"; } +.bi-paperclip::before { content: "\f4b3"; } +.bi-paragraph::before { content: "\f4b4"; } +.bi-patch-check-fill::before { content: "\f4b5"; } +.bi-patch-check::before { content: "\f4b6"; } +.bi-patch-exclamation-fill::before { content: "\f4b7"; } +.bi-patch-exclamation::before { content: "\f4b8"; } +.bi-patch-minus-fill::before { content: "\f4b9"; } +.bi-patch-minus::before { content: "\f4ba"; } +.bi-patch-plus-fill::before { content: "\f4bb"; } +.bi-patch-plus::before { content: "\f4bc"; } +.bi-patch-question-fill::before { content: "\f4bd"; } +.bi-patch-question::before { content: "\f4be"; } +.bi-pause-btn-fill::before { content: "\f4bf"; } +.bi-pause-btn::before { content: "\f4c0"; } +.bi-pause-circle-fill::before { content: "\f4c1"; } +.bi-pause-circle::before { content: "\f4c2"; } +.bi-pause-fill::before { content: "\f4c3"; } +.bi-pause::before { content: "\f4c4"; } +.bi-peace-fill::before { content: "\f4c5"; } +.bi-peace::before { content: "\f4c6"; } +.bi-pen-fill::before { content: "\f4c7"; } +.bi-pen::before { content: "\f4c8"; } +.bi-pencil-fill::before { content: "\f4c9"; } +.bi-pencil-square::before { content: "\f4ca"; } +.bi-pencil::before { content: "\f4cb"; } +.bi-pentagon-fill::before { content: "\f4cc"; } +.bi-pentagon-half::before { content: "\f4cd"; } +.bi-pentagon::before { content: "\f4ce"; } +.bi-people-fill::before { content: "\f4cf"; } +.bi-people::before { content: "\f4d0"; } +.bi-percent::before { content: "\f4d1"; } +.bi-person-badge-fill::before { content: "\f4d2"; } +.bi-person-badge::before { content: "\f4d3"; } +.bi-person-bounding-box::before { content: "\f4d4"; } +.bi-person-check-fill::before { content: "\f4d5"; } +.bi-person-check::before { content: "\f4d6"; } +.bi-person-circle::before { content: "\f4d7"; } +.bi-person-dash-fill::before { content: "\f4d8"; } +.bi-person-dash::before { content: "\f4d9"; } +.bi-person-fill::before { content: "\f4da"; } +.bi-person-lines-fill::before { content: "\f4db"; } +.bi-person-plus-fill::before { content: "\f4dc"; } +.bi-person-plus::before { content: "\f4dd"; } +.bi-person-square::before { content: "\f4de"; } +.bi-person-x-fill::before { content: "\f4df"; } +.bi-person-x::before { content: "\f4e0"; } +.bi-person::before { content: "\f4e1"; } +.bi-phone-fill::before { content: "\f4e2"; } +.bi-phone-landscape-fill::before { content: "\f4e3"; } +.bi-phone-landscape::before { content: "\f4e4"; } +.bi-phone-vibrate-fill::before { content: "\f4e5"; } +.bi-phone-vibrate::before { content: "\f4e6"; } +.bi-phone::before { content: "\f4e7"; } +.bi-pie-chart-fill::before { content: "\f4e8"; } +.bi-pie-chart::before { content: "\f4e9"; } +.bi-pin-angle-fill::before { content: "\f4ea"; } +.bi-pin-angle::before { content: "\f4eb"; } +.bi-pin-fill::before { content: "\f4ec"; } +.bi-pin::before { content: "\f4ed"; } +.bi-pip-fill::before { content: "\f4ee"; } +.bi-pip::before { content: "\f4ef"; } +.bi-play-btn-fill::before { content: "\f4f0"; } +.bi-play-btn::before { content: "\f4f1"; } +.bi-play-circle-fill::before { content: "\f4f2"; } +.bi-play-circle::before { content: "\f4f3"; } +.bi-play-fill::before { content: "\f4f4"; } +.bi-play::before { content: "\f4f5"; } +.bi-plug-fill::before { content: "\f4f6"; } +.bi-plug::before { content: "\f4f7"; } +.bi-plus-circle-dotted::before { content: "\f4f8"; } +.bi-plus-circle-fill::before { content: "\f4f9"; } +.bi-plus-circle::before { content: "\f4fa"; } +.bi-plus-square-dotted::before { content: "\f4fb"; } +.bi-plus-square-fill::before { content: "\f4fc"; } +.bi-plus-square::before { content: "\f4fd"; } +.bi-plus::before { content: "\f4fe"; } +.bi-power::before { content: "\f4ff"; } +.bi-printer-fill::before { content: "\f500"; } +.bi-printer::before { content: "\f501"; } +.bi-puzzle-fill::before { content: "\f502"; } +.bi-puzzle::before { content: "\f503"; } +.bi-question-circle-fill::before { content: "\f504"; } +.bi-question-circle::before { content: "\f505"; } +.bi-question-diamond-fill::before { content: "\f506"; } +.bi-question-diamond::before { content: "\f507"; } +.bi-question-octagon-fill::before { content: "\f508"; } +.bi-question-octagon::before { content: "\f509"; } +.bi-question-square-fill::before { content: "\f50a"; } +.bi-question-square::before { content: "\f50b"; } +.bi-question::before { content: "\f50c"; } +.bi-rainbow::before { content: "\f50d"; } +.bi-receipt-cutoff::before { content: "\f50e"; } +.bi-receipt::before { content: "\f50f"; } +.bi-reception-0::before { content: "\f510"; } +.bi-reception-1::before { content: "\f511"; } +.bi-reception-2::before { content: "\f512"; } +.bi-reception-3::before { content: "\f513"; } +.bi-reception-4::before { content: "\f514"; } +.bi-record-btn-fill::before { content: "\f515"; } +.bi-record-btn::before { content: "\f516"; } +.bi-record-circle-fill::before { content: "\f517"; } +.bi-record-circle::before { content: "\f518"; } +.bi-record-fill::before { content: "\f519"; } +.bi-record::before { content: "\f51a"; } +.bi-record2-fill::before { content: "\f51b"; } +.bi-record2::before { content: "\f51c"; } +.bi-reply-all-fill::before { content: "\f51d"; } +.bi-reply-all::before { content: "\f51e"; } +.bi-reply-fill::before { content: "\f51f"; } +.bi-reply::before { content: "\f520"; } +.bi-rss-fill::before { content: "\f521"; } +.bi-rss::before { content: "\f522"; } +.bi-rulers::before { content: "\f523"; } +.bi-save-fill::before { content: "\f524"; } +.bi-save::before { content: "\f525"; } +.bi-save2-fill::before { content: "\f526"; } +.bi-save2::before { content: "\f527"; } +.bi-scissors::before { content: "\f528"; } +.bi-screwdriver::before { content: "\f529"; } +.bi-search::before { content: "\f52a"; } +.bi-segmented-nav::before { content: "\f52b"; } +.bi-server::before { content: "\f52c"; } +.bi-share-fill::before { content: "\f52d"; } +.bi-share::before { content: "\f52e"; } +.bi-shield-check::before { content: "\f52f"; } +.bi-shield-exclamation::before { content: "\f530"; } +.bi-shield-fill-check::before { content: "\f531"; } +.bi-shield-fill-exclamation::before { content: "\f532"; } +.bi-shield-fill-minus::before { content: "\f533"; } +.bi-shield-fill-plus::before { content: "\f534"; } +.bi-shield-fill-x::before { content: "\f535"; } +.bi-shield-fill::before { content: "\f536"; } +.bi-shield-lock-fill::before { content: "\f537"; } +.bi-shield-lock::before { content: "\f538"; } +.bi-shield-minus::before { content: "\f539"; } +.bi-shield-plus::before { content: "\f53a"; } +.bi-shield-shaded::before { content: "\f53b"; } +.bi-shield-slash-fill::before { content: "\f53c"; } +.bi-shield-slash::before { content: "\f53d"; } +.bi-shield-x::before { content: "\f53e"; } +.bi-shield::before { content: "\f53f"; } +.bi-shift-fill::before { content: "\f540"; } +.bi-shift::before { content: "\f541"; } +.bi-shop-window::before { content: "\f542"; } +.bi-shop::before { content: "\f543"; } +.bi-shuffle::before { content: "\f544"; } +.bi-signpost-2-fill::before { content: "\f545"; } +.bi-signpost-2::before { content: "\f546"; } +.bi-signpost-fill::before { content: "\f547"; } +.bi-signpost-split-fill::before { content: "\f548"; } +.bi-signpost-split::before { content: "\f549"; } +.bi-signpost::before { content: "\f54a"; } +.bi-sim-fill::before { content: "\f54b"; } +.bi-sim::before { content: "\f54c"; } +.bi-skip-backward-btn-fill::before { content: "\f54d"; } +.bi-skip-backward-btn::before { content: "\f54e"; } +.bi-skip-backward-circle-fill::before { content: "\f54f"; } +.bi-skip-backward-circle::before { content: "\f550"; } +.bi-skip-backward-fill::before { content: "\f551"; } +.bi-skip-backward::before { content: "\f552"; } +.bi-skip-end-btn-fill::before { content: "\f553"; } +.bi-skip-end-btn::before { content: "\f554"; } +.bi-skip-end-circle-fill::before { content: "\f555"; } +.bi-skip-end-circle::before { content: "\f556"; } +.bi-skip-end-fill::before { content: "\f557"; } +.bi-skip-end::before { content: "\f558"; } +.bi-skip-forward-btn-fill::before { content: "\f559"; } +.bi-skip-forward-btn::before { content: "\f55a"; } +.bi-skip-forward-circle-fill::before { content: "\f55b"; } +.bi-skip-forward-circle::before { content: "\f55c"; } +.bi-skip-forward-fill::before { content: "\f55d"; } +.bi-skip-forward::before { content: "\f55e"; } +.bi-skip-start-btn-fill::before { content: "\f55f"; } +.bi-skip-start-btn::before { content: "\f560"; } +.bi-skip-start-circle-fill::before { content: "\f561"; } +.bi-skip-start-circle::before { content: "\f562"; } +.bi-skip-start-fill::before { content: "\f563"; } +.bi-skip-start::before { content: "\f564"; } +.bi-slack::before { content: "\f565"; } +.bi-slash-circle-fill::before { content: "\f566"; } +.bi-slash-circle::before { content: "\f567"; } +.bi-slash-square-fill::before { content: "\f568"; } +.bi-slash-square::before { content: "\f569"; } +.bi-slash::before { content: "\f56a"; } +.bi-sliders::before { content: "\f56b"; } +.bi-smartwatch::before { content: "\f56c"; } +.bi-snow::before { content: "\f56d"; } +.bi-snow2::before { content: "\f56e"; } +.bi-snow3::before { content: "\f56f"; } +.bi-sort-alpha-down-alt::before { content: "\f570"; } +.bi-sort-alpha-down::before { content: "\f571"; } +.bi-sort-alpha-up-alt::before { content: "\f572"; } +.bi-sort-alpha-up::before { content: "\f573"; } +.bi-sort-down-alt::before { content: "\f574"; } +.bi-sort-down::before { content: "\f575"; } +.bi-sort-numeric-down-alt::before { content: "\f576"; } +.bi-sort-numeric-down::before { content: "\f577"; } +.bi-sort-numeric-up-alt::before { content: "\f578"; } +.bi-sort-numeric-up::before { content: "\f579"; } +.bi-sort-up-alt::before { content: "\f57a"; } +.bi-sort-up::before { content: "\f57b"; } +.bi-soundwave::before { content: "\f57c"; } +.bi-speaker-fill::before { content: "\f57d"; } +.bi-speaker::before { content: "\f57e"; } +.bi-speedometer::before { content: "\f57f"; } +.bi-speedometer2::before { content: "\f580"; } +.bi-spellcheck::before { content: "\f581"; } +.bi-square-fill::before { content: "\f582"; } +.bi-square-half::before { content: "\f583"; } +.bi-square::before { content: "\f584"; } +.bi-stack::before { content: "\f585"; } +.bi-star-fill::before { content: "\f586"; } +.bi-star-half::before { content: "\f587"; } +.bi-star::before { content: "\f588"; } +.bi-stars::before { content: "\f589"; } +.bi-stickies-fill::before { content: "\f58a"; } +.bi-stickies::before { content: "\f58b"; } +.bi-sticky-fill::before { content: "\f58c"; } +.bi-sticky::before { content: "\f58d"; } +.bi-stop-btn-fill::before { content: "\f58e"; } +.bi-stop-btn::before { content: "\f58f"; } +.bi-stop-circle-fill::before { content: "\f590"; } +.bi-stop-circle::before { content: "\f591"; } +.bi-stop-fill::before { content: "\f592"; } +.bi-stop::before { content: "\f593"; } +.bi-stoplights-fill::before { content: "\f594"; } +.bi-stoplights::before { content: "\f595"; } +.bi-stopwatch-fill::before { content: "\f596"; } +.bi-stopwatch::before { content: "\f597"; } +.bi-subtract::before { content: "\f598"; } +.bi-suit-club-fill::before { content: "\f599"; } +.bi-suit-club::before { content: "\f59a"; } +.bi-suit-diamond-fill::before { content: "\f59b"; } +.bi-suit-diamond::before { content: "\f59c"; } +.bi-suit-heart-fill::before { content: "\f59d"; } +.bi-suit-heart::before { content: "\f59e"; } +.bi-suit-spade-fill::before { content: "\f59f"; } +.bi-suit-spade::before { content: "\f5a0"; } +.bi-sun-fill::before { content: "\f5a1"; } +.bi-sun::before { content: "\f5a2"; } +.bi-sunglasses::before { content: "\f5a3"; } +.bi-sunrise-fill::before { content: "\f5a4"; } +.bi-sunrise::before { content: "\f5a5"; } +.bi-sunset-fill::before { content: "\f5a6"; } +.bi-sunset::before { content: "\f5a7"; } +.bi-symmetry-horizontal::before { content: "\f5a8"; } +.bi-symmetry-vertical::before { content: "\f5a9"; } +.bi-table::before { content: "\f5aa"; } +.bi-tablet-fill::before { content: "\f5ab"; } +.bi-tablet-landscape-fill::before { content: "\f5ac"; } +.bi-tablet-landscape::before { content: "\f5ad"; } +.bi-tablet::before { content: "\f5ae"; } +.bi-tag-fill::before { content: "\f5af"; } +.bi-tag::before { content: "\f5b0"; } +.bi-tags-fill::before { content: "\f5b1"; } +.bi-tags::before { content: "\f5b2"; } +.bi-telegram::before { content: "\f5b3"; } +.bi-telephone-fill::before { content: "\f5b4"; } +.bi-telephone-forward-fill::before { content: "\f5b5"; } +.bi-telephone-forward::before { content: "\f5b6"; } +.bi-telephone-inbound-fill::before { content: "\f5b7"; } +.bi-telephone-inbound::before { content: "\f5b8"; } +.bi-telephone-minus-fill::before { content: "\f5b9"; } +.bi-telephone-minus::before { content: "\f5ba"; } +.bi-telephone-outbound-fill::before { content: "\f5bb"; } +.bi-telephone-outbound::before { content: "\f5bc"; } +.bi-telephone-plus-fill::before { content: "\f5bd"; } +.bi-telephone-plus::before { content: "\f5be"; } +.bi-telephone-x-fill::before { content: "\f5bf"; } +.bi-telephone-x::before { content: "\f5c0"; } +.bi-telephone::before { content: "\f5c1"; } +.bi-terminal-fill::before { content: "\f5c2"; } +.bi-terminal::before { content: "\f5c3"; } +.bi-text-center::before { content: "\f5c4"; } +.bi-text-indent-left::before { content: "\f5c5"; } +.bi-text-indent-right::before { content: "\f5c6"; } +.bi-text-left::before { content: "\f5c7"; } +.bi-text-paragraph::before { content: "\f5c8"; } +.bi-text-right::before { content: "\f5c9"; } +.bi-textarea-resize::before { content: "\f5ca"; } +.bi-textarea-t::before { content: "\f5cb"; } +.bi-textarea::before { content: "\f5cc"; } +.bi-thermometer-half::before { content: "\f5cd"; } +.bi-thermometer-high::before { content: "\f5ce"; } +.bi-thermometer-low::before { content: "\f5cf"; } +.bi-thermometer-snow::before { content: "\f5d0"; } +.bi-thermometer-sun::before { content: "\f5d1"; } +.bi-thermometer::before { content: "\f5d2"; } +.bi-three-dots-vertical::before { content: "\f5d3"; } +.bi-three-dots::before { content: "\f5d4"; } +.bi-toggle-off::before { content: "\f5d5"; } +.bi-toggle-on::before { content: "\f5d6"; } +.bi-toggle2-off::before { content: "\f5d7"; } +.bi-toggle2-on::before { content: "\f5d8"; } +.bi-toggles::before { content: "\f5d9"; } +.bi-toggles2::before { content: "\f5da"; } +.bi-tools::before { content: "\f5db"; } +.bi-tornado::before { content: "\f5dc"; } +.bi-trash-fill::before { content: "\f5dd"; } +.bi-trash::before { content: "\f5de"; } +.bi-trash2-fill::before { content: "\f5df"; } +.bi-trash2::before { content: "\f5e0"; } +.bi-tree-fill::before { content: "\f5e1"; } +.bi-tree::before { content: "\f5e2"; } +.bi-triangle-fill::before { content: "\f5e3"; } +.bi-triangle-half::before { content: "\f5e4"; } +.bi-triangle::before { content: "\f5e5"; } +.bi-trophy-fill::before { content: "\f5e6"; } +.bi-trophy::before { content: "\f5e7"; } +.bi-tropical-storm::before { content: "\f5e8"; } +.bi-truck-flatbed::before { content: "\f5e9"; } +.bi-truck::before { content: "\f5ea"; } +.bi-tsunami::before { content: "\f5eb"; } +.bi-tv-fill::before { content: "\f5ec"; } +.bi-tv::before { content: "\f5ed"; } +.bi-twitch::before { content: "\f5ee"; } +.bi-twitter::before { content: "\f5ef"; } +.bi-type-bold::before { content: "\f5f0"; } +.bi-type-h1::before { content: "\f5f1"; } +.bi-type-h2::before { content: "\f5f2"; } +.bi-type-h3::before { content: "\f5f3"; } +.bi-type-italic::before { content: "\f5f4"; } +.bi-type-strikethrough::before { content: "\f5f5"; } +.bi-type-underline::before { content: "\f5f6"; } +.bi-type::before { content: "\f5f7"; } +.bi-ui-checks-grid::before { content: "\f5f8"; } +.bi-ui-checks::before { content: "\f5f9"; } +.bi-ui-radios-grid::before { content: "\f5fa"; } +.bi-ui-radios::before { content: "\f5fb"; } +.bi-umbrella-fill::before { content: "\f5fc"; } +.bi-umbrella::before { content: "\f5fd"; } +.bi-union::before { content: "\f5fe"; } +.bi-unlock-fill::before { content: "\f5ff"; } +.bi-unlock::before { content: "\f600"; } +.bi-upc-scan::before { content: "\f601"; } +.bi-upc::before { content: "\f602"; } +.bi-upload::before { content: "\f603"; } +.bi-vector-pen::before { content: "\f604"; } +.bi-view-list::before { content: "\f605"; } +.bi-view-stacked::before { content: "\f606"; } +.bi-vinyl-fill::before { content: "\f607"; } +.bi-vinyl::before { content: "\f608"; } +.bi-voicemail::before { content: "\f609"; } +.bi-volume-down-fill::before { content: "\f60a"; } +.bi-volume-down::before { content: "\f60b"; } +.bi-volume-mute-fill::before { content: "\f60c"; } +.bi-volume-mute::before { content: "\f60d"; } +.bi-volume-off-fill::before { content: "\f60e"; } +.bi-volume-off::before { content: "\f60f"; } +.bi-volume-up-fill::before { content: "\f610"; } +.bi-volume-up::before { content: "\f611"; } +.bi-vr::before { content: "\f612"; } +.bi-wallet-fill::before { content: "\f613"; } +.bi-wallet::before { content: "\f614"; } +.bi-wallet2::before { content: "\f615"; } +.bi-watch::before { content: "\f616"; } +.bi-water::before { content: "\f617"; } +.bi-whatsapp::before { content: "\f618"; } +.bi-wifi-1::before { content: "\f619"; } +.bi-wifi-2::before { content: "\f61a"; } +.bi-wifi-off::before { content: "\f61b"; } +.bi-wifi::before { content: "\f61c"; } +.bi-wind::before { content: "\f61d"; } +.bi-window-dock::before { content: "\f61e"; } +.bi-window-sidebar::before { content: "\f61f"; } +.bi-window::before { content: "\f620"; } +.bi-wrench::before { content: "\f621"; } +.bi-x-circle-fill::before { content: "\f622"; } +.bi-x-circle::before { content: "\f623"; } +.bi-x-diamond-fill::before { content: "\f624"; } +.bi-x-diamond::before { content: "\f625"; } +.bi-x-octagon-fill::before { content: "\f626"; } +.bi-x-octagon::before { content: "\f627"; } +.bi-x-square-fill::before { content: "\f628"; } +.bi-x-square::before { content: "\f629"; } +.bi-x::before { content: "\f62a"; } +.bi-youtube::before { content: "\f62b"; } +.bi-zoom-in::before { content: "\f62c"; } +.bi-zoom-out::before { content: "\f62d"; } +.bi-bank::before { content: "\f62e"; } +.bi-bank2::before { content: "\f62f"; } +.bi-bell-slash-fill::before { content: "\f630"; } +.bi-bell-slash::before { content: "\f631"; } +.bi-cash-coin::before { content: "\f632"; } +.bi-check-lg::before { content: "\f633"; } +.bi-coin::before { content: "\f634"; } +.bi-currency-bitcoin::before { content: "\f635"; } +.bi-currency-dollar::before { content: "\f636"; } +.bi-currency-euro::before { content: "\f637"; } +.bi-currency-exchange::before { content: "\f638"; } +.bi-currency-pound::before { content: "\f639"; } +.bi-currency-yen::before { content: "\f63a"; } +.bi-dash-lg::before { content: "\f63b"; } +.bi-exclamation-lg::before { content: "\f63c"; } +.bi-file-earmark-pdf-fill::before { content: "\f63d"; } +.bi-file-earmark-pdf::before { content: "\f63e"; } +.bi-file-pdf-fill::before { content: "\f63f"; } +.bi-file-pdf::before { content: "\f640"; } +.bi-gender-ambiguous::before { content: "\f641"; } +.bi-gender-female::before { content: "\f642"; } +.bi-gender-male::before { content: "\f643"; } +.bi-gender-trans::before { content: "\f644"; } +.bi-headset-vr::before { content: "\f645"; } +.bi-info-lg::before { content: "\f646"; } +.bi-mastodon::before { content: "\f647"; } +.bi-messenger::before { content: "\f648"; } +.bi-piggy-bank-fill::before { content: "\f649"; } +.bi-piggy-bank::before { content: "\f64a"; } +.bi-pin-map-fill::before { content: "\f64b"; } +.bi-pin-map::before { content: "\f64c"; } +.bi-plus-lg::before { content: "\f64d"; } +.bi-question-lg::before { content: "\f64e"; } +.bi-recycle::before { content: "\f64f"; } +.bi-reddit::before { content: "\f650"; } +.bi-safe-fill::before { content: "\f651"; } +.bi-safe2-fill::before { content: "\f652"; } +.bi-safe2::before { content: "\f653"; } +.bi-sd-card-fill::before { content: "\f654"; } +.bi-sd-card::before { content: "\f655"; } +.bi-skype::before { content: "\f656"; } +.bi-slash-lg::before { content: "\f657"; } +.bi-translate::before { content: "\f658"; } +.bi-x-lg::before { content: "\f659"; } +.bi-safe::before { content: "\f65a"; } +.bi-apple::before { content: "\f65b"; } +.bi-microsoft::before { content: "\f65d"; } +.bi-windows::before { content: "\f65e"; } +.bi-behance::before { content: "\f65c"; } +.bi-dribbble::before { content: "\f65f"; } +.bi-line::before { content: "\f660"; } +.bi-medium::before { content: "\f661"; } +.bi-paypal::before { content: "\f662"; } +.bi-pinterest::before { content: "\f663"; } +.bi-signal::before { content: "\f664"; } +.bi-snapchat::before { content: "\f665"; } +.bi-spotify::before { content: "\f666"; } +.bi-stack-overflow::before { content: "\f667"; } +.bi-strava::before { content: "\f668"; } +.bi-wordpress::before { content: "\f669"; } +.bi-vimeo::before { content: "\f66a"; } +.bi-activity::before { content: "\f66b"; } +.bi-easel2-fill::before { content: "\f66c"; } +.bi-easel2::before { content: "\f66d"; } +.bi-easel3-fill::before { content: "\f66e"; } +.bi-easel3::before { content: "\f66f"; } +.bi-fan::before { content: "\f670"; } +.bi-fingerprint::before { content: "\f671"; } +.bi-graph-down-arrow::before { content: "\f672"; } +.bi-graph-up-arrow::before { content: "\f673"; } +.bi-hypnotize::before { content: "\f674"; } +.bi-magic::before { content: "\f675"; } +.bi-person-rolodex::before { content: "\f676"; } +.bi-person-video::before { content: "\f677"; } +.bi-person-video2::before { content: "\f678"; } +.bi-person-video3::before { content: "\f679"; } +.bi-person-workspace::before { content: "\f67a"; } +.bi-radioactive::before { content: "\f67b"; } +.bi-webcam-fill::before { content: "\f67c"; } +.bi-webcam::before { content: "\f67d"; } +.bi-yin-yang::before { content: "\f67e"; } +.bi-bandaid-fill::before { content: "\f680"; } +.bi-bandaid::before { content: "\f681"; } +.bi-bluetooth::before { content: "\f682"; } +.bi-body-text::before { content: "\f683"; } +.bi-boombox::before { content: "\f684"; } +.bi-boxes::before { content: "\f685"; } +.bi-dpad-fill::before { content: "\f686"; } +.bi-dpad::before { content: "\f687"; } +.bi-ear-fill::before { content: "\f688"; } +.bi-ear::before { content: "\f689"; } +.bi-envelope-check-1::before { content: "\f68a"; } +.bi-envelope-check-fill::before { content: "\f68b"; } +.bi-envelope-check::before { content: "\f68c"; } +.bi-envelope-dash-1::before { content: "\f68d"; } +.bi-envelope-dash-fill::before { content: "\f68e"; } +.bi-envelope-dash::before { content: "\f68f"; } +.bi-envelope-exclamation-1::before { content: "\f690"; } +.bi-envelope-exclamation-fill::before { content: "\f691"; } +.bi-envelope-exclamation::before { content: "\f692"; } +.bi-envelope-plus-fill::before { content: "\f693"; } +.bi-envelope-plus::before { content: "\f694"; } +.bi-envelope-slash-1::before { content: "\f695"; } +.bi-envelope-slash-fill::before { content: "\f696"; } +.bi-envelope-slash::before { content: "\f697"; } +.bi-envelope-x-1::before { content: "\f698"; } +.bi-envelope-x-fill::before { content: "\f699"; } +.bi-envelope-x::before { content: "\f69a"; } +.bi-explicit-fill::before { content: "\f69b"; } +.bi-explicit::before { content: "\f69c"; } +.bi-git::before { content: "\f69d"; } +.bi-infinity::before { content: "\f69e"; } +.bi-list-columns-reverse::before { content: "\f69f"; } +.bi-list-columns::before { content: "\f6a0"; } +.bi-meta::before { content: "\f6a1"; } +.bi-mortorboard-fill::before { content: "\f6a2"; } +.bi-mortorboard::before { content: "\f6a3"; } +.bi-nintendo-switch::before { content: "\f6a4"; } +.bi-pc-display-horizontal::before { content: "\f6a5"; } +.bi-pc-display::before { content: "\f6a6"; } +.bi-pc-horizontal::before { content: "\f6a7"; } +.bi-pc::before { content: "\f6a8"; } +.bi-playstation::before { content: "\f6a9"; } +.bi-plus-slash-minus::before { content: "\f6aa"; } +.bi-projector-fill::before { content: "\f6ab"; } +.bi-projector::before { content: "\f6ac"; } +.bi-qr-code-scan::before { content: "\f6ad"; } +.bi-qr-code::before { content: "\f6ae"; } +.bi-quora::before { content: "\f6af"; } +.bi-quote::before { content: "\f6b0"; } +.bi-robot::before { content: "\f6b1"; } +.bi-send-check-fill::before { content: "\f6b2"; } +.bi-send-check::before { content: "\f6b3"; } +.bi-send-dash-fill::before { content: "\f6b4"; } +.bi-send-dash::before { content: "\f6b5"; } +.bi-send-exclamation-1::before { content: "\f6b6"; } +.bi-send-exclamation-fill::before { content: "\f6b7"; } +.bi-send-exclamation::before { content: "\f6b8"; } +.bi-send-fill::before { content: "\f6b9"; } +.bi-send-plus-fill::before { content: "\f6ba"; } +.bi-send-plus::before { content: "\f6bb"; } +.bi-send-slash-fill::before { content: "\f6bc"; } +.bi-send-slash::before { content: "\f6bd"; } +.bi-send-x-fill::before { content: "\f6be"; } +.bi-send-x::before { content: "\f6bf"; } +.bi-send::before { content: "\f6c0"; } +.bi-steam::before { content: "\f6c1"; } +.bi-terminal-dash-1::before { content: "\f6c2"; } +.bi-terminal-dash::before { content: "\f6c3"; } +.bi-terminal-plus::before { content: "\f6c4"; } +.bi-terminal-split::before { content: "\f6c5"; } +.bi-ticket-detailed-fill::before { content: "\f6c6"; } +.bi-ticket-detailed::before { content: "\f6c7"; } +.bi-ticket-fill::before { content: "\f6c8"; } +.bi-ticket-perforated-fill::before { content: "\f6c9"; } +.bi-ticket-perforated::before { content: "\f6ca"; } +.bi-ticket::before { content: "\f6cb"; } +.bi-tiktok::before { content: "\f6cc"; } +.bi-window-dash::before { content: "\f6cd"; } +.bi-window-desktop::before { content: "\f6ce"; } +.bi-window-fullscreen::before { content: "\f6cf"; } +.bi-window-plus::before { content: "\f6d0"; } +.bi-window-split::before { content: "\f6d1"; } +.bi-window-stack::before { content: "\f6d2"; } +.bi-window-x::before { content: "\f6d3"; } +.bi-xbox::before { content: "\f6d4"; } +.bi-ethernet::before { content: "\f6d5"; } +.bi-hdmi-fill::before { content: "\f6d6"; } +.bi-hdmi::before { content: "\f6d7"; } +.bi-usb-c-fill::before { content: "\f6d8"; } +.bi-usb-c::before { content: "\f6d9"; } +.bi-usb-fill::before { content: "\f6da"; } +.bi-usb-plug-fill::before { content: "\f6db"; } +.bi-usb-plug::before { content: "\f6dc"; } +.bi-usb-symbol::before { content: "\f6dd"; } +.bi-usb::before { content: "\f6de"; } +.bi-boombox-fill::before { content: "\f6df"; } +.bi-displayport-1::before { content: "\f6e0"; } +.bi-displayport::before { content: "\f6e1"; } +.bi-gpu-card::before { content: "\f6e2"; } +.bi-memory::before { content: "\f6e3"; } +.bi-modem-fill::before { content: "\f6e4"; } +.bi-modem::before { content: "\f6e5"; } +.bi-motherboard-fill::before { content: "\f6e6"; } +.bi-motherboard::before { content: "\f6e7"; } +.bi-optical-audio-fill::before { content: "\f6e8"; } +.bi-optical-audio::before { content: "\f6e9"; } +.bi-pci-card::before { content: "\f6ea"; } +.bi-router-fill::before { content: "\f6eb"; } +.bi-router::before { content: "\f6ec"; } +.bi-ssd-fill::before { content: "\f6ed"; } +.bi-ssd::before { content: "\f6ee"; } +.bi-thunderbolt-fill::before { content: "\f6ef"; } +.bi-thunderbolt::before { content: "\f6f0"; } +.bi-usb-drive-fill::before { content: "\f6f1"; } +.bi-usb-drive::before { content: "\f6f2"; } +.bi-usb-micro-fill::before { content: "\f6f3"; } +.bi-usb-micro::before { content: "\f6f4"; } +.bi-usb-mini-fill::before { content: "\f6f5"; } +.bi-usb-mini::before { content: "\f6f6"; } +.bi-cloud-haze2::before { content: "\f6f7"; } +.bi-device-hdd-fill::before { content: "\f6f8"; } +.bi-device-hdd::before { content: "\f6f9"; } +.bi-device-ssd-fill::before { content: "\f6fa"; } +.bi-device-ssd::before { content: "\f6fb"; } +.bi-displayport-fill::before { content: "\f6fc"; } +.bi-mortarboard-fill::before { content: "\f6fd"; } +.bi-mortarboard::before { content: "\f6fe"; } +.bi-terminal-x::before { content: "\f6ff"; } +.bi-arrow-through-heart-fill::before { content: "\f700"; } +.bi-arrow-through-heart::before { content: "\f701"; } +.bi-badge-sd-fill::before { content: "\f702"; } +.bi-badge-sd::before { content: "\f703"; } +.bi-bag-heart-fill::before { content: "\f704"; } +.bi-bag-heart::before { content: "\f705"; } +.bi-balloon-fill::before { content: "\f706"; } +.bi-balloon-heart-fill::before { content: "\f707"; } +.bi-balloon-heart::before { content: "\f708"; } +.bi-balloon::before { content: "\f709"; } +.bi-box2-fill::before { content: "\f70a"; } +.bi-box2-heart-fill::before { content: "\f70b"; } +.bi-box2-heart::before { content: "\f70c"; } +.bi-box2::before { content: "\f70d"; } +.bi-braces-asterisk::before { content: "\f70e"; } +.bi-calendar-heart-fill::before { content: "\f70f"; } +.bi-calendar-heart::before { content: "\f710"; } +.bi-calendar2-heart-fill::before { content: "\f711"; } +.bi-calendar2-heart::before { content: "\f712"; } +.bi-chat-heart-fill::before { content: "\f713"; } +.bi-chat-heart::before { content: "\f714"; } +.bi-chat-left-heart-fill::before { content: "\f715"; } +.bi-chat-left-heart::before { content: "\f716"; } +.bi-chat-right-heart-fill::before { content: "\f717"; } +.bi-chat-right-heart::before { content: "\f718"; } +.bi-chat-square-heart-fill::before { content: "\f719"; } +.bi-chat-square-heart::before { content: "\f71a"; } +.bi-clipboard-check-fill::before { content: "\f71b"; } +.bi-clipboard-data-fill::before { content: "\f71c"; } +.bi-clipboard-fill::before { content: "\f71d"; } +.bi-clipboard-heart-fill::before { content: "\f71e"; } +.bi-clipboard-heart::before { content: "\f71f"; } +.bi-clipboard-minus-fill::before { content: "\f720"; } +.bi-clipboard-plus-fill::before { content: "\f721"; } +.bi-clipboard-pulse::before { content: "\f722"; } +.bi-clipboard-x-fill::before { content: "\f723"; } +.bi-clipboard2-check-fill::before { content: "\f724"; } +.bi-clipboard2-check::before { content: "\f725"; } +.bi-clipboard2-data-fill::before { content: "\f726"; } +.bi-clipboard2-data::before { content: "\f727"; } +.bi-clipboard2-fill::before { content: "\f728"; } +.bi-clipboard2-heart-fill::before { content: "\f729"; } +.bi-clipboard2-heart::before { content: "\f72a"; } +.bi-clipboard2-minus-fill::before { content: "\f72b"; } +.bi-clipboard2-minus::before { content: "\f72c"; } +.bi-clipboard2-plus-fill::before { content: "\f72d"; } +.bi-clipboard2-plus::before { content: "\f72e"; } +.bi-clipboard2-pulse-fill::before { content: "\f72f"; } +.bi-clipboard2-pulse::before { content: "\f730"; } +.bi-clipboard2-x-fill::before { content: "\f731"; } +.bi-clipboard2-x::before { content: "\f732"; } +.bi-clipboard2::before { content: "\f733"; } +.bi-emoji-kiss-fill::before { content: "\f734"; } +.bi-emoji-kiss::before { content: "\f735"; } +.bi-envelope-heart-fill::before { content: "\f736"; } +.bi-envelope-heart::before { content: "\f737"; } +.bi-envelope-open-heart-fill::before { content: "\f738"; } +.bi-envelope-open-heart::before { content: "\f739"; } +.bi-envelope-paper-fill::before { content: "\f73a"; } +.bi-envelope-paper-heart-fill::before { content: "\f73b"; } +.bi-envelope-paper-heart::before { content: "\f73c"; } +.bi-envelope-paper::before { content: "\f73d"; } +.bi-filetype-aac::before { content: "\f73e"; } +.bi-filetype-ai::before { content: "\f73f"; } +.bi-filetype-bmp::before { content: "\f740"; } +.bi-filetype-cs::before { content: "\f741"; } +.bi-filetype-css::before { content: "\f742"; } +.bi-filetype-csv::before { content: "\f743"; } +.bi-filetype-doc::before { content: "\f744"; } +.bi-filetype-docx::before { content: "\f745"; } +.bi-filetype-exe::before { content: "\f746"; } +.bi-filetype-gif::before { content: "\f747"; } +.bi-filetype-heic::before { content: "\f748"; } +.bi-filetype-html::before { content: "\f749"; } +.bi-filetype-java::before { content: "\f74a"; } +.bi-filetype-jpg::before { content: "\f74b"; } +.bi-filetype-js::before { content: "\f74c"; } +.bi-filetype-jsx::before { content: "\f74d"; } +.bi-filetype-key::before { content: "\f74e"; } +.bi-filetype-m4p::before { content: "\f74f"; } +.bi-filetype-md::before { content: "\f750"; } +.bi-filetype-mdx::before { content: "\f751"; } +.bi-filetype-mov::before { content: "\f752"; } +.bi-filetype-mp3::before { content: "\f753"; } +.bi-filetype-mp4::before { content: "\f754"; } +.bi-filetype-otf::before { content: "\f755"; } +.bi-filetype-pdf::before { content: "\f756"; } +.bi-filetype-php::before { content: "\f757"; } +.bi-filetype-png::before { content: "\f758"; } +.bi-filetype-ppt-1::before { content: "\f759"; } +.bi-filetype-ppt::before { content: "\f75a"; } +.bi-filetype-psd::before { content: "\f75b"; } +.bi-filetype-py::before { content: "\f75c"; } +.bi-filetype-raw::before { content: "\f75d"; } +.bi-filetype-rb::before { content: "\f75e"; } +.bi-filetype-sass::before { content: "\f75f"; } +.bi-filetype-scss::before { content: "\f760"; } +.bi-filetype-sh::before { content: "\f761"; } +.bi-filetype-svg::before { content: "\f762"; } +.bi-filetype-tiff::before { content: "\f763"; } +.bi-filetype-tsx::before { content: "\f764"; } +.bi-filetype-ttf::before { content: "\f765"; } +.bi-filetype-txt::before { content: "\f766"; } +.bi-filetype-wav::before { content: "\f767"; } +.bi-filetype-woff::before { content: "\f768"; } +.bi-filetype-xls-1::before { content: "\f769"; } +.bi-filetype-xls::before { content: "\f76a"; } +.bi-filetype-xml::before { content: "\f76b"; } +.bi-filetype-yml::before { content: "\f76c"; } +.bi-heart-arrow::before { content: "\f76d"; } +.bi-heart-pulse-fill::before { content: "\f76e"; } +.bi-heart-pulse::before { content: "\f76f"; } +.bi-heartbreak-fill::before { content: "\f770"; } +.bi-heartbreak::before { content: "\f771"; } +.bi-hearts::before { content: "\f772"; } +.bi-hospital-fill::before { content: "\f773"; } +.bi-hospital::before { content: "\f774"; } +.bi-house-heart-fill::before { content: "\f775"; } +.bi-house-heart::before { content: "\f776"; } +.bi-incognito::before { content: "\f777"; } +.bi-magnet-fill::before { content: "\f778"; } +.bi-magnet::before { content: "\f779"; } +.bi-person-heart::before { content: "\f77a"; } +.bi-person-hearts::before { content: "\f77b"; } +.bi-phone-flip::before { content: "\f77c"; } +.bi-plugin::before { content: "\f77d"; } +.bi-postage-fill::before { content: "\f77e"; } +.bi-postage-heart-fill::before { content: "\f77f"; } +.bi-postage-heart::before { content: "\f780"; } +.bi-postage::before { content: "\f781"; } +.bi-postcard-fill::before { content: "\f782"; } +.bi-postcard-heart-fill::before { content: "\f783"; } +.bi-postcard-heart::before { content: "\f784"; } +.bi-postcard::before { content: "\f785"; } +.bi-search-heart-fill::before { content: "\f786"; } +.bi-search-heart::before { content: "\f787"; } +.bi-sliders2-vertical::before { content: "\f788"; } +.bi-sliders2::before { content: "\f789"; } +.bi-trash3-fill::before { content: "\f78a"; } +.bi-trash3::before { content: "\f78b"; } +.bi-valentine::before { content: "\f78c"; } +.bi-valentine2::before { content: "\f78d"; } +.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } +.bi-wrench-adjustable-circle::before { content: "\f78f"; } +.bi-wrench-adjustable::before { content: "\f790"; } +.bi-filetype-json::before { content: "\f791"; } +.bi-filetype-pptx::before { content: "\f792"; } +.bi-filetype-xlsx::before { content: "\f793"; } diff --git a/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap-icons.woff b/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap-icons.woff new file mode 100644 index 0000000000000000000000000000000000000000..b26ccd1ac9f9f1fbc980e93531398364f6f03cd2 GIT binary patch literal 137124 zcma%@WmHsO*tchh85%_d=?89+ekW&jlt>5?8mK%`q5lx_q;Ktj4Z z9P&N;zt;19cs@O@b*{PhZ(sYKea<=z1I*Gx=l*>d90r5oP=AIILy!31eE%Cm<^TSt zs`o?*27?noxioY0||Y(@`+kwH7G5My@3M+~Jw$D;RuR7h1;z9n8o&IKSgF z2Wuz;`;moC(#~BZw)T~iiz^JiQwoD|?ZIHrw~Cjt{5(^wES_6f%vs*GD7CV1etkgr zY_3Crm7f z=n=G8&(x)dwD8Z`oU?O@l*ViWIyOc;v0Jcr|m||MPEPduEz$rMP{kAw6Jj zU`0;PBS!euK=D_zSw{5x)b}DJB=<#H7uxo&hSA6c18lRo0qs?@c?~?TBOpDH^MiR3 zrmkGJShh?yN47#Xud%SPz_0M)^F^6>xp@vq{X0apR%VYZ0r+*z3m#BoaVEXF_hjC4o5ZZ_~@d-KHiiui2yY}Uhm&y<=r zq$6i<-e*Jg!WO1|Yj(U%giu=}c6d<)Ut3*ocvOT`TXSUiaL;s5O?bFZgt%X$Vt7*o z*{|+0{6~bmpHBX-uZTRK0`X6!%Da3@!KjC{T4BTUm3X9?9JVyH8b44*Pa_iYZlY9Z zAMgzKR1y_w6b!FdB8t@QhY6mhjAgpn%0A5y!;sptJ1A$PtR~-x<@BRmCWER!7oqGY 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%0Av_>K5 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:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:#6c757d}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-bg: transparent;--bs-table-accent-bg: transparent;--bs-table-striped-color: #212529;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #212529;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #212529;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg: var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg: var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg: #cfe2ff;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg: #e2e3e5;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg: #d1e7dd;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg: #cff4fc;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg: #fff3cd;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg: #f8d7da;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg: #f8f9fa;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg: #212529;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #ffffff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #ffffff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #ffffff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::-webkit-file-upload-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px);padding:.25rem .5rem;font-size:0.875rem;border-radius:.2rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:.2rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.3rem}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;color-adjust:exact;-webkit-print-color-adjust:exact}.form-check-input[type=checkbox],.shiny-input-container .checkbox input[type=checkbox],.shiny-input-container .checkbox-inline input[type=checkbox],.shiny-input-container .radio input[type=checkbox],.shiny-input-container .radio-inline input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-inline,.shiny-input-container .checkbox-inline,.shiny-input-container .radio-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#198754;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#198754}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#198754}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#198754}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group .form-control:valid,.input-group .form-control.is-valid,.was-validated .input-group .form-select:valid,.input-group .form-select.is-valid{z-index:1}.was-validated .input-group .form-control:valid:focus,.input-group .form-control.is-valid:focus,.was-validated .input-group .form-select:valid:focus,.input-group .form-select.is-valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#dc3545}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#dc3545}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#dc3545}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group .form-control:invalid,.input-group .form-control.is-invalid,.was-validated .input-group .form-select:invalid,.input-group .form-select.is-invalid{z-index:2}.was-validated .input-group .form-control:invalid:focus,.input-group .form-control.is-invalid:focus,.was-validated .input-group .form-select:invalid:focus,.input-group .form-select.is-invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-default{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-default:hover{color:#000;background-color:#e3e6ea;border-color:#e1e5e9}.btn-check:focus+.btn-default,.btn-default:focus{color:#000;background-color:#e3e6ea;border-color:#e1e5e9;box-shadow:0 0 0 .25rem rgba(189,192,196,.5)}.btn-check:checked+.btn-default,.btn-check:active+.btn-default,.btn-default:active,.btn-default.active,.show>.btn-default.dropdown-toggle{color:#000;background-color:#e5e8eb;border-color:#e1e5e9}.btn-check:checked+.btn-default:focus,.btn-check:active+.btn-default:focus,.btn-default:active:focus,.btn-default.active:focus,.show>.btn-default.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(189,192,196,.5)}.btn-default:disabled,.btn-default.disabled{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:checked+.btn-primary,.btn-check:active+.btn-primary,.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:checked+.btn-primary:focus,.btn-check:active+.btn-primary:focus,.btn-primary:active:focus,.btn-primary.active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary:disabled,.btn-primary.disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:checked+.btn-secondary,.btn-check:active+.btn-secondary,.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:checked+.btn-secondary:focus,.btn-check:active+.btn-secondary:focus,.btn-secondary:active:focus,.btn-secondary.active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary:disabled,.btn-secondary.disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:checked+.btn-success,.btn-check:active+.btn-success,.btn-success:active,.btn-success.active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:checked+.btn-success:focus,.btn-check:active+.btn-success:focus,.btn-success:active:focus,.btn-success.active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success:disabled,.btn-success.disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:checked+.btn-info,.btn-check:active+.btn-info,.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:checked+.btn-info:focus,.btn-check:active+.btn-info:focus,.btn-info:active:focus,.btn-info.active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info:disabled,.btn-info.disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:checked+.btn-warning,.btn-check:active+.btn-warning,.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:checked+.btn-warning:focus,.btn-check:active+.btn-warning:focus,.btn-warning:active:focus,.btn-warning.active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning:disabled,.btn-warning.disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:checked+.btn-danger,.btn-check:active+.btn-danger,.btn-danger:active,.btn-danger.active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:checked+.btn-danger:focus,.btn-check:active+.btn-danger:focus,.btn-danger:active:focus,.btn-danger.active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger:disabled,.btn-danger.disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:checked+.btn-light,.btn-check:active+.btn-light,.btn-light:active,.btn-light.active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:checked+.btn-light:focus,.btn-check:active+.btn-light:focus,.btn-light:active:focus,.btn-light.active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light:disabled,.btn-light.disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:checked+.btn-dark,.btn-check:active+.btn-dark,.btn-dark:active,.btn-dark.active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:checked+.btn-dark:focus,.btn-check:active+.btn-dark:focus,.btn-dark:active:focus,.btn-dark.active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark:disabled,.btn-dark.disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-default{color:#dee2e6;border-color:#dee2e6;background-color:transparent}.btn-outline-default:hover{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-check:focus+.btn-outline-default,.btn-outline-default:focus{box-shadow:0 0 0 .25rem rgba(222,226,230,.5)}.btn-check:checked+.btn-outline-default,.btn-check:active+.btn-outline-default,.btn-outline-default:active,.btn-outline-default.active,.btn-outline-default.dropdown-toggle.show{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-check:checked+.btn-outline-default:focus,.btn-check:active+.btn-outline-default:focus,.btn-outline-default:active:focus,.btn-outline-default.active:focus,.btn-outline-default.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(222,226,230,.5)}.btn-outline-default:disabled,.btn-outline-default.disabled{color:#dee2e6;background-color:transparent}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd;background-color:transparent}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:checked+.btn-outline-primary,.btn-check:active+.btn-outline-primary,.btn-outline-primary:active,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:checked+.btn-outline-primary:focus,.btn-check:active+.btn-outline-primary:focus,.btn-outline-primary:active:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary:disabled,.btn-outline-primary.disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d;background-color:transparent}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:checked+.btn-outline-secondary,.btn-check:active+.btn-outline-secondary,.btn-outline-secondary:active,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:checked+.btn-outline-secondary:focus,.btn-check:active+.btn-outline-secondary:focus,.btn-outline-secondary:active:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary:disabled,.btn-outline-secondary.disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754;background-color:transparent}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:checked+.btn-outline-success,.btn-check:active+.btn-outline-success,.btn-outline-success:active,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show{color:#fff;background-color:#198754;border-color:#198754}.btn-check:checked+.btn-outline-success:focus,.btn-check:active+.btn-outline-success:focus,.btn-outline-success:active:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success:disabled,.btn-outline-success.disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0;background-color:transparent}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:checked+.btn-outline-info,.btn-check:active+.btn-outline-info,.btn-outline-info:active,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:checked+.btn-outline-info:focus,.btn-check:active+.btn-outline-info:focus,.btn-outline-info:active:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info:disabled,.btn-outline-info.disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107;background-color:transparent}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:checked+.btn-outline-warning,.btn-check:active+.btn-outline-warning,.btn-outline-warning:active,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:checked+.btn-outline-warning:focus,.btn-check:active+.btn-outline-warning:focus,.btn-outline-warning:active:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning:disabled,.btn-outline-warning.disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545;background-color:transparent}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:checked+.btn-outline-danger,.btn-check:active+.btn-outline-danger,.btn-outline-danger:active,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:checked+.btn-outline-danger:focus,.btn-check:active+.btn-outline-danger:focus,.btn-outline-danger:active:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger:disabled,.btn-outline-danger.disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa;background-color:transparent}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:checked+.btn-outline-light,.btn-check:active+.btn-outline-light,.btn-outline-light:active,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:checked+.btn-outline-light:focus,.btn-check:active+.btn-outline-light:focus,.btn-outline-light:active:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light:disabled,.btn-outline-light.disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529;background-color:transparent}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:checked+.btn-outline-dark,.btn-check:active+.btn-outline-dark,.btn-outline-dark:active,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show{color:#fff;background-color:#212529;border-color:#212529}.btn-check:checked+.btn-outline-dark:focus,.btn-check:active+.btn-outline-dark:focus,.btn-outline-dark:active:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark:disabled,.btn-outline-dark.disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:0.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:hover,.dropdown-menu-dark .dropdown-item:focus{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:none;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:none;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container-xxl,.navbar>.container-xl,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container,.navbar>.container-fluid{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-top,.navbar-expand-sm .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-top,.navbar-expand-md .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-top,.navbar-expand-lg .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-top,.navbar-expand-xl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-top,.navbar-expand-xxl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-top,.navbar-expand .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-light{background-color:#517699}.navbar-light .navbar-brand{color:#fdfefe}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#fdfefe}.navbar-light .navbar-nav .nav-link{color:#fdfefe}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(253,254,254,.8)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(253,254,254,.75)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .nav-link.active{color:#fdfefe}.navbar-light .navbar-toggler{color:#fdfefe;border-color:rgba(253,254,254,.4)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#fdfefe}.navbar-light .navbar-text a,.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#fdfefe}.navbar-dark{background-color:#517699}.navbar-dark .navbar-brand{color:#fdfefe}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fdfefe}.navbar-dark .navbar-nav .nav-link{color:#fdfefe}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(253,254,254,.8)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(253,254,254,.75)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active{color:#fdfefe}.navbar-dark .navbar-toggler{color:#fdfefe;border-color:rgba(253,254,254,.4)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:#fdfefe}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fdfefe}.card{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-0.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:0.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:0.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{color:#595a5c;background-color:#f8f9fa;border-color:#f5f6f8}.alert-default .alert-link{color:#47484a}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;display:-webkit-flex;height:1rem;overflow:hidden;font-size:0.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:1rem 1rem}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{color:#595a5c;background-color:#f8f9fa}.list-group-item-default.list-group-item-action:hover,.list-group-item-default.list-group-item-action:focus{color:#595a5c;background-color:#dfe0e1}.list-group-item-default.list-group-item-action.active{color:#fff;background-color:#595a5c;border-color:#595a5c}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:0.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.toast-header .btn-close{margin-right:-0.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(0.3rem - 1px);border-top-right-radius:calc(0.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-0.5rem -0.5rem -0.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem}.modal-footer{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(0.3rem - 1px);border-bottom-left-radius:calc(0.3rem - 1px)}.modal-footer>*{margin:.25rem}@media(min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media(min-width: 992px){.modal-lg,.modal-xl{max-width:800px}}@media(min-width: 1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[data-popper-placement^=top]{padding:.4rem 0}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:0}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-end,.bs-tooltip-auto[data-popper-placement^=right]{padding:0 .4rem}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[data-popper-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:0}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-start,.bs-tooltip-auto[data-popper-placement^=left]{padding:0 .4rem}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0 /* rtl:ignore */;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-0.5rem - 1px)}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-0.5rem - 1px)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-0.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(0.3rem - 1px);border-top-right-radius:calc(0.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;background-color:currentColor;border-radius:50%;opacity:0;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{animation-duration:1.5s;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-0.5rem;margin-right:-0.5rem;margin-bottom:-0.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-default{color:#dee2e6}.link-default:hover,.link-default:focus{color:#e5e8eb}.link-primary{color:#0d6efd}.link-primary:hover,.link-primary:focus{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:hover,.link-secondary:focus{color:#565e64}.link-success{color:#198754}.link-success:hover,.link-success:focus{color:#146c43}.link-info{color:#0dcaf0}.link-info:hover,.link-info:focus{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:hover,.link-warning:focus{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:hover,.link-danger:focus{color:#b02a37}.link-light{color:#f8f9fa}.link-light:hover,.link-light:focus{color:#f9fafb}.link-dark{color:#212529}.link-dark:hover,.link-dark:focus{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio: calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio: calc(9 / 21 * 100%)}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-top-0{border-top:0 !important}.border-end{border-right:1px solid #dee2e6 !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:1px solid #dee2e6 !important}.border-start-0{border-left:0 !important}.border-default{border-color:#dee2e6 !important}.border-primary{border-color:#0d6efd !important}.border-secondary{border-color:#6c757d !important}.border-success{border-color:#198754 !important}.border-info{border-color:#0dcaf0 !important}.border-warning{border-color:#ffc107 !important}.border-danger{border-color:#dc3545 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#212529 !important}.border-white{border-color:#fff !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.345rem + 1.14vw) !important}.fs-2{font-size:calc(1.3rem + 0.6vw) !important}.fs-3{font-size:calc(1.275rem + 0.3vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-light{font-weight:300 !important}.fw-lighter{font-weight:lighter !important}.fw-normal{font-weight:400 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:#6c757d !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:transparent !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:.25rem !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:.2rem !important}.rounded-2{border-radius:.25rem !important}.rounded-3{border-radius:.3rem !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:50rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-end{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-start{border-bottom-left-radius:.25rem !important;border-top-left-radius:.25rem !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#000}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#000}.bg-warning{color:#000}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2.2rem !important}.fs-2{font-size:1.75rem !important}.fs-3{font-size:1.5rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.tippy-box[data-theme~=quarto]{background-color:#fff;color:#212529;border-radius:.25rem;border:solid 1px #dee2e6;font-size:.875rem}.tippy-box[data-theme~=quarto] .tippy-arrow{color:#dee2e6}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:-1px}.tippy-box[data-placement^=bottom]>.tippy-content{padding:.75em 1em;z-index:1}.top-right{position:absolute;top:1em;right:1em}.hidden{display:none !important}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:inline-block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p{text-align:left}.quarto-figure-center>figure>p{text-align:center}.quarto-figure-right>figure>p{text-align:right}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link,div[id^=tbl-]>.anchorjs-link{position:absolute;top:0;right:0}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,.table{caption-side:top;margin-bottom:1.5rem}caption,.table-caption{text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:#6c757d}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}div.ansi-escaped-output{font-family:monospace;display:block}/*! +* +* ansi colors from IPython notebook's +* +*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-fg{color:#282c36}.ansi-black-intense-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-fg{color:#b22b31}.ansi-red-intense-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-fg{color:#007427}.ansi-green-intense-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-fg{color:#b27d12}.ansi-yellow-intense-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-fg{color:#0065ca}.ansi-blue-intense-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-fg{color:#a03196}.ansi-magenta-intense-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-fg{color:#258f8f}.ansi-cyan-intense-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-fg{color:#a1a6b2}.ansi-white-intense-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #ffffff;--quarto-body-color: #212529;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.25rem}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:transparent}.code-copy-button:focus{outline:none}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] 50px [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}.zindex-content{z-index:998;transform:translate3d(0, 0, 0)}.zindex-modal{z-index:1055;transform:translate3d(0, 0, 0)}.zindex-over-content{z-index:999;transform:translate3d(0, 0, 0)}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside,.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{margin-top:2rem;margin-bottom:1rem}h1.title,.title.h1{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3,h4,.h4{margin-top:1.5rem}.header-section-number{color:#5a6570}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,caption,.figure-caption{font-size:1rem}.panel-caption,.figure-caption,figcaption{color:#5a6570}.table-caption,caption{color:#212529}.quarto-layout-cell[data-ref-parent] caption{color:#5a6570}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#5a6570;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:1em}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.25rem}pre.sourceCode{background-color:transparent}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#5a6570}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p code:not(.sourceCode),li code:not(.sourceCode){background-color:#f6f6f6;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode){background-color:transparent;padding:0}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:#6c757d;background-color:transparent;transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.toc-left>*,.sidebar.margin-sidebar>*{padding-top:.5em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem;font-weight:400;margin-bottom:.5rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar nav[role=doc-toc] ul{padding-left:0;list-style:none;font-size:.875rem;font-weight:300}.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}.sidebar nav[role=doc-toc] ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}kbd,.kbd{color:#212529;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}div.hanging-indent{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.table a{word-break:break-word}.table>:not(:first-child){border-top-width:1px;border-top-color:#dee2e6}.table>thead{border-bottom:1px solid currentColor}.table>tbody{border-top:1px solid #dee2e6}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout.callout-captioned .callout-body{margin-top:.2em}.callout:not(.no-icon).callout-captioned.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-captioned>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body>:first-child{margin-top:.5em}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-captioned .callout-body>:last-child:not(.sourceCode),.callout.callout-captioned .callout-body>div>:last-child:not(.sourceCode){margin-bottom:.5rem}.callout:not(.callout-captioned) .callout-body>:first-child,.callout:not(.callout-captioned) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-captioned) .callout-body>:last-child,.callout:not(.callout-captioned) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-caption-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}div.callout-note.callout{border-left-color:#0d6efd}div.callout-note.callout-style-default>.callout-header{background-color:#e7f1ff}div.callout-note:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#198754}div.callout-tip.callout-style-default>.callout-header{background-color:#e8f3ee}div.callout-tip:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ffc107}div.callout-warning.callout-style-default>.callout-header{background-color:#fff9e6}div.callout-warning:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#fd7e14}div.callout-caution.callout-style-default>.callout-header{background-color:#fff2e8}div.callout-caution:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#dc3545}div.callout-important.callout-style-default>.callout-header{background-color:#fcebec}div.callout-important:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex}@media(min-width: 992px){.navbar .quarto-color-scheme-toggle{padding-left:.5rem;padding-right:.5rem}}@media(max-width: 767.98px){.navbar .quarto-color-scheme-toggle{padding-left:0;padding-right:0;padding-bottom:.5em}}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.navbar-collapse .quarto-color-scheme-toggle{padding-left:.6rem;padding-right:0;margin-top:-12px}.sidebar-navigation{padding-left:20px}.sidebar-navigation .quarto-color-scheme-toggle .bi::before{padding-top:.2rem;margin-bottom:-0.2rem}.sidebar-tools-main .quarto-color-scheme-toggle .bi::before{padding-top:.2rem;margin-bottom:-0.2rem}.navbar .quarto-color-scheme-toggle .bi::before{padding-top:7px;margin-bottom:-7px;padding-left:2px;margin-right:2px}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#212529}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{color:#fefefe;background-color:#6c757d;border-color:#6c757d}.btn.btn-quarto:hover,div.cell-output-display .btn-quarto:hover{color:#fefefe;background-color:#828a91;border-color:#7b838a}.btn-check:focus+.btn.btn-quarto,.btn.btn-quarto:focus,.btn-check:focus+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:focus{color:#fefefe;background-color:#828a91;border-color:#7b838a;box-shadow:0 0 0 .25rem rgba(130,138,144,.5)}.btn-check:checked+.btn.btn-quarto,.btn-check:active+.btn.btn-quarto,.btn.btn-quarto:active,.btn.btn-quarto.active,.show>.btn.btn-quarto.dropdown-toggle,.btn-check:checked+div.cell-output-display .btn-quarto,.btn-check:active+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:active,div.cell-output-display .btn-quarto.active,.show>div.cell-output-display .btn-quarto.dropdown-toggle{color:#000;background-color:#899197;border-color:#7b838a}.btn-check:checked+.btn.btn-quarto:focus,.btn-check:active+.btn.btn-quarto:focus,.btn.btn-quarto:active:focus,.btn.btn-quarto.active:focus,.show>.btn.btn-quarto.dropdown-toggle:focus,.btn-check:checked+div.cell-output-display .btn-quarto:focus,.btn-check:active+div.cell-output-display .btn-quarto:focus,div.cell-output-display .btn-quarto:active:focus,div.cell-output-display .btn-quarto.active:focus,.show>div.cell-output-display .btn-quarto.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,144,.5)}.btn.btn-quarto:disabled,.btn.btn-quarto.disabled,div.cell-output-display .btn-quarto:disabled,div.cell-output-display .btn-quarto.disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}nav.quarto-secondary-nav.color-navbar{background-color:#517699;color:#fdfefe}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfefe}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner,body.nav-sidebar .quarto-title-banner{display:none}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */a.external:after{display:inline-block;height:.75rem;width:.75rem;margin-bottom:.15em;margin-left:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.quarto-title-banner{margin-bottom:1em;color:#fdfefe;background:#517699}.quarto-title-banner .code-tools-button{color:#b9dcdc}.quarto-title-banner .code-tools-button:hover{color:#fdfefe}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}main.quarto-banner-title-block section:first-of-type h2:first-of-type,main.quarto-banner-title-block section:first-of-type .h2:first-of-type,main.quarto-banner-title-block section:first-of-type h3:first-of-type,main.quarto-banner-title-block section:first-of-type .h3:first-of-type,main.quarto-banner-title-block section:first-of-type h4:first-of-type,main.quarto-banner-title-block section:first-of-type .h4:first-of-type{margin-top:0}.quarto-title .quarto-categories{display:flex;column-gap:.4em;padding-bottom:.5em;margin-top:.25em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr)}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-5px}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents a{color:#212529}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.7em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .description .abstract-title,#title-block-header.quarto-title-block.default .abstract .abstract-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:1fr 1fr}/*# sourceMappingURL=397ef2e52d54cf686e4908b90039e9db.css.map */ diff --git a/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap.min.js b/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap.min.js new file mode 100644 index 0000000..cc0a255 --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/bootstrap/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof 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()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/_freeze/tidymodels-regression-part2/libs/clipboard/clipboard.min.js b/_freeze/tidymodels-regression-part2/libs/clipboard/clipboard.min.js new file mode 100644 index 0000000..41c6a0f --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/clipboard/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.10 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.js b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.js new file mode 100644 index 0000000..fd9eb53 --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.js @@ -0,0 +1,1474 @@ +(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) { + return 1; + } +} + +/** + * @private + */ + +var FilterSet = function () { + function FilterSet() { + _classCallCheck(this, FilterSet); + + this.reset(); + } + + _createClass(FilterSet, [{ + key: "reset", + value: function reset() { + // Key: handle ID, Value: array of selected keys, or null + this._handles = {}; + // Key: key string, Value: count of handles that include it + this._keys = {}; + this._value = null; + this._activeHandles = 0; + } + }, { + key: "update", + value: function update(handleId, keys) { + if (keys !== null) { + keys = keys.slice(0); // clone before sorting + keys.sort(naturalComparator); + } + + var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys), + added = _diffSortedLists.added, + removed = _diffSortedLists.removed; + + this._handles[handleId] = keys; + + for (var i = 0; i < added.length; i++) { + this._keys[added[i]] = (this._keys[added[i]] || 0) + 1; + } + for (var _i = 0; _i < removed.length; _i++) { + this._keys[removed[_i]]--; + } + + this._updateValue(keys); + } + + /** + * @param {string[]} keys Sorted array of strings that indicate + * a superset of possible keys. + * @private + */ + + }, { + key: "_updateValue", + value: function _updateValue() { + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys; + + var handleCount = Object.keys(this._handles).length; + if (handleCount === 0) { + this._value = null; + } else { + this._value = []; + for (var i = 0; i < keys.length; i++) { + var count = this._keys[keys[i]]; + if (count === handleCount) { + this._value.push(keys[i]); + } + } + } + } + }, { + key: "clear", + value: function clear(handleId) { + if (typeof this._handles[handleId] === "undefined") { + return; + } + + var keys = this._handles[handleId]; + if (!keys) { + keys = []; + } + + for (var i = 0; i < keys.length; i++) { + this._keys[keys[i]]--; + } + delete this._handles[handleId]; + + this._updateValue(); + } + }, { + key: "value", + get: function get() { + return this._value; + } + }, { + key: "_allKeys", + get: function get() { + var allKeys = Object.keys(this._keys); + allKeys.sort(naturalComparator); + return allKeys; + } + }]); + + return FilterSet; +}(); + +exports.default = FilterSet; + +},{"./util":11}],4:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.default = group; + +var _var2 = require("./var"); + +var _var3 = _interopRequireDefault(_var2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// Use a global so that multiple copies of crosstalk.js can be loaded and still +// have groups behave as singletons across all copies. +global.__crosstalk_groups = global.__crosstalk_groups || {}; +var groups = global.__crosstalk_groups; + +function group(groupName) { + if (groupName && typeof groupName === "string") { + if (!groups.hasOwnProperty(groupName)) { + groups[groupName] = new Group(groupName); + } + return groups[groupName]; + } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) { + // Appears to already be a group object + return groupName; + } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") { + return group(groupName[0]); + } else { + throw new Error("Invalid groupName argument"); + } +} + +var Group = function () { + function Group(name) { + _classCallCheck(this, Group); + + this.name = name; + this._vars = {}; + } + + _createClass(Group, [{ + key: "var", + value: function _var(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name); + return this._vars[name]; + } + }, { + key: "has", + value: function has(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + return this._vars.hasOwnProperty(name); + } + }]); + + return Group; +}(); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./var":12}],5:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _selection = require("./selection"); + +var _filter = require("./filter"); + +var _input = require("./input"); + +require("./input_selectize"); + +require("./input_checkboxgroup"); + +require("./input_slider"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var defaultGroup = (0, _group2.default)("default"); + +function var_(name) { + return defaultGroup.var(name); +} + +function has(name) { + return defaultGroup.has(name); +} + +if (global.Shiny) { + global.Shiny.addCustomMessageHandler("update-client-value", function (message) { + if (typeof message.group === "string") { + (0, _group2.default)(message.group).var(message.name).set(message.value); + } else { + var_(message.name).set(message.value); + } + }); +} + +var crosstalk = { + group: _group2.default, + var: var_, + has: has, + SelectionHandle: _selection.SelectionHandle, + FilterHandle: _filter.FilterHandle, + bind: _input.bind +}; + +/** + * @namespace crosstalk + */ +exports.default = crosstalk; + +global.crosstalk = crosstalk; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.register = register; +exports.bind = bind; +var $ = global.jQuery; + +var bindings = {}; + +function register(reg) { + bindings[reg.className] = reg; + if (global.document && global.document.readyState !== "complete") { + $(function () { + bind(); + }); + } else if (global.document) { + setTimeout(bind, 100); + } +} + +function bind() { + Object.keys(bindings).forEach(function (className) { + var binding = bindings[className]; + $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) { + bindInstance(binding, el); + }); + }); +} + +// Escape jQuery identifier +function $escape(val) { + return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1"); +} + +function bindEl(el) { + var $el = $(el); + Object.keys(bindings).forEach(function (className) { + if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) { + var binding = bindings[className]; + bindInstance(binding, el); + } + }); +} + +function bindInstance(binding, el) { + var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']"); + var data = JSON.parse(jsonEl[0].innerText); + + var instance = binding.factory(el, data); + $(el).data("crosstalk-instance", instance); + $(el).addClass("crosstalk-input-bound"); +} + +if (global.Shiny) { + var inputBinding = new global.Shiny.InputBinding(); + var _$ = global.jQuery; + _$.extend(inputBinding, { + find: function find(scope) { + return _$(scope).find(".crosstalk-input"); + }, + initialize: function initialize(el) { + if (!_$(el).hasClass("crosstalk-input-bound")) { + bindEl(el); + } + }, + getId: function getId(el) { + return el.id; + }, + getValue: function getValue(el) {}, + setValue: function setValue(el, value) {}, + receiveMessage: function receiveMessage(el, data) {}, + subscribe: function subscribe(el, callback) { + _$(el).data("crosstalk-instance").resume(); + }, + unsubscribe: function unsubscribe(el) { + _$(el).data("crosstalk-instance").suspend(); + } + }); + global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding"); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],7:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-checkboxgroup", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + var $el = $(el); + $el.on("change", "input[type='checkbox']", function () { + var checked = $el.find("input[type='checkbox']:checked"); + if (checked.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + checked.each(function () { + data.map[this.value].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],8:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-select", + + factory: function factory(el, data) { + /* + * items: {value: [...], label: [...]} + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + + var first = [{ value: "", label: "(All)" }]; + var items = util.dataframeToD3(data.items); + var opts = { + options: first.concat(items), + valueField: "value", + labelField: "label", + searchField: "label" + }; + + var select = $(el).find("select")[0]; + + var selectize = $(select).selectize(opts)[0].selectize; + + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + selectize.on("change", function () { + if (selectize.items.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + selectize.items.forEach(function (group) { + data.map[group].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; +var strftime = global.strftime; + +input.register({ + className: "crosstalk-input-slider", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var opts = {}; + var $el = $(el).find("input"); + var dataType = $el.data("data-type"); + var timeFormat = $el.data("time-format"); + var round = $el.data("round"); + var timeFormatter = void 0; + + // Set up formatting functions + if (dataType === "date") { + timeFormatter = strftime.utc(); + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "datetime") { + var timezone = $el.data("timezone"); + if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime; + + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "number") { + if (typeof round !== "undefined") opts.prettify = function (num) { + var factor = Math.pow(10, round); + return Math.round(num * factor) / factor; + }; + } + + $el.ionRangeSlider(opts); + + function getValue() { + var result = $el.data("ionRangeSlider").result; + + // Function for converting numeric value from slider to appropriate type. + var convert = void 0; + var dataType = $el.data("data-type"); + if (dataType === "date") { + convert = function convert(val) { + return formatDateUTC(new Date(+val)); + }; + } else if (dataType === "datetime") { + convert = function convert(val) { + // Convert ms to s + return +val / 1000; + }; + } else { + convert = function convert(val) { + return +val; + }; + } + + if ($el.data("ionRangeSlider").options.type === "double") { + return [convert(result.from), convert(result.to)]; + } else { + return convert(result.from); + } + } + + var lastKnownKeys = null; + + $el.on("change.crosstalkSliderInput", function (event) { + if (!$el.data("updating") && !$el.data("animating")) { + var _getValue = getValue(), + _getValue2 = _slicedToArray(_getValue, 2), + from = _getValue2[0], + to = _getValue2[1]; + + var keys = []; + for (var i = 0; i < data.values.length; i++) { + var val = data.values[i]; + if (val >= from && val <= to) { + keys.push(data.keys[i]); + } + } + keys.sort(); + ctHandle.set(keys); + lastKnownKeys = keys; + } + }); + + // let $el = $(el); + // $el.on("change", "input[type="checkbox"]", function() { + // let checked = $el.find("input[type="checkbox"]:checked"); + // if (checked.length === 0) { + // ctHandle.clear(); + // } else { + // let keys = {}; + // checked.each(function() { + // data.map[this.value].forEach(function(key) { + // keys[key] = true; + // }); + // }); + // let keyArray = Object.keys(keys); + // keyArray.sort(); + // ctHandle.set(keyArray); + // } + // }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +// Convert a number to a string with leading zeros +function padZeros(n, digits) { + var str = n.toString(); + while (str.length < digits) { + str = "0" + str; + }return str; +} + +// Given a Date object, return a string in yyyy-mm-dd format, using the +// UTC date. This may be a day off from the date in the local time zone. +function formatDateUTC(date) { + if (date instanceof Date) { + return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2); + } else { + return null; + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SelectionHandle = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Use this class to read and write (and listen for changes to) the selection + * for a Crosstalk group. This is intended to be used for linked brushing. + * + * If two (or more) `SelectionHandle` instances in the same webpage share the + * same group name, they will share the same state. Setting the selection using + * one `SelectionHandle` instance will result in the `value` property instantly + * changing across the others, and `"change"` event listeners on all instances + * (including the one that initiated the sending) will fire. + * + * @param {string} [group] - The name of the Crosstalk group, or if none, + * null or undefined (or any other falsy value). This can be changed later + * via the [SelectionHandle#setGroup](#setGroup) method. + * @param {Object} [extraInfo] - An object whose properties will be copied to + * the event object whenever an event is emitted. + */ +var SelectionHandle = exports.SelectionHandle = function () { + function SelectionHandle() { + var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, SelectionHandle); + + this._eventRelay = new _events2.default(); + this._emitter = new util.SubscriptionTracker(this._eventRelay); + + // Name of the group we're currently tracking, if any. Can change over time. + this._group = null; + // The Var we're currently tracking, if any. Can change over time. + this._var = null; + // The event handler subscription we currently have on var.on("change"). + this._varOnChangeSub = null; + + this._extraInfo = util.extend({ sender: this }, extraInfo); + + this.setGroup(group); + } + + /** + * Changes the Crosstalk group membership of this SelectionHandle. The group + * being switched away from (if any) will not have its selection value + * modified as a result of calling `setGroup`, even if this handle was the + * most recent handle to set the selection of the group. + * + * The group being switched to (if any) will also not have its selection value + * modified as a result of calling `setGroup`. If you want to set the + * selection value of the new group, call `set` explicitly. + * + * @param {string} group - The name of the Crosstalk group, or null (or + * undefined) to clear the group. + */ + + + _createClass(SelectionHandle, [{ + key: "setGroup", + value: function setGroup(group) { + var _this = this; + + // If group is unchanged, do nothing + if (this._group === group) return; + // Treat null, undefined, and other falsy values the same + if (!this._group && !group) return; + + if (this._var) { + this._var.off("change", this._varOnChangeSub); + this._var = null; + this._varOnChangeSub = null; + } + + this._group = group; + + if (group) { + this._var = (0, _group2.default)(group).var("selection"); + var sub = this._var.on("change", function (e) { + _this._eventRelay.trigger("change", e, _this); + }); + this._varOnChangeSub = sub; + } + } + + /** + * Retrieves the current selection for the group represented by this + * `SelectionHandle`. + * + * - If no selection is active, then this value will be falsy. + * - If a selection is active, but no data points are selected, then this + * value will be an empty array. + * - If a selection is active, and data points are selected, then the keys + * of the selected data points will be present in the array. + */ + + }, { + key: "_mergeExtraInfo", + + + /** + * Combines the given `extraInfo` (if any) with the handle's default + * `_extraInfo` (if any). + * @private + */ + value: function _mergeExtraInfo(extraInfo) { + // Important incidental effect: shallow clone is returned + return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see + * {@link SelectionHandle#value}). + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any options that were + * passed into the `SelectionHandle` constructor). + */ + + }, { + key: "set", + value: function set(selectedKeys, extraInfo) { + if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo)); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any that were passed + * into the `SelectionHandle` constructor). + */ + + }, { + key: "clear", + value: function clear(extraInfo) { + if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo)); + } + + /** + * Subscribes to events on this `SelectionHandle`. + * + * @param {string} eventType - Indicates the type of events to listen to. + * Currently, only `"change"` is supported. + * @param {SelectionHandle~listener} listener - The callback function that + * will be invoked when the event occurs. + * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel + * this subscription. + */ + + }, { + key: "on", + value: function on(eventType, listener) { + return this._emitter.on(eventType, listener); + } + + /** + * Cancels event subscriptions created by {@link SelectionHandle#on}. + * + * @param {string} eventType - The type of event to unsubscribe. + * @param {string|SelectionHandle~listener} listener - Either the callback + * function previously passed into {@link SelectionHandle#on}, or the + * string that was returned from {@link SelectionHandle#on}. + */ + + }, { + key: "off", + value: function off(eventType, listener) { + return this._emitter.off(eventType, listener); + } + + /** + * Shuts down the `SelectionHandle` object. + * + * Removes all event listeners that were added through this handle. + */ + + }, { + key: "close", + value: function close() { + this._emitter.removeAllListeners(); + this.setGroup(null); + } + }, { + key: "value", + get: function get() { + return this._var ? this._var.get() : null; + } + }]); + + return SelectionHandle; +}(); + +/** + * @callback SelectionHandle~listener + * @param {Object} event - An object containing details of the event. For + * `"change"` events, this includes the properties `value` (the new + * value of the selection, or `undefined` if no selection is active), + * `oldValue` (the previous value of the selection), and `sender` (the + * `SelectionHandle` instance that made the change). + */ + +/** + * @event SelectionHandle#change + * @type {object} + * @property {object} value - The new value of the selection, or `undefined` + * if no selection is active. + * @property {object} oldValue - The previous value of the selection. + * @property {SelectionHandle} sender - The `SelectionHandle` instance that + * changed the value. + */ + +},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extend = extend; +exports.checkSorted = checkSorted; +exports.diffSortedLists = diffSortedLists; +exports.dataframeToD3 = dataframeToD3; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function extend(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var src = sources[i]; + if (typeof src === "undefined" || src === null) continue; + + for (var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + } + return target; +} + +function checkSorted(list) { + for (var i = 1; i < list.length; i++) { + if (list[i] <= list[i - 1]) { + throw new Error("List is not sorted or contains duplicate"); + } + } +} + +function diffSortedLists(a, b) { + var i_a = 0; + var i_b = 0; + + if (!a) a = []; + if (!b) b = []; + + var a_only = []; + var b_only = []; + + checkSorted(a); + checkSorted(b); + + while (i_a < a.length && i_b < b.length) { + if (a[i_a] === b[i_b]) { + i_a++; + i_b++; + } else if (a[i_a] < b[i_b]) { + a_only.push(a[i_a++]); + } else { + b_only.push(b[i_b++]); + } + } + + if (i_a < a.length) a_only = a_only.concat(a.slice(i_a)); + if (i_b < b.length) b_only = b_only.concat(b.slice(i_b)); + return { + removed: a_only, + added: b_only + }; +} + +// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... } +// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ] +function dataframeToD3(df) { + var names = []; + var length = void 0; + for (var name in df) { + if (df.hasOwnProperty(name)) names.push(name); + if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof length !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item = void 0; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; +} + +/** + * Keeps track of all event listener additions/removals and lets all active + * listeners be removed with a single operation. + * + * @private + */ + +var SubscriptionTracker = exports.SubscriptionTracker = function () { + function SubscriptionTracker(emitter) { + _classCallCheck(this, SubscriptionTracker); + + this._emitter = emitter; + this._subs = {}; + } + + _createClass(SubscriptionTracker, [{ + key: "on", + value: function on(eventType, listener) { + var sub = this._emitter.on(eventType, listener); + this._subs[sub] = eventType; + return sub; + } + }, { + key: "off", + value: function off(eventType, listener) { + var sub = this._emitter.off(eventType, listener); + if (sub) { + delete this._subs[sub]; + } + return sub; + } + }, { + key: "removeAllListeners", + value: function removeAllListeners() { + var _this = this; + + var current_subs = this._subs; + this._subs = {}; + Object.keys(current_subs).forEach(function (sub) { + _this._emitter.off(current_subs[sub], sub); + }); + } + }]); + + return SubscriptionTracker; +}(); + +},{}],12:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Var = function () { + function Var(group, name, /*optional*/value) { + _classCallCheck(this, Var); + + this._group = group; + this._name = name; + this._value = value; + this._events = new _events2.default(); + } + + _createClass(Var, [{ + key: "get", + value: function get() { + return this._value; + } + }, { + key: "set", + value: function set(value, /*optional*/event) { + if (this._value === value) { + // Do nothing; the value hasn't changed + return; + } + var oldValue = this._value; + this._value = value; + // Alert JavaScript listeners that the value has changed + var evt = {}; + if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") { + for (var k in event) { + if (event.hasOwnProperty(k)) evt[k] = event[k]; + } + } + evt.oldValue = oldValue; + evt.value = value; + this._events.trigger("change", evt, this); + + // TODO: Make this extensible, to let arbitrary back-ends know that + // something has changed + if (global.Shiny && global.Shiny.onInputChange) { + global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value); + } + } + }, { + key: "on", + value: function on(eventType, listener) { + return this._events.on(eventType, listener); + } + }, { + key: "off", + value: function off(eventType, listener) { + return this._events.off(eventType, listener); + } + }]); + + return Var; +}(); + +exports.default = Var; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./events":1}]},{},[5]) +//# sourceMappingURL=crosstalk.js.map diff --git a/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.js.map b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.js.map new file mode 100644 index 0000000..cff94f0 --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.js.map @@ -0,0 +1,37 @@ +{ + "version": 3, + "sources": [ + "node_modules/browser-pack/_prelude.js", + "javascript/src/events.js", + "javascript/src/filter.js", + "javascript/src/filterset.js", + "javascript/src/group.js", + "javascript/src/index.js", + "javascript/src/input.js", + "javascript/src/input_checkboxgroup.js", + "javascript/src/input_selectize.js", + "javascript/src/input_slider.js", + "javascript/src/selection.js", + "javascript/src/util.js", + "javascript/src/var.js" + ], + "names": [], + "mappings": "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", + "file": "generated.js", + "sourceRoot": "", + "sourcesContent": [ + "(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n", + "import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n", + "import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n", + "import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n", + "let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n", + "import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n", + "export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n", + "import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n" + ] +} \ No newline at end of file diff --git a/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.min.js b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.min.js new file mode 100644 index 0000000..b7ec0ac --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/js/crosstalk.min.js @@ -0,0 +1,2 @@ +!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]} \ No newline at end of file diff --git a/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/scss/crosstalk.scss b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/scss/crosstalk.scss new file mode 100644 index 0000000..3566561 --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/crosstalk-1.2.0/scss/crosstalk.scss @@ -0,0 +1,75 @@ +/* Adjust margins outwards, so column contents line up with the edges of the + parent of container-fluid. */ +.container-fluid.crosstalk-bscols { + margin-left: -30px; + margin-right: -30px; + white-space: normal; +} + +/* But don't adjust the margins outwards if we're directly under the body, + i.e. we were the top-level of something at the console. */ +body > .container-fluid.crosstalk-bscols { + margin-left: auto; + margin-right: auto; +} + +.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: inline-block; + padding-right: 12px; + vertical-align: top; +} + +@media only screen and (max-width:480px) { + .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: block; + padding-right: inherit; + } +} + +/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ +.crosstalk-input { + margin-bottom: 15px; /* a la .form-group */ + .control-label { + margin-bottom: 0; + vertical-align: middle; + } + input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px; + line-height: normal; + } + .checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + } + .checkbox > label{ + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + cursor: pointer; + } + .checkbox input[type="checkbox"], + .checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 2px; + margin-left: -20px; + } + .checkbox + .checkbox { + margin-top: -5px; + } + .checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + vertical-align: middle; + cursor: pointer; + } + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; + } +} diff --git a/_freeze/tidymodels-regression-part2/libs/htmlwidgets-1.6.2/htmlwidgets.js b/_freeze/tidymodels-regression-part2/libs/htmlwidgets-1.6.2/htmlwidgets.js new file mode 100644 index 0000000..1067d02 --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/htmlwidgets-1.6.2/htmlwidgets.js @@ -0,0 +1,901 @@ +(function() { + // If window.HTMLWidgets is already defined, then use it; otherwise create a + // new object. This allows preceding code to set options that affect the + // initialization process (though none currently exist). + window.HTMLWidgets = window.HTMLWidgets || {}; + + // See if we're running in a viewer pane. If not, we're in a web browser. + var viewerMode = window.HTMLWidgets.viewerMode = + /\bviewer_pane=1\b/.test(window.location); + + // See if we're running in Shiny mode. If not, it's a static document. + // Note that static widgets can appear in both Shiny and static modes, but + // obviously, Shiny widgets can only appear in Shiny apps/documents. + var shinyMode = window.HTMLWidgets.shinyMode = + typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings; + + // We can't count on jQuery being available, so we implement our own + // version if necessary. + function querySelectorAll(scope, selector) { + if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) { + return scope.find(selector); + } + if (scope.querySelectorAll) { + return scope.querySelectorAll(selector); + } + } + + function asArray(value) { + if (value === null) + return []; + if ($.isArray(value)) + return value; + return [value]; + } + + // Implement jQuery's extend + function extend(target /*, ... */) { + if (arguments.length == 1) { + return target; + } + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + } + return target; + } + + // IE8 doesn't support Array.forEach. + function forEach(values, callback, thisArg) { + if (values.forEach) { + values.forEach(callback, thisArg); + } else { + for (var i = 0; i < values.length; i++) { + callback.call(thisArg, values[i], i, values); + } + } + } + + // Replaces the specified method with the return value of funcSource. + // + // Note that funcSource should not BE the new method, it should be a function + // that RETURNS the new method. funcSource receives a single argument that is + // the overridden method, it can be called from the new method. The overridden + // method can be called like a regular function, it has the target permanently + // bound to it so "this" will work correctly. + function overrideMethod(target, methodName, funcSource) { + var superFunc = target[methodName] || function() {}; + var superFuncBound = function() { + return superFunc.apply(target, arguments); + }; + target[methodName] = funcSource(superFuncBound); + } + + // Add a method to delegator that, when invoked, calls + // delegatee.methodName. If there is no such method on + // the delegatee, but there was one on delegator before + // delegateMethod was called, then the original version + // is invoked instead. + // For example: + // + // var a = { + // method1: function() { console.log('a1'); } + // method2: function() { console.log('a2'); } + // }; + // var b = { + // method1: function() { console.log('b1'); } + // }; + // delegateMethod(a, b, "method1"); + // delegateMethod(a, b, "method2"); + // a.method1(); + // a.method2(); + // + // The output would be "b1", "a2". + function delegateMethod(delegator, delegatee, methodName) { + var inherited = delegator[methodName]; + delegator[methodName] = function() { + var target = delegatee; + var method = delegatee[methodName]; + + // The method doesn't exist on the delegatee. Instead, + // call the method on the delegator, if it exists. + if (!method) { + target = delegator; + method = inherited; + } + + if (method) { + return method.apply(target, arguments); + } + }; + } + + // Implement a vague facsimilie of jQuery's data method + function elementData(el, name, value) { + if (arguments.length == 2) { + return el["htmlwidget_data_" + name]; + } else if (arguments.length == 3) { + el["htmlwidget_data_" + name] = value; + return el; + } else { + throw new Error("Wrong number of arguments for elementData: " + + arguments.length); + } + } + + // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex + function escapeRegExp(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + } + + function hasClass(el, className) { + var re = new RegExp("\\b" + escapeRegExp(className) + "\\b"); + return re.test(el.className); + } + + // elements - array (or array-like object) of HTML elements + // className - class name to test for + // include - if true, only return elements with given className; + // if false, only return elements *without* given className + function filterByClass(elements, className, include) { + var results = []; + for (var i = 0; i < elements.length; i++) { + if (hasClass(elements[i], className) == include) + results.push(elements[i]); + } + return results; + } + + function on(obj, eventName, func) { + if (obj.addEventListener) { + obj.addEventListener(eventName, func, false); + } else if (obj.attachEvent) { + obj.attachEvent(eventName, func); + } + } + + function off(obj, eventName, func) { + if (obj.removeEventListener) + obj.removeEventListener(eventName, func, false); + else if (obj.detachEvent) { + obj.detachEvent(eventName, func); + } + } + + // Translate array of values to top/right/bottom/left, as usual with + // the "padding" CSS property + // https://developer.mozilla.org/en-US/docs/Web/CSS/padding + function unpackPadding(value) { + if (typeof(value) === "number") + value = [value]; + if (value.length === 1) { + return {top: value[0], right: value[0], bottom: value[0], left: value[0]}; + } + if (value.length === 2) { + return {top: value[0], right: value[1], bottom: value[0], left: value[1]}; + } + if (value.length === 3) { + return {top: value[0], right: value[1], bottom: value[2], left: value[1]}; + } + if (value.length === 4) { + return {top: value[0], right: value[1], bottom: value[2], left: value[3]}; + } + } + + // Convert an unpacked padding object to a CSS value + function paddingToCss(paddingObj) { + return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px"; + } + + // Makes a number suitable for CSS + function px(x) { + if (typeof(x) === "number") + return x + "px"; + else + return x; + } + + // Retrieves runtime widget sizing information for an element. + // The return value is either null, or an object with fill, padding, + // defaultWidth, defaultHeight fields. + function sizingPolicy(el) { + var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']"); + if (!sizingEl) + return null; + var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}"); + if (viewerMode) { + return sp.viewer; + } else { + return sp.browser; + } + } + + // @param tasks Array of strings (or falsy value, in which case no-op). + // Each element must be a valid JavaScript expression that yields a + // function. Or, can be an array of objects with "code" and "data" + // properties; in this case, the "code" property should be a string + // of JS that's an expr that yields a function, and "data" should be + // an object that will be added as an additional argument when that + // function is called. + // @param target The object that will be "this" for each function + // execution. + // @param args Array of arguments to be passed to the functions. (The + // same arguments will be passed to all functions.) + function evalAndRun(tasks, target, args) { + if (tasks) { + forEach(tasks, function(task) { + var theseArgs = args; + if (typeof(task) === "object") { + theseArgs = theseArgs.concat([task.data]); + task = task.code; + } + var taskFunc = tryEval(task); + if (typeof(taskFunc) !== "function") { + throw new Error("Task must be a function! Source:\n" + task); + } + taskFunc.apply(target, theseArgs); + }); + } + } + + // Attempt eval() both with and without enclosing in parentheses. + // Note that enclosing coerces a function declaration into + // an expression that eval() can parse + // (otherwise, a SyntaxError is thrown) + function tryEval(code) { + var result = null; + try { + result = eval("(" + code + ")"); + } catch(error) { + if (!(error instanceof SyntaxError)) { + throw error; + } + try { + result = eval(code); + } catch(e) { + if (e instanceof SyntaxError) { + throw error; + } else { + throw e; + } + } + } + return result; + } + + function initSizing(el) { + var sizing = sizingPolicy(el); + if (!sizing) + return; + + var cel = document.getElementById("htmlwidget_container"); + if (!cel) + return; + + if (typeof(sizing.padding) !== "undefined") { + document.body.style.margin = "0"; + document.body.style.padding = paddingToCss(unpackPadding(sizing.padding)); + } + + if (sizing.fill) { + document.body.style.overflow = "hidden"; + document.body.style.width = "100%"; + document.body.style.height = "100%"; + document.documentElement.style.width = "100%"; + document.documentElement.style.height = "100%"; + cel.style.position = "absolute"; + var pad = unpackPadding(sizing.padding); + cel.style.top = pad.top + "px"; + cel.style.right = pad.right + "px"; + cel.style.bottom = pad.bottom + "px"; + cel.style.left = pad.left + "px"; + el.style.width = "100%"; + el.style.height = "100%"; + + return { + getWidth: function() { return cel.getBoundingClientRect().width; }, + getHeight: function() { return cel.getBoundingClientRect().height; } + }; + + } else { + el.style.width = px(sizing.width); + el.style.height = px(sizing.height); + + return { + getWidth: function() { return cel.getBoundingClientRect().width; }, + getHeight: function() { return cel.getBoundingClientRect().height; } + }; + } + } + + // Default implementations for methods + var defaults = { + find: function(scope) { + return querySelectorAll(scope, "." + this.name); + }, + renderError: function(el, err) { + var $el = $(el); + + this.clearError(el); + + // Add all these error classes, as Shiny does + var errClass = "shiny-output-error"; + if (err.type !== null) { + // use the classes of the error condition as CSS class names + errClass = errClass + " " + $.map(asArray(err.type), function(type) { + return errClass + "-" + type; + }).join(" "); + } + errClass = errClass + " htmlwidgets-error"; + + // Is el inline or block? If inline or inline-block, just display:none it + // and add an inline error. + var display = $el.css("display"); + $el.data("restore-display-mode", display); + + if (display === "inline" || display === "inline-block") { + $el.hide(); + if (err.message !== "") { + var errorSpan = $("").addClass(errClass); + errorSpan.text(err.message); + $el.after(errorSpan); + } + } else if (display === "block") { + // If block, add an error just after the el, set visibility:none on the + // el, and position the error to be on top of the el. + // Mark it with a unique ID and CSS class so we can remove it later. + $el.css("visibility", "hidden"); + if (err.message !== "") { + var errorDiv = $("
    ").addClass(errClass).css("position", "absolute") + .css("top", el.offsetTop) + .css("left", el.offsetLeft) + // setting width can push out the page size, forcing otherwise + // unnecessary scrollbars to appear and making it impossible for + // the element to shrink; so use max-width instead + .css("maxWidth", el.offsetWidth) + .css("height", el.offsetHeight); + errorDiv.text(err.message); + $el.after(errorDiv); + + // Really dumb way to keep the size/position of the error in sync with + // the parent element as the window is resized or whatever. + var intId = setInterval(function() { + if (!errorDiv[0].parentElement) { + clearInterval(intId); + return; + } + errorDiv + .css("top", el.offsetTop) + .css("left", el.offsetLeft) + .css("maxWidth", el.offsetWidth) + .css("height", el.offsetHeight); + }, 500); + } + } + }, + clearError: function(el) { + var $el = $(el); + var display = $el.data("restore-display-mode"); + $el.data("restore-display-mode", null); + + if (display === "inline" || display === "inline-block") { + if (display) + $el.css("display", display); + $(el.nextSibling).filter(".htmlwidgets-error").remove(); + } else if (display === "block"){ + $el.css("visibility", "inherit"); + $(el.nextSibling).filter(".htmlwidgets-error").remove(); + } + }, + sizing: {} + }; + + // Called by widget bindings to register a new type of widget. The definition + // object can contain the following properties: + // - name (required) - A string indicating the binding name, which will be + // used by default as the CSS classname to look for. + // - initialize (optional) - A function(el) that will be called once per + // widget element; if a value is returned, it will be passed as the third + // value to renderValue. + // - renderValue (required) - A function(el, data, initValue) that will be + // called with data. Static contexts will cause this to be called once per + // element; Shiny apps will cause this to be called multiple times per + // element, as the data changes. + window.HTMLWidgets.widget = function(definition) { + if (!definition.name) { + throw new Error("Widget must have a name"); + } + if (!definition.type) { + throw new Error("Widget must have a type"); + } + // Currently we only support output widgets + if (definition.type !== "output") { + throw new Error("Unrecognized widget type '" + definition.type + "'"); + } + // TODO: Verify that .name is a valid CSS classname + + // Support new-style instance-bound definitions. Old-style class-bound + // definitions have one widget "object" per widget per type/class of + // widget; the renderValue and resize methods on such widget objects + // take el and instance arguments, because the widget object can't + // store them. New-style instance-bound definitions have one widget + // object per widget instance; the definition that's passed in doesn't + // provide renderValue or resize methods at all, just the single method + // factory(el, width, height) + // which returns an object that has renderValue(x) and resize(w, h). + // This enables a far more natural programming style for the widget + // author, who can store per-instance state using either OO-style + // instance fields or functional-style closure variables (I guess this + // is in contrast to what can only be called C-style pseudo-OO which is + // what we required before). + if (definition.factory) { + definition = createLegacyDefinitionAdapter(definition); + } + + if (!definition.renderValue) { + throw new Error("Widget must have a renderValue function"); + } + + // For static rendering (non-Shiny), use a simple widget registration + // scheme. We also use this scheme for Shiny apps/documents that also + // contain static widgets. + window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || []; + // Merge defaults into the definition; don't mutate the original definition. + var staticBinding = extend({}, defaults, definition); + overrideMethod(staticBinding, "find", function(superfunc) { + return function(scope) { + var results = superfunc(scope); + // Filter out Shiny outputs, we only want the static kind + return filterByClass(results, "html-widget-output", false); + }; + }); + window.HTMLWidgets.widgets.push(staticBinding); + + if (shinyMode) { + // Shiny is running. Register the definition with an output binding. + // The definition itself will not be the output binding, instead + // we will make an output binding object that delegates to the + // definition. This is because we foolishly used the same method + // name (renderValue) for htmlwidgets definition and Shiny bindings + // but they actually have quite different semantics (the Shiny + // bindings receive data that includes lots of metadata that it + // strips off before calling htmlwidgets renderValue). We can't + // just ignore the difference because in some widgets it's helpful + // to call this.renderValue() from inside of resize(), and if + // we're not delegating, then that call will go to the Shiny + // version instead of the htmlwidgets version. + + // Merge defaults with definition, without mutating either. + var bindingDef = extend({}, defaults, definition); + + // This object will be our actual Shiny binding. + var shinyBinding = new Shiny.OutputBinding(); + + // With a few exceptions, we'll want to simply use the bindingDef's + // version of methods if they are available, otherwise fall back to + // Shiny's defaults. NOTE: If Shiny's output bindings gain additional + // methods in the future, and we want them to be overrideable by + // HTMLWidget binding definitions, then we'll need to add them to this + // list. + delegateMethod(shinyBinding, bindingDef, "getId"); + delegateMethod(shinyBinding, bindingDef, "onValueChange"); + delegateMethod(shinyBinding, bindingDef, "onValueError"); + delegateMethod(shinyBinding, bindingDef, "renderError"); + delegateMethod(shinyBinding, bindingDef, "clearError"); + delegateMethod(shinyBinding, bindingDef, "showProgress"); + + // The find, renderValue, and resize are handled differently, because we + // want to actually decorate the behavior of the bindingDef methods. + + shinyBinding.find = function(scope) { + var results = bindingDef.find(scope); + + // Only return elements that are Shiny outputs, not static ones + var dynamicResults = results.filter(".html-widget-output"); + + // It's possible that whatever caused Shiny to think there might be + // new dynamic outputs, also caused there to be new static outputs. + // Since there might be lots of different htmlwidgets bindings, we + // schedule execution for later--no need to staticRender multiple + // times. + if (results.length !== dynamicResults.length) + scheduleStaticRender(); + + return dynamicResults; + }; + + // Wrap renderValue to handle initialization, which unfortunately isn't + // supported natively by Shiny at the time of this writing. + + shinyBinding.renderValue = function(el, data) { + Shiny.renderDependencies(data.deps); + // Resolve strings marked as javascript literals to objects + if (!(data.evals instanceof Array)) data.evals = [data.evals]; + for (var i = 0; data.evals && i < data.evals.length; i++) { + window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]); + } + if (!bindingDef.renderOnNullValue) { + if (data.x === null) { + el.style.visibility = "hidden"; + return; + } else { + el.style.visibility = "inherit"; + } + } + if (!elementData(el, "initialized")) { + initSizing(el); + + elementData(el, "initialized", true); + if (bindingDef.initialize) { + var rect = el.getBoundingClientRect(); + var result = bindingDef.initialize(el, rect.width, rect.height); + elementData(el, "init_result", result); + } + } + bindingDef.renderValue(el, data.x, elementData(el, "init_result")); + evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]); + }; + + // Only override resize if bindingDef implements it + if (bindingDef.resize) { + shinyBinding.resize = function(el, width, height) { + // Shiny can call resize before initialize/renderValue have been + // called, which doesn't make sense for widgets. + if (elementData(el, "initialized")) { + bindingDef.resize(el, width, height, elementData(el, "init_result")); + } + }; + } + + Shiny.outputBindings.register(shinyBinding, bindingDef.name); + } + }; + + var scheduleStaticRenderTimerId = null; + function scheduleStaticRender() { + if (!scheduleStaticRenderTimerId) { + scheduleStaticRenderTimerId = setTimeout(function() { + scheduleStaticRenderTimerId = null; + window.HTMLWidgets.staticRender(); + }, 1); + } + } + + // Render static widgets after the document finishes loading + // Statically render all elements that are of this widget's class + window.HTMLWidgets.staticRender = function() { + var bindings = window.HTMLWidgets.widgets || []; + forEach(bindings, function(binding) { + var matches = binding.find(document.documentElement); + forEach(matches, function(el) { + var sizeObj = initSizing(el, binding); + + var getSize = function(el) { + if (sizeObj) { + return {w: sizeObj.getWidth(), h: sizeObj.getHeight()} + } else { + var rect = el.getBoundingClientRect(); + return {w: rect.width, h: rect.height} + } + }; + + if (hasClass(el, "html-widget-static-bound")) + return; + el.className = el.className + " html-widget-static-bound"; + + var initResult; + if (binding.initialize) { + var size = getSize(el); + initResult = binding.initialize(el, size.w, size.h); + elementData(el, "init_result", initResult); + } + + if (binding.resize) { + var lastSize = getSize(el); + var resizeHandler = function(e) { + var size = getSize(el); + if (size.w === 0 && size.h === 0) + return; + if (size.w === lastSize.w && size.h === lastSize.h) + return; + lastSize = size; + binding.resize(el, size.w, size.h, initResult); + }; + + on(window, "resize", resizeHandler); + + // This is needed for cases where we're running in a Shiny + // app, but the widget itself is not a Shiny output, but + // rather a simple static widget. One example of this is + // an rmarkdown document that has runtime:shiny and widget + // that isn't in a render function. Shiny only knows to + // call resize handlers for Shiny outputs, not for static + // widgets, so we do it ourselves. + if (window.jQuery) { + window.jQuery(document).on( + "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets", + resizeHandler + ); + window.jQuery(document).on( + "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets", + resizeHandler + ); + } + + // This is needed for the specific case of ioslides, which + // flips slides between display:none and display:block. + // Ideally we would not have to have ioslide-specific code + // here, but rather have ioslides raise a generic event, + // but the rmarkdown package just went to CRAN so the + // window to getting that fixed may be long. + if (window.addEventListener) { + // It's OK to limit this to window.addEventListener + // browsers because ioslides itself only supports + // such browsers. + on(document, "slideenter", resizeHandler); + on(document, "slideleave", resizeHandler); + } + } + + var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']"); + if (scriptData) { + var data = JSON.parse(scriptData.textContent || scriptData.text); + // Resolve strings marked as javascript literals to objects + if (!(data.evals instanceof Array)) data.evals = [data.evals]; + for (var k = 0; data.evals && k < data.evals.length; k++) { + window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]); + } + binding.renderValue(el, data.x, initResult); + evalAndRun(data.jsHooks.render, initResult, [el, data.x]); + } + }); + }); + + invokePostRenderHandlers(); + } + + + function has_jQuery3() { + if (!window.jQuery) { + return false; + } + var $version = window.jQuery.fn.jquery; + var $major_version = parseInt($version.split(".")[0]); + return $major_version >= 3; + } + + /* + / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's + / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now + / really means $(setTimeout(fn)). + / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous + / + / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny + / one tick later than it did before, which means staticRender() is + / called renderValue() earlier than (advanced) widget authors might be expecting. + / https://github.com/rstudio/shiny/issues/2630 + / + / For a concrete example, leaflet has some methods (e.g., updateBounds) + / which reference Shiny methods registered in initShiny (e.g., setInputValue). + / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to + / delay execution of those methods (until Shiny methods are ready) + / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268 + / + / Ideally widget authors wouldn't need to use this setTimeout() hack that + / leaflet uses to call Shiny methods on a staticRender(). In the long run, + / the logic initShiny should be broken up so that method registration happens + / right away, but binding happens later. + */ + function maybeStaticRenderLater() { + if (shinyMode && has_jQuery3()) { + window.jQuery(window.HTMLWidgets.staticRender); + } else { + window.HTMLWidgets.staticRender(); + } + } + + if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", function() { + document.removeEventListener("DOMContentLoaded", arguments.callee, false); + maybeStaticRenderLater(); + }, false); + } else if (document.attachEvent) { + document.attachEvent("onreadystatechange", function() { + if (document.readyState === "complete") { + document.detachEvent("onreadystatechange", arguments.callee); + maybeStaticRenderLater(); + } + }); + } + + + window.HTMLWidgets.getAttachmentUrl = function(depname, key) { + // If no key, default to the first item + if (typeof(key) === "undefined") + key = 1; + + var link = document.getElementById(depname + "-" + key + "-attachment"); + if (!link) { + throw new Error("Attachment " + depname + "/" + key + " not found in document"); + } + return link.getAttribute("href"); + }; + + window.HTMLWidgets.dataframeToD3 = function(df) { + var names = []; + var length; + for (var name in df) { + if (df.hasOwnProperty(name)) + names.push(name); + if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof(length) !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; + }; + + window.HTMLWidgets.transposeArray2D = function(array) { + if (array.length === 0) return array; + var newArray = array[0].map(function(col, i) { + return array.map(function(row) { + return row[i] + }) + }); + return newArray; + }; + // Split value at splitChar, but allow splitChar to be escaped + // using escapeChar. Any other characters escaped by escapeChar + // will be included as usual (including escapeChar itself). + function splitWithEscape(value, splitChar, escapeChar) { + var results = []; + var escapeMode = false; + var currentResult = ""; + for (var pos = 0; pos < value.length; pos++) { + if (!escapeMode) { + if (value[pos] === splitChar) { + results.push(currentResult); + currentResult = ""; + } else if (value[pos] === escapeChar) { + escapeMode = true; + } else { + currentResult += value[pos]; + } + } else { + currentResult += value[pos]; + escapeMode = false; + } + } + if (currentResult !== "") { + results.push(currentResult); + } + return results; + } + // Function authored by Yihui/JJ Allaire + window.HTMLWidgets.evaluateStringMember = function(o, member) { + var parts = splitWithEscape(member, '.', '\\'); + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i]; + // part may be a character or 'numeric' member name + if (o !== null && typeof o === "object" && part in o) { + if (i == (l - 1)) { // if we are at the end of the line then evalulate + if (typeof o[part] === "string") + o[part] = tryEval(o[part]); + } else { // otherwise continue to next embedded object + o = o[part]; + } + } + } + }; + + // Retrieve the HTMLWidget instance (i.e. the return value of an + // HTMLWidget binding's initialize() or factory() function) + // associated with an element, or null if none. + window.HTMLWidgets.getInstance = function(el) { + return elementData(el, "init_result"); + }; + + // Finds the first element in the scope that matches the selector, + // and returns the HTMLWidget instance (i.e. the return value of + // an HTMLWidget binding's initialize() or factory() function) + // associated with that element, if any. If no element matches the + // selector, or the first matching element has no HTMLWidget + // instance associated with it, then null is returned. + // + // The scope argument is optional, and defaults to window.document. + window.HTMLWidgets.find = function(scope, selector) { + if (arguments.length == 1) { + selector = scope; + scope = document; + } + + var el = scope.querySelector(selector); + if (el === null) { + return null; + } else { + return window.HTMLWidgets.getInstance(el); + } + }; + + // Finds all elements in the scope that match the selector, and + // returns the HTMLWidget instances (i.e. the return values of + // an HTMLWidget binding's initialize() or factory() function) + // associated with the elements, in an array. If elements that + // match the selector don't have an associated HTMLWidget + // instance, the returned array will contain nulls. + // + // The scope argument is optional, and defaults to window.document. + window.HTMLWidgets.findAll = function(scope, selector) { + if (arguments.length == 1) { + selector = scope; + scope = document; + } + + var nodes = scope.querySelectorAll(selector); + var results = []; + for (var i = 0; i < nodes.length; i++) { + results.push(window.HTMLWidgets.getInstance(nodes[i])); + } + return results; + }; + + var postRenderHandlers = []; + function invokePostRenderHandlers() { + while (postRenderHandlers.length) { + var handler = postRenderHandlers.shift(); + if (handler) { + handler(); + } + } + } + + // Register the given callback function to be invoked after the + // next time static widgets are rendered. + window.HTMLWidgets.addPostRenderHandler = function(callback) { + postRenderHandlers.push(callback); + }; + + // Takes a new-style instance-bound definition, and returns an + // old-style class-bound definition. This saves us from having + // to rewrite all the logic in this file to accomodate both + // types of definitions. + function createLegacyDefinitionAdapter(defn) { + var result = { + name: defn.name, + type: defn.type, + initialize: function(el, width, height) { + return defn.factory(el, width, height); + }, + renderValue: function(el, x, instance) { + return instance.renderValue(x); + }, + resize: function(el, width, height, instance) { + return instance.resize(width, height); + } + }; + + if (defn.find) + result.find = defn.find; + if (defn.renderError) + result.renderError = defn.renderError; + if (defn.clearError) + result.clearError = defn.clearError; + + return result; + } +})(); diff --git a/_freeze/tidymodels-regression-part2/libs/jquery-3.5.1/jquery-AUTHORS.txt b/_freeze/tidymodels-regression-part2/libs/jquery-3.5.1/jquery-AUTHORS.txt new file mode 100644 index 0000000..06df1a5 --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/jquery-3.5.1/jquery-AUTHORS.txt @@ -0,0 +1,357 @@ +Authors ordered by first contribution. + +John Resig +Gilles van den Hoven +Michael Geary +Stefan Petre +Yehuda Katz +Corey Jewett +Klaus Hartl +Franck Marcia +Jörn Zaefferer +Paul Bakaus +Brandon Aaron +Mike Alsup +Dave Methvin +Ed Engelhardt +Sean Catchpole +Paul Mclanahan +David Serduke +Richard D. Worth +Scott González +Ariel Flesler +Cheah Chu Yeow +Andrew Chalkley +Fabio Buffoni +Stefan Bauckmeier  +Jon Evans +TJ Holowaychuk +Riccardo De Agostini +Michael Bensoussan +Louis-Rémi Babé +Robert Katić +Damian Janowski +Anton Kovalyov +Dušan B. Jovanovic +Earle Castledine +Rich Dougherty +Kim Dalsgaard +Andrea Giammarchi +Fabian Jakobs +Mark Gibson +Karl Swedberg +Justin Meyer +Ben Alman +James Padolsey +David Petersen +Batiste Bieler +Jake Archibald +Alexander Farkas +Filipe Fortes +Rick Waldron +Neeraj Singh +Paul Irish +Iraê Carvalho +Matt Curry +Michael Monteleone +Noah Sloan +Tom Viner +J. Ryan Stinnett +Douglas Neiner +Adam J. Sontag +Heungsub Lee +Dave Reed +Carl Fürstenberg +Jacob Wright +Ralph Whitbeck +unknown +temp01 +Colin Snover +Jared Grippe +Ryan W Tenney +Alex Sexton +Pinhook +Ron Otten +Jephte Clain +Anton Matzneller +Dan Heberden +Henri Wiechers +Russell Holbrook +Julian Aubourg +Gianni Alessandro Chiappetta +Scott Jehl +James Burke +Jonas Pfenniger +Xavi Ramirez +Sylvester Keil +Brandon Sterne +Mathias Bynens +Lee Carpenter +Timmy Willison <4timmywil@gmail.com> +Corey Frang +Digitalxero +David Murdoch +Josh Varner +Charles McNulty +Jordan Boesch +Jess Thrysoee +Michael Murray +Alexis Abril +Rob Morgan +John Firebaugh +Sam Bisbee +Gilmore Davidson +Brian Brennan +Xavier Montillet +Daniel Pihlstrom +Sahab Yazdani +avaly +Scott Hughes +Mike Sherov +Greg Hazel +Schalk Neethling +Denis Knauf +Timo Tijhof +Steen Nielsen +Anton Ryzhov +Shi Chuan +Matt Mueller +Berker Peksag +Toby Brain +Justin +Daniel Herman +Oleg Gaidarenko +Rock Hymas +Richard Gibson +Rafaël Blais Masson +cmc3cn <59194618@qq.com> +Joe Presbrey +Sindre Sorhus +Arne de Bree +Vladislav Zarakovsky +Andrew E Monat +Oskari +Joao Henrique de Andrade Bruni +tsinha +Dominik D. Geyer +Matt Farmer +Trey Hunner +Jason Moon +Jeffery To +Kris Borchers +Vladimir Zhuravlev +Jacob Thornton +Chad Killingsworth +Vitya Muhachev +Nowres Rafid +David Benjamin +Alan Plum +Uri Gilad +Chris Faulkner +Marcel Greter +Elijah Manor +Daniel Chatfield +Daniel Gálvez +Nikita Govorov +Wesley Walser +Mike Pennisi +Matthias Jäggli +Devin Cooper +Markus Staab +Dave Riddle +Callum Macrae +Jonathan Sampson +Benjamin Truyman +Jay Merrifield +James Huston +Sai Lung Wong +Erick Ruiz de Chávez +David Bonner +Allen J Schmidt Jr +Akintayo Akinwunmi +MORGAN +Ismail Khair +Carl Danley +Mike Petrovich +Greg Lavallee +Tom H Fuertes +Roland Eckl +Yiming He +David Fox +Bennett Sorbo +Paul Ramos +Rod Vagg +Sebastian Burkhard +Zachary Adam Kaplan +Adam Coulombe +nanto_vi +nanto +Danil Somsikov +Ryunosuke SATO +Diego Tres +Jean Boussier +Andrew Plummer +Mark Raddatz +Pascal Borreli +Isaac Z. Schlueter +Karl Sieburg +Nguyen Phuc Lam +Dmitry Gusev +Steven Benner +Li Xudong +Michał Gołębiowski-Owczarek +Renato Oliveira dos Santos +Frederic Junod +Tom H Fuertes +Mitch Foley +ros3cin +Kyle Robinson Young +John Paul +Jason Bedard +Chris Talkington +Eddie Monge +Terry Jones +Jason Merino +Dan Burzo +Jeremy Dunck +Chris Price +Guy Bedford +njhamann +Goare Mao +Amey Sakhadeo +Mike Sidorov +Anthony Ryan +Lihan Li +George Kats +Dongseok Paeng +Ronny Springer +Ilya Kantor +Marian Sollmann +Chris Antaki +David Hong +Jakob Stoeck +Christopher Jones +Forbes Lindesay +S. Andrew Sheppard +Leonardo Balter +Rodrigo Rosenfeld Rosas +Daniel Husar +Philip Jägenstedt +John Hoven +Roman Reiß +Benjy Cui +Christian Kosmowski +David Corbacho +Liang Peng +TJ VanToll +Aurelio De Rosa +Senya Pugach +Dan Hart +Nazar Mokrynskyi +Benjamin Tan +Amit Merchant +Jason Bedard +Veaceslav Grimalschi +Richard McDaniel +Arthur Verschaeve +Shivaji Varma +Ben Toews +Bin Xin +Neftaly Hernandez +T.J. Crowder +Nicolas HENRY +Frederic Hemberger +Victor Homyakov +Aditya Raghavan +Anne-Gaelle Colom +Leonardo Braga +George Mauer +Stephen Edgar +Thomas Tortorini +Jörn Wagner +Jon Hester +Colin Frick +Winston Howes +Alexander O'Mara +Chris Rebert +Bastian Buchholz +Mu Haibao +Calvin Metcalf +Arthur Stolyar +Gabriel Schulhof +Gilad Peleg +Julian Alexander Murillo +Kevin Kirsche +Martin Naumann +Yongwoo Jeon +John-David Dalton +Marek Lewandowski +Bruno Pérel +Daniel Nill +Reed Loden +Sean Henderson +Gary Ye +Richard Kraaijenhagen +Connor Atherton +Christian Grete +Tom von Clef +Liza Ramo +Joelle Fleurantin +Steve Mao +Jon Dufresne +Jae Sung Park +Josh Soref +Saptak Sengupta +Henry Wong +Jun Sun +Martijn W. van der Lee +Devin Wilson +Damian Senn +Zack Hall +Vitaliy Terziev +Todor Prikumov +Bernhard M. Wiedemann +Jha Naman +Alexander Lisianoi +William Robinet +Joe Trumbull +Alexander K +Ralin Chimev +Felipe Sateler +Christophe Tafani-Dereeper +Manoj Kumar +David Broder-Rodgers +Alex Louden +Alex Padilla +karan-96 +南漂一卒 +Erik Lax +Boom Lee +Andreas Solleder +Pierre Spring +Shashanka Nataraj +CDAGaming +Matan Kotler-Berkowitz <205matan@gmail.com> +Jordan Beland +Henry Zhu +Nilton Cesar +basil.belokon +Andrey Meshkov +tmybr11 +Luis Emilio Velasco Sanchez +Ed S +Bert Zhang +Sébastien Règne +wartmanm <3869625+wartmanm@users.noreply.github.com> +Siddharth Dungarwal +abnud1 +Andrei Fangli +Marja Hölttä +buddh4 +Hoang +Wonseop Kim +Pat O'Callaghan +JuanMa Ruiz +Ahmed.S.ElAfifi +Sean Robinson +Christian Oliff diff --git a/_freeze/tidymodels-regression-part2/libs/jquery-3.5.1/jquery.js b/_freeze/tidymodels-regression-part2/libs/jquery-3.5.1/jquery.js new file mode 100644 index 0000000..5093733 --- /dev/null +++ b/_freeze/tidymodels-regression-part2/libs/jquery-3.5.1/jquery.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "\n```\n:::\n:::\n\n\nYou can either hit play in the resulting plot and then sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", + "markdown": "# Introducing the ARX forecaster\n\nThe ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nIt can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data.\n\nFrom the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `\"death_rate\"`, and predictors of `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" in the raw `jhu` data and the `lag_14_death_rate` is the value from \"2021-09-01\". In this way, we can manually check that the model used the correct predictor data if we're so inclined.\n\nNow that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nLike with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature.\n\nOk. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_623d4d77ac1bb400822d8937f0b1b87e'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done is to not impose an upper bound the data used in `hist` to make the death rate lines (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_579614de5d067c1e3c156707ca8e42ce'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAs our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nRemember the adapted \"Customize choropleth code\" that we introduced at the end of the [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). \nThat's all it takes.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nYou can either hit play in the resulting plot and then sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/_freeze/tidymodels-regression-part2/execute-results/html.json b/_freeze/tidymodels-regression-part2/execute-results/html.json index b674049..1e35f68 100644 --- a/_freeze/tidymodels-regression-part2/execute-results/html.json +++ b/_freeze/tidymodels-regression-part2/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "7ee32c5ba1c0989372740ec26327360f", + "hash": "19eea9ce59de8a2e50ff400f23e72d2c", "result": { - "markdown": "# Regression in Tidymodels - Part 2\n\nThis chapter is starts off as the Regression in Tidymodels chapter - Epidemiological time series edition and goes from there to making (slightly) more sophisticated predictions and interactive plots.\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the Regression in `Tidymodels` chapter, we're going to look at how the functions we used to perform linear regression fair when applied to a small set of epidemiological time series data. We'll be working with the built-in data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021 (this was originally compiled by JHU).\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data) just yet. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. And to do this, we'll essentially work through the same routine that we went through above (just in a different scenario). Thus, we'll opt for the same linear regression model specification. As we mentioned previously, setting the mode is unnecessary for linear regression, so let's drop that bit this time round. In addition, `lm` is the default engine for linear regression, so, we don't have to include that bit either.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_c8e1a2301b605fd10d31d77d5991e127'}\n\n```{.r .cell-code}\nlm_spec_way2 <- linear_reg()\n```\n:::\n\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_d07c113145028a505520eff20bc12b90'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec_way2 %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow let's forge ahead and get some predictions for the existing dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAnd to get a side-by-side view of the observed and predicted values (which sets us up well to compare them), we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling a bit of epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, do we only want to look to the concurrent (same-day) case information? Or should we look into the past as well? Since what happened in the past can inform us where things are heading, we could also include case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting a sliver of the future\n\nNow the big question is how far back in the past should we look? More specifically, what past case and death rates are most predictive of current deaths. This is a natural question to have at this point, but it ventures into model selection territory which beyond the scope of this article. For those interested, a lagged correlation analysis as described in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. So read it if you dare (or if you have the time).\n\nTo start, we will add predictors for the lagged 1-day death and case rates as those seem to be perhaps the most sensible choices (because yesterday is generally more predictive of today than two weeks ago would be).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can go ahead and create our recipe, and we can add a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor before, by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_fcbd0b889567108db17d97a251f4394f'}\n\n```{.r .cell-code}\nrec_spec_lag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNow, we just pop the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d034bd6f77589f3ee04a81e46a60dcd5'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec_way2) %>%\n add_recipe(rec_spec_lag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAnd viola, we got ourselves a trained workflow - which to be clear has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow we'll try to use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). So we'll throw this info. in a short dataframe and feed it into `new_data`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_e83e7a002d9bbaaec824dca5be879089'}\n\n```{.r .cell-code}\nlast_row_ca <- ca_case_death_rate_subset %>% tail(n = 1)\n\npredict(ca_lm_fit_lag, new_data = data.frame(\n case_rate = 84.7,\n lag_1_death_rate = last_row_ca$death_rate,\n lag_1_case_rate = last_row_ca$case_rate\n))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 NA\n```\n:::\n:::\n\n\nHold up... Why is our prediction NA? We inputted the necessary data with the correct variable names (no typos there). So what went wrong? The answer is two paragraphs above. And here it is: Recall that we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original model specification. So this means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. This is a bit of a pain, but so be it. The quick and dirty fix is to simply change `n = 1` to 2 in `tail()`, but let's flex our skills with `bind_rows()` instead.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_bc7c5328ace16c27fd53eb0610be2f1f'}\n\n```{.r .cell-code}\n# Add new row of to ca_case_death_rate_subset\nca_subset_plus_row <- bind_rows(\n ca_case_death_rate_subset,\n data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last_row_ca$death_rate\n )\n)\n```\n:::\n\n\nAnd then pop that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_1ab4d7dbf51419f8ddf299c5062e5c79'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_plus_row) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\n\nWonderful. We got ourselves a prediction. But that was a heck of a lot of work to get here. How could we simplify things for ourselves? Well there's a couple things that `epipredict` offers that could help us out here. \n\n### Option 1 - manually create our own `epi_recipe`\n\nInstead of using a plain old recipe, it is more advantageous to use an `epi_recipe` on an `epi_df`. Why? It unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combo above to get the lagged case and death rate variables, we can simply write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, just throw the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_26578b49ef4da25d864cd088f8349259'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec_way2) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nNotice we get the same prediction as before, just as we'd expect.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nWe can take things a notch further because the `epipredict` package has the `arx_forecaster()` function to make our lives easier by pre-processing, training the model, predicting, and performing some basic post-processing, all in one go. The reason why we can use this model is that the above is a technically a type of autoregressive (AR) model, in which a linear combination of previous values are use forecast the variable of interest. In contrast, in a multiple linear regression model, we use a linear combination of predictors to forecast the variable we're interested in.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_87146e4ff6e311476c6feb27e5127719'}\n\n```{.r .cell-code}\nca_arx_pred_jan_22 <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_pred_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nWe could easily add more lags for the case and death rates into the function . All that we got to do is add a couple of choice numbers to the `lags` argument. This is infinitely preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for each of case and death rate to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_a71bf5dcf8b9a859dc6f0736cbd53241'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the above forecaster is that it is equipped to handle panel data. That means that for our example we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nNeat! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we simply adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The major changes are that we specified what we would like to show when we hover (the predictions and the corresponding 90% predictive interval). As well, we modified the trace (a trace is just a layer to add to the plot with its own data and visualization components), so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nPretty cool for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, this checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", + "markdown": "# Regression in Tidymodels - Part 2\n\nThis chapter is starts off as the Regression in Tidymodels chapter - Epidemiological time series edition and goes from there to making (slightly) more sophisticated predictions and interactive plots.\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the Regression in `Tidymodels` chapter, we're going to look at how the functions we used to perform linear regression fair when applied to a small set of epidemiological time series data. We'll be working with the built-in data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021 (this was originally compiled by JHU).\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data) just yet. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. And to do this, we'll essentially work through the same routine that we went through above (just in a different scenario). Thus, we'll opt for the same linear regression model specification. As we mentioned previously, setting the mode is unnecessary for linear regression, so let's drop that bit this time round. In addition, `lm` is the default engine for linear regression, so, we don't have to include that bit either.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_c8e1a2301b605fd10d31d77d5991e127'}\n\n```{.r .cell-code}\nlm_spec_way2 <- linear_reg()\n```\n:::\n\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_d07c113145028a505520eff20bc12b90'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec_way2 %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow let's forge ahead and get some predictions for the existing dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAnd to get a side-by-side view of the observed and predicted values (which sets us up well to compare them), we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling a bit of epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, do we only want to look to the concurrent (same-day) case information? Or should we look into the past as well? Since what happened in the past can inform us where things are heading, we could also include case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting a sliver of the future\n\nNow the big question is how far back in the past should we look? More specifically, what past case and death rates are most predictive of current deaths. This is a natural question to have at this point, but it ventures into model selection territory which beyond the scope of this article. For those interested, a lagged correlation analysis as described in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. So read it if you dare (or if you have the time).\n\nTo start, we will add predictors for the lagged 1-day death and case rates as those seem to be perhaps the most sensible choices (because yesterday is generally more predictive of today than two weeks ago would be).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can go ahead and create our recipe, and we can add a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor before, by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_fcbd0b889567108db17d97a251f4394f'}\n\n```{.r .cell-code}\nrec_spec_lag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNow, we just pop the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d034bd6f77589f3ee04a81e46a60dcd5'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec_way2) %>%\n add_recipe(rec_spec_lag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAnd viola, we got ourselves a trained workflow - which to be clear has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow we'll try to use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). So we'll throw this info. in a short dataframe and feed it into `new_data`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_e83e7a002d9bbaaec824dca5be879089'}\n\n```{.r .cell-code}\nlast_row_ca <- ca_case_death_rate_subset %>% tail(n = 1)\n\npredict(ca_lm_fit_lag, new_data = data.frame(\n case_rate = 84.7,\n lag_1_death_rate = last_row_ca$death_rate,\n lag_1_case_rate = last_row_ca$case_rate\n))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 NA\n```\n:::\n:::\n\n\nHold up... Why is our prediction NA? We inputted the necessary data with the correct variable names (no typos there). So what went wrong? The answer is two paragraphs above. And here it is: Recall that we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original model specification. So this means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. This is a bit of a pain, but so be it. The quick and dirty fix is to simply change `n = 1` to 2 in `tail()`, but let's flex our skills with `bind_rows()` instead.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_bc7c5328ace16c27fd53eb0610be2f1f'}\n\n```{.r .cell-code}\n# Add new row of to ca_case_death_rate_subset\nca_subset_plus_row <- bind_rows(\n ca_case_death_rate_subset,\n data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last_row_ca$death_rate\n )\n)\n```\n:::\n\n\nAnd then pop that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_1ab4d7dbf51419f8ddf299c5062e5c79'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_plus_row) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\n\nWonderful. We got ourselves a prediction. But that was a heck of a lot of work to get here. How could we simplify things for ourselves? Well there's a couple things that `epipredict` offers that could help us out here. \n\n### Option 1 - manually create our own `epi_recipe`\n\nInstead of using a plain old recipe, it is more advantageous to use an `epi_recipe` on an `epi_df`. Why? It unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combo above to get the lagged case and death rate variables, we can simply write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, just throw the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_26578b49ef4da25d864cd088f8349259'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec_way2) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nNotice we get the same prediction as before, just as we'd expect.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nWe can take things a notch further because the `epipredict` package has the `arx_forecaster()` function to make our lives easier by pre-processing, training the model, predicting, and performing some basic post-processing, all in one go. The reason why we can use this model is that the above is a technically a type of autoregressive (AR) model, in which a linear combination of previous values are use forecast the variable of interest. In contrast, in a multiple linear regression model, we use a linear combination of predictors to forecast the variable we're interested in.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_87146e4ff6e311476c6feb27e5127719'}\n\n```{.r .cell-code}\nca_arx_pred_jan_22 <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_pred_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nWe could easily add more lags for the case and death rates into the function . All that we got to do is add a couple of choice numbers to the `lags` argument. This is infinitely preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for each of case and death rate to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_a71bf5dcf8b9a859dc6f0736cbd53241'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the above forecaster is that it is equipped to handle panel data. That means that for our example we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nNeat! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we simply adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The major changes are that we specified what we would like to show when we hover (the predictions and the corresponding 90% predictive interval). As well, we modified the trace (a trace is just a layer to add to the plot with its own data and visualization components), so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nPretty cool for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, this checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/arx-forecaster.qmd b/arx-forecaster.qmd index e128374..e679c63 100644 --- a/arx-forecaster.qmd +++ b/arx-forecaster.qmd @@ -227,7 +227,7 @@ all_the_states_df <- out_df %>% pivot_wider(names_from = tau, values_from = q) ``` -Remember the adapted "Customize choropleth code" that we introduced at the end of the Regression In Tidymodels chapter (UPDATE THIS REFERENCE/LINK)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). +Remember the adapted "Customize choropleth code" that we introduced at the end of the [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). That's all it takes. ```{r} diff --git a/tidymodels-regression-part2.qmd b/tidymodels-regression-part2.qmd index aa34deb..0b8b2fc 100644 --- a/tidymodels-regression-part2.qmd +++ b/tidymodels-regression-part2.qmd @@ -206,7 +206,7 @@ all_the_states$predictions Neat! We'll learn more about this and other forecasters in later chapters. -## Interactive plot of predictions +## Interactive plot of predictions {#sec-interactive-plot} Let's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related. From dbc630dbedec63edafa8d03363f8d620d34fb26b Mon Sep 17 00:00:00 2001 From: rachlobay Date: Mon, 10 Jul 2023 04:53:23 -0700 Subject: [PATCH 04/16] Extra space --- arx-forecaster.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arx-forecaster.qmd b/arx-forecaster.qmd index e679c63..4b7ec76 100644 --- a/arx-forecaster.qmd +++ b/arx-forecaster.qmd @@ -227,7 +227,7 @@ all_the_states_df <- out_df %>% pivot_wider(names_from = tau, values_from = q) ``` -Remember the adapted "Customize choropleth code" that we introduced at the end of the [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). +Remember the adapted "Customize choropleth code" that we introduced at the end of the [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). That's all it takes. ```{r} From f86a797280560361b4fafe742f782e9396319ffe Mon Sep 17 00:00:00 2001 From: rachlobay Date: Mon, 10 Jul 2023 04:54:14 -0700 Subject: [PATCH 05/16] Remove the --- _freeze/arx-forecaster/execute-results/html.json | 4 ++-- arx-forecaster.qmd | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/_freeze/arx-forecaster/execute-results/html.json b/_freeze/arx-forecaster/execute-results/html.json index 8d2d9f4..63617ca 100644 --- a/_freeze/arx-forecaster/execute-results/html.json +++ b/_freeze/arx-forecaster/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "fb1b589eca198b272ad448c6fdabeec6", + "hash": "a669d6b4ea49209c904a6632e3cf9a27", "result": { - "markdown": "# Introducing the ARX forecaster\n\nThe ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nIt can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data.\n\nFrom the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `\"death_rate\"`, and predictors of `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" in the raw `jhu` data and the `lag_14_death_rate` is the value from \"2021-09-01\". In this way, we can manually check that the model used the correct predictor data if we're so inclined.\n\nNow that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nLike with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature.\n\nOk. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_623d4d77ac1bb400822d8937f0b1b87e'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done is to not impose an upper bound the data used in `hist` to make the death rate lines (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_579614de5d067c1e3c156707ca8e42ce'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAs our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nRemember the adapted \"Customize choropleth code\" that we introduced at the end of the [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). \nThat's all it takes.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nYou can either hit play in the resulting plot and then sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", + "markdown": "# Introducing the ARX forecaster\n\nThe ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nIt can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data.\n\nFrom the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `\"death_rate\"`, and predictors of `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" in the raw `jhu` data and the `lag_14_death_rate` is the value from \"2021-09-01\". In this way, we can manually check that the model used the correct predictor data if we're so inclined.\n\nNow that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nLike with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature.\n\nOk. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_623d4d77ac1bb400822d8937f0b1b87e'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done is to not impose an upper bound the data used in `hist` to make the death rate lines (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_579614de5d067c1e3c156707ca8e42ce'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAs our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nRemember the adapted \"Customize choropleth code\" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). \nThat's all it takes.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nYou can either hit play in the resulting plot and then sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/arx-forecaster.qmd b/arx-forecaster.qmd index 4b7ec76..1174f06 100644 --- a/arx-forecaster.qmd +++ b/arx-forecaster.qmd @@ -227,7 +227,7 @@ all_the_states_df <- out_df %>% pivot_wider(names_from = tau, values_from = q) ``` -Remember the adapted "Customize choropleth code" that we introduced at the end of the [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). +Remember the adapted "Customize choropleth code" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). That's all it takes. ```{r} From 2c027b56b8860d3a5df3f7022d79615f53bddfa4 Mon Sep 17 00:00:00 2001 From: rachlobay Date: Mon, 10 Jul 2023 05:48:15 -0700 Subject: [PATCH 06/16] Edits to image alignment --- .../execute-results/html.json | 14 ++ _quarto.yml | 1 + tidymodels-intro-part2.qmd | 232 ++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 _freeze/tidymodels-intro-part2/execute-results/html.json create mode 100644 tidymodels-intro-part2.qmd diff --git a/_freeze/tidymodels-intro-part2/execute-results/html.json b/_freeze/tidymodels-intro-part2/execute-results/html.json new file mode 100644 index 0000000..55d6490 --- /dev/null +++ b/_freeze/tidymodels-intro-part2/execute-results/html.json @@ -0,0 +1,14 @@ +{ + "hash": "c65830c1baea7104088540e1a0c1b7d0", + "result": { + "markdown": "# Introduction to Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## A gentle introduction to tidymodels - `epipredict` edition\n\nThe `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To that end, let's see how some of the techniques we previously applied in the previous chapter fair on some real-world `epi_df` data.\n\nWe'll start off by loading the `epipredict` and `tidymodels` packages.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-2_19e8bed772562d5965d7b8dd83ee81ec'}\n\n```{.r .cell-code}\nlibrary(epipredict)\nlibrary(tidymodels)\n```\n:::\n\n\nThe data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We're only going to use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-3_b7bda51898d2684ae78c8343363f29d5'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(\n time_value >= \"2021-01-08\",\n time_value <= \"2021-03-08\",\n geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\")\n )\n```\n:::\n\n\nOur goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last time of March 8, 2021 using past (lagged) deaths and cases for each state. \n\nWe'll use `jhu` as our training data and we' will hold off on creating the test portion for now. One reason for this unexpected move can be understood by asking the question... Can we use the `initial_split()` function from the `rsample` package here in the way that we did before? Remember that we used it to randomly split the `penguins` dataset into a training and test set, where we used 70% of the data for training and reserved the remaining 30% for testing. But does such a random split make sense to use on time series data (and, moreover, on time series data that is grouped by state)? No. Now, the `rsample` package does offer `initial_time_split()`, which takes the first `prop` samples for training instead of a random selection (so this may be appropriate for time series data where we want to predict for one segment in the future given the past). And `group_initial_split()` creates splits of the data based on some grouping variable, but what we would ideally like is a function that accounts for both time and grouping. And to our knowledge, there's no `initial_time_group_split()` function in existence just yet. So we've got to come up with something else to do here. \n\n### Pre-processing \n\nThe pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. These pre-processing transformations that are specific for such data often include the infix of `epi` as in `step_epi` to make the distinction between them and the steps that come with `tidymodels`. \n\nAnd while there are many such transformations available, we will only showcase the following four in our example for the sake of simplicity.\n\n:::: {.columns}\n\n::: {.column width=\"52%\"}\n- `step_epi_lag()` to lag specified columns ahead by some amount (generally these would be particular numeric predictors)\n\n- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response)\n\n- `step_center()` to normalize numeric data to have a mean of zero\n\n- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"47%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-4_7b223521154c75f02574f73d1cfce866'}\n::: {.cell-output-display}\n![](img/epi_recipe_card.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nIn our case, we will center the numerical predictors to help level the playing field across them for a more meaningful interpretation of the intercept. Note that by default the ahead and lag steps assign analysis roles to the used inputted variables. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-5_63bf118edb2cc9beb0b70853f247c3c3'}\n\n```{.r .cell-code}\nr <- epi_recipe(jhu) %>%\n step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>%\n step_epi_ahead(death_rate, ahead = 7) %>%\n step_center(contains(\"lag\")) %>%\n step_epi_naomit()\n```\n:::\n\n\n### Get test data\n\nNow that we've got our recipe wrapped up and ready to go, let's revisit the problem of getting test data. What we'll do use is a function from `epipredict` that's primed to receive an `epi_recipe`. This function gets test data for predictions based on the longest lag period in the recipe. The reason that we use the longest lag is that it is the farthest back we need to go to get the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So, what `get_test_data()` does is that it will get the last 14 + 1 = 15 days for each `geo_value` and all together those comprise `latest`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-6_aaafd314f98b68f4e1262d33585a98d4'}\n\n```{.r .cell-code}\nlatest <- get_test_data(recipe = r, x = jhu)\n```\n:::\n\n\n### Model and use a trained epi_workflow to predict\n\nFor our model, we'll opt for the classic least squares regression model. However, we should note that, while least squares is often computationally simple, it may be better to use something like quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. That is, no matter the underlying distribution of the data (which, in the case of pandemic data, may be unpredictable or hard to pin down), obtaining the median or other quantiles and minimizing the absolute residuals tends to work well and be a safe bet. \n\nBelow we create an `epi_workflow()`, which extends the functionality of a `workflow()` to handle the typical panel data structures found in epidemiology. It also has one other major perk. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So we've got additional capability here to post-process our results. For our example, since we only have a recipe, and a parsnip model, we will only fill in the first two arguments.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-7_33c29e2839d7ac26850a4d6f9579060e'}\n\n```{.r .cell-code}\nwf <- epi_workflow(r, parsnip::linear_reg()) %>%\n fit(jhu)\n```\n:::\n\n\nLet's extract the model to briefly inspect it. We expect that it should contain three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-8_cb1bb2d102c6d646279a976828932f56'}\n\n```{.r .cell-code}\nwf %>%\n extract_fit_parsnip()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290\n```\n:::\n:::\n\n\nGreat! Now, we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-9_7e0bf7f2a71e797853dd3640c72699cf'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\nSuccess! Now, you may have been thinking that at this point it sure would be nice to clean up our predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts for a simpler view of the results. While post-processing is not currently supported by `tidymodels`, the good news is that `epipredict` does have such tools ready to be used. And what's great is that they are in a format that parallels what we've seen for adding pre-processing steps. \n\n### Post-processing\n\n:::: {.columns}\n\n::: {.column width=\"75%\"}\n\nBasically, each post-processing step is a layer to be added to the `frosting()`, which is a post-processing container that is akin to `recipe()`. To our `frosting()`, we'll add the following four layers\n\n- `layer_predict()` to add a prediction layer for post-processing\n\n- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for)\n\n- `layer_threshold()` to set the predictions to be at least 0\n\n- `layer_population_scaling()` to \"undo\" per-capita scaling by state to get counts from rates\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"24%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-10_d2383a6f21e32688dede0ec33e71c1be'}\n::: {.cell-output-display}\n![](img/postprocessing_cupcake.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nNote that, as with the pre-processing steps, order matters like when you follow a recipe. Thus, put the layers in so that they result in the chain of events that you want to happen and not something that belongs on Hell's Kitchen. In general, put `layer_predict()` in first and then what you want to do to the predictions after. That is, `layer_predict()` should be the first layer to make an appearance after `frosting()`, then input whatever other layers you want in the order you want them carried out. In our example, it is logical to add the layer to bound our predictions at 0 before scaling them.\n\nBut first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and just select the two columns that we need - the state abbreviation and corresponding population estimate. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-11_ffd27d99045db1ab9863dc028009dbeb'}\n\n```{.r .cell-code}\npop_dat <- state_census %>% select(abbr, pop)\n```\n:::\n\n\nNow, let's go ahead and do the post-processing that we outlined above.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-12_2027ee70ea5ffca3616ea9b7d2fd3598'}\n\n```{.r .cell-code}\nf <- frosting() %>%\n layer_predict() %>%\n layer_add_target_date() %>%\n layer_threshold(.pred, lower = 0) %>%\n layer_population_scaling(\n .pred,\n df = pop_dat,\n rate_rescaling = 1e5,\n by = c(\"geo_value\" = \"abbr\"),\n df_pop_col = \"pop\"\n )\n```\n:::\n\n\nEverything is pretty straight forward, but there's perhaps one curious choice... Why did we pick `1e5` for `rescaling_rate`? This is because the rates are \"per 100,000 people\" rather than \"per person\" as can be seen in the dataset documentation (have a look at `?case_death_rate_subset`).\n\nNow, we predict by inputting a workflow and the test data into `predict()` the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-13_067858085e13b87eabcbfb2dc3112e3b'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\n\nIt's good practice to perform a quick inspection of the predictions before moving on. But when we do that here, something doesn't quite add up... Notice that we have a negative prediction for `hi`. And the predictions look to still be rates and not counts. It looks like the postprocessing wasn't implemented at all... So what is the problem? The answer is that we forgot to add the frosting to the `epi_workflow`. Once we do that and pop the updated workflow into `predict()`, then we should get predictions that align more with our expectations.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-14_f165919016aa09119396184d3e494719'}\n\n```{.r .cell-code}\nwf_fixed <- wf %>%\n add_frosting(f)\nwf_fixed\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 5 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_center()\n#> • step_naomit()\n#> • step_naomit()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 4 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_add_target_date()\n#> • layer_threshold()\n#> • layer_population_scaling()\n```\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-15_25a3d285bb27ec86007b66be2bbb49ac'}\n\n```{.r .cell-code}\np_round2 <- predict(wf_fixed, latest)\np_round2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 5 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 5\n#> geo_value time_value .pred target_date .pred_scaled\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57\n#> 2 ca 2021-03-08 0.492 2021-03-15 194. \n#> 3 hi 2021-03-08 0 2021-03-15 0 \n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145.\n```\n:::\n:::\n\n\nMuch better! \n\n### Model validation\n\nLet's now get out the true death rates for these dates from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times may not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth on hand, and it is of course recommended that you put it to good use in validation as we are doing here. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-16_1b7fd8b3e15581ab21e5dcc02364f0ab'}\n\n```{.r .cell-code}\ntrue_death_rates <- case_death_rate_subset %>%\n filter(geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\") &\n time_value == \"2021-03-15\") %>%\n select(geo_value, death_rate)\n```\n:::\n\n\nTo adjoin the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but one important thing is that the order of the rows (states) should match up in both otherwise we could mismatch data (meant for one state to another). For instance, in our example notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_round2`. And if we had more states to deal with, it could be especially troublesome to have to go in and re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_round2` dataframe by `geo_value`. The order of the rows doesn't matter for this function because it matches based on the linking variable `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-17_62b0df9c6535a76ba0543d4601e48c09'}\n\n```{.r .cell-code}\np_w_truth <- left_join(p_round2, true_death_rates, by = \"geo_value\")\np_w_truth\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 6 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 6\n#> geo_value time_value .pred target_date .pred_scaled death_rate\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57 0.651 \n#> 2 ca 2021-03-08 0.492 2021-03-15 194. 0.481 \n#> 3 hi 2021-03-08 0 2021-03-15 0 0.0609\n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 0.456 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145. 0.539\n```\n:::\n:::\n\n\nNow let's use `metrics()` function to briefly assess our model performance. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-18_84628c2362e543e1ba7f12b0dbc7ab3c'}\n\n```{.r .cell-code}\np_w_truth %>%\n metrics(truth = death_rate, estimate = .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 3 × 3\n#> .metric .estimator .estimate\n#> \n#> 1 rmse standard 0.241\n#> 2 rsq standard 0.244\n#> 3 mae standard 0.135\n```\n:::\n:::\n\n\nAs before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better as you might expect, and the absolute minimum value that could be achieved is 0. \n\nMean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is also 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (just think of what happens when you square a large value - ie. a large difference between the predicted and the truth), so the impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). \n\nR-squared (Rsq) or the coefficient of determination tells us what proportion variation of the response is explained or captured by the independent variables. So if R-squared is 0.7, this means that the predictors explain about 70% of the variability in the response. It's calculated as the squared correlation coefficient, so it also ranges between 0 and 1, and being closer to 1 (ie. explaining more of the variance in the response) is better.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-19_f8d1a85d47783013e17dbf9a82b0808d'}\n::: {.cell-output-display}\n![](img/RMSE_MAE_RSq_oh_my.png){fig-align='center' width=80%}\n:::\n:::\n\n\nOverall, even though RMSE, MAE, and Rsq are all considered measures of goodness of (model) fit, their views on it are different. RMSE and MAE look at accuracy of predictions (in terms of small residuals), whereas R-squared looks at how the predictors are fairing (in terms of explaining the response).\n\nWhile it can be difficult to pinpoint how well exactly each metric is performing for real life data (what are \"good\" values of each metric depends on the situation), from a quick inspection the values that `metrics()` churned out, we can say that roughly-speaking the RMSE and MAE look low enough to not set off any major alarm bells. And as for R-squared, though it is perhaps not as high as we'd like, it is decent.\n\nWe will leave it at that and not venture further into model-validation territory here as it can get quite murky for epidemiological data (ex. consider the question of what to do about validating COVID-19 infection estimates), but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject.\n\n## Concluding remarks\n\nIn these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned!\n\n## Attribution\n\nThis vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). \n\n", + "supporting": [], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": {}, + "engineDependencies": {}, + "preserve": {}, + "postProcess": true + } +} \ No newline at end of file diff --git a/_quarto.yml b/_quarto.yml index c2e1e50..1df8f5e 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -42,6 +42,7 @@ book: - flatline-forecaster.qmd - arx-forecaster.qmd - tidymodels-intro.qmd + - tidymodels-intro-part2.qmd - tidymodels-regression.qmd - tidymodels-regression-part2.qmd - preprocessing-and-models.qmd diff --git a/tidymodels-intro-part2.qmd b/tidymodels-intro-part2.qmd new file mode 100644 index 0000000..7bd55ed --- /dev/null +++ b/tidymodels-intro-part2.qmd @@ -0,0 +1,232 @@ +# Introduction to Tidymodels - Part 2 + +```{r} +#| echo: false +source("_common.R") +``` + +## A gentle introduction to tidymodels - `epipredict` edition + +The `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To that end, let's see how some of the techniques we previously applied in the previous chapter fair on some real-world `epi_df` data. + +We'll start off by loading the `epipredict` and `tidymodels` packages. + +```{r, message = FALSE} +library(epipredict) +library(tidymodels) +``` + +The data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We're only going to use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. + +```{r} +jhu <- case_death_rate_subset %>% + dplyr::filter(time_value >= "2021-01-08", + time_value <= "2021-03-08", + geo_value %in% c("ca", "ny", "ar", "tx", "hi")) +``` + +Our goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last time of March 8, 2021 using past (lagged) deaths and cases for each state. + +We'll use `jhu` as our training data and we' will hold off on creating the test portion for now. One reason for this unexpected move can be understood by asking the question... Can we use the `initial_split()` function from the `rsample` package here in the way that we did before? Remember that we used it to randomly split the `penguins` dataset into a training and test set, where we used 70% of the data for training and reserved the remaining 30% for testing. But does such a random split make sense to use on time series data (and, moreover, on time series data that is grouped by state)? No. Now, the `rsample` package does offer `initial_time_split()`, which takes the first `prop` samples for training instead of a random selection (so this may be appropriate for time series data where we want to predict for one segment in the future given the past). And `group_initial_split()` creates splits of the data based on some grouping variable, but what we would ideally like is a function that accounts for both time and grouping. And to our knowledge, there's no `initial_time_group_split()` function in existence just yet. So we've got to come up with something else to do here. + +### Pre-processing + +The pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. These pre-processing transformations that are specific for such data often include the infix of `epi` as in `step_epi` to make the distinction between them and the steps that come with `tidymodels`. + +And while there are many such transformations available, we will only showcase the following four in our example for the sake of simplicity. + +:::: {.columns} + +::: {.column width="52%"} +- `step_epi_lag()` to lag specified columns ahead by some amount (generally these would be particular numeric predictors) + +- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response) + +- `step_center()` to normalize numeric data to have a mean of zero + +- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model +::: + +::: {.column width="1%"} + +::: + +::: {.column width="47%"} + +```{r, echo = FALSE} +knitr::include_graphics("img/epi_recipe_card.png") +``` +::: + +:::: + +In our case, we will center the numerical predictors to help level the playing field across them for a more meaningful interpretation of the intercept. Note that by default the ahead and lag steps assign analysis roles to the used inputted variables. + +```{r} +r <- epi_recipe(jhu) %>% + step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>% + step_epi_ahead(death_rate, ahead = 7) %>% + step_center(contains("lag")) %>% + step_epi_naomit() +``` + +### Get test data + +Now that we've got our recipe wrapped up and ready to go, let's revisit the problem of getting test data. What we'll do use is a function from `epipredict` that's primed to receive an `epi_recipe`. This function gets test data for predictions based on the longest lag period in the recipe. The reason that we use the longest lag is that it is the farthest back we need to go to get the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So, what `get_test_data()` does is that it will get the last 14 + 1 = 15 days for each `geo_value` and all together those comprise `latest`. + +```{r} +latest <- get_test_data(recipe = r, x = jhu) +``` + +### Model and use a trained epi_workflow to predict + +For our model, we'll opt for the classic least squares regression model. However, we should note that, while least squares is often computationally simple, it may be better to use something like quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. That is, no matter the underlying distribution of the data (which, in the case of pandemic data, may be unpredictable or hard to pin down), obtaining the median or other quantiles and minimizing the absolute residuals tends to work well and be a safe bet. + +Below we create an `epi_workflow()`, which extends the functionality of a `workflow()` to handle the typical panel data structures found in epidemiology. It also has one other major perk. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So we've got additional capability here to post-process our results. For our example, since we only have a recipe, and a parsnip model, we will only fill in the first two arguments. + +```{r} +wf <- epi_workflow(r, parsnip::linear_reg()) %>% + fit(jhu) +``` + +Let's extract the model to briefly inspect it. We expect that it should contain three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors. + +```{r} +wf %>% + extract_fit_parsnip() +``` + +Great! Now, we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. + +```{r} +p <- predict(wf, latest) +p +``` +Success! Now, you may have been thinking that at this point it sure would be nice to clean up our predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts for a simpler view of the results. While post-processing is not currently supported by `tidymodels`, the good news is that `epipredict` does have such tools ready to be used. And what's great is that they are in a format that parallels what we've seen for adding pre-processing steps. + +### Post-processing + +:::: {.columns} + +::: {.column width="75%"} + +Basically, each post-processing step is a layer to be added to the `frosting()`, which is a post-processing container that is akin to `recipe()`. To our `frosting()`, we'll add the following four layers + +- `layer_predict()` to add a prediction layer for post-processing + +- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for) + +- `layer_threshold()` to set the predictions to be at least 0 + +- `layer_population_scaling()` to "undo" per-capita scaling by state to get counts from rates +::: + +::: {.column width="1%"} + +::: + +::: {.column width="24%"} + +```{r, echo = FALSE} +knitr::include_graphics("img/postprocessing_cupcake.png") +``` +::: + +:::: + +Note that, as with the pre-processing steps, order matters like when you follow a recipe. Thus, put the layers in so that they result in the chain of events that you want to happen and not something that belongs on Hell's Kitchen. In general, put `layer_predict()` in first and then what you want to do to the predictions after. That is, `layer_predict()` should be the first layer to make an appearance after `frosting()`, then input whatever other layers you want in the order you want them carried out. In our example, it is logical to add the layer to bound our predictions at 0 before scaling them. + +But first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and just select the two columns that we need - the state abbreviation and corresponding population estimate. + +```{r} +pop_dat <- state_census %>% select(abbr, pop) +``` + +Now, let's go ahead and do the post-processing that we outlined above. + +```{r} +f <- frosting() %>% + layer_predict() %>% + layer_add_target_date() %>% + layer_threshold(.pred, lower = 0) %>% + layer_population_scaling( + .pred, + df = pop_dat, + rate_rescaling = 1e5, + by = c("geo_value" = "abbr"), + df_pop_col = "pop") +``` + +Everything is pretty straight forward, but there's perhaps one curious choice... Why did we pick `1e5` for `rescaling_rate`? This is because the rates are "per 100,000 people" rather than "per person" as can be seen in the dataset documentation (have a look at `?case_death_rate_subset`). + +Now, we predict by inputting a workflow and the test data into `predict()` the same way as before. + +```{r} +p <- predict(wf, latest) +p +``` + +It's good practice to perform a quick inspection of the predictions before moving on. But when we do that here, something doesn't quite add up... Notice that we have a negative prediction for `hi`. And the predictions look to still be rates and not counts. It looks like the postprocessing wasn't implemented at all... So what is the problem? The answer is that we forgot to add the frosting to the `epi_workflow`. Once we do that and pop the updated workflow into `predict()`, then we should get predictions that align more with our expectations. + +```{r} +wf_fixed <- wf %>% + add_frosting(f) +wf_fixed +``` + +```{r} +p_round2 <- predict(wf_fixed, latest) +p_round2 +``` + +Much better! + +### Model validation + +Let's now get out the true death rates for these dates from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times may not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth on hand, and it is of course recommended that you put it to good use in validation as we are doing here. + +```{r} +true_death_rates <- case_death_rate_subset %>% + filter(geo_value %in% c("ca", "ny", "ar", "tx", "hi") & + time_value == "2021-03-15") %>% + select(geo_value, death_rate) +``` + +To adjoin the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but one important thing is that the order of the rows (states) should match up in both otherwise we could mismatch data (meant for one state to another). For instance, in our example notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_round2`. And if we had more states to deal with, it could be especially troublesome to have to go in and re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_round2` dataframe by `geo_value`. The order of the rows doesn't matter for this function because it matches based on the linking variable `geo_value`. + +```{r} +p_w_truth <- left_join(p_round2, true_death_rates, by = "geo_value") +p_w_truth +``` + +Now let's use `metrics()` function to briefly assess our model performance. + +```{r} +p_w_truth %>% + metrics(truth = death_rate, estimate = .pred) +``` + +As before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better as you might expect, and the absolute minimum value that could be achieved is 0. + +Mean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is also 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (just think of what happens when you square a large value - ie. a large difference between the predicted and the truth), so the impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). + +R-squared (Rsq) or the coefficient of determination tells us what proportion variation of the response is explained or captured by the independent variables. So if R-squared is 0.7, this means that the predictors explain about 70% of the variability in the response. It's calculated as the squared correlation coefficient, so it also ranges between 0 and 1, and being closer to 1 (ie. explaining more of the variance in the response) is better. + +```{r, echo = FALSE, out.width = "80%"} +knitr::include_graphics("img/RMSE_MAE_RSq_oh_my.png") +``` + +Overall, even though RMSE, MAE, and Rsq are all considered measures of goodness of (model) fit, their views on it are different. RMSE and MAE look at accuracy of predictions (in terms of small residuals), whereas R-squared looks at how the predictors are fairing (in terms of explaining the response). + +While it can be difficult to pinpoint how well exactly each metric is performing for real life data (what are "good" values of each metric depends on the situation), from a quick inspection the values that `metrics()` churned out, we can say that roughly-speaking the RMSE and MAE look low enough to not set off any major alarm bells. And as for R-squared, though it is perhaps not as high as we'd like, it is decent. + +We will leave it at that and not venture further into model-validation territory here as it can get quite murky for epidemiological data (ex. consider the question of what to do about validating COVID-19 infection estimates), but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject. + +## Concluding remarks + +In these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned! + +## Attribution + +This vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). + From 4c8f769c845b2f735e8735a269e015aacc6c9c82 Mon Sep 17 00:00:00 2001 From: rachlobay Date: Mon, 10 Jul 2023 05:56:24 -0700 Subject: [PATCH 07/16] Change order of chapters in sidebar --- _quarto.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_quarto.yml b/_quarto.yml index 1df8f5e..3390d6e 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -39,12 +39,12 @@ book: chapters: - epipredict.qmd - forecast-framework.qmd - - flatline-forecaster.qmd - - arx-forecaster.qmd - - tidymodels-intro.qmd - - tidymodels-intro-part2.qmd - tidymodels-regression.qmd - tidymodels-regression-part2.qmd + - tidymodels-intro.qmd + - tidymodels-intro-part2.qmd + - flatline-forecaster.qmd + - arx-forecaster.qmd - preprocessing-and-models.qmd - sliding-forecasters.qmd - references.qmd From 9c99da4fe98a16ea1980e396c4d24d0b6f81565e Mon Sep 17 00:00:00 2001 From: rachlobay Date: Sun, 16 Jul 2023 00:26:30 -0700 Subject: [PATCH 08/16] Multiple aheads as geom_ribbon() instead of interval --- .../arx-forecaster/execute-results/html.json | 4 +- .../figure-html/unnamed-chunk-15-1.svg | 1030 ++++++----------- .../figure-html/unnamed-chunk-16-1.svg | 1030 ++++++----------- arx-forecaster.qmd | 36 +- 4 files changed, 771 insertions(+), 1329 deletions(-) diff --git a/_freeze/arx-forecaster/execute-results/html.json b/_freeze/arx-forecaster/execute-results/html.json index 63617ca..cf6f5d1 100644 --- a/_freeze/arx-forecaster/execute-results/html.json +++ b/_freeze/arx-forecaster/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "a669d6b4ea49209c904a6632e3cf9a27", + "hash": "4202c72997458146be9357e4568362e0", "result": { - "markdown": "# Introducing the ARX forecaster\n\nThe ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nIt can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data.\n\nFrom the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `\"death_rate\"`, and predictors of `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" in the raw `jhu` data and the `lag_14_death_rate` is the value from \"2021-09-01\". In this way, we can manually check that the model used the correct predictor data if we're so inclined.\n\nNow that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nLike with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature.\n\nOk. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_623d4d77ac1bb400822d8937f0b1b87e'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done is to not impose an upper bound the data used in `hist` to make the death rate lines (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_579614de5d067c1e3c156707ca8e42ce'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"bottom\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAs our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nRemember the adapted \"Customize choropleth code\" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). \nThat's all it takes.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nYou can either hit play in the resulting plot and then sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", + "markdown": "# Introducing the ARX forecaster\n\nThe ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nIt can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data.\n\nFrom the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `\"death_rate\"`, and predictors of `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" in the raw `jhu` data and the `lag_14_death_rate` is the value from \"2021-09-01\". In this way, we can manually check that the model used the correct predictor data if we're so inclined.\n\nNow that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nLike with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature.\n\nOk. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_c0b32b43e54a1e4afd53477c4efe790f'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d() +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done to make the death rate lines is to not impose an upper bound the data used in `hist` (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_a81d6b7174c650bfed1401a0aeb31e70'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(alpha = .7) +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAs our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nRemember the adapted \"Customize choropleth code\" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). \nThat's all it takes.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nYou can either hit play in the above plot and sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/_freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg b/_freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg index b868388..1ea0707 100644 --- a/_freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg +++ b/_freeze/arx-forecaster/figure-html/unnamed-chunk-15-1.svg @@ -79,15 +79,6 @@ - - - - - - - - - @@ -143,961 +134,688 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - + + - + - + - + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + diff --git a/_freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg b/_freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg index fcef859..2f62de9 100644 --- a/_freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg +++ b/_freeze/arx-forecaster/figure-html/unnamed-chunk-16-1.svg @@ -79,15 +79,6 @@ - - - - - - - - - @@ -143,961 +134,688 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - + + - + - + - + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + diff --git a/arx-forecaster.qmd b/arx-forecaster.qmd index 1174f06..4acdcc9 100644 --- a/arx-forecaster.qmd +++ b/arx-forecaster.qmd @@ -177,20 +177,23 @@ preds <- out_df %>% unnest(q) %>% pivot_wider(names_from = tau, values_from = q) -ggplot(hist, aes(color = geo_value)) + +ggplot(hist) + geom_line(aes(time_value, death_rate)) + - theme_bw() + - geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) + - geom_point(data = preds, aes(target_date, .pred)) + + geom_ribbon( + data = preds, + aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value) + ) + + geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) + geom_vline(data = preds, aes(xintercept = forecast_date)) + - scale_colour_viridis_d(name = "") + + scale_colour_viridis_d() + + scale_fill_viridis_d(alpha = .4) + scale_x_date(date_labels = "%b %Y") + facet_grid(rows = vars(geo_value)) + - theme(legend.position = "bottom") + + theme(legend.position = "none") + labs(x = "", y = "Incident deaths per 100K\n inhabitants") ``` -All three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done is to not impose an upper bound the data used in `hist` to make the death rate lines (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021). +All three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done to make the death rate lines is to not impose an upper bound the data used in `hist` (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021). ```{r} #| fig-height: 5 @@ -198,17 +201,20 @@ All three bear a striking resemblance to what we'd expect when using the flatlin hist <- case_death_rate_subset %>% dplyr::filter(time_value >= as.Date("2021-09-01")) %>%# No ub so we get up to the last date of Dec. 31, 2021 filter(geo_value %in% samp_geos) - -ggplot(hist, aes(color = geo_value)) + + +ggplot(hist) + geom_line(aes(time_value, death_rate)) + - theme_bw() + - geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) + - geom_point(data = preds, aes(target_date, .pred)) + + geom_ribbon( + data = preds, + aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value) + ) + + geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) + geom_vline(data = preds, aes(xintercept = forecast_date)) + - scale_colour_viridis_d(name = "") + + scale_colour_viridis_d(alpha = .7) + + scale_fill_viridis_d(alpha = .4) + scale_x_date(date_labels = "%b %Y") + facet_grid(rows = vars(geo_value)) + - theme(legend.position = "bottom") + + theme(legend.position = "none") + labs(x = "", y = "Incident deaths per 100K\n inhabitants") ``` @@ -270,7 +276,7 @@ fig <- fig %>% layout( fig ``` -You can either hit play in the resulting plot and then sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them. +You can either hit play in the above plot and sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them. A possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills. From c1e4affb8ada6ad0457ca28f1059df0f2c38b749 Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Fri, 27 Oct 2023 01:56:51 -0700 Subject: [PATCH 09/16] Remove intro-part2 & replace with tidymodels-epipredict --- .../execute-results/html.json | 14 ++ .../execute-results/html.json | 4 +- _quarto.yml | 2 +- tidymodels-epipredict.qmd | 218 ++++++++++++++++ tidymodels-intro-part2.qmd | 232 ------------------ 5 files changed, 235 insertions(+), 235 deletions(-) create mode 100644 _freeze/tidymodels-epipredict/execute-results/html.json create mode 100644 tidymodels-epipredict.qmd delete mode 100644 tidymodels-intro-part2.qmd diff --git a/_freeze/tidymodels-epipredict/execute-results/html.json b/_freeze/tidymodels-epipredict/execute-results/html.json new file mode 100644 index 0000000..9e96826 --- /dev/null +++ b/_freeze/tidymodels-epipredict/execute-results/html.json @@ -0,0 +1,14 @@ +{ + "hash": "d381a5795c10342501ec7195b8353eff", + "result": { + "markdown": "# Tidymodels with epidemiological time series data\n\n\n::: {.cell}\n\n:::\n\n\n## A gentle introduction to tidymodels - `epipredict` edition\n\nThe `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To this end, let's see how some of the techniques we applied in the previous chapter fare on some real-world `epi_df` data.\n\nWe'll start off by loading the `epipredict` and `tidymodels` packages.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-2_8f142ccff712fd9d4c964ab7b2d4a90e'}\n\n```{.r .cell-code}\nlibrary(epipredict)\nlibrary(tidymodels)\n```\n:::\n\n\nThe data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We will only use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-3_5f066f24a4c4d13fbc62d8bcae2da3d3'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(\n time_value >= \"2021-01-08\",\n time_value <= \"2021-03-08\",\n geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\")\n )\n```\n:::\n\n\nOur goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last day using past (lagged) deaths and cases for each state. \n\nWe'll use `jhu` as our training data and we will hold off on creating the test set for now. One reason for this is because we cannot reasonably apply the `initial_split()` function or any variant of it from the `rsample` package to time series data. This is because randomly splitting the data into the training and test sets (as we did with the `penguins` dataset) does not make sense for data that is ordered by time and, moreover, for such data that is grouped by state. Ideally, what we want is a function that accounts for both time and grouping. And because there's no `initial_time_group_split()` function in existence just yet, we must take an alternative approach to split the data.\n\n### Pre-processing \n\nThe pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. The pre-processing transformations that are designed for such data include the infix of `epi` as in `step_epi` to make the distinction between them and the more general steps that come with `tidymodels`. \n\nWhile there are a number of epi recipe preprocessing steps available (which are listed under the [functions reference page of the epipredict website](https://cmu-delphi.github.io/epipredict/reference/index.html), we will focus on the following four in our example for simplicity.\n\n:::: {.columns}\n\n::: {.column width=\"52%\"}\n- `step_epi_lag()` to lag specified columns by some amount (generally these would be particular numeric predictors)\n\n- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response)\n\n- `step_center()` to normalize numeric data to have a mean of zero\n\n- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"47%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-4_3b934949a97e35dfe46883ee221ff80e'}\n::: {.cell-output-display}\n![](img/epi_recipe_card.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nIn our case, we center the numerical predictors for a more meaningful interpretation of the intercept.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-5_b28af94b7fa13753fb479184627241f3'}\n\n```{.r .cell-code}\nr <- epi_recipe(jhu) %>%\n step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>%\n step_epi_ahead(death_rate, ahead = 7) %>%\n step_center(contains(\"lag\")) %>%\n step_epi_naomit()\n```\n:::\n\n\n### Get test data\n\nNow that we have our recipe ready, let's revisit the problem of getting test data. Our approach is to utilize a function from `epipredict` that is designed for epidemiological time series data. This function, `get_test_data()` has two main inputs, an `epi_recipe` and a `epi_df`. It obtains test data for predictions from the inputted `epi_df` based on the longest lag period in the `epi_recipe`. The reason that we use the longest lag is that it is the farthest back we need to go to obtain the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So `get_test_data()` obtains the last 14 + 1 = 15 days for each `geo_value` and all together these comprise the test data, `latest`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-6_1a6156d3699b1c76719531c52b560035'}\n\n```{.r .cell-code}\nlatest <- get_test_data(recipe = r, x = jhu)\n```\n:::\n\n\n### Model and using a trained epi_workflow to predict\n\nAn `epi_workflow` extends the functionality of a `workflow` to handle the typical panel data structures found in epidemiology. Before we proceed to create an `epi_workflow` where we can specify our pre-processing and model, we should note one major benefit of this over a traditional `workflow`. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So there is the additional capability to post-process the results. For our example, since we only have a recipe (`r`), and a parsnip model (`parsnip::linear_reg()`), we will only fill in the first two arguments.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-7_4006d2aa2411d65640e110c9d25cc7ed'}\n\n```{.r .cell-code}\nwf <- epi_workflow(r, parsnip::linear_reg()) %>%\n fit(jhu)\n```\n:::\n\nWhile we opted for the classic least squares regression model, we could also consider to use quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. \n\nLet's extract the model to briefly inspect it. We expect that it contains three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-8_e5f9a841c4bda0b28eb30df1b71829f9'}\n\n```{.r .cell-code}\nwf %>%\n extract_fit_parsnip()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290\n```\n:::\n:::\n\nNow we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-9_7cded75c01f7836a571a65abc1284fbe'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\nSuccess! At this point, one might consider cleaning up these predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts. While post-processing is not currently supported by `tidymodels`, `epipredict` has several post-processing operations built into the package. And what's great is that the the work flow mirrors that for adding pre-processing steps. \n\n### Post-processing\n\n:::: {.columns}\n\n::: {.column width=\"75%\"}\n\nEssentially, each post-processing step is a layer to be added to the `frosting()` post-processing container, which is akin to a `recipe()`. To our `frosting()`, we'll add the following four layers\n\n- `layer_predict()` to add a prediction layer for post-processing\n\n- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for)\n\n- `layer_threshold()` to set the predictions to be at least 0\n\n- `layer_population_scaling()` to \"undo\" per-capita scaling by state to get counts from rates\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"24%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-10_f8569ce3f32f40ebd4d324f36b6553f3'}\n::: {.cell-output-display}\n![](img/postprocessing_cupcake.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nNote that the ordering matters for the layers of frosting like it does for the steps of a recipe. In general, put `layer_predict()` in first and then what you want to do to the predictions after (in the order that you want them to happen). In our example, it is logical to add the layer to bound our predictions at 0 before scaling them.\n\nBut first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and select the two columns that we need - the state abbreviation and corresponding population estimate. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-11_a6784fe55be3368f43db02124ca5ab62'}\n\n```{.r .cell-code}\npop_dat <- state_census %>% select(abbr, pop)\n```\n:::\n\nLet's go ahead and implement the post-processing that we outlined above.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-12_de0da0ea08c1b7608deb46424945dcd5'}\n\n```{.r .cell-code}\nf <- frosting() %>%\n layer_predict() %>%\n layer_add_target_date() %>%\n layer_threshold(.pred, lower = 0) %>%\n layer_population_scaling(\n .pred,\n df = pop_dat,\n rate_rescaling = 1e5,\n by = c(\"geo_value\" = \"abbr\"),\n df_pop_col = \"pop\"\n )\n```\n:::\n\nNote that `1e5` was selected for the `rescaling_rate` because the rates are \"per 100,000 people\" rather than \"per person\" as can be seen in the dataset documentation (see `?case_death_rate_subset`).\n\nNow that the post-processing is set-up, do not forget to add the `frosting` to the `epi_workflow` before you predict. If you skip adding the `frosting` to the `epi_workflow` and go straight to predicting, then you will get the following:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-13_950a9d24c76ebfcf16fc438a672a8099'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\nNotice that we have a negative prediction for `hi`. And the predictions are rates and not counts. Based on these observations, is clear that the postprocessing was not implemented at all.\n\nLet's fix this by adding our frosting object, `f`, to our `epi_workflow` and then using the updated workflow to `predict()`. As a result of this, we should get predictions that align more with our expectations.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-14_73075de6fcaf6f5ce378b2432dc1bd2f'}\n\n```{.r .cell-code}\nwf_fixed <- wf %>%\n add_frosting(f)\nwf_fixed\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 5 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_center()\n#> • step_naomit()\n#> • step_naomit()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 4 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_add_target_date()\n#> • layer_threshold()\n#> • layer_population_scaling()\n```\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-15_cb9979730a805dddc415091f214fead3'}\n\n```{.r .cell-code}\np_fixed <- predict(wf_fixed, latest)\np_fixed\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 5 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 5\n#> geo_value time_value .pred target_date .pred_scaled\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57\n#> 2 ca 2021-03-08 0.492 2021-03-15 194. \n#> 3 hi 2021-03-08 0 2021-03-15 0 \n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145.\n```\n:::\n:::\n\nMuch better! \n\n### Model validation\n\nLet's compare our predicted death rates to the the true death rates that we can obtain from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times are not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth at your disposal. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-16_8545e31d1806a490e8199fdf7190ded3'}\n\n```{.r .cell-code}\ntrue_death_rates <- case_death_rate_subset %>%\n filter(geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\") &\n time_value == \"2021-03-15\") %>%\n select(geo_value, death_rate)\n```\n:::\n\nTo join the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but since that function binds the rows in order of their appearance, the order of rows in both dataframes must match (otherwise we risk matching data meant for one state to another). In our example, notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_fixed`. And if we had more states to manage, it could become especially bothersome to have to re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_fixed` dataframe by `geo_value`. The order of the rows does not matter for `left_join()` because it matches based on the linking variable `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-17_d6305e5a6b8cc69e27eab8659b41e5d1'}\n\n```{.r .cell-code}\np_w_truth <- left_join(p_fixed, true_death_rates, by = \"geo_value\")\np_w_truth\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 6 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 6\n#> geo_value time_value .pred target_date .pred_scaled death_rate\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57 0.651 \n#> 2 ca 2021-03-08 0.492 2021-03-15 194. 0.481 \n#> 3 hi 2021-03-08 0 2021-03-15 0 0.0609\n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 0.456 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145. 0.539\n```\n:::\n:::\n\n\nNow let's use `metrics()` function to briefly assess our model performance. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-epipredict_cache/html/unnamed-chunk-18_abf2bc13e057630086dedae5a247a344'}\n\n```{.r .cell-code}\np_w_truth %>%\n metrics(truth = death_rate, estimate = .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 3 × 3\n#> .metric .estimator .estimate\n#> \n#> 1 rmse standard 0.241\n#> 2 rsq standard 0.244\n#> 3 mae standard 0.135\n```\n:::\n:::\n\nAs before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better, and the absolute minimum value that could be achieved is 0. \n\nMean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (consider what happens when you square a large value - there's a large difference between the predicted and the truth). The impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). \n\nWhile it can be difficult to pinpoint how well exactly each metric is performing when using real life data (what are \"good\" values of each metric depends on the situation), from a quick inspection of the values that `metrics()` gives us, the RMSE and MAE are small enough such that there is no serious cause for concern.\n\nWe will leave it at that and not venture further into model-validation territory here, but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject.\n\n## Concluding remarks\n\nIn these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned!\n\n## Attribution\n\nThis vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). \n\n", + "supporting": [], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": {}, + "engineDependencies": {}, + "preserve": {}, + "postProcess": true + } +} \ No newline at end of file diff --git a/_freeze/tidymodels-intro-part2/execute-results/html.json b/_freeze/tidymodels-intro-part2/execute-results/html.json index 55d6490..c75f73b 100644 --- a/_freeze/tidymodels-intro-part2/execute-results/html.json +++ b/_freeze/tidymodels-intro-part2/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "c65830c1baea7104088540e1a0c1b7d0", + "hash": "a9c5f3dad427395e85f7d799dd61d01b", "result": { - "markdown": "# Introduction to Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## A gentle introduction to tidymodels - `epipredict` edition\n\nThe `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To that end, let's see how some of the techniques we previously applied in the previous chapter fair on some real-world `epi_df` data.\n\nWe'll start off by loading the `epipredict` and `tidymodels` packages.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-2_19e8bed772562d5965d7b8dd83ee81ec'}\n\n```{.r .cell-code}\nlibrary(epipredict)\nlibrary(tidymodels)\n```\n:::\n\n\nThe data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We're only going to use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-3_b7bda51898d2684ae78c8343363f29d5'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(\n time_value >= \"2021-01-08\",\n time_value <= \"2021-03-08\",\n geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\")\n )\n```\n:::\n\n\nOur goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last time of March 8, 2021 using past (lagged) deaths and cases for each state. \n\nWe'll use `jhu` as our training data and we' will hold off on creating the test portion for now. One reason for this unexpected move can be understood by asking the question... Can we use the `initial_split()` function from the `rsample` package here in the way that we did before? Remember that we used it to randomly split the `penguins` dataset into a training and test set, where we used 70% of the data for training and reserved the remaining 30% for testing. But does such a random split make sense to use on time series data (and, moreover, on time series data that is grouped by state)? No. Now, the `rsample` package does offer `initial_time_split()`, which takes the first `prop` samples for training instead of a random selection (so this may be appropriate for time series data where we want to predict for one segment in the future given the past). And `group_initial_split()` creates splits of the data based on some grouping variable, but what we would ideally like is a function that accounts for both time and grouping. And to our knowledge, there's no `initial_time_group_split()` function in existence just yet. So we've got to come up with something else to do here. \n\n### Pre-processing \n\nThe pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. These pre-processing transformations that are specific for such data often include the infix of `epi` as in `step_epi` to make the distinction between them and the steps that come with `tidymodels`. \n\nAnd while there are many such transformations available, we will only showcase the following four in our example for the sake of simplicity.\n\n:::: {.columns}\n\n::: {.column width=\"52%\"}\n- `step_epi_lag()` to lag specified columns ahead by some amount (generally these would be particular numeric predictors)\n\n- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response)\n\n- `step_center()` to normalize numeric data to have a mean of zero\n\n- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"47%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-4_7b223521154c75f02574f73d1cfce866'}\n::: {.cell-output-display}\n![](img/epi_recipe_card.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nIn our case, we will center the numerical predictors to help level the playing field across them for a more meaningful interpretation of the intercept. Note that by default the ahead and lag steps assign analysis roles to the used inputted variables. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-5_63bf118edb2cc9beb0b70853f247c3c3'}\n\n```{.r .cell-code}\nr <- epi_recipe(jhu) %>%\n step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>%\n step_epi_ahead(death_rate, ahead = 7) %>%\n step_center(contains(\"lag\")) %>%\n step_epi_naomit()\n```\n:::\n\n\n### Get test data\n\nNow that we've got our recipe wrapped up and ready to go, let's revisit the problem of getting test data. What we'll do use is a function from `epipredict` that's primed to receive an `epi_recipe`. This function gets test data for predictions based on the longest lag period in the recipe. The reason that we use the longest lag is that it is the farthest back we need to go to get the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So, what `get_test_data()` does is that it will get the last 14 + 1 = 15 days for each `geo_value` and all together those comprise `latest`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-6_aaafd314f98b68f4e1262d33585a98d4'}\n\n```{.r .cell-code}\nlatest <- get_test_data(recipe = r, x = jhu)\n```\n:::\n\n\n### Model and use a trained epi_workflow to predict\n\nFor our model, we'll opt for the classic least squares regression model. However, we should note that, while least squares is often computationally simple, it may be better to use something like quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. That is, no matter the underlying distribution of the data (which, in the case of pandemic data, may be unpredictable or hard to pin down), obtaining the median or other quantiles and minimizing the absolute residuals tends to work well and be a safe bet. \n\nBelow we create an `epi_workflow()`, which extends the functionality of a `workflow()` to handle the typical panel data structures found in epidemiology. It also has one other major perk. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So we've got additional capability here to post-process our results. For our example, since we only have a recipe, and a parsnip model, we will only fill in the first two arguments.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-7_33c29e2839d7ac26850a4d6f9579060e'}\n\n```{.r .cell-code}\nwf <- epi_workflow(r, parsnip::linear_reg()) %>%\n fit(jhu)\n```\n:::\n\n\nLet's extract the model to briefly inspect it. We expect that it should contain three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-8_cb1bb2d102c6d646279a976828932f56'}\n\n```{.r .cell-code}\nwf %>%\n extract_fit_parsnip()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290\n```\n:::\n:::\n\n\nGreat! Now, we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-9_7e0bf7f2a71e797853dd3640c72699cf'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\nSuccess! Now, you may have been thinking that at this point it sure would be nice to clean up our predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts for a simpler view of the results. While post-processing is not currently supported by `tidymodels`, the good news is that `epipredict` does have such tools ready to be used. And what's great is that they are in a format that parallels what we've seen for adding pre-processing steps. \n\n### Post-processing\n\n:::: {.columns}\n\n::: {.column width=\"75%\"}\n\nBasically, each post-processing step is a layer to be added to the `frosting()`, which is a post-processing container that is akin to `recipe()`. To our `frosting()`, we'll add the following four layers\n\n- `layer_predict()` to add a prediction layer for post-processing\n\n- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for)\n\n- `layer_threshold()` to set the predictions to be at least 0\n\n- `layer_population_scaling()` to \"undo\" per-capita scaling by state to get counts from rates\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"24%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-10_d2383a6f21e32688dede0ec33e71c1be'}\n::: {.cell-output-display}\n![](img/postprocessing_cupcake.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nNote that, as with the pre-processing steps, order matters like when you follow a recipe. Thus, put the layers in so that they result in the chain of events that you want to happen and not something that belongs on Hell's Kitchen. In general, put `layer_predict()` in first and then what you want to do to the predictions after. That is, `layer_predict()` should be the first layer to make an appearance after `frosting()`, then input whatever other layers you want in the order you want them carried out. In our example, it is logical to add the layer to bound our predictions at 0 before scaling them.\n\nBut first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and just select the two columns that we need - the state abbreviation and corresponding population estimate. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-11_ffd27d99045db1ab9863dc028009dbeb'}\n\n```{.r .cell-code}\npop_dat <- state_census %>% select(abbr, pop)\n```\n:::\n\n\nNow, let's go ahead and do the post-processing that we outlined above.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-12_2027ee70ea5ffca3616ea9b7d2fd3598'}\n\n```{.r .cell-code}\nf <- frosting() %>%\n layer_predict() %>%\n layer_add_target_date() %>%\n layer_threshold(.pred, lower = 0) %>%\n layer_population_scaling(\n .pred,\n df = pop_dat,\n rate_rescaling = 1e5,\n by = c(\"geo_value\" = \"abbr\"),\n df_pop_col = \"pop\"\n )\n```\n:::\n\n\nEverything is pretty straight forward, but there's perhaps one curious choice... Why did we pick `1e5` for `rescaling_rate`? This is because the rates are \"per 100,000 people\" rather than \"per person\" as can be seen in the dataset documentation (have a look at `?case_death_rate_subset`).\n\nNow, we predict by inputting a workflow and the test data into `predict()` the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-13_067858085e13b87eabcbfb2dc3112e3b'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\n\nIt's good practice to perform a quick inspection of the predictions before moving on. But when we do that here, something doesn't quite add up... Notice that we have a negative prediction for `hi`. And the predictions look to still be rates and not counts. It looks like the postprocessing wasn't implemented at all... So what is the problem? The answer is that we forgot to add the frosting to the `epi_workflow`. Once we do that and pop the updated workflow into `predict()`, then we should get predictions that align more with our expectations.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-14_f165919016aa09119396184d3e494719'}\n\n```{.r .cell-code}\nwf_fixed <- wf %>%\n add_frosting(f)\nwf_fixed\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 5 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_center()\n#> • step_naomit()\n#> • step_naomit()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 4 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_add_target_date()\n#> • layer_threshold()\n#> • layer_population_scaling()\n```\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-15_25a3d285bb27ec86007b66be2bbb49ac'}\n\n```{.r .cell-code}\np_round2 <- predict(wf_fixed, latest)\np_round2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 5 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 5\n#> geo_value time_value .pred target_date .pred_scaled\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57\n#> 2 ca 2021-03-08 0.492 2021-03-15 194. \n#> 3 hi 2021-03-08 0 2021-03-15 0 \n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145.\n```\n:::\n:::\n\n\nMuch better! \n\n### Model validation\n\nLet's now get out the true death rates for these dates from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times may not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth on hand, and it is of course recommended that you put it to good use in validation as we are doing here. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-16_1b7fd8b3e15581ab21e5dcc02364f0ab'}\n\n```{.r .cell-code}\ntrue_death_rates <- case_death_rate_subset %>%\n filter(geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\") &\n time_value == \"2021-03-15\") %>%\n select(geo_value, death_rate)\n```\n:::\n\n\nTo adjoin the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but one important thing is that the order of the rows (states) should match up in both otherwise we could mismatch data (meant for one state to another). For instance, in our example notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_round2`. And if we had more states to deal with, it could be especially troublesome to have to go in and re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_round2` dataframe by `geo_value`. The order of the rows doesn't matter for this function because it matches based on the linking variable `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-17_62b0df9c6535a76ba0543d4601e48c09'}\n\n```{.r .cell-code}\np_w_truth <- left_join(p_round2, true_death_rates, by = \"geo_value\")\np_w_truth\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 6 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 6\n#> geo_value time_value .pred target_date .pred_scaled death_rate\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57 0.651 \n#> 2 ca 2021-03-08 0.492 2021-03-15 194. 0.481 \n#> 3 hi 2021-03-08 0 2021-03-15 0 0.0609\n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 0.456 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145. 0.539\n```\n:::\n:::\n\n\nNow let's use `metrics()` function to briefly assess our model performance. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-18_84628c2362e543e1ba7f12b0dbc7ab3c'}\n\n```{.r .cell-code}\np_w_truth %>%\n metrics(truth = death_rate, estimate = .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 3 × 3\n#> .metric .estimator .estimate\n#> \n#> 1 rmse standard 0.241\n#> 2 rsq standard 0.244\n#> 3 mae standard 0.135\n```\n:::\n:::\n\n\nAs before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better as you might expect, and the absolute minimum value that could be achieved is 0. \n\nMean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is also 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (just think of what happens when you square a large value - ie. a large difference between the predicted and the truth), so the impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). \n\nR-squared (Rsq) or the coefficient of determination tells us what proportion variation of the response is explained or captured by the independent variables. So if R-squared is 0.7, this means that the predictors explain about 70% of the variability in the response. It's calculated as the squared correlation coefficient, so it also ranges between 0 and 1, and being closer to 1 (ie. explaining more of the variance in the response) is better.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-19_f8d1a85d47783013e17dbf9a82b0808d'}\n::: {.cell-output-display}\n![](img/RMSE_MAE_RSq_oh_my.png){fig-align='center' width=80%}\n:::\n:::\n\n\nOverall, even though RMSE, MAE, and Rsq are all considered measures of goodness of (model) fit, their views on it are different. RMSE and MAE look at accuracy of predictions (in terms of small residuals), whereas R-squared looks at how the predictors are fairing (in terms of explaining the response).\n\nWhile it can be difficult to pinpoint how well exactly each metric is performing for real life data (what are \"good\" values of each metric depends on the situation), from a quick inspection the values that `metrics()` churned out, we can say that roughly-speaking the RMSE and MAE look low enough to not set off any major alarm bells. And as for R-squared, though it is perhaps not as high as we'd like, it is decent.\n\nWe will leave it at that and not venture further into model-validation territory here as it can get quite murky for epidemiological data (ex. consider the question of what to do about validating COVID-19 infection estimates), but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject.\n\n## Concluding remarks\n\nIn these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned!\n\n## Attribution\n\nThis vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). \n\n", + "markdown": "# Introduction to Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## A gentle introduction to tidymodels - `epipredict` edition\n\nThe `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To that end, let's see how some of the techniques we previously applied in the previous chapter fair on some real-world `epi_df` data.\n\nWe'll start off by loading the `epipredict` and `tidymodels` packages.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-2_19e8bed772562d5965d7b8dd83ee81ec'}\n\n```{.r .cell-code}\nlibrary(epipredict)\nlibrary(tidymodels)\n```\n:::\n\n\nThe data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We're only going to use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-3_b7bda51898d2684ae78c8343363f29d5'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(\n time_value >= \"2021-01-08\",\n time_value <= \"2021-03-08\",\n geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\")\n )\n```\n:::\n\n\nOur goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last time of March 8, 2021 using past (lagged) deaths and cases for each state. \n\nWe'll use `jhu` as our training data and we' will hold off on creating the test portion for now. One reason for this unexpected move can be understood by asking the question... Can we use the `initial_split()` function from the `rsample` package here in the way that we did before? Remember that we used it to randomly split the `penguins` dataset into a training and test set, where we used 70% of the data for training and reserved the remaining 30% for testing. But does such a random split make sense to use on time series data (and, moreover, on time series data that is grouped by state)? No. Now, the `rsample` package does offer `initial_time_split()`, which takes the first `prop` samples for training instead of a random selection (so this may be appropriate for time series data where we want to predict for one segment in the future given the past). And `group_initial_split()` creates splits of the data based on some grouping variable, but what we would ideally like is a function that accounts for both time and grouping. And to our knowledge, there's no `initial_time_group_split()` function in existence just yet. So we've got to come up with something else to do here. \n\n### Pre-processing \n\nThe pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. These pre-processing transformations that are specific for such data often include the infix of `epi` as in `step_epi` to make the distinction between them and the steps that come with `tidymodels`. \n\nAnd while there are many such transformations available, we will only showcase the following four in our example for the sake of simplicity.\n\n:::: {.columns}\n\n::: {.column width=\"52%\"}\n- `step_epi_lag()` to lag specified columns ahead by some amount (generally these would be particular numeric predictors)\n\n- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response)\n\n- `step_center()` to normalize numeric data to have a mean of zero\n\n- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"47%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-4_7b223521154c75f02574f73d1cfce866'}\n::: {.cell-output-display}\n![](img/epi_recipe_card.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nIn our case, we will center the numerical predictors to help level the playing field across them for a more meaningful interpretation of the intercept. Note that by default the ahead and lag steps assign analysis roles to the used inputted variables. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-5_63bf118edb2cc9beb0b70853f247c3c3'}\n\n```{.r .cell-code}\nr <- epi_recipe(jhu) %>%\n step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>%\n step_epi_ahead(death_rate, ahead = 7) %>%\n step_center(contains(\"lag\")) %>%\n step_epi_naomit()\n```\n:::\n\n\n### Get test data\n\nNow that we've got our recipe wrapped up and ready to go, let's revisit the problem of getting test data. What we'll do use is a function from `epipredict` that's primed to receive an `epi_recipe`. This function gets test data for predictions based on the longest lag period in the recipe. The reason that we use the longest lag is that it is the farthest back we need to go to get the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So, what `get_test_data()` does is that it will get the last 14 + 1 = 15 days for each `geo_value` and all together those comprise `latest`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-6_aaafd314f98b68f4e1262d33585a98d4'}\n\n```{.r .cell-code}\nlatest <- get_test_data(recipe = r, x = jhu)\n```\n:::\n\n\n### Model and use a trained epi_workflow to predict\n\nFor our model, we'll opt for the classic least squares regression model. However, we should note that, while least squares is often computationally simple, it may be better to use something like quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. That is, no matter the underlying distribution of the data (which, in the case of pandemic data, may be unpredictable or hard to pin down), obtaining the median or other quantiles and minimizing the absolute residuals tends to work well and be a safe bet. \n\nBelow we create an `epi_workflow()`, which extends the functionality of a `workflow()` to handle the typical panel data structures found in epidemiology. It also has one other major perk. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So we've got additional capability here to post-process our results. For our example, since we only have a recipe, and a parsnip model, we will only fill in the first two arguments.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-7_33c29e2839d7ac26850a4d6f9579060e'}\n\n```{.r .cell-code}\nwf <- epi_workflow(r, parsnip::linear_reg()) %>%\n fit(jhu)\n```\n:::\n\n\nLet's extract the model to briefly inspect it. We expect that it should contain three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-8_cb1bb2d102c6d646279a976828932f56'}\n\n```{.r .cell-code}\nwf %>%\n extract_fit_parsnip()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290\n```\n:::\n:::\n\n\nGreat! Now, we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-9_7e0bf7f2a71e797853dd3640c72699cf'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\nSuccess! Now, you may have been thinking that at this point it sure would be nice to clean up our predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts for a simpler view of the results. While post-processing is not currently supported by `tidymodels`, the good news is that `epipredict` does have such tools ready to be used. And what's great is that they are in a format that parallels what we've seen for adding pre-processing steps. \n\n### Post-processing\n\n:::: {.columns}\n\n::: {.column width=\"75%\"}\n\nBasically, each post-processing step is a layer to be added to the `frosting()`, which is a post-processing container that is akin to `recipe()`. To our `frosting()`, we'll add the following four layers\n\n- `layer_predict()` to add a prediction layer for post-processing\n\n- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for)\n\n- `layer_threshold()` to set the predictions to be at least 0\n\n- `layer_population_scaling()` to \"undo\" per-capita scaling by state to get counts from rates\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"24%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-10_d2383a6f21e32688dede0ec33e71c1be'}\n::: {.cell-output-display}\n![](img/postprocessing_cupcake.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nNote that, as with the pre-processing steps, order matters like when you follow a recipe. Thus, put the layers in so that they result in the chain of events that you want to happen and not something that belongs on Hell's Kitchen. In general, put `layer_predict()` in first and then what you want to do to the predictions after. That is, `layer_predict()` should be the first layer to make an appearance after `frosting()`, then input whatever other layers you want in the order you want them carried out. In our example, it is logical to add the layer to bound our predictions at 0 before scaling them.\n\nBut first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and just select the two columns that we need - the state abbreviation and corresponding population estimate. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-11_ffd27d99045db1ab9863dc028009dbeb'}\n\n```{.r .cell-code}\npop_dat <- state_census %>% select(abbr, pop)\n```\n:::\n\n\nNow, let's go ahead and do the post-processing that we outlined above.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-12_2027ee70ea5ffca3616ea9b7d2fd3598'}\n\n```{.r .cell-code}\nf <- frosting() %>%\n layer_predict() %>%\n layer_add_target_date() %>%\n layer_threshold(.pred, lower = 0) %>%\n layer_population_scaling(\n .pred,\n df = pop_dat,\n rate_rescaling = 1e5,\n by = c(\"geo_value\" = \"abbr\"),\n df_pop_col = \"pop\"\n )\n```\n:::\n\n\nEverything is pretty straight forward, but there's perhaps one curious choice... Why did we pick `1e5` for `rescaling_rate`? This is because the rates are \"per 100,000 people\" rather than \"per person\" as can be seen in the dataset documentation (have a look at `?case_death_rate_subset`).\n\nNow, we predict by inputting a workflow and the test data into `predict()` the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-13_067858085e13b87eabcbfb2dc3112e3b'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\n\nIt's good practice to perform a quick inspection of the predictions before moving on. But when we do that here, something doesn't quite add up... Notice that we have a negative prediction for `hi`. And the predictions look to still be rates and not counts. It looks like the postprocessing wasn't implemented at all... So what is the problem? The answer is that we forgot to add the frosting to the `epi_workflow`. Once we do that and pop the updated workflow into `predict()`, then we should get predictions that align more with our expectations.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-14_f165919016aa09119396184d3e494719'}\n\n```{.r .cell-code}\nwf_fixed <- wf %>%\n add_frosting(f)\nwf_fixed\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 5 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_center()\n#> • step_naomit()\n#> • step_naomit()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 4 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_add_target_date()\n#> • layer_threshold()\n#> • layer_population_scaling()\n```\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-15_25a3d285bb27ec86007b66be2bbb49ac'}\n\n```{.r .cell-code}\np_round2 <- predict(wf_fixed, latest)\np_round2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 5 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 5\n#> geo_value time_value .pred target_date .pred_scaled\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57\n#> 2 ca 2021-03-08 0.492 2021-03-15 194. \n#> 3 hi 2021-03-08 0 2021-03-15 0 \n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145.\n```\n:::\n:::\n\n\nMuch better! \n\n### Model validation\n\nLet's now get out the true death rates for these dates from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times may not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth on hand, and it is of course recommended that you put it to good use in validation as we are doing here. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-16_1b7fd8b3e15581ab21e5dcc02364f0ab'}\n\n```{.r .cell-code}\ntrue_death_rates <- case_death_rate_subset %>%\n filter(geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\") &\n time_value == \"2021-03-15\") %>%\n select(geo_value, death_rate)\n```\n:::\n\n\nTo adjoin the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but one important thing is that the order of the rows (states) should match up in both otherwise we could mismatch data (meant for one state to another). For instance, in our example notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_round2`. And if we had more states to deal with, it could be especially troublesome to have to go in and re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_round2` dataframe by `geo_value`. The order of the rows doesn't matter for this function because it matches based on the linking variable `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-17_62b0df9c6535a76ba0543d4601e48c09'}\n\n```{.r .cell-code}\np_w_truth <- left_join(p_round2, true_death_rates, by = \"geo_value\")\np_w_truth\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 6 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 6\n#> geo_value time_value .pred target_date .pred_scaled death_rate\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57 0.651 \n#> 2 ca 2021-03-08 0.492 2021-03-15 194. 0.481 \n#> 3 hi 2021-03-08 0 2021-03-15 0 0.0609\n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 0.456 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145. 0.539\n```\n:::\n:::\n\n\nNow let's use `metrics()` function to briefly assess our model performance. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-18_84628c2362e543e1ba7f12b0dbc7ab3c'}\n\n```{.r .cell-code}\np_w_truth %>%\n metrics(truth = death_rate, estimate = .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 3 × 3\n#> .metric .estimator .estimate\n#> \n#> 1 rmse standard 0.241\n#> 2 rsq standard 0.244\n#> 3 mae standard 0.135\n```\n:::\n:::\n\n\nAs before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better, and the absolute minimum value that could be achieved is 0. \n\nMean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is also 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (consider what happens when you square a large value - there's a large difference between the predicted and the truth). The impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). \n\nWhile it can be difficult to pinpoint how well exactly each metric is performing for real life data (what are \"good\" values of each metric depends on the situation), from a quick inspection of the values that `metrics()` churned out, the RMSE and MAE look low enough to not raise alarms.\n\nWe will leave it at that and not venture further into model-validation territory here as it can get quite murky for epidemiological data (ex. consider the question of what to do about validating COVID-19 infection estimates), but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject.\n\n## Concluding remarks\n\nIn these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned!\n\n## Attribution\n\nThis vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). \n\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/_quarto.yml b/_quarto.yml index 3390d6e..f735dc3 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -42,7 +42,7 @@ book: - tidymodels-regression.qmd - tidymodels-regression-part2.qmd - tidymodels-intro.qmd - - tidymodels-intro-part2.qmd + - tidymodels-epipredict.qmd - flatline-forecaster.qmd - arx-forecaster.qmd - preprocessing-and-models.qmd diff --git a/tidymodels-epipredict.qmd b/tidymodels-epipredict.qmd new file mode 100644 index 0000000..27cb03d --- /dev/null +++ b/tidymodels-epipredict.qmd @@ -0,0 +1,218 @@ +# Tidymodels with epidemiological time series data + +```{r} +#| echo: false +source("_common.R") +``` + +## A gentle introduction to tidymodels - `epipredict` edition + +The `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To this end, let's see how some of the techniques we applied in the previous chapter fare on some real-world `epi_df` data. + +We'll start off by loading the `epipredict` and `tidymodels` packages. + +```{r, message = FALSE} +library(epipredict) +library(tidymodels) +``` + +The data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We will only use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. + +```{r} +jhu <- case_death_rate_subset %>% + dplyr::filter(time_value >= "2021-01-08", + time_value <= "2021-03-08", + geo_value %in% c("ca", "ny", "ar", "tx", "hi")) +``` + +Our goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last day using past (lagged) deaths and cases for each state. + +We'll use `jhu` as our training data and we will hold off on creating the test set for now. One reason for this is because we cannot reasonably apply the `initial_split()` function or any variant of it from the `rsample` package to time series data. This is because randomly splitting the data into the training and test sets (as we did with the `penguins` dataset) does not make sense for data that is ordered by time and, moreover, for such data that is grouped by state. Ideally, what we want is a function that accounts for both time and grouping. And because there's no `initial_time_group_split()` function in existence just yet, we must take an alternative approach to split the data. + +### Pre-processing + +The pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. The pre-processing transformations that are designed for such data include the infix of `epi` as in `step_epi` to make the distinction between them and the more general steps that come with `tidymodels`. + +While there are a number of epi recipe preprocessing steps available (which are listed under the [functions reference page of the epipredict website](https://cmu-delphi.github.io/epipredict/reference/index.html), we will focus on the following four in our example for simplicity. + +:::: {.columns} + +::: {.column width="52%"} +- `step_epi_lag()` to lag specified columns by some amount (generally these would be particular numeric predictors) + +- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response) + +- `step_center()` to normalize numeric data to have a mean of zero + +- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model +::: + +::: {.column width="1%"} + +::: + +::: {.column width="47%"} + +```{r, echo = FALSE} +knitr::include_graphics("img/epi_recipe_card.png") +``` +::: + +:::: + +In our case, we center the numerical predictors for a more meaningful interpretation of the intercept. + +```{r} +r <- epi_recipe(jhu) %>% + step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>% + step_epi_ahead(death_rate, ahead = 7) %>% + step_center(contains("lag")) %>% + step_epi_naomit() +``` + +### Get test data + +Now that we have our recipe ready, let's revisit the problem of getting test data. Our approach is to utilize a function from `epipredict` that is designed for epidemiological time series data. This function, `get_test_data()` has two main inputs, an `epi_recipe` and a `epi_df`. It obtains test data for predictions from the inputted `epi_df` based on the longest lag period in the `epi_recipe`. The reason that we use the longest lag is that it is the farthest back we need to go to obtain the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So `get_test_data()` obtains the last 14 + 1 = 15 days for each `geo_value` and all together these comprise the test data, `latest`. + +```{r} +latest <- get_test_data(recipe = r, x = jhu) +``` + +### Model and using a trained epi_workflow to predict + +An `epi_workflow` extends the functionality of a `workflow` to handle the typical panel data structures found in epidemiology. Before we proceed to create an `epi_workflow` where we can specify our pre-processing and model, we should note one major benefit of this over a traditional `workflow`. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So there is the additional capability to post-process the results. For our example, since we only have a recipe (`r`), and a parsnip model (`parsnip::linear_reg()`), we will only fill in the first two arguments. + +```{r} +wf <- epi_workflow(r, parsnip::linear_reg()) %>% + fit(jhu) +``` +While we opted for the classic least squares regression model, we could also consider to use quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. + +Let's extract the model to briefly inspect it. We expect that it contains three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors. + +```{r} +wf %>% + extract_fit_parsnip() +``` +Now we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. + +```{r} +p <- predict(wf, latest) +p +``` +Success! At this point, one might consider cleaning up these predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts. While post-processing is not currently supported by `tidymodels`, `epipredict` has several post-processing operations built into the package. And what's great is that the the work flow mirrors that for adding pre-processing steps. + +### Post-processing + +:::: {.columns} + +::: {.column width="75%"} + +Essentially, each post-processing step is a layer to be added to the `frosting()` post-processing container, which is akin to a `recipe()`. To our `frosting()`, we'll add the following four layers + +- `layer_predict()` to add a prediction layer for post-processing + +- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for) + +- `layer_threshold()` to set the predictions to be at least 0 + +- `layer_population_scaling()` to "undo" per-capita scaling by state to get counts from rates +::: + +::: {.column width="1%"} + +::: + +::: {.column width="24%"} + +```{r, echo = FALSE} +knitr::include_graphics("img/postprocessing_cupcake.png") +``` +::: + +:::: + +Note that the ordering matters for the layers of frosting like it does for the steps of a recipe. In general, put `layer_predict()` in first and then what you want to do to the predictions after (in the order that you want them to happen). In our example, it is logical to add the layer to bound our predictions at 0 before scaling them. + +But first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and select the two columns that we need - the state abbreviation and corresponding population estimate. + +```{r} +pop_dat <- state_census %>% select(abbr, pop) +``` +Let's go ahead and implement the post-processing that we outlined above. + +```{r} +f <- frosting() %>% + layer_predict() %>% + layer_add_target_date() %>% + layer_threshold(.pred, lower = 0) %>% + layer_population_scaling( + .pred, + df = pop_dat, + rate_rescaling = 1e5, + by = c("geo_value" = "abbr"), + df_pop_col = "pop") +``` +Note that `1e5` was selected for the `rescaling_rate` because the rates are "per 100,000 people" rather than "per person" as can be seen in the dataset documentation (see `?case_death_rate_subset`). + +Now that the post-processing is set-up, do not forget to add the `frosting` to the `epi_workflow` before you predict. If you skip adding the `frosting` to the `epi_workflow` and go straight to predicting, then you will get the following: + +```{r} +p <- predict(wf, latest) +p +``` +Notice that we have a negative prediction for `hi`. And the predictions are rates and not counts. Based on these observations, is clear that the postprocessing was not implemented at all. + +Let's fix this by adding our frosting object, `f`, to our `epi_workflow` and then using the updated workflow to `predict()`. As a result of this, we should get predictions that align more with our expectations. + +```{r} +wf_fixed <- wf %>% + add_frosting(f) +wf_fixed +``` + +```{r} +p_fixed <- predict(wf_fixed, latest) +p_fixed +``` +Much better! + +### Model validation + +Let's compare our predicted death rates to the the true death rates that we can obtain from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times are not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth at your disposal. + +```{r} +true_death_rates <- case_death_rate_subset %>% + filter(geo_value %in% c("ca", "ny", "ar", "tx", "hi") & + time_value == "2021-03-15") %>% + select(geo_value, death_rate) +``` +To join the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but since that function binds the rows in order of their appearance, the order of rows in both dataframes must match (otherwise we risk matching data meant for one state to another). In our example, notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_fixed`. And if we had more states to manage, it could become especially bothersome to have to re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_fixed` dataframe by `geo_value`. The order of the rows does not matter for `left_join()` because it matches based on the linking variable `geo_value`. + +```{r} +p_w_truth <- left_join(p_fixed, true_death_rates, by = "geo_value") +p_w_truth +``` + +Now let's use `metrics()` function to briefly assess our model performance. + +```{r} +p_w_truth %>% + metrics(truth = death_rate, estimate = .pred) +``` +As before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better, and the absolute minimum value that could be achieved is 0. + +Mean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (consider what happens when you square a large value - there's a large difference between the predicted and the truth). The impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). + +While it can be difficult to pinpoint how well exactly each metric is performing when using real life data (what are "good" values of each metric depends on the situation), from a quick inspection of the values that `metrics()` gives us, the RMSE and MAE are small enough such that there is no serious cause for concern. + +We will leave it at that and not venture further into model-validation territory here, but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject. + +## Concluding remarks + +In these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned! + +## Attribution + +This vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). + diff --git a/tidymodels-intro-part2.qmd b/tidymodels-intro-part2.qmd deleted file mode 100644 index 7bd55ed..0000000 --- a/tidymodels-intro-part2.qmd +++ /dev/null @@ -1,232 +0,0 @@ -# Introduction to Tidymodels - Part 2 - -```{r} -#| echo: false -source("_common.R") -``` - -## A gentle introduction to tidymodels - `epipredict` edition - -The `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To that end, let's see how some of the techniques we previously applied in the previous chapter fair on some real-world `epi_df` data. - -We'll start off by loading the `epipredict` and `tidymodels` packages. - -```{r, message = FALSE} -library(epipredict) -library(tidymodels) -``` - -The data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We're only going to use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. - -```{r} -jhu <- case_death_rate_subset %>% - dplyr::filter(time_value >= "2021-01-08", - time_value <= "2021-03-08", - geo_value %in% c("ca", "ny", "ar", "tx", "hi")) -``` - -Our goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last time of March 8, 2021 using past (lagged) deaths and cases for each state. - -We'll use `jhu` as our training data and we' will hold off on creating the test portion for now. One reason for this unexpected move can be understood by asking the question... Can we use the `initial_split()` function from the `rsample` package here in the way that we did before? Remember that we used it to randomly split the `penguins` dataset into a training and test set, where we used 70% of the data for training and reserved the remaining 30% for testing. But does such a random split make sense to use on time series data (and, moreover, on time series data that is grouped by state)? No. Now, the `rsample` package does offer `initial_time_split()`, which takes the first `prop` samples for training instead of a random selection (so this may be appropriate for time series data where we want to predict for one segment in the future given the past). And `group_initial_split()` creates splits of the data based on some grouping variable, but what we would ideally like is a function that accounts for both time and grouping. And to our knowledge, there's no `initial_time_group_split()` function in existence just yet. So we've got to come up with something else to do here. - -### Pre-processing - -The pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. These pre-processing transformations that are specific for such data often include the infix of `epi` as in `step_epi` to make the distinction between them and the steps that come with `tidymodels`. - -And while there are many such transformations available, we will only showcase the following four in our example for the sake of simplicity. - -:::: {.columns} - -::: {.column width="52%"} -- `step_epi_lag()` to lag specified columns ahead by some amount (generally these would be particular numeric predictors) - -- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response) - -- `step_center()` to normalize numeric data to have a mean of zero - -- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model -::: - -::: {.column width="1%"} - -::: - -::: {.column width="47%"} - -```{r, echo = FALSE} -knitr::include_graphics("img/epi_recipe_card.png") -``` -::: - -:::: - -In our case, we will center the numerical predictors to help level the playing field across them for a more meaningful interpretation of the intercept. Note that by default the ahead and lag steps assign analysis roles to the used inputted variables. - -```{r} -r <- epi_recipe(jhu) %>% - step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>% - step_epi_ahead(death_rate, ahead = 7) %>% - step_center(contains("lag")) %>% - step_epi_naomit() -``` - -### Get test data - -Now that we've got our recipe wrapped up and ready to go, let's revisit the problem of getting test data. What we'll do use is a function from `epipredict` that's primed to receive an `epi_recipe`. This function gets test data for predictions based on the longest lag period in the recipe. The reason that we use the longest lag is that it is the farthest back we need to go to get the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So, what `get_test_data()` does is that it will get the last 14 + 1 = 15 days for each `geo_value` and all together those comprise `latest`. - -```{r} -latest <- get_test_data(recipe = r, x = jhu) -``` - -### Model and use a trained epi_workflow to predict - -For our model, we'll opt for the classic least squares regression model. However, we should note that, while least squares is often computationally simple, it may be better to use something like quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. That is, no matter the underlying distribution of the data (which, in the case of pandemic data, may be unpredictable or hard to pin down), obtaining the median or other quantiles and minimizing the absolute residuals tends to work well and be a safe bet. - -Below we create an `epi_workflow()`, which extends the functionality of a `workflow()` to handle the typical panel data structures found in epidemiology. It also has one other major perk. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So we've got additional capability here to post-process our results. For our example, since we only have a recipe, and a parsnip model, we will only fill in the first two arguments. - -```{r} -wf <- epi_workflow(r, parsnip::linear_reg()) %>% - fit(jhu) -``` - -Let's extract the model to briefly inspect it. We expect that it should contain three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors. - -```{r} -wf %>% - extract_fit_parsnip() -``` - -Great! Now, we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. - -```{r} -p <- predict(wf, latest) -p -``` -Success! Now, you may have been thinking that at this point it sure would be nice to clean up our predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts for a simpler view of the results. While post-processing is not currently supported by `tidymodels`, the good news is that `epipredict` does have such tools ready to be used. And what's great is that they are in a format that parallels what we've seen for adding pre-processing steps. - -### Post-processing - -:::: {.columns} - -::: {.column width="75%"} - -Basically, each post-processing step is a layer to be added to the `frosting()`, which is a post-processing container that is akin to `recipe()`. To our `frosting()`, we'll add the following four layers - -- `layer_predict()` to add a prediction layer for post-processing - -- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for) - -- `layer_threshold()` to set the predictions to be at least 0 - -- `layer_population_scaling()` to "undo" per-capita scaling by state to get counts from rates -::: - -::: {.column width="1%"} - -::: - -::: {.column width="24%"} - -```{r, echo = FALSE} -knitr::include_graphics("img/postprocessing_cupcake.png") -``` -::: - -:::: - -Note that, as with the pre-processing steps, order matters like when you follow a recipe. Thus, put the layers in so that they result in the chain of events that you want to happen and not something that belongs on Hell's Kitchen. In general, put `layer_predict()` in first and then what you want to do to the predictions after. That is, `layer_predict()` should be the first layer to make an appearance after `frosting()`, then input whatever other layers you want in the order you want them carried out. In our example, it is logical to add the layer to bound our predictions at 0 before scaling them. - -But first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and just select the two columns that we need - the state abbreviation and corresponding population estimate. - -```{r} -pop_dat <- state_census %>% select(abbr, pop) -``` - -Now, let's go ahead and do the post-processing that we outlined above. - -```{r} -f <- frosting() %>% - layer_predict() %>% - layer_add_target_date() %>% - layer_threshold(.pred, lower = 0) %>% - layer_population_scaling( - .pred, - df = pop_dat, - rate_rescaling = 1e5, - by = c("geo_value" = "abbr"), - df_pop_col = "pop") -``` - -Everything is pretty straight forward, but there's perhaps one curious choice... Why did we pick `1e5` for `rescaling_rate`? This is because the rates are "per 100,000 people" rather than "per person" as can be seen in the dataset documentation (have a look at `?case_death_rate_subset`). - -Now, we predict by inputting a workflow and the test data into `predict()` the same way as before. - -```{r} -p <- predict(wf, latest) -p -``` - -It's good practice to perform a quick inspection of the predictions before moving on. But when we do that here, something doesn't quite add up... Notice that we have a negative prediction for `hi`. And the predictions look to still be rates and not counts. It looks like the postprocessing wasn't implemented at all... So what is the problem? The answer is that we forgot to add the frosting to the `epi_workflow`. Once we do that and pop the updated workflow into `predict()`, then we should get predictions that align more with our expectations. - -```{r} -wf_fixed <- wf %>% - add_frosting(f) -wf_fixed -``` - -```{r} -p_round2 <- predict(wf_fixed, latest) -p_round2 -``` - -Much better! - -### Model validation - -Let's now get out the true death rates for these dates from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times may not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth on hand, and it is of course recommended that you put it to good use in validation as we are doing here. - -```{r} -true_death_rates <- case_death_rate_subset %>% - filter(geo_value %in% c("ca", "ny", "ar", "tx", "hi") & - time_value == "2021-03-15") %>% - select(geo_value, death_rate) -``` - -To adjoin the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but one important thing is that the order of the rows (states) should match up in both otherwise we could mismatch data (meant for one state to another). For instance, in our example notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_round2`. And if we had more states to deal with, it could be especially troublesome to have to go in and re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_round2` dataframe by `geo_value`. The order of the rows doesn't matter for this function because it matches based on the linking variable `geo_value`. - -```{r} -p_w_truth <- left_join(p_round2, true_death_rates, by = "geo_value") -p_w_truth -``` - -Now let's use `metrics()` function to briefly assess our model performance. - -```{r} -p_w_truth %>% - metrics(truth = death_rate, estimate = .pred) -``` - -As before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better as you might expect, and the absolute minimum value that could be achieved is 0. - -Mean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is also 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (just think of what happens when you square a large value - ie. a large difference between the predicted and the truth), so the impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). - -R-squared (Rsq) or the coefficient of determination tells us what proportion variation of the response is explained or captured by the independent variables. So if R-squared is 0.7, this means that the predictors explain about 70% of the variability in the response. It's calculated as the squared correlation coefficient, so it also ranges between 0 and 1, and being closer to 1 (ie. explaining more of the variance in the response) is better. - -```{r, echo = FALSE, out.width = "80%"} -knitr::include_graphics("img/RMSE_MAE_RSq_oh_my.png") -``` - -Overall, even though RMSE, MAE, and Rsq are all considered measures of goodness of (model) fit, their views on it are different. RMSE and MAE look at accuracy of predictions (in terms of small residuals), whereas R-squared looks at how the predictors are fairing (in terms of explaining the response). - -While it can be difficult to pinpoint how well exactly each metric is performing for real life data (what are "good" values of each metric depends on the situation), from a quick inspection the values that `metrics()` churned out, we can say that roughly-speaking the RMSE and MAE look low enough to not set off any major alarm bells. And as for R-squared, though it is perhaps not as high as we'd like, it is decent. - -We will leave it at that and not venture further into model-validation territory here as it can get quite murky for epidemiological data (ex. consider the question of what to do about validating COVID-19 infection estimates), but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject. - -## Concluding remarks - -In these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned! - -## Attribution - -This vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). - From 096b69506cd7903508e9a15450413b5d8af270a7 Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:03:15 -0700 Subject: [PATCH 10/16] Remove unnecessary files --- .../execute-results/html.json | 14 -------------- img/RMSE_MAE_RSq_oh_my.png | Bin 289375 -> 0 bytes 2 files changed, 14 deletions(-) delete mode 100644 _freeze/tidymodels-intro-part2/execute-results/html.json delete mode 100644 img/RMSE_MAE_RSq_oh_my.png diff --git a/_freeze/tidymodels-intro-part2/execute-results/html.json b/_freeze/tidymodels-intro-part2/execute-results/html.json deleted file mode 100644 index c75f73b..0000000 --- a/_freeze/tidymodels-intro-part2/execute-results/html.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "hash": "a9c5f3dad427395e85f7d799dd61d01b", - "result": { - "markdown": "# Introduction to Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## A gentle introduction to tidymodels - `epipredict` edition\n\nThe `epipredict` package builds off of the `tidymodels` framework to help it run smoothly with epidemiological time series data that can be composed as an `epi_df`. To that end, let's see how some of the techniques we previously applied in the previous chapter fair on some real-world `epi_df` data.\n\nWe'll start off by loading the `epipredict` and `tidymodels` packages.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-2_19e8bed772562d5965d7b8dd83ee81ec'}\n\n```{.r .cell-code}\nlibrary(epipredict)\nlibrary(tidymodels)\n```\n:::\n\n\nThe data we'll work with is a subset of the built-in `case_death_rate_subset` dataset that contains COVID-19 death and case rates from Johns Hopkins University. We're only going to use the data for California, New York, Arkansas, Texas, and Hawaii over the modest time window of Jan. 8, 2021 to March 8, 2021. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-3_b7bda51898d2684ae78c8343363f29d5'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(\n time_value >= \"2021-01-08\",\n time_value <= \"2021-03-08\",\n geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\")\n )\n```\n:::\n\n\nOur goal for this example is to use this data to train a basic linear regression forecaster to predict the death rate one week ahead of the last time of March 8, 2021 using past (lagged) deaths and cases for each state. \n\nWe'll use `jhu` as our training data and we' will hold off on creating the test portion for now. One reason for this unexpected move can be understood by asking the question... Can we use the `initial_split()` function from the `rsample` package here in the way that we did before? Remember that we used it to randomly split the `penguins` dataset into a training and test set, where we used 70% of the data for training and reserved the remaining 30% for testing. But does such a random split make sense to use on time series data (and, moreover, on time series data that is grouped by state)? No. Now, the `rsample` package does offer `initial_time_split()`, which takes the first `prop` samples for training instead of a random selection (so this may be appropriate for time series data where we want to predict for one segment in the future given the past). And `group_initial_split()` creates splits of the data based on some grouping variable, but what we would ideally like is a function that accounts for both time and grouping. And to our knowledge, there's no `initial_time_group_split()` function in existence just yet. So we've got to come up with something else to do here. \n\n### Pre-processing \n\nThe pre-processing steps are added to an `epi_recipe()` in the same way as for an ordinary `recipe()`. The major benefit from using an `epi_recipe()` is that we have more epi-themed steps at our disposal which allow for analysis that's more tailored to epidemiological data. These pre-processing transformations that are specific for such data often include the infix of `epi` as in `step_epi` to make the distinction between them and the steps that come with `tidymodels`. \n\nAnd while there are many such transformations available, we will only showcase the following four in our example for the sake of simplicity.\n\n:::: {.columns}\n\n::: {.column width=\"52%\"}\n- `step_epi_lag()` to lag specified columns ahead by some amount (generally these would be particular numeric predictors)\n\n- `step_epi_ahead()` to shift specified data ahead by some amount (generally this would be the response)\n\n- `step_center()` to normalize numeric data to have a mean of zero\n\n- `step_epi_naomit()` to omit NAs from both predictors and outcomes at training time to fit the model\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"47%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-4_7b223521154c75f02574f73d1cfce866'}\n::: {.cell-output-display}\n![](img/epi_recipe_card.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nIn our case, we will center the numerical predictors to help level the playing field across them for a more meaningful interpretation of the intercept. Note that by default the ahead and lag steps assign analysis roles to the used inputted variables. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-5_63bf118edb2cc9beb0b70853f247c3c3'}\n\n```{.r .cell-code}\nr <- epi_recipe(jhu) %>%\n step_epi_lag(case_rate, death_rate, lag = c(0, 7, 14)) %>%\n step_epi_ahead(death_rate, ahead = 7) %>%\n step_center(contains(\"lag\")) %>%\n step_epi_naomit()\n```\n:::\n\n\n### Get test data\n\nNow that we've got our recipe wrapped up and ready to go, let's revisit the problem of getting test data. What we'll do use is a function from `epipredict` that's primed to receive an `epi_recipe`. This function gets test data for predictions based on the longest lag period in the recipe. The reason that we use the longest lag is that it is the farthest back we need to go to get the required values of the predictors to make the forecast. In our above recipe, the longest lag is 14 days. So, what `get_test_data()` does is that it will get the last 14 + 1 = 15 days for each `geo_value` and all together those comprise `latest`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-6_aaafd314f98b68f4e1262d33585a98d4'}\n\n```{.r .cell-code}\nlatest <- get_test_data(recipe = r, x = jhu)\n```\n:::\n\n\n### Model and use a trained epi_workflow to predict\n\nFor our model, we'll opt for the classic least squares regression model. However, we should note that, while least squares is often computationally simple, it may be better to use something like quantile regression (using the `quantile_reg` engine) to create median predictions because it is more robust than least squares to the type of distribution. That is, no matter the underlying distribution of the data (which, in the case of pandemic data, may be unpredictable or hard to pin down), obtaining the median or other quantiles and minimizing the absolute residuals tends to work well and be a safe bet. \n\nBelow we create an `epi_workflow()`, which extends the functionality of a `workflow()` to handle the typical panel data structures found in epidemiology. It also has one other major perk. Whereas a `workflow` can take in a pre-processor and a parsnip model specification, an `epi_workflow` may take in up to three arguments: a pre-processor, a parsnip model specification, and a post-processor. So we've got additional capability here to post-process our results. For our example, since we only have a recipe, and a parsnip model, we will only fill in the first two arguments.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-7_33c29e2839d7ac26850a4d6f9579060e'}\n\n```{.r .cell-code}\nwf <- epi_workflow(r, parsnip::linear_reg()) %>%\n fit(jhu)\n```\n:::\n\n\nLet's extract the model to briefly inspect it. We expect that it should contain three coefficients for the 0, 7, and 14 day lagged case rate predictors and three coefficients for the 0, 7, and 14 day lagged death rate predictors.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-8_cb1bb2d102c6d646279a976828932f56'}\n\n```{.r .cell-code}\nwf %>%\n extract_fit_parsnip()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290\n```\n:::\n:::\n\n\nGreat! Now, we can use our trained workflow to predict the one-week-ahead death rate for each sampled state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-9_7e0bf7f2a71e797853dd3640c72699cf'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\nSuccess! Now, you may have been thinking that at this point it sure would be nice to clean up our predictions by bounding them to ensure that they are at least 0 and by converting them from rates to counts for a simpler view of the results. While post-processing is not currently supported by `tidymodels`, the good news is that `epipredict` does have such tools ready to be used. And what's great is that they are in a format that parallels what we've seen for adding pre-processing steps. \n\n### Post-processing\n\n:::: {.columns}\n\n::: {.column width=\"75%\"}\n\nBasically, each post-processing step is a layer to be added to the `frosting()`, which is a post-processing container that is akin to `recipe()`. To our `frosting()`, we'll add the following four layers\n\n- `layer_predict()` to add a prediction layer for post-processing\n\n- `layer_add_target_date()` to add the target date (ie. the date that the forecast is for)\n\n- `layer_threshold()` to set the predictions to be at least 0\n\n- `layer_population_scaling()` to \"undo\" per-capita scaling by state to get counts from rates\n:::\n\n::: {.column width=\"1%\"}\n\n:::\n\n::: {.column width=\"24%\"}\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-10_d2383a6f21e32688dede0ec33e71c1be'}\n::: {.cell-output-display}\n![](img/postprocessing_cupcake.png){fig-align='center' width=90%}\n:::\n:::\n\n:::\n\n::::\n\nNote that, as with the pre-processing steps, order matters like when you follow a recipe. Thus, put the layers in so that they result in the chain of events that you want to happen and not something that belongs on Hell's Kitchen. In general, put `layer_predict()` in first and then what you want to do to the predictions after. That is, `layer_predict()` should be the first layer to make an appearance after `frosting()`, then input whatever other layers you want in the order you want them carried out. In our example, it is logical to add the layer to bound our predictions at 0 before scaling them.\n\nBut first we should ready the dataframe that contains the population data. We'll use the 2019 US Census data that comes built-in with the `epipredict` package and just select the two columns that we need - the state abbreviation and corresponding population estimate. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-11_ffd27d99045db1ab9863dc028009dbeb'}\n\n```{.r .cell-code}\npop_dat <- state_census %>% select(abbr, pop)\n```\n:::\n\n\nNow, let's go ahead and do the post-processing that we outlined above.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-12_2027ee70ea5ffca3616ea9b7d2fd3598'}\n\n```{.r .cell-code}\nf <- frosting() %>%\n layer_predict() %>%\n layer_add_target_date() %>%\n layer_threshold(.pred, lower = 0) %>%\n layer_population_scaling(\n .pred,\n df = pop_dat,\n rate_rescaling = 1e5,\n by = c(\"geo_value\" = \"abbr\"),\n df_pop_col = \"pop\"\n )\n```\n:::\n\n\nEverything is pretty straight forward, but there's perhaps one curious choice... Why did we pick `1e5` for `rescaling_rate`? This is because the rates are \"per 100,000 people\" rather than \"per person\" as can be seen in the dataset documentation (have a look at `?case_death_rate_subset`).\n\nNow, we predict by inputting a workflow and the test data into `predict()` the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-13_067858085e13b87eabcbfb2dc3112e3b'}\n\n```{.r .cell-code}\np <- predict(wf, latest)\np\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ar 2021-03-08 0.118 \n#> 2 ca 2021-03-08 0.492 \n#> 3 hi 2021-03-08 -0.00303\n#> 4 ny 2021-03-08 0.484 \n#> 5 tx 2021-03-08 0.499\n```\n:::\n:::\n\n\nIt's good practice to perform a quick inspection of the predictions before moving on. But when we do that here, something doesn't quite add up... Notice that we have a negative prediction for `hi`. And the predictions look to still be rates and not counts. It looks like the postprocessing wasn't implemented at all... So what is the problem? The answer is that we forgot to add the frosting to the `epi_workflow`. Once we do that and pop the updated workflow into `predict()`, then we should get predictions that align more with our expectations.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-14_f165919016aa09119396184d3e494719'}\n\n```{.r .cell-code}\nwf_fixed <- wf %>%\n add_frosting(f)\nwf_fixed\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 5 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_center()\n#> • step_naomit()\n#> • step_naomit()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.665200 0.005861 -0.001566 0.001720 \n#> lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> 0.480520 0.131260 0.021290 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 4 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_add_target_date()\n#> • layer_threshold()\n#> • layer_population_scaling()\n```\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-15_25a3d285bb27ec86007b66be2bbb49ac'}\n\n```{.r .cell-code}\np_round2 <- predict(wf_fixed, latest)\np_round2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 5 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 5\n#> geo_value time_value .pred target_date .pred_scaled\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57\n#> 2 ca 2021-03-08 0.492 2021-03-15 194. \n#> 3 hi 2021-03-08 0 2021-03-15 0 \n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145.\n```\n:::\n:::\n\n\nMuch better! \n\n### Model validation\n\nLet's now get out the true death rates for these dates from the `case_death_rate_subset` data. One thing to keep in mind is that in epidemiological modelling, there often times may not be true values to validate against - especially in the midst of an epidemic or pandemic. For instance, if you are predicting case or death rates one week ahead during the COVID-19 pandemic, at the time you are predicting you will not have the true case or death rates at your disposal. In contrast, when you are doing retrospective analysis, you should have some estimate of the truth on hand, and it is of course recommended that you put it to good use in validation as we are doing here. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-16_1b7fd8b3e15581ab21e5dcc02364f0ab'}\n\n```{.r .cell-code}\ntrue_death_rates <- case_death_rate_subset %>%\n filter(geo_value %in% c(\"ca\", \"ny\", \"ar\", \"tx\", \"hi\") &\n time_value == \"2021-03-15\") %>%\n select(geo_value, death_rate)\n```\n:::\n\n\nTo adjoin the two dataframes containing the truth and the predictions, we could force `bind_cols()` to work, but one important thing is that the order of the rows (states) should match up in both otherwise we could mismatch data (meant for one state to another). For instance, in our example notice that the first `geo_value` in `true_death_rates` is for `ar`, while it is for `ak` in `p_round2`. And if we had more states to deal with, it could be especially troublesome to have to go in and re-organize the rows. In such situations, we can turn to `dplyr`'s `left_join()` function to add `true_death_rates` values as a column to the `p_round2` dataframe by `geo_value`. The order of the rows doesn't matter for this function because it matches based on the linking variable `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-17_62b0df9c6535a76ba0543d4601e48c09'}\n\n```{.r .cell-code}\np_w_truth <- left_join(p_round2, true_death_rates, by = \"geo_value\")\np_w_truth\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5 x 6 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5 × 6\n#> geo_value time_value .pred target_date .pred_scaled death_rate\n#> * \n#> 1 ar 2021-03-08 0.118 2021-03-15 3.57 0.651 \n#> 2 ca 2021-03-08 0.492 2021-03-15 194. 0.481 \n#> 3 hi 2021-03-08 0 2021-03-15 0 0.0609\n#> 4 ny 2021-03-08 0.484 2021-03-15 94.2 0.456 \n#> 5 tx 2021-03-08 0.499 2021-03-15 145. 0.539\n```\n:::\n:::\n\n\nNow let's use `metrics()` function to briefly assess our model performance. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-intro-part2_cache/html/unnamed-chunk-18_84628c2362e543e1ba7f12b0dbc7ab3c'}\n\n```{.r .cell-code}\np_w_truth %>%\n metrics(truth = death_rate, estimate = .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 3 × 3\n#> .metric .estimator .estimate\n#> \n#> 1 rmse standard 0.241\n#> 2 rsq standard 0.244\n#> 3 mae standard 0.135\n```\n:::\n:::\n\n\nAs before, let's briefly go through the metrics that were produced. Root mean square error (RMSE) is the square root of the average squared difference between the predicted and the actual values. So it is a measure of accuracy because it informs us how well the model hit the mark (the truth). Since this is an error, lower values are better, and the absolute minimum value that could be achieved is 0. \n\nMean absolute error (MAE) is the average absolute difference between the predicted and the actual values. It's interpretation is similar to RMSE in that lower values are better and the minimum that can be achieved is also 0. A major difference between them is how much each error contributes. RMSE is more sensitive to outliers (consider what happens when you square a large value - there's a large difference between the predicted and the truth). The impact of larger errors is magnified, while smaller errors don't contribute as much. In contrast, the error contribution in MAE increases linearly (ex. an error of 4 would contribute twice as much as an error of 2). \n\nWhile it can be difficult to pinpoint how well exactly each metric is performing for real life data (what are \"good\" values of each metric depends on the situation), from a quick inspection of the values that `metrics()` churned out, the RMSE and MAE look low enough to not raise alarms.\n\nWe will leave it at that and not venture further into model-validation territory here as it can get quite murky for epidemiological data (ex. consider the question of what to do about validating COVID-19 infection estimates), but feel free to venture further on your own. We recommend [this book](https://www.google.ca/books/edition/Medical_Risk_Prediction_Models/VQEWEAAAQBAJ?hl=en&gbpv=1&printsec=frontcover) on medical risk prediction models for further reading on the subject.\n\n## Concluding remarks\n\nIn these past two chapters, we introduced `tidymodels` and illustrated how to its packages work together by way of example. Since they were both elementary examples, use them as a starting point to explore what more can be done with this wonderful set of packages. And yet, however wonderful they are, there are limitations like the glaring lack of a set of post-processing tools to refine the results. We fill this gap for epidemiological modelling with [frosting](https://cmu-delphi.github.io/epipredict/reference/add_frosting.html), which will be demonstrated in greater detail in later chapters, so stay tuned!\n\n## Attribution\n\nThis vignette was largely adapted from [A Gentle Introduction to Tidymodels](https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/) as well as [Tidymodels - Getting Started](https://www.tidymodels.org/start/recipes/) and [Tidymodels](https://wec.wur.nl/dse/24-tidymodels.html). \n\n", - "supporting": [], - "filters": [ - "rmarkdown/pagebreak.lua" - ], - "includes": {}, - "engineDependencies": {}, - "preserve": {}, - "postProcess": true - } -} \ No newline at end of file diff --git a/img/RMSE_MAE_RSq_oh_my.png b/img/RMSE_MAE_RSq_oh_my.png deleted file mode 100644 index f6c491f50b0cd591e0f6611231d28f13979cfed2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 289375 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

    YWE(_;quUKbW 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 z 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

    eWWef)l8U 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 I*GwM&e||YZ&;S4c From a2eef773116595c6abc4e8fd188e77e53204364e Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:13:10 -0700 Subject: [PATCH 11/16] Update tidymodels-regression-part2 based on comments --- .../execute-results/html.json | 4 +- .../execute-results/html.json | 4 +- tidymodels-regression-part2.qmd | 86 +++++++++---------- tidymodels-regression.qmd | 2 +- 4 files changed, 45 insertions(+), 51 deletions(-) diff --git a/_freeze/tidymodels-regression-part2/execute-results/html.json b/_freeze/tidymodels-regression-part2/execute-results/html.json index 1e35f68..1c1b30e 100644 --- a/_freeze/tidymodels-regression-part2/execute-results/html.json +++ b/_freeze/tidymodels-regression-part2/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "19eea9ce59de8a2e50ff400f23e72d2c", + "hash": "5d712a62250e03d006b7b1bd85780b0b", "result": { - "markdown": "# Regression in Tidymodels - Part 2\n\nThis chapter is starts off as the Regression in Tidymodels chapter - Epidemiological time series edition and goes from there to making (slightly) more sophisticated predictions and interactive plots.\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the Regression in `Tidymodels` chapter, we're going to look at how the functions we used to perform linear regression fair when applied to a small set of epidemiological time series data. We'll be working with the built-in data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021 (this was originally compiled by JHU).\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data) just yet. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. And to do this, we'll essentially work through the same routine that we went through above (just in a different scenario). Thus, we'll opt for the same linear regression model specification. As we mentioned previously, setting the mode is unnecessary for linear regression, so let's drop that bit this time round. In addition, `lm` is the default engine for linear regression, so, we don't have to include that bit either.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_c8e1a2301b605fd10d31d77d5991e127'}\n\n```{.r .cell-code}\nlm_spec_way2 <- linear_reg()\n```\n:::\n\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_d07c113145028a505520eff20bc12b90'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec_way2 %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow let's forge ahead and get some predictions for the existing dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAnd to get a side-by-side view of the observed and predicted values (which sets us up well to compare them), we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling a bit of epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, do we only want to look to the concurrent (same-day) case information? Or should we look into the past as well? Since what happened in the past can inform us where things are heading, we could also include case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting a sliver of the future\n\nNow the big question is how far back in the past should we look? More specifically, what past case and death rates are most predictive of current deaths. This is a natural question to have at this point, but it ventures into model selection territory which beyond the scope of this article. For those interested, a lagged correlation analysis as described in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. So read it if you dare (or if you have the time).\n\nTo start, we will add predictors for the lagged 1-day death and case rates as those seem to be perhaps the most sensible choices (because yesterday is generally more predictive of today than two weeks ago would be).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can go ahead and create our recipe, and we can add a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor before, by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_fcbd0b889567108db17d97a251f4394f'}\n\n```{.r .cell-code}\nrec_spec_lag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNow, we just pop the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d034bd6f77589f3ee04a81e46a60dcd5'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec_way2) %>%\n add_recipe(rec_spec_lag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAnd viola, we got ourselves a trained workflow - which to be clear has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow we'll try to use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). So we'll throw this info. in a short dataframe and feed it into `new_data`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_e83e7a002d9bbaaec824dca5be879089'}\n\n```{.r .cell-code}\nlast_row_ca <- ca_case_death_rate_subset %>% tail(n = 1)\n\npredict(ca_lm_fit_lag, new_data = data.frame(\n case_rate = 84.7,\n lag_1_death_rate = last_row_ca$death_rate,\n lag_1_case_rate = last_row_ca$case_rate\n))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 NA\n```\n:::\n:::\n\n\nHold up... Why is our prediction NA? We inputted the necessary data with the correct variable names (no typos there). So what went wrong? The answer is two paragraphs above. And here it is: Recall that we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original model specification. So this means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. This is a bit of a pain, but so be it. The quick and dirty fix is to simply change `n = 1` to 2 in `tail()`, but let's flex our skills with `bind_rows()` instead.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_bc7c5328ace16c27fd53eb0610be2f1f'}\n\n```{.r .cell-code}\n# Add new row of to ca_case_death_rate_subset\nca_subset_plus_row <- bind_rows(\n ca_case_death_rate_subset,\n data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last_row_ca$death_rate\n )\n)\n```\n:::\n\n\nAnd then pop that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_1ab4d7dbf51419f8ddf299c5062e5c79'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_plus_row) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\n\nWonderful. We got ourselves a prediction. But that was a heck of a lot of work to get here. How could we simplify things for ourselves? Well there's a couple things that `epipredict` offers that could help us out here. \n\n### Option 1 - manually create our own `epi_recipe`\n\nInstead of using a plain old recipe, it is more advantageous to use an `epi_recipe` on an `epi_df`. Why? It unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combo above to get the lagged case and death rate variables, we can simply write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, just throw the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_26578b49ef4da25d864cd088f8349259'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec_way2) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nNotice we get the same prediction as before, just as we'd expect.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nWe can take things a notch further because the `epipredict` package has the `arx_forecaster()` function to make our lives easier by pre-processing, training the model, predicting, and performing some basic post-processing, all in one go. The reason why we can use this model is that the above is a technically a type of autoregressive (AR) model, in which a linear combination of previous values are use forecast the variable of interest. In contrast, in a multiple linear regression model, we use a linear combination of predictors to forecast the variable we're interested in.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_87146e4ff6e311476c6feb27e5127719'}\n\n```{.r .cell-code}\nca_arx_pred_jan_22 <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_pred_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nWe could easily add more lags for the case and death rates into the function . All that we got to do is add a couple of choice numbers to the `lags` argument. This is infinitely preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for each of case and death rate to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_a71bf5dcf8b9a859dc6f0736cbd53241'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the above forecaster is that it is equipped to handle panel data. That means that for our example we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nNeat! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we simply adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The major changes are that we specified what we would like to show when we hover (the predictions and the corresponding 90% predictive interval). As well, we modified the trace (a trace is just a layer to add to the plot with its own data and visualization components), so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n

    \n\n```\n:::\n:::\n\nPretty cool for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, this checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", + "markdown": "# Regression in Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021.\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_8e4a55d2cf5dd5462ea1ea929bd3f6f8'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg()\n```\n:::\n\n\nWe made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either.\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_bdf235a5206620fbc7d51847c37e572d'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow we may generate predictions for the dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\nTo get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting for a target date\n\nAt this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include.\n\nTo begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_fcbd0b889567108db17d97a251f4394f'}\n\n```{.r .cell-code}\nrec_spec_lag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNext, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_e820094ca6bae5ef1af884da84b13d2f'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_lag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAs a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_d6dba693544d6cab62dbde71da21f181'}\n\n```{.r .cell-code}\njan_1_df <- data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last(ca_subset_wlag)$death_rate\n)\n```\n:::\n\n\nNotice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_efab5d9cb5bbebe16ecb68605535f783'}\n\n```{.r .cell-code}\n# Add new row of to ca_subset_wlag\nca_subset_plus_row <- bind_rows(\n ca_subset_wlag,\n jan_1_df\n)\n```\n:::\n\n\nAnd then input that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_1ab4d7dbf51419f8ddf299c5062e5c79'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_plus_row) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\nWonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options...\n\n### Option 1 - manually create our own `epi_recipe`\n\nIt is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_1b37a617156ce9ddf5057e0c04102ba9'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nAs expected, we obtain the same prediction as when we used the first approach.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nThe `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_87146e4ff6e311476c6feb27e5127719'}\n\n```{.r .cell-code}\nca_arx_pred_jan_22 <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_pred_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nWe can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_a71bf5dcf8b9a859dc6f0736cbd53241'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nAwesome! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nNot bad for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try implementing such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/_freeze/tidymodels-regression/execute-results/html.json b/_freeze/tidymodels-regression/execute-results/html.json index 870aef4..849db8a 100644 --- a/_freeze/tidymodels-regression/execute-results/html.json +++ b/_freeze/tidymodels-regression/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "32d328d89edf5809d8c765c336133b00", + "hash": "c25c9724a020bcde2f97469c1007a60c", "result": { - "markdown": "# Regression in Tidymodels\n\n\n::: {.cell}\n\n:::\n\n\nThis chapter is a gentle introduction into performing simple and multiple linear regression using `tidymodels`. Model fitting will be done using [parsnip](https://www.tidymodels.org/start/models/), which provides a unifying interface for model fitting and the resulting output. This means that parsnip provides a single interface with standardized argument names for each class of models so that you don't have to directly deal with the different interfaces for different functions that aim to do the same thing (like linear regression). See [here](https://www.tidymodels.org/find/parsnip/) for a list of models that `parsnip` currently supports.\n\n## Libraries\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-2_f1b70260de9274ceee0de0930c458b3d'}\n\n```{.r .cell-code}\nlibrary(tidymodels)\nlibrary(broom)\nlibrary(performance)\n```\n:::\n\n\n## Simple linear regression\n\nThe key steps to perform linear regression in `tidymodels` are to first specify the model type and then to specify the model form and the data to be used to construct it.\n\nTo illustrate, we shall look to `penguins` dataset from the `tidymodels`' `modeldata` package. This dataset contains measurements for 344 penguins from three islands in Palmer Archipelago, Antarctica, and includes information on their species, island home, size (flipper length, body mass, bill dimensions), and sex.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-3_473e0ea4ec6d47826afc1c168bb38198'}\n::: {.cell-output-display}\n![](img/palmer_penguin_species.png){fig-align='center' width=75%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-4_aa7c3f7c67794e4868c4a9be11dcebfd'}\n\n```{.r .cell-code}\n# Let's inspect the data\nhead(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 6 × 7\n#> species island bill_length_mm bill_depth_mm flipper_length_mm\n#> \n#> 1 Adelie Torgersen 39.1 18.7 181\n#> 2 Adelie Torgersen 39.5 17.4 186\n#> 3 Adelie Torgersen 40.3 18 195\n#> 4 Adelie Torgersen NA NA NA\n#> 5 Adelie Torgersen 36.7 19.3 193\n#> 6 Adelie Torgersen 39.3 20.6 190\n#> # ℹ 2 more variables: body_mass_g , sex \n```\n:::\n:::\n\n\nOne thing you may have spotted is that there's missing data in this dataset in the fourth row. For simplicity, we will only work with the complete cases. This reduces the number of rows in our dataset to 333.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-5_6c5cb7769e50f22fea43f07d1fca5e94'}\n\n```{.r .cell-code}\npenguins <- penguins %>%\n filter(complete.cases(.))\n\nhead(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 6 × 7\n#> species island bill_length_mm bill_depth_mm flipper_length_mm\n#> \n#> 1 Adelie Torgersen 39.1 18.7 181\n#> 2 Adelie Torgersen 39.5 17.4 186\n#> 3 Adelie Torgersen 40.3 18 195\n#> 4 Adelie Torgersen 36.7 19.3 193\n#> 5 Adelie Torgersen 39.3 20.6 190\n#> 6 Adelie Torgersen 38.9 17.8 181\n#> # ℹ 2 more variables: body_mass_g , sex \n```\n:::\n:::\n\n\nMuch better! We will now build a simple linear regression model to model bill length as a function of bill depth.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-6_9752f79826c0bd2c0727f0d373aa20ff'}\n::: {.cell-output-display}\n![](img/bill_length_depth.png){fig-align='center' width=60%}\n:::\n:::\n\n\nIn `parsnip`, the model specification is broken down into small functions such as `set_mode()` and `set_engine()` to make the interface more flexible and readable. The general structure is to first specify a mode (regression or classification) and then an engine to indicate what software (or implementation of the algorithm) will be used to fit the model. For our purposes, the mode is `regression` and the engine is `lm` for ordinary least squares. You may note that setting the mode is unnecessary for linear regression, but we include it here as it is a good practice.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-7_d894b718918a6c425b9e0fff7ad8299b'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg() %>%\n set_mode(\"regression\") %>%\n set_engine(\"lm\")\n```\n:::\n\n\nThe above specification does not actually carry out the regression, rather it just states what we would like to do.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-8_dbdab6875a55b8152227310053c8cadd'}\n\n```{.r .cell-code}\nlm_spec\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> Linear Regression Model Specification (regression)\n#> \n#> Computational engine: lm\n```\n:::\n:::\n\n\nOnce we have such a blueprint, we may fit a model by inputting data and a formula. Recall that in R, a formula takes the form `y ~ x` where `y` ix the response and `x` is the predictor variable. For our example, where the response of bill length and predictor of bill depth, we would write the formula as `bill_length_mm ~ bill_depth_mm`. \n\n::: {.callout-note}\nUnlike with standard R `formula()` objects, the names used this a formula must \nbe identical to the variable names in the dataset. No processing functions\nare allowed (processing is handled by the `recipe()`).\n:::\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-9_4435e7400b6dd465d61c248470b8ec32'}\n\n```{.r .cell-code}\nlm_fit <- lm_spec %>%\n fit(bill_length_mm ~ bill_depth_mm, data = penguins)\n\nlm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm, data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm \n#> 54.8909 -0.6349\n```\n:::\n:::\n\n\nThe resulting `parsnip` object includes basic information about the fit such as the model coefficients. To access the underlying fit object, we could use the standard `lm_fit$fit` or with `purrr`'s `pluck()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-10_c44cea2b4ccca541a75e2249a6991015'}\n\n```{.r .cell-code}\nlm_fit %>%\n pluck(\"fit\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm, data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm \n#> 54.8909 -0.6349\n```\n:::\n:::\n\n\nTo get additional information about the fit (such as standard errors, and goodness-of-fit statistics), we can get a summary of the model fit as follows:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-11_170fec411bf1e01a30f67a906726bc21'}\n\n```{.r .cell-code}\nlm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -12.9498 -3.9530 -0.3657 3.7327 15.5025 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 54.8909 2.5673 21.380 < 2e-16 ***\n#> bill_depth_mm -0.6349 0.1486 -4.273 2.53e-05 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 5.332 on 331 degrees of freedom\n#> Multiple R-squared: 0.05227,\tAdjusted R-squared: 0.04941 \n#> F-statistic: 18.26 on 1 and 331 DF, p-value: 2.528e-05\n```\n:::\n:::\n\n\nTo get a tidy summary of the model parameter estimates, simply use the tidy function from the [broom](https://broom.tidymodels.org/) package on the model fit. To extract model statistics, `glance()` can be used.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-12_3c6cda9ae2eea12f6c255b8bf2cd5061'}\n\n```{.r .cell-code}\ntidy(lm_fit)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 2 × 5\n#> term estimate std.error statistic p.value\n#> \n#> 1 (Intercept) 54.9 2.57 21.4 2.54e-64\n#> 2 bill_depth_mm -0.635 0.149 -4.27 2.53e- 5\n```\n:::\n\n```{.r .cell-code}\nglance(lm_fit)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 12\n#> r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC\n#> \n#> 1 0.0523 0.0494 5.33 18.3 0.0000253 1 -1029. 2064. 2075.\n#> # ℹ 3 more variables: deviance , df.residual , nobs \n```\n:::\n:::\n\n\nNow, to make predictions, we simply use `predict()` on the parnsip model object. In there, we must specify the dataset we want to predict on in the `new_data` argument. Note that this may be a different dataset than we used for fitting the model, but this input data must include all predictor variables that were used to fit the model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-13_0370f690b7e270998042a729bdbf587f'}\n\n```{.r .cell-code}\npredict(lm_fit, new_data = penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 1\n#> .pred\n#> \n#> 1 43.0\n#> 2 43.8\n#> 3 43.5\n#> 4 42.6\n#> 5 41.8\n#> 6 43.6\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nFor parnsip models, the predictions are always outputted in a tibble.\n\nTo specify the type of prediction made, modify `type` argument. If we set `type = \"conf_int\"`, we get a 95% confidence interval.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-14_ef093136394a01ed5d663b2ea837c983'}\n\n```{.r .cell-code}\npredict(lm_fit, new_data = penguins, type = \"conf_int\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 2\n#> .pred_lower .pred_upper\n#> \n#> 1 42.3 43.7\n#> 2 43.3 44.4\n#> 3 42.8 44.1\n#> 4 41.8 43.5\n#> 5 40.7 43.0\n#> 6 43.0 44.2\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nTo evaluate model predictive performance, it is logical to compare the each of the observed and predicted values. To see these values side-by-side we simply bind the two vectors of interest.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-15_e464c86a9e8050cfa6b8e3174a99d1ee'}\n\n```{.r .cell-code}\nbind_cols(\n predict(lm_fit, new_data = penguins),\n penguins\n) %>%\n select(bill_length_mm, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 2\n#> bill_length_mm .pred\n#> \n#> 1 39.1 43.0\n#> 2 39.5 43.8\n#> 3 40.3 43.5\n#> 4 36.7 42.6\n#> 5 39.3 41.8\n#> 6 38.9 43.6\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nA simpler way to do this is to use the nifty `augment()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-16_008a078253bb995f610dd7929c7c4874'}\n\n```{.r .cell-code}\naugment(lm_fit, new_data = penguins) %>%\n select(bill_length_mm, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 2\n#> bill_length_mm .pred\n#> \n#> 1 39.1 43.0\n#> 2 39.5 43.8\n#> 3 40.3 43.5\n#> 4 36.7 42.6\n#> 5 39.3 41.8\n#> 6 38.9 43.6\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\n## Multiple linear regression\n\nThe only difference about fitting a multiple linear regression model in comparison to a simple linear regression model lies the formula. For multiple linear regression, the predictors are specified in the formula expression, separated by `+`. For example, if we have a response variable `y` and three predictors, `x1, x2,` and `x3`, we would write the formula as, `y ~ x1 + x2 + x3`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-17_77a1ab952443165abb55d9b9fdae419e'}\n\n```{.r .cell-code}\nlm_fit2 <- lm_spec %>% fit(\n formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm + body_mass_g,\n data = penguins\n)\nlm_fit2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm + \n#> body_mass_g, data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm flipper_length_mm body_mass_g \n#> -2.571e+01 6.131e-01 2.872e-01 3.472e-04\n```\n:::\n:::\n\n\nEverything else proceeds much the same as before. Such as obtaining parameter estimates\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-18_2f633c83ebc971b730b1364d8a51e402'}\n\n```{.r .cell-code}\ntidy(lm_fit2)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 4 × 5\n#> term estimate std.error statistic p.value\n#> \n#> 1 (Intercept) -25.7 6.72 -3.83 1.55e- 4\n#> 2 bill_depth_mm 0.613 0.138 4.43 1.26e- 5\n#> 3 flipper_length_mm 0.287 0.0351 8.18 6.28e-15\n#> 4 body_mass_g 0.000347 0.000566 0.614 5.40e- 1\n```\n:::\n:::\n\n\nas well as predicting new values.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-19_bade4f9eb41832a1bfdb0efeae87f940'}\n\n```{.r .cell-code}\npredict(lm_fit2, new_data = penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 1\n#> .pred\n#> \n#> 1 39.0\n#> 2 39.7\n#> 3 42.5\n#> 4 42.8\n#> 5 42.8\n#> 6 38.4\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nIf you would like to use all variables aside from your response as predictors, a shortcut is to use the formula form `y ~ .`\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-20_4a1fb1bf15b09cf0cb3b73cb1f3a7c72'}\n\n```{.r .cell-code}\nlm_fit3 <- lm_spec %>% fit(bill_length_mm ~ ., data = penguins)\nlm_fit3\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) speciesChinstrap speciesGentoo islandDream \n#> 15.343291 9.835502 6.117675 -0.503815 \n#> islandTorgersen bill_depth_mm flipper_length_mm body_mass_g \n#> -0.127431 0.300670 0.069257 0.001081 \n#> sexmale \n#> 2.047859\n```\n:::\n:::\n\n\n## Checking model assumptions\n\nAfter fitting a model, it is good to check whether the assumptions of linear regression are met. For this, we will use the `performance` package, in particular the `check_model()` function to produce several helpful plots we may use to check the assumptions for our first multiple linear regression model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-21_9f0e50621ab07bb69b919f860e7a0ba9'}\n\n```{.r .cell-code}\nlm_fit2 %>%\n extract_fit_engine() %>%\n check_model()\n```\n\n::: {.cell-output-display}\n![](tidymodels-regression_files/figure-html/unnamed-chunk-21-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nNotice that on each plot it says what we should expect to see if the model assumption is met.\n\nWe shall now briefly walk you through what each plot means.\n\nThe first two plots help us to examine the linearity of the errors versus the fitted values. Ideally, we want this error to be relatively flat and horizontal. The third plot is for checking homogeneity of the variance, where we want the points to be roughly the same distance from the line as this indicates similar dispersion. The fourth plot helps us to see if there are high leverage points - points that have command or influence over the model fit. As a result, these can have a great effect on the model predictions. So the removal of such points or modifications to the model may be necessary to deal with them. The fifth plot helps us to discern collinearity, which is when predictors are highly correlated. Since independent variables should be independent, this can throw off simple regression models (in standard error of coefficient estimates and the estimates themselves, which would likely be sensitive to changes in the predictors that are included in the model). The last plot enables us to check the normality of residuals. If the distribution of the model error is non-normal, then that suggests a linear model may not be appropriate. For a QQ plot, we want the points to fall along a straight diagonal line.\n\nFor our example, we observe that there's a pretty high correlation between `body_mass_g` and `flipper_length_mm` (not quite in the red-zone of 10 and above, but close enough for concern). That is indicative of multicollinearity between them. Intuitively, it makes sense for the body mass and flipper length variables - we'd expect that as once increases, so should the other.\n\nWe can take a closer look at the correlation by whipping up a correlation matrix by using base R's `cor()` function. Since for collinearity we're only usually interested in the numerical predictors, we'll only include the four numeric variables.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-22_49987b72aff741a32f5dfc50558d4948'}\n\n```{.r .cell-code}\npenguins_corr <- penguins %>%\n select(body_mass_g, ends_with(\"_mm\")) %>%\n cor()\npenguins_corr\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> body_mass_g bill_length_mm bill_depth_mm flipper_length_mm\n#> body_mass_g 1.0000000 0.5894511 -0.4720157 0.8729789\n#> bill_length_mm 0.5894511 1.0000000 -0.2286256 0.6530956\n#> bill_depth_mm -0.4720157 -0.2286256 1.0000000 -0.5777917\n#> flipper_length_mm 0.8729789 0.6530956 -0.5777917 1.0000000\n```\n:::\n:::\n\n\nIndeed `body_mass_g` and `flipper_length_mm` are highly positively correlated. To deal with this problem, we'll re-fit the model without `body_mass_g`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-23_306a0e9cc19412e08433bd04830dd697'}\n\n```{.r .cell-code}\nlm_fit3 <- lm_spec %>% fit(\n formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm,\n data = penguins\n)\nlm_fit3\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm, \n#> data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm flipper_length_mm \n#> -27.9762 0.6200 0.3052\n```\n:::\n:::\n\n\nand then check again to see whether the assumptions are met.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-24_6508d43288ce1be6d4caff814eec9b9f'}\n\n```{.r .cell-code}\nlm_fit3 %>%\n extract_fit_engine() %>%\n check_model()\n```\n\n::: {.cell-output-display}\n![](tidymodels-regression_files/figure-html/unnamed-chunk-24-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nOverall, the plots look pretty good. For details on how to interpret each of these plots and more details about model assumptions please see [here](https://easystats.github.io/see/articles/performance.html) and [here](https://rdrr.io/cran/performance/man/check_model.html).\n\n## Interaction terms\n\nIn general, the syntax to add an interaction term to a formula is as follows:\n\n- `x:y` denotes an interaction term between `x` and `y`.\n- `x*y` denotes the interaction between `x` and `y` as well as `x` and `y`; that is, `x + y + x*y`.\n\nIt is important to note that this syntax is not compatible with all engines. Thus, we shall explain how to bypass this issue by adding an interaction term in a recipe later on. For now, let's start simple by adding an interaction term between `species` and `bill_length_mm`, which allows for a species-specific slope.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-25_be09e39914328ca51bbe6fb2207c82b1'}\n\n```{.r .cell-code}\nlm_fit4 <- lm_spec %>% fit(\n formula = bill_length_mm ~ species * bill_depth_mm,\n data = penguins\n)\nlm_fit4\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ species * bill_depth_mm, \n#> data = data)\n#> \n#> Coefficients:\n#> (Intercept) speciesChinstrap \n#> 23.3668 -9.9389 \n#> speciesGentoo bill_depth_mm \n#> -6.6966 0.8425 \n#> speciesChinstrap:bill_depth_mm speciesGentoo:bill_depth_mm \n#> 1.0796 1.2178\n```\n:::\n:::\n\n\nUsing recipes, the interaction term is specified by using `step_interact()`. Then we construct a workflow object, where we add the linear regression model specification and recipe. Finally, we fit the model as we did for a `parsnip` model. Note that the workflow object does not need the variables that were specified in the recipe to be specified again.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-26_5d6b5266d0b373c844a38e0a080436d0'}\n\n```{.r .cell-code}\nrec_spec_interact <- recipe(\n formula = bill_length_mm ~ species + bill_depth_mm,\n data = penguins\n) %>%\n step_interact(~ species:bill_depth_mm)\n\nlm_wf_interact <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_interact)\n\nlm_wf_interact %>% fit(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_interact()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) speciesChinstrap \n#> 23.3668 -9.9389 \n#> speciesGentoo bill_depth_mm \n#> -6.6966 0.8425 \n#> speciesChinstrap_x_bill_depth_mm speciesGentoo_x_bill_depth_mm \n#> 1.0796 1.2178\n```\n:::\n:::\n\n\nNotice the variable name for the interaction term is not the same as it is in base R (which is simply of the form `x:y`). In `step_interact()`, the default separator between the variable names is `_x_`. You can change this default by specifying the `sep` argument in the function.\n\nTo read more about formula syntax, see [?formula](https://rdrr.io/r/stats/formula.html).\n\n## Non-linear transformations of the predictors\n\nSimilar to how we were able to add an interaction term using recipes, we can also perform a transformation as a pre-processing step. The function used for this is `step_mutate()` (which acts like `dplyr`'s `mutate`).\n\nNote that, in general, if you are specifying a recipe aim to keep as much of the pre-processing in your recipe specification as possible. This helps to ensure that the transformation will be applied to new data consistently.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-27_b7d9eb46155f4d760ade7a95ee6ba5d7'}\n\n```{.r .cell-code}\nrec_spec_pow2 <- recipe(bill_length_mm ~ bill_depth_mm, data = penguins) %>%\n step_mutate(bill_depth_mm2 = bill_depth_mm^2)\n\nlm_wf_pow2 <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_pow2)\n\nlm_wf_pow2 %>% fit(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm bill_depth_mm2 \n#> 95.2558 -5.4431 0.1413\n```\n:::\n:::\n\n\nThere are many transformations already built into recipes such as `step_log()`. So, for basic transformations, there's often no need to make your own transformation from scratch. See [here](https://recipes.tidymodels.org/reference/#section-step-functions-individual-transformations) for a comprehensive list of the transformations that are offered in recipes.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-28_53a92b75fcd1ad219c04c0fcc94425be'}\n\n```{.r .cell-code}\nrec_spec_log <- recipe(bill_length_mm ~ bill_depth_mm, data = penguins) %>%\n step_log(bill_depth_mm) # transforms the var in-place, keeps it's name\n\nlm_wf_log <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_log)\n\nlm_wf_log %>% fit(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_log()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm \n#> 74.95 -10.91\n```\n:::\n:::\n\n\n\\\n\\\n🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧\n\n## Attribution\n\nThis Chapter was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). Checking linear regression assumptions using the performance package is based on [this article](https://easystats.github.io/performance/reference/check_model.html) and [this blog post](https://www.r-bloggers.com/2021/07/easystats-quickly-investigate-model-performance/) on investigating model performance. The artwork used is by [Allison Horst](https://twitter.com/allison_horst).[Allison Horst](https://twitter.com/allison_horst).\n\n🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧\n", + "markdown": "# Regression in Tidymodels\n\n\n::: {.cell}\n\n:::\n\n\nThis chapter is a gentle introduction into performing simple and multiple linear regression using `tidymodels`. Model fitting will be done using [parsnip](https://www.tidymodels.org/start/models/), which provides a unifying interface for model fitting and the resulting output. This means that parsnip provides a single interface with standardized argument names for each class of models so that you don't have to directly deal with the different interfaces for different functions that aim to do the same thing (like linear regression). See [here](https://www.tidymodels.org/find/parsnip/) for a list of models that `parsnip` currently supports.\n\n## Libraries\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-2_f1b70260de9274ceee0de0930c458b3d'}\n\n```{.r .cell-code}\nlibrary(tidymodels)\nlibrary(broom)\nlibrary(performance)\n```\n:::\n\n\n## Simple linear regression\n\nThe key steps to perform linear regression in `tidymodels` are to first specify the model type and then to specify the model form and the data to be used to construct it.\n\nTo illustrate, we shall look to `penguins` dataset from the `tidymodels`' `modeldata` package. This dataset contains measurements for 344 penguins from three islands in Palmer Archipelago, Antarctica, and includes information on their species, island home, size (flipper length, body mass, bill dimensions), and sex.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-3_473e0ea4ec6d47826afc1c168bb38198'}\n::: {.cell-output-display}\n![](img/palmer_penguin_species.png){fig-align='center' width=75%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-4_aa7c3f7c67794e4868c4a9be11dcebfd'}\n\n```{.r .cell-code}\n# Let's inspect the data\nhead(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 6 × 7\n#> species island bill_length_mm bill_depth_mm flipper_length_mm\n#> \n#> 1 Adelie Torgersen 39.1 18.7 181\n#> 2 Adelie Torgersen 39.5 17.4 186\n#> 3 Adelie Torgersen 40.3 18 195\n#> 4 Adelie Torgersen NA NA NA\n#> 5 Adelie Torgersen 36.7 19.3 193\n#> 6 Adelie Torgersen 39.3 20.6 190\n#> # ℹ 2 more variables: body_mass_g , sex \n```\n:::\n:::\n\n\nOne thing you may have spotted is that there's missing data in this dataset in the fourth row. For simplicity, we will only work with the complete cases. This reduces the number of rows in our dataset to 333.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-5_6c5cb7769e50f22fea43f07d1fca5e94'}\n\n```{.r .cell-code}\npenguins <- penguins %>%\n filter(complete.cases(.))\n\nhead(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 6 × 7\n#> species island bill_length_mm bill_depth_mm flipper_length_mm\n#> \n#> 1 Adelie Torgersen 39.1 18.7 181\n#> 2 Adelie Torgersen 39.5 17.4 186\n#> 3 Adelie Torgersen 40.3 18 195\n#> 4 Adelie Torgersen 36.7 19.3 193\n#> 5 Adelie Torgersen 39.3 20.6 190\n#> 6 Adelie Torgersen 38.9 17.8 181\n#> # ℹ 2 more variables: body_mass_g , sex \n```\n:::\n:::\n\n\nMuch better! We will now build a simple linear regression model to model bill length as a function of bill depth.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-6_9752f79826c0bd2c0727f0d373aa20ff'}\n::: {.cell-output-display}\n![](img/bill_length_depth.png){fig-align='center' width=60%}\n:::\n:::\n\n\nIn `parsnip`, the model specification is broken down into small functions such as `set_mode()` and `set_engine()` to make the interface more flexible and readable. The general structure is to first specify a mode (regression or classification) and then an engine to indicate what software (or implementation of the algorithm) will be used to fit the model. For our purposes, the mode is `regression` and the engine is `lm` for ordinary least squares. You may note that setting the mode is unnecessary for linear regression, but we include it here as it is a good practice.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-7_d894b718918a6c425b9e0fff7ad8299b'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg() %>%\n set_mode(\"regression\") %>%\n set_engine(\"lm\")\n```\n:::\n\n\nThe above specification does not actually carry out the regression, rather it just states what we would like to do.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-8_dbdab6875a55b8152227310053c8cadd'}\n\n```{.r .cell-code}\nlm_spec\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> Linear Regression Model Specification (regression)\n#> \n#> Computational engine: lm\n```\n:::\n:::\n\n\nOnce we have such a blueprint, we may fit a model by inputting data and a formula. Recall that in R, a formula takes the form `y ~ x` where `y` ix the response and `x` is the predictor variable. For our example, where the response of bill length and predictor of bill depth, we would write the formula as `bill_length_mm ~ bill_depth_mm`. \n\n::: {.callout-note}\nUnlike with standard R `formula()` objects, the names used this a formula must \nbe identical to the variable names in the dataset. No processing functions\nare allowed (processing is handled by the `recipe()`).\n:::\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-9_4435e7400b6dd465d61c248470b8ec32'}\n\n```{.r .cell-code}\nlm_fit <- lm_spec %>%\n fit(bill_length_mm ~ bill_depth_mm, data = penguins)\n\nlm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm, data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm \n#> 54.8909 -0.6349\n```\n:::\n:::\n\n\nThe resulting `parsnip` object includes basic information about the fit such as the model coefficients. To access the underlying fit object, we could use the standard `lm_fit$fit` or `purrr`'s `pluck()` (which is a general purpose function that's used to grab a list component):\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-10_c44cea2b4ccca541a75e2249a6991015'}\n\n```{.r .cell-code}\nlm_fit %>%\n pluck(\"fit\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm, data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm \n#> 54.8909 -0.6349\n```\n:::\n:::\n\n\nTo get additional information about the fit (such as standard errors, and goodness-of-fit statistics), we can get a summary of the model fit as follows:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-11_170fec411bf1e01a30f67a906726bc21'}\n\n```{.r .cell-code}\nlm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -12.9498 -3.9530 -0.3657 3.7327 15.5025 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 54.8909 2.5673 21.380 < 2e-16 ***\n#> bill_depth_mm -0.6349 0.1486 -4.273 2.53e-05 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 5.332 on 331 degrees of freedom\n#> Multiple R-squared: 0.05227,\tAdjusted R-squared: 0.04941 \n#> F-statistic: 18.26 on 1 and 331 DF, p-value: 2.528e-05\n```\n:::\n:::\n\n\nTo get a tidy summary of the model parameter estimates, simply use the tidy function from the [broom](https://broom.tidymodels.org/) package on the model fit. To extract model statistics, `glance()` can be used.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-12_3c6cda9ae2eea12f6c255b8bf2cd5061'}\n\n```{.r .cell-code}\ntidy(lm_fit)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 2 × 5\n#> term estimate std.error statistic p.value\n#> \n#> 1 (Intercept) 54.9 2.57 21.4 2.54e-64\n#> 2 bill_depth_mm -0.635 0.149 -4.27 2.53e- 5\n```\n:::\n\n```{.r .cell-code}\nglance(lm_fit)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 12\n#> r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC\n#> \n#> 1 0.0523 0.0494 5.33 18.3 0.0000253 1 -1029. 2064. 2075.\n#> # ℹ 3 more variables: deviance , df.residual , nobs \n```\n:::\n:::\n\n\nNow, to make predictions, we simply use `predict()` on the parnsip model object. In there, we must specify the dataset we want to predict on in the `new_data` argument. Note that this may be a different dataset than we used for fitting the model, but this input data must include all predictor variables that were used to fit the model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-13_0370f690b7e270998042a729bdbf587f'}\n\n```{.r .cell-code}\npredict(lm_fit, new_data = penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 1\n#> .pred\n#> \n#> 1 43.0\n#> 2 43.8\n#> 3 43.5\n#> 4 42.6\n#> 5 41.8\n#> 6 43.6\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nFor parnsip models, the predictions are always outputted in a tibble.\n\nTo specify the type of prediction made, modify `type` argument. If we set `type = \"conf_int\"`, we get a 95% confidence interval.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-14_ef093136394a01ed5d663b2ea837c983'}\n\n```{.r .cell-code}\npredict(lm_fit, new_data = penguins, type = \"conf_int\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 2\n#> .pred_lower .pred_upper\n#> \n#> 1 42.3 43.7\n#> 2 43.3 44.4\n#> 3 42.8 44.1\n#> 4 41.8 43.5\n#> 5 40.7 43.0\n#> 6 43.0 44.2\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nTo evaluate model predictive performance, it is logical to compare the each of the observed and predicted values. To see these values side-by-side we simply bind the two vectors of interest.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-15_e464c86a9e8050cfa6b8e3174a99d1ee'}\n\n```{.r .cell-code}\nbind_cols(\n predict(lm_fit, new_data = penguins),\n penguins\n) %>%\n select(bill_length_mm, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 2\n#> bill_length_mm .pred\n#> \n#> 1 39.1 43.0\n#> 2 39.5 43.8\n#> 3 40.3 43.5\n#> 4 36.7 42.6\n#> 5 39.3 41.8\n#> 6 38.9 43.6\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nA simpler way to do this is to use the nifty `augment()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-16_008a078253bb995f610dd7929c7c4874'}\n\n```{.r .cell-code}\naugment(lm_fit, new_data = penguins) %>%\n select(bill_length_mm, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 2\n#> bill_length_mm .pred\n#> \n#> 1 39.1 43.0\n#> 2 39.5 43.8\n#> 3 40.3 43.5\n#> 4 36.7 42.6\n#> 5 39.3 41.8\n#> 6 38.9 43.6\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\n## Multiple linear regression\n\nThe only difference about fitting a multiple linear regression model in comparison to a simple linear regression model lies the formula. For multiple linear regression, the predictors are specified in the formula expression, separated by `+`. For example, if we have a response variable `y` and three predictors, `x1, x2,` and `x3`, we would write the formula as, `y ~ x1 + x2 + x3`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-17_77a1ab952443165abb55d9b9fdae419e'}\n\n```{.r .cell-code}\nlm_fit2 <- lm_spec %>% fit(\n formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm + body_mass_g,\n data = penguins\n)\nlm_fit2\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm + \n#> body_mass_g, data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm flipper_length_mm body_mass_g \n#> -2.571e+01 6.131e-01 2.872e-01 3.472e-04\n```\n:::\n:::\n\n\nEverything else proceeds much the same as before. Such as obtaining parameter estimates\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-18_2f633c83ebc971b730b1364d8a51e402'}\n\n```{.r .cell-code}\ntidy(lm_fit2)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 4 × 5\n#> term estimate std.error statistic p.value\n#> \n#> 1 (Intercept) -25.7 6.72 -3.83 1.55e- 4\n#> 2 bill_depth_mm 0.613 0.138 4.43 1.26e- 5\n#> 3 flipper_length_mm 0.287 0.0351 8.18 6.28e-15\n#> 4 body_mass_g 0.000347 0.000566 0.614 5.40e- 1\n```\n:::\n:::\n\n\nas well as predicting new values.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-19_bade4f9eb41832a1bfdb0efeae87f940'}\n\n```{.r .cell-code}\npredict(lm_fit2, new_data = penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 333 × 1\n#> .pred\n#> \n#> 1 39.0\n#> 2 39.7\n#> 3 42.5\n#> 4 42.8\n#> 5 42.8\n#> 6 38.4\n#> # ℹ 327 more rows\n```\n:::\n:::\n\n\nIf you would like to use all variables aside from your response as predictors, a shortcut is to use the formula form `y ~ .`\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-20_4a1fb1bf15b09cf0cb3b73cb1f3a7c72'}\n\n```{.r .cell-code}\nlm_fit3 <- lm_spec %>% fit(bill_length_mm ~ ., data = penguins)\nlm_fit3\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) speciesChinstrap speciesGentoo islandDream \n#> 15.343291 9.835502 6.117675 -0.503815 \n#> islandTorgersen bill_depth_mm flipper_length_mm body_mass_g \n#> -0.127431 0.300670 0.069257 0.001081 \n#> sexmale \n#> 2.047859\n```\n:::\n:::\n\n\n## Checking model assumptions\n\nAfter fitting a model, it is good to check whether the assumptions of linear regression are met. For this, we will use the `performance` package, in particular the `check_model()` function to produce several helpful plots we may use to check the assumptions for our first multiple linear regression model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-21_9f0e50621ab07bb69b919f860e7a0ba9'}\n\n```{.r .cell-code}\nlm_fit2 %>%\n extract_fit_engine() %>%\n check_model()\n```\n\n::: {.cell-output-display}\n![](tidymodels-regression_files/figure-html/unnamed-chunk-21-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nNotice that on each plot it says what we should expect to see if the model assumption is met.\n\nWe shall now briefly walk you through what each plot means.\n\nThe first two plots help us to examine the linearity of the errors versus the fitted values. Ideally, we want this error to be relatively flat and horizontal. The third plot is for checking homogeneity of the variance, where we want the points to be roughly the same distance from the line as this indicates similar dispersion. The fourth plot helps us to see if there are high leverage points - points that have command or influence over the model fit. As a result, these can have a great effect on the model predictions. So the removal of such points or modifications to the model may be necessary to deal with them. The fifth plot helps us to discern collinearity, which is when predictors are highly correlated. Since independent variables should be independent, this can throw off simple regression models (in standard error of coefficient estimates and the estimates themselves, which would likely be sensitive to changes in the predictors that are included in the model). The last plot enables us to check the normality of residuals. If the distribution of the model error is non-normal, then that suggests a linear model may not be appropriate. For a QQ plot, we want the points to fall along a straight diagonal line.\n\nFor our example, we observe that there's a pretty high correlation between `body_mass_g` and `flipper_length_mm` (not quite in the red-zone of 10 and above, but close enough for concern). That is indicative of multicollinearity between them. Intuitively, it makes sense for the body mass and flipper length variables - we'd expect that as once increases, so should the other.\n\nWe can take a closer look at the correlation by whipping up a correlation matrix by using base R's `cor()` function. Since for collinearity we're only usually interested in the numerical predictors, we'll only include the four numeric variables.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-22_49987b72aff741a32f5dfc50558d4948'}\n\n```{.r .cell-code}\npenguins_corr <- penguins %>%\n select(body_mass_g, ends_with(\"_mm\")) %>%\n cor()\npenguins_corr\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> body_mass_g bill_length_mm bill_depth_mm flipper_length_mm\n#> body_mass_g 1.0000000 0.5894511 -0.4720157 0.8729789\n#> bill_length_mm 0.5894511 1.0000000 -0.2286256 0.6530956\n#> bill_depth_mm -0.4720157 -0.2286256 1.0000000 -0.5777917\n#> flipper_length_mm 0.8729789 0.6530956 -0.5777917 1.0000000\n```\n:::\n:::\n\n\nIndeed `body_mass_g` and `flipper_length_mm` are highly positively correlated. To deal with this problem, we'll re-fit the model without `body_mass_g`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-23_306a0e9cc19412e08433bd04830dd697'}\n\n```{.r .cell-code}\nlm_fit3 <- lm_spec %>% fit(\n formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm,\n data = penguins\n)\nlm_fit3\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ bill_depth_mm + flipper_length_mm, \n#> data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm flipper_length_mm \n#> -27.9762 0.6200 0.3052\n```\n:::\n:::\n\n\nand then check again to see whether the assumptions are met.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-24_6508d43288ce1be6d4caff814eec9b9f'}\n\n```{.r .cell-code}\nlm_fit3 %>%\n extract_fit_engine() %>%\n check_model()\n```\n\n::: {.cell-output-display}\n![](tidymodels-regression_files/figure-html/unnamed-chunk-24-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nOverall, the plots look pretty good. For details on how to interpret each of these plots and more details about model assumptions please see [here](https://easystats.github.io/see/articles/performance.html) and [here](https://rdrr.io/cran/performance/man/check_model.html).\n\n## Interaction terms\n\nIn general, the syntax to add an interaction term to a formula is as follows:\n\n- `x:y` denotes an interaction term between `x` and `y`.\n- `x*y` denotes the interaction between `x` and `y` as well as `x` and `y`; that is, `x + y + x*y`.\n\nIt is important to note that this syntax is not compatible with all engines. Thus, we shall explain how to bypass this issue by adding an interaction term in a recipe later on. For now, let's start simple by adding an interaction term between `species` and `bill_length_mm`, which allows for a species-specific slope.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-25_be09e39914328ca51bbe6fb2207c82b1'}\n\n```{.r .cell-code}\nlm_fit4 <- lm_spec %>% fit(\n formula = bill_length_mm ~ species * bill_depth_mm,\n data = penguins\n)\nlm_fit4\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = bill_length_mm ~ species * bill_depth_mm, \n#> data = data)\n#> \n#> Coefficients:\n#> (Intercept) speciesChinstrap \n#> 23.3668 -9.9389 \n#> speciesGentoo bill_depth_mm \n#> -6.6966 0.8425 \n#> speciesChinstrap:bill_depth_mm speciesGentoo:bill_depth_mm \n#> 1.0796 1.2178\n```\n:::\n:::\n\n\nUsing recipes, the interaction term is specified by using `step_interact()`. Then we construct a workflow object, where we add the linear regression model specification and recipe. Finally, we fit the model as we did for a `parsnip` model. Note that the workflow object does not need the variables that were specified in the recipe to be specified again.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-26_5d6b5266d0b373c844a38e0a080436d0'}\n\n```{.r .cell-code}\nrec_spec_interact <- recipe(\n formula = bill_length_mm ~ species + bill_depth_mm,\n data = penguins\n) %>%\n step_interact(~ species:bill_depth_mm)\n\nlm_wf_interact <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_interact)\n\nlm_wf_interact %>% fit(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_interact()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) speciesChinstrap \n#> 23.3668 -9.9389 \n#> speciesGentoo bill_depth_mm \n#> -6.6966 0.8425 \n#> speciesChinstrap_x_bill_depth_mm speciesGentoo_x_bill_depth_mm \n#> 1.0796 1.2178\n```\n:::\n:::\n\n\nNotice the variable name for the interaction term is not the same as it is in base R (which is simply of the form `x:y`). In `step_interact()`, the default separator between the variable names is `_x_`. You can change this default by specifying the `sep` argument in the function.\n\nTo read more about formula syntax, see [?formula](https://rdrr.io/r/stats/formula.html).\n\n## Non-linear transformations of the predictors\n\nSimilar to how we were able to add an interaction term using recipes, we can also perform a transformation as a pre-processing step. The function used for this is `step_mutate()` (which acts like `dplyr`'s `mutate`).\n\nNote that, in general, if you are specifying a recipe aim to keep as much of the pre-processing in your recipe specification as possible. This helps to ensure that the transformation will be applied to new data consistently.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-27_b7d9eb46155f4d760ade7a95ee6ba5d7'}\n\n```{.r .cell-code}\nrec_spec_pow2 <- recipe(bill_length_mm ~ bill_depth_mm, data = penguins) %>%\n step_mutate(bill_depth_mm2 = bill_depth_mm^2)\n\nlm_wf_pow2 <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_pow2)\n\nlm_wf_pow2 %>% fit(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm bill_depth_mm2 \n#> 95.2558 -5.4431 0.1413\n```\n:::\n:::\n\n\nThere are many transformations already built into recipes such as `step_log()`. So, for basic transformations, there's often no need to make your own transformation from scratch. See [here](https://recipes.tidymodels.org/reference/#section-step-functions-individual-transformations) for a comprehensive list of the transformations that are offered in recipes.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression_cache/html/unnamed-chunk-28_53a92b75fcd1ad219c04c0fcc94425be'}\n\n```{.r .cell-code}\nrec_spec_log <- recipe(bill_length_mm ~ bill_depth_mm, data = penguins) %>%\n step_log(bill_depth_mm) # transforms the var in-place, keeps it's name\n\nlm_wf_log <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_log)\n\nlm_wf_log %>% fit(penguins)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_log()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) bill_depth_mm \n#> 74.95 -10.91\n```\n:::\n:::\n\n\n\\\n\\\n🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧\n\n## Attribution\n\nThis Chapter was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). Checking linear regression assumptions using the performance package is based on [this article](https://easystats.github.io/performance/reference/check_model.html) and [this blog post](https://www.r-bloggers.com/2021/07/easystats-quickly-investigate-model-performance/) on investigating model performance. The artwork used is by [Allison Horst](https://twitter.com/allison_horst).[Allison Horst](https://twitter.com/allison_horst).\n\n🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧 🐧\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/tidymodels-regression-part2.qmd b/tidymodels-regression-part2.qmd index 0b8b2fc..522eaec 100644 --- a/tidymodels-regression-part2.qmd +++ b/tidymodels-regression-part2.qmd @@ -1,7 +1,5 @@ # Regression in Tidymodels - Part 2 -This chapter is starts off as the Regression in Tidymodels chapter - Epidemiological time series edition and goes from there to making (slightly) more sophisticated predictions and interactive plots. - ```{r} #| echo: false source("_common.R") @@ -15,9 +13,9 @@ library(tidymodels) library(plotly) ``` -As a follow-up to the Regression in `Tidymodels` chapter, we're going to look at how the functions we used to perform linear regression fair when applied to a small set of epidemiological time series data. We'll be working with the built-in data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021 (this was originally compiled by JHU). +As a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021. -Note that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data) just yet. +Note that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). ```{r} # Load and subset data @@ -27,20 +25,22 @@ ca_case_death_rate_subset <- case_death_rate_subset %>% ## Simple linear regression -Our goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. And to do this, we'll essentially work through the same routine that we went through above (just in a different scenario). Thus, we'll opt for the same linear regression model specification. As we mentioned previously, setting the mode is unnecessary for linear regression, so let's drop that bit this time round. In addition, `lm` is the default engine for linear regression, so, we don't have to include that bit either. +Our goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. ```{r, echo = FALSE, out.width = "50%", fig.align='center'} knitr::include_graphics("img/set_engine.png") ``` ```{r} -lm_spec_way2 <- linear_reg() +lm_spec <- linear_reg() ``` +We made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either. + Now we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function. ```{r} -ca_lm_fit <- lm_spec_way2 %>% +ca_lm_fit <- lm_spec %>% fit(death_rate ~ case_rate, data = ca_case_death_rate_subset) ca_lm_fit ``` @@ -53,13 +53,12 @@ ca_lm_fit %>% summary() ``` -Now let's forge ahead and get some predictions for the existing dataset. +Now we may generate predictions for the dataset. ```{r} predict(ca_lm_fit, new_data = ca_case_death_rate_subset) ``` - -And to get a side-by-side view of the observed and predicted values (which sets us up well to compare them), we'll use `augment()`. +To get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`. ```{r} # adjoin the model predictions to `ca_case_death_rate_subset`). @@ -67,13 +66,13 @@ augment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>% select(death_rate, .pred) ``` -All in all, everything that we did before seems to translate seamlessly over to handling a bit of epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, do we only want to look to the concurrent (same-day) case information? Or should we look into the past as well? Since what happened in the past can inform us where things are heading, we could also include case rates and death rates as predictors. +All in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors. -## Adding lagged predictors and predicting a sliver of the future +## Adding lagged predictors and predicting for a target date -Now the big question is how far back in the past should we look? More specifically, what past case and death rates are most predictive of current deaths. This is a natural question to have at this point, but it ventures into model selection territory which beyond the scope of this article. For those interested, a lagged correlation analysis as described in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. So read it if you dare (or if you have the time). +At this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include. -To start, we will add predictors for the lagged 1-day death and case rates as those seem to be perhaps the most sensible choices (because yesterday is generally more predictive of today than two weeks ago would be). +To begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago). So first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function. @@ -82,61 +81,56 @@ ca_subset_wlag <- ca_case_death_rate_subset %>% mutate(lag_1_death_rate = lag(death_rate, 1)) ``` -Then, we can go ahead and create our recipe, and we can add a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor before, by using `step_mutate()` on the predictor that's been specified in the recipe formula. +Then, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula. ```{r} rec_spec_lag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>% step_mutate(lag_1_case_rate = lag(case_rate, 1)) ``` -Now, we just pop the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before. +Next, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before. ```{r} lm_wf_lag <- workflow() %>% - add_model(lm_spec_way2) %>% + add_model(lm_spec) %>% add_recipe(rec_spec_lag) ca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag) ca_lm_fit_lag ``` -And viola, we got ourselves a trained workflow - which to be clear has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. +As a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. -Now we'll try to use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). So we'll throw this info. in a short dataframe and feed it into `new_data`. +Now, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe: ```{r} -last_row_ca <- ca_case_death_rate_subset %>% tail(n = 1) - -predict(ca_lm_fit_lag, new_data = data.frame(case_rate = 84.7, - lag_1_death_rate = last_row_ca$death_rate, - lag_1_case_rate = last_row_ca$case_rate)) +jan_1_df <- data.frame(geo_value = "ca", + time_value = as.Date("2022-01-01"), + case_rate = 84.7, + lag_1_death_rate = last(ca_subset_wlag)$death_rate) ``` -Hold up... Why is our prediction NA? We inputted the necessary data with the correct variable names (no typos there). So what went wrong? The answer is two paragraphs above. And here it is: Recall that we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original model specification. So this means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. This is a bit of a pain, but so be it. The quick and dirty fix is to simply change `n = 1` to 2 in `tail()`, but let's flex our skills with `bind_rows()` instead. +Notice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`: ```{r} -# Add new row of to ca_case_death_rate_subset +# Add new row of to ca_subset_wlag ca_subset_plus_row <- bind_rows( - ca_case_death_rate_subset, - data.frame(geo_value = "ca", - time_value = as.Date("2022-01-01"), - case_rate = 84.7, - lag_1_death_rate = last_row_ca$death_rate) + ca_subset_wlag, + jan_1_df ) ``` -And then pop that into predict... +And then input that into predict... ```{r} predict(ca_lm_fit_lag, new_data = ca_subset_plus_row) %>% tail(n = 1) ``` - -Wonderful. We got ourselves a prediction. But that was a heck of a lot of work to get here. How could we simplify things for ourselves? Well there's a couple things that `epipredict` offers that could help us out here. +Wonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options... ### Option 1 - manually create our own `epi_recipe` -Instead of using a plain old recipe, it is more advantageous to use an `epi_recipe` on an `epi_df`. Why? It unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combo above to get the lagged case and death rate variables, we can simply write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`. +It is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`. ```{r} ca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>% @@ -145,21 +139,21 @@ ca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>% step_epi_ahead(death_rate, ahead = 0) ``` -Then, just throw the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before. +Then, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before. ```{r} -ca_epi_wf <- epi_workflow(ca_epi_r, lm_spec_way2) %>% +ca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>% fit(ca_case_death_rate_subset) predict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>% filter(time_value == "2022-01-01") ``` -Notice we get the same prediction as before, just as we'd expect. +As expected, we obtain the same prediction as when we used the first approach. ### Option 2 - let the `arx_forecaster()` do the work for us -We can take things a notch further because the `epipredict` package has the `arx_forecaster()` function to make our lives easier by pre-processing, training the model, predicting, and performing some basic post-processing, all in one go. The reason why we can use this model is that the above is a technically a type of autoregressive (AR) model, in which a linear combination of previous values are use forecast the variable of interest. In contrast, in a multiple linear regression model, we use a linear combination of predictors to forecast the variable we're interested in. +The `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). ```{r, warning = FALSE} ca_arx_pred_jan_22 <- arx_forecaster( @@ -174,7 +168,7 @@ ca_arx_pred_jan_22 <- arx_forecaster( ca_arx_pred_jan_22$predictions ``` -We could easily add more lags for the case and death rates into the function . All that we got to do is add a couple of choice numbers to the `lags` argument. This is infinitely preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for each of case and death rate to `arx_forecaster()`: +We can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`: ```{r, warning = FALSE} lots_of_lags_ca <- arx_forecaster( @@ -189,7 +183,7 @@ lots_of_lags_ca <- arx_forecaster( lots_of_lags_ca$predictions ``` -The other major benefit of the above forecaster is that it is equipped to handle panel data. That means that for our example we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. +The other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. ```{r, warning = FALSE} all_the_states <- arx_forecaster( @@ -204,7 +198,7 @@ all_the_states <- arx_forecaster( all_the_states$predictions ``` -Neat! We'll learn more about this and other forecasters in later chapters. +Awesome! We'll learn more about this and other forecasters in later chapters. ## Interactive plot of predictions {#sec-interactive-plot} @@ -224,7 +218,7 @@ all_the_states_df <- all_the_states_df %>% ``` -Then, we simply adapted the "Customize choropleth code" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The major changes are that we specified what we would like to show when we hover (the predictions and the corresponding 90% predictive interval). As well, we modified the trace (a trace is just a layer to add to the plot with its own data and visualization components), so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`. +Then, we adapted the "Customize choropleth code" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`. ```{r} #| fig-height: 1.75 @@ -263,11 +257,11 @@ fig <- fig %>% layout( fig ``` -Pretty cool for a quick adaptation of existing `plotly` code. +Not bad for a quick adaptation of existing `plotly` code. -At this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, this checks out. +At this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out. -Finally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try such extensions on their own. +Finally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try implementing such extensions on their own. ## Attribution diff --git a/tidymodels-regression.qmd b/tidymodels-regression.qmd index e205e55..bd6df1b 100644 --- a/tidymodels-regression.qmd +++ b/tidymodels-regression.qmd @@ -74,7 +74,7 @@ lm_fit <- lm_spec %>% lm_fit ``` -The resulting `parsnip` object includes basic information about the fit such as the model coefficients. To access the underlying fit object, we could use the standard `lm_fit$fit` or with `purrr`'s `pluck()` function. +The resulting `parsnip` object includes basic information about the fit such as the model coefficients. To access the underlying fit object, we could use the standard `lm_fit$fit` or `purrr`'s `pluck()` (which is a general purpose function that's used to grab a list component): ```{r} lm_fit %>% From ea6cb0cde0b2966b119638ff411e155f22524233 Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:16:23 -0700 Subject: [PATCH 12/16] Small changes to text --- tidymodels-regression-part2.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tidymodels-regression-part2.qmd b/tidymodels-regression-part2.qmd index 522eaec..4654ef0 100644 --- a/tidymodels-regression-part2.qmd +++ b/tidymodels-regression-part2.qmd @@ -261,7 +261,7 @@ Not bad for a quick adaptation of existing `plotly` code. At this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out. -Finally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try implementing such extensions on their own. +Finally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it as an exercise to reader to try implementing such extensions on their own. ## Attribution From 5fc8103831779169be9c4646a3e10211e5aeebf5 Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:17:00 -0700 Subject: [PATCH 13/16] Simplify sentence a bit --- tidymodels-regression-part2.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tidymodels-regression-part2.qmd b/tidymodels-regression-part2.qmd index 4654ef0..64c0570 100644 --- a/tidymodels-regression-part2.qmd +++ b/tidymodels-regression-part2.qmd @@ -261,7 +261,7 @@ Not bad for a quick adaptation of existing `plotly` code. At this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out. -Finally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it as an exercise to reader to try implementing such extensions on their own. +Finally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own. ## Attribution From 57c20caeb0d65e8cc63f28b2555ee8b531ee3b37 Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:24:47 -0700 Subject: [PATCH 14/16] Simplify var names a bit --- .../execute-results/html.json | 4 +-- tidymodels-regression-part2.qmd | 25 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/_freeze/tidymodels-regression-part2/execute-results/html.json b/_freeze/tidymodels-regression-part2/execute-results/html.json index 1c1b30e..434caac 100644 --- a/_freeze/tidymodels-regression-part2/execute-results/html.json +++ b/_freeze/tidymodels-regression-part2/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "5d712a62250e03d006b7b1bd85780b0b", + "hash": "1452a67c4a4abddf2bb40e93537ddc6f", "result": { - "markdown": "# Regression in Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021.\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_8e4a55d2cf5dd5462ea1ea929bd3f6f8'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg()\n```\n:::\n\n\nWe made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either.\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_bdf235a5206620fbc7d51847c37e572d'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow we may generate predictions for the dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\nTo get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting for a target date\n\nAt this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include.\n\nTo begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_fcbd0b889567108db17d97a251f4394f'}\n\n```{.r .cell-code}\nrec_spec_lag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNext, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_e820094ca6bae5ef1af884da84b13d2f'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_lag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAs a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_d6dba693544d6cab62dbde71da21f181'}\n\n```{.r .cell-code}\njan_1_df <- data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last(ca_subset_wlag)$death_rate\n)\n```\n:::\n\n\nNotice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_efab5d9cb5bbebe16ecb68605535f783'}\n\n```{.r .cell-code}\n# Add new row of to ca_subset_wlag\nca_subset_plus_row <- bind_rows(\n ca_subset_wlag,\n jan_1_df\n)\n```\n:::\n\n\nAnd then input that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_1ab4d7dbf51419f8ddf299c5062e5c79'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_plus_row) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\nWonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options...\n\n### Option 1 - manually create our own `epi_recipe`\n\nIt is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_1b37a617156ce9ddf5057e0c04102ba9'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nAs expected, we obtain the same prediction as when we used the first approach.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nThe `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_87146e4ff6e311476c6feb27e5127719'}\n\n```{.r .cell-code}\nca_arx_pred_jan_22 <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_pred_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nWe can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_a71bf5dcf8b9a859dc6f0736cbd53241'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nAwesome! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nNot bad for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot... For instance, if we had the true death rates for that date, then we could show these on the same or on another chloropleth map that's side-by-side to this one. We'll leave it to the reader to try implementing such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", + "markdown": "# Regression in Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021.\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_8e4a55d2cf5dd5462ea1ea929bd3f6f8'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg()\n```\n:::\n\n\nWe made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either.\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_bdf235a5206620fbc7d51847c37e572d'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow we may generate predictions for the dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\nTo get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting for a target date\n\nAt this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include.\n\nTo begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_3053fccd91b5661f92aa86d6087ee54c'}\n\n```{.r .cell-code}\nrec_spec_wlag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNext, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d001ce8805d69846f1eef56be8685456'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_wlag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAs a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_aa9511094763cc41fbd6d3b12835ccf8'}\n\n```{.r .cell-code}\nca_jan1_df <- data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last(ca_subset_wlag)$death_rate\n)\n```\n:::\n\n\nNotice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_7b7452b2ab67a22552c00592d5b91c2e'}\n\n```{.r .cell-code}\n# Add new row of to ca_subset_wlag\nca_subset_plus_jan1 <- bind_rows(\n ca_subset_wlag,\n ca_jan1_df\n)\n```\n:::\n\n\nAnd then input that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_60cb8c33c2b0e76c96a5328cec60c86a'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_plus_jan1) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\nWonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options...\n\n### Option 1 - manually create our own `epi_recipe`\n\nIt is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_1b37a617156ce9ddf5057e0c04102ba9'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nAs expected, we obtain the same prediction as when we used the first approach.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nThe `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_87146e4ff6e311476c6feb27e5127719'}\n\n```{.r .cell-code}\nca_arx_pred_jan_22 <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_pred_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nWe can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_a71bf5dcf8b9a859dc6f0736cbd53241'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nAwesome! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nNot bad for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/tidymodels-regression-part2.qmd b/tidymodels-regression-part2.qmd index 64c0570..a97a033 100644 --- a/tidymodels-regression-part2.qmd +++ b/tidymodels-regression-part2.qmd @@ -84,7 +84,7 @@ ca_subset_wlag <- ca_case_death_rate_subset %>% Then, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula. ```{r} -rec_spec_lag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>% +rec_spec_wlag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>% step_mutate(lag_1_case_rate = lag(case_rate, 1)) ``` @@ -93,7 +93,7 @@ Next, we input the model and recipe into our workflow and then fit the model to ```{r} lm_wf_lag <- workflow() %>% add_model(lm_spec) %>% - add_recipe(rec_spec_lag) + add_recipe(rec_spec_wlag) ca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag) ca_lm_fit_lag @@ -104,7 +104,7 @@ As a result, we obtain a trained workflow that has undergone both pre-processing Now, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe: ```{r} -jan_1_df <- data.frame(geo_value = "ca", +ca_jan1_df <- data.frame(geo_value = "ca", time_value = as.Date("2022-01-01"), case_rate = 84.7, lag_1_death_rate = last(ca_subset_wlag)$death_rate) @@ -114,16 +114,16 @@ Notice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the abov ```{r} # Add new row of to ca_subset_wlag -ca_subset_plus_row <- bind_rows( +ca_subset_wlag_jan1 <- bind_rows( ca_subset_wlag, - jan_1_df + ca_jan1_df ) ``` And then input that into predict... ```{r} -predict(ca_lm_fit_lag, new_data = ca_subset_plus_row) %>% +predict(ca_lm_fit_lag, new_data = ca_subset_wlag_jan1) %>% tail(n = 1) ``` Wonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options... @@ -145,7 +145,7 @@ Then, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and ca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>% fit(ca_case_death_rate_subset) -predict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>% +predict(ca_epi_wf, ca_subset_wlag_jan1 %>% select(-lag_1_death_rate)) %>% filter(time_value == "2022-01-01") ``` @@ -156,8 +156,8 @@ As expected, we obtain the same prediction as when we used the first approach. The `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). ```{r, warning = FALSE} -ca_arx_pred_jan_22 <- arx_forecaster( - ca_subset_plus_row %>% select(-lag_1_death_rate), +ca_arx_jan_22 <- arx_forecaster( + ca_subset_wlag_jan1 %>% select(-lag_1_death_rate), outcome = "death_rate", predictors = c("death_rate", "case_rate"), args_list = arx_args_list( @@ -165,14 +165,13 @@ ca_arx_pred_jan_22 <- arx_forecaster( ahead = 0L ) ) -ca_arx_pred_jan_22$predictions +ca_arx_jan_22$predictions ``` - We can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`: ```{r, warning = FALSE} lots_of_lags_ca <- arx_forecaster( - ca_subset_plus_row %>% select(-lag_1_death_rate), + ca_subset_wlag_jan1 %>% select(-lag_1_death_rate), outcome = "death_rate", predictors = c("case_rate", "death_rate"), args_list = arx_args_list( @@ -183,7 +182,7 @@ lots_of_lags_ca <- arx_forecaster( lots_of_lags_ca$predictions ``` -The other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. +The other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state: ```{r, warning = FALSE} all_the_states <- arx_forecaster( From ed643be45eaef39ca14619f423de558b2b8c0c5f Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Sun, 12 Nov 2023 21:07:14 -0800 Subject: [PATCH 15/16] Proofread arx chapter --- .../arx-forecaster/execute-results/html.json | 4 +- .../execute-results/html.json | 4 +- arx-forecaster.qmd | 54 +++++++++---------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/_freeze/arx-forecaster/execute-results/html.json b/_freeze/arx-forecaster/execute-results/html.json index cf6f5d1..9d2c2d7 100644 --- a/_freeze/arx-forecaster/execute-results/html.json +++ b/_freeze/arx-forecaster/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "4202c72997458146be9357e4568362e0", + "hash": "1d18061a6d66aa58a854e9c087388279", "result": { - "markdown": "# Introducing the ARX forecaster\n\nThe ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nIt can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data.\n\nFrom the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `\"death_rate\"`, and predictors of `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" in the raw `jhu` data and the `lag_14_death_rate` is the value from \"2021-09-01\". In this way, we can manually check that the model used the correct predictor data if we're so inclined.\n\nNow that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nLike with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature.\n\nOk. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_c0b32b43e54a1e4afd53477c4efe790f'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d() +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done to make the death rate lines is to not impose an upper bound the data used in `hist` (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_a81d6b7174c650bfed1401a0aeb31e70'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(alpha = .7) +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAs our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nRemember the adapted \"Customize choropleth code\" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). \nThat's all it takes.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nYou can either hit play in the above plot and sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them.\n\nA possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox.\n", + "markdown": "# Introducing the ARX forecaster\n\nThe built-in ARX forecaster is a direct forecasting approach used to estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nPreparing exogenous variables for input into an ARX model is not necessarily a simple task. For instance, it is fairly common to have to modify such variables to match the temporal resolution of the variable being forecasted upon. Additionally, there may be other considerations such as correlation or interactions between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will reserve further discussion of this for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). Hence, the output is a data frame of point (optionally interval) forecasts at a single unique horizon for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecasterm which contains a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our primary goal is to predict death rates one week ahead of the last date available for each state. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ coefficients are obtained from fitting a model to the training data.\n\nThe above formulation makes it clear that the `arx_forecaster` function must have a predictors parameter in addition to a parameter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. So the simplest way to use `arx_forecaster()` to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input a minimum of three arguments: the `epi_df` data, the outcome of `\"death_rate\"`, and the predictors that are based on `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation, the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the molded/pre-processed training data that is contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (since we only need to consider lags of `death_rate` to construct the predictors).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" and `lag_14_death_rate` is the value from \"2021-09-01\" in the raw `jhu` data. In this way, we can manually check that the model used the correct predictor data if we are so inclined.\n\nNow that we are clear on how the lags work, we can proceed from a basic AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nAs with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components: the metadata, the `epi_workflow`, and the tibble of predictions. From the summary, we can note that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days ahead of the forecast date is the default for the target date. And as we saw for the flatline forecaster, to change this you must change the ahead parameter in the additional arguments list, `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter to enumerate the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from the pre-processing, to the model fitting, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to obtain that is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see the pre-processing operations in the order they are carried out. Firstly lag the death and case rates by the stated lags (`step_epi_lag()`), then lead the death rate by 5 days (`step_epi_ahead()`), remove the rows containing NAs in the predictors or outcomes, and finally, do not restrict of the number of recent observations used in the training window (as in `step_training_window()` `n_training = Inf`). More pre-processing is done here in comparison to the flatline forecaster. In particular, there are now steps to lag each the predictor variables as well as to remove any rows that contain a NA value.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates, and bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors that for the flatline forecaster. The vertical black line marks the forecast date. The point beyond that is the prediction and the band about it is the 90% prediction interval. In comparison to the flatline forecaster, the key difference is that these predictions are not simply the last values pulled forward in time. Rather, there's more variability, more separation from the recent past, as we would expect to see in nature.\n\nWhat we've explored so far is for for a single ahead that is not very far off from the forecast date, but what do we see when we look at the predictions for various aheads?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_c0b32b43e54a1e4afd53477c4efe790f'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d() +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it aligns with the truth (there was a period of relative stability). Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model fared. The way that we will extend the black death rate lines is to not impose an upper bound of the data used in `hist` (so that we use all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_a81d6b7174c650bfed1401a0aeb31e70'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(alpha = .7) +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nWe can see that the predictions get increasingly questionable as they get farther away from the forecast date (as indicated by the larger prediction bands), but still they are not entirely unreasonable. Certainly they are more more sensible than those produced by the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two forecasters is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is indicative of the future.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable its long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. That is, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the recent past has been stable and uneventful, then a basic ARX model trained solely on the most recent past will fail to capture the volatility. In that case, amendments should be made or another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. We will construct a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nWe will base our code on that from the \"Customize choropleth code\" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot). The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). Making these changes will give us a slider bar so that we may see what happens over time for each state. \n\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nNow, you can either hit play in the above plot and watch what happens over time or you can manually slide the bar at the bottom and inspect the states by hovering over them.\n\nOne possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We will leave this extension as an exercise to the reader.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple and intuitive model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be fantastic to have in your forecasting toolbox.\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/_freeze/tidymodels-regression-part2/execute-results/html.json b/_freeze/tidymodels-regression-part2/execute-results/html.json index 434caac..8dbca08 100644 --- a/_freeze/tidymodels-regression-part2/execute-results/html.json +++ b/_freeze/tidymodels-regression-part2/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "1452a67c4a4abddf2bb40e93537ddc6f", + "hash": "da179d0be521fc2c714a8839a67a92cb", "result": { - "markdown": "# Regression in Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021.\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_8e4a55d2cf5dd5462ea1ea929bd3f6f8'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg()\n```\n:::\n\n\nWe made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either.\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_bdf235a5206620fbc7d51847c37e572d'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow we may generate predictions for the dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\nTo get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting for a target date\n\nAt this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include.\n\nTo begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_3053fccd91b5661f92aa86d6087ee54c'}\n\n```{.r .cell-code}\nrec_spec_wlag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNext, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d001ce8805d69846f1eef56be8685456'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_wlag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAs a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_aa9511094763cc41fbd6d3b12835ccf8'}\n\n```{.r .cell-code}\nca_jan1_df <- data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last(ca_subset_wlag)$death_rate\n)\n```\n:::\n\n\nNotice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_7b7452b2ab67a22552c00592d5b91c2e'}\n\n```{.r .cell-code}\n# Add new row of to ca_subset_wlag\nca_subset_plus_jan1 <- bind_rows(\n ca_subset_wlag,\n ca_jan1_df\n)\n```\n:::\n\n\nAnd then input that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_60cb8c33c2b0e76c96a5328cec60c86a'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_plus_jan1) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\nWonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options...\n\n### Option 1 - manually create our own `epi_recipe`\n\nIt is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_1b37a617156ce9ddf5057e0c04102ba9'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_plus_row %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nAs expected, we obtain the same prediction as when we used the first approach.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nThe `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_87146e4ff6e311476c6feb27e5127719'}\n\n```{.r .cell-code}\nca_arx_pred_jan_22 <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_pred_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nWe can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_a71bf5dcf8b9a859dc6f0736cbd53241'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_plus_row %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nAwesome! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nNot bad for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", + "markdown": "# Regression in Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021.\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_8e4a55d2cf5dd5462ea1ea929bd3f6f8'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg()\n```\n:::\n\n\nWe made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either.\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_bdf235a5206620fbc7d51847c37e572d'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow we may generate predictions for the dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\nTo get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting for a target date\n\nAt this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include.\n\nTo begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_3053fccd91b5661f92aa86d6087ee54c'}\n\n```{.r .cell-code}\nrec_spec_wlag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNext, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d001ce8805d69846f1eef56be8685456'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_wlag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAs a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_aa9511094763cc41fbd6d3b12835ccf8'}\n\n```{.r .cell-code}\nca_jan1_df <- data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last(ca_subset_wlag)$death_rate\n)\n```\n:::\n\n\nNotice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_2fe2f73c5a3dbe0b0f2478e7deba2ea6'}\n\n```{.r .cell-code}\n# Add new row of to ca_subset_wlag\nca_subset_wlag_jan1 <- bind_rows(\n ca_subset_wlag,\n ca_jan1_df\n)\n```\n:::\n\n\nAnd then input that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_0c8d22a80615f73c3899ca17a3d35f1d'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_wlag_jan1) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\nWonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options...\n\n### Option 1 - manually create our own `epi_recipe`\n\nIt is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_a96c7f12005fcc2817806330f5d3d081'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_wlag_jan1 %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nAs expected, we obtain the same prediction as when we used the first approach.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nThe `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_9739aad549f8766041f4db73dc9b21e6'}\n\n```{.r .cell-code}\nca_arx_jan_22 <- arx_forecaster(\n ca_subset_wlag_jan1 %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\nWe can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_f4989c3184965d788fd29f19a9611a30'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_wlag_jan1 %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state: \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nAwesome! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nNot bad for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/arx-forecaster.qmd b/arx-forecaster.qmd index 4acdcc9..fb90af3 100644 --- a/arx-forecaster.qmd +++ b/arx-forecaster.qmd @@ -1,12 +1,12 @@ # Introducing the ARX forecaster -The ARX forecaster built-in to the `epipredict` package is an autoregressive forecasting model that is intended for `epi_df` data. This is a direct forecasting approach, which means that it will estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. +The built-in ARX forecaster is a direct forecasting approach used to estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. ::: {.callout-note} -It can be quite the task to prepare exogenous variables for input into the model. For example, we may have to modify these variables match the temporal resolution of the variable being forecasted upon. In addition, there may be other considerations such as correlation or interaction between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will hold off on having that discussion here and instead reserve it for its own chapter. +Preparing exogenous variables for input into an ARX model is not necessarily a simple task. For instance, it is fairly common to have to modify such variables to match the temporal resolution of the variable being forecasted upon. Additionally, there may be other considerations such as correlation or interactions between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will reserve further discussion of this for its own chapter. ::: -Similar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). So as before the output is a data frame of point (optionally interval) forecasts at a single unique horizon (`ahead`) for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to the what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. +Similar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). Hence, the output is a data frame of point (optionally interval) forecasts at a single unique horizon for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. ## Example of using the ARX forecaster @@ -28,7 +28,7 @@ library(plotly) ### A brief re-introduction to the dataset -In our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecaster (that comes with the `epipredict` package) that is a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1, 2021 to Dec. 1, 2021. +In our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecasterm which contains a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1 to Dec. 1, 2021. ```{r} jhu <- case_death_rate_subset %>% @@ -39,20 +39,20 @@ jhu ### The basic mechanics of the ARX forecaster -Suppose that our goal is to predict death rates one week ahead of the last date available for each state as with the flatline forecaster. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict +Suppose that our primary goal is to predict death rates one week ahead of the last date available for each state. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict $$ \hat{y}_{j,{t+h}} = \mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14} $$ -where $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ are the coefficients that are obtained from fitting a model to the training data. +where $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ coefficients are obtained from fitting a model to the training data. -From the above, we can gather that the the `arx_forecaster()` function must have a predictors parameter in addition to a paramter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. Hence, the simplest way to use the `arx_forecaster()` function to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input at minimum three arguments in the `arx_forecaster() function`: the `epi_df` data followed by the outcome of `"death_rate"`, and predictors of `"death_rate"`. As we can see in the above equation and from the `arx_args_list()` documentation) the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago. +The above formulation makes it clear that the `arx_forecaster` function must have a predictors parameter in addition to a parameter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. So the simplest way to use `arx_forecaster()` to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input a minimum of three arguments: the `epi_df` data, the outcome of `"death_rate"`, and the predictors that are based on `"death_rate"`. As we can see in the above equation and from the `arx_args_list()` documentation, the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago. ```{r} ar_one_week_ahead <- arx_forecaster(jhu, outcome = "death_rate", predictors = "death_rate") ar_one_week_ahead ``` -To make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the the molded/pre-processed training data that's contained in `one_week_ahead$epi_workflow$pre` to the raw training data. +To make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the molded/pre-processed training data that is contained in `one_week_ahead$epi_workflow$pre` to the raw training data. ```{r} cbind(ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value, @@ -61,22 +61,22 @@ cbind(ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value, head() ``` -Now, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (as we only need to consider lags here). +Now, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (since we only need to consider lags of `death_rate` to construct the predictors). ```{r} jhu %>% filter(geo_value == "ak" & time_value <= "2021-09-15") ``` -We can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from "2021-09-08" in the raw `jhu` data and the `lag_14_death_rate` is the value from "2021-09-01". In this way, we can manually check that the model used the correct predictor data if we're so inclined. +We can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from "2021-09-08" and `lag_14_death_rate` is the value from "2021-09-01" in the raw `jhu` data. In this way, we can manually check that the model used the correct predictor data if we are so inclined. -Now that we are crystal clear on how the lags work, we can kick our model up a notch and go from an AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables). +Now that we are clear on how the lags work, we can proceed from a basic AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables). ```{r} arx_one_week_ahead <- arx_forecaster(jhu, outcome = "death_rate", predictors = c("death_rate", "case_rate")) arx_one_week_ahead ``` -Like with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components, which are the metadata, the `epi_workflow`, and a tibble of predictions as usual. We should take note that from the summary we can see that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days is yet again the default for how many days the target date is ahead of the forecast date. And as we saw for the flatline forecaster, to change this, you must change the ahead parameter in the additional arguments list `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter that is for enumerating the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days. +As with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components: the metadata, the `epi_workflow`, and the tibble of predictions. From the summary, we can note that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days ahead of the forecast date is the default for the target date. And as we saw for the flatline forecaster, to change this you must change the ahead parameter in the additional arguments list, `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter to enumerate the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days. ```{r} arx_five_days_ahead_many_lags <- arx_forecaster( @@ -92,18 +92,18 @@ arx_five_days_ahead_many_lags Now, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out. -The `epi_workflow` is contains everything necessary to produce the predictions from pre-processing, to the model, to post-processing operations performed. +The `epi_workflow` is contains everything necessary to produce the predictions from the pre-processing, to the model fitting, to post-processing operations performed. ```{r} arx_one_week_ahead$epi_workflow ``` -Let's walk through the pre-processing that was done. The easy way to get this is to use `extract_preprocessor()` on the `epi_workflow` as follows: +Let's walk through the pre-processing that was done. The easy way to obtain that is to use `extract_preprocessor()` on the `epi_workflow` as follows: ```{r} extract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow) ``` -Under Operations, we can see that the pre-processing operations in the order they were carried out were to lag the death and case rates by the stated lags (`step_epi_lag()`), lead the death rate by 5 days (`step_epi_ahead()`), remove rows containing any NAs for the predictors or outcomes, and finally the number of recent observations used in the training window were not restricted (as in `step_training_window()` `n_training = Inf`). So, more was done here in comparison to the flatline forecaster. In particular, we now have steps to lag each of the predictor variables as well as to remove any rows containing a NA for any of the variables that make an appearance in the model. +Under Operations, we can see the pre-processing operations in the order they are carried out. Firstly lag the death and case rates by the stated lags (`step_epi_lag()`), then lead the death rate by 5 days (`step_epi_ahead()`), remove the rows containing NAs in the predictors or outcomes, and finally, do not restrict of the number of recent observations used in the training window (as in `step_training_window()` `n_training = Inf`). More pre-processing is done here in comparison to the flatline forecaster. In particular, there are now steps to lag each the predictor variables as well as to remove any rows that contain a NA value. Next, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`. @@ -111,7 +111,7 @@ Next, let's have a brief look at the post-processing operations, which we can ea extract_frosting(arx_five_days_ahead_many_lags$epi_workflow) ``` -We can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates and lower bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster. +We can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates, and bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster. Let's now move on to examining the predictions themselves. @@ -149,9 +149,9 @@ ggplot(hist, aes(color = geo_value)) + theme(legend.position = "none") + labs(x = "", y = "Incident deaths per 100K\n inhabitants") ``` -You may have noticed that the above figure mirrors looks a lot like that for the flatline forecaster. The vertical black line marks the forecast date, the point beyond that is the prediction, and the band about that is the 90% prediction interval. So, nothing new there. The key difference is that here the predictions are not simply the last value each state pulled forward in time. In those shown here, there is more variability, more separation from the recent past, as we would expect to see in nature. +You may have noticed that the above figure mirrors that for the flatline forecaster. The vertical black line marks the forecast date. The point beyond that is the prediction and the band about it is the 90% prediction interval. In comparison to the flatline forecaster, the key difference is that these predictions are not simply the last values pulled forward in time. Rather, there's more variability, more separation from the recent past, as we would expect to see in nature. -Ok. That's for a single ahead that is not very far off from the forecast date, but how about when we look at the predictions for various aheads. What do we see then? +What we've explored so far is for for a single ahead that is not very far off from the forecast date, but what do we see when we look at the predictions for various aheads? Let's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results. @@ -193,7 +193,7 @@ ggplot(hist) + labs(x = "", y = "Incident deaths per 100K\n inhabitants") ``` -All three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it does align with the truth and there was a period of relative stability. Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model faired. The way we'll get the job done to make the death rate lines is to not impose an upper bound the data used in `hist` (so that we get all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021). +All three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it aligns with the truth (there was a period of relative stability). Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model fared. The way that we will extend the black death rate lines is to not impose an upper bound of the data used in `hist` (so that we use all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021). ```{r} #| fig-height: 5 @@ -218,11 +218,11 @@ ggplot(hist) + labs(x = "", y = "Incident deaths per 100K\n inhabitants") ``` -As our predictions get farther away from the forecast date, they don't seem unreasonable - sure they get increasingly questionable (as indicated by the larger prediction bands), but they are still not entirely unreasonable. Certainly they are more more sensible than the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is worthwhile for the future. And while we don't want to rule that out (it is possible), it is not usually something to base the future on; it is like saying that only what happened yesterday matters for today and for the rest of the month. +We can see that the predictions get increasingly questionable as they get farther away from the forecast date (as indicated by the larger prediction bands), but still they are not entirely unreasonable. Certainly they are more more sensible than those produced by the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two forecasters is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is indicative of the future. -It is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable the long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. So, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where we think the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the past leading up to it has been relatively stable and uneventful, then a basic ARX model trained on the most recent past will not capture the upcoming insanity. In that case, amendments should be made and another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling things like infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning. +It is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable its long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. That is, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the recent past has been stable and uneventful, then a basic ARX model trained solely on the most recent past will fail to capture the volatility. In that case, amendments should be made or another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning. -To wrap this up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. To do this, we'll make a dynamic chloropleth plot using `plotly`. +To wrap up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. We will construct a dynamic chloropleth plot using `plotly`. To prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`). @@ -233,8 +233,8 @@ all_the_states_df <- out_df %>% pivot_wider(names_from = tau, values_from = q) ``` -Remember the adapted "Customize choropleth code" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot)? Well all we got to do is make a few select changes to that code to get a slider bar so that we may see what happens over time for each state. The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). -That's all it takes. +We will base our code on that from the "Customize choropleth code" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot). The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). Making these changes will give us a slider bar so that we may see what happens over time for each state. + ```{r} #| fig-height: 1.75 @@ -276,10 +276,10 @@ fig <- fig %>% layout( fig ``` -You can either hit play in the above plot and sit back and watch what happens over time or you can manually slide the bar at the bottom across time and inspect the states of interest by hovering over them. +Now, you can either hit play in the above plot and watch what happens over time or you can manually slide the bar at the bottom and inspect the states by hovering over them. -A possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We'll leave this as an exercise to the reader that would like to take this opportunity to level up their skills. +One possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We will leave this extension as an exercise to the reader. ## What we've learned in a nutshell -While the ARX forecaster is a simple model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be a fantastic to have in your forecasting toolbox. +While the ARX forecaster is a simple and intuitive model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be fantastic to have in your forecasting toolbox. From bed7b749fd016500dbd0a787251b13522311e0ba Mon Sep 17 00:00:00 2001 From: rachlobay <42976509+rachlobay@users.noreply.github.com> Date: Tue, 5 Dec 2023 05:36:45 -0800 Subject: [PATCH 16/16] Caught minor typo --- _freeze/arx-forecaster/execute-results/html.json | 4 ++-- _freeze/tidymodels-regression-part2/execute-results/html.json | 4 ++-- arx-forecaster.qmd | 2 +- tidymodels-regression-part2.qmd | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/_freeze/arx-forecaster/execute-results/html.json b/_freeze/arx-forecaster/execute-results/html.json index 9d2c2d7..7b83bab 100644 --- a/_freeze/arx-forecaster/execute-results/html.json +++ b/_freeze/arx-forecaster/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "1d18061a6d66aa58a854e9c087388279", + "hash": "57f878867ee219af61fdc9b77a698ca5", "result": { - "markdown": "# Introducing the ARX forecaster\n\nThe built-in ARX forecaster is a direct forecasting approach used to estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nPreparing exogenous variables for input into an ARX model is not necessarily a simple task. For instance, it is fairly common to have to modify such variables to match the temporal resolution of the variable being forecasted upon. Additionally, there may be other considerations such as correlation or interactions between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will reserve further discussion of this for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). Hence, the output is a data frame of point (optionally interval) forecasts at a single unique horizon for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecasterm which contains a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our primary goal is to predict death rates one week ahead of the last date available for each state. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ coefficients are obtained from fitting a model to the training data.\n\nThe above formulation makes it clear that the `arx_forecaster` function must have a predictors parameter in addition to a parameter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. So the simplest way to use `arx_forecaster()` to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input a minimum of three arguments: the `epi_df` data, the outcome of `\"death_rate\"`, and the predictors that are based on `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation, the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the molded/pre-processed training data that is contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (since we only need to consider lags of `death_rate` to construct the predictors).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" and `lag_14_death_rate` is the value from \"2021-09-01\" in the raw `jhu` data. In this way, we can manually check that the model used the correct predictor data if we are so inclined.\n\nNow that we are clear on how the lags work, we can proceed from a basic AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nAs with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components: the metadata, the `epi_workflow`, and the tibble of predictions. From the summary, we can note that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days ahead of the forecast date is the default for the target date. And as we saw for the flatline forecaster, to change this you must change the ahead parameter in the additional arguments list, `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter to enumerate the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from the pre-processing, to the model fitting, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to obtain that is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see the pre-processing operations in the order they are carried out. Firstly lag the death and case rates by the stated lags (`step_epi_lag()`), then lead the death rate by 5 days (`step_epi_ahead()`), remove the rows containing NAs in the predictors or outcomes, and finally, do not restrict of the number of recent observations used in the training window (as in `step_training_window()` `n_training = Inf`). More pre-processing is done here in comparison to the flatline forecaster. In particular, there are now steps to lag each the predictor variables as well as to remove any rows that contain a NA value.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates, and bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors that for the flatline forecaster. The vertical black line marks the forecast date. The point beyond that is the prediction and the band about it is the 90% prediction interval. In comparison to the flatline forecaster, the key difference is that these predictions are not simply the last values pulled forward in time. Rather, there's more variability, more separation from the recent past, as we would expect to see in nature.\n\nWhat we've explored so far is for for a single ahead that is not very far off from the forecast date, but what do we see when we look at the predictions for various aheads?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_c0b32b43e54a1e4afd53477c4efe790f'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d() +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it aligns with the truth (there was a period of relative stability). Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model fared. The way that we will extend the black death rate lines is to not impose an upper bound of the data used in `hist` (so that we use all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_a81d6b7174c650bfed1401a0aeb31e70'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(alpha = .7) +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nWe can see that the predictions get increasingly questionable as they get farther away from the forecast date (as indicated by the larger prediction bands), but still they are not entirely unreasonable. Certainly they are more more sensible than those produced by the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two forecasters is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is indicative of the future.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable its long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. That is, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the recent past has been stable and uneventful, then a basic ARX model trained solely on the most recent past will fail to capture the volatility. In that case, amendments should be made or another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. We will construct a dynamic chloropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nWe will base our code on that from the \"Customize choropleth code\" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot). The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). Making these changes will give us a slider bar so that we may see what happens over time for each state. \n\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nNow, you can either hit play in the above plot and watch what happens over time or you can manually slide the bar at the bottom and inspect the states by hovering over them.\n\nOne possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We will leave this extension as an exercise to the reader.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple and intuitive model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be fantastic to have in your forecasting toolbox.\n", + "markdown": "# Introducing the ARX forecaster\n\nThe built-in ARX forecaster is a direct forecasting approach used to estimate a model for a particular target horizon. It is based upon the widely used autoregressive (AR) model, in which events in the future using a linear combination of events in the near past. An ARX model is an extension to the basic AR model where exogenous variables are included as predictors. Exogenous variables are incorporated as predictors into a forecasting model not because they are being predicted themselves, but because they add measurable value to it. So they are sometimes referred to as features or additional covariates. \n\n::: {.callout-note}\nPreparing exogenous variables for input into an ARX model is not necessarily a simple task. For instance, it is fairly common to have to modify such variables to match the temporal resolution of the variable being forecasted upon. Additionally, there may be other considerations such as correlation or interactions between the exogenous variables. Since these are endeavours in feature selection and/or engineering, we will reserve further discussion of this for its own chapter.\n:::\n\nSimilar to the flatline forecaster, prediction intervals based on the quantiles of the residuals of the training data are obtained separately for each combination of keys (most commonly by `geo_value`). Hence, the output is a data frame of point (optionally interval) forecasts at a single unique horizon for each unique combination of keys. The ARX forecaster (using quantile regression) is comparable to what the Delphi forecast team used for its COVID-19 forecasts over the course of the pandemic. \n\n## Example of using the ARX forecaster\n\n\n::: {.cell}\n\n:::\n\n\n### Load required packages\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-2_623477395faf9aaafb176ba4e3b9c817'}\n\n```{.r .cell-code}\nlibrary(tidyverse)\nlibrary(epipredict)\nlibrary(workflows)\nlibrary(plotly)\n```\n:::\n\n\n### A brief re-introduction to the dataset\n\nIn our guided example using the ARX forecaster, we'll use the same `case_death_rate_subset` dataset that we used to showcase the flatline forecasterm which contains a subset of COVID-19 cases and deaths for US states and territories. To keep our example simple, we will only consider the data from Sept. 1 to Dec. 1, 2021.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-3_5fe7a023d12cc5c1a1aa3b196c654006'}\n\n```{.r .cell-code}\njhu <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\") & time_value <= \"2021-12-01\")\n\njhu\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 5,152 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 5,152 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 al 2021-09-01 113. 0.845\n#> 3 ar 2021-09-01 68.5 0.919\n#> 4 as 2021-09-01 0 0 \n#> 5 az 2021-09-01 48.8 0.414\n#> 6 ca 2021-09-01 38.4 0.246\n#> # ℹ 5,146 more rows\n```\n:::\n:::\n\n\n### The basic mechanics of the ARX forecaster\n\nSuppose that our primary goal is to predict death rates one week ahead of the last date available for each state. Mathematically, on day $t$, we want to predict new deaths $y$ that are $h$ days ahead at many locations $j$ using the death rate from today, 1 week ago, and 2 weeks ago. So for each location, we'll predict\n\n$$\n\\hat{y}_{j,{t+h}} = \\mu + a_0y_{j, t} + a_7y_{j, t-7} + a_{14}y_{j, t-14}\n$$\n\nwhere $t$ is 2021-12-01, $h$ is 7 days, and $j$ is the state in our example. The $a_0$, $a_7$, and $a_14$ coefficients are obtained from fitting a model to the training data.\n\nThe above formulation makes it clear that the `arx_forecaster` function must have a predictors parameter in addition to a parameter for the data and the outcome. This is because there must be at least one predictor that is based on past values of the outcome. So the simplest way to use `arx_forecaster()` to predict the death rate one week into the future, is to create an AR-type model. And to do this, we must input a minimum of three arguments: the `epi_df` data, the outcome of `\"death_rate\"`, and the predictors that are based on `\"death_rate\"`. As we can see in the above equation and from the `arx_args_list()` documentation, the default number of lags used for the predictors are 0, 7, and 14 days. In other words, what this forecaster aims to do is to predict the outcome (`death_rate`) one week ahead based on the predictor (`death_rate`) values from today, 1 week ago and 2 weeks ago.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-4_147a7744c4dfdacf6cee84849c167e75'}\n\n```{.r .cell-code}\nar_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = \"death_rate\")\nar_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:15\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nTo make sure we understand exactly how the predictors were created from the training data (lags and all), we can compare the molded/pre-processed training data that is contained in `one_week_ahead$epi_workflow$pre` to the raw training data.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-5_af8a1090e69c5be0b80ebc9b6c780f55'}\n\n```{.r .cell-code}\ncbind(\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$geo_value,\n ar_one_week_ahead$epi_workflow$pre$mold$extras$roles$time_value,\n ar_one_week_ahead$epi_workflow$pre$mold$predictors\n) %>%\n head()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> geo_value time_value lag_0_death_rate lag_7_death_rate lag_14_death_rate\n#> 1 ak 2021-09-15 0.2371631 0.1383451 0.1976359\n#> 2 al 2021-09-15 0.8591982 0.5718312 0.8446847\n#> 3 ar 2021-09-15 1.0370679 0.8155125 0.9192193\n#> 4 as 2021-09-15 0.0000000 0.0000000 0.0000000\n#> 5 az 2021-09-15 0.4889335 0.4350353 0.4138610\n#> 6 ca 2021-09-15 0.3450947 0.2565530 0.2456668\n```\n:::\n:::\n\n\nNow, let's just focus on the first row for `ak` and filter the corresponding raw data for that `geo_value` and any dates before the `time_value` given (since we only need to consider lags of `death_rate` to construct the predictors).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-6_2a950523774f34e286b5a9ebe9a31ed7'}\n\n```{.r .cell-code}\njhu %>% filter(geo_value == \"ak\" & time_value <= \"2021-09-15\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 15 x 4 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 15 × 4\n#> geo_value time_value case_rate death_rate\n#> * \n#> 1 ak 2021-09-01 75.3 0.198\n#> 2 ak 2021-09-02 74.9 0.198\n#> 3 ak 2021-09-03 75.8 0.198\n#> 4 ak 2021-09-04 75.8 0.198\n#> 5 ak 2021-09-05 75.8 0.198\n#> 6 ak 2021-09-06 53.5 0.198\n#> # ℹ 9 more rows\n```\n:::\n:::\n\n\nWe can then check whether the predictor values from the pre-processed data have been correctly taken from the raw data. For example, the `lag_0_death_rate` should be the `death_rate` on the `time_value` of 2021-09-15 for `ak` in the raw data. And indeed it is. Similarly, we can confirm that the `lag_7_death_rate` is the value from \"2021-09-08\" and `lag_14_death_rate` is the value from \"2021-09-01\" in the raw `jhu` data. In this way, we can manually check that the model used the correct predictor data if we are so inclined.\n\nNow that we are clear on how the lags work, we can proceed from a basic AR model to an ARX model by adding additional predictors (for any additional time-varying covariates that are being treated as exogenous variables).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-7_0d5bbaf45522cdd3138129509a66623d'}\n\n```{.r .cell-code}\narx_one_week_ahead <- arx_forecaster(jhu, outcome = \"death_rate\", predictors = c(\"death_rate\", \"case_rate\"))\narx_one_week_ahead\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:16\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-08.\n```\n:::\n:::\n\n\nAs with the flatline model, the result is an S3 object that by default outputs a short summary of the training data and the predictions. The object itself contains three components: the metadata, the `epi_workflow`, and the tibble of predictions. From the summary, we can note that the predictions are for the target date of Dec. 8, 2021, which is 7 days after the Dec. 1, 2021 forecast date (aka. the date on which the forecast was made). This implies that the 7 days ahead of the forecast date is the default for the target date. And as we saw for the flatline forecaster, to change this you must change the ahead parameter in the additional arguments list, `arx_args_list()`. If you look at the help file for that function, you will see that the key difference between this list and that for the flatline forecaster is that here there's a lags parameter to enumerate the lags for predictors in autoregressive-type models. And we can tailor the number of lags to the predictor. For some practice, we'll change the lags argument for each of our `case_rate` and `death_rate` predictors as well as the ahead value to 5 days.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-8_f5e8fd1f8809abb139cb9459c7545788'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags <- arx_forecaster(\n jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(\n case_rate = c(0, 1:7, 14, 21),\n death_rate = c(0, 7, 14, 21)\n ),\n ahead = 5L\n )\n)\narx_five_days_ahead_many_lags\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> ══ A basic forecaster of type ARX Forecaster ════════════════════════════════\n#> \n#> This forecaster was fit on 2023-07-10 03:34:18\n#> \n#> Training data was an `epi_df` with\n#> • Geography: state,\n#> • Time type: day,\n#> • Using data up-to-date as of: 2022-05-31 12:08:25.\n#> \n#> ── Predictions ──────────────────────────────────────────────────────────────\n#> \n#> A total of 56 predictions are available for\n#> • 56 unique geographic regions,\n#> • At forecast dates: 2021-12-01,\n#> • For target dates: 2021-12-06.\n```\n:::\n:::\n\n\nNow, instead of just inspecting the summary, we'll go a little deeper this time around and look into the `epi_workflow` as well as the pre-processing and post-processing operations that were carried out.\n\nThe `epi_workflow` is contains everything necessary to produce the predictions from the pre-processing, to the model fitting, to post-processing operations performed.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-9_0b4e1234cfbfe653d287df55b7235dba'}\n\n```{.r .cell-code}\narx_one_week_ahead$epi_workflow\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Epi Workflow [trained] ═══════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> Postprocessor: Frosting\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 6 Recipe Steps\n#> \n#> • step_epi_lag()\n#> • step_epi_lag()\n#> • step_epi_ahead()\n#> • step_naomit()\n#> • step_naomit()\n#> • step_training_window()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) lag_0_death_rate lag_7_death_rate lag_14_death_rate \n#> -0.013924 0.116500 0.124025 0.276121 \n#> lag_0_case_rate lag_7_case_rate lag_14_case_rate \n#> 0.001310 0.002376 0.002590 \n#> \n#> ── Postprocessor ────────────────────────────────────────────────────────────\n#> 5 Frosting Layers\n#> \n#> • layer_predict()\n#> • layer_residual_quantiles()\n#> • layer_add_forecast_date()\n#> • layer_add_target_date()\n#> • layer_threshold()\n```\n:::\n:::\n\nLet's walk through the pre-processing that was done. The easy way to obtain that is to use `extract_preprocessor()` on the `epi_workflow` as follows:\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-10_0b752978a9fa400bd48fcde4ef889043'}\n\n```{.r .cell-code}\nextract_preprocessor(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nUnder Operations, we can see the pre-processing operations in the order they are carried out. Firstly lag the death and case rates by the stated lags (`step_epi_lag()`), then lead the death rate by 5 days (`step_epi_ahead()`), remove the rows containing NAs in the predictors or outcomes, and finally, do not restrict of the number of recent observations used in the training window (as in `step_training_window()` `n_training = Inf`). More pre-processing is done here in comparison to the flatline forecaster. In particular, there are now steps to lag each the predictor variables as well as to remove any rows that contain a NA value.\n\nNext, let's have a brief look at the post-processing operations, which we can easily extract by using the `extract_frosting()` function on the `epi_workflow`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-11_19fe9ee9fd4c52ba5b6819d40d2f2fc9'}\n\n```{.r .cell-code}\nextract_frosting(arx_five_days_ahead_many_lags$epi_workflow)\n```\n:::\n\n\nWe can see that the post-processing operations were to create the predictions and the corresponding 90% prediction intervals, add the forecast and target dates, and bound the predictions at zero. You may note that what was done here is the same as for the flatline forecaster.\n\nLet's now move on to examining the predictions themselves. \n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-12_060c4ae8b2ccd4d360ab866849bbb229'}\n\n```{.r .cell-code}\narx_five_days_ahead_many_lags$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0.605 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 2 al 0.223 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 3 ar 0.271 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 4 as 0 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 5 az 0.513 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> 6 ca 0.167 [0.05, 0.95] 2021-12-01 2021-12-06 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nFor the target date of Dec. 6, 2021 (which is five days ahead of the forecast date), there is one prediction for the death rate per 100K inhabitants along with a 90% prediction interval for every state (`geo_value`). \n\nThe following figure shows the prediction and prediction interval for three sample states: Arizona, New York, and Florida.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-13_14925cac5b2ec36081d652fac4d1678c'}\n\n```{.r .cell-code code-fold=\"true\"}\nsamp_geos <- c(\"az\", \"ny\", \"fl\")\n\nhist <- jhu %>%\n filter(geo_value %in% samp_geos)\n\npreds <- arx_five_days_ahead_many_lags$predictions %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist, aes(color = geo_value)) +\n geom_line(aes(time_value, death_rate)) +\n theme_bw() +\n geom_errorbar(data = preds, aes(x = target_date, ymin = `0.05`, ymax = `0.95`)) +\n geom_point(data = preds, aes(target_date, .pred)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(name = \"\") +\n scale_x_date(date_labels = \"%b %Y\", date_breaks = \"1 month\") +\n facet_grid(geo_value ~ ., scales = \"free_y\") +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-13-1.svg){fig-align='center' width=90%}\n:::\n:::\n\nYou may have noticed that the above figure mirrors that for the flatline forecaster. The vertical black line marks the forecast date. The point beyond that is the prediction and the band about it is the 90% prediction interval. In comparison to the flatline forecaster, the key difference is that these predictions are not simply the last values pulled forward in time. Rather, there's more variability, more separation from the recent past, as we would expect to see in nature.\n\nWhat we've explored so far is for for a single ahead that is not very far off from the forecast date, but what do we see when we look at the predictions for various aheads?\n\nLet's create predictions (and prediction intervals) for each of 1 to 28 days beyond the forecast date. To do this, we'll again use `map()` from `purrr` to apply the forecaster to each ahead value and then row bind the list of results.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-14_c408ebd61678f136c401348dd3ac2753'}\n\n```{.r .cell-code}\n# Multiple predictions\nout_df <- map(1:28, ~ arx_forecaster(\n epi_data = jhu,\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(ahead = .x)\n)$predictions) %>%\n list_rbind()\n```\n:::\n\n\nThen, we can recycle the code we used to produce the plot for one forecast - the only difference being that we'll use `out_df` in place of `arx_five_days_ahead_many_lags$predictions`.\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-15_c0b32b43e54a1e4afd53477c4efe790f'}\n\n```{.r .cell-code code-fold=\"true\"}\npreds <- out_df %>%\n filter(geo_value %in% samp_geos) %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d() +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-15-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nAll three bear a striking resemblance to what we'd expect when using the flatline forecaster. So, our simple ARX model either failed to capture the rise or fall in death rates or it aligns with the truth (there was a period of relative stability). Since we have the true number of deaths over the prediction period in the `case_death_rate_subset` data, let's go ahead and overlay them on our plot to see for ourselves how our model fared. The way that we will extend the black death rate lines is to not impose an upper bound of the data used in `hist` (so that we use all data available from our Sept. 2, 2021 start until the last date of Dec. 31, 2021).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-16_a81d6b7174c650bfed1401a0aeb31e70'}\n\n```{.r .cell-code code-fold=\"true\"}\nhist <- case_death_rate_subset %>%\n dplyr::filter(time_value >= as.Date(\"2021-09-01\")) %>% # No ub so we get up to the last date of Dec. 31, 2021\n filter(geo_value %in% samp_geos)\n\nggplot(hist) +\n geom_line(aes(time_value, death_rate)) +\n geom_ribbon(\n data = preds,\n aes(x = target_date, ymin = `0.05`, ymax = `0.95`, fill = geo_value)\n ) +\n geom_point(data = preds, aes(target_date, .pred, colour = geo_value)) +\n geom_vline(data = preds, aes(xintercept = forecast_date)) +\n scale_colour_viridis_d(alpha = .7) +\n scale_fill_viridis_d(alpha = .4) +\n scale_x_date(date_labels = \"%b %Y\") +\n facet_grid(rows = vars(geo_value)) +\n theme(legend.position = \"none\") +\n labs(x = \"\", y = \"Incident deaths per 100K\\n inhabitants\")\n```\n\n::: {.cell-output-display}\n![](arx-forecaster_files/figure-html/unnamed-chunk-16-1.svg){fig-align='center' width=90%}\n:::\n:::\n\n\nWe can see that the predictions get increasingly questionable as they get farther away from the forecast date (as indicated by the larger prediction bands), but still they are not entirely unreasonable. Certainly they are more more sensible than those produced by the flatline forecaster (in which we simply propagated the last observation forward). The major philosophical difference between the two forecasters is that the ARX forecaster is built on the premise that the recent past is indicative of the future, whereas the flatline forecaster proceeds as though nothing but the single most recent instance is indicative of the future.\n\nIt is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable its long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. That is, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the recent past has been stable and uneventful, then a basic ARX model trained solely on the most recent past will fail to capture the volatility. In that case, amendments should be made or another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning.\n\nTo wrap up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. We will construct a dynamic choropleth plot using `plotly`.\n\nTo prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`).\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-17_948827f1ecc3c79eeb543c5245af8c45'}\n\n```{.r .cell-code}\nall_the_states_df <- out_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nWe will base our code on that from the \"Customize choropleth code\" that we introduced at the end of [Regression In Tidymodels - Part 2](tidymodels-regression-part2.qmd#sec-interactive-plot). The two key changes to make to that code are to convert the target dates vector to a character vector (to be compatible with `plotly`) and to specify that frame is based on `target_date` when initializing the plotly-geo object (in `plot_geo()`). Making these changes will give us a slider bar so that we may see what happens over time for each state. \n\n\n\n::: {.cell layout-align=\"center\" hash='arx-forecaster_cache/html/unnamed-chunk-18_178dd8cb9d789aee5a69f03d96f3a62f'}\n\n```{.r .cell-code code-fold=\"true\"}\n# Convert target dates to char\nall_the_states_df$target_date <- as.character(all_the_states_df$target_date)\n\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n# Initialize the plotly-geo object\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\", frame = ~target_date)\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"Predicted death rate (per 100,000) by state over time
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\n\nNow, you can either hit play in the above plot and watch what happens over time or you can manually slide the bar at the bottom and inspect the states by hovering over them.\n\nOne possible improvement to make to the above plot is to add the true death rates to it or to a similar plot that is positioned beside it. We will leave this extension as an exercise to the reader.\n\n## What we've learned in a nutshell\n\nWhile the ARX forecaster is a simple and intuitive model at it core, it is competitive with more complicated forecasters. So mastering the basics of this forecaster and equipping yourself with the knowledge to customize it can be fantastic to have in your forecasting toolbox.\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/_freeze/tidymodels-regression-part2/execute-results/html.json b/_freeze/tidymodels-regression-part2/execute-results/html.json index 8dbca08..d4ed6aa 100644 --- a/_freeze/tidymodels-regression-part2/execute-results/html.json +++ b/_freeze/tidymodels-regression-part2/execute-results/html.json @@ -1,7 +1,7 @@ { - "hash": "da179d0be521fc2c714a8839a67a92cb", + "hash": "d46b11b81cb12f35b6303e27958c7c23", "result": { - "markdown": "# Regression in Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021.\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_8e4a55d2cf5dd5462ea1ea929bd3f6f8'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg()\n```\n:::\n\n\nWe made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either.\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_bdf235a5206620fbc7d51847c37e572d'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow we may generate predictions for the dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\nTo get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting for a target date\n\nAt this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include.\n\nTo begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_3053fccd91b5661f92aa86d6087ee54c'}\n\n```{.r .cell-code}\nrec_spec_wlag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNext, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d001ce8805d69846f1eef56be8685456'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_wlag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAs a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_aa9511094763cc41fbd6d3b12835ccf8'}\n\n```{.r .cell-code}\nca_jan1_df <- data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last(ca_subset_wlag)$death_rate\n)\n```\n:::\n\n\nNotice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_2fe2f73c5a3dbe0b0f2478e7deba2ea6'}\n\n```{.r .cell-code}\n# Add new row of to ca_subset_wlag\nca_subset_wlag_jan1 <- bind_rows(\n ca_subset_wlag,\n ca_jan1_df\n)\n```\n:::\n\n\nAnd then input that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_0c8d22a80615f73c3899ca17a3d35f1d'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_wlag_jan1) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\nWonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options...\n\n### Option 1 - manually create our own `epi_recipe`\n\nIt is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_a96c7f12005fcc2817806330f5d3d081'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_wlag_jan1 %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nAs expected, we obtain the same prediction as when we used the first approach.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nThe `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_9739aad549f8766041f4db73dc9b21e6'}\n\n```{.r .cell-code}\nca_arx_jan_22 <- arx_forecaster(\n ca_subset_wlag_jan1 %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\nWe can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_f4989c3184965d788fd29f19a9611a30'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_wlag_jan1 %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state: \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nAwesome! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nNot bad for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", + "markdown": "# Regression in Tidymodels - Part 2\n\n\n::: {.cell}\n\n:::\n\n\n## Libraries and data\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-2_2c39d10eba215aedfac490542d500110'}\n\n```{.r .cell-code}\n# Load necessary packages\nlibrary(tidymodels)\nlibrary(plotly)\n```\n:::\n\n\nAs a follow-up to the [Regression in Tidymodels chapter](tidymodels-regression.qmd), we're going to look at how the functions we used to perform linear regression fare when applied to a small set of epidemiological time series data. We'll be working with the built-in JHU data on daily confirmed COVID-19 case and death rates for California over Dec. 31, 2020 to Dec. 31, 2021.\n\nNote that while data is available for all states, we're focusing on just one state's worth of data to avoid having to manage multiple regions (panel data). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-3_285a3f7cc79d33f0328599de942fcaa4'}\n\n```{.r .cell-code}\n# Load and subset data\nca_case_death_rate_subset <- case_death_rate_subset %>%\n filter(geo_value == \"ca\")\n```\n:::\n\n\n## Simple linear regression\n\nOur goal for this exercise is to construct a simple linear regression model of daily death rate as a function of daily case rate. To do this, we'll apply the sequence of steps to build a model that we went through in the previous chapter (only in a different scenario). Thus, we'll opt for the same linear regression model specification. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-4_9d2c534c117001f34f0ffec4c97ca8ee'}\n::: {.cell-output-display}\n![](img/set_engine.png){fig-align='center' width=50%}\n:::\n:::\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-5_8e4a55d2cf5dd5462ea1ea929bd3f6f8'}\n\n```{.r .cell-code}\nlm_spec <- linear_reg()\n```\n:::\n\n\nWe made two simplifications to the linear regression model specification shown in the previous chapter. Firstly, setting the mode is unnecessary for linear regression, and, secondly, `lm` is the default engine for linear regression, so we do not have to include either.\n\nNow we fit our model by inputting the formula (of the form `y ~ x`) `death_rate ~ case_rate` and the `ca_case_death_rate_subset` into the `fit()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-6_bdf235a5206620fbc7d51847c37e572d'}\n\n```{.r .cell-code}\nca_lm_fit <- lm_spec %>%\n fit(death_rate ~ case_rate, data = ca_case_death_rate_subset)\nca_lm_fit\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> parsnip model object\n#> \n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate \n#> 0.158168 0.009175\n```\n:::\n:::\n\n\nAs before, let's use `purrr`’s `pluck()` function to access the underlying fit and then pipe that into `summary()` to get a basic synopsis of our model.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-7_c75b0213d815c274ab67c3fa1cb68811'}\n\n```{.r .cell-code}\nca_lm_fit %>%\n pluck(\"fit\") %>%\n summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> \n#> Call:\n#> stats::lm(formula = death_rate ~ case_rate, data = data)\n#> \n#> Residuals:\n#> Min 1Q Median 3Q Max \n#> -0.79039 -0.14212 -0.07560 0.02259 0.87239 \n#> \n#> Coefficients:\n#> Estimate Std. Error t value Pr(>|t|) \n#> (Intercept) 0.1581681 0.0213029 7.425 8.09e-13 ***\n#> case_rate 0.0091755 0.0006504 14.107 < 2e-16 ***\n#> ---\n#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1\n#> \n#> Residual standard error: 0.3021 on 364 degrees of freedom\n#> Multiple R-squared: 0.3535,\tAdjusted R-squared: 0.3517 \n#> F-statistic: 199 on 1 and 364 DF, p-value: < 2.2e-16\n```\n:::\n:::\n\n\nNow we may generate predictions for the dataset. \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-8_aa8fab980d307cfa71a1213383688695'}\n\n```{.r .cell-code}\npredict(ca_lm_fit, new_data = ca_case_death_rate_subset)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 1\n#> .pred\n#> \n#> 1 1.04\n#> 2 1.12\n#> 3 1.10\n#> 4 1.09\n#> 5 1.09\n#> 6 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\nTo get a side-by-side view of the observed and predicted values for an informal comparison, we'll use `augment()`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-9_a16c95fbd9e3ef41769d07e6f19f39e9'}\n\n```{.r .cell-code}\n# adjoin the model predictions to `ca_case_death_rate_subset`).\naugment(ca_lm_fit, new_data = ca_case_death_rate_subset) %>%\n select(death_rate, .pred)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 366 × 2\n#> death_rate .pred\n#> \n#> 1 0.751 1.04\n#> 2 0.850 1.12\n#> 3 0.857 1.10\n#> 4 0.860 1.09\n#> 5 0.911 1.09\n#> 6 0.908 1.09\n#> # ℹ 360 more rows\n```\n:::\n:::\n\n\nAll in all, everything that we did before seems to translate seamlessly over to handling this epidemiological time series data. But realistically, if we're tasked with predicting COVID-19 deaths, we do not only want to consider the concurrent case information. Since what happened in the past can inform us where things are heading, it is natural to include past case rates and death rates as predictors.\n\n## Adding lagged predictors and predicting for a target date\n\nAt this point, it is important to consider how far back in the past to look. More specifically, we should consider what past case and death rates are most predictive of current deaths. If you are interested, conducting a lagged correlation analysis as in the [Correlate signals over space and time chapter](correlations.qmd) is one way to start exploring this. We will not take that route because it ventures into model selection territory, which is beyond the scope of this article. Instead, we will take a more ad hoc approach for deciding what lagged predictors to include.\n\nTo begin, we will add predictors for the lagged 1-day death and case rates as those seem to be the most sensible choices (because it is reasonable to expect that yesterday is more predictive of today than two weeks ago).\n\nSo first, let's add a column for the lagged 1-day death rates by using `dplyr`'s `mutate()` function.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-10_a109c0cce6077fa034dfa6482d916f26'}\n\n```{.r .cell-code}\nca_subset_wlag <- ca_case_death_rate_subset %>%\n mutate(lag_1_death_rate = lag(death_rate, 1))\n```\n:::\n\n\nThen, we can create our recipe, adding a `lag_1_day_case_rate` column in the same way as we added a non-linear transformation of a predictor previously - by using `step_mutate()` on the predictor that's been specified in the recipe formula.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-11_3053fccd91b5661f92aa86d6087ee54c'}\n\n```{.r .cell-code}\nrec_spec_wlag <- recipe(death_rate ~ case_rate + lag_1_death_rate, data = ca_subset_wlag) %>%\n step_mutate(lag_1_case_rate = lag(case_rate, 1))\n```\n:::\n\n\nNext, we input the model and recipe into our workflow and then fit the model to our dataset in the same way as we did before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-12_d001ce8805d69846f1eef56be8685456'}\n\n```{.r .cell-code}\nlm_wf_lag <- workflow() %>%\n add_model(lm_spec) %>%\n add_recipe(rec_spec_wlag)\n\nca_lm_fit_lag <- lm_wf_lag %>% fit(ca_subset_wlag)\nca_lm_fit_lag\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> ══ Workflow [trained] ═══════════════════════════════════════════════════════\n#> Preprocessor: Recipe\n#> Model: linear_reg()\n#> \n#> ── Preprocessor ─────────────────────────────────────────────────────────────\n#> 1 Recipe Step\n#> \n#> • step_mutate()\n#> \n#> ── Model ────────────────────────────────────────────────────────────────────\n#> \n#> Call:\n#> stats::lm(formula = ..y ~ ., data = data)\n#> \n#> Coefficients:\n#> (Intercept) case_rate lag_1_death_rate lag_1_case_rate \n#> -0.0040422 0.0013087 0.9793506 -0.0008568\n```\n:::\n:::\n\n\nAs a result, we obtain a trained workflow that has undergone both pre-processing (`step_mutate` to add the 1-day lagged case rate as a predictor) and model fitting. \n\nNow, we'll use our model to predict the death rate for a day beyond the last in the dataset (so our target date is Jan. 1, 2022). Suppose that a reliable source tells us that the case rate for that day is 84.7 (cases per 100,000 population). From the last row of our dataset, we can see that the lagged 1-day case rate is about 84.4 and the lagged death rate is about 0.142 (deaths per 100,000 population). We'll put this information in a short dataframe:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-13_aa9511094763cc41fbd6d3b12835ccf8'}\n\n```{.r .cell-code}\nca_jan1_df <- data.frame(\n geo_value = \"ca\",\n time_value = as.Date(\"2022-01-01\"),\n case_rate = 84.7,\n lag_1_death_rate = last(ca_subset_wlag)$death_rate\n)\n```\n:::\n\n\nNotice that we included `lag_1_death_rate`, but no `lag_1_case_rate` in the above dataframe. The reason for this is that there is `lag_1_death_rate` in the `ca_subset_wlag` dataset that we used to construct the recipe. So the recipe expects that variable. In contrast, we used `step_mutate` to dynamically add the lagged case rate variable as a predictor. It was not part of the original recipe specification. This means that we do not want to designate a variable `lag_1_case_rate`, rather we just need enough rows of data in `new_data` so that when it undergoes the pre-processing step, that step can reach back to grab the lagged 1-day case rate from the `case_rate` variable. The easy way to ensure this can happen is to append `jan_1_df` to `ca_subset_wlag` using `bind_rows()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-14_2fe2f73c5a3dbe0b0f2478e7deba2ea6'}\n\n```{.r .cell-code}\n# Add new row of to ca_subset_wlag\nca_subset_wlag_jan1 <- bind_rows(\n ca_subset_wlag,\n ca_jan1_df\n)\n```\n:::\n\n\nAnd then input that into predict...\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-15_0c8d22a80615f73c3899ca17a3d35f1d'}\n\n```{.r .cell-code}\npredict(ca_lm_fit_lag, new_data = ca_subset_wlag_jan1) %>%\n tail(n = 1)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 1\n#> .pred\n#> \n#> 1 0.173\n```\n:::\n:::\n\nWonderful. We've successfully obtained a prediction. But it was a lot of work to to force recipes work with such data. How can we simplify things for ourselves? Well `epipredict` offers two clear options...\n\n### Option 1 - manually create our own `epi_recipe`\n\nIt is more advantageous to use an `epi_recipe` than a `recipe` on an `epi_df` because it unlocks a number of features specific to epidemiological data such as tailored pre-processing steps like creating columns of lagged data. So, instead of using the `mutate()` and `step_mutate()` combination to get the lagged case and death rate variables, we can write the following where we use `step_epi_lag` to lag the predictors and specify how far ahead we want to predict the outcome using `step_epi_ahead`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-16_e2a37e8f587941899cfb661c9593a47a'}\n\n```{.r .cell-code}\nca_epi_r <- epi_recipe(ca_case_death_rate_subset) %>%\n step_epi_lag(case_rate, lag = c(0, 1)) %>%\n step_epi_lag(death_rate, lag = 1) %>%\n step_epi_ahead(death_rate, ahead = 0)\n```\n:::\n\n\nThen, input the `epi_recipe` into an `epi_workflow()`, fit the linear model, and predict in the same way as before.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-17_a96c7f12005fcc2817806330f5d3d081'}\n\n```{.r .cell-code}\nca_epi_wf <- epi_workflow(ca_epi_r, lm_spec) %>%\n fit(ca_case_death_rate_subset)\n\npredict(ca_epi_wf, ca_subset_wlag_jan1 %>% select(-lag_1_death_rate)) %>%\n filter(time_value == \"2022-01-01\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> An `epi_df` object, 1 x 3 with metadata:\n#> * geo_type = state\n#> * time_type = day\n#> * as_of = 2022-05-31 12:08:25.791826\n#> \n#> # A tibble: 1 × 3\n#> geo_value time_value .pred\n#> * \n#> 1 ca 2022-01-01 0.173\n```\n:::\n:::\n\n\nAs expected, we obtain the same prediction as when we used the first approach.\n\n### Option 2 - let the `arx_forecaster()` do the work for us\n\nThe `epipredict` package has the `arx_forecaster()` function that pre-processes, trains the model, predicts, and performs some basic post-processing all in one go. The reason why we can use this model is that the task of predicting the death rate for one day ahead using the lagged 1-day death and case rates is a type of autoregressive (AR) model (in which a linear combination of previous values are use forecast the variable of interest). \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-18_9739aad549f8766041f4db73dc9b21e6'}\n\n```{.r .cell-code}\nca_arx_jan_22 <- arx_forecaster(\n ca_subset_wlag_jan1 %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"death_rate\", \"case_rate\"),\n args_list = arx_args_list(\n lags = list(death_rate = c(1), case_rate = c(0, 1)),\n ahead = 0L\n )\n)\nca_arx_jan_22$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.173 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\nWe can easily add more lags for the case and death rates into the function. All that we must do is add a couple of choice numbers to the `lags` argument. This is preferable to the (longwinded) alternative of adding them one by one to `step_mutate()`. So let's go ahead and try adding various lags for the case and death rates to `arx_forecaster()`:\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-19_f4989c3184965d788fd29f19a9611a30'}\n\n```{.r .cell-code}\nlots_of_lags_ca <- arx_forecaster(\n ca_subset_wlag_jan1 %>% select(-lag_1_death_rate),\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(case_rate = c(0, 1, 2, 3, 4, 7), death_rate = c(1, 2, 3, 4, 7)),\n ahead = 0L\n )\n)\nlots_of_lags_ca$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 1 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ca 0.106 [0.05, 0.95] 2022-01-01 2022-01-01\n```\n:::\n:::\n\n\nThe other major benefit of the forecaster is that it is equipped to handle panel data. This means that we could input several other states worth of data, and get a prediction for each state. For example, we can try plugging in the entirety of the original `case_death_rate_subset` and get a prediction of the death rate on Jan. 1, 2022 for each state: \n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-20_d6fbfbec04c3b860c6788bbf25e7b600'}\n\n```{.r .cell-code}\nall_the_states <- arx_forecaster(\n case_death_rate_subset,\n outcome = \"death_rate\",\n predictors = c(\"case_rate\", \"death_rate\"),\n args_list = arx_args_list(\n lags = list(c(0, 1, 2, 3, 4, 7), c(1, 2, 3, 4, 7)),\n ahead = 1L\n )\n)\nall_the_states$predictions\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n#> # A tibble: 56 × 5\n#> geo_value .pred .pred_distn forecast_date target_date\n#> \n#> 1 ak 0 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 2 al 0.197 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 3 ar 0.513 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 4 as 0.00896 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 5 az 0.603 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> 6 ca 0.192 [0.05, 0.95] 2021-12-31 2022-01-01 \n#> # ℹ 50 more rows\n```\n:::\n:::\n\n\nAwesome! We'll learn more about this and other forecasters in later chapters.\n\n## Interactive plot of predictions {#sec-interactive-plot}\n\nLet's finish off by producing an interactive `plotly` choropleth map of our above predictions (along with the 90% predictive intervals) to get a sense of how they may be geospatially related.\n\nFirst we'll ready our data. The key part is the extraction of the quantiles that make up the 90% predictive intervals. These are by default contained inside a distribution (`.pred_distn`) which we must unnest to get to.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-21_fab146b9a2df02676de7ded1301578cd'}\n\n```{.r .cell-code}\n# Rename df of predictions to shorten up\nall_the_states_df <- all_the_states$predictions\n\n# Extract nested quantiles\nall_the_states_df <- all_the_states_df %>%\n mutate(q = nested_quantiles(.pred_distn)) %>%\n unnest(q) %>%\n pivot_wider(names_from = tau, values_from = q)\n```\n:::\n\n\nThen, we adapted the \"Customize choropleth code\" from the [plotly website](https://plotly.com/r/choropleth-maps/) to our data. The two major changes we made are that we specified the text we would like to reveal when we hover (the predictions and the corresponding 90% predictive interval) and we modified the trace so that the predictions determine the colour of the state and the locations are based on the state abbreviations in `geo_value`.\n\n\n::: {.cell layout-align=\"center\" hash='tidymodels-regression-part2_cache/html/unnamed-chunk-22_39e447856a7ca6e1873a7e60b6edba78'}\n\n```{.r .cell-code code-fold=\"true\"}\n# See on hover\nall_the_states_df$hover <- with(\n all_the_states_df,\n paste(\n toupper(geo_value), \"
    \",\n \"Pred death rate:\", round(.pred, digits = 3), \"
    \",\n \"90% pred distn:\", paste(round(`0.05`, digits = 3),\n round(`0.95`, digits = 3),\n sep = \", \"\n )\n )\n)\n\n# Give state boundaries a white border\nl <- list(color = toRGB(\"white\"), width = 2)\n\n# Specify some map projection/options\ng <- list(\n scope = \"usa\",\n projection = list(type = \"albers usa\"),\n showlakes = TRUE,\n lakecolor = toRGB(\"white\")\n)\n\nfig <- plot_geo(all_the_states_df, locationmode = \"USA-states\")\nfig <- fig %>% add_trace(\n z = ~.pred, text = ~hover, hoverinfo = \"text\", locations = ~ toupper(geo_value),\n color = ~.pred, colors = \"Purples\"\n)\n\n# Add titles and such\nfig <- fig %>% colorbar(title = \"Death rate\")\nfig <- fig %>% layout(\n title = \"2022-01-01 predicted death rate (per 100,000) by state
    (Hover for breakdown)\",\n geo = g\n)\n\nfig\n```\n\n::: {.cell-output-display}\n```{=html}\n
    \n\n```\n:::\n:::\n\nNot bad for a quick adaptation of existing `plotly` code. \n\nAt this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out.\n\nFinally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another choropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own.\n\n## Attribution\n\nThis vignette was largely adapted from [Chapter 3 of ISLR tidymodels labs](https://emilhvitfeldt.github.io/ISLR-tidymodels-labs/03-linear-regression.html). \n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/arx-forecaster.qmd b/arx-forecaster.qmd index fb90af3..dd6b2bc 100644 --- a/arx-forecaster.qmd +++ b/arx-forecaster.qmd @@ -222,7 +222,7 @@ We can see that the predictions get increasingly questionable as they get farthe It is clear that the ARX forecaster is almost always more justifiable than the flatline forecaster to make farther-reaching predictions. And yet, however reasonable its long-term forecasts can seem, we should be careful to not overreach and make major long term predictions with a model that only uses data from the recent past. Such predictions have little to no practical value. That is, in general, the ARX forecaster is more suited for short-term forecasts than for long-term forecasts and for instances where the future is well-represented by the past. For instance, if we expect there to be a period of major volatility coming up, but the recent past has been stable and uneventful, then a basic ARX model trained solely on the most recent past will fail to capture the volatility. In that case, amendments should be made or another model should be tried (though it may be hard to construct a good predictive model even in the best of such circumstances - in some cases it may be like trying to predict the unpredictable). This is an ever-present danger when modelling infectious diseases where there can be an explosion of cases or deaths rapidly and without much warning. -To wrap up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. We will construct a dynamic chloropleth plot using `plotly`. +To wrap up this discussion, let's visually inspect how our predictions change over time and how they may be geospatially related. We will construct a dynamic choropleth plot using `plotly`. To prepare the data, we must extract the quantiles that make up the 90% predictive intervals (nested inside `.pred_distn`). diff --git a/tidymodels-regression-part2.qmd b/tidymodels-regression-part2.qmd index a97a033..8cea280 100644 --- a/tidymodels-regression-part2.qmd +++ b/tidymodels-regression-part2.qmd @@ -260,7 +260,7 @@ Not bad for a quick adaptation of existing `plotly` code. At this point, it is good to do your own sanity check to make sure that the prediction values shown on the plot match up to those shown in the output (`all_the_states$predictions`) for each state. From our quick inspection, that checks out. -Finally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another chloropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own. +Finally, it's good to consider what modifications we could make to improve the plot. For instance, if we had the true death rates, then we could show them on the same or on another choropleth map that's side-by-side to the one with the predictions. We'll leave it to the reader to try implementing such extensions on their own. ## Attribution