#devtools::install_github("jbkunst/highcharter")
#install.packages("highcharter")
library(highcharter)
Highcharts (www.highcharts.com) is a Highsoft software product which is
not free for commercial and Governmental use

Attaching package: ‘highcharter’

The following object is masked _by_ ‘.GlobalEnv’:

    stars
data(citytemp)
hc <- highchart() %>% 
  hc_xAxis(categories = citytemp$month) %>% 
  hc_add_series(name = "Tokyo", data = citytemp$tokyo) %>% 
  hc_add_series(name = "London", data = citytemp$london) %>% 
  hc_add_series(name = "Other city",
                data = (citytemp$tokyo + citytemp$london)/2)
hc
library(magrittr)
library(highcharter)
highchart() %>% 
  hc_title(text = "Scatter chart with size and color") %>% 
  hc_add_series_scatter(mtcars$wt, mtcars$mpg,
                        mtcars$drat, mtcars$hp)
'hc_add_series_scatter' is deprecated.
Use 'hc_add_series' instead.
See help("Deprecated")
hc <- hc %>% 
  hc_chart(type = "column",
           options3d = list(enabled = TRUE, beta = 15, alpha = 15))
hc
hc %>% 
  hc_chart(borderColor = '#EBBA95',
           borderRadius = 10,
           borderWidth = 2,
           backgroundColor = list(
             linearGradient = c(0, 0, 500, 500),
             stops = list(
               list(0, 'rgb(255, 255, 255)'),
               list(1, 'rgb(200, 200, 255)')
             )))
hc <- highchart() %>% 
  hc_xAxis(categories = citytemp$month) %>% 
  hc_add_series(name = "Tokyo", data = citytemp$tokyo) %>% 
  hc_add_series(name = "New York", data = citytemp$new_york) 
hc 
hc %>% 
  hc_add_series(name = "London", data = citytemp$london, type = "area") %>% 
  hc_rm_series(name = "New York")
hc %>% 
  hc_title(text = "This is a title with <i>margin</i> and <b>Strong or bold text</b>",
           margin = 20, align = "left",
           style = list(color = "#90ed7d", useHTML = TRUE)) %>% 
  hc_subtitle(text = "And this is a subtitle with more information",
              align = "left",
              style = list(color = "#2b908f", fontWeight = "bold")) %>% 
  hc_credits(enabled = TRUE, # add credits
             text = "www.lonk.tomy.site",
             href = "http://jkunst.com") %>% 
  hc_legend(align = "left", verticalAlign = "top",
            layout = "vertical", x = 0, y = 100) %>%
  hc_tooltip(crosshairs = TRUE, backgroundColor = "#FCFFC5",
             shared = TRUE, borderWidth = 5) %>% 
  hc_exporting(enabled = TRUE) # enable exporting option
data(diamonds, economics_long, mpg, package = "ggplot2")
library(dplyr)
package ‘dplyr’ was built under R version 3.4.1
Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
hchart(mpg, "scatter", hcaes(x = displ, y = hwy, group = class))
mpgman2 <- mpg %>% 
  count(class, year) %>% 
  glimpse()
Observations: 14
Variables: 3
$ class <chr> "2seater", "2seater", "compact", "compact", "midsize",...
$ year  <int> 1999, 2008, 1999, 2008, 1999, 2008, 1999, 2008, 1999, ...
$ n     <int> 2, 3, 25, 22, 20, 21, 6, 5, 16, 17, 19, 16, 29, 33
## Observations: 14
## Variables: 3
## $ class <chr> "2seater", "2seater", "compact", "compact", "midsize", "...
## $ year  <int> 1999, 2008, 1999, 2008, 1999, 2008, 1999, 2008, 1999, 20...
## $ n     <int> 2, 3, 25, 22, 20, 21, 6, 5, 16, 17, 19, 16, 29, 33
hchart(mpgman2, "column", hcaes(x = class, y = n, group = year))
mpgman3 <- mpg %>% 
  group_by(manufacturer) %>% 
  summarise(n = n(), unique = length(unique(model))) %>% 
  arrange(-n, -unique) %>% 
  glimpse()
Observations: 15
Variables: 3
$ manufacturer <chr> "dodge", "toyota", "volkswagen", "ford", "chevr...
$ n            <int> 37, 34, 27, 25, 19, 18, 14, 14, 13, 9, 8, 5, 4,...
$ unique       <int> 4, 6, 4, 4, 4, 3, 2, 2, 3, 1, 1, 1, 1, 1, 1
## Observations: 15
## Variables: 3
## $ manufacturer <chr> "dodge", "toyota", "volkswagen", "ford", "chevrol...
## $ n            <int> 37, 34, 27, 25, 19, 18, 14, 14, 13, 9, 8, 5, 4, 4, 3
## $ unique       <int> 4, 6, 4, 4, 4, 3, 2, 2, 3, 1, 1, 1, 1, 1, 1
hchart(mpgman3, "treemap", hcaes(x = manufacturer, value = n, color = unique))
economics_long2 <- economics_long %>% 
  filter(variable %in% c("pop", "uempmed", "unemploy")) %>% 
  print()
## Source: local data frame [1,722 x 4]
## Groups: variable [3]
## 
##          date variable  value     value01
##        <date>   <fctr>  <dbl>       <dbl>
## 1  1967-07-01      pop 198712 0.000000000
## 2  1967-08-01      pop 198911 0.001628811
## 3  1967-09-01      pop 199113 0.003282177
## 4  1967-10-01      pop 199311 0.004902803
## 5  1967-11-01      pop 199498 0.006433395
## 6  1967-12-01      pop 199657 0.007734807
## 7  1968-01-01      pop 199808 0.008970739
## 8  1968-02-01      pop 199920 0.009887457
## 9  1968-03-01      pop 200056 0.011000614
## 10 1968-04-01      pop 200208 0.012244731
## # ... with 1,712 more rows
hchart(economics_long2, "line", hcaes(x = date, y = value01, group = variable))
hchart(diamonds$price) 
hchart(density(diamonds$price), type = "area", color = "#B71C1C", name = "Price")
hchart(diamonds$cut, type = "column")
hchart(LakeHuron)

Time Series

x <- stl(log(AirPassengers), "per")
hchart(x)

library("forecast")
x <- forecast(ets(USAccDeaths), h = 48, level = 95)
hchart(x)

igraph

library("igraph")
package ‘igraph’ was built under R version 3.4.1
Attaching package: ‘igraph’

The following objects are masked from ‘package:dplyr’:

    as_data_frame, groups, union

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
N <- 40
net <- sample_gnp(N, p = 2/N)
wc <- cluster_walktrap(net)
V(net)$label <- seq(N)
V(net)$name <- paste("I'm #", seq(N))
V(net)$page_rank <- round(page.rank(net)$vector, 2)
V(net)$betweenness <- round(betweenness(net), 2)
V(net)$degree <- degree(net)
V(net)$size <- V(net)$degree
V(net)$comm <- membership(wc)
V(net)$color <- colorize(membership(wc))
hchart(net, layout = layout_with_fr)

xts from quantmod package

library(quantmod)
package ‘quantmod’ was built under R version 3.4.1Loading required package: xts
package ‘xts’ was built under R version 3.4.1Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric


Attaching package: ‘xts’

The following objects are masked from ‘package:dplyr’:

    first, last

Loading required package: TTR
package ‘TTR’ was built under R version 3.4.1Version 0.4-0 included new data defaults. See ?getSymbols.
Learn from a quantmod author: https://www.datacamp.com/courses/importing-and-managing-financial-data-in-r
x <- getSymbols("USD/JPY", src = "oanda", auto.assign = FALSE)
‘getSymbols’ currently uses auto.assign=TRUE by default, but will
use auto.assign=FALSE in 0.5-0. You will still be able to use
‘loadSymbols’ to automatically load data. getOption("getSymbols.env")
and getOption("getSymbols.auto.assign") will still be checked for
alternate defaults.

This message is shown once per session and may be disabled by setting 
options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
hchart(x)

The shares of what used to be known as Yahoo under the ticker symbol YHOO started trading Monday as Altaba (think alternative Alibaba) and trade under the symbol AABA.

x <- getSymbols("AABA", auto.assign = FALSE)

WARNING: There have been significant changes to Yahoo Finance data.
Please see the Warning section of ‘?getSymbols.yahoo’ for details.

This message is shown once per session and may be disabled by setting
options("getSymbols.yahoo.warning"=FALSE).
hchart(x)
x <- acf(diff(AirPassengers), plot = FALSE)
hchart(x)
x <- cbind(mdeaths, fdeaths)
hchart(x)
Survival Models
library(survival)

Attaching package: ‘survival’

The following object is masked _by_ ‘.GlobalEnv’:

    lung

The following object is masked from ‘package:deepboost’:

    heart
data(lung)
lung <- mutate(lung, sex = ifelse(sex == 1, "Male", "Female"))
fit <- survfit(Surv(time, status) ~ sex, data = lung) 
hchart(fit, ranges = TRUE)

Principal Components

hchart(princomp(USArrests, cor = TRUE))
Matrix
data(volcano)
hchart(volcano) %>% 
  # changing default color
  hc_colorAxis(stops = color_stops(colors = viridis::inferno(10)))

Distance matrix

mtcars2 <- mtcars[1:20, ]
x <- dist(mtcars2)
hchart(x)

Correlation matrix

hchart(cor(mtcars))
Stars Wars

A better version (in a syntax way) than http://jkunst.com/r/presenting-highcharter/.

#install.packages("rwars")
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
package ‘tibble’ was built under R version 3.4.1package ‘tidyr’ was built under R version 3.4.1Conflicts with tidy packages --------------------------------------------
as_data_frame(): dplyr, tibble, igraph
compose():       purrr, igraph
crossing():      tidyr, igraph
filter():        dplyr, stats
first():         dplyr, xts
groups():        dplyr, igraph
lag():           dplyr, stats
last():          dplyr, xts
simplify():      purrr, igraph
library(rwars)
swmovies <- get_all_films()
swdata <- map_df(swmovies$results, function(x){
  data_frame(
    movie = x$title,
    species = length(x$species),
    planets = length(x$planets),
    characters = length(x$characters),
    vehicles = length(x$vehicles),
    release = x$release_date
  )
}) 
swdata <- gather(swdata, key, number, -movie, -release) %>% 
  arrange(release)
swdata
## # A tibble: 28 × 4
##                      movie    release        key number
##                      <chr>      <chr>      <chr>  <int>
## 1               A New Hope 1977-05-25    species      5
## 2               A New Hope 1977-05-25    planets      3
## 3               A New Hope 1977-05-25 characters     18
## 4               A New Hope 1977-05-25   vehicles      4
## 5  The Empire Strikes Back 1980-05-17    species      5
## 6  The Empire Strikes Back 1980-05-17    planets      4
## 7  The Empire Strikes Back 1980-05-17 characters     16
## 8  The Empire Strikes Back 1980-05-17   vehicles      6
## 9       Return of the Jedi 1983-05-25    species      9
## 10      Return of the Jedi 1983-05-25    planets      5
## # ... with 18 more rows
hchart(swdata, "line", hcaes(x = movie, y = number, group = key),
       color = c("#e5b13a", "#4bd5ee", "#4AA942", "#FAFAFA")) %>% 
  hc_title(
    text = "Diversity in <span style=\"color:#e5b13a\"> STAR WARS</span> movies",
    useHTML = TRUE) %>% 
  hc_tooltip(table = TRUE, sort = TRUE) %>% 
  hc_credits(
    enabled = TRUE,
    text = "Source: SWAPI via rwars package",
    href = "https://swapi.co/") %>% 
  hc_add_theme(
    hc_theme_flatdark(
      chart = list(
        backgroundColor = "transparent",
        divBackgroundImage = "http://www.wired.com/images_blogs/underwire/2013/02/xwing-bg.gif"
      )
    )
  )
data(stars)
colors <- c("#FB1108","#FD150B","#FA7806","#FBE426","#FCFB8F",
            "#F3F5E7", "#C7E4EA","#ABD6E6","#9AD2E1")
stars$color <- colorize(log(stars$temp), colors)
x <- c("Luminosity", "Temperature", "Distance")
y <- sprintf("{point.%s:.2f}", c("lum", "temp", "distance"))
tltip <- tooltip_table(x, y)
hchart(stars, "scatter", hcaes(temp, lum, size = radiussun, color = color)) %>% 
  hc_chart(backgroundColor = "black") %>% 
  hc_xAxis(type = "logarithmic", reversed = TRUE) %>% 
  hc_yAxis(type = "logarithmic", gridLineWidth = 0) %>% 
  hc_title(text = "Our nearest Stars") %>% 
  hc_subtitle(text = "In a Hertzsprung-Russell diagram") %>% 
  hc_tooltip(useHTML = TRUE, headerFormat = "", pointFormat = tltip) %>% 
  hc_size(height = 600)

Global temperatures

data("globaltemp")
x <- c("Min", "Median", "Max")
y <- sprintf("{point.%s}", c("lower", "median", "upper"))
tltip <- tooltip_table(x, y)
hchart(globaltemp, type = "columnrange",
       hcaes(x = date, low = lower, high = upper, color = median)) %>% 
  hc_yAxis(tickPositions = c(-2, 0, 1.5, 2),
           gridLineColor = "#B71C1C",
           labels = list(format = "{value} C", useHTML = TRUE)) %>% 
  hc_tooltip(
    useHTML = TRUE,
    headerFormat = as.character(tags$small("{point.x: %Y %b}")),
    pointFormat = tltip
  ) %>% 
  hc_add_theme(hc_theme_db())

Weathers Radials

From here and replicated in http://jkunst.com/r/how-to-weather-radials/

data("weather")
x <- c("Min", "Mean", "Max")
y <- sprintf("{point.%s}", c("min_temperaturec", "mean_temperaturec", "max_temperaturec"))
tltip <- tooltip_table(x, y)
hchart(weather, type = "columnrange",
       hcaes(x = date, low = min_temperaturec, high = max_temperaturec,
             color = mean_temperaturec)) %>% 
  hc_chart(polar = TRUE) %>%
  hc_yAxis( max = 30, min = -10, labels = list(format = "{value} C"),
            showFirstLabel = FALSE) %>% 
  hc_xAxis(
    title = list(text = ""), gridLineWidth = 0.5,
    labels = list(format = "{value: %b}")) %>% 
  hc_tooltip(useHTML = TRUE, pointFormat = tltip,
             headerFormat = as.character(tags$small("{point.x:%d %B, %Y}")))
The Impact of Vaccines

heatmap

From WSJ graphic: Battling Infectious Diseases in the 20th Century:

data("vaccines")
library("viridis")
Loading required package: viridisLite
fntltp <- JS("function(){
  return this.point.x + ' ' +  this.series.yAxis.categories[this.point.y] + ':<br>' +
  Highcharts.numberFormat(this.point.value, 2);
}")
plotline <- list(
  color = "#fde725", value = 1963, width = 2, zIndex = 5,
  label = list(
    text = "Vaccine Intoduced", verticalAlign = "top",
    style = list(color = "#606060"), textAlign = "left",
    rotation = 0, y = -5)
)
hchart(vaccines, "heatmap", hcaes(x = year, y = state, value = count)) %>% 
  hc_colorAxis(stops = color_stops(10, rev(inferno(10))),
               type = "logarithmic") %>% 
  hc_yAxis(reversed = TRUE, offset = -20, tickLength = 0,
           gridLineWidth = 0, minorGridLineWidth = 0,
           labels = list(style = list(fontSize = "8px"))) %>% 
  hc_tooltip(formatter = fntltp) %>% 
  hc_xAxis(plotLines = list(plotline)) %>%
  hc_title(text = "Infectious Diseases and Vaccines") %>% 
  hc_legend(layout = "vertical", verticalAlign = "top",
            align = "right", valueDecimals = 0) %>% 
  hc_size(height = 800)
Boxplot
data(diamonds, package = "ggplot2")
hcboxplot(x = diamonds$x, var = diamonds$color,
          name = "Length", color = "#2980b9") 
hcboxplot(x = diamonds$x, var = diamonds$color, var2 = diamonds$cut,
          outliers = FALSE) %>% 
  hc_chart(type = "column") # to put box vertical

Parallel Coordinates

require(viridisLite)
n <- 15
#hcparcords(head(mtcars, n), color = hex_to_rgba(magma(n), 0.5))

Icon Arrays

set.seed(123)
icons <- c("motorcycle", "taxi", "bus", "plane")
n <- sample(3:10, length(icons)) %>% 
  sort(decreasing = TRUE) %>% 
  {. *  seq(length(icons), 1) } 
hciconarray(icons, n, icons = icons, size = 5)

Treemaps

Here we use the treemap package to create a treemap object and then we create the same treemap via highcharts ;).

library(treemap)
library(viridisLite)
data(GNI2014)
GNI2014%>%head()
#install.packages("treemap")
library(treemap)
library(viridisLite)
data(GNI2014)
tm <- treemap(GNI2014, index = c("continent", "iso3"),
              vSize = "population", vColor = "GNI",
              type = "value", palette = viridis(6))

hctreemap(tm)

Themes

hc <- highcharts_demo()
hc

hc %>% hc_add_theme(hc_theme_538())

hc %>% hc_add_theme(hc_theme_economist())

hc %>% hc_add_theme(hc_theme_ft())

hc %>% hc_add_theme(hc_theme_db())

hc %>% hc_add_theme(hc_theme_flat())

hc %>% hc_add_theme(hc_theme_flatdark())

hc %>% hc_add_theme(hc_theme_smpl())

hc %>% hc_add_theme(hc_theme_elementary())

hc %>% hc_add_theme(hc_theme_google())

hc %>% hc_add_theme(hc_theme_ffx())

hc %>% hc_add_theme(hc_theme_monokai())

hc %>% hc_add_theme(hc_theme_gridlight())

hc %>% hc_add_theme(hc_theme_sandsignika())

hc %>% hc_add_theme(hc_theme_darkunica())

hc %>% hc_add_theme(hc_theme_chalk())

hc %>% hc_add_theme(hc_theme_handdrawn())

hc %>% hc_add_theme(hc_theme_null())
n <- 15
dta <- dplyr::data_frame(
  x = rnorm(n),
  y = 1.5 * x + rnorm(n))
highchart() %>%
  hc_chart(type = "scatter") %>% 
  hc_add_series(data = list_parse(dta)) %>% 
  hc_add_theme(hc_theme_tufte())

values <- 1 + abs(rnorm(12))
highchart() %>%
  hc_chart(type = "column") %>%
  hc_add_series(data = values) %>%
  hc_xAxis(categories = month.abb) %>%
  hc_add_theme(hc_theme_tufte2())

# You can test:
# hc %>% hc_add_theme(hc_theme_sparkline())
data(economics_long, package = "ggplot2")
library(dplyr)
economics_long %>%
  group_by(variable) %>%
  do(spark = hcts(.$value, type = "area",
                  name = first(.$variable), showInLegend = FALSE) %>%
       hc_add_theme(hc_theme_sparkline())) %>% 
  .[["spark"]] %>% 
  as.list() %>% 
  hw_grid(rowheight = 100)
thm <- hc_theme(
  colors = c('red', 'green', 'blue'),
  chart = list(
    backgroundColor = NULL,
    divBackgroundImage = "http://media3.giphy.com/media/FzxkWdiYp5YFW/giphy.gif"
  ),
  title = list(
    style = list(
      color = '#333333',
      fontFamily = "Lato"
    )
  ),
  subtitle = list(
    style = list(
      color = '#666666',
      fontFamily = "Shadows Into Light"
    )
  ),
  legend = list(
    itemStyle = list(
      fontFamily = 'Tangerine',
      color = 'black'
    ),
    itemHoverStyle = list(
      color = 'gray'
    )   
  )
)
hc %>% hc_add_theme(thm)
thm <- hc_theme_merge(
  hc_theme_darkunica(),
  hc_theme(
    chart = list(
      backgroundColor = "transparent",
      divBackgroundImage = "http://cdn.wall-pix.net/albums/art-3Dview/00025095.jpg"
    ),
    title = list(
      style = list(
        color = 'white',
        fontFamily = "Open Sans"
      )
    )
  )
)
hc %>% hc_add_theme(thm)

Highstock

Basics · Candlestick and OHLC charts · Time series · Flags · A More Interesting Example Basics Highstock work well with the quantmod package. It’s easy chart symbols. And then you can add more series using hc_add_series (see below).

library("quantmod")
x <- getSymbols("GOOG", auto.assign = FALSE)
hchart(x)

Candlestick and OHLC charts If you want to chart more symbols in you can use the hc_add_series function.

x <- getSymbols("GOOG", auto.assign = FALSE)
y <- getSymbols("AMZN", auto.assign = FALSE)
highchart(type = "stock") %>% 
  hc_add_series(x) %>% 
  hc_add_series(y, type = "ohlc")

Time series

library("quantmod")
usdjpy <- getSymbols("USD/JPY", src = "oanda", auto.assign = FALSE)
eurkpw <- getSymbols("EUR/KPW", src = "oanda", auto.assign = FALSE)
hc <- highchart(type = "stock") %>% 
  hc_title(text = "Charting some Symbols") %>% 
  hc_subtitle(text = "Data extracted using quantmod package") %>% 
  hc_add_series(usdjpy, id = "usdjpy") %>% 
  hc_add_series(eurkpw, id = "eurkpw")
hc

Flags

Previously we used the id parameter. This is necessary to add flags:

library(dplyr)
set.seed(123)
data_flags <- data_frame(
  date = sample(time(usdjpy), size = 5),
  title = sprintf("E #%s", seq_along(date)),
  text = sprintf("An interesting event #%s in %s", seq_along(date), date)
)
glimpse(data_flags)
Observations: 5
Variables: 3
$ date  <date> 2017-04-28, 2017-07-27, 2017-05-19, 2017-08-11, 2017-...
$ title <chr> "E #1", "E #2", "E #3", "E #4", "E #5"
$ text  <chr> "An interesting event #1 in 2017-04-28", "An interesti...
## Observations: 5
## Variables: 3
## $ date  <date> 2016-02-06, 2016-10-12, 2016-04-06, 2016-11-26, 2016-12-24
## $ title <chr> "E #1", "E #2", "E #3", "E #4", "E #5"
## $ text  <chr> "An interesting event #1 in 2016-02-06", "An interesting...
hc %>% 
  hc_add_series(data_flags, hcaes(x = date),
                type = "flags", onSeries = "usdjpy")
SPY <- getSymbols("SPY", from = Sys.Date() - lubridate::years(1), auto.assign = FALSE)
SPY <- adjustOHLC(SPY)
SPY.SMA.10 <- SMA(Cl(SPY), n = 5)
SPY.SMA.200 <- SMA(Cl(SPY), n = 100)
SPY.RSI.14 <- RSI(Cl(SPY))
SPY.RSI.SellLevel <- xts(rep(70, NROW(SPY)), index(SPY))
SPY.RSI.BuyLevel <- xts(rep(30, NROW(SPY)), index(SPY))
highchart(type = "stock") %>% 
  # create axis :)
  hc_yAxis_multiples(
    create_yaxis(3, height = c(2, 1, 1), turnopposite = TRUE)
  ) %>% 
  # series :D
  hc_add_series(SPY, yAxis = 0, name = "SPY") %>% 
  hc_add_series(SPY.SMA.10, yAxis = 0, name = "Fast MA") %>% 
  hc_add_series(SPY.SMA.200, yAxis = 0, name = "Slow MA") %>% 
  hc_add_series(SPY$SPY.Volume, color = "gray", yAxis = 1, name = "Volume", type = "column") %>% 
  hc_add_series(SPY.RSI.14, yAxis = 2, name = "Osciallator", color = hex_to_rgba("green", 0.7)) %>%
  hc_add_series(SPY.RSI.SellLevel, color = hex_to_rgba("red", 0.7),
                yAxis = 2, name = "Sell level") %>% 
  hc_add_series(SPY.RSI.BuyLevel, color = hex_to_rgba("blue", 0.7),
                yAxis = 2, name = "Buy level") 

Highmaps

Basics · Choropleths · Adding More Data · Advanced Maps · Motion Plugin · geojsonio Package Basics The easiest way to chart a map with highcharter is using hcmap function. Select a map (a url) from the highmaps collection https://code.highcharts.com/mapdata/. and use the url as a map in hcmap function. This will download the map and create a object using the info as a mapData argument.

Choropleths

What about add data to get a choropleth? Every map downloaded from the highcharts maps collection have keys to join data. There are 2 functions to help to know what are the regions coded to know how to join the map and data:

download_map_data: Download the geojson data from the highcharts collection. get_data_from_map: Get the properties for each region in the map, as the keys from the map data.

library(dplyr)
mapdata <- get_data_from_map(download_map_data("countries/us/us-all"))
trying URL 'https://code.highcharts.com/mapdata/countries/us/us-all.js'
Content type 'application/x-javascript' length 66923 bytes (65 KB)
==================================================
downloaded 65 KB
glimpse(mapdata)
Observations: 52
Variables: 19
$ `hc-group`    <chr> "admin1", "admin1", "admin1", "admin1", "admin...
$ `hc-middle-x` <dbl> 0.36, 0.56, 0.51, 0.47, 0.41, 0.43, 0.71, 0.46...
$ `hc-middle-y` <dbl> 0.47, 0.52, 0.67, 0.52, 0.38, 0.40, 0.67, 0.38...
$ `hc-key`      <chr> "us-ma", "us-wa", "us-ca", "us-or", "us-wi", "...
$ `hc-a2`       <chr> "MA", "WA", "CA", "OR", "WI", "ME", "MI", "NV"...
$ labelrank     <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "...
$ hasc          <chr> "US.MA", "US.WA", "US.CA", "US.OR", "US.WI", "...
$ `woe-id`      <chr> "2347580", "2347606", "2347563", "2347596", "2...
$ `state-fips`  <chr> "25", "53", "6", "41", "55", "23", "26", "32",...
$ fips          <chr> "US25", "US53", "US06", "US41", "US55", "US23"...
$ `postal-code` <chr> "MA", "WA", "CA", "OR", "WI", "ME", "MI", "NV"...
$ name          <chr> "Massachusetts", "Washington", "California", "...
$ country       <chr> "United States of America", "United States of ...
$ region        <chr> "Northeast", "West", "West", "West", "Midwest"...
$ longitude     <chr> "-71.99930000000001", "-120.361", "-119.591", ...
$ `woe-name`    <chr> "Massachusetts", "Washington", "California", "...
$ latitude      <chr> "42.3739", "47.4865", "36.7496", "43.8333", "4...
$ `woe-label`   <chr> "Massachusetts, US, United States", "Washingto...
$ type          <chr> "State", "State", "State", "State", "State", "...
## Observations: 52
## Variables: 19
## $ hc-group    <chr> "admin1", "admin1", "admin1", "admin1", "admin1", ...
## $ hc-middle-x <dbl> 0.36, 0.56, 0.51, 0.47, 0.41, 0.43, 0.71, 0.46, 0....
## $ hc-middle-y <dbl> 0.47, 0.52, 0.67, 0.52, 0.38, 0.40, 0.67, 0.38, 0....
## $ hc-key      <chr> "us-ma", "us-wa", "us-ca", "us-or", "us-wi", "us-m...
## $ hc-a2       <chr> "MA", "WA", "CA", "OR", "WI", "ME", "MI", "NV", "N...
## $ labelrank   <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", ...
## $ hasc        <chr> "US.MA", "US.WA", "US.CA", "US.OR", "US.WI", "US.M...
## $ woe-id      <chr> "2347580", "2347606", "2347563", "2347596", "23476...
## $ state-fips  <chr> "25", "53", "6", "41", "55", "23", "26", "32", "35...
## $ fips        <chr> "US25", "US53", "US06", "US41", "US55", "US23", "U...
## $ postal-code <chr> "MA", "WA", "CA", "OR", "WI", "ME", "MI", "NV", "N...
## $ name        <chr> "Massachusetts", "Washington", "California", "Oreg...
## $ country     <chr> "United States of America", "United States of Amer...
## $ region      <chr> "Northeast", "West", "West", "West", "Midwest", "N...
## $ longitude   <chr> "-71.99930000000001", "-120.361", "-119.591", "-12...
## $ woe-name    <chr> "Massachusetts", "Washington", "California", "Oreg...
## $ latitude    <chr> "42.3739", "47.4865", "36.7496", "43.8333", "44.37...
## $ woe-label   <chr> "Massachusetts, US, United States", "Washington, U...
## $ type        <chr> "State", "State", "State", "State", "State", "Stat...
set.seed(1234)
data_fake <- mapdata %>% 
  select(code = `hc-a2`) %>% 
  mutate(value = 1e5 * abs(rt(nrow(.), df = 10)))
glimpse(data_fake)
Observations: 52
Variables: 2
$ code  <chr> "MA", "WA", "CA", "OR", "WI", "ME", "MI", "NV", "NM", ...
$ value <dbl> 119426.518, 255662.317, 3668.575, 122246.930, 79283.06...
## Observations: 52
## Variables: 2
## $ code  <chr> "MA", "WA", "CA", "OR", "WI", "ME", "MI", "NV", "NM", "C...
## $ value <dbl> 119426.518, 255662.317, 3668.575, 122246.930, 79283.064,...
hcmap("countries/us/us-all", data = data_fake, value = "value",
      joinBy = c("hc-a2", "code"), name = "Fake data",
      dataLabels = list(enabled = TRUE, format = '{point.name}'),
      borderColor = "#FAFAFA", borderWidth = 0.1,
      tooltip = list(valueDecimals = 2, valuePrefix = "$", valueSuffix = " USD"))
trying URL 'https://code.highcharts.com/mapdata/countries/us/us-all.js'
Content type 'application/x-javascript' length 66923 bytes (65 KB)
==================================================
downloaded 65 KB
library(highcharter)
library(dplyr)
library(purrr)
set.seed(1234)
n <- 20
z <-  sample(1:n)
sequences <- map2(1:n, z, function(x, y){ ifelse(x == 1:n, y, 0) })
df <- data_frame(
  lat = runif(n, -180, 180),
  lon = runif(n, -180, 180),
  z = z,
  color = colorize(z),
  sequence = sequences
)
hcmap() %>% 
  hc_add_series(data = df, type = "mapbubble",
                minSize = 0, maxSize = 30) %>% 
  hc_motion(enabled = TRUE, series = 1, labels = 1:n,
            loop = TRUE, autoPlay = TRUE, 
            updateInterval = 1000, magnet = list(step =  1)) %>% 
  hc_plotOptions(series = list(showInLegend = FALSE))
trying URL 'https://code.highcharts.com/mapdata/custom/world.js'
Content type 'application/x-javascript' length 190328 bytes (185 KB)
==================================================
downloaded 185 KB
hcmap("countries/us/us-ca-all") %>%
  hc_title(text = "California")
trying URL 'https://code.highcharts.com/mapdata/countries/us/us-ca-all.js'
Content type 'application/x-javascript' length 40824 bytes (39 KB)
==================================================
downloaded 39 KB

hcmap("custom/usa-and-canada", showInLegend = FALSE)
trying URL 'https://code.highcharts.com/mapdata/custom/usa-and-canada.js'
Content type 'application/x-javascript' length 134466 bytes (131 KB)
==================================================
downloaded 131 KB

hcmap("countries/nz/nz-all")
trying URL 'https://code.highcharts.com/mapdata/countries/nz/nz-all.js'
Content type 'application/x-javascript' length 36810 bytes (35 KB)
==================================================
downloaded 35 KB
highchart() %>% 
  hc_chart(type = "column") %>% 
  hc_yAxis(max = 6, min = 0) %>% 
  hc_add_series(name = "A", data = c(2,3,4), zIndex = -10) %>% 
  hc_add_series(name = "B",
                data = list(
                  list(sequence = c(1,2,3,4)),
                  list(sequence = c(3,2,1,3)),
                  list(sequence = c(2,5,4,3))
                )) %>% 
  hc_add_series(name = "C",
                data = list(
                  list(sequence = c(3,2,1,3)),
                  list(sequence = c(2,5,4,3)),
                  list(sequence = c(1,2,3,4))
                )) %>% 
  hc_motion(enabled = TRUE,
            labels = 2000:2003,
            series = c(1,2))
install.packages("idbr")
Installing package into ‘/Users/nanaakwasiabayieboateng/Library/R/3.4/library’
(as ‘lib’ is unspecified)
also installing the dependency ‘countrycode’

trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.4/countrycode_0.19.tgz'
Content type 'application/x-gzip' length 47143 bytes (46 KB)
==================================================
downloaded 46 KB

trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.4/idbr_0.2.tgz'
Content type 'application/x-gzip' length 27358 bytes (26 KB)
==================================================
downloaded 26 KB

The downloaded binary packages are in
    /var/folders/mj/w1gxzjcd0qx2cw_0690z7y640000gn/T//RtmpNTeDp4/downloaded_packages
library("idbr")
library("purrr")
library("dplyr")
idb_api_key("35f116582d5a89d11a47c7ffbfc2ba309133f09d")
yrs <-  seq(1980, 2030, by = 5)
df <- map_df(c("male", "female"), function(sex){
  mutate(idb1("US", yrs, sex = sex), sex_label = sex)
})
names(df) <- tolower(names(df))
df <- df %>%
  mutate(population = pop*ifelse(sex_label == "male", -1, 1))
series <- df %>% 
  group_by(sex_label, age) %>% 
  do(data = list(sequence = .$population)) %>% 
  ungroup() %>% 
  group_by(sex_label) %>% 
  do(data = .$data) %>%
  mutate(name = sex_label) %>% 
  list_parse()
maxpop <- max(abs(df$population))
xaxis <- list(categories = sort(unique(df$age)),
              reversed = FALSE, tickInterval = 5,
              labels = list(step = 5))
highchart() %>%
  hc_chart(type = "bar") %>%
  hc_motion(enabled = TRUE, labels = yrs, series = c(0,1), autoplay = TRUE, updateInterval = 1) %>% 
  hc_add_series_list(series) %>% 
  hc_plotOptions(
    series = list(stacking = "normal"),
    bar = list(groupPadding = 0, pointPadding =  0, borderWidth = 0)
  ) %>% 
  hc_tooltip(shared = TRUE) %>% 
  hc_yAxis(
    labels = list(
      formatter = JS("function(){ return Math.abs(this.value) / 1000000 + 'M'; }") 
    ),
    tickInterval = 0.5e6,
    min = -maxpop,
    max = maxpop) %>% 
  hc_xAxis(
    xaxis,
    rlist::list.merge(xaxis, list(opposite = TRUE, linkedTo = 0))
  ) %>% 
  hc_tooltip(shared = FALSE,
             formatter = JS("function () { return '<b>' + this.series.name + ', age ' + this.point.category + '</b><br/>' + 'Population: ' + Highcharts.numberFormat(Math.abs(this.point.y), 0);}")
  ) 
data("citytemp")
highchart() %>% 
  hc_chart(animation = FALSE) %>% 
  hc_title(text = "draggable points demo") %>% 
  hc_subtitle(text = "Drang my points plz") %>% 
  hc_xAxis(categories = month.abb) %>% 
  hc_plotOptions(
    series = list(
      point = list(
        events = list(
          drop = JS("function(){
                    alert(this.series.name + ' ' + this.category + ' ' + Highcharts.numberFormat(this.y, 2))
                    }")
        )
          ),
      stickyTracking = FALSE
        ),
    column = list(
      stacking = "normal"
    ),
    line = list(
      cursor = "ns-resize"
    )
    ) %>% 
  hc_tooltip(yDecimals = 2) %>% 
  hc_add_series(
    data = citytemp$tokyo,
    draggableY = TRUE,
    dragMinY = 0,
    type = "column",
    minPointLength = 2
  ) %>% 
  hc_add_series(
    data = citytemp$new_york,
    draggableY = TRUE,
    dragMinY = 0,
    type = "column",
    minPointLength = 2
  ) %>% 
  hc_add_series(
    data = citytemp$berlin,
    draggableY = TRUE
  )

Grouped Categories

library(purrr) # map function to make grouped categories argument
library(dplyr) # for select function 
data(mpg, package = "ggplot2")
mpgg <- mpg %>% 
  filter(class %in% c("suv", "compact", "midsize")) %>% 
  group_by(class, manufacturer) %>% 
  summarize(count = n())
categories_grouped <- mpgg %>% 
  group_by(name = class) %>% 
  do(categories = .$manufacturer) %>% 
  list_parse()
highchart() %>% 
  hc_xAxis(categories = categories_grouped) %>% 
  hc_add_series(data = mpgg, type = "bar", hcaes(y = count, color = manufacturer),
                showInLegend = FALSE)
data(mpg, package = "ggplot2")
mpgman <- mpg %>% 
  group_by(manufacturer) %>% 
  summarise(n = n(),
            unique = length(unique(model))) %>% 
  arrange(-n, -unique)
head(mpgman)
diamonds%>%head()
highchart() %>%
  hc_add_series(data=diamonds, type = "scatter",
                hcaes(x = carat, y = price, size = depth, group = cut)) 

|============================                   | 60% ~2 s remaining     
|=====================================          | 80% ~1 s remaining     
|===============================================|100% ~0 s remaining     
LS0tCnRpdGxlOiAiSGlnaGNoYXJ0ZXIiCm91dHB1dDogaHRtbF9ub3RlYm9vawphdXRob3I6IE5hbmEgQm9hdGVuZwotLS0KCgpgYGB7cn0KI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiamJrdW5zdC9oaWdoY2hhcnRlciIpCgojaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQoKYGBgCgoKYGBge3J9CmRhdGEoY2l0eXRlbXApCgpoYyA8LSBoaWdoY2hhcnQoKSAlPiUgCiAgaGNfeEF4aXMoY2F0ZWdvcmllcyA9IGNpdHl0ZW1wJG1vbnRoKSAlPiUgCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gIlRva3lvIiwgZGF0YSA9IGNpdHl0ZW1wJHRva3lvKSAlPiUgCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gIkxvbmRvbiIsIGRhdGEgPSBjaXR5dGVtcCRsb25kb24pICU+JSAKICBoY19hZGRfc2VyaWVzKG5hbWUgPSAiT3RoZXIgY2l0eSIsCiAgICAgICAgICAgICAgICBkYXRhID0gKGNpdHl0ZW1wJHRva3lvICsgY2l0eXRlbXAkbG9uZG9uKS8yKQoKaGMKYGBgCgpgYGB7cn0KbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShoaWdoY2hhcnRlcikKaGlnaGNoYXJ0KCkgJT4lIAogIGhjX3RpdGxlKHRleHQgPSAiU2NhdHRlciBjaGFydCB3aXRoIHNpemUgYW5kIGNvbG9yIikgJT4lIAogIGhjX2FkZF9zZXJpZXNfc2NhdHRlcihtdGNhcnMkd3QsIG10Y2FycyRtcGcsCiAgICAgICAgICAgICAgICAgICAgICAgIG10Y2FycyRkcmF0LCBtdGNhcnMkaHApCmBgYAoKCgpgYGB7cn0KaGMgPC0gaGMgJT4lIAogIGhjX2NoYXJ0KHR5cGUgPSAiY29sdW1uIiwKICAgICAgICAgICBvcHRpb25zM2QgPSBsaXN0KGVuYWJsZWQgPSBUUlVFLCBiZXRhID0gMTUsIGFscGhhID0gMTUpKQoKaGMKYGBgCgoKYGBge3J9CmhjICU+JSAKICBoY19jaGFydChib3JkZXJDb2xvciA9ICcjRUJCQTk1JywKICAgICAgICAgICBib3JkZXJSYWRpdXMgPSAxMCwKICAgICAgICAgICBib3JkZXJXaWR0aCA9IDIsCiAgICAgICAgICAgYmFja2dyb3VuZENvbG9yID0gbGlzdCgKICAgICAgICAgICAgIGxpbmVhckdyYWRpZW50ID0gYygwLCAwLCA1MDAsIDUwMCksCiAgICAgICAgICAgICBzdG9wcyA9IGxpc3QoCiAgICAgICAgICAgICAgIGxpc3QoMCwgJ3JnYigyNTUsIDI1NSwgMjU1KScpLAogICAgICAgICAgICAgICBsaXN0KDEsICdyZ2IoMjAwLCAyMDAsIDI1NSknKQogICAgICAgICAgICAgKSkpCmBgYAoKCgoKYGBge3J9CmhjIDwtIGhpZ2hjaGFydCgpICU+JSAKICBoY194QXhpcyhjYXRlZ29yaWVzID0gY2l0eXRlbXAkbW9udGgpICU+JSAKICBoY19hZGRfc2VyaWVzKG5hbWUgPSAiVG9reW8iLCBkYXRhID0gY2l0eXRlbXAkdG9reW8pICU+JSAKICBoY19hZGRfc2VyaWVzKG5hbWUgPSAiTmV3IFlvcmsiLCBkYXRhID0gY2l0eXRlbXAkbmV3X3lvcmspIAoKaGMgCmBgYAoKCgpgYGB7cn0KaGMgJT4lIAogIGhjX2FkZF9zZXJpZXMobmFtZSA9ICJMb25kb24iLCBkYXRhID0gY2l0eXRlbXAkbG9uZG9uLCB0eXBlID0gImFyZWEiKSAlPiUgCiAgaGNfcm1fc2VyaWVzKG5hbWUgPSAiTmV3IFlvcmsiKQpgYGAKCgoKCmBgYHtyfQpoYyAlPiUgCiAgaGNfdGl0bGUodGV4dCA9ICJUaGlzIGlzIGEgdGl0bGUgd2l0aCA8aT5tYXJnaW48L2k+IGFuZCA8Yj5TdHJvbmcgb3IgYm9sZCB0ZXh0PC9iPiIsCiAgICAgICAgICAgbWFyZ2luID0gMjAsIGFsaWduID0gImxlZnQiLAogICAgICAgICAgIHN0eWxlID0gbGlzdChjb2xvciA9ICIjOTBlZDdkIiwgdXNlSFRNTCA9IFRSVUUpKSAlPiUgCiAgaGNfc3VidGl0bGUodGV4dCA9ICJBbmQgdGhpcyBpcyBhIHN1YnRpdGxlIHdpdGggbW9yZSBpbmZvcm1hdGlvbiIsCiAgICAgICAgICAgICAgYWxpZ24gPSAibGVmdCIsCiAgICAgICAgICAgICAgc3R5bGUgPSBsaXN0KGNvbG9yID0gIiMyYjkwOGYiLCBmb250V2VpZ2h0ID0gImJvbGQiKSkgJT4lIAogIGhjX2NyZWRpdHMoZW5hYmxlZCA9IFRSVUUsICMgYWRkIGNyZWRpdHMKICAgICAgICAgICAgIHRleHQgPSAid3d3LmxvbmsudG9teS5zaXRlIiwKICAgICAgICAgICAgIGhyZWYgPSAiaHR0cDovL2prdW5zdC5jb20iKSAlPiUgCiAgaGNfbGVnZW5kKGFsaWduID0gImxlZnQiLCB2ZXJ0aWNhbEFsaWduID0gInRvcCIsCiAgICAgICAgICAgIGxheW91dCA9ICJ2ZXJ0aWNhbCIsIHggPSAwLCB5ID0gMTAwKSAlPiUKICBoY190b29sdGlwKGNyb3NzaGFpcnMgPSBUUlVFLCBiYWNrZ3JvdW5kQ29sb3IgPSAiI0ZDRkZDNSIsCiAgICAgICAgICAgICBzaGFyZWQgPSBUUlVFLCBib3JkZXJXaWR0aCA9IDUpICU+JSAKICBoY19leHBvcnRpbmcoZW5hYmxlZCA9IFRSVUUpICMgZW5hYmxlIGV4cG9ydGluZyBvcHRpb24KYGBgCgoKCgpgYGB7cn0KZGF0YShkaWFtb25kcywgZWNvbm9taWNzX2xvbmcsIG1wZywgcGFja2FnZSA9ICJnZ3Bsb3QyIikKbGlicmFyeShkcGx5cikKCmhjaGFydChtcGcsICJzY2F0dGVyIiwgaGNhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBncm91cCA9IGNsYXNzKSkKYGBgCgoKCmBgYHtyfQptcGdtYW4yIDwtIG1wZyAlPiUgCiAgY291bnQoY2xhc3MsIHllYXIpICU+JSAKICBnbGltcHNlKCkKIyMgT2JzZXJ2YXRpb25zOiAxNAojIyBWYXJpYWJsZXM6IDMKIyMgJCBjbGFzcyA8Y2hyPiAiMnNlYXRlciIsICIyc2VhdGVyIiwgImNvbXBhY3QiLCAiY29tcGFjdCIsICJtaWRzaXplIiwgIi4uLgojIyAkIHllYXIgIDxpbnQ+IDE5OTksIDIwMDgsIDE5OTksIDIwMDgsIDE5OTksIDIwMDgsIDE5OTksIDIwMDgsIDE5OTksIDIwLi4uCiMjICQgbiAgICAgPGludD4gMiwgMywgMjUsIDIyLCAyMCwgMjEsIDYsIDUsIDE2LCAxNywgMTksIDE2LCAyOSwgMzMKCmhjaGFydChtcGdtYW4yLCAiY29sdW1uIiwgaGNhZXMoeCA9IGNsYXNzLCB5ID0gbiwgZ3JvdXAgPSB5ZWFyKSkKYGBgCgoKCgpgYGB7cn0KbXBnbWFuMyA8LSBtcGcgJT4lIAogIGdyb3VwX2J5KG1hbnVmYWN0dXJlcikgJT4lIAogIHN1bW1hcmlzZShuID0gbigpLCB1bmlxdWUgPSBsZW5ndGgodW5pcXVlKG1vZGVsKSkpICU+JSAKICBhcnJhbmdlKC1uLCAtdW5pcXVlKSAlPiUgCiAgZ2xpbXBzZSgpCiMjIE9ic2VydmF0aW9uczogMTUKIyMgVmFyaWFibGVzOiAzCiMjICQgbWFudWZhY3R1cmVyIDxjaHI+ICJkb2RnZSIsICJ0b3lvdGEiLCAidm9sa3N3YWdlbiIsICJmb3JkIiwgImNoZXZyb2wuLi4KIyMgJCBuICAgICAgICAgICAgPGludD4gMzcsIDM0LCAyNywgMjUsIDE5LCAxOCwgMTQsIDE0LCAxMywgOSwgOCwgNSwgNCwgNCwgMwojIyAkIHVuaXF1ZSAgICAgICA8aW50PiA0LCA2LCA0LCA0LCA0LCAzLCAyLCAyLCAzLCAxLCAxLCAxLCAxLCAxLCAxCgpoY2hhcnQobXBnbWFuMywgInRyZWVtYXAiLCBoY2Flcyh4ID0gbWFudWZhY3R1cmVyLCB2YWx1ZSA9IG4sIGNvbG9yID0gdW5pcXVlKSkKYGBgCgoKCgpgYGB7cn0KZWNvbm9taWNzX2xvbmcyIDwtIGVjb25vbWljc19sb25nICU+JSAKICBmaWx0ZXIodmFyaWFibGUgJWluJSBjKCJwb3AiLCAidWVtcG1lZCIsICJ1bmVtcGxveSIpKSAlPiUgCiAgcHJpbnQoKQojIyBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzEsNzIyIHggNF0KIyMgR3JvdXBzOiB2YXJpYWJsZSBbM10KIyMgCiMjICAgICAgICAgIGRhdGUgdmFyaWFibGUgIHZhbHVlICAgICB2YWx1ZTAxCiMjICAgICAgICA8ZGF0ZT4gICA8ZmN0cj4gIDxkYmw+ICAgICAgIDxkYmw+CiMjIDEgIDE5NjctMDctMDEgICAgICBwb3AgMTk4NzEyIDAuMDAwMDAwMDAwCiMjIDIgIDE5NjctMDgtMDEgICAgICBwb3AgMTk4OTExIDAuMDAxNjI4ODExCiMjIDMgIDE5NjctMDktMDEgICAgICBwb3AgMTk5MTEzIDAuMDAzMjgyMTc3CiMjIDQgIDE5NjctMTAtMDEgICAgICBwb3AgMTk5MzExIDAuMDA0OTAyODAzCiMjIDUgIDE5NjctMTEtMDEgICAgICBwb3AgMTk5NDk4IDAuMDA2NDMzMzk1CiMjIDYgIDE5NjctMTItMDEgICAgICBwb3AgMTk5NjU3IDAuMDA3NzM0ODA3CiMjIDcgIDE5NjgtMDEtMDEgICAgICBwb3AgMTk5ODA4IDAuMDA4OTcwNzM5CiMjIDggIDE5NjgtMDItMDEgICAgICBwb3AgMTk5OTIwIDAuMDA5ODg3NDU3CiMjIDkgIDE5NjgtMDMtMDEgICAgICBwb3AgMjAwMDU2IDAuMDExMDAwNjE0CiMjIDEwIDE5NjgtMDQtMDEgICAgICBwb3AgMjAwMjA4IDAuMDEyMjQ0NzMxCiMjICMgLi4uIHdpdGggMSw3MTIgbW9yZSByb3dzCmhjaGFydChlY29ub21pY3NfbG9uZzIsICJsaW5lIiwgaGNhZXMoeCA9IGRhdGUsIHkgPSB2YWx1ZTAxLCBncm91cCA9IHZhcmlhYmxlKSkKYGBgCgoKCmBgYHtyfQpoY2hhcnQoZGlhbW9uZHMkcHJpY2UpIApgYGAKCgoKYGBge3J9CmhjaGFydChkZW5zaXR5KGRpYW1vbmRzJHByaWNlKSwgdHlwZSA9ICJhcmVhIiwgY29sb3IgPSAiI0I3MUMxQyIsIG5hbWUgPSAiUHJpY2UiKQpgYGAKCgoKYGBge3J9CmhjaGFydChkaWFtb25kcyRjdXQsIHR5cGUgPSAiY29sdW1uIikKYGBgCgoKCmBgYHtyfQpoY2hhcnQoTGFrZUh1cm9uKQpgYGAKCiMjIyMgVGltZSBTZXJpZXMKYGBge3J9CnggPC0gc3RsKGxvZyhBaXJQYXNzZW5nZXJzKSwgInBlciIpCmhjaGFydCh4KQoKCmxpYnJhcnkoImZvcmVjYXN0IikKCnggPC0gZm9yZWNhc3QoZXRzKFVTQWNjRGVhdGhzKSwgaCA9IDQ4LCBsZXZlbCA9IDk1KQpoY2hhcnQoeCkKYGBgCgoKIyMjIyBpZ3JhcGgKYGBge3J9CmxpYnJhcnkoImlncmFwaCIpCk4gPC0gNDAKCm5ldCA8LSBzYW1wbGVfZ25wKE4sIHAgPSAyL04pCndjIDwtIGNsdXN0ZXJfd2Fsa3RyYXAobmV0KQoKVihuZXQpJGxhYmVsIDwtIHNlcShOKQpWKG5ldCkkbmFtZSA8LSBwYXN0ZSgiSSdtICMiLCBzZXEoTikpClYobmV0KSRwYWdlX3JhbmsgPC0gcm91bmQocGFnZS5yYW5rKG5ldCkkdmVjdG9yLCAyKQpWKG5ldCkkYmV0d2Vlbm5lc3MgPC0gcm91bmQoYmV0d2Vlbm5lc3MobmV0KSwgMikKVihuZXQpJGRlZ3JlZSA8LSBkZWdyZWUobmV0KQpWKG5ldCkkc2l6ZSA8LSBWKG5ldCkkZGVncmVlClYobmV0KSRjb21tIDwtIG1lbWJlcnNoaXAod2MpClYobmV0KSRjb2xvciA8LSBjb2xvcml6ZShtZW1iZXJzaGlwKHdjKSkKCmhjaGFydChuZXQsIGxheW91dCA9IGxheW91dF93aXRoX2ZyKQpgYGAKCgoKIyMjIyB4dHMgZnJvbSBxdWFudG1vZCBwYWNrYWdlCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQoKeCA8LSBnZXRTeW1ib2xzKCJVU0QvSlBZIiwgc3JjID0gIm9hbmRhIiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKaGNoYXJ0KHgpCmBgYAoKClRoZSBzaGFyZXMgb2Ygd2hhdCB1c2VkIHRvIGJlIGtub3duIGFzIFlhaG9vIHVuZGVyIHRoZSB0aWNrZXIgc3ltYm9sIFlIT08gc3RhcnRlZCB0cmFkaW5nIE1vbmRheSBhcyBBbHRhYmEgKHRoaW5rIGFsdGVybmF0aXZlIEFsaWJhYmEpIGFuZCB0cmFkZSB1bmRlciB0aGUgc3ltYm9sIEFBQkEuCmBgYHtyfQoKeCA8LSBnZXRTeW1ib2xzKCJBQUJBIiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKaGNoYXJ0KHgpCmBgYAoKCgoKYGBge3J9CnggPC0gYWNmKGRpZmYoQWlyUGFzc2VuZ2VycyksIHBsb3QgPSBGQUxTRSkKaGNoYXJ0KHgpCmBgYAoKCgpgYGB7cn0KeCA8LSBjYmluZChtZGVhdGhzLCBmZGVhdGhzKQpoY2hhcnQoeCkKYGBgCgoKCiMjIyMjIFN1cnZpdmFsIE1vZGVscwoKYGBge3J9CmxpYnJhcnkoc3Vydml2YWwpCgpkYXRhKGx1bmcpCmx1bmcgPC0gbXV0YXRlKGx1bmcsIHNleCA9IGlmZWxzZShzZXggPT0gMSwgIk1hbGUiLCAiRmVtYWxlIikpCmZpdCA8LSBzdXJ2Zml0KFN1cnYodGltZSwgc3RhdHVzKSB+IHNleCwgZGF0YSA9IGx1bmcpIAoKaGNoYXJ0KGZpdCwgcmFuZ2VzID0gVFJVRSkKYGBgCgoKCiMjIyMgUHJpbmNpcGFsIENvbXBvbmVudHMKCmBgYHtyfQpoY2hhcnQocHJpbmNvbXAoVVNBcnJlc3RzLCBjb3IgPSBUUlVFKSkKYGBgCgoKCiMjIyMjIE1hdHJpeAoKYGBge3J9CmRhdGEodm9sY2FubykKaGNoYXJ0KHZvbGNhbm8pICU+JSAKICAjIGNoYW5naW5nIGRlZmF1bHQgY29sb3IKICBoY19jb2xvckF4aXMoc3RvcHMgPSBjb2xvcl9zdG9wcyhjb2xvcnMgPSB2aXJpZGlzOjppbmZlcm5vKDEwKSkpCmBgYAoKCgojIyMjIERpc3RhbmNlIG1hdHJpeApgYGB7cn0KbXRjYXJzMiA8LSBtdGNhcnNbMToyMCwgXQp4IDwtIGRpc3QobXRjYXJzMikKaGNoYXJ0KHgpCmBgYAoKIyMjIyBDb3JyZWxhdGlvbiBtYXRyaXgKCmBgYHtyfQpoY2hhcnQoY29yKG10Y2FycykpCmBgYAoKCgoKIyMjIyMgU3RhcnMgV2FycwpBIGJldHRlciB2ZXJzaW9uIChpbiBhIHN5bnRheCB3YXkpIHRoYW4gaHR0cDovL2prdW5zdC5jb20vci9wcmVzZW50aW5nLWhpZ2hjaGFydGVyLy4KCmBgYHtyfQoKI2luc3RhbGwucGFja2FnZXMoInJ3YXJzIikKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJ3YXJzKQoKc3dtb3ZpZXMgPC0gZ2V0X2FsbF9maWxtcygpCgpzd2RhdGEgPC0gbWFwX2RmKHN3bW92aWVzJHJlc3VsdHMsIGZ1bmN0aW9uKHgpewogIGRhdGFfZnJhbWUoCiAgICBtb3ZpZSA9IHgkdGl0bGUsCiAgICBzcGVjaWVzID0gbGVuZ3RoKHgkc3BlY2llcyksCiAgICBwbGFuZXRzID0gbGVuZ3RoKHgkcGxhbmV0cyksCiAgICBjaGFyYWN0ZXJzID0gbGVuZ3RoKHgkY2hhcmFjdGVycyksCiAgICB2ZWhpY2xlcyA9IGxlbmd0aCh4JHZlaGljbGVzKSwKICAgIHJlbGVhc2UgPSB4JHJlbGVhc2VfZGF0ZQogICkKfSkgCgpzd2RhdGEgPC0gZ2F0aGVyKHN3ZGF0YSwga2V5LCBudW1iZXIsIC1tb3ZpZSwgLXJlbGVhc2UpICU+JSAKICBhcnJhbmdlKHJlbGVhc2UpCgpzd2RhdGEKIyMgIyBBIHRpYmJsZTogMjggw5cgNAojIyAgICAgICAgICAgICAgICAgICAgICBtb3ZpZSAgICByZWxlYXNlICAgICAgICBrZXkgbnVtYmVyCiMjICAgICAgICAgICAgICAgICAgICAgIDxjaHI+ICAgICAgPGNocj4gICAgICA8Y2hyPiAgPGludD4KIyMgMSAgICAgICAgICAgICAgIEEgTmV3IEhvcGUgMTk3Ny0wNS0yNSAgICBzcGVjaWVzICAgICAgNQojIyAyICAgICAgICAgICAgICAgQSBOZXcgSG9wZSAxOTc3LTA1LTI1ICAgIHBsYW5ldHMgICAgICAzCiMjIDMgICAgICAgICAgICAgICBBIE5ldyBIb3BlIDE5NzctMDUtMjUgY2hhcmFjdGVycyAgICAgMTgKIyMgNCAgICAgICAgICAgICAgIEEgTmV3IEhvcGUgMTk3Ny0wNS0yNSAgIHZlaGljbGVzICAgICAgNAojIyA1ICBUaGUgRW1waXJlIFN0cmlrZXMgQmFjayAxOTgwLTA1LTE3ICAgIHNwZWNpZXMgICAgICA1CiMjIDYgIFRoZSBFbXBpcmUgU3RyaWtlcyBCYWNrIDE5ODAtMDUtMTcgICAgcGxhbmV0cyAgICAgIDQKIyMgNyAgVGhlIEVtcGlyZSBTdHJpa2VzIEJhY2sgMTk4MC0wNS0xNyBjaGFyYWN0ZXJzICAgICAxNgojIyA4ICBUaGUgRW1waXJlIFN0cmlrZXMgQmFjayAxOTgwLTA1LTE3ICAgdmVoaWNsZXMgICAgICA2CiMjIDkgICAgICAgUmV0dXJuIG9mIHRoZSBKZWRpIDE5ODMtMDUtMjUgICAgc3BlY2llcyAgICAgIDkKIyMgMTAgICAgICBSZXR1cm4gb2YgdGhlIEplZGkgMTk4My0wNS0yNSAgICBwbGFuZXRzICAgICAgNQojIyAjIC4uLiB3aXRoIDE4IG1vcmUgcm93cwoKaGNoYXJ0KHN3ZGF0YSwgImxpbmUiLCBoY2Flcyh4ID0gbW92aWUsIHkgPSBudW1iZXIsIGdyb3VwID0ga2V5KSwKICAgICAgIGNvbG9yID0gYygiI2U1YjEzYSIsICIjNGJkNWVlIiwgIiM0QUE5NDIiLCAiI0ZBRkFGQSIpKSAlPiUgCiAgaGNfdGl0bGUoCiAgICB0ZXh0ID0gIkRpdmVyc2l0eSBpbiA8c3BhbiBzdHlsZT1cImNvbG9yOiNlNWIxM2FcIj4gU1RBUiBXQVJTPC9zcGFuPiBtb3ZpZXMiLAogICAgdXNlSFRNTCA9IFRSVUUpICU+JSAKICBoY190b29sdGlwKHRhYmxlID0gVFJVRSwgc29ydCA9IFRSVUUpICU+JSAKICBoY19jcmVkaXRzKAogICAgZW5hYmxlZCA9IFRSVUUsCiAgICB0ZXh0ID0gIlNvdXJjZTogU1dBUEkgdmlhIHJ3YXJzIHBhY2thZ2UiLAogICAgaHJlZiA9ICJodHRwczovL3N3YXBpLmNvLyIpICU+JSAKICBoY19hZGRfdGhlbWUoCiAgICBoY190aGVtZV9mbGF0ZGFyaygKICAgICAgY2hhcnQgPSBsaXN0KAogICAgICAgIGJhY2tncm91bmRDb2xvciA9ICJ0cmFuc3BhcmVudCIsCiAgICAgICAgZGl2QmFja2dyb3VuZEltYWdlID0gImh0dHA6Ly93d3cud2lyZWQuY29tL2ltYWdlc19ibG9ncy91bmRlcndpcmUvMjAxMy8wMi94d2luZy1iZy5naWYiCiAgICAgICkKICAgICkKICApCmBgYAoKCgpgYGB7cn0KZGF0YShzdGFycykKCmNvbG9ycyA8LSBjKCIjRkIxMTA4IiwiI0ZEMTUwQiIsIiNGQTc4MDYiLCIjRkJFNDI2IiwiI0ZDRkI4RiIsCiAgICAgICAgICAgICIjRjNGNUU3IiwgIiNDN0U0RUEiLCIjQUJENkU2IiwiIzlBRDJFMSIpCgpzdGFycyRjb2xvciA8LSBjb2xvcml6ZShsb2coc3RhcnMkdGVtcCksIGNvbG9ycykKCnggPC0gYygiTHVtaW5vc2l0eSIsICJUZW1wZXJhdHVyZSIsICJEaXN0YW5jZSIpCnkgPC0gc3ByaW50Zigie3BvaW50LiVzOi4yZn0iLCBjKCJsdW0iLCAidGVtcCIsICJkaXN0YW5jZSIpKQp0bHRpcCA8LSB0b29sdGlwX3RhYmxlKHgsIHkpCgpoY2hhcnQoc3RhcnMsICJzY2F0dGVyIiwgaGNhZXModGVtcCwgbHVtLCBzaXplID0gcmFkaXVzc3VuLCBjb2xvciA9IGNvbG9yKSkgJT4lIAogIGhjX2NoYXJ0KGJhY2tncm91bmRDb2xvciA9ICJibGFjayIpICU+JSAKICBoY194QXhpcyh0eXBlID0gImxvZ2FyaXRobWljIiwgcmV2ZXJzZWQgPSBUUlVFKSAlPiUgCiAgaGNfeUF4aXModHlwZSA9ICJsb2dhcml0aG1pYyIsIGdyaWRMaW5lV2lkdGggPSAwKSAlPiUgCiAgaGNfdGl0bGUodGV4dCA9ICJPdXIgbmVhcmVzdCBTdGFycyIpICU+JSAKICBoY19zdWJ0aXRsZSh0ZXh0ID0gIkluIGEgSGVydHpzcHJ1bmctUnVzc2VsbCBkaWFncmFtIikgJT4lIAogIGhjX3Rvb2x0aXAodXNlSFRNTCA9IFRSVUUsIGhlYWRlckZvcm1hdCA9ICIiLCBwb2ludEZvcm1hdCA9IHRsdGlwKSAlPiUgCiAgaGNfc2l6ZShoZWlnaHQgPSA2MDApCmBgYAoKCiMjIyMgR2xvYmFsIHRlbXBlcmF0dXJlcwoKYGBge3J9CmRhdGEoImdsb2JhbHRlbXAiKQoKeCA8LSBjKCJNaW4iLCAiTWVkaWFuIiwgIk1heCIpCnkgPC0gc3ByaW50Zigie3BvaW50LiVzfSIsIGMoImxvd2VyIiwgIm1lZGlhbiIsICJ1cHBlciIpKQp0bHRpcCA8LSB0b29sdGlwX3RhYmxlKHgsIHkpCgpoY2hhcnQoZ2xvYmFsdGVtcCwgdHlwZSA9ICJjb2x1bW5yYW5nZSIsCiAgICAgICBoY2Flcyh4ID0gZGF0ZSwgbG93ID0gbG93ZXIsIGhpZ2ggPSB1cHBlciwgY29sb3IgPSBtZWRpYW4pKSAlPiUgCiAgaGNfeUF4aXModGlja1Bvc2l0aW9ucyA9IGMoLTIsIDAsIDEuNSwgMiksCiAgICAgICAgICAgZ3JpZExpbmVDb2xvciA9ICIjQjcxQzFDIiwKICAgICAgICAgICBsYWJlbHMgPSBsaXN0KGZvcm1hdCA9ICJ7dmFsdWV9IEMiLCB1c2VIVE1MID0gVFJVRSkpICU+JSAKICBoY190b29sdGlwKAogICAgdXNlSFRNTCA9IFRSVUUsCiAgICBoZWFkZXJGb3JtYXQgPSBhcy5jaGFyYWN0ZXIodGFncyRzbWFsbCgie3BvaW50Lng6ICVZICVifSIpKSwKICAgIHBvaW50Rm9ybWF0ID0gdGx0aXAKICApICU+JSAKICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZGIoKSkKCmBgYAoKCiMjIyMgV2VhdGhlcnMgUmFkaWFscwpGcm9tIGhlcmUgYW5kIHJlcGxpY2F0ZWQgaW4gaHR0cDovL2prdW5zdC5jb20vci9ob3ctdG8td2VhdGhlci1yYWRpYWxzLwoKCmBgYHtyfQpkYXRhKCJ3ZWF0aGVyIikKCnggPC0gYygiTWluIiwgIk1lYW4iLCAiTWF4IikKeSA8LSBzcHJpbnRmKCJ7cG9pbnQuJXN9IiwgYygibWluX3RlbXBlcmF0dXJlYyIsICJtZWFuX3RlbXBlcmF0dXJlYyIsICJtYXhfdGVtcGVyYXR1cmVjIikpCnRsdGlwIDwtIHRvb2x0aXBfdGFibGUoeCwgeSkKCmhjaGFydCh3ZWF0aGVyLCB0eXBlID0gImNvbHVtbnJhbmdlIiwKICAgICAgIGhjYWVzKHggPSBkYXRlLCBsb3cgPSBtaW5fdGVtcGVyYXR1cmVjLCBoaWdoID0gbWF4X3RlbXBlcmF0dXJlYywKICAgICAgICAgICAgIGNvbG9yID0gbWVhbl90ZW1wZXJhdHVyZWMpKSAlPiUgCiAgaGNfY2hhcnQocG9sYXIgPSBUUlVFKSAlPiUKICBoY195QXhpcyggbWF4ID0gMzAsIG1pbiA9IC0xMCwgbGFiZWxzID0gbGlzdChmb3JtYXQgPSAie3ZhbHVlfSBDIiksCiAgICAgICAgICAgIHNob3dGaXJzdExhYmVsID0gRkFMU0UpICU+JSAKICBoY194QXhpcygKICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gIiIpLCBncmlkTGluZVdpZHRoID0gMC41LAogICAgbGFiZWxzID0gbGlzdChmb3JtYXQgPSAie3ZhbHVlOiAlYn0iKSkgJT4lIAogIGhjX3Rvb2x0aXAodXNlSFRNTCA9IFRSVUUsIHBvaW50Rm9ybWF0ID0gdGx0aXAsCiAgICAgICAgICAgICBoZWFkZXJGb3JtYXQgPSBhcy5jaGFyYWN0ZXIodGFncyRzbWFsbCgie3BvaW50Lng6JWQgJUIsICVZfSIpKSkKYGBgCgoKIyMjIyMgVGhlIEltcGFjdCBvZiBWYWNjaW5lcwojIyMjIGhlYXRtYXAKRnJvbSBXU0ogZ3JhcGhpYzogQmF0dGxpbmcgSW5mZWN0aW91cyBEaXNlYXNlcyBpbiB0aGUgMjB0aCBDZW50dXJ5OgpgYGB7cn0KZGF0YSgidmFjY2luZXMiKQpsaWJyYXJ5KCJ2aXJpZGlzIikKCmZudGx0cCA8LSBKUygiZnVuY3Rpb24oKXsKICByZXR1cm4gdGhpcy5wb2ludC54ICsgJyAnICsgIHRoaXMuc2VyaWVzLnlBeGlzLmNhdGVnb3JpZXNbdGhpcy5wb2ludC55XSArICc6PGJyPicgKwogIEhpZ2hjaGFydHMubnVtYmVyRm9ybWF0KHRoaXMucG9pbnQudmFsdWUsIDIpOwp9IikKCnBsb3RsaW5lIDwtIGxpc3QoCiAgY29sb3IgPSAiI2ZkZTcyNSIsIHZhbHVlID0gMTk2Mywgd2lkdGggPSAyLCB6SW5kZXggPSA1LAogIGxhYmVsID0gbGlzdCgKICAgIHRleHQgPSAiVmFjY2luZSBJbnRvZHVjZWQiLCB2ZXJ0aWNhbEFsaWduID0gInRvcCIsCiAgICBzdHlsZSA9IGxpc3QoY29sb3IgPSAiIzYwNjA2MCIpLCB0ZXh0QWxpZ24gPSAibGVmdCIsCiAgICByb3RhdGlvbiA9IDAsIHkgPSAtNSkKKQoKaGNoYXJ0KHZhY2NpbmVzLCAiaGVhdG1hcCIsIGhjYWVzKHggPSB5ZWFyLCB5ID0gc3RhdGUsIHZhbHVlID0gY291bnQpKSAlPiUgCiAgaGNfY29sb3JBeGlzKHN0b3BzID0gY29sb3Jfc3RvcHMoMTAsIHJldihpbmZlcm5vKDEwKSkpLAogICAgICAgICAgICAgICB0eXBlID0gImxvZ2FyaXRobWljIikgJT4lIAogIGhjX3lBeGlzKHJldmVyc2VkID0gVFJVRSwgb2Zmc2V0ID0gLTIwLCB0aWNrTGVuZ3RoID0gMCwKICAgICAgICAgICBncmlkTGluZVdpZHRoID0gMCwgbWlub3JHcmlkTGluZVdpZHRoID0gMCwKICAgICAgICAgICBsYWJlbHMgPSBsaXN0KHN0eWxlID0gbGlzdChmb250U2l6ZSA9ICI4cHgiKSkpICU+JSAKICBoY190b29sdGlwKGZvcm1hdHRlciA9IGZudGx0cCkgJT4lIAogIGhjX3hBeGlzKHBsb3RMaW5lcyA9IGxpc3QocGxvdGxpbmUpKSAlPiUKICBoY190aXRsZSh0ZXh0ID0gIkluZmVjdGlvdXMgRGlzZWFzZXMgYW5kIFZhY2NpbmVzIikgJT4lIAogIGhjX2xlZ2VuZChsYXlvdXQgPSAidmVydGljYWwiLCB2ZXJ0aWNhbEFsaWduID0gInRvcCIsCiAgICAgICAgICAgIGFsaWduID0gInJpZ2h0IiwgdmFsdWVEZWNpbWFscyA9IDApICU+JSAKICBoY19zaXplKGhlaWdodCA9IDgwMCkKYGBgCgoKIyMjIyMgQm94cGxvdAoKCmBgYHtyfQpkYXRhKGRpYW1vbmRzLCBwYWNrYWdlID0gImdncGxvdDIiKQoKaGNib3hwbG90KHggPSBkaWFtb25kcyR4LCB2YXIgPSBkaWFtb25kcyRjb2xvciwKICAgICAgICAgIG5hbWUgPSAiTGVuZ3RoIiwgY29sb3IgPSAiIzI5ODBiOSIpIApgYGAKCgoKYGBge3J9CmhjYm94cGxvdCh4ID0gZGlhbW9uZHMkeCwgdmFyID0gZGlhbW9uZHMkY29sb3IsIHZhcjIgPSBkaWFtb25kcyRjdXQsCiAgICAgICAgICBvdXRsaWVycyA9IEZBTFNFKSAlPiUgCiAgaGNfY2hhcnQodHlwZSA9ICJjb2x1bW4iKSAjIHRvIHB1dCBib3ggdmVydGljYWwKYGBgCgoKCiMjIyMgUGFyYWxsZWwgQ29vcmRpbmF0ZXMKCmBgYHtyfQpyZXF1aXJlKHZpcmlkaXNMaXRlKQoKbiA8LSAxNQoKI2hjcGFyY29yZHMoaGVhZChtdGNhcnMsIG4pLCBjb2xvciA9IGhleF90b19yZ2JhKG1hZ21hKG4pLCAwLjUpKQoKYGBgCgojIyMjIEljb24gQXJyYXlzCgpgYGB7cn0Kc2V0LnNlZWQoMTIzKQoKaWNvbnMgPC0gYygibW90b3JjeWNsZSIsICJ0YXhpIiwgImJ1cyIsICJwbGFuZSIpCgpuIDwtIHNhbXBsZSgzOjEwLCBsZW5ndGgoaWNvbnMpKSAlPiUgCiAgc29ydChkZWNyZWFzaW5nID0gVFJVRSkgJT4lIAogIHsuICogIHNlcShsZW5ndGgoaWNvbnMpLCAxKSB9IAoKaGNpY29uYXJyYXkoaWNvbnMsIG4sIGljb25zID0gaWNvbnMsIHNpemUgPSA1KQpgYGAKCgoKIyMjIyBUcmVlbWFwcwpIZXJlIHdlIHVzZSB0aGUgdHJlZW1hcCBwYWNrYWdlIHRvIGNyZWF0ZSBhIHRyZWVtYXAgb2JqZWN0IGFuZCB0aGVuIHdlIGNyZWF0ZSB0aGUgc2FtZSB0cmVlbWFwIHZpYSBoaWdoY2hhcnRzIDspLgoKCmBgYHtyfQpsaWJyYXJ5KHRyZWVtYXApCmxpYnJhcnkodmlyaWRpc0xpdGUpCgpkYXRhKEdOSTIwMTQpCgpHTkkyMDE0JT4laGVhZCgpCgoKYGBgCgoKCmBgYHtyfQojaW5zdGFsbC5wYWNrYWdlcygidHJlZW1hcCIpCmxpYnJhcnkodHJlZW1hcCkKbGlicmFyeSh2aXJpZGlzTGl0ZSkKCmRhdGEoR05JMjAxNCkKCgp0bSA8LSB0cmVlbWFwKEdOSTIwMTQsIGluZGV4ID0gYygiY29udGluZW50IiwgImlzbzMiKSwKICAgICAgICAgICAgICB2U2l6ZSA9ICJwb3B1bGF0aW9uIiwgdkNvbG9yID0gIkdOSSIsCiAgICAgICAgICAgICAgdHlwZSA9ICJ2YWx1ZSIsIHBhbGV0dGUgPSB2aXJpZGlzKDYpKQoKaGN0cmVlbWFwKHRtKQpgYGAKCgojIyMjIFRoZW1lcwoKYGBge3J9CmhjIDwtIGhpZ2hjaGFydHNfZGVtbygpCgpoYwoKaGMgJT4lIGhjX2FkZF90aGVtZShoY190aGVtZV81MzgoKSkKCmhjICU+JSBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZWNvbm9taXN0KCkpCgpoYyAlPiUgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2Z0KCkpCgpoYyAlPiUgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2RiKCkpCgpoYyAlPiUgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2ZsYXQoKSkKCmhjICU+JSBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZmxhdGRhcmsoKSkKCmhjICU+JSBoY19hZGRfdGhlbWUoaGNfdGhlbWVfc21wbCgpKQoKaGMgJT4lIGhjX2FkZF90aGVtZShoY190aGVtZV9lbGVtZW50YXJ5KCkpCgpoYyAlPiUgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2dvb2dsZSgpKQoKaGMgJT4lIGhjX2FkZF90aGVtZShoY190aGVtZV9mZngoKSkKCmhjICU+JSBoY19hZGRfdGhlbWUoaGNfdGhlbWVfbW9ub2thaSgpKQoKaGMgJT4lIGhjX2FkZF90aGVtZShoY190aGVtZV9ncmlkbGlnaHQoKSkKCmhjICU+JSBoY19hZGRfdGhlbWUoaGNfdGhlbWVfc2FuZHNpZ25pa2EoKSkKCmhjICU+JSBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZGFya3VuaWNhKCkpCgpoYyAlPiUgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2NoYWxrKCkpCgpoYyAlPiUgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2hhbmRkcmF3bigpKQoKaGMgJT4lIGhjX2FkZF90aGVtZShoY190aGVtZV9udWxsKCkpCgpgYGAKCgoKYGBge3J9Cm4gPC0gMTUKZHRhIDwtIGRwbHlyOjpkYXRhX2ZyYW1lKAogIHggPSBybm9ybShuKSwKICB5ID0gMS41ICogeCArIHJub3JtKG4pKQoKaGlnaGNoYXJ0KCkgJT4lCiAgaGNfY2hhcnQodHlwZSA9ICJzY2F0dGVyIikgJT4lIAogIGhjX2FkZF9zZXJpZXMoZGF0YSA9IGxpc3RfcGFyc2UoZHRhKSkgJT4lIAogIGhjX2FkZF90aGVtZShoY190aGVtZV90dWZ0ZSgpKQoKCnZhbHVlcyA8LSAxICsgYWJzKHJub3JtKDEyKSkKCmhpZ2hjaGFydCgpICU+JQogIGhjX2NoYXJ0KHR5cGUgPSAiY29sdW1uIikgJT4lCiAgaGNfYWRkX3NlcmllcyhkYXRhID0gdmFsdWVzKSAlPiUKICBoY194QXhpcyhjYXRlZ29yaWVzID0gbW9udGguYWJiKSAlPiUKICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfdHVmdGUyKCkpCgojIFlvdSBjYW4gdGVzdDoKIyBoYyAlPiUgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX3NwYXJrbGluZSgpKQoKZGF0YShlY29ub21pY3NfbG9uZywgcGFja2FnZSA9ICJnZ3Bsb3QyIikKbGlicmFyeShkcGx5cikKCmVjb25vbWljc19sb25nICU+JQogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUKICBkbyhzcGFyayA9IGhjdHMoLiR2YWx1ZSwgdHlwZSA9ICJhcmVhIiwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGZpcnN0KC4kdmFyaWFibGUpLCBzaG93SW5MZWdlbmQgPSBGQUxTRSkgJT4lCiAgICAgICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfc3BhcmtsaW5lKCkpKSAlPiUgCiAgLltbInNwYXJrIl1dICU+JSAKICBhcy5saXN0KCkgJT4lIAogIGh3X2dyaWQocm93aGVpZ2h0ID0gMTAwKQoKCmBgYAoKCgoKYGBge3J9CnRobSA8LSBoY190aGVtZSgKICBjb2xvcnMgPSBjKCdyZWQnLCAnZ3JlZW4nLCAnYmx1ZScpLAogIGNoYXJ0ID0gbGlzdCgKICAgIGJhY2tncm91bmRDb2xvciA9IE5VTEwsCiAgICBkaXZCYWNrZ3JvdW5kSW1hZ2UgPSAiaHR0cDovL21lZGlhMy5naXBoeS5jb20vbWVkaWEvRnp4a1dkaVlwNVlGVy9naXBoeS5naWYiCiAgKSwKICB0aXRsZSA9IGxpc3QoCiAgICBzdHlsZSA9IGxpc3QoCiAgICAgIGNvbG9yID0gJyMzMzMzMzMnLAogICAgICBmb250RmFtaWx5ID0gIkxhdG8iCiAgICApCiAgKSwKICBzdWJ0aXRsZSA9IGxpc3QoCiAgICBzdHlsZSA9IGxpc3QoCiAgICAgIGNvbG9yID0gJyM2NjY2NjYnLAogICAgICBmb250RmFtaWx5ID0gIlNoYWRvd3MgSW50byBMaWdodCIKICAgICkKICApLAogIGxlZ2VuZCA9IGxpc3QoCiAgICBpdGVtU3R5bGUgPSBsaXN0KAogICAgICBmb250RmFtaWx5ID0gJ1RhbmdlcmluZScsCiAgICAgIGNvbG9yID0gJ2JsYWNrJwogICAgKSwKICAgIGl0ZW1Ib3ZlclN0eWxlID0gbGlzdCgKICAgICAgY29sb3IgPSAnZ3JheScKICAgICkgICAKICApCikKCmhjICU+JSBoY19hZGRfdGhlbWUodGhtKQpgYGAKCgoKCmBgYHtyfQp0aG0gPC0gaGNfdGhlbWVfbWVyZ2UoCiAgaGNfdGhlbWVfZGFya3VuaWNhKCksCiAgaGNfdGhlbWUoCiAgICBjaGFydCA9IGxpc3QoCiAgICAgIGJhY2tncm91bmRDb2xvciA9ICJ0cmFuc3BhcmVudCIsCiAgICAgIGRpdkJhY2tncm91bmRJbWFnZSA9ICJodHRwOi8vY2RuLndhbGwtcGl4Lm5ldC9hbGJ1bXMvYXJ0LTNEdmlldy8wMDAyNTA5NS5qcGciCiAgICApLAogICAgdGl0bGUgPSBsaXN0KAogICAgICBzdHlsZSA9IGxpc3QoCiAgICAgICAgY29sb3IgPSAnd2hpdGUnLAogICAgICAgIGZvbnRGYW1pbHkgPSAiT3BlbiBTYW5zIgogICAgICApCiAgICApCiAgKQopCgpoYyAlPiUgaGNfYWRkX3RoZW1lKHRobSkKYGBgCgoKIyMjIyBIaWdoc3RvY2sKCkJhc2ljcyAgIMK3ICAgQ2FuZGxlc3RpY2sgYW5kIE9ITEMgY2hhcnRzICAgwrcgICBUaW1lIHNlcmllcyAgIMK3ICAgRmxhZ3MgICDCtyAgIEEgTW9yZSBJbnRlcmVzdGluZyBFeGFtcGxlCkJhc2ljcwpIaWdoc3RvY2sgd29yayB3ZWxsIHdpdGggdGhlIHF1YW50bW9kIHBhY2thZ2UuIEl04oCZcyBlYXN5IGNoYXJ0IHN5bWJvbHMuIEFuZCB0aGVuIHlvdSBjYW4gYWRkIG1vcmUgc2VyaWVzIHVzaW5nIGhjX2FkZF9zZXJpZXMgKHNlZSBiZWxvdykuCgoKYGBge3J9CmxpYnJhcnkoInF1YW50bW9kIikKCnggPC0gZ2V0U3ltYm9scygiR09PRyIsIGF1dG8uYXNzaWduID0gRkFMU0UpCgpoY2hhcnQoeCkKYGBgCgoKCkNhbmRsZXN0aWNrIGFuZCBPSExDIGNoYXJ0cwpJZiB5b3Ugd2FudCB0byBjaGFydCBtb3JlIHN5bWJvbHMgaW4geW91IGNhbiB1c2UgdGhlIGhjX2FkZF9zZXJpZXMgZnVuY3Rpb24uCgoKYGBge3J9CnggPC0gZ2V0U3ltYm9scygiR09PRyIsIGF1dG8uYXNzaWduID0gRkFMU0UpCnkgPC0gZ2V0U3ltYm9scygiQU1aTiIsIGF1dG8uYXNzaWduID0gRkFMU0UpCgpoaWdoY2hhcnQodHlwZSA9ICJzdG9jayIpICU+JSAKICBoY19hZGRfc2VyaWVzKHgpICU+JSAKICBoY19hZGRfc2VyaWVzKHksIHR5cGUgPSAib2hsYyIpCmBgYAoKCgojIyMjIFRpbWUgc2VyaWVzCgpgYGB7cn0KbGlicmFyeSgicXVhbnRtb2QiKQoKdXNkanB5IDwtIGdldFN5bWJvbHMoIlVTRC9KUFkiLCBzcmMgPSAib2FuZGEiLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQpldXJrcHcgPC0gZ2V0U3ltYm9scygiRVVSL0tQVyIsIHNyYyA9ICJvYW5kYSIsIGF1dG8uYXNzaWduID0gRkFMU0UpCgpoYyA8LSBoaWdoY2hhcnQodHlwZSA9ICJzdG9jayIpICU+JSAKICBoY190aXRsZSh0ZXh0ID0gIkNoYXJ0aW5nIHNvbWUgU3ltYm9scyIpICU+JSAKICBoY19zdWJ0aXRsZSh0ZXh0ID0gIkRhdGEgZXh0cmFjdGVkIHVzaW5nIHF1YW50bW9kIHBhY2thZ2UiKSAlPiUgCiAgaGNfYWRkX3Nlcmllcyh1c2RqcHksIGlkID0gInVzZGpweSIpICU+JSAKICBoY19hZGRfc2VyaWVzKGV1cmtwdywgaWQgPSAiZXVya3B3IikKCmhjCmBgYAoKCgojIyMjIEZsYWdzClByZXZpb3VzbHkgd2UgdXNlZCB0aGUgaWQgcGFyYW1ldGVyLiBUaGlzIGlzIG5lY2Vzc2FyeSB0byBhZGQgZmxhZ3M6CgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCgpzZXQuc2VlZCgxMjMpCgpkYXRhX2ZsYWdzIDwtIGRhdGFfZnJhbWUoCiAgZGF0ZSA9IHNhbXBsZSh0aW1lKHVzZGpweSksIHNpemUgPSA1KSwKICB0aXRsZSA9IHNwcmludGYoIkUgIyVzIiwgc2VxX2Fsb25nKGRhdGUpKSwKICB0ZXh0ID0gc3ByaW50ZigiQW4gaW50ZXJlc3RpbmcgZXZlbnQgIyVzIGluICVzIiwgc2VxX2Fsb25nKGRhdGUpLCBkYXRlKQopCgpnbGltcHNlKGRhdGFfZmxhZ3MpCiMjIE9ic2VydmF0aW9uczogNQojIyBWYXJpYWJsZXM6IDMKIyMgJCBkYXRlICA8ZGF0ZT4gMjAxNi0wMi0wNiwgMjAxNi0xMC0xMiwgMjAxNi0wNC0wNiwgMjAxNi0xMS0yNiwgMjAxNi0xMi0yNAojIyAkIHRpdGxlIDxjaHI+ICJFICMxIiwgIkUgIzIiLCAiRSAjMyIsICJFICM0IiwgIkUgIzUiCiMjICQgdGV4dCAgPGNocj4gIkFuIGludGVyZXN0aW5nIGV2ZW50ICMxIGluIDIwMTYtMDItMDYiLCAiQW4gaW50ZXJlc3RpbmcuLi4KCmhjICU+JSAKICBoY19hZGRfc2VyaWVzKGRhdGFfZmxhZ3MsIGhjYWVzKHggPSBkYXRlKSwKICAgICAgICAgICAgICAgIHR5cGUgPSAiZmxhZ3MiLCBvblNlcmllcyA9ICJ1c2RqcHkiKQpgYGAKCgoKCmBgYHtyfQpTUFkgPC0gZ2V0U3ltYm9scygiU1BZIiwgZnJvbSA9IFN5cy5EYXRlKCkgLSBsdWJyaWRhdGU6OnllYXJzKDEpLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQpTUFkgPC0gYWRqdXN0T0hMQyhTUFkpCgpTUFkuU01BLjEwIDwtIFNNQShDbChTUFkpLCBuID0gNSkKU1BZLlNNQS4yMDAgPC0gU01BKENsKFNQWSksIG4gPSAxMDApClNQWS5SU0kuMTQgPC0gUlNJKENsKFNQWSkpClNQWS5SU0kuU2VsbExldmVsIDwtIHh0cyhyZXAoNzAsIE5ST1coU1BZKSksIGluZGV4KFNQWSkpClNQWS5SU0kuQnV5TGV2ZWwgPC0geHRzKHJlcCgzMCwgTlJPVyhTUFkpKSwgaW5kZXgoU1BZKSkKCgpoaWdoY2hhcnQodHlwZSA9ICJzdG9jayIpICU+JSAKICAjIGNyZWF0ZSBheGlzIDopCiAgaGNfeUF4aXNfbXVsdGlwbGVzKAogICAgY3JlYXRlX3lheGlzKDMsIGhlaWdodCA9IGMoMiwgMSwgMSksIHR1cm5vcHBvc2l0ZSA9IFRSVUUpCiAgKSAlPiUgCiAgIyBzZXJpZXMgOkQKICBoY19hZGRfc2VyaWVzKFNQWSwgeUF4aXMgPSAwLCBuYW1lID0gIlNQWSIpICU+JSAKICBoY19hZGRfc2VyaWVzKFNQWS5TTUEuMTAsIHlBeGlzID0gMCwgbmFtZSA9ICJGYXN0IE1BIikgJT4lIAogIGhjX2FkZF9zZXJpZXMoU1BZLlNNQS4yMDAsIHlBeGlzID0gMCwgbmFtZSA9ICJTbG93IE1BIikgJT4lIAogIGhjX2FkZF9zZXJpZXMoU1BZJFNQWS5Wb2x1bWUsIGNvbG9yID0gImdyYXkiLCB5QXhpcyA9IDEsIG5hbWUgPSAiVm9sdW1lIiwgdHlwZSA9ICJjb2x1bW4iKSAlPiUgCiAgaGNfYWRkX3NlcmllcyhTUFkuUlNJLjE0LCB5QXhpcyA9IDIsIG5hbWUgPSAiT3NjaWFsbGF0b3IiLCBjb2xvciA9IGhleF90b19yZ2JhKCJncmVlbiIsIDAuNykpICU+JQogIGhjX2FkZF9zZXJpZXMoU1BZLlJTSS5TZWxsTGV2ZWwsIGNvbG9yID0gaGV4X3RvX3JnYmEoInJlZCIsIDAuNyksCiAgICAgICAgICAgICAgICB5QXhpcyA9IDIsIG5hbWUgPSAiU2VsbCBsZXZlbCIpICU+JSAKICBoY19hZGRfc2VyaWVzKFNQWS5SU0kuQnV5TGV2ZWwsIGNvbG9yID0gaGV4X3RvX3JnYmEoImJsdWUiLCAwLjcpLAogICAgICAgICAgICAgICAgeUF4aXMgPSAyLCBuYW1lID0gIkJ1eSBsZXZlbCIpIApgYGAKCgoKCiMjIyMgSGlnaG1hcHMKCkJhc2ljcyAgIMK3ICAgQ2hvcm9wbGV0aHMgICDCtyAgIEFkZGluZyBNb3JlIERhdGEgICDCtyAgIEFkdmFuY2VkIE1hcHMgICDCtyAgIE1vdGlvbiBQbHVnaW4gICDCtyAgIGdlb2pzb25pbyBQYWNrYWdlCkJhc2ljcwpUaGUgZWFzaWVzdCB3YXkgdG8gY2hhcnQgYSBtYXAgd2l0aCBoaWdoY2hhcnRlciBpcyB1c2luZyBoY21hcCBmdW5jdGlvbi4gU2VsZWN0IGEgbWFwIChhIHVybCkgZnJvbSB0aGUgaGlnaG1hcHMgY29sbGVjdGlvbiBodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vbWFwZGF0YS8uIGFuZCB1c2UgdGhlIHVybCBhcyBhIG1hcCBpbiBoY21hcCBmdW5jdGlvbi4gVGhpcyB3aWxsIGRvd25sb2FkIHRoZSBtYXAgYW5kIGNyZWF0ZSBhIG9iamVjdCB1c2luZyB0aGUgaW5mbyBhcyBhIG1hcERhdGEgYXJndW1lbnQuCgojIyMjIENob3JvcGxldGhzCldoYXQgYWJvdXQgYWRkIGRhdGEgdG8gZ2V0IGEgY2hvcm9wbGV0aD8gRXZlcnkgbWFwIGRvd25sb2FkZWQgZnJvbSB0aGUgaGlnaGNoYXJ0cyBtYXBzIGNvbGxlY3Rpb24gaGF2ZSBrZXlzIHRvIGpvaW4gZGF0YS4gVGhlcmUgYXJlIDIgZnVuY3Rpb25zIHRvIGhlbHAgdG8ga25vdyB3aGF0IGFyZSB0aGUgcmVnaW9ucyBjb2RlZCB0byBrbm93IGhvdyB0byBqb2luIHRoZSBtYXAgYW5kIGRhdGE6Cgpkb3dubG9hZF9tYXBfZGF0YTogRG93bmxvYWQgdGhlIGdlb2pzb24gZGF0YSBmcm9tIHRoZSBoaWdoY2hhcnRzIGNvbGxlY3Rpb24uCmdldF9kYXRhX2Zyb21fbWFwOiBHZXQgdGhlIHByb3BlcnRpZXMgZm9yIGVhY2ggcmVnaW9uIGluIHRoZSBtYXAsIGFzIHRoZSBrZXlzIGZyb20gdGhlIG1hcCBkYXRhLgpgYGB7cn0KbGlicmFyeShkcGx5cikKCm1hcGRhdGEgPC0gZ2V0X2RhdGFfZnJvbV9tYXAoZG93bmxvYWRfbWFwX2RhdGEoImNvdW50cmllcy91cy91cy1hbGwiKSkKZ2xpbXBzZShtYXBkYXRhKQojIyBPYnNlcnZhdGlvbnM6IDUyCiMjIFZhcmlhYmxlczogMTkKIyMgJCBoYy1ncm91cCAgICA8Y2hyPiAiYWRtaW4xIiwgImFkbWluMSIsICJhZG1pbjEiLCAiYWRtaW4xIiwgImFkbWluMSIsIC4uLgojIyAkIGhjLW1pZGRsZS14IDxkYmw+IDAuMzYsIDAuNTYsIDAuNTEsIDAuNDcsIDAuNDEsIDAuNDMsIDAuNzEsIDAuNDYsIDAuLi4uCiMjICQgaGMtbWlkZGxlLXkgPGRibD4gMC40NywgMC41MiwgMC42NywgMC41MiwgMC4zOCwgMC40MCwgMC42NywgMC4zOCwgMC4uLi4KIyMgJCBoYy1rZXkgICAgICA8Y2hyPiAidXMtbWEiLCAidXMtd2EiLCAidXMtY2EiLCAidXMtb3IiLCAidXMtd2kiLCAidXMtbS4uLgojIyAkIGhjLWEyICAgICAgIDxjaHI+ICJNQSIsICJXQSIsICJDQSIsICJPUiIsICJXSSIsICJNRSIsICJNSSIsICJOViIsICJOLi4uCiMjICQgbGFiZWxyYW5rICAgPGNocj4gIjAiLCAiMCIsICIwIiwgIjAiLCAiMCIsICIwIiwgIjAiLCAiMCIsICIwIiwgIjAiLCAuLi4KIyMgJCBoYXNjICAgICAgICA8Y2hyPiAiVVMuTUEiLCAiVVMuV0EiLCAiVVMuQ0EiLCAiVVMuT1IiLCAiVVMuV0kiLCAiVVMuTS4uLgojIyAkIHdvZS1pZCAgICAgIDxjaHI+ICIyMzQ3NTgwIiwgIjIzNDc2MDYiLCAiMjM0NzU2MyIsICIyMzQ3NTk2IiwgIjIzNDc2Li4uCiMjICQgc3RhdGUtZmlwcyAgPGNocj4gIjI1IiwgIjUzIiwgIjYiLCAiNDEiLCAiNTUiLCAiMjMiLCAiMjYiLCAiMzIiLCAiMzUuLi4KIyMgJCBmaXBzICAgICAgICA8Y2hyPiAiVVMyNSIsICJVUzUzIiwgIlVTMDYiLCAiVVM0MSIsICJVUzU1IiwgIlVTMjMiLCAiVS4uLgojIyAkIHBvc3RhbC1jb2RlIDxjaHI+ICJNQSIsICJXQSIsICJDQSIsICJPUiIsICJXSSIsICJNRSIsICJNSSIsICJOViIsICJOLi4uCiMjICQgbmFtZSAgICAgICAgPGNocj4gIk1hc3NhY2h1c2V0dHMiLCAiV2FzaGluZ3RvbiIsICJDYWxpZm9ybmlhIiwgIk9yZWcuLi4KIyMgJCBjb3VudHJ5ICAgICA8Y2hyPiAiVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhIiwgIlVuaXRlZCBTdGF0ZXMgb2YgQW1lci4uLgojIyAkIHJlZ2lvbiAgICAgIDxjaHI+ICJOb3J0aGVhc3QiLCAiV2VzdCIsICJXZXN0IiwgIldlc3QiLCAiTWlkd2VzdCIsICJOLi4uCiMjICQgbG9uZ2l0dWRlICAgPGNocj4gIi03MS45OTkzMDAwMDAwMDAwMSIsICItMTIwLjM2MSIsICItMTE5LjU5MSIsICItMTIuLi4KIyMgJCB3b2UtbmFtZSAgICA8Y2hyPiAiTWFzc2FjaHVzZXR0cyIsICJXYXNoaW5ndG9uIiwgIkNhbGlmb3JuaWEiLCAiT3JlZy4uLgojIyAkIGxhdGl0dWRlICAgIDxjaHI+ICI0Mi4zNzM5IiwgIjQ3LjQ4NjUiLCAiMzYuNzQ5NiIsICI0My44MzMzIiwgIjQ0LjM3Li4uCiMjICQgd29lLWxhYmVsICAgPGNocj4gIk1hc3NhY2h1c2V0dHMsIFVTLCBVbml0ZWQgU3RhdGVzIiwgIldhc2hpbmd0b24sIFUuLi4KIyMgJCB0eXBlICAgICAgICA8Y2hyPiAiU3RhdGUiLCAiU3RhdGUiLCAiU3RhdGUiLCAiU3RhdGUiLCAiU3RhdGUiLCAiU3RhdC4uLgoKc2V0LnNlZWQoMTIzNCkKCmRhdGFfZmFrZSA8LSBtYXBkYXRhICU+JSAKICBzZWxlY3QoY29kZSA9IGBoYy1hMmApICU+JSAKICBtdXRhdGUodmFsdWUgPSAxZTUgKiBhYnMocnQobnJvdyguKSwgZGYgPSAxMCkpKQoKZ2xpbXBzZShkYXRhX2Zha2UpCiMjIE9ic2VydmF0aW9uczogNTIKIyMgVmFyaWFibGVzOiAyCiMjICQgY29kZSAgPGNocj4gIk1BIiwgIldBIiwgIkNBIiwgIk9SIiwgIldJIiwgIk1FIiwgIk1JIiwgIk5WIiwgIk5NIiwgIkMuLi4KIyMgJCB2YWx1ZSA8ZGJsPiAxMTk0MjYuNTE4LCAyNTU2NjIuMzE3LCAzNjY4LjU3NSwgMTIyMjQ2LjkzMCwgNzkyODMuMDY0LC4uLgoKCmhjbWFwKCJjb3VudHJpZXMvdXMvdXMtYWxsIiwgZGF0YSA9IGRhdGFfZmFrZSwgdmFsdWUgPSAidmFsdWUiLAogICAgICBqb2luQnkgPSBjKCJoYy1hMiIsICJjb2RlIiksIG5hbWUgPSAiRmFrZSBkYXRhIiwKICAgICAgZGF0YUxhYmVscyA9IGxpc3QoZW5hYmxlZCA9IFRSVUUsIGZvcm1hdCA9ICd7cG9pbnQubmFtZX0nKSwKICAgICAgYm9yZGVyQ29sb3IgPSAiI0ZBRkFGQSIsIGJvcmRlcldpZHRoID0gMC4xLAogICAgICB0b29sdGlwID0gbGlzdCh2YWx1ZURlY2ltYWxzID0gMiwgdmFsdWVQcmVmaXggPSAiJCIsIHZhbHVlU3VmZml4ID0gIiBVU0QiKSkKCgpgYGAKCgoKYGBge3J9CmxpYnJhcnkoaGlnaGNoYXJ0ZXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocHVycnIpCgpzZXQuc2VlZCgxMjM0KQoKbiA8LSAyMAp6IDwtICBzYW1wbGUoMTpuKQpzZXF1ZW5jZXMgPC0gbWFwMigxOm4sIHosIGZ1bmN0aW9uKHgsIHkpeyBpZmVsc2UoeCA9PSAxOm4sIHksIDApIH0pCgpkZiA8LSBkYXRhX2ZyYW1lKAogIGxhdCA9IHJ1bmlmKG4sIC0xODAsIDE4MCksCiAgbG9uID0gcnVuaWYobiwgLTE4MCwgMTgwKSwKICB6ID0geiwKICBjb2xvciA9IGNvbG9yaXplKHopLAogIHNlcXVlbmNlID0gc2VxdWVuY2VzCikKCmhjbWFwKCkgJT4lIAogIGhjX2FkZF9zZXJpZXMoZGF0YSA9IGRmLCB0eXBlID0gIm1hcGJ1YmJsZSIsCiAgICAgICAgICAgICAgICBtaW5TaXplID0gMCwgbWF4U2l6ZSA9IDMwKSAlPiUgCiAgaGNfbW90aW9uKGVuYWJsZWQgPSBUUlVFLCBzZXJpZXMgPSAxLCBsYWJlbHMgPSAxOm4sCiAgICAgICAgICAgIGxvb3AgPSBUUlVFLCBhdXRvUGxheSA9IFRSVUUsIAogICAgICAgICAgICB1cGRhdGVJbnRlcnZhbCA9IDEwMDAsIG1hZ25ldCA9IGxpc3Qoc3RlcCA9ICAxKSkgJT4lIAogIGhjX3Bsb3RPcHRpb25zKHNlcmllcyA9IGxpc3Qoc2hvd0luTGVnZW5kID0gRkFMU0UpKQpgYGAKCgpgYGB7cn0KaGNtYXAoImNvdW50cmllcy91cy91cy1jYS1hbGwiKSAlPiUKICBoY190aXRsZSh0ZXh0ID0gIkNhbGlmb3JuaWEiKQoKaGNtYXAoImN1c3RvbS91c2EtYW5kLWNhbmFkYSIsIHNob3dJbkxlZ2VuZCA9IEZBTFNFKQoKaGNtYXAoImNvdW50cmllcy9uei9uei1hbGwiKQpgYGAKCgoKYGBge3J9CmhpZ2hjaGFydCgpICU+JSAKICBoY19jaGFydCh0eXBlID0gImNvbHVtbiIpICU+JSAKICBoY195QXhpcyhtYXggPSA2LCBtaW4gPSAwKSAlPiUgCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gIkEiLCBkYXRhID0gYygyLDMsNCksIHpJbmRleCA9IC0xMCkgJT4lIAogIGhjX2FkZF9zZXJpZXMobmFtZSA9ICJCIiwKICAgICAgICAgICAgICAgIGRhdGEgPSBsaXN0KAogICAgICAgICAgICAgICAgICBsaXN0KHNlcXVlbmNlID0gYygxLDIsMyw0KSksCiAgICAgICAgICAgICAgICAgIGxpc3Qoc2VxdWVuY2UgPSBjKDMsMiwxLDMpKSwKICAgICAgICAgICAgICAgICAgbGlzdChzZXF1ZW5jZSA9IGMoMiw1LDQsMykpCiAgICAgICAgICAgICAgICApKSAlPiUgCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gIkMiLAogICAgICAgICAgICAgICAgZGF0YSA9IGxpc3QoCiAgICAgICAgICAgICAgICAgIGxpc3Qoc2VxdWVuY2UgPSBjKDMsMiwxLDMpKSwKICAgICAgICAgICAgICAgICAgbGlzdChzZXF1ZW5jZSA9IGMoMiw1LDQsMykpLAogICAgICAgICAgICAgICAgICBsaXN0KHNlcXVlbmNlID0gYygxLDIsMyw0KSkKICAgICAgICAgICAgICAgICkpICU+JSAKICBoY19tb3Rpb24oZW5hYmxlZCA9IFRSVUUsCiAgICAgICAgICAgIGxhYmVscyA9IDIwMDA6MjAwMywKICAgICAgICAgICAgc2VyaWVzID0gYygxLDIpKQpgYGAKCgoKCmBgYHtyfQojaW5zdGFsbC5wYWNrYWdlcygiaWRiciIpCmxpYnJhcnkoImlkYnIiKQpsaWJyYXJ5KCJwdXJyciIpCmxpYnJhcnkoImRwbHlyIikKCmlkYl9hcGlfa2V5KCIzNWYxMTY1ODJkNWE4OWQxMWE0N2M3ZmZiZmMyYmEzMDkxMzNmMDlkIikKeXJzIDwtICBzZXEoMTk4MCwgMjAzMCwgYnkgPSA1KQoKZGYgPC0gbWFwX2RmKGMoIm1hbGUiLCAiZmVtYWxlIiksIGZ1bmN0aW9uKHNleCl7CiAgbXV0YXRlKGlkYjEoIlVTIiwgeXJzLCBzZXggPSBzZXgpLCBzZXhfbGFiZWwgPSBzZXgpCn0pCgpuYW1lcyhkZikgPC0gdG9sb3dlcihuYW1lcyhkZikpCgpkZiA8LSBkZiAlPiUKICBtdXRhdGUocG9wdWxhdGlvbiA9IHBvcCppZmVsc2Uoc2V4X2xhYmVsID09ICJtYWxlIiwgLTEsIDEpKQoKc2VyaWVzIDwtIGRmICU+JSAKICBncm91cF9ieShzZXhfbGFiZWwsIGFnZSkgJT4lIAogIGRvKGRhdGEgPSBsaXN0KHNlcXVlbmNlID0gLiRwb3B1bGF0aW9uKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ3JvdXBfYnkoc2V4X2xhYmVsKSAlPiUgCiAgZG8oZGF0YSA9IC4kZGF0YSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBzZXhfbGFiZWwpICU+JSAKICBsaXN0X3BhcnNlKCkKCm1heHBvcCA8LSBtYXgoYWJzKGRmJHBvcHVsYXRpb24pKQoKeGF4aXMgPC0gbGlzdChjYXRlZ29yaWVzID0gc29ydCh1bmlxdWUoZGYkYWdlKSksCiAgICAgICAgICAgICAgcmV2ZXJzZWQgPSBGQUxTRSwgdGlja0ludGVydmFsID0gNSwKICAgICAgICAgICAgICBsYWJlbHMgPSBsaXN0KHN0ZXAgPSA1KSkKCmhpZ2hjaGFydCgpICU+JQogIGhjX2NoYXJ0KHR5cGUgPSAiYmFyIikgJT4lCiAgaGNfbW90aW9uKGVuYWJsZWQgPSBUUlVFLCBsYWJlbHMgPSB5cnMsIHNlcmllcyA9IGMoMCwxKSwgYXV0b3BsYXkgPSBUUlVFLCB1cGRhdGVJbnRlcnZhbCA9IDEpICU+JSAKICBoY19hZGRfc2VyaWVzX2xpc3Qoc2VyaWVzKSAlPiUgCiAgaGNfcGxvdE9wdGlvbnMoCiAgICBzZXJpZXMgPSBsaXN0KHN0YWNraW5nID0gIm5vcm1hbCIpLAogICAgYmFyID0gbGlzdChncm91cFBhZGRpbmcgPSAwLCBwb2ludFBhZGRpbmcgPSAgMCwgYm9yZGVyV2lkdGggPSAwKQogICkgJT4lIAogIGhjX3Rvb2x0aXAoc2hhcmVkID0gVFJVRSkgJT4lIAogIGhjX3lBeGlzKAogICAgbGFiZWxzID0gbGlzdCgKICAgICAgZm9ybWF0dGVyID0gSlMoImZ1bmN0aW9uKCl7IHJldHVybiBNYXRoLmFicyh0aGlzLnZhbHVlKSAvIDEwMDAwMDAgKyAnTSc7IH0iKSAKICAgICksCiAgICB0aWNrSW50ZXJ2YWwgPSAwLjVlNiwKICAgIG1pbiA9IC1tYXhwb3AsCiAgICBtYXggPSBtYXhwb3ApICU+JSAKICBoY194QXhpcygKICAgIHhheGlzLAogICAgcmxpc3Q6Omxpc3QubWVyZ2UoeGF4aXMsIGxpc3Qob3Bwb3NpdGUgPSBUUlVFLCBsaW5rZWRUbyA9IDApKQogICkgJT4lIAogIGhjX3Rvb2x0aXAoc2hhcmVkID0gRkFMU0UsCiAgICAgICAgICAgICBmb3JtYXR0ZXIgPSBKUygiZnVuY3Rpb24gKCkgeyByZXR1cm4gJzxiPicgKyB0aGlzLnNlcmllcy5uYW1lICsgJywgYWdlICcgKyB0aGlzLnBvaW50LmNhdGVnb3J5ICsgJzwvYj48YnIvPicgKyAnUG9wdWxhdGlvbjogJyArIEhpZ2hjaGFydHMubnVtYmVyRm9ybWF0KE1hdGguYWJzKHRoaXMucG9pbnQueSksIDApO30iKQogICkgCmBgYAoKCgoKYGBge3J9CmRhdGEoImNpdHl0ZW1wIikKCmhpZ2hjaGFydCgpICU+JSAKICBoY19jaGFydChhbmltYXRpb24gPSBGQUxTRSkgJT4lIAogIGhjX3RpdGxlKHRleHQgPSAiZHJhZ2dhYmxlIHBvaW50cyBkZW1vIikgJT4lIAogIGhjX3N1YnRpdGxlKHRleHQgPSAiRHJhbmcgbXkgcG9pbnRzIHBseiIpICU+JSAKICBoY194QXhpcyhjYXRlZ29yaWVzID0gbW9udGguYWJiKSAlPiUgCiAgaGNfcGxvdE9wdGlvbnMoCiAgICBzZXJpZXMgPSBsaXN0KAogICAgICBwb2ludCA9IGxpc3QoCiAgICAgICAgZXZlbnRzID0gbGlzdCgKICAgICAgICAgIGRyb3AgPSBKUygiZnVuY3Rpb24oKXsKICAgICAgICAgICAgICAgICAgICBhbGVydCh0aGlzLnNlcmllcy5uYW1lICsgJyAnICsgdGhpcy5jYXRlZ29yeSArICcgJyArIEhpZ2hjaGFydHMubnVtYmVyRm9ybWF0KHRoaXMueSwgMikpCiAgICAgICAgICAgICAgICAgICAgfSIpCiAgICAgICAgKQogICAgICAgICAgKSwKICAgICAgc3RpY2t5VHJhY2tpbmcgPSBGQUxTRQogICAgICAgICksCiAgICBjb2x1bW4gPSBsaXN0KAogICAgICBzdGFja2luZyA9ICJub3JtYWwiCiAgICApLAogICAgbGluZSA9IGxpc3QoCiAgICAgIGN1cnNvciA9ICJucy1yZXNpemUiCiAgICApCiAgICApICU+JSAKICBoY190b29sdGlwKHlEZWNpbWFscyA9IDIpICU+JSAKICBoY19hZGRfc2VyaWVzKAogICAgZGF0YSA9IGNpdHl0ZW1wJHRva3lvLAogICAgZHJhZ2dhYmxlWSA9IFRSVUUsCiAgICBkcmFnTWluWSA9IDAsCiAgICB0eXBlID0gImNvbHVtbiIsCiAgICBtaW5Qb2ludExlbmd0aCA9IDIKICApICU+JSAKICBoY19hZGRfc2VyaWVzKAogICAgZGF0YSA9IGNpdHl0ZW1wJG5ld195b3JrLAogICAgZHJhZ2dhYmxlWSA9IFRSVUUsCiAgICBkcmFnTWluWSA9IDAsCiAgICB0eXBlID0gImNvbHVtbiIsCiAgICBtaW5Qb2ludExlbmd0aCA9IDIKICApICU+JSAKICBoY19hZGRfc2VyaWVzKAogICAgZGF0YSA9IGNpdHl0ZW1wJGJlcmxpbiwKICAgIGRyYWdnYWJsZVkgPSBUUlVFCiAgKQpgYGAKCgoKCiMjIyMgR3JvdXBlZCBDYXRlZ29yaWVzCgpgYGB7cn0KbGlicmFyeShwdXJycikgIyBtYXAgZnVuY3Rpb24gdG8gbWFrZSBncm91cGVkIGNhdGVnb3JpZXMgYXJndW1lbnQKbGlicmFyeShkcGx5cikgIyBmb3Igc2VsZWN0IGZ1bmN0aW9uIAoKZGF0YShtcGcsIHBhY2thZ2UgPSAiZ2dwbG90MiIpCgptcGdnIDwtIG1wZyAlPiUgCiAgZmlsdGVyKGNsYXNzICVpbiUgYygic3V2IiwgImNvbXBhY3QiLCAibWlkc2l6ZSIpKSAlPiUgCiAgZ3JvdXBfYnkoY2xhc3MsIG1hbnVmYWN0dXJlcikgJT4lIAogIHN1bW1hcml6ZShjb3VudCA9IG4oKSkKCmNhdGVnb3JpZXNfZ3JvdXBlZCA8LSBtcGdnICU+JSAKICBncm91cF9ieShuYW1lID0gY2xhc3MpICU+JSAKICBkbyhjYXRlZ29yaWVzID0gLiRtYW51ZmFjdHVyZXIpICU+JSAKICBsaXN0X3BhcnNlKCkKCmhpZ2hjaGFydCgpICU+JSAKICBoY194QXhpcyhjYXRlZ29yaWVzID0gY2F0ZWdvcmllc19ncm91cGVkKSAlPiUgCiAgaGNfYWRkX3NlcmllcyhkYXRhID0gbXBnZywgdHlwZSA9ICJiYXIiLCBoY2Flcyh5ID0gY291bnQsIGNvbG9yID0gbWFudWZhY3R1cmVyKSwKICAgICAgICAgICAgICAgIHNob3dJbkxlZ2VuZCA9IEZBTFNFKQpgYGAKCgoKYGBge3J9CmRhdGEobXBnLCBwYWNrYWdlID0gImdncGxvdDIiKQptcGdtYW4gPC0gbXBnICU+JSAKICBncm91cF9ieShtYW51ZmFjdHVyZXIpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSwKICAgICAgICAgICAgdW5pcXVlID0gbGVuZ3RoKHVuaXF1ZShtb2RlbCkpKSAlPiUgCiAgYXJyYW5nZSgtbiwgLXVuaXF1ZSkKCmhlYWQobXBnbWFuKQpgYGAKCgoKCmBgYHtyfQoKZGlhbW9uZHMlPiVoZWFkKCkKCmhpZ2hjaGFydCgpICU+JQogIGhjX2FkZF9zZXJpZXMoZGF0YT1kaWFtb25kcywgdHlwZSA9ICJzY2F0dGVyIiwKICAgICAgICAgICAgICAgIGhjYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlLCBzaXplID0gZGVwdGgsIGdyb3VwID0gY3V0KSkgCmBgYAoK