Many of you will have read articles from the FiveThirtyEight website, which often uses data to support narratives on a wide variety of subjects

538 have recently made available many of the datasets they have used as an R package and I plan to look at some where there appears the potential not only to replicate their findings but also to


Dear Mona, Which State Has The Worst Drivers?

The first I have chosen, Which State Has The Worst Drivers, was written in October 2014 by one of their, then star data journalists Mona Chalabi, also infamous for the Vagina Dispatches series for the Guardian

The data originates from The National Highway Traffic Safety Administration (NHTSA) website


As always, the libraries and any obligatory files need to be loaded.

(The htmltools package is an addition to help overcome CSS issues arising through using the crosstalk package with blogdown. Props to htmlwidgets king Kenton Russell for his assistance)

library(htmltools)
Warning message:
running command '"C:/Program Files/RStudio/bin/pandoc/pandoc" +RTS -K512m -RTS badDrivers_538.utf8.md --to html --from markdown+autolink_bare_uris+ascii_identifiers+tex_math_single_backslash --output pandoc32c0793628fd.html --smart --email-obfuscation none --self-contained --standalone --section-divs --template "C:\Users\Andrew\Documents\R\win-library\3.3\rmarkdown\rmd\h\default.html" --no-highlight --variable highlightjs=1 --variable "theme:bootstrap" --include-in-header "C:\Users\Andrew\AppData\Local\Temp\Rtmpuetp0F\rmarkdown-str32c0766c1433.html" --mathjax --variable "mathjax-url:https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" --variable code_folding=show --variable source_embed=badDrivers_538.Rmd --include-after-body "C:\Users\Andrew\AppData\Local\Temp\Rtmpuetp0F\file32c031925ee2.html" --variable code_menu=1 --variable kable-scroll=1' had status 67 
library(plotly)
library(fivethirtyeight)
library(crosstalk)
library(tabulizer)
library(DT)
library(tidyverse)
# a simple table linking stateID to state name
states <- read_csv("data/states.csv") %>%
# improve column names
select(state = State, stateID = Abbreviation)

Enhance

Let us first explore the supplied data; do any necessary wrangling; attempt to replicate the charts in Plotly; and use the filter control of the crosstalk package (which enables inter-widget interactivity for htmlWidgets) so that the plots can be shown more concisely

Here is the first of the charts from the original article

Let’s look at the data in the package

    df <- bad_drivers
    glimpse(df)
Observations: 51
Variables: 8
$ state               <chr> "Alabama", "Alaska", "Arizona", "Arkansas", "Califo...
$ num_drivers         <dbl> 18.8, 18.1, 18.6, 22.4, 12.0, 13.6, 10.8, 16.2, 5.9...
$ perc_speeding       <int> 39, 41, 35, 18, 35, 37, 46, 38, 34, 21, 19, 54, 36,...
$ perc_alcohol        <int> 30, 25, 28, 26, 28, 28, 36, 30, 27, 29, 25, 41, 29,...
$ perc_not_distracted <int> 96, 90, 84, 94, 91, 79, 87, 87, 100, 92, 95, 82, 85...
$ perc_no_previous    <int> 80, 94, 96, 95, 89, 95, 82, 99, 100, 94, 93, 87, 98...
$ insurance_premiums  <dbl> 784.55, 1053.48, 899.47, 827.34, 878.41, 835.50, 10...
$ losses              <dbl> 145.08, 133.93, 110.35, 142.39, 165.63, 139.91, 167...

The data is preprocessed to give rounded percentages whilst the charts are in actual numbers of fatalities per billion miles travelled. We could search for the raw data but for present purposes we will just need to recalculate.
However, to act on the data it will by much easier to transform the dataframe to a narrow rather than wide form. In addition, it would be nice to have the chart shown in meaningful order rather than alphabetically by state

df_gather <-  df %>%
  # restrict to columns required
  select(1:6) %>%
  # use a function within the tidyr package (part of the tidyverse)
  gather(cause, pc, -c(state, num_drivers)) %>%
  # calculate an approximate actual count
  mutate(value = round(num_drivers * pc / 100, 1)) %>%
  # add a stateID column for use in map %>%
  left_join(states)
  
  
  # In order to improve data display, the state needs to be changed from a character to a factor and ordered
  ## NB more work required
   df_gather$state <-
   factor(df_gather$state, levels = df_gather$state[order(df_gather$value)])
  
  df_gather
NA

We now have the df in format required for our first chart. As I mentioned earlier, I want to use just one aspect of the much wider potential of the crosstalk package. I anticipate utilizing this more fully in future posts but beware that it is still in beta

# this enables the filter to interact with chart and, later, map
sd <- SharedData$new(df_gather)
fs <- filter_select(
id = "cause",
label = "Cause",
sharedData = sd,
group =  ~ cause,
allLevels = FALSE,
multiple = FALSE
)
## this is needed as crosstalk does not work nicely with bootstrap, apparently
fs_nobootstrap <- fs
attr(fs_nobootstrap, "html_dependencies") <- Filter(
  function(dep) {dep$name != "bootstrap"},
  attr(fs_nobootstrap, "html_dependencies")
)
myChart <- sd %>%
  # need to set a larger than default height to encompass all states
  plot_ly(
    x =  ~ num_drivers,
    y =  ~ state,
    height = 800
  ) %>%
  # first put in all fatalities
  add_bars(color = I("#f2dfa8"), name = "Total", width=0.8) %>%
  # then those according to cause
  add_bars(width=0.2,
    x =  ~ value,
    y =  ~ state,
    color = I("#F6B900"),
    name = "Cause",
    hoverinfo="text",
    text=~paste0(pc,"%")
  ) %>%
  # make it an overlay barchart and inprove look
  layout(
    barmode = "overlay",
    title = "Drivers involved in Fatal collisions by State - 2012",
    xaxis = list(title = "Fatal collisons per billion miles"),
    yaxis = list(title = ""),
    margin = list(l = 120)
  ) %>%
  config(displayModeBar = F, showLink = F)
## combine the selector and chart
  tagList(
  fs_nobootstrap,
   myChart
)

So some progress. There is now a more compact display with an infoactive element on hover and the states are no longer in alphabetical order but not by rate for individual cause. It would also be useful if the selector showed the default


Extend

Now, how about extending the original article with some maps. Plotly offers a choropleth option

map <- sd %>%
plot_ly(
type = "choropleth",
locations =  ~ stateID,
locationmode = "USA-states",
z =  ~ value,
reversescale = TRUE
) %>% layout(geo = list(scope = "usa"))
tagList(
  fs_nobootstrap,
  map
)

Combining would make sense and let’s throw in a table for good measure. If going this route, a dashboard might be a more sensible option


Update

I found it a difficult to locate the raw data that the fivethirtyeight dataset was based on so, in lieu of that and because it is a good news story, mapped the considerable reduction in fatalaties per miles travelled over the past forty years

The NHTSA data is available in the form of downloadable pdfs. A year ago this would have been enough for me to say, well, ‘Enough’: but at least two packages I am aware of pdftools and tabulizer attempt to address the problem of extracting data from pdfs.

Here I have used tabulizer. Downloading data takes a few seconds

Because there is an interactive element involved in setting the part of the page to collect the data from, I have commented out the initial process and supply the cleaner data from a local file

# # Ideally we would use the extract_tables function but
crash_data <-
extract_tables(
"https://crashstats.nhtsa.dot.gov/Api/Public/ViewPublication/812293",
pages = 5,
method = "data.frame"
)
head(crash_data[[1]])
#Luckily there is an interactive option where a rectangle can be drawn artound the displayed image. I know we just want the first 4 columns
# I have written its output to a file
#         crash_data <-    extract_areas("https://crashstats.nhtsa.dot.gov/Api/Public/ViewPublication/812293", pages = 5)
# df <- data.frame(crash_data)
# glimpse(df)
# Observations: 51
# Variables: 5
# $ X1 <fctr> Alabama , Alaska , Arizona , Arkansas , California , C...
# $ X2 <fctr> 3.63 , 4.38 , 4.19 , 4.01 , 3.09 , 3.50 , 2.13 , 3.37 ...
# $ X3 <fctr> 1.92 , 1.45 , 1.97 , 2.05 , 1.32 , 1.26 , 0.88 , 1.40 ...
# $ X4 <fctr> 1.31 , 1.05 , 1.40 , 1.49 , 0.94 , 1.03 , 0.92 , 1.06 ...
# $ X5 <fctr> 1.25, 1.50, 1.23, 1.37, 0.92, 1.00, 0.80, 1.26, 0.65, ...
# write_csv(df,"../../data/crash_data1975_2014.csv")
# Here we get the data back from the local file
# The package, correctly, guages that we want the state column to be
# of class character with the rest numeric
df <- read_csv("data/crash_data1975_2014.csv")
glimpse(df)
Observations: 51
Variables: 5
$ X1 <chr> "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "De...
$ X2 <dbl> 3.63, 4.38, 4.19, 4.01, 3.09, 3.50, 2.13, 3.37, 2.27, 3.24, 3.46, 3.47, 4.78, 3.56, 3.02...
$ X3 <dbl> 1.92, 1.45, 1.97, 2.05, 1.32, 1.26, 0.88, 1.40, 1.29, 1.75, 1.52, 1.39, 1.85, 1.27, 1.31...
$ X4 <dbl> 1.31, 1.05, 1.40, 1.49, 0.94, 1.03, 0.92, 1.06, 0.57, 1.25, 1.08, 1.01, 1.34, 0.94, 1.00...
$ X5 <dbl> 1.25, 1.50, 1.23, 1.37, 0.92, 1.00, 0.80, 1.26, 0.65, 1.24, 1.04, 0.93, 1.15, 0.88, 0.94...
# just need to enter more informative column names
names(df) <- c('state', 'yr_1975', 'yr_2005', 'yr_2013', 'yr_2014')
# and again put into tidy version and add state abbreviations
df_gather <-  df %>%
gather(year, rate, -state) %>%
left_join(states)
glimpse(df_gather)
Observations: 204
Variables: 4
$ state   <chr> "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut"...
$ year    <chr> "yr_1975", "yr_1975", "yr_1975", "yr_1975", "yr_1975", "yr_1975", "yr_1975", "yr_19...
$ rate    <dbl> 3.63, 4.38, 4.19, 4.01, 3.09, 3.50, 2.13, 3.37, 2.27, 3.24, 3.46, 3.47, 4.78, 3.56,...
$ stateID <chr> "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL",...

We can now map the changes over time for three years. Note the key input of zmin and zmax which ensures same color scale applies to all maps

# layout in 3 columns
#bscols(widths=c(4,4,4),
map_1975 <- df_gather %>%
  filter(year=="yr_1975") %>%
  # create a choropleth map
  plot_geo(locationmode="USA-states") %>%
  add_trace(z=~rate, color = ~rate, colors = "Reds",
            # ensure that color scale extends beyond the values in individual map
            zmin=0,zmax=6,
            locations = ~stateID,
            showscale=TRUE) %>%
  layout(geo=list(scope="usa"),
         title="1975") %>%
  config(displayModeBar = F, showLink = F)
map_2005 <- df_gather %>%
  filter(year=="yr_2005") %>%
  plot_geo(locationmode="USA-states") %>%
  add_trace(z=~rate, color = ~rate, colors = "Reds",
            zmin=0,zmax=6,
            locations = ~stateID,
            showscale=TRUE) %>%
  layout(geo=list(scope="usa") %>%
           config(displayModeBar = F, showLink = F),
         title="2005")
map_2014 <- df_gather %>%
  filter(year=="yr_2014") %>%
  plot_geo(locationmode="USA-states") %>%
  add_trace(z=~rate, color = ~rate, colors = "Reds",
            zmin=0,zmax=6,
            locations = ~stateID,
            # add a scale
            showscale=TRUE) %>%
  layout(geo=list(scope="usa") %>%
           config(displayModeBar = F, showLink = F),
         title="2014")
tagList(
  map_1975,
  map_2005,
  map_2014
)

Ideally, these maps would be side by side but this is difficult within a blog format. Please note that there is a much larger time gap between the first two maps than the latter two. Hover individual states and you can see that by 2005 pretty well all states had their rate as low the best state thirty years prior


Let’s try one map showing % decline in rates

df %>%
  left_join(states) %>%
  mutate(change = round(100 * yr_2014 / yr_1975 - 100)) %>%
  plot_geo(locationmode = "USA-states") %>%
  add_trace(
  z =  ~ change,
  color = ~ change,
  colors = "Greens",
  # zmin=0,zmax=6,
  locations = ~ stateID,
  showscale = TRUE,
  reversescale = TRUE
  ) %>%
  layout(
  geo = list(scope = "usa") %>%
  config(displayModeBar = F, showLink = F),
  title = "% change in rate of Fatalities 1975 to 2014"
  ) %>%
  config(displayModeBar = F, showLink = F)
Joining, by = "state"

Obviously, there has been a sharp downward trend in fatalities and even in absolute terms, current levels are a third less than the peak of 1972

Clearly several factors, including better cars and roads, awareness and legislation regarding alcohol and drugs will have played a part. There is a host of data on the NHTSAsite that could be used for further analyses

LS0tDQp0aXRsZTogIkVuaGFuY2luZywgVXBkYXRpbmcgYW5kIGV4dGVuZGluZyBmaXZldGhpcnR5ZWlnaHQgYXJ0aWNsZXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCk1hbnkgb2YgeW91IHdpbGwgaGF2ZSByZWFkIGFydGljbGVzIGZyb20gdGhlIFtGaXZlVGhpcnR5RWlnaHQgd2Vic2l0ZV0oaHR0cHM6Ly9maXZldGhpcnR5ZWlnaHQuY29tLyksIHdoaWNoIG9mdGVuIHVzZXMgZGF0YSB0byBzdXBwb3J0IG5hcnJhdGl2ZXMgb24gYSB3aWRlIHZhcmlldHkgb2Ygc3ViamVjdHMgDQoNCjUzOCBoYXZlIHJlY2VudGx5IG1hZGUgYXZhaWxhYmxlIG1hbnkgb2YgdGhlIGRhdGFzZXRzIHRoZXkgaGF2ZSB1c2VkIGFzIGFuIFtSIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9maXZldGhpcnR5ZWlnaHQvaW5kZXguaHRtbCkgYW5kIEkgcGxhbiB0byBsb29rIGF0IHNvbWUNCndoZXJlIHRoZXJlIGFwcGVhcnMgdGhlIHBvdGVudGlhbCBub3Qgb25seSB0byByZXBsaWNhdGUgdGhlaXIgZmluZGluZ3MgYnV0IGFsc28gdG8NCg0KKiBFbmhhbmNlDQoqIFVwZGF0ZQ0KKiBFeHRlbmQNCg0KLS0tDQoNCiMgRGVhciBNb25hLCBXaGljaCBTdGF0ZSBIYXMgVGhlIFdvcnN0IERyaXZlcnM/DQoNClRoZSBmaXJzdCBJIGhhdmUgY2hvc2VuLCBbV2hpY2ggU3RhdGUgSGFzIFRoZSBXb3JzdCBEcml2ZXJzXShodHRwczovL2ZpdmV0aGlydHllaWdodC5jb20vZGF0YWxhYi93aGljaC1zdGF0ZS1oYXMtdGhlLXdvcnN0LWRyaXZlcnMvKSwgd2FzIHdyaXR0ZW4gaW4gT2N0b2JlciAyMDE0IGJ5IG9uZSBvZiB0aGVpciwgdGhlbiBzdGFyIGRhdGEgam91cm5hbGlzdHMgW01vbmEgQ2hhbGFiaV0oaHR0cHM6Ly90d2l0dGVyLmNvbS9Nb25hQ2hhbGFiaSksIGFsc28gaW5mYW1vdXMgZm9yIHRoZSBbVmFnaW5hIERpc3BhdGNoZXNdKGh0dHBzOi8vd3d3LnRoZWd1YXJkaWFuLmNvbS9saWZlYW5kc3R5bGUvc2VyaWVzL3ZhZ2luYS1kaXNwYXRjaGVzKSBzZXJpZXMgZm9yIHRoZSBHdWFyZGlhbg0KDQpUaGUgZGF0YSBvcmlnaW5hdGVzIGZyb20gVGhlIE5hdGlvbmFsIEhpZ2h3YXkgVHJhZmZpYyBTYWZldHkgQWRtaW5pc3RyYXRpb24gKE5IVFNBKSBbd2Vic2l0ZV0oaHR0cHM6Ly93d3cubmh0c2EuZ292LykNCg0KLS0tDQoNCkFzIGFsd2F5cywgdGhlIGxpYnJhcmllcyBhbmQgYW55IG9ibGlnYXRvcnkgZmlsZXMgbmVlZCB0byBiZSBsb2FkZWQuICAgICANCg0KKCpUaGUgaHRtbHRvb2xzIHBhY2thZ2UgaXMgYW4gYWRkaXRpb24gdG8gaGVscCBvdmVyY29tZSBDU1MgaXNzdWVzIGFyaXNpbmcgdGhyb3VnaCB1c2luZyB0aGUgY3Jvc3N0YWxrIHBhY2thZ2Ugd2l0aCBibG9nZG93bi4gUHJvcHMgdG8gaHRtbHdpZGdldHMga2luZyBbS2VudG9uIFJ1c3NlbGxdKGh0dHBzOi8vdHdpdHRlci5jb20vdGltZWx5cG9ydGZvbGlvKSBmb3IgaGlzIGFzc2lzdGFuY2UqKQ0KDQpgYGB7ciBzZXR1cCwgd2FybmluZz0gRkFMU0UgLG1lc3NhZ2UgPSBGQUxTRX0NCg0KbGlicmFyeShodG1sdG9vbHMpDQoNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShmaXZldGhpcnR5ZWlnaHQpDQpsaWJyYXJ5KGNyb3NzdGFsaykNCmxpYnJhcnkodGFidWxpemVyKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQojIGEgc2ltcGxlIHRhYmxlIGxpbmtpbmcgc3RhdGVJRCB0byBzdGF0ZSBuYW1lDQpzdGF0ZXMgPC0gcmVhZF9jc3YoImRhdGEvc3RhdGVzLmNzdiIpICU+JQ0KIyBpbXByb3ZlIGNvbHVtbiBuYW1lcw0Kc2VsZWN0KHN0YXRlID0gU3RhdGUsIHN0YXRlSUQgPSBBYmJyZXZpYXRpb24pDQoNCg0KYGBgDQoNCiMjIEVuaGFuY2UNCg0KTGV0IHVzIGZpcnN0IGV4cGxvcmUgdGhlIHN1cHBsaWVkIGRhdGE7IGRvIGFueSBuZWNlc3Nhcnkgd3JhbmdsaW5nOyBhdHRlbXB0IHRvIHJlcGxpY2F0ZSB0aGUgY2hhcnRzIGluIFBsb3RseTsgIGFuZCB1c2UgdGhlIGZpbHRlciBjb250cm9sIG9mIHRoZSBjcm9zc3RhbGsgcGFja2FnZSAod2hpY2ggZW5hYmxlcyBpbnRlci13aWRnZXQgaW50ZXJhY3Rpdml0eSBmb3IgaHRtbFdpZGdldHMpIHNvIHRoYXQgdGhlIHBsb3RzIGNhbiBiZSBzaG93biBtb3JlIGNvbmNpc2VseQ0KDQpIZXJlIGlzIHRoZSBmaXJzdCBvZiB0aGUgY2hhcnRzIGZyb20gdGhlIG9yaWdpbmFsIGFydGljbGUNCg0KIA0KICFbXShpbWFnZXMvZml2ZTM4RHJpdmVycy5wbmcpIA0KLS0tDQoNCkxldCdzIGxvb2sgYXQgdGhlIGRhdGEgaW4gdGhlIHBhY2thZ2UNCg0KYGBge3IgZGF0YSwgd2FybmluZz0gRkFMU0UgLG1lc3NhZ2UgPSBGQUxTRX0NCg0KICAgIGRmIDwtIGJhZF9kcml2ZXJzDQogICAgZ2xpbXBzZShkZikNCg0KYGBgICAgICAgICANCiAgIFRoZSBkYXRhIGlzIHByZXByb2Nlc3NlZCB0byBnaXZlIHJvdW5kZWQgcGVyY2VudGFnZXMgd2hpbHN0IHRoZSBjaGFydHMgYXJlIGluIGFjdHVhbCBudW1iZXJzIG9mIGZhdGFsaXRpZXMgcGVyIGJpbGxpb24gbWlsZXMgdHJhdmVsbGVkLiBXZSBjb3VsZCBzZWFyY2ggZm9yIHRoZSByYXcgZGF0YSBidXQgZm9yIHByZXNlbnQgcHVycG9zZXMgd2Ugd2lsbCBqdXN0IG5lZWQgdG8gcmVjYWxjdWxhdGUuICAgICANCiAgIEhvd2V2ZXIsIHRvIGFjdCBvbiB0aGUgZGF0YSBpdCB3aWxsIGJ5IG11Y2ggZWFzaWVyIHRvIHRyYW5zZm9ybSB0aGUgZGF0YWZyYW1lIHRvIGEgbmFycm93IHJhdGhlciB0aGFuIHdpZGUgZm9ybS4gSW4gYWRkaXRpb24sIGl0IHdvdWxkIGJlIG5pY2UgdG8gaGF2ZSB0aGUgY2hhcnQgc2hvd24gaW4gbWVhbmluZ2Z1bCBvcmRlciByYXRoZXIgdGhhbiBhbHBoYWJldGljYWxseSBieSBzdGF0ZQ0KICAgDQpgYGB7ciB3cmFuZ2xpbmcsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfSAgDQoNCmRmX2dhdGhlciA8LSAgZGYgJT4lDQogICMgcmVzdHJpY3QgdG8gY29sdW1ucyByZXF1aXJlZA0KICBzZWxlY3QoMTo2KSAlPiUNCiAgIyB1c2UgYSBmdW5jdGlvbiB3aXRoaW4gdGhlIHRpZHlyIHBhY2thZ2UgKHBhcnQgb2YgdGhlIHRpZHl2ZXJzZSkNCiAgZ2F0aGVyKGNhdXNlLCBwYywgLWMoc3RhdGUsIG51bV9kcml2ZXJzKSkgJT4lDQogICMgY2FsY3VsYXRlIGFuIGFwcHJveGltYXRlIGFjdHVhbCBjb3VudA0KICBtdXRhdGUodmFsdWUgPSByb3VuZChudW1fZHJpdmVycyAqIHBjIC8gMTAwLCAxKSkgJT4lDQogICMgYWRkIGEgc3RhdGVJRCBjb2x1bW4gZm9yIHVzZSBpbiBtYXAgJT4lDQogIGxlZnRfam9pbihzdGF0ZXMpDQogIA0KICANCiAgIyBJbiBvcmRlciB0byBpbXByb3ZlIGRhdGEgZGlzcGxheSwgdGhlIHN0YXRlIG5lZWRzIHRvIGJlIGNoYW5nZWQgZnJvbSBhIGNoYXJhY3RlciB0byBhIGZhY3RvciBhbmQgb3JkZXJlZA0KICAjIyBOQiBtb3JlIHdvcmsgcmVxdWlyZWQNCiAgIGRmX2dhdGhlciRzdGF0ZSA8LQ0KICAgZmFjdG9yKGRmX2dhdGhlciRzdGF0ZSwgbGV2ZWxzID0gZGZfZ2F0aGVyJHN0YXRlW29yZGVyKGRmX2dhdGhlciR2YWx1ZSldKQ0KICANCiAgZGZfZ2F0aGVyDQogIA0KDQoNCg0KYGBgDQoNCldlIG5vdyBoYXZlIHRoZSBkZiBpbiBmb3JtYXQgcmVxdWlyZWQgZm9yIG91ciBmaXJzdCBjaGFydC4gQXMgSSBtZW50aW9uZWQgZWFybGllciwgSSB3YW50IHRvIHVzZSBqdXN0IG9uZSBhc3BlY3Qgb2YgdGhlIG11Y2ggd2lkZXIgcG90ZW50aWFsIG9mIHRoZSBbY3Jvc3N0YWxrIHBhY2thZ2VdKGh0dHA6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9jcm9zc3RhbGsvKS4gSSBhbnRpY2lwYXRlIHV0aWxpemluZyB0aGlzIG1vcmUgZnVsbHkgaW4gZnV0dXJlIHBvc3RzIGJ1dCBiZXdhcmUgdGhhdCBpdCBpcyBzdGlsbCBpbiBiZXRhDQoNCg0KDQpgYGB7ciBjaGFydCwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9ICANCg0KIyB0aGlzIGVuYWJsZXMgdGhlIGZpbHRlciB0byBpbnRlcmFjdCB3aXRoIGNoYXJ0IGFuZCwgbGF0ZXIsIG1hcA0Kc2QgPC0gU2hhcmVkRGF0YSRuZXcoZGZfZ2F0aGVyKQ0KDQoNCmZzIDwtIGZpbHRlcl9zZWxlY3QoDQppZCA9ICJjYXVzZSIsDQpsYWJlbCA9ICJDYXVzZSIsDQpzaGFyZWREYXRhID0gc2QsDQpncm91cCA9ICB+IGNhdXNlLA0KYWxsTGV2ZWxzID0gRkFMU0UsDQptdWx0aXBsZSA9IEZBTFNFDQopDQoNCiMjIHRoaXMgaXMgbmVlZGVkIGFzIGNyb3NzdGFsayBkb2VzIG5vdCB3b3JrIG5pY2VseSB3aXRoIGJvb3RzdHJhcCwgYXBwYXJlbnRseQ0KZnNfbm9ib290c3RyYXAgPC0gZnMNCg0KYXR0cihmc19ub2Jvb3RzdHJhcCwgImh0bWxfZGVwZW5kZW5jaWVzIikgPC0gRmlsdGVyKA0KICBmdW5jdGlvbihkZXApIHtkZXAkbmFtZSAhPSAiYm9vdHN0cmFwIn0sDQogIGF0dHIoZnNfbm9ib290c3RyYXAsICJodG1sX2RlcGVuZGVuY2llcyIpDQopDQoNCm15Q2hhcnQgPC0gc2QgJT4lDQogICMgbmVlZCB0byBzZXQgYSBsYXJnZXIgdGhhbiBkZWZhdWx0IGhlaWdodCB0byBlbmNvbXBhc3MgYWxsIHN0YXRlcw0KICBwbG90X2x5KA0KICAgIHggPSAgfiBudW1fZHJpdmVycywNCiAgICB5ID0gIH4gc3RhdGUsDQogICAgaGVpZ2h0ID0gODAwDQogICkgJT4lDQoNCiAgIyBmaXJzdCBwdXQgaW4gYWxsIGZhdGFsaXRpZXMNCiAgYWRkX2JhcnMoY29sb3IgPSBJKCIjZjJkZmE4IiksIG5hbWUgPSAiVG90YWwiLCB3aWR0aD0wLjgpICU+JQ0KICAjIHRoZW4gdGhvc2UgYWNjb3JkaW5nIHRvIGNhdXNlDQogIGFkZF9iYXJzKHdpZHRoPTAuMiwNCg0KICAgIHggPSAgfiB2YWx1ZSwNCiAgICB5ID0gIH4gc3RhdGUsDQogICAgY29sb3IgPSBJKCIjRjZCOTAwIiksDQogICAgbmFtZSA9ICJDYXVzZSIsDQogICAgaG92ZXJpbmZvPSJ0ZXh0IiwNCiAgICB0ZXh0PX5wYXN0ZTAocGMsIiUiKQ0KICApICU+JQ0KICAjIG1ha2UgaXQgYW4gb3ZlcmxheSBiYXJjaGFydCBhbmQgaW5wcm92ZSBsb29rDQogIGxheW91dCgNCiAgICBiYXJtb2RlID0gIm92ZXJsYXkiLA0KICAgIHRpdGxlID0gIkRyaXZlcnMgaW52b2x2ZWQgaW4gRmF0YWwgY29sbGlzaW9ucyBieSBTdGF0ZSAtIDIwMTIiLA0KICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJGYXRhbCBjb2xsaXNvbnMgcGVyIGJpbGxpb24gbWlsZXMiKSwNCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiIiksDQogICAgbWFyZ2luID0gbGlzdChsID0gMTIwKQ0KICApICU+JQ0KICBjb25maWcoZGlzcGxheU1vZGVCYXIgPSBGLCBzaG93TGluayA9IEYpDQoNCg0KIyMgY29tYmluZSB0aGUgc2VsZWN0b3IgYW5kIGNoYXJ0DQoNCiAgdGFnTGlzdCgNCiAgZnNfbm9ib290c3RyYXAsDQogICBteUNoYXJ0DQopDQoNCg0KYGBgDQoNCiAgICANClNvIHNvbWUgcHJvZ3Jlc3MuIFRoZXJlIGlzIG5vdyBhIG1vcmUgY29tcGFjdCBkaXNwbGF5ICB3aXRoIGFuIGluZm9hY3RpdmUgZWxlbWVudCBvbiBob3ZlciBhbmQgdGhlIHN0YXRlcyBhcmUgbm8gbG9uZ2VyIGluIGFscGhhYmV0aWNhbCBvcmRlciBidXQgbm90IGJ5IHJhdGUgZm9yIGluZGl2aWR1YWwgY2F1c2UuIEl0IHdvdWxkIGFsc28gYmUgdXNlZnVsIGlmIHRoZSBzZWxlY3RvciBzaG93ZWQgdGhlIGRlZmF1bHQNCg0KLS0tDQoNCiMjIEV4dGVuZA0KDQpOb3csIGhvdyBhYm91dCBleHRlbmRpbmcgdGhlIG9yaWdpbmFsIGFydGljbGUgd2l0aCBzb21lIG1hcHMuIFBsb3RseSBvZmZlcnMgYSBjaG9yb3BsZXRoIG9wdGlvbg0KDQpgYGB7ciBtYXBzLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0NCg0KDQptYXAgPC0gc2QgJT4lDQpwbG90X2x5KA0KdHlwZSA9ICJjaG9yb3BsZXRoIiwNCmxvY2F0aW9ucyA9ICB+IHN0YXRlSUQsDQpsb2NhdGlvbm1vZGUgPSAiVVNBLXN0YXRlcyIsDQp6ID0gIH4gdmFsdWUsDQpyZXZlcnNlc2NhbGUgPSBUUlVFDQopICU+JSBsYXlvdXQoZ2VvID0gbGlzdChzY29wZSA9ICJ1c2EiKSkNCg0KdGFnTGlzdCgNCiAgZnNfbm9ib290c3RyYXAsDQogIG1hcA0KKQ0KDQoNCg0KYGBgDQoNCkNvbWJpbmluZyB3b3VsZCBtYWtlIHNlbnNlIGFuZCBsZXQncyB0aHJvdyBpbiBhIHRhYmxlIGZvciBnb29kIG1lYXN1cmUuIElmIGdvaW5nIHRoaXMgcm91dGUsIGEgZGFzaGJvYXJkIG1pZ2h0IGJlIGEgbW9yZSBzZW5zaWJsZSBvcHRpb24NCg0KDQpgYGB7ciBjb21ibywgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVjaG89RkFMU0V9DQoNCiMgbXlUYWJsZSA8LXNkICU+JQ0KIyBEVDo6ZGF0YXRhYmxlKGNsYXNzPSdjb21wYWN0IHN0cmlwZSBob3ZlciByb3ctYm9yZGVyIG9yZGVyLWNvbHVtbicscm93bmFtZXM9RkFMU0Usb3B0aW9ucz0gbGlzdChwYWdpbmcgPSBUUlVFLCBzZWFyY2hpbmcgPSBUUlVFLGluZm89RkFMU0UpKQ0KDQpteVRhYmxlIDwtc2QgJT4lICMgbm8gaW1wcm92ZW1lbnQgLWRvZXMgYXBwZWFyIGluIHZpZXcgc291cmNlIGNsYXNzPSJkYXRhdGFibGVzIGh0bWwtd2lkZ2V0Ij4NCiAgZGF0YXRhYmxlKCkNCg0KDQp0YWdMaXN0KA0KICAgZnNfbm9ib290c3RyYXAsDQogICAgbXlUYWJsZSwgIyBzaG93cyBpbiBybWQgYnV0IG5vdCBpbiBicm93c2VyIHRob3VnaCB0aGVyZSBpcyAgYSBzcGFjZQ0KICAgDQogICBteUNoYXJ0LA0KICAgbWFwDQogIA0KKQ0KDQoNCmBgYA0KICAgIA0KDQoNCi0tLQ0KDQojIyBVcGRhdGUNCg0KSSBmb3VuZCBpdCBhIGRpZmZpY3VsdCB0byBsb2NhdGUgdGhlIHJhdyBkYXRhIHRoYXQgdGhlIGZpdmV0aGlydHllaWdodCBkYXRhc2V0IHdhcyBiYXNlZCBvbiBzbywgaW4gbGlldSBvZiB0aGF0IGFuZCBiZWNhdXNlIGl0IGlzIGEgZ29vZCBuZXdzIHN0b3J5LCBtYXBwZWQgdGhlIGNvbnNpZGVyYWJsZSByZWR1Y3Rpb24gaW4gZmF0YWxhdGllcyBwZXIgbWlsZXMgdHJhdmVsbGVkIG92ZXIgdGhlIHBhc3QgZm9ydHkgeWVhcnMNCg0KVGhlIE5IVFNBIGRhdGEgaXMgYXZhaWxhYmxlIGluIHRoZSBmb3JtIG9mIFtkb3dubG9hZGFibGUgcGRmc10oaHR0cHM6Ly9jcmFzaHN0YXRzLm5odHNhLmRvdC5nb3YvQXBpL1B1YmxpYy9WaWV3UHVibGljYXRpb24vODEyMjkzKS4gQSB5ZWFyIGFnbyB0aGlzIHdvdWxkIGhhdmUgYmVlbiBlbm91Z2ggZm9yIG1lIHRvIHNheSwgd2VsbCwgJ0Vub3VnaCc6IGJ1dCBhdCBsZWFzdCB0d28gcGFja2FnZXMgSSBhbSBhd2FyZSBvZiBbcGRmdG9vbHNdKGh0dHBzOi8vZ2l0aHViLmNvbS9yb3BlbnNjaS9wZGZ0b29scykgYW5kIFt0YWJ1bGl6ZXJdKGh0dHBzOi8vZ2l0aHViLmNvbS9yb3BlbnNjaS90YWJ1bGl6ZXIpIGF0dGVtcHQgdG8gYWRkcmVzcyB0aGUgcHJvYmxlbSBvZiBleHRyYWN0aW5nIGRhdGEgZnJvbSBwZGZzLg0KDQpIZXJlIEkgaGF2ZSB1c2VkIHRhYnVsaXplci4gRG93bmxvYWRpbmcgZGF0YSB0YWtlcyBhIGZldyBzZWNvbmRzDQoNCkJlY2F1c2UgdGhlcmUgaXMgYW4gaW50ZXJhY3RpdmUgZWxlbWVudCBpbnZvbHZlZCBpbiBzZXR0aW5nIHRoZSBwYXJ0IG9mIHRoZSBwYWdlIHRvIGNvbGxlY3QgdGhlIGRhdGEgZnJvbSwgSSBoYXZlIGNvbW1lbnRlZCBvdXQgdGhlIGluaXRpYWwgcHJvY2VzcyBhbmQgc3VwcGx5IHRoZSBjbGVhbmVyIGRhdGEgZnJvbSBhIGxvY2FsIGZpbGUNCg0KYGBge3IgbWFwX211bmdpbmcsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KDQoNCg0KIyAjIElkZWFsbHkgd2Ugd291bGQgdXNlIHRoZSBleHRyYWN0X3RhYmxlcyBmdW5jdGlvbiBidXQNCmNyYXNoX2RhdGEgPC0NCmV4dHJhY3RfdGFibGVzKA0KImh0dHBzOi8vY3Jhc2hzdGF0cy5uaHRzYS5kb3QuZ292L0FwaS9QdWJsaWMvVmlld1B1YmxpY2F0aW9uLzgxMjI5MyIsDQpwYWdlcyA9IDUsDQptZXRob2QgPSAiZGF0YS5mcmFtZSINCikNCmhlYWQoY3Jhc2hfZGF0YVtbMV1dKQ0KDQojTHVja2lseSB0aGVyZSBpcyBhbiBpbnRlcmFjdGl2ZSBvcHRpb24gd2hlcmUgYSByZWN0YW5nbGUgY2FuIGJlIGRyYXduIGFydG91bmQgdGhlIGRpc3BsYXllZCBpbWFnZS4gSSBrbm93IHdlIGp1c3Qgd2FudCB0aGUgZmlyc3QgNCBjb2x1bW5zDQojIEkgaGF2ZSB3cml0dGVuIGl0cyBvdXRwdXQgdG8gYSBmaWxlDQojICAgICAgICAgY3Jhc2hfZGF0YSA8LSAgICBleHRyYWN0X2FyZWFzKCJodHRwczovL2NyYXNoc3RhdHMubmh0c2EuZG90Lmdvdi9BcGkvUHVibGljL1ZpZXdQdWJsaWNhdGlvbi84MTIyOTMiLCBwYWdlcyA9IDUpDQoNCiMgZGYgPC0gZGF0YS5mcmFtZShjcmFzaF9kYXRhKQ0KIyBnbGltcHNlKGRmKQ0KIyBPYnNlcnZhdGlvbnM6IDUxDQojIFZhcmlhYmxlczogNQ0KIyAkIFgxIDxmY3RyPiBBbGFiYW1hICwgQWxhc2thICwgQXJpem9uYSAsIEFya2Fuc2FzICwgQ2FsaWZvcm5pYSAsIEMuLi4NCiMgJCBYMiA8ZmN0cj4gMy42MyAsIDQuMzggLCA0LjE5ICwgNC4wMSAsIDMuMDkgLCAzLjUwICwgMi4xMyAsIDMuMzcgLi4uDQojICQgWDMgPGZjdHI+IDEuOTIgLCAxLjQ1ICwgMS45NyAsIDIuMDUgLCAxLjMyICwgMS4yNiAsIDAuODggLCAxLjQwIC4uLg0KIyAkIFg0IDxmY3RyPiAxLjMxICwgMS4wNSAsIDEuNDAgLCAxLjQ5ICwgMC45NCAsIDEuMDMgLCAwLjkyICwgMS4wNiAuLi4NCiMgJCBYNSA8ZmN0cj4gMS4yNSwgMS41MCwgMS4yMywgMS4zNywgMC45MiwgMS4wMCwgMC44MCwgMS4yNiwgMC42NSwgLi4uDQoNCiMgd3JpdGVfY3N2KGRmLCIuLi8uLi9kYXRhL2NyYXNoX2RhdGExOTc1XzIwMTQuY3N2IikNCg0KIyBIZXJlIHdlIGdldCB0aGUgZGF0YSBiYWNrIGZyb20gdGhlIGxvY2FsIGZpbGUNCiMgVGhlIHBhY2thZ2UsIGNvcnJlY3RseSwgZ3VhZ2VzIHRoYXQgd2Ugd2FudCB0aGUgc3RhdGUgY29sdW1uIHRvIGJlDQojIG9mIGNsYXNzIGNoYXJhY3RlciB3aXRoIHRoZSByZXN0IG51bWVyaWMNCmRmIDwtIHJlYWRfY3N2KCJkYXRhL2NyYXNoX2RhdGExOTc1XzIwMTQuY3N2IikNCmdsaW1wc2UoZGYpDQojIGp1c3QgbmVlZCB0byBlbnRlciBtb3JlIGluZm9ybWF0aXZlIGNvbHVtbiBuYW1lcw0KbmFtZXMoZGYpIDwtIGMoJ3N0YXRlJywgJ3lyXzE5NzUnLCAneXJfMjAwNScsICd5cl8yMDEzJywgJ3lyXzIwMTQnKQ0KIyBhbmQgYWdhaW4gcHV0IGludG8gdGlkeSB2ZXJzaW9uIGFuZCBhZGQgc3RhdGUgYWJicmV2aWF0aW9ucw0KDQpkZl9nYXRoZXIgPC0gIGRmICU+JQ0KZ2F0aGVyKHllYXIsIHJhdGUsIC1zdGF0ZSkgJT4lDQpsZWZ0X2pvaW4oc3RhdGVzKQ0KDQpnbGltcHNlKGRmX2dhdGhlcikNCg0KYGBgDQoNCldlIGNhbiBub3cgbWFwIHRoZSBjaGFuZ2VzIG92ZXIgdGltZSBmb3IgdGhyZWUgeWVhcnMuICBOb3RlIHRoZSBrZXkgaW5wdXQgb2Ygem1pbiBhbmQgem1heCB3aGljaCBlbnN1cmVzIHNhbWUgY29sb3Igc2NhbGUgYXBwbGllcyB0byBhbGwgbWFwcw0KDQoNCg0KYGBge3IgbWFwX291dHB1dCwgd2FybmluZz0gRkFMU0UgLG1lc3NhZ2UgPSBGQUxTRX0NCg0KIyBsYXlvdXQgaW4gMyBjb2x1bW5zDQojYnNjb2xzKHdpZHRocz1jKDQsNCw0KSwNCm1hcF8xOTc1IDwtIGRmX2dhdGhlciAlPiUNCiAgZmlsdGVyKHllYXI9PSJ5cl8xOTc1IikgJT4lDQogICMgY3JlYXRlIGEgY2hvcm9wbGV0aCBtYXANCiAgcGxvdF9nZW8obG9jYXRpb25tb2RlPSJVU0Etc3RhdGVzIikgJT4lDQogIGFkZF90cmFjZSh6PX5yYXRlLCBjb2xvciA9IH5yYXRlLCBjb2xvcnMgPSAiUmVkcyIsDQogICAgICAgICAgICAjIGVuc3VyZSB0aGF0IGNvbG9yIHNjYWxlIGV4dGVuZHMgYmV5b25kIHRoZSB2YWx1ZXMgaW4gaW5kaXZpZHVhbCBtYXANCiAgICAgICAgICAgIHptaW49MCx6bWF4PTYsDQogICAgICAgICAgICBsb2NhdGlvbnMgPSB+c3RhdGVJRCwNCiAgICAgICAgICAgIHNob3dzY2FsZT1UUlVFKSAlPiUNCiAgbGF5b3V0KGdlbz1saXN0KHNjb3BlPSJ1c2EiKSwNCiAgICAgICAgIHRpdGxlPSIxOTc1IikgJT4lDQogIGNvbmZpZyhkaXNwbGF5TW9kZUJhciA9IEYsIHNob3dMaW5rID0gRikNCg0KbWFwXzIwMDUgPC0gZGZfZ2F0aGVyICU+JQ0KICBmaWx0ZXIoeWVhcj09InlyXzIwMDUiKSAlPiUNCiAgcGxvdF9nZW8obG9jYXRpb25tb2RlPSJVU0Etc3RhdGVzIikgJT4lDQogIGFkZF90cmFjZSh6PX5yYXRlLCBjb2xvciA9IH5yYXRlLCBjb2xvcnMgPSAiUmVkcyIsDQogICAgICAgICAgICB6bWluPTAsem1heD02LA0KICAgICAgICAgICAgbG9jYXRpb25zID0gfnN0YXRlSUQsDQogICAgICAgICAgICBzaG93c2NhbGU9VFJVRSkgJT4lDQogIGxheW91dChnZW89bGlzdChzY29wZT0idXNhIikgJT4lDQogICAgICAgICAgIGNvbmZpZyhkaXNwbGF5TW9kZUJhciA9IEYsIHNob3dMaW5rID0gRiksDQogICAgICAgICB0aXRsZT0iMjAwNSIpDQoNCm1hcF8yMDE0IDwtIGRmX2dhdGhlciAlPiUNCiAgZmlsdGVyKHllYXI9PSJ5cl8yMDE0IikgJT4lDQogIHBsb3RfZ2VvKGxvY2F0aW9ubW9kZT0iVVNBLXN0YXRlcyIpICU+JQ0KICBhZGRfdHJhY2Uoej1+cmF0ZSwgY29sb3IgPSB+cmF0ZSwgY29sb3JzID0gIlJlZHMiLA0KICAgICAgICAgICAgem1pbj0wLHptYXg9NiwNCiAgICAgICAgICAgIGxvY2F0aW9ucyA9IH5zdGF0ZUlELA0KICAgICAgICAgICAgIyBhZGQgYSBzY2FsZQ0KICAgICAgICAgICAgc2hvd3NjYWxlPVRSVUUpICU+JQ0KICBsYXlvdXQoZ2VvPWxpc3Qoc2NvcGU9InVzYSIpICU+JQ0KICAgICAgICAgICBjb25maWcoZGlzcGxheU1vZGVCYXIgPSBGLCBzaG93TGluayA9IEYpLA0KICAgICAgICAgdGl0bGU9IjIwMTQiKQ0KDQoNCnRhZ0xpc3QoDQogIG1hcF8xOTc1LA0KICBtYXBfMjAwNSwNCiAgbWFwXzIwMTQNCikNCg0KYGBgDQoNCiBJZGVhbGx5LCB0aGVzZSBtYXBzIHdvdWxkIGJlIHNpZGUgYnkgc2lkZSBidXQgdGhpcyBpcyBkaWZmaWN1bHQgd2l0aGluIGEgYmxvZyBmb3JtYXQuIFBsZWFzZSBub3RlIHRoYXQgdGhlcmUgaXMgYSBtdWNoDQogbGFyZ2VyIHRpbWUgZ2FwIGJldHdlZW4gdGhlIGZpcnN0IHR3byBtYXBzIHRoYW4gdGhlIGxhdHRlciB0d28uIEhvdmVyIGluZGl2aWR1YWwgc3RhdGVzIGFuZCB5b3UgY2FuIHNlZSB0aGF0IGJ5IDIwMDUgcHJldHR5ICB3ZWxsIGFsbCBzdGF0ZXMgaGFkIHRoZWlyIHJhdGUgYXMgbG93IHRoZSBiZXN0IHN0YXRlIHRoaXJ0eSB5ZWFycyBwcmlvcg0KDQotLS0gDQoNCiBMZXQncyB0cnkgb25lIG1hcCBzaG93aW5nICUgZGVjbGluZSBpbiByYXRlcyANCg0KYGBge3J9DQoNCmRmICU+JQ0KICBsZWZ0X2pvaW4oc3RhdGVzKSAlPiUNCiAgbXV0YXRlKGNoYW5nZSA9IHJvdW5kKDEwMCAqIHlyXzIwMTQgLyB5cl8xOTc1IC0gMTAwKSkgJT4lDQogIHBsb3RfZ2VvKGxvY2F0aW9ubW9kZSA9ICJVU0Etc3RhdGVzIikgJT4lDQogIGFkZF90cmFjZSgNCiAgeiA9ICB+IGNoYW5nZSwNCiAgY29sb3IgPSB+IGNoYW5nZSwNCiAgY29sb3JzID0gIkdyZWVucyIsDQogICMgem1pbj0wLHptYXg9NiwNCiAgbG9jYXRpb25zID0gfiBzdGF0ZUlELA0KICBzaG93c2NhbGUgPSBUUlVFLA0KICByZXZlcnNlc2NhbGUgPSBUUlVFDQogICkgJT4lDQogIGxheW91dCgNCiAgZ2VvID0gbGlzdChzY29wZSA9ICJ1c2EiKSAlPiUNCiAgY29uZmlnKGRpc3BsYXlNb2RlQmFyID0gRiwgc2hvd0xpbmsgPSBGKSwNCiAgdGl0bGUgPSAiJSBjaGFuZ2UgaW4gcmF0ZSBvZiBGYXRhbGl0aWVzIDE5NzUgdG8gMjAxNCINCiAgKSAlPiUNCiAgY29uZmlnKGRpc3BsYXlNb2RlQmFyID0gRiwgc2hvd0xpbmsgPSBGKQ0KDQpgYGANCg0KT2J2aW91c2x5LCB0aGVyZSBoYXMgYmVlbiBhIHNoYXJwIGRvd253YXJkIHRyZW5kIGluIGZhdGFsaXRpZXMgYW5kIGV2ZW4gaW4gYWJzb2x1dGUgdGVybXMsIGN1cnJlbnQgbGV2ZWxzIGFyZSBhIHRoaXJkIGxlc3MgdGhhbiB0aGUgW3BlYWsgb2YgMTk3Ml0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9tb3Rvcl92ZWhpY2xlX2RlYXRoc19pbl9VLlMuX2J5X3llYXIpDQoNCkNsZWFybHkgc2V2ZXJhbCBmYWN0b3JzLCBpbmNsdWRpbmcgYmV0dGVyIGNhcnMgYW5kIHJvYWRzLCBhd2FyZW5lc3MgYW5kIGxlZ2lzbGF0aW9uIHJlZ2FyZGluZyBhbGNvaG9sIGFuZCBkcnVncw0Kd2lsbCBoYXZlIHBsYXllZCBhIHBhcnQuIFRoZXJlIGlzIGEgaG9zdCBvZiBkYXRhIG9uIHRoZSBOSFRTQXNpdGUgdGhhdCBjb3VsZCBiZSB1c2VkIGZvciBmdXJ0aGVyIGFuYWx5c2VzDQoNCg==