This document is a quick introduction to data wrangling, graphics, and typesetting in R. You can download the code by clicking the “Code” button to the upper right.

First thing is first; let’s install/load all of the packages that we will be using, and clear out the environment.

packages <- c("haven","dplyr","ggplot2","countrycode","tidyr","gridExtra","grid",
              "stargazer")
for(i in packages){
  if(!require(i,character.only = T, quietly = T)){
    install.packages(i)
    library(i, character.only = T, quietly = T)
  }
}

rm(list=ls())

We will be using data from Peterson (2017): Export Diversity and Human Rights. You can download the replication archive by clicking here or download the data directly by running the following chunk.

d <- read_dta("https://bit.ly/3a9nUSL")
d
## # A tibble: 5,188 x 18
##    ccode  year twoway inhhi comper polity2 physint conflictonlocat~ lnpop
##    <dbl> <dbl>  <dbl> <dbl>  <dbl>   <dbl>   <dbl>            <dbl> <dbl>
##  1     2  1981  0.986 0.990  0.997      10       8                0  19.3
##  2     2  1982  0.988 0.989  0.998      10       8                0  19.3
##  3     2  1983  0.982 0.989  0.994      10       8                1  19.3
##  4     2  1984  0.987 0.987  1          10       8                0  19.3
##  5     2  1985  0.985 0.987  0.998      10       7                0  19.3
##  6     2  1986  0.980 0.987  0.994      10       7                0  19.3
##  7     2  1987  0.982 0.987  0.995      10       8                0  19.3
##  8     2  1988  0.977 0.988  0.989      10       7                0  19.3
##  9     2  1989  0.980 0.988  0.992      10       7                1  19.3
## 10     2  1990  0.983 0.988  0.995      10       8                0  19.4
## # ... with 5,178 more rows, and 9 more variables: lngdppc <dbl>, gdppc <dbl>,
## #   expdep <dbl>, gdpgrowth <dbl>, lib_HK <dbl>, meanarab <dbl>, meanpop <dbl>,
## #   sdarab_manual <dbl>, sdpop_manual <dbl>

Data Wrangling

Selecting Cases and Subsetting

As with most things in R there are multiple ways of accomplishing the same goal. Being able to switch between approaches can help you accomplish more complicated tasks. I generally stick to base R for subsetting. To get indices which satisfy logical statements you can use the which function

which(d$gdppc > 50000)
##  [1] 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 2116 2117 2118
## [16] 2119 2120 2121 2122 2123 2124 2125 2126 3981 3982 3983 3984 3985 3986 4017
## [31] 4018 4019 4020 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046
## [46] 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816
## [61] 4817 4818 4820 4821 4823 4824 4825 4826 4827 4828 4830
which(d$gdppc < 2000 & d$polity2 == 10)
## [1] 4277 4278 4279 4280
which(d$gdpgrowth < -.5 | d$gdppc < 100)
## [1] 3040 3369 3717 3805 3967

We can combine this with indexing to subset down the data. We can also call columns in a variety of ways. Remember that you can create objects carying this information to modularize your code, which might be helpful in particular situations to keep everything clear.

inds <- which(d$gdppc > 50000)
cols <- c("ccode","year","physint","lnpop")

sub1 <- d[inds,cols]
sub1
## # A tibble: 71 x 4
##    ccode  year physint lnpop
##    <dbl> <dbl>   <dbl> <dbl>
##  1   212  1999       8  13.0
##  2   212  2000       8  13.0
##  3   212  2001       8  13.0
##  4   212  2002       8  13.0
##  5   212  2003       8  13.0
##  6   212  2004       8  13.0
##  7   212  2005       8  13.0
##  8   212  2006       8  13.1
##  9   212  2007       8  13.1
## 10   212  2008       8  13.1
## # ... with 61 more rows

Alternatively, one could use the subset function from base R to get the same result.

sub2 <- subset(d,d$gdppc > 50000,cols)
sub2
## # A tibble: 71 x 4
##    ccode  year physint lnpop
##    <dbl> <dbl>   <dbl> <dbl>
##  1   212  1999       8  13.0
##  2   212  2000       8  13.0
##  3   212  2001       8  13.0
##  4   212  2002       8  13.0
##  5   212  2003       8  13.0
##  6   212  2004       8  13.0
##  7   212  2005       8  13.0
##  8   212  2006       8  13.1
##  9   212  2007       8  13.1
## 10   212  2008       8  13.1
## # ... with 61 more rows
identical(sub1,sub2)
## [1] TRUE

Another great option is the dplyr package, which is part of the tidyverse alongside the packages haven and ggplot2. One of the best things about the tidyverse family of packages is that they are very well documented, including a variety of cheatsheets and books. One thing that makes the wrangling tools particularly powerful is that they leverage a pipe (%>%) from the magrittr package which says,in pseudo-code, that x %>% f(y) is the same as f(x,y). This can create nice work flow. For example, to get the same subset yet again:

d %>% filter(gdppc > 50000) %>% select(all_of(cols)) -> sub3

all(sub1 == sub3, na.rm=T)
## [1] TRUE

Neat. What we did was took our dataframe, filtered the rows that we wanted, and then selected the columns of interest.

If we want to sort data, there is a base R approach for vectors.

head(sort(d$gdpgrowth))
## [1] -0.6532034 -0.6011391 -0.5537450 -0.5498320 -0.5225903 -0.4939937

For dataframes you have to use order, which produces index numbers that can be used as before

d[order(d$gdpgrowth),c("ccode","year","gdpgrowth")]
## # A tibble: 5,188 x 3
##    ccode  year gdpgrowth
##    <dbl> <dbl>     <dbl>
##  1   645  1991    -0.653
##  2   572  2003    -0.601
##  3   517  1994    -0.554
##  4   690  1991    -0.550
##  5   660  1989    -0.523
##  6    92  2007    -0.494
##  7   475  1986    -0.480
##  8   450  1990    -0.475
##  9   373  1993    -0.440
## 10   411  1990    -0.423
## # ... with 5,178 more rows

We can also switch the ordering around by setting decreasing = T

d[order(d$gdpgrowth,decreasing = T),c("ccode","year","gdpgrowth")]
## # A tibble: 5,188 x 3
##    ccode  year gdpgrowth
##    <dbl> <dbl>     <dbl>
##  1   690  1992     1.86 
##  2   572  2005     1.48 
##  3   450  1997     1.39 
##  4   411  1997     1.38 
##  5    92  2009     1.13 
##  6   411  2002     0.874
##  7   345  1996     0.854
##  8   411  1999     0.788
##  9   552  2010     0.752
## 10   411  1992     0.731
## # ... with 5,178 more rows

Or we could use the handy %>%. In this case we have to use the placeholder . for the input, which might be handy to know that you can do for more complicated functions.

order(d$gdpgrowth,decreasing = T) %>% d[.,c("ccode","year","gdpgrowth")]
## # A tibble: 5,188 x 3
##    ccode  year gdpgrowth
##    <dbl> <dbl>     <dbl>
##  1   690  1992     1.86 
##  2   572  2005     1.48 
##  3   450  1997     1.39 
##  4   411  1997     1.38 
##  5    92  2009     1.13 
##  6   411  2002     0.874
##  7   345  1996     0.854
##  8   411  1999     0.788
##  9   552  2010     0.752
## 10   411  1992     0.731
## # ... with 5,178 more rows

There is also a handy arrange function in dplyr for accomplishing the same sort of task but allowing to sort based on multiple columns.

d %>% select(c("ccode","year","gdpgrowth")) %>% arrange(ccode,gdpgrowth)
## # A tibble: 5,188 x 3
##    ccode  year gdpgrowth
##    <dbl> <dbl>     <dbl>
##  1     2  2009  -0.0359 
##  2     2  1982  -0.0233 
##  3     2  2008  -0.00629
##  4     2  1991  -0.00469
##  5     2  2001   0.00829
##  6     2  2002   0.0129 
##  7     2  1990   0.0150 
##  8     2  2007   0.0195 
##  9     2  2003   0.0238 
## 10     2  2010   0.0256 
## # ... with 5,178 more rows

Converting between Long and Wide

Sometimes data comes in “Long” format, like the data we have been working with, where each row represents an observational unit (here country - year). In other cases data will come in “Wide” format like this or this

We might want to convert data back and forth depending on what we want to do. Let’s do this for the GDP per capita variable; see NYU Data Services for a handy guide to reshaping.

long <- d[,c("ccode","year","gdppc")]
long
## # A tibble: 5,188 x 3
##    ccode  year  gdppc
##    <dbl> <dbl>  <dbl>
##  1     2  1981 25977.
##  2     2  1982 25131.
##  3     2  1983 26026.
##  4     2  1984 27751.
##  5     2  1985 28455.
##  6     2  1986 29014.
##  7     2  1987 29639.
##  8     2  1988 30506.
##  9     2  1989 31274.
## 10     2  1990 31432.
## # ... with 5,178 more rows

Long to Wide with tidyr (updated versions of gather and spread)

long %>% pivot_wider(names_from = year, values_from = gdppc) -> wide
wide
## # A tibble: 189 x 31
##    ccode `1981` `1982` `1983` `1984` `1985` `1986` `1987` `1988` `1989` `1990`
##    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
##  1     2 25977. 25131. 26026. 27751. 28455. 29014. 29639. 30506. 31274. 31432.
##  2    20 22718. 22267. 23001. 24238. 25387. 25987. 27535. 28487. 29005. 28589.
##  3    31 12648. 14004. 14880. 17393. 18428. 17593. 18885. 17582. 18414. 16909.
##  4    40    NA     NA     NA     NA     NA     NA     NA     NA     NA     NA 
##  5    41    NA     NA     NA     NA     NA     NA     NA     NA     NA     NA 
##  6    42  3600.  3638.  3719.  4064.  4100.  4273.  4673.  4826.  4364.  3923.
##  7    51  3904.  3811.  3862.  3744.  3329.  3539.  3875.  3958.  3962.  4267.
##  8    52 24382. 25326. 22556. 20483. 19106. 17596. 14946. 14170. 12743. 12770.
##  9    53 10365. 10358. 10463. 10725.  9966. 11390. 13180. 13719. 15294. 15270.
## 10    54  4407.  4683.  4862.  5109.  5008.  5477.  5973.  6233.  6168.  6562.
## # ... with 179 more rows, and 20 more variables: `1991` <dbl>, `1992` <dbl>,
## #   `1993` <dbl>, `1994` <dbl>, `1995` <dbl>, `1996` <dbl>, `1997` <dbl>,
## #   `1998` <dbl>, `1999` <dbl>, `2000` <dbl>, `2001` <dbl>, `2002` <dbl>,
## #   `2003` <dbl>, `2004` <dbl>, `2005` <dbl>, `2006` <dbl>, `2007` <dbl>,
## #   `2008` <dbl>, `2009` <dbl>, `2010` <dbl>

Back to long

wide %>% pivot_longer(cols=-ccode,names_to = "year", values_to = "gdppc") -> long_again
long_again
## # A tibble: 5,670 x 3
##    ccode year   gdppc
##    <dbl> <chr>  <dbl>
##  1     2 1981  25977.
##  2     2 1982  25131.
##  3     2 1983  26026.
##  4     2 1984  27751.
##  5     2 1985  28455.
##  6     2 1986  29014.
##  7     2 1987  29639.
##  8     2 1988  30506.
##  9     2 1989  31274.
## 10     2 1990  31432.
## # ... with 5,660 more rows

Merging Datasets

You may have noticed that the ccode variable isn’t particularly descriptive for which country it means. We can use this to illustrate merging datasets together. At the start we loaded in the countrycode package which contains additional information.

codes <- countrycode::codelist_panel

Let’s see what they have.

colnames(codes)
##  [1] "country.name.en"       "year"                  "ar5"                  
##  [4] "continent"             "country.name.de"       "country.name.de.regex"
##  [7] "country.name.en.regex" "cow.name"              "cowc"                 
## [10] "cown"                  "ecb"                   "ecb.name"             
## [13] "eu28"                  "eurocontrol_pru"       "eurocontrol_statfor"  
## [16] "eurostat"              "eurostat.name"         "fao"                  
## [19] "fao.name"              "fips"                  "fips.name"            
## [22] "gaul"                  "genc.name"             "genc2c"               
## [25] "genc3c"                "genc3n"                "gwc"                  
## [28] "gwn"                   "icao.name"             "icao.region"          
## [31] "imf"                   "ioc"                   "ioc.name"             
## [34] "iso.name.en"           "iso.name.fr"           "iso2c"                
## [37] "iso3c"                 "iso3n"                 "p4.name"              
## [40] "p4c"                   "p4n"                   "region"               
## [43] "un"                    "un.name.ar"            "un.name.en"           
## [46] "un.name.es"            "un.name.fr"            "un.name.ru"           
## [49] "un.name.zh"            "unpd"                  "unpd.name"            
## [52] "vdem"                  "vdem.name"             "wb"                   
## [55] "wb_api.name"           "wb_api2c"              "wb_api3c"             
## [58] "wb.name"               "wvs"                   "wvs.name"

The country codes we are currently using are cown. Let’s grab iso3c and region to add to the dataset. We also know that the dataset we are working with only has years from 1981 to 2010, so let’s practice our subsetting skillz

codes <- codes[codes$year %in% 1981:2010,c("cown","year","iso3c","country.name.en","region")]

One thing to pay attention to is losing or gaining observations durring a merge. For a great overview, check out this handy NYU Data Services guide.

nrow(d)
## [1] 5188
out1 <- merge(d,codes,by.x=c("ccode","year"),by.y=c("cown","year"))
nrow(out1)
## [1] 5125
out2 <- merge(d,codes,by.x=c("ccode","year"),by.y=c("cown","year"),all.x=T)
nrow(out2)
## [1] 5188
out3 <- merge(d,codes,by.x=c("ccode","year"),by.y=c("cown","year"),all.y=T)
nrow(out3)
## [1] 6959
out4 <- merge(d,codes,by.x=c("ccode","year"),by.y=c("cown","year"),all=T)
nrow(out4)
## [1] 7022

And, of course, we can do the same merges using dplyr with inner_join, left_join, right_join, and full_join respectively. Going forward we will keep out2 as the working dataset.

Aggregates and Summaries

There are a number of great things you can do with the apply family of functions, including easily going in parallel with the pbapply package. If you are interested in more details on this you should check out this tutorial and this taskview. We will focus on using dplyr to calculate summaries of interest.

One reason for this is that it is super easy to calculate summaries grouping on another variable. For example, if we wanted to think about regional variation in gdppc we could

out2 %>% group_by(region) %>% 
  summarize(mean=mean(gdppc,na.rm=T),sd=sd(gdppc,na.rm=T),sum=sum(gdppc,na.rm=T))
## # A tibble: 23 x 4
##    region                      mean     sd      sum
##    <chr>                      <dbl>  <dbl>    <dbl>
##  1 Australia and New Zealand 24990.  5898. 1499423.
##  2 Caribbean                  9328.  5894. 3059582.
##  3 Central America            5276.  3314. 1107909.
##  4 Central Asia               4762.  2813.  452347.
##  5 Eastern Africa             1803.  2240.  735621.
##  6 Eastern Asia              11792. 10740. 1415087.
##  7 Eastern Europe             9855.  4712. 2305957.
##  8 Melanesia                  4459.   558.  133778.
##  9 Micronesia                  NaN     NA        0 
## 10 Middle Africa              3184.  4070.  859647.
## # ... with 13 more rows

We can also use the mutate function to add this information to our dataframe. In base R this would take mergeing the output of aggregate, so it can certainly be done, but dplyr makes it somewhat more straightforward and scaleable.

out2 %>% group_by(region) %>% 
  mutate(mean_gdppc=mean(gdppc,na.rm=T),sd_gdppc=sd(gdppc,na.rm=T)) -> out2

out2
## # A tibble: 5,188 x 23
## # Groups:   region [23]
##    ccode  year twoway inhhi comper polity2 physint conflictonlocat~ lnpop
##    <dbl> <dbl>  <dbl> <dbl>  <dbl>   <dbl>   <dbl>            <dbl> <dbl>
##  1     2  1981  0.986 0.990  0.997      10       8                0  19.3
##  2     2  1982  0.988 0.989  0.998      10       8                0  19.3
##  3     2  1983  0.982 0.989  0.994      10       8                1  19.3
##  4     2  1984  0.987 0.987  1          10       8                0  19.3
##  5     2  1985  0.985 0.987  0.998      10       7                0  19.3
##  6     2  1986  0.980 0.987  0.994      10       7                0  19.3
##  7     2  1987  0.982 0.987  0.995      10       8                0  19.3
##  8     2  1988  0.977 0.988  0.989      10       7                0  19.3
##  9     2  1989  0.980 0.988  0.992      10       7                1  19.3
## 10     2  1990  0.983 0.988  0.995      10       8                0  19.4
## # ... with 5,178 more rows, and 14 more variables: lngdppc <dbl>, gdppc <dbl>,
## #   expdep <dbl>, gdpgrowth <dbl>, lib_HK <dbl>, meanarab <dbl>, meanpop <dbl>,
## #   sdarab_manual <dbl>, sdpop_manual <dbl>, iso3c <chr>,
## #   country.name.en <chr>, region <chr>, mean_gdppc <dbl>, sd_gdppc <dbl>

A base R version of the above might be

a1 <- aggregate(out2$gdppc,by=list(out2$region),mean,na.rm=T)
a1
##                      Group.1         x
## 1  Australia and New Zealand 24990.386
## 2                  Caribbean  9327.994
## 3            Central America  5275.757
## 4               Central Asia  4761.549
## 5             Eastern Africa  1802.991
## 6               Eastern Asia 11792.392
## 7             Eastern Europe  9854.516
## 8                  Melanesia  4459.267
## 9                 Micronesia       NaN
## 10             Middle Africa  3183.878
## 11           Northern Africa  3388.796
## 12          Northern America 32390.804
## 13           Northern Europe 24848.061
## 14                 Polynesia       NaN
## 15        South-Eastern Asia 12756.196
## 16             South America  6143.031
## 17           Southern Africa  5279.329
## 18             Southern Asia  3029.750
## 19           Southern Europe 14384.153
## 20            Western Africa  1175.762
## 21              Western Asia 15632.999
## 22            Western Europe 30016.166
colnames(a1) <- c("region","mean_gdppc")
a2 <- aggregate(out2$gdppc,by=list(out2$region),sd,na.rm=T)
colnames(a2) <- c("region","sd_gdppc")

t1 <- merge(out2,a1,by="region")
t2 <- merge(t1,a2,by="region")
tbl_df(t2)
## # A tibble: 5,063 x 25
##    region ccode  year twoway inhhi comper polity2 physint conflictonlocat~ lnpop
##    <chr>  <dbl> <dbl>  <dbl> <dbl>  <dbl>   <dbl>   <dbl>            <dbl> <dbl>
##  1 Austr~   900  1982  0.915 0.955  0.958      10       8                0  16.5
##  2 Austr~   900  1983  0.920 0.951  0.968      10       7                0  16.5
##  3 Austr~   900  1984  0.917 0.952  0.963      10       8                0  16.6
##  4 Austr~   900  1986  0.912 0.945  0.965      10       7                0  16.6
##  5 Austr~   900  1987  0.921 0.954  0.966      10       8                0  16.6
##  6 Austr~   900  1988  0.924 0.958  0.965      10       6                0  16.6
##  7 Austr~   900  1985  0.903 0.945  0.955      10       8                0  16.6
##  8 Austr~   900  1990  0.928 0.961  0.966      10       7                0  16.7
##  9 Austr~   900  1991  0.914 0.958  0.955      10       7                0  16.7
## 10 Austr~   900  1992  0.932 0.958  0.972      10       7                0  16.7
## # ... with 5,053 more rows, and 15 more variables: lngdppc <dbl>, gdppc <dbl>,
## #   expdep <dbl>, gdpgrowth <dbl>, lib_HK <dbl>, meanarab <dbl>, meanpop <dbl>,
## #   sdarab_manual <dbl>, sdpop_manual <dbl>, iso3c <chr>,
## #   country.name.en <chr>, mean_gdppc.x <dbl>, sd_gdppc.x <dbl>,
## #   mean_gdppc.y <dbl>, sd_gdppc.y <dbl>

but the dplyr approach really is quite nice.

Graphics

We will focus on using ggplot2 for graphics in R, although base R has nice capabilities on its own. ggplot is all about the `grammar of graphics’ which follows a layered approach to describe and construct graphics in a structured manner. To begin, we will always initialize a plot:

p1 <- ggplot(out2[which(out2$region == "Northern America"),], aes(x=log(gdppc)))

To get different plots, we will add layers. For example, if we wanted a dot plot

p1 + geom_dotplot(binwidth=0.03)

or a histogram

p1 + geom_histogram(binwidth=0.03)

or a density plot

p1 + geom_density()

we can just add a different layer to the same underlying plot.

The order of the layers does not matter, and there are a bunch more customizations that we can add.

p1 + geom_histogram(color="black",fill="darkblue",binwidth = 0.03) +
     xlab("Natural Log of Per Capita GDP") +
     ylab("Frequency") +
     ggtitle('North American GDPPC') +
     theme_bw()  -> g1
g1

You can also add multiple geometries to the same underderlying plot.

p2 <- ggplot(out2[which(out2$region == "Eastern Europe"),],aes(x=year,y=log(gdppc),color=iso3c))
p2  + geom_point(na.rm=T) + 
      geom_line(na.rm=T) +
      labs(color="Country") +
      scale_color_brewer(palette="Spectral")  -> g2
g2

You can even add some smoothers if you want.

p3 <- ggplot(out3[which(out3$iso3c=="RUS"),],aes(x=year,y=gdppc))
p3 + geom_point(na.rm=T) +
     geom_smooth(color ="gray", method = "lm", se = TRUE,na.rm=T, formula=y~x)

p3 <- ggplot(out3[which(out3$iso3c=="RUS"),],aes(x=year,y=gdppc))
p3 + geom_point(na.rm=T) +
     geom_smooth(color ="gray", method = "loess", se = TRUE,formula=y~x, na.rm=T) -> g3
g3

Two last notes on plots – faceting and adding plots together into a larger image.

Faceting can be a nice way to break up a continuous variable by category.

p4 <- ggplot(na.omit(out2[which(out2$region %in% c("Western Europe","Western Africa","Eastern Europe")),]),aes(x=log(gdppc)))
p4 + geom_histogram(binwidth = 0.1) + 
     facet_grid(region ~ .)

p4 <- ggplot(na.omit(out2[which(out2$region %in% c("Western Europe","Western Africa","Eastern Europe")),]),aes(x=log(gdppc)))
p4 + geom_histogram(binwidth = 0.1) + 
     facet_grid(. ~ region)

Once we do all that, we might want to add multiple plots together into a larger multi-panel graphic. The gridExtra package is great for this.

grid.arrange(g1,g2,g3,textGrob("Spiffy!"),ncol=2,nrow=2)

You should take a look at the ggplot2 book linked to above, as well as other stuff like ggpubr, some examples can be found here.

Typesetting

In R it is relatively easy to create tables that are presentable in Word, LaTex, or HTML. A large number of packages – apsrtable, xtable, texreg, memisc, outreg and others – cater to LaTex users. If you’re using word to prepare your documents, stargazer is an option that can work nicely. One thing we might want to do from the above is greate a table of descriptive statistics.

vars <- c("polity2","physint","conflictonlocation","lnpop")
path <- "C:/Users/Schwarz/Dropbox/AQR"

stargazer(as.data.frame(out2[,vars]),type="html",
          title="Descriptive Statistics",
          covariate.labels = c("Democracy","Human Rights","Any Conflict?",
                               "Population (Logged)"),
          out=paste0(path,"/summary1.doc"))

As you might have gathered from the code above, what we are going to do is use the ability of Word to render html by saving the output with a .doc extension.

Otherwise, the table looks like this:

Descriptive Statistics
Statistic N Mean St. Dev. Min Pctl(25) Pctl(75) Max
Democracy 4,380 1.746 7.203 -10.000 -6.000 9.000 10.000
Human Rights 4,487 4.838 2.322 0.000 3.000 7.000 8.000
Any Conflict? 5,188 0.171 0.377 0 0 0 1
Population (Logged) 4,457 15.674 1.925 10.615 14.671 16.902 21.000

If you’re interested in what other summary statistics are available natively from stargazer, check out the link in omit.summary.stat in their documentation

?stargazer

Something a bit more interesting would be to take a look at Regression tables. First, let’s run some models. To replicate the Peterson (2017) results, we need to define a function for leading a variable.

tscslead <- function(x, cs,ts){ 
  obs <- 1:length(x) 
  lagobs <- match(paste(cs, ts+1, sep="::"), paste(cs, ts, sep="::")) 
  lagx <- x[lagobs]
  lagx
}

The next thing that we will do is create the dependent variable with a one period lead

out2$physint_lead <- tscslead(out2$physint, out2$ccode, out2$year)

And then we will replicate models 1-3

m1 <- lm(physint_lead ~ twoway +lib_HK + polity2 + conflictonlocation
              + lngdppc + gdpgrowth + lnpop + year + physint, data = out2)

m2 <- lm(physint_lead ~ twoway + expdep + polity2 + conflictonlocation
              + lngdppc + gdpgrowth + lnpop + year + physint, data = out2)

m3 <- lm(physint_lead ~ twoway + expdep +lib_HK + polity2 + conflictonlocation
              + lngdppc + gdpgrowth + lnpop + year + physint, data = out2)

stargazer(m1,m2,m3,type="html",out = paste0(path,"/regressions.doc"),
          covariate.labels = c("Export Diversification","Liberalization","
                               Export Dependence","Democracy","Conflict","
                               Log Income","Growth","Log Population",
                               "Linear Time Trend","Lagged DV"),
          title="Replication of Peterson (2017) Models 1-3",
          dep.var.caption = "All States",
          dep.var.labels = "Human Rights")

The output looks like this:

Replication of Peterson (2017) Models 1-3
All States
Human Rights
(1) (2) (3)
Export Diversification 0.276** 0.242** 0.226**
(0.114) (0.113) (0.114)
Liberalization -10.638 -57.858***
(8.896) (13.994)
Export Dependence 0.202** 0.707***
(0.101) (0.162)
Democracy 0.026*** 0.026*** 0.027***
(0.004) (0.004) (0.004)
Conflict -0.583*** -0.555*** -0.611***
(0.062) (0.061) (0.062)
Log Income 0.126*** 0.118*** 0.131***
(0.023) (0.022) (0.023)
Growth -0.154 -0.207 -0.140
(0.193) (0.191) (0.192)
Log Population -0.190*** -0.174*** -0.226***
(0.020) (0.018) (0.022)
Linear Time Trend -0.014*** -0.014*** -0.016***
(0.002) (0.002) (0.002)
Lagged DV 0.675*** 0.679*** 0.666***
(0.013) (0.012) (0.013)
Constant 31.817*** 31.360*** 35.327***
(4.914) (4.876) (4.967)
Observations 3,479 3,562 3,479
R2 0.751 0.754 0.753
Adjusted R2 0.751 0.753 0.752
Residual Std. Error 1.118 (df = 3469) 1.121 (df = 3552) 1.115 (df = 3468)
F Statistic 1,164.520*** (df = 9; 3469) 1,208.221*** (df = 9; 3552) 1,055.422*** (df = 10; 3468)
Note: p<0.1; p<0.05; p<0.01

Stargazer has a number of useful “style” options which format close to a number of major journals, which may be worth looking at or playing around with.

Exercises

The best way to learn R is to use R. Let’s play around with some of the above concepts and coding approaches to replicate a number of other aspects of the paper and ‘probe robustness’ to deviations in specification.

Exercise 1

Description

Figure 1 of Peterson (2017) shows two histograms of Export Diversity (twoway), one for all states and the other excluding high states (those with a GDP Per Capita larger than 11101.2). Reproduce this image as closely as possible; this will take digging into the documentation or Googling to accomplish particular customizations! The final output should look something like this:

Exercise 1 Desired Output

Answer

sub <- out2[which(out2$gdppc < 11101.2),]

out2$all_states <- "All States"
sub$exc <- "Excluding high-income states"

out2 %>% ggplot(aes(x=twoway)) + 
  geom_histogram(binwidth=0.03,col="black") +
  theme_bw() +
  theme(plot.title = element_text(hjust=0.5),
        strip.background = element_rect(fill="grey"),
        strip.text = element_text(size=13)) +
  xlab("Export diversity") +
  ylab("Frequency") +
  facet_grid(.~all_states)-> f1
sub %>% ggplot(aes(x=twoway)) + 
  geom_histogram(binwidth=0.03,col="black") +
  theme_bw() +
  theme(plot.title = element_text(hjust=0.5),
        strip.background = element_rect(fill="grey"),
        strip.text = element_text(size=13)) +
  xlab("Export diversity") +
  ylab("Frequency") +
  facet_grid(.~exc) -> f2

jpeg(paste0(path,"/Exercise1.jpg"))

grid.arrange(f1,f2,ncol=2,nrow=1, 
             bottom = textGrob("Figure 1. Histogram of export diversity for all states (left) and excluding high-income states (right).", gp=gpar(fontsize=10)))
grid.rect(width = 1, height = 0.96, vjust=0.485 , gp = gpar(lwd = 2, col = "black", fill = NA))

dev.off()

Exercise 2

Description

Models 4-6 replicate use the same specifications as above but excluding high income states. Run these regressions and format the results to get the following:

Replication of Peterson (2017) Models 4-6
Excluding high income states
Human Rights
(4) (5) (6)
Export Diversification 0.472*** 0.471*** 0.450***
(0.141) (0.139) (0.141)
Liberalization -19.891* -44.903**
(11.636) (20.707)
Export Dependence -0.077 0.333
(0.126) (0.228)
Democracy 0.024*** 0.023*** 0.025***
(0.004) (0.004) (0.004)
Conflict -0.598*** -0.578*** -0.597***
(0.072) (0.071) (0.072)
Log Income -0.030 -0.038 -0.017
(0.034) (0.034) (0.035)
Growth -0.066 -0.141 -0.060
(0.232) (0.229) (0.232)
Log Population -0.290*** -0.273*** -0.307***
(0.027) (0.024) (0.029)
Linear Time Trend -0.015*** -0.014*** -0.015***
(0.003) (0.003) (0.003)
Lagged DV 0.622*** 0.628*** 0.621***
(0.016) (0.016) (0.016)
Constant 36.093*** 34.344*** 37.349***
(6.419) (6.352) (6.475)
Observations 2,488 2,550 2,488
R2 0.682 0.682 0.683
Adjusted R2 0.681 0.681 0.681
Residual Std. Error 1.190 (df = 2478) 1.196 (df = 2540) 1.190 (df = 2477)
F Statistic 591.627*** (df = 9; 2478) 605.829*** (df = 9; 2540) 532.921*** (df = 10; 2477)
Note: p<0.1; p<0.05; p<0.01

Answer

m5 <- lm(physint_lead ~ twoway +lib_HK + polity2 + conflictonlocation
         + lngdppc + gdpgrowth + lnpop + year + physint, data = sub)

m6 <- lm(physint_lead ~ twoway + expdep + polity2 + conflictonlocation
         + lngdppc + gdpgrowth + lnpop + year + physint, data = sub)

m7 <- lm(physint_lead ~ twoway + expdep +lib_HK + polity2 + conflictonlocation
         + lngdppc + gdpgrowth + lnpop + year + physint, data = sub)

stargazer(m5,m6,m7,type="html",out = paste0(path,"/regressions2.doc"),
          covariate.labels = c("Export Diversification","Liberalization","
                               Export Dependence","Democracy","Conflict","
                               Log Income","Growth","Log Population",
                               "Linear Time Trend","Lagged DV"),
          column.labels = c("(4)","(5)","(6)"),
          model.numbers = F,
          title="Replication of Peterson (2017) Models 4-6",
          dep.var.caption = "Excluding high income states",
          dep.var.labels = "Human Rights")

Exercise 3

Description

One might wonder whether the results are robust to the inclusion of region or state fixed effects. These can be entered into the regression equation by including, for example, as.factor(ccode) to the regression equation. Fixed effects are generally omitted from regression tables; figure out how to exclude regressors from stargazer output and add an additional note to the table indicating that fixed effects were included. You should also remove the R-squared, Residual Standard Error, and F Statistic from being reported. The output should look something like this:

Robustness of Peterson (2017) Models 1-3
All States
Human Rights
(1a) (2a) (3a)
Export Diversification 0.190 0.220 0.248
(0.259) (0.257) (0.260)
Liberalization 21.905 -9.210
(17.509) (20.824)
Export Dependence 0.587*** 0.633***
(0.191) (0.230)
Democracy 0.037*** 0.039*** 0.039***
(0.006) (0.006) (0.006)
Conflict -0.520*** -0.495*** -0.508***
(0.077) (0.075) (0.077)
Log Income 0.029 0.086 0.077
(0.091) (0.090) (0.092)
Growth 0.016 -0.039 0.032
(0.188) (0.186) (0.188)
Log Population -0.324 -0.244 -0.267
(0.237) (0.234) (0.238)
Linear Time Trend -0.017*** -0.022*** -0.022***
(0.005) (0.006) (0.006)
Lagged DV
Constant 44.060*** 50.103*** 50.438***
(7.467) (7.665) (7.811)
Observations 3,479 3,562 3,479
Adjusted R2 0.775 0.779 0.776
Note: p<0.1; p<0.05; p<0.01
All models include country fixed effects.

Answer

m7 <- lm(physint_lead ~ twoway +lib_HK + polity2 + conflictonlocation
         + lngdppc + gdpgrowth + lnpop + year + physint + as.factor(ccode), data = out2)

m8 <- lm(physint_lead ~ twoway + expdep + polity2 + conflictonlocation
         + lngdppc + gdpgrowth + lnpop + year + physint + as.factor(ccode), data = out2)

m9 <- lm(physint_lead ~ twoway + expdep +lib_HK + polity2 + conflictonlocation
         + lngdppc + gdpgrowth + lnpop + year + physint + as.factor(ccode), data = out2)

stargazer(m7,m8,m9,type="html",out = paste0(path,"/regressions3.doc"),
          covariate.labels = c("Export Diversification","Liberalization","
                               Export Dependence","Democracy","Conflict","
                               Log Income","Growth","Log Population",
                               "Linear Time Trend","Lagged DV"),
          title="Robustness of Peterson (2017) Models 1-3",
          omit=11:length(m9$coefficients),
          notes = "All models include country fixed effects.",
          notes.append=TRUE,
          column.labels = c("(1a)","(2a)","(3a)"),
          model.numbers = F,
          dep.var.caption = "All States",
          dep.var.labels = "Human Rights",
          omit.stat = c("f","rsq","ser"))

Final Words

That’s all I have for you today. Hope it was helpful! Feel free to reach out to NYU Data Services if you encounter any issues with programming in R or would like to be directed to any additional resources. Over the past two sessions we have only touched the surface of what R is able to do thanks to the vibrant community of scholars and practitioners who contribute to the project. If you are looking to get further into R for statistical analysis, I highly recommend checking out what is available on the various taskviews or even these neat swirl courses where you can learn R in R.

LS0tDQp0aXRsZTogJ0FRUiBQcm9zZW1pbmFyOiBXcmFuZ2xpbmcsIEdyYXBoaWNzLCBhbmQgVHlwZXNldHRpbmcgaW4gUicNCmF1dGhvcjogIkNocmlzdG9waGVyIFNjaHdhcnoiDQpkYXRlOiAiMy8yMy8yMDIwIg0KcGFnZXM6DQogIGV4dHJhOiB0cnVlDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpUaGlzIGRvY3VtZW50IGlzIGEgcXVpY2sgaW50cm9kdWN0aW9uIHRvIGRhdGEgd3JhbmdsaW5nLCBncmFwaGljcywgYW5kIHR5cGVzZXR0aW5nIGluIFIuICBZb3UgY2FuIGRvd25sb2FkIHRoZSBjb2RlIGJ5IGNsaWNraW5nIHRoZSAiQ29kZSIgYnV0dG9uIHRvIHRoZSB1cHBlciByaWdodC4NCg0KRmlyc3QgdGhpbmcgaXMgZmlyc3Q7IGxldCdzIGluc3RhbGwvbG9hZCBhbGwgb2YgdGhlIHBhY2thZ2VzIHRoYXQgd2Ugd2lsbCBiZSB1c2luZywgYW5kIGNsZWFyIG91dCB0aGUgZW52aXJvbm1lbnQuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYWNrYWdlcyA8LSBjKCJoYXZlbiIsImRwbHlyIiwiZ2dwbG90MiIsImNvdW50cnljb2RlIiwidGlkeXIiLCJncmlkRXh0cmEiLCJncmlkIiwNCiAgICAgICAgICAgICAgInN0YXJnYXplciIpDQpmb3IoaSBpbiBwYWNrYWdlcyl7DQogIGlmKCFyZXF1aXJlKGksY2hhcmFjdGVyLm9ubHkgPSBULCBxdWlldGx5ID0gVCkpew0KICAgIGluc3RhbGwucGFja2FnZXMoaSkNCiAgICBsaWJyYXJ5KGksIGNoYXJhY3Rlci5vbmx5ID0gVCwgcXVpZXRseSA9IFQpDQogIH0NCn0NCg0Kcm0obGlzdD1scygpKQ0KYGBgDQoNCg0KV2Ugd2lsbCBiZSB1c2luZyBkYXRhIGZyb20gUGV0ZXJzb24gKDIwMTcpOiBFeHBvcnQgRGl2ZXJzaXR5IGFuZCBIdW1hbiBSaWdodHMuICBZb3UgY2FuIGRvd25sb2FkIHRoZSByZXBsaWNhdGlvbiBhcmNoaXZlIGJ5IGNsaWNraW5nIFtoZXJlXShodHRwczovL3NpdGVzLmdvb2dsZS5jb20vc2l0ZS90aW1vdGh5bXBldGVyc29udXNjL0pDUiUyMC0lMjBleHBvcnQlMjBkaXZlcnNpdHklMjAtJTIwcmVwbGljYXRpb24lMjBkYXRhLnppcCkgb3IgZG93bmxvYWQgdGhlIGRhdGEgZGlyZWN0bHkgYnkgcnVubmluZyB0aGUgZm9sbG93aW5nIGNodW5rLg0KDQpgYGB7cn0NCmQgPC0gcmVhZF9kdGEoImh0dHBzOi8vYml0Lmx5LzNhOW5VU0wiKQ0KZA0KYGBgDQoNCg0KIyBEYXRhIFdyYW5nbGluZw0KDQojIyBTZWxlY3RpbmcgQ2FzZXMgYW5kIFN1YnNldHRpbmcNCg0KQXMgd2l0aCBtb3N0IHRoaW5ncyBpbiBSIHRoZXJlIGFyZSBtdWx0aXBsZSB3YXlzIG9mIGFjY29tcGxpc2hpbmcgdGhlIHNhbWUgZ29hbC4gIEJlaW5nIGFibGUgdG8gc3dpdGNoIGJldHdlZW4gYXBwcm9hY2hlcyBjYW4gaGVscCB5b3UgYWNjb21wbGlzaCBtb3JlIGNvbXBsaWNhdGVkIHRhc2tzLiAgSSBnZW5lcmFsbHkgc3RpY2sgdG8gYmFzZSBSIGZvciBzdWJzZXR0aW5nLiAgVG8gZ2V0IGluZGljZXMgd2hpY2ggc2F0aXNmeSBsb2dpY2FsIHN0YXRlbWVudHMgeW91IGNhbiB1c2UgdGhlIGB3aGljaGAgZnVuY3Rpb24gDQpgYGB7cn0NCndoaWNoKGQkZ2RwcGMgPiA1MDAwMCkNCmBgYA0KDQpgYGB7cn0NCndoaWNoKGQkZ2RwcGMgPCAyMDAwICYgZCRwb2xpdHkyID09IDEwKQ0KYGBgDQoNCmBgYHtyfQ0Kd2hpY2goZCRnZHBncm93dGggPCAtLjUgfCBkJGdkcHBjIDwgMTAwKQ0KYGBgDQoNCldlIGNhbiBjb21iaW5lIHRoaXMgd2l0aCBpbmRleGluZyB0byBzdWJzZXQgZG93biB0aGUgZGF0YS4gIFdlIGNhbiBhbHNvIGNhbGwgY29sdW1ucyBpbiBhIHZhcmlldHkgb2Ygd2F5cy4gIFJlbWVtYmVyIHRoYXQgeW91IGNhbiBjcmVhdGUgb2JqZWN0cyBjYXJ5aW5nIHRoaXMgaW5mb3JtYXRpb24gdG8gbW9kdWxhcml6ZSB5b3VyIGNvZGUsIHdoaWNoIG1pZ2h0IGJlIGhlbHBmdWwgaW4gcGFydGljdWxhciBzaXR1YXRpb25zIHRvIGtlZXAgZXZlcnl0aGluZyBjbGVhci4NCg0KYGBge3J9DQppbmRzIDwtIHdoaWNoKGQkZ2RwcGMgPiA1MDAwMCkNCmNvbHMgPC0gYygiY2NvZGUiLCJ5ZWFyIiwicGh5c2ludCIsImxucG9wIikNCg0Kc3ViMSA8LSBkW2luZHMsY29sc10NCnN1YjENCmBgYA0KDQpBbHRlcm5hdGl2ZWx5LCBvbmUgY291bGQgdXNlIHRoZSBgc3Vic2V0YCBmdW5jdGlvbiBmcm9tIGJhc2UgUiB0byBnZXQgdGhlIHNhbWUgcmVzdWx0Lg0KDQpgYGB7cn0NCnN1YjIgPC0gc3Vic2V0KGQsZCRnZHBwYyA+IDUwMDAwLGNvbHMpDQpzdWIyDQpgYGANCmBgYHtyfQ0KaWRlbnRpY2FsKHN1YjEsc3ViMikNCmBgYA0KDQpBbm90aGVyIGdyZWF0IG9wdGlvbiBpcyB0aGUgYGRwbHlyYCBwYWNrYWdlLCB3aGljaCBpcyBwYXJ0IG9mIHRoZSBbdGlkeXZlcnNlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLykgYWxvbmdzaWRlIHRoZSBwYWNrYWdlcyBgaGF2ZW5gIGFuZCBgZ2dwbG90MmAuICBPbmUgb2YgdGhlIGJlc3QgdGhpbmdzIGFib3V0IHRoZSB0aWR5dmVyc2UgZmFtaWx5IG9mIHBhY2thZ2VzIGlzIHRoYXQgdGhleSBhcmUgdmVyeSB3ZWxsIGRvY3VtZW50ZWQsIGluY2x1ZGluZyBbYV0oaHR0cHM6Ly9yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wMi9kYXRhLXdyYW5nbGluZy1jaGVhdHNoZWV0LnBkZikgW3ZhcmlldHldKGh0dHBzOi8vcnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDMvZ2dwbG90Mi1jaGVhdHNoZWV0LnBkZikgW29mXShodHRwOi8vd3d3LmZsdXR0ZXJieXMuY29tLmF1L3N0YXRzL2Rvd25sb2Fkcy9zbGlkZXMvZmlndXJlL2ZhY3RvcnMucGRmKSBbY2hlYXRzaGVldHNdKGh0dHBzOi8vZXZvbGR5bi5naXRsYWIuaW8vZXZvbWljcy0yMDE4L3JlZi1zaGVldHMvUl9wdXJyci5wZGYpIFthbmRdKGh0dHBzOi8vZ2dwbG90Mi1ib29rLm9yZy8pIFtib29rc10oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei8pLiAgT25lIHRoaW5nIHRoYXQgbWFrZXMgdGhlIHdyYW5nbGluZyB0b29scyBwYXJ0aWN1bGFybHkgcG93ZXJmdWwgaXMgdGhhdCB0aGV5IGxldmVyYWdlIGEgcGlwZSAoYCU+JWApIGZyb20gdGhlIGBtYWdyaXR0cmAgcGFja2FnZSB3aGljaCBzYXlzLGluIHBzZXVkby1jb2RlLCB0aGF0IGB4ICU+JSBmKHkpYCBpcyB0aGUgc2FtZSBhcyBgZih4LHkpYC4gIFRoaXMgY2FuIGNyZWF0ZSBuaWNlIHdvcmsgZmxvdy4gIEZvciBleGFtcGxlLCB0byBnZXQgdGhlIHNhbWUgc3Vic2V0IHlldCBhZ2FpbjoNCmBgYHtyfQ0KZCAlPiUgZmlsdGVyKGdkcHBjID4gNTAwMDApICU+JSBzZWxlY3QoYWxsX29mKGNvbHMpKSAtPiBzdWIzDQoNCmFsbChzdWIxID09IHN1YjMsIG5hLnJtPVQpDQpgYGANCg0KTmVhdC4gIFdoYXQgd2UgZGlkIHdhcyB0b29rIG91ciBkYXRhZnJhbWUsIGBmaWx0ZXJgZWQgdGhlIHJvd3MgdGhhdCB3ZSB3YW50ZWQsIGFuZCB0aGVuIGBzZWxlY3RgZWQgdGhlIGNvbHVtbnMgb2YgaW50ZXJlc3QuDQoNCklmIHdlIHdhbnQgdG8gYHNvcnRgIGRhdGEsIHRoZXJlIGlzIGEgYmFzZSBSIGFwcHJvYWNoIGZvciB2ZWN0b3JzLg0KDQpgYGB7cn0NCmhlYWQoc29ydChkJGdkcGdyb3d0aCkpDQpgYGANCg0KRm9yIGRhdGFmcmFtZXMgeW91IGhhdmUgdG8gdXNlIGBvcmRlcmAsIHdoaWNoIHByb2R1Y2VzIGluZGV4IG51bWJlcnMgdGhhdCBjYW4gYmUgdXNlZCBhcyBiZWZvcmUNCmBgYHtyfQ0KZFtvcmRlcihkJGdkcGdyb3d0aCksYygiY2NvZGUiLCJ5ZWFyIiwiZ2RwZ3Jvd3RoIildDQpgYGANCldlIGNhbiBhbHNvIHN3aXRjaCB0aGUgb3JkZXJpbmcgYXJvdW5kIGJ5IHNldHRpbmcgYGRlY3JlYXNpbmcgPSBUYA0KYGBge3J9DQpkW29yZGVyKGQkZ2RwZ3Jvd3RoLGRlY3JlYXNpbmcgPSBUKSxjKCJjY29kZSIsInllYXIiLCJnZHBncm93dGgiKV0NCmBgYA0KT3Igd2UgY291bGQgdXNlIHRoZSBoYW5keSBgJT4lYC4gIEluIHRoaXMgY2FzZSB3ZSBoYXZlIHRvIHVzZSB0aGUgcGxhY2Vob2xkZXIgYC5gIGZvciB0aGUgaW5wdXQsIHdoaWNoIG1pZ2h0IGJlIGhhbmR5IHRvIGtub3cgdGhhdCB5b3UgY2FuIGRvIGZvciBtb3JlIGNvbXBsaWNhdGVkIGZ1bmN0aW9ucy4NCmBgYHtyfQ0Kb3JkZXIoZCRnZHBncm93dGgsZGVjcmVhc2luZyA9IFQpICU+JSBkWy4sYygiY2NvZGUiLCJ5ZWFyIiwiZ2RwZ3Jvd3RoIildDQpgYGANCg0KVGhlcmUgaXMgYWxzbyBhIGhhbmR5IGBhcnJhbmdlYCBmdW5jdGlvbiBpbiBgZHBseXJgIGZvciBhY2NvbXBsaXNoaW5nIHRoZSBzYW1lIHNvcnQgb2YgdGFzayBidXQgYWxsb3dpbmcgdG8gc29ydCBiYXNlZCBvbiBtdWx0aXBsZSBjb2x1bW5zLg0KDQpgYGB7cn0NCmQgJT4lIHNlbGVjdChjKCJjY29kZSIsInllYXIiLCJnZHBncm93dGgiKSkgJT4lIGFycmFuZ2UoY2NvZGUsZ2RwZ3Jvd3RoKQ0KYGBgDQoNCiMjIENvbnZlcnRpbmcgYmV0d2VlbiBMb25nIGFuZCBXaWRlDQoNClNvbWV0aW1lcyBkYXRhIGNvbWVzIGluICJMb25nIiBmb3JtYXQsIGxpa2UgdGhlIGRhdGEgd2UgaGF2ZSBiZWVuIHdvcmtpbmcgd2l0aCwgd2hlcmUgZWFjaCByb3cgcmVwcmVzZW50cyBhbiBvYnNlcnZhdGlvbmFsIHVuaXQgKGhlcmUgY291bnRyeSAtIHllYXIpLiAgSW4gb3RoZXIgY2FzZXMgZGF0YSB3aWxsIGNvbWUgaW4gIldpZGUiIGZvcm1hdCBsaWtlIFt0aGlzXShodHRwczovL2RhdGEuaW1mLm9yZy9yZWd1bGFyLmFzcHg/a2V5PTYwOTkxNDY3KSBvciBbdGhpc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVW5pdGVkX1N0YXRlc19FbGVjdG9yYWxfQ29sbGVnZSNDaHJvbm9sb2dpY2FsX3RhYmxlKQ0KDQpXZSBtaWdodCB3YW50IHRvIGNvbnZlcnQgZGF0YSBiYWNrIGFuZCBmb3J0aCBkZXBlbmRpbmcgb24gd2hhdCB3ZSB3YW50IHRvIGRvLiAgTGV0J3MgZG8gdGhpcyBmb3IgdGhlIEdEUCBwZXIgY2FwaXRhIHZhcmlhYmxlOyBzZWUgTllVIERhdGEgU2VydmljZXMgZm9yIGEgaGFuZHkgW2d1aWRlIHRvIHJlc2hhcGluZ10oaHR0cHM6Ly9ndWlkZXMubnl1LmVkdS9xdWFudC9yZXNoYXBlKS4NCg0KYGBge3J9DQpsb25nIDwtIGRbLGMoImNjb2RlIiwieWVhciIsImdkcHBjIildDQpsb25nDQpgYGANCg0KTG9uZyB0byBXaWRlIHdpdGggdGlkeXIgKHVwZGF0ZWQgdmVyc2lvbnMgb2YgYGdhdGhlcmAgYW5kIGBzcHJlYWRgKQ0KYGBge3J9DQpsb25nICU+JSBwaXZvdF93aWRlcihuYW1lc19mcm9tID0geWVhciwgdmFsdWVzX2Zyb20gPSBnZHBwYykgLT4gd2lkZQ0Kd2lkZQ0KYGBgDQpCYWNrIHRvIGxvbmcNCmBgYHtyfQ0Kd2lkZSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHM9LWNjb2RlLG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAiZ2RwcGMiKSAtPiBsb25nX2FnYWluDQpsb25nX2FnYWluDQpgYGANCg0KIyMgTWVyZ2luZyBEYXRhc2V0cw0KDQpZb3UgbWF5IGhhdmUgbm90aWNlZCB0aGF0IHRoZSBjY29kZSB2YXJpYWJsZSBpc24ndCBwYXJ0aWN1bGFybHkgZGVzY3JpcHRpdmUgZm9yIHdoaWNoIGNvdW50cnkgaXQgbWVhbnMuICBXZSBjYW4gdXNlIHRoaXMgdG8gaWxsdXN0cmF0ZSBtZXJnaW5nIGRhdGFzZXRzIHRvZ2V0aGVyLiAgQXQgdGhlIHN0YXJ0IHdlIGxvYWRlZCBpbiB0aGUgYGNvdW50cnljb2RlYCBwYWNrYWdlIHdoaWNoIGNvbnRhaW5zIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24uDQoNCmBgYHtyfQ0KY29kZXMgPC0gY291bnRyeWNvZGU6OmNvZGVsaXN0X3BhbmVsDQpgYGANCg0KTGV0J3Mgc2VlIHdoYXQgdGhleSBoYXZlLg0KYGBge3J9DQpjb2xuYW1lcyhjb2RlcykNCmBgYA0KDQpUaGUgY291bnRyeSBjb2RlcyB3ZSBhcmUgY3VycmVudGx5IHVzaW5nIGFyZSBgY293bmAuICBMZXQncyBncmFiIGBpc28zY2AgYW5kIGByZWdpb25gIHRvIGFkZCB0byB0aGUgZGF0YXNldC4gIFdlIGFsc28ga25vdyB0aGF0IHRoZSBkYXRhc2V0IHdlIGFyZSB3b3JraW5nIHdpdGggb25seSBoYXMgeWVhcnMgZnJvbSAxOTgxIHRvIDIwMTAsIHNvIGxldCdzIHByYWN0aWNlIG91ciBzdWJzZXR0aW5nIHNraWxseg0KYGBge3J9DQpjb2RlcyA8LSBjb2Rlc1tjb2RlcyR5ZWFyICVpbiUgMTk4MToyMDEwLGMoImNvd24iLCJ5ZWFyIiwiaXNvM2MiLCJjb3VudHJ5Lm5hbWUuZW4iLCJyZWdpb24iKV0NCmBgYA0KDQpPbmUgdGhpbmcgdG8gcGF5IGF0dGVudGlvbiB0byBpcyBsb3Npbmcgb3IgZ2FpbmluZyBvYnNlcnZhdGlvbnMgZHVycmluZyBhIG1lcmdlLiAgRm9yIGEgZ3JlYXQgb3ZlcnZpZXcsIGNoZWNrIG91dCB0aGlzIGhhbmR5IE5ZVSBEYXRhIFNlcnZpY2VzIFtndWlkZV0oaHR0cHM6Ly9ndWlkZXMubnl1LmVkdS9xdWFudC9tZXJnZSkuDQpgYGB7cn0NCm5yb3coZCkNCmBgYA0KDQpgYGB7cn0NCm91dDEgPC0gbWVyZ2UoZCxjb2RlcyxieS54PWMoImNjb2RlIiwieWVhciIpLGJ5Lnk9YygiY293biIsInllYXIiKSkNCm5yb3cob3V0MSkNCmBgYA0KYGBge3J9DQpvdXQyIDwtIG1lcmdlKGQsY29kZXMsYnkueD1jKCJjY29kZSIsInllYXIiKSxieS55PWMoImNvd24iLCJ5ZWFyIiksYWxsLng9VCkNCm5yb3cob3V0MikNCmBgYA0KYGBge3J9DQpvdXQzIDwtIG1lcmdlKGQsY29kZXMsYnkueD1jKCJjY29kZSIsInllYXIiKSxieS55PWMoImNvd24iLCJ5ZWFyIiksYWxsLnk9VCkNCm5yb3cob3V0MykNCmBgYA0KYGBge3J9DQpvdXQ0IDwtIG1lcmdlKGQsY29kZXMsYnkueD1jKCJjY29kZSIsInllYXIiKSxieS55PWMoImNvd24iLCJ5ZWFyIiksYWxsPVQpDQpucm93KG91dDQpDQpgYGANCg0KQW5kLCBvZiBjb3Vyc2UsIHdlIGNhbiBkbyB0aGUgc2FtZSBtZXJnZXMgdXNpbmcgZHBseXIgd2l0aCBgaW5uZXJfam9pbmAsIGBsZWZ0X2pvaW5gLCBgcmlnaHRfam9pbmAsIGFuZCBgZnVsbF9qb2luYCByZXNwZWN0aXZlbHkuICBHb2luZyBmb3J3YXJkIHdlIHdpbGwga2VlcCBgb3V0MmAgYXMgdGhlIHdvcmtpbmcgZGF0YXNldC4NCg0KIyMgQWdncmVnYXRlcyBhbmQgU3VtbWFyaWVzDQoNClRoZXJlIGFyZSBhIG51bWJlciBvZiBncmVhdCB0aGluZ3MgeW91IGNhbiBkbyB3aXRoIHRoZSBgYXBwbHlgIGZhbWlseSBvZiBmdW5jdGlvbnMsIGluY2x1ZGluZyBlYXNpbHkgZ29pbmcgaW4gcGFyYWxsZWwgd2l0aCB0aGUgYHBiYXBwbHlgIHBhY2thZ2UuICBJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gbW9yZSBkZXRhaWxzIG9uIHRoaXMgeW91IHNob3VsZCBjaGVjayBvdXQgW3RoaXMgdHV0b3JpYWxdKGh0dHBzOi8vd3d3LmRhdGFjYW1wLmNvbS9jb21tdW5pdHkvdHV0b3JpYWxzL3ItdHV0b3JpYWwtYXBwbHktZmFtaWx5KSBhbmQgW3RoaXMgdGFza3ZpZXddKGh0dHBzOi8vd3d3LnItcGtnLm9yZy9jdHYvSGlnaFBlcmZvcm1hbmNlQ29tcHV0aW5nKS4gIFdlIHdpbGwgZm9jdXMgb24gdXNpbmcgYGRwbHlyYCB0byBjYWxjdWxhdGUgc3VtbWFyaWVzIG9mIGludGVyZXN0Lg0KDQpPbmUgcmVhc29uIGZvciB0aGlzIGlzIHRoYXQgaXQgaXMgc3VwZXIgZWFzeSB0byBjYWxjdWxhdGUgc3VtbWFyaWVzIGdyb3VwaW5nIG9uIGFub3RoZXIgdmFyaWFibGUuICBGb3IgZXhhbXBsZSwgaWYgd2Ugd2FudGVkIHRvIHRoaW5rIGFib3V0IHJlZ2lvbmFsIHZhcmlhdGlvbiBpbiBgZ2RwcGNgIHdlIGNvdWxkDQoNCmBgYHtyfQ0Kb3V0MiAlPiUgZ3JvdXBfYnkocmVnaW9uKSAlPiUgDQogIHN1bW1hcml6ZShtZWFuPW1lYW4oZ2RwcGMsbmEucm09VCksc2Q9c2QoZ2RwcGMsbmEucm09VCksc3VtPXN1bShnZHBwYyxuYS5ybT1UKSkNCmBgYA0KDQpXZSBjYW4gYWxzbyB1c2UgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIGFkZCB0aGlzIGluZm9ybWF0aW9uIHRvIG91ciBkYXRhZnJhbWUuICBJbiBiYXNlIFIgdGhpcyB3b3VsZCB0YWtlIGBtZXJnZWBpbmcgdGhlIG91dHB1dCBvZiBgYWdncmVnYXRlYCwgc28gaXQgY2FuIGNlcnRhaW5seSBiZSBkb25lLCBidXQgYGRwbHlyYCBtYWtlcyBpdCBzb21ld2hhdCBtb3JlIHN0cmFpZ2h0Zm9yd2FyZCBhbmQgc2NhbGVhYmxlLg0KYGBge3J9DQpvdXQyICU+JSBncm91cF9ieShyZWdpb24pICU+JSANCiAgbXV0YXRlKG1lYW5fZ2RwcGM9bWVhbihnZHBwYyxuYS5ybT1UKSxzZF9nZHBwYz1zZChnZHBwYyxuYS5ybT1UKSkgLT4gb3V0Mg0KDQpvdXQyDQpgYGANCg0KQSBiYXNlIFIgdmVyc2lvbiBvZiB0aGUgYWJvdmUgbWlnaHQgYmUNCmBgYHtyfQ0KYTEgPC0gYWdncmVnYXRlKG91dDIkZ2RwcGMsYnk9bGlzdChvdXQyJHJlZ2lvbiksbWVhbixuYS5ybT1UKQ0KYTENCg0KY29sbmFtZXMoYTEpIDwtIGMoInJlZ2lvbiIsIm1lYW5fZ2RwcGMiKQ0KYTIgPC0gYWdncmVnYXRlKG91dDIkZ2RwcGMsYnk9bGlzdChvdXQyJHJlZ2lvbiksc2QsbmEucm09VCkNCmNvbG5hbWVzKGEyKSA8LSBjKCJyZWdpb24iLCJzZF9nZHBwYyIpDQoNCnQxIDwtIG1lcmdlKG91dDIsYTEsYnk9InJlZ2lvbiIpDQp0MiA8LSBtZXJnZSh0MSxhMixieT0icmVnaW9uIikNCnRibF9kZih0MikNCmBgYA0KYnV0IHRoZSBgZHBseXJgIGFwcHJvYWNoIHJlYWxseSBpcyBxdWl0ZSBuaWNlLg0KDQojIEdyYXBoaWNzDQoNCldlIHdpbGwgZm9jdXMgb24gdXNpbmcgYGdncGxvdDJgIGZvciBncmFwaGljcyBpbiBSLCBhbHRob3VnaCBiYXNlIFIgaGFzIG5pY2UgY2FwYWJpbGl0aWVzIG9uIGl0cyBvd24uICBgZ2dwbG90YCBpcyBhbGwgYWJvdXQgdGhlIGBncmFtbWFyIG9mIGdyYXBoaWNzJyB3aGljaCBmb2xsb3dzIGEgbGF5ZXJlZCBhcHByb2FjaCB0byBkZXNjcmliZSBhbmQgY29uc3RydWN0IGdyYXBoaWNzIGluIGEgc3RydWN0dXJlZCBtYW5uZXIuICBUbyBiZWdpbiwgd2Ugd2lsbCBhbHdheXMgaW5pdGlhbGl6ZSBhIHBsb3Q6DQoNCmBgYHtyfQ0KcDEgPC0gZ2dwbG90KG91dDJbd2hpY2gob3V0MiRyZWdpb24gPT0gIk5vcnRoZXJuIEFtZXJpY2EiKSxdLCBhZXMoeD1sb2coZ2RwcGMpKSkNCmBgYA0KDQpUbyBnZXQgZGlmZmVyZW50IHBsb3RzLCB3ZSB3aWxsIGFkZCBsYXllcnMuICBGb3IgZXhhbXBsZSwgaWYgd2Ugd2FudGVkIGEgZG90IHBsb3QNCmBgYHtyfQ0KcDEgKyBnZW9tX2RvdHBsb3QoYmlud2lkdGg9MC4wMykNCmBgYA0Kb3IgYSBoaXN0b2dyYW0NCmBgYHtyfQ0KcDEgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0wLjAzKQ0KYGBgDQpvciBhIGRlbnNpdHkgcGxvdA0KYGBge3J9DQpwMSArIGdlb21fZGVuc2l0eSgpDQpgYGANCndlIGNhbiBqdXN0IGFkZCBhIGRpZmZlcmVudCBsYXllciB0byB0aGUgc2FtZSB1bmRlcmx5aW5nIHBsb3QuDQoNClRoZSBvcmRlciBvZiB0aGUgbGF5ZXJzIGRvZXMgbm90IG1hdHRlciwgYW5kIHRoZXJlIGFyZSBhIGJ1bmNoIG1vcmUgY3VzdG9taXphdGlvbnMgdGhhdCB3ZSBjYW4gYWRkLg0KDQpgYGB7cn0NCnAxICsgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsYWNrIixmaWxsPSJkYXJrYmx1ZSIsYmlud2lkdGggPSAwLjAzKSArDQogICAgIHhsYWIoIk5hdHVyYWwgTG9nIG9mIFBlciBDYXBpdGEgR0RQIikgKw0KICAgICB5bGFiKCJGcmVxdWVuY3kiKSArDQogICAgIGdndGl0bGUoJ05vcnRoIEFtZXJpY2FuIEdEUFBDJykgKw0KICAgICB0aGVtZV9idygpICAtPiBnMQ0KZzENCmBgYA0KDQpZb3UgY2FuIGFsc28gYWRkIG11bHRpcGxlIGdlb21ldHJpZXMgdG8gdGhlIHNhbWUgdW5kZXJkZXJseWluZyBwbG90Lg0KDQpgYGB7cn0NCnAyIDwtIGdncGxvdChvdXQyW3doaWNoKG91dDIkcmVnaW9uID09ICJFYXN0ZXJuIEV1cm9wZSIpLF0sYWVzKHg9eWVhcix5PWxvZyhnZHBwYyksY29sb3I9aXNvM2MpKQ0KcDIgICsgZ2VvbV9wb2ludChuYS5ybT1UKSArIA0KICAgICAgZ2VvbV9saW5lKG5hLnJtPVQpICsNCiAgICAgIGxhYnMoY29sb3I9IkNvdW50cnkiKSArDQogICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU3BlY3RyYWwiKSAgLT4gZzINCmcyDQpgYGANCg0KWW91IGNhbiBldmVuIGFkZCBzb21lIHNtb290aGVycyBpZiB5b3Ugd2FudC4NCg0KYGBge3J9DQpwMyA8LSBnZ3Bsb3Qob3V0M1t3aGljaChvdXQzJGlzbzNjPT0iUlVTIiksXSxhZXMoeD15ZWFyLHk9Z2RwcGMpKQ0KcDMgKyBnZW9tX3BvaW50KG5hLnJtPVQpICsNCiAgICAgZ2VvbV9zbW9vdGgoY29sb3IgPSJncmF5IiwgbWV0aG9kID0gImxtIiwgc2UgPSBUUlVFLG5hLnJtPVQsIGZvcm11bGE9eX54KQ0KDQpgYGANCg0KYGBge3Igd2FybmluZ3M9RkFMU0V9DQpwMyA8LSBnZ3Bsb3Qob3V0M1t3aGljaChvdXQzJGlzbzNjPT0iUlVTIiksXSxhZXMoeD15ZWFyLHk9Z2RwcGMpKQ0KcDMgKyBnZW9tX3BvaW50KG5hLnJtPVQpICsNCiAgICAgZ2VvbV9zbW9vdGgoY29sb3IgPSJncmF5IiwgbWV0aG9kID0gImxvZXNzIiwgc2UgPSBUUlVFLGZvcm11bGE9eX54LCBuYS5ybT1UKSAtPiBnMw0KZzMNCmBgYA0KDQpUd28gbGFzdCBub3RlcyBvbiBwbG90cyAtLSBmYWNldGluZyBhbmQgYWRkaW5nIHBsb3RzIHRvZ2V0aGVyIGludG8gYSBsYXJnZXIgaW1hZ2UuDQoNCg0KRmFjZXRpbmcgY2FuIGJlIGEgbmljZSB3YXkgdG8gYnJlYWsgdXAgYSBjb250aW51b3VzIHZhcmlhYmxlIGJ5IGNhdGVnb3J5Lg0KYGBge3J9DQpwNCA8LSBnZ3Bsb3QobmEub21pdChvdXQyW3doaWNoKG91dDIkcmVnaW9uICVpbiUgYygiV2VzdGVybiBFdXJvcGUiLCJXZXN0ZXJuIEFmcmljYSIsIkVhc3Rlcm4gRXVyb3BlIikpLF0pLGFlcyh4PWxvZyhnZHBwYykpKQ0KcDQgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMSkgKyANCiAgICAgZmFjZXRfZ3JpZChyZWdpb24gfiAuKQ0KYGBgDQpgYGB7cn0NCnA0IDwtIGdncGxvdChuYS5vbWl0KG91dDJbd2hpY2gob3V0MiRyZWdpb24gJWluJSBjKCJXZXN0ZXJuIEV1cm9wZSIsIldlc3Rlcm4gQWZyaWNhIiwiRWFzdGVybiBFdXJvcGUiKSksXSksYWVzKHg9bG9nKGdkcHBjKSkpDQpwNCArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4xKSArIA0KICAgICBmYWNldF9ncmlkKC4gfiByZWdpb24pDQpgYGANCg0KT25jZSB3ZSBkbyBhbGwgdGhhdCwgd2UgbWlnaHQgd2FudCB0byBhZGQgbXVsdGlwbGUgcGxvdHMgdG9nZXRoZXIgaW50byBhIGxhcmdlciBtdWx0aS1wYW5lbCBncmFwaGljLiAgVGhlIGBncmlkRXh0cmFgIHBhY2thZ2UgaXMgZ3JlYXQgZm9yIHRoaXMuDQoNCmBgYHtyfQ0KZ3JpZC5hcnJhbmdlKGcxLGcyLGczLHRleHRHcm9iKCJTcGlmZnkhIiksbmNvbD0yLG5yb3c9MikNCmBgYA0KDQpZb3Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBgZ2dwbG90MmAgYm9vayBsaW5rZWQgdG8gYWJvdmUsIGFzIHdlbGwgYXMgb3RoZXIgc3R1ZmYgbGlrZSBgZ2dwdWJyYCwgc29tZSBleGFtcGxlcyBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvYXJ0aWNsZXMvMjQtZ2dwdWJyLXB1YmxpY2F0aW9uLXJlYWR5LXBsb3RzLzgxLWdncGxvdDItZWFzeS13YXktdG8tbWl4LW11bHRpcGxlLWdyYXBocy1vbi10aGUtc2FtZS1wYWdlLykuDQoNCiMgVHlwZXNldHRpbmcNCg0KSW4gUiBpdCBpcyByZWxhdGl2ZWx5IGVhc3kgdG8gY3JlYXRlIHRhYmxlcyB0aGF0IGFyZSBwcmVzZW50YWJsZSBpbiBXb3JkLCBMYVRleCwgb3IgSFRNTC4gIEEgbGFyZ2UgbnVtYmVyIG9mIHBhY2thZ2VzIC0tIGBhcHNydGFibGVgLCBgeHRhYmxlYCwgYHRleHJlZ2AsIGBtZW1pc2NgLCBgb3V0cmVnYCBhbmQgb3RoZXJzIC0tIGNhdGVyIHRvIExhVGV4IHVzZXJzLiAgSWYgeW91J3JlIHVzaW5nIHdvcmQgdG8gcHJlcGFyZSB5b3VyIGRvY3VtZW50cywgYHN0YXJnYXplcmAgaXMgYW4gb3B0aW9uIHRoYXQgY2FuIHdvcmsgbmljZWx5LiAgT25lIHRoaW5nIHdlIG1pZ2h0IHdhbnQgdG8gZG8gZnJvbSB0aGUgYWJvdmUgaXMgZ3JlYXRlIGEgdGFibGUgb2YgZGVzY3JpcHRpdmUgc3RhdGlzdGljcy4NCg0KYGBge3IgcmVzdWx0cz1GQUxTRX0NCnZhcnMgPC0gYygicG9saXR5MiIsInBoeXNpbnQiLCJjb25mbGljdG9ubG9jYXRpb24iLCJsbnBvcCIpDQpwYXRoIDwtICJDOi9Vc2Vycy9TY2h3YXJ6L0Ryb3Bib3gvQVFSIg0KDQpzdGFyZ2F6ZXIoYXMuZGF0YS5mcmFtZShvdXQyWyx2YXJzXSksdHlwZT0iaHRtbCIsDQogICAgICAgICAgdGl0bGU9IkRlc2NyaXB0aXZlIFN0YXRpc3RpY3MiLA0KICAgICAgICAgIGNvdmFyaWF0ZS5sYWJlbHMgPSBjKCJEZW1vY3JhY3kiLCJIdW1hbiBSaWdodHMiLCJBbnkgQ29uZmxpY3Q/IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9wdWxhdGlvbiAoTG9nZ2VkKSIpLA0KICAgICAgICAgIG91dD1wYXN0ZTAocGF0aCwiL3N1bW1hcnkxLmRvYyIpKQ0KDQpgYGANCg0KQXMgeW91IG1pZ2h0IGhhdmUgZ2F0aGVyZWQgZnJvbSB0aGUgY29kZSBhYm92ZSwgd2hhdCB3ZSBhcmUgZ29pbmcgdG8gZG8gaXMgdXNlIHRoZSBhYmlsaXR5IG9mIFdvcmQgdG8gcmVuZGVyIGh0bWwgYnkgc2F2aW5nIHRoZSBvdXRwdXQgd2l0aCBhIC5kb2MgZXh0ZW5zaW9uLiAgDQoNCk90aGVyd2lzZSwgdGhlIHRhYmxlIGxvb2tzIGxpa2UgdGhpczoNCg0KPGNlbnRlcj4NCjx0YWJsZSBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPjxjYXB0aW9uPjxzdHJvbmc+RGVzY3JpcHRpdmUgU3RhdGlzdGljczwvc3Ryb25nPjwvY2FwdGlvbj4NCjx0cj48dGQgY29sc3Bhbj0iOCIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCBibGFjayI+PC90ZD48L3RyPjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+U3RhdGlzdGljPC90ZD48dGQ+TjwvdGQ+PHRkPk1lYW48L3RkPjx0ZD5TdC4gRGV2LjwvdGQ+PHRkPk1pbjwvdGQ+PHRkPlBjdGwoMjUpPC90ZD48dGQ+UGN0bCg3NSk8L3RkPjx0ZD5NYXg8L3RkPjwvdHI+DQo8dHI+PHRkIGNvbHNwYW49IjgiIHN0eWxlPSJib3JkZXItYm90dG9tOiAxcHggc29saWQgYmxhY2siPjwvdGQ+PC90cj48dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkRlbW9jcmFjeTwvdGQ+PHRkPjQsMzgwPC90ZD48dGQ+MS43NDY8L3RkPjx0ZD43LjIwMzwvdGQ+PHRkPi0xMC4wMDA8L3RkPjx0ZD4tNi4wMDA8L3RkPjx0ZD45LjAwMDwvdGQ+PHRkPjEwLjAwMDwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+SHVtYW4gUmlnaHRzPC90ZD48dGQ+NCw0ODc8L3RkPjx0ZD40LjgzODwvdGQ+PHRkPjIuMzIyPC90ZD48dGQ+MC4wMDA8L3RkPjx0ZD4zLjAwMDwvdGQ+PHRkPjcuMDAwPC90ZD48dGQ+OC4wMDA8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkFueSBDb25mbGljdD88L3RkPjx0ZD41LDE4ODwvdGQ+PHRkPjAuMTcxPC90ZD48dGQ+MC4zNzc8L3RkPjx0ZD4wPC90ZD48dGQ+MDwvdGQ+PHRkPjA8L3RkPjx0ZD4xPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5Qb3B1bGF0aW9uIChMb2dnZWQpPC90ZD48dGQ+NCw0NTc8L3RkPjx0ZD4xNS42NzQ8L3RkPjx0ZD4xLjkyNTwvdGQ+PHRkPjEwLjYxNTwvdGQ+PHRkPjE0LjY3MTwvdGQ+PHRkPjE2LjkwMjwvdGQ+PHRkPjIxLjAwMDwvdGQ+PC90cj4NCjx0cj48dGQgY29sc3Bhbj0iOCIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCBibGFjayI+PC90ZD48L3RyPjwvdGFibGU+DQo8L2NlbnRlcj4NCg0KSWYgeW91J3JlIGludGVyZXN0ZWQgaW4gd2hhdCBvdGhlciBzdW1tYXJ5IHN0YXRpc3RpY3MgYXJlIGF2YWlsYWJsZSBuYXRpdmVseSBmcm9tIGBzdGFyZ2F6ZXJgLCBjaGVjayBvdXQgdGhlIGxpbmsgaW4gYG9taXQuc3VtbWFyeS5zdGF0YCBpbiB0aGVpciBkb2N1bWVudGF0aW9uDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQo/c3RhcmdhemVyDQpgYGANCg0KU29tZXRoaW5nIGEgYml0IG1vcmUgaW50ZXJlc3Rpbmcgd291bGQgYmUgdG8gdGFrZSBhIGxvb2sgYXQgUmVncmVzc2lvbiB0YWJsZXMuICBGaXJzdCwgbGV0J3MgcnVuIHNvbWUgbW9kZWxzLiAgVG8gcmVwbGljYXRlIHRoZSBQZXRlcnNvbiAoMjAxNykgcmVzdWx0cywgd2UgbmVlZCB0byBkZWZpbmUgYSBmdW5jdGlvbiBmb3IgbGVhZGluZyBhIHZhcmlhYmxlLg0KDQpgYGB7cn0NCnRzY3NsZWFkIDwtIGZ1bmN0aW9uKHgsIGNzLHRzKXsgDQogIG9icyA8LSAxOmxlbmd0aCh4KSANCiAgbGFnb2JzIDwtIG1hdGNoKHBhc3RlKGNzLCB0cysxLCBzZXA9Ijo6IiksIHBhc3RlKGNzLCB0cywgc2VwPSI6OiIpKSANCiAgbGFneCA8LSB4W2xhZ29ic10NCiAgbGFneA0KfQ0KYGBgDQoNClRoZSBuZXh0IHRoaW5nIHRoYXQgd2Ugd2lsbCBkbyBpcyBjcmVhdGUgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSB3aXRoIGEgb25lIHBlcmlvZCBsZWFkDQpgYGB7cn0NCm91dDIkcGh5c2ludF9sZWFkIDwtIHRzY3NsZWFkKG91dDIkcGh5c2ludCwgb3V0MiRjY29kZSwgb3V0MiR5ZWFyKQ0KYGBgDQoNCkFuZCB0aGVuIHdlIHdpbGwgcmVwbGljYXRlIG1vZGVscyAxLTMNCmBgYHtyIHJlc3VsdHM9RkFMU0V9DQptMSA8LSBsbShwaHlzaW50X2xlYWQgfiB0d293YXkgK2xpYl9ISyArIHBvbGl0eTIgKyBjb25mbGljdG9ubG9jYXRpb24NCiAgICAgICAgICAgICAgKyBsbmdkcHBjICsgZ2RwZ3Jvd3RoICsgbG5wb3AgKyB5ZWFyICsgcGh5c2ludCwgZGF0YSA9IG91dDIpDQoNCm0yIDwtIGxtKHBoeXNpbnRfbGVhZCB+IHR3b3dheSArIGV4cGRlcCArIHBvbGl0eTIgKyBjb25mbGljdG9ubG9jYXRpb24NCiAgICAgICAgICAgICAgKyBsbmdkcHBjICsgZ2RwZ3Jvd3RoICsgbG5wb3AgKyB5ZWFyICsgcGh5c2ludCwgZGF0YSA9IG91dDIpDQoNCm0zIDwtIGxtKHBoeXNpbnRfbGVhZCB+IHR3b3dheSArIGV4cGRlcCArbGliX0hLICsgcG9saXR5MiArIGNvbmZsaWN0b25sb2NhdGlvbg0KICAgICAgICAgICAgICArIGxuZ2RwcGMgKyBnZHBncm93dGggKyBsbnBvcCArIHllYXIgKyBwaHlzaW50LCBkYXRhID0gb3V0MikNCg0Kc3RhcmdhemVyKG0xLG0yLG0zLHR5cGU9Imh0bWwiLG91dCA9IHBhc3RlMChwYXRoLCIvcmVncmVzc2lvbnMuZG9jIiksDQogICAgICAgICAgY292YXJpYXRlLmxhYmVscyA9IGMoIkV4cG9ydCBEaXZlcnNpZmljYXRpb24iLCJMaWJlcmFsaXphdGlvbiIsIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV4cG9ydCBEZXBlbmRlbmNlIiwiRGVtb2NyYWN5IiwiQ29uZmxpY3QiLCINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb2cgSW5jb21lIiwiR3Jvd3RoIiwiTG9nIFBvcHVsYXRpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMaW5lYXIgVGltZSBUcmVuZCIsIkxhZ2dlZCBEViIpLA0KICAgICAgICAgIHRpdGxlPSJSZXBsaWNhdGlvbiBvZiBQZXRlcnNvbiAoMjAxNykgTW9kZWxzIDEtMyIsDQogICAgICAgICAgZGVwLnZhci5jYXB0aW9uID0gIkFsbCBTdGF0ZXMiLA0KICAgICAgICAgIGRlcC52YXIubGFiZWxzID0gIkh1bWFuIFJpZ2h0cyIpDQpgYGANCg0KVGhlIG91dHB1dCBsb29rcyBsaWtlIHRoaXM6DQoNCjxjZW50ZXI+DQo8dGFibGUgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj48Y2FwdGlvbj48c3Ryb25nPlJlcGxpY2F0aW9uIG9mIFBldGVyc29uICgyMDE3KSBNb2RlbHMgMS0zPC9zdHJvbmc+PC9jYXB0aW9uPg0KPHRyPjx0ZCBjb2xzcGFuPSI0IiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+PHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZCBjb2xzcGFuPSIzIj5BbGwgU3RhdGVzPC90ZD48L3RyPg0KPHRyPjx0ZD48L3RkPjx0ZCBjb2xzcGFuPSIzIiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkIGNvbHNwYW49IjMiPkh1bWFuIFJpZ2h0czwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDEpPC90ZD48dGQ+KDIpPC90ZD48dGQ+KDMpPC90ZD48L3RyPg0KPHRyPjx0ZCBjb2xzcGFuPSI0IiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+PHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5FeHBvcnQgRGl2ZXJzaWZpY2F0aW9uPC90ZD48dGQ+MC4yNzY8c3VwPioqPC9zdXA+PC90ZD48dGQ+MC4yNDI8c3VwPioqPC9zdXA+PC90ZD48dGQ+MC4yMjY8c3VwPioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4xMTQpPC90ZD48dGQ+KDAuMTEzKTwvdGQ+PHRkPigwLjExNCk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+TGliZXJhbGl6YXRpb248L3RkPjx0ZD4tMTAuNjM4PC90ZD48dGQ+PC90ZD48dGQ+LTU3Ljg1ODxzdXA+KioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oOC44OTYpPC90ZD48dGQ+PC90ZD48dGQ+KDEzLjk5NCk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+RXhwb3J0IERlcGVuZGVuY2U8L3RkPjx0ZD48L3RkPjx0ZD4wLjIwMjxzdXA+Kio8L3N1cD48L3RkPjx0ZD4wLjcwNzxzdXA+KioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD4oMC4xMDEpPC90ZD48dGQ+KDAuMTYyKTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5EZW1vY3JhY3k8L3RkPjx0ZD4wLjAyNjxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MC4wMjY8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPjAuMDI3PHN1cD4qKio8L3N1cD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigwLjAwNCk8L3RkPjx0ZD4oMC4wMDQpPC90ZD48dGQ+KDAuMDA0KTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5Db25mbGljdDwvdGQ+PHRkPi0wLjU4MzxzdXA+KioqPC9zdXA+PC90ZD48dGQ+LTAuNTU1PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4tMC42MTE8c3VwPioqKjwvc3VwPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDAuMDYyKTwvdGQ+PHRkPigwLjA2MSk8L3RkPjx0ZD4oMC4wNjIpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkxvZyBJbmNvbWU8L3RkPjx0ZD4wLjEyNjxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MC4xMTg8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPjAuMTMxPHN1cD4qKio8L3N1cD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigwLjAyMyk8L3RkPjx0ZD4oMC4wMjIpPC90ZD48dGQ+KDAuMDIzKTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5Hcm93dGg8L3RkPjx0ZD4tMC4xNTQ8L3RkPjx0ZD4tMC4yMDc8L3RkPjx0ZD4tMC4xNDA8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigwLjE5Myk8L3RkPjx0ZD4oMC4xOTEpPC90ZD48dGQ+KDAuMTkyKTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5Mb2cgUG9wdWxhdGlvbjwvdGQ+PHRkPi0wLjE5MDxzdXA+KioqPC9zdXA+PC90ZD48dGQ+LTAuMTc0PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4tMC4yMjY8c3VwPioqKjwvc3VwPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDAuMDIwKTwvdGQ+PHRkPigwLjAxOCk8L3RkPjx0ZD4oMC4wMjIpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkxpbmVhciBUaW1lIFRyZW5kPC90ZD48dGQ+LTAuMDE0PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4tMC4wMTQ8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPi0wLjAxNjxzdXA+KioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4wMDIpPC90ZD48dGQ+KDAuMDAyKTwvdGQ+PHRkPigwLjAwMik8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+TGFnZ2VkIERWPC90ZD48dGQ+MC42NzU8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPjAuNjc5PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4wLjY2NjxzdXA+KioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4wMTMpPC90ZD48dGQ+KDAuMDEyKTwvdGQ+PHRkPigwLjAxMyk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+Q29uc3RhbnQ8L3RkPjx0ZD4zMS44MTc8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPjMxLjM2MDxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MzUuMzI3PHN1cD4qKio8L3N1cD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPig0LjkxNCk8L3RkPjx0ZD4oNC44NzYpPC90ZD48dGQ+KDQuOTY3KTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBjb2xzcGFuPSI0IiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+PHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5PYnNlcnZhdGlvbnM8L3RkPjx0ZD4zLDQ3OTwvdGQ+PHRkPjMsNTYyPC90ZD48dGQ+Myw0Nzk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPlI8c3VwPjI8L3N1cD48L3RkPjx0ZD4wLjc1MTwvdGQ+PHRkPjAuNzU0PC90ZD48dGQ+MC43NTM8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkFkanVzdGVkIFI8c3VwPjI8L3N1cD48L3RkPjx0ZD4wLjc1MTwvdGQ+PHRkPjAuNzUzPC90ZD48dGQ+MC43NTI8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPlJlc2lkdWFsIFN0ZC4gRXJyb3I8L3RkPjx0ZD4xLjExOCAoZGYgPSAzNDY5KTwvdGQ+PHRkPjEuMTIxIChkZiA9IDM1NTIpPC90ZD48dGQ+MS4xMTUgKGRmID0gMzQ2OCk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkYgU3RhdGlzdGljPC90ZD48dGQ+MSwxNjQuNTIwPHN1cD4qKio8L3N1cD4gKGRmID0gOTsgMzQ2OSk8L3RkPjx0ZD4xLDIwOC4yMjE8c3VwPioqKjwvc3VwPiAoZGYgPSA5OyAzNTUyKTwvdGQ+PHRkPjEsMDU1LjQyMjxzdXA+KioqPC9zdXA+IChkZiA9IDEwOyAzNDY4KTwvdGQ+PC90cj4NCjx0cj48dGQgY29sc3Bhbj0iNCIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCBibGFjayI+PC90ZD48L3RyPjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PGVtPk5vdGU6PC9lbT48L3RkPjx0ZCBjb2xzcGFuPSIzIiBzdHlsZT0idGV4dC1hbGlnbjpyaWdodCI+PHN1cD4qPC9zdXA+cDwwLjE7IDxzdXA+Kio8L3N1cD5wPDAuMDU7IDxzdXA+KioqPC9zdXA+cDwwLjAxPC90ZD48L3RyPg0KPC90YWJsZT4NCjwvY2VudGVyPg0KDQpTdGFyZ2F6ZXIgaGFzIGEgbnVtYmVyIG9mIHVzZWZ1bCAic3R5bGUiIG9wdGlvbnMgd2hpY2ggZm9ybWF0IGNsb3NlIHRvIGEgbnVtYmVyIG9mIG1ham9yIGpvdXJuYWxzLCB3aGljaCBtYXkgYmUgd29ydGggbG9va2luZyBhdCBvciBwbGF5aW5nIGFyb3VuZCB3aXRoLg0KDQojIEV4ZXJjaXNlcw0KDQpUaGUgYmVzdCB3YXkgdG8gbGVhcm4gUiBpcyB0byB1c2UgUi4gIExldCdzIHBsYXkgYXJvdW5kIHdpdGggc29tZSBvZiB0aGUgYWJvdmUgY29uY2VwdHMgYW5kIGNvZGluZyBhcHByb2FjaGVzIHRvIHJlcGxpY2F0ZSBhIG51bWJlciBvZiBvdGhlciBhc3BlY3RzIG9mIHRoZSBwYXBlciBhbmQgJ3Byb2JlIHJvYnVzdG5lc3MnIHRvIGRldmlhdGlvbnMgaW4gc3BlY2lmaWNhdGlvbi4NCg0KIyMgRXhlcmNpc2UgMSB7LnRhYnNldH0NCiMjIyBEZXNjcmlwdGlvbg0KRmlndXJlIDEgb2YgUGV0ZXJzb24gKDIwMTcpIHNob3dzIHR3byBoaXN0b2dyYW1zIG9mIEV4cG9ydCBEaXZlcnNpdHkgKGB0d293YXlgKSwgb25lIGZvciBhbGwgc3RhdGVzIGFuZCB0aGUgb3RoZXIgZXhjbHVkaW5nIGhpZ2ggc3RhdGVzICh0aG9zZSB3aXRoIGEgR0RQIFBlciBDYXBpdGEgbGFyZ2VyIHRoYW4gMTExMDEuMikuICBSZXByb2R1Y2UgdGhpcyBpbWFnZSBhcyBjbG9zZWx5IGFzIHBvc3NpYmxlOyB0aGlzIHdpbGwgdGFrZSBkaWdnaW5nIGludG8gdGhlIGRvY3VtZW50YXRpb24gb3IgR29vZ2xpbmcgdG8gYWNjb21wbGlzaCBwYXJ0aWN1bGFyIGN1c3RvbWl6YXRpb25zISAgVGhlIGZpbmFsIG91dHB1dCBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOg0KDQo8Y2VudGVyPg0KIVtFeGVyY2lzZSAxIERlc2lyZWQgT3V0cHV0XShDOi9Vc2Vycy9TY2h3YXJ6L0Ryb3Bib3gvQVFSL0V4ZXJjaXNlMS5qcGcpDQo8L2NlbnRlcj4NCg0KIyMjIEFuc3dlcg0KYGBge3IgcmVzdWx0cz1GQUxTRX0NCnN1YiA8LSBvdXQyW3doaWNoKG91dDIkZ2RwcGMgPCAxMTEwMS4yKSxdDQoNCm91dDIkYWxsX3N0YXRlcyA8LSAiQWxsIFN0YXRlcyINCnN1YiRleGMgPC0gIkV4Y2x1ZGluZyBoaWdoLWluY29tZSBzdGF0ZXMiDQoNCm91dDIgJT4lIGdncGxvdChhZXMoeD10d293YXkpKSArIA0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0wLjAzLGNvbD0iYmxhY2siKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0PTAuNSksDQogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0iZ3JleSIpLA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTMpKSArDQogIHhsYWIoIkV4cG9ydCBkaXZlcnNpdHkiKSArDQogIHlsYWIoIkZyZXF1ZW5jeSIpICsNCiAgZmFjZXRfZ3JpZCgufmFsbF9zdGF0ZXMpLT4gZjENCnN1YiAlPiUgZ2dwbG90KGFlcyh4PXR3b3dheSkpICsgDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTAuMDMsY29sPSJibGFjayIpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3Q9MC41KSwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJncmV5IiksDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMykpICsNCiAgeGxhYigiRXhwb3J0IGRpdmVyc2l0eSIpICsNCiAgeWxhYigiRnJlcXVlbmN5IikgKw0KICBmYWNldF9ncmlkKC5+ZXhjKSAtPiBmMg0KDQpqcGVnKHBhc3RlMChwYXRoLCIvRXhlcmNpc2UxLmpwZyIpKQ0KDQpncmlkLmFycmFuZ2UoZjEsZjIsbmNvbD0yLG5yb3c9MSwgDQogICAgICAgICAgICAgYm90dG9tID0gdGV4dEdyb2IoIkZpZ3VyZSAxLiBIaXN0b2dyYW0gb2YgZXhwb3J0IGRpdmVyc2l0eSBmb3IgYWxsIHN0YXRlcyAobGVmdCkgYW5kIGV4Y2x1ZGluZyBoaWdoLWluY29tZSBzdGF0ZXMgKHJpZ2h0KS4iLCBncD1ncGFyKGZvbnRzaXplPTEwKSkpDQpncmlkLnJlY3Qod2lkdGggPSAxLCBoZWlnaHQgPSAwLjk2LCB2anVzdD0wLjQ4NSAsIGdwID0gZ3Bhcihsd2QgPSAyLCBjb2wgPSAiYmxhY2siLCBmaWxsID0gTkEpKQ0KDQpkZXYub2ZmKCkNCmBgYA0KDQojIyBFeGVyY2lzZSAyIHsudGFic2V0fQ0KDQojIyMgRGVzY3JpcHRpb24NCk1vZGVscyA0LTYgcmVwbGljYXRlIHVzZSB0aGUgc2FtZSBzcGVjaWZpY2F0aW9ucyBhcyBhYm92ZSBidXQgZXhjbHVkaW5nIGhpZ2ggaW5jb21lIHN0YXRlcy4gIFJ1biB0aGVzZSByZWdyZXNzaW9ucyBhbmQgZm9ybWF0IHRoZSByZXN1bHRzIHRvIGdldCB0aGUgZm9sbG93aW5nOg0KDQo8Y2VudGVyPg0KPHRhYmxlIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+PGNhcHRpb24+PHN0cm9uZz5SZXBsaWNhdGlvbiBvZiBQZXRlcnNvbiAoMjAxNykgTW9kZWxzIDQtNjwvc3Ryb25nPjwvY2FwdGlvbj4NCjx0cj48dGQgY29sc3Bhbj0iNCIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCBibGFjayI+PC90ZD48L3RyPjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQgY29sc3Bhbj0iMyI+RXhjbHVkaW5nIGhpZ2ggaW5jb21lIHN0YXRlczwvdGQ+PC90cj4NCjx0cj48dGQ+PC90ZD48dGQgY29sc3Bhbj0iMyIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCBibGFjayI+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZCBjb2xzcGFuPSIzIj5IdW1hbiBSaWdodHM8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPig0KTwvdGQ+PHRkPig1KTwvdGQ+PHRkPig2KTwvdGQ+PC90cj4NCjx0cj48dGQgY29sc3Bhbj0iNCIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCBibGFjayI+PC90ZD48L3RyPjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+RXhwb3J0IERpdmVyc2lmaWNhdGlvbjwvdGQ+PHRkPjAuNDcyPHN1cD4qKio8L3N1cD48L3RkPjx0ZD4wLjQ3MTxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MC40NTA8c3VwPioqKjwvc3VwPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDAuMTQxKTwvdGQ+PHRkPigwLjEzOSk8L3RkPjx0ZD4oMC4xNDEpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkxpYmVyYWxpemF0aW9uPC90ZD48dGQ+LTE5Ljg5MTxzdXA+Kjwvc3VwPjwvdGQ+PHRkPjwvdGQ+PHRkPi00NC45MDM8c3VwPioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMTEuNjM2KTwvdGQ+PHRkPjwvdGQ+PHRkPigyMC43MDcpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkV4cG9ydCBEZXBlbmRlbmNlPC90ZD48dGQ+PC90ZD48dGQ+LTAuMDc3PC90ZD48dGQ+MC4zMzM8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPigwLjEyNik8L3RkPjx0ZD4oMC4yMjgpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkRlbW9jcmFjeTwvdGQ+PHRkPjAuMDI0PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4wLjAyMzxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MC4wMjU8c3VwPioqKjwvc3VwPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDAuMDA0KTwvdGQ+PHRkPigwLjAwNCk8L3RkPjx0ZD4oMC4wMDQpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkNvbmZsaWN0PC90ZD48dGQ+LTAuNTk4PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4tMC41Nzg8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPi0wLjU5NzxzdXA+KioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4wNzIpPC90ZD48dGQ+KDAuMDcxKTwvdGQ+PHRkPigwLjA3Mik8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+TG9nIEluY29tZTwvdGQ+PHRkPi0wLjAzMDwvdGQ+PHRkPi0wLjAzODwvdGQ+PHRkPi0wLjAxNzwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDAuMDM0KTwvdGQ+PHRkPigwLjAzNCk8L3RkPjx0ZD4oMC4wMzUpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkdyb3d0aDwvdGQ+PHRkPi0wLjA2NjwvdGQ+PHRkPi0wLjE0MTwvdGQ+PHRkPi0wLjA2MDwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDAuMjMyKTwvdGQ+PHRkPigwLjIyOSk8L3RkPjx0ZD4oMC4yMzIpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkxvZyBQb3B1bGF0aW9uPC90ZD48dGQ+LTAuMjkwPHN1cD4qKio8L3N1cD48L3RkPjx0ZD4tMC4yNzM8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPi0wLjMwNzxzdXA+KioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4wMjcpPC90ZD48dGQ+KDAuMDI0KTwvdGQ+PHRkPigwLjAyOSk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+TGluZWFyIFRpbWUgVHJlbmQ8L3RkPjx0ZD4tMC4wMTU8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPi0wLjAxNDxzdXA+KioqPC9zdXA+PC90ZD48dGQ+LTAuMDE1PHN1cD4qKio8L3N1cD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigwLjAwMyk8L3RkPjx0ZD4oMC4wMDMpPC90ZD48dGQ+KDAuMDAzKTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5MYWdnZWQgRFY8L3RkPjx0ZD4wLjYyMjxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MC42Mjg8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPjAuNjIxPHN1cD4qKio8L3N1cD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigwLjAxNik8L3RkPjx0ZD4oMC4wMTYpPC90ZD48dGQ+KDAuMDE2KTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5Db25zdGFudDwvdGQ+PHRkPjM2LjA5MzxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MzQuMzQ0PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4zNy4zNDk8c3VwPioqKjwvc3VwPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDYuNDE5KTwvdGQ+PHRkPig2LjM1Mik8L3RkPjx0ZD4oNi40NzUpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIGNvbHNwYW49IjQiIHN0eWxlPSJib3JkZXItYm90dG9tOiAxcHggc29saWQgYmxhY2siPjwvdGQ+PC90cj48dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPk9ic2VydmF0aW9uczwvdGQ+PHRkPjIsNDg4PC90ZD48dGQ+Miw1NTA8L3RkPjx0ZD4yLDQ4ODwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+UjxzdXA+Mjwvc3VwPjwvdGQ+PHRkPjAuNjgyPC90ZD48dGQ+MC42ODI8L3RkPjx0ZD4wLjY4MzwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+QWRqdXN0ZWQgUjxzdXA+Mjwvc3VwPjwvdGQ+PHRkPjAuNjgxPC90ZD48dGQ+MC42ODE8L3RkPjx0ZD4wLjY4MTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+UmVzaWR1YWwgU3RkLiBFcnJvcjwvdGQ+PHRkPjEuMTkwIChkZiA9IDI0NzgpPC90ZD48dGQ+MS4xOTYgKGRmID0gMjU0MCk8L3RkPjx0ZD4xLjE5MCAoZGYgPSAyNDc3KTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+RiBTdGF0aXN0aWM8L3RkPjx0ZD41OTEuNjI3PHN1cD4qKio8L3N1cD4gKGRmID0gOTsgMjQ3OCk8L3RkPjx0ZD42MDUuODI5PHN1cD4qKio8L3N1cD4gKGRmID0gOTsgMjU0MCk8L3RkPjx0ZD41MzIuOTIxPHN1cD4qKio8L3N1cD4gKGRmID0gMTA7IDI0NzcpPC90ZD48L3RyPg0KPHRyPjx0ZCBjb2xzcGFuPSI0IiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+PHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48ZW0+Tm90ZTo8L2VtPjwvdGQ+PHRkIGNvbHNwYW49IjMiIHN0eWxlPSJ0ZXh0LWFsaWduOnJpZ2h0Ij48c3VwPio8L3N1cD5wPDAuMTsgPHN1cD4qKjwvc3VwPnA8MC4wNTsgPHN1cD4qKio8L3N1cD5wPDAuMDE8L3RkPjwvdHI+DQo8L3RhYmxlPg0KPC9jZW50ZXI+DQoNCiMjIyBBbnN3ZXINCmBgYHtyIHJlc3VsdHM9RkFMU0V9DQptNSA8LSBsbShwaHlzaW50X2xlYWQgfiB0d293YXkgK2xpYl9ISyArIHBvbGl0eTIgKyBjb25mbGljdG9ubG9jYXRpb24NCiAgICAgICAgICsgbG5nZHBwYyArIGdkcGdyb3d0aCArIGxucG9wICsgeWVhciArIHBoeXNpbnQsIGRhdGEgPSBzdWIpDQoNCm02IDwtIGxtKHBoeXNpbnRfbGVhZCB+IHR3b3dheSArIGV4cGRlcCArIHBvbGl0eTIgKyBjb25mbGljdG9ubG9jYXRpb24NCiAgICAgICAgICsgbG5nZHBwYyArIGdkcGdyb3d0aCArIGxucG9wICsgeWVhciArIHBoeXNpbnQsIGRhdGEgPSBzdWIpDQoNCm03IDwtIGxtKHBoeXNpbnRfbGVhZCB+IHR3b3dheSArIGV4cGRlcCArbGliX0hLICsgcG9saXR5MiArIGNvbmZsaWN0b25sb2NhdGlvbg0KICAgICAgICAgKyBsbmdkcHBjICsgZ2RwZ3Jvd3RoICsgbG5wb3AgKyB5ZWFyICsgcGh5c2ludCwgZGF0YSA9IHN1YikNCg0Kc3RhcmdhemVyKG01LG02LG03LHR5cGU9Imh0bWwiLG91dCA9IHBhc3RlMChwYXRoLCIvcmVncmVzc2lvbnMyLmRvYyIpLA0KICAgICAgICAgIGNvdmFyaWF0ZS5sYWJlbHMgPSBjKCJFeHBvcnQgRGl2ZXJzaWZpY2F0aW9uIiwiTGliZXJhbGl6YXRpb24iLCINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFeHBvcnQgRGVwZW5kZW5jZSIsIkRlbW9jcmFjeSIsIkNvbmZsaWN0IiwiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTG9nIEluY29tZSIsIkdyb3d0aCIsIkxvZyBQb3B1bGF0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGluZWFyIFRpbWUgVHJlbmQiLCJMYWdnZWQgRFYiKSwNCiAgICAgICAgICBjb2x1bW4ubGFiZWxzID0gYygiKDQpIiwiKDUpIiwiKDYpIiksDQogICAgICAgICAgbW9kZWwubnVtYmVycyA9IEYsDQogICAgICAgICAgdGl0bGU9IlJlcGxpY2F0aW9uIG9mIFBldGVyc29uICgyMDE3KSBNb2RlbHMgNC02IiwNCiAgICAgICAgICBkZXAudmFyLmNhcHRpb24gPSAiRXhjbHVkaW5nIGhpZ2ggaW5jb21lIHN0YXRlcyIsDQogICAgICAgICAgZGVwLnZhci5sYWJlbHMgPSAiSHVtYW4gUmlnaHRzIikNCmBgYA0KDQojIyBFeGVyY2lzZSAzIHsudGFic2V0fQ0KDQojIyMgRGVzY3JpcHRpb24NCk9uZSBtaWdodCB3b25kZXIgd2hldGhlciB0aGUgcmVzdWx0cyBhcmUgcm9idXN0IHRvIHRoZSBpbmNsdXNpb24gb2YgcmVnaW9uIG9yIHN0YXRlIGZpeGVkIGVmZmVjdHMuICBUaGVzZSBjYW4gYmUgZW50ZXJlZCBpbnRvIHRoZSByZWdyZXNzaW9uIGVxdWF0aW9uIGJ5IGluY2x1ZGluZywgZm9yIGV4YW1wbGUsIGBhcy5mYWN0b3IoY2NvZGUpYCB0byB0aGUgcmVncmVzc2lvbiBlcXVhdGlvbi4gIEZpeGVkIGVmZmVjdHMgYXJlIGdlbmVyYWxseSBvbWl0dGVkIGZyb20gcmVncmVzc2lvbiB0YWJsZXM7IGZpZ3VyZSBvdXQgaG93IHRvIGV4Y2x1ZGUgcmVncmVzc29ycyBmcm9tIGBzdGFyZ2F6ZXJgIG91dHB1dCBhbmQgYWRkIGFuIGFkZGl0aW9uYWwgbm90ZSB0byB0aGUgdGFibGUgaW5kaWNhdGluZyB0aGF0IGZpeGVkIGVmZmVjdHMgd2VyZSBpbmNsdWRlZC4gIFlvdSBzaG91bGQgYWxzbyByZW1vdmUgdGhlIFItc3F1YXJlZCwgUmVzaWR1YWwgU3RhbmRhcmQgRXJyb3IsIGFuZCBGIFN0YXRpc3RpYyBmcm9tIGJlaW5nIHJlcG9ydGVkLiAgVGhlIG91dHB1dCBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOg0KDQo8Y2VudGVyPg0KPHRhYmxlIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+PGNhcHRpb24+PHN0cm9uZz5Sb2J1c3RuZXNzIG9mIFBldGVyc29uICgyMDE3KSBNb2RlbHMgMS0zPC9zdHJvbmc+PC9jYXB0aW9uPg0KPHRyPjx0ZCBjb2xzcGFuPSI0IiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+PHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZCBjb2xzcGFuPSIzIj5BbGwgU3RhdGVzPC90ZD48L3RyPg0KPHRyPjx0ZD48L3RkPjx0ZCBjb2xzcGFuPSIzIiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkIGNvbHNwYW49IjMiPkh1bWFuIFJpZ2h0czwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDFhKTwvdGQ+PHRkPigyYSk8L3RkPjx0ZD4oM2EpPC90ZD48L3RyPg0KPHRyPjx0ZCBjb2xzcGFuPSI0IiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIGJsYWNrIj48L3RkPjwvdHI+PHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5FeHBvcnQgRGl2ZXJzaWZpY2F0aW9uPC90ZD48dGQ+MC4xOTA8L3RkPjx0ZD4wLjIyMDwvdGQ+PHRkPjAuMjQ4PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4yNTkpPC90ZD48dGQ+KDAuMjU3KTwvdGQ+PHRkPigwLjI2MCk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+TGliZXJhbGl6YXRpb248L3RkPjx0ZD4yMS45MDU8L3RkPjx0ZD48L3RkPjx0ZD4tOS4yMTA8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigxNy41MDkpPC90ZD48dGQ+PC90ZD48dGQ+KDIwLjgyNCk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+RXhwb3J0IERlcGVuZGVuY2U8L3RkPjx0ZD48L3RkPjx0ZD4wLjU4NzxzdXA+KioqPC9zdXA+PC90ZD48dGQ+MC42MzM8c3VwPioqKjwvc3VwPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+KDAuMTkxKTwvdGQ+PHRkPigwLjIzMCk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+RGVtb2NyYWN5PC90ZD48dGQ+MC4wMzc8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPjAuMDM5PHN1cD4qKio8L3N1cD48L3RkPjx0ZD4wLjAzOTxzdXA+KioqPC9zdXA+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4wMDYpPC90ZD48dGQ+KDAuMDA2KTwvdGQ+PHRkPigwLjAwNik8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+Q29uZmxpY3Q8L3RkPjx0ZD4tMC41MjA8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPi0wLjQ5NTxzdXA+KioqPC9zdXA+PC90ZD48dGQ+LTAuNTA4PHN1cD4qKio8L3N1cD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigwLjA3Nyk8L3RkPjx0ZD4oMC4wNzUpPC90ZD48dGQ+KDAuMDc3KTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5Mb2cgSW5jb21lPC90ZD48dGQ+MC4wMjk8L3RkPjx0ZD4wLjA4NjwvdGQ+PHRkPjAuMDc3PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4wOTEpPC90ZD48dGQ+KDAuMDkwKTwvdGQ+PHRkPigwLjA5Mik8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+R3Jvd3RoPC90ZD48dGQ+MC4wMTY8L3RkPjx0ZD4tMC4wMzk8L3RkPjx0ZD4wLjAzMjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDAuMTg4KTwvdGQ+PHRkPigwLjE4Nik8L3RkPjx0ZD4oMC4xODgpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPkxvZyBQb3B1bGF0aW9uPC90ZD48dGQ+LTAuMzI0PC90ZD48dGQ+LTAuMjQ0PC90ZD48dGQ+LTAuMjY3PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD4oMC4yMzcpPC90ZD48dGQ+KDAuMjM0KTwvdGQ+PHRkPigwLjIzOCk8L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+TGluZWFyIFRpbWUgVHJlbmQ8L3RkPjx0ZD4tMC4wMTc8c3VwPioqKjwvc3VwPjwvdGQ+PHRkPi0wLjAyMjxzdXA+KioqPC9zdXA+PC90ZD48dGQ+LTAuMDIyPHN1cD4qKio8L3N1cD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPigwLjAwNSk8L3RkPjx0ZD4oMC4wMDYpPC90ZD48dGQ+KDAuMDA2KTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5MYWdnZWQgRFY8L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PHRkPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48dGQ+PC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij5Db25zdGFudDwvdGQ+PHRkPjQ0LjA2MDxzdXA+KioqPC9zdXA+PC90ZD48dGQ+NTAuMTAzPHN1cD4qKio8L3N1cD48L3RkPjx0ZD41MC40Mzg8c3VwPioqKjwvc3VwPjwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PC90ZD48dGQ+KDcuNDY3KTwvdGQ+PHRkPig3LjY2NSk8L3RkPjx0ZD4oNy44MTEpPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjx0ZD48L3RkPjwvdHI+DQo8dHI+PHRkIGNvbHNwYW49IjQiIHN0eWxlPSJib3JkZXItYm90dG9tOiAxcHggc29saWQgYmxhY2siPjwvdGQ+PC90cj48dHI+PHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQiPk9ic2VydmF0aW9uczwvdGQ+PHRkPjMsNDc5PC90ZD48dGQ+Myw1NjI8L3RkPjx0ZD4zLDQ3OTwvdGQ+PC90cj4NCjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+QWRqdXN0ZWQgUjxzdXA+Mjwvc3VwPjwvdGQ+PHRkPjAuNzc1PC90ZD48dGQ+MC43Nzk8L3RkPjx0ZD4wLjc3NjwvdGQ+PC90cj4NCjx0cj48dGQgY29sc3Bhbj0iNCIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCBibGFjayI+PC90ZD48L3RyPjx0cj48dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdCI+PGVtPk5vdGU6PC9lbT48L3RkPjx0ZCBjb2xzcGFuPSIzIiBzdHlsZT0idGV4dC1hbGlnbjpyaWdodCI+PHN1cD4qPC9zdXA+cDwwLjE7IDxzdXA+Kio8L3N1cD5wPDAuMDU7IDxzdXA+KioqPC9zdXA+cDwwLjAxPC90ZD48L3RyPg0KPHRyPjx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij48L3RkPjx0ZCBjb2xzcGFuPSIzIiBzdHlsZT0idGV4dC1hbGlnbjpyaWdodCI+QWxsIG1vZGVscyBpbmNsdWRlIGNvdW50cnkgZml4ZWQgZWZmZWN0cy48L3RkPjwvdHI+DQo8L3RhYmxlPg0KPC9jZW50ZXI+DQoNCiMjIyBBbnN3ZXINCmBgYHtyIHJlc3VsdHM9RkFMU0V9DQptNyA8LSBsbShwaHlzaW50X2xlYWQgfiB0d293YXkgK2xpYl9ISyArIHBvbGl0eTIgKyBjb25mbGljdG9ubG9jYXRpb24NCiAgICAgICAgICsgbG5nZHBwYyArIGdkcGdyb3d0aCArIGxucG9wICsgeWVhciArIHBoeXNpbnQgKyBhcy5mYWN0b3IoY2NvZGUpLCBkYXRhID0gb3V0MikNCg0KbTggPC0gbG0ocGh5c2ludF9sZWFkIH4gdHdvd2F5ICsgZXhwZGVwICsgcG9saXR5MiArIGNvbmZsaWN0b25sb2NhdGlvbg0KICAgICAgICAgKyBsbmdkcHBjICsgZ2RwZ3Jvd3RoICsgbG5wb3AgKyB5ZWFyICsgcGh5c2ludCArIGFzLmZhY3RvcihjY29kZSksIGRhdGEgPSBvdXQyKQ0KDQptOSA8LSBsbShwaHlzaW50X2xlYWQgfiB0d293YXkgKyBleHBkZXAgK2xpYl9ISyArIHBvbGl0eTIgKyBjb25mbGljdG9ubG9jYXRpb24NCiAgICAgICAgICsgbG5nZHBwYyArIGdkcGdyb3d0aCArIGxucG9wICsgeWVhciArIHBoeXNpbnQgKyBhcy5mYWN0b3IoY2NvZGUpLCBkYXRhID0gb3V0MikNCg0Kc3RhcmdhemVyKG03LG04LG05LHR5cGU9Imh0bWwiLG91dCA9IHBhc3RlMChwYXRoLCIvcmVncmVzc2lvbnMzLmRvYyIpLA0KICAgICAgICAgIGNvdmFyaWF0ZS5sYWJlbHMgPSBjKCJFeHBvcnQgRGl2ZXJzaWZpY2F0aW9uIiwiTGliZXJhbGl6YXRpb24iLCINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFeHBvcnQgRGVwZW5kZW5jZSIsIkRlbW9jcmFjeSIsIkNvbmZsaWN0IiwiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTG9nIEluY29tZSIsIkdyb3d0aCIsIkxvZyBQb3B1bGF0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGluZWFyIFRpbWUgVHJlbmQiLCJMYWdnZWQgRFYiKSwNCiAgICAgICAgICB0aXRsZT0iUm9idXN0bmVzcyBvZiBQZXRlcnNvbiAoMjAxNykgTW9kZWxzIDEtMyIsDQogICAgICAgICAgb21pdD0xMTpsZW5ndGgobTkkY29lZmZpY2llbnRzKSwNCiAgICAgICAgICBub3RlcyA9ICJBbGwgbW9kZWxzIGluY2x1ZGUgY291bnRyeSBmaXhlZCBlZmZlY3RzLiIsDQogICAgICAgICAgbm90ZXMuYXBwZW5kPVRSVUUsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIigxYSkiLCIoMmEpIiwiKDNhKSIpLA0KICAgICAgICAgIG1vZGVsLm51bWJlcnMgPSBGLA0KICAgICAgICAgIGRlcC52YXIuY2FwdGlvbiA9ICJBbGwgU3RhdGVzIiwNCiAgICAgICAgICBkZXAudmFyLmxhYmVscyA9ICJIdW1hbiBSaWdodHMiLA0KICAgICAgICAgIG9taXQuc3RhdCA9IGMoImYiLCJyc3EiLCJzZXIiKSkNCmBgYA0KDQojIEZpbmFsIFdvcmRzDQoNClRoYXQncyBhbGwgSSBoYXZlIGZvciB5b3UgdG9kYXkuICBIb3BlIGl0IHdhcyBoZWxwZnVsISAgRmVlbCBmcmVlIHRvIHJlYWNoIG91dCB0byBOWVUgRGF0YSBTZXJ2aWNlcyBpZiB5b3UgZW5jb3VudGVyIGFueSBpc3N1ZXMgd2l0aCBwcm9ncmFtbWluZyBpbiBSIG9yIHdvdWxkIGxpa2UgdG8gYmUgZGlyZWN0ZWQgdG8gYW55IGFkZGl0aW9uYWwgcmVzb3VyY2VzLiAgT3ZlciB0aGUgcGFzdCB0d28gc2Vzc2lvbnMgd2UgaGF2ZSBvbmx5IHRvdWNoZWQgdGhlIHN1cmZhY2Ugb2Ygd2hhdCBSIGlzIGFibGUgdG8gZG8gdGhhbmtzIHRvIHRoZSB2aWJyYW50IGNvbW11bml0eSBvZiBzY2hvbGFycyBhbmQgcHJhY3RpdGlvbmVycyB3aG8gY29udHJpYnV0ZSB0byB0aGUgcHJvamVjdC4gIElmIHlvdSBhcmUgbG9va2luZyB0byBnZXQgZnVydGhlciBpbnRvIFIgZm9yIHN0YXRpc3RpY2FsIGFuYWx5c2lzLCBJIGhpZ2hseSByZWNvbW1lbmQgY2hlY2tpbmcgb3V0IHdoYXQgaXMgYXZhaWxhYmxlIG9uIHRoZSB2YXJpb3VzIFt0YXNrdmlld3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi92aWV3cy8pIG9yIGV2ZW4gdGhlc2UgbmVhdCBbc3dpcmwgY291cnNlc10oaHR0cHM6Ly9zd2lybHN0YXRzLmNvbS8pIHdoZXJlIHlvdSBjYW4gbGVhcm4gUiBpbiBSLg0KDQoNCg0KDQo=