diff --git a/.Rproj.user/shared/notebooks/paths b/.Rproj.user/shared/notebooks/paths
index 386675d..e8a43b6 100644
--- a/.Rproj.user/shared/notebooks/paths
+++ b/.Rproj.user/shared/notebooks/paths
@@ -1,7 +1,7 @@
-C:/Users/advai/OneDrive/Desktop/DACSS/DACSS601Fall21/_posts/2021-09-29-reading-in-data-hw2/Reading_in_data_HW2.Rmd="893A94FE"
-C:/Users/advai/OneDrive/Desktop/DACSS/DACSS601Fall21/_posts/2021-09-30-hw2-allyson-beach/hw2-allyson-beach.Rmd="A735AE2F"
-C:/Users/advai/OneDrive/Desktop/DACSS/DACSS601Fall21/_posts/2021-10-01-hw3-allyson-beach/hw3-allyson-beach.Rmd="733A13CC"
-C:/Users/advai/OneDrive/Desktop/DACSS/DACSS601Fall21/_posts/2021-10-04-hw3-continued-allyson-beach/hw3-continued-allyson-beach.Rmd="20190822"
-C:/Users/advai/OneDrive/Desktop/DACSS/DACSS601Fall21/_posts/2021-10-04-hw3-data-wrangling/hw3-data-wrangling.Rmd="A5D2EB0E"
-C:/Users/advai/OneDrive/Desktop/DACSS/DACSS601Fall21/_posts/2021-10-05-hw3-blog-georges/hw3-blog-georges.Rmd="B0313095"
-C:/Users/advai/OneDrive/Desktop/DACSS/DACSS601Fall21/index.Rmd="F5445BD0"
+/Users/mollyhackbarth/Desktop/Desktop/Graduate School/DACSS 601/Github Projects/DACSS601Fall21/.gitignore="8386CEFF"
+/Users/mollyhackbarth/Desktop/Desktop/Graduate School/DACSS 601/Github Projects/DACSS601Fall21/_data/FedFundsRate.csv="ED4DCDFC"
+/Users/mollyhackbarth/Desktop/Desktop/Graduate School/DACSS 601/Github Projects/DACSS601Fall21/_data/birds.csv="80DA6F1E"
+/Users/mollyhackbarth/Desktop/Desktop/Graduate School/DACSS 601/Github Projects/DACSS601Fall21/_posts/2021-10-01-the-pivot-challenge-molly-hackbarth/the-pivot-challenge.Rmd="121D3EDA"
+/Users/mollyhackbarth/Desktop/Desktop/Graduate School/DACSS 601/Github Projects/DACSS601Fall21/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4.Rmd="A43FA6C0"
+/Users/mollyhackbarth/Desktop/Desktop/Graduate School/DACSS 601/Github Projects/DACSS601Fall21/_posts/2021-10-14-homework-5-molly-hackbarth /homework-5.Rmd="21DB110D"
+/Users/mollyhackbarth/Desktop/Desktop/Graduate School/DACSS 601/Github Projects/testrepo/Final Project - Draft.Rmd="D572D65D"
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4.Rmd b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4.Rmd
new file mode 100644
index 0000000..1b6fd38
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4.Rmd
@@ -0,0 +1,356 @@
+---
+title: "Homework 4"
+description: |
+ Working on univariate statistics with cereal and debt in trillions.
+author: Molly Hackbarth
+date: 10-05-2021
+output:
+ distill::distill_article:
+ self_contained: false
+ toc: true
+draft: true
+---
+
+
+```{r setup}
+knitr::opts_chunk$set(layout = "l-body-outset", echo = TRUE)
+library(tidyverse)
+library(here)
+library(readxl)
+library(stringr)
+library(rmarkdown)
+library(readr)
+library(knitr)
+library(DT)
+library(patchwork)
+library(zoo)
+```
+
+# Introduction
+
+For this homework assignment I plan to work with three different types of data sets. Below I will read in the data sets. This time instead of putting layout="l-body-outset" I put that in the setup as a opts_chunk$set function.
+
+## Cleaning the data
+
+I will first clean data that is needed to be cleaned. I had previously cleaned the debt in trillions so below you will find my work and how I did it.
+
+### Cereal data
+
+```{r reading in cereal}
+
+cereal <- read_csv(here("_data", "cereal.csv"))
+
+datatable(cereal, options = list(
+ initComplete = JS(
+ "function(settings, json) {",
+ "$(this.api().table().header()).css({'background-color': '#000', 'color': '#fff'});",
+ "}"), caption = 'Cereal',
+ width = '100%', options = list(scrollX = TRUE)))
+
+```
+
+### Debt in Trillions
+
+```{r reading in debt in trillions}
+dt <- read_excel(here("_data", "debt_in_trillions.xlsx"))
+
+dt <- rename(dt, "year_and_quarter" = "Year and Quarter",
+ "herevolving" = "HE Revolving",
+ "autoloan" = "Auto Loan",
+ "creditcard" = "Credit Card",
+ "studentloan" = "Student Loan",) %>%
+ select(!starts_with("total"))
+
+# I changed the rest of the names to lowercase but it doesn't have to be done.
+# I just prefer to not have to press the shift key when typing if I can avoid it.
+ colnames(dt)<-tolower(colnames(dt))
+
+dt <- dt %>%
+separate(year_and_quarter, into = c("year", "quarter"), sep=":")
+dt <- transform(dt, year = as.numeric(year))
+
+# This is adding 2000 so that the years will be in the 2000s-2010s
+ dt$year <- dt$year+2000
+
+# Needed to change mortgage to a numeric form, it was originally a character form.
+ dt$mortgage <- as.numeric(dt$mortgage)
+
+datatable(dt, options = list(
+ initComplete = JS(
+ "function(settings, json) {",
+ "$(this.api().table().header()).css({'background-color': '#000', 'color': '#fff'});",
+ "}"),
+ caption = 'Debt in Trillions',
+ width = '100%', options = list(scrollX = TRUE)))
+```
+
+
+## Picking variables
+
+All variables were picked from the data sets we were provided. There are no missing values.
+
+### Picking variables for Cereal
+
+For variables I'm going to focus on the sugar and sodium columns and compare them based on the different cereals.
+
+### Picking variables for Debt in trillions
+
+For debt in trillions I want to focus on the type of debt and how it fluctuates by year and quarter.
+
+
+## Descriptive Statstics
+
+### Cereal descprtive stastics
+
+First lets look at descriptive statics of sodium and and sugar.
+
+```{r cereal visual statstics}
+summarize_all(cereal, list(mean=mean, median=median, mean=mean, max=max, sd=sd, IQR=IQR ), na.rm=TRUE)
+
+summarize(cereal,quantile.sodium = quantile(Sodium, 0.25), quantile.sugar = quantile(Sugar, 0.75)
+ )
+
+summarise
+
+
+```
+
+For the sugar quartile I found that for the third quartile that 25% of the cereal had 12.5 of sugar or more.
+
+For the sodium quartile I found that for the first quartile that 25% of the cereal had 137.5 of sodium or less. For the standard deviation, the mean was 167 while the standard deviation was about 77.3. Only one data item, 340 was more than two standard deviations above the mean, and only one data item, 0 was more than two standard deviations below the mean.
+
+The fact that sodium is so much higher in sodium than sugar surprised me because of people mostly talking about how "sugary" cereals are. Sodium ranged from 0-340 grams compared to sugar's 0-18 grams.
+
+
+
+### Debt in trillions descrpitve statstics
+
+Now lets look at the descriptive statics for debt in trillions.
+
+```{r debt in trillions statstics}
+summarize_all(dt, list(mean=mean, median=median, mean=mean, max=max, sd=sd, IQR=IQR), na.rm=TRUE)
+
+```
+
+We can notice that because quarters is a character column it is returning NA.
+
+Here we can see some interesting statistics. If we look at all the means we have three that are relatively close in amount (from about .73-.91 ) two that are lower (.39-.52) other and he_revolving (I believe to be home equity revolving), and one that is way higher than any of them, mortgage at 8.41
+
+For other loans we don't know what loans are in the category, so it makes sense for it to be smaller than the major loans. he_revolving may be lower due to a much lower range of debt than the other loan types.
+
+However for mortgage the median is a much larger number. I believe this may because of how many people purchase homes and need to borrow money from the bank, unlike for the other types of loans. Usually these loans are much larger.
+
+Looking at the means for each of these categories the means seem to be on a similar path to the medians with all the categories being close to their median amount.
+
+## Visulazation
+
+Now that I've done some stastics I would like to see it in a visualized form. Below you will find both data sets broken out into different graphs.
+
+### Cereal
+
+For cereal I'm interested in seeing the sodium compared to sugar for each cereal brand.
+
+```{r cereal visual}
+
+p1 <- ggplot(cereal, aes(Cereal, Sodium)) +
+ geom_col() +
+ scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
+ theme(text=element_text(size=5))
+
+p2 <- ggplot(cereal, aes(Cereal, Sugar)) +
+ geom_col() +
+ scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
+ theme(text=element_text(size=5))
+
+p1 / p2
+```
+
+This gets me two separate graphs, however I'm more interested in having them on one graph. Additionally I noticed that the font had to be extremely small to fit the whole bar chart in with the names. This time I'll try using a legend.
+
+```{r cereal together visual}
+
+p3<- ggplot(cereal, aes(x=Sodium, y=Sugar, group=Cereal)) +
+ geom_col(aes(color=Cereal, position='dodge')) +
+ theme(legend.key.size = unit(.5, 'cm'))
+
+p4 <- ggplot(cereal, aes(fill=Cereal, y=Sugar, x=Sodium)) +
+ geom_bar(stat='identity', position='dodge') +
+ theme(legend.key.size = unit(.5, 'cm'))
+
+p3 | p4
+
+```
+
+This is closer to what I want but not exactly. This time I'm going to try to force sodium and sugar as the key with the cereal being on the chart.
+
+```{r cereal line chart visual}
+cereal1 <- cereal
+cereal1 <- cereal %>%
+ select(!starts_with("Type")) %>%
+ gather(key = Type, value = Amount, Sugar,Sodium)
+
+cereal1 %>%
+ggplot(aes(x=Cereal, y=Amount, group=Type, color=Type)) +
+ geom_line() +
+ geom_point() +
+ ggtitle("Cereal by amount of sodium vs sugar") +
+ scale_x_discrete(guide = guide_axis(n.dodge = 2), labels = function(x)
+ stringr::str_wrap(x, width = 10)) +
+ theme(text=element_text(size=9))
+
+
+```
+This is what I wanted! This allows you to see how sugar and sodium's amount compared to the cereal. As you can see sodium is much more drastically different compared to the sugar.
+
+### Debt in trillions
+
+With what I learned about plotting in Cereal, I'm going to focus on trying to make tables here.
+
+```{r debt in trillions visual}
+dt1 <- dt %>%
+ gather(key = debt, value = totaldebt, mortgage:other)
+
+p5 <- ggplot(dt1, aes(year, totaldebt, fill = debt)) +
+ geom_col(position = "dodge")
+
+p6 <- ggplot(dt1, aes(quarter, totaldebt, fill = debt)) +
+ geom_col(position = "dodge")
+
+p5 / p6 + plot_layout(guides = "collect") + plot_annotation(
+ title = "Total debt by year and quarter")
+
+p7 <- ggplot(dt, aes(year, creditcard)) +
+ geom_col(position = "dodge")
+
+p8 <- ggplot(dt, aes(year, mortgage)) +
+ geom_col(position = "dodge")
+
+p9 <- ggplot(dt, aes(year, herevolving)) +
+ geom_col(position = "dodge")
+
+p10 <- ggplot(dt, aes(year, autoloan)) +
+ geom_col(position = "dodge")
+
+
+p11 <- ggplot(dt, aes(year, studentloan)) +
+ geom_col(position = "dodge")
+
+p12 <- ggplot(dt, aes(year, other)) +
+ geom_col(position = "dodge")
+
+p7+p8+p9+p10+p11+p12+plot_layout(ncol = 3) + plot_annotation(
+ title = "Different debt in trillions",
+ caption = "by credit card, mortgage,
+ he revolving, auto loan, student loan, other"
+)
+```
+From the different types of debt you can see that each debt has it's own graph, while student loan seems to always go up compared to he revolving going down after 2010, the rest seemed to have a dip between 2010-2015.
+
+For overall mortgage was by far the largest amount.
+
+# Attempting Debt in Trillions in Time
+
+For this I'm going to attempt to turn the quarter and years into time frames.
+
+## Using the zoo package
+
+```{r debt in trillons to time}
+dt2 <- dt
+dt2 <- dt2 %>%
+# Mutating all quarters to turn into the first of the month for that quarter
+ mutate(quarter = case_when(
+ startsWith(quarter, "Q1") ~ "-1",
+ startsWith(quarter, "Q2") ~ "-4",
+ startsWith(quarter, "Q3") ~ "-7",
+ startsWith(quarter, "Q4") ~ "-10"
+)) %>%
+# Uniting the year and quarter columns back into one column
+ unite('yq', year:quarter, remove = FALSE) %>%
+ select(-c(year, quarter)) %>%
+# Removing the _ that was in the year quarter that made it look like this 2003_-1
+ mutate_at("yq", str_replace, "_", "")
+# I used zoo to first change this into a date type column
+dt2$yq <- as.Date(as.yearmon(dt2$yq))
+# and then change it into a year quarter one like before!
+dt2$yq <- as.yearqtr(dt2$yq, format = "%Y-%m-%d")
+
+# Using the paged table you can see that the column type has changed to S3: yearqtr :)
+
+paged_table(dt2)
+
+```
+
+Now that I've been able to change the year and quarter column to a date I'm going to try to plot it this way. I attempted to use the lubridate package but I was having trouble getting the dates back into Q1 form. So I just used the zoo package.
+
+## Visulizing through time for debt in trillions
+
+First I'll try to visualize debt in trillions without using it as a time function.
+
+```{r visual year and quarter}
+dt2 <- dt2 %>%
+ gather(key = debt, value = totaldebt, mortgage:other)
+
+p13 <- ggplot(dt2, aes(x=yq, y=totaldebt, fill=debt)) +
+ geom_area(alpha=0.6) +
+ scale_fill_brewer(palette="Dark2") +
+ scale_x_continuous(name="year") +
+ scale_y_continuous(name="total debt")
+
+p14 <- ggplot(dt2, aes(y = totaldebt, x = yq, colour = debt)) +
+ geom_line() +
+ scale_x_continuous(name="year") +
+ scale_y_continuous(name="total debt")
+
+p13/p14
+
+
+```
+
+Now that I know that it works I will try to do it using a time frame.
+
+```{r visualizing through time}
+
+p15 <- ggplot(dt2, aes(y = totaldebt, x = yq, colour = debt)) +
+ geom_line() +
+ scale_x_date(date_labels = "%YQ%q") +
+ scale_x_continuous(name="year") +
+ scale_y_continuous(name="total debt")
+
+p15
+```
+
+I noticed there was not much difference because quarter is not being read in. Instead I decided to try this with the zoo package.
+
+```{r visualize with zoo}
+# Here is reading in ggplot and using the zoo package
+p16 <- ggplot(dt2, aes(yq, totaldebt)) +
+ geom_line() +
+ scale_x_yearqtr(format = "%YQ%q", name="year and quarter - ggplot") +
+ scale_y_continuous(name="total debt")
+# Here is only using the zoo package
+p17 <- zoo(dt2$totaldebt, as.yearqtr(dt2$yq))
+p17 <- autoplot(p17) +
+ scale_x_yearqtr(format = "%YQ%q", name="year and quarter - zoo package") +
+ scale_y_continuous(name="total debt")
+
+p16/p17
+
+```
+
+Both look the same, however using the only zoo package I get "Warning in zoo(dt2$totaldebt, as.yearqtr(dt2$yq)): some methods for “zoo” objects do not work if the index entries in ‘order.by’ are not unique"
+
+Lets see if I can combine graphs together.
+
+```{r putting time graphs together}
+p18 <- ggplot(dt2, aes(yq, totaldebt, colour = debt)) +
+ geom_line() +
+ ggtitle("Total Debt in Trillions") +
+ scale_x_yearqtr(format = "%YQ%q", name="year and quarter") +
+ scale_y_continuous(name="total debt")
+p18
+```
+
+I did it!
+
+
+
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4.html b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4.html
new file mode 100644
index 0000000..f1d8a6d
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4.html
@@ -0,0 +1,1928 @@
+
+
+
+
+
For this homework assignment I plan to work with three different types of data sets. Below I will read in the data sets. This time instead of putting layout=“l-body-outset” I put that in the setup as a opts_chunk$set function.
+
Cleaning the data
+
I will first clean data that is needed to be cleaned. I had previously cleaned the debt in trillions so below you will find my work and how I did it.
dt<-read_excel(here("_data", "debt_in_trillions.xlsx"))
+
+dt<-rename(dt, "year_and_quarter"="Year and Quarter",
+ "herevolving"="HE Revolving",
+ "autoloan"="Auto Loan",
+ "creditcard"="Credit Card",
+ "studentloan"="Student Loan",)%>%
+ select(!starts_with("total"))
+
+# I changed the rest of the names to lowercase but it doesn't have to be done.
+# I just prefer to not have to press the shift key when typing if I can avoid it.
+ colnames(dt)<-tolower(colnames(dt))
+
+dt<-dt%>%
+separate(year_and_quarter, into =c("year", "quarter"), sep=":")
+dt<-transform(dt, year =as.numeric(year))
+
+# This is adding 2000 so that the years will be in the 2000s-2010s
+ dt$year<-dt$year+2000
+
+# Needed to change mortgage to a numeric form, it was originally a character form.
+ dt$mortgage<-as.numeric(dt$mortgage)
+
+datatable(dt, options =list(
+ initComplete =JS(
+ "function(settings, json) {",
+ "$(this.api().table().header()).css({'background-color': '#000', 'color': '#fff'});",
+ "}"),
+ caption ='Debt in Trillions',
+ width ='100%', options =list(scrollX =TRUE)))
+
+
+
+
+
+
Picking variables
+
All variables were picked from the data sets we were provided. There are no missing values.
+
Picking variables for Cereal
+
For variables I’m going to focus on the sugar and sodium columns and compare them based on the different cereals.
+
Picking variables for Debt in trillions
+
For debt in trillions I want to focus on the type of debt and how it fluctuates by year and quarter.
+
Descriptive Statstics
+
Cereal descprtive stastics
+
First lets look at descriptive statics of sodium and and sugar.
For the sugar quartile I found that for the third quartile that 25% of the cereal had 12.5 of sugar or more.
+
For the sodium quartile I found that for the first quartile that 25% of the cereal had 137.5 of sodium or less. For the standard deviation, the mean was 167 while the standard deviation was about 77.3. Only one data item, 340 was more than two standard deviations above the mean, and only one data item, 0 was more than two standard deviations below the mean.
+
The fact that sodium is so much higher in sodium than sugar surprised me because of people mostly talking about how “sugary” cereals are. Sodium ranged from 0-340 grams compared to sugar’s 0-18 grams.
+
Debt in trillions descrpitve statstics
+
Now lets look at the descriptive statics for debt in trillions.
We can notice that because quarters is a character column it is returning NA.
+
Here we can see some interesting statistics. If we look at all the means we have three that are relatively close in amount (from about .73-.91 ) two that are lower (.39-.52) other and he_revolving (I believe to be home equity revolving), and one that is way higher than any of them, mortgage at 8.41
+
For other loans we don’t know what loans are in the category, so it makes sense for it to be smaller than the major loans. he_revolving may be lower due to a much lower range of debt than the other loan types.
+
However for mortgage the median is a much larger number. I believe this may because of how many people purchase homes and need to borrow money from the bank, unlike for the other types of loans. Usually these loans are much larger.
+
Looking at the means for each of these categories the means seem to be on a similar path to the medians with all the categories being close to their median amount.
+
Visulazation
+
Now that I’ve done some stastics I would like to see it in a visualized form. Below you will find both data sets broken out into different graphs.
+
Cereal
+
For cereal I’m interested in seeing the sodium compared to sugar for each cereal brand.
This gets me two separate graphs, however I’m more interested in having them on one graph. Additionally I noticed that the font had to be extremely small to fit the whole bar chart in with the names. This time I’ll try using a legend.
This is what I wanted! This allows you to see how sugar and sodium’s amount compared to the cereal. As you can see sodium is much more drastically different compared to the sugar.
+
Debt in trillions
+
With what I learned about plotting in Cereal, I’m going to focus on trying to make tables here.
+
+
+
dt1<-dt%>%
+ gather(key =debt, value =totaldebt, mortgage:other)
+
+p5<-ggplot(dt1, aes(year, totaldebt, fill =debt))+
+ geom_col(position ="dodge")
+
+p6<-ggplot(dt1, aes(quarter, totaldebt, fill =debt))+
+ geom_col(position ="dodge")
+
+p5/p6+plot_layout(guides ="collect")+plot_annotation(
+ title ="Total debt by year and quarter")
+
From the different types of debt you can see that each debt has it’s own graph, while student loan seems to always go up compared to he revolving going down after 2010, the rest seemed to have a dip between 2010-2015.
+
For overall mortgage was by far the largest amount.
+
Attempting Debt in Trillions in Time
+
For this I’m going to attempt to turn the quarter and years into time frames.
+
Using the zoo package
+
+
+
dt2<-dt
+dt2<-dt2%>%
+# Mutating all quarters to turn into the first of the month for that quarter
+ mutate(quarter =case_when(
+ startsWith(quarter, "Q1")~"-1",
+ startsWith(quarter, "Q2")~"-4",
+ startsWith(quarter, "Q3")~"-7",
+ startsWith(quarter, "Q4")~"-10"
+))%>%
+# Uniting the year and quarter columns back into one column
+ unite('yq', year:quarter, remove =FALSE)%>%
+ select(-c(year, quarter))%>%
+# Removing the _ that was in the year quarter that made it look like this 2003_-1
+ mutate_at("yq", str_replace, "_", "")
+# I used zoo to first change this into a date type column
+dt2$yq<-as.Date(as.yearmon(dt2$yq))
+# and then change it into a year quarter one like before!
+dt2$yq<-as.yearqtr(dt2$yq, format ="%Y-%m-%d")
+
+# Using the paged table you can see that the column type has changed to S3: yearqtr :)
+
+paged_table(dt2)
+
+
+
+
+
+
+
Now that I’ve been able to change the year and quarter column to a date I’m going to try to plot it this way. I attempted to use the lubridate package but I was having trouble getting the dates back into Q1 form. So I just used the zoo package.
+
Visulizing through time for debt in trillions
+
First I’ll try to visualize debt in trillions without using it as a time function.
I noticed there was not much difference because quarter is not being read in. Instead I decided to try this with the zoo package.
+
+
+
# Here is reading in ggplot and using the zoo package
+p16<-ggplot(dt2, aes(yq, totaldebt))+
+ geom_line()+
+ scale_x_yearqtr(format ="%YQ%q", name="year and quarter - ggplot")+
+ scale_y_continuous(name="total debt")
+# Here is only using the zoo package
+p17<-zoo(dt2$totaldebt, as.yearqtr(dt2$yq))
+p17<-autoplot(p17)+
+ scale_x_yearqtr(format ="%YQ%q", name="year and quarter - zoo package")+
+ scale_y_continuous(name="total debt")
+
+p16/p17
+
+
+
+
+
Both look the same, however using the only zoo package I get “Warning in zoo(dt2\(totaldebt, as.yearqtr(dt2\)yq)): some methods for “zoo” objects do not work if the index entries in ‘order.by’ are not unique”
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/anchor-4.2.2/anchor.min.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/anchor-4.2.2/anchor.min.js
new file mode 100644
index 0000000..26908ec
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/anchor-4.2.2/anchor.min.js
@@ -0,0 +1,9 @@
+// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
+//
+// AnchorJS - v4.2.2 - 2019-11-14
+// https://www.bryanbraun.com/anchorjs/
+// Copyright (c) 2019 Bryan Braun; Licensed MIT
+//
+// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
+!function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){"use strict";return function(A){function f(A){A.icon=A.hasOwnProperty("icon")?A.icon:"",A.visible=A.hasOwnProperty("visible")?A.visible:"hover",A.placement=A.hasOwnProperty("placement")?A.placement:"right",A.ariaLabel=A.hasOwnProperty("ariaLabel")?A.ariaLabel:"Anchor",A.class=A.hasOwnProperty("class")?A.class:"",A.base=A.hasOwnProperty("base")?A.base:"",A.truncate=A.hasOwnProperty("truncate")?Math.floor(A.truncate):64,A.titleText=A.hasOwnProperty("titleText")?A.titleText:""}function p(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new Error("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}this.options=A||{},this.elements=[],f(this.options),this.isTouchDevice=function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var e,t,i,n,o,s,a,r,c,h,l,u,d=[];if(f(this.options),"touch"===(l=this.options.visible)&&(l=this.isTouchDevice()?"always":"hover"),0===(e=p(A=A||"h2, h3, h4, h5, h6")).length)return this;for(!function(){if(null!==document.head.querySelector("style.anchorjs"))return;var A,e=document.createElement("style");e.className="anchorjs",e.appendChild(document.createTextNode("")),void 0===(A=document.head.querySelector('[rel="stylesheet"], style'))?document.head.appendChild(e):document.head.insertBefore(e,A);e.sheet.insertRule(" .anchorjs-link { opacity: 0; text-decoration: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }",e.sheet.cssRules.length),e.sheet.insertRule(" *:hover > .anchorjs-link, .anchorjs-link:focus { opacity: 1; }",e.sheet.cssRules.length),e.sheet.insertRule(" [data-anchorjs-icon]::after { content: attr(data-anchorjs-icon); }",e.sheet.cssRules.length),e.sheet.insertRule(' @font-face { font-family: "anchorjs-icons"; src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype"); }',e.sheet.cssRules.length)}(),t=document.querySelectorAll("[id]"),i=[].map.call(t,function(A){return A.id}),o=0;o\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),t=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||t||!1}}});
+// @license-end
\ No newline at end of file
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/bowser-1.9.3/bowser.min.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/bowser-1.9.3/bowser.min.js
new file mode 100644
index 0000000..5866337
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/bowser-1.9.3/bowser.min.js
@@ -0,0 +1,6 @@
+/*!
+ * Bowser - a browser detector
+ * https://github.com/ded/bowser
+ * MIT License | (c) Dustin Diaz 2015
+ */
+!function(e,t,n){typeof module!="undefined"&&module.exports?module.exports=n():typeof define=="function"&&define.amd?define(t,n):e[t]=n()}(this,"bowser",function(){function t(t){function n(e){var n=t.match(e);return n&&n.length>1&&n[1]||""}function r(e){var n=t.match(e);return n&&n.length>1&&n[2]||""}function N(e){switch(e){case"NT":return"NT";case"XP":return"XP";case"NT 5.0":return"2000";case"NT 5.1":return"XP";case"NT 5.2":return"2003";case"NT 6.0":return"Vista";case"NT 6.1":return"7";case"NT 6.2":return"8";case"NT 6.3":return"8.1";case"NT 10.0":return"10";default:return undefined}}var i=n(/(ipod|iphone|ipad)/i).toLowerCase(),s=/like android/i.test(t),o=!s&&/android/i.test(t),u=/nexus\s*[0-6]\s*/i.test(t),a=!u&&/nexus\s*[0-9]+/i.test(t),f=/CrOS/.test(t),l=/silk/i.test(t),c=/sailfish/i.test(t),h=/tizen/i.test(t),p=/(web|hpw)os/i.test(t),d=/windows phone/i.test(t),v=/SamsungBrowser/i.test(t),m=!d&&/windows/i.test(t),g=!i&&!l&&/macintosh/i.test(t),y=!o&&!c&&!h&&!p&&/linux/i.test(t),b=r(/edg([ea]|ios)\/(\d+(\.\d+)?)/i),w=n(/version\/(\d+(\.\d+)?)/i),E=/tablet/i.test(t)&&!/tablet pc/i.test(t),S=!E&&/[^-]mobi/i.test(t),x=/xbox/i.test(t),T;/opera/i.test(t)?T={name:"Opera",opera:e,version:w||n(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i)}:/opr\/|opios/i.test(t)?T={name:"Opera",opera:e,version:n(/(?:opr|opios)[\s\/](\d+(\.\d+)?)/i)||w}:/SamsungBrowser/i.test(t)?T={name:"Samsung Internet for Android",samsungBrowser:e,version:w||n(/(?:SamsungBrowser)[\s\/](\d+(\.\d+)?)/i)}:/coast/i.test(t)?T={name:"Opera Coast",coast:e,version:w||n(/(?:coast)[\s\/](\d+(\.\d+)?)/i)}:/yabrowser/i.test(t)?T={name:"Yandex Browser",yandexbrowser:e,version:w||n(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i)}:/ucbrowser/i.test(t)?T={name:"UC Browser",ucbrowser:e,version:n(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i)}:/mxios/i.test(t)?T={name:"Maxthon",maxthon:e,version:n(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i)}:/epiphany/i.test(t)?T={name:"Epiphany",epiphany:e,version:n(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i)}:/puffin/i.test(t)?T={name:"Puffin",puffin:e,version:n(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i)}:/sleipnir/i.test(t)?T={name:"Sleipnir",sleipnir:e,version:n(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i)}:/k-meleon/i.test(t)?T={name:"K-Meleon",kMeleon:e,version:n(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i)}:d?(T={name:"Windows Phone",osname:"Windows Phone",windowsphone:e},b?(T.msedge=e,T.version=b):(T.msie=e,T.version=n(/iemobile\/(\d+(\.\d+)?)/i))):/msie|trident/i.test(t)?T={name:"Internet Explorer",msie:e,version:n(/(?:msie |rv:)(\d+(\.\d+)?)/i)}:f?T={name:"Chrome",osname:"Chrome OS",chromeos:e,chromeBook:e,chrome:e,version:n(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:/edg([ea]|ios)/i.test(t)?T={name:"Microsoft Edge",msedge:e,version:b}:/vivaldi/i.test(t)?T={name:"Vivaldi",vivaldi:e,version:n(/vivaldi\/(\d+(\.\d+)?)/i)||w}:c?T={name:"Sailfish",osname:"Sailfish OS",sailfish:e,version:n(/sailfish\s?browser\/(\d+(\.\d+)?)/i)}:/seamonkey\//i.test(t)?T={name:"SeaMonkey",seamonkey:e,version:n(/seamonkey\/(\d+(\.\d+)?)/i)}:/firefox|iceweasel|fxios/i.test(t)?(T={name:"Firefox",firefox:e,version:n(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i)},/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(t)&&(T.firefoxos=e,T.osname="Firefox OS")):l?T={name:"Amazon Silk",silk:e,version:n(/silk\/(\d+(\.\d+)?)/i)}:/phantom/i.test(t)?T={name:"PhantomJS",phantom:e,version:n(/phantomjs\/(\d+(\.\d+)?)/i)}:/slimerjs/i.test(t)?T={name:"SlimerJS",slimer:e,version:n(/slimerjs\/(\d+(\.\d+)?)/i)}:/blackberry|\bbb\d+/i.test(t)||/rim\stablet/i.test(t)?T={name:"BlackBerry",osname:"BlackBerry OS",blackberry:e,version:w||n(/blackberry[\d]+\/(\d+(\.\d+)?)/i)}:p?(T={name:"WebOS",osname:"WebOS",webos:e,version:w||n(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)},/touchpad\//i.test(t)&&(T.touchpad=e)):/bada/i.test(t)?T={name:"Bada",osname:"Bada",bada:e,version:n(/dolfin\/(\d+(\.\d+)?)/i)}:h?T={name:"Tizen",osname:"Tizen",tizen:e,version:n(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i)||w}:/qupzilla/i.test(t)?T={name:"QupZilla",qupzilla:e,version:n(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i)||w}:/chromium/i.test(t)?T={name:"Chromium",chromium:e,version:n(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i)||w}:/chrome|crios|crmo/i.test(t)?T={name:"Chrome",chrome:e,version:n(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:o?T={name:"Android",version:w}:/safari|applewebkit/i.test(t)?(T={name:"Safari",safari:e},w&&(T.version=w)):i?(T={name:i=="iphone"?"iPhone":i=="ipad"?"iPad":"iPod"},w&&(T.version=w)):/googlebot/i.test(t)?T={name:"Googlebot",googlebot:e,version:n(/googlebot\/(\d+(\.\d+))/i)||w}:T={name:n(/^(.*)\/(.*) /),version:r(/^(.*)\/(.*) /)},!T.msedge&&/(apple)?webkit/i.test(t)?(/(apple)?webkit\/537\.36/i.test(t)?(T.name=T.name||"Blink",T.blink=e):(T.name=T.name||"Webkit",T.webkit=e),!T.version&&w&&(T.version=w)):!T.opera&&/gecko\//i.test(t)&&(T.name=T.name||"Gecko",T.gecko=e,T.version=T.version||n(/gecko\/(\d+(\.\d+)?)/i)),!T.windowsphone&&(o||T.silk)?(T.android=e,T.osname="Android"):!T.windowsphone&&i?(T[i]=e,T.ios=e,T.osname="iOS"):g?(T.mac=e,T.osname="macOS"):x?(T.xbox=e,T.osname="Xbox"):m?(T.windows=e,T.osname="Windows"):y&&(T.linux=e,T.osname="Linux");var C="";T.windows?C=N(n(/Windows ((NT|XP)( \d\d?.\d)?)/i)):T.windowsphone?C=n(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i):T.mac?(C=n(/Mac OS X (\d+([_\.\s]\d+)*)/i),C=C.replace(/[_\s]/g,".")):i?(C=n(/os (\d+([_\s]\d+)*) like mac os x/i),C=C.replace(/[_\s]/g,".")):o?C=n(/android[ \/-](\d+(\.\d+)*)/i):T.webos?C=n(/(?:web|hpw)os\/(\d+(\.\d+)*)/i):T.blackberry?C=n(/rim\stablet\sos\s(\d+(\.\d+)*)/i):T.bada?C=n(/bada\/(\d+(\.\d+)*)/i):T.tizen&&(C=n(/tizen[\/\s](\d+(\.\d+)*)/i)),C&&(T.osversion=C);var k=!T.windows&&C.split(".")[0];if(E||a||i=="ipad"||o&&(k==3||k>=4&&!S)||T.silk)T.tablet=e;else if(S||i=="iphone"||i=="ipod"||o||u||T.blackberry||T.webos||T.bada)T.mobile=e;return T.msedge||T.msie&&T.version>=10||T.yandexbrowser&&T.version>=15||T.vivaldi&&T.version>=1||T.chrome&&T.version>=20||T.samsungBrowser&&T.version>=4||T.firefox&&T.version>=20||T.safari&&T.version>=6||T.opera&&T.version>=10||T.ios&&T.osversion&&T.osversion.split(".")[0]>=6||T.blackberry&&T.version>=10.1||T.chromium&&T.version>=20?T.a=e:T.msie&&T.version<10||T.chrome&&T.version<20||T.firefox&&T.version<20||T.safari&&T.version<6||T.opera&&T.version<10||T.ios&&T.osversion&&T.osversion.split(".")[0]<6||T.chromium&&T.version<20?T.c=e:T.x=e,T}function r(e){return e.split(".").length}function i(e,t){var n=[],r;if(Array.prototype.map)return Array.prototype.map.call(e,t);for(r=0;r=0){if(n[0][t]>n[1][t])return 1;if(n[0][t]!==n[1][t])return-1;if(t===0)return 0}}function o(e,r,i){var o=n;typeof r=="string"&&(i=r,r=void 0),r===void 0&&(r=!1),i&&(o=t(i));var u=""+o.version;for(var a in e)if(e.hasOwnProperty(a)&&o[a]){if(typeof e[a]!="string")throw new Error("Browser version in the minVersion map should be a string: "+a+": "+String(e));return s([u,e[a]])<0}return r}function u(e,t,n){return!o(e,t,n)}var e=!0,n=t(typeof navigator!="undefined"?navigator.userAgent||"":"");return n.test=function(e){for(var t=0;t .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;
+ }
+}
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/js/crosstalk.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/js/crosstalk.js
new file mode 100644
index 0000000..fd9eb53
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/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/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/js/crosstalk.js.map b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/js/crosstalk.js.map
new file mode 100644
index 0000000..cff94f0
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/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/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/js/crosstalk.min.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/js/crosstalk.min.js
new file mode 100644
index 0000000..b7ec0ac
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/crosstalk-1.1.1/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/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/datatables-binding-0.19/datatables.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/datatables-binding-0.19/datatables.js
new file mode 100644
index 0000000..fc04fd2
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/datatables-binding-0.19/datatables.js
@@ -0,0 +1,1421 @@
+(function() {
+
+// some helper functions: using a global object DTWidget so that it can be used
+// in JS() code, e.g. datatable(options = list(foo = JS('code'))); unlike R's
+// dynamic scoping, when 'code' is eval()'ed, JavaScript does not know objects
+// from the "parent frame", e.g. JS('DTWidget') will not work unless it was made
+// a global object
+var DTWidget = {};
+
+// 123456666.7890 -> 123,456,666.7890
+var markInterval = function(d, digits, interval, mark, decMark, precision) {
+ x = precision ? d.toPrecision(digits) : d.toFixed(digits);
+ if (!/^-?[\d.]+$/.test(x)) return x;
+ var xv = x.split('.');
+ if (xv.length > 2) return x; // should have at most one decimal point
+ xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark);
+ return xv.join(decMark);
+};
+
+DTWidget.formatCurrency = function(data, currency, digits, interval, mark, decMark, before) {
+ var d = parseFloat(data);
+ if (isNaN(d)) return '';
+ var res = markInterval(d, digits, interval, mark, decMark);
+ res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) :
+ res + currency;
+ return res;
+};
+
+DTWidget.formatString = function(data, prefix, suffix) {
+ var d = data;
+ if (d === null) return '';
+ return prefix + d + suffix;
+};
+
+DTWidget.formatPercentage = function(data, digits, interval, mark, decMark) {
+ var d = parseFloat(data);
+ if (isNaN(d)) return '';
+ return markInterval(d * 100, digits, interval, mark, decMark) + '%';
+};
+
+DTWidget.formatRound = function(data, digits, interval, mark, decMark) {
+ var d = parseFloat(data);
+ if (isNaN(d)) return '';
+ return markInterval(d, digits, interval, mark, decMark);
+};
+
+DTWidget.formatSignif = function(data, digits, interval, mark, decMark) {
+ var d = parseFloat(data);
+ if (isNaN(d)) return '';
+ return markInterval(d, digits, interval, mark, decMark, true);
+};
+
+DTWidget.formatDate = function(data, method, params) {
+ var d = data;
+ if (d === null) return '';
+ // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the
+ // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)',
+ // i.e. the date-only string is treated as UTC time instead of local time
+ if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) {
+ d = d.split(/\D/);
+ d = new Date(d[0], d[1] - 1, d[2]);
+ } else {
+ d = new Date(d);
+ }
+ return d[method].apply(d, params);
+};
+
+window.DTWidget = DTWidget;
+
+var transposeArray2D = function(a) {
+ return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a);
+};
+
+var crosstalkPluginsInstalled = false;
+
+function maybeInstallCrosstalkPlugins() {
+ if (crosstalkPluginsInstalled)
+ return;
+ crosstalkPluginsInstalled = true;
+
+ $.fn.dataTable.ext.afnFiltering.push(
+ function(oSettings, aData, iDataIndex) {
+ var ctfilter = oSettings.nTable.ctfilter;
+ if (ctfilter && !ctfilter[iDataIndex])
+ return false;
+
+ var ctselect = oSettings.nTable.ctselect;
+ if (ctselect && !ctselect[iDataIndex])
+ return false;
+
+ return true;
+ }
+ );
+}
+
+HTMLWidgets.widget({
+ name: "datatables",
+ type: "output",
+ renderOnNullValue: true,
+ initialize: function(el, width, height) {
+ $(el).html(' ');
+ return {
+ data: null,
+ ctfilterHandle: new crosstalk.FilterHandle(),
+ ctfilterSubscription: null,
+ ctselectHandle: new crosstalk.SelectionHandle(),
+ ctselectSubscription: null
+ };
+ },
+ renderValue: function(el, data, instance) {
+ if (el.offsetWidth === 0 || el.offsetHeight === 0) {
+ instance.data = data;
+ return;
+ }
+ instance.data = null;
+ var $el = $(el);
+ $el.empty();
+
+ if (data === null) {
+ $el.append(' ');
+ // clear previous Shiny inputs (if any)
+ for (var i in instance.clearInputs) instance.clearInputs[i]();
+ instance.clearInputs = {};
+ return;
+ }
+
+ var crosstalkOptions = data.crosstalkOptions;
+ if (!crosstalkOptions) crosstalkOptions = {
+ 'key': null, 'group': null
+ };
+ if (crosstalkOptions.group) {
+ maybeInstallCrosstalkPlugins();
+ instance.ctfilterHandle.setGroup(crosstalkOptions.group);
+ instance.ctselectHandle.setGroup(crosstalkOptions.group);
+ }
+
+ // if we are in the viewer then we always want to fillContainer and
+ // and autoHideNavigation (unless the user has explicitly set these)
+ if (window.HTMLWidgets.viewerMode) {
+ if (!data.hasOwnProperty("fillContainer"))
+ data.fillContainer = true;
+ if (!data.hasOwnProperty("autoHideNavigation"))
+ data.autoHideNavigation = true;
+ }
+
+ // propagate fillContainer to instance (so we have it in resize)
+ instance.fillContainer = data.fillContainer;
+
+ var cells = data.data;
+
+ if (cells instanceof Array) cells = transposeArray2D(cells);
+
+ $el.append(data.container);
+ var $table = $el.find('table');
+ if (data.class) $table.addClass(data.class);
+ if (data.caption) $table.prepend(data.caption);
+
+ if (!data.selection) data.selection = {
+ mode: 'none', selected: null, target: 'row', selectable: null
+ };
+ if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' &&
+ data.selection.target === 'row+column') {
+ if ($table.children('tfoot').length === 0) {
+ $table.append($(''));
+ $table.find('thead tr').clone().appendTo($table.find('tfoot'));
+ }
+ }
+
+ // column filters
+ var filterRow;
+ switch (data.filter) {
+ case 'top':
+ $table.children('thead').append(data.filterHTML);
+ filterRow = $table.find('thead tr:last td');
+ break;
+ case 'bottom':
+ if ($table.children('tfoot').length === 0) {
+ $table.append($(''));
+ }
+ $table.children('tfoot').prepend(data.filterHTML);
+ filterRow = $table.find('tfoot tr:first td');
+ break;
+ }
+
+ var options = { searchDelay: 1000 };
+ if (cells !== null) $.extend(options, {
+ data: cells
+ });
+
+ // options for fillContainer
+ var bootstrapActive = typeof($.fn.popover) != 'undefined';
+ if (instance.fillContainer) {
+
+ // force scrollX/scrollY and turn off autoWidth
+ options.scrollX = true;
+ options.scrollY = "100px"; // can be any value, we'll adjust below
+
+ // if we aren't paginating then move around the info/filter controls
+ // to save space at the bottom and rephrase the info callback
+ if (data.options.paging === false) {
+
+ // we know how to do this cleanly for bootstrap, not so much
+ // for other themes/layouts
+ if (bootstrapActive) {
+ options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" +
+ "<'row'<'col-sm-12'tr>>";
+ }
+
+ options.fnInfoCallback = function(oSettings, iStart, iEnd,
+ iMax, iTotal, sPre) {
+ return Number(iTotal).toLocaleString() + " records";
+ };
+ }
+ }
+
+ // auto hide navigation if requested
+ // Note, this only works on client-side processing mode as on server-side,
+ // cells (data.data) is null; In addition, we require the pageLength option
+ // being provided explicitly to enable this. Despite we may be able to deduce
+ // the default value of pageLength, it may complicate things so we'd rather
+ // put this responsiblity to users and warn them on the R side.
+ if (data.autoHideNavigation === true && data.options.paging !== false) {
+ // strip all nav if length >= cells
+ if ((cells instanceof Array) && data.options.pageLength >= cells.length)
+ options.dom = bootstrapActive ? "<'row'<'col-sm-12'tr>>" : "t";
+ // alternatively lean things out for flexdashboard mobile portrait
+ else if (bootstrapActive && window.FlexDashboard && window.FlexDashboard.isMobilePhone())
+ options.dom = "<'row'<'col-sm-12'f>>" +
+ "<'row'<'col-sm-12'tr>>" +
+ "<'row'<'col-sm-12'p>>";
+ }
+
+ $.extend(true, options, data.options || {});
+
+ var searchCols = options.searchCols;
+ if (searchCols) {
+ searchCols = searchCols.map(function(x) {
+ return x === null ? '' : x.search;
+ });
+ // FIXME: this means I don't respect the escapeRegex setting
+ delete options.searchCols;
+ }
+
+ // server-side processing?
+ var server = options.serverSide === true;
+
+ // use the dataSrc function to pre-process JSON data returned from R
+ var DT_rows_all = [], DT_rows_current = [];
+ if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' &&
+ /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) {
+ options.ajax.dataSrc = function(json) {
+ DT_rows_all = $.makeArray(json.DT_rows_all);
+ DT_rows_current = $.makeArray(json.DT_rows_current);
+ var data = json.data;
+ if (!colReorderEnabled()) return data;
+ var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row;
+ for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false;
+ if (flag) return data;
+ for (i = 0; i < data.length; ++i) {
+ row = data[i].slice();
+ for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]];
+ }
+ return data;
+ };
+ }
+
+ var thiz = this;
+ if (instance.fillContainer) $table.on('init.dt', function(e) {
+ thiz.fillAvailableHeight(el, $(el).innerHeight());
+ });
+ // If the page contains serveral datatables and one of which enables colReorder,
+ // the table.colReorder.order() function will exist but throws error when called.
+ // So it seems like the only way to know if colReorder is enabled or not is to
+ // check the options.
+ var colReorderEnabled = function() { return "colReorder" in options; };
+ var table = $table.DataTable(options);
+ $el.data('datatable', table);
+
+ // Unregister previous Crosstalk event subscriptions, if they exist
+ if (instance.ctfilterSubscription) {
+ instance.ctfilterHandle.off("change", instance.ctfilterSubscription);
+ instance.ctfilterSubscription = null;
+ }
+ if (instance.ctselectSubscription) {
+ instance.ctselectHandle.off("change", instance.ctselectSubscription);
+ instance.ctselectSubscription = null;
+ }
+
+ if (!crosstalkOptions.group) {
+ $table[0].ctfilter = null;
+ $table[0].ctselect = null;
+ } else {
+ var key = crosstalkOptions.key;
+ function keysToMatches(keys) {
+ if (!keys) {
+ return null;
+ } else {
+ var selectedKeys = {};
+ for (var i = 0; i < keys.length; i++) {
+ selectedKeys[keys[i]] = true;
+ }
+ var matches = {};
+ for (var j = 0; j < key.length; j++) {
+ if (selectedKeys[key[j]])
+ matches[j] = true;
+ }
+ return matches;
+ }
+ }
+
+ function applyCrosstalkFilter(e) {
+ $table[0].ctfilter = keysToMatches(e.value);
+ table.draw();
+ }
+ instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter);
+ applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys});
+
+ function applyCrosstalkSelection(e) {
+ if (e.sender !== instance.ctselectHandle) {
+ table
+ .rows('.' + selClass, {search: 'applied'})
+ .nodes()
+ .to$()
+ .removeClass(selClass);
+ if (selectedRows)
+ changeInput('rows_selected', selectedRows(), void 0, true);
+ }
+
+ if (e.sender !== instance.ctselectHandle && e.value && e.value.length) {
+ var matches = keysToMatches(e.value);
+
+ // persistent selection with plotly (& leaflet)
+ var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {};
+ if (ctOpts.persistent === true) {
+ var matches = $.extend(matches, $table[0].ctselect);
+ }
+
+ $table[0].ctselect = matches;
+ table.draw();
+ } else {
+ if ($table[0].ctselect) {
+ $table[0].ctselect = null;
+ table.draw();
+ }
+ }
+ }
+ instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection);
+ // TODO: This next line doesn't seem to work when renderDataTable is used
+ applyCrosstalkSelection({value: instance.ctselectHandle.value});
+ }
+
+ var inArray = function(val, array) {
+ return $.inArray(val, $.makeArray(array)) > -1;
+ };
+
+ // encode + to %2B when searching in the table on server side, because
+ // shiny::parseQueryString() treats + as spaces, and DataTables does not
+ // encode + to %2B (or % to %25) when sending the request
+ var encode_plus = function(x) {
+ return server ? x.replace(/%/g, '%25').replace(/\+/g, '%2B') : x;
+ };
+
+ // search the i-th column
+ var searchColumn = function(i, value) {
+ var regex = false, ci = true;
+ if (options.search) {
+ regex = options.search.regex,
+ ci = options.search.caseInsensitive !== false;
+ }
+ return table.column(i).search(encode_plus(value), regex, !regex, ci);
+ };
+
+ if (data.filter !== 'none') {
+
+ filterRow.each(function(i, td) {
+
+ var $td = $(td), type = $td.data('type'), filter;
+ var $input = $td.children('div').first().children('input');
+ $input.prop('disabled', !table.settings()[0].aoColumns[i].bSearchable || type === 'disabled');
+ $input.on('input blur', function() {
+ $input.next('span').toggle(Boolean($input.val()));
+ });
+ // Bootstrap sets pointer-events to none and we won't be able to click
+ // the clear button
+ $input.next('span').css('pointer-events', 'auto').hide().click(function() {
+ $(this).hide().prev('input').val('').trigger('input').focus();
+ });
+ var searchCol; // search string for this column
+ if (searchCols && searchCols[i]) {
+ searchCol = searchCols[i];
+ $input.val(searchCol).trigger('input');
+ }
+ var $x = $td.children('div').last();
+
+ // remove the overflow: hidden attribute of the scrollHead
+ // (otherwise the scrolling table body obscures the filters)
+ // The workaround and the discussion from
+ // https://github.com/rstudio/DT/issues/554#issuecomment-518007347
+ // Otherwise the filter selection will not be anchored to the values
+ // when the columns number is many and scrollX is enabled.
+ var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot');
+ var cssOverflowHead = scrollHead.css('overflow');
+ var scrollBody = $(el).find('.dataTables_scrollBody');
+ var cssOverflowBody = scrollBody.css('overflow');
+ var scrollTable = $(el).find('.dataTables_scroll');
+ var cssOverflowTable = scrollTable.css('overflow');
+ if (cssOverflowHead === 'hidden') {
+ $x.on('show hide', function(e) {
+ if (e.type === 'show') {
+ scrollHead.css('overflow', 'visible');
+ scrollBody.css('overflow', 'visible');
+ scrollTable.css('overflow-x', 'scroll');
+ } else {
+ scrollHead.css('overflow', cssOverflowHead);
+ scrollBody.css('overflow', cssOverflowBody);
+ scrollTable.css('overflow-x', cssOverflowTable);
+ }
+ });
+ $x.css('z-index', 25);
+ }
+
+ if (inArray(type, ['factor', 'logical'])) {
+ $input.on({
+ click: function() {
+ $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus();
+ },
+ input: function() {
+ if ($input.val() === '') filter[0].selectize.setValue([]);
+ }
+ });
+ var $input2 = $x.children('select');
+ filter = $input2.selectize({
+ options: $input2.data('options').map(function(v, i) {
+ return ({text: v, value: v});
+ }),
+ plugins: ['remove_button'],
+ hideSelected: true,
+ onChange: function(value) {
+ if (value === null) value = []; // compatibility with jQuery 3.0
+ $input.val(value.length ? JSON.stringify(value) : '');
+ if (value.length) $input.trigger('input');
+ $input.attr('title', $input.val());
+ if (server) {
+ table.column(i).search(value.length ? encode_plus(JSON.stringify(value)) : '').draw();
+ return;
+ }
+ // turn off filter if nothing selected
+ $td.data('filter', value.length > 0);
+ table.draw(); // redraw table, and filters will be applied
+ }
+ });
+ if (searchCol) filter[0].selectize.setValue(JSON.parse(searchCol));
+ filter[0].selectize.on('blur', function() {
+ $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur');
+ });
+ filter.next('div').css('margin-bottom', 'auto');
+ } else if (type === 'character') {
+ var fun = function() {
+ searchColumn(i, $input.val()).draw();
+ };
+ if (server) {
+ fun = $.fn.dataTable.util.throttle(fun, options.searchDelay);
+ }
+ $input.on('input', fun);
+ } else if (inArray(type, ['number', 'integer', 'date', 'time'])) {
+ var $x0 = $x;
+ $x = $x0.children('div').first();
+ $x0.css({
+ 'background-color': '#fff',
+ 'border': '1px #ddd solid',
+ 'border-radius': '4px',
+ 'padding': data.vertical ? '35px 20px': '20px 20px 10px 20px'
+ });
+ var $spans = $x0.children('span').css({
+ 'margin-top': data.vertical ? '0' : '10px',
+ 'white-space': 'nowrap'
+ });
+ var $span1 = $spans.first(), $span2 = $spans.last();
+ var r1 = +$x.data('min'), r2 = +$x.data('max');
+ // when the numbers are too small or have many decimal places, the
+ // slider may have numeric precision problems (#150)
+ var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0));
+ r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale);
+ var scaleBack = function(x, scale) {
+ if (scale === 1) return x;
+ var d = Math.round(Math.log(scale) / Math.log(10));
+ // to avoid problems like 3.423/100 -> 0.034230000000000003
+ return (x / scale).toFixed(d);
+ };
+ var slider_min = function() {
+ return filter.noUiSlider('options').range.min;
+ };
+ var slider_max = function() {
+ return filter.noUiSlider('options').range.max;
+ };
+ $input.on({
+ focus: function() {
+ $x0.show().trigger('show');
+ // first, make sure the slider div leaves at least 20px between
+ // the two (slider value) span's
+ $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20));
+ // then, if the input is really wide or slider is vertical,
+ // make the slider the same width as the input
+ if ($x0.outerWidth() < $input.outerWidth() || data.vertical) {
+ $x0.outerWidth($input.outerWidth());
+ }
+ // make sure the slider div does not reach beyond the right margin
+ if ($(window).width() < $x0.offset().left + $x0.width()) {
+ $x0.offset({
+ 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth()
+ });
+ }
+ },
+ blur: function() {
+ $x0.hide().trigger('hide');
+ },
+ input: function() {
+ if ($input.val() === '') filter.val([slider_min(), slider_max()]);
+ },
+ change: function() {
+ var v = $input.val().replace(/\s/g, '');
+ if (v === '') return;
+ v = v.split('...');
+ if (v.length !== 2) {
+ $input.parent().addClass('has-error');
+ return;
+ }
+ if (v[0] === '') v[0] = slider_min();
+ if (v[1] === '') v[1] = slider_max();
+ $input.parent().removeClass('has-error');
+ // treat date as UTC time at midnight
+ var strTime = function(x) {
+ var s = type === 'date' ? 'T00:00:00Z' : '';
+ var t = new Date(x + s).getTime();
+ // add 10 minutes to date since it does not hurt the date, and
+ // it helps avoid the tricky floating point arithmetic problems,
+ // e.g. sometimes the date may be a few milliseconds earlier
+ // than the midnight due to precision problems in noUiSlider
+ return type === 'date' ? t + 3600000 : t;
+ };
+ if (inArray(type, ['date', 'time'])) {
+ v[0] = strTime(v[0]);
+ v[1] = strTime(v[1]);
+ }
+ if (v[0] != slider_min()) v[0] *= scale;
+ if (v[1] != slider_max()) v[1] *= scale;
+ filter.val(v);
+ }
+ });
+ var formatDate = function(d, isoFmt) {
+ d = scaleBack(d, scale);
+ if (type === 'number') return d;
+ if (type === 'integer') return parseInt(d);
+ var x = new Date(+d);
+ var fmt = ('filterDateFmt' in data) ? data.filterDateFmt[i] : undefined;
+ if (fmt !== undefined && isoFmt === false) return x[fmt.method].apply(x, fmt.params);
+ if (type === 'date') {
+ var pad0 = function(x) {
+ return ('0' + x).substr(-2, 2);
+ };
+ return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth())
+ + '-' + pad0(x.getUTCDate());
+ } else {
+ return x.toISOString();
+ }
+ };
+ var opts = type === 'date' ? { step: 60 * 60 * 1000 } :
+ type === 'integer' ? { step: 1 } : {};
+
+ opts.orientation = data.vertical ? 'vertical': 'horizontal';
+ opts.direction = data.vertical ? 'rtl': 'ltr';
+
+ filter = $x.noUiSlider($.extend({
+ start: [r1, r2],
+ range: {min: r1, max: r2},
+ connect: true
+ }, opts));
+ if (scale > 1) (function() {
+ var t1 = r1, t2 = r2;
+ var val = filter.val();
+ while (val[0] > r1 || val[1] < r2) {
+ if (val[0] > r1) {
+ t1 -= val[0] - r1;
+ }
+ if (val[1] < r2) {
+ t2 += r2 - val[1];
+ }
+ filter = $x.noUiSlider($.extend({
+ start: [t1, t2],
+ range: {min: t1, max: t2},
+ connect: true
+ }, opts), true);
+ val = filter.val();
+ }
+ r1 = t1; r2 = t2;
+ })();
+ var updateSliderText = function(v1, v2) {
+ $span1.text(formatDate(v1, false)); $span2.text(formatDate(v2, false));
+ };
+ updateSliderText(r1, r2);
+ var updateSlider = function(e) {
+ var val = filter.val();
+ // turn off filter if in full range
+ $td.data('filter', val[0] > slider_min() || val[1] < slider_max());
+ var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival;
+ if ($td.data('filter')) {
+ ival = v1 + ' ... ' + v2;
+ $input.attr('title', ival).val(ival).trigger('input');
+ } else {
+ $input.attr('title', '').val('');
+ }
+ updateSliderText(val[0], val[1]);
+ if (e.type === 'slide') return; // no searching when sliding only
+ if (server) {
+ table.column(i).search($td.data('filter') ? ival : '').draw();
+ return;
+ }
+ table.draw();
+ };
+ filter.on({
+ set: updateSlider,
+ slide: updateSlider
+ });
+ }
+
+ // server-side processing will be handled by R (or whatever server
+ // language you use); the following code is only needed for client-side
+ // processing
+ if (server) {
+ // if a search string has been pre-set, search now
+ if (searchCol) searchColumn(i, searchCol).draw();
+ return;
+ }
+
+ var customFilter = function(settings, data, dataIndex) {
+ // there is no way to attach a search function to a specific table,
+ // and we need to make sure a global search function is not applied to
+ // all tables (i.e. a range filter in a previous table should not be
+ // applied to the current table); we use the settings object to
+ // determine if we want to perform searching on the current table,
+ // since settings.sTableId will be different to different tables
+ if (table.settings()[0] !== settings) return true;
+ // no filter on this column or no need to filter this column
+ if (typeof filter === 'undefined' || !$td.data('filter')) return true;
+
+ var r = filter.val(), v, r0, r1;
+ var i_data = function(i) {
+ if (!colReorderEnabled()) return i;
+ var order = table.colReorder.order(), k;
+ for (k = 0; k < order.length; ++k) if (order[k] === i) return k;
+ return i; // in theory it will never be here...
+ }
+ v = data[i_data(i)];
+ if (type === 'number' || type === 'integer') {
+ v = parseFloat(v);
+ // how to handle NaN? currently exclude these rows
+ if (isNaN(v)) return(false);
+ r0 = parseFloat(scaleBack(r[0], scale))
+ r1 = parseFloat(scaleBack(r[1], scale));
+ if (v >= r0 && v <= r1) return true;
+ } else if (type === 'date' || type === 'time') {
+ v = new Date(v);
+ r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale);
+ if (v >= r0 && v <= r1) return true;
+ } else if (type === 'factor') {
+ if (r.length === 0 || inArray(v, r)) return true;
+ } else if (type === 'logical') {
+ if (r.length === 0) return true;
+ if (inArray(v === '' ? 'na' : v, r)) return true;
+ }
+ return false;
+ };
+
+ $.fn.dataTable.ext.search.push(customFilter);
+
+ // search for the preset search strings if it is non-empty
+ if (searchCol) {
+ if (inArray(type, ['factor', 'logical'])) {
+ filter[0].selectize.setValue(JSON.parse(searchCol));
+ } else if (type === 'character') {
+ $input.trigger('input');
+ } else if (inArray(type, ['number', 'integer', 'date', 'time'])) {
+ $input.trigger('change');
+ }
+ }
+
+ });
+
+ }
+
+ // highlight search keywords
+ var highlight = function() {
+ var body = $(table.table().body());
+ // removing the old highlighting first
+ body.unhighlight();
+
+ // don't highlight the "not found" row, so we get the rows using the api
+ if (table.rows({ filter: 'applied' }).data().length === 0) return;
+ // highlight global search keywords
+ body.highlight($.trim(table.search()).split(/\s+/));
+ // then highlight keywords from individual column filters
+ if (filterRow) filterRow.each(function(i, td) {
+ var $td = $(td), type = $td.data('type');
+ if (type !== 'character') return;
+ var $input = $td.children('div').first().children('input');
+ var column = table.column(i).nodes().to$(),
+ val = $.trim($input.val());
+ if (type !== 'character' || val === '') return;
+ column.highlight(val.split(/\s+/));
+ });
+ };
+
+ if (options.searchHighlight) {
+ table
+ .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight)
+ .on('destroy', function() {
+ // remove event handler
+ table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth');
+ });
+
+ // Set the option for escaping regex characters in our search string. This will be used
+ // for all future matching.
+ jQuery.fn.highlight.options.escapeRegex = (!options.search || !options.search.regex);
+
+ // initial highlight for state saved conditions and initial states
+ highlight();
+ }
+
+ // run the callback function on the table instance
+ if (typeof data.callback === 'function') data.callback(table);
+
+ // double click to edit the cell, row, column, or all cells
+ if (data.editable) table.on('dblclick.dt', 'tbody td', function(e) {
+ // only bring up the editor when the cell itself is dbclicked, and ignore
+ // other dbclick events bubbled up (e.g. from the )
+ if (e.target !== this) return;
+ var target = [], immediate = false;
+ switch (data.editable.target) {
+ case 'cell':
+ target = [this];
+ immediate = true; // edit will take effect immediately
+ break;
+ case 'row':
+ target = table.cells(table.cell(this).index().row, '*').nodes();
+ break;
+ case 'column':
+ target = table.cells('*', table.cell(this).index().column).nodes();
+ break;
+ case 'all':
+ target = table.cells().nodes();
+ break;
+ default:
+ throw 'The editable parameter must be "cell", "row", "column", or "all"';
+ }
+ var disableCols = data.editable.disable ? data.editable.disable.columns : null;
+ var numericCols = data.editable.numeric;
+ var areaCols = data.editable.area;
+ for (var i = 0; i < target.length; i++) {
+ (function(cell, current) {
+ var $cell = $(cell), html = $cell.html();
+ var _cell = table.cell(cell), value = _cell.data(), index = _cell.index().column;
+ var $input;
+ if (inArray(index, numericCols)) {
+ $input = $('');
+ } else if (inArray(index, areaCols)) {
+ $input = $('');
+ } else {
+ $input = $('');
+ }
+ if (!immediate) {
+ $cell.data('input', $input).data('html', html);
+ $input.attr('title', 'Hit Ctrl+Enter to finish editing, or Esc to cancel');
+ }
+ $input.val(value);
+ if (inArray(index, disableCols)) {
+ $input.attr('readonly', '').css('filter', 'invert(25%)');
+ }
+ $cell.empty().append($input);
+ if (cell === current) $input.focus();
+ $input.css('width', '100%');
+
+ if (immediate) $input.on('blur', function(e) {
+ var valueNew = $input.val();
+ if (valueNew != value) {
+ _cell.data(valueNew);
+ if (HTMLWidgets.shinyMode) {
+ changeInput('cell_edit', [cellInfo(cell)], 'DT.cellInfo', null, {priority: 'event'});
+ }
+ // for server-side processing, users have to call replaceData() to update the table
+ if (!server) table.draw(false);
+ } else {
+ $cell.html(html);
+ }
+ }).on('keyup', function(e) {
+ // hit Escape to cancel editing
+ if (e.keyCode === 27) $input.trigger('blur');
+ });
+
+ // bulk edit (row, column, or all)
+ if (!immediate) $input.on('keyup', function(e) {
+ var removeInput = function($cell, restore) {
+ $cell.data('input').remove();
+ if (restore) $cell.html($cell.data('html'));
+ }
+ if (e.keyCode === 27) {
+ for (var i = 0; i < target.length; i++) {
+ removeInput($(target[i]), true);
+ }
+ } else if (e.keyCode === 13 && e.ctrlKey) {
+ // Ctrl + Enter
+ var cell, $cell, _cell, cellData = [];
+ for (var i = 0; i < target.length; i++) {
+ cell = target[i]; $cell = $(cell); _cell = table.cell(cell);
+ _cell.data($cell.data('input').val());
+ HTMLWidgets.shinyMode && cellData.push(cellInfo(cell));
+ removeInput($cell, false);
+ }
+ if (HTMLWidgets.shinyMode) {
+ changeInput('cell_edit', cellData, 'DT.cellInfo', null, {priority: "event"});
+ }
+ if (!server) table.draw(false);
+ }
+ });
+ })(target[i], this);
+ }
+ });
+
+ // interaction with shiny
+ if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return;
+
+ var methods = {};
+ var shinyData = {};
+
+ methods.updateCaption = function(caption) {
+ if (!caption) return;
+ $table.children('caption').replaceWith(caption);
+ }
+
+ // register clear functions to remove input values when the table is removed
+ instance.clearInputs = {};
+
+ var changeInput = function(id, value, type, noCrosstalk, opts) {
+ var event = id;
+ id = el.id + '_' + id;
+ if (type) id = id + ':' + type;
+ // do not update if the new value is the same as old value
+ if (event !== 'cell_edit' && !/_clicked$/.test(event) && shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value))
+ return;
+ shinyData[id] = JSON.stringify(value);
+ if (HTMLWidgets.shinyMode && Shiny.setInputValue) {
+ Shiny.setInputValue(id, value, opts);
+ if (!instance.clearInputs[id]) instance.clearInputs[id] = function() {
+ Shiny.setInputValue(id, null);
+ }
+ }
+
+ // HACK
+ if (event === "rows_selected" && !noCrosstalk) {
+ if (crosstalkOptions.group) {
+ var keys = crosstalkOptions.key;
+ var selectedKeys = null;
+ if (value) {
+ selectedKeys = [];
+ for (var i = 0; i < value.length; i++) {
+ // The value array's contents use 1-based row numbers, so we must
+ // convert to 0-based before indexing into the keys array.
+ selectedKeys.push(keys[value[i] - 1]);
+ }
+ }
+ instance.ctselectHandle.set(selectedKeys);
+ }
+ }
+ };
+
+ var addOne = function(x) {
+ return x.map(function(i) { return 1 + i; });
+ };
+
+ var unique = function(x) {
+ var ux = [];
+ $.each(x, function(i, el){
+ if ($.inArray(el, ux) === -1) ux.push(el);
+ });
+ return ux;
+ }
+
+ // change the row index of a cell
+ var tweakCellIndex = function(cell) {
+ var info = cell.index();
+ // some cell may not be valid. e.g, #759
+ // when using the RowGroup extension, datatables will
+ // generate the row label and the cells are not part of
+ // the data thus contain no row/col info
+ if (info === undefined)
+ return {row: null, col: null};
+ if (server) {
+ info.row = DT_rows_current[info.row];
+ } else {
+ info.row += 1;
+ }
+ return {row: info.row, col: info.column};
+ }
+
+ var cleanSelectedValues = function() {
+ changeInput('rows_selected', []);
+ changeInput('columns_selected', []);
+ changeInput('cells_selected', transposeArray2D([]), 'shiny.matrix');
+ }
+ // #828 we should clean the selection on the server-side when the table reloads
+ cleanSelectedValues();
+
+ // a flag to indicates if select extension is initialized or not
+ var flagSelectExt = table.settings()[0]._select !== undefined;
+ // the Select extension should only be used in the client mode and
+ // when the selection.mode is set to none
+ if (data.selection.mode === 'none' && !server && flagSelectExt) {
+ var updateRowsSelected = function() {
+ var rows = table.rows({selected: true});
+ var selected = [];
+ $.each(rows.indexes().toArray(), function(i, v) {
+ selected.push(v + 1);
+ });
+ changeInput('rows_selected', selected);
+ }
+ var updateColsSelected = function() {
+ var columns = table.columns({selected: true});
+ changeInput('columns_selected', columns.indexes().toArray());
+ }
+ var updateCellsSelected = function() {
+ var cells = table.cells({selected: true});
+ var selected = [];
+ cells.every(function() {
+ var row = this.index().row;
+ var col = this.index().column;
+ selected = selected.concat([[row + 1, col]]);
+ });
+ changeInput('cells_selected', transposeArray2D(selected), 'shiny.matrix');
+ }
+ table.on('select deselect', function(e, dt, type, indexes) {
+ updateRowsSelected();
+ updateColsSelected();
+ updateCellsSelected();
+ })
+ }
+
+ var selMode = data.selection.mode, selTarget = data.selection.target;
+ var selDisable = data.selection.selectable === false;
+ if (inArray(selMode, ['single', 'multiple'])) {
+ var selClass = inArray(data.style, ['bootstrap', 'bootstrap4']) ? 'active' : 'selected';
+ // selected1: row indices; selected2: column indices
+ var initSel = function(x) {
+ if (x === null || typeof x === 'boolean' || selTarget === 'cell') {
+ return {rows: [], cols: []};
+ } else if (selTarget === 'row') {
+ return {rows: $.makeArray(x), cols: []};
+ } else if (selTarget === 'column') {
+ return {rows: [], cols: $.makeArray(x)};
+ } else if (selTarget === 'row+column') {
+ return {rows: $.makeArray(x.rows), cols: $.makeArray(x.cols)};
+ }
+ }
+ var selected = data.selection.selected;
+ var selected1 = initSel(selected).rows, selected2 = initSel(selected).cols;
+ // selectable should contain either all positive or all non-positive values, not both
+ // positive values indicate "selectable" while non-positive values means "nonselectable"
+ // the assertion is performed on R side. (only column indicides could be zero which indicates
+ // the row name)
+ var selectable = data.selection.selectable;
+ var selectable1 = initSel(selectable).rows, selectable2 = initSel(selectable).cols;
+
+ // After users reorder the rows or filter the table, we cannot use the table index
+ // directly. Instead, we need this function to find out the rows between the two clicks.
+ // If user filter the table again between the start click and the end click, the behavior
+ // would be undefined, but it should not be a problem.
+ var shiftSelRowsIndex = function(start, end) {
+ var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray();
+ start = indexes.indexOf(start); end = indexes.indexOf(end);
+ // if start is larger than end, we need to swap
+ if (start > end) {
+ var tmp = end; end = start; start = tmp;
+ }
+ return indexes.slice(start, end + 1);
+ }
+
+ var serverRowIndex = function(clientRowIndex) {
+ return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1;
+ }
+
+ // row, column, or cell selection
+ var lastClickedRow;
+ if (inArray(selTarget, ['row', 'row+column'])) {
+ // Get the current selected rows. It will also
+ // update the selected1's value based on the current row selection state
+ // Note we can't put this function inside selectRows() directly,
+ // the reason is method.selectRows() will override selected1's value but this
+ // function will add rows to selected1 (keep the existing selection), which is
+ // inconsistent with column and cell selection.
+ var selectedRows = function() {
+ var rows = table.rows('.' + selClass);
+ var idx = rows.indexes().toArray();
+ if (!server) {
+ selected1 = addOne(idx);
+ return selected1;
+ }
+ idx = idx.map(function(i) {
+ return DT_rows_current[i];
+ });
+ selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx;
+ return selected1;
+ }
+ // Change selected1's value based on selectable1, then refresh the row state
+ var onlyKeepSelectableRows = function() {
+ if (selDisable) { // users can't select; useful when only want backend select
+ selected1 = [];
+ return;
+ }
+ if (selectable1.length === 0) return;
+ var nonselectable = selectable1[0] <= 0;
+ if (nonselectable) {
+ // should make selectable1 positive
+ selected1 = $(selected1).not(selectable1.map(function(i) { return -i; })).get();
+ } else {
+ selected1 = $(selected1).filter(selectable1).get();
+ }
+ }
+ // Change selected1's value based on selectable1, then
+ // refresh the row selection state according to values in selected1
+ var selectRows = function(ignoreSelectable) {
+ if (!ignoreSelectable) onlyKeepSelectableRows();
+ table.$('tr.' + selClass).removeClass(selClass);
+ if (selected1.length === 0) return;
+ if (server) {
+ table.rows({page: 'current'}).every(function() {
+ if (inArray(DT_rows_current[this.index()], selected1)) {
+ $(this.node()).addClass(selClass);
+ }
+ });
+ } else {
+ var selected0 = selected1.map(function(i) { return i - 1; });
+ $(table.rows(selected0).nodes()).addClass(selClass);
+ }
+ }
+ table.on('mousedown.dt', 'tbody tr', function(e) {
+ var $this = $(this), thisRow = table.row(this);
+ if (selMode === 'multiple') {
+ if (e.shiftKey && lastClickedRow !== undefined) {
+ // select or de-select depends on the last clicked row's status
+ var flagSel = !$this.hasClass(selClass);
+ var crtClickedRow = serverRowIndex(thisRow.index());
+ if (server) {
+ var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow);
+ // update current page's selClass
+ rowsIndex.map(function(i) {
+ var rowIndex = DT_rows_current.indexOf(i);
+ if (rowIndex >= 0) {
+ var row = table.row(rowIndex).nodes().to$();
+ var flagRowSel = !row.hasClass(selClass);
+ if (flagSel === flagRowSel) row.toggleClass(selClass);
+ }
+ });
+ // update selected1
+ if (flagSel) {
+ selected1 = unique(selected1.concat(rowsIndex));
+ } else {
+ selected1 = selected1.filter(function(index) {
+ return !inArray(index, rowsIndex);
+ });
+ }
+ } else {
+ // js starts from 0
+ shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) {
+ var row = table.row(value).nodes().to$();
+ var flagRowSel = !row.hasClass(selClass);
+ if (flagSel === flagRowSel) row.toggleClass(selClass);
+ });
+ }
+ e.preventDefault();
+ } else {
+ $this.toggleClass(selClass);
+ }
+ } else {
+ if ($this.hasClass(selClass)) {
+ $this.removeClass(selClass);
+ } else {
+ table.$('tr.' + selClass).removeClass(selClass);
+ $this.addClass(selClass);
+ }
+ }
+ if (server && !$this.hasClass(selClass)) {
+ var id = DT_rows_current[thisRow.index()];
+ // remove id from selected1 since its class .selected has been removed
+ if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1);
+ }
+ selectedRows(); // update selected1's value based on selClass
+ selectRows(false); // only keep the selectable rows
+ changeInput('rows_selected', selected1);
+ changeInput('row_last_clicked', serverRowIndex(thisRow.index()), null, null, {priority: 'event'});
+ lastClickedRow = serverRowIndex(thisRow.index());
+ });
+ selectRows(false); // in case users have specified pre-selected rows
+ // restore selected rows after the table is redrawn (e.g. sort/search/page);
+ // client-side tables will preserve the selections automatically; for
+ // server-side tables, we have to *real* row indices are in `selected1`
+ changeInput('rows_selected', selected1);
+ if (server) table.on('draw.dt', function(e) { selectRows(false); });
+ methods.selectRows = function(selected, ignoreSelectable) {
+ selected1 = $.makeArray(selected);
+ selectRows(ignoreSelectable);
+ changeInput('rows_selected', selected1);
+ }
+ }
+
+ if (inArray(selTarget, ['column', 'row+column'])) {
+ if (selTarget === 'row+column') {
+ $(table.columns().footer()).css('cursor', 'pointer');
+ }
+ // update selected2's value based on selectable2
+ var onlyKeepSelectableCols = function() {
+ if (selDisable) { // users can't select; useful when only want backend select
+ selected2 = [];
+ return;
+ }
+ if (selectable2.length === 0) return;
+ var nonselectable = selectable2[0] <= 0;
+ if (nonselectable) {
+ // need to make selectable2 positive
+ selected2 = $(selected2).not(selectable2.map(function(i) { return -i; })).get();
+ } else {
+ selected2 = $(selected2).filter(selectable2).get();
+ }
+ }
+ // update selected2 and then
+ // refresh the col selection state according to values in selected2
+ var selectCols = function(ignoreSelectable) {
+ if (!ignoreSelectable) onlyKeepSelectableCols();
+ // if selected2 is not a valide index (e.g., larger than the column number)
+ // table.columns(selected2) will fail and result in a blank table
+ // this is different from the table.rows(), where the out-of-range indexes
+ // doesn't affect at all
+ selected2 = $(selected2).filter(table.columns().indexes()).get();
+ table.columns().nodes().flatten().to$().removeClass(selClass);
+ if (selected2.length > 0)
+ table.columns(selected2).nodes().flatten().to$().addClass(selClass);
+ }
+ var callback = function() {
+ var colIdx = selTarget === 'column' ? table.cell(this).index().column :
+ $.inArray(this, table.columns().footer()),
+ thisCol = $(table.column(colIdx).nodes());
+ if (colIdx === -1) return;
+ if (thisCol.hasClass(selClass)) {
+ thisCol.removeClass(selClass);
+ selected2.splice($.inArray(colIdx, selected2), 1);
+ } else {
+ if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass);
+ thisCol.addClass(selClass);
+ selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx]));
+ }
+ selectCols(false); // update selected2 based on selectable
+ changeInput('columns_selected', selected2);
+ }
+ if (selTarget === 'column') {
+ $(table.table().body()).on('click.dt', 'td', callback);
+ } else {
+ $(table.table().footer()).on('click.dt', 'tr th', callback);
+ }
+ selectCols(false); // in case users have specified pre-selected columns
+ changeInput('columns_selected', selected2);
+ if (server) table.on('draw.dt', function(e) { selectCols(false); });
+ methods.selectColumns = function(selected, ignoreSelectable) {
+ selected2 = $.makeArray(selected);
+ selectCols(ignoreSelectable);
+ changeInput('columns_selected', selected2);
+ }
+ }
+
+ if (selTarget === 'cell') {
+ var selected3 = [], selectable3 = [];
+ if (selected !== null) selected3 = selected;
+ if (selectable !== null && typeof selectable !== 'boolean') selectable3 = selectable;
+ var findIndex = function(ij, sel) {
+ for (var i = 0; i < sel.length; i++) {
+ if (ij[0] === sel[i][0] && ij[1] === sel[i][1]) return i;
+ }
+ return -1;
+ }
+ // Change selected3's value based on selectable3, then refresh the cell state
+ var onlyKeepSelectableCells = function() {
+ if (selDisable) { // users can't select; useful when only want backend select
+ selected3 = [];
+ return;
+ }
+ if (selectable3.length === 0) return;
+ var nonselectable = selectable3[0][0] <= 0;
+ var out = [];
+ if (nonselectable) {
+ selected3.map(function(ij) {
+ // should make selectable3 positive
+ if (findIndex([-ij[0], -ij[1]], selectable3) === -1) { out.push(ij); }
+ });
+ } else {
+ selected3.map(function(ij) {
+ if (findIndex(ij, selectable3) > -1) { out.push(ij); }
+ });
+ }
+ selected3 = out;
+ }
+ // Change selected3's value based on selectable3, then
+ // refresh the cell selection state according to values in selected3
+ var selectCells = function(ignoreSelectable) {
+ if (!ignoreSelectable) onlyKeepSelectableCells();
+ table.$('td.' + selClass).removeClass(selClass);
+ if (selected3.length === 0) return;
+ if (server) {
+ table.cells({page: 'current'}).every(function() {
+ var info = tweakCellIndex(this);
+ if (findIndex([info.row, info.col], selected3) > -1)
+ $(this.node()).addClass(selClass);
+ });
+ } else {
+ selected3.map(function(ij) {
+ $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass);
+ });
+ }
+ };
+ table.on('click.dt', 'tbody td', function() {
+ var $this = $(this), info = tweakCellIndex(table.cell(this));
+ if ($this.hasClass(selClass)) {
+ $this.removeClass(selClass);
+ selected3.splice(findIndex([info.row, info.col], selected3), 1);
+ } else {
+ if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass);
+ $this.addClass(selClass);
+ selected3 = selMode === 'single' ? [[info.row, info.col]] :
+ unique(selected3.concat([[info.row, info.col]]));
+ }
+ selectCells(false); // must call this to update selected3 based on selectable3
+ changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix');
+ });
+ selectCells(false); // in case users have specified pre-selected columns
+ changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix');
+
+ if (server) table.on('draw.dt', function(e) { selectCells(false); });
+ methods.selectCells = function(selected, ignoreSelectable) {
+ selected3 = selected ? selected : [];
+ selectCells(ignoreSelectable);
+ changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix');
+ }
+ }
+ }
+
+ // expose some table info to Shiny
+ var updateTableInfo = function(e, settings) {
+ // TODO: is anyone interested in the page info?
+ // changeInput('page_info', table.page.info());
+ var updateRowInfo = function(id, modifier) {
+ var idx;
+ if (server) {
+ idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all;
+ } else {
+ var rows = table.rows($.extend({
+ search: 'applied',
+ page: 'all'
+ }, modifier));
+ idx = addOne(rows.indexes().toArray());
+ }
+ changeInput('rows' + '_' + id, idx);
+ };
+ updateRowInfo('current', {page: 'current'});
+ updateRowInfo('all', {});
+ }
+ table.on('draw.dt', updateTableInfo);
+ updateTableInfo();
+
+ // state info
+ table.on('draw.dt column-visibility.dt', function() {
+ changeInput('state', table.state());
+ });
+ changeInput('state', table.state());
+
+ // search info
+ var updateSearchInfo = function() {
+ changeInput('search', table.search());
+ if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) {
+ return $(td).find('input').first().val();
+ }));
+ }
+ table.on('draw.dt', updateSearchInfo);
+ updateSearchInfo();
+
+ var cellInfo = function(thiz) {
+ var info = tweakCellIndex(table.cell(thiz));
+ info.value = table.cell(thiz).data();
+ return info;
+ }
+ // the current cell clicked on
+ table.on('click.dt', 'tbody td', function() {
+ changeInput('cell_clicked', cellInfo(this), null, null, {priority: 'event'});
+ })
+ changeInput('cell_clicked', {});
+
+ // do not trigger table selection when clicking on links unless they have classes
+ table.on('click.dt', 'tbody td a', function(e) {
+ if (this.className === '') e.stopPropagation();
+ });
+
+ methods.addRow = function(data, rowname, resetPaging) {
+ var n = table.columns().indexes().length, d = n - data.length;
+ if (d === 1) {
+ data = rowname.concat(data)
+ } else if (d !== 0) {
+ console.log(data);
+ console.log(table.columns().indexes());
+ throw 'New data must be of the same length as current data (' + n + ')';
+ };
+ table.row.add(data).draw(resetPaging);
+ }
+
+ methods.updateSearch = function(keywords) {
+ if (keywords.global !== null)
+ $(table.table().container()).find('input[type=search]').first()
+ .val(keywords.global).trigger('input');
+ var columns = keywords.columns;
+ if (!filterRow || columns === null) return;
+ filterRow.toArray().map(function(td, i) {
+ var v = typeof columns === 'string' ? columns : columns[i];
+ if (typeof v === 'undefined') {
+ console.log('The search keyword for column ' + i + ' is undefined')
+ return;
+ }
+ $(td).find('input').first().val(v);
+ searchColumn(i, v);
+ });
+ table.draw();
+ }
+
+ methods.hideCols = function(hide, reset) {
+ if (reset) table.columns().visible(true, false);
+ table.columns(hide).visible(false);
+ }
+
+ methods.showCols = function(show, reset) {
+ if (reset) table.columns().visible(false, false);
+ table.columns(show).visible(true);
+ }
+
+ methods.colReorder = function(order, origOrder) {
+ table.colReorder.order(order, origOrder);
+ }
+
+ methods.selectPage = function(page) {
+ if (table.page.info().pages < page || page < 1) {
+ throw 'Selected page is out of range';
+ };
+ table.page(page - 1).draw(false);
+ }
+
+ methods.reloadData = function(resetPaging, clearSelection) {
+ // empty selections first if necessary
+ if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]);
+ if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]);
+ if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]);
+ table.ajax.reload(null, resetPaging);
+ }
+
+ table.shinyMethods = methods;
+ },
+ resize: function(el, width, height, instance) {
+ if (instance.data) this.renderValue(el, instance.data, instance);
+
+ // dynamically adjust height if fillContainer = TRUE
+ if (instance.fillContainer)
+ this.fillAvailableHeight(el, height);
+
+ this.adjustWidth(el);
+ },
+
+ // dynamically set the scroll body to fill available height
+ // (used with fillContainer = TRUE)
+ fillAvailableHeight: function(el, availableHeight) {
+
+ // see how much of the table is occupied by header/footer elements
+ // and use that to compute a target scroll body height
+ var dtWrapper = $(el).find('div.dataTables_wrapper');
+ var dtScrollBody = $(el).find($('div.dataTables_scrollBody'));
+ var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight();
+ var scrollBodyHeight = availableHeight - framingHeight;
+
+ // set the height
+ dtScrollBody.height(scrollBodyHeight + 'px');
+ },
+
+ // adjust the width of columns; remove the hard-coded widths on table and the
+ // scroll header when scrollX/Y are enabled
+ adjustWidth: function(el) {
+ var $el = $(el), table = $el.data('datatable');
+ if (table) table.columns.adjust();
+ $el.find('.dataTables_scrollHeadInner').css('width', '')
+ .children('table').css('margin-left', '');
+ }
+});
+
+ if (!HTMLWidgets.shinyMode) return;
+
+ Shiny.addCustomMessageHandler('datatable-calls', function(data) {
+ var id = data.id;
+ var el = document.getElementById(id);
+ var table = el ? $(el).data('datatable') : null;
+ if (!table) {
+ console.log("Couldn't find table with id " + id);
+ return;
+ }
+
+ var methods = table.shinyMethods, call = data.call;
+ if (methods[call.method]) {
+ methods[call.method].apply(table, call.args);
+ } else {
+ console.log("Unknown method " + call.method);
+ }
+ });
+
+})();
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/datatables-css-0.0.0/datatables-crosstalk.css b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/datatables-css-0.0.0/datatables-crosstalk.css
new file mode 100644
index 0000000..fb5bae8
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/datatables-css-0.0.0/datatables-crosstalk.css
@@ -0,0 +1,23 @@
+.dt-crosstalk-fade {
+ opacity: 0.2;
+}
+
+html body div.DTS div.dataTables_scrollBody {
+ background: none;
+}
+
+
+/*
+Fix https://github.com/rstudio/DT/issues/563
+If the `table.display` is set to "block" (e.g., pkgdown), the browser will display
+datatable objects strangely. The search panel and the page buttons will still be
+in full-width but the table body will be "compact" and shorter.
+In therory, having this attributes will affect `dom="t"`
+with `display: block` users. But in reality, there should be no one.
+We may remove the below lines in the future if the upstream agree to have this there.
+See https://github.com/DataTables/DataTablesSrc/issues/160
+*/
+
+table.dataTable {
+ display: table;
+}
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/distill-2.2.21/template.v2.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/distill-2.2.21/template.v2.js
new file mode 100644
index 0000000..3ef99a7
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/distill-2.2.21/template.v2.js
@@ -0,0 +1,744 @@
+function load_distill_framework() {
+(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?t():'function'==typeof define&&define.amd?define(t):t()})(this,function(){'use strict';function e(e,t){e.title=t.title,t.published&&(t.published instanceof Date?e.publishedDate=t.published:t.published.constructor===String&&(e.publishedDate=new Date(t.published))),t.publishedDate&&(t.publishedDate instanceof Date?e.publishedDate=t.publishedDate:t.publishedDate.constructor===String?e.publishedDate=new Date(t.publishedDate):console.error('Don\'t know what to do with published date: '+t.publishedDate)),e.description=t.description,e.authors=t.authors.map((e)=>new Qn(e)),e.katex=t.katex,e.password=t.password}function t(e=document){const t=new Set,n=e.querySelectorAll('d-cite');for(const i of n){const e=i.getAttribute('key').split(',');for(const n of e)t.add(n)}return[...t]}function n(e,t,n,i){if(null==e.author)return'';var a=e.author.split(' and ');let d=a.map((e)=>{if(e=e.trim(),e.match(/\{.+\}/)){var n=/\{([^}]+)\}/,i=n.exec(e);return i[1]}if(-1!=e.indexOf(','))var a=e.split(',')[0].trim(),d=e.split(',')[1];else var a=e.split(' ').slice(-1)[0].trim(),d=e.split(' ').slice(0,-1).join(' ');var r='';return void 0!=d&&(r=d.trim().split(' ').map((e)=>e.trim()[0]),r=r.join('.')+'.'),t.replace('${F}',d).replace('${L}',a).replace('${I}',r)});if(1[${i||'link'}]`}return''}function d(e,t){return'doi'in e?`${t?' ':''} DOI: ${e.doi}`:''}function r(e){return''+e.title+' '}function o(e){if(e){var t=r(e);return t+=a(e)+' ',e.author&&(t+=n(e,'${L}, ${I}',', ',' and '),(e.year||e.date)&&(t+=', ')),t+=e.year||e.date?(e.year||e.date)+'. ':'. ',t+=i(e),t+=d(e),t}return'?'}function l(e){if(e){var t='';t+=''+e.title+'',t+=a(e),t+=' ';var r=n(e,'${I} ${L}',', ')+'.',o=i(e).trim()+' '+e.year+'. '+d(e,!0);return t+=(r+o).length'+o,t}return'?'}function s(e){for(let t of e.authors){const e=!!t.affiliation,n=!!t.affiliations;if(e)if(n)console.warn(`Author ${t.author} has both old-style ("affiliation" & "affiliationURL") and new style ("affiliations") affiliation information!`);else{let e={name:t.affiliation};t.affiliationURL&&(e.url=t.affiliationURL),t.affiliations=[e]}}return console.log(e),e}function c(e){const t=e.querySelector('script');if(t){const e=t.getAttribute('type');if('json'==e.split('/')[1]){const e=t.textContent,n=JSON.parse(e);return s(n)}console.error('Distill only supports JSON frontmatter tags anymore; no more YAML.')}else console.error('You added a frontmatter tag but did not provide a script tag with front matter data in it. Please take a look at our templates.');return{}}function u(){return-1!==['interactive','complete'].indexOf(document.readyState)}function p(e){const t='distill-prerendered-styles',n=e.getElementById(t);if(!n){const n=e.createElement('style');n.id=t,n.type='text/css';const i=e.createTextNode(bi);n.appendChild(i);const a=e.head.querySelector('script');e.head.insertBefore(n,a)}}function g(e,t){console.info('Runlevel 0: Polyfill required: '+e.name);const n=document.createElement('script');n.src=e.url,n.async=!1,t&&(n.onload=function(){t(e)}),n.onerror=function(){new Error('Runlevel 0: Polyfills failed to load script '+e.name)},document.head.appendChild(n)}function f(e,t){return t={exports:{}},e(t,t.exports),t.exports}function h(e){return e.replace(/[\t\n ]+/g,' ').replace(/{\\["^`.'acu~Hvs]( )?([a-zA-Z])}/g,(e,t,n)=>n).replace(/{\\([a-zA-Z])}/g,(e,t)=>t)}function b(e){const t=new Map,n=_i.toJSON(e);for(const i of n){for(const[e,t]of Object.entries(i.entryTags))i.entryTags[e.toLowerCase()]=h(t);i.entryTags.type=i.entryType,t.set(i.citationKey,i.entryTags)}return t}function m(e){return`@article{${e.slug},
+ author = {${e.bibtexAuthors}},
+ title = {${e.title}},
+ journal = {${e.journal.title}},
+ year = {${e.publishedYear}},
+ note = {${e.url}},
+ doi = {${e.doi}}
+}`}function y(e){return`
+
`;for(const i of t){const e='D-TITLE'==i.parentElement.tagName,t=i.getAttribute('no-toc');if(e||t)continue;const a=i.textContent,d='#'+i.getAttribute('id');let r='
Diagrams and text are licensed under Creative Commons Attribution CC-BY 4.0 with the source available on GitHub, unless noted otherwise. The figures that have been reused from other sources don’t fall under this license and can be recognized by a note in their caption: “Figure from …”.
+ `),'undefined'!=typeof e.publishedDate&&(t+=`
+
Citation
+
For attribution in academic contexts, please cite this work as
=k&&(++x,i=k);if(d[x]instanceof n||d[T-1].greedy)continue;w=T-x,y=e.slice(i,k),v.index-=i}if(v){g&&(h=v[1].length);var S=v.index+h,v=v[0].slice(h),C=S+v.length,_=y.slice(0,S),L=y.slice(C),A=[x,w];_&&A.push(_);var E=new n(o,u?a.tokenize(v,u):v,b,v,f);A.push(E),L&&A.push(L),Array.prototype.splice.apply(d,A)}}}}}return d},hooks:{all:{},add:function(e,t){var n=a.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=a.hooks.all[e];if(n&&n.length)for(var d,r=0;d=n[r++];)d(t)}}},i=a.Token=function(e,t,n,i,a){this.type=e,this.content=t,this.alias=n,this.length=0|(i||'').length,this.greedy=!!a};if(i.stringify=function(e,t,n){if('string'==typeof e)return e;if('Array'===a.util.type(e))return e.map(function(n){return i.stringify(n,t,e)}).join('');var d={type:e.type,content:i.stringify(e.content,t,n),tag:'span',classes:['token',e.type],attributes:{},language:t,parent:n};if('comment'==d.type&&(d.attributes.spellcheck='true'),e.alias){var r='Array'===a.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(d.classes,r)}a.hooks.run('wrap',d);var l=Object.keys(d.attributes).map(function(e){return e+'="'+(d.attributes[e]||'').replace(/"/g,'"')+'"'}).join(' ');return'<'+d.tag+' class="'+d.classes.join(' ')+'"'+(l?' '+l:'')+'>'+d.content+''+d.tag+'>'},!t.document)return t.addEventListener?(t.addEventListener('message',function(e){var n=JSON.parse(e.data),i=n.language,d=n.code,r=n.immediateClose;t.postMessage(a.highlight(d,a.languages[i],i)),r&&t.close()},!1),t.Prism):t.Prism;var d=document.currentScript||[].slice.call(document.getElementsByTagName('script')).pop();return d&&(a.filename=d.src,document.addEventListener&&!d.hasAttribute('data-manual')&&('loading'===document.readyState?document.addEventListener('DOMContentLoaded',a.highlightAll):window.requestAnimationFrame?window.requestAnimationFrame(a.highlightAll):window.setTimeout(a.highlightAll,16))),t.Prism}();e.exports&&(e.exports=n),'undefined'!=typeof Ti&&(Ti.Prism=n),n.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},n.hooks.add('wrap',function(e){'entity'===e.type&&(e.attributes.title=e.content.replace(/&/,'&'))}),n.languages.xml=n.languages.markup,n.languages.html=n.languages.markup,n.languages.mathml=n.languages.markup,n.languages.svg=n.languages.markup,n.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},n.languages.css.atrule.inside.rest=n.util.clone(n.languages.css),n.languages.markup&&(n.languages.insertBefore('markup','tag',{style:{pattern:/(
+
+
+
+`);class Ni extends ei(Ii(HTMLElement)){renderContent(){if(this.languageName=this.getAttribute('language'),!this.languageName)return void console.warn('You need to provide a language attribute to your block to let us know how to highlight your code; e.g.:\n zeros = np.zeros(shape).');const e=Ui.languages[this.languageName];if(void 0==e)return void console.warn(`Distill does not yet support highlighting your code block in "${this.languageName}'.`);let t=this.textContent;const n=this.shadowRoot.querySelector('#code-container');if(this.hasAttribute('block')){t=t.replace(/\n/,'');const e=t.match(/\s*/);if(t=t.replace(new RegExp('\n'+e,'g'),'\n'),t=t.trim(),n.parentNode instanceof ShadowRoot){const e=document.createElement('pre');this.shadowRoot.removeChild(n),e.appendChild(n),this.shadowRoot.appendChild(e)}}n.className=`language-${this.languageName}`,n.innerHTML=Ui.highlight(t,e)}}const ji=ti('d-footnote',`
+
+
+
+
+
+`,!1);class Fi extends qi(HTMLElement){connectedCallback(){super.connectedCallback(),this.list=this.root.querySelector('ol'),this.root.style.display='none'}set footnotes(e){if(this.list.innerHTML='',e.length){this.root.style.display='';for(const t of e){const e=document.createElement('li');e.id=t.id+'-listing',e.innerHTML=t.innerHTML;const n=document.createElement('a');n.setAttribute('class','footnote-backlink'),n.textContent='[\u21A9]',n.href='#'+t.id,e.appendChild(n),this.list.appendChild(e)}}else this.root.style.display='none'}}const Pi=ti('d-hover-box',`
+
+
+
+
+
+
+
+`);class Hi extends Pi(HTMLElement){constructor(){super()}connectedCallback(){}listen(e){this.bindDivEvents(this),this.bindTriggerEvents(e)}bindDivEvents(e){e.addEventListener('mouseover',()=>{this.visible||this.showAtNode(e),this.stopTimeout()}),e.addEventListener('mouseout',()=>{this.extendTimeout(500)}),e.addEventListener('touchstart',(e)=>{e.stopPropagation()},{passive:!0}),document.body.addEventListener('touchstart',()=>{this.hide()},{passive:!0})}bindTriggerEvents(e){e.addEventListener('mouseover',()=>{this.visible||this.showAtNode(e),this.stopTimeout()}),e.addEventListener('mouseout',()=>{this.extendTimeout(300)}),e.addEventListener('touchstart',(t)=>{this.visible?this.hide():this.showAtNode(e),t.stopPropagation()},{passive:!0})}show(e){this.visible=!0,this.style.display='block',this.style.top=Pn(e[1]+10)+'px'}showAtNode(e){const t=e.getBoundingClientRect();this.show([e.offsetLeft+t.width,e.offsetTop+t.height])}hide(){this.visible=!1,this.style.display='none',this.stopTimeout()}stopTimeout(){this.timeout&&clearTimeout(this.timeout)}extendTimeout(e){this.stopTimeout(),this.timeout=setTimeout(()=>{this.hide()},e)}}class zi extends HTMLElement{static get is(){return'd-title'}}const Yi=ti('d-references',`
+
+`,!1);class Bi extends Yi(HTMLElement){}class Wi extends HTMLElement{static get is(){return'd-toc'}connectedCallback(){this.getAttribute('prerendered')||(window.onload=()=>{const e=document.querySelector('d-article'),t=e.querySelectorAll('h2, h3');k(this,t)})}}class Vi extends HTMLElement{static get is(){return'd-figure'}static get readyQueue(){return Vi._readyQueue||(Vi._readyQueue=[]),Vi._readyQueue}static addToReadyQueue(e){-1===Vi.readyQueue.indexOf(e)&&(Vi.readyQueue.push(e),Vi.runReadyQueue())}static runReadyQueue(){const e=Vi.readyQueue.sort((e,t)=>e._seenOnScreen-t._seenOnScreen).filter((e)=>!e._ready).pop();e&&(e.ready(),requestAnimationFrame(Vi.runReadyQueue))}constructor(){super(),this._ready=!1,this._onscreen=!1,this._offscreen=!0}connectedCallback(){this.loadsWhileScrolling=this.hasAttribute('loadsWhileScrolling'),Vi.marginObserver.observe(this),Vi.directObserver.observe(this)}disconnectedCallback(){Vi.marginObserver.unobserve(this),Vi.directObserver.unobserve(this)}static get marginObserver(){if(!Vi._marginObserver){const e=window.innerHeight,t=Fn(2*e),n=Vi.didObserveMarginIntersection,i=new IntersectionObserver(n,{rootMargin:t+'px 0px '+t+'px 0px',threshold:0.01});Vi._marginObserver=i}return Vi._marginObserver}static didObserveMarginIntersection(e){for(const t of e){const e=t.target;t.isIntersecting&&!e._ready&&Vi.addToReadyQueue(e)}}static get directObserver(){return Vi._directObserver||(Vi._directObserver=new IntersectionObserver(Vi.didObserveDirectIntersection,{rootMargin:'0px',threshold:[0,1]})),Vi._directObserver}static didObserveDirectIntersection(e){for(const t of e){const e=t.target;t.isIntersecting?(e._seenOnScreen=new Date,e._offscreen&&e.onscreen()):e._onscreen&&e.offscreen()}}addEventListener(e,t){super.addEventListener(e,t),'ready'===e&&-1!==Vi.readyQueue.indexOf(this)&&(this._ready=!1,Vi.runReadyQueue()),'onscreen'===e&&this.onscreen()}ready(){this._ready=!0,Vi.marginObserver.unobserve(this);const e=new CustomEvent('ready');this.dispatchEvent(e)}onscreen(){this._onscreen=!0,this._offscreen=!1;const e=new CustomEvent('onscreen');this.dispatchEvent(e)}offscreen(){this._onscreen=!1,this._offscreen=!0;const e=new CustomEvent('offscreen');this.dispatchEvent(e)}}if('undefined'!=typeof window){Vi.isScrolling=!1;let e;window.addEventListener('scroll',()=>{Vi.isScrolling=!0,clearTimeout(e),e=setTimeout(()=>{Vi.isScrolling=!1,Vi.runReadyQueue()},500)},!0)}const Ki=ti('d-interstitial',`
+
+
+
+
+
This article is in review.
+
Do not share this URL or the contents of this article. Thank you!
+
+
Enter the password we shared with you as part of the review process to view the article.
/g,">").replace(/"/g,"""):a};q.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return ib(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+a)+f+(e||"")}}},text:function(){return{display:ib,filter:ib}}};f.extend(q.ext.internal,{_fnExternApiFunc:Qb,_fnBuildAjax:va,_fnAjaxUpdate:qb,_fnAjaxParameters:zb,_fnAjaxUpdateDraw:Ab,_fnAjaxDataSrc:wa,_fnAddColumn:Ia,_fnColumnOptions:ma,_fnAdjustColumnSizing:aa,_fnVisibleToColumnIndex:ba,_fnColumnIndexToVisible:ca,_fnVisbleColumns:W,_fnGetColumns:oa,_fnColumnTypes:Ka,_fnApplyColumnDefs:nb,_fnHungarianMap:H,_fnCamelToHungarian:L,_fnLanguageCompat:Ga,_fnBrowserDetect:lb,_fnAddData:R,_fnAddTr:pa,_fnNodeToDataIndex:function(a,
+b){return b._DT_RowIndex!==p?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return f.inArray(c,a.aoData[b].anCells)},_fnGetCellData:I,_fnSetCellData:ob,_fnSplitObjNotation:Na,_fnGetObjectDataFn:U,_fnSetObjectDataFn:Q,_fnGetDataMaster:Oa,_fnClearTable:qa,_fnDeleteIndex:ra,_fnInvalidate:ea,_fnGetRowElements:Ma,_fnCreateTr:La,_fnBuildHead:pb,_fnDrawHead:ha,_fnDraw:S,_fnReDraw:V,_fnAddOptionsHtml:sb,_fnDetectHeader:fa,_fnGetUniqueThs:ua,_fnFeatureHtmlFilter:ub,_fnFilterComplete:ia,_fnFilterCustom:Db,
+_fnFilterColumn:Cb,_fnFilter:Bb,_fnFilterCreateSearch:Ta,_fnEscapeRegex:Ua,_fnFilterData:Eb,_fnFeatureHtmlInfo:xb,_fnUpdateInfo:Hb,_fnInfoMacros:Ib,_fnInitialise:ja,_fnInitComplete:xa,_fnLengthChange:Va,_fnFeatureHtmlLength:tb,_fnFeatureHtmlPaginate:yb,_fnPageChange:Xa,_fnFeatureHtmlProcessing:vb,_fnProcessingDisplay:K,_fnFeatureHtmlTable:wb,_fnScrollDraw:na,_fnApplyToChildren:N,_fnCalculateColumnWidths:Ja,_fnThrottle:Sa,_fnConvertToWidth:Jb,_fnGetWidestNode:Kb,_fnGetMaxLenString:Lb,_fnStringToCss:B,
+_fnSortFlatten:Y,_fnSort:rb,_fnSortAria:Nb,_fnSortListener:Za,_fnSortAttachListener:Qa,_fnSortingClasses:Aa,_fnSortData:Mb,_fnSaveState:Ba,_fnLoadState:Ob,_fnSettingsFromNode:Ca,_fnLog:O,_fnMap:M,_fnBindAction:$a,_fnCallbackReg:E,_fnCallbackFire:A,_fnLengthOverflow:Wa,_fnRenderer:Ra,_fnDataSource:D,_fnRowAttributes:Pa,_fnExtend:ab,_fnCalculateEnd:function(){}});f.fn.dataTable=q;q.$=f;f.fn.dataTableSettings=q.settings;f.fn.dataTableExt=q.ext;f.fn.DataTable=function(a){return f(this).dataTable(a).api()};
+f.each(q,function(a,b){f.fn.DataTable[a]=b});return f.fn.dataTable});
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal line chart visual-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal line chart visual-1.png
new file mode 100644
index 0000000..71ecac4
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal line chart visual-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal together visual-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal together visual-1.png
new file mode 100644
index 0000000..0d82695
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal together visual-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal visual-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal visual-1.png
new file mode 100644
index 0000000..e4218fc
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/cereal visual-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/debt in trillions visual-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/debt in trillions visual-1.png
new file mode 100644
index 0000000..7abe4cf
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/debt in trillions visual-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/debt in trillions visual-2.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/debt in trillions visual-2.png
new file mode 100644
index 0000000..21e5b4c
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/debt in trillions visual-2.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/putting time graphs together-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/putting time graphs together-1.png
new file mode 100644
index 0000000..e7dfbbf
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/putting time graphs together-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visual year and quarter-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visual year and quarter-1.png
new file mode 100644
index 0000000..2d02633
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visual year and quarter-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visualize with zoo-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visualize with zoo-1.png
new file mode 100644
index 0000000..8598e38
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visualize with zoo-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visualizing through time-1.png b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visualizing through time-1.png
new file mode 100644
index 0000000..cfa1143
Binary files /dev/null and b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/figure-html5/visualizing through time-1.png differ
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/header-attrs-2.11/header-attrs.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/header-attrs-2.11/header-attrs.js
new file mode 100644
index 0000000..dd57d92
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/header-attrs-2.11/header-attrs.js
@@ -0,0 +1,12 @@
+// Pandoc 2.9 adds attributes on both header and div. We remove the former (to
+// be compatible with the behavior of Pandoc < 2.8).
+document.addEventListener('DOMContentLoaded', function(e) {
+ var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
+ var i, h, a;
+ for (i = 0; i < hs.length; i++) {
+ h = hs[i];
+ if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
+ a = h.attributes;
+ while (a.length > 0) h.removeAttribute(a[0].name);
+ }
+});
diff --git a/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/htmlwidgets-1.5.4/htmlwidgets.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/htmlwidgets-1.5.4/htmlwidgets.js
new file mode 100644
index 0000000..da8b236
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/htmlwidgets-1.5.4/htmlwidgets.js
@@ -0,0 +1,903 @@
+(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%";
+ if (cel) {
+ 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.offsetWidth; },
+ getHeight: function() { return cel.offsetHeight; }
+ };
+
+ } else {
+ el.style.width = px(sizing.width);
+ el.style.height = px(sizing.height);
+
+ return {
+ getWidth: function() { return el.offsetWidth; },
+ getHeight: function() { return el.offsetHeight; }
+ };
+ }
+ }
+
+ // 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 result = bindingDef.initialize(el, el.offsetWidth,
+ el.offsetHeight);
+ 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);
+
+ if (hasClass(el, "html-widget-static-bound"))
+ return;
+ el.className = el.className + " html-widget-static-bound";
+
+ var initResult;
+ if (binding.initialize) {
+ initResult = binding.initialize(el,
+ sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ );
+ elementData(el, "init_result", initResult);
+ }
+
+ if (binding.resize) {
+ var lastSize = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ var resizeHandler = function(e) {
+ var size = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ 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/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/jquery-3.6.0/jquery-3.6.0.js b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/jquery-3.6.0/jquery-3.6.0.js
new file mode 100644
index 0000000..fc6c299
--- /dev/null
+++ b/_posts/2021-10-05-homework-4-molly-hackbarth/homework-4_files/jquery-3.6.0/jquery-3.6.0.js
@@ -0,0 +1,10881 @@
+/*!
+ * jQuery JavaScript Library v3.6.0
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright OpenJS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2021-03-02T17:08Z
+ */
+( 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