1 getting started

Start with clean workspace

rm(list = ls())

2 Goal

We have two goals:

  1. How to make an RSiena object ready to analyze.
  2. Analyze a (very very) simple network evolution model

3 Custom functions

  • fpackage.check: Check if packages are installed (and install if not) in R (source).
  • fsave: Save to processed data in repository
  • f_pubnets: select scholars and construct directed publication network.
fpackage.check <- function(packages) {
    lapply(packages, FUN = function(x) {
        if (!require(x, character.only = TRUE)) {
            install.packages(x, dependencies = TRUE)
            library(x, character.only = TRUE)
        }
    })
}

fsave <- function(x, file = NULL, location = "./data/processed/") {
    ifelse(!dir.exists("data"), dir.create("data"), FALSE)
    ifelse(!dir.exists("data/processed"), dir.create("data/processed"), FALSE)
    if (is.null(file))
        file = deparse(substitute(x))
    datename <- substr(gsub("[:-]", "", Sys.time()), 1, 8)
    totalname <- paste(location, datename, file, ".rda", sep = "")
    save(x, file = totalname)  #need to fix if file is reloaded as input name, not as x. 
}

fload <- function(filename) {
    load(filename)
    get(ls()[ls() != "filename"])
}

fshowdf <- function(x, ...) {
    knitr::kable(x, digits = 2, "html", ...) %>%
        kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
        kableExtra::scroll_box(width = "100%", height = "300px")
}

# this is the most important one. We created it in the previous script

f_pubnets <- function(df_scholars = df, list_publications = publications, discip = "sociology", affiliation = "RU",
    waves = list(wave1 = c(2018, 2019, 2020), wave2 = c(2021, 2022, 2023))) {

    publications <- list_publications %>%
        bind_rows() %>%
        distinct(title, .keep_all = TRUE)

    df_scholars %>%
        filter(affil1 == affiliation | affil2 == affiliation) %>%
        filter(discipline == discip) -> df_sel

    networklist <- list()
    for (wave in 1:length(waves)) {
        networklist[[wave]] <- matrix(0, nrow = nrow(df_sel), ncol = nrow(df_sel))
    }

    publicationlist <- list()
    for (wave in 1:length(waves)) {
        publicationlist[[wave]] <- publications %>%
            filter(gs_id %in% df_sel$gs_id) %>%
            filter(year %in% waves[[wave]]) %>%
            select(author) %>%
            lapply(str_split, pattern = ",")
    }

    publicationlist2 <- list()
    for (wave in 1:length(waves)) {
        publicationlist2[[wave]] <- publicationlist[[wave]]$author %>%
            # lowercase
        lapply(tolower) %>%
            # Removing diacritics
        lapply(stri_trans_general, id = "latin-ascii") %>%
            # only last name
        lapply(word, start = -1, sep = " ") %>%
            # only last last name
        lapply(word, start = -1, sep = "-")
    }

    for (wave in 1:length(waves)) {
        # let us remove all publications with only one author
        remove <- which(sapply(publicationlist2[[wave]], FUN = function(x) length(x) == 1) == TRUE)
        publicationlist2[[wave]] <- publicationlist2[[wave]][-remove]
    }

    for (wave in 1:length(waves)) {
        pubs <- publicationlist2[[wave]]
        for (ego in 1:nrow(df_sel)) {
            # which ego?
            lastname_ego <- df_sel$lastname[ego]
            # for all publications
            for (pub in 1:length(pubs)) {
                # only continue if ego is author of pub
                if (lastname_ego %in% pubs[[pub]]) {
                  aut_pot <- which.max(pubs[[pub]] %in% lastname_ego)
                  # only continue if ego is first author of pub
                  if (aut_pot == 1) {
                    # check all alters/co-authors
                    for (alter in 1:nrow(df_sel)) {
                      # which alter
                      lastname_alter <- df_sel$lastname[alter]
                      if (lastname_alter %in% pubs[[pub]]) {
                        networklist[[wave]][ego, alter] <- networklist[[wave]][ego, alter] + 1
                      }
                    }
                  }
                }
            }
        }
    }
    return(list(df = df_sel, network = networklist))
}

4 packages

  • RSiena: what do you think? :-)
packages = c("RSiena", "tidyverse", "stringdist", "stringi")

fpackage.check(packages)

5 input

df <- fload("./data/processed/20230621df_complete.rda")
publications <- fload("./data/processed/20230621list_publications_jt.rda")

6 RU - sociology

output <- f_pubnets()
df_soc <- output[[1]]
df_network <- output[[2]]

6.1 Step 1: define data

6.1.1 dependent variable

# let us check the number of waves
length(df_network)
#> [1] 2
wave1 <- df_network[[1]]
wave2 <- df_network[[2]]
# let us put the diagonal to zero
diag(wave1) <- 0
diag(wave2) <- 0
# we want a binary tie (not a weighted tie)
wave1[wave1 > 1] <- 1
wave2[wave2 > 1] <- 1
# put the nets in an array
net_soc_array <- array(data = c(wave1, wave2), dim = c(dim(wave1), 2))
# dependent
net <- sienaDependent(net_soc_array)

6.1.2 independent variables

# gender
gender <- as.numeric(df_soc$gender == "female")
gender <- coCovar(gender)

Note that you can and must add a lot more relevant independent variables.

mydata <- sienaDataCreate(net, gender)

6.2 Step 2: create effects structure

myeff <- getEffects(mydata)
# effectsDocumentation(myeff)

6.3 Step 3: get initial description

ifelse(!dir.exists("results"), dir.create("results"), FALSE)
#> [1] FALSE
print01Report(mydata, modelname = "./results/soc_init")

And have a look at it!!

What do we learn from this file?

6.4 Step 4: specify model

This should be both empirically and theoretically motivated. Most importantly, hopefully you have already thought about this step when you formulated your hypotheses and even before you constructed your data.

Let us discuss the model below. What do these effects mean?
Why did we include these effects (and not others)?

myeff <- includeEffects(myeff, isolateNet, inPop, outAct, inAct, transTrip)  #we know that quite a lot of staff has not published with someone else
#>   effectName            include fix   test  initialValue parm
#> 1 transitive triplets   TRUE    FALSE FALSE          0   0   
#> 2 indegree - popularity TRUE    FALSE FALSE          0   0   
#> 3 outdegree - activity  TRUE    FALSE FALSE          0   0   
#> 4 indegree - activity   TRUE    FALSE FALSE          0   0   
#> 5 network-isolate       TRUE    FALSE FALSE          0   0
myeff <- includeEffects(myeff, sameX, egoX, altX, interaction1 = "gender")
#>   effectName   include fix   test  initialValue parm
#> 1 gender alter TRUE    FALSE FALSE          0   0   
#> 2 gender ego   TRUE    FALSE FALSE          0   0   
#> 3 same gender  TRUE    FALSE FALSE          0   0

What structural effects would we normally want to include?

6.5 Step5 estimate

myAlgorithm <- sienaAlgorithmCreate(projname = "soc_init")
(ans <- siena07(myAlgorithm, data = mydata, effects = myeff))
# (the outer parentheses lead to printing the obtained result on the screen) if necessary, estimate
# further
(ans <- siena07(myAlgorithm, data = mydata, effects = myeff, prevAns = ans, returnDeps = TRUE))
ans
#> Estimates, standard errors and convergence t-ratios
#> 
#>                                  Estimate   Standard   Convergence 
#>                                               Error      t-ratio   
#> 
#> Rate parameters: 
#>   0        Rate parameter         4.1454  ( 1.0037   )             
#> 
#> Other parameters: 
#>    1. eval outdegree (density)   -2.4708  ( 0.7370   )   -0.1259   
#>    2. eval reciprocity            2.3635  ( 0.6552   )   -0.0341   
#>    3. eval transitive triplets    0.7667  ( 0.4227   )   -0.1454   
#>    4. eval indegree - popularity  0.2207  ( 0.0623   )   -0.1125   
#>    5. eval outdegree - activity   0.0194  ( 0.1030   )   -0.1130   
#>    6. eval indegree - activity   -0.4241  ( 0.3033   )   -0.1311   
#>    7. eval network-isolate        2.4386  ( 1.1223   )    0.0809   
#>    8. eval gender alter          -0.3887  ( 0.2977   )    0.1094   
#>    9. eval gender ego             0.1515  ( 0.3344   )    0.0128   
#>   10. eval same gender            0.1572  ( 0.2825   )   -0.0639   
#> 
#> Overall maximum convergence ratio:    0.1886 
#> 
#> 
#> Total of 2876 iteration steps.

Assignment 5: Note, this is a challening one, intended for you folks who have been bored so far. ;-) Can you think of influence effects?
5a: scrape (or manually collect) the current H-index for our scholars and add it to your dataframe.
5b: Formulate a hypotheses with respect to authors influencing each others H-index
5b: based on the two H-index scores over time, and your hypo, define a behavioral dependent variable.
5e: update your model, including now a network and behavioral dependent variable and respective statistics.
5f: estimate model

6.6 Step 6: GOF

Here, scripts are shown that can be used to present violin plots representing how well the simulations of our SIENA models capture the distribution of features of the dependent variable(s) (i.e., networks and ‘behavior’) that were not directly modeled, but for which a good fit between model and data is desirable.

Background reading: Lospinoso & Snijders (2019)

6.6.1 Background

The goal of GOF-testing is to ensure that our estimated SIENA model accurately represents the observed data of the dependent variable, based on so-called auxiliary statistics, such as the distribution of outdegrees, indegrees, reciprocity, triadic configurations, geodesic distances, behavior traits, edgewise similarity, etc. This list is not exhaustive and should be tailored to the specific research question.

The assessment of fit involves comparing observed network features to their expected values in the estimated distribution of networks, derived from a large number of simulations (saved when returnDeps=TRUE in the siena07-call). If the assessment reveals a poor fit, it becomes necessary to propose model elaborations to improve the fit between the model and data.

Although one might possess theoretical notions about remediation, the complex nature of networks introduces a vast array of potential effects to consider (as shown by the large list of effects in the RSiena manual). In many instances, relying solely on theory and experience is insufficient to confidently propose the effects that ought to be incorporated for better model fit. Also, experimenting with various model specifications can be time-consuming.

RSiena provides a computationally efficient predictor for assessing the fit if the model were to be extended by specific additional effects. This estimator can be evaluated using only ingredients calculated already for the method-of-moments estimation of the restricted model (thus, testing an effect without estimating it, by setting test=TRUE and fix=TRUE in the includeEffects-call).

The results can be plotted which then produce violin plots, which present the distribution of the statistic as a combination of a box plot and a smooth approximation to the density (by a kernel density estimate), with the observed values superimposed.

The p-values for sienaGOF compare, in the space of outcomes of the auxiliary statistic, the position of the observed data to the cloud of points formed by the simulated data sets that correspond to the estimated model. This comparison is with respect to the ‘distance’ from the center of the cloud of points, where ‘distance’ is between quotation marks because it is the Mahalanobis distance, which takes into account the correlations and different variances of the components of the auxiliary statistic.

A very small value of p indicates poor fit. The customary value of p = 0.05 may be used as a threshold determining whether the fit is adequate, but this threshold is of even less importance here than it is in the case of regular hypothesis testing. Concluding, if p = 0, then with respect to the auxiliary statistic the fit is poor; it might be rather poor or extremely poor, and you do not know how extreme it is.

For more info, we refer to the article by Lospinoso & Snijders (2019) and the RSiena manual section 5.14.


6.6.2 Define GOF-auilliary

Now we define some functions from sienaGOF-auxiliary.

# see here: ?'sienaGOF-auxiliary'

# The geodesic distribution is not available from within RSiena, and therefore is copied from the
# help page of sienaGOF-auxiliary:

# GeodesicDistribution calculates the distribution of non-directed geodesic distances; see
# ?sna::geodist The default for \code{levls} reflects the usual phenomenon that geodesic distances
# larger than 5 do not differ appreciably with respect to interpretation.  Note that the levels of
# the result are named; these names are used in the \code{plot} method.
GeodesicDistribution <- function(i, data, sims, period, groupName, varName, levls = c(1:5, Inf), cumulative = TRUE,
    ...) {
    x <- networkExtraction(i, data, sims, period, groupName, varName)
    require(sna)
    a <- sna::geodist(symmetrize(x))$gdist
    if (cumulative) {
        gdi <- sapply(levls, function(i) {
            sum(a <= i)
        })
    } else {
        gdi <- sapply(levls, function(i) {
            sum(a == i)
        })
    }
    names(gdi) <- as.character(levls)
    gdi
}

# The following function is taken from the help page for sienaTest

testall <- function(ans) {
    for (i in which(ans$test)) {
        sct <- score.Test(ans, i)
        cat(ans$requestedEffects$effectName[i], "\n")
        print(sct)
    }
    invisible(score.Test(ans))
}


6.6.3 apply sienaGOF

Now, we can go to applying sienaGOF to our data. Goodness-of-fit tests based on various auxiliary statistics:

gofi0 <- sienaGOF(ans, IndegreeDistribution, verbose = FALSE, join = TRUE, varName = "net")
gofo0 <- sienaGOF(ans, OutdegreeDistribution, verbose = FALSE, join = TRUE, varName = "net")
gof0.gd <- sienaGOF(ans, GeodesicDistribution, cumulative = FALSE, verbose = FALSE, join = TRUE, varName = "net")
gof0.tc <- sienaGOF(ans, TriadCensus, verbose = FALSE, join = TRUE, varName = "net")


# ?sienaGOF

6.6.4 GOF plots initial model

6.6.4.1 indegree distribution

plot(gofi0)

6.6.4.2 outdegree distribution

plot(gofo0)

6.6.4.3 geodesic distances

plot(gof0.gd)

6.6.4.4 triad census

plot(gof0.tc, center = TRUE, scale = TRUE)

6.7 Step 7 (optional): Relative Influence

Here, scripts are shown that can be used to calculate the expected relative importance of our effects.

Background reading: Indlekofer & Brandes (2013)

6.7.1 Background

Until now, the interpretation of estimated effects in our SIENA models has been limited to testing their statistical significance, which determines whether an effect plays a role in the evolution of the network (using t-statistics). But we do not yet know how these effects fare against each other.

There are four issues when extrapolating the size of estimated parameters to their relative importance in SIENA models:

  1. Explanatory statistics have different scales (e.g., one micro-step may increase the number of reciprocated ties by at most 1 but may result in up to 2(N-2) new transitive triplets).

  2. Explanatory variables are often correlated, making it difficult to establish causality (e.g., a tie abridging a two-path may yield a new transitive triplet, while at the same time, a reciprocated tie).

  3. Multiple and complex choice sets exist, where network effects influence the probabilities of several alternative choices, and these effects are themselves influenced by a combination of several effects. This interdependence makes it challenging to assess the individual contribution of each effect to actor decisions.

  4. The data undergoes substantial unobserved changes over time, and the size of parameter estimates is strongly dependent on the structure of the evolving network data. The absence of certain network configurations can render specific effects irrelevant in decision-making processes at certain points in time (e.g., if an ego has no incoming ties, he has no opportunity to reciprocate a tie, making that the reciprocity effect cannot influence his decision).

To compare the relative importance of effects within a model, among different models, or across different datasets, we require a measure that specifically focuses on the extent to which effects influence actor decision probabilities.

This is where the concept of ‘Relative Importance’ (RI) measures comes into play. This measure reflects the extent that estimated model parameters affect change probabilities in network decision probabilities. They should be interpreted as the influence of effects on network changes relative to one another. The importance of an effect is estimated based on the extent to which network micro-steps would have differed if this effect were to be omitted. Probabilities for tie changes from the perspective of each actor are calculated using the fitted model parameters. Subsequently, each parameter is fixed to 0 and the change probabilities are recalculated. The influence of an effect on network (or: behavior) micro-steps is evaluated based on the magnitude of the difference in the distribution of change probabilities with the particular effect present versus absent. These differences are normalized so that their sum is 1 for each actor, and subsequently averaged across actors.

For more info, we refer to the article by Indlekofer & Brandes (2013) and the RSiena manual section 13.5.1.


6.7.2 SienaRI

Now, we can go to applying sienaRI to co-publishing network data.

# get parameters
theta.eval <- ans$theta
# and effects
myeff.eval <- ans$effects

# use sienaRI()
RI <- sienaRI(data = mydata, theta = theta.eval, algorithm = myAlgorithm, effects = myeff.eval)


And plot it.

plot(RI, addPieChart = TRUE)


The bar charts display the relative impacts of effects of our model on individual actor decisions for all observations. The last bar chart in each row, as well as the pie chart, display expected relative importance of included effects for the next step, averaged across actors.


6.8 Step 8 (optional): Micro-Macro (SIENA as ABM)

To gain a better understanding of how consequential our (selection) effects of interest at the micro-level are for social network properties at the macro-level, we can use our estimated SAOMs as empirically calibrated agent-based simulation models.

Background reading: Snijders & Steglich (2015).

We set initial effects values of our simulation models based on our empirically estimated model (ans) and we fix the effects at these values. We specify 2 additional models:

  • no indegree-popularity (inPop) model
  • stronger indegree-popularity (inPop) model

Our macro- / network outcome of interest is the skewness of the in-degree distribution. We measure this through the Gini index. We will extract the Gini for the in-degrees from each simulation run.

#make new effects objects for simulation models
myeff_obs <- myeff

#set initial values based on estimated model
myeff_obs <- setEffect(myeff_obs, density, initialValue = ans$theta[which(ans$effects$shortName == "density")])
#>   effectName          include fix   test  initialValue parm
#> 1 outdegree (density) TRUE    FALSE FALSE   -2.47081   0
myeff_obs <- setEffect(myeff_obs, recip, initialValue = ans$theta[which(ans$effects$shortName == "recip")])
#>   effectName  include fix   test  initialValue parm
#> 1 reciprocity TRUE    FALSE FALSE    2.36353   0
myeff_obs <- setEffect(myeff_obs, transTrip, initialValue = ans$theta[which(ans$effects$shortName == "transTrip")])
#>   effectName          include fix   test  initialValue parm
#> 1 transitive triplets TRUE    FALSE FALSE    0.76667   0
myeff_obs <- setEffect(myeff_obs, inPop, initialValue = ans$theta[which(ans$effects$shortName == "inPop")])
#>   effectName            include fix   test  initialValue parm
#> 1 indegree - popularity TRUE    FALSE FALSE    0.22069   0
myeff_obs <- setEffect(myeff_obs, outAct, initialValue = ans$theta[which(ans$effects$shortName == "outAct")])
#>   effectName           include fix   test  initialValue parm
#> 1 outdegree - activity TRUE    FALSE FALSE    0.01937   0
myeff_obs <- setEffect(myeff_obs, inAct, initialValue = ans$theta[which(ans$effects$shortName == "inAct")])
#>   effectName          include fix   test  initialValue parm
#> 1 indegree - activity TRUE    FALSE FALSE   -0.42412   0
myeff_obs <- setEffect(myeff_obs, isolateNet, initialValue = ans$theta[which(ans$effects$shortName == "isolateNet")])
#>   effectName      include fix   test  initialValue parm
#> 1 network-isolate TRUE    FALSE FALSE    2.43861   0
myeff_obs <- setEffect(myeff_obs, altX, interaction1 = "gender", initialValue = ans$theta[which(ans$effects$shortName == "altX")])
#>   effectName   include fix   test  initialValue parm
#> 1 gender alter TRUE    FALSE FALSE   -0.38869   0
myeff_obs <- setEffect(myeff_obs, egoX, interaction1 = "gender", initialValue = ans$theta[which(ans$effects$shortName == "egoX")])
#>   effectName include fix   test  initialValue parm
#> 1 gender ego TRUE    FALSE FALSE    0.15153   0
myeff_obs <- setEffect(myeff_obs, sameX, interaction1 = "gender", initialValue = ans$theta[which(ans$effects$shortName == "sameX")])
#>   effectName  include fix   test  initialValue parm
#> 1 same gender TRUE    FALSE FALSE    0.15722   0
#fix effects at this value
myeff_obs$fix[myeff_obs$include == TRUE] <- TRUE

#additional models:
myeff_no <- myeff_high <- myeff_obs

#adjust inPop effect
myeff_no <- setEffect(myeff_obs, inPop, initialValue = 0, fix = TRUE)
#>   effectName            include fix  test  initialValue parm
#> 1 indegree - popularity TRUE    TRUE FALSE          0   0
myeff_high <- setEffect(myeff_obs, inPop, initialValue = ans$theta[which(ans$effects$shortName == "inPop")] * 2, fix = TRUE)
#>   effectName            include fix  test  initialValue parm
#> 1 indegree - popularity TRUE    TRUE FALSE    0.44137   0
#set up the simulation settings
nIter <- 1000 # number of iterations

sim_model <- sienaAlgorithmCreate(
    projname = 'simulation',
    cond = FALSE,
    useStdInits = FALSE, nsub = 0,
    n3 = nIter, 
    seed=242452, # seed for replication
    simOnly = TRUE)
#> If you use this algorithm object, siena07 will create/use an output file simulation.txt .
#make vector to store gini across models (observed, no inPop, high inPop)
#we also make vectors to calculate gini excluding the in-isolates

gini_obs <- gini_no <- gini_high <- gini_obs2 <- gini_no2 <- gini_high2 <- rep(0, nIter)

# simulation using estimated parameters
sim_ans_obs <- siena07(sim_model,      # simulation settings
                   data = mydata,      # data
                   effects = myeff_obs,# defined effects and set parameters
                   returnDeps = TRUE)  # return simulated networks
  
sim_ans_no <- siena07(sim_model,       # simulation settings
                   data = mydata,      # data
                   effects = myeff_no,# defined effects and set parameters
                   returnDeps = TRUE)  # return simulated networks
  
sim_ans_high <- siena07(sim_model,     # simulation settings
                   data = mydata,      # data
                   effects = myeff_high,# defined effects and set parameters
                   returnDeps = TRUE)  # return simulated networks

#extract gini from simulation runs

#no. of actors
n <- length(mydata$nodeSets[[1]])

#observed model
for (i in 1:nIter) { 
  #create empty adjacency matrix
  adj <- matrix(0, n, n)
  
  #shorter notation for edge list for iteration i
  edges <- sim_ans_obs$sims[[i]][[1]][[1]][[1]]

  #The numbering is as follows: first the number of the simulation run (i); then the number of the group (1 in the usual case of single-group data structures); then the number of the dependent variable (here 1, because it is supposed that there only is a dependent network); then the period number (i.e., wave number minus 1). 
  
  #str(sim_ans_high$sims[[i]])
  
    #put edge values in desired place
  adj[edges[, 1:2]] <- edges[, 3]
  
  #count number of indegrees
  indegs <- colSums(adj)
  gini_obs[i] <- DescTools::Gini(indegs)
  
  #exclude the 0s
  gini_obs2[i] <- DescTools::Gini(indegs[!indegs==0])
}

#no inPop model
for (i in 1:nIter) { 
  #create empty adjacency matrix
  adj <- matrix(0, n, n)
  
  #shorter notation for edge list for iteration i
  edges <- sim_ans_no$sims[[i]][[1]][[1]][[1]]
  #put edge values in desired place
  adj[edges[, 1:2]] <- edges[, 3]
  
  #count number of indegrees
  indegs <- colSums(adj)
  gini_no[i] <- DescTools::Gini(indegs)
  
    #exclude the 0s
  gini_no2[i] <- DescTools::Gini(indegs[!indegs==0])
}

#high inPop model
for (i in 1:nIter) { 
  #create empty adjacency matrix
  adj <- matrix(0, n, n)
  
  #shorter notation for edge list for iteration i
  edges <- sim_ans_high$sims[[i]][[1]][[1]][[1]]
  
  #put edge values in desired place
  adj[edges[, 1:2]] <- edges[, 3]
  
  #count number of indegrees
  indegs <- colSums(adj)
  gini_high[i] <- DescTools::Gini(indegs)
  
    #exclude the 0s
  gini_high2[i] <- DescTools::Gini(indegs[!indegs==0])
}

plotdata <- data.frame(condition = c(rep("obs", nIter), rep("no_inPop", nIter), rep("inPop_x2", nIter)),
                       gini = c(gini_obs, gini_no, gini_high))
plotdata$condition <- factor(plotdata$condition, levels = c("obs", "no_inPop", "inPop_x2"))

#exclude in-isolates

plotdata2 <- data.frame(condition = c(rep("obs", nIter), rep("no_inPop", nIter), rep("inPop_x2", nIter)),
                       gini = c(gini_obs2, gini_no2, gini_high2))
plotdata2$condition <- factor(plotdata$condition, levels = c("obs", "no_inPop", "inPop_x2"))

p1 <- ggplot(plotdata, aes(x = condition, y = gini)) +
  geom_boxplot() +
  labs(title = "Distribution of Gini of In-degrees over 1000 iterations, across simulation models",
       x = "simulation model",
       y = "Gini") +
  ylim(0,1) +
  theme_minimal()

p2 <- ggplot(plotdata2, aes(x = condition, y = gini)) +
  geom_boxplot() +
  labs(x = "simulation model",
       y = "Gini") +
  ylim(0,1) +
  theme_minimal()

ggpubr::ggarrange(p1,p2, align = "h", labels = c("all actors", "excl. in-isolates"), vjust = 3)

7 THE END

YES, you made it until the end!.

Congrats. Time for drinks.


References

Indlekofer, Natalie, and Ulrik Brandes. 2013. “Relative Importance of Effects in Stochastic Actor-Oriented Models.” Network Science 1 (3): 278–304. doi:10.1017/nws.2013.21.
Lospinoso, J., and T. A. B. Snijders. 2019. “Goodness of Fit for Stochastic Actor-Oriented Models.” Methodological Innovations 12 (3). https://doi.org/10.1177/2059799119884282.
Snijders, & Steglich, T. A. 2015. “Representing Micro–Macro Linkages by Actor-Based Dynamic Network Models.” Sociological Methods & Research 44 (2): 222–71. https://doi.org/10.1177/004912411349457.
LS0tICANCnRpdGxlOiAiU05BIHdpdGggUlNpZW5hIg0KYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYg0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQoNCiAgDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KbGlicmFyeShrbml0cikNCm9wdHNfY2h1bmskc2V0KHRpZHkub3B0cz1saXN0KHdpZHRoLmN1dG9mZj0xMDApLHRpZHk9VFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsY29tbWVudCA9ICIjPiIsIGNhY2hlPVRSVUUsIGNsYXNzLnNvdXJjZT1jKCJ0ZXN0IiksIGNsYXNzLm91dHB1dD1jKCJ0ZXN0MiIpLCBjYWNoZS5sYXp5ID0gRkFMU0UpDQpvcHRpb25zKHdpZHRoID0gMTAwKSANCnJnbDo6c2V0dXBLbml0cigpDQoNCmNvbG9yaXplIDwtIGZ1bmN0aW9uKHgsIGNvbG9yKSB7c3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCB4KSB9DQoNCmBgYA0KDQpgYGB7ciBrbGlwcHksIGVjaG89RkFMU0UsIGluY2x1ZGU9VFJVRSwgbWVzc2FnZT1GQUxTRX0NCiMgaW5zdGFsbC5wYWNrYWdlcygicmVtb3RlcyIpDQojcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInJsZXN1ci9rbGlwcHkiKQ0Ka2xpcHB5OjprbGlwcHkocG9zaXRpb24gPSBjKCd0b3AnLCAncmlnaHQnKSkNCiNrbGlwcHk6OmtsaXBweShjb2xvciA9ICdkYXJrcmVkJykNCiNrbGlwcHk6OmtsaXBweSh0b29sdGlwX21lc3NhZ2UgPSAnQ2xpY2sgdG8gY29weScsIHRvb2x0aXBfc3VjY2VzcyA9ICdEb25lJykNCmBgYA0KDQoNCi0tLS0NCg0KIyBnZXR0aW5nIHN0YXJ0ZWQNCg0KU3RhcnQgd2l0aCBjbGVhbiB3b3Jrc3BhY2UgDQoNCmBgYHtyfQ0Kcm0obGlzdD1scygpKQ0KYGBgDQoNCi0tLS0NCg0KIyBHb2FsDQoNCldlIGhhdmUgdHdvIGdvYWxzOiAgDQoNCjEuIEhvdyB0byBtYWtlIGFuIFJTaWVuYSBvYmplY3QgcmVhZHkgdG8gYW5hbHl6ZS4gIA0KMi4gQW5hbHl6ZSBhICh2ZXJ5IHZlcnkpIHNpbXBsZSBuZXR3b3JrIGV2b2x1dGlvbiBtb2RlbCAgDQoNCg0KIyBDdXN0b20gZnVuY3Rpb25zDQoNCi0gYGZwYWNrYWdlLmNoZWNrYDogQ2hlY2sgaWYgcGFja2FnZXMgYXJlIGluc3RhbGxlZCAoYW5kIGluc3RhbGwgaWYgbm90KSBpbiBSIChbc291cmNlXShodHRwczovL3ZiYWxpZ2EuZ2l0aHViLmlvL3ZlcmlmeS10aGF0LXItcGFja2FnZXMtYXJlLWluc3RhbGxlZC1hbmQtbG9hZGVkLykpLiAgDQotIGBmc2F2ZWA6IFNhdmUgdG8gcHJvY2Vzc2VkIGRhdGEgaW4gcmVwb3NpdG9yeSAgDQotIGBmX3B1Ym5ldHNgOiBzZWxlY3Qgc2Nob2xhcnMgYW5kIGNvbnN0cnVjdCBkaXJlY3RlZCBwdWJsaWNhdGlvbiBuZXR3b3JrLiANCg0KYGBge3IgY3VzdG9tZnVuY3Rpb25zLCByZXN1bHRzPSdoaWRlJ30NCmZwYWNrYWdlLmNoZWNrIDwtIGZ1bmN0aW9uKHBhY2thZ2VzKSB7DQogIGxhcHBseShwYWNrYWdlcywgRlVOID0gZnVuY3Rpb24oeCkgew0KICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7DQogICAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICAgICBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCiAgICB9DQogIH0pDQp9DQoNCmZzYXZlIDwtIGZ1bmN0aW9uKHgsIGZpbGU9TlVMTCwgbG9jYXRpb249Ii4vZGF0YS9wcm9jZXNzZWQvIikgew0KICBpZmVsc2UoIWRpci5leGlzdHMoImRhdGEiKSwgZGlyLmNyZWF0ZSgiZGF0YSIpLCBGQUxTRSkNCiAgaWZlbHNlKCFkaXIuZXhpc3RzKCJkYXRhL3Byb2Nlc3NlZCIpLCBkaXIuY3JlYXRlKCJkYXRhL3Byb2Nlc3NlZCIpLCBGQUxTRSkNCiAgaWYgKGlzLm51bGwoZmlsZSkpIGZpbGU9IGRlcGFyc2Uoc3Vic3RpdHV0ZSh4KSkNCiAgZGF0ZW5hbWUgPC0gc3Vic3RyKGdzdWIoIls6LV0iLCAiIiwgU3lzLnRpbWUoKSksIDEsOCkgIA0KICB0b3RhbG5hbWUgPC0gcGFzdGUobG9jYXRpb24sIGRhdGVuYW1lLCBmaWxlLCAiLnJkYSIsIHNlcD0iIikNCiAgc2F2ZSh4LCBmaWxlID0gdG90YWxuYW1lKSAgI25lZWQgdG8gZml4IGlmIGZpbGUgaXMgcmVsb2FkZWQgYXMgaW5wdXQgbmFtZSwgbm90IGFzIHguIA0KfQ0KDQpmbG9hZCA8LSBmdW5jdGlvbihmaWxlbmFtZSkgew0KICBsb2FkKGZpbGVuYW1lKQ0KICBnZXQobHMoKVtscygpICE9ICJmaWxlbmFtZSJdKQ0KfQ0KDQpmc2hvd2RmIDwtICBmdW5jdGlvbih4LCAuLi4pIHsNCiAga25pdHI6OmthYmxlKHgsIGRpZ2l0cz0yLCAiaHRtbCIsIC4uLikgJT4lDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICBrYWJsZUV4dHJhOjpzY3JvbGxfYm94KHdpZHRoPSIxMDAlIiwgaGVpZ2h0PSAiMzAwcHgiKQ0KfSANCg0KI3RoaXMgaXMgdGhlIG1vc3QgaW1wb3J0YW50IG9uZS4gV2UgY3JlYXRlZCBpdCBpbiB0aGUgcHJldmlvdXMgc2NyaXB0DQoNCmZfcHVibmV0cyA8LSBmdW5jdGlvbihkZl9zY2hvbGFycz1kZiwgbGlzdF9wdWJsaWNhdGlvbnM9cHVibGljYXRpb25zLCBkaXNjaXA9InNvY2lvbG9neSIsIGFmZmlsaWF0aW9uPSJSVSIsIHdhdmVzPWxpc3Qod2F2ZTE9YygyMDE4LDIwMTksMjAyMCksIHdhdmUyPWMoMjAyMSwyMDIyLDIwMjMpKSkgew0KICANCiAgcHVibGljYXRpb25zIDwtIGxpc3RfcHVibGljYXRpb25zICU+JSANCiAgYmluZF9yb3dzKCkgJT4lDQogIGRpc3RpbmN0KHRpdGxlLCAua2VlcF9hbGwgPSBUUlVFKSANCiAgDQogIGRmX3NjaG9sYXJzICU+JSANCiAgZmlsdGVyKGFmZmlsMT09YWZmaWxpYXRpb24gfCBhZmZpbDI9PWFmZmlsaWF0aW9uKSAlPiUNCiAgZmlsdGVyKGRpc2NpcGxpbmU9PWRpc2NpcCkgLT4gZGZfc2VsDQogIA0KICBuZXR3b3JrbGlzdCA8LSBsaXN0KCkNCiAgZm9yICh3YXZlIGluIDE6bGVuZ3RoKHdhdmVzKSkgew0KICAgIG5ldHdvcmtsaXN0W1t3YXZlXV0gPC0gbWF0cml4KDAsIG5yb3c9bnJvdyhkZl9zZWwpLCBuY29sPW5yb3coZGZfc2VsKSkNCiAgfQ0KICANCiAgcHVibGljYXRpb25saXN0IDwtIGxpc3QoKQ0KICBmb3IgKHdhdmUgaW4gMTpsZW5ndGgod2F2ZXMpKSB7DQogICAgcHVibGljYXRpb25saXN0W1t3YXZlXV0gPC0gcHVibGljYXRpb25zICU+JQ0KICAgIGZpbHRlcihnc19pZCAlaW4lIGRmX3NlbCRnc19pZCkgJT4lIA0KICAgIGZpbHRlciAoeWVhciAlaW4lIHdhdmVzW1t3YXZlXV0pICU+JQ0KICAgIHNlbGVjdChhdXRob3IpICU+JSANCiAgICBsYXBwbHkoc3RyX3NwbGl0LCBwYXR0ZXJuPSIsIikgDQogIH0gIA0KICAgIA0KICBwdWJsaWNhdGlvbmxpc3QyIDwtIGxpc3QoKQ0KICBmb3IgKHdhdmUgaW4gMTpsZW5ndGgod2F2ZXMpKSB7DQogICAgcHVibGljYXRpb25saXN0Mltbd2F2ZV1dIDwtIHB1YmxpY2F0aW9ubGlzdFtbd2F2ZV1dJGF1dGhvciAlPiUNCiAgICAjbG93ZXJjYXNlDQogICAgbGFwcGx5KHRvbG93ZXIpICU+JSANCiAgICAjIFJlbW92aW5nIGRpYWNyaXRpY3MNCiAgICBsYXBwbHkoc3RyaV90cmFuc19nZW5lcmFsLCBpZCA9ICJsYXRpbi1hc2NpaSIpICU+JQ0KICAgICMgb25seSBsYXN0IG5hbWUNCiAgICBsYXBwbHkod29yZCwgc3RhcnQ9LTEsIHNlcD0iICIpICU+JQ0KICAgICMgb25seSBsYXN0IGxhc3QgbmFtZQ0KICAgIGxhcHBseSh3b3JkLCBzdGFydD0tMSwgc2VwPSItIikNCiAgfQ0KICANCiAgZm9yICh3YXZlIGluIDE6bGVuZ3RoKHdhdmVzKSkgew0KICAgICNsZXQgdXMgcmVtb3ZlIGFsbCBwdWJsaWNhdGlvbnMgd2l0aCBvbmx5IG9uZSBhdXRob3INCiAgICByZW1vdmUgPC0gd2hpY2goc2FwcGx5KHB1YmxpY2F0aW9ubGlzdDJbW3dhdmVdXSwgRlVOID0gZnVuY3Rpb24oeCkgbGVuZ3RoKHgpPT0xICk9PVRSVUUpDQogICAgcHVibGljYXRpb25saXN0Mltbd2F2ZV1dIDwtIHB1YmxpY2F0aW9ubGlzdDJbW3dhdmVdXVstcmVtb3ZlXQ0KICB9DQoNCiAgZm9yICh3YXZlIGluIDE6bGVuZ3RoKHdhdmVzKSkgew0KICAgIHB1YnMgPC0gcHVibGljYXRpb25saXN0Mltbd2F2ZV1dDQogICAgZm9yIChlZ28gaW4gMTogbnJvdyhkZl9zZWwpKSB7DQogICAgICAjd2hpY2ggZWdvPyANCiAgICAgIGxhc3RuYW1lX2VnbyA8LSBkZl9zZWwkbGFzdG5hbWVbZWdvXQ0KICAgICAgI2ZvciBhbGwgcHVibGljYXRpb25zDQogICAgICBmb3IgKHB1YiBpbiAxOmxlbmd0aChwdWJzKSkgew0KICAgICAgICAjb25seSBjb250aW51ZSBpZiBlZ28gaXMgYXV0aG9yIG9mIHB1Yg0KICAgICAgICBpZiAobGFzdG5hbWVfZWdvICVpbiUgcHVic1tbcHViXV0pIHsNCiAgICAgICAgICBhdXRfcG90IDwtIHdoaWNoLm1heChwdWJzW1twdWJdXSAlaW4lIGxhc3RuYW1lX2VnbykNCiAgICAgICAgICAjb25seSBjb250aW51ZSBpZiBlZ28gaXMgZmlyc3QgYXV0aG9yIG9mIHB1Yg0KICAgICAgICAgIGlmIChhdXRfcG90PT0xKSB7DQogICAgICAgICAgICAjY2hlY2sgYWxsIGFsdGVycy9jby1hdXRob3JzDQogICAgICAgICAgICBmb3IgKGFsdGVyIGluIDE6IG5yb3coZGZfc2VsKSkgew0KICAgICAgICAgICAgICAjd2hpY2ggYWx0ZXINCiAgICAgICAgICAgICAgbGFzdG5hbWVfYWx0ZXIgPC0gZGZfc2VsJGxhc3RuYW1lW2FsdGVyXQ0KICAgICAgICAgICAgICBpZiAobGFzdG5hbWVfYWx0ZXIgJWluJSBwdWJzW1twdWJdXSkgew0KICAgICAgICAgICAgICAgIG5ldHdvcmtsaXN0W1t3YXZlXV1bZWdvLGFsdGVyXSA8LSBuZXR3b3JrbGlzdFtbd2F2ZV1dW2VnbyxhbHRlcl0gKyAxDQogICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0NCiAgICAgICAgICB9DQogICAgICAgIH0NCiAgICAgIH0NCiAgICB9DQogIH0NCiAgcmV0dXJuKGxpc3QoZGY9ZGZfc2VsLCBuZXR3b3JrPW5ldHdvcmtsaXN0KSkNCn0NCmBgYA0KDQoNCg0KDQoNCiMgcGFja2FnZXMNCg0KLSBgUlNpZW5hYDogd2hhdCBkbyB5b3UgdGhpbms/IDotKQ0KDQoNCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCnBhY2thZ2VzID0gYygiUlNpZW5hIiwgInRpZHl2ZXJzZSIsICJzdHJpbmdkaXN0IiwgInN0cmluZ2kiKQ0KDQpmcGFja2FnZS5jaGVjayhwYWNrYWdlcykNCmBgYA0KDQojIGlucHV0DQoNCmBgYHtyfQ0KZGYgPC0gZmxvYWQoIi4vZGF0YS9wcm9jZXNzZWQvMjAyMzA2MjFkZl9jb21wbGV0ZS5yZGEiKQ0KcHVibGljYXRpb25zIDwtIGZsb2FkKCIuL2RhdGEvcHJvY2Vzc2VkLzIwMjMwNjIxbGlzdF9wdWJsaWNhdGlvbnNfanQucmRhIikNCmBgYA0KDQoNCiMgUlUgLSBzb2Npb2xvZ3kgDQoNCmBgYHtyfQ0Kb3V0cHV0IDwtIGZfcHVibmV0cygpDQpkZl9zb2MgPC0gb3V0cHV0W1sxXV0NCmRmX25ldHdvcmsgPC0gb3V0cHV0W1syXV0NCg0KYGBgDQoNCiMjIFN0ZXAgMTogZGVmaW5lIGRhdGENCg0KIyMjIGRlcGVuZGVudCB2YXJpYWJsZSAgDQoNCmBgYHtyfQ0KI2xldCB1cyBjaGVjayB0aGUgbnVtYmVyIG9mIHdhdmVzDQpsZW5ndGgoZGZfbmV0d29yaykNCndhdmUxIDwtIGRmX25ldHdvcmtbWzFdXQ0Kd2F2ZTIgPC0gZGZfbmV0d29ya1tbMl1dDQojbGV0IHVzIHB1dCB0aGUgZGlhZ29uYWwgdG8gemVybw0KZGlhZyh3YXZlMSkgPC0gMA0KZGlhZyh3YXZlMikgPC0gMA0KI3dlIHdhbnQgYSBiaW5hcnkgdGllIChub3QgYSB3ZWlnaHRlZCB0aWUpIA0Kd2F2ZTFbd2F2ZTE+MV0gPC0gMQ0Kd2F2ZTJbd2F2ZTI+MV0gPC0gMQ0KI3B1dCB0aGUgbmV0cyBpbiBhbiBhcnJheQ0KbmV0X3NvY19hcnJheSA8LSBhcnJheShkYXRhID0gYyh3YXZlMSwgd2F2ZTIpLCBkaW09YyhkaW0od2F2ZTEpLDIpKQ0KI2RlcGVuZGVudA0KbmV0IDwtIHNpZW5hRGVwZW5kZW50KG5ldF9zb2NfYXJyYXkpDQpgYGANCg0KIyMjIGluZGVwZW5kZW50IHZhcmlhYmxlcw0KDQpgYGB7cn0NCiNnZW5kZXINCmdlbmRlciA8LSBhcy5udW1lcmljKGRmX3NvYyRnZW5kZXI9PSJmZW1hbGUiKQ0KZ2VuZGVyIDwtIGNvQ292YXIoZ2VuZGVyKQ0KYGBgDQoNCk5vdGUgdGhhdCB5b3UgY2FuIGFuZCBtdXN0IGFkZCBhIGxvdCBtb3JlIHJlbGV2YW50IGluZGVwZW5kZW50IHZhcmlhYmxlcy4gIA0KDQpgYGB7cn0NCm15ZGF0YSA8LSBzaWVuYURhdGFDcmVhdGUobmV0LCBnZW5kZXIpDQpgYGANCg0KIyMgU3RlcCAyOiBjcmVhdGUgZWZmZWN0cyBzdHJ1Y3R1cmUNCg0KYGBge3J9DQpteWVmZiA8LSBnZXRFZmZlY3RzKG15ZGF0YSkNCiNlZmZlY3RzRG9jdW1lbnRhdGlvbihteWVmZikNCmBgYA0KDQoNCiMjIFN0ZXAgMzogZ2V0IGluaXRpYWwgZGVzY3JpcHRpb24NCg0KYGBge3J9DQppZmVsc2UoIWRpci5leGlzdHMoInJlc3VsdHMiKSwgZGlyLmNyZWF0ZSgicmVzdWx0cyIpLCBGQUxTRSkNCnByaW50MDFSZXBvcnQobXlkYXRhLCBtb2RlbG5hbWUgPSAiLi9yZXN1bHRzL3NvY19pbml0IikNCmBgYA0KDQoqKkFuZCBoYXZlIGEgbG9vayBhdCBpdCEhKioNCg0KIVtdKHJlc3VsdHMvc29jX2luaXQudHh0KXsjaWQgLmNsYXNzIHdpZHRoPTEwMCUgaGVpZ2h0PTIwMHB4fQ0KDQpXaGF0IGRvIHdlIGxlYXJuIGZyb20gdGhpcyBmaWxlPyAgDQoNCiMjIFN0ZXAgNDogc3BlY2lmeSBtb2RlbCAgDQoNClRoaXMgc2hvdWxkIGJlIGJvdGggZW1waXJpY2FsbHkgYW5kIHRoZW9yZXRpY2FsbHkgbW90aXZhdGVkLiANCk1vc3QgaW1wb3J0YW50bHksIGhvcGVmdWxseSB5b3UgaGF2ZSBhbHJlYWR5IHRob3VnaHQgYWJvdXQgdGhpcyBzdGVwIHdoZW4geW91IGZvcm11bGF0ZWQgeW91ciBoeXBvdGhlc2VzIGFuZCBldmVuIGJlZm9yZSB5b3UgY29uc3RydWN0ZWQgeW91ciBkYXRhLiAgDQoNCkxldCB1cyBkaXNjdXNzIHRoZSBtb2RlbCBiZWxvdy4gDQpXaGF0IGRvIHRoZXNlIGVmZmVjdHMgbWVhbj8gIA0KV2h5IGRpZCB3ZSBpbmNsdWRlIHRoZXNlIGVmZmVjdHMgKGFuZCBub3Qgb3RoZXJzKT8gDQoNCg0KYGBge3IsIGV2YWw9VFJVRX0NCm15ZWZmIDwtIGluY2x1ZGVFZmZlY3RzKG15ZWZmLCBpc29sYXRlTmV0LCBpblBvcCwgb3V0QWN0LCBpbkFjdCwgdHJhbnNUcmlwKSAjd2Uga25vdyB0aGF0IHF1aXRlIGEgbG90IG9mIHN0YWZmIGhhcyBub3QgcHVibGlzaGVkIHdpdGggc29tZW9uZSBlbHNlDQpteWVmZiA8LSBpbmNsdWRlRWZmZWN0cyhteWVmZiwgc2FtZVgsIGVnb1gsIGFsdFgsIGludGVyYWN0aW9uMSA9ICJnZW5kZXIiKQ0KYGBgDQoNCldoYXQgc3RydWN0dXJhbCBlZmZlY3RzIHdvdWxkIHdlIG5vcm1hbGx5IHdhbnQgdG8gaW5jbHVkZT8gDQoNCg0KIyMgU3RlcDUgZXN0aW1hdGUNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpteUFsZ29yaXRobSA8LSBzaWVuYUFsZ29yaXRobUNyZWF0ZShwcm9qbmFtZSA9ICJzb2NfaW5pdCIpDQooYW5zIDwtIHNpZW5hMDcobXlBbGdvcml0aG0sIGRhdGEgPSBteWRhdGEsIGVmZmVjdHMgPSBteWVmZikpDQojICh0aGUgb3V0ZXIgcGFyZW50aGVzZXMgbGVhZCB0byBwcmludGluZyB0aGUgb2J0YWluZWQgcmVzdWx0IG9uIHRoZSBzY3JlZW4pIGlmIG5lY2Vzc2FyeSwgZXN0aW1hdGUNCiMgZnVydGhlcg0KKGFucyA8LSBzaWVuYTA3KG15QWxnb3JpdGhtLCBkYXRhID0gbXlkYXRhLCBlZmZlY3RzID0gbXllZmYsIHByZXZBbnMgPSBhbnMsIHJldHVybkRlcHM9VFJVRSkpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9DQpmc2F2ZShhbnMpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQphbnMgPC0gZmxvYWQoIi4vZGF0YS9wcm9jZXNzZWQvMjAyNDA2MjNhbnMucmRhIikNCmBgYA0KDQoNCmBgYHtyfQ0KYW5zDQpgYGANCg0KPiAqKkFzc2lnbm1lbnQgNToqKiANCj4gTm90ZSwgdGhpcyBpcyBhIGNoYWxsZW5pbmcgb25lLCBpbnRlbmRlZCBmb3IgeW91IGZvbGtzIHdobyBoYXZlIGJlZW4gYm9yZWQgc28gZmFyLiA7LSkgDQo+IENhbiB5b3UgdGhpbmsgb2YgaW5mbHVlbmNlIGVmZmVjdHM/ICANCj4gNWE6IHNjcmFwZSAob3IgbWFudWFsbHkgY29sbGVjdCkgdGhlIGN1cnJlbnQgSC1pbmRleCBmb3Igb3VyIHNjaG9sYXJzIGFuZCBhZGQgaXQgdG8geW91ciBkYXRhZnJhbWUuICANCj4gNWI6IEZvcm11bGF0ZSBhIGh5cG90aGVzZXMgd2l0aCByZXNwZWN0IHRvIGF1dGhvcnMgaW5mbHVlbmNpbmcgZWFjaCBvdGhlcnMgSC1pbmRleCAgDQo+IDViOiBiYXNlZCBvbiB0aGUgdHdvIEgtaW5kZXggc2NvcmVzIG92ZXIgdGltZSwgYW5kIHlvdXIgaHlwbywgZGVmaW5lIGEgYmVoYXZpb3JhbCBkZXBlbmRlbnQgdmFyaWFibGUuICANCj4gNWU6IHVwZGF0ZSB5b3VyIG1vZGVsLCBpbmNsdWRpbmcgbm93IGEgbmV0d29yayBhbmQgYmVoYXZpb3JhbCBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIHJlc3BlY3RpdmUgc3RhdGlzdGljcy4gIA0KPiA1ZjogZXN0aW1hdGUgbW9kZWwgDQoNCiMjIFN0ZXAgNjogR09GDQoNCkhlcmUsIHNjcmlwdHMgYXJlIHNob3duIHRoYXQgY2FuIGJlIHVzZWQgdG8gcHJlc2VudCB2aW9saW4gcGxvdHMgcmVwcmVzZW50aW5nIGhvdyB3ZWxsIHRoZSBzaW11bGF0aW9ucyBvZiBvdXIgU0lFTkEgbW9kZWxzIGNhcHR1cmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBmZWF0dXJlcyBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlKHMpIChpLmUuLCBuZXR3b3JrcyBhbmQgJ2JlaGF2aW9yJykgdGhhdCB3ZXJlIG5vdCBkaXJlY3RseSBtb2RlbGVkLCBidXQgZm9yIHdoaWNoIGEgZ29vZCBmaXQgYmV0d2VlbiBtb2RlbCBhbmQgZGF0YSBpcyBkZXNpcmFibGUuIA0KDQpCYWNrZ3JvdW5kIHJlYWRpbmc6IExvc3Bpbm9zbyAmIFNuaWpkZXJzIFstQExvc3Bpbm9zbzIwMTldDQoNCg0KIyMjIEJhY2tncm91bmQNCg0KDQpUaGUgZ29hbCBvZiBHT0YtdGVzdGluZyBpcyB0byBlbnN1cmUgdGhhdCBvdXIgZXN0aW1hdGVkIFNJRU5BIG1vZGVsIGFjY3VyYXRlbHkgcmVwcmVzZW50cyB0aGUgb2JzZXJ2ZWQgZGF0YSBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLCBiYXNlZCBvbiBzby1jYWxsZWQgKmF1eGlsaWFyeSogc3RhdGlzdGljcywgc3VjaCBhcyB0aGUgZGlzdHJpYnV0aW9uIG9mIG91dGRlZ3JlZXMsIGluZGVncmVlcywgcmVjaXByb2NpdHksIHRyaWFkaWMgY29uZmlndXJhdGlvbnMsIGdlb2Rlc2ljIGRpc3RhbmNlcywgYmVoYXZpb3IgdHJhaXRzLCBlZGdld2lzZSBzaW1pbGFyaXR5LCBldGMuIFRoaXMgbGlzdCBpcyBub3QgZXhoYXVzdGl2ZSBhbmQgc2hvdWxkIGJlIHRhaWxvcmVkIHRvIHRoZSBzcGVjaWZpYyByZXNlYXJjaCBxdWVzdGlvbi4NCg0KVGhlIGFzc2Vzc21lbnQgb2YgZml0IGludm9sdmVzIGNvbXBhcmluZyBvYnNlcnZlZCBuZXR3b3JrIGZlYXR1cmVzIHRvIHRoZWlyIGV4cGVjdGVkIHZhbHVlcyBpbiB0aGUgZXN0aW1hdGVkIGRpc3RyaWJ1dGlvbiBvZiBuZXR3b3JrcywgZGVyaXZlZCBmcm9tIGEgbGFyZ2UgbnVtYmVyIG9mIHNpbXVsYXRpb25zIChzYXZlZCB3aGVuIGByZXR1cm5EZXBzPVRSVUVgIGluIHRoZSBgc2llbmEwN2AtY2FsbCkuIElmIHRoZSBhc3Nlc3NtZW50IHJldmVhbHMgYSBwb29yIGZpdCwgaXQgYmVjb21lcyBuZWNlc3NhcnkgdG8gcHJvcG9zZSBtb2RlbCBlbGFib3JhdGlvbnMgdG8gaW1wcm92ZSB0aGUgZml0IGJldHdlZW4gdGhlIG1vZGVsIGFuZCBkYXRhLg0KDQpBbHRob3VnaCBvbmUgbWlnaHQgcG9zc2VzcyB0aGVvcmV0aWNhbCBub3Rpb25zIGFib3V0IHJlbWVkaWF0aW9uLCB0aGUgY29tcGxleCBuYXR1cmUgb2YgbmV0d29ya3MgaW50cm9kdWNlcyBhIHZhc3QgYXJyYXkgb2YgcG90ZW50aWFsIGVmZmVjdHMgdG8gY29uc2lkZXIgKGFzIHNob3duIGJ5IHRoZSBsYXJnZSBsaXN0IG9mIGVmZmVjdHMgaW4gdGhlIFJTaWVuYSBtYW51YWwpLiBJbiBtYW55IGluc3RhbmNlcywgcmVseWluZyBzb2xlbHkgb24gdGhlb3J5IGFuZCBleHBlcmllbmNlIGlzIGluc3VmZmljaWVudCB0byBjb25maWRlbnRseSBwcm9wb3NlIHRoZSBlZmZlY3RzIHRoYXQgb3VnaHQgdG8gYmUgaW5jb3Jwb3JhdGVkIGZvciBiZXR0ZXIgbW9kZWwgZml0LiBBbHNvLCBleHBlcmltZW50aW5nIHdpdGggdmFyaW91cyBtb2RlbCBzcGVjaWZpY2F0aW9ucyBjYW4gYmUgdGltZS1jb25zdW1pbmcuDQoNCmBSU2llbmFgIHByb3ZpZGVzIGEgY29tcHV0YXRpb25hbGx5IGVmZmljaWVudCBwcmVkaWN0b3IgZm9yIGFzc2Vzc2luZyB0aGUgZml0IGlmIHRoZSBtb2RlbCB3ZXJlIHRvIGJlIGV4dGVuZGVkIGJ5IHNwZWNpZmljIGFkZGl0aW9uYWwgZWZmZWN0cy4gVGhpcyBlc3RpbWF0b3IgY2FuIGJlIGV2YWx1YXRlZCB1c2luZyBvbmx5IGluZ3JlZGllbnRzIGNhbGN1bGF0ZWQgYWxyZWFkeSBmb3IgdGhlIG1ldGhvZC1vZi1tb21lbnRzIGVzdGltYXRpb24gb2YgdGhlIHJlc3RyaWN0ZWQgbW9kZWwgKHRodXMsIHRlc3RpbmcgYW4gZWZmZWN0IHdpdGhvdXQgZXN0aW1hdGluZyBpdCwgYnkgc2V0dGluZyBgdGVzdD1UUlVFYCBhbmQgYGZpeD1UUlVFYCBpbiB0aGUgYGluY2x1ZGVFZmZlY3RzYC1jYWxsKS4gDQoNCg0KVGhlIHJlc3VsdHMgY2FuIGJlIHBsb3R0ZWQgd2hpY2ggdGhlbiBwcm9kdWNlIHZpb2xpbiBwbG90cywgd2hpY2ggcHJlc2VudCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBzdGF0aXN0aWMgYXMgYSBjb21iaW5hdGlvbiBvZiBhIGJveCBwbG90IGFuZCBhIHNtb290aCBhcHByb3hpbWF0aW9uIHRvIHRoZSBkZW5zaXR5IChieSBhIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRlKSwgd2l0aCB0aGUgb2JzZXJ2ZWQgdmFsdWVzIHN1cGVyaW1wb3NlZC4NCg0KVGhlICpwKi12YWx1ZXMgZm9yIGBzaWVuYUdPRmAgY29tcGFyZSwgaW4gdGhlIHNwYWNlIG9mIG91dGNvbWVzIG9mIHRoZSBhdXhpbGlhcnkgc3RhdGlzdGljLCB0aGUgcG9zaXRpb24gb2YgdGhlIG9ic2VydmVkIGRhdGEgdG8gdGhlIGNsb3VkIG9mIHBvaW50cyBmb3JtZWQgYnkgdGhlIHNpbXVsYXRlZCBkYXRhIHNldHMgdGhhdCBjb3JyZXNwb25kIHRvIHRoZSBlc3RpbWF0ZWQgbW9kZWwuIFRoaXMgY29tcGFyaXNvbiBpcyB3aXRoIHJlc3BlY3QgdG8gdGhlIOKAmGRpc3RhbmNl4oCZIGZyb20gdGhlIGNlbnRlciBvZg0KdGhlIGNsb3VkIG9mIHBvaW50cywgd2hlcmUg4oCYZGlzdGFuY2XigJkgaXMgYmV0d2VlbiBxdW90YXRpb24gbWFya3MgYmVjYXVzZSBpdCBpcyB0aGUgTWFoYWxhbm9iaXMgZGlzdGFuY2UsIHdoaWNoIHRha2VzIGludG8gYWNjb3VudCB0aGUgY29ycmVsYXRpb25zIGFuZCBkaWZmZXJlbnQgdmFyaWFuY2VzIG9mIHRoZSBjb21wb25lbnRzIG9mIHRoZSBhdXhpbGlhcnkgc3RhdGlzdGljLg0KDQpBIHZlcnkgc21hbGwgdmFsdWUgb2YgKnAqIGluZGljYXRlcyBwb29yIGZpdC4gVGhlIGN1c3RvbWFyeSB2YWx1ZSBvZiAqcCogPSAwLjA1IG1heSBiZSB1c2VkIGFzIGEgdGhyZXNob2xkIGRldGVybWluaW5nIHdoZXRoZXIgdGhlDQpmaXQgaXMgYWRlcXVhdGUsIGJ1dCB0aGlzIHRocmVzaG9sZCBpcyBvZiBldmVuIGxlc3MgaW1wb3J0YW5jZSBoZXJlIHRoYW4gaXQgaXMgaW4gdGhlIGNhc2Ugb2YgcmVndWxhciBoeXBvdGhlc2lzIHRlc3RpbmcuICBDb25jbHVkaW5nLCBpZiBwID0gMCwgdGhlbiB3aXRoIHJlc3BlY3QgdG8gdGhlIGF1eGlsaWFyeSBzdGF0aXN0aWMgdGhlIGZpdCBpcyBwb29yOyBpdCBtaWdodCBiZSByYXRoZXIgcG9vciBvciBleHRyZW1lbHkgcG9vciwgYW5kIHlvdSBkbyBub3Qga25vdyBob3cgZXh0cmVtZSBpdCBpcy4NCg0KRm9yIG1vcmUgaW5mbywgd2UgcmVmZXIgdG8gdGhlIGFydGljbGUgYnkgTG9zcGlub3NvICYgU25pamRlcnMgWy1ATG9zcGlub3NvMjAxOV0gYW5kIHRoZSBSU2llbmEgbWFudWFsIHNlY3Rpb24gNS4xNC4gDQoNCi0tLQ0KDQojIyMgRGVmaW5lIEdPRi1hdWlsbGlhcnkgIA0KDQpOb3cgd2UgZGVmaW5lIHNvbWUgZnVuY3Rpb25zIGZyb20gYHNpZW5hR09GLWF1eGlsaWFyeWAuDQoNCmBgYHtyfQ0KI3NlZSBoZXJlOg0KIz8nc2llbmFHT0YtYXV4aWxpYXJ5Jw0KDQojIFRoZSBnZW9kZXNpYyBkaXN0cmlidXRpb24gaXMgbm90IGF2YWlsYWJsZSBmcm9tIHdpdGhpbiBSU2llbmEsDQojIGFuZCB0aGVyZWZvcmUgaXMgY29waWVkIGZyb20gdGhlIGhlbHAgcGFnZSBvZiBzaWVuYUdPRi1hdXhpbGlhcnk6DQoNCiMgR2VvZGVzaWNEaXN0cmlidXRpb24gY2FsY3VsYXRlcyB0aGUgZGlzdHJpYnV0aW9uIG9mIG5vbi1kaXJlY3RlZA0KICAgIyBnZW9kZXNpYyBkaXN0YW5jZXM7IHNlZSA/c25hOjpnZW9kaXN0DQogICAjIFRoZSBkZWZhdWx0IGZvciBcY29kZXtsZXZsc30gcmVmbGVjdHMgdGhlIHVzdWFsIHBoZW5vbWVub24NCiAgICMgdGhhdCBnZW9kZXNpYyBkaXN0YW5jZXMgbGFyZ2VyIHRoYW4gNQ0KICAgIyBkbyBub3QgZGlmZmVyIGFwcHJlY2lhYmx5IHdpdGggcmVzcGVjdCB0byBpbnRlcnByZXRhdGlvbi4NCiAgICMgTm90ZSB0aGF0IHRoZSBsZXZlbHMgb2YgdGhlIHJlc3VsdCBhcmUgbmFtZWQ7DQogICAjIHRoZXNlIG5hbWVzIGFyZSB1c2VkIGluIHRoZSBcY29kZXtwbG90fSBtZXRob2QuDQpHZW9kZXNpY0Rpc3RyaWJ1dGlvbiA8LSBmdW5jdGlvbiAoaSwgZGF0YSwgc2ltcywgcGVyaW9kLCBncm91cE5hbWUsDQogICB2YXJOYW1lLCBsZXZscz1jKDE6NSxJbmYpLCBjdW11bGF0aXZlPVRSVUUsIC4uLikgew0KICAgICB4IDwtIG5ldHdvcmtFeHRyYWN0aW9uKGksIGRhdGEsIHNpbXMsIHBlcmlvZCwgZ3JvdXBOYW1lLCB2YXJOYW1lKQ0KICAgICByZXF1aXJlKHNuYSkNCiAgICAgYSA8LSBzbmE6Omdlb2Rpc3Qoc3ltbWV0cml6ZSh4KSkkZ2Rpc3QNCiAgICAgaWYgKGN1bXVsYXRpdmUpDQogICAgIHsNCiAgICAgICBnZGkgPC0gc2FwcGx5KGxldmxzLCBmdW5jdGlvbihpKXsgc3VtKGE8PWkpIH0pDQogICAgIH0NCiAgICAgZWxzZQ0KICAgICB7DQogICAgICAgZ2RpIDwtIHNhcHBseShsZXZscywgZnVuY3Rpb24oaSl7IHN1bShhPT1pKSB9KQ0KICAgICB9DQogICAgIG5hbWVzKGdkaSkgPC0gYXMuY2hhcmFjdGVyKGxldmxzKQ0KICAgICBnZGkNCn0NCg0KIyBUaGUgZm9sbG93aW5nIGZ1bmN0aW9uIGlzIHRha2VuIGZyb20gdGhlIGhlbHAgcGFnZSBmb3Igc2llbmFUZXN0DQoNCnRlc3RhbGwgPC0gZnVuY3Rpb24oYW5zKXsNCiAgICBmb3IgKGkgaW4gd2hpY2goYW5zJHRlc3QpKXsNCiAgICBzY3QgPC0gc2NvcmUuVGVzdChhbnMsaSkNCiAgICBjYXQoYW5zJHJlcXVlc3RlZEVmZmVjdHMkZWZmZWN0TmFtZVtpXSwgJ1xuJykNCiAgICBwcmludChzY3QpfQ0KICAgIGludmlzaWJsZShzY29yZS5UZXN0KGFucykpDQp9DQpgYGANCg0KPGJyPg0KDQojIyMgYXBwbHkgc2llbmFHT0YgIA0KDQpOb3csIHdlIGNhbiBnbyB0byBhcHBseWluZyBgc2llbmFHT0ZgIHRvIG91ciBkYXRhLiANCkdvb2RuZXNzLW9mLWZpdCB0ZXN0cyBiYXNlZCBvbiB2YXJpb3VzIGF1eGlsaWFyeSBzdGF0aXN0aWNzOg0KDQpgYGB7cn0NCmdvZmkwIDwtIHNpZW5hR09GKGFucywgSW5kZWdyZWVEaXN0cmlidXRpb24sIHZlcmJvc2U9RkFMU0UsIGpvaW49VFJVRSwNCiAgICAgdmFyTmFtZT0ibmV0IikNCmdvZm8wIDwtIHNpZW5hR09GKGFucywgT3V0ZGVncmVlRGlzdHJpYnV0aW9uLCB2ZXJib3NlPUZBTFNFLCBqb2luPVRSVUUsdmFyTmFtZT0ibmV0IikNCmdvZjAuZ2QgPC0gc2llbmFHT0YoYW5zLCBHZW9kZXNpY0Rpc3RyaWJ1dGlvbiwgY3VtdWxhdGl2ZT1GQUxTRSwNCiAgICAgdmVyYm9zZT1GQUxTRSwgam9pbj1UUlVFLCB2YXJOYW1lPSJuZXQiKQ0KZ29mMC50YyA8LSBzaWVuYUdPRihhbnMsIFRyaWFkQ2Vuc3VzLCANCiAgICAgdmVyYm9zZT1GQUxTRSwgam9pbj1UUlVFLCB2YXJOYW1lPSJuZXQiKQ0KDQoNCiM/c2llbmFHT0YNCmBgYA0KDQojIyMgR09GIHBsb3RzIGluaXRpYWwgbW9kZWwgey50YWJzZXQgLnRhYnNldC1mYWRlfSANCg0KIyMjIyBpbmRlZ3JlZSBkaXN0cmlidXRpb24NCg0KYGBge3J9DQpwbG90KGdvZmkwKQ0KYGBgDQoNCiMjIyMgb3V0ZGVncmVlIGRpc3RyaWJ1dGlvbg0KDQpgYGB7cn0NCnBsb3QoZ29mbzApDQpgYGANCg0KIyMjIyBnZW9kZXNpYyBkaXN0YW5jZXMNCg0KYGBge3J9DQpwbG90KGdvZjAuZ2QpDQpgYGANCg0KIyMjIyB0cmlhZCBjZW5zdXMgIA0KDQpgYGB7cn0NCnBsb3QoZ29mMC50YywgY2VudGVyPVRSVUUsIHNjYWxlPVRSVUUpDQpgYGANCg0KDQojIyMgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KIyMgU3RlcCA3IChvcHRpb25hbCk6IFJlbGF0aXZlIEluZmx1ZW5jZQ0KDQoNCkhlcmUsIHNjcmlwdHMgYXJlIHNob3duIHRoYXQgY2FuIGJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBleHBlY3RlZCByZWxhdGl2ZSBpbXBvcnRhbmNlIG9mIG91ciBlZmZlY3RzLg0KDQpCYWNrZ3JvdW5kIHJlYWRpbmc6IEluZGxla29mZXIgJiBCcmFuZGVzIFstQGluZGxla29mZXIyMDEzXSANCg0KIyMjIEJhY2tncm91bmQNCg0KVW50aWwgbm93LCB0aGUgaW50ZXJwcmV0YXRpb24gb2YgZXN0aW1hdGVkIGVmZmVjdHMgaW4gb3VyIFNJRU5BIG1vZGVscyBoYXMgYmVlbiBsaW1pdGVkIHRvIHRlc3RpbmcgdGhlaXIgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlLCB3aGljaCBkZXRlcm1pbmVzIHdoZXRoZXIgYW4gZWZmZWN0IHBsYXlzIGEgcm9sZSBpbiB0aGUgZXZvbHV0aW9uIG9mIHRoZSBuZXR3b3JrICh1c2luZyB0LXN0YXRpc3RpY3MpLiBCdXQgd2UgZG8gbm90IHlldCBrbm93IGhvdyB0aGVzZSBlZmZlY3RzIGZhcmUgYWdhaW5zdCBlYWNoIG90aGVyLg0KDQpUaGVyZSBhcmUgZm91ciBpc3N1ZXMgd2hlbiBleHRyYXBvbGF0aW5nIHRoZSBzaXplIG9mIGVzdGltYXRlZCBwYXJhbWV0ZXJzIHRvIHRoZWlyIHJlbGF0aXZlIGltcG9ydGFuY2UgaW4gU0lFTkEgbW9kZWxzOg0KDQoxLiAqRXhwbGFuYXRvcnkgc3RhdGlzdGljcyBoYXZlIGRpZmZlcmVudCBzY2FsZXMqIChlLmcuLCBvbmUgbWljcm8tc3RlcCBtYXkgaW5jcmVhc2UgdGhlIG51bWJlciBvZiByZWNpcHJvY2F0ZWQgdGllcyBieSBhdCBtb3N0IDEgYnV0IG1heSByZXN1bHQgaW4gdXAgdG8gMigqTiotMikgbmV3IHRyYW5zaXRpdmUgdHJpcGxldHMpLg0KDQoyLiAqRXhwbGFuYXRvcnkgdmFyaWFibGVzIGFyZSBvZnRlbiBjb3JyZWxhdGVkKiwgbWFraW5nIGl0IGRpZmZpY3VsdCB0byBlc3RhYmxpc2ggY2F1c2FsaXR5IChlLmcuLCBhIHRpZSBhYnJpZGdpbmcgYSB0d28tcGF0aCBtYXkgeWllbGQgYSBuZXcgdHJhbnNpdGl2ZSB0cmlwbGV0LCB3aGlsZSBhdCB0aGUgc2FtZSB0aW1lLCBhIHJlY2lwcm9jYXRlZCB0aWUpLg0KDQozLiAqTXVsdGlwbGUgYW5kIGNvbXBsZXggY2hvaWNlIHNldHMgZXhpc3QqLCB3aGVyZSBuZXR3b3JrIGVmZmVjdHMgaW5mbHVlbmNlIHRoZSBwcm9iYWJpbGl0aWVzIG9mIHNldmVyYWwgYWx0ZXJuYXRpdmUgY2hvaWNlcywgYW5kIHRoZXNlIGVmZmVjdHMgYXJlIHRoZW1zZWx2ZXMgaW5mbHVlbmNlZCBieSBhIGNvbWJpbmF0aW9uIG9mIHNldmVyYWwgZWZmZWN0cy4gVGhpcyBpbnRlcmRlcGVuZGVuY2UgbWFrZXMgaXQgY2hhbGxlbmdpbmcgdG8gYXNzZXNzIHRoZSBpbmRpdmlkdWFsIGNvbnRyaWJ1dGlvbiBvZiBlYWNoIGVmZmVjdCB0byBhY3RvciBkZWNpc2lvbnMuDQoNCjQuICpUaGUgZGF0YSB1bmRlcmdvZXMgc3Vic3RhbnRpYWwgdW5vYnNlcnZlZCBjaGFuZ2VzIG92ZXIgdGltZSosIGFuZCB0aGUgc2l6ZSBvZiBwYXJhbWV0ZXIgZXN0aW1hdGVzIGlzIHN0cm9uZ2x5IGRlcGVuZGVudCBvbiB0aGUgc3RydWN0dXJlIG9mIHRoZSBldm9sdmluZyBuZXR3b3JrIGRhdGEuIFRoZSBhYnNlbmNlIG9mIGNlcnRhaW4gbmV0d29yayBjb25maWd1cmF0aW9ucyBjYW4gcmVuZGVyIHNwZWNpZmljIGVmZmVjdHMgaXJyZWxldmFudCBpbiBkZWNpc2lvbi1tYWtpbmcgcHJvY2Vzc2VzIGF0IGNlcnRhaW4gcG9pbnRzIGluIHRpbWUgKGUuZy4sIGlmIGFuIGVnbyBoYXMgbm8gaW5jb21pbmcgdGllcywgaGUgaGFzIG5vIG9wcG9ydHVuaXR5IHRvIHJlY2lwcm9jYXRlIGEgdGllLCBtYWtpbmcgdGhhdCB0aGUgYHJlY2lwcm9jaXR5YCBlZmZlY3QgY2Fubm90IGluZmx1ZW5jZSBoaXMgZGVjaXNpb24pLg0KDQpUbyBjb21wYXJlIHRoZSByZWxhdGl2ZSBpbXBvcnRhbmNlIG9mIGVmZmVjdHMgd2l0aGluIGEgbW9kZWwsIGFtb25nIGRpZmZlcmVudCBtb2RlbHMsIG9yIGFjcm9zcyBkaWZmZXJlbnQgZGF0YXNldHMsIHdlIHJlcXVpcmUgYSBtZWFzdXJlIHRoYXQgc3BlY2lmaWNhbGx5IGZvY3VzZXMgb24gdGhlIGV4dGVudCB0byB3aGljaCBlZmZlY3RzIGluZmx1ZW5jZSBhY3RvciBkZWNpc2lvbiBwcm9iYWJpbGl0aWVzLg0KDQpUaGlzIGlzIHdoZXJlIHRoZSBjb25jZXB0IG9mICdSZWxhdGl2ZSBJbXBvcnRhbmNlJyAoUkkpIG1lYXN1cmVzIGNvbWVzIGludG8gcGxheS4gVGhpcyBtZWFzdXJlIHJlZmxlY3RzIHRoZSBleHRlbnQgdGhhdCBlc3RpbWF0ZWQgbW9kZWwgcGFyYW1ldGVycyBhZmZlY3QgY2hhbmdlIHByb2JhYmlsaXRpZXMgaW4gbmV0d29yayBkZWNpc2lvbiBwcm9iYWJpbGl0aWVzLiBUaGV5IHNob3VsZCBiZSBpbnRlcnByZXRlZCBhcyB0aGUgaW5mbHVlbmNlIG9mIGVmZmVjdHMgb24gbmV0d29yayBjaGFuZ2VzIHJlbGF0aXZlIHRvIG9uZSBhbm90aGVyLiBUaGUgaW1wb3J0YW5jZSBvZiBhbiBlZmZlY3QgaXMgZXN0aW1hdGVkIGJhc2VkIG9uIHRoZSBleHRlbnQgdG8gd2hpY2ggbmV0d29yayBtaWNyby1zdGVwcyB3b3VsZCBoYXZlIGRpZmZlcmVkIGlmIHRoaXMgZWZmZWN0IHdlcmUgdG8gYmUgb21pdHRlZC4gUHJvYmFiaWxpdGllcyBmb3IgdGllIGNoYW5nZXMgZnJvbSB0aGUgcGVyc3BlY3RpdmUgb2YgZWFjaCBhY3RvciBhcmUgY2FsY3VsYXRlZCB1c2luZyB0aGUgZml0dGVkIG1vZGVsIHBhcmFtZXRlcnMuIFN1YnNlcXVlbnRseSwgZWFjaCBwYXJhbWV0ZXIgaXMgZml4ZWQgdG8gMCBhbmQgdGhlIGNoYW5nZSBwcm9iYWJpbGl0aWVzIGFyZSByZWNhbGN1bGF0ZWQuIFRoZSBpbmZsdWVuY2Ugb2YgYW4gZWZmZWN0IG9uIG5ldHdvcmsgKG9yOiBiZWhhdmlvcikgbWljcm8tc3RlcHMgaXMgZXZhbHVhdGVkIGJhc2VkIG9uIHRoZSBtYWduaXR1ZGUgb2YgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBjaGFuZ2UgcHJvYmFiaWxpdGllcyB3aXRoIHRoZSBwYXJ0aWN1bGFyIGVmZmVjdCBwcmVzZW50IHZlcnN1cyBhYnNlbnQuIFRoZXNlIGRpZmZlcmVuY2VzIGFyZSBub3JtYWxpemVkIHNvIHRoYXQgdGhlaXIgc3VtIGlzIDEgZm9yIGVhY2ggYWN0b3IsIGFuZCBzdWJzZXF1ZW50bHkgYXZlcmFnZWQgYWNyb3NzIGFjdG9ycy4gDQoNCg0KRm9yIG1vcmUgaW5mbywgd2UgcmVmZXIgdG8gdGhlIGFydGljbGUgYnkgSW5kbGVrb2ZlciAmIEJyYW5kZXMgWy1AaW5kbGVrb2ZlcjIwMTNdIGFuZCB0aGUgUlNpZW5hIG1hbnVhbCBzZWN0aW9uIDEzLjUuMS4gDQoNCi0tLQ0KDQojIyMgU2llbmFSSQ0KDQpOb3csIHdlIGNhbiBnbyB0byBhcHBseWluZyBgc2llbmFSSWAgdG8gY28tcHVibGlzaGluZyBuZXR3b3JrIGRhdGEuIA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiNnZXQgcGFyYW1ldGVycyANCnRoZXRhLmV2YWwgPC0gYW5zJHRoZXRhDQojYW5kIGVmZmVjdHMNCm15ZWZmLmV2YWwgPC0gYW5zJGVmZmVjdHMNCg0KI3VzZSBzaWVuYVJJKCkNClJJIDwtIHNpZW5hUkkoDQogIGRhdGEgPSBteWRhdGEsDQogIHRoZXRhID0gdGhldGEuZXZhbCwNCiAgYWxnb3JpdGhtID0gbXlBbGdvcml0aG0sDQogIGVmZmVjdHMgPSBteWVmZi5ldmFsDQopDQpgYGANCg0KPGJyPg0KDQpBbmQgcGxvdCBpdC4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpwbG90KFJJLCBhZGRQaWVDaGFydCA9IFRSVUUgKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQ0KcG5nKCIuL3Jlc3VsdHMvUklhbnMucG5nIiwgd2lkdGg9OTAwLCBoZWlnaHQ9OTAwKQ0KDQpwbG90KFJJLCBhZGRQaWVDaGFydCA9IFRSVUUgKQ0KDQojIENsb3NpbmcgdGhlIGdyYXBoaWNhbCBkZXZpY2UNCmRldi5vZmYoKSANCmBgYA0KYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iMTAwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiLi9yZXN1bHRzL1JJYW5zLnBuZyIpDQpgYGANCg0KPGJyPg0KDQpUaGUgYmFyIGNoYXJ0cyBkaXNwbGF5IHRoZSByZWxhdGl2ZSBpbXBhY3RzIG9mIGVmZmVjdHMgb2Ygb3VyIG1vZGVsIG9uIGluZGl2aWR1YWwgYWN0b3IgZGVjaXNpb25zIGZvciBhbGwgb2JzZXJ2YXRpb25zLiBUaGUgbGFzdCBiYXIgY2hhcnQgaW4gZWFjaCByb3csIGFzIHdlbGwgYXMgdGhlIHBpZSBjaGFydCwgZGlzcGxheSBleHBlY3RlZCByZWxhdGl2ZSBpbXBvcnRhbmNlIG9mIGluY2x1ZGVkIGVmZmVjdHMgZm9yIHRoZSBuZXh0IHN0ZXAsIGF2ZXJhZ2VkIGFjcm9zcyBhY3RvcnMuIA0KDQoNCi0tLQ0KDQojIyBTdGVwIDggKG9wdGlvbmFsKTogTWljcm8tTWFjcm8gKFNJRU5BIGFzIEFCTSkNCg0KVG8gZ2FpbiBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIGhvdyBjb25zZXF1ZW50aWFsIG91ciAoc2VsZWN0aW9uKSBlZmZlY3RzIG9mIGludGVyZXN0IGF0IHRoZSBtaWNyby1sZXZlbCBhcmUgZm9yIHNvY2lhbCBuZXR3b3JrIHByb3BlcnRpZXMgYXQgdGhlIG1hY3JvLWxldmVsLCB3ZSBjYW4gdXNlIG91ciBlc3RpbWF0ZWQgU0FPTXMgYXMgZW1waXJpY2FsbHkgY2FsaWJyYXRlZCBhZ2VudC1iYXNlZCBzaW11bGF0aW9uIG1vZGVscy4NCg0KQmFja2dyb3VuZCByZWFkaW5nOiBTbmlqZGVycyAmIFN0ZWdsaWNoIFstQHN0ZWdsaWNoMjAxNV0uDQoNCldlIHNldCBpbml0aWFsIGVmZmVjdHMgdmFsdWVzIG9mIG91ciBzaW11bGF0aW9uIG1vZGVscyBiYXNlZCBvbiBvdXIgZW1waXJpY2FsbHkgZXN0aW1hdGVkIG1vZGVsIChgYW5zYCkgYW5kIHdlIGZpeCB0aGUgZWZmZWN0cyBhdCB0aGVzZSB2YWx1ZXMuIFdlIHNwZWNpZnkgMiBhZGRpdGlvbmFsIG1vZGVsczoNCg0KLSBubyBpbmRlZ3JlZS1wb3B1bGFyaXR5IChpblBvcCkgbW9kZWwNCi0gc3Ryb25nZXIgaW5kZWdyZWUtcG9wdWxhcml0eSAoaW5Qb3ApIG1vZGVsDQoNCk91ciBtYWNyby0gLyBuZXR3b3JrIG91dGNvbWUgb2YgaW50ZXJlc3QgaXMgdGhlIHNrZXduZXNzIG9mIHRoZSBpbi1kZWdyZWUgZGlzdHJpYnV0aW9uLiBXZSBtZWFzdXJlIHRoaXMgdGhyb3VnaCB0aGUgR2luaSBpbmRleC4gV2Ugd2lsbCBleHRyYWN0IHRoZSBHaW5pIGZvciB0aGUgaW4tZGVncmVlcyBmcm9tIGVhY2ggc2ltdWxhdGlvbiBydW4uDQoNCg0KYGBge3J9DQojbWFrZSBuZXcgZWZmZWN0cyBvYmplY3RzIGZvciBzaW11bGF0aW9uIG1vZGVscw0KbXllZmZfb2JzIDwtIG15ZWZmDQoNCiNzZXQgaW5pdGlhbCB2YWx1ZXMgYmFzZWQgb24gZXN0aW1hdGVkIG1vZGVsDQpteWVmZl9vYnMgPC0gc2V0RWZmZWN0KG15ZWZmX29icywgZGVuc2l0eSwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZSA9PSAiZGVuc2l0eSIpXSkNCg0KbXllZmZfb2JzIDwtIHNldEVmZmVjdChteWVmZl9vYnMsIHJlY2lwLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lID09ICJyZWNpcCIpXSkNCg0KbXllZmZfb2JzIDwtIHNldEVmZmVjdChteWVmZl9vYnMsIHRyYW5zVHJpcCwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZSA9PSAidHJhbnNUcmlwIildKQ0KDQpteWVmZl9vYnMgPC0gc2V0RWZmZWN0KG15ZWZmX29icywgaW5Qb3AsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWUgPT0gImluUG9wIildKQ0KDQpteWVmZl9vYnMgPC0gc2V0RWZmZWN0KG15ZWZmX29icywgb3V0QWN0LCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lID09ICJvdXRBY3QiKV0pDQoNCm15ZWZmX29icyA8LSBzZXRFZmZlY3QobXllZmZfb2JzLCBpbkFjdCwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZSA9PSAiaW5BY3QiKV0pDQoNCm15ZWZmX29icyA8LSBzZXRFZmZlY3QobXllZmZfb2JzLCBpc29sYXRlTmV0LCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lID09ICJpc29sYXRlTmV0IildKQ0KDQpteWVmZl9vYnMgPC0gc2V0RWZmZWN0KG15ZWZmX29icywgYWx0WCwgaW50ZXJhY3Rpb24xID0gImdlbmRlciIsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWUgPT0gImFsdFgiKV0pDQoNCm15ZWZmX29icyA8LSBzZXRFZmZlY3QobXllZmZfb2JzLCBlZ29YLCBpbnRlcmFjdGlvbjEgPSAiZ2VuZGVyIiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZSA9PSAiZWdvWCIpXSkNCg0KbXllZmZfb2JzIDwtIHNldEVmZmVjdChteWVmZl9vYnMsIHNhbWVYLCBpbnRlcmFjdGlvbjEgPSAiZ2VuZGVyIiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZSA9PSAic2FtZVgiKV0pDQoNCiNmaXggZWZmZWN0cyBhdCB0aGlzIHZhbHVlDQpteWVmZl9vYnMkZml4W215ZWZmX29icyRpbmNsdWRlID09IFRSVUVdIDwtIFRSVUUNCg0KI2FkZGl0aW9uYWwgbW9kZWxzOg0KbXllZmZfbm8gPC0gbXllZmZfaGlnaCA8LSBteWVmZl9vYnMNCg0KI2FkanVzdCBpblBvcCBlZmZlY3QNCm15ZWZmX25vIDwtIHNldEVmZmVjdChteWVmZl9vYnMsIGluUG9wLCBpbml0aWFsVmFsdWUgPSAwLCBmaXggPSBUUlVFKQ0KbXllZmZfaGlnaCA8LSBzZXRFZmZlY3QobXllZmZfb2JzLCBpblBvcCwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZSA9PSAiaW5Qb3AiKV0gKiAyLCBmaXggPSBUUlVFKQ0KDQojc2V0IHVwIHRoZSBzaW11bGF0aW9uIHNldHRpbmdzDQpuSXRlciA8LSAxMDAwICMgbnVtYmVyIG9mIGl0ZXJhdGlvbnMNCg0Kc2ltX21vZGVsIDwtIHNpZW5hQWxnb3JpdGhtQ3JlYXRlKA0KICAgIHByb2puYW1lID0gJ3NpbXVsYXRpb24nLA0KICAgIGNvbmQgPSBGQUxTRSwNCiAgICB1c2VTdGRJbml0cyA9IEZBTFNFLCBuc3ViID0gMCwNCiAgICBuMyA9IG5JdGVyLCANCiAgICBzZWVkPTI0MjQ1MiwgIyBzZWVkIGZvciByZXBsaWNhdGlvbg0KICAgIHNpbU9ubHkgPSBUUlVFKQ0KDQoNCiNtYWtlIHZlY3RvciB0byBzdG9yZSBnaW5pIGFjcm9zcyBtb2RlbHMgKG9ic2VydmVkLCBubyBpblBvcCwgaGlnaCBpblBvcCkNCiN3ZSBhbHNvIG1ha2UgdmVjdG9ycyB0byBjYWxjdWxhdGUgZ2luaSBleGNsdWRpbmcgdGhlIGluLWlzb2xhdGVzDQoNCmdpbmlfb2JzIDwtIGdpbmlfbm8gPC0gZ2luaV9oaWdoIDwtIGdpbmlfb2JzMiA8LSBnaW5pX25vMiA8LSBnaW5pX2hpZ2gyIDwtIHJlcCgwLCBuSXRlcikNCg0KIyBzaW11bGF0aW9uIHVzaW5nIGVzdGltYXRlZCBwYXJhbWV0ZXJzDQpzaW1fYW5zX29icyA8LSBzaWVuYTA3KHNpbV9tb2RlbCwgICAgICAjIHNpbXVsYXRpb24gc2V0dGluZ3MNCiAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhLCAgICAgICMgZGF0YQ0KICAgICAgICAgICAgICAgICAgIGVmZmVjdHMgPSBteWVmZl9vYnMsIyBkZWZpbmVkIGVmZmVjdHMgYW5kIHNldCBwYXJhbWV0ZXJzDQogICAgICAgICAgICAgICAgICAgcmV0dXJuRGVwcyA9IFRSVUUpICAjIHJldHVybiBzaW11bGF0ZWQgbmV0d29ya3MNCiAgDQpzaW1fYW5zX25vIDwtIHNpZW5hMDcoc2ltX21vZGVsLCAgICAgICAjIHNpbXVsYXRpb24gc2V0dGluZ3MNCiAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhLCAgICAgICMgZGF0YQ0KICAgICAgICAgICAgICAgICAgIGVmZmVjdHMgPSBteWVmZl9ubywjIGRlZmluZWQgZWZmZWN0cyBhbmQgc2V0IHBhcmFtZXRlcnMNCiAgICAgICAgICAgICAgICAgICByZXR1cm5EZXBzID0gVFJVRSkgICMgcmV0dXJuIHNpbXVsYXRlZCBuZXR3b3Jrcw0KICANCnNpbV9hbnNfaGlnaCA8LSBzaWVuYTA3KHNpbV9tb2RlbCwgICAgICMgc2ltdWxhdGlvbiBzZXR0aW5ncw0KICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsICAgICAgIyBkYXRhDQogICAgICAgICAgICAgICAgICAgZWZmZWN0cyA9IG15ZWZmX2hpZ2gsIyBkZWZpbmVkIGVmZmVjdHMgYW5kIHNldCBwYXJhbWV0ZXJzDQogICAgICAgICAgICAgICAgICAgcmV0dXJuRGVwcyA9IFRSVUUpICAjIHJldHVybiBzaW11bGF0ZWQgbmV0d29ya3MNCg0KI2V4dHJhY3QgZ2luaSBmcm9tIHNpbXVsYXRpb24gcnVucw0KDQojbm8uIG9mIGFjdG9ycw0KbiA8LSBsZW5ndGgobXlkYXRhJG5vZGVTZXRzW1sxXV0pDQoNCiNvYnNlcnZlZCBtb2RlbA0KZm9yIChpIGluIDE6bkl0ZXIpIHsgDQogICNjcmVhdGUgZW1wdHkgYWRqYWNlbmN5IG1hdHJpeA0KICBhZGogPC0gbWF0cml4KDAsIG4sIG4pDQogIA0KICAjc2hvcnRlciBub3RhdGlvbiBmb3IgZWRnZSBsaXN0IGZvciBpdGVyYXRpb24gaQ0KICBlZGdlcyA8LSBzaW1fYW5zX29icyRzaW1zW1tpXV1bWzFdXVtbMV1dW1sxXV0NCg0KICAjVGhlIG51bWJlcmluZyBpcyBhcyBmb2xsb3dzOiBmaXJzdCB0aGUgbnVtYmVyIG9mIHRoZSBzaW11bGF0aW9uIHJ1biAoaSk7IHRoZW4gdGhlIG51bWJlciBvZiB0aGUgZ3JvdXAgKDEgaW4gdGhlIHVzdWFsIGNhc2Ugb2Ygc2luZ2xlLWdyb3VwIGRhdGEgc3RydWN0dXJlcyk7IHRoZW4gdGhlIG51bWJlciBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIChoZXJlIDEsIGJlY2F1c2UgaXQgaXMgc3VwcG9zZWQgdGhhdCB0aGVyZSBvbmx5IGlzIGEgZGVwZW5kZW50IG5ldHdvcmspOyB0aGVuIHRoZSBwZXJpb2QgbnVtYmVyIChpLmUuLCB3YXZlIG51bWJlciBtaW51cyAxKS4gDQogIA0KICAjc3RyKHNpbV9hbnNfaGlnaCRzaW1zW1tpXV0pDQogIA0KICAgICNwdXQgZWRnZSB2YWx1ZXMgaW4gZGVzaXJlZCBwbGFjZQ0KICBhZGpbZWRnZXNbLCAxOjJdXSA8LSBlZGdlc1ssIDNdDQogIA0KICAjY291bnQgbnVtYmVyIG9mIGluZGVncmVlcw0KICBpbmRlZ3MgPC0gY29sU3VtcyhhZGopDQogIGdpbmlfb2JzW2ldIDwtIERlc2NUb29sczo6R2luaShpbmRlZ3MpDQogIA0KICAjZXhjbHVkZSB0aGUgMHMNCiAgZ2luaV9vYnMyW2ldIDwtIERlc2NUb29sczo6R2luaShpbmRlZ3NbIWluZGVncz09MF0pDQp9DQoNCiNubyBpblBvcCBtb2RlbA0KZm9yIChpIGluIDE6bkl0ZXIpIHsgDQogICNjcmVhdGUgZW1wdHkgYWRqYWNlbmN5IG1hdHJpeA0KICBhZGogPC0gbWF0cml4KDAsIG4sIG4pDQogIA0KICAjc2hvcnRlciBub3RhdGlvbiBmb3IgZWRnZSBsaXN0IGZvciBpdGVyYXRpb24gaQ0KICBlZGdlcyA8LSBzaW1fYW5zX25vJHNpbXNbW2ldXVtbMV1dW1sxXV1bWzFdXQ0KICAjcHV0IGVkZ2UgdmFsdWVzIGluIGRlc2lyZWQgcGxhY2UNCiAgYWRqW2VkZ2VzWywgMToyXV0gPC0gZWRnZXNbLCAzXQ0KICANCiAgI2NvdW50IG51bWJlciBvZiBpbmRlZ3JlZXMNCiAgaW5kZWdzIDwtIGNvbFN1bXMoYWRqKQ0KICBnaW5pX25vW2ldIDwtIERlc2NUb29sczo6R2luaShpbmRlZ3MpDQogIA0KICAgICNleGNsdWRlIHRoZSAwcw0KICBnaW5pX25vMltpXSA8LSBEZXNjVG9vbHM6OkdpbmkoaW5kZWdzWyFpbmRlZ3M9PTBdKQ0KfQ0KDQojaGlnaCBpblBvcCBtb2RlbA0KZm9yIChpIGluIDE6bkl0ZXIpIHsgDQogICNjcmVhdGUgZW1wdHkgYWRqYWNlbmN5IG1hdHJpeA0KICBhZGogPC0gbWF0cml4KDAsIG4sIG4pDQogIA0KICAjc2hvcnRlciBub3RhdGlvbiBmb3IgZWRnZSBsaXN0IGZvciBpdGVyYXRpb24gaQ0KICBlZGdlcyA8LSBzaW1fYW5zX2hpZ2gkc2ltc1tbaV1dW1sxXV1bWzFdXVtbMV1dDQogIA0KICAjcHV0IGVkZ2UgdmFsdWVzIGluIGRlc2lyZWQgcGxhY2UNCiAgYWRqW2VkZ2VzWywgMToyXV0gPC0gZWRnZXNbLCAzXQ0KICANCiAgI2NvdW50IG51bWJlciBvZiBpbmRlZ3JlZXMNCiAgaW5kZWdzIDwtIGNvbFN1bXMoYWRqKQ0KICBnaW5pX2hpZ2hbaV0gPC0gRGVzY1Rvb2xzOjpHaW5pKGluZGVncykNCiAgDQogICAgI2V4Y2x1ZGUgdGhlIDBzDQogIGdpbmlfaGlnaDJbaV0gPC0gRGVzY1Rvb2xzOjpHaW5pKGluZGVnc1shaW5kZWdzPT0wXSkNCn0NCg0KcGxvdGRhdGEgPC0gZGF0YS5mcmFtZShjb25kaXRpb24gPSBjKHJlcCgib2JzIiwgbkl0ZXIpLCByZXAoIm5vX2luUG9wIiwgbkl0ZXIpLCByZXAoImluUG9wX3gyIiwgbkl0ZXIpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZ2luaSA9IGMoZ2luaV9vYnMsIGdpbmlfbm8sIGdpbmlfaGlnaCkpDQpwbG90ZGF0YSRjb25kaXRpb24gPC0gZmFjdG9yKHBsb3RkYXRhJGNvbmRpdGlvbiwgbGV2ZWxzID0gYygib2JzIiwgIm5vX2luUG9wIiwgImluUG9wX3gyIikpDQoNCiNleGNsdWRlIGluLWlzb2xhdGVzDQoNCnBsb3RkYXRhMiA8LSBkYXRhLmZyYW1lKGNvbmRpdGlvbiA9IGMocmVwKCJvYnMiLCBuSXRlciksIHJlcCgibm9faW5Qb3AiLCBuSXRlciksIHJlcCgiaW5Qb3BfeDIiLCBuSXRlcikpLA0KICAgICAgICAgICAgICAgICAgICAgICBnaW5pID0gYyhnaW5pX29iczIsIGdpbmlfbm8yLCBnaW5pX2hpZ2gyKSkNCnBsb3RkYXRhMiRjb25kaXRpb24gPC0gZmFjdG9yKHBsb3RkYXRhJGNvbmRpdGlvbiwgbGV2ZWxzID0gYygib2JzIiwgIm5vX2luUG9wIiwgImluUG9wX3gyIikpDQoNCnAxIDwtIGdncGxvdChwbG90ZGF0YSwgYWVzKHggPSBjb25kaXRpb24sIHkgPSBnaW5pKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEdpbmkgb2YgSW4tZGVncmVlcyBvdmVyIDEwMDAgaXRlcmF0aW9ucywgYWNyb3NzIHNpbXVsYXRpb24gbW9kZWxzIiwNCiAgICAgICB4ID0gInNpbXVsYXRpb24gbW9kZWwiLA0KICAgICAgIHkgPSAiR2luaSIpICsNCiAgeWxpbSgwLDEpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnAyIDwtIGdncGxvdChwbG90ZGF0YTIsIGFlcyh4ID0gY29uZGl0aW9uLCB5ID0gZ2luaSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKHggPSAic2ltdWxhdGlvbiBtb2RlbCIsDQogICAgICAgeSA9ICJHaW5pIikgKw0KICB5bGltKDAsMSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2dwdWJyOjpnZ2FycmFuZ2UocDEscDIsIGFsaWduID0gImgiLCBsYWJlbHMgPSBjKCJhbGwgYWN0b3JzIiwgImV4Y2wuIGluLWlzb2xhdGVzIiksIHZqdXN0ID0gMykNCmBgYCANCg0KDQoNCiMgVEhFIEVORCAgDQoNCllFUywgeW91IG1hZGUgaXQgdW50aWwgdGhlIGVuZCEuIA0KDQpDb25ncmF0cy4gVGltZSBmb3IgZHJpbmtzLiANCg0KLS0tLQ0KDQojIFJlZmVyZW5jZXMNCg0K


Copyright © 2024 Jochem Tolsma