Intro

This website is a replication package for the paper “Twitter and divides in the Dutch Parliament: Social and Political Segregation in the following, @-mentions and retweets networks” by Tolsma and Spierings ((submitted)).

It contains R code to replicate all Tables/Figures/Appendix in the manuscript.

To copy the code click the button in the upper right corner of the code-chunks.

Use the top menu to navigate to the section of interest.

The source code of this website can be found on Github

Questions can be addressed to Jochem Tolsma.


Packages

# install if necessary
if (!require("tidyverse", character.only = TRUE)) {
    install.packages("tidyverse", dependencies = TRUE)
}
if (!require("dplyr", character.only = TRUE)) {
    install.packages("dplyr", dependencies = TRUE)
}
if (!require("foreign", character.only = TRUE)) {
    install.packages("foreign", dependencies = TRUE)
}
if (!require("igraph", character.only = TRUE)) {
    install.packages("igraph", dependencies = TRUE)
}
if (!require("knitr", character.only = TRUE)) {
    install.packages("knitr", dependencies = TRUE)
}
if (!require("kableExtra", character.only = TRUE)) {
    install.packages("kableExtra", dependencies = TRUE)
}
if (!require("RSiena", character.only = TRUE)) {
    install.packages("RSiena", dependencies = TRUE)
}

# load packages.
library(tidyverse)
library(dplyr)
library(foreign)
library(igraph)
library(knitr)
library(kableExtra)
library(RSiena)

Load data objects

Data objects:

  • key: information on all politicians on election list
  • twitter
    • keyf: information on all 147 MPs with twitter handle
    • mydata: RSiena object with all kind of goodies inside
    • seats: seating coordinates of HoP (used for plotting)
# STAP 1: read in data
key <- read.spss("data-processed\\key moederbestand 20171114.sav", use.value.labels = T, to.data.frame = T)


load("data-processed\\twitter_20190919.RData")
# str(twitter_20190919,1)
keyf <- twitter_20190919[[1]]
mydata <- twitter_20190919[[2]]
seats <- twitter_20190919[[3]]

fnet <- mydata$depvars$fnet  #following network
atmnet <- mydata$depvars$atmnet  #atmention network
rtnet <- mydata$depvars$rtnet  #retweet network

fnet1 <- fnet[, , 1]  #first wave
atmnet1 <- atmnet[, , 1]  #first wave
rtnet1 <- rtnet[, , 1]  #first wave

fnet1[fnet1 == 10] <- 0  #replace missings with 0 for plotting
atmnet1[atmnet1 == 10] <- 0  #replace missings with 0 for plotting
rtnet1[rtnet1 == 10] <- 0  #replace missings with 0 for plotting

# define undirected networks of reciprocated ties
fnet1_un <- fnet1 == 1 & t(fnet1) == 1
atmnet1_un <- atmnet1 == 1 & t(atmnet1) == 1
rtnet1_un <- rtnet1 == 1 & t(rtnet1) == 1

vrouw <- mydata$cCovars$vrouw
partij <- mydata$cCovars$partij
ethminz <- mydata$cCovars$ethminz
lft <- mydata$cCovars$lft

ethminz <- ethminz + attributes(ethminz)$mean
partij <- partij + attributes(partij)$mean
vrouw <- vrouw + attributes(vrouw)$mean
lft <- lft + attributes(lft)$mean

Build plots

The first step is to make a ‘graph object’.

# define directed network
G1d <- graph_from_adjacency_matrix(fnet1, mode = "directed", weighted = NULL, diag = TRUE, add.colnames = NA,
    add.rownames = NA)
G2d <- graph_from_adjacency_matrix(atmnet1, mode = "directed", weighted = NULL, diag = TRUE, add.colnames = NA,
    add.rownames = NA)
G3d <- graph_from_adjacency_matrix(rtnet1, mode = "directed", weighted = NULL, diag = TRUE, add.colnames = NA,
    add.rownames = NA)

# define undirected network
G1u <- graph_from_adjacency_matrix(fnet1_un, mode = "undirected", weighted = NULL, diag = TRUE, add.colnames = NA,
    add.rownames = NA)
G2u <- graph_from_adjacency_matrix(atmnet1_un, mode = "undirected", weighted = NULL, diag = TRUE, add.colnames = NA,
    add.rownames = NA)
G3u <- graph_from_adjacency_matrix(rtnet1_un, mode = "undirected", weighted = NULL, diag = TRUE, add.colnames = NA,
    add.rownames = NA)

Plots

Followers (directed)

FIXED LOCATIONS AS IN HoP

G1 <- G1d

E(G1)$curved = 0.1
E(G1)$arrow.size = 0.1
V(G1)$color <- keyf$Partij_col
V(G1)$size = degree(G1, mode = "out") * 0.1 + 6
V(G1)$label = ""

owncoords <- cbind(keyf$X, keyf$Y)
owncoords <- owncoords/8
owncoords[, 1] <- (owncoords[, 1] - mean(owncoords[, 1]))
owncoords[, 2] <- (owncoords[, 2] - mean(owncoords[, 2]))

# change color of edges based on intra or interparty ties for transparant black: #0000007D
edges <- get.adjacency(G1)
edges_mat <- matrix(as.numeric(edges), nrow = nrow(edges))
# edges_mat[lower.tri(edges_mat)] <- 0
teller <- 1
coloredges <- NA
for (i in 1:nrow(edges)) {
    for (j in 1:ncol(edges)) {
        if (edges_mat[i, j] == 1) {
            if (keyf$Partij_col[i] == keyf$Partij_col[j]) {
                coloredges[teller] <- keyf$Partij_col[i]
            }
            if (keyf$Partij_col[i] != keyf$Partij_col[j]) {
                coloredges[teller] <- "#0000001B"
            }
            teller <- teller + 1
        }
    }
}
E(G1)$color = coloredges

# prepare a legend
Party_names <- unique(keyf$Partij)
Party_cols <- unique(keyf$Partij_col)

# reorder
Party_names <- Party_names[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]
Party_cols <- Party_cols[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]


# png('MPplotG1dv2.png',width = 900, height= 900)
{
    plot.igraph(G1, mode = "directed", layout = owncoords, rescale = F, margin = c(0, 0, 0, 0), xlim = c(min(owncoords[,
        1]), max(owncoords[, 1])), ylim = c(min(owncoords[, 2]), max(owncoords[, 2])), main = "Follower relations between Dutch MPs (2017)")

    legend("topleft", legend = Party_names, pch = 21, col = "#777777", pt.bg = Party_cols, pt.cex = 2,
        cex = 0.8, bty = "n", ncol = 3)

    text(-2.2, -1.2, "Note 1: Node size based on degree", adj = 0, cex = 0.8)
    text(-2.2, -1.3, "Note 2: Edge color based on Party of MPs, black if MPs from different party", adj = 0,
        cex = 0.8)
}
# dev.off()

Fruchterman-Reingold layout algorithm

# change colors a bit
df_col <- col2rgb(V(G1)$color)
V(G1)$color2 <- rgb(t(df_col), alpha = 100, maxColorValue = 255)

df_col <- col2rgb(E(G1)$color)
E(G1)$color2 <- rgb(t(df_col), alpha = 100, maxColorValue = 255)
E(G1)$color2[which(E(G1)$color == "#0000001B")] <- "#00000010"

# remove isolates
Isolated = which(degree(G1) == 0)
G1_sel = delete.vertices(G1, Isolated)
# G2_sel = delete.vertices(G2_sel, c(72,27)) #only connected to each other

V(G1_sel)$color <- V(G1_sel)$color2
E(G1_sel)$color <- E(G1_sel)$color2

# smaller arrows
E(G1)$arrow.size = 0.01

# bit smaller
V(G1_sel)$size = 0.5 * V(G1_sel)$size

# layout
set.seed(2435675)
c4 = layout_with_fr(G1_sel)
# c4[72,1] <- 5 c4[27,1] <- 5.5


# plot

# png('RR_followers_directed.png',width = 900, height= 900)
{
    plot(G1_sel, layout = c4, margin = c(0, 0, 0, 0), main = "Followers relations between Dutch MPs (2017)")

    legend("topleft", legend = Party_names, pch = 21, col = "#777777", pt.bg = Party_cols, pt.cex = 2,
        cex = 0.8, bty = "n", ncol = 3)

    text(-1.2, -1.2, "Note 1: Node size based on degree", adj = 0, cex = 0.8)
    text(-1.2, -1.25, "Note 2: Edge colar based on Party of MPs, black if MPs from different party",
        adj = 0, cex = 0.8)
    text(-1.2, -1.3, "Note 3: Isolates removed", adj = 0, cex = 0.8)

}
# dev.off()

png("RR_followers_directedv2.png", width = 900, height = 900)
{
    plot(G1_sel, layout = c4, margin = c(0, 0, 0, 0))
}
dev.off()


Followers (undirected)

FIXED LOCATIONS AS IN HoP

G1 <- G1u

E(G1)$curved = 0.1

V(G1)$color <- keyf$Partij_col
V(G1)$size = degree(G1) * 0.3 + 6
V(G1)$label = ""

owncoords <- cbind(keyf$X, keyf$Y)
owncoords <- owncoords/8
owncoords[, 1] <- (owncoords[, 1] - mean(owncoords[, 1]))
owncoords[, 2] <- (owncoords[, 2] - mean(owncoords[, 2]))

# change color of edges based on intra or interparty ties for transparant black: #0000007D
edges <- get.adjacency(G1)
edges_mat <- matrix(as.numeric(edges), nrow = nrow(edges))
edges_mat[lower.tri(edges_mat)] <- 0
teller <- 1
coloredges <- NA
for (i in 1:nrow(edges)) {
    for (j in 1:ncol(edges)) {
        if (edges_mat[i, j] == 1) {
            if (keyf$Partij_col[i] == keyf$Partij_col[j]) {
                coloredges[teller] <- keyf$Partij_col[i]
            }
            if (keyf$Partij_col[i] != keyf$Partij_col[j]) {
                coloredges[teller] <- "#0000004B"
            }
            teller <- teller + 1
        }
    }
}
E(G1)$color = coloredges

# prepare a legend
Party_names <- unique(keyf$Partij)
Party_cols <- unique(keyf$Partij_col)

# reorder
Party_names <- Party_names[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]
Party_cols <- Party_cols[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]

# png('MPplotG1uv2.png',width = 900, height= 900)
{
    plot.igraph(G1, mode = "undirected", layout = owncoords, rescale = F, margin = c(0, 0, 0, 0), xlim = c(min(owncoords[,
        1]), max(owncoords[, 1])), ylim = c(min(owncoords[, 2]), max(owncoords[, 2])), main = "Reciprocated follower relations between Dutch MPs (2017)")

    legend("topleft", legend = Party_names, pch = 21, col = "#777777", pt.bg = Party_cols, pt.cex = 2,
        cex = 0.8, bty = "n", ncol = 3)

    text(-2.2, -1.2, "Note 1: Node size based on degree", adj = 0, cex = 0.8)
    text(-2.2, -1.3, "Note 2: Edge color based on Party of MPs, black if MPs from different party", adj = 0,
        cex = 0.8)
}
# dev.off()

Fruchterman-Reingold layout algorithm

# change colors a bit
df_col <- col2rgb(V(G1)$color)
V(G1)$color2 <- rgb(t(df_col), alpha = 100, maxColorValue = 255)

df_col <- col2rgb(E(G1)$color)
E(G1)$color2 <- rgb(t(df_col), alpha = 100, maxColorValue = 255)
E(G1)$color2[which(E(G1)$color == "#0000004B")] <- "#00000010"

# remove isolates
Isolated = which(degree(G1) == 0)
G1_sel = delete.vertices(G1, Isolated)
# G2_sel = delete.vertices(G2_sel, c(72,27)) #only connected to each other

V(G1_sel)$color <- V(G1_sel)$color2
E(G1_sel)$color <- E(G1_sel)$color2

# smaller arrows
E(G1)$arrow.size = 0.01

# bit smaller
V(G1_sel)$size = 0.5 * V(G1_sel)$size

# layout
set.seed(2435675)
c4 = layout_with_fr(G1_sel)
# c4[72,1] <- 5 c4[27,1] <- 5.5

# plot

# png('RR_followers_undirected.png',width = 900, height= 900)
{
    plot(G1_sel, layout = c4, margin = c(0, 0, 0, 0), main = "Reciprocated followers relations between Dutch MPs (2017)")

    legend("topleft", legend = Party_names, pch = 21, col = "#777777", pt.bg = Party_cols, pt.cex = 2,
        cex = 0.8, bty = "n", ncol = 3)

    text(-1.2, -1.2, "Note 1: Node size based on degree", adj = 0, cex = 0.8)
    text(-1.2, -1.25, "Note 2: Edge colar based on Party of MPs, black if MPs from different party",
        adj = 0, cex = 0.8)
    text(-1.2, -1.3, "Note 3: Isolates removed", adj = 0, cex = 0.8)

}
# dev.off()

png("RR_followers_undirectedv2.png", width = 900, height = 900)
{
    plot(G1_sel, layout = c4, margin = c(0, 0, 0, 0))
}
dev.off()


at-mention (directed)

FIXED LOCATIONS AS IN HoP

Fruchterman-Reingold layout algorithm


atmentions (undirected)

FIXED LOCATIONS AS IN HoP

G2 <- G2u

E(G2)$curved = 0.1

V(G2)$color <- keyf$Partij_col
V(G2)$size = degree(G2) * 1.05 + 6
V(G2)$label = ""

owncoords <- cbind(keyf$X, keyf$Y)
owncoords <- owncoords/8
owncoords[, 1] <- (owncoords[, 1] - mean(owncoords[, 1]))
owncoords[, 2] <- (owncoords[, 2] - mean(owncoords[, 2]))

# change color of edges based on intra or interparty ties
edges <- get.adjacency(G2)
edges_mat <- matrix(as.numeric(edges), nrow = nrow(edges))
edges_mat[lower.tri(edges_mat)] <- 0
teller <- 1
coloredges <- NA
for (i in 1:nrow(edges)) {
    for (j in 1:ncol(edges)) {
        if (edges_mat[i, j] == 1) {
            if (keyf$Partij_col[i] == keyf$Partij_col[j]) {
                coloredges[teller] <- keyf$Partij_col[i]
            }
            if (keyf$Partij_col[i] != keyf$Partij_col[j]) {
                coloredges[teller] <- "#0000004B"
            }
            teller <- teller + 1
        }
    }
}
E(G2)$color = coloredges

# prepare a legend
Party_names <- unique(keyf$Partij)
Party_cols <- unique(keyf$Partij_col)

# reorder
Party_names <- Party_names[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]
Party_cols <- Party_cols[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]

# png('MPplotG2uv2.png',width = 900, height= 900)
{
    plot.igraph(G2, mode = "undirected", layout = owncoords, rescale = F, margin = c(0, 0, 0, 0), xlim = c(min(owncoords[,
        1]), max(owncoords[, 1])), ylim = c(min(owncoords[, 2]), max(owncoords[, 2])), main = "Reciprocated @mention relations between Dutch MPs (2017)")

    legend("topleft", legend = Party_names, pch = 21, col = "#777777", pt.bg = Party_cols, pt.cex = 2,
        cex = 0.8, bty = "n", ncol = 3)

    text(-2.2, -1.2, "Note 1: Node size based on degree", adj = 0, cex = 0.8)
    text(-2.2, -1.3, "Note 2: Edge colar based on Party of MPs, black if MPs from different party", adj = 0,
        cex = 0.8)
}
# dev.off()

Fruchterman-Reingold layout algorithm


retweet (directed)

FIXED LOCATIONS AS IN HoP

G3 <- G3d

E(G3)$curved = 0.1
E(G3)$arrow.size = 0.1

V(G3)$color <- keyf$Partij_col
V(G3)$size = degree(G3, mode = "out") * 0.5 + 6
V(G3)$label = ""

owncoords <- cbind(keyf$X, keyf$Y)
owncoords <- owncoords/8
owncoords[, 1] <- (owncoords[, 1] - mean(owncoords[, 1]))
owncoords[, 2] <- (owncoords[, 2] - mean(owncoords[, 2]))

# change color of edges based on intra or interparty ties
edges <- get.adjacency(G3)
edges_mat <- matrix(as.numeric(edges), nrow = nrow(edges))
# edges_mat[lower.tri(edges_mat)] <- 0
teller <- 1
coloredges <- NA
for (i in 1:nrow(edges)) {
    for (j in 1:ncol(edges)) {
        if (edges_mat[i, j] == 1) {
            if (keyf$Partij_col[i] == keyf$Partij_col[j]) {
                coloredges[teller] <- keyf$Partij_col[i]
            }
            if (keyf$Partij_col[i] != keyf$Partij_col[j]) {
                coloredges[teller] <- "#0000004B"
            }
            teller <- teller + 1
        }
    }
}
E(G3)$color = coloredges

# prepare a legend
Party_names <- unique(keyf$Partij)
Party_cols <- unique(keyf$Partij_col)

# reorder
Party_names <- Party_names[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]
Party_cols <- Party_cols[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]

# png('MPplotG3dv2.png',width = 900, height= 900)
{
    plot.igraph(G3, mode = "undirected", layout = owncoords, rescale = F, margin = c(0, 0, 0, 0), xlim = c(min(owncoords[,
        1]) - 0.2, max(owncoords[, 1])) + 0.2, ylim = c(min(owncoords[, 2]), max(owncoords[, 2])), main = "Retweet relations between Dutch MPs (2017)")

    legend("topleft", legend = Party_names, pch = 21, col = "#777777", pt.bg = Party_cols, pt.cex = 2,
        cex = 0.8, bty = "n", ncol = 3)

    text(-2.2, -1.2, "Note 1: Node size based on degree", adj = 0, cex = 0.8)
    text(-2.2, -1.3, "Note 2: Edge colar based on Party of MPs, black if MPs from different party", adj = 0,
        cex = 0.8)
}
# dev.off()

Fruchterman-Reingold layout algorithm


retweet (undirected)

FIXED LOCATIONS AS IN HoP

G3 <- G3u

E(G3)$curved = 0.1

V(G3)$color <- keyf$Partij_col
V(G3)$size = degree(G3) * 1.05 + 6
V(G3)$label = ""

owncoords <- cbind(keyf$X, keyf$Y)
owncoords <- owncoords/8
owncoords[, 1] <- (owncoords[, 1] - mean(owncoords[, 1]))
owncoords[, 2] <- (owncoords[, 2] - mean(owncoords[, 2]))

# change color of edges based on intra or interparty ties
edges <- get.adjacency(G3)
edges_mat <- matrix(as.numeric(edges), nrow = nrow(edges))
edges_mat[lower.tri(edges_mat)] <- 0
teller <- 1
coloredges <- NA
for (i in 1:nrow(edges)) {
    for (j in 1:ncol(edges)) {
        if (edges_mat[i, j] == 1) {
            if (keyf$Partij_col[i] == keyf$Partij_col[j]) {
                coloredges[teller] <- keyf$Partij_col[i]
            }
            if (keyf$Partij_col[i] != keyf$Partij_col[j]) {
                coloredges[teller] <- "#0000004B"
            }
            teller <- teller + 1
        }
    }
}
E(G3)$color = coloredges

# prepare a legend
Party_names <- unique(keyf$Partij)
Party_cols <- unique(keyf$Partij_col)

# reorder
Party_names <- Party_names[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]
Party_cols <- Party_cols[c(7, 3, 9, 10, 12, 11, 5, 4, 6, 2, 8, 1, 13)]

# png('MPplotG3uv2.png',width = 900, height= 900)
{
    plot.igraph(G3, mode = "undirected", layout = owncoords, rescale = F, margin = c(0, 0, 0, 0), xlim = c(min(owncoords[,
        1]) - 0.2, max(owncoords[, 1])) + 0.2, ylim = c(min(owncoords[, 2]), max(owncoords[, 2])), main = "Reciprocated retweet relations between Dutch MPs (2017)")

    legend("topleft", legend = Party_names, pch = 21, col = "#777777", pt.bg = Party_cols, pt.cex = 2,
        cex = 0.8, bty = "n", ncol = 3)

    text(-2.2, -1.2, "Note 1: Node size based on degree", adj = 0, cex = 0.8)
    text(-2.2, -1.3, "Note 2: Edge colar based on Party of MPs, black if MPs from different party", adj = 0,
        cex = 0.8)
}
# dev.off()

Fruchterman-Reingold layout algorithm


Rank orders and description

Most follower outdegrees:

G1 <- G1d
foutdegree <- degree(G1, mode = "out")
keyf$Partij[which(foutdegree == max(foutdegree))]
keyf$Naam[which(foutdegree == max(foutdegree))]
#> [1] CDA
#> 19 Levels: Artikel1 CDA CU DENK D66 FvD GeenPeil GroenLinks Piraten PvdA PvdDieren PVV SGP ... uit fractie getreden, zonder partij als eenmansfractie
#> [1] Heerma, Pieter                          
#> 969 Levels:  Stephan van Baarle                      ... Zohair el Yassini

Most atmention outdegrees:

G2 <- G2d
atmdegree <- degree(G2, mode = "out")
keyf$Partij[which(atmdegree == max(atmdegree))]
keyf$Naam[which(atmdegree == max(atmdegree))]
#> [1] SP
#> 19 Levels: Artikel1 CDA CU DENK D66 FvD GeenPeil GroenLinks Piraten PvdA PvdDieren PVV SGP ... uit fractie getreden, zonder partij als eenmansfractie
#> [1] PETER KWINT                             
#> 969 Levels:  Stephan van Baarle                      ... Zohair el Yassini

Most retweet outdegrees:

G3 <- G3d
rtdegree <- degree(G3, mode = "out")
keyf$Partij[which(rtdegree == max(rtdegree))]
keyf$Naam[which(rtdegree == max(rtdegree))]
#> [1] VVD
#> 19 Levels: Artikel1 CDA CU DENK D66 FvD GeenPeil GroenLinks Piraten PvdA PvdDieren PVV SGP ... uit fractie getreden, zonder partij als eenmansfractie
#> [1] Dilan Yesilgöz-Zegerius                 
#> 969 Levels:  Stephan van Baarle                      ... Zohair el Yassini

Spearman’s rank correlation rho

follower outdegree and atmention outdegree

cor.test(foutdegree, atmdegree, method = "spearman")
#> 
#>  Spearman's rank correlation rho
#> 
#> data:  foutdegree and atmdegree
#> S = 322905, p-value = 1.042e-06
#> alternative hypothesis: true rho is not equal to 0
#> sample estimates:
#>       rho 
#> 0.3900495

follower outdegree and retweet outdegree

cor.test(foutdegree, rtdegree, method = "spearman")
#> 
#>  Spearman's rank correlation rho
#> 
#> data:  foutdegree and rtdegree
#> S = 336405, p-value = 5.641e-06
#> alternative hypothesis: true rho is not equal to 0
#> sample estimates:
#>       rho 
#> 0.3645494

retweet outdegree and atmention outdegree

cor.test(rtdegree, atmdegree, method = "spearman")
#> 
#>  Spearman's rank correlation rho
#> 
#> data:  rtdegree and atmdegree
#> S = 249178, p-value = 5.475e-12
#> alternative hypothesis: true rho is not equal to 0
#> sample estimates:
#>      rho 
#> 0.529317

Tolsma, Jochem, and Niels Spierings. (submitted). “Twitter and Divides in the Dutch Parliament: Social and Political Segregation in the Following, @-Mentions and Retweets Networks.” - - (-): –. -.
LS0tDQp0aXRsZTogIlJlcGxpY2F0aW9uIHBhY2thZ2UtRmlndXJlcyINCmF1dGhvcjogJ1tKb2NoZW0gVG9sc21hXShodHRwczovL3d3dy5qb2NoZW10b2xzbWEubmwpIC0gUmFkYm91ZCBVbml2ZXJzaXR5IC8gVW5pdmVyc2l0eSBvZiBHcm9uaW5nZW4sIHRoZSBOZXRoZXJsYW5kcycNCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWINCmRhdGU6ICJMYXN0IGNvbXBpbGVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJUIsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6ICB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KLS0tDQoNCmBgYHtyIGdsb2JhbHNldHRpbmdzLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCm9wdHNfY2h1bmskc2V0KHRpZHkub3B0cz1saXN0KHdpZHRoLmN1dG9mZj0xMDApLHRpZHk9VFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsY29tbWVudCA9ICIjPiIsIGNhY2hlPVRSVUUsIGVjaG89RkFMU0UsIGNsYXNzLnNvdXJjZT1jKCJ0ZXN0IiksIGNsYXNzLm91dHB1dD1jKCJ0ZXN0MiIpLCBldmFsPUZBTFNFKQ0Kb3B0aW9ucyh3aWR0aCA9IDEwMCkNCnJnbDo6c2V0dXBLbml0cigpDQpgYGANCg0KYGBge3IgY29sb3JpemUsIGVjaG89RkFMU0V9DQpjb2xvcml6ZSA8LSBmdW5jdGlvbih4LCBjb2xvcikgew0KICBpZiAoa25pdHI6OmlzX2xhdGV4X291dHB1dCgpKSB7DQogICAgc3ByaW50ZigiXFx0ZXh0Y29sb3J7JXN9eyVzfSIsIGNvbG9yLCB4KQ0KICB9IGVsc2UgaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogICAgc3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCANCiAgICAgICAgICAgIHgpDQogIH0gZWxzZSB4DQp9DQoNCmBgYA0KDQpgYGB7ciBrbGlwcHksIGVjaG89RkFMU0UsIGluY2x1ZGU9VFJVRSwgZXZhbD1UUlVFfQ0Ka2xpcHB5OjprbGlwcHkocG9zaXRpb24gPSBjKCd0b3AnLCAncmlnaHQnKSkNCiNrbGlwcHk6OmtsaXBweShjb2xvciA9ICdkYXJrcmVkJykNCiNrbGlwcHk6OmtsaXBweSh0b29sdGlwX21lc3NhZ2UgPSAnQ2xpY2sgdG8gY29weScsIHRvb2x0aXBfc3VjY2VzcyA9ICdEb25lJykNCmBgYA0KDQpgYGB7Y3NzLCBlY2hvPUZBTFNFfQ0KcHJlLnRlc3Qgew0KICBtYXgtaGVpZ2h0OiAzMDBweDsNCiAgb3ZlcmZsb3cteTogYXV0bzsNCiAgb3ZlcmZsb3cteDogYXV0bzsNCiAgbWFyZ2luOiAwcHg7DQp9DQoNCnByZS50ZXN0MiB7DQogIG1heC1oZWlnaHQ6IDMwMHB4Ow0KICBvdmVyZmxvdy15OiBhdXRvOw0KICBvdmVyZmxvdy14OiBhdXRvOw0KICBtYXJnaW46IDBweDsNCiAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7DQogIGNvbG9yOiByZ2IoMjAxLCA3NiwgNzYpOw0KfQ0KDQoNCmgxLCAuaDEsIGgyLCAuaDIsIGgzLCAuaDMgew0KICBtYXJnaW4tdG9wOiAyNHB4Ow0KfQ0KDQoNCmBgYA0KDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KIyBJbnRybyAgDQoNCg0KVGhpcyBbd2Vic2l0ZV0oaHR0cHM6Ly9qb2NoZW10b2xzbWEuZ2l0aHViLmlvL1R3aXR0ZXIvKSBpcyBhIHJlcGxpY2F0aW9uIHBhY2thZ2UgZm9yIHRoZSBwYXBlciAiKipUd2l0dGVyIGFuZCBkaXZpZGVzIGluIHRoZSBEdXRjaCBQYXJsaWFtZW50OiBTb2NpYWwgYW5kIFBvbGl0aWNhbCBTZWdyZWdhdGlvbiBpbiB0aGUgZm9sbG93aW5nLCBALW1lbnRpb25zIGFuZCByZXR3ZWV0cyBuZXR3b3JrcyoqIiBieSBAVG9sc21hMjAyMS4NCg0KSXQgY29udGFpbnMgUiBjb2RlIHRvIHJlcGxpY2F0ZSBhbGwgVGFibGVzL0ZpZ3VyZXMvQXBwZW5kaXggaW4gdGhlIG1hbnVzY3JpcHQuDQoNClRvIGNvcHkgdGhlIGNvZGUgY2xpY2sgdGhlIGJ1dHRvbiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyIG9mIHRoZSBjb2RlLWNodW5rcy4NCg0KVXNlIHRoZSB0b3AgbWVudSB0byBuYXZpZ2F0ZSB0byB0aGUgc2VjdGlvbiBvZiBpbnRlcmVzdC4gDQoNClRoZSBzb3VyY2UgY29kZSBvZiB0aGlzIHdlYnNpdGUgY2FuIGJlIGZvdW5kIG9uIFtHaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9Kb2NoZW1Ub2xzbWEvVHdpdHRlcikNCg0KUXVlc3Rpb25zIGNhbiBiZSBhZGRyZXNzZWQgdG8gW0pvY2hlbSBUb2xzbWFdKG1haWx0bzpqb2NoZW0udG9sc21hQHJ1Lm5sKS4NCg0KLS0tICANCg0KIyMgUGFja2FnZXMgIA0KDQpgYGB7ciBwYWNrYWdlcywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPVRSVUV9DQojaW5zdGFsbCBpZiBuZWNlc3NhcnkgDQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHtpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiLCBkZXBlbmRlbmNpZXM9VFJVRSl9DQppZiAoIXJlcXVpcmUoImRwbHlyIiwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkge2luc3RhbGwucGFja2FnZXMoImRwbHlyIiwgZGVwZW5kZW5jaWVzPVRSVUUpfQ0KaWYgKCFyZXF1aXJlKCJmb3JlaWduIiwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkge2luc3RhbGwucGFja2FnZXMoImZvcmVpZ24iLCBkZXBlbmRlbmNpZXM9VFJVRSl9DQppZiAoIXJlcXVpcmUoImlncmFwaCIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHtpbnN0YWxsLnBhY2thZ2VzKCJpZ3JhcGgiLCBkZXBlbmRlbmNpZXM9VFJVRSl9DQppZiAoIXJlcXVpcmUoImtuaXRyIiwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkge2luc3RhbGwucGFja2FnZXMoImtuaXRyIiwgZGVwZW5kZW5jaWVzPVRSVUUpfQ0KaWYgKCFyZXF1aXJlKCJrYWJsZUV4dHJhIiwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkge2luc3RhbGwucGFja2FnZXMoImthYmxlRXh0cmEiLCBkZXBlbmRlbmNpZXM9VFJVRSl9DQppZiAoIXJlcXVpcmUoIlJTaWVuYSIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHtpbnN0YWxsLnBhY2thZ2VzKCJSU2llbmEiLCBkZXBlbmRlbmNpZXM9VFJVRSl9DQoNCiNsb2FkIHBhY2thZ2VzLg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShmb3JlaWduKQ0KbGlicmFyeShpZ3JhcGgpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShSU2llbmEpDQoNCmBgYA0KDQoNCi0tLSAgIA0KDQoNCiMjIExvYWQgZGF0YSBvYmplY3RzIHsudGFic2V0IC50YWJzZXQtZmFkZX0gIA0KDQogDQoNCkRhdGEgb2JqZWN0czogIA0KDQotIFtrZXldKC4vZGF0YS1wcm9jZXNzZWQva2V5IG1vZWRlcmJlc3RhbmQgMjAxNzExMTQuc2F2KTogaW5mb3JtYXRpb24gb24gYWxsIHBvbGl0aWNpYW5zIG9uIGVsZWN0aW9uIGxpc3QgIA0KLSBbdHdpdHRlcl0oLi9kYXRhLXByb2Nlc3NlZC90d2l0dGVyXzIwMTkwOTE5LlJEYXRhKSAgDQogICAgLSBrZXlmOiBpbmZvcm1hdGlvbiBvbiBhbGwgMTQ3IE1QcyB3aXRoIHR3aXR0ZXIgaGFuZGxlICANCiAgICAtIG15ZGF0YTogUlNpZW5hIG9iamVjdCB3aXRoIGFsbCBraW5kIG9mIGdvb2RpZXMgaW5zaWRlICANCiAgICAtIHNlYXRzOiBzZWF0aW5nIGNvb3JkaW5hdGVzIG9mIEhvUCAodXNlZCBmb3IgcGxvdHRpbmcpDQoNCmBgYHtyIGRhdGEsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1UUlVFfQ0KI1NUQVAgMTogcmVhZCBpbiBkYXRhDQprZXkgPC0gcmVhZC5zcHNzKCdkYXRhLXByb2Nlc3NlZFxca2V5IG1vZWRlcmJlc3RhbmQgMjAxNzExMTQuc2F2JywgdXNlLnZhbHVlLmxhYmVscz1ULCB0by5kYXRhLmZyYW1lPVQpDQoNCg0KbG9hZCgiZGF0YS1wcm9jZXNzZWRcXHR3aXR0ZXJfMjAxOTA5MTkuUkRhdGEiKQ0KI3N0cih0d2l0dGVyXzIwMTkwOTE5LDEpDQprZXlmIDwtIHR3aXR0ZXJfMjAxOTA5MTlbWzFdXQ0KbXlkYXRhIDwtIHR3aXR0ZXJfMjAxOTA5MTlbWzJdXQ0Kc2VhdHMgPC0gdHdpdHRlcl8yMDE5MDkxOVtbM11dDQoNCmZuZXQgPC0gbXlkYXRhJGRlcHZhcnMkZm5ldCAjZm9sbG93aW5nIG5ldHdvcmsNCmF0bW5ldCA8LSBteWRhdGEkZGVwdmFycyRhdG1uZXQgI2F0bWVudGlvbiBuZXR3b3JrDQpydG5ldCA8LSBteWRhdGEkZGVwdmFycyRydG5ldCAjcmV0d2VldCBuZXR3b3JrDQoNCmZuZXQxIDwtIGZuZXRbLCwxXSAjZmlyc3Qgd2F2ZQ0KYXRtbmV0MSA8LSBhdG1uZXRbLCwxXSAjZmlyc3Qgd2F2ZQ0KcnRuZXQxIDwtIHJ0bmV0WywsMV0gI2ZpcnN0IHdhdmUNCg0KZm5ldDFbZm5ldDE9PTEwXSA8LSAwICNyZXBsYWNlIG1pc3NpbmdzIHdpdGggMCBmb3IgcGxvdHRpbmcNCmF0bW5ldDFbYXRtbmV0MT09MTBdIDwtIDAgI3JlcGxhY2UgbWlzc2luZ3Mgd2l0aCAwIGZvciBwbG90dGluZw0KcnRuZXQxW3J0bmV0MT09MTBdIDwtIDAgI3JlcGxhY2UgbWlzc2luZ3Mgd2l0aCAwIGZvciBwbG90dGluZw0KDQojZGVmaW5lIHVuZGlyZWN0ZWQgbmV0d29ya3Mgb2YgcmVjaXByb2NhdGVkIHRpZXMgDQpmbmV0MV91biA8LSBmbmV0MSA9PTEgJiB0KGZuZXQxKT09MQ0KYXRtbmV0MV91biA8LSBhdG1uZXQxID09MSAmIHQoYXRtbmV0MSk9PTENCnJ0bmV0MV91biA8LSBydG5ldDEgPT0xICYgdChydG5ldDEpPT0xDQoNCnZyb3V3IDwtIG15ZGF0YSRjQ292YXJzJHZyb3V3DQpwYXJ0aWogPC0gbXlkYXRhJGNDb3ZhcnMkcGFydGlqDQpldGhtaW56IDwtIG15ZGF0YSRjQ292YXJzJGV0aG1pbnoNCmxmdCA8LSBteWRhdGEkY0NvdmFycyRsZnQNCg0KZXRobWlueiA8LSBldGhtaW56ICsgYXR0cmlidXRlcyhldGhtaW56KSRtZWFuDQpwYXJ0aWogPC0gcGFydGlqICsgYXR0cmlidXRlcyhwYXJ0aWopJG1lYW4NCnZyb3V3IDwtIHZyb3V3ICsgYXR0cmlidXRlcyh2cm91dykkbWVhbg0KbGZ0IDwtIGxmdCArIGF0dHJpYnV0ZXMobGZ0KSRtZWFuDQoNCg0KYGBgDQoNCi0tLSAgDQoNCg0KDQojIyBCdWlsZCBwbG90cyB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNClRoZSBmaXJzdCBzdGVwIGlzIHRvIG1ha2UgYSAnZ3JhcGggb2JqZWN0Jy4gDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0NCiNkZWZpbmUgZGlyZWN0ZWQgbmV0d29yayANCkcxZCA8LSBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgoZm5ldDEsIG1vZGUgPSAiZGlyZWN0ZWQiLCB3ZWlnaHRlZCA9IE5VTEwsIGRpYWcgPSBUUlVFLCAgYWRkLmNvbG5hbWVzID0gTkEsIGFkZC5yb3duYW1lcyA9IE5BKQ0KRzJkIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeChhdG1uZXQxLCBtb2RlID0gImRpcmVjdGVkIiwgd2VpZ2h0ZWQgPSBOVUxMLCBkaWFnID0gVFJVRSwgIGFkZC5jb2xuYW1lcyA9IE5BLCBhZGQucm93bmFtZXMgPSBOQSkNCkczZCA8LSBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgocnRuZXQxLCBtb2RlID0gImRpcmVjdGVkIiwgd2VpZ2h0ZWQgPSBOVUxMLCBkaWFnID0gVFJVRSwgIGFkZC5jb2xuYW1lcyA9IE5BLCBhZGQucm93bmFtZXMgPSBOQSkNCg0KI2RlZmluZSB1bmRpcmVjdGVkIG5ldHdvcmsgDQpHMXUgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KGZuZXQxX3VuLCBtb2RlID0gInVuZGlyZWN0ZWQiLCB3ZWlnaHRlZCA9IE5VTEwsIGRpYWcgPSBUUlVFLCAgYWRkLmNvbG5hbWVzID0gTkEsIGFkZC5yb3duYW1lcyA9IE5BKQ0KRzJ1IDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeChhdG1uZXQxX3VuLCBtb2RlID0gInVuZGlyZWN0ZWQiLCB3ZWlnaHRlZCA9IE5VTEwsIGRpYWcgPSBUUlVFLCAgYWRkLmNvbG5hbWVzID0gTkEsIGFkZC5yb3duYW1lcyA9IE5BKQ0KRzN1IDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeChydG5ldDFfdW4sIG1vZGUgPSAidW5kaXJlY3RlZCIsIHdlaWdodGVkID0gTlVMTCwgZGlhZyA9IFRSVUUsICBhZGQuY29sbmFtZXMgPSBOQSwgYWRkLnJvd25hbWVzID0gTkEpDQoNCmBgYA0KDQoNCiMjIFBsb3RzIHsudGFic2V0IC50YWJzZXQtZmFkZX0gDQoNCiMjIyBGb2xsb3dlcnMgKGRpcmVjdGVkKQ0KDQoqKkZJWEVEIExPQ0FUSU9OUyBBUyBJTiBIb1AqKg0KDQpgYGB7ciBHMWQsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0NCkcxIDwtIEcxZA0KDQpFKEcxKSRjdXJ2ZWQ9LjENCkUoRzEpJGFycm93LnNpemU9LjENClYoRzEpJGNvbG9yIDwtIGtleWYkUGFydGlqX2NvbA0KVihHMSkkc2l6ZT0gZGVncmVlKEcxLCBtb2RlPSJvdXQiKSouMSArIDYNClYoRzEpJGxhYmVsPSIiDQoNCm93bmNvb3JkcyA8LSBjYmluZChrZXlmJFgsIGtleWYkWSkNCm93bmNvb3JkcyA8LSBvd25jb29yZHMvOA0Kb3duY29vcmRzWywxXSA8LSAob3duY29vcmRzWywxXSAtIG1lYW4ob3duY29vcmRzWywxXSkpDQpvd25jb29yZHNbLDJdIDwtIChvd25jb29yZHNbLDJdIC0gbWVhbihvd25jb29yZHNbLDJdKSkNCg0KI2NoYW5nZSBjb2xvciBvZiBlZGdlcyBiYXNlZCBvbiBpbnRyYSBvciBpbnRlcnBhcnR5IHRpZXMNCiNmb3IgdHJhbnNwYXJhbnQgYmxhY2s6ICMwMDAwMDA3RA0KZWRnZXMgPC0gZ2V0LmFkamFjZW5jeShHMSkNCmVkZ2VzX21hdCA8LSBtYXRyaXgoYXMubnVtZXJpYyhlZGdlcyksIG5yb3c9bnJvdyhlZGdlcykpDQojZWRnZXNfbWF0W2xvd2VyLnRyaShlZGdlc19tYXQpXSA8LSAwDQp0ZWxsZXIgPC0gMQ0KY29sb3JlZGdlcyA8LSBOQQ0KZm9yIChpIGluIDE6bnJvdyhlZGdlcykpIHsNCiAgZm9yIChqIGluIDE6bmNvbChlZGdlcykpIHsNCiAgICBpZiAoZWRnZXNfbWF0W2ksal09PTEpIHsNCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gPT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtIGtleWYkUGFydGlqX2NvbFtpXX0NCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gIT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtICIjMDAwMDAwMUIifQ0KICAgICAgdGVsbGVyIDwtIHRlbGxlciArIDENCiAgICB9DQogIH0NCn0NCkUoRzEpJGNvbG9yPWNvbG9yZWRnZXMNCg0KI3ByZXBhcmUgYSBsZWdlbmQNClBhcnR5X25hbWVzIDwtIHVuaXF1ZShrZXlmJFBhcnRpaikNClBhcnR5X2NvbHMgPC0gdW5pcXVlKGtleWYkUGFydGlqX2NvbCkNCg0KIyByZW9yZGVyDQpQYXJ0eV9uYW1lcyA8LSBQYXJ0eV9uYW1lc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NClBhcnR5X2NvbHMgPC0gUGFydHlfY29sc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NCg0KDQojcG5nKCJNUHBsb3RHMWR2Mi5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsgDQogIHBsb3QuaWdyYXBoKEcxLCBtb2RlPSJkaXJlY3RlZCIsIGxheW91dD1vd25jb29yZHMsIHJlc2NhbGU9RiwgbWFyZ2luPWMoMCwwLDAsMCksIHhsaW09YyhtaW4ob3duY29vcmRzWywxXSksbWF4KG93bmNvb3Jkc1ssMV0pKSwgIHlsaW09YyhtaW4ob3duY29vcmRzWywyXSksbWF4KG93bmNvb3Jkc1ssMl0pKSwgbWFpbj0iRm9sbG93ZXIgcmVsYXRpb25zIGJldHdlZW4gRHV0Y2ggTVBzICgyMDE3KSIpDQoNCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZD1QYXJ0eV9uYW1lcywgcGNoPTIxLCBjb2w9IiM3Nzc3NzciLCBwdC5iZz1QYXJ0eV9jb2xzLCBwdC5jZXg9MiwgY2V4PS44LCBidHk9Im4iLCBuY29sPTMpDQoNCnRleHQoLTIuMiwtMS4yLCAiTm90ZSAxOiBOb2RlIHNpemUgYmFzZWQgb24gZGVncmVlIiwgYWRqPTAsIGNleD0wLjgpDQp0ZXh0KC0yLjIsLTEuMywgIk5vdGUgMjogRWRnZSBjb2xvciBiYXNlZCBvbiBQYXJ0eSBvZiBNUHMsIGJsYWNrIGlmIE1QcyBmcm9tIGRpZmZlcmVudCBwYXJ0eSIsIGFkaj0wLCBjZXg9MC44KQ0KfSAgDQojZGV2Lm9mZigpDQogDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPVRSVUUsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnTVBwbG90RzFkdjIucG5nJykNCmBgYA0KDQoqKkZydWNodGVybWFuLVJlaW5nb2xkIGxheW91dCBhbGdvcml0aG0qKg0KDQpgYGB7ciwgZWNobz1UUlVFLCBldmFsPUZBTFNFfQ0KI2NoYW5nZSBjb2xvcnMgYSBiaXQNCmRmX2NvbCA8LSBjb2wycmdiKFYoRzEpJGNvbG9yKQ0KVihHMSkkY29sb3IyIDwtIHJnYih0KGRmX2NvbCksIGFscGhhPTEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkNCg0KZGZfY29sIDwtIGNvbDJyZ2IoRShHMSkkY29sb3IpDQpFKEcxKSRjb2xvcjIgPC0gcmdiKHQoZGZfY29sKSwgYWxwaGE9MTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KQ0KRShHMSkkY29sb3IyW3doaWNoKEUoRzEpJGNvbG9yPT0iIzAwMDAwMDFCIildIDwtICIjMDAwMDAwMTAiDQoNCiNyZW1vdmUgaXNvbGF0ZXMNCklzb2xhdGVkID0gd2hpY2goZGVncmVlKEcxKT09MCkNCkcxX3NlbCA9IGRlbGV0ZS52ZXJ0aWNlcyhHMSwgSXNvbGF0ZWQpDQojRzJfc2VsID0gZGVsZXRlLnZlcnRpY2VzKEcyX3NlbCwgYyg3MiwyNykpICNvbmx5IGNvbm5lY3RlZCB0byBlYWNoIG90aGVyDQoNClYoRzFfc2VsKSRjb2xvciA8LSBWKEcxX3NlbCkkY29sb3IyDQpFKEcxX3NlbCkkY29sb3IgPC0gRShHMV9zZWwpJGNvbG9yMg0KDQojc21hbGxlciBhcnJvd3MNCkUoRzEpJGFycm93LnNpemU9LjAxDQoNCiNiaXQgc21hbGxlcg0KVihHMV9zZWwpJHNpemU9IDAuNSpWKEcxX3NlbCkkc2l6ZQ0KDQojbGF5b3V0DQpzZXQuc2VlZCgyNDM1Njc1KQ0KYzQgPSBsYXlvdXRfd2l0aF9mcihHMV9zZWwpDQojYzRbNzIsMV0gPC0gNQ0KI2M0WzI3LDFdIDwtIDUuNQ0KDQoNCiNwbG90DQoNCiNwbmcoIlJSX2ZvbGxvd2Vyc19kaXJlY3RlZC5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsNCnBsb3QoRzFfc2VsLCBsYXlvdXQ9YzQsIG1hcmdpbj1jKDAsMCwwLDApLCAgbWFpbj0iRm9sbG93ZXJzIHJlbGF0aW9ucyBiZXR3ZWVuIER1dGNoIE1QcyAoMjAxNykiKQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9UGFydHlfbmFtZXMsIHBjaD0yMSwgY29sPSIjNzc3Nzc3IiwgcHQuYmc9UGFydHlfY29scywgcHQuY2V4PTIsIGNleD0uOCwgYnR5PSJuIiwgbmNvbD0zKQ0KDQp0ZXh0KC0xLjIsLTEuMiwgIk5vdGUgMTogTm9kZSBzaXplIGJhc2VkIG9uIGRlZ3JlZSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMS4yLC0xLjI1LCAiTm90ZSAyOiBFZGdlIGNvbGFyIGJhc2VkIG9uIFBhcnR5IG9mIE1QcywgYmxhY2sgaWYgTVBzIGZyb20gZGlmZmVyZW50IHBhcnR5IiwgYWRqPTAsIGNleD0wLjgpDQp0ZXh0KC0xLjIsLTEuMywgIk5vdGUgMzogSXNvbGF0ZXMgcmVtb3ZlZCIsIGFkaj0wLCBjZXg9MC44KQ0KDQp9ICANCiNkZXYub2ZmKCkNCg0KcG5nKCJSUl9mb2xsb3dlcnNfZGlyZWN0ZWR2Mi5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsNCnBsb3QoRzFfc2VsLCBsYXlvdXQ9YzQsIG1hcmdpbj1jKDAsMCwwLDApKQ0KfSAgDQpkZXYub2ZmKCkNCg0KDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPVRSVUUsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnUlJmb2xsb3dlcnNkaXJlY3RlZC5wbmcnKQ0KYGBgDQoNCi0tLSAgDQoNCiMjIyBGb2xsb3dlcnMgKHVuZGlyZWN0ZWQpDQoNCioqRklYRUQgTE9DQVRJT05TIEFTIElOIEhvUCoqDQoNCmBgYHtyIEcxLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0V9DQpHMSA8LSBHMXUNCg0KRShHMSkkY3VydmVkPS4xDQoNClYoRzEpJGNvbG9yIDwtIGtleWYkUGFydGlqX2NvbA0KVihHMSkkc2l6ZT0gZGVncmVlKEcxKSouMyArIDYNClYoRzEpJGxhYmVsPSIiDQoNCm93bmNvb3JkcyA8LSBjYmluZChrZXlmJFgsIGtleWYkWSkNCm93bmNvb3JkcyA8LSBvd25jb29yZHMvOA0Kb3duY29vcmRzWywxXSA8LSAob3duY29vcmRzWywxXSAtIG1lYW4ob3duY29vcmRzWywxXSkpDQpvd25jb29yZHNbLDJdIDwtIChvd25jb29yZHNbLDJdIC0gbWVhbihvd25jb29yZHNbLDJdKSkNCg0KI2NoYW5nZSBjb2xvciBvZiBlZGdlcyBiYXNlZCBvbiBpbnRyYSBvciBpbnRlcnBhcnR5IHRpZXMNCiNmb3IgdHJhbnNwYXJhbnQgYmxhY2s6ICMwMDAwMDA3RA0KZWRnZXMgPC0gZ2V0LmFkamFjZW5jeShHMSkNCmVkZ2VzX21hdCA8LSBtYXRyaXgoYXMubnVtZXJpYyhlZGdlcyksIG5yb3c9bnJvdyhlZGdlcykpDQplZGdlc19tYXRbbG93ZXIudHJpKGVkZ2VzX21hdCldIDwtIDANCnRlbGxlciA8LSAxDQpjb2xvcmVkZ2VzIDwtIE5BDQpmb3IgKGkgaW4gMTpucm93KGVkZ2VzKSkgew0KICBmb3IgKGogaW4gMTpuY29sKGVkZ2VzKSkgew0KICAgIGlmIChlZGdlc19tYXRbaSxqXT09MSkgew0KICAgICAgaWYgKGtleWYkUGFydGlqX2NvbFtpXSA9PSBrZXlmJFBhcnRpal9jb2xbal0pIHtjb2xvcmVkZ2VzW3RlbGxlcl0gPC0ga2V5ZiRQYXJ0aWpfY29sW2ldfQ0KICAgICAgaWYgKGtleWYkUGFydGlqX2NvbFtpXSAhPSBrZXlmJFBhcnRpal9jb2xbal0pIHtjb2xvcmVkZ2VzW3RlbGxlcl0gPC0gIiMwMDAwMDA0QiJ9DQogICAgICB0ZWxsZXIgPC0gdGVsbGVyICsgMQ0KICAgIH0NCiAgfQ0KfQ0KRShHMSkkY29sb3I9Y29sb3JlZGdlcw0KDQojcHJlcGFyZSBhIGxlZ2VuZA0KUGFydHlfbmFtZXMgPC0gdW5pcXVlKGtleWYkUGFydGlqKQ0KUGFydHlfY29scyA8LSB1bmlxdWUoa2V5ZiRQYXJ0aWpfY29sKQ0KDQojIHJlb3JkZXINClBhcnR5X25hbWVzIDwtIFBhcnR5X25hbWVzW2MoNywgMywgOSwgMTAsIDEyLCAxMSwgNSwgNCwgNiwgMiwgOCwgMSwgMTMpXQ0KUGFydHlfY29scyA8LSBQYXJ0eV9jb2xzW2MoNywgMywgOSwgMTAsIDEyLCAxMSwgNSwgNCwgNiwgMiwgOCwgMSwgMTMpXQ0KDQojcG5nKCJNUHBsb3RHMXV2Mi5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsgDQogIHBsb3QuaWdyYXBoKEcxLCBtb2RlPSJ1bmRpcmVjdGVkIiwgbGF5b3V0PW93bmNvb3JkcywgcmVzY2FsZT1GLCBtYXJnaW49YygwLDAsMCwwKSwgeGxpbT1jKG1pbihvd25jb29yZHNbLDFdKSxtYXgob3duY29vcmRzWywxXSkpLCAgeWxpbT1jKG1pbihvd25jb29yZHNbLDJdKSxtYXgob3duY29vcmRzWywyXSkpLCBtYWluPSJSZWNpcHJvY2F0ZWQgZm9sbG93ZXIgcmVsYXRpb25zIGJldHdlZW4gRHV0Y2ggTVBzICgyMDE3KSIpDQoNCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZD1QYXJ0eV9uYW1lcywgcGNoPTIxLCBjb2w9IiM3Nzc3NzciLCBwdC5iZz1QYXJ0eV9jb2xzLCBwdC5jZXg9MiwgY2V4PS44LCBidHk9Im4iLCBuY29sPTMpDQoNCnRleHQoLTIuMiwtMS4yLCAiTm90ZSAxOiBOb2RlIHNpemUgYmFzZWQgb24gZGVncmVlIiwgYWRqPTAsIGNleD0wLjgpDQp0ZXh0KC0yLjIsLTEuMywgIk5vdGUgMjogRWRnZSBjb2xvciBiYXNlZCBvbiBQYXJ0eSBvZiBNUHMsIGJsYWNrIGlmIE1QcyBmcm9tIGRpZmZlcmVudCBwYXJ0eSIsIGFkaj0wLCBjZXg9MC44KQ0KfSAgDQojZGV2Lm9mZigpDQogDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPVRSVUUsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnTVBwbG90RzF1djIucG5nJykNCmBgYA0KDQoqKkZydWNodGVybWFuLVJlaW5nb2xkIGxheW91dCBhbGdvcml0aG0qKg0KDQpgYGB7ciwgZWNobz1UUlVFLCBldmFsPUZBTFNFfQ0KI2NoYW5nZSBjb2xvcnMgYSBiaXQNCmRmX2NvbCA8LSBjb2wycmdiKFYoRzEpJGNvbG9yKQ0KVihHMSkkY29sb3IyIDwtIHJnYih0KGRmX2NvbCksIGFscGhhPTEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkNCg0KZGZfY29sIDwtIGNvbDJyZ2IoRShHMSkkY29sb3IpDQpFKEcxKSRjb2xvcjIgPC0gcmdiKHQoZGZfY29sKSwgYWxwaGE9MTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KQ0KRShHMSkkY29sb3IyW3doaWNoKEUoRzEpJGNvbG9yPT0iIzAwMDAwMDRCIildIDwtICIjMDAwMDAwMTAiDQoNCiNyZW1vdmUgaXNvbGF0ZXMNCklzb2xhdGVkID0gd2hpY2goZGVncmVlKEcxKT09MCkNCkcxX3NlbCA9IGRlbGV0ZS52ZXJ0aWNlcyhHMSwgSXNvbGF0ZWQpDQojRzJfc2VsID0gZGVsZXRlLnZlcnRpY2VzKEcyX3NlbCwgYyg3MiwyNykpICNvbmx5IGNvbm5lY3RlZCB0byBlYWNoIG90aGVyDQoNClYoRzFfc2VsKSRjb2xvciA8LSBWKEcxX3NlbCkkY29sb3IyDQpFKEcxX3NlbCkkY29sb3IgPC0gRShHMV9zZWwpJGNvbG9yMg0KDQojc21hbGxlciBhcnJvd3MNCkUoRzEpJGFycm93LnNpemU9LjAxDQoNCiNiaXQgc21hbGxlcg0KVihHMV9zZWwpJHNpemU9IDAuNSpWKEcxX3NlbCkkc2l6ZQ0KDQojbGF5b3V0DQpzZXQuc2VlZCgyNDM1Njc1KQ0KYzQgPSBsYXlvdXRfd2l0aF9mcihHMV9zZWwpDQojYzRbNzIsMV0gPC0gNQ0KI2M0WzI3LDFdIDwtIDUuNQ0KDQojcGxvdA0KDQojcG5nKCJSUl9mb2xsb3dlcnNfdW5kaXJlY3RlZC5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsNCnBsb3QoRzFfc2VsLCBsYXlvdXQ9YzQsIG1hcmdpbj1jKDAsMCwwLDApLCAgbWFpbj0iUmVjaXByb2NhdGVkIGZvbGxvd2VycyByZWxhdGlvbnMgYmV0d2VlbiBEdXRjaCBNUHMgKDIwMTcpIikNCg0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kPVBhcnR5X25hbWVzLCBwY2g9MjEsIGNvbD0iIzc3Nzc3NyIsIHB0LmJnPVBhcnR5X2NvbHMsIHB0LmNleD0yLCBjZXg9LjgsIGJ0eT0ibiIsIG5jb2w9MykNCg0KdGV4dCgtMS4yLC0xLjIsICJOb3RlIDE6IE5vZGUgc2l6ZSBiYXNlZCBvbiBkZWdyZWUiLCBhZGo9MCwgY2V4PTAuOCkNCnRleHQoLTEuMiwtMS4yNSwgIk5vdGUgMjogRWRnZSBjb2xhciBiYXNlZCBvbiBQYXJ0eSBvZiBNUHMsIGJsYWNrIGlmIE1QcyBmcm9tIGRpZmZlcmVudCBwYXJ0eSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMS4yLC0xLjMsICJOb3RlIDM6IElzb2xhdGVzIHJlbW92ZWQiLCBhZGo9MCwgY2V4PTAuOCkNCg0KfSAgDQojZGV2Lm9mZigpDQoNCnBuZygiUlJfZm9sbG93ZXJzX3VuZGlyZWN0ZWR2Mi5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsNCnBsb3QoRzFfc2VsLCBsYXlvdXQ9YzQsIG1hcmdpbj1jKDAsMCwwLDApKQ0KfSAgDQpkZXYub2ZmKCkNCg0KDQoNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdSUmZvbGxvd2Vyc3VuZGlyZWN0ZWQucG5nJykNCmBgYA0KDQotLS0gIA0KDQojIyMgYXQtbWVudGlvbiAoZGlyZWN0ZWQpIA0KDQoqKkZJWEVEIExPQ0FUSU9OUyBBUyBJTiBIb1AqKg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCg0KRzIgPC0gRzJkDQoNCkUoRzIpJGN1cnZlZD0uMQ0KRShHMikkYXJyb3cuc2l6ZT0uMQ0KVihHMikkY29sb3IgPC0ga2V5ZiRQYXJ0aWpfY29sDQpWKEcyKSRzaXplPSBkZWdyZWUoRzIsIG1vZGU9Im91dCIpKi41ICsgNg0KVihHMikkbGFiZWw9IiINCg0Kb3duY29vcmRzIDwtIGNiaW5kKGtleWYkWCwga2V5ZiRZKQ0Kb3duY29vcmRzIDwtIG93bmNvb3Jkcy84DQpvd25jb29yZHNbLDFdIDwtIChvd25jb29yZHNbLDFdIC0gbWVhbihvd25jb29yZHNbLDFdKSkNCm93bmNvb3Jkc1ssMl0gPC0gKG93bmNvb3Jkc1ssMl0gLSBtZWFuKG93bmNvb3Jkc1ssMl0pKQ0KDQojY2hhbmdlIGNvbG9yIG9mIGVkZ2VzIGJhc2VkIG9uIGludHJhIG9yIGludGVycGFydHkgdGllcw0KZWRnZXMgPC0gZ2V0LmFkamFjZW5jeShHMikNCmVkZ2VzX21hdCA8LSBtYXRyaXgoYXMubnVtZXJpYyhlZGdlcyksIG5yb3c9bnJvdyhlZGdlcykpDQojZWRnZXNfbWF0W2xvd2VyLnRyaShlZGdlc19tYXQpXSA8LSAwDQp0ZWxsZXIgPC0gMQ0KY29sb3JlZGdlcyA8LSBOQQ0KZm9yIChpIGluIDE6bnJvdyhlZGdlcykpIHsNCiAgZm9yIChqIGluIDE6bmNvbChlZGdlcykpIHsNCiAgICBpZiAoZWRnZXNfbWF0W2ksal09PTEpIHsNCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gPT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtIGtleWYkUGFydGlqX2NvbFtpXX0NCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gIT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtICIjMDAwMDAwNEIifQ0KICAgICAgdGVsbGVyIDwtIHRlbGxlciArIDENCiAgICB9DQogIH0NCn0NCkUoRzIpJGNvbG9yPWNvbG9yZWRnZXMNCg0KI3ByZXBhcmUgYSBsZWdlbmQNClBhcnR5X25hbWVzIDwtIHVuaXF1ZShrZXlmJFBhcnRpaikNClBhcnR5X2NvbHMgPC0gdW5pcXVlKGtleWYkUGFydGlqX2NvbCkNCg0KIyByZW9yZGVyDQpQYXJ0eV9uYW1lcyA8LSBQYXJ0eV9uYW1lc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NClBhcnR5X2NvbHMgPC0gUGFydHlfY29sc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NCg0KI3BuZygiTVBwbG90RzJkdjIucG5nIix3aWR0aCA9IDkwMCwgaGVpZ2h0PSA5MDApDQp7IA0KICBwbG90LmlncmFwaChHMiwgbW9kZT0iZGlyZWN0ZWQiLCBsYXlvdXQ9b3duY29vcmRzLCByZXNjYWxlPUYsIG1hcmdpbj1jKDAsMCwwLDApLCB4bGltPWMobWluKG93bmNvb3Jkc1ssMV0pLG1heChvd25jb29yZHNbLDFdKSksICB5bGltPWMobWluKG93bmNvb3Jkc1ssMl0pLG1heChvd25jb29yZHNbLDJdKSksIG1haW49IkBtZW50aW9uIHJlbGF0aW9ucyBiZXR3ZWVuIER1dGNoIE1QcyAoMjAxNykiKQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9UGFydHlfbmFtZXMsIHBjaD0yMSwgY29sPSIjNzc3Nzc3IiwgcHQuYmc9UGFydHlfY29scywgcHQuY2V4PTIsIGNleD0uOCwgYnR5PSJuIiwgbmNvbD0zKQ0KDQp0ZXh0KC0yLjIsLTEuMiwgIk5vdGUgMTogTm9kZSBzaXplIGJhc2VkIG9uIGRlZ3JlZSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMi4yLC0xLjMsICJOb3RlIDI6IEVkZ2UgY29sYXIgYmFzZWQgb24gUGFydHkgb2YgTVBzLCBibGFjayBpZiBNUHMgZnJvbSBkaWZmZXJlbnQgcGFydHkiLCBhZGo9MCwgY2V4PTAuOCkNCn0gIA0KI2Rldi5vZmYoKQ0KIA0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdNUHBsb3RHMmQucG5nJykNCmBgYA0KDQoqKkZydWNodGVybWFuLVJlaW5nb2xkIGxheW91dCBhbGdvcml0aG0qKg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiNjaGFuZ2UgY29sb3JzIGEgYml0DQpkZl9jb2wgPC0gY29sMnJnYihWKEcyKSRjb2xvcikNClYoRzIpJGNvbG9yMiA8LSByZ2IodChkZl9jb2wpLCBhbHBoYT0xNzUsIG1heENvbG9yVmFsdWUgPSAyNTUpDQoNCmRmX2NvbCA8LSBjb2wycmdiKEUoRzIpJGNvbG9yKQ0KRShHMikkY29sb3IyIDwtIHJnYih0KGRmX2NvbCksIGFscGhhPTE3NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkNCkUoRzIpJGNvbG9yMlt3aGljaChFKEcyKSRjb2xvcj09IiMwMDAwMDA0QiIpXSA8LSAiIzAwMDAwMDRCIg0KDQojcmVtb3ZlIGlzb2xhdGVzDQpJc29sYXRlZCA9IHdoaWNoKGRlZ3JlZShHMik9PTApDQpHMl9zZWwgPSBkZWxldGUudmVydGljZXMoRzIsIElzb2xhdGVkKQ0KI0cyX3NlbCA9IGRlbGV0ZS52ZXJ0aWNlcyhHMl9zZWwsIGMoNzIsMjcpKSAjb25seSBjb25uZWN0ZWQgdG8gZWFjaCBvdGhlcg0KDQpWKEcyX3NlbCkkY29sb3IgPC0gVihHMl9zZWwpJGNvbG9yMg0KRShHMl9zZWwpJGNvbG9yIDwtIEUoRzJfc2VsKSRjb2xvcjINCg0KI3NtYWxsZXIgYXJyb3dzDQpFKEcyKSRhcnJvdy5zaXplPS4xDQoNCiNiaXQgc21hbGxlcg0KVihHMl9zZWwpJHNpemU9IDAuNypWKEcyX3NlbCkkc2l6ZQ0KDQojbGF5b3V0DQpzZXQuc2VlZCgyNDM1Njc2KQ0KYzQgPSBsYXlvdXRfd2l0aF9mcihHMl9zZWwpDQpjNFs3MiwxXSA8LSA1DQpjNFsyNywxXSA8LSA1LjUNCg0KcGxvdChHMl9zZWwsIGxheW91dD1jNCwgbWFyZ2luPWMoMCwwLDAsMCksIHJlc2NhbGU9RkFMU0UsIHhsaW09YyhtaW4oYzRbLDFdKSxtYXgoYzRbLDFdKSksICB5bGltPWMobWluKGM0WywyXSksbWF4KGM0WywyXSkpLCBtYWluPSJAbWVudGlvbiByZWxhdGlvbnMgYmV0d2VlbiBEdXRjaCBNUHMgKDIwMTcpIikNCiNwbG90DQoNCnBuZygiUlJfYXRtZW50aW9uX2RpcmVjdGVkLnBuZyIsd2lkdGggPSA5MDAsIGhlaWdodD0gOTAwKQ0Kew0KcGxvdChHMl9zZWwsIGxheW91dD1jNCwgbWFyZ2luPWMoMCwwLDAsMCksICBtYWluPSJAbWVudGlvbiByZWxhdGlvbnMgYmV0d2VlbiBEdXRjaCBNUHMgKDIwMTcpIikNCg0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kPVBhcnR5X25hbWVzLCBwY2g9MjEsIGNvbD0iIzc3Nzc3NyIsIHB0LmJnPVBhcnR5X2NvbHMsIHB0LmNleD0yLCBjZXg9LjgsIGJ0eT0ibiIsIG5jb2w9MykNCg0KdGV4dCgtMS4yLC0xLjIsICJOb3RlIDE6IE5vZGUgc2l6ZSBiYXNlZCBvbiBkZWdyZWUiLCBhZGo9MCwgY2V4PTAuOCkNCnRleHQoLTEuMiwtMS4yNSwgIk5vdGUgMjogRWRnZSBjb2xhciBiYXNlZCBvbiBQYXJ0eSBvZiBNUHMsIGJsYWNrIGlmIE1QcyBmcm9tIGRpZmZlcmVudCBwYXJ0eSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMS4yLC0xLjMsICJOb3RlIDM6IElzb2xhdGVzIHJlbW92ZWQiLCBhZGo9MCwgY2V4PTAuOCkNCg0KfSAgDQpkZXYub2ZmKCkNCg0KcG5nKCJSUl9hdG1lbnRpb25fZGlyZWN0ZWR2Mi5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsNCnBsb3QoRzJfc2VsLCBsYXlvdXQ9YzQsIG1hcmdpbj1jKDAsMCwwLDApKQ0KfSAgDQpkZXYub2ZmKCkNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdSUmF0bWVudGlvbmRpcmVjdGVkLnBuZycpDQpgYGANCg0KLS0tICAgDQoNCiMjIyBhdG1lbnRpb25zICh1bmRpcmVjdGVkKQ0KDQoqKkZJWEVEIExPQ0FUSU9OUyBBUyBJTiBIb1AqKg0KDQpgYGB7ciBHMiwgZWNobz1UUlVFLCBldmFsPUZBTFNFfQ0KRzIgPC0gRzJ1DQoNCkUoRzIpJGN1cnZlZD0uMQ0KDQpWKEcyKSRjb2xvciA8LSBrZXlmJFBhcnRpal9jb2wNClYoRzIpJHNpemU9IGRlZ3JlZShHMikqMS4wNSArIDYNClYoRzIpJGxhYmVsPSIiDQoNCm93bmNvb3JkcyA8LSBjYmluZChrZXlmJFgsIGtleWYkWSkNCm93bmNvb3JkcyA8LSBvd25jb29yZHMvOA0Kb3duY29vcmRzWywxXSA8LSAob3duY29vcmRzWywxXSAtIG1lYW4ob3duY29vcmRzWywxXSkpDQpvd25jb29yZHNbLDJdIDwtIChvd25jb29yZHNbLDJdIC0gbWVhbihvd25jb29yZHNbLDJdKSkNCg0KI2NoYW5nZSBjb2xvciBvZiBlZGdlcyBiYXNlZCBvbiBpbnRyYSBvciBpbnRlcnBhcnR5IHRpZXMNCmVkZ2VzIDwtIGdldC5hZGphY2VuY3koRzIpDQplZGdlc19tYXQgPC0gbWF0cml4KGFzLm51bWVyaWMoZWRnZXMpLCBucm93PW5yb3coZWRnZXMpKQ0KZWRnZXNfbWF0W2xvd2VyLnRyaShlZGdlc19tYXQpXSA8LSAwDQp0ZWxsZXIgPC0gMQ0KY29sb3JlZGdlcyA8LSBOQQ0KZm9yIChpIGluIDE6bnJvdyhlZGdlcykpIHsNCiAgZm9yIChqIGluIDE6bmNvbChlZGdlcykpIHsNCiAgICBpZiAoZWRnZXNfbWF0W2ksal09PTEpIHsNCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gPT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtIGtleWYkUGFydGlqX2NvbFtpXX0NCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gIT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtICIjMDAwMDAwNEIifQ0KICAgICAgdGVsbGVyIDwtIHRlbGxlciArIDENCiAgICB9DQogIH0NCn0NCkUoRzIpJGNvbG9yPWNvbG9yZWRnZXMNCg0KI3ByZXBhcmUgYSBsZWdlbmQNClBhcnR5X25hbWVzIDwtIHVuaXF1ZShrZXlmJFBhcnRpaikNClBhcnR5X2NvbHMgPC0gdW5pcXVlKGtleWYkUGFydGlqX2NvbCkNCg0KIyByZW9yZGVyDQpQYXJ0eV9uYW1lcyA8LSBQYXJ0eV9uYW1lc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NClBhcnR5X2NvbHMgPC0gUGFydHlfY29sc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NCg0KI3BuZygiTVBwbG90RzJ1djIucG5nIix3aWR0aCA9IDkwMCwgaGVpZ2h0PSA5MDApDQp7IA0KICBwbG90LmlncmFwaChHMiwgbW9kZT0idW5kaXJlY3RlZCIsIGxheW91dD1vd25jb29yZHMsIHJlc2NhbGU9RiwgbWFyZ2luPWMoMCwwLDAsMCksIHhsaW09YyhtaW4ob3duY29vcmRzWywxXSksbWF4KG93bmNvb3Jkc1ssMV0pKSwgIHlsaW09YyhtaW4ob3duY29vcmRzWywyXSksbWF4KG93bmNvb3Jkc1ssMl0pKSwgbWFpbj0iUmVjaXByb2NhdGVkIEBtZW50aW9uIHJlbGF0aW9ucyBiZXR3ZWVuIER1dGNoIE1QcyAoMjAxNykiKQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9UGFydHlfbmFtZXMsIHBjaD0yMSwgY29sPSIjNzc3Nzc3IiwgcHQuYmc9UGFydHlfY29scywgcHQuY2V4PTIsIGNleD0uOCwgYnR5PSJuIiwgbmNvbD0zKQ0KDQp0ZXh0KC0yLjIsLTEuMiwgIk5vdGUgMTogTm9kZSBzaXplIGJhc2VkIG9uIGRlZ3JlZSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMi4yLC0xLjMsICJOb3RlIDI6IEVkZ2UgY29sYXIgYmFzZWQgb24gUGFydHkgb2YgTVBzLCBibGFjayBpZiBNUHMgZnJvbSBkaWZmZXJlbnQgcGFydHkiLCBhZGo9MCwgY2V4PTAuOCkNCn0gIA0KI2Rldi5vZmYoKQ0KDQpgYGANCg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPVRSVUUsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnTVBwbG90RzJ1LnBuZycpDQpgYGANCg0KKipGcnVjaHRlcm1hbi1SZWluZ29sZCBsYXlvdXQgYWxnb3JpdGhtKioNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojY2hhbmdlIGNvbG9ycyBhIGJpdA0KZGZfY29sIDwtIGNvbDJyZ2IoVihHMikkY29sb3IpDQpWKEcyKSRjb2xvcjIgPC0gcmdiKHQoZGZfY29sKSwgYWxwaGE9MTc1LCBtYXhDb2xvclZhbHVlID0gMjU1KQ0KDQpkZl9jb2wgPC0gY29sMnJnYihFKEcyKSRjb2xvcikNCkUoRzIpJGNvbG9yMiA8LSByZ2IodChkZl9jb2wpLCBhbHBoYT0xNzUsIG1heENvbG9yVmFsdWUgPSAyNTUpDQpFKEcyKSRjb2xvcjJbd2hpY2goRShHMikkY29sb3I9PSIjMDAwMDAwNEIiKV0gPC0gIiMwMDAwMDA0QiINCg0KI3JlbW92ZSBpc29sYXRlcw0KSXNvbGF0ZWQgPSB3aGljaChkZWdyZWUoRzIpPT0wKQ0KRzJfc2VsID0gZGVsZXRlLnZlcnRpY2VzKEcyLCBJc29sYXRlZCkNCiNHMl9zZWwgPSBkZWxldGUudmVydGljZXMoRzJfc2VsLCBjKDcyLDI3KSkgI29ubHkgY29ubmVjdGVkIHRvIGVhY2ggb3RoZXINCg0KVihHMl9zZWwpJGNvbG9yIDwtIFYoRzJfc2VsKSRjb2xvcjINCkUoRzJfc2VsKSRjb2xvciA8LSBFKEcyX3NlbCkkY29sb3IyDQoNCiNzbWFsbGVyIGFycm93cw0KRShHMikkYXJyb3cuc2l6ZT0uMQ0KDQojYml0IHNtYWxsZXINClYoRzJfc2VsKSRzaXplPSAwLjcqVihHMl9zZWwpJHNpemUNCg0KI2xheW91dA0Kc2V0LnNlZWQoMjQzNTY3NikNCmM0ID0gbGF5b3V0X3dpdGhfZnIoRzJfc2VsKQ0KDQpwbG90KEcyX3NlbCwgbGF5b3V0PWM0LCBtYXJnaW49YygwLDAsMCwwKSwgcmVzY2FsZT1GQUxTRSwgeGxpbT1jKG1pbihjNFssMV0pLG1heChjNFssMV0pKSwgIHlsaW09YyhtaW4oYzRbLDJdKSxtYXgoYzRbLDJdKSksIG1haW49IkBtZW50aW9uIHJlbGF0aW9ucyBiZXR3ZWVuIER1dGNoIE1QcyAoMjAxNykiKQ0KI3Bsb3QNCg0KI3BuZygiUlJfYXRtZW50aW9uX3VuZGlyZWN0ZWQucG5nIix3aWR0aCA9IDkwMCwgaGVpZ2h0PSA5MDApDQp7DQpwbG90KEcyX3NlbCwgbGF5b3V0PWM0LCBtYXJnaW49YygwLDAsMCwuMTUpLCAgbWFpbj0iUmVjaXByb2NhdGVkIEBtZW50aW9uIHJlbGF0aW9ucyBiZXR3ZWVuIER1dGNoIE1QcyAoMjAxNykiKQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9UGFydHlfbmFtZXMsIHBjaD0yMSwgY29sPSIjNzc3Nzc3IiwgcHQuYmc9UGFydHlfY29scywgcHQuY2V4PTIsIGNleD0uOCwgYnR5PSJuIiwgbmNvbD0zKQ0KDQp0ZXh0KC0xLjIsLTEuMiwgIk5vdGUgMTogTm9kZSBzaXplIGJhc2VkIG9uIGRlZ3JlZSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMS4yLC0xLjI1LCAiTm90ZSAyOiBFZGdlIGNvbGFyIGJhc2VkIG9uIFBhcnR5IG9mIE1QcywgYmxhY2sgaWYgTVBzIGZyb20gZGlmZmVyZW50IHBhcnR5IiwgYWRqPTAsIGNleD0wLjgpDQp0ZXh0KC0xLjIsLTEuMywgIk5vdGUgMzogSXNvbGF0ZXMgcmVtb3ZlZCIsIGFkaj0wLCBjZXg9MC44KQ0KDQp9ICANCiNkZXYub2ZmKCkNCg0KcG5nKCJSUl9hdG1lbnRpb25fdW5kaXJlY3RlZHYyLnBuZyIsd2lkdGggPSA5MDAsIGhlaWdodD0gOTAwKQ0Kew0KcGxvdChHMl9zZWwsIGxheW91dD1jNCwgbWFyZ2luPWMoMCwwLDAsLjE1KSkNCn0gIA0KZGV2Lm9mZigpDQoNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdSUmF0bWVudGlvbnVuZGlyZWN0ZWQucG5nJykNCmBgYA0KDQoNCi0tLSAgDQoNCiMjIyByZXR3ZWV0IChkaXJlY3RlZCkNCg0KKipGSVhFRCBMT0NBVElPTlMgQVMgSU4gSG9QKioNCg0KYGBge3IgRzNkLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0V9DQpHMyA8LSBHM2QNCg0KRShHMykkY3VydmVkPS4xDQpFKEczKSRhcnJvdy5zaXplPS4xDQoNClYoRzMpJGNvbG9yIDwtIGtleWYkUGFydGlqX2NvbA0KVihHMykkc2l6ZT0gZGVncmVlKEczLCBtb2RlPSJvdXQiKSouNSArIDYNClYoRzMpJGxhYmVsPSIiDQoNCm93bmNvb3JkcyA8LSBjYmluZChrZXlmJFgsIGtleWYkWSkNCm93bmNvb3JkcyA8LSBvd25jb29yZHMvOA0Kb3duY29vcmRzWywxXSA8LSAob3duY29vcmRzWywxXSAtIG1lYW4ob3duY29vcmRzWywxXSkpDQpvd25jb29yZHNbLDJdIDwtIChvd25jb29yZHNbLDJdIC0gbWVhbihvd25jb29yZHNbLDJdKSkNCg0KI2NoYW5nZSBjb2xvciBvZiBlZGdlcyBiYXNlZCBvbiBpbnRyYSBvciBpbnRlcnBhcnR5IHRpZXMNCmVkZ2VzIDwtIGdldC5hZGphY2VuY3koRzMpDQplZGdlc19tYXQgPC0gbWF0cml4KGFzLm51bWVyaWMoZWRnZXMpLCBucm93PW5yb3coZWRnZXMpKQ0KI2VkZ2VzX21hdFtsb3dlci50cmkoZWRnZXNfbWF0KV0gPC0gMA0KdGVsbGVyIDwtIDENCmNvbG9yZWRnZXMgPC0gTkENCmZvciAoaSBpbiAxOm5yb3coZWRnZXMpKSB7DQogIGZvciAoaiBpbiAxOm5jb2woZWRnZXMpKSB7DQogICAgaWYgKGVkZ2VzX21hdFtpLGpdPT0xKSB7DQogICAgICBpZiAoa2V5ZiRQYXJ0aWpfY29sW2ldID09IGtleWYkUGFydGlqX2NvbFtqXSkge2NvbG9yZWRnZXNbdGVsbGVyXSA8LSBrZXlmJFBhcnRpal9jb2xbaV19DQogICAgICBpZiAoa2V5ZiRQYXJ0aWpfY29sW2ldICE9IGtleWYkUGFydGlqX2NvbFtqXSkge2NvbG9yZWRnZXNbdGVsbGVyXSA8LSAiIzAwMDAwMDRCIn0NCiAgICAgIHRlbGxlciA8LSB0ZWxsZXIgKyAxDQogICAgfQ0KICB9DQp9DQpFKEczKSRjb2xvcj1jb2xvcmVkZ2VzDQoNCiNwcmVwYXJlIGEgbGVnZW5kDQpQYXJ0eV9uYW1lcyA8LSB1bmlxdWUoa2V5ZiRQYXJ0aWopDQpQYXJ0eV9jb2xzIDwtIHVuaXF1ZShrZXlmJFBhcnRpal9jb2wpDQoNCiMgcmVvcmRlcg0KUGFydHlfbmFtZXMgPC0gUGFydHlfbmFtZXNbYyg3LCAzLCA5LCAxMCwgMTIsIDExLCA1LCA0LCA2LCAyLCA4LCAxLCAxMyldDQpQYXJ0eV9jb2xzIDwtIFBhcnR5X2NvbHNbYyg3LCAzLCA5LCAxMCwgMTIsIDExLCA1LCA0LCA2LCAyLCA4LCAxLCAxMyldDQoNCiNwbmcoIk1QcGxvdEczZHYyLnBuZyIsd2lkdGggPSA5MDAsIGhlaWdodD0gOTAwKQ0KeyANCiAgcGxvdC5pZ3JhcGgoRzMsIG1vZGU9InVuZGlyZWN0ZWQiLCBsYXlvdXQ9b3duY29vcmRzLCByZXNjYWxlPUYsIG1hcmdpbj1jKDAsMCwwLDApLCB4bGltPWMobWluKG93bmNvb3Jkc1ssMV0pLTAuMixtYXgob3duY29vcmRzWywxXSkpICsuMiAsICB5bGltPWMobWluKG93bmNvb3Jkc1ssMl0pLG1heChvd25jb29yZHNbLDJdKSksIG1haW49IlJldHdlZXQgcmVsYXRpb25zIGJldHdlZW4gRHV0Y2ggTVBzICgyMDE3KSIpDQoNCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZD1QYXJ0eV9uYW1lcywgcGNoPTIxLCBjb2w9IiM3Nzc3NzciLCBwdC5iZz1QYXJ0eV9jb2xzLCBwdC5jZXg9MiwgY2V4PS44LCBidHk9Im4iLCBuY29sPTMpDQoNCnRleHQoLTIuMiwtMS4yLCAiTm90ZSAxOiBOb2RlIHNpemUgYmFzZWQgb24gZGVncmVlIiwgYWRqPTAsIGNleD0wLjgpDQp0ZXh0KC0yLjIsLTEuMywgIk5vdGUgMjogRWRnZSBjb2xhciBiYXNlZCBvbiBQYXJ0eSBvZiBNUHMsIGJsYWNrIGlmIE1QcyBmcm9tIGRpZmZlcmVudCBwYXJ0eSIsIGFkaj0wLCBjZXg9MC44KQ0KfSAgDQojZGV2Lm9mZigpDQogDQoNCmBgYA0KDQoNCmBgYHtyIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdNUHBsb3RHM2QucG5nJykNCmBgYA0KDQoqKkZydWNodGVybWFuLVJlaW5nb2xkIGxheW91dCBhbGdvcml0aG0qKg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiNjaGFuZ2UgY29sb3JzIGEgYml0DQpkZl9jb2wgPC0gY29sMnJnYihWKEczKSRjb2xvcikNClYoRzMpJGNvbG9yMiA8LSByZ2IodChkZl9jb2wpLCBhbHBoYT0xNzUsIG1heENvbG9yVmFsdWUgPSAyNTUpDQoNCmRmX2NvbCA8LSBjb2wycmdiKEUoRzMpJGNvbG9yKQ0KRShHMykkY29sb3IyIDwtIHJnYih0KGRmX2NvbCksIGFscGhhPTE3NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkNCkUoRzMpJGNvbG9yMlt3aGljaChFKEczKSRjb2xvcj09IiMwMDAwMDA0QiIpXSA8LSAiIzAwMDAwMDRCIg0KDQojcmVtb3ZlIGlzb2xhdGVzDQpJc29sYXRlZCA9IHdoaWNoKGRlZ3JlZShHMyk9PTApDQpHM19zZWwgPSBkZWxldGUudmVydGljZXMoRzMsIElzb2xhdGVkKQ0KI0czX3NlbCA9IGRlbGV0ZS52ZXJ0aWNlcyhHM19zZWwsIGMoNzIsMjcpKSAjb25seSBjb25uZWN0ZWQgdG8gZWFjaCBvdGhlcg0KDQpWKEczX3NlbCkkY29sb3IgPC0gVihHM19zZWwpJGNvbG9yMg0KRShHM19zZWwpJGNvbG9yIDwtIEUoRzNfc2VsKSRjb2xvcjINCg0KI3NtYWxsZXIgYXJyb3dzDQpFKEczKSRhcnJvdy5zaXplPS4xDQoNCiNiaXQgc21hbGxlcg0KVihHM19zZWwpJHNpemU9IDAuNypWKEczX3NlbCkkc2l6ZQ0KDQojbGF5b3V0DQpzZXQuc2VlZCgyNDM1Njc3KQ0KYzQgPSBsYXlvdXRfd2l0aF9mcihHM19zZWwpDQoNCiNwbmcoIlJSX3JldHdlZXRfZGlyZWN0ZWQucG5nIix3aWR0aCA9IDkwMCwgaGVpZ2h0PSA5MDApDQp7DQpwbG90KEczX3NlbCwgbGF5b3V0PWM0LCBtYXJnaW49YygwLDAsMCwuMTUpLCAgbWFpbj0iUmV0d2VldCByZWxhdGlvbnMgYmV0d2VlbiBEdXRjaCBNUHMgKDIwMTcpIikNCg0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kPVBhcnR5X25hbWVzLCBwY2g9MjEsIGNvbD0iIzc3Nzc3NyIsIHB0LmJnPVBhcnR5X2NvbHMsIHB0LmNleD0yLCBjZXg9LjgsIGJ0eT0ibiIsIG5jb2w9MykNCg0KdGV4dCgtMS4yLC0xLjIsICJOb3RlIDE6IE5vZGUgc2l6ZSBiYXNlZCBvbiBkZWdyZWUiLCBhZGo9MCwgY2V4PTAuOCkNCnRleHQoLTEuMiwtMS4yNSwgIk5vdGUgMjogRWRnZSBjb2xhciBiYXNlZCBvbiBQYXJ0eSBvZiBNUHMsIGJsYWNrIGlmIE1QcyBmcm9tIGRpZmZlcmVudCBwYXJ0eSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMS4yLC0xLjMsICJOb3RlIDM6IElzb2xhdGVzIHJlbW92ZWQiLCBhZGo9MCwgY2V4PTAuOCkNCg0KfSAgDQojZGV2Lm9mZigpDQoNCnBuZygiUlJfcmV0d2VldF9kaXJlY3RlZHYyLnBuZyIsd2lkdGggPSA5MDAsIGhlaWdodD0gOTAwKQ0Kew0KcGxvdChHM19zZWwsIGxheW91dD1jNCwgbWFyZ2luPWMoMCwwLDAsLjE1KSkNCn0gIA0KZGV2Lm9mZigpDQoNCg0KDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRSwgZXZhbD1UUlVFLCBvdXQud2lkdGg9JzEwMCUnfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ1JScmV0d2VldGRpcmVjdGVkLnBuZycpDQpgYGANCg0KLS0tICANCg0KIyMjIHJldHdlZXQgKHVuZGlyZWN0ZWQpDQoNCioqRklYRUQgTE9DQVRJT05TIEFTIElOIEhvUCoqDQoNCmBgYHtyIEczdSwgZWNobz1UUlVFLCBldmFsPUZBTFNFfQ0KRzMgPC0gRzN1DQoNCkUoRzMpJGN1cnZlZD0uMQ0KDQpWKEczKSRjb2xvciA8LSBrZXlmJFBhcnRpal9jb2wNClYoRzMpJHNpemU9IGRlZ3JlZShHMykqMS4wNSArIDYNClYoRzMpJGxhYmVsPSIiDQoNCm93bmNvb3JkcyA8LSBjYmluZChrZXlmJFgsIGtleWYkWSkNCm93bmNvb3JkcyA8LSBvd25jb29yZHMvOA0Kb3duY29vcmRzWywxXSA8LSAob3duY29vcmRzWywxXSAtIG1lYW4ob3duY29vcmRzWywxXSkpDQpvd25jb29yZHNbLDJdIDwtIChvd25jb29yZHNbLDJdIC0gbWVhbihvd25jb29yZHNbLDJdKSkNCg0KI2NoYW5nZSBjb2xvciBvZiBlZGdlcyBiYXNlZCBvbiBpbnRyYSBvciBpbnRlcnBhcnR5IHRpZXMNCmVkZ2VzIDwtIGdldC5hZGphY2VuY3koRzMpDQplZGdlc19tYXQgPC0gbWF0cml4KGFzLm51bWVyaWMoZWRnZXMpLCBucm93PW5yb3coZWRnZXMpKQ0KZWRnZXNfbWF0W2xvd2VyLnRyaShlZGdlc19tYXQpXSA8LSAwDQp0ZWxsZXIgPC0gMQ0KY29sb3JlZGdlcyA8LSBOQQ0KZm9yIChpIGluIDE6bnJvdyhlZGdlcykpIHsNCiAgZm9yIChqIGluIDE6bmNvbChlZGdlcykpIHsNCiAgICBpZiAoZWRnZXNfbWF0W2ksal09PTEpIHsNCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gPT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtIGtleWYkUGFydGlqX2NvbFtpXX0NCiAgICAgIGlmIChrZXlmJFBhcnRpal9jb2xbaV0gIT0ga2V5ZiRQYXJ0aWpfY29sW2pdKSB7Y29sb3JlZGdlc1t0ZWxsZXJdIDwtICIjMDAwMDAwNEIifQ0KICAgICAgdGVsbGVyIDwtIHRlbGxlciArIDENCiAgICB9DQogIH0NCn0NCkUoRzMpJGNvbG9yPWNvbG9yZWRnZXMNCg0KI3ByZXBhcmUgYSBsZWdlbmQNClBhcnR5X25hbWVzIDwtIHVuaXF1ZShrZXlmJFBhcnRpaikNClBhcnR5X2NvbHMgPC0gdW5pcXVlKGtleWYkUGFydGlqX2NvbCkNCg0KIyByZW9yZGVyDQpQYXJ0eV9uYW1lcyA8LSBQYXJ0eV9uYW1lc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NClBhcnR5X2NvbHMgPC0gUGFydHlfY29sc1tjKDcsIDMsIDksIDEwLCAxMiwgMTEsIDUsIDQsIDYsIDIsIDgsIDEsIDEzKV0NCg0KI3BuZygiTVBwbG90RzN1djIucG5nIix3aWR0aCA9IDkwMCwgaGVpZ2h0PSA5MDApDQp7IA0KICBwbG90LmlncmFwaChHMywgbW9kZT0idW5kaXJlY3RlZCIsIGxheW91dD1vd25jb29yZHMsIHJlc2NhbGU9RiwgbWFyZ2luPWMoMCwwLDAsMCksIHhsaW09YyhtaW4ob3duY29vcmRzWywxXSkgLSAwLjIgLG1heChvd25jb29yZHNbLDFdKSkgKzAuMiwgIHlsaW09YyhtaW4ob3duY29vcmRzWywyXSksbWF4KG93bmNvb3Jkc1ssMl0pKSwgbWFpbj0iUmVjaXByb2NhdGVkIHJldHdlZXQgcmVsYXRpb25zIGJldHdlZW4gRHV0Y2ggTVBzICgyMDE3KSIpDQoNCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZD1QYXJ0eV9uYW1lcywgcGNoPTIxLCBjb2w9IiM3Nzc3NzciLCBwdC5iZz1QYXJ0eV9jb2xzLCBwdC5jZXg9MiwgY2V4PS44LCBidHk9Im4iLCBuY29sPTMpDQoNCnRleHQoLTIuMiwtMS4yLCAiTm90ZSAxOiBOb2RlIHNpemUgYmFzZWQgb24gZGVncmVlIiwgYWRqPTAsIGNleD0wLjgpDQp0ZXh0KC0yLjIsLTEuMywgIk5vdGUgMjogRWRnZSBjb2xhciBiYXNlZCBvbiBQYXJ0eSBvZiBNUHMsIGJsYWNrIGlmIE1QcyBmcm9tIGRpZmZlcmVudCBwYXJ0eSIsIGFkaj0wLCBjZXg9MC44KQ0KfSAgDQojZGV2Lm9mZigpDQogDQoNCmBgYA0KDQoNCmBgYHtyIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdNUHBsb3RHM3V2Mi5wbmcnKQ0KYGBgDQoNCioqRnJ1Y2h0ZXJtYW4tUmVpbmdvbGQgbGF5b3V0IGFsZ29yaXRobSoqDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KI2NoYW5nZSBjb2xvcnMgYSBiaXQNCmRmX2NvbCA8LSBjb2wycmdiKFYoRzMpJGNvbG9yKQ0KVihHMykkY29sb3IyIDwtIHJnYih0KGRmX2NvbCksIGFscGhhPTE3NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkNCg0KZGZfY29sIDwtIGNvbDJyZ2IoRShHMykkY29sb3IpDQpFKEczKSRjb2xvcjIgPC0gcmdiKHQoZGZfY29sKSwgYWxwaGE9MTc1LCBtYXhDb2xvclZhbHVlID0gMjU1KQ0KRShHMykkY29sb3IyW3doaWNoKEUoRzMpJGNvbG9yPT0iIzAwMDAwMDRCIildIDwtICIjMDAwMDAwNEIiDQoNCiNyZW1vdmUgaXNvbGF0ZXMNCklzb2xhdGVkID0gd2hpY2goZGVncmVlKEczKT09MCkNCkczX3NlbCA9IGRlbGV0ZS52ZXJ0aWNlcyhHMywgSXNvbGF0ZWQpDQojRzNfc2VsID0gZGVsZXRlLnZlcnRpY2VzKEczX3NlbCwgYyg3MiwyNykpICNvbmx5IGNvbm5lY3RlZCB0byBlYWNoIG90aGVyDQoNClYoRzNfc2VsKSRjb2xvciA8LSBWKEczX3NlbCkkY29sb3IyDQpFKEczX3NlbCkkY29sb3IgPC0gRShHM19zZWwpJGNvbG9yMg0KDQojc21hbGxlciBhcnJvd3MNCkUoRzMpJGFycm93LnNpemU9LjENCg0KI2JpdCBzbWFsbGVyDQpWKEczX3NlbCkkc2l6ZT0gMC43KlYoRzNfc2VsKSRzaXplDQoNCiNsYXlvdXQNCnNldC5zZWVkKDI0MzU2NzcpDQpjNCA9IGxheW91dF93aXRoX2ZyKEczX3NlbCkNCg0KI3BuZygiUlJfcmV0d2VldF91bmRpcmVjdGVkLnBuZyIsd2lkdGggPSA5MDAsIGhlaWdodD0gOTAwKQ0Kew0KcGxvdChHM19zZWwsIGxheW91dD1jNCwgbWFyZ2luPWMoMCwwLDAsLjE1KSwgIG1haW49IlJlY2lwcm9jYXRlZCByZXR3ZWV0IHJlbGF0aW9ucyBiZXR3ZWVuIER1dGNoIE1QcyAoMjAxNykiKQ0KDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9UGFydHlfbmFtZXMsIHBjaD0yMSwgY29sPSIjNzc3Nzc3IiwgcHQuYmc9UGFydHlfY29scywgcHQuY2V4PTIsIGNleD0uOCwgYnR5PSJuIiwgbmNvbD0zKQ0KDQp0ZXh0KC0xLjIsLTEuMiwgIk5vdGUgMTogTm9kZSBzaXplIGJhc2VkIG9uIGRlZ3JlZSIsIGFkaj0wLCBjZXg9MC44KQ0KdGV4dCgtMS4yLC0xLjI1LCAiTm90ZSAyOiBFZGdlIGNvbGFyIGJhc2VkIG9uIFBhcnR5IG9mIE1QcywgYmxhY2sgaWYgTVBzIGZyb20gZGlmZmVyZW50IHBhcnR5IiwgYWRqPTAsIGNleD0wLjgpDQp0ZXh0KC0xLjIsLTEuMywgIk5vdGUgMzogSXNvbGF0ZXMgcmVtb3ZlZCIsIGFkaj0wLCBjZXg9MC44KQ0KDQp9ICANCiNkZXYub2ZmKCkNCg0KcG5nKCJSUl9yZXR3ZWV0X3VuZGlyZWN0ZWR2Mi5wbmciLHdpZHRoID0gOTAwLCBoZWlnaHQ9IDkwMCkNCnsNCnBsb3QoRzNfc2VsLCBsYXlvdXQ9YzQsIG1hcmdpbj1jKC4xLC4xLC4xLC4yKSkNCn0gIA0KZGV2Lm9mZigpDQoNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdSUnJldHdlZXR1bmRpcmVjdGVkLnBuZycpDQpgYGANCg0KLS0tICANCg0KIyMgUmFuayBvcmRlcnMgYW5kIGRlc2NyaXB0aW9uICANCg0KTW9zdCBmb2xsb3dlciBvdXRkZWdyZWVzOg0KYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFLCByZXN1bHRzPSdob2xkJ30NCg0KDQpHMSA8LSBHMWQNCmZvdXRkZWdyZWUgPC0gZGVncmVlKEcxLCBtb2RlPSJvdXQiKQ0Ka2V5ZiRQYXJ0aWpbd2hpY2goZm91dGRlZ3JlZT09bWF4KGZvdXRkZWdyZWUpKV0NCmtleWYkTmFhbVt3aGljaChmb3V0ZGVncmVlPT1tYXgoZm91dGRlZ3JlZSkpXQ0KYGBgDQoNCg0KTW9zdCBhdG1lbnRpb24gb3V0ZGVncmVlczogDQpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUUsIHJlc3VsdHM9J2hvbGQnfQ0KDQpHMiA8LSBHMmQNCmF0bWRlZ3JlZSA8LSBkZWdyZWUoRzIsIG1vZGU9Im91dCIpDQprZXlmJFBhcnRpalt3aGljaChhdG1kZWdyZWU9PW1heChhdG1kZWdyZWUpKV0NCmtleWYkTmFhbVt3aGljaChhdG1kZWdyZWU9PW1heChhdG1kZWdyZWUpKV0NCmBgYA0KDQpNb3N0IHJldHdlZXQgb3V0ZGVncmVlczogDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9VFJVRSwgcmVzdWx0cz0naG9sZCd9DQpHMyA8LSBHM2QNCnJ0ZGVncmVlIDwtIGRlZ3JlZShHMywgbW9kZT0ib3V0IikNCmtleWYkUGFydGlqW3doaWNoKHJ0ZGVncmVlPT1tYXgocnRkZWdyZWUpKV0NCmtleWYkTmFhbVt3aGljaChydGRlZ3JlZT09bWF4KHJ0ZGVncmVlKSldDQpgYGANCg0KU3BlYXJtYW4ncyByYW5rIGNvcnJlbGF0aW9uIHJobyAgDQoNCioqZm9sbG93ZXIgb3V0ZGVncmVlIGFuZCBhdG1lbnRpb24gb3V0ZGVncmVlKioNCg0KYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQ0KY29yLnRlc3QoZm91dGRlZ3JlZSwgYXRtZGVncmVlLCBtZXRob2Q9InNwZWFybWFuIikNCmBgYA0KDQoqKmZvbGxvd2VyIG91dGRlZ3JlZSBhbmQgcmV0d2VldCBvdXRkZWdyZWUqKg0KYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQ0KY29yLnRlc3QoZm91dGRlZ3JlZSwgcnRkZWdyZWUsIG1ldGhvZD0ic3BlYXJtYW4iKQ0KYGBgDQoNCioqcmV0d2VldCBvdXRkZWdyZWUgYW5kIGF0bWVudGlvbiBvdXRkZWdyZWUqKg0KYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQ0KY29yLnRlc3QocnRkZWdyZWUsIGF0bWRlZ3JlZSwgbWV0aG9kPSJzcGVhcm1hbiIpDQpgYGANCg0KDQo8IS0tLQ0KUGxvdGplcyB2b29yIG91dGRlZ3JlZSBkaXN0cmlidXRpb24NCg0KdHJ5IHRvIGNvbWJpbmUgdGhlIHRocmVlIGRlcHMgaW4gb25lIGdyYXBoIGFuZCB0aGVuIGNvbWJpbmUgYWxzbyBvdXRkZWdyZWUgYW5kIGluZGVncmVlLiANCg0KaHR0cHM6Ly93d3cuci1ncmFwaC1nYWxsZXJ5LmNvbS8xMzUtc3RhY2tlZC1kZW5zaXR5LWdyYXBoLmh0bWwNCmh0dHBzOi8vd3d3LnItZ3JhcGgtZ2FsbGVyeS5jb20vZGVuc2l0eV9taXJyb3JfZ2dwbG90Mi5odG1sDQotLS0+ICANCg0KLS0tICANCg0KDQoNCg0K


Copyright © 2021 Jochem Tolsma