1 Introduction

This RMarkdown document is part of the Generic Skills Component (GSK) of the Course of the Foundation Studies Programme at Srishti Manipal Institute of Art, Design, and Technology, Bangalore India. The material is based on A Layered Grammar of Graphics by Hadley Wickham. The course is meant for First Year students pursuing a Degree in Art and Design.

The intent of this GSK part is to build Skill in coding in R, and also appreciate R as a way to metaphorically visualize information of various kinds, using predominantly geometric figures and structures.

All RMarkdown files combine code, text, web-images, and figures developed using code. Everything is text; code chunks are enclosed in fences (```)

2 Goals

  • (Re)Understand different kinds of data variables
  • Appreciate how they can be identified based on the Interrogative Pronouns they answer to
  • Understand how each kind of variable lends itself to a specific choice of colour scale in the data visualization.

3 Pedagogical Note

The method followed will be based on PRIMM:

  • PREDICT Inspect the code and guess at what the code might do, write predictions
  • RUN the code provided and check what happens
  • INFER what the parameters of the code do and write comments to explain. What bells and whistles can you see?
  • MODIFY the parameters code provided to understand the options available. Write comments to show what you have aimed for and achieved.
  • MAKE : take an idea/concept of your own, and graph it.

In the following, there is some boiler plate code demonstrating the use of colour palettes in R. There are places where YOUR TURN is mention; copy and play with the boiler plate code to see what happens !

4 Data

We will use the penguins dataset built into the palmerpenguins package. Your should try other datasets too!

Here is a glimpse of the data:

glimpse(penguins)
Rows: 344
Columns: 8
$ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie…
$ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgersen, Torgersen, Torgersen, Torgersen, Torgersen, Tor…
$ bill_length_mm    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, 42.0, 37.8, 37.8, 41.1, 38.6, 34.6, 36.6, 38.7, 42…
$ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, 20.2, 17.1, 17.3, 17.6, 21.2, 21.1, 17.8, 19.0, 20…
$ flipper_length_mm <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186, 180, 182, 191, 198, 185, 195, 197, 184, 194, 174…
$ body_mass_g       <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, 4250, 3300, 3700, 3200, 3800, 4400, 3700, 3450, 45…
$ sex               <fct> male, female, female, NA, female, male, female, male, NA, NA, NA, NA, female, male, male, female, fema…
$ year              <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, …

Note that the unit of observation here is one-row-per-penguin.

Variables you need for this lab:

5 Colour vs fill aesthetic

Fill and colour scales in ggplot2 can use the same palettes. Some shapes such as lines only accept the colour aesthetic, while others, such as polygons, accept both colour and fill aesthetics. In the latter case, the colour refers to the border of the shape, and the fill to the interior.

## A look at all 25 symbols
df <- data.frame(x = 1:5,
                 y = rep(rev(seq(0, 24, by = 5)), each = 5),
                 z = 1:25)
s <- ggplot(df, aes(x = x, y = y)) +
  geom_text(aes(label = z, y = y - 1)) +
  theme_void()
s + geom_point(aes(shape = z), size = 4) + scale_shape_identity()

All symbols have a foreground colour, so if we add color = "navy", they all are affected.

s + geom_point(aes(shape = z), size = 4, colour = "blue")  + scale_shape_identity()

While all symbols have a foreground colour, symbols 21-25 also take a background colour (fill). So if we add fill = "orchid", only the last row of symbols are affected.

s + geom_point(aes(shape = z), size = 4, colour = "blue", fill = "orchid")  + scale_shape_identity()

6 Discrete vs continuous variables

WHAT IS THE DIFFERENCE BETWEEN CATEGORICAL, ORDINAL AND INTERVAL VARIABLES?

In order to use color with your data, most importantly, you need to know if you’re dealing with discrete or continuous variables.

6.1 Some Colour Palette Packages in R

We have the following example packages that offer palettes in R:

  • RColorBrewer
  • wesanderson
  • paletteer
  • colorspace

See Appendix for a detailed graphical analysis of these palette packages.

6.2 Colour Palette Types

These palettes can be:

Sequential (type = “seq”) palettes are suited to ordered data that progress from low to high. Lightness steps dominate the look of these schemes, with light colors for low data values to dark colors for high data values. (for numerical data, that are ordered)

Diverging (type = “div”) palettes put equal emphasis on mid-range critical values and extremes at both ends of the data range. The critical class or break in the middle of the legend is emphasized with light colors and low and high extremes are emphasized with dark colors that have contrasting hues.(for numerical data that can be positive or negative, often representing deviations from some norm or baseline)

Qualitative (type = “qual”) palettes do not imply magnitude differences between legend classes, and hues are used to create the primary visual differences between classes. Qualitative schemes are best suited to representing nominal or categorical data. (for qualitative unordered data)

6.3 Create a simple set of scatter plots

We will create simple base plots in ggplot and see how we may alter the colour scales using palettes.

names(penguins)
[1] "species"           "island"            "bill_length_mm"    "bill_depth_mm"     "flipper_length_mm" "body_mass_g"      
[7] "sex"               "year"             
p1 <- penguins %>% 
  drop_na() %>% 
  # pipe data into ggplot
  # after removing data rows that have missing ( NA ) values
  ggplot(aes(y = body_mass_g, x = flipper_length_mm, 
           color = species # COLOUR = DISCRETE/QUAL VARIABLE
           )) +
           geom_point() + 
           labs(title = "Default Colours in ggplot", 
                subtitle = "P1: DISCRETE/QUAL Colour Palette")


p2 <- 
penguins %>% 
  drop_na() %>% 
  # pipe the data into ggplot, 
  # after removing data rows that have missing ( NA ) values
  ggplot(aes(y = body_mass_g, x = flipper_length_mm, 
           color = bill_length_mm # COLOUR = CONT/QUANT VARIABLE
           )) +
           geom_point() + 
           labs(title = "Default Colours in ggplot", 
                subtitle = "P2: CONTINUOUS/QUANT Colour Palette")

p1

p2

Note that these use the default colours in R.

7 Colours for Discrete (QUAL) Variables

The commands below are used to fill colours based on Qualitative Variables:

  1. scale_colour/fill_discrete
  2. scale_colour/fill_brewer # RColorBrewer
  3. ….

Now to use these!

8 Plotting Colours based on Discrete Variables

8.1 Discrete n-Colour palettes from RColorBrewer

RColorBrewer::brewer.pal.info
         maxcolors category colorblind
BrBG            11      div       TRUE
PiYG            11      div       TRUE
PRGn            11      div       TRUE
PuOr            11      div       TRUE
RdBu            11      div       TRUE
RdGy            11      div      FALSE
RdYlBu          11      div       TRUE
RdYlGn          11      div      FALSE
Spectral        11      div      FALSE
Accent           8     qual      FALSE
Dark2            8     qual       TRUE
Paired          12     qual       TRUE
Pastel1          9     qual      FALSE
Pastel2          8     qual      FALSE
Set1             9     qual      FALSE
Set2             8     qual       TRUE
Set3            12     qual      FALSE
Blues            9      seq       TRUE
BuGn             9      seq       TRUE
BuPu             9      seq       TRUE
GnBu             9      seq       TRUE
Greens           9      seq       TRUE
Greys            9      seq       TRUE
Oranges          9      seq       TRUE
OrRd             9      seq       TRUE
PuBu             9      seq       TRUE
PuBuGn           9      seq       TRUE
PuRd             9      seq       TRUE
Purples          9      seq       TRUE
RdPu             9      seq       TRUE
Reds             9      seq       TRUE
YlGn             9      seq       TRUE
YlGnBu           9      seq       TRUE
YlOrBr           9      seq       TRUE
YlOrRd           9      seq       TRUE
RColorBrewer::display.brewer.all()

p1 +
  # default palette = "Blues"
  scale_colour_brewer() +
  labs(title = "Brewer Palette = Blues")

p1 +
  scale_color_brewer(palette = "Spectral") +
  labs(title = "Brewer Palette = Spectral") 

8.2 Discrete Colour scales using wesanderson palettes

wesanderson::wes_palettes %>% names()
 [1] "BottleRocket1"  "BottleRocket2"  "Rushmore1"      "Rushmore"       "Royal1"         "Royal2"         "Zissou1"       
 [8] "Darjeeling1"    "Darjeeling2"    "Chevalier1"     "FantasticFox1"  "Moonrise1"      "Moonrise2"      "Moonrise3"     
[15] "Cavalcanti1"    "GrandBudapest1" "GrandBudapest2" "IsleofDogs1"    "IsleofDogs2"   
p1 +
  scale_colour_discrete(type = wes_palette(name = "GrandBudapest1",
                                           n = 3)) +
  labs(title = "Wes Anderson Palette: GrandBudapest")

# We can also specify colour codes ourselves with scale_x_discrete.
# Use argument "values" instead of "type"
manual_colours <- c("#afc4b8", "#f1a4b2", "#ffb1e1") 
manual_colours
[1] "#afc4b8" "#f1a4b2" "#ffb1e1"
p1 +
  scale_colour_manual(values =  manual_colours) +
  labs(title = "Manual Colours")

8.3 Discrete n-Colour palettes from RColorBrewer

# scale_x_brewer() for DISCRETE data
p1 +
  scale_colour_brewer(palette = "Spectral") +
  
  labs(title = "RColorBrewer Palette = Spectral")

8.4 Discrete Colour scales using paletteer palettes

palettes_d_names
# A tibble: 2,037 × 5
   package   palette   length type        novelty
   <chr>     <chr>      <int> <chr>       <lgl>  
 1 awtools   a_palette      8 sequential  TRUE   
 2 awtools   ppalette       8 qualitative TRUE   
 3 awtools   bpalette      16 qualitative TRUE   
 4 awtools   gpalette       4 sequential  TRUE   
 5 awtools   mpalette       9 qualitative TRUE   
 6 awtools   spalette       6 qualitative TRUE   
 7 basetheme brutal        10 qualitative TRUE   
 8 basetheme clean         10 qualitative TRUE   
 9 basetheme dark          10 qualitative TRUE   
10 basetheme deepblue      10 qualitative TRUE   
# … with 2,027 more rows
# ℹ Use `print(n = ...)` to see more rows
palettes_dynamic_names
              package       palette length        type
1         cartography      blue.pal     20  sequential
2         cartography    orange.pal     20  sequential
3         cartography       red.pal     20  sequential
4         cartography     brown.pal     20  sequential
5         cartography     green.pal     20  sequential
6         cartography    purple.pal     20  sequential
7         cartography      pink.pal     20  sequential
8         cartography      wine.pal     20  sequential
9         cartography      grey.pal     20  sequential
10        cartography turquoise.pal     20  sequential
11        cartography      sand.pal     20  sequential
12        cartography     taupe.pal     20  sequential
13        cartography      kaki.pal     20  sequential
14        cartography     harmo.pal     20  sequential
15        cartography    pastel.pal     20 qualitative
16        cartography     multi.pal     20 qualitative
17      ggthemes_ptol   qualitative     12 qualitative
18 ggthemes_solarized        yellow      8 qualitative
19 ggthemes_solarized        orange      8 qualitative
20 ggthemes_solarized           red      8 qualitative
21 ggthemes_solarized       magenta      8 qualitative
22 ggthemes_solarized        violet      8 qualitative
23 ggthemes_solarized          blue      8 qualitative
24 ggthemes_solarized          cyan      8 qualitative
25 ggthemes_solarized         green      8 qualitative
paletteer_d("dutchmasters::pearl_earring")
<colors>
#A65141FF #E7CDC2FF #80A0C7FF #394165FF #FCF9F0FF #B1934AFF #DCA258FF #100F14FF #8B9DAFFF #EEDA9DFF #E8DCCFFF 
paletteer_dynamic("ggthemes_ptol::qualitative", n = 3)
<colors>
#4477AAFF #DDCC77FF #CC6677FF 
p1 +
  scale_colour_paletteer_d("ggthemes_ptol::qualitative", 
                           dynamic = TRUE) +
  
  labs(title = "ggThemes Palette: Qualitative", 
          subtitle = "")

# I like Vermeer's "Girl with the Pearl Earring"!
p1 +
  scale_colour_paletteer_d("dutchmasters::pearl_earring",
                           dynamic = FALSE) +
  
  labs(title = "Palettes from `paletteer`", 
          subtitle = " Palette from Vermeer: Girl with Pearl Earring")

9 Colours for Continuous (QUANT) Variables

The commands below are used to fill colours based on Quantitative Variables:

  1. scale_colour/fill_gradient (Two colour gradient)
  2. scale_colour/fill_gradient2 (Three colour gradient)
  3. scale_colour/fill_gradientn (Specify Palette, from other packages also, like wesanderson )
  4. scale_colour/fill_distiller (Palettes from RColorBrewer)

10 Plotting Colours based on Continuous Variables

10.1 Continuous Two Colour Gradients

Creates a pallete containing continuous shades between two colours:

p2 +
    scale_color_gradient(
      low = "yellow", # Play with this in the chunk below
      high = "purple") + # Play with this in the chnk below
  
  labs(title = "Two Colour Gradients",
          subtitle = "P2: Continuous 2-Colour Pallete")

10.2 Continuous Three Colour Gradients

Sometimes we want a palette this way: a midpoint colour, and colours for the two extremes of a continuous variable:

colour_midpoint <- mean(penguins$bill_length_mm, 
                         na.rm = TRUE) # remove missing values
# Struggled all morning on 22 Aug 2020 to get at this ;-D

# Play with the function: 0/mean/median/mode/max/min

p2 +
  scale_colour_gradient2(
  low = "brown", # Play with this in the chunk below
  mid = "white", # Play with this in the chunk below
  high = "purple", # Play with this in the chunk below
  midpoint = colour_midpoint, # see above
  space = "Lab", # don't mess with this!
  na.value = "grey50")  +
  labs(title = "Three colour continuous gradient", 
          subtitle = "Mid Colour mapped to midpoint of data variable",
          caption = "Colours inspired by my favourite cocker spaniel, Lord Chestnut") # Play with these

10.3 Continuous n-Colour Gradients - grDevices package

# grDevices Palettes
p2 +
  scale_colour_gradientn(
    colours = terrain.colors(10)) +
  # Try these:
  # heat.colors() / topo.colors() / cm.colors() / rainbow()
  
  labs(title = "N-colour continuous gradients", 
          subtitle = "Palettes from grDevices",
          caption = "Palette: terrain.colors")

10.4 Continuous n-Colour Gradients - wesanderson Palettes

wes_palettes
$BottleRocket1
[1] "#A42820" "#5F5647" "#9B110E" "#3F5151" "#4E2A1E" "#550307" "#0C1707"

$BottleRocket2
[1] "#FAD510" "#CB2314" "#273046" "#354823" "#1E1E1E"

$Rushmore1
[1] "#E1BD6D" "#EABE94" "#0B775E" "#35274A" "#F2300F"

$Rushmore
[1] "#E1BD6D" "#EABE94" "#0B775E" "#35274A" "#F2300F"

$Royal1
[1] "#899DA4" "#C93312" "#FAEFD1" "#DC863B"

$Royal2
[1] "#9A8822" "#F5CDB4" "#F8AFA8" "#FDDDA0" "#74A089"

$Zissou1
[1] "#3B9AB2" "#78B7C5" "#EBCC2A" "#E1AF00" "#F21A00"

$Darjeeling1
[1] "#FF0000" "#00A08A" "#F2AD00" "#F98400" "#5BBCD6"

$Darjeeling2
[1] "#ECCBAE" "#046C9A" "#D69C4E" "#ABDDDE" "#000000"

$Chevalier1
[1] "#446455" "#FDD262" "#D3DDDC" "#C7B19C"

$FantasticFox1
[1] "#DD8D29" "#E2D200" "#46ACC8" "#E58601" "#B40F20"

$Moonrise1
[1] "#F3DF6C" "#CEAB07" "#D5D5D3" "#24281A"

$Moonrise2
[1] "#798E87" "#C27D38" "#CCC591" "#29211F"

$Moonrise3
[1] "#85D4E3" "#F4B5BD" "#9C964A" "#CDC08C" "#FAD77B"

$Cavalcanti1
[1] "#D8B70A" "#02401B" "#A2A475" "#81A88D" "#972D15"

$GrandBudapest1
[1] "#F1BB7B" "#FD6467" "#5B1A18" "#D67236"

$GrandBudapest2
[1] "#E6A0C4" "#C6CDF7" "#D8A499" "#7294D4"

$IsleofDogs1
[1] "#9986A5" "#79402E" "#CCBA72" "#0F0D0E" "#D9D0D3" "#8D8680"

$IsleofDogs2
[1] "#EAD3BF" "#AA9486" "#B6854D" "#39312F" "#1C1718"
names(wes_palettes)
 [1] "BottleRocket1"  "BottleRocket2"  "Rushmore1"      "Rushmore"       "Royal1"         "Royal2"         "Zissou1"       
 [8] "Darjeeling1"    "Darjeeling2"    "Chevalier1"     "FantasticFox1"  "Moonrise1"      "Moonrise2"      "Moonrise3"     
[15] "Cavalcanti1"    "GrandBudapest1" "GrandBudapest2" "IsleofDogs1"    "IsleofDogs2"   
p2 +
    scale_colour_gradientn(
      colors = wes_palette(name = "GrandBudapest1", 
                           n = 4), # Keep an eye on "n".
      na.value = "grey") +
  # Try these:
  # "BottleRocket1"  "BottleRocket2"  "Rushmore1"
  # "Rushmore"       "Royal1"         "Royal2"
  # "Zissou1"        "Darjeeling1"    "Darjeeling2"   
  # "Chevalier1"     "FantasticFox1"  "Moonrise1"     
  # "Moonrise2"      "Moonrise3"      "Cavalcanti1"   
  # "GrandBudapest1" "GrandBudapest2" "IsleofDogs1"   
  # "IsleofDogs2"   
  # Keep an eye on "n".
  
  labs(title = "N-colour continuous gradients", 
       subtitle = "Palettes from wesanderson",
       caption = "Palette: GrandBudapest1") # Change this caption based on palette choice

10.5 Continuous n-Colour palettes from RColorBrewer

Recall Palette types

  • seq for continuous data mapped to colour
  • qual for categorical data mapped to colour ( discrete)
  • div continuous data mapped to colour, that has pos and neg extremes from a middle value
brewer.pal.info
         maxcolors category colorblind
BrBG            11      div       TRUE
PiYG            11      div       TRUE
PRGn            11      div       TRUE
PuOr            11      div       TRUE
RdBu            11      div       TRUE
RdGy            11      div      FALSE
RdYlBu          11      div       TRUE
RdYlGn          11      div      FALSE
Spectral        11      div      FALSE
Accent           8     qual      FALSE
Dark2            8     qual       TRUE
Paired          12     qual       TRUE
Pastel1          9     qual      FALSE
Pastel2          8     qual      FALSE
Set1             9     qual      FALSE
Set2             8     qual       TRUE
Set3            12     qual      FALSE
Blues            9      seq       TRUE
BuGn             9      seq       TRUE
BuPu             9      seq       TRUE
GnBu             9      seq       TRUE
Greens           9      seq       TRUE
Greys            9      seq       TRUE
Oranges          9      seq       TRUE
OrRd             9      seq       TRUE
PuBu             9      seq       TRUE
PuBuGn           9      seq       TRUE
PuRd             9      seq       TRUE
Purples          9      seq       TRUE
RdPu             9      seq       TRUE
Reds             9      seq       TRUE
YlGn             9      seq       TRUE
YlGnBu           9      seq       TRUE
YlOrBr           9      seq       TRUE
YlOrRd           9      seq       TRUE
# scale_color_distiller() and scale_fill_distiller() 
# are used to apply the ColorBrewer colour scales 
# to continuous data.

p2 +
  scale_colour_distiller(
    palette = "YlGnBu") + # Play with this palette
  
  labs(title = "RColorBrewer Palette")

10.6 Continuous Colour scales using paletteer palettes

This palette seems to have everything accessible in a simple way! NOTE: In order to access some palettes in paletteer, you may be asked to install other packages. E.g. harrypotter or scico. These need not be brought into your session using library() but are accessed directly by paletteer which is very convenient!!

# What continuous palettes are there in paletteer?
paletteer::palettes_c_names
# A tibble: 330 × 3
   package       palette    type      
   <chr>         <chr>      <chr>     
 1 gameofthrones targaryen  sequential
 2 gameofthrones targaryen2 sequential
 3 gameofthrones stark      sequential
 4 gameofthrones stark2     sequential
 5 gameofthrones lannister  sequential
 6 gameofthrones martell    sequential
 7 gameofthrones tully      diverging 
 8 gameofthrones greyjoy    sequential
 9 gameofthrones baratheon  sequential
10 gameofthrones baratheon2 sequential
# … with 320 more rows
# ℹ Use `print(n = ...)` to see more rows

OK, one of the Games of Thrones Palettes, and Harry Potter!

p2 +
  scale_colour_paletteer_c("gameofthrones::jon_snow") +
  labs(title = "Using Paletteer",
       subtitle = "Continuous Palette-Game of Thrones: Jon Snow",
       caption = "Oh you awful Srishti people...") +
  
  # Harry Potter Gryffindor Palette.
  # Will ask for `harrypotter` package to be installed. Say yes!
  p2 +
  scale_colour_paletteer_c("harrypotter::gryffindor") +
  labs(title = "Using Paletteer",
       subtitle = "Continuous Palette-Harry Potter:Gryffindor")

LS0tDQp0aXRsZTogIkxhYiAwNTogQ29sb3JzIHdpdGggUGVuZ3VpbnMiDQpzdWJ0aXRsZTogIlBhbGV0dGVzIGZyb20gRmFtb3VzIFBhaW50aW5ncywgR29ULCBIYXJyeSBQb3R0ZXIsIGFuZCBXZXMgQW5kZXJzb24iDQphdXRob3I6ICJBcnZpbmQgVmVua2F0YWRyaSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgdG9jX2RlcHRoOiAyDQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0UsIGNhY2hlID0gRkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3IgPSBUUlVFLCBjb21tZW50ID0gTkEsIHdhcm5pbmcgPSBGQUxTRSwgZXJyb3JzID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgdGlkeSA9IEZBTFNFLCBjYWNoZSA9IEZBTFNFLCBmaWcucGF0aD0gIjAzLWZpZ3MvIikNCg0KbGlicmFyeSh0aWR5dmVyc2UpICMgTWFuYWdlIGRhdGENCmxpYnJhcnkoc2NhbGVzKSAjIENyZWF0ZSBzcGVjaWFsICggJSBvciAkICkgc2NhbGVzDQojDQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKSAjIHNvdXJjZSBvZiBvdXIgZGF0YQ0KIw0KbGlicmFyeShSQ29sb3JCcmV3ZXIpICMgQ29sb3VyIFBhbGV0dGVzDQpsaWJyYXJ5KHdlc2FuZGVyc29uKSAjIENvbG91ciBQYWxldHRlcw0KI2xpYnJhcnkoZ2FtZW9mdGhyb25lcykgIyBZb3UgYWxsIGtub3cgdGhpcyENCiMNCmxpYnJhcnkocGFsZXR0ZWVyKSAjIENvbG91ciBQYWxldHRlcw0KbGlicmFyeShjb2xvcnNwYWNlKSAjIENvbG91ciBQYWxldHRlcw0KIw0KbGlicmFyeShwYXRjaHdvcmspICMgYXJyYW5nZXMgcGxvdHMgb24gUm93LUNvbCANCmxpYnJhcnkoZ2d0aGVtZXMpDQoNCmBgYA0KDQojIEludHJvZHVjdGlvbg0KDQpUaGlzIFJNYXJrZG93biBkb2N1bWVudCBpcyBwYXJ0IG9mIHRoZSBHZW5lcmljIFNraWxscyBDb21wb25lbnQgIChHU0spIG9mIHRoZSBDb3Vyc2Ugb2YgdGhlICBGb3VuZGF0aW9uIFN0dWRpZXMgUHJvZ3JhbW1lIGF0IFNyaXNodGkgTWFuaXBhbCBJbnN0aXR1dGUgb2YgQXJ0LCBEZXNpZ24sIGFuZCBUZWNobm9sb2d5LCBCYW5nYWxvcmUgSW5kaWEuIFRoZSBtYXRlcmlhbCBpcyBiYXNlZCBvbiAqQSBMYXllcmVkIEdyYW1tYXIgb2YgR3JhcGhpY3MqIGJ5IEhhZGxleSBXaWNraGFtLiBUaGUgY291cnNlIGlzIG1lYW50IGZvciBGaXJzdCBZZWFyIHN0dWRlbnRzIHB1cnN1aW5nIGEgRGVncmVlIGluIEFydCBhbmQgRGVzaWduLiANCg0KVGhlIGludGVudCBvZiB0aGlzIEdTSyBwYXJ0IGlzIHRvIGJ1aWxkIFNraWxsIGluIGNvZGluZyBpbiBSLCBhbmQgYWxzbyBhcHByZWNpYXRlIFIgYXMgYSB3YXkgdG8gbWV0YXBob3JpY2FsbHkgdmlzdWFsaXplIGluZm9ybWF0aW9uIG9mIHZhcmlvdXMga2luZHMsIHVzaW5nIHByZWRvbWluYW50bHkgZ2VvbWV0cmljIGZpZ3VyZXMgYW5kIHN0cnVjdHVyZXMuDQoNCkFsbCBSTWFya2Rvd24gZmlsZXMgY29tYmluZSBjb2RlLCB0ZXh0LCB3ZWItaW1hZ2VzLCBhbmQgZmlndXJlcyBkZXZlbG9wZWQgdXNpbmcgY29kZS4gRXZlcnl0aGluZyBpcyB0ZXh0OyBjb2RlIGNodW5rcyBhcmUgZW5jbG9zZWQgaW4gKipmZW5jZXMqKiAoYGBgKQ0KDQojIEdvYWxzDQoNCi0gKFJlKVVuZGVyc3RhbmQgZGlmZmVyZW50IGtpbmRzIG9mIGRhdGEgdmFyaWFibGVzDQotIEFwcHJlY2lhdGUgaG93IHRoZXkgY2FuIGJlIGlkZW50aWZpZWQgYmFzZWQgb24gdGhlICpJbnRlcnJvZ2F0aXZlIFByb25vdW5zKiB0aGV5IGFuc3dlciB0bw0KLSBVbmRlcnN0YW5kIGhvdyBlYWNoIGtpbmQgb2YgdmFyaWFibGUgbGVuZHMgaXRzZWxmIHRvIGEgc3BlY2lmaWMgY2hvaWNlIG9mICoqY29sb3VyIHNjYWxlKiogaW4gdGhlIGRhdGEgdmlzdWFsaXphdGlvbi4NCg0KDQojIFBlZGFnb2dpY2FsIE5vdGUNCg0KVGhlIG1ldGhvZCBmb2xsb3dlZCB3aWxsIGJlIGJhc2VkIG9uDQpbUFJJTU1dKGh0dHBzOi8vYmxvZ3Mua2NsLmFjLnVrL2NzZXIvMjAxNy8wOS8wMS9wcmltbS1hLXN0cnVjdHVyZWQtYXBwcm9hY2gtdG8tdGVhY2hpbmctcHJvZ3JhbW1pbmcvKToNCg0KLSAgICoqUFJFRElDVCoqIEluc3BlY3QgdGhlIGNvZGUgYW5kIGd1ZXNzIGF0IHdoYXQgdGhlIGNvZGUgbWlnaHQgZG8sDQogICAgKip3cml0ZSBwcmVkaWN0aW9ucyoqDQotICAgKipSVU4qKiB0aGUgY29kZSBwcm92aWRlZCBhbmQgY2hlY2sgd2hhdCBoYXBwZW5zDQotICAgKipJTkZFUioqIHdoYXQgdGhlIGBwYXJhbWV0ZXJzYCBvZiB0aGUgY29kZSBkbyBhbmQgKip3cml0ZSBjb21tZW50cyB0byBleHBsYWluKiouIFdoYXQgYmVsbHMgYW5kIHdoaXN0bGVzIGNhbiB5b3Ugc2VlPw0KLSAgICoqTU9ESUZZKiogdGhlIGBwYXJhbWV0ZXJzYCBjb2RlIHByb3ZpZGVkIHRvIHVuZGVyc3RhbmQgdGhlDQogICAgYG9wdGlvbnNgIGF2YWlsYWJsZS4gKipXcml0ZSBjb21tZW50cyoqIHRvIHNob3cgd2hhdCB5b3UgaGF2ZSBhaW1lZCBmb3IgYW5kIGFjaGlldmVkLg0KLSAgICoqTUFLRSoqIDogdGFrZSBhbiBpZGVhL2NvbmNlcHQgb2YgeW91ciBvd24sIGFuZCBncmFwaCBpdC4NCg0KSW4gdGhlIGZvbGxvd2luZywgdGhlcmUgaXMgc29tZSBib2lsZXIgcGxhdGUgY29kZSBkZW1vbnN0cmF0aW5nIHRoZSB1c2Ugb2YgY29sb3VyIHBhbGV0dGVzIGluIFIuIFRoZXJlIGFyZSBwbGFjZXMgd2hlcmUgKipZT1VSIFRVUk4qKiBpcyBtZW50aW9uOyBjb3B5IGFuZCBwbGF5IHdpdGggdGhlIGJvaWxlciBwbGF0ZSBjb2RlIHRvIHNlZSB3aGF0IGhhcHBlbnMgIQ0KDQojIERhdGENCg0KV2Ugd2lsbCB1c2UgdGhlIGBwZW5ndWluc2AgZGF0YXNldCBidWlsdCBpbnRvIHRoZSBgcGFsbWVycGVuZ3VpbnNgIHBhY2thZ2UuIFlvdXIgc2hvdWxkIHRyeSBvdGhlciBkYXRhc2V0cyB0b28hDQoNCkhlcmUgaXMgYSBnbGltcHNlIG9mIHRoZSBkYXRhOg0KDQpgYGB7cn0NCg0KZ2xpbXBzZShwZW5ndWlucykNCg0KYGBgDQoNCk5vdGUgdGhhdCB0aGUgdW5pdCBvZiBvYnNlcnZhdGlvbiBoZXJlIGlzIG9uZS1yb3ctcGVyLXBlbmd1aW4uDQoNClZhcmlhYmxlcyB5b3UgbmVlZCBmb3IgdGhpcyBsYWI6DQoNCiFbXShodHRwczovL2FsbGlzb25ob3JzdC5naXRodWIuaW8vcGFsbWVycGVuZ3VpbnMvcmVmZXJlbmNlL2ZpZ3VyZXMvbHRlcl9wZW5ndWlucy5wbmcpDQoNCiFbXShodHRwczovL2FsbGlzb25ob3JzdC5naXRodWIuaW8vcGFsbWVycGVuZ3VpbnMvcmVmZXJlbmNlL2ZpZ3VyZXMvY3VsbWVuX2RlcHRoLnBuZykNCg0KDQojIENvbG91ciB2cyBmaWxsIGFlc3RoZXRpYw0KDQpGaWxsIGFuZCBjb2xvdXIgc2NhbGVzIGluIGdncGxvdDIgY2FuIHVzZSB0aGUgc2FtZSBwYWxldHRlcy4gU29tZSBzaGFwZXMgc3VjaCBhcyBsaW5lcyBvbmx5IGFjY2VwdCB0aGUgY29sb3VyIGFlc3RoZXRpYywgd2hpbGUgb3RoZXJzLCBzdWNoIGFzIHBvbHlnb25zLCBhY2NlcHQgYm90aCBjb2xvdXIgYW5kIGZpbGwgYWVzdGhldGljcy4gSW4gdGhlIGxhdHRlciBjYXNlLCB0aGUgY29sb3VyIHJlZmVycyB0byB0aGUgYm9yZGVyIG9mIHRoZSBzaGFwZSwgYW5kIHRoZSBmaWxsIHRvIHRoZSBpbnRlcmlvci4NCg0KDQoNCmBgYHtyfQ0KDQojIyBBIGxvb2sgYXQgYWxsIDI1IHN5bWJvbHMNCmRmIDwtIGRhdGEuZnJhbWUoeCA9IDE6NSwNCiAgICAgICAgICAgICAgICAgeSA9IHJlcChyZXYoc2VxKDAsIDI0LCBieSA9IDUpKSwgZWFjaCA9IDUpLA0KICAgICAgICAgICAgICAgICB6ID0gMToyNSkNCnMgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IHgsIHkgPSB5KSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0geiwgeSA9IHkgLSAxKSkgKw0KICB0aGVtZV92b2lkKCkNCnMgKyBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHopLCBzaXplID0gNCkgKyBzY2FsZV9zaGFwZV9pZGVudGl0eSgpDQoNCmBgYA0KDQoNCkFsbCBzeW1ib2xzIGhhdmUgYSBmb3JlZ3JvdW5kIGNvbG91ciwgc28gaWYgd2UgYWRkIGBjb2xvciA9ICJuYXZ5ImAsIHRoZXkgYWxsIGFyZSBhZmZlY3RlZC4NCg0KYGBge3J9DQoNCnMgKyBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHopLCBzaXplID0gNCwgY29sb3VyID0gImJsdWUiKSAgKyBzY2FsZV9zaGFwZV9pZGVudGl0eSgpDQoNCmBgYA0KDQoNCldoaWxlIGFsbCBzeW1ib2xzIGhhdmUgYSBmb3JlZ3JvdW5kIGNvbG91ciwgc3ltYm9scyAyMS0yNSBhbHNvIHRha2UgYSBiYWNrZ3JvdW5kIGNvbG91ciAoZmlsbCkuIFNvIGlmIHdlIGFkZCBgZmlsbCA9ICJvcmNoaWQiYCwgb25seSB0aGUgbGFzdCByb3cgb2Ygc3ltYm9scyBhcmUgYWZmZWN0ZWQuDQoNCmBgYHtyfQ0KDQpzICsgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSB6KSwgc2l6ZSA9IDQsIGNvbG91ciA9ICJibHVlIiwgZmlsbCA9ICJvcmNoaWQiKSAgKyBzY2FsZV9zaGFwZV9pZGVudGl0eSgpDQoNCmBgYA0KDQoNCiMgRGlzY3JldGUgdnMgY29udGludW91cyB2YXJpYWJsZXMNCg0KW1dIQVQgSVMgVEhFIERJRkZFUkVOQ0UgQkVUV0VFTiBDQVRFR09SSUNBTCwgT1JESU5BTCBBTkQgSU5URVJWQUwgVkFSSUFCTEVTP10oaHR0cHM6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L290aGVyL211bHQtcGtnL3doYXRzdGF0L3doYXQtaXMtdGhlLWRpZmZlcmVuY2UtYmV0d2Vlbi1jYXRlZ29yaWNhbC1vcmRpbmFsLWFuZC1pbnRlcnZhbC12YXJpYWJsZXMvKQ0KDQpJbiBvcmRlciB0byB1c2UgY29sb3Igd2l0aCB5b3VyIGRhdGEsIG1vc3QgaW1wb3J0YW50bHksIHlvdSBuZWVkIHRvIGtub3cgaWYgeW914oCZcmUgZGVhbGluZyB3aXRoIGRpc2NyZXRlIG9yIGNvbnRpbnVvdXMgdmFyaWFibGVzLiANCg0KDQojIyBTb21lIENvbG91ciBQYWxldHRlIFBhY2thZ2VzIGluIFINCg0KV2UgaGF2ZSB0aGUgZm9sbG93aW5nIGV4YW1wbGUgcGFja2FnZXMgdGhhdCBvZmZlciBwYWxldHRlcyBpbiBSOg0KDQotIGBSQ29sb3JCcmV3ZXJgDQotIGB3ZXNhbmRlcnNvbmANCi0gYHBhbGV0dGVlcmANCi0gYGNvbG9yc3BhY2VgDQoNClNlZSBBcHBlbmRpeCBmb3IgYSBkZXRhaWxlZCBncmFwaGljYWwgYW5hbHlzaXMgb2YgdGhlc2UgcGFsZXR0ZSBwYWNrYWdlcy4gDQoNCg0KIyMgQ29sb3VyIFBhbGV0dGUgVHlwZXMNCg0KVGhlc2UgcGFsZXR0ZXMgY2FuIGJlOg0KDQo+ICoqU2VxdWVudGlhbCoqICh0eXBlID0gInNlcSIpIHBhbGV0dGVzIGFyZSBzdWl0ZWQgdG8gb3JkZXJlZCBkYXRhIHRoYXQgcHJvZ3Jlc3MgZnJvbSBsb3cgdG8gaGlnaC4gTGlnaHRuZXNzIHN0ZXBzIGRvbWluYXRlIHRoZSBsb29rIG9mIHRoZXNlIHNjaGVtZXMsIHdpdGggbGlnaHQgY29sb3JzIGZvciBsb3cgZGF0YSB2YWx1ZXMgdG8gZGFyayBjb2xvcnMgZm9yIGhpZ2ggZGF0YSB2YWx1ZXMuIChmb3IgKipudW1lcmljYWwqKiBkYXRhLCB0aGF0IGFyZSBvcmRlcmVkKQ0KDQo+ICoqRGl2ZXJnaW5nKiogKHR5cGUgPSAiZGl2IikgcGFsZXR0ZXMgcHV0IGVxdWFsIGVtcGhhc2lzIG9uIG1pZC1yYW5nZSBjcml0aWNhbCB2YWx1ZXMgYW5kIGV4dHJlbWVzIGF0IGJvdGggZW5kcyBvZiB0aGUgZGF0YSByYW5nZS4gVGhlIGNyaXRpY2FsIGNsYXNzIG9yIGJyZWFrIGluIHRoZSBtaWRkbGUgb2YgdGhlIGxlZ2VuZCBpcyBlbXBoYXNpemVkIHdpdGggbGlnaHQgY29sb3JzIGFuZCBsb3cgYW5kIGhpZ2ggZXh0cmVtZXMgYXJlIGVtcGhhc2l6ZWQgd2l0aCBkYXJrIGNvbG9ycyB0aGF0IGhhdmUgY29udHJhc3RpbmcgaHVlcy4oZm9yICoqbnVtZXJpY2FsIGRhdGEgdGhhdCBjYW4gYmUgcG9zaXRpdmUgb3IgbmVnYXRpdmUqKiwgb2Z0ZW4gcmVwcmVzZW50aW5nIGRldmlhdGlvbnMgZnJvbSBzb21lIG5vcm0gb3IgYmFzZWxpbmUpDQoNCj4gKipRdWFsaXRhdGl2ZSoqICh0eXBlID0gInF1YWwiKSBwYWxldHRlcyBkbyBub3QgaW1wbHkgbWFnbml0dWRlIGRpZmZlcmVuY2VzIGJldHdlZW4gbGVnZW5kIGNsYXNzZXMsIGFuZCBodWVzIGFyZSB1c2VkIHRvIGNyZWF0ZSB0aGUgcHJpbWFyeSB2aXN1YWwgZGlmZmVyZW5jZXMgYmV0d2VlbiBjbGFzc2VzLiBRdWFsaXRhdGl2ZSBzY2hlbWVzIGFyZSBiZXN0IHN1aXRlZCB0byByZXByZXNlbnRpbmcgKipub21pbmFsIG9yIGNhdGVnb3JpY2FsKiogZGF0YS4gKGZvciBxdWFsaXRhdGl2ZSB1bm9yZGVyZWQgZGF0YSkNCg0KDQojIyBDcmVhdGUgYSBzaW1wbGUgc2V0IG9mIHNjYXR0ZXIgcGxvdHMNCg0KV2Ugd2lsbCBjcmVhdGUgc2ltcGxlIGJhc2UgcGxvdHMgaW4gYGdncGxvdGAgYW5kIHNlZSBob3cgd2UgbWF5IGFsdGVyIHRoZSBjb2xvdXIgc2NhbGVzIHVzaW5nIHBhbGV0dGVzLg0KDQoNCmBgYHtyIHBlbmd1aW5fbmFtZXMgfQ0KDQpuYW1lcyhwZW5ndWlucykNCg0KYGBgDQoNCg0KYGBge3IgUGVuZ3VpbnNfZGVmYXVsdF9zaW1wbGVfcGxvdHN9DQoNCnAxIDwtIHBlbmd1aW5zICU+JSANCiAgZHJvcF9uYSgpICU+JSANCiAgIyBwaXBlIGRhdGEgaW50byBnZ3Bsb3QNCiAgIyBhZnRlciByZW1vdmluZyBkYXRhIHJvd3MgdGhhdCBoYXZlIG1pc3NpbmcgKCBOQSApIHZhbHVlcw0KICBnZ3Bsb3QoYWVzKHkgPSBib2R5X21hc3NfZywgeCA9IGZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgY29sb3IgPSBzcGVjaWVzICMgQ09MT1VSID0gRElTQ1JFVEUvUVVBTCBWQVJJQUJMRQ0KICAgICAgICAgICApKSArDQogICAgICAgICAgIGdlb21fcG9pbnQoKSArIA0KICAgICAgICAgICBsYWJzKHRpdGxlID0gIkRlZmF1bHQgQ29sb3VycyBpbiBnZ3Bsb3QiLCANCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJQMTogRElTQ1JFVEUvUVVBTCBDb2xvdXIgUGFsZXR0ZSIpDQoNCg0KcDIgPC0gDQpwZW5ndWlucyAlPiUgDQogIGRyb3BfbmEoKSAlPiUgDQogICMgcGlwZSB0aGUgZGF0YSBpbnRvIGdncGxvdCwgDQogICMgYWZ0ZXIgcmVtb3ZpbmcgZGF0YSByb3dzIHRoYXQgaGF2ZSBtaXNzaW5nICggTkEgKSB2YWx1ZXMNCiAgZ2dwbG90KGFlcyh5ID0gYm9keV9tYXNzX2csIHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgIGNvbG9yID0gYmlsbF9sZW5ndGhfbW0gIyBDT0xPVVIgPSBDT05UL1FVQU5UIFZBUklBQkxFDQogICAgICAgICAgICkpICsNCiAgICAgICAgICAgZ2VvbV9wb2ludCgpICsgDQogICAgICAgICAgIGxhYnModGl0bGUgPSAiRGVmYXVsdCBDb2xvdXJzIGluIGdncGxvdCIsIA0KICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gIlAyOiBDT05USU5VT1VTL1FVQU5UIENvbG91ciBQYWxldHRlIikNCg0KcDENCnAyDQoNCmBgYA0KDQpOb3RlIHRoYXQgdGhlc2UgdXNlIHRoZSAqKmRlZmF1bHQgY29sb3VycyoqIGluIFIuIA0KDQojIENvbG91cnMgZm9yICoqRGlzY3JldGUqKiAoKipRVUFMKiopIFZhcmlhYmxlcw0KDQpUaGUgY29tbWFuZHMgYmVsb3cgYXJlIHVzZWQgdG8gZmlsbCBjb2xvdXJzIGJhc2VkIG9uIFF1YWxpdGF0aXZlIFZhcmlhYmxlczoNCg0KMSkgYHNjYWxlX2NvbG91ci9maWxsX2Rpc2NyZXRlYA0KMikgYHNjYWxlX2NvbG91ci9maWxsX2JyZXdlcmAgIyBSQ29sb3JCcmV3ZXINCjMpIC4uLi4NCg0KDQpOb3cgdG8gdXNlIHRoZXNlIQ0KDQojIFBsb3R0aW5nIENvbG91cnMgYmFzZWQgb24gRGlzY3JldGUgVmFyaWFibGVzDQoNCiMjIERpc2NyZXRlIG4tQ29sb3VyIHBhbGV0dGVzIGZyb20gYFJDb2xvckJyZXdlcmANCg0KYGBge3IgYnJld2VyX3BhbGV0dGVzfQ0KDQpSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwuaW5mbw0KUkNvbG9yQnJld2VyOjpkaXNwbGF5LmJyZXdlci5hbGwoKQ0KDQpgYGANCg0KDQpgYGB7ciBBcHBseWluZ19SQ29sb3JCcmV3ZXJfRGlzY3JldGVfcGFsZXR0ZXN9DQoNCnAxICsNCiAgIyBkZWZhdWx0IHBhbGV0dGUgPSAiQmx1ZXMiDQogIHNjYWxlX2NvbG91cl9icmV3ZXIoKSArDQogIGxhYnModGl0bGUgPSAiQnJld2VyIFBhbGV0dGUgPSBCbHVlcyIpDQoNCnAxICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKSArDQogIGxhYnModGl0bGUgPSAiQnJld2VyIFBhbGV0dGUgPSBTcGVjdHJhbCIpIA0KDQoNCmBgYA0KDQoNCmBgYHtyIFlPVVJfVFVSTl8xfQ0KDQpgYGANCg0KDQojIyBEaXNjcmV0ZSBDb2xvdXIgc2NhbGVzIHVzaW5nIGB3ZXNhbmRlcnNvbmAgcGFsZXR0ZXMNCg0KYGBge3Igd2VzYW5kZXJfbGlzdH0NCg0Kd2VzYW5kZXJzb246Ondlc19wYWxldHRlcyAlPiUgbmFtZXMoKQ0KDQpgYGANCg0KDQpgYGB7ciB3ZXNhbmRlcnNvbl9kaXNjcmV0ZX0NCg0KcDEgKw0KICBzY2FsZV9jb2xvdXJfZGlzY3JldGUodHlwZSA9IHdlc19wYWxldHRlKG5hbWUgPSAiR3JhbmRCdWRhcGVzdDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSAzKSkgKw0KICBsYWJzKHRpdGxlID0gIldlcyBBbmRlcnNvbiBQYWxldHRlOiBHcmFuZEJ1ZGFwZXN0IikNCg0KDQojIFdlIGNhbiBhbHNvIHNwZWNpZnkgY29sb3VyIGNvZGVzIG91cnNlbHZlcyB3aXRoIHNjYWxlX3hfZGlzY3JldGUuDQojIFVzZSBhcmd1bWVudCAidmFsdWVzIiBpbnN0ZWFkIG9mICJ0eXBlIg0KbWFudWFsX2NvbG91cnMgPC0gYygiI2FmYzRiOCIsICIjZjFhNGIyIiwgIiNmZmIxZTEiKSANCm1hbnVhbF9jb2xvdXJzDQoNCnAxICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSAgbWFudWFsX2NvbG91cnMpICsNCiAgbGFicyh0aXRsZSA9ICJNYW51YWwgQ29sb3VycyIpDQoNCmBgYA0KDQoNCg0KYGBge3IgWU9VUl9UVVJOXzJ9DQoNCmBgYA0KDQojIyBEaXNjcmV0ZSBuLUNvbG91ciBwYWxldHRlcyBmcm9tIGBSQ29sb3JCcmV3ZXJgDQoNCmBgYHtyIEJyZXdlci1kaXNjcmV0ZX0NCg0KIyBzY2FsZV94X2JyZXdlcigpIGZvciBESVNDUkVURSBkYXRhDQpwMSArDQogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpICsNCiAgDQogIGxhYnModGl0bGUgPSAiUkNvbG9yQnJld2VyIFBhbGV0dGUgPSBTcGVjdHJhbCIpDQoNCmBgYA0KDQoNCg0KYGBge3IgWU9VUl9UVVJOXzN9DQoNCmBgYA0KDQoNCiMjIERpc2NyZXRlIENvbG91ciBzY2FsZXMgdXNpbmcgYHBhbGV0dGVlcmAgcGFsZXR0ZXMNCg0KYGBge3IgcGFsZXR0ZWVyIGRpc2NyZXRlfQ0KDQpwYWxldHRlc19kX25hbWVzDQpwYWxldHRlc19keW5hbWljX25hbWVzDQpwYWxldHRlZXJfZCgiZHV0Y2htYXN0ZXJzOjpwZWFybF9lYXJyaW5nIikNCnBhbGV0dGVlcl9keW5hbWljKCJnZ3RoZW1lc19wdG9sOjpxdWFsaXRhdGl2ZSIsIG4gPSAzKQ0KDQpwMSArDQogIHNjYWxlX2NvbG91cl9wYWxldHRlZXJfZCgiZ2d0aGVtZXNfcHRvbDo6cXVhbGl0YXRpdmUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGR5bmFtaWMgPSBUUlVFKSArDQogIA0KICBsYWJzKHRpdGxlID0gImdnVGhlbWVzIFBhbGV0dGU6IFF1YWxpdGF0aXZlIiwgDQogICAgICAgICAgc3VidGl0bGUgPSAiIikNCg0KDQojIEkgbGlrZSBWZXJtZWVyJ3MgIkdpcmwgd2l0aCB0aGUgUGVhcmwgRWFycmluZyIhDQpwMSArDQogIHNjYWxlX2NvbG91cl9wYWxldHRlZXJfZCgiZHV0Y2htYXN0ZXJzOjpwZWFybF9lYXJyaW5nIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGR5bmFtaWMgPSBGQUxTRSkgKw0KICANCiAgbGFicyh0aXRsZSA9ICJQYWxldHRlcyBmcm9tIGBwYWxldHRlZXJgIiwgDQogICAgICAgICAgc3VidGl0bGUgPSAiIFBhbGV0dGUgZnJvbSBWZXJtZWVyOiBHaXJsIHdpdGggUGVhcmwgRWFycmluZyIpDQogIA0KDQpgYGANCg0KDQpgYGB7ciBZT1VSX1RVUk5fNH0NCg0KYGBgDQoNCg0KDQojIENvbG91cnMgZm9yICoqQ29udGludW91cyoqICgqKlFVQU5UKiopIFZhcmlhYmxlcw0KDQpUaGUgY29tbWFuZHMgYmVsb3cgYXJlIHVzZWQgdG8gZmlsbCBjb2xvdXJzIGJhc2VkIG9uIFF1YW50aXRhdGl2ZSBWYXJpYWJsZXM6DQoNCjEpIGBzY2FsZV9jb2xvdXIvZmlsbF9ncmFkaWVudGAgKFR3byBjb2xvdXIgZ3JhZGllbnQpDQoyKSBgc2NhbGVfY29sb3VyL2ZpbGxfZ3JhZGllbnQyYCAoVGhyZWUgY29sb3VyIGdyYWRpZW50KQ0KMykgYHNjYWxlX2NvbG91ci9maWxsX2dyYWRpZW50bmAgKFNwZWNpZnkgUGFsZXR0ZSwgZnJvbSBvdGhlciBwYWNrYWdlcyBhbHNvLCBsaWtlIGB3ZXNhbmRlcnNvbmAgKQ0KNCkgYHNjYWxlX2NvbG91ci9maWxsX2Rpc3RpbGxlcmAgKFBhbGV0dGVzIGZyb20gUkNvbG9yQnJld2VyKQ0KDQoNCiMgUGxvdHRpbmcgQ29sb3VycyBiYXNlZCBvbiBDb250aW51b3VzIFZhcmlhYmxlcw0KDQoNCiMjIENvbnRpbnVvdXMgVHdvIENvbG91ciBHcmFkaWVudHMNCg0KQ3JlYXRlcyBhIHBhbGxldGUgY29udGFpbmluZyAqY29udGludW91cyogc2hhZGVzIGJldHdlZW4gdHdvIGNvbG91cnM6DQoNCmBgYHtyIENvbnRpbnVvdXNfVHdvX0NvbG91cl9HcmFkaWVudHN9DQoNCnAyICsNCiAgICBzY2FsZV9jb2xvcl9ncmFkaWVudCgNCiAgICAgIGxvdyA9ICJ5ZWxsb3ciLCAjIFBsYXkgd2l0aCB0aGlzIGluIHRoZSBjaHVuayBiZWxvdw0KICAgICAgaGlnaCA9ICJwdXJwbGUiKSArICMgUGxheSB3aXRoIHRoaXMgaW4gdGhlIGNobmsgYmVsb3cNCiAgDQogIGxhYnModGl0bGUgPSAiVHdvIENvbG91ciBHcmFkaWVudHMiLA0KICAgICAgICAgIHN1YnRpdGxlID0gIlAyOiBDb250aW51b3VzIDItQ29sb3VyIFBhbGxldGUiKQ0KDQpgYGANCg0KYGBge3IgWU9VUl9UVVJOXzV9DQoNCmBgYA0KDQoNCiMjIENvbnRpbnVvdXMgVGhyZWUgQ29sb3VyIEdyYWRpZW50cw0KDQpTb21ldGltZXMgd2Ugd2FudCBhIHBhbGV0dGUgdGhpcyB3YXk6IGEgKm1pZHBvaW50KiBjb2xvdXIsIGFuZCBjb2xvdXJzIGZvciB0aGUgdHdvIGV4dHJlbWVzIG9mIGEgY29udGludW91cyB2YXJpYWJsZToNCg0KYGBge3IgQ29udGludW91c19UaHJlZV9Db2xvdXJfR3JhZGllbnRzfQ0KDQpjb2xvdXJfbWlkcG9pbnQgPC0gbWVhbihwZW5ndWlucyRiaWxsX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSAjIHJlbW92ZSBtaXNzaW5nIHZhbHVlcw0KIyBTdHJ1Z2dsZWQgYWxsIG1vcm5pbmcgb24gMjIgQXVnIDIwMjAgdG8gZ2V0IGF0IHRoaXMgOy1EDQoNCiMgUGxheSB3aXRoIHRoZSBmdW5jdGlvbjogMC9tZWFuL21lZGlhbi9tb2RlL21heC9taW4NCg0KcDIgKw0KICBzY2FsZV9jb2xvdXJfZ3JhZGllbnQyKA0KICBsb3cgPSAiYnJvd24iLCAjIFBsYXkgd2l0aCB0aGlzIGluIHRoZSBjaHVuayBiZWxvdw0KICBtaWQgPSAid2hpdGUiLCAjIFBsYXkgd2l0aCB0aGlzIGluIHRoZSBjaHVuayBiZWxvdw0KICBoaWdoID0gInB1cnBsZSIsICMgUGxheSB3aXRoIHRoaXMgaW4gdGhlIGNodW5rIGJlbG93DQogIG1pZHBvaW50ID0gY29sb3VyX21pZHBvaW50LCAjIHNlZSBhYm92ZQ0KICBzcGFjZSA9ICJMYWIiLCAjIGRvbid0IG1lc3Mgd2l0aCB0aGlzIQ0KICBuYS52YWx1ZSA9ICJncmV5NTAiKSAgKw0KICBsYWJzKHRpdGxlID0gIlRocmVlIGNvbG91ciBjb250aW51b3VzIGdyYWRpZW50IiwgDQogICAgICAgICAgc3VidGl0bGUgPSAiTWlkIENvbG91ciBtYXBwZWQgdG8gbWlkcG9pbnQgb2YgZGF0YSB2YXJpYWJsZSIsDQogICAgICAgICAgY2FwdGlvbiA9ICJDb2xvdXJzIGluc3BpcmVkIGJ5IG15IGZhdm91cml0ZSBjb2NrZXIgc3BhbmllbCwgTG9yZCBDaGVzdG51dCIpICMgUGxheSB3aXRoIHRoZXNlDQoNCmBgYA0KDQpgYGB7ciBZT1VSX1RVUk5fNn0NCg0KYGBgDQoNCiMjIENvbnRpbnVvdXMgbi1Db2xvdXIgR3JhZGllbnRzIC0gZ3JEZXZpY2VzIHBhY2thZ2UNCg0KDQpgYGB7ciBDb250aW51b3VzX25fQ29sb3VyX0dyYWRpZW50c19nckRldmljZXN9DQoNCiMgZ3JEZXZpY2VzIFBhbGV0dGVzDQpwMiArDQogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oDQogICAgY29sb3VycyA9IHRlcnJhaW4uY29sb3JzKDEwKSkgKw0KICAjIFRyeSB0aGVzZToNCiAgIyBoZWF0LmNvbG9ycygpIC8gdG9wby5jb2xvcnMoKSAvIGNtLmNvbG9ycygpIC8gcmFpbmJvdygpDQogIA0KICBsYWJzKHRpdGxlID0gIk4tY29sb3VyIGNvbnRpbnVvdXMgZ3JhZGllbnRzIiwgDQogICAgICAgICAgc3VidGl0bGUgPSAiUGFsZXR0ZXMgZnJvbSBnckRldmljZXMiLA0KICAgICAgICAgIGNhcHRpb24gPSAiUGFsZXR0ZTogdGVycmFpbi5jb2xvcnMiKQ0KDQpgYGANCg0KDQpgYGB7ciBZT1VSX1RVUk5fN30NCg0KYGBgDQoNCg0KIyMgQ29udGludW91cyBuLUNvbG91ciBHcmFkaWVudHMgLSBgd2VzYW5kZXJzb25gIFBhbGV0dGVzDQoNCmBgYHtyIHdlc2FuZGVyc29ufQ0KDQp3ZXNfcGFsZXR0ZXMNCm5hbWVzKHdlc19wYWxldHRlcykNCg0KYGBgDQoNCmBgYHtyIFVzaW5nX3dlc2FuZGVyc29ufQ0KDQpwMiArDQogICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bigNCiAgICAgIGNvbG9ycyA9IHdlc19wYWxldHRlKG5hbWUgPSAiR3JhbmRCdWRhcGVzdDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSA0KSwgIyBLZWVwIGFuIGV5ZSBvbiAibiIuDQogICAgICBuYS52YWx1ZSA9ICJncmV5IikgKw0KICAjIFRyeSB0aGVzZToNCiAgIyAiQm90dGxlUm9ja2V0MSIgICJCb3R0bGVSb2NrZXQyIiAgIlJ1c2htb3JlMSINCiAgIyAiUnVzaG1vcmUiICAgICAgICJSb3lhbDEiICAgICAgICAgIlJveWFsMiINCiAgIyAiWmlzc291MSIgICAgICAgICJEYXJqZWVsaW5nMSIgICAgIkRhcmplZWxpbmcyIiAgIA0KICAjICJDaGV2YWxpZXIxIiAgICAgIkZhbnRhc3RpY0ZveDEiICAiTW9vbnJpc2UxIiAgICAgDQogICMgIk1vb25yaXNlMiIgICAgICAiTW9vbnJpc2UzIiAgICAgICJDYXZhbGNhbnRpMSIgICANCiAgIyAiR3JhbmRCdWRhcGVzdDEiICJHcmFuZEJ1ZGFwZXN0MiIgIklzbGVvZkRvZ3MxIiAgIA0KICAjICJJc2xlb2ZEb2dzMiIgICANCiAgIyBLZWVwIGFuIGV5ZSBvbiAibiIuDQogIA0KICBsYWJzKHRpdGxlID0gIk4tY29sb3VyIGNvbnRpbnVvdXMgZ3JhZGllbnRzIiwgDQogICAgICAgc3VidGl0bGUgPSAiUGFsZXR0ZXMgZnJvbSB3ZXNhbmRlcnNvbiIsDQogICAgICAgY2FwdGlvbiA9ICJQYWxldHRlOiBHcmFuZEJ1ZGFwZXN0MSIpICMgQ2hhbmdlIHRoaXMgY2FwdGlvbiBiYXNlZCBvbiBwYWxldHRlIGNob2ljZQ0KDQpgYGANCg0KYGBge3IgWU9VUl9UVVJOXzh9DQoNCmBgYA0KDQoNCiMjIENvbnRpbnVvdXMgbi1Db2xvdXIgcGFsZXR0ZXMgZnJvbSBgUkNvbG9yQnJld2VyYA0KDQpSZWNhbGwgUGFsZXR0ZSAqKnR5cGVzKioNCg0KLSBgc2VxYCBmb3IgY29udGludW91cyBkYXRhIG1hcHBlZCB0byBjb2xvdXINCi0gYHF1YWxgIGZvciBjYXRlZ29yaWNhbCBkYXRhIG1hcHBlZCB0byBjb2xvdXIgKCBkaXNjcmV0ZSkNCi0gYGRpdmAgY29udGludW91cyBkYXRhIG1hcHBlZCB0byBjb2xvdXIsIHRoYXQgaGFzIHBvcyBhbmQgbmVnIGV4dHJlbWVzIGZyb20gYSBtaWRkbGUgdmFsdWUNCg0KDQpgYGB7ciBicmV3ZXJfcGFsZXR0ZV9uYW1lc30NCg0KYnJld2VyLnBhbC5pbmZvDQoNCmBgYA0KDQoNCmBgYHtyIFVzaW5nX0NvbG9yX0JyZXdlcl9wYWxldHRlc30NCg0KIyBzY2FsZV9jb2xvcl9kaXN0aWxsZXIoKSBhbmQgc2NhbGVfZmlsbF9kaXN0aWxsZXIoKSANCiMgYXJlIHVzZWQgdG8gYXBwbHkgdGhlIENvbG9yQnJld2VyIGNvbG91ciBzY2FsZXMgDQojIHRvIGNvbnRpbnVvdXMgZGF0YS4NCg0KcDIgKw0KICBzY2FsZV9jb2xvdXJfZGlzdGlsbGVyKA0KICAgIHBhbGV0dGUgPSAiWWxHbkJ1IikgKyAjIFBsYXkgd2l0aCB0aGlzIHBhbGV0dGUNCiAgDQogIGxhYnModGl0bGUgPSAiUkNvbG9yQnJld2VyIFBhbGV0dGUiKQ0KDQpgYGANCg0KYGBge3IgWU9VUl9UVVJOXzl9DQoNCmBgYA0KDQojIyBDb250aW51b3VzIENvbG91ciBzY2FsZXMgdXNpbmcgYHBhbGV0dGVlcmAgcGFsZXR0ZXMNCg0KVGhpcyBwYWxldHRlIHNlZW1zIHRvIGhhdmUgZXZlcnl0aGluZyBhY2Nlc3NpYmxlIGluIGEgc2ltcGxlIHdheSENCk5PVEU6IEluIG9yZGVyIHRvIGFjY2VzcyBzb21lIHBhbGV0dGVzIGluIGBwYWxldHRlZXJgLCB5b3UgbWF5IGJlIGFza2VkIHRvIGluc3RhbGwgb3RoZXIgcGFja2FnZXMuIEUuZy4gYGhhcnJ5cG90dGVyYCBvciBgc2NpY29gLiBUaGVzZSBuZWVkIG5vdCBiZSBicm91Z2h0IGludG8geW91ciBzZXNzaW9uIHVzaW5nIGBsaWJyYXJ5KClgIGJ1dCBhcmUgYWNjZXNzZWQgZGlyZWN0bHkgYnkgYHBhbGV0dGVlcmAgd2hpY2ggaXMgdmVyeSBjb252ZW5pZW50ISENCg0KYGBge3IgcGFsZXR0ZWVyX2NvbnRpbnVwdXNfcGFsZXR0ZXNfbGlzdH0NCg0KIyBXaGF0IGNvbnRpbnVvdXMgcGFsZXR0ZXMgYXJlIHRoZXJlIGluIHBhbGV0dGVlcj8NCnBhbGV0dGVlcjo6cGFsZXR0ZXNfY19uYW1lcw0KDQpgYGANCg0KDQpPSywgb25lIG9mIHRoZSBHYW1lcyBvZiBUaHJvbmVzIFBhbGV0dGVzLCBhbmQgSGFycnkgUG90dGVyISANCg0KYGBge3IgcGFsZXR0ZWVyX2NvbnRpbnVvdXNfcGFsZXR0ZXN9DQoNCnAyICsNCiAgc2NhbGVfY29sb3VyX3BhbGV0dGVlcl9jKCJnYW1lb2Z0aHJvbmVzOjpqb25fc25vdyIpICsNCiAgbGFicyh0aXRsZSA9ICJVc2luZyBQYWxldHRlZXIiLA0KICAgICAgIHN1YnRpdGxlID0gIkNvbnRpbnVvdXMgUGFsZXR0ZS1HYW1lIG9mIFRocm9uZXM6IEpvbiBTbm93IiwNCiAgICAgICBjYXB0aW9uID0gIk9oIHlvdSBhd2Z1bCBTcmlzaHRpIHBlb3BsZS4uLiIpICsNCiAgDQogICMgSGFycnkgUG90dGVyIEdyeWZmaW5kb3IgUGFsZXR0ZS4NCiAgIyBXaWxsIGFzayBmb3IgYGhhcnJ5cG90dGVyYCBwYWNrYWdlIHRvIGJlIGluc3RhbGxlZC4gU2F5IHllcyENCiAgcDIgKw0KICBzY2FsZV9jb2xvdXJfcGFsZXR0ZWVyX2MoImhhcnJ5cG90dGVyOjpncnlmZmluZG9yIikgKw0KICBsYWJzKHRpdGxlID0gIlVzaW5nIFBhbGV0dGVlciIsDQogICAgICAgc3VidGl0bGUgPSAiQ29udGludW91cyBQYWxldHRlLUhhcnJ5IFBvdHRlcjpHcnlmZmluZG9yIikNCg0KYGBgDQoNCmBgYHtyIFlPVVJfVFVSTl8xMH0NCg0KYGBgDQogDQoNCg0K