diff --git a/_quarto.yml b/_quarto.yml
index 2f8ca7b..ffd8a87 100644
--- a/_quarto.yml
+++ b/_quarto.yml
@@ -2,7 +2,8 @@ project:
type: website
render:
- "*.qmd"
- - "!old_posts/"
+ - "*.rmd"
+ - "!old_posts/" #using for the time being to store old blog post while converting
website:
title: "Kyle Belanger"
diff --git a/_site/blog.html b/_site/blog.html
index 6be9fcb..2a34b64 100644
--- a/_site/blog.html
+++ b/_site/blog.html
@@ -156,7 +156,7 @@ ul.task-list li input[type="checkbox"] {
-
Categories
All (1)
+
Categories
All (4)
@@ -169,7 +169,91 @@ ul.task-list li input[type="checkbox"] {
Todays post is a lesson in Facets, as well as humility. The task this week was to replicate the graph in Chapter 8 of Tableau for Healthcare in R. The graph in question is called a Table Lens (This is the name the book uses, however I did have trouble finding this name in Google searches), it is a collection of charts with a common theme, this time looking at countries in various WHO regions and some statistics associated with mortality as well as health expenditure. I say this is a lesson in humiltiy as I have read through the excellent book R for Data Science, and yet the idea of faceting a ggplot graph slipped my mind. This ended with hours of trying to find a package in R to line up graphs, and way more time then I care to admit spent on getting things prefect. I did find such a package called cowplots, which can be found here. While this is an excellent package, its use was unecessary and I reverted back to using the excellent facet feature of GGplot, which can be seen below!
ds <- readxl::read_xlsx(path ="../2020-01-04_my-start-to-r/Tableau 10 Training Practice Data.xlsx"
+ ,sheet ="03 - WHO Life Expect & Mort"
+ )
+
+
+
+
Clean Names and Transform
+
+
varnames <-c("who_region", "country", "year" , "sex" , "life_expect_birth" , "neo_mort"
+ ,"under_five_mort" , "health_expenditure")
+names(ds) <- varnames
+
+# Order Countries based on Life Expectancy at Birth
+
+ds$country <-factor(ds$country, levels = ds$country[order(ds$life_expect_birth)])
+
+#To "Long" Form
+
+ds1 <- ds %>%pivot_longer(5:8)#select columns 5 throuh 8, leave new columns at default names
+
+# Set up labels for Facet, as well as function for Facet Labeller
+
+facet_labels <-list(
+"life_expect_birth"="Life Expectancy at Birth "
+,"neo_mort"="Neonatal Mortality Rate"
+,"under_five_mort"="Under-Five Mortality Rate"
+,"health_expenditure"="Health Expenditure per Capita (US$)" )
+
+variable_labeller <-function(variable,value){
+return(facet_labels[value])
+}
Today’s post is all about line graphs using both ggplot for a static graph as well as a package called plotly for interactivity (more on this later). The example graph and data is again coming from Tableau for Healthcare, Chapter 10.
+
+
Load Libraries
+
As always first step is to load in our libraries, I am using quite a few here, some are a bit overkill for this example but I wanted to play around with some fun features today.
+
+
library(magrittr) #pipes
+library(ggplot2) #ploting
+library(dplyr) # data manipulation
+library(tidyr) # tidy data
+library(lubridate) #work with dates
+library(stringr) # manipulate strings
+library(plotly)
+
+
+
+
Import Data
+
Next lets import our data, this week we are using the sheet Flu Occurrence FY2013-2016. I am unsure if this is form a real data set or not but it is good for demonstration purposes! After importing we can glimpse at our data to understand what is contained within.
+
+
ds <- readxl::read_xlsx(path ="../2020-01-04_my-start-to-r/Tableau 10 Training Practice Data.xlsx"
+ ,sheet ="05 - Flu Occurrence FY2013-2016"
+ )
+ds %>%glimpse()
I went a bit overboard today with renaming the variables. I wanted to practice writing a function and while it might not be the prettiest or the best way to do this, it worked for what I was trying to accomplish. Note the use of sapply, which lets us run the function on each column name.
+
+
format_names <-function(x) {
+#Fucntion to set all names to lower case, and strip unneeded characters
+ x <-tolower(x)
+ x <-str_replace_all(x,c(#set each pattern equal to replacement
+" "="_"
+ ,"\\(\\+\\)"="pos"#regualr experssion to match (+)
+ ,"\\("=""
+ ,"\\)"=""
+ ,"\\%"="pct"
+ )
+ )
+ }
+
+#run the format name function on all names from DS
+colnames(ds) <-sapply(colnames(ds),format_names)
+
+
Now is were the fun really starts! For this particular data set there are a couple things we need to add to replicate the example. In the original data set the date is stored with month, day, and year; the day is irrelevant and we need to pull out the month as well as the year. For this we can use the lubridate package, first we pull out the month and set it as a factor. For this example our year actually starts in October, so we set our factor to start at October (10), and end with September (9). We then pull out the year, which presents us with a different problem. Again our year starts in October, instead of January. To solve this I have created a variable called date adjustment, in this column is our month is 10 or greater, we will place a 1, if not a 0. We then set our fiscal year to be the actual year plus the date adjustment, this allows us to have our dates in the right fiscal year. Last the percent column is currently listed as a decimal, so we will convert this to a percentage.
+
+
# split date time
+ds1 <- ds %>%mutate(
+#create month column, then set factors and labels to start fiscal year in Oct
+month =month(ds$date)
+ ,month =factor(month
+ ,levels =c(10:12, 1:9)
+ ,labels =c(month.abb[10:12],month.abb[1:9]))
+ ,year =year(ds$date)
+ ,date_adjustment =ifelse(month(ds$date) >=10, 1,0 )
+ ,fiscal_year =factor(year + date_adjustment)
+#convert % Pos from decmial to pct
+ ,pct_tests_pos_for_influenza =round(pct_tests_pos_for_influenza *100, digits =0)
+ )
+
+ds1 %>%glimpse()
The graph here is pretty straight forward with one exception, group! For this line graph we want ggplot to connect the lines of the same year, if we do not explicitly state this using the group mapping, ggplot will try to connect all the lines together, which of course is not at all what we want!
One of the nice features of Tableau is the fact the graphs are interactive, while a good graph should speak for itself, end users love pretty things. I have been experimenting with Plotly, which has an open source package for R (as well as many other programming languages!). This example only just scratches the surface, but there will be many more to come!
Today I am going to dive into some real life data from the World Health Organization (WHO), exploring new and relapse cases of Tuberculosis. I clean up the data, and then make a few graphs to explore different variables.
Today I am going to dive into some real life data from the World Health Organization (WHO), exploring new and relapse cases of Tuberculosis. I clean up the data, and then make a few graphs to explore different variables.
+
+
+
Load Packages
+
Since I am going to use quite a few packages in the tidyverse I am going to load them all in at once instead of individually.
+
+
library(tidyverse)
+
+
+
+
Load in Data
+
We are using the WHO data set which contains tuberculosis (TB) cases broken down by year, this data set is contained in the Tidyr package, however its only recent up to 2014. For a little added fun I have downloaded the latest data from the WHO website, Found here. For some added fun I have also included GDP per Capita data from World bank Found here
+
+
who_raw <-read.csv("TB_notifications_2020-02-11.csv")
+
+#GPD file contains 4 rows of instrusctions above the actually data, we can tell
+#read.csv to skip these using the skip command
+gpd_raw <-read.csv("API_NY.GDP.PCAP.CD_DS2_en_csv_v2_713080.csv",
+skip =4)
+
+
+
+
Transform
+
This data set is very ugly looking! The first 3 columns are all country Identifiers, with column four indicating the WHO region. This is redundant and can be dropped down to one Identifier and Region. As we can see there are quite a few Variable columns that are in fact values and not true Variables. When reading the data dictionary for this data set, WHO has changed their reporting over the years, so for our purposes we can strip a lot of the extra data out. Lets try and look at three types of TB, Extrapulmonary, Lab Diagnosed, and Clinician Diagnosed. As well as try and look at the breakdowns by Age and Sex of new and relapse case (post 2012) Lots of Cleaning to do, lets get to it!
+
+
who1 <- who_raw %>%
+#lets drop some columns not needed for our exploration, what each column means can be found in the CSV Data dictionary file
+select(-iso2
+ ,-iso_numeric
+ ,-(rdx_data_available:hiv_reg_new2)
+ ,-(new_sp:rel_in_agesex_flg)
+ ) %>%
+#Lets just look at new date
+filter(year >=2013) %>%
+#Move the values that are currently stored as variables to observations
+pivot_longer(cols = newrel_m04:newrel_sexunkageunk
+ ,names_to ="key"
+ ,values_to ="values"
+ ) %>%
+separate(col = key
+ ,into =c("new","sexage")
+ ,sep ="_"
+ ) %>%
+#the data set contains male, female and unknown
+mutate_if(is.character
+ ,str_replace_all
+ ,pattern ="sexunk"
+ , replacement ="u"
+ ) %>%
+separate(col = sexage
+ ,into =c("sex","age")
+ ,sep =1) %>%
+mutate(age_start =case_when(
+str_detect(age, "65") ~"65"
+ ,(str_length(age) ==2) ~str_match(age, "\\S")
+ ,(str_length(age) ==3) ~str_match(age, "\\S")
+ ,(str_length(age) ==4) ~str_match(age, "\\S\\S")
+
+ ,TRUE~""
+ )
+ ,age_end =case_when(
+str_detect(age, "65") ~"& Over"
+ ,(str_length(age) ==2) ~str_match(age, "\\S$")
+ ,(str_length(age) ==3) ~str_match(age, "\\S\\S$")
+ ,(str_length(age) ==4) ~str_match(age, "\\S\\S$")
+ ,TRUE~""
+ ))
+
+#overall WHO data is now cleaned and tidy.
+
+# Lets tidy up the GPD data so we can match it to our WHO data set
+gdp1 <- gpd_raw %>%
+select(-(Indicator.Name:X2012)
+ ,-X2019
+ ,-X) %>%
+pivot_longer(cols = X2013:X2018
+ ,names_to ="year"
+ ,values_to ="gdp") %>%
+mutate_if(is.character
+ ,str_remove_all
+ ,pattern ="X(?=\\d*)") # regex to check for an X followed by a digit
+
+
+
+
Join Data
+
Lets combine the data sets so we can later visual TB Cases based on a countries GDP per capita.
We can see in the graph above there seems to be a small correlation between lower GDP and amount of TB cases.
+
+
+
A different way to look
+
Could there be any correlation between a countries population and the amount of TB cases? Maybe its just as simple as having more people means more people to get sick? Lets bring in another data set, again from World Bank Found Here, this contains total population data by country.
+
+
pop_raw <-read.csv("API_SP.POP.TOTL_DS2_en_csv_v2_713131.csv"
+ ,skip =4)
+#If this looks famialer its because it is, the data set looks very simalar to the GDP data
+#In the future this could be moved to a function to allow cleaning much easier
+pop1 <- pop_raw %>%
+select(-(Indicator.Name:X2012)
+ ,-X2019
+ ,-X) %>%
+pivot_longer(cols = X2013:X2018
+ ,names_to ="year"
+ ,values_to ="population") %>%
+mutate_if(is.character
+ ,str_remove_all
+ ,pattern ="X(?=\\d*)")
+
+#now lets combine this into are overall data set
+
+who_combined <- who_combined %>%
+mutate(year =as.character(year)) %>%
+left_join(y = pop1) %>%
+select(-Country.Name)
+
+#now lets Graph again
+
+g3 <- who_combined %>%
+filter(str_detect(age,"014|15plus|u"),year ==2018) %>%
+group_by(country) %>%
+summarise(sum_tb_cases = (sum(values,na.rm =TRUE)/10000)
+ ,population =first(population)/1000000
+ ,who_region =first(g_whoregion)) %>%
+mutate(
+label =ifelse((population>250), yes =as.character(country),no ="")) %>%
+ggplot(aes(x = population, y = sum_tb_cases )) +
+geom_point(aes(color = who_region)) +
+ ggrepel::geom_text_repel(aes(x = population, y = sum_tb_cases, label = label)) +
+labs(
+title ="Total TB Cases by Country compared to Gross Domestic Product (GDP)"
+ ,x ="Population (in Millions)"
+ ,y ="Total TB Case (per 10,000 cases)"
+ ,color ="WHO Region"
+ ) +
+theme_bw()
+
+ g3
+
+
+
+
+
+
Further Exploration
+
Maybe we are on to something, the more people, the more likely they are to get sick! However India seems to have a very large number of cases so lets break these cases down further by age group for 2018.
+
+
g4 <- who_combined %>%
+filter(year ==2018
+ ,country =="India"
+ ,!(str_detect(age,"15plus|ageunk|u|014"))
+ ,(str_detect(sex,"m|f"))
+ ) %>%
+mutate(age_range = glue::glue("{age_start} -- {age_end}")) %>%
+ggplot(aes(x =reorder(age_range, as.numeric(age_start)), y = (values/1000), fill = sex)) +
+geom_col(position ="dodge") +
+labs(
+title ="TB Case in India by age and gender 2018"
+ ,x =NULL
+ ,y ="Total Cases (per 1000)"
+ ,fill ="Gender") +
+scale_fill_manual(labels =c("Female","Male"), values =c("#e9a3c9","#67a9cf") )
+
+g4
+
+
+
+
+
There seems to be a huge spike in cases after adolescences. Females have a sharp decline the older they get, where as male case stay elevated with a slight decrease at 55.
+
+
+
+
Last Exploration
+
Lets look at overall cases in India, going back to 1980 and see if there as been any trends. To get these numbers we will go back to our raw data and strip everything out expect the total count
+
+
g5 <- who_raw %>%
+filter(country =="India") %>%
+select(year, c_newinc) %>%
+ggplot(aes(x = year, y = c_newinc/1000000)) +
+geom_line() +
+geom_point() +
+labs(
+title ="New and Relapse Tuberculosis Cases In India \n1980 -- 2018"
+ ,x =NULL
+ ,y ="Total Cases (in millions)") +
+theme_bw() +
+theme(plot.title =element_text(hjust =0.5)) +#center title
+scale_x_continuous(breaks =seq(1980,2020,5)) +
+scale_y_continuous(breaks = scales::pretty_breaks(n=10)) #different way to add tick marks
+g5
+
+
+
+
+
Cases were steadily rising from 1980 to 1990, then suddenly feel off. Starting in the early 2010s there was a sharp increase and the amount of new and relapse cases just keep growing.
+
+
+
+
Next Steps
+
While no other country has the amount of cases that India does, the sudden spike in cases at adolescences asks the question do other countries follow this same trend? We can also see the sudden spike in the 2010s, again is this just based in India or do we see this trend in other countries. There is much more exploration we can do with this data set at a later time!
@online{belanger2020,
+ author = {Belanger, Kyle},
+ title = {Basic {Exploration} of {WHO} {Tuberculosis} {Data}},
+ date = {2020-02-13},
+ langid = {en}
+}
+
For attribution, please cite this work as:
+Belanger, Kyle. 2020. “Basic Exploration of WHO Tuberculosis
+Data.” February 13, 2020.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-5-1.png b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-5-1.png
new file mode 100644
index 0000000..6654801
Binary files /dev/null and b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-5-1.png differ
diff --git a/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-6-1.png b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-6-1.png
new file mode 100644
index 0000000..15e321e
Binary files /dev/null and b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-6-1.png differ
diff --git a/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-7-1.png b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-7-1.png
new file mode 100644
index 0000000..76dadac
Binary files /dev/null and b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-7-1.png differ
diff --git a/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-8-1.png b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-8-1.png
new file mode 100644
index 0000000..c7f95c4
Binary files /dev/null and b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-8-1.png differ
diff --git a/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-9-1.png b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-9-1.png
new file mode 100644
index 0000000..450ffc0
Binary files /dev/null and b/_site/posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data_files/figure-html/unnamed-chunk-9-1.png differ
diff --git a/_site/search.json b/_site/search.json
index 81766a6..da44963 100644
--- a/_site/search.json
+++ b/_site/search.json
@@ -39,7 +39,7 @@
"href": "blog.html",
"title": "Posts",
"section": "",
- "text": "My Start to R\n\n\nA short introduction to my blog, and R journey.\n\n\n\n\n\n\n\n\n\nJan 24, 2020\n\n\nKyle Belanger\n\n\n\n\n\n\nNo matching items"
+ "text": "Basic Exploration of WHO Tuberculosis Data\n\n\nToday I am going to dive into some real life data from the World Health Organization (WHO), exploring new and relapse cases of Tuberculosis. I clean up the data, and then make a few graphs to explore different variables.\n\n\n\n\n\n\n\n\n\nFeb 13, 2020\n\n\nKyle Belanger\n\n\n\n\n\n\n \n\n\n\n\nLine Graphs and Interactivity\n\n\nTableau for Healthcare Chapter 10. Static and Interactive examples\n\n\n\n\n\n\n\n\n\nFeb 10, 2020\n\n\nKyle Belanger\n\n\n\n\n\n\n \n\n\n\n\nFacets and a Lesson in Humility\n\n\nA look at Tableau for Healthcare Chapter 8. Table Lens graph.\n\n\n\n\n\n\n\n\n\nJan 29, 2020\n\n\nKyle Belanger\n\n\n\n\n\n\n \n\n\n\n\nMy Start to R\n\n\nA short introduction to my blog, and R journey.\n\n\n\n\n\n\n\n\n\nJan 24, 2020\n\n\nKyle Belanger\n\n\n\n\n\n\nNo matching items"
},
{
"objectID": "posts/post-with-code/index.html",
@@ -54,5 +54,75 @@
"title": "My Start to R",
"section": "",
"text": "Today starts my attempt at sharing my R journey with the world! I have been learning R off and on now since late 2019, I have begun to take it much more serious as I work through my Data Analytics class at UCF. My love for all things numbers and graphs has really blossomed, and I am choosing to share that love with anyone who cares to read. I will not claim to be the best at R, or any programming for that matter, but these are my attempts. Each post in this serious will be replicated a graph created in Tableau from the book Tableau for Healthcare. Todays graph is a simple horizontal bar chart, in transferring to both a new blog site and computer I have unfortunately lost the original bar graph, but trust me the one I created looks just like it.\n\nLoad Libraries\n\nlibrary(tidyr)\nlibrary(magrittr)\nlibrary(ggplot2)\nlibrary(stringr)\nlibrary(dplyr)\n\n\n\nImport Data\n\nds <- readxl::read_excel(\n path = \"Tableau 10 Training Practice Data.xlsx\" \n ,sheet = \"02 - Patient Falls-Single Hosp\"\n )\n\n\n\nClean Data Names\n\n#should make reusable forumla at later time\nnames(ds) <- tolower(names(ds))\nnames(ds) <- str_replace_all(names(ds),\" \", \"_\")\n\n\n\nConvert Data to ‘Long Form’\n\nds1 <- ds %>% \n gather(\"patient_falls_no_injury_rate\" , \"patient_falls_with_injury_rate\"\n ,key = \"injury\" \n ,value = \"rate\" ) %>% \n mutate(injury = (injury == \"patient_falls_with_injury_rate\"))\n\n\n\nGraph 5.1\n\nb1 <- ds %>% \n ggplot(mapping = aes(x = reorder(type_of_care,total_patient_falls_rate ) , y = total_patient_falls_rate)) +\n geom_col(fill = \"#2b83ba\") + \n coord_flip() +\n scale_y_continuous(breaks = NULL) +\n theme(axis.ticks = element_blank()) +\n labs(title = \"Rate of Patient Falls (per 1,000 Pateint Days)\\nby Type of Care for FY2017\"\n ,x = NULL\n ,y = NULL\n ) +\n theme_classic() +\n geom_text(aes(label = format(total_patient_falls_rate, digits = 2)), nudge_y = -.25, color = \"white\")\n \nb1\n\n\n\n\n\n\n\n\nCitationBibTeX citation:@online{belanger2020,\n author = {Belanger, Kyle},\n title = {My {Start} to {R}},\n date = {2020-01-24},\n langid = {en}\n}\nFor attribution, please cite this work as:\nBelanger, Kyle. 2020. “My Start to R.” January 24, 2020."
+ },
+ {
+ "objectID": "posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data.html",
+ "href": "posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data.html",
+ "title": "Basic Exploration of WHO Tuberculosis Data",
+ "section": "",
+ "text": "Today I am going to dive into some real life data from the World Health Organization (WHO), exploring new and relapse cases of Tuberculosis. I clean up the data, and then make a few graphs to explore different variables."
+ },
+ {
+ "objectID": "posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data.html#a-different-way-to-look",
+ "href": "posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data.html#a-different-way-to-look",
+ "title": "Basic Exploration of WHO Tuberculosis Data",
+ "section": "A different way to look",
+ "text": "A different way to look\nCould there be any correlation between a countries population and the amount of TB cases? Maybe its just as simple as having more people means more people to get sick? Lets bring in another data set, again from World Bank Found Here, this contains total population data by country.\n\npop_raw <- read.csv(\"API_SP.POP.TOTL_DS2_en_csv_v2_713131.csv\"\n ,skip = 4)\n#If this looks famialer its because it is, the data set looks very simalar to the GDP data\n#In the future this could be moved to a function to allow cleaning much easier\npop1 <- pop_raw %>% \n select(-(Indicator.Name:X2012)\n ,-X2019\n ,-X) %>% \n pivot_longer(cols = X2013:X2018\n ,names_to = \"year\" \n ,values_to = \"population\") %>% \n mutate_if(is.character\n ,str_remove_all\n ,pattern = \"X(?=\\\\d*)\")\n\n#now lets combine this into are overall data set\n\nwho_combined <- who_combined %>% \n mutate(year = as.character(year)) %>% \n left_join(y = pop1) %>% \n select(-Country.Name)\n\n#now lets Graph again\n\ng3 <- who_combined %>% \n filter(str_detect(age,\"014|15plus|u\"),year == 2018) %>% \n group_by(country) %>% \n summarise(sum_tb_cases = (sum(values,na.rm = TRUE)/10000)\n ,population = first(population)/1000000\n ,who_region = first(g_whoregion)) %>% \n mutate(\n label = ifelse((population>250), yes = as.character(country),no = \"\")) %>%\n ggplot(aes(x = population, y = sum_tb_cases )) +\n geom_point(aes(color = who_region)) +\n ggrepel::geom_text_repel(aes(x = population, y = sum_tb_cases, label = label)) +\n labs(\n title = \"Total TB Cases by Country compared to Gross Domestic Product (GDP)\"\n ,x = \"Population (in Millions)\"\n ,y = \"Total TB Case (per 10,000 cases)\"\n ,color = \"WHO Region\"\n ) +\n theme_bw() \n\n g3 \n\n\n\n\n\nFurther Exploration\nMaybe we are on to something, the more people, the more likely they are to get sick! However India seems to have a very large number of cases so lets break these cases down further by age group for 2018.\n\ng4 <- who_combined %>% \n filter(year == 2018\n ,country == \"India\"\n ,!(str_detect(age,\"15plus|ageunk|u|014\"))\n ,(str_detect(sex,\"m|f\"))\n ) %>% \n mutate(age_range = glue::glue(\"{age_start} -- {age_end}\")) %>% \n ggplot(aes(x = reorder(age_range, as.numeric(age_start)), y = (values/1000), fill = sex)) +\n geom_col(position = \"dodge\") +\n labs(\n title = \"TB Case in India by age and gender 2018\"\n ,x = NULL\n ,y = \"Total Cases (per 1000)\"\n ,fill = \"Gender\") +\n scale_fill_manual(labels = c(\"Female\",\"Male\"), values = c(\"#e9a3c9\",\"#67a9cf\") )\n \ng4\n\n\n\n\nThere seems to be a huge spike in cases after adolescences. Females have a sharp decline the older they get, where as male case stay elevated with a slight decrease at 55."
+ },
+ {
+ "objectID": "posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data.html#last-exploration",
+ "href": "posts/2020-02-13_basic-who-TB-data/basic-exploration-of-who-tuberculosis-data.html#last-exploration",
+ "title": "Basic Exploration of WHO Tuberculosis Data",
+ "section": "Last Exploration",
+ "text": "Last Exploration\nLets look at overall cases in India, going back to 1980 and see if there as been any trends. To get these numbers we will go back to our raw data and strip everything out expect the total count\n\ng5 <- who_raw %>% \n filter(country == \"India\") %>% \n select(year, c_newinc) %>% \n ggplot(aes(x = year, y = c_newinc/1000000)) +\n geom_line() +\n geom_point() +\n labs(\n title = \"New and Relapse Tuberculosis Cases In India \\n1980 -- 2018\"\n ,x = NULL\n ,y = \"Total Cases (in millions)\") +\n theme_bw() +\n theme(plot.title = element_text(hjust = 0.5)) + #center title \n scale_x_continuous(breaks = seq(1980,2020,5)) +\n scale_y_continuous(breaks = scales::pretty_breaks(n=10)) #different way to add tick marks\ng5\n\n\n\n\nCases were steadily rising from 1980 to 1990, then suddenly feel off. Starting in the early 2010s there was a sharp increase and the amount of new and relapse cases just keep growing."
+ },
+ {
+ "objectID": "posts/2020-01-29_facets-and-humility/facets-and-a-lesson-in-humility.html",
+ "href": "posts/2020-01-29_facets-and-humility/facets-and-a-lesson-in-humility.html",
+ "title": "Facets and a Lesson in Humility",
+ "section": "",
+ "text": "Todays post is a lesson in Facets, as well as humility. The task this week was to replicate the graph in Chapter 8 of Tableau for Healthcare in R. The graph in question is called a Table Lens (This is the name the book uses, however I did have trouble finding this name in Google searches), it is a collection of charts with a common theme, this time looking at countries in various WHO regions and some statistics associated with mortality as well as health expenditure. I say this is a lesson in humiltiy as I have read through the excellent book R for Data Science, and yet the idea of faceting a ggplot graph slipped my mind. This ended with hours of trying to find a package in R to line up graphs, and way more time then I care to admit spent on getting things prefect. I did find such a package called cowplots, which can be found here. While this is an excellent package, its use was unecessary and I reverted back to using the excellent facet feature of GGplot, which can be seen below! \n\nLoad Libraries\n\nlibrary(magrittr) #pipes\nlibrary(ggplot2) #ploting \nlibrary(dplyr)\nlibrary(tidyr)\n\n\n\nImport Data\n\nds <- readxl::read_xlsx(path = \"../2020-01-04_my-start-to-r/Tableau 10 Training Practice Data.xlsx\"\n ,sheet = \"03 - WHO Life Expect & Mort\"\n )\n\n\n\nClean Names and Transform\n\nvarnames <- c(\"who_region\", \"country\", \"year\" , \"sex\" , \"life_expect_birth\" , \"neo_mort\"\n ,\"under_five_mort\" , \"health_expenditure\")\nnames(ds) <- varnames\n\n# Order Countries based on Life Expectancy at Birth\n\nds$country <- factor(ds$country, levels = ds$country[order(ds$life_expect_birth)]) \n\n#To \"Long\" Form\n\nds1 <- ds %>% pivot_longer(5:8)#select columns 5 throuh 8, leave new columns at default names\n\n# Set up labels for Facet, as well as function for Facet Labeller\n\nfacet_labels <- list(\n\"life_expect_birth\" = \"Life Expectancy at Birth \" \n,\"neo_mort\" = \"Neonatal Mortality Rate\" \n,\"under_five_mort\" = \"Under-Five Mortality Rate\"\n,\"health_expenditure\" = \"Health Expenditure per Capita (US$)\" )\n\nvariable_labeller <- function(variable,value){\n return(facet_labels[value])\n}\n\n\n\nGraphs\n\nhightlight_countries <- (c(\"Mauritania\", \"South Africa\")) \n\ng1 <- ds1 %>% filter(who_region == \"Africa\") %>% \n mutate(name = factor(name, levels = c(\"life_expect_birth\" , \"neo_mort\"\n ,\"under_five_mort\" , \"health_expenditure\"))\n ,highlight = country %in% hightlight_countries) %>% \n ggplot(aes(x = country, y = value, fill = highlight)) +\n geom_col(show.legend = FALSE) +\n coord_flip() +\n labs(\n title = \"World Bank Life Expectancy, Neonatal & Under-Five Mortality Rates, and Health Expenditure Analysis\"\n ,x = NULL\n ,y = NULL\n ) +\n facet_grid(~name, scales = \"free_x\",labeller = variable_labeller) +\n theme_bw() +\n geom_text(aes(label = round(value, 0)), hjust = 0) +\n scale_y_continuous(expand = expand_scale(mult = c(0,0.2))) +\n scale_fill_manual(values = c(\"TRUE\" = \"#fc8d59\", \"FALSE\" = \"#2b83ba\"))\ng1\n\n\n\n\n\n\n\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{belanger2020,\n author = {Belanger, Kyle},\n title = {Facets and a {Lesson} in {Humility}},\n date = {2020-01-29},\n langid = {en}\n}\nFor attribution, please cite this work as:\nBelanger, Kyle. 2020. “Facets and a Lesson in Humility.”\nJanuary 29, 2020."
+ },
+ {
+ "objectID": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html",
+ "href": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html",
+ "title": "Line Graphs and Interactivity",
+ "section": "",
+ "text": "Today’s post is all about line graphs using both ggplot for a static graph as well as a package called plotly for interactivity (more on this later). The example graph and data is again coming from Tableau for Healthcare, Chapter 10."
+ },
+ {
+ "objectID": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#load-libraries",
+ "href": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#load-libraries",
+ "title": "Line Graphs and Interactivity",
+ "section": "Load Libraries",
+ "text": "Load Libraries\nAs always first step is to load in our libraries, I am using quite a few here, some are a bit overkill for this example but I wanted to play around with some fun features today.\n\nlibrary(magrittr) #pipes\nlibrary(ggplot2) #ploting \nlibrary(dplyr) # data manipulation\nlibrary(tidyr) # tidy data\nlibrary(lubridate) #work with dates\nlibrary(stringr) # manipulate strings\nlibrary(plotly)"
+ },
+ {
+ "objectID": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#import-data",
+ "href": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#import-data",
+ "title": "Line Graphs and Interactivity",
+ "section": "Import Data",
+ "text": "Import Data\nNext lets import our data, this week we are using the sheet Flu Occurrence FY2013-2016. I am unsure if this is form a real data set or not but it is good for demonstration purposes! After importing we can glimpse at our data to understand what is contained within.\n\nds <- readxl::read_xlsx(path = \"../2020-01-04_my-start-to-r/Tableau 10 Training Practice Data.xlsx\"\n ,sheet = \"05 - Flu Occurrence FY2013-2016\"\n )\nds %>% glimpse()\n\nRows: 48\nColumns: 4\n$ Date <dttm> 2012-10-27, 2012-11-24, …\n$ `Tests (+) for Influenza (count)` <dbl> 995, 3228, 22368, 24615, …\n$ `Total Respiratory Specimens Tested (count)` <dbl> 18986, 24757, 66683, 7561…\n$ `% Tests (+) for Influenza` <dbl> 0.05240704, 0.13038737, 0…"
+ },
+ {
+ "objectID": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#transform-data",
+ "href": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#transform-data",
+ "title": "Line Graphs and Interactivity",
+ "section": "Transform Data",
+ "text": "Transform Data\nI went a bit overboard today with renaming the variables. I wanted to practice writing a function and while it might not be the prettiest or the best way to do this, it worked for what I was trying to accomplish. Note the use of sapply, which lets us run the function on each column name.\n\nformat_names <- function(x) {\n #Fucntion to set all names to lower case, and strip unneeded characters\n x <- tolower(x)\n x <- str_replace_all(x,c(#set each pattern equal to replacement\n \" \" = \"_\"\n ,\"\\\\(\\\\+\\\\)\" = \"pos\" #regualr experssion to match (+)\n ,\"\\\\(\" = \"\"\n ,\"\\\\)\" = \"\"\n ,\"\\\\%\" = \"pct\"\n )\n ) \n }\n\n#run the format name function on all names from DS\ncolnames(ds) <- sapply(colnames(ds),format_names) \n\nNow is were the fun really starts! For this particular data set there are a couple things we need to add to replicate the example. In the original data set the date is stored with month, day, and year; the day is irrelevant and we need to pull out the month as well as the year. For this we can use the lubridate package, first we pull out the month and set it as a factor. For this example our year actually starts in October, so we set our factor to start at October (10), and end with September (9). We then pull out the year, which presents us with a different problem. Again our year starts in October, instead of January. To solve this I have created a variable called date adjustment, in this column is our month is 10 or greater, we will place a 1, if not a 0. We then set our fiscal year to be the actual year plus the date adjustment, this allows us to have our dates in the right fiscal year. Last the percent column is currently listed as a decimal, so we will convert this to a percentage.\n\n# split date time\nds1 <- ds %>% mutate(\n #create month column, then set factors and labels to start fiscal year in Oct\n month = month(ds$date)\n ,month = factor(month\n ,levels = c(10:12, 1:9)\n ,labels = c(month.abb[10:12],month.abb[1:9]))\n ,year = year(ds$date)\n ,date_adjustment = ifelse(month(ds$date) >= 10, 1,0 )\n ,fiscal_year = factor(year + date_adjustment)\n #convert % Pos from decmial to pct\n ,pct_tests_pos_for_influenza = round(pct_tests_pos_for_influenza * 100, digits = 0)\n )\n\nds1 %>% glimpse()\n\nRows: 48\nColumns: 8\n$ date <dttm> 2012-10-27, 2012-11-24, 2012…\n$ tests_pos_for_influenza_count <dbl> 995, 3228, 22368, 24615, 1179…\n$ total_respiratory_specimens_tested_count <dbl> 18986, 24757, 66683, 75614, 5…\n$ pct_tests_pos_for_influenza <dbl> 5, 13, 34, 33, 23, 17, 11, 6,…\n$ month <fct> Oct, Nov, Dec, Jan, Feb, Mar,…\n$ year <dbl> 2012, 2012, 2012, 2013, 2013,…\n$ date_adjustment <dbl> 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,…\n$ fiscal_year <fct> 2013, 2013, 2013, 2013, 2013,…"
+ },
+ {
+ "objectID": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#ggplot",
+ "href": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#ggplot",
+ "title": "Line Graphs and Interactivity",
+ "section": "GGplot",
+ "text": "GGplot\nThe graph here is pretty straight forward with one exception, group! For this line graph we want ggplot to connect the lines of the same year, if we do not explicitly state this using the group mapping, ggplot will try to connect all the lines together, which of course is not at all what we want!\n\ng1 <- ds1 %>% \n ggplot(aes(x = month, y = pct_tests_pos_for_influenza, color = fiscal_year\n ,group = fiscal_year)) +\n geom_line() +\n labs(\n x = NULL\n ,y = \"% Tests (+) for Influenza\"\n ,color = NULL\n ,title = \"Flu Viral Surveillance: % Respiratory Specimens Positive for Influenza \\nOctober - September \\nFor Flu Seasons 2013 - 2016\"\n ) +\n theme_classic() +\n scale_y_continuous(breaks = seq(0,40,5)) +\n scale_color_manual(values = c(\"#a6611a\",\"#dfc27d\",\"#80cdc1\",\"#018571\"))\n\ng1"
+ },
+ {
+ "objectID": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#plotly",
+ "href": "posts/2020-02-10_line-graphs-and-interactivity/line-graphs-and-interactivity.html#plotly",
+ "title": "Line Graphs and Interactivity",
+ "section": "plotly",
+ "text": "plotly\nOne of the nice features of Tableau is the fact the graphs are interactive, while a good graph should speak for itself, end users love pretty things. I have been experimenting with Plotly, which has an open source package for R (as well as many other programming languages!). This example only just scratches the surface, but there will be many more to come!\n\ng2 <- ds1 %>% \n plot_ly(x = ~month, y = ~pct_tests_pos_for_influenza, type = \"scatter\", mode = \"lines\" \n ,color = ~fiscal_year\n ,colors = c(\"#a6611a\",\"#dfc27d\",\"#80cdc1\",\"#018571\")\n , hoverinfo = 'y') %>% \n layout(xaxis = list(\n title = \"\"\n )\n ,yaxis = list(\n title = \"% Tests (+) for Influenza\"\n )\n ,title = \"Flu Viral Surveillance: % Respiratory Specimens Positive for Influenza\"\n ,legend = list(\n x = 100\n ,y = 0.5\n ) \n \n )\n\ng2"
}
]
\ No newline at end of file
diff --git a/_site/site_libs/crosstalk-1.2.0/css/crosstalk.min.css b/_site/site_libs/crosstalk-1.2.0/css/crosstalk.min.css
new file mode 100644
index 0000000..6b45382
--- /dev/null
+++ b/_site/site_libs/crosstalk-1.2.0/css/crosstalk.min.css
@@ -0,0 +1 @@
+.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}
diff --git a/_site/site_libs/crosstalk-1.2.0/js/crosstalk.js b/_site/site_libs/crosstalk-1.2.0/js/crosstalk.js
new file mode 100644
index 0000000..fd9eb53
--- /dev/null
+++ b/_site/site_libs/crosstalk-1.2.0/js/crosstalk.js
@@ -0,0 +1,1474 @@
+(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) {
+ return 1;
+ }
+}
+
+/**
+ * @private
+ */
+
+var FilterSet = function () {
+ function FilterSet() {
+ _classCallCheck(this, FilterSet);
+
+ this.reset();
+ }
+
+ _createClass(FilterSet, [{
+ key: "reset",
+ value: function reset() {
+ // Key: handle ID, Value: array of selected keys, or null
+ this._handles = {};
+ // Key: key string, Value: count of handles that include it
+ this._keys = {};
+ this._value = null;
+ this._activeHandles = 0;
+ }
+ }, {
+ key: "update",
+ value: function update(handleId, keys) {
+ if (keys !== null) {
+ keys = keys.slice(0); // clone before sorting
+ keys.sort(naturalComparator);
+ }
+
+ var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys),
+ added = _diffSortedLists.added,
+ removed = _diffSortedLists.removed;
+
+ this._handles[handleId] = keys;
+
+ for (var i = 0; i < added.length; i++) {
+ this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;
+ }
+ for (var _i = 0; _i < removed.length; _i++) {
+ this._keys[removed[_i]]--;
+ }
+
+ this._updateValue(keys);
+ }
+
+ /**
+ * @param {string[]} keys Sorted array of strings that indicate
+ * a superset of possible keys.
+ * @private
+ */
+
+ }, {
+ key: "_updateValue",
+ value: function _updateValue() {
+ var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys;
+
+ var handleCount = Object.keys(this._handles).length;
+ if (handleCount === 0) {
+ this._value = null;
+ } else {
+ this._value = [];
+ for (var i = 0; i < keys.length; i++) {
+ var count = this._keys[keys[i]];
+ if (count === handleCount) {
+ this._value.push(keys[i]);
+ }
+ }
+ }
+ }
+ }, {
+ key: "clear",
+ value: function clear(handleId) {
+ if (typeof this._handles[handleId] === "undefined") {
+ return;
+ }
+
+ var keys = this._handles[handleId];
+ if (!keys) {
+ keys = [];
+ }
+
+ for (var i = 0; i < keys.length; i++) {
+ this._keys[keys[i]]--;
+ }
+ delete this._handles[handleId];
+
+ this._updateValue();
+ }
+ }, {
+ key: "value",
+ get: function get() {
+ return this._value;
+ }
+ }, {
+ key: "_allKeys",
+ get: function get() {
+ var allKeys = Object.keys(this._keys);
+ allKeys.sort(naturalComparator);
+ return allKeys;
+ }
+ }]);
+
+ return FilterSet;
+}();
+
+exports.default = FilterSet;
+
+},{"./util":11}],4:[function(require,module,exports){
+(function (global){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+exports.default = group;
+
+var _var2 = require("./var");
+
+var _var3 = _interopRequireDefault(_var2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+// Use a global so that multiple copies of crosstalk.js can be loaded and still
+// have groups behave as singletons across all copies.
+global.__crosstalk_groups = global.__crosstalk_groups || {};
+var groups = global.__crosstalk_groups;
+
+function group(groupName) {
+ if (groupName && typeof groupName === "string") {
+ if (!groups.hasOwnProperty(groupName)) {
+ groups[groupName] = new Group(groupName);
+ }
+ return groups[groupName];
+ } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) {
+ // Appears to already be a group object
+ return groupName;
+ } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") {
+ return group(groupName[0]);
+ } else {
+ throw new Error("Invalid groupName argument");
+ }
+}
+
+var Group = function () {
+ function Group(name) {
+ _classCallCheck(this, Group);
+
+ this.name = name;
+ this._vars = {};
+ }
+
+ _createClass(Group, [{
+ key: "var",
+ value: function _var(name) {
+ if (!name || typeof name !== "string") {
+ throw new Error("Invalid var name");
+ }
+
+ if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name);
+ return this._vars[name];
+ }
+ }, {
+ key: "has",
+ value: function has(name) {
+ if (!name || typeof name !== "string") {
+ throw new Error("Invalid var name");
+ }
+
+ return this._vars.hasOwnProperty(name);
+ }
+ }]);
+
+ return Group;
+}();
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./var":12}],5:[function(require,module,exports){
+(function (global){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _group = require("./group");
+
+var _group2 = _interopRequireDefault(_group);
+
+var _selection = require("./selection");
+
+var _filter = require("./filter");
+
+var _input = require("./input");
+
+require("./input_selectize");
+
+require("./input_checkboxgroup");
+
+require("./input_slider");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var defaultGroup = (0, _group2.default)("default");
+
+function var_(name) {
+ return defaultGroup.var(name);
+}
+
+function has(name) {
+ return defaultGroup.has(name);
+}
+
+if (global.Shiny) {
+ global.Shiny.addCustomMessageHandler("update-client-value", function (message) {
+ if (typeof message.group === "string") {
+ (0, _group2.default)(message.group).var(message.name).set(message.value);
+ } else {
+ var_(message.name).set(message.value);
+ }
+ });
+}
+
+var crosstalk = {
+ group: _group2.default,
+ var: var_,
+ has: has,
+ SelectionHandle: _selection.SelectionHandle,
+ FilterHandle: _filter.FilterHandle,
+ bind: _input.bind
+};
+
+/**
+ * @namespace crosstalk
+ */
+exports.default = crosstalk;
+
+global.crosstalk = crosstalk;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){
+(function (global){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.register = register;
+exports.bind = bind;
+var $ = global.jQuery;
+
+var bindings = {};
+
+function register(reg) {
+ bindings[reg.className] = reg;
+ if (global.document && global.document.readyState !== "complete") {
+ $(function () {
+ bind();
+ });
+ } else if (global.document) {
+ setTimeout(bind, 100);
+ }
+}
+
+function bind() {
+ Object.keys(bindings).forEach(function (className) {
+ var binding = bindings[className];
+ $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) {
+ bindInstance(binding, el);
+ });
+ });
+}
+
+// Escape jQuery identifier
+function $escape(val) {
+ return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
+}
+
+function bindEl(el) {
+ var $el = $(el);
+ Object.keys(bindings).forEach(function (className) {
+ if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) {
+ var binding = bindings[className];
+ bindInstance(binding, el);
+ }
+ });
+}
+
+function bindInstance(binding, el) {
+ var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']");
+ var data = JSON.parse(jsonEl[0].innerText);
+
+ var instance = binding.factory(el, data);
+ $(el).data("crosstalk-instance", instance);
+ $(el).addClass("crosstalk-input-bound");
+}
+
+if (global.Shiny) {
+ var inputBinding = new global.Shiny.InputBinding();
+ var _$ = global.jQuery;
+ _$.extend(inputBinding, {
+ find: function find(scope) {
+ return _$(scope).find(".crosstalk-input");
+ },
+ initialize: function initialize(el) {
+ if (!_$(el).hasClass("crosstalk-input-bound")) {
+ bindEl(el);
+ }
+ },
+ getId: function getId(el) {
+ return el.id;
+ },
+ getValue: function getValue(el) {},
+ setValue: function setValue(el, value) {},
+ receiveMessage: function receiveMessage(el, data) {},
+ subscribe: function subscribe(el, callback) {
+ _$(el).data("crosstalk-instance").resume();
+ },
+ unsubscribe: function unsubscribe(el) {
+ _$(el).data("crosstalk-instance").suspend();
+ }
+ });
+ global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding");
+}
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{}],7:[function(require,module,exports){
+(function (global){
+"use strict";
+
+var _input = require("./input");
+
+var input = _interopRequireWildcard(_input);
+
+var _filter = require("./filter");
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+var $ = global.jQuery;
+
+input.register({
+ className: "crosstalk-input-checkboxgroup",
+
+ factory: function factory(el, data) {
+ /*
+ * map: {"groupA": ["keyA", "keyB", ...], ...}
+ * group: "ct-groupname"
+ */
+ var ctHandle = new _filter.FilterHandle(data.group);
+
+ var lastKnownKeys = void 0;
+ var $el = $(el);
+ $el.on("change", "input[type='checkbox']", function () {
+ var checked = $el.find("input[type='checkbox']:checked");
+ if (checked.length === 0) {
+ lastKnownKeys = null;
+ ctHandle.clear();
+ } else {
+ var keys = {};
+ checked.each(function () {
+ data.map[this.value].forEach(function (key) {
+ keys[key] = true;
+ });
+ });
+ var keyArray = Object.keys(keys);
+ keyArray.sort();
+ lastKnownKeys = keyArray;
+ ctHandle.set(keyArray);
+ }
+ });
+
+ return {
+ suspend: function suspend() {
+ ctHandle.clear();
+ },
+ resume: function resume() {
+ if (lastKnownKeys) ctHandle.set(lastKnownKeys);
+ }
+ };
+ }
+});
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./filter":2,"./input":6}],8:[function(require,module,exports){
+(function (global){
+"use strict";
+
+var _input = require("./input");
+
+var input = _interopRequireWildcard(_input);
+
+var _util = require("./util");
+
+var util = _interopRequireWildcard(_util);
+
+var _filter = require("./filter");
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+var $ = global.jQuery;
+
+input.register({
+ className: "crosstalk-input-select",
+
+ factory: function factory(el, data) {
+ /*
+ * items: {value: [...], label: [...]}
+ * map: {"groupA": ["keyA", "keyB", ...], ...}
+ * group: "ct-groupname"
+ */
+
+ var first = [{ value: "", label: "(All)" }];
+ var items = util.dataframeToD3(data.items);
+ var opts = {
+ options: first.concat(items),
+ valueField: "value",
+ labelField: "label",
+ searchField: "label"
+ };
+
+ var select = $(el).find("select")[0];
+
+ var selectize = $(select).selectize(opts)[0].selectize;
+
+ var ctHandle = new _filter.FilterHandle(data.group);
+
+ var lastKnownKeys = void 0;
+ selectize.on("change", function () {
+ if (selectize.items.length === 0) {
+ lastKnownKeys = null;
+ ctHandle.clear();
+ } else {
+ var keys = {};
+ selectize.items.forEach(function (group) {
+ data.map[group].forEach(function (key) {
+ keys[key] = true;
+ });
+ });
+ var keyArray = Object.keys(keys);
+ keyArray.sort();
+ lastKnownKeys = keyArray;
+ ctHandle.set(keyArray);
+ }
+ });
+
+ return {
+ suspend: function suspend() {
+ ctHandle.clear();
+ },
+ resume: function resume() {
+ if (lastKnownKeys) ctHandle.set(lastKnownKeys);
+ }
+ };
+ }
+});
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){
+(function (global){
+"use strict";
+
+var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
+
+var _input = require("./input");
+
+var input = _interopRequireWildcard(_input);
+
+var _filter = require("./filter");
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+var $ = global.jQuery;
+var strftime = global.strftime;
+
+input.register({
+ className: "crosstalk-input-slider",
+
+ factory: function factory(el, data) {
+ /*
+ * map: {"groupA": ["keyA", "keyB", ...], ...}
+ * group: "ct-groupname"
+ */
+ var ctHandle = new _filter.FilterHandle(data.group);
+
+ var opts = {};
+ var $el = $(el).find("input");
+ var dataType = $el.data("data-type");
+ var timeFormat = $el.data("time-format");
+ var round = $el.data("round");
+ var timeFormatter = void 0;
+
+ // Set up formatting functions
+ if (dataType === "date") {
+ timeFormatter = strftime.utc();
+ opts.prettify = function (num) {
+ return timeFormatter(timeFormat, new Date(num));
+ };
+ } else if (dataType === "datetime") {
+ var timezone = $el.data("timezone");
+ if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime;
+
+ opts.prettify = function (num) {
+ return timeFormatter(timeFormat, new Date(num));
+ };
+ } else if (dataType === "number") {
+ if (typeof round !== "undefined") opts.prettify = function (num) {
+ var factor = Math.pow(10, round);
+ return Math.round(num * factor) / factor;
+ };
+ }
+
+ $el.ionRangeSlider(opts);
+
+ function getValue() {
+ var result = $el.data("ionRangeSlider").result;
+
+ // Function for converting numeric value from slider to appropriate type.
+ var convert = void 0;
+ var dataType = $el.data("data-type");
+ if (dataType === "date") {
+ convert = function convert(val) {
+ return formatDateUTC(new Date(+val));
+ };
+ } else if (dataType === "datetime") {
+ convert = function convert(val) {
+ // Convert ms to s
+ return +val / 1000;
+ };
+ } else {
+ convert = function convert(val) {
+ return +val;
+ };
+ }
+
+ if ($el.data("ionRangeSlider").options.type === "double") {
+ return [convert(result.from), convert(result.to)];
+ } else {
+ return convert(result.from);
+ }
+ }
+
+ var lastKnownKeys = null;
+
+ $el.on("change.crosstalkSliderInput", function (event) {
+ if (!$el.data("updating") && !$el.data("animating")) {
+ var _getValue = getValue(),
+ _getValue2 = _slicedToArray(_getValue, 2),
+ from = _getValue2[0],
+ to = _getValue2[1];
+
+ var keys = [];
+ for (var i = 0; i < data.values.length; i++) {
+ var val = data.values[i];
+ if (val >= from && val <= to) {
+ keys.push(data.keys[i]);
+ }
+ }
+ keys.sort();
+ ctHandle.set(keys);
+ lastKnownKeys = keys;
+ }
+ });
+
+ // let $el = $(el);
+ // $el.on("change", "input[type="checkbox"]", function() {
+ // let checked = $el.find("input[type="checkbox"]:checked");
+ // if (checked.length === 0) {
+ // ctHandle.clear();
+ // } else {
+ // let keys = {};
+ // checked.each(function() {
+ // data.map[this.value].forEach(function(key) {
+ // keys[key] = true;
+ // });
+ // });
+ // let keyArray = Object.keys(keys);
+ // keyArray.sort();
+ // ctHandle.set(keyArray);
+ // }
+ // });
+
+ return {
+ suspend: function suspend() {
+ ctHandle.clear();
+ },
+ resume: function resume() {
+ if (lastKnownKeys) ctHandle.set(lastKnownKeys);
+ }
+ };
+ }
+});
+
+// Convert a number to a string with leading zeros
+function padZeros(n, digits) {
+ var str = n.toString();
+ while (str.length < digits) {
+ str = "0" + str;
+ }return str;
+}
+
+// Given a Date object, return a string in yyyy-mm-dd format, using the
+// UTC date. This may be a day off from the date in the local time zone.
+function formatDateUTC(date) {
+ if (date instanceof Date) {
+ return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2);
+ } else {
+ return null;
+ }
+}
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./filter":2,"./input":6}],10:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SelectionHandle = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _events = require("./events");
+
+var _events2 = _interopRequireDefault(_events);
+
+var _group = require("./group");
+
+var _group2 = _interopRequireDefault(_group);
+
+var _util = require("./util");
+
+var util = _interopRequireWildcard(_util);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+/**
+ * Use this class to read and write (and listen for changes to) the selection
+ * for a Crosstalk group. This is intended to be used for linked brushing.
+ *
+ * If two (or more) `SelectionHandle` instances in the same webpage share the
+ * same group name, they will share the same state. Setting the selection using
+ * one `SelectionHandle` instance will result in the `value` property instantly
+ * changing across the others, and `"change"` event listeners on all instances
+ * (including the one that initiated the sending) will fire.
+ *
+ * @param {string} [group] - The name of the Crosstalk group, or if none,
+ * null or undefined (or any other falsy value). This can be changed later
+ * via the [SelectionHandle#setGroup](#setGroup) method.
+ * @param {Object} [extraInfo] - An object whose properties will be copied to
+ * the event object whenever an event is emitted.
+ */
+var SelectionHandle = exports.SelectionHandle = function () {
+ function SelectionHandle() {
+ var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
+ var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
+
+ _classCallCheck(this, SelectionHandle);
+
+ this._eventRelay = new _events2.default();
+ this._emitter = new util.SubscriptionTracker(this._eventRelay);
+
+ // Name of the group we're currently tracking, if any. Can change over time.
+ this._group = null;
+ // The Var we're currently tracking, if any. Can change over time.
+ this._var = null;
+ // The event handler subscription we currently have on var.on("change").
+ this._varOnChangeSub = null;
+
+ this._extraInfo = util.extend({ sender: this }, extraInfo);
+
+ this.setGroup(group);
+ }
+
+ /**
+ * Changes the Crosstalk group membership of this SelectionHandle. The group
+ * being switched away from (if any) will not have its selection value
+ * modified as a result of calling `setGroup`, even if this handle was the
+ * most recent handle to set the selection of the group.
+ *
+ * The group being switched to (if any) will also not have its selection value
+ * modified as a result of calling `setGroup`. If you want to set the
+ * selection value of the new group, call `set` explicitly.
+ *
+ * @param {string} group - The name of the Crosstalk group, or null (or
+ * undefined) to clear the group.
+ */
+
+
+ _createClass(SelectionHandle, [{
+ key: "setGroup",
+ value: function setGroup(group) {
+ var _this = this;
+
+ // If group is unchanged, do nothing
+ if (this._group === group) return;
+ // Treat null, undefined, and other falsy values the same
+ if (!this._group && !group) return;
+
+ if (this._var) {
+ this._var.off("change", this._varOnChangeSub);
+ this._var = null;
+ this._varOnChangeSub = null;
+ }
+
+ this._group = group;
+
+ if (group) {
+ this._var = (0, _group2.default)(group).var("selection");
+ var sub = this._var.on("change", function (e) {
+ _this._eventRelay.trigger("change", e, _this);
+ });
+ this._varOnChangeSub = sub;
+ }
+ }
+
+ /**
+ * Retrieves the current selection for the group represented by this
+ * `SelectionHandle`.
+ *
+ * - If no selection is active, then this value will be falsy.
+ * - If a selection is active, but no data points are selected, then this
+ * value will be an empty array.
+ * - If a selection is active, and data points are selected, then the keys
+ * of the selected data points will be present in the array.
+ */
+
+ }, {
+ key: "_mergeExtraInfo",
+
+
+ /**
+ * Combines the given `extraInfo` (if any) with the handle's default
+ * `_extraInfo` (if any).
+ * @private
+ */
+ value: function _mergeExtraInfo(extraInfo) {
+ // Important incidental effect: shallow clone is returned
+ return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null);
+ }
+
+ /**
+ * Overwrites the current selection for the group, and raises the `"change"`
+ * event among all of the group's '`SelectionHandle` instances (including
+ * this one).
+ *
+ * @fires SelectionHandle#change
+ * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see
+ * {@link SelectionHandle#value}).
+ * @param {Object} [extraInfo] - Extra properties to be included on the event
+ * object that's passed to listeners (in addition to any options that were
+ * passed into the `SelectionHandle` constructor).
+ */
+
+ }, {
+ key: "set",
+ value: function set(selectedKeys, extraInfo) {
+ if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));
+ }
+
+ /**
+ * Overwrites the current selection for the group, and raises the `"change"`
+ * event among all of the group's '`SelectionHandle` instances (including
+ * this one).
+ *
+ * @fires SelectionHandle#change
+ * @param {Object} [extraInfo] - Extra properties to be included on the event
+ * object that's passed to listeners (in addition to any that were passed
+ * into the `SelectionHandle` constructor).
+ */
+
+ }, {
+ key: "clear",
+ value: function clear(extraInfo) {
+ if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo));
+ }
+
+ /**
+ * Subscribes to events on this `SelectionHandle`.
+ *
+ * @param {string} eventType - Indicates the type of events to listen to.
+ * Currently, only `"change"` is supported.
+ * @param {SelectionHandle~listener} listener - The callback function that
+ * will be invoked when the event occurs.
+ * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel
+ * this subscription.
+ */
+
+ }, {
+ key: "on",
+ value: function on(eventType, listener) {
+ return this._emitter.on(eventType, listener);
+ }
+
+ /**
+ * Cancels event subscriptions created by {@link SelectionHandle#on}.
+ *
+ * @param {string} eventType - The type of event to unsubscribe.
+ * @param {string|SelectionHandle~listener} listener - Either the callback
+ * function previously passed into {@link SelectionHandle#on}, or the
+ * string that was returned from {@link SelectionHandle#on}.
+ */
+
+ }, {
+ key: "off",
+ value: function off(eventType, listener) {
+ return this._emitter.off(eventType, listener);
+ }
+
+ /**
+ * Shuts down the `SelectionHandle` object.
+ *
+ * Removes all event listeners that were added through this handle.
+ */
+
+ }, {
+ key: "close",
+ value: function close() {
+ this._emitter.removeAllListeners();
+ this.setGroup(null);
+ }
+ }, {
+ key: "value",
+ get: function get() {
+ return this._var ? this._var.get() : null;
+ }
+ }]);
+
+ return SelectionHandle;
+}();
+
+/**
+ * @callback SelectionHandle~listener
+ * @param {Object} event - An object containing details of the event. For
+ * `"change"` events, this includes the properties `value` (the new
+ * value of the selection, or `undefined` if no selection is active),
+ * `oldValue` (the previous value of the selection), and `sender` (the
+ * `SelectionHandle` instance that made the change).
+ */
+
+/**
+ * @event SelectionHandle#change
+ * @type {object}
+ * @property {object} value - The new value of the selection, or `undefined`
+ * if no selection is active.
+ * @property {object} oldValue - The previous value of the selection.
+ * @property {SelectionHandle} sender - The `SelectionHandle` instance that
+ * changed the value.
+ */
+
+},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+exports.extend = extend;
+exports.checkSorted = checkSorted;
+exports.diffSortedLists = diffSortedLists;
+exports.dataframeToD3 = dataframeToD3;
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function extend(target) {
+ for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ sources[_key - 1] = arguments[_key];
+ }
+
+ for (var i = 0; i < sources.length; i++) {
+ var src = sources[i];
+ if (typeof src === "undefined" || src === null) continue;
+
+ for (var key in src) {
+ if (src.hasOwnProperty(key)) {
+ target[key] = src[key];
+ }
+ }
+ }
+ return target;
+}
+
+function checkSorted(list) {
+ for (var i = 1; i < list.length; i++) {
+ if (list[i] <= list[i - 1]) {
+ throw new Error("List is not sorted or contains duplicate");
+ }
+ }
+}
+
+function diffSortedLists(a, b) {
+ var i_a = 0;
+ var i_b = 0;
+
+ if (!a) a = [];
+ if (!b) b = [];
+
+ var a_only = [];
+ var b_only = [];
+
+ checkSorted(a);
+ checkSorted(b);
+
+ while (i_a < a.length && i_b < b.length) {
+ if (a[i_a] === b[i_b]) {
+ i_a++;
+ i_b++;
+ } else if (a[i_a] < b[i_b]) {
+ a_only.push(a[i_a++]);
+ } else {
+ b_only.push(b[i_b++]);
+ }
+ }
+
+ if (i_a < a.length) a_only = a_only.concat(a.slice(i_a));
+ if (i_b < b.length) b_only = b_only.concat(b.slice(i_b));
+ return {
+ removed: a_only,
+ added: b_only
+ };
+}
+
+// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }
+// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]
+function dataframeToD3(df) {
+ var names = [];
+ var length = void 0;
+ for (var name in df) {
+ if (df.hasOwnProperty(name)) names.push(name);
+ if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") {
+ throw new Error("All fields must be arrays");
+ } else if (typeof length !== "undefined" && length !== df[name].length) {
+ throw new Error("All fields must be arrays of the same length");
+ }
+ length = df[name].length;
+ }
+ var results = [];
+ var item = void 0;
+ for (var row = 0; row < length; row++) {
+ item = {};
+ for (var col = 0; col < names.length; col++) {
+ item[names[col]] = df[names[col]][row];
+ }
+ results.push(item);
+ }
+ return results;
+}
+
+/**
+ * Keeps track of all event listener additions/removals and lets all active
+ * listeners be removed with a single operation.
+ *
+ * @private
+ */
+
+var SubscriptionTracker = exports.SubscriptionTracker = function () {
+ function SubscriptionTracker(emitter) {
+ _classCallCheck(this, SubscriptionTracker);
+
+ this._emitter = emitter;
+ this._subs = {};
+ }
+
+ _createClass(SubscriptionTracker, [{
+ key: "on",
+ value: function on(eventType, listener) {
+ var sub = this._emitter.on(eventType, listener);
+ this._subs[sub] = eventType;
+ return sub;
+ }
+ }, {
+ key: "off",
+ value: function off(eventType, listener) {
+ var sub = this._emitter.off(eventType, listener);
+ if (sub) {
+ delete this._subs[sub];
+ }
+ return sub;
+ }
+ }, {
+ key: "removeAllListeners",
+ value: function removeAllListeners() {
+ var _this = this;
+
+ var current_subs = this._subs;
+ this._subs = {};
+ Object.keys(current_subs).forEach(function (sub) {
+ _this._emitter.off(current_subs[sub], sub);
+ });
+ }
+ }]);
+
+ return SubscriptionTracker;
+}();
+
+},{}],12:[function(require,module,exports){
+(function (global){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _events = require("./events");
+
+var _events2 = _interopRequireDefault(_events);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Var = function () {
+ function Var(group, name, /*optional*/value) {
+ _classCallCheck(this, Var);
+
+ this._group = group;
+ this._name = name;
+ this._value = value;
+ this._events = new _events2.default();
+ }
+
+ _createClass(Var, [{
+ key: "get",
+ value: function get() {
+ return this._value;
+ }
+ }, {
+ key: "set",
+ value: function set(value, /*optional*/event) {
+ if (this._value === value) {
+ // Do nothing; the value hasn't changed
+ return;
+ }
+ var oldValue = this._value;
+ this._value = value;
+ // Alert JavaScript listeners that the value has changed
+ var evt = {};
+ if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") {
+ for (var k in event) {
+ if (event.hasOwnProperty(k)) evt[k] = event[k];
+ }
+ }
+ evt.oldValue = oldValue;
+ evt.value = value;
+ this._events.trigger("change", evt, this);
+
+ // TODO: Make this extensible, to let arbitrary back-ends know that
+ // something has changed
+ if (global.Shiny && global.Shiny.onInputChange) {
+ global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value);
+ }
+ }
+ }, {
+ key: "on",
+ value: function on(eventType, listener) {
+ return this._events.on(eventType, listener);
+ }
+ }, {
+ key: "off",
+ value: function off(eventType, listener) {
+ return this._events.off(eventType, listener);
+ }
+ }]);
+
+ return Var;
+}();
+
+exports.default = Var;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./events":1}]},{},[5])
+//# sourceMappingURL=crosstalk.js.map
diff --git a/_site/site_libs/crosstalk-1.2.0/js/crosstalk.js.map b/_site/site_libs/crosstalk-1.2.0/js/crosstalk.js.map
new file mode 100644
index 0000000..cff94f0
--- /dev/null
+++ b/_site/site_libs/crosstalk-1.2.0/js/crosstalk.js.map
@@ -0,0 +1,37 @@
+{
+ "version": 3,
+ "sources": [
+ "node_modules/browser-pack/_prelude.js",
+ "javascript/src/events.js",
+ "javascript/src/filter.js",
+ "javascript/src/filterset.js",
+ "javascript/src/group.js",
+ "javascript/src/index.js",
+ "javascript/src/input.js",
+ "javascript/src/input_checkboxgroup.js",
+ "javascript/src/input_selectize.js",
+ "javascript/src/input_slider.js",
+ "javascript/src/selection.js",
+ "javascript/src/util.js",
+ "javascript/src/var.js"
+ ],
+ "names": [],
+ "mappings": "AAAA;;;;;;;;;;;ICAqB,M;AACnB,oBAAc;AAAA;;AACZ,SAAK,MAAL,GAAc,EAAd;AACA,SAAK,IAAL,GAAY,CAAZ;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,KAAK,MAAL,CAAY,SAAZ,IAAyB,EAAhC;AACD;AACD,UAAI,MAAM,QAAS,KAAK,IAAL,EAAnB;AACA,WAAK,GAAL,IAAY,QAAZ;AACA,aAAO,GAAP;AACD;;AAED;;;;wBACI,S,EAAW,Q,EAAU;AACvB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,OAAO,QAAP,KAAqB,UAAzB,EAAqC;AACnC,aAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,cAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,gBAAI,KAAK,GAAL,MAAc,QAAlB,EAA4B;AAC1B,qBAAO,KAAK,GAAL,CAAP;AACA,qBAAO,GAAP;AACD;AACF;AACF;AACD,eAAO,KAAP;AACD,OAVD,MAUO,IAAI,OAAO,QAAP,KAAqB,QAAzB,EAAmC;AACxC,YAAI,QAAQ,KAAK,QAAL,CAAZ,EAA4B;AAC1B,iBAAO,KAAK,QAAL,CAAP;AACA,iBAAO,QAAP;AACD;AACD,eAAO,KAAP;AACD,OANM,MAMA;AACL,cAAM,IAAI,KAAJ,CAAU,8BAAV,CAAN;AACD;AACF;;;4BAEO,S,EAAW,G,EAAK,O,EAAS;AAC/B,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,WAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,YAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,eAAK,GAAL,EAAU,IAAV,CAAe,OAAf,EAAwB,GAAxB;AACD;AACF;AACF;;;;;;kBA/CkB,M;;;;;;;;;;;;ACArB;;;;AACA;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ,SAAS,YAAT,CAAsB,KAAtB,EAA6B;AAC3B,MAAI,QAAQ,MAAM,GAAN,CAAU,WAAV,CAAZ;AACA,MAAI,SAAS,MAAM,GAAN,EAAb;AACA,MAAI,CAAC,MAAL,EAAa;AACX,aAAS,yBAAT;AACA,UAAM,GAAN,CAAU,MAAV;AACD;AACD,SAAO,MAAP;AACD;;AAED,IAAI,KAAK,CAAT;AACA,SAAS,MAAT,GAAkB;AAChB,SAAO,IAAP;AACD;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;IAwBa,Y,WAAA,Y;AACX,wBAAY,KAAZ,EAAmB,SAAnB,EAA8B;AAAA;;AAC5B,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,GAAL,GAAW,WAAW,QAAtB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;6BAUS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,UAAT,EAAqB;AACnB,aAAK,UAAL,CAAgB,GAAhB,CAAoB,QAApB,EAA8B,KAAK,eAAnC;AACA,aAAK,KAAL;AACA,aAAK,eAAL,GAAuB,IAAvB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,gBAAQ,qBAAI,KAAJ,CAAR;AACA,aAAK,UAAL,GAAkB,aAAa,KAAb,CAAlB;AACA,aAAK,UAAL,GAAkB,qBAAI,KAAJ,EAAW,GAAX,CAAe,QAAf,CAAlB;AACA,YAAI,MAAM,KAAK,UAAL,CAAgB,EAAhB,CAAmB,QAAnB,EAA6B,UAAC,CAAD,EAAO;AAC5C,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;oCAKgB,S,EAAW;AACzB,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;4BAIQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,KAAL;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;AAED;;;;;;;;;;;;0BASM,S,EAAW;AACf,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,KAAhB,CAAsB,KAAK,GAA3B;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;;;;;;;;;;;wBAiBI,I,EAAM,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,MAAhB,CAAuB,KAAK,GAA5B,EAAiC,IAAjC;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;AASA;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;;8BAES,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,GAAhB,CAAoB,KAAK,UAAL,CAAgB,KAApC,EAA2C,KAAK,eAAL,CAAqB,SAArB,CAA3C;AACD;;AAED;;;;;;;;;;;wBApCmB;AACjB,aAAO,KAAK,UAAL,GAAkB,KAAK,UAAL,CAAgB,KAAlC,GAA0C,IAAjD;AACD;;;;;;AA6CH;;;;;;;;;;;;;;;;;;;ACzNA;;;;AAEA,SAAS,iBAAT,CAA2B,CAA3B,EAA8B,CAA9B,EAAiC;AAC/B,MAAI,MAAM,CAAV,EAAa;AACX,WAAO,CAAP;AACD,GAFD,MAEO,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAC,CAAR;AACD,GAFM,MAEA,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAP;AACD;AACF;;AAED;;;;IAGqB,S;AACnB,uBAAc;AAAA;;AACZ,SAAK,KAAL;AACD;;;;4BAEO;AACN;AACA,WAAK,QAAL,GAAgB,EAAhB;AACA;AACA,WAAK,KAAL,GAAa,EAAb;AACA,WAAK,MAAL,GAAc,IAAd;AACA,WAAK,cAAL,GAAsB,CAAtB;AACD;;;2BAMM,Q,EAAU,I,EAAM;AACrB,UAAI,SAAS,IAAb,EAAmB;AACjB,eAAO,KAAK,KAAL,CAAW,CAAX,CAAP,CADiB,CACK;AACtB,aAAK,IAAL,CAAU,iBAAV;AACD;;AAJoB,6BAME,2BAAgB,KAAK,QAAL,CAAc,QAAd,CAAhB,EAAyC,IAAzC,CANF;AAAA,UAMhB,KANgB,oBAMhB,KANgB;AAAA,UAMT,OANS,oBAMT,OANS;;AAOrB,WAAK,QAAL,CAAc,QAAd,IAA0B,IAA1B;;AAEA,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,MAAM,MAA1B,EAAkC,GAAlC,EAAuC;AACrC,aAAK,KAAL,CAAW,MAAM,CAAN,CAAX,IAAuB,CAAC,KAAK,KAAL,CAAW,MAAM,CAAN,CAAX,KAAwB,CAAzB,IAA8B,CAArD;AACD;AACD,WAAK,IAAI,KAAI,CAAb,EAAgB,KAAI,QAAQ,MAA5B,EAAoC,IAApC,EAAyC;AACvC,aAAK,KAAL,CAAW,QAAQ,EAAR,CAAX;AACD;;AAED,WAAK,YAAL,CAAkB,IAAlB;AACD;;AAED;;;;;;;;mCAKmC;AAAA,UAAtB,IAAsB,uEAAf,KAAK,QAAU;;AACjC,UAAI,cAAc,OAAO,IAAP,CAAY,KAAK,QAAjB,EAA2B,MAA7C;AACA,UAAI,gBAAgB,CAApB,EAAuB;AACrB,aAAK,MAAL,GAAc,IAAd;AACD,OAFD,MAEO;AACL,aAAK,MAAL,GAAc,EAAd;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,cAAI,QAAQ,KAAK,KAAL,CAAW,KAAK,CAAL,CAAX,CAAZ;AACA,cAAI,UAAU,WAAd,EAA2B;AACzB,iBAAK,MAAL,CAAY,IAAZ,CAAiB,KAAK,CAAL,CAAjB;AACD;AACF;AACF;AACF;;;0BAEK,Q,EAAU;AACd,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAP,KAAoC,WAAxC,EAAqD;AACnD;AACD;;AAED,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,EAAP;AACD;;AAED,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,aAAK,KAAL,CAAW,KAAK,CAAL,CAAX;AACD;AACD,aAAO,KAAK,QAAL,CAAc,QAAd,CAAP;;AAEA,WAAK,YAAL;AACD;;;wBA3DW;AACV,aAAO,KAAK,MAAZ;AACD;;;wBA2Dc;AACb,UAAI,UAAU,OAAO,IAAP,CAAY,KAAK,KAAjB,CAAd;AACA,cAAQ,IAAR,CAAa,iBAAb;AACA,aAAO,OAAP;AACD;;;;;;kBA/EkB,S;;;;;;;;;;;;;;kBCRG,K;;AAPxB;;;;;;;;AAEA;AACA;AACA,OAAO,kBAAP,GAA4B,OAAO,kBAAP,IAA6B,EAAzD;AACA,IAAI,SAAS,OAAO,kBAApB;;AAEe,SAAS,KAAT,CAAe,SAAf,EAA0B;AACvC,MAAI,aAAa,OAAO,SAAP,KAAsB,QAAvC,EAAiD;AAC/C,QAAI,CAAC,OAAO,cAAP,CAAsB,SAAtB,CAAL,EAAuC;AACrC,aAAO,SAAP,IAAoB,IAAI,KAAJ,CAAU,SAAV,CAApB;AACD;AACD,WAAO,OAAO,SAAP,CAAP;AACD,GALD,MAKO,IAAI,QAAO,SAAP,yCAAO,SAAP,OAAsB,QAAtB,IAAkC,UAAU,KAA5C,IAAqD,UAAU,GAAnE,EAAwE;AAC7E;AACA,WAAO,SAAP;AACD,GAHM,MAGA,IAAI,MAAM,OAAN,CAAc,SAAd,KACP,UAAU,MAAV,IAAoB,CADb,IAEP,OAAO,UAAU,CAAV,CAAP,KAAyB,QAFtB,EAEgC;AACrC,WAAO,MAAM,UAAU,CAAV,CAAN,CAAP;AACD,GAJM,MAIA;AACL,UAAM,IAAI,KAAJ,CAAU,4BAAV,CAAN;AACD;AACF;;IAEK,K;AACJ,iBAAY,IAAZ,EAAkB;AAAA;;AAChB,SAAK,IAAL,GAAY,IAAZ;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;yBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,UAAI,CAAC,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAL,EACE,KAAK,KAAL,CAAW,IAAX,IAAmB,kBAAQ,IAAR,EAAc,IAAd,CAAnB;AACF,aAAO,KAAK,KAAL,CAAW,IAAX,CAAP;AACD;;;wBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,aAAO,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAP;AACD;;;;;;;;;;;;;;;;AC/CH;;;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEA,IAAM,eAAe,qBAAM,SAAN,CAArB;;AAEA,SAAS,IAAT,CAAc,IAAd,EAAoB;AAClB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,SAAS,GAAT,CAAa,IAAb,EAAmB;AACjB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,SAAO,KAAP,CAAa,uBAAb,CAAqC,qBAArC,EAA4D,UAAS,OAAT,EAAkB;AAC5E,QAAI,OAAO,QAAQ,KAAf,KAA0B,QAA9B,EAAwC;AACtC,2BAAM,QAAQ,KAAd,EAAqB,GAArB,CAAyB,QAAQ,IAAjC,EAAuC,GAAvC,CAA2C,QAAQ,KAAnD;AACD,KAFD,MAEO;AACL,WAAK,QAAQ,IAAb,EAAmB,GAAnB,CAAuB,QAAQ,KAA/B;AACD;AACF,GAND;AAOD;;AAED,IAAM,YAAY;AAChB,wBADgB;AAEhB,OAAK,IAFW;AAGhB,OAAK,GAHW;AAIhB,6CAJgB;AAKhB,oCALgB;AAMhB;AANgB,CAAlB;;AASA;;;kBAGe,S;;AACf,OAAO,SAAP,GAAmB,SAAnB;;;;;;;;;;;QCrCgB,Q,GAAA,Q;QAWA,I,GAAA,I;AAfhB,IAAI,IAAI,OAAO,MAAf;;AAEA,IAAI,WAAW,EAAf;;AAEO,SAAS,QAAT,CAAkB,GAAlB,EAAuB;AAC5B,WAAS,IAAI,SAAb,IAA0B,GAA1B;AACA,MAAI,OAAO,QAAP,IAAmB,OAAO,QAAP,CAAgB,UAAhB,KAA+B,UAAtD,EAAkE;AAChE,MAAE,YAAM;AACN;AACD,KAFD;AAGD,GAJD,MAIO,IAAI,OAAO,QAAX,EAAqB;AAC1B,eAAW,IAAX,EAAiB,GAAjB;AACD;AACF;;AAEM,SAAS,IAAT,GAAgB;AACrB,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,UAAU,SAAS,SAAT,CAAd;AACA,MAAE,MAAM,QAAQ,SAAhB,EAA2B,GAA3B,CAA+B,wBAA/B,EAAyD,IAAzD,CAA8D,UAAS,CAAT,EAAY,EAAZ,EAAgB;AAC5E,mBAAa,OAAb,EAAsB,EAAtB;AACD,KAFD;AAGD,GALD;AAMD;;AAED;AACA,SAAS,OAAT,CAAiB,GAAjB,EAAsB;AACpB,SAAO,IAAI,OAAJ,CAAY,uCAAZ,EAAqD,MAArD,CAAP;AACD;;AAED,SAAS,MAAT,CAAgB,EAAhB,EAAoB;AAClB,MAAI,MAAM,EAAE,EAAF,CAAV;AACA,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,IAAI,QAAJ,CAAa,SAAb,KAA2B,CAAC,IAAI,QAAJ,CAAa,uBAAb,CAAhC,EAAuE;AACrE,UAAI,UAAU,SAAS,SAAT,CAAd;AACA,mBAAa,OAAb,EAAsB,EAAtB;AACD;AACF,GALD;AAMD;;AAED,SAAS,YAAT,CAAsB,OAAtB,EAA+B,EAA/B,EAAmC;AACjC,MAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,+CAA+C,QAAQ,GAAG,EAAX,CAA/C,GAAgE,IAA3E,CAAb;AACA,MAAI,OAAO,KAAK,KAAL,CAAW,OAAO,CAAP,EAAU,SAArB,CAAX;;AAEA,MAAI,WAAW,QAAQ,OAAR,CAAgB,EAAhB,EAAoB,IAApB,CAAf;AACA,IAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,QAAjC;AACA,IAAE,EAAF,EAAM,QAAN,CAAe,uBAAf;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,MAAI,eAAe,IAAI,OAAO,KAAP,CAAa,YAAjB,EAAnB;AACA,MAAI,KAAI,OAAO,MAAf;AACA,KAAE,MAAF,CAAS,YAAT,EAAuB;AACrB,UAAM,cAAS,KAAT,EAAgB;AACpB,aAAO,GAAE,KAAF,EAAS,IAAT,CAAc,kBAAd,CAAP;AACD,KAHoB;AAIrB,gBAAY,oBAAS,EAAT,EAAa;AACvB,UAAI,CAAC,GAAE,EAAF,EAAM,QAAN,CAAe,uBAAf,CAAL,EAA8C;AAC5C,eAAO,EAAP;AACD;AACF,KARoB;AASrB,WAAO,eAAS,EAAT,EAAa;AAClB,aAAO,GAAG,EAAV;AACD,KAXoB;AAYrB,cAAU,kBAAS,EAAT,EAAa,CAEtB,CAdoB;AAerB,cAAU,kBAAS,EAAT,EAAa,KAAb,EAAoB,CAE7B,CAjBoB;AAkBrB,oBAAgB,wBAAS,EAAT,EAAa,IAAb,EAAmB,CAElC,CApBoB;AAqBrB,eAAW,mBAAS,EAAT,EAAa,QAAb,EAAuB;AAChC,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,MAAjC;AACD,KAvBoB;AAwBrB,iBAAa,qBAAS,EAAT,EAAa;AACxB,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,OAAjC;AACD;AA1BoB,GAAvB;AA4BA,SAAO,KAAP,CAAa,aAAb,CAA2B,QAA3B,CAAoC,YAApC,EAAkD,wBAAlD;AACD;;;;;;;;AChFD;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,+BADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,QAAI,MAAM,EAAE,EAAF,CAAV;AACA,QAAI,EAAJ,CAAO,QAAP,EAAiB,wBAAjB,EAA2C,YAAW;AACpD,UAAI,UAAU,IAAI,IAAJ,CAAS,gCAAT,CAAd;AACA,UAAI,QAAQ,MAAR,KAAmB,CAAvB,EAA0B;AACxB,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,gBAAQ,IAAR,CAAa,YAAW;AACtB,eAAK,GAAL,CAAS,KAAK,KAAd,EAAqB,OAArB,CAA6B,UAAS,GAAT,EAAc;AACzC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAjBD;;AAmBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AAxCY,CAAf;;;;;;;;ACLA;;IAAY,K;;AACZ;;IAAY,I;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;;;AAMA,QAAI,QAAQ,CAAC,EAAC,OAAO,EAAR,EAAY,OAAO,OAAnB,EAAD,CAAZ;AACA,QAAI,QAAQ,KAAK,aAAL,CAAmB,KAAK,KAAxB,CAAZ;AACA,QAAI,OAAO;AACT,eAAS,MAAM,MAAN,CAAa,KAAb,CADA;AAET,kBAAY,OAFH;AAGT,kBAAY,OAHH;AAIT,mBAAa;AAJJ,KAAX;;AAOA,QAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,QAAX,EAAqB,CAArB,CAAb;;AAEA,QAAI,YAAY,EAAE,MAAF,EAAU,SAAV,CAAoB,IAApB,EAA0B,CAA1B,EAA6B,SAA7C;;AAEA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,cAAU,EAAV,CAAa,QAAb,EAAuB,YAAW;AAChC,UAAI,UAAU,KAAV,CAAgB,MAAhB,KAA2B,CAA/B,EAAkC;AAChC,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,kBAAU,KAAV,CAAgB,OAAhB,CAAwB,UAAS,KAAT,EAAgB;AACtC,eAAK,GAAL,CAAS,KAAT,EAAgB,OAAhB,CAAwB,UAAS,GAAT,EAAc;AACpC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAhBD;;AAkBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AArDY,CAAf;;;;;;;;;;ACNA;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;AACA,IAAI,WAAW,OAAO,QAAtB;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,OAAO,EAAX;AACA,QAAI,MAAM,EAAE,EAAF,EAAM,IAAN,CAAW,OAAX,CAAV;AACA,QAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,QAAI,aAAa,IAAI,IAAJ,CAAS,aAAT,CAAjB;AACA,QAAI,QAAQ,IAAI,IAAJ,CAAS,OAAT,CAAZ;AACA,QAAI,sBAAJ;;AAEA;AACA,QAAI,aAAa,MAAjB,EAAyB;AACvB,sBAAgB,SAAS,GAAT,EAAhB;AACA,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAID,KAND,MAMO,IAAI,aAAa,UAAjB,EAA6B;AAClC,UAAI,WAAW,IAAI,IAAJ,CAAS,UAAT,CAAf;AACA,UAAI,QAAJ,EACE,gBAAgB,SAAS,QAAT,CAAkB,QAAlB,CAAhB,CADF,KAGE,gBAAgB,QAAhB;;AAEF,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAGD,KAVM,MAUA,IAAI,aAAa,QAAjB,EAA2B;AAChC,UAAI,OAAO,KAAP,KAAiB,WAArB,EACE,KAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,YAAI,SAAS,KAAK,GAAL,CAAS,EAAT,EAAa,KAAb,CAAb;AACA,eAAO,KAAK,KAAL,CAAW,MAAM,MAAjB,IAA2B,MAAlC;AACD,OAHD;AAIH;;AAED,QAAI,cAAJ,CAAmB,IAAnB;;AAEA,aAAS,QAAT,GAAoB;AAClB,UAAI,SAAS,IAAI,IAAJ,CAAS,gBAAT,EAA2B,MAAxC;;AAEA;AACA,UAAI,gBAAJ;AACA,UAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,UAAI,aAAa,MAAjB,EAAyB;AACvB,kBAAU,iBAAS,GAAT,EAAc;AACtB,iBAAO,cAAc,IAAI,IAAJ,CAAS,CAAC,GAAV,CAAd,CAAP;AACD,SAFD;AAGD,OAJD,MAIO,IAAI,aAAa,UAAjB,EAA6B;AAClC,kBAAU,iBAAS,GAAT,EAAc;AACtB;AACA,iBAAO,CAAC,GAAD,GAAO,IAAd;AACD,SAHD;AAID,OALM,MAKA;AACL,kBAAU,iBAAS,GAAT,EAAc;AAAE,iBAAO,CAAC,GAAR;AAAc,SAAxC;AACD;;AAED,UAAI,IAAI,IAAJ,CAAS,gBAAT,EAA2B,OAA3B,CAAmC,IAAnC,KAA4C,QAAhD,EAA0D;AACxD,eAAO,CAAC,QAAQ,OAAO,IAAf,CAAD,EAAuB,QAAQ,OAAO,EAAf,CAAvB,CAAP;AACD,OAFD,MAEO;AACL,eAAO,QAAQ,OAAO,IAAf,CAAP;AACD;AACF;;AAED,QAAI,gBAAgB,IAApB;;AAEA,QAAI,EAAJ,CAAO,6BAAP,EAAsC,UAAS,KAAT,EAAgB;AACpD,UAAI,CAAC,IAAI,IAAJ,CAAS,UAAT,CAAD,IAAyB,CAAC,IAAI,IAAJ,CAAS,WAAT,CAA9B,EAAqD;AAAA,wBAClC,UADkC;AAAA;AAAA,YAC9C,IAD8C;AAAA,YACxC,EADwC;;AAEnD,YAAI,OAAO,EAAX;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAL,CAAY,MAAhC,EAAwC,GAAxC,EAA6C;AAC3C,cAAI,MAAM,KAAK,MAAL,CAAY,CAAZ,CAAV;AACA,cAAI,OAAO,IAAP,IAAe,OAAO,EAA1B,EAA8B;AAC5B,iBAAK,IAAL,CAAU,KAAK,IAAL,CAAU,CAAV,CAAV;AACD;AACF;AACD,aAAK,IAAL;AACA,iBAAS,GAAT,CAAa,IAAb;AACA,wBAAgB,IAAhB;AACD;AACF,KAdD;;AAiBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AApHY,CAAf;;AAwHA;AACA,SAAS,QAAT,CAAkB,CAAlB,EAAqB,MAArB,EAA6B;AAC3B,MAAI,MAAM,EAAE,QAAF,EAAV;AACA,SAAO,IAAI,MAAJ,GAAa,MAApB;AACE,UAAM,MAAM,GAAZ;AADF,GAEA,OAAO,GAAP;AACD;;AAED;AACA;AACA,SAAS,aAAT,CAAuB,IAAvB,EAA6B;AAC3B,MAAI,gBAAgB,IAApB,EAA0B;AACxB,WAAO,KAAK,cAAL,KAAwB,GAAxB,GACA,SAAS,KAAK,WAAL,KAAmB,CAA5B,EAA+B,CAA/B,CADA,GACoC,GADpC,GAEA,SAAS,KAAK,UAAL,EAAT,EAA4B,CAA5B,CAFP;AAID,GALD,MAKO;AACL,WAAO,IAAP;AACD;AACF;;;;;;;;;;;;;;ACjJD;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ;;;;;;;;;;;;;;;;IAgBa,e,WAAA,e;AAEX,6BAA4C;AAAA,QAAhC,KAAgC,uEAAxB,IAAwB;AAAA,QAAlB,SAAkB,uEAAN,IAAM;;AAAA;;AAC1C,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,IAAL,GAAY,IAAZ;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;;;;6BAaS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,IAAT,EAAe;AACb,aAAK,IAAL,CAAU,GAAV,CAAc,QAAd,EAAwB,KAAK,eAA7B;AACA,aAAK,IAAL,GAAY,IAAZ;AACA,aAAK,eAAL,GAAuB,IAAvB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,aAAK,IAAL,GAAY,qBAAI,KAAJ,EAAW,GAAX,CAAe,WAAf,CAAZ;AACA,YAAI,MAAM,KAAK,IAAL,CAAU,EAAV,CAAa,QAAb,EAAuB,UAAC,CAAD,EAAO;AACtC,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;;;;;;;;AAcA;;;;;oCAKgB,S,EAAW;AACzB;AACA,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;;;;;;;;;wBAYI,Y,EAAc,S,EAAW;AAC3B,UAAI,KAAK,IAAT,EACE,KAAK,IAAL,CAAU,GAAV,CAAc,YAAd,EAA4B,KAAK,eAAL,CAAqB,SAArB,CAA5B;AACH;;AAED;;;;;;;;;;;;;0BAUM,S,EAAW;AACf,UAAI,KAAK,IAAT,EACE,KAAK,GAAL,CAAS,KAAK,CAAd,EAAiB,KAAK,eAAL,CAAqB,SAArB,CAAjB;AACH;;AAED;;;;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;AAED;;;;;;;;4BAKQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;;wBAlFW;AACV,aAAO,KAAK,IAAL,GAAY,KAAK,IAAL,CAAU,GAAV,EAAZ,GAA8B,IAArC;AACD;;;;;;AAmFH;;;;;;;;;AASA;;;;;;;;;;;;;;;;;;;;;QCpLgB,M,GAAA,M;QAeA,W,GAAA,W;QAQA,e,GAAA,e;QAoCA,a,GAAA,a;;;;AA3DT,SAAS,MAAT,CAAgB,MAAhB,EAAoC;AAAA,oCAAT,OAAS;AAAT,WAAS;AAAA;;AACzC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,QAAQ,MAA5B,EAAoC,GAApC,EAAyC;AACvC,QAAI,MAAM,QAAQ,CAAR,CAAV;AACA,QAAI,OAAO,GAAP,KAAgB,WAAhB,IAA+B,QAAQ,IAA3C,EACE;;AAEF,SAAK,IAAI,GAAT,IAAgB,GAAhB,EAAqB;AACnB,UAAI,IAAI,cAAJ,CAAmB,GAAnB,CAAJ,EAA6B;AAC3B,eAAO,GAAP,IAAc,IAAI,GAAJ,CAAd;AACD;AACF;AACF;AACD,SAAO,MAAP;AACD;;AAEM,SAAS,WAAT,CAAqB,IAArB,EAA2B;AAChC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,QAAI,KAAK,CAAL,KAAW,KAAK,IAAE,CAAP,CAAf,EAA0B;AACxB,YAAM,IAAI,KAAJ,CAAU,0CAAV,CAAN;AACD;AACF;AACF;;AAEM,SAAS,eAAT,CAAyB,CAAzB,EAA4B,CAA5B,EAA+B;AACpC,MAAI,MAAM,CAAV;AACA,MAAI,MAAM,CAAV;;AAEA,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;AACR,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;;AAER,MAAI,SAAS,EAAb;AACA,MAAI,SAAS,EAAb;;AAEA,cAAY,CAAZ;AACA,cAAY,CAAZ;;AAEA,SAAO,MAAM,EAAE,MAAR,IAAkB,MAAM,EAAE,MAAjC,EAAyC;AACvC,QAAI,EAAE,GAAF,MAAW,EAAE,GAAF,CAAf,EAAuB;AACrB;AACA;AACD,KAHD,MAGO,IAAI,EAAE,GAAF,IAAS,EAAE,GAAF,CAAb,EAAqB;AAC1B,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD,KAFM,MAEA;AACL,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD;AACF;;AAED,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,SAAO;AACL,aAAS,MADJ;AAEL,WAAO;AAFF,GAAP;AAID;;AAED;AACA;AACO,SAAS,aAAT,CAAuB,EAAvB,EAA2B;AAChC,MAAI,QAAQ,EAAZ;AACA,MAAI,eAAJ;AACA,OAAK,IAAI,IAAT,IAAiB,EAAjB,EAAqB;AACnB,QAAI,GAAG,cAAH,CAAkB,IAAlB,CAAJ,EACE,MAAM,IAAN,CAAW,IAAX;AACF,QAAI,QAAO,GAAG,IAAH,CAAP,MAAqB,QAArB,IAAiC,OAAO,GAAG,IAAH,EAAS,MAAhB,KAA4B,WAAjE,EAA8E;AAC5E,YAAM,IAAI,KAAJ,CAAU,2BAAV,CAAN;AACD,KAFD,MAEO,IAAI,OAAO,MAAP,KAAmB,WAAnB,IAAkC,WAAW,GAAG,IAAH,EAAS,MAA1D,EAAkE;AACvE,YAAM,IAAI,KAAJ,CAAU,8CAAV,CAAN;AACD;AACD,aAAS,GAAG,IAAH,EAAS,MAAlB;AACD;AACD,MAAI,UAAU,EAAd;AACA,MAAI,aAAJ;AACA,OAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAxB,EAAgC,KAAhC,EAAuC;AACrC,WAAO,EAAP;AACA,SAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAM,MAA9B,EAAsC,KAAtC,EAA6C;AAC3C,WAAK,MAAM,GAAN,CAAL,IAAmB,GAAG,MAAM,GAAN,CAAH,EAAe,GAAf,CAAnB;AACD;AACD,YAAQ,IAAR,CAAa,IAAb;AACD;AACD,SAAO,OAAP;AACD;;AAED;;;;;;;IAMa,mB,WAAA,mB;AACX,+BAAY,OAAZ,EAAqB;AAAA;;AACnB,SAAK,QAAL,GAAgB,OAAhB;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,MAAM,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAV;AACA,WAAK,KAAL,CAAW,GAAX,IAAkB,SAAlB;AACA,aAAO,GAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,UAAI,MAAM,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAV;AACA,UAAI,GAAJ,EAAS;AACP,eAAO,KAAK,KAAL,CAAW,GAAX,CAAP;AACD;AACD,aAAO,GAAP;AACD;;;yCAEoB;AAAA;;AACnB,UAAI,eAAe,KAAK,KAAxB;AACA,WAAK,KAAL,GAAa,EAAb;AACA,aAAO,IAAP,CAAY,YAAZ,EAA0B,OAA1B,CAAkC,UAAC,GAAD,EAAS;AACzC,cAAK,QAAL,CAAc,GAAd,CAAkB,aAAa,GAAb,CAAlB,EAAqC,GAArC;AACD,OAFD;AAGD;;;;;;;;;;;;;;;;;;ACpHH;;;;;;;;IAEqB,G;AACnB,eAAY,KAAZ,EAAmB,IAAnB,EAAyB,YAAa,KAAtC,EAA6C;AAAA;;AAC3C,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,KAAL,GAAa,IAAb;AACA,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,OAAL,GAAe,sBAAf;AACD;;;;0BAEK;AACJ,aAAO,KAAK,MAAZ;AACD;;;wBAEG,K,EAAO,YAAa,K,EAAO;AAC7B,UAAI,KAAK,MAAL,KAAgB,KAApB,EAA2B;AACzB;AACA;AACD;AACD,UAAI,WAAW,KAAK,MAApB;AACA,WAAK,MAAL,GAAc,KAAd;AACA;AACA,UAAI,MAAM,EAAV;AACA,UAAI,SAAS,QAAO,KAAP,yCAAO,KAAP,OAAkB,QAA/B,EAAyC;AACvC,aAAK,IAAI,CAAT,IAAc,KAAd,EAAqB;AACnB,cAAI,MAAM,cAAN,CAAqB,CAArB,CAAJ,EACE,IAAI,CAAJ,IAAS,MAAM,CAAN,CAAT;AACH;AACF;AACD,UAAI,QAAJ,GAAe,QAAf;AACA,UAAI,KAAJ,GAAY,KAAZ;AACA,WAAK,OAAL,CAAa,OAAb,CAAqB,QAArB,EAA+B,GAA/B,EAAoC,IAApC;;AAEA;AACA;AACA,UAAI,OAAO,KAAP,IAAgB,OAAO,KAAP,CAAa,aAAjC,EAAgD;AAC9C,eAAO,KAAP,CAAa,aAAb,CACE,mBACG,KAAK,MAAL,CAAY,IAAZ,KAAqB,IAArB,GAA4B,KAAK,MAAL,CAAY,IAAZ,GAAmB,GAA/C,GAAqD,EADxD,IAEE,KAAK,KAHT,EAIE,OAAO,KAAP,KAAkB,WAAlB,GAAgC,IAAhC,GAAuC,KAJzC;AAMD;AACF;;;uBAEE,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,OAAL,CAAa,EAAb,CAAgB,SAAhB,EAA2B,QAA3B,CAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,OAAL,CAAa,GAAb,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;;;;;kBAjDkB,G",
+ "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/_site/site_libs/crosstalk-1.2.0/js/crosstalk.min.js b/_site/site_libs/crosstalk-1.2.0/js/crosstalk.min.js
new file mode 100644
index 0000000..b7ec0ac
--- /dev/null
+++ b/_site/site_libs/crosstalk-1.2.0/js/crosstalk.min.js
@@ -0,0 +1,2 @@
+!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]}
\ No newline at end of file
diff --git a/_site/site_libs/crosstalk-1.2.0/scss/crosstalk.scss b/_site/site_libs/crosstalk-1.2.0/scss/crosstalk.scss
new file mode 100644
index 0000000..3566561
--- /dev/null
+++ b/_site/site_libs/crosstalk-1.2.0/scss/crosstalk.scss
@@ -0,0 +1,75 @@
+/* Adjust margins outwards, so column contents line up with the edges of the
+ parent of container-fluid. */
+.container-fluid.crosstalk-bscols {
+ margin-left: -30px;
+ margin-right: -30px;
+ white-space: normal;
+}
+
+/* But don't adjust the margins outwards if we're directly under the body,
+ i.e. we were the top-level of something at the console. */
+body > .container-fluid.crosstalk-bscols {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column {
+ display: inline-block;
+ padding-right: 12px;
+ vertical-align: top;
+}
+
+@media only screen and (max-width:480px) {
+ .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column {
+ display: block;
+ padding-right: inherit;
+ }
+}
+
+/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */
+.crosstalk-input {
+ margin-bottom: 15px; /* a la .form-group */
+ .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ input[type="checkbox"] {
+ margin: 4px 0 0;
+ margin-top: 1px;
+ line-height: normal;
+ }
+ .checkbox {
+ position: relative;
+ display: block;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ }
+ .checkbox > label{
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: 400;
+ cursor: pointer;
+ }
+ .checkbox input[type="checkbox"],
+ .checkbox-inline input[type="checkbox"] {
+ position: absolute;
+ margin-top: 2px;
+ margin-left: -20px;
+ }
+ .checkbox + .checkbox {
+ margin-top: -5px;
+ }
+ .checkbox-inline {
+ position: relative;
+ display: inline-block;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: 400;
+ vertical-align: middle;
+ cursor: pointer;
+ }
+ .checkbox-inline + .checkbox-inline {
+ margin-top: 0;
+ margin-left: 10px;
+ }
+}
diff --git a/_site/site_libs/htmlwidgets-1.6.2/htmlwidgets.js b/_site/site_libs/htmlwidgets-1.6.2/htmlwidgets.js
new file mode 100644
index 0000000..1067d02
--- /dev/null
+++ b/_site/site_libs/htmlwidgets-1.6.2/htmlwidgets.js
@@ -0,0 +1,901 @@
+(function() {
+ // If window.HTMLWidgets is already defined, then use it; otherwise create a
+ // new object. This allows preceding code to set options that affect the
+ // initialization process (though none currently exist).
+ window.HTMLWidgets = window.HTMLWidgets || {};
+
+ // See if we're running in a viewer pane. If not, we're in a web browser.
+ var viewerMode = window.HTMLWidgets.viewerMode =
+ /\bviewer_pane=1\b/.test(window.location);
+
+ // See if we're running in Shiny mode. If not, it's a static document.
+ // Note that static widgets can appear in both Shiny and static modes, but
+ // obviously, Shiny widgets can only appear in Shiny apps/documents.
+ var shinyMode = window.HTMLWidgets.shinyMode =
+ typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings;
+
+ // We can't count on jQuery being available, so we implement our own
+ // version if necessary.
+ function querySelectorAll(scope, selector) {
+ if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) {
+ return scope.find(selector);
+ }
+ if (scope.querySelectorAll) {
+ return scope.querySelectorAll(selector);
+ }
+ }
+
+ function asArray(value) {
+ if (value === null)
+ return [];
+ if ($.isArray(value))
+ return value;
+ return [value];
+ }
+
+ // Implement jQuery's extend
+ function extend(target /*, ... */) {
+ if (arguments.length == 1) {
+ return target;
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+ for (var prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+ return target;
+ }
+
+ // IE8 doesn't support Array.forEach.
+ function forEach(values, callback, thisArg) {
+ if (values.forEach) {
+ values.forEach(callback, thisArg);
+ } else {
+ for (var i = 0; i < values.length; i++) {
+ callback.call(thisArg, values[i], i, values);
+ }
+ }
+ }
+
+ // Replaces the specified method with the return value of funcSource.
+ //
+ // Note that funcSource should not BE the new method, it should be a function
+ // that RETURNS the new method. funcSource receives a single argument that is
+ // the overridden method, it can be called from the new method. The overridden
+ // method can be called like a regular function, it has the target permanently
+ // bound to it so "this" will work correctly.
+ function overrideMethod(target, methodName, funcSource) {
+ var superFunc = target[methodName] || function() {};
+ var superFuncBound = function() {
+ return superFunc.apply(target, arguments);
+ };
+ target[methodName] = funcSource(superFuncBound);
+ }
+
+ // Add a method to delegator that, when invoked, calls
+ // delegatee.methodName. If there is no such method on
+ // the delegatee, but there was one on delegator before
+ // delegateMethod was called, then the original version
+ // is invoked instead.
+ // For example:
+ //
+ // var a = {
+ // method1: function() { console.log('a1'); }
+ // method2: function() { console.log('a2'); }
+ // };
+ // var b = {
+ // method1: function() { console.log('b1'); }
+ // };
+ // delegateMethod(a, b, "method1");
+ // delegateMethod(a, b, "method2");
+ // a.method1();
+ // a.method2();
+ //
+ // The output would be "b1", "a2".
+ function delegateMethod(delegator, delegatee, methodName) {
+ var inherited = delegator[methodName];
+ delegator[methodName] = function() {
+ var target = delegatee;
+ var method = delegatee[methodName];
+
+ // The method doesn't exist on the delegatee. Instead,
+ // call the method on the delegator, if it exists.
+ if (!method) {
+ target = delegator;
+ method = inherited;
+ }
+
+ if (method) {
+ return method.apply(target, arguments);
+ }
+ };
+ }
+
+ // Implement a vague facsimilie of jQuery's data method
+ function elementData(el, name, value) {
+ if (arguments.length == 2) {
+ return el["htmlwidget_data_" + name];
+ } else if (arguments.length == 3) {
+ el["htmlwidget_data_" + name] = value;
+ return el;
+ } else {
+ throw new Error("Wrong number of arguments for elementData: " +
+ arguments.length);
+ }
+ }
+
+ // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
+ function escapeRegExp(str) {
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ }
+
+ function hasClass(el, className) {
+ var re = new RegExp("\\b" + escapeRegExp(className) + "\\b");
+ return re.test(el.className);
+ }
+
+ // elements - array (or array-like object) of HTML elements
+ // className - class name to test for
+ // include - if true, only return elements with given className;
+ // if false, only return elements *without* given className
+ function filterByClass(elements, className, include) {
+ var results = [];
+ for (var i = 0; i < elements.length; i++) {
+ if (hasClass(elements[i], className) == include)
+ results.push(elements[i]);
+ }
+ return results;
+ }
+
+ function on(obj, eventName, func) {
+ if (obj.addEventListener) {
+ obj.addEventListener(eventName, func, false);
+ } else if (obj.attachEvent) {
+ obj.attachEvent(eventName, func);
+ }
+ }
+
+ function off(obj, eventName, func) {
+ if (obj.removeEventListener)
+ obj.removeEventListener(eventName, func, false);
+ else if (obj.detachEvent) {
+ obj.detachEvent(eventName, func);
+ }
+ }
+
+ // Translate array of values to top/right/bottom/left, as usual with
+ // the "padding" CSS property
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/padding
+ function unpackPadding(value) {
+ if (typeof(value) === "number")
+ value = [value];
+ if (value.length === 1) {
+ return {top: value[0], right: value[0], bottom: value[0], left: value[0]};
+ }
+ if (value.length === 2) {
+ return {top: value[0], right: value[1], bottom: value[0], left: value[1]};
+ }
+ if (value.length === 3) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[1]};
+ }
+ if (value.length === 4) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[3]};
+ }
+ }
+
+ // Convert an unpacked padding object to a CSS value
+ function paddingToCss(paddingObj) {
+ return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px";
+ }
+
+ // Makes a number suitable for CSS
+ function px(x) {
+ if (typeof(x) === "number")
+ return x + "px";
+ else
+ return x;
+ }
+
+ // Retrieves runtime widget sizing information for an element.
+ // The return value is either null, or an object with fill, padding,
+ // defaultWidth, defaultHeight fields.
+ function sizingPolicy(el) {
+ var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']");
+ if (!sizingEl)
+ return null;
+ var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}");
+ if (viewerMode) {
+ return sp.viewer;
+ } else {
+ return sp.browser;
+ }
+ }
+
+ // @param tasks Array of strings (or falsy value, in which case no-op).
+ // Each element must be a valid JavaScript expression that yields a
+ // function. Or, can be an array of objects with "code" and "data"
+ // properties; in this case, the "code" property should be a string
+ // of JS that's an expr that yields a function, and "data" should be
+ // an object that will be added as an additional argument when that
+ // function is called.
+ // @param target The object that will be "this" for each function
+ // execution.
+ // @param args Array of arguments to be passed to the functions. (The
+ // same arguments will be passed to all functions.)
+ function evalAndRun(tasks, target, args) {
+ if (tasks) {
+ forEach(tasks, function(task) {
+ var theseArgs = args;
+ if (typeof(task) === "object") {
+ theseArgs = theseArgs.concat([task.data]);
+ task = task.code;
+ }
+ var taskFunc = tryEval(task);
+ if (typeof(taskFunc) !== "function") {
+ throw new Error("Task must be a function! Source:\n" + task);
+ }
+ taskFunc.apply(target, theseArgs);
+ });
+ }
+ }
+
+ // Attempt eval() both with and without enclosing in parentheses.
+ // Note that enclosing coerces a function declaration into
+ // an expression that eval() can parse
+ // (otherwise, a SyntaxError is thrown)
+ function tryEval(code) {
+ var result = null;
+ try {
+ result = eval("(" + code + ")");
+ } catch(error) {
+ if (!(error instanceof SyntaxError)) {
+ throw error;
+ }
+ try {
+ result = eval(code);
+ } catch(e) {
+ if (e instanceof SyntaxError) {
+ throw error;
+ } else {
+ throw e;
+ }
+ }
+ }
+ return result;
+ }
+
+ function initSizing(el) {
+ var sizing = sizingPolicy(el);
+ if (!sizing)
+ return;
+
+ var cel = document.getElementById("htmlwidget_container");
+ if (!cel)
+ return;
+
+ if (typeof(sizing.padding) !== "undefined") {
+ document.body.style.margin = "0";
+ document.body.style.padding = paddingToCss(unpackPadding(sizing.padding));
+ }
+
+ if (sizing.fill) {
+ document.body.style.overflow = "hidden";
+ document.body.style.width = "100%";
+ document.body.style.height = "100%";
+ document.documentElement.style.width = "100%";
+ document.documentElement.style.height = "100%";
+ cel.style.position = "absolute";
+ var pad = unpackPadding(sizing.padding);
+ cel.style.top = pad.top + "px";
+ cel.style.right = pad.right + "px";
+ cel.style.bottom = pad.bottom + "px";
+ cel.style.left = pad.left + "px";
+ el.style.width = "100%";
+ el.style.height = "100%";
+
+ return {
+ getWidth: function() { return cel.getBoundingClientRect().width; },
+ getHeight: function() { return cel.getBoundingClientRect().height; }
+ };
+
+ } else {
+ el.style.width = px(sizing.width);
+ el.style.height = px(sizing.height);
+
+ return {
+ getWidth: function() { return cel.getBoundingClientRect().width; },
+ getHeight: function() { return cel.getBoundingClientRect().height; }
+ };
+ }
+ }
+
+ // Default implementations for methods
+ var defaults = {
+ find: function(scope) {
+ return querySelectorAll(scope, "." + this.name);
+ },
+ renderError: function(el, err) {
+ var $el = $(el);
+
+ this.clearError(el);
+
+ // Add all these error classes, as Shiny does
+ var errClass = "shiny-output-error";
+ if (err.type !== null) {
+ // use the classes of the error condition as CSS class names
+ errClass = errClass + " " + $.map(asArray(err.type), function(type) {
+ return errClass + "-" + type;
+ }).join(" ");
+ }
+ errClass = errClass + " htmlwidgets-error";
+
+ // Is el inline or block? If inline or inline-block, just display:none it
+ // and add an inline error.
+ var display = $el.css("display");
+ $el.data("restore-display-mode", display);
+
+ if (display === "inline" || display === "inline-block") {
+ $el.hide();
+ if (err.message !== "") {
+ var errorSpan = $("").addClass(errClass);
+ errorSpan.text(err.message);
+ $el.after(errorSpan);
+ }
+ } else if (display === "block") {
+ // If block, add an error just after the el, set visibility:none on the
+ // el, and position the error to be on top of the el.
+ // Mark it with a unique ID and CSS class so we can remove it later.
+ $el.css("visibility", "hidden");
+ if (err.message !== "") {
+ var errorDiv = $("
").addClass(errClass).css("position", "absolute")
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ // setting width can push out the page size, forcing otherwise
+ // unnecessary scrollbars to appear and making it impossible for
+ // the element to shrink; so use max-width instead
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ errorDiv.text(err.message);
+ $el.after(errorDiv);
+
+ // Really dumb way to keep the size/position of the error in sync with
+ // the parent element as the window is resized or whatever.
+ var intId = setInterval(function() {
+ if (!errorDiv[0].parentElement) {
+ clearInterval(intId);
+ return;
+ }
+ errorDiv
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ }, 500);
+ }
+ }
+ },
+ clearError: function(el) {
+ var $el = $(el);
+ var display = $el.data("restore-display-mode");
+ $el.data("restore-display-mode", null);
+
+ if (display === "inline" || display === "inline-block") {
+ if (display)
+ $el.css("display", display);
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ } else if (display === "block"){
+ $el.css("visibility", "inherit");
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ }
+ },
+ sizing: {}
+ };
+
+ // Called by widget bindings to register a new type of widget. The definition
+ // object can contain the following properties:
+ // - name (required) - A string indicating the binding name, which will be
+ // used by default as the CSS classname to look for.
+ // - initialize (optional) - A function(el) that will be called once per
+ // widget element; if a value is returned, it will be passed as the third
+ // value to renderValue.
+ // - renderValue (required) - A function(el, data, initValue) that will be
+ // called with data. Static contexts will cause this to be called once per
+ // element; Shiny apps will cause this to be called multiple times per
+ // element, as the data changes.
+ window.HTMLWidgets.widget = function(definition) {
+ if (!definition.name) {
+ throw new Error("Widget must have a name");
+ }
+ if (!definition.type) {
+ throw new Error("Widget must have a type");
+ }
+ // Currently we only support output widgets
+ if (definition.type !== "output") {
+ throw new Error("Unrecognized widget type '" + definition.type + "'");
+ }
+ // TODO: Verify that .name is a valid CSS classname
+
+ // Support new-style instance-bound definitions. Old-style class-bound
+ // definitions have one widget "object" per widget per type/class of
+ // widget; the renderValue and resize methods on such widget objects
+ // take el and instance arguments, because the widget object can't
+ // store them. New-style instance-bound definitions have one widget
+ // object per widget instance; the definition that's passed in doesn't
+ // provide renderValue or resize methods at all, just the single method
+ // factory(el, width, height)
+ // which returns an object that has renderValue(x) and resize(w, h).
+ // This enables a far more natural programming style for the widget
+ // author, who can store per-instance state using either OO-style
+ // instance fields or functional-style closure variables (I guess this
+ // is in contrast to what can only be called C-style pseudo-OO which is
+ // what we required before).
+ if (definition.factory) {
+ definition = createLegacyDefinitionAdapter(definition);
+ }
+
+ if (!definition.renderValue) {
+ throw new Error("Widget must have a renderValue function");
+ }
+
+ // For static rendering (non-Shiny), use a simple widget registration
+ // scheme. We also use this scheme for Shiny apps/documents that also
+ // contain static widgets.
+ window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || [];
+ // Merge defaults into the definition; don't mutate the original definition.
+ var staticBinding = extend({}, defaults, definition);
+ overrideMethod(staticBinding, "find", function(superfunc) {
+ return function(scope) {
+ var results = superfunc(scope);
+ // Filter out Shiny outputs, we only want the static kind
+ return filterByClass(results, "html-widget-output", false);
+ };
+ });
+ window.HTMLWidgets.widgets.push(staticBinding);
+
+ if (shinyMode) {
+ // Shiny is running. Register the definition with an output binding.
+ // The definition itself will not be the output binding, instead
+ // we will make an output binding object that delegates to the
+ // definition. This is because we foolishly used the same method
+ // name (renderValue) for htmlwidgets definition and Shiny bindings
+ // but they actually have quite different semantics (the Shiny
+ // bindings receive data that includes lots of metadata that it
+ // strips off before calling htmlwidgets renderValue). We can't
+ // just ignore the difference because in some widgets it's helpful
+ // to call this.renderValue() from inside of resize(), and if
+ // we're not delegating, then that call will go to the Shiny
+ // version instead of the htmlwidgets version.
+
+ // Merge defaults with definition, without mutating either.
+ var bindingDef = extend({}, defaults, definition);
+
+ // This object will be our actual Shiny binding.
+ var shinyBinding = new Shiny.OutputBinding();
+
+ // With a few exceptions, we'll want to simply use the bindingDef's
+ // version of methods if they are available, otherwise fall back to
+ // Shiny's defaults. NOTE: If Shiny's output bindings gain additional
+ // methods in the future, and we want them to be overrideable by
+ // HTMLWidget binding definitions, then we'll need to add them to this
+ // list.
+ delegateMethod(shinyBinding, bindingDef, "getId");
+ delegateMethod(shinyBinding, bindingDef, "onValueChange");
+ delegateMethod(shinyBinding, bindingDef, "onValueError");
+ delegateMethod(shinyBinding, bindingDef, "renderError");
+ delegateMethod(shinyBinding, bindingDef, "clearError");
+ delegateMethod(shinyBinding, bindingDef, "showProgress");
+
+ // The find, renderValue, and resize are handled differently, because we
+ // want to actually decorate the behavior of the bindingDef methods.
+
+ shinyBinding.find = function(scope) {
+ var results = bindingDef.find(scope);
+
+ // Only return elements that are Shiny outputs, not static ones
+ var dynamicResults = results.filter(".html-widget-output");
+
+ // It's possible that whatever caused Shiny to think there might be
+ // new dynamic outputs, also caused there to be new static outputs.
+ // Since there might be lots of different htmlwidgets bindings, we
+ // schedule execution for later--no need to staticRender multiple
+ // times.
+ if (results.length !== dynamicResults.length)
+ scheduleStaticRender();
+
+ return dynamicResults;
+ };
+
+ // Wrap renderValue to handle initialization, which unfortunately isn't
+ // supported natively by Shiny at the time of this writing.
+
+ shinyBinding.renderValue = function(el, data) {
+ Shiny.renderDependencies(data.deps);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var i = 0; data.evals && i < data.evals.length; i++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]);
+ }
+ if (!bindingDef.renderOnNullValue) {
+ if (data.x === null) {
+ el.style.visibility = "hidden";
+ return;
+ } else {
+ el.style.visibility = "inherit";
+ }
+ }
+ if (!elementData(el, "initialized")) {
+ initSizing(el);
+
+ elementData(el, "initialized", true);
+ if (bindingDef.initialize) {
+ var rect = el.getBoundingClientRect();
+ var result = bindingDef.initialize(el, rect.width, rect.height);
+ elementData(el, "init_result", result);
+ }
+ }
+ bindingDef.renderValue(el, data.x, elementData(el, "init_result"));
+ evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]);
+ };
+
+ // Only override resize if bindingDef implements it
+ if (bindingDef.resize) {
+ shinyBinding.resize = function(el, width, height) {
+ // Shiny can call resize before initialize/renderValue have been
+ // called, which doesn't make sense for widgets.
+ if (elementData(el, "initialized")) {
+ bindingDef.resize(el, width, height, elementData(el, "init_result"));
+ }
+ };
+ }
+
+ Shiny.outputBindings.register(shinyBinding, bindingDef.name);
+ }
+ };
+
+ var scheduleStaticRenderTimerId = null;
+ function scheduleStaticRender() {
+ if (!scheduleStaticRenderTimerId) {
+ scheduleStaticRenderTimerId = setTimeout(function() {
+ scheduleStaticRenderTimerId = null;
+ window.HTMLWidgets.staticRender();
+ }, 1);
+ }
+ }
+
+ // Render static widgets after the document finishes loading
+ // Statically render all elements that are of this widget's class
+ window.HTMLWidgets.staticRender = function() {
+ var bindings = window.HTMLWidgets.widgets || [];
+ forEach(bindings, function(binding) {
+ var matches = binding.find(document.documentElement);
+ forEach(matches, function(el) {
+ var sizeObj = initSizing(el, binding);
+
+ var getSize = function(el) {
+ if (sizeObj) {
+ return {w: sizeObj.getWidth(), h: sizeObj.getHeight()}
+ } else {
+ var rect = el.getBoundingClientRect();
+ return {w: rect.width, h: rect.height}
+ }
+ };
+
+ if (hasClass(el, "html-widget-static-bound"))
+ return;
+ el.className = el.className + " html-widget-static-bound";
+
+ var initResult;
+ if (binding.initialize) {
+ var size = getSize(el);
+ initResult = binding.initialize(el, size.w, size.h);
+ elementData(el, "init_result", initResult);
+ }
+
+ if (binding.resize) {
+ var lastSize = getSize(el);
+ var resizeHandler = function(e) {
+ var size = getSize(el);
+ if (size.w === 0 && size.h === 0)
+ return;
+ if (size.w === lastSize.w && size.h === lastSize.h)
+ return;
+ lastSize = size;
+ binding.resize(el, size.w, size.h, initResult);
+ };
+
+ on(window, "resize", resizeHandler);
+
+ // This is needed for cases where we're running in a Shiny
+ // app, but the widget itself is not a Shiny output, but
+ // rather a simple static widget. One example of this is
+ // an rmarkdown document that has runtime:shiny and widget
+ // that isn't in a render function. Shiny only knows to
+ // call resize handlers for Shiny outputs, not for static
+ // widgets, so we do it ourselves.
+ if (window.jQuery) {
+ window.jQuery(document).on(
+ "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ window.jQuery(document).on(
+ "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ }
+
+ // This is needed for the specific case of ioslides, which
+ // flips slides between display:none and display:block.
+ // Ideally we would not have to have ioslide-specific code
+ // here, but rather have ioslides raise a generic event,
+ // but the rmarkdown package just went to CRAN so the
+ // window to getting that fixed may be long.
+ if (window.addEventListener) {
+ // It's OK to limit this to window.addEventListener
+ // browsers because ioslides itself only supports
+ // such browsers.
+ on(document, "slideenter", resizeHandler);
+ on(document, "slideleave", resizeHandler);
+ }
+ }
+
+ var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']");
+ if (scriptData) {
+ var data = JSON.parse(scriptData.textContent || scriptData.text);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var k = 0; data.evals && k < data.evals.length; k++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]);
+ }
+ binding.renderValue(el, data.x, initResult);
+ evalAndRun(data.jsHooks.render, initResult, [el, data.x]);
+ }
+ });
+ });
+
+ invokePostRenderHandlers();
+ }
+
+
+ function has_jQuery3() {
+ if (!window.jQuery) {
+ return false;
+ }
+ var $version = window.jQuery.fn.jquery;
+ var $major_version = parseInt($version.split(".")[0]);
+ return $major_version >= 3;
+ }
+
+ /*
+ / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
+ / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
+ / really means $(setTimeout(fn)).
+ / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
+ /
+ / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
+ / one tick later than it did before, which means staticRender() is
+ / called renderValue() earlier than (advanced) widget authors might be expecting.
+ / https://github.com/rstudio/shiny/issues/2630
+ /
+ / For a concrete example, leaflet has some methods (e.g., updateBounds)
+ / which reference Shiny methods registered in initShiny (e.g., setInputValue).
+ / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
+ / delay execution of those methods (until Shiny methods are ready)
+ / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
+ /
+ / Ideally widget authors wouldn't need to use this setTimeout() hack that
+ / leaflet uses to call Shiny methods on a staticRender(). In the long run,
+ / the logic initShiny should be broken up so that method registration happens
+ / right away, but binding happens later.
+ */
+ function maybeStaticRenderLater() {
+ if (shinyMode && has_jQuery3()) {
+ window.jQuery(window.HTMLWidgets.staticRender);
+ } else {
+ window.HTMLWidgets.staticRender();
+ }
+ }
+
+ if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", function() {
+ document.removeEventListener("DOMContentLoaded", arguments.callee, false);
+ maybeStaticRenderLater();
+ }, false);
+ } else if (document.attachEvent) {
+ document.attachEvent("onreadystatechange", function() {
+ if (document.readyState === "complete") {
+ document.detachEvent("onreadystatechange", arguments.callee);
+ maybeStaticRenderLater();
+ }
+ });
+ }
+
+
+ window.HTMLWidgets.getAttachmentUrl = function(depname, key) {
+ // If no key, default to the first item
+ if (typeof(key) === "undefined")
+ key = 1;
+
+ var link = document.getElementById(depname + "-" + key + "-attachment");
+ if (!link) {
+ throw new Error("Attachment " + depname + "/" + key + " not found in document");
+ }
+ return link.getAttribute("href");
+ };
+
+ window.HTMLWidgets.dataframeToD3 = function(df) {
+ var names = [];
+ var length;
+ for (var name in df) {
+ if (df.hasOwnProperty(name))
+ names.push(name);
+ if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") {
+ throw new Error("All fields must be arrays");
+ } else if (typeof(length) !== "undefined" && length !== df[name].length) {
+ throw new Error("All fields must be arrays of the same length");
+ }
+ length = df[name].length;
+ }
+ var results = [];
+ var item;
+ for (var row = 0; row < length; row++) {
+ item = {};
+ for (var col = 0; col < names.length; col++) {
+ item[names[col]] = df[names[col]][row];
+ }
+ results.push(item);
+ }
+ return results;
+ };
+
+ window.HTMLWidgets.transposeArray2D = function(array) {
+ if (array.length === 0) return array;
+ var newArray = array[0].map(function(col, i) {
+ return array.map(function(row) {
+ return row[i]
+ })
+ });
+ return newArray;
+ };
+ // Split value at splitChar, but allow splitChar to be escaped
+ // using escapeChar. Any other characters escaped by escapeChar
+ // will be included as usual (including escapeChar itself).
+ function splitWithEscape(value, splitChar, escapeChar) {
+ var results = [];
+ var escapeMode = false;
+ var currentResult = "";
+ for (var pos = 0; pos < value.length; pos++) {
+ if (!escapeMode) {
+ if (value[pos] === splitChar) {
+ results.push(currentResult);
+ currentResult = "";
+ } else if (value[pos] === escapeChar) {
+ escapeMode = true;
+ } else {
+ currentResult += value[pos];
+ }
+ } else {
+ currentResult += value[pos];
+ escapeMode = false;
+ }
+ }
+ if (currentResult !== "") {
+ results.push(currentResult);
+ }
+ return results;
+ }
+ // Function authored by Yihui/JJ Allaire
+ window.HTMLWidgets.evaluateStringMember = function(o, member) {
+ var parts = splitWithEscape(member, '.', '\\');
+ for (var i = 0, l = parts.length; i < l; i++) {
+ var part = parts[i];
+ // part may be a character or 'numeric' member name
+ if (o !== null && typeof o === "object" && part in o) {
+ if (i == (l - 1)) { // if we are at the end of the line then evalulate
+ if (typeof o[part] === "string")
+ o[part] = tryEval(o[part]);
+ } else { // otherwise continue to next embedded object
+ o = o[part];
+ }
+ }
+ }
+ };
+
+ // Retrieve the HTMLWidget instance (i.e. the return value of an
+ // HTMLWidget binding's initialize() or factory() function)
+ // associated with an element, or null if none.
+ window.HTMLWidgets.getInstance = function(el) {
+ return elementData(el, "init_result");
+ };
+
+ // Finds the first element in the scope that matches the selector,
+ // and returns the HTMLWidget instance (i.e. the return value of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with that element, if any. If no element matches the
+ // selector, or the first matching element has no HTMLWidget
+ // instance associated with it, then null is returned.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.find = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var el = scope.querySelector(selector);
+ if (el === null) {
+ return null;
+ } else {
+ return window.HTMLWidgets.getInstance(el);
+ }
+ };
+
+ // Finds all elements in the scope that match the selector, and
+ // returns the HTMLWidget instances (i.e. the return values of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with the elements, in an array. If elements that
+ // match the selector don't have an associated HTMLWidget
+ // instance, the returned array will contain nulls.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.findAll = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var nodes = scope.querySelectorAll(selector);
+ var results = [];
+ for (var i = 0; i < nodes.length; i++) {
+ results.push(window.HTMLWidgets.getInstance(nodes[i]));
+ }
+ return results;
+ };
+
+ var postRenderHandlers = [];
+ function invokePostRenderHandlers() {
+ while (postRenderHandlers.length) {
+ var handler = postRenderHandlers.shift();
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ // Register the given callback function to be invoked after the
+ // next time static widgets are rendered.
+ window.HTMLWidgets.addPostRenderHandler = function(callback) {
+ postRenderHandlers.push(callback);
+ };
+
+ // Takes a new-style instance-bound definition, and returns an
+ // old-style class-bound definition. This saves us from having
+ // to rewrite all the logic in this file to accomodate both
+ // types of definitions.
+ function createLegacyDefinitionAdapter(defn) {
+ var result = {
+ name: defn.name,
+ type: defn.type,
+ initialize: function(el, width, height) {
+ return defn.factory(el, width, height);
+ },
+ renderValue: function(el, x, instance) {
+ return instance.renderValue(x);
+ },
+ resize: function(el, width, height, instance) {
+ return instance.resize(width, height);
+ }
+ };
+
+ if (defn.find)
+ result.find = defn.find;
+ if (defn.renderError)
+ result.renderError = defn.renderError;
+ if (defn.clearError)
+ result.clearError = defn.clearError;
+
+ return result;
+ }
+})();
diff --git a/_site/site_libs/jquery-3.5.1/jquery-AUTHORS.txt b/_site/site_libs/jquery-3.5.1/jquery-AUTHORS.txt
new file mode 100644
index 0000000..06df1a5
--- /dev/null
+++ b/_site/site_libs/jquery-3.5.1/jquery-AUTHORS.txt
@@ -0,0 +1,357 @@
+Authors ordered by first contribution.
+
+John Resig
+Gilles van den Hoven
+Michael Geary
+Stefan Petre
+Yehuda Katz
+Corey Jewett
+Klaus Hartl
+Franck Marcia
+Jörn Zaefferer
+Paul Bakaus
+Brandon Aaron
+Mike Alsup
+Dave Methvin
+Ed Engelhardt
+Sean Catchpole
+Paul Mclanahan
+David Serduke
+Richard D. Worth
+Scott González
+Ariel Flesler
+Cheah Chu Yeow
+Andrew Chalkley
+Fabio Buffoni
+Stefan Bauckmeier
+Jon Evans
+TJ Holowaychuk
+Riccardo De Agostini
+Michael Bensoussan
+Louis-Rémi Babé
+Robert Katić
+Damian Janowski
+Anton Kovalyov
+Dušan B. Jovanovic
+Earle Castledine
+Rich Dougherty
+Kim Dalsgaard
+Andrea Giammarchi
+Fabian Jakobs
+Mark Gibson
+Karl Swedberg
+Justin Meyer
+Ben Alman
+James Padolsey
+David Petersen
+Batiste Bieler
+Jake Archibald
+Alexander Farkas
+Filipe Fortes
+Rick Waldron
+Neeraj Singh
+Paul Irish
+Iraê Carvalho
+Matt Curry
+Michael Monteleone
+Noah Sloan
+Tom Viner
+J. Ryan Stinnett
+Douglas Neiner
+Adam J. Sontag
+Heungsub Lee
+Dave Reed
+Carl Fürstenberg
+Jacob Wright
+Ralph Whitbeck
+unknown
+temp01
+Colin Snover
+Jared Grippe
+Ryan W Tenney
+Alex Sexton
+Pinhook
+Ron Otten
+Jephte Clain
+Anton Matzneller
+Dan Heberden
+Henri Wiechers
+Russell Holbrook
+Julian Aubourg
+Gianni Alessandro Chiappetta
+Scott Jehl
+James Burke
+Jonas Pfenniger
+Xavi Ramirez
+Sylvester Keil
+Brandon Sterne
+Mathias Bynens
+Lee Carpenter
+Timmy Willison <4timmywil@gmail.com>
+Corey Frang
+Digitalxero
+David Murdoch
+Josh Varner
+Charles McNulty
+Jordan Boesch
+Jess Thrysoee
+Michael Murray
+Alexis Abril
+Rob Morgan
+John Firebaugh
+Sam Bisbee
+Gilmore Davidson
+Brian Brennan
+Xavier Montillet
+Daniel Pihlstrom
+Sahab Yazdani
+avaly
+Scott Hughes
+Mike Sherov
+Greg Hazel
+Schalk Neethling
+Denis Knauf
+Timo Tijhof
+Steen Nielsen
+Anton Ryzhov
+Shi Chuan
+Matt Mueller
+Berker Peksag
+Toby Brain
+Justin
+Daniel Herman
+Oleg Gaidarenko
+Rock Hymas
+Richard Gibson
+Rafaël Blais Masson
+cmc3cn <59194618@qq.com>
+Joe Presbrey
+Sindre Sorhus
+Arne de Bree
+Vladislav Zarakovsky
+Andrew E Monat
+Oskari
+Joao Henrique de Andrade Bruni
+tsinha
+Dominik D. Geyer
+Matt Farmer
+Trey Hunner
+Jason Moon
+Jeffery To
+Kris Borchers
+Vladimir Zhuravlev
+Jacob Thornton
+Chad Killingsworth
+Vitya Muhachev
+Nowres Rafid
+David Benjamin
+Alan Plum
+Uri Gilad
+Chris Faulkner
+Marcel Greter
+Elijah Manor
+Daniel Chatfield
+Daniel Gálvez
+Nikita Govorov
+Wesley Walser
+Mike Pennisi
+Matthias Jäggli
+Devin Cooper
+Markus Staab
+Dave Riddle
+Callum Macrae
+Jonathan Sampson
+Benjamin Truyman
+Jay Merrifield
+James Huston
+Sai Lung Wong
+Erick Ruiz de Chávez
+David Bonner
+Allen J Schmidt Jr
+Akintayo Akinwunmi
+MORGAN
+Ismail Khair
+Carl Danley
+Mike Petrovich
+Greg Lavallee
+Tom H Fuertes
+Roland Eckl
+Yiming He
+David Fox
+Bennett Sorbo
+Paul Ramos
+Rod Vagg
+Sebastian Burkhard
+Zachary Adam Kaplan
+Adam Coulombe
+nanto_vi
+nanto
+Danil Somsikov
+Ryunosuke SATO
+Diego Tres
+Jean Boussier
+Andrew Plummer
+Mark Raddatz
+Pascal Borreli
+Isaac Z. Schlueter
+Karl Sieburg
+Nguyen Phuc Lam
+Dmitry Gusev
+Steven Benner
+Li Xudong
+Michał Gołębiowski-Owczarek
+Renato Oliveira dos Santos
+Frederic Junod
+Tom H Fuertes
+Mitch Foley
+ros3cin
+Kyle Robinson Young
+John Paul
+Jason Bedard
+Chris Talkington
+Eddie Monge
+Terry Jones
+Jason Merino
+Dan Burzo
+Jeremy Dunck
+Chris Price
+Guy Bedford
+njhamann
+Goare Mao
+Amey Sakhadeo
+Mike Sidorov
+Anthony Ryan
+Lihan Li
+George Kats
+Dongseok Paeng
+Ronny Springer
+Ilya Kantor
+Marian Sollmann
+Chris Antaki
+David Hong
+Jakob Stoeck
+Christopher Jones
+Forbes Lindesay
+S. Andrew Sheppard
+Leonardo Balter
+Rodrigo Rosenfeld Rosas
+Daniel Husar
+Philip Jägenstedt
+John Hoven
+Roman Reiß
+Benjy Cui
+Christian Kosmowski
+David Corbacho
+Liang Peng
+TJ VanToll
+Aurelio De Rosa
+Senya Pugach
+Dan Hart