@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code. Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ##

Code beschikbaar gesteld onder voorwaarden CC BY-NC-SA 4.0

[Attribution-NonCommercial-ShareAlike 4.0 International]

RIVM, 23 Februari2022

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

In dit document worden eerder los bepaalde UFP achtergronden, verkeersbijdragen en bijdragen van luchtvaart (grond en in de lucht) in de omgeving van Schiphol in 2017 en 2018 gefit aan gemeten totale UFP deeltjesaantallen in 36 windsectoren op 10 meetlocaties. De meetlocatie 6 (NH1, begin Polderbaan) wordt weggelaten, zie de eerdere RIVM rapportage voor de redenen daarvan.

Om op het laatst het verschil tussen de meetwaarden en de bijdragen vanuit de achtergrond en verkeer toe te wijzen aan de bijdragen van luchtvaart is het noodzakelijk dat de verschillende bijdragen zo onafhankelijk mogelijk worden bepaald. Daarom wordt de omrekening van NOx verkeersbijdragen naar UFP apart gecheckt.

De achtergronden worden in een aparte Excel file toegelicht. Bij de bepaling hiervan is deels”expert-judgement” gebruikt om te schatten vanuit welke windrichtingen (van buiten het studiegebied) er redelijkerwijs sprake is van achtergrond. Wegen buiten het studiegebied zijn namelijk wel voor een deel expliciet doorgerekend.

———————————————————————————

Stap 1, Invoer Datavelden:

Naam: naam meetlocatie, zie eerdere rapport.

windr: windrichting van de meting.

UFP: gemiddelde meetwaarde van ufp in aantal deeltjes per kubieke centimeter, zie eerder rapport.

NOx: berekende NOx bijdrage in microgram per kubieke meter.

Background: gemiddelde meetwaarde ufp in de aangenomen achtergrond in aantal deeltjes per kubieke centimeter.

BGR_P1: gemiddelde meetwaarde ufp in de aangenomen achtergrond in aantal deeltjes per kubieke centimeter gedurende enkel meetperode 1.

BGR_P2: gemiddelde meetwaarde ufp in de aangenomen achtergrond in aantal deeltjes per kubieke centimeter gedurende enkel meetperode 2.

Mazaheri: berekende ufp ten gevolge van luchtvaartactiviteiten in aantal deeltjes per kubieke centimeter, zie eerder rapport.

Uren: Aantal uren dat er bij deze combinatie van station en windrichting data beschikbaar is.

Periode: Meetperiode 1 of 2.

Eerst de data inlezen …


###############################################################################
library(simpleboot)

# setwd("HIER_PAD_INVOEGEN") 
UFPU = read.table("AlleData_18Feb22.txt", header=TRUE, sep = '\t')
head (UFPU)

———————————————————————————

Stap 2, Check UFP van verkeer

We verifiëren de omrekening van NOx verkeersbijdragen naar geschatte UFP bijdragen. Doe dit door een fit van de berekende NOx bijdragen van wegverkeer en de achtergronden aan de meetdata voor de locaties dat er naar verwachting wel wegverkeerbijdragen en weinig/geen luchtvaartbijdragen zijn. We gaan er van uit dat er weinig luchtvaartbijdragen en veel verkeersbijdragen zijn als in de data Mazaheri < 50 & Nox > 2. Deze waarden zijn een beetje arbitrair. Andere keuzes voor de grenzen geven iets andere resultaten. Voor de overall resultaten maakt dat niet wezenlijk uit. Let wel: deze fit is alleen om te verifiëren dat verkeersbijdragen goed los van de luchtvaartbijdragen kunnen worden bepaald.


##############################################################################
# ------- Fit verkeer met lm() met weging van het aantal uren!
##############################################################################
# Selecteer de data: veel verkeersbijdragen en weing van de luchtvaart.
ufp_uren <- subset(UFPU, select=c("naam", "UFP", "NOx", "Background", "Mazaheri", "Uren"),   
        NOx > 2 & Mazaheri < 50 )

# Definieer als weegfactoren de aantallen uren. 
wgt <- ufp_uren$Uren
ufps.fit <- lm( UFP ~ 0 + Background + NOx , data = ufp_uren, weights = wgt )
print(summary(ufps.fit))

Call:
lm(formula = UFP ~ 0 + Background + NOx, data = ufp_uren, weights = wgt)

Weighted Residuals:
   Min     1Q Median     3Q    Max 
-25539 -13655  -7287   3483  33838 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
Background   0.69242    0.05088   13.61 7.25e-14 ***
NOx        662.40101   67.24641    9.85 1.34e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 15880 on 28 degrees of freedom
Multiple R-squared:  0.9784,    Adjusted R-squared:  0.9768 
F-statistic: 632.7 on 2 and 28 DF,  p-value: < 2.2e-16
predicted <- predict(ufps.fit,newdata=ufp_uren)
plot(ufp_uren$UFP, predicted, main = "Verkeer, 7 km, met gewogen fit",  
     cex = 0.95, xlim=c(0,30000), ylim=c(0,30000)) ; abline(0,1)

———————————————————————————

Stap 3, Gecombineerde fit

Vervolgens worden de afzonderlijke bijdragen (background, NOx en Mazaheri) integraal aan de gemeten UFP concentraties gefit. De achtergronden zijn apart bepaald, we schalen die alleen omdat we nu alles in een analyse integreren, de vorm en structuur blijft ongewijzigd. De bijdragen van wegverkeer worden ook alleen geschaald omdat we van hierboven weten dat de vorm van de verdeling in principe past bij de metingen. Voor de bijdragen van de luchtvaart verifiëren we of de verdeling past bij de metingen. De onzekerheden in de fit worden via een bootstrap procedure geschat.


##############################################################################
# ------- Fit alles gecombineerd met lm() met weging van het aantal uren.
# ------- Doe ook bootstrap voor onzekerheden.
##############################################################################
# Selecteer alle data.
ufp_uren <- subset(UFPU, select=c("naam", "UFP", "NOx", "Background", "Mazaheri", "Uren") )
# Definieer als weegfactoren de aantallen uren. 
wgt <- ufp_uren$Uren
ufps.fit <- lm( UFP ~ 0 + Background + NOx + Mazaheri , data = ufp_uren, weights = wgt )
print(summary(ufps.fit))

Call:
lm(formula = UFP ~ 0 + Background + NOx + Mazaheri, data = ufp_uren, 
    weights = wgt)

Weighted Residuals:
    Min      1Q  Median      3Q     Max 
-220862  -22486   -3102   24868  318726 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
Background   1.04114    0.04123   25.25   <2e-16 ***
NOx        675.44635   52.15934   12.95   <2e-16 ***
Mazaheri     0.78259    0.02825   27.71   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 53960 on 393 degrees of freedom
Multiple R-squared:  0.9284,    Adjusted R-squared:  0.9279 
F-statistic:  1699 on 3 and 393 DF,  p-value: < 2.2e-16
predicted <- predict(ufps.fit,newdata=ufp_uren)
plot(ufp_uren$UFP, predicted, main = "Schiphol met gewogen fit, alle data",  cex = 0.65, 
     xlim=c(0,70000), ylim=c(0,70000)) ; abline(0,1)



##############################################################################
# Een simpele bootstrap ... 
# https://www.rdocumentation.org/packages/simpleboot/versions/1.1-7/topics/lm.boot 
lboot <- lm.boot(ufps.fit, rows = TRUE, R=10000)
summary(lboot)
BOOTSTRAP OF LINEAR MODEL  (method = rows)

Original Model Fit
------------------
Call:
lm(formula = UFP ~ 0 + Background + NOx + Mazaheri, data = ufp_uren, 
    weights = wgt)

Coefficients:
Background         NOx    Mazaheri  
    1.0411    675.4464      0.7826  

Bootstrap SD's:
 Background          NOx     Mazaheri  
 0.04206733  74.99985779   0.07070741  

———————————————————————————

Periode 1

Doe nu hetzelfde voor de data van periode 1:


##############################################################################
# ------- Fit PERIODE 1 gecombineerd met lm() met weging van het aantal uren.
# ------- Doe ook bootstrap voor onzekerheden.
##############################################################################
# Selecteer alle data.
ufp_uren <- subset(UFPU, select=c("naam", "UFP", "NOx", "Background", "Mazaheri", "Uren", "BGR_P1"), 
                   Periode == 1 )
# Definieer als weegfactoren de aantallen uren. 
wgt <- ufp_uren$Uren
ufps.fit <- lm( UFP ~ 0 + BGR_P1 + NOx + Mazaheri , data = ufp_uren, weights = wgt )
print(summary(ufps.fit))

Call:
lm(formula = UFP ~ 0 + BGR_P1 + NOx + Mazaheri, data = ufp_uren, 
    weights = wgt)

Weighted Residuals:
    Min      1Q  Median      3Q     Max 
-298834  -19477   -2192   15721  263994 

Coefficients:
          Estimate Std. Error t value Pr(>|t|)    
BGR_P1   8.830e-01  6.538e-02  13.505  < 2e-16 ***
NOx      1.018e+03  1.239e+02   8.221 4.18e-14 ***
Mazaheri 9.509e-01  4.858e-02  19.574  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 51430 on 177 degrees of freedom
Multiple R-squared:  0.9237,    Adjusted R-squared:  0.9224 
F-statistic: 714.5 on 3 and 177 DF,  p-value: < 2.2e-16
predicted <- predict(ufps.fit,newdata=ufp_uren)
plot(ufp_uren$UFP, predicted, main = "Schiphol met gewogen fit, Periode 1",  cex = 0.65, 
     xlim=c(0,70000), ylim=c(0,70000)) ; abline(0,1)


lboot <- lm.boot(ufps.fit, rows = TRUE, R=10000)
summary(lboot)
BOOTSTRAP OF LINEAR MODEL  (method = rows)

Original Model Fit
------------------
Call:
lm(formula = UFP ~ 0 + BGR_P1 + NOx + Mazaheri, data = ufp_uren, 
    weights = wgt)

Coefficients:
   BGR_P1        NOx   Mazaheri  
   0.8830  1018.1519     0.9509  

Bootstrap SD's:
      BGR_P1           NOx      Mazaheri  
  0.08425056  267.55642282    0.18026863  

———————————————————————————

Periode 2

Doe nu hetzelfde voor de data van periode 2:

##############################################################################
# ------- Fit PERIODE 2 gecombineerd met lm() met weging van het aantal uren.
# ------- Doe ook bootstrap voor onzekerheden.
##############################################################################
# Selecteer alle data.
ufp_uren <- subset(UFPU, select=c("naam", "UFP", "NOx", "Background", "Mazaheri", "Uren", "BGR_P2"), 
                   Periode == 2 )
# Definieer als weegfactoren de aantallen uren. 
wgt <- ufp_uren$Uren
ufps.fit <- lm( UFP ~ 0 + BGR_P2 + NOx + Mazaheri , data = ufp_uren, weights = wgt )
print(summary(ufps.fit))

Call:
lm(formula = UFP ~ 0 + BGR_P2 + NOx + Mazaheri, data = ufp_uren, 
    weights = wgt)

Weighted Residuals:
    Min      1Q  Median      3Q     Max 
-139314  -25007   -3247   35956  173263 

Coefficients:
          Estimate Std. Error t value Pr(>|t|)    
BGR_P2     1.05561    0.04984   21.18   <2e-16 ***
NOx      619.67167   56.55073   10.96   <2e-16 ***
Mazaheri   0.68633    0.03296   20.83   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 51860 on 213 degrees of freedom
Multiple R-squared:  0.9418,    Adjusted R-squared:  0.941 
F-statistic:  1149 on 3 and 213 DF,  p-value: < 2.2e-16
predicted <- predict(ufps.fit,newdata=ufp_uren)
plot(ufp_uren$UFP, predicted, main = "Schiphol met gewogen fit, Periode 2",  cex = 0.65, 
     xlim=c(0,70000), ylim=c(0,70000)) ; abline(0,1)


lboot <- lm.boot(ufps.fit, rows = TRUE, R=10000)
summary(lboot)
BOOTSTRAP OF LINEAR MODEL  (method = rows)

Original Model Fit
------------------
Call:
lm(formula = UFP ~ 0 + BGR_P2 + NOx + Mazaheri, data = ufp_uren, 
    weights = wgt)

Coefficients:
  BGR_P2       NOx  Mazaheri  
  1.0556  619.6717    0.6863  

Bootstrap SD's:
     BGR_P2          NOx     Mazaheri  
 0.04246216  69.81639278   0.05656197  

———————————————————————————

Stap 4, Bijdragen luchtvaart

Nu gaan we de geschatte gemiddelde bijdragen van de luchtvaart vergelijken met de berekende gemiddelde bijdragen. We doen dit door de gefitte achtergrond en berekende verkeersbijdragen van de metingen af te trekken en het verschil dan te vergelijken met de gefitte berekende bijdragen van de luchtvaart. Deze laatste twee moeten goed bij elkaar passen, dat testen we met de correlatie tussen de twee sets. Net als in de eerdere rapportage nemen we de gemiddelden per meetlocatie.


ufp_uren <- subset(UFPU, select=c("naam", "UFP", "NOx", "Background", "Mazaheri", "Uren") )
wgt <- ufp_uren$Uren

SNAMES <- ufp_uren$naam
SUNAMES <- unique(SNAMES)
print(SUNAMES)
 [1] "Oude_Meer"    "Ookmeer"      "Amstelveen"   "Aalsmeer"     "Vijfhuizen"   "Nieuwe_Meer"  "Hoofddorp"    "Spaarnewoude" "Badhoevedorp"
[10] "Oude_Meer2"   "Ookmeer2"    
# uitgangsput is de fit aan alle data:
ufps.fit <- lm( UFP ~ 0 + Background + NOx + Mazaheri , data = ufp_uren, weights = wgt )
cf = coefficients(ufps.fit)
print(cf)
 Background         NOx    Mazaheri 
  1.0411405 675.4463519   0.7825934 
# Aggregeer de waarden per meetpunt in een nieuwe set tabellen.
Aircraft.naam <- array(1:15, dim=c(1))
Aircraft.estimate <- array(1:15, dim=c(1))
Aircraft.Mazaheri <- array(1:15, dim=c(1))
Aircraft.estimateUren <- array(1:15, dim=c(1))
Aircraft.MazaheriUren <- array(1:15, dim=c(1))

# Bepaal de gemiddelde waarden per meetlocatie.
for (i in 1:length(SUNAMES))  {
  single = ufp_uren[ufp_uren$naam == SUNAMES[i]  , ]
  single$mod = single$UFP - cf[1] * single$Background - cf[2] * single$NOx
  Aircraft.naam[i] = single$naam[1]
  
  # Gewogen met aantal uren:
  Aircraft.estimateUren[i] = mean(single$mod * single$Uren) / mean(single$Uren)
  Aircraft.MazaheriUren[i] = cf[3] * mean(single$Mazaheri * single$Uren)  / mean(single$Uren)
}

# Maak plots:
plot(Aircraft.estimateUren, Aircraft.MazaheriUren, main = "Gemiddelde luchtvaartbijdragen per locatie, gewogen met uren",  cex = 0.95, xlim=c(0,15000), ylim=c(0,15000)) ; abline(0,1)


# En de correlatie tussen de geaggregeerde geschatte luchtvaartbijdragen en Mazaheri:
print("Correlatie:")
[1] "Correlatie:"
print(cor(Aircraft.estimateUren, Aircraft.MazaheriUren))
[1] 0.8774251

———————————————————————————

Einde

———————————————————————————

@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ NOTE:

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I. When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed. @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @

LS0tCnRpdGxlOiAiT3Bib3V3IHZhbiBVRlAgcm9uZCBTY2hpcGhvbCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBACgpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiBUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgpAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBACiMjCgojIyBDb2RlIGJlc2NoaWtiYWFyIGdlc3RlbGQgb25kZXIgdm9vcndhYXJkZW4gQ0MgQlktTkMtU0EgNC4wIAoKIyMgICBbQXR0cmlidXRpb24tTm9uQ29tbWVyY2lhbC1TaGFyZUFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsXQoKIyMKCiMjIFJJVk0sIDIzIEZlYnJ1YXJpMjAyMgoKIyMKQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAoKSW4gZGl0IGRvY3VtZW50IHdvcmRlbiBlZXJkZXIgbG9zIGJlcGFhbGRlIFVGUCBhY2h0ZXJncm9uZGVuLCB2ZXJrZWVyc2JpamRyYWdlbiBlbiBiaWpkcmFnZW4gdmFuIGx1Y2h0dmFhcnQgKGdyb25kIGVuIGluIGRlIGx1Y2h0KSBpbiBkZSBvbWdldmluZyB2YW4gU2NoaXBob2wgaW4gMjAxNyBlbiAyMDE4IGdlZml0IGFhbiBnZW1ldGVuIHRvdGFsZSBVRlAgZGVlbHRqZXNhYW50YWxsZW4gaW4gMzYgd2luZHNlY3RvcmVuIG9wIDEwIG1lZXRsb2NhdGllcy4gRGUgbWVldGxvY2F0aWUgNiAoTkgxLCBiZWdpbiBQb2xkZXJiYWFuKSB3b3JkdCB3ZWdnZWxhdGVuLCB6aWUgZGUgZWVyZGVyZSBSSVZNIHJhcHBvcnRhZ2Ugdm9vciBkZSByZWRlbmVuIGRhYXJ2YW4uCgpPbSBvcCBoZXQgbGFhdHN0IGhldCB2ZXJzY2hpbCB0dXNzZW4gZGUgbWVldHdhYXJkZW4gZW4gZGUgYmlqZHJhZ2VuIHZhbnVpdCBkZSBhY2h0ZXJncm9uZCBlbiB2ZXJrZWVyIHRvZSB0ZSB3aWp6ZW4gYWFuIGRlIGJpamRyYWdlbiB2YW4gbHVjaHR2YWFydCBpcyBoZXQgbm9vZHpha2VsaWprIGRhdCBkZSB2ZXJzY2hpbGxlbmRlIGJpamRyYWdlbiB6byBvbmFmaGFua2VsaWprIG1vZ2VsaWprIHdvcmRlbiBiZXBhYWxkLiBEYWFyb20gd29yZHQgZGUgb21yZWtlbmluZyB2YW4gTk94IHZlcmtlZXJzYmlqZHJhZ2VuIG5hYXIgVUZQIGFwYXJ0IGdlY2hlY2t0LiAgCgpEZSBhY2h0ZXJncm9uZGVuIHdvcmRlbiBpbiBlZW4gYXBhcnRlIEV4Y2VsIGZpbGUgdG9lZ2VsaWNodC4gQmlqIGRlIGJlcGFsaW5nIGhpZXJ2YW4gaXMgZGVlbHMiZXhwZXJ0LWp1ZGdlbWVudCIgZ2VicnVpa3Qgb20gdGUgc2NoYXR0ZW4gdmFudWl0IHdlbGtlIHdpbmRyaWNodGluZ2VuICh2YW4gYnVpdGVuIGhldCBzdHVkaWVnZWJpZWQpIGVyIHJlZGVsaWprZXJ3aWpzIHNwcmFrZSBpcyB2YW4gYWNodGVyZ3JvbmQuIFdlZ2VuIGJ1aXRlbiBoZXQgc3R1ZGllZ2ViaWVkIHppam4gbmFtZWxpamsgd2VsIHZvb3IgZWVuIGRlZWwgZXhwbGljaWV0IGRvb3JnZXJla2VuZC4KCioqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKioKCioqU3RhcCAxLCBJbnZvZXIqKiAKRGF0YXZlbGRlbjoKCk5hYW06IG5hYW0gbWVldGxvY2F0aWUsIHppZSBlZXJkZXJlIHJhcHBvcnQuCgp3aW5kcjogd2luZHJpY2h0aW5nIHZhbiBkZSBtZXRpbmcuCgpVRlA6IGdlbWlkZGVsZGUgbWVldHdhYXJkZSB2YW4gdWZwIGluIGFhbnRhbCBkZWVsdGplcyBwZXIga3ViaWVrZSBjZW50aW1ldGVyLCB6aWUgZWVyZGVyIHJhcHBvcnQuCgpOT3g6IGJlcmVrZW5kZSBOT3ggYmlqZHJhZ2UgaW4gbWljcm9ncmFtIHBlciBrdWJpZWtlIG1ldGVyLgoKQmFja2dyb3VuZDogZ2VtaWRkZWxkZSBtZWV0d2FhcmRlIHVmcCBpbiBkZSBhYW5nZW5vbWVuIGFjaHRlcmdyb25kIGluIGFhbnRhbCBkZWVsdGplcyBwZXIga3ViaWVrZSBjZW50aW1ldGVyLgoKQkdSX1AxOiBnZW1pZGRlbGRlIG1lZXR3YWFyZGUgdWZwIGluIGRlIGFhbmdlbm9tZW4gYWNodGVyZ3JvbmQgaW4gYWFudGFsIGRlZWx0amVzIHBlciBrdWJpZWtlIGNlbnRpbWV0ZXIgZ2VkdXJlbmRlIGVua2VsIG1lZXRwZXJvZGUgMS4KCkJHUl9QMjogZ2VtaWRkZWxkZSBtZWV0d2FhcmRlIHVmcCBpbiBkZSBhYW5nZW5vbWVuIGFjaHRlcmdyb25kIGluIGFhbnRhbCBkZWVsdGplcyBwZXIga3ViaWVrZSBjZW50aW1ldGVyIGdlZHVyZW5kZSBlbmtlbCBtZWV0cGVyb2RlIDIuCgpNYXphaGVyaTogYmVyZWtlbmRlIHVmcCB0ZW4gZ2V2b2xnZSB2YW4gbHVjaHR2YWFydGFjdGl2aXRlaXRlbiBpbiBhYW50YWwgZGVlbHRqZXMgcGVyIGt1Ymlla2UgY2VudGltZXRlciwgemllIGVlcmRlciByYXBwb3J0LgoKVXJlbjogQWFudGFsIHVyZW4gZGF0IGVyIGJpaiBkZXplIGNvbWJpbmF0aWUgdmFuIHN0YXRpb24gZW4gd2luZHJpY2h0aW5nIGRhdGEgYmVzY2hpa2JhYXIgaXMuCgpQZXJpb2RlOiBNZWV0cGVyaW9kZSAxIG9mIDIuCgpFZXJzdCBkZSBkYXRhIGlubGV6ZW4gLi4uCgpgYGB7cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbGlicmFyeShzaW1wbGVib290KQoKIyBzZXR3ZCgiSElFUl9QQURfSU5WT0VHRU4iKSAKVUZQVSA9IHJlYWQudGFibGUoIkFsbGVEYXRhXzE4RmViMjIudHh0IiwgaGVhZGVyPVRSVUUsIHNlcCA9ICdcdCcpCmhlYWQgKFVGUFUpCmBgYAoqKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSoqCgoqKlN0YXAgMiwgQ2hlY2sgVUZQIHZhbiB2ZXJrZWVyKiogCgpXZSB2ZXJpZmnDq3JlbiBkZSBvbXJla2VuaW5nIHZhbiBOT3ggdmVya2VlcnNiaWpkcmFnZW4gbmFhciBnZXNjaGF0dGUgVUZQIGJpamRyYWdlbi4gRG9lIGRpdCBkb29yIGVlbiBmaXQgdmFuIGRlIGJlcmVrZW5kZSBOT3ggYmlqZHJhZ2VuIHZhbiB3ZWd2ZXJrZWVyIGVuIGRlIGFjaHRlcmdyb25kZW4gYWFuIGRlIG1lZXRkYXRhIHZvb3IgZGUgbG9jYXRpZXMgZGF0IGVyIG5hYXIgdmVyd2FjaHRpbmcgd2VsIHdlZ3ZlcmtlZXJiaWpkcmFnZW4gZW4gd2VpbmlnL2dlZW4gbHVjaHR2YWFydGJpamRyYWdlbiB6aWpuLiBXZSBnYWFuIGVyIHZhbiB1aXQgZGF0IGVyIHdlaW5pZyBsdWNodHZhYXJ0YmlqZHJhZ2VuIGVuIHZlZWwgdmVya2VlcnNiaWpkcmFnZW4gemlqbiBhbHMgaW4gZGUgZGF0YSAgTWF6YWhlcmkgPCA1MCAmIE5veCA+IDIuIERlemUgd2FhcmRlbiB6aWpuIGVlbiBiZWV0amUgYXJiaXRyYWlyLiBBbmRlcmUga2V1emVzIHZvb3IgZGUgZ3JlbnplbiBnZXZlbiBpZXRzIGFuZGVyZSByZXN1bHRhdGVuLiBWb29yIGRlIG92ZXJhbGwgcmVzdWx0YXRlbiBtYWFrdCBkYXQgbmlldCB3ZXplbmxpamsgdWl0LiBMZXQgd2VsOiBkZXplIGZpdCBpcyBhbGxlZW4gb20gdGUgdmVyaWZpw6tyZW4gZGF0IHZlcmtlZXJzYmlqZHJhZ2VuIGdvZWQgbG9zIHZhbiBkZSBsdWNodHZhYXJ0YmlqZHJhZ2VuIGt1bm5lbiB3b3JkZW4gYmVwYWFsZC4KCgpgYGB7cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIC0tLS0tLS0gRml0IHZlcmtlZXIgbWV0IGxtKCkgbWV0IHdlZ2luZyB2YW4gaGV0IGFhbnRhbCB1cmVuIQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBTZWxlY3RlZXIgZGUgZGF0YTogdmVlbCB2ZXJrZWVyc2JpamRyYWdlbiBlbiB3ZWluZyB2YW4gZGUgbHVjaHR2YWFydC4KdWZwX3VyZW4gPC0gc3Vic2V0KFVGUFUsIHNlbGVjdD1jKCJuYWFtIiwgIlVGUCIsICJOT3giLCAiQmFja2dyb3VuZCIsICJNYXphaGVyaSIsICJVcmVuIiksICAgCiAgICAgICAgTk94ID4gMiAmIE1hemFoZXJpIDwgNTAgKQoKIyBEZWZpbmllZXIgYWxzIHdlZWdmYWN0b3JlbiBkZSBhYW50YWxsZW4gdXJlbi4gCndndCA8LSB1ZnBfdXJlbiRVcmVuCnVmcHMuZml0IDwtIGxtKCBVRlAgfiAwICsgQmFja2dyb3VuZCArIE5PeCAsIGRhdGEgPSB1ZnBfdXJlbiwgd2VpZ2h0cyA9IHdndCApCnByaW50KHN1bW1hcnkodWZwcy5maXQpKQpwcmVkaWN0ZWQgPC0gcHJlZGljdCh1ZnBzLmZpdCxuZXdkYXRhPXVmcF91cmVuKQpwbG90KHVmcF91cmVuJFVGUCwgcHJlZGljdGVkLCBtYWluID0gIlZlcmtlZXIsIDcga20sIG1ldCBnZXdvZ2VuIGZpdCIsICAKICAgICBjZXggPSAwLjk1LCB4bGltPWMoMCwzMDAwMCksIHlsaW09YygwLDMwMDAwKSkgOyBhYmxpbmUoMCwxKQoKYGBgCgoqKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSoqCgoqKlN0YXAgMywgR2Vjb21iaW5lZXJkZSBmaXQqKiAKClZlcnZvbGdlbnMgd29yZGVuIGRlIGFmem9uZGVybGlqa2UgYmlqZHJhZ2VuIChiYWNrZ3JvdW5kLCBOT3ggZW4gTWF6YWhlcmkpIGludGVncmFhbCBhYW4gZGUgZ2VtZXRlbiBVRlAgY29uY2VudHJhdGllcyBnZWZpdC4gRGUgYWNodGVyZ3JvbmRlbiB6aWpuIGFwYXJ0IGJlcGFhbGQsIHdlIHNjaGFsZW4gZGllIGFsbGVlbiBvbWRhdCB3ZSBudSBhbGxlcyBpbiBlZW4gYW5hbHlzZSBpbnRlZ3JlcmVuLCBkZSB2b3JtIGVuIHN0cnVjdHV1ciBibGlqZnQgb25nZXdpanppZ2QuIERlIGJpamRyYWdlbiB2YW4gd2VndmVya2VlciB3b3JkZW4gb29rIGFsbGVlbiBnZXNjaGFhbGQgb21kYXQgd2UgdmFuIGhpZXJib3ZlbiB3ZXRlbiBkYXQgZGUgdm9ybSB2YW4gZGUgdmVyZGVsaW5nIGluIHByaW5jaXBlIHBhc3QgYmlqIGRlIG1ldGluZ2VuLiBWb29yIGRlIGJpamRyYWdlbiB2YW4gZGUgbHVjaHR2YWFydCB2ZXJpZmnDq3JlbiB3ZSBvZiBkZSB2ZXJkZWxpbmcgcGFzdCBiaWogZGUgbWV0aW5nZW4uIERlIG9uemVrZXJoZWRlbiBpbiBkZSBmaXQgd29yZGVuIHZpYSBlZW4gYm9vdHN0cmFwIHByb2NlZHVyZSBnZXNjaGF0LgoKYGBge3J9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyAtLS0tLS0tIEZpdCBhbGxlcyBnZWNvbWJpbmVlcmQgbWV0IGxtKCkgbWV0IHdlZ2luZyB2YW4gaGV0IGFhbnRhbCB1cmVuLgojIC0tLS0tLS0gRG9lIG9vayBib290c3RyYXAgdm9vciBvbnpla2VyaGVkZW4uCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFNlbGVjdGVlciBhbGxlIGRhdGEuCnVmcF91cmVuIDwtIHN1YnNldChVRlBVLCBzZWxlY3Q9YygibmFhbSIsICJVRlAiLCAiTk94IiwgIkJhY2tncm91bmQiLCAiTWF6YWhlcmkiLCAiVXJlbiIpICkKIyBEZWZpbmllZXIgYWxzIHdlZWdmYWN0b3JlbiBkZSBhYW50YWxsZW4gdXJlbi4gCndndCA8LSB1ZnBfdXJlbiRVcmVuCnVmcHMuZml0IDwtIGxtKCBVRlAgfiAwICsgQmFja2dyb3VuZCArIE5PeCArIE1hemFoZXJpICwgZGF0YSA9IHVmcF91cmVuLCB3ZWlnaHRzID0gd2d0ICkKcHJpbnQoc3VtbWFyeSh1ZnBzLmZpdCkpCnByZWRpY3RlZCA8LSBwcmVkaWN0KHVmcHMuZml0LG5ld2RhdGE9dWZwX3VyZW4pCnBsb3QodWZwX3VyZW4kVUZQLCBwcmVkaWN0ZWQsIG1haW4gPSAiU2NoaXBob2wgbWV0IGdld29nZW4gZml0LCBhbGxlIGRhdGEiLCAgY2V4ID0gMC42NSwgCiAgICAgeGxpbT1jKDAsNzAwMDApLCB5bGltPWMoMCw3MDAwMCkpIDsgYWJsaW5lKDAsMSkKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBFZW4gc2ltcGVsZSBib290c3RyYXAgLi4uIAojIGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9zaW1wbGVib290L3ZlcnNpb25zLzEuMS03L3RvcGljcy9sbS5ib290IApsYm9vdCA8LSBsbS5ib290KHVmcHMuZml0LCByb3dzID0gVFJVRSwgUj0xMDAwMCkKc3VtbWFyeShsYm9vdCkKCmBgYAoKKiotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qKgoKKipQZXJpb2RlIDEgKiogCgpEb2UgbnUgaGV0emVsZmRlIHZvb3IgZGUgZGF0YSB2YW4gcGVyaW9kZSAxOgoKLSBBY2h0ZXJncm9uZCBlbiBsdWNodHZhYXJ0YmpkcmFnZW4gc3BlY2lmaWVrIHZvb3IgZGV6ZSBwZXJpb2RlOwoKLSBWZXJrZWVyIGdlbmVyaWVrIHZvb3IgMjAxOCBvbWRhdCB3ZSBkaWUgbmlldCBwZXIgcGVyaW9kZSBrdW5uZW4gYmVwYWxlbi4KCmBgYHtyfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgLS0tLS0tLSBGaXQgUEVSSU9ERSAxIGdlY29tYmluZWVyZCBtZXQgbG0oKSBtZXQgd2VnaW5nIHZhbiBoZXQgYWFudGFsIHVyZW4uCiMgLS0tLS0tLSBEb2Ugb29rIGJvb3RzdHJhcCB2b29yIG9uemVrZXJoZWRlbi4KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgU2VsZWN0ZWVyIGFsbGUgZGF0YS4KdWZwX3VyZW4gPC0gc3Vic2V0KFVGUFUsIHNlbGVjdD1jKCJuYWFtIiwgIlVGUCIsICJOT3giLCAiQmFja2dyb3VuZCIsICJNYXphaGVyaSIsICJVcmVuIiwgIkJHUl9QMSIpLCAKICAgICAgICAgICAgICAgICAgIFBlcmlvZGUgPT0gMSApCiMgRGVmaW5pZWVyIGFscyB3ZWVnZmFjdG9yZW4gZGUgYWFudGFsbGVuIHVyZW4uIAp3Z3QgPC0gdWZwX3VyZW4kVXJlbgp1ZnBzLmZpdCA8LSBsbSggVUZQIH4gMCArIEJHUl9QMSArIE5PeCArIE1hemFoZXJpICwgZGF0YSA9IHVmcF91cmVuLCB3ZWlnaHRzID0gd2d0ICkKcHJpbnQoc3VtbWFyeSh1ZnBzLmZpdCkpCnByZWRpY3RlZCA8LSBwcmVkaWN0KHVmcHMuZml0LG5ld2RhdGE9dWZwX3VyZW4pCnBsb3QodWZwX3VyZW4kVUZQLCBwcmVkaWN0ZWQsIG1haW4gPSAiU2NoaXBob2wgbWV0IGdld29nZW4gZml0LCBQZXJpb2RlIDEiLCAgY2V4ID0gMC42NSwgCiAgICAgeGxpbT1jKDAsNzAwMDApLCB5bGltPWMoMCw3MDAwMCkpIDsgYWJsaW5lKDAsMSkKCmxib290IDwtIGxtLmJvb3QodWZwcy5maXQsIHJvd3MgPSBUUlVFLCBSPTEwMDAwKQpzdW1tYXJ5KGxib290KQoKYGBgCgoqKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSoqCgoqKlBlcmlvZGUgMiAqKiAKCkRvZSBudSBoZXR6ZWxmZGUgdm9vciBkZSBkYXRhIHZhbiBwZXJpb2RlIDI6CgotIEFjaHRlcmdyb25kIGVuIGx1Y2h0dmFhcnRiamRyYWdlbiBzcGVjaWZpZWsgdm9vciBkZXplIHBlcmlvZGU7CgotIFZpZXIgd2luZHJpY2h0aW5nZW4ga3dhbWVuIGluIHBlcmlvZGUgMiBpbiBoZXQgbWVldGdlYmllZCBuaWV0IHZvb3IgZW4gZXIgd2FyZW4gZXIgZ2VlbiBnZW1ldGVuIGRhdGEsIGhpZXJ2b29yIHppam4gZGUgd2FhcmRlbiB2YW4gcGVyaW9kZSAxIGdlYnJ1aWt0LgoKLSBWZXJrZWVyIGdlbmVyaWVrIHZvb3IgMjAxOCBvbWRhdCB3ZSBkaWUgbmlldCBwZXIgcGVyaW9kZSBrdW5uZW4gYmVwYWxlbi4gCgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgLS0tLS0tLSBGaXQgUEVSSU9ERSAyIGdlY29tYmluZWVyZCBtZXQgbG0oKSBtZXQgd2VnaW5nIHZhbiBoZXQgYWFudGFsIHVyZW4uCiMgLS0tLS0tLSBEb2Ugb29rIGJvb3RzdHJhcCB2b29yIG9uemVrZXJoZWRlbi4KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgU2VsZWN0ZWVyIGFsbGUgZGF0YS4KdWZwX3VyZW4gPC0gc3Vic2V0KFVGUFUsIHNlbGVjdD1jKCJuYWFtIiwgIlVGUCIsICJOT3giLCAiQmFja2dyb3VuZCIsICJNYXphaGVyaSIsICJVcmVuIiwgIkJHUl9QMiIpLCAKICAgICAgICAgICAgICAgICAgIFBlcmlvZGUgPT0gMiApCiMgRGVmaW5pZWVyIGFscyB3ZWVnZmFjdG9yZW4gZGUgYWFudGFsbGVuIHVyZW4uIAp3Z3QgPC0gdWZwX3VyZW4kVXJlbgp1ZnBzLmZpdCA8LSBsbSggVUZQIH4gMCArIEJHUl9QMiArIE5PeCArIE1hemFoZXJpICwgZGF0YSA9IHVmcF91cmVuLCB3ZWlnaHRzID0gd2d0ICkKcHJpbnQoc3VtbWFyeSh1ZnBzLmZpdCkpCnByZWRpY3RlZCA8LSBwcmVkaWN0KHVmcHMuZml0LG5ld2RhdGE9dWZwX3VyZW4pCnBsb3QodWZwX3VyZW4kVUZQLCBwcmVkaWN0ZWQsIG1haW4gPSAiU2NoaXBob2wgbWV0IGdld29nZW4gZml0LCBQZXJpb2RlIDIiLCAgY2V4ID0gMC42NSwgCiAgICAgeGxpbT1jKDAsNzAwMDApLCB5bGltPWMoMCw3MDAwMCkpIDsgYWJsaW5lKDAsMSkKCmxib290IDwtIGxtLmJvb3QodWZwcy5maXQsIHJvd3MgPSBUUlVFLCBSPTEwMDAwKQpzdW1tYXJ5KGxib290KQpgYGAKKiotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qKgoKKipTdGFwIDQsIEJpamRyYWdlbiBsdWNodHZhYXJ0ICoqIAoKTnUgZ2FhbiB3ZSBkZSBnZXNjaGF0dGUgZ2VtaWRkZWxkZSBiaWpkcmFnZW4gdmFuIGRlIGx1Y2h0dmFhcnQgdmVyZ2VsaWprZW4gbWV0IGRlIGJlcmVrZW5kZSBnZW1pZGRlbGRlIGJpamRyYWdlbi4gV2UgZG9lbiBkaXQgZG9vciBkZSBnZWZpdHRlIGFjaHRlcmdyb25kIGVuIGJlcmVrZW5kZSB2ZXJrZWVyc2JpamRyYWdlbiB2YW4gZGUgbWV0aW5nZW4gYWYgdGUgdHJla2tlbiBlbiBoZXQgdmVyc2NoaWwgZGFuIHRlIHZlcmdlbGlqa2VuIG1ldCBkZSBnZWZpdHRlIGJlcmVrZW5kZSBiaWpkcmFnZW4gdmFuIGRlIGx1Y2h0dmFhcnQuIERlemUgbGFhdHN0ZSB0d2VlIG1vZXRlbiBnb2VkIGJpaiBlbGthYXIgcGFzc2VuLCBkYXQgdGVzdGVuIHdlIG1ldCBkZSBjb3JyZWxhdGllIHR1c3NlbiBkZSB0d2VlIHNldHMuIE5ldCBhbHMgaW4gZGUgZWVyZGVyZSByYXBwb3J0YWdlIG5lbWVuIHdlIGRlIGdlbWlkZGVsZGVuIHBlciBtZWV0bG9jYXRpZS4KCmBgYHtyfQoKdWZwX3VyZW4gPC0gc3Vic2V0KFVGUFUsIHNlbGVjdD1jKCJuYWFtIiwgIlVGUCIsICJOT3giLCAiQmFja2dyb3VuZCIsICJNYXphaGVyaSIsICJVcmVuIikgKQp3Z3QgPC0gdWZwX3VyZW4kVXJlbgoKU05BTUVTIDwtIHVmcF91cmVuJG5hYW0KU1VOQU1FUyA8LSB1bmlxdWUoU05BTUVTKQpwcmludChTVU5BTUVTKQoKIyB1aXRnYW5nc3B1dCBpcyBkZSBmaXQgYWFuIGFsbGUgZGF0YToKdWZwcy5maXQgPC0gbG0oIFVGUCB+IDAgKyBCYWNrZ3JvdW5kICsgTk94ICsgTWF6YWhlcmkgLCBkYXRhID0gdWZwX3VyZW4sIHdlaWdodHMgPSB3Z3QgKQpjZiA9IGNvZWZmaWNpZW50cyh1ZnBzLmZpdCkKcHJpbnQoY2YpCgojIEFnZ3JlZ2VlciBkZSB3YWFyZGVuIHBlciBtZWV0cHVudCBpbiBlZW4gbmlldXdlIHNldCB0YWJlbGxlbi4KQWlyY3JhZnQubmFhbSA8LSBhcnJheSgxOjE1LCBkaW09YygxKSkKQWlyY3JhZnQuZXN0aW1hdGUgPC0gYXJyYXkoMToxNSwgZGltPWMoMSkpCkFpcmNyYWZ0Lk1hemFoZXJpIDwtIGFycmF5KDE6MTUsIGRpbT1jKDEpKQpBaXJjcmFmdC5lc3RpbWF0ZVVyZW4gPC0gYXJyYXkoMToxNSwgZGltPWMoMSkpCkFpcmNyYWZ0Lk1hemFoZXJpVXJlbiA8LSBhcnJheSgxOjE1LCBkaW09YygxKSkKCiMgQmVwYWFsIGRlIGdlbWlkZGVsZGUgd2FhcmRlbiBwZXIgbWVldGxvY2F0aWUuCmZvciAoaSBpbiAxOmxlbmd0aChTVU5BTUVTKSkgIHsKICBzaW5nbGUgPSB1ZnBfdXJlblt1ZnBfdXJlbiRuYWFtID09IFNVTkFNRVNbaV0gICwgXQogIHNpbmdsZSRtb2QgPSBzaW5nbGUkVUZQIC0gY2ZbMV0gKiBzaW5nbGUkQmFja2dyb3VuZCAtIGNmWzJdICogc2luZ2xlJE5PeAogIEFpcmNyYWZ0Lm5hYW1baV0gPSBzaW5nbGUkbmFhbVsxXQogIAogICMgR2V3b2dlbiBtZXQgYWFudGFsIHVyZW46CiAgQWlyY3JhZnQuZXN0aW1hdGVVcmVuW2ldID0gbWVhbihzaW5nbGUkbW9kICogc2luZ2xlJFVyZW4pIC8gbWVhbihzaW5nbGUkVXJlbikKICBBaXJjcmFmdC5NYXphaGVyaVVyZW5baV0gPSBjZlszXSAqIG1lYW4oc2luZ2xlJE1hemFoZXJpICogc2luZ2xlJFVyZW4pICAvIG1lYW4oc2luZ2xlJFVyZW4pCn0KCiMgTWFhayBwbG90czoKcGxvdChBaXJjcmFmdC5lc3RpbWF0ZVVyZW4sIEFpcmNyYWZ0Lk1hemFoZXJpVXJlbiwgbWFpbiA9ICJHZW1pZGRlbGRlIGx1Y2h0dmFhcnRiaWpkcmFnZW4gcGVyIGxvY2F0aWUsIGdld29nZW4gbWV0IHVyZW4iLCAgY2V4ID0gMC45NSwgeGxpbT1jKDAsMTUwMDApLCB5bGltPWMoMCwxNTAwMCkpIDsgYWJsaW5lKDAsMSkKCiMgRW4gZGUgY29ycmVsYXRpZSB0dXNzZW4gZGUgZ2VhZ2dyZWdlZXJkZSBnZXNjaGF0dGUgbHVjaHR2YWFydGJpamRyYWdlbiBlbiBNYXphaGVyaToKcHJpbnQoIkNvcnJlbGF0aWU6IikKcHJpbnQoY29yKEFpcmNyYWZ0LmVzdGltYXRlVXJlbiwgQWlyY3JhZnQuTWF6YWhlcmlVcmVuKSkKCmBgYAoKKiotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qKgoKKipFaW5kZSAgKiogCgoqKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSoqCgpACkBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAKQApOT1RFOgoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouIFdoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ21kK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLgpACkBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAKQAo=