## NULL

This website converted the following original .R scripts into .rmd files.

  • RScriptSNADescriptives.R
  • Rscript01DataFormat.R
  • Rscript02SienaVariableFormat.R
  • Rscript03SienaRunModel.R
  • Rscript04SienaBehaviour.R

Please visit GitHub for the latest .R files.


Data

All files (data, scripts, etc.) can also be found on Github


Contact

Specific questions with respect to the .rmd files can be addressed to: Jochem Tolsma.

For questions on RSiena please visit the designated GitHub page.


to do: conver to .rmd

################################################################################ ----
################################################################################ Rscript04SienaBehaviour.R:
################################################################################ a script for the
################################################################################ introduction to
################################################################################ RSiena ----
################################################################################ version September
################################################################################ 8, 2020 The
################################################################################ introductory
################################################################################ script is divided
################################################################################ into the following
################################################################################ script files:
################################################################################ Rscript01DataFormat.R,
################################################################################ followed by
################################################################################ RScriptSNADescriptives.R,
################################################################################ code for
################################################################################ descriptive
################################################################################ analysis of the
################################################################################ data, and
################################################################################ Rscript02SienaVariableFormat.R,
################################################################################ that formats data
################################################################################ and specifies the
################################################################################ model, and
################################################################################ Rscript03SienaRunModel.R,
################################################################################ that runs the
################################################################################ model and
################################################################################ estimates
################################################################################ parameters
################################################################################ Rscript04SienaBehaviour.R,
################################################################################ that illustrates
################################################################################ an example of
################################################################################ analysing the
################################################################################ coevolution of
################################################################################ networks and
################################################################################ behaviour Written
################################################################################ with contributions
################################################################################ by Robin Gauthier,
################################################################################ Tom Snijders, Ruth
################################################################################ Ripley, and Johan
################################################################################ Koskinen.

# Here is a short script for analysing the co-evolution of the friendship network and drinking
# behaviour for the 50 girls in the Teenage Friends and Lifestyle Study data
# (http://www.stats.ox.ac.uk/~snijders/siena/s50_data.zip), described in
# http://www.stats.ox.ac.uk/~snijders/siena/s50_data.htm

# Read in the adjacency matrices, covariates and dependent behavioural variable assuming data are
# in current working directory

# \t\tfriend.data.w1 <- as.matrix(read.table('s50-network1.dat')) # network \t\tfriend.data.w2 <-
# as.matrix(read.table('s50-network2.dat')) \t\tfriend.data.w3 <-
# as.matrix(read.table('s50-network3.dat')) \t\tdrink <- as.matrix(read.table('s50-alcohol.dat')) #
# behaviour \t\tsmoke <- as.matrix(read.table('s50-smoke.dat')) # covariate

# If you wish to make it easier, you can use this data set as included in the package - but the
# above is included to show you how to use data from files.  To use the internal data set:

friend.data.w1 <- s501
friend.data.w2 <- s502
friend.data.w3 <- s503
drink <- s50a
smoke <- s50s

# At this point it is a good idea to use the sna package to plot the networks and the behavioural
# variable. Descriptive measures of the similarity of 'friends' with respect to behaviour (like
# Moran's I) are given by the function nacf() in the sna package. See the script
# RscriptSNADescriptives.R.

# Tell RSiena that the adjacency matrices are network data and in what order they should be treated

friendship <- sienaDependent(array(c(friend.data.w1, friend.data.w2, friend.data.w3), dim = c(50, 50,
    3)))  # create dependent variable

# Tell RSiena that the variable 'drink' should be treated as a dependent variable

drinkingbeh <- sienaDependent(drink, type = "behavior")
smoke1 <- coCovar(smoke[, 1])

# Define the data set and obtain the basic effects object
myCoEvolutionData <- sienaDataCreate(friendship, smoke1, drinkingbeh)
myCoEvolutionEff <- getEffects(myCoEvolutionData)

# Run reports to check that data is properly formated and to get some basic descriptives

print01Report(myCoEvolutionData, modelname = "s50_3_CoEvinit")

# Define the effects to include in the coevolution model Start with some structural effects (use
# the shortnames that you find in effectsDocumentation(myCoEvolutionEff) )

myCoEvolutionEff <- includeEffects(myCoEvolutionEff, transTrip, cycle3)
#>   effectName          include fix   test  initialValue parm
#> 1 transitive triplets TRUE    FALSE FALSE          0   0   
#> 2 3-cycles            TRUE    FALSE FALSE          0   0
# Include a homophily effect for the constant covariate smoking

myCoEvolutionEff <- includeEffects(myCoEvolutionEff, simX, interaction1 = "smoke1")
#>   effectName        include fix   test  initialValue parm
#> 1 smoke1 similarity TRUE    FALSE FALSE          0   0
# If we want to parse out whether there is a selection or influence (or both) effect for drinking
# behaviour, we need to also include sender, receiver and homophily effects of drinking for
# friendship formation:

myCoEvolutionEff <- includeEffects(myCoEvolutionEff, egoX, altX, simX, interaction1 = "drinkingbeh")
#>   effectName             include fix   test  initialValue parm
#> 1 drinkingbeh alter      TRUE    FALSE FALSE          0   0   
#> 2 drinkingbeh ego        TRUE    FALSE FALSE          0   0   
#> 3 drinkingbeh similarity TRUE    FALSE FALSE          0   0
# For the influence part, i.e. the effect of the network on behaviour, we specify the following
# effects: indegree, outdegree and assimilation effects for drinking

myCoEvolutionEff <- includeEffects(myCoEvolutionEff, name = "drinkingbeh", avAlt, indeg, outdeg, interaction1 = "friendship")
#>   effectName                include fix   test  initialValue parm
#> 1 drinkingbeh indegree      TRUE    FALSE FALSE          0   0   
#> 2 drinkingbeh outdegree     TRUE    FALSE FALSE          0   0   
#> 3 drinkingbeh average alter TRUE    FALSE FALSE          0   0
# Check what effects you have decided to include:

myCoEvolutionEff
#>    name        effectName                          include fix   test  initialValue parm
#> 1  friendship  constant friendship rate (period 1) TRUE    FALSE FALSE    4.69604   0   
#> 2  friendship  constant friendship rate (period 2) TRUE    FALSE FALSE    4.32885   0   
#> 3  friendship  outdegree (density)                 TRUE    FALSE FALSE   -1.46770   0   
#> 4  friendship  reciprocity                         TRUE    FALSE FALSE    0.00000   0   
#> 5  friendship  transitive triplets                 TRUE    FALSE FALSE    0.00000   0   
#> 6  friendship  3-cycles                            TRUE    FALSE FALSE    0.00000   0   
#> 7  friendship  smoke1 similarity                   TRUE    FALSE FALSE    0.00000   0   
#> 8  friendship  drinkingbeh alter                   TRUE    FALSE FALSE    0.00000   0   
#> 9  friendship  drinkingbeh ego                     TRUE    FALSE FALSE    0.00000   0   
#> 10 friendship  drinkingbeh similarity              TRUE    FALSE FALSE    0.00000   0   
#> 11 drinkingbeh rate drinkingbeh (period 1)         TRUE    FALSE FALSE    0.70571   0   
#> 12 drinkingbeh rate drinkingbeh (period 2)         TRUE    FALSE FALSE    0.84939   0   
#> 13 drinkingbeh drinkingbeh linear shape            TRUE    FALSE FALSE    0.32237   0   
#> 14 drinkingbeh drinkingbeh quadratic shape         TRUE    FALSE FALSE    0.00000   0   
#> 15 drinkingbeh drinkingbeh indegree                TRUE    FALSE FALSE    0.00000   0   
#> 16 drinkingbeh drinkingbeh outdegree               TRUE    FALSE FALSE    0.00000   0   
#> 17 drinkingbeh drinkingbeh average alter           TRUE    FALSE FALSE    0.00000   0
# Now we have to define the algorithm settings.  The defaults are adequate. You only have to
# specify the filename that will receive the results in text format.

myCoEvAlgorithm <- sienaAlgorithmCreate(projname = "s50CoEv_3")
#> If you use this algorithm object, siena07 will create/use an output file s50CoEv_3.txt .
# Finally, estimate the model; the whole command is put in parentheses to have the results printed
# directly to the screen.

(ans <- siena07(myCoEvAlgorithm, data = myCoEvolutionData, effects = myCoEvolutionEff))
#> Estimates, standard errors and convergence t-ratios
#> 
#>                                                Estimate   Standard   Convergence 
#>                                                             Error      t-ratio   
#> Network Dynamics 
#>    1. rate constant friendship rate (period 1)  6.4800  ( 1.2439   )   -0.0641   
#>    2. rate constant friendship rate (period 2)  5.1314  ( 0.8404   )    0.0138   
#>    3. eval outdegree (density)                 -2.7681  ( 0.1556   )    0.0127   
#>    4. eval reciprocity                          2.3747  ( 0.2222   )   -0.0011   
#>    5. eval transitive triplets                  0.6483  ( 0.1344   )    0.0402   
#>    6. eval 3-cycles                            -0.0730  ( 0.2837   )    0.0360   
#>    7. eval smoke1 similarity                    0.1858  ( 0.2230   )    0.0932   
#>    8. eval drinkingbeh alter                   -0.0383  ( 0.1164   )   -0.0521   
#>    9. eval drinkingbeh ego                      0.0720  ( 0.1265   )   -0.0709   
#>   10. eval drinkingbeh similarity               1.3180  ( 0.6331   )    0.0602   
#> 
#> Behavior Dynamics
#>   11. rate rate drinkingbeh (period 1)          1.2443  ( 0.3677   )    0.0144   
#>   12. rate rate drinkingbeh (period 2)          1.6758  ( 0.4256   )   -0.1003   
#>   13. eval drinkingbeh linear shape            -0.8497  ( 2.2964   )    0.0008   
#>   14. eval drinkingbeh quadratic shape         -1.7646  ( 3.7417   )   -0.0192   
#>   15. eval drinkingbeh indegree                -0.9942  ( 2.8822   )    0.0246   
#>   16. eval drinkingbeh outdegree                1.7308  ( 4.3426   )    0.0272   
#>   17. eval drinkingbeh average alter            3.8412  ( 8.6979   )    0.0023   
#> 
#> Overall maximum convergence ratio:    0.2272 
#> 
#> 
#> Total of 3406 iteration steps.
# THE RESULTS

# Note that the 'convergence t-ratio' is the t-ratio for convergence checking, not the t statistic
# for testing the significance of this effect.  (See Section 6.1.2 of the manual.)  For good
# convergence, the t-ratios for convergence all should be less than .1 in absolute value, and the
# overall maximum convergence ratio should be less than 0.25.  If this is not yet the case, you
# should try again, starting from the last estimate as the 'previous answer':

(ans1 <- siena07(myCoEvAlgorithm, data = myCoEvolutionData, effects = myCoEvolutionEff, prevAns = ans))
#> Estimates, standard errors and convergence t-ratios
#> 
#>                                                Estimate   Standard   Convergence 
#>                                                             Error      t-ratio   
#> Network Dynamics 
#>    1. rate constant friendship rate (period 1)  6.5731  ( 1.3339   )    0.0203   
#>    2. rate constant friendship rate (period 2)  5.1349  ( 1.0727   )   -0.0655   
#>    3. eval outdegree (density)                 -2.7726  ( 0.1761   )   -0.0059   
#>    4. eval reciprocity                          2.3789  ( 0.2463   )   -0.0020   
#>    5. eval transitive triplets                  0.6245  ( 0.1544   )   -0.0103   
#>    6. eval 3-cycles                            -0.0286  ( 0.3158   )    0.0065   
#>    7. eval smoke1 similarity                    0.1797  ( 0.2613   )    0.0466   
#>    8. eval drinkingbeh alter                   -0.0378  ( 0.1149   )    0.0249   
#>    9. eval drinkingbeh ego                      0.0744  ( 0.1153   )    0.0125   
#>   10. eval drinkingbeh similarity               1.3572  ( 0.8138   )    0.0581   
#> 
#> Behavior Dynamics
#>   11. rate rate drinkingbeh (period 1)          1.2365  ( 0.3339   )    0.0308   
#>   12. rate rate drinkingbeh (period 2)          1.7081  ( 0.4566   )    0.0222   
#>   13. eval drinkingbeh linear shape            -0.9161  ( 2.0818   )   -0.0003   
#>   14. eval drinkingbeh quadratic shape         -1.7939  ( 2.8311   )   -0.0061   
#>   15. eval drinkingbeh indegree                -1.0705  ( 2.4082   )    0.0511   
#>   16. eval drinkingbeh outdegree                1.8347  ( 3.6174   )    0.0336   
#>   17. eval drinkingbeh average alter            3.8696  ( 6.2498   )   -0.0410   
#> 
#> Overall maximum convergence ratio:    0.2656 
#> 
#> 
#> Total of 3348 iteration steps.
# which can be repeated if necessary.

# For this small data set, the model for behavior dynamics is over-specified, leading to some very
# large standard errors.  For this data set it is better to drop the degree effects on behaviour,
# because the data does not contain enough information to estimate them.

myCoEvolutionEff2 <- includeEffects(myCoEvolutionEff, name = "drinkingbeh", indeg, outdeg, interaction1 = "friendship",
    include = FALSE)
#> [1] effectName   include      fix          test         initialValue parm        
#> <0 rows> (or 0-length row.names)
(ans2 <- siena07(myCoEvAlgorithm, data = myCoEvolutionData, effects = myCoEvolutionEff2))
#> Estimates, standard errors and convergence t-ratios
#> 
#>                                                Estimate   Standard   Convergence 
#>                                                             Error      t-ratio   
#> Network Dynamics 
#>    1. rate constant friendship rate (period 1)  6.5490  ( 1.1566   )   -0.0211   
#>    2. rate constant friendship rate (period 2)  5.1581  ( 0.9815   )    0.0637   
#>    3. eval outdegree (density)                 -2.7601  ( 0.1450   )    0.0188   
#>    4. eval reciprocity                          2.3730  ( 0.2064   )    0.0096   
#>    5. eval transitive triplets                  0.6382  ( 0.1406   )    0.0062   
#>    6. eval 3-cycles                            -0.0604  ( 0.2859   )    0.0116   
#>    7. eval smoke1 similarity                    0.1764  ( 0.2209   )    0.0110   
#>    8. eval drinkingbeh alter                   -0.0436  ( 0.1213   )   -0.0188   
#>    9. eval drinkingbeh ego                      0.0717  ( 0.1337   )   -0.0115   
#>   10. eval drinkingbeh similarity               1.3418  ( 0.6484   )   -0.0177   
#> 
#> Behavior Dynamics
#>   11. rate rate drinkingbeh (period 1)          1.3194  ( 0.3736   )   -0.0149   
#>   12. rate rate drinkingbeh (period 2)          1.7806  ( 0.5254   )   -0.0173   
#>   13. eval drinkingbeh linear shape             0.4179  ( 0.2382   )   -0.0202   
#>   14. eval drinkingbeh quadratic shape         -0.5948  ( 0.3620   )    0.0038   
#>   15. eval drinkingbeh average alter            1.3014  ( 0.9056   )   -0.0222   
#> 
#> Overall maximum convergence ratio:    0.1123 
#> 
#> 
#> Total of 3252 iteration steps.
############################################################################### Some other effects
############################################################################### ## The set of
############################################################################### available effects
############################################################################### for this data set
############################################################################### can be obtained by
############################################################################### requesting
effectsDocumentation(myCoEvolutionEff)
# See the manual, Chapter 12, for the meaning of these effects.  To study the direct effect of the
# actor covariate smoking on the dependent variable drinking, use the effFrom effect:

myCoEvolutionEff3 <- includeEffects(myCoEvolutionEff2, name = "drinkingbeh", effFrom, interaction1 = "smoke1")
#>   effectName                      include fix   test  initialValue parm
#> 1 drinkingbeh: effect from smoke1 TRUE    FALSE FALSE          0   0
# Since we already have a good result for a simpler model, it is helpful to start estimating from
# these estimates as starting values:

(ans3 <- siena07(myCoEvAlgorithm, data = myCoEvolutionData, effects = myCoEvolutionEff3, prevAns = ans2))
#> Estimates, standard errors and convergence t-ratios
#> 
#>                                                Estimate   Standard   Convergence 
#>                                                             Error      t-ratio   
#> Network Dynamics 
#>    1. rate constant friendship rate (period 1)  6.5686  ( 1.2079   )   -0.0390   
#>    2. rate constant friendship rate (period 2)  5.1513  ( 0.8772   )   -0.0364   
#>    3. eval outdegree (density)                 -2.7731  ( 0.1439   )   -0.0535   
#>    4. eval reciprocity                          2.3938  ( 0.2113   )   -0.0156   
#>    5. eval transitive triplets                  0.6305  ( 0.1458   )   -0.0261   
#>    6. eval 3-cycles                            -0.0424  ( 0.2785   )   -0.0062   
#>    7. eval smoke1 similarity                    0.1868  ( 0.2309   )    0.0027   
#>    8. eval drinkingbeh alter                   -0.0394  ( 0.1231   )   -0.0175   
#>    9. eval drinkingbeh ego                      0.0679  ( 0.1239   )   -0.0448   
#>   10. eval drinkingbeh similarity               1.3310  ( 0.6729   )    0.0033   
#> 
#> Behavior Dynamics
#>   11. rate rate drinkingbeh (period 1)          1.2809  ( 0.3422   )   -0.0173   
#>   12. rate rate drinkingbeh (period 2)          1.7066  ( 0.4539   )    0.0096   
#>   13. eval drinkingbeh linear shape             0.4345  ( 0.2945   )   -0.0118   
#>   14. eval drinkingbeh quadratic shape         -0.6347  ( 0.4529   )    0.0359   
#>   15. eval drinkingbeh average alter            1.5132  ( 1.1349   )    0.0848   
#>   16. eval drinkingbeh: effect from smoke1     -0.2412  ( 0.3955   )   -0.0025   
#> 
#> Overall maximum convergence ratio:    0.2508 
#> 
#> 
#> Total of 3322 iteration steps.
# In my case, convergence was not good enough:
(ans3 <- siena07(myCoEvAlgorithm, data = myCoEvolutionData, effects = myCoEvolutionEff3, prevAns = ans3))
#> Estimates, standard errors and convergence t-ratios
#> 
#>                                                Estimate   Standard   Convergence 
#>                                                             Error      t-ratio   
#> Network Dynamics 
#>    1. rate constant friendship rate (period 1)  6.5114  ( 1.0970   )   -0.0251   
#>    2. rate constant friendship rate (period 2)  5.2016  ( 0.8726   )    0.0756   
#>    3. eval outdegree (density)                 -2.7703  ( 0.1311   )   -0.0072   
#>    4. eval reciprocity                          2.3784  ( 0.2060   )    0.0108   
#>    5. eval transitive triplets                  0.6279  ( 0.1449   )    0.0256   
#>    6. eval 3-cycles                            -0.0341  ( 0.2875   )    0.0401   
#>    7. eval smoke1 similarity                    0.1822  ( 0.2057   )   -0.0191   
#>    8. eval drinkingbeh alter                   -0.0414  ( 0.1202   )    0.0656   
#>    9. eval drinkingbeh ego                      0.0744  ( 0.1268   )    0.0304   
#>   10. eval drinkingbeh similarity               1.3608  ( 0.6272   )    0.0243   
#> 
#> Behavior Dynamics
#>   11. rate rate drinkingbeh (period 1)          1.2897  ( 0.3725   )    0.0816   
#>   12. rate rate drinkingbeh (period 2)          1.7271  ( 0.4554   )    0.0116   
#>   13. eval drinkingbeh linear shape             0.4472  ( 0.2380   )    0.0261   
#>   14. eval drinkingbeh quadratic shape         -0.6494  ( 0.3851   )   -0.0409   
#>   15. eval drinkingbeh average alter            1.5168  ( 0.9566   )    0.0366   
#>   16. eval drinkingbeh: effect from smoke1     -0.2083  ( 0.3921   )    0.0309   
#> 
#> Overall maximum convergence ratio:    0.2431 
#> 
#> 
#> Total of 3267 iteration steps.
# You can get a nicer presentation of the results in a file in your working directory in LaTeX by
siena.table(ans3)
# and in html (can be imported into MS-Word) by
siena.table(ans3, type = "html")
LS0tDQp0aXRsZTogIkJlaGF2aW91ciINCmF1dGhvcjogJ1tKb2NoZW0gVG9sc21hXShodHRwczovL3d3dy5qb2NoZW10b2xzbWEubmwpIC0gUmFkYm91ZCBVbml2ZXJzaXR5LCB0aGUgTmV0aGVybGFuZHMnDQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliDQpkYXRlOiAiTGFzdCBjb21waWxlZCBvbiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCLCAlWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiAgdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGtuaXRyKQ0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGguY3V0b2ZmPTEwMCksdGlkeT1UUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSxjb21tZW50ID0gIiM+IiwgY2FjaGU9VFJVRSwgY2xhc3Muc291cmNlPWMoInRlc3QiKSwgY2xhc3Mub3V0cHV0PWMoInRlc3QyIikpDQpvcHRpb25zKHdpZHRoID0gMTAwKQ0KcmdsOjpzZXR1cEtuaXRyKCkNCg0KDQpjb2xvcml6ZSA8LSBmdW5jdGlvbih4LCBjb2xvcikgew0KICBpZiAoa25pdHI6OmlzX2xhdGV4X291dHB1dCgpKSB7DQogICAgc3ByaW50ZigiXFx0ZXh0Y29sb3J7JXN9eyVzfSIsIGNvbG9yLCB4KQ0KICB9IGVsc2UgaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogICAgc3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCANCiAgICAgIHgpDQogIH0gZWxzZSB4DQp9DQoNCmBgYA0KDQpgYGB7ciBrbGlwcHksIGVjaG89RkFMU0UsIGluY2x1ZGU9VFJVRX0NCmtsaXBweTo6a2xpcHB5KHBvc2l0aW9uID0gYygndG9wJywgJ3JpZ2h0JykpDQoja2xpcHB5OjprbGlwcHkoY29sb3IgPSAnZGFya3JlZCcpDQoja2xpcHB5OjprbGlwcHkodG9vbHRpcF9tZXNzYWdlID0gJ0NsaWNrIHRvIGNvcHknLCB0b29sdGlwX3N1Y2Nlc3MgPSAnRG9uZScpDQpgYGANCg0KYGBge2NzcywgZWNobz1GQUxTRX0NCnByZS50ZXN0IHsNCiAgbWF4LWhlaWdodDogMzAwcHg7DQogIG92ZXJmbG93LXk6IGF1dG87DQogIG92ZXJmbG93LXg6IGF1dG87DQogIG1hcmdpbjogMTBweDsNCn0NCg0KcHJlLnRlc3QyIHsNCiAgbWF4LWhlaWdodDogMzAwcHg7DQogIG92ZXJmbG93LXk6IGF1dG87DQogIG92ZXJmbG93LXg6IGF1dG87DQogIG1hcmdpbjogMTBweDsNCiAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGUNCn0NCg0KDQpoMSwgLmgxLCBoMiwgLmgyLCBoMywgLmgzIHsNCiAgICBtYXJnaW4tdG9wOiAyNHB4Ow0KfQ0KDQoNCmBgYA0KDQotLS0tDQoNClRoaXMgd2Vic2l0ZSBjb252ZXJ0ZWQgdGhlIGZvbGxvd2luZyBvcmlnaW5hbCAuUiBzY3JpcHRzIGludG8gLnJtZCBmaWxlcy4gDQoNCi0gUlNjcmlwdFNOQURlc2NyaXB0aXZlcy5SIA0KLSBSc2NyaXB0MDFEYXRhRm9ybWF0LlIgIA0KLSBSc2NyaXB0MDJTaWVuYVZhcmlhYmxlRm9ybWF0LlIgIA0KLSBSc2NyaXB0MDNTaWVuYVJ1bk1vZGVsLlIgIA0KLSBSc2NyaXB0MDRTaWVuYUJlaGF2aW91ci5SDQoNClBsZWFzZSB2aXNpdCBbR2l0SHViXShodHRwczovL2dpdGh1Yi5jb20vc25sYWItbmwvcnNpZW5hL3RyZWUvbWFpbi9pbnN0L3NjcmlwdHMpIGZvciB0aGUgbGF0ZXN0IC5SIGZpbGVzLiANCg0KLS0tLQ0KDQojIyBEYXRhDQpBbGwgZmlsZXMgKGRhdGEsIHNjcmlwdHMsIGV0Yy4pIGNhbiBhbHNvIGJlIGZvdW5kIG9uIFtHaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9Kb2NoZW1Ub2xzbWEvUnNpZW5hLXNjcmlwdHMpDQoNCi0tLS0NCg0KIyMgQ29udGFjdA0KU3BlY2lmaWMgcXVlc3Rpb25zIHdpdGggcmVzcGVjdCB0byB0aGUgLnJtZCBmaWxlcyBjYW4gYmUgYWRkcmVzc2VkIHRvOiBbSm9jaGVtIFRvbHNtYV0obWFpbHRvOmoudG9sc21hQHJ1Lm5sKS4gIA0KDQpGb3IgcXVlc3Rpb25zIG9uIFJTaWVuYSBwbGVhc2UgdmlzaXQgdGhlIGRlc2lnbmF0ZWQgW0dpdEh1Yl0oaHR0cHM6Ly9naXRodWIuY29tL3NubGFiLW5sL3JzaWVuYSkgcGFnZS4gDQoNCi0tLS0gIA0KDQp0byBkbzogY29udmVyIHRvIC5ybWQNCg0KYGBge3J9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyMjDQojIyMgLS0tLSBSc2NyaXB0MDRTaWVuYUJlaGF2aW91ci5SOiBhIHNjcmlwdCBmb3IgdGhlIGludHJvZHVjdGlvbiB0byBSU2llbmEgLS0tLQ0KIyMjDQojIyMgICAgICAgICAgICAgICAgICAgICAgICAgdmVyc2lvbiBTZXB0ZW1iZXIgOCwgMjAyMA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMNCiMgVGhlIGludHJvZHVjdG9yeSBzY3JpcHQgaXMgZGl2aWRlZCBpbnRvIHRoZSBmb2xsb3dpbmcgc2NyaXB0IGZpbGVzOg0KIyBSc2NyaXB0MDFEYXRhRm9ybWF0LlIsIGZvbGxvd2VkIGJ5DQojIFJTY3JpcHRTTkFEZXNjcmlwdGl2ZXMuUiwgY29kZSBmb3IgZGVzY3JpcHRpdmUgYW5hbHlzaXMgb2YgdGhlIGRhdGEsIGFuZA0KIyBSc2NyaXB0MDJTaWVuYVZhcmlhYmxlRm9ybWF0LlIsIHRoYXQgZm9ybWF0cyBkYXRhIGFuZCBzcGVjaWZpZXMgdGhlIG1vZGVsLCBhbmQNCiMgUnNjcmlwdDAzU2llbmFSdW5Nb2RlbC5SLCB0aGF0IHJ1bnMgdGhlIG1vZGVsIGFuZCBlc3RpbWF0ZXMgcGFyYW1ldGVycw0KIyBSc2NyaXB0MDRTaWVuYUJlaGF2aW91ci5SLCB0aGF0IGlsbHVzdHJhdGVzIGFuIGV4YW1wbGUgb2YgYW5hbHlzaW5nIHRoZQ0KIyBjb2V2b2x1dGlvbiBvZiBuZXR3b3JrcyBhbmQgYmVoYXZpb3VyDQojIFdyaXR0ZW4gd2l0aCBjb250cmlidXRpb25zIGJ5IFJvYmluIEdhdXRoaWVyLCBUb20gU25pamRlcnMsIFJ1dGggUmlwbGV5LA0KIyBhbmQgSm9oYW4gS29za2luZW4uDQojDQoNCiMgSGVyZSBpcyBhIHNob3J0IHNjcmlwdCBmb3IgYW5hbHlzaW5nIHRoZSBjby1ldm9sdXRpb24gb2YgdGhlDQojIGZyaWVuZHNoaXAgbmV0d29yayBhbmQgZHJpbmtpbmcgYmVoYXZpb3VyIGZvciB0aGUgNTAgZ2lybHMgaW4gdGhlDQojIFRlZW5hZ2UgRnJpZW5kcyBhbmQgTGlmZXN0eWxlIFN0dWR5IGRhdGENCiMgKGh0dHA6Ly93d3cuc3RhdHMub3guYWMudWsvfnNuaWpkZXJzL3NpZW5hL3M1MF9kYXRhLnppcCksIGRlc2NyaWJlZCBpbg0KIyBodHRwOi8vd3d3LnN0YXRzLm94LmFjLnVrL35zbmlqZGVycy9zaWVuYS9zNTBfZGF0YS5odG0NCg0KIyBSZWFkIGluIHRoZSBhZGphY2VuY3kgbWF0cmljZXMsIGNvdmFyaWF0ZXMgYW5kIGRlcGVuZGVudCBiZWhhdmlvdXJhbCB2YXJpYWJsZQ0KIyBhc3N1bWluZyBkYXRhIGFyZSBpbiBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5DQoNCiMJCWZyaWVuZC5kYXRhLncxIDwtIGFzLm1hdHJpeChyZWFkLnRhYmxlKCJzNTAtbmV0d29yazEuZGF0IikpICMgbmV0d29yaw0KIwkJZnJpZW5kLmRhdGEudzIgPC0gYXMubWF0cml4KHJlYWQudGFibGUoInM1MC1uZXR3b3JrMi5kYXQiKSkNCiMJCWZyaWVuZC5kYXRhLnczIDwtIGFzLm1hdHJpeChyZWFkLnRhYmxlKCJzNTAtbmV0d29yazMuZGF0IikpDQojCQlkcmluayA8LSBhcy5tYXRyaXgocmVhZC50YWJsZSgiczUwLWFsY29ob2wuZGF0IikpICMgYmVoYXZpb3VyDQojCQlzbW9rZSA8LSBhcy5tYXRyaXgocmVhZC50YWJsZSgiczUwLXNtb2tlLmRhdCIpKSAjIGNvdmFyaWF0ZQ0KDQojIElmIHlvdSB3aXNoIHRvIG1ha2UgaXQgZWFzaWVyLCB5b3UgY2FuIHVzZSB0aGlzIGRhdGEgc2V0IGFzIGluY2x1ZGVkDQojIGluIHRoZSBwYWNrYWdlIC0gYnV0IHRoZSBhYm92ZSBpcyBpbmNsdWRlZCB0byBzaG93IHlvdQ0KIyBob3cgdG8gdXNlIGRhdGEgZnJvbSBmaWxlcy4NCiMgVG8gdXNlIHRoZSBpbnRlcm5hbCBkYXRhIHNldDoNCg0KZnJpZW5kLmRhdGEudzEgPC0gczUwMQ0KZnJpZW5kLmRhdGEudzIgPC0gczUwMg0KZnJpZW5kLmRhdGEudzMgPC0gczUwMw0KZHJpbmsgPC0gczUwYQ0Kc21va2UgPC0gczUwcw0KDQojIEF0IHRoaXMgcG9pbnQgaXQgaXMgYSBnb29kIGlkZWEgdG8gdXNlIHRoZSBzbmEgcGFja2FnZSB0byBwbG90IHRoZSBuZXR3b3Jrcw0KIyBhbmQgdGhlIGJlaGF2aW91cmFsIHZhcmlhYmxlLiBEZXNjcmlwdGl2ZSBtZWFzdXJlcyBvZiB0aGUgc2ltaWxhcml0eSBvZg0KIyAiZnJpZW5kcyIgd2l0aCByZXNwZWN0IHRvIGJlaGF2aW91ciAobGlrZSBNb3JhbidzIEkpIGFyZSBnaXZlbiBieSB0aGUgZnVuY3Rpb24NCiMgbmFjZigpIGluIHRoZSBzbmEgcGFja2FnZS4gU2VlIHRoZSBzY3JpcHQgUnNjcmlwdFNOQURlc2NyaXB0aXZlcy5SLg0KDQojIFRlbGwgUlNpZW5hIHRoYXQgdGhlIGFkamFjZW5jeSBtYXRyaWNlcyBhcmUgbmV0d29yayBkYXRhIGFuZCBpbiB3aGF0IG9yZGVyDQojIHRoZXkgc2hvdWxkIGJlIHRyZWF0ZWQNCg0KZnJpZW5kc2hpcCA8LSBzaWVuYURlcGVuZGVudCggYXJyYXkoIGMoIGZyaWVuZC5kYXRhLncxLCBmcmllbmQuZGF0YS53MiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcmllbmQuZGF0YS53MyApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbSA9IGMoIDUwLCA1MCwgMyApICkgKSMgY3JlYXRlIGRlcGVuZGVudCB2YXJpYWJsZQ0KDQojIFRlbGwgUlNpZW5hIHRoYXQgdGhlIHZhcmlhYmxlICJkcmluayIgc2hvdWxkIGJlIHRyZWF0ZWQNCiMgYXMgYSBkZXBlbmRlbnQgdmFyaWFibGUNCg0KZHJpbmtpbmdiZWggPC0gc2llbmFEZXBlbmRlbnQoIGRyaW5rLCB0eXBlID0gImJlaGF2aW9yIiApDQpzbW9rZTEgPC0gY29Db3Zhciggc21va2VbICwgMSBdICkNCg0KIyBEZWZpbmUgdGhlIGRhdGEgc2V0IGFuZCBvYnRhaW4gdGhlIGJhc2ljIGVmZmVjdHMgb2JqZWN0DQpteUNvRXZvbHV0aW9uRGF0YSA8LSBzaWVuYURhdGFDcmVhdGUoIGZyaWVuZHNoaXAsIHNtb2tlMSwgZHJpbmtpbmdiZWggKQ0KbXlDb0V2b2x1dGlvbkVmZiA8LSBnZXRFZmZlY3RzKCBteUNvRXZvbHV0aW9uRGF0YSApDQoNCiMgUnVuIHJlcG9ydHMgdG8gY2hlY2sgdGhhdCBkYXRhIGlzIHByb3Blcmx5IGZvcm1hdGVkIGFuZA0KIyB0byBnZXQgc29tZSBiYXNpYyBkZXNjcmlwdGl2ZXMNCg0KcHJpbnQwMVJlcG9ydCggbXlDb0V2b2x1dGlvbkRhdGEsIG1vZGVsbmFtZSA9ICdzNTBfM19Db0V2aW5pdCcgKQ0KDQojIERlZmluZSB0aGUgZWZmZWN0cyB0byBpbmNsdWRlIGluIHRoZSBjb2V2b2x1dGlvbiBtb2RlbA0KIyBTdGFydCB3aXRoIHNvbWUgc3RydWN0dXJhbCBlZmZlY3RzICh1c2UgdGhlIHNob3J0bmFtZXMgdGhhdCB5b3UgZmluZCBpbg0KIyBlZmZlY3RzRG9jdW1lbnRhdGlvbihteUNvRXZvbHV0aW9uRWZmKSApDQoNCm15Q29Fdm9sdXRpb25FZmYgPC0gaW5jbHVkZUVmZmVjdHMoIG15Q29Fdm9sdXRpb25FZmYsIHRyYW5zVHJpcCwgY3ljbGUzKQ0KDQojIEluY2x1ZGUgYSBob21vcGhpbHkgZWZmZWN0IGZvciB0aGUgY29uc3RhbnQgY292YXJpYXRlIHNtb2tpbmcNCg0KbXlDb0V2b2x1dGlvbkVmZiA8LSBpbmNsdWRlRWZmZWN0cyggbXlDb0V2b2x1dGlvbkVmZiwgc2ltWCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aW9uMSA9ICJzbW9rZTEiICkNCg0KIyBJZiB3ZSB3YW50IHRvIHBhcnNlIG91dCB3aGV0aGVyIHRoZXJlIGlzIGEgc2VsZWN0aW9uIG9yIGluZmx1ZW5jZSAob3IgYm90aCkNCiMgZWZmZWN0IGZvciBkcmlua2luZyBiZWhhdmlvdXIsDQojIHdlIG5lZWQgdG8gYWxzbyBpbmNsdWRlIHNlbmRlciwgcmVjZWl2ZXIgYW5kIGhvbW9waGlseSBlZmZlY3RzDQojIG9mIGRyaW5raW5nIGZvciBmcmllbmRzaGlwIGZvcm1hdGlvbjoNCg0KbXlDb0V2b2x1dGlvbkVmZiA8LSBpbmNsdWRlRWZmZWN0cyhteUNvRXZvbHV0aW9uRWZmLCBlZ29YLCBhbHRYLCBzaW1YLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbjEgPSAiZHJpbmtpbmdiZWgiICkNCg0KIyBGb3IgdGhlIGluZmx1ZW5jZSBwYXJ0LCBpLmUuIHRoZSBlZmZlY3Qgb2YgdGhlIG5ldHdvcmsgb24gYmVoYXZpb3VyLA0KIyB3ZSBzcGVjaWZ5IHRoZSBmb2xsb3dpbmcgZWZmZWN0czoNCiMgaW5kZWdyZWUsIG91dGRlZ3JlZSBhbmQgYXNzaW1pbGF0aW9uIGVmZmVjdHMgZm9yIGRyaW5raW5nDQoNCm15Q29Fdm9sdXRpb25FZmYgPC0gaW5jbHVkZUVmZmVjdHMoIG15Q29Fdm9sdXRpb25FZmYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gImRyaW5raW5nYmVoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF2QWx0LGluZGVnLCBvdXRkZWcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbjEgPSAiZnJpZW5kc2hpcCIgKQ0KDQojIENoZWNrIHdoYXQgZWZmZWN0cyB5b3UgaGF2ZSBkZWNpZGVkIHRvIGluY2x1ZGU6DQoNCm15Q29Fdm9sdXRpb25FZmYNCg0KIw0KIyBOb3cgd2UgaGF2ZSB0byBkZWZpbmUgdGhlIGFsZ29yaXRobSBzZXR0aW5ncy4NCiMgVGhlIGRlZmF1bHRzIGFyZSBhZGVxdWF0ZS4gWW91IG9ubHkgaGF2ZSB0byBzcGVjaWZ5IHRoZSBmaWxlbmFtZQ0KIyB0aGF0IHdpbGwgcmVjZWl2ZSB0aGUgcmVzdWx0cyBpbiB0ZXh0IGZvcm1hdC4NCg0KbXlDb0V2QWxnb3JpdGhtIDwtIHNpZW5hQWxnb3JpdGhtQ3JlYXRlKCBwcm9qbmFtZSA9ICdzNTBDb0V2XzMnICkNCg0KIyBGaW5hbGx5LCBlc3RpbWF0ZSB0aGUgbW9kZWw7IHRoZSB3aG9sZSBjb21tYW5kIGlzIHB1dCBpbiBwYXJlbnRoZXNlcw0KIyB0byBoYXZlIHRoZSByZXN1bHRzIHByaW50ZWQgZGlyZWN0bHkgdG8gdGhlIHNjcmVlbi4NCg0KKGFucyA8LSBzaWVuYTA3KCBteUNvRXZBbGdvcml0aG0sIGRhdGEgPSBteUNvRXZvbHV0aW9uRGF0YSwNCiAgICAgICAgICAgICAgICAgZWZmZWN0cyA9IG15Q29Fdm9sdXRpb25FZmYgKSkNCg0KIyBUSEUgUkVTVUxUUw0KDQojIE5vdGUgdGhhdCB0aGUgImNvbnZlcmdlbmNlIHQtcmF0aW8iIGlzIHRoZSB0LXJhdGlvIGZvciBjb252ZXJnZW5jZSBjaGVja2luZywNCiMgbm90IHRoZSB0IHN0YXRpc3RpYyBmb3IgdGVzdGluZyB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoaXMgZWZmZWN0Lg0KIyAoU2VlIFNlY3Rpb24gNi4xLjIgb2YgdGhlIG1hbnVhbC4pDQojIEZvciBnb29kIGNvbnZlcmdlbmNlLCB0aGUgdC1yYXRpb3MgZm9yIGNvbnZlcmdlbmNlDQojIGFsbCBzaG91bGQgYmUgbGVzcyB0aGFuIC4xIGluIGFic29sdXRlIHZhbHVlLA0KIyBhbmQgdGhlIG92ZXJhbGwgbWF4aW11bSBjb252ZXJnZW5jZSByYXRpbyBzaG91bGQgYmUgbGVzcyB0aGFuIDAuMjUuDQojIElmIHRoaXMgaXMgbm90IHlldCB0aGUgY2FzZSwgeW91IHNob3VsZCB0cnkgYWdhaW4sIHN0YXJ0aW5nIGZyb20gdGhlDQojIGxhc3QgZXN0aW1hdGUgYXMgdGhlICJwcmV2aW91cyBhbnN3ZXIiOg0KDQooYW5zMSA8LSBzaWVuYTA3KCBteUNvRXZBbGdvcml0aG0sIGRhdGEgPSBteUNvRXZvbHV0aW9uRGF0YSwNCiAgICAgICAgICAgICAgICAgIGVmZmVjdHMgPSBteUNvRXZvbHV0aW9uRWZmLCBwcmV2QW5zID0gYW5zICkpDQoNCiMgd2hpY2ggY2FuIGJlIHJlcGVhdGVkIGlmIG5lY2Vzc2FyeS4NCg0KIyBGb3IgdGhpcyBzbWFsbCBkYXRhIHNldCwgdGhlIG1vZGVsIGZvciBiZWhhdmlvciBkeW5hbWljcyBpcyBvdmVyLXNwZWNpZmllZCwNCiMgbGVhZGluZyB0byBzb21lIHZlcnkgbGFyZ2Ugc3RhbmRhcmQgZXJyb3JzLg0KIyBGb3IgdGhpcyBkYXRhIHNldCBpdCBpcyBiZXR0ZXIgdG8gZHJvcCB0aGUgZGVncmVlIGVmZmVjdHMgb24gYmVoYXZpb3VyLA0KIyBiZWNhdXNlIHRoZSBkYXRhIGRvZXMgbm90IGNvbnRhaW4gZW5vdWdoIGluZm9ybWF0aW9uIHRvIGVzdGltYXRlIHRoZW0uDQoNCm15Q29Fdm9sdXRpb25FZmYyIDwtIGluY2x1ZGVFZmZlY3RzKCBteUNvRXZvbHV0aW9uRWZmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiZHJpbmtpbmdiZWgiLCBpbmRlZywgb3V0ZGVnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aW9uMSA9ICJmcmllbmRzaGlwIiwgaW5jbHVkZSA9IEZBTFNFKQ0KDQooYW5zMiA8LSBzaWVuYTA3KCBteUNvRXZBbGdvcml0aG0sIGRhdGEgPSBteUNvRXZvbHV0aW9uRGF0YSwNCiAgICAgICAgICAgICAgICAgIGVmZmVjdHMgPSBteUNvRXZvbHV0aW9uRWZmMiApKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNvbWUgb3RoZXIgZWZmZWN0cyAgICAgICAgICAgICAgICAgICAgICAgICAgICMjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojDQojIFRoZSBzZXQgb2YgYXZhaWxhYmxlIGVmZmVjdHMgZm9yIHRoaXMgZGF0YSBzZXQgY2FuIGJlIG9idGFpbmVkIGJ5IHJlcXVlc3RpbmcNCmVmZmVjdHNEb2N1bWVudGF0aW9uKCAgbXlDb0V2b2x1dGlvbkVmZiApDQojIFNlZSB0aGUgbWFudWFsLCBDaGFwdGVyIDEyLCBmb3IgdGhlIG1lYW5pbmcgb2YgdGhlc2UgZWZmZWN0cy4NCiMgVG8gc3R1ZHkgdGhlIGRpcmVjdCBlZmZlY3Qgb2YgdGhlIGFjdG9yIGNvdmFyaWF0ZSBzbW9raW5nIG9uIHRoZSBkZXBlbmRlbnQNCiMgdmFyaWFibGUgZHJpbmtpbmcsIHVzZSB0aGUgZWZmRnJvbSBlZmZlY3Q6DQoNCm15Q29Fdm9sdXRpb25FZmYzIDwtIGluY2x1ZGVFZmZlY3RzKCBteUNvRXZvbHV0aW9uRWZmMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gImRyaW5raW5nYmVoIiwgZWZmRnJvbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGlvbjEgPSAic21va2UxIikNCg0KIyBTaW5jZSB3ZSBhbHJlYWR5IGhhdmUgYSBnb29kIHJlc3VsdCBmb3IgYSBzaW1wbGVyIG1vZGVsLA0KIyBpdCBpcyBoZWxwZnVsIHRvIHN0YXJ0IGVzdGltYXRpbmcgZnJvbSB0aGVzZSBlc3RpbWF0ZXMNCiMgYXMgc3RhcnRpbmcgdmFsdWVzOg0KDQooYW5zMyA8LSBzaWVuYTA3KCBteUNvRXZBbGdvcml0aG0sIGRhdGEgPSBteUNvRXZvbHV0aW9uRGF0YSwNCiAgICAgICAgICAgICAgICAgIGVmZmVjdHMgPSBteUNvRXZvbHV0aW9uRWZmMywgcHJldkFucyA9IGFuczIgKSkNCiMgSW4gbXkgY2FzZSwgY29udmVyZ2VuY2Ugd2FzIG5vdCBnb29kIGVub3VnaDoNCihhbnMzIDwtIHNpZW5hMDcoIG15Q29FdkFsZ29yaXRobSwgZGF0YSA9IG15Q29Fdm9sdXRpb25EYXRhLA0KICAgICAgICAgICAgICAgICAgZWZmZWN0cyA9IG15Q29Fdm9sdXRpb25FZmYzLCBwcmV2QW5zID0gYW5zMyApKQ0KIyBZb3UgY2FuIGdldCBhIG5pY2VyIHByZXNlbnRhdGlvbiBvZiB0aGUgcmVzdWx0cyBpbiBhIGZpbGUNCiMgaW4geW91ciB3b3JraW5nIGRpcmVjdG9yeSBpbiBMYVRlWCBieQ0Kc2llbmEudGFibGUoYW5zMykNCiMgYW5kIGluIGh0bWwgKGNhbiBiZSBpbXBvcnRlZCBpbnRvIE1TLVdvcmQpIGJ5DQpzaWVuYS50YWJsZShhbnMzLCB0eXBlPSJodG1sIikNCg0KYGBgDQoNCg==

Copyright © 2020 Jochem Tolsma