packages = c(
  "dplyr","ggplot2","stringr", "dslabs", "readr", "tidyr", "purrr",
  "lubridate"
  )
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)
rm(list=ls(all=T))
Sys.setlocale("LC_ALL","C")
options(digits=4, scipen=12)
library(readr)
library(dplyr)
library(ggplot2)
library(stringr)
library(lubridate)
library(tidyr)
library(dslabs)

A. Tidy Data Overview

A1 Tidy Data

Q1: A collaborator sends you a file containing data for three years of average race finish times.

read.csv("data/AgeGroup.txt") %>% setNames(c('age_group',2015:2017))
  age_group 2015 2016 2017
1        20 3:46 3:22 3:50
2        30 3:50 3:43 4:43
3        40 4:39 3:49 4:51
4        50 4:48 4:59 5:01

Are these data considered “tidy” in R? Why or why not?

  • No. These data are not considered “tidy” because the variable “year” is stored in the header.

Q2: Below are four versions of the same dataset.

read.table("data/state1.txt",header=T,sep="")
       state abb region population total
1    Alabama  AL  South    4779736   135
2     Alaska  AK   West     710231    19
3    Arizona  AZ   West    6392017   232
4   Arkansas  AR  South    2915918    93
5 California  CA   West   37253956  1257
6   Colorado  CO   West    5029196    65
read.table("data/state2.txt",header=T,sep="")
    state abb region        var  people
1 Alabama  AL  South population 4779736
2 Alabama  AL  South      total     135
3  Alaska  AK   West population  710231
4  Alaska  AK   West      total      19
5 Arizona  AZ   West population 6392017
6 Arizona  AZ   West      total     232
read.table("data/state3.txt",header=T,sep="")
read.table("data/state4.txt",header=T,sep="")
       state abb region      rate
1    Alabama  AL  South 0.0000282
2     Alaska  AK   West 0.0000268
3    Arizona  AZ   West 0.0000363
4   Arkansas  AR  South 0.0000319
5 California  CA   West 0.0000337
6   Colorado  CO   West 0.0000129

Which one is in a tidy format?

  • in tidy format, every observation is a row and every variable is a column.



B. Reshaping Data

B1. Reshaping Data

Q1: Your file called “times.csv” has age groups and average race finish times for three years of marathons. You read in the data file using the following command.

d = read_csv("data/times.csv") 
Parsed with column specification:
cols(
  age_group = col_integer(),
  `2015` = col_time(format = ""),
  `2016` = col_time(format = ""),
  `2017` = col_time(format = "")
)

Which commands will help you “tidy” the data?

d %>% gather(year, time, `2015`:`2017`) %>% data.frame
   age_group year     time
1         20 2015 03:46:00
2         30 2015 03:50:00
3         40 2015 04:39:00
4         50 2015 04:48:00
5         20 2016 03:22:00
6         30 2016 03:43:00
7         40 2016 03:49:00
8         50 2016 04:59:00
9         20 2017 03:50:00
10        30 2017 04:43:00
11        40 2017 04:51:00
12        50 2017 05:01:00

Q2: You have a dataset on U.S. contagious diseases, but it is in the following wide format:

D = read.table("data/diseases.txt", header=T, sep="")
D
    state year population Hepatitis_A Mumps Polio Rubella
1 Alabama 1990    4040587          86    19    76       1
2 Alabama 1991    4066003          39    14    65       0
3 Alabama 1992    4097169          35    12    24       0
4 Alabama 1993    4133242          40    22    67       0
5 Alabama 1994    4173361          72    12    39       0
6 Alabama 1995    4216645          75     2    38       0

Which of the following would transform this into a tidy dataset, with each row representing an observation of the incidence of each specific disease (as shown below)?

D %>% gather(disease, count, "Hepatitis_A": "Rubella") %>% head(10)
     state year population     disease count
1  Alabama 1990    4040587 Hepatitis_A    86
2  Alabama 1991    4066003 Hepatitis_A    39
3  Alabama 1992    4097169 Hepatitis_A    35
4  Alabama 1993    4133242 Hepatitis_A    40
5  Alabama 1994    4173361 Hepatitis_A    72
6  Alabama 1995    4216645 Hepatitis_A    75
7  Alabama 1990    4040587       Mumps    19
8  Alabama 1991    4066003       Mumps    14
9  Alabama 1992    4097169       Mumps    12
10 Alabama 1993    4133242       Mumps    22

Q3: You have successfully formatted marathon finish times into a tidy object called D. The first few lines are shown below.

D = read.table("data/times_long.txt", header=T, sep=",")
D
  age_group year  time
1        20 2015 03:46
2        30 2015 03:50
3        40 2015 04:39
4        50 2015 04:48
5        20 2016 03:22

Select the code that converts these data back to the wide format, where each year has a separate column.

D %>% spread(year, time)
  age_group  2015  2016
1        20 03:46 03:22
2        30 03:50  <NA>
3        40 04:39  <NA>
4        50 04:48  <NA>

Q4: You have a file

D = read.table("data/state2.txt", header=T, sep="")
D
    state abb region        var  people
1 Alabama  AL  South population 4779736
2 Alabama  AL  South      total     135
3  Alaska  AK   West population  710231
4  Alaska  AK   West      total      19
5 Arizona  AZ   West population 6392017
6 Arizona  AZ   West      total     232

You would like to transform it into a dataset where population and total are each their own column (shown below). Which code would best accomplish this? Select the code that converts these data back to the wide format, where each year has a separate column.

D %>% spread(key=var, value=people)
    state abb region population total
1 Alabama  AL  South    4779736   135
2  Alaska  AK   West     710231    19
3 Arizona  AZ   West    6392017   232
B3 Separate and Unite

Q1: A collaborator sends you a file containing data for two years of average race finish times.

D = read.csv("data/times2.txt")
D
  age_group X2015_time X2015_participants X2016_time
1        20       3:46                 54       3:22
2        30       3:50                 60       3:43
3        40       4:39                 29       3:49
4        50       4:48                 10       4:59
  X2016_participants
1                 62
2                 58
3                 33
4                 14

Which of the answers below best tidys the data?

D %>% gather(key=key, value=value, -age_group) %>%
    separate(col=key, into=c("year", "variable_name"), sep = "_") %>% 
    spread(key=variable_name, value=value) %>% data.frame
attributes are not identical across measure variables;
they will be dropped
  age_group  year participants time
1        20 X2015           54 3:46
2        20 X2016           62 3:22
3        30 X2015           60 3:50
4        30 X2016           58 3:43
5        40 X2015           29 4:39
6        40 X2016           33 3:49
7        50 X2015           10 4:48
8        50 X2016           14 4:59

Q2: You are in the process of tidying some data on heights, hand length, and wingspan for basketball players in the draft. Currently, you have the following:

stats = read.table("data/player.txt",header=T,sep="")
stats
                key value
1      allen_height 75.00
2 allen_hand_length  8.25
3    allen_wingspan 79.25
4      bamba_height 83.25
5 bamba_hand_length  9.75
6    bamba_wingspan 94.00

Select all of the correct commands below that would turn this data into a “tidy” format.

stats %>%
    separate(col=key, into=c("player", "variable_name"), sep="_", extra="merge") %>% 
    spread(key=variable_name, value=value)
  player hand_length height wingspan
1  allen        8.25  75.00    79.25
2  bamba        9.75  83.25    94.00
stats %>%
    separate(col=key, into=c("player", "variable_name1", "variable_name2"), 
             sep="_", fill="right") %>% 
    unite(col = variable_name, variable_name1, variable_name2, sep = "_") %>% 
    spread(key = variable_name, value = value)
  player hand_length height_NA wingspan_NA
1  allen        8.25     75.00       79.25
2  bamba        9.75     83.25       94.00



C. Combining Tables

C1 Combining Tables

Q1: You have created a tab1 and tab2 of state population and election data, similar to our module videos:

tab1 = read.table("data/tab1.txt",header=T,sep="",stringsAsFactors=F)
tab1
                 state population
1              Alabama    4779736
2               Alaska     710231
3              Arizona    6392017
4             Delaware     897934
5 District_of_Columbia     601723
tab2 = read.table("data/tab2.txt",header=T,sep="",stringsAsFactors=F)
tab2
        state electoral_votes
1     Alabama               9
2      Alaska               3
3     Arizona              11
4  California              55
5    Colorado               9
6 Connecticut               7

What are the dimensions of the table dat, created by the following command?

left_join(tab1, tab2, by = "state") %>% dim
[1] 5 3

Q2: We are still using the tab1 and tab2 tables shown in question 1. What join command would create a new table dat with three rows and two columns?

semi_join(tab1, tab2, by = "state")
    state population
1 Alabama    4779736
2  Alaska     710231
3 Arizona    6392017
C2 Binding

Q1: Which of the following are real differences between the join and bind functions? Please select all correct answers.

  • Binding functions combine by position, while join functions match by variables.
  • Joining functions can join datasets of different dimensions, but the bind functions must match on the appropriate dimension (either same row or column numbers).
  • Bind functions can combine both vectors and dataframes, while join functions work for only for dataframes.
C3 Set Operators

Q1: We have two simple tables, shown below:

df1 = data.frame(x=c("a","b"), y=c("a","a"), stringsAsFactors=F); df1
  x y
1 a a
2 b a
df2 = data.frame(x=c("a","a"), y=c("a","b"), stringsAsFactors=F); df2
  x y
1 a a
2 a b

Which command would result in the following table?

dplyr::setdiff(df1, df2)
  x y
1 b a



D. Web Scraping

D1 Web Scraping

Q1: Which feature of html documents allows us to extract the table that we are interested in?

  • All elements in an html page are specified as “nodes”; we can use the node “tables” to identify and extract the specific table we are interested in before we do additional data cleaning.

Q2: In the video, we use the following code to extract the murders table (tab) from our downloaded html file h:

tab <- h %>% html_nodes(“table”) 
tab <- tab[[2]] %>% html_table

Why did we use the html_nodes() command instead of the html_node command?

  • The html_node command only selects the first node of a specified type. In this example the first “table” node is a legend table and not the actual data we are interested in.
  • We used html_nodes so that we could specify the second “table” element using the tab[[2]] command








LS0tDQp0aXRsZTogIldyYW5nbGluZywgVGlkeSBEYXRhIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KPGJyPg0KDQpgYGB7cn0NCnBhY2thZ2VzID0gYygNCiAgImRwbHlyIiwiZ2dwbG90MiIsInN0cmluZ3IiLCAiZHNsYWJzIiwgInJlYWRyIiwgInRpZHlyIiwgInB1cnJyIiwNCiAgImx1YnJpZGF0ZSINCiAgKQ0KZXhpc3RpbmcgPSBhcy5jaGFyYWN0ZXIoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdKQ0KZm9yKHBrZyBpbiBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgZXhpc3RpbmcpXSkgaW5zdGFsbC5wYWNrYWdlcyhwa2cpDQpgYGANCg0KYGBge3IgZWNobz1ULCBtZXNzYWdlPUYsIGNhY2hlPUYsIHdhcm5pbmc9Rn0NCnJtKGxpc3Q9bHMoYWxsPVQpKQ0KU3lzLnNldGxvY2FsZSgiTENfQUxMIiwiQyIpDQpvcHRpb25zKGRpZ2l0cz00LCBzY2lwZW49MTIpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZHNsYWJzKQ0KYGBgDQoNCi0gLSAtDQoNCiMjIyBBLiBUaWR5IERhdGEgT3ZlcnZpZXcNCg0KIyMjIyMgQTEgVGlkeSBEYXRhDQoNCioqUTE6KiogQSBjb2xsYWJvcmF0b3Igc2VuZHMgeW91IGEgZmlsZSBjb250YWluaW5nIGRhdGEgZm9yIHRocmVlIHllYXJzIG9mIGF2ZXJhZ2UgcmFjZSBmaW5pc2ggdGltZXMuIA0KYGBge3J9DQpyZWFkLmNzdigiZGF0YS9BZ2VHcm91cC50eHQiKSAlPiUgc2V0TmFtZXMoYygnYWdlX2dyb3VwJywyMDE1OjIwMTcpKQ0KYGBgDQpfQXJlIHRoZXNlIGRhdGEgY29uc2lkZXJlZCDigJx0aWR54oCdIGluIFI/IFdoeSBvciB3aHkgbm90P18NCg0KKyBOby4gVGhlc2UgZGF0YSBhcmUgbm90IGNvbnNpZGVyZWQg4oCcdGlkeeKAnSBiZWNhdXNlIHRoZSB2YXJpYWJsZSDigJx5ZWFy4oCdIGlzIHN0b3JlZCBpbiB0aGUgaGVhZGVyLg0KKw0KDQoqKlEyOioqIEJlbG93IGFyZSBmb3VyIHZlcnNpb25zIG9mIHRoZSBzYW1lIGRhdGFzZXQuIA0KYGBge3J9DQpyZWFkLnRhYmxlKCJkYXRhL3N0YXRlMS50eHQiLGhlYWRlcj1ULHNlcD0iIikNCmBgYA0KDQpgYGB7cn0NCnJlYWQudGFibGUoImRhdGEvc3RhdGUyLnR4dCIsaGVhZGVyPVQsc2VwPSIiKQ0KYGBgDQoNCmBgYHtyIGV2YWw9Rn0NCnJlYWQudGFibGUoImRhdGEvc3RhdGUzLnR4dCIsaGVhZGVyPVQsc2VwPSIiKQ0KYGBgDQoNCmBgYHtyfQ0KcmVhZC50YWJsZSgiZGF0YS9zdGF0ZTQudHh0IixoZWFkZXI9VCxzZXA9IiIpDQpgYGANCl9XaGljaCBvbmUgaXMgaW4gYSB0aWR5IGZvcm1hdD9fDQoNCisgaW4gdGlkeSBmb3JtYXQsIGV2ZXJ5IG9ic2VydmF0aW9uIGlzIGEgcm93IGFuZCBldmVyeSB2YXJpYWJsZSBpcyBhIGNvbHVtbi4gDQoNCjxicj4NCg0KLSAtIC0NCg0KIyMjIEIuIFJlc2hhcGluZyBEYXRhDQoNCiMjIyMjIEIxLiBSZXNoYXBpbmcgRGF0YQ0KDQoqKlExOioqIFlvdXIgZmlsZSBjYWxsZWQg4oCcdGltZXMuY3N24oCdIGhhcyBhZ2UgZ3JvdXBzIGFuZCBhdmVyYWdlIHJhY2UgZmluaXNoIHRpbWVzIGZvciB0aHJlZSB5ZWFycyBvZiBtYXJhdGhvbnMuIFlvdSByZWFkIGluIHRoZSBkYXRhIGZpbGUgdXNpbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kLg0KDQpgYGB7cn0NCmQgPSByZWFkX2NzdigiZGF0YS90aW1lcy5jc3YiKSANCmBgYA0KDQpfV2hpY2ggY29tbWFuZHMgd2lsbCBoZWxwIHlvdSDigJx0aWR54oCdIHRoZSBkYXRhP18NCmBgYHtyfQ0KZCAlPiUgZ2F0aGVyKHllYXIsIHRpbWUsIGAyMDE1YDpgMjAxN2ApICU+JSBkYXRhLmZyYW1lDQpgYGANCg0KKipRMjoqKiBZb3UgaGF2ZSBhIGRhdGFzZXQgb24gVS5TLiBjb250YWdpb3VzIGRpc2Vhc2VzLCBidXQgaXQgaXMgaW4gdGhlIGZvbGxvd2luZyB3aWRlIGZvcm1hdDoNCmBgYHtyfQ0KRCA9IHJlYWQudGFibGUoImRhdGEvZGlzZWFzZXMudHh0IiwgaGVhZGVyPVQsIHNlcD0iIikNCkQNCmBgYA0KDQpfV2hpY2ggb2YgdGhlIGZvbGxvd2luZyB3b3VsZCB0cmFuc2Zvcm0gdGhpcyBpbnRvIGEgdGlkeSBkYXRhc2V0LCB3aXRoIGVhY2ggcm93IHJlcHJlc2VudGluZyBhbiBvYnNlcnZhdGlvbiBvZiB0aGUgaW5jaWRlbmNlIG9mIGVhY2ggc3BlY2lmaWMgZGlzZWFzZSAoYXMgc2hvd24gYmVsb3cpP18NCmBgYHtyfQ0KRCAlPiUgZ2F0aGVyKGRpc2Vhc2UsIGNvdW50LCAiSGVwYXRpdGlzX0EiOiAiUnViZWxsYSIpICU+JSBoZWFkKDEwKQ0KYGBgDQoNCioqUTM6KiogWW91IGhhdmUgc3VjY2Vzc2Z1bGx5IGZvcm1hdHRlZCBtYXJhdGhvbiBmaW5pc2ggdGltZXMgaW50byBhIHRpZHkgb2JqZWN0IGNhbGxlZCBgRGAuIFRoZSBmaXJzdCBmZXcgbGluZXMgYXJlIHNob3duIGJlbG93Lg0KYGBge3J9DQpEID0gcmVhZC50YWJsZSgiZGF0YS90aW1lc19sb25nLnR4dCIsIGhlYWRlcj1ULCBzZXA9IiwiKQ0KRA0KYGBgDQoNCl9TZWxlY3QgdGhlIGNvZGUgdGhhdCBjb252ZXJ0cyB0aGVzZSBkYXRhIGJhY2sgdG8gdGhlIHdpZGUgZm9ybWF0LCB3aGVyZSBlYWNoIHllYXIgaGFzIGEgc2VwYXJhdGUgY29sdW1uLl8NCmBgYHtyfQ0KRCAlPiUgc3ByZWFkKHllYXIsIHRpbWUpDQpgYGANCg0KKipRNDoqKiBZb3UgaGF2ZSBhIGZpbGUNCmBgYHtyfQ0KRCA9IHJlYWQudGFibGUoImRhdGEvc3RhdGUyLnR4dCIsIGhlYWRlcj1ULCBzZXA9IiIpDQpEDQpgYGANCllvdSB3b3VsZCBsaWtlIHRvIHRyYW5zZm9ybSBpdCBpbnRvIGEgZGF0YXNldCB3aGVyZSBwb3B1bGF0aW9uIGFuZCB0b3RhbCBhcmUgZWFjaCB0aGVpciBvd24gY29sdW1uIChzaG93biBiZWxvdykuIF9XaGljaCBjb2RlIHdvdWxkIGJlc3QgYWNjb21wbGlzaCB0aGlzPyBTZWxlY3QgdGhlIGNvZGUgdGhhdCBjb252ZXJ0cyB0aGVzZSBkYXRhIGJhY2sgdG8gdGhlIHdpZGUgZm9ybWF0LCB3aGVyZSBlYWNoIHllYXIgaGFzIGEgc2VwYXJhdGUgY29sdW1uLl8NCmBgYHtyfQ0KRCAlPiUgc3ByZWFkKGtleT12YXIsIHZhbHVlPXBlb3BsZSkNCmBgYA0KDQojIyMjIyBCMyBTZXBhcmF0ZSBhbmQgVW5pdGUNCg0KKipRMToqKiBBIGNvbGxhYm9yYXRvciBzZW5kcyB5b3UgYSBmaWxlIGNvbnRhaW5pbmcgZGF0YSBmb3IgdHdvIHllYXJzIG9mIGF2ZXJhZ2UgcmFjZSBmaW5pc2ggdGltZXMuDQpgYGB7cn0NCkQgPSByZWFkLmNzdigiZGF0YS90aW1lczIudHh0IikNCkQNCmBgYA0KDQpfV2hpY2ggb2YgdGhlIGFuc3dlcnMgYmVsb3cgYmVzdCB0aWR5cyB0aGUgZGF0YT9fDQpgYGB7cn0NCkQgJT4lIGdhdGhlcihrZXk9a2V5LCB2YWx1ZT12YWx1ZSwgLWFnZV9ncm91cCkgJT4lDQoJc2VwYXJhdGUoY29sPWtleSwgaW50bz1jKCJ5ZWFyIiwgInZhcmlhYmxlX25hbWUiKSwgc2VwID0gIl8iKSAlPiUgDQoJc3ByZWFkKGtleT12YXJpYWJsZV9uYW1lLCB2YWx1ZT12YWx1ZSkgJT4lIGRhdGEuZnJhbWUNCmBgYA0KDQoqKlEyOioqIFlvdSBhcmUgaW4gdGhlIHByb2Nlc3Mgb2YgdGlkeWluZyBzb21lIGRhdGEgb24gaGVpZ2h0cywgaGFuZCBsZW5ndGgsIGFuZCB3aW5nc3BhbiBmb3IgYmFza2V0YmFsbCBwbGF5ZXJzIGluIHRoZSBkcmFmdC4gQ3VycmVudGx5LCB5b3UgaGF2ZSB0aGUgZm9sbG93aW5nOg0KYGBge3J9DQpzdGF0cyA9IHJlYWQudGFibGUoImRhdGEvcGxheWVyLnR4dCIsaGVhZGVyPVQsc2VwPSIiKQ0Kc3RhdHMNCmBgYA0KDQpfU2VsZWN0IGFsbCBvZiB0aGUgY29ycmVjdCBjb21tYW5kcyBiZWxvdyB0aGF0IHdvdWxkIHR1cm4gdGhpcyBkYXRhIGludG8gYSDigJx0aWR54oCdIGZvcm1hdC5fDQoNCmBgYHtyfQ0Kc3RhdHMgJT4lDQoJc2VwYXJhdGUoY29sPWtleSwgaW50bz1jKCJwbGF5ZXIiLCAidmFyaWFibGVfbmFtZSIpLCBzZXA9Il8iLCBleHRyYT0ibWVyZ2UiKSAlPiUgDQoJc3ByZWFkKGtleT12YXJpYWJsZV9uYW1lLCB2YWx1ZT12YWx1ZSkNCmBgYA0KDQpgYGB7cn0NCnN0YXRzICU+JQ0KCXNlcGFyYXRlKGNvbD1rZXksIGludG89YygicGxheWVyIiwgInZhcmlhYmxlX25hbWUxIiwgInZhcmlhYmxlX25hbWUyIiksIA0KCSAgICAgICAgIHNlcD0iXyIsIGZpbGw9InJpZ2h0IikgJT4lIA0KCXVuaXRlKGNvbCA9IHZhcmlhYmxlX25hbWUsIHZhcmlhYmxlX25hbWUxLCB2YXJpYWJsZV9uYW1lMiwgc2VwID0gIl8iKSAlPiUgDQoJc3ByZWFkKGtleSA9IHZhcmlhYmxlX25hbWUsIHZhbHVlID0gdmFsdWUpDQpgYGANCg0KPGJyPg0KDQotIC0gLQ0KDQojIyMgQy4gQ29tYmluaW5nIFRhYmxlcw0KDQojIyMjIyBDMSBDb21iaW5pbmcgVGFibGVzDQoNCioqUTE6KiogWW91IGhhdmUgY3JlYXRlZCBhIHRhYjEgYW5kIHRhYjIgb2Ygc3RhdGUgcG9wdWxhdGlvbiBhbmQgZWxlY3Rpb24gZGF0YSwgc2ltaWxhciB0byBvdXIgbW9kdWxlIHZpZGVvczoNCmBgYHtyfQ0KdGFiMSA9IHJlYWQudGFibGUoImRhdGEvdGFiMS50eHQiLGhlYWRlcj1ULHNlcD0iIixzdHJpbmdzQXNGYWN0b3JzPUYpDQp0YWIxDQp0YWIyID0gcmVhZC50YWJsZSgiZGF0YS90YWIyLnR4dCIsaGVhZGVyPVQsc2VwPSIiLHN0cmluZ3NBc0ZhY3RvcnM9RikNCnRhYjINCmBgYA0KDQpfV2hhdCBhcmUgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIHRhYmxlIGRhdCwgY3JlYXRlZCBieSB0aGUgZm9sbG93aW5nIGNvbW1hbmQ/Xw0KYGBge3J9DQpsZWZ0X2pvaW4odGFiMSwgdGFiMiwgYnkgPSAic3RhdGUiKSAlPiUgZGltDQpgYGANCg0KDQoqKlEyOioqIF9XZSBhcmUgc3RpbGwgdXNpbmcgdGhlIHRhYjEgYW5kIHRhYjIgdGFibGVzIHNob3duIGluIHF1ZXN0aW9uIDEuIFdoYXQgam9pbiBjb21tYW5kIHdvdWxkIGNyZWF0ZSBhIG5ldyB0YWJsZSBgZGF0YCB3aXRoIHRocmVlIHJvd3MgYW5kIHR3byBjb2x1bW5zP18NCmBgYHtyfQ0Kc2VtaV9qb2luKHRhYjEsIHRhYjIsIGJ5ID0gInN0YXRlIikNCmBgYA0KDQojIyMjIyBDMiBCaW5kaW5nDQoNCioqUTE6KiogX1doaWNoIG9mIHRoZSBmb2xsb3dpbmcgYXJlIHJlYWwgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgam9pbiBhbmQgYmluZCBmdW5jdGlvbnM/IFBsZWFzZSBzZWxlY3QgYWxsIGNvcnJlY3QgYW5zd2Vycy5fDQoNCisgQmluZGluZyBmdW5jdGlvbnMgY29tYmluZSBieSBwb3NpdGlvbiwgd2hpbGUgam9pbiBmdW5jdGlvbnMgbWF0Y2ggYnkgdmFyaWFibGVzLg0KKyBKb2luaW5nIGZ1bmN0aW9ucyBjYW4gam9pbiBkYXRhc2V0cyBvZiBkaWZmZXJlbnQgZGltZW5zaW9ucywgYnV0IHRoZSBiaW5kIGZ1bmN0aW9ucyBtdXN0IG1hdGNoIG9uIHRoZSBhcHByb3ByaWF0ZSBkaW1lbnNpb24gKGVpdGhlciBzYW1lIHJvdyBvciBjb2x1bW4gbnVtYmVycykuDQorIEJpbmQgZnVuY3Rpb25zIGNhbiBjb21iaW5lIGJvdGggdmVjdG9ycyBhbmQgZGF0YWZyYW1lcywgd2hpbGUgam9pbiBmdW5jdGlvbnMgd29yayBmb3Igb25seSBmb3IgZGF0YWZyYW1lcy4NCisNCg0KDQojIyMjIyBDMyBTZXQgT3BlcmF0b3JzDQoNCioqUTE6KiogV2UgaGF2ZSB0d28gc2ltcGxlIHRhYmxlcywgc2hvd24gYmVsb3c6DQpgYGB7cn0NCmRmMSA9IGRhdGEuZnJhbWUoeD1jKCJhIiwiYiIpLCB5PWMoImEiLCJhIiksIHN0cmluZ3NBc0ZhY3RvcnM9Rik7IGRmMQ0KZGYyID0gZGF0YS5mcmFtZSh4PWMoImEiLCJhIiksIHk9YygiYSIsImIiKSwgc3RyaW5nc0FzRmFjdG9ycz1GKTsgZGYyDQpgYGANCg0KX1doaWNoIGNvbW1hbmQgd291bGQgcmVzdWx0IGluIHRoZSBmb2xsb3dpbmcgdGFibGU/Xw0KYGBge3J9DQpkcGx5cjo6c2V0ZGlmZihkZjEsIGRmMikNCmBgYA0KDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyBELiBXZWIgU2NyYXBpbmcNCg0KIyMjIyMgRDEgV2ViIFNjcmFwaW5nDQoNCioqUTE6KiogX1doaWNoIGZlYXR1cmUgb2YgaHRtbCBkb2N1bWVudHMgYWxsb3dzIHVzIHRvIGV4dHJhY3QgdGhlIHRhYmxlIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4/Xw0KDQorIEFsbCBlbGVtZW50cyBpbiBhbiBodG1sIHBhZ2UgYXJlIHNwZWNpZmllZCBhcyDigJxub2Rlc+KAnTsgd2UgY2FuIHVzZSB0aGUgbm9kZSDigJx0YWJsZXPigJ0gdG8gaWRlbnRpZnkgYW5kIGV4dHJhY3QgdGhlIHNwZWNpZmljIHRhYmxlIHdlIGFyZSBpbnRlcmVzdGVkIGluIGJlZm9yZSB3ZSBkbyBhZGRpdGlvbmFsIGRhdGEgY2xlYW5pbmcuDQorDQoNCioqUTI6KiogSW4gdGhlIHZpZGVvLCB3ZSB1c2UgdGhlIGZvbGxvd2luZyBjb2RlIHRvIGV4dHJhY3QgdGhlIG11cmRlcnMgdGFibGUgKHRhYikgZnJvbSBvdXIgZG93bmxvYWRlZCBodG1sIGZpbGUgYGhgOg0KYGBge3IgZXZhbD1GfQ0KdGFiIDwtIGggJT4lIGh0bWxfbm9kZXMo4oCcdGFibGXigJ0pIA0KdGFiIDwtIHRhYltbMl1dICU+JSBodG1sX3RhYmxlDQpgYGANCg0KX1doeSBkaWQgd2UgdXNlIHRoZSBodG1sX25vZGVzKCkgY29tbWFuZCBpbnN0ZWFkIG9mIHRoZSBodG1sX25vZGUgY29tbWFuZD9fDQoNCisgVGhlIGh0bWxfbm9kZSBjb21tYW5kIG9ubHkgc2VsZWN0cyB0aGUgZmlyc3Qgbm9kZSBvZiBhIHNwZWNpZmllZCB0eXBlLiBJbiB0aGlzIGV4YW1wbGUgdGhlIGZpcnN0IOKAnHRhYmxl4oCdIG5vZGUgaXMgYSBsZWdlbmQgdGFibGUgYW5kIG5vdCB0aGUgYWN0dWFsIGRhdGEgd2UgYXJlIGludGVyZXN0ZWQgaW4uDQorIFdlIHVzZWQgaHRtbF9ub2RlcyBzbyB0aGF0IHdlIGNvdWxkIHNwZWNpZnkgdGhlIHNlY29uZCDigJx0YWJsZeKAnSBlbGVtZW50IHVzaW5nIHRoZSB0YWJbWzJdXSBjb21tYW5kDQorDQoNCjxicj4NCg0KLSAtIC0NCg0KPGJyPjxicj48YnI+PGJyPjxicj4NCg0KPHN0eWxlPg0KLmNhcHRpb24gew0KICBjb2xvcjogIzc3NzsNCiAgbWFyZ2luLXRvcDogMTBweDsNCn0NCnAgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcHJlIHsNCiAgd29yZC1icmVhazogbm9ybWFsOw0KICB3b3JkLXdyYXA6IG5vcm1hbDsNCiAgbGluZS1oZWlnaHQ6IDE7DQp9DQpwcmUgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcCxsaSB7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQoucnsNCiAgbGluZS1oZWlnaHQ6IDEuMjsNCn0NCg0KdGl0bGV7DQogIGNvbG9yOiAjY2MwMDAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KYm9keXsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgxLGgyLGgzLGg0LGg1ew0KICBjb2xvcjogIzAwODgwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgzew0KICBjb2xvcjogI2IzNmIwMDsNCiAgYmFja2dyb3VuZDogI2ZmZTBiMzsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpoNXsNCiAgY29sb3I6ICMwMDYwMDA7DQogIGJhY2tncm91bmQ6ICNmZmZmZTA7DQogIGxpbmUtaGVpZ2h0OiAyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KZW17DQogIGNvbG9yOiAjMDAwMGMwOw0KICBiYWNrZ3JvdW5kOiAjZjBmMGYwOw0KICB9DQo8L3N0eWxlPg0K