Additional topics in Multilevel Modeling

Including survey design information in multilevel models

When analyzing data from surveys, we must pay attention to the design of the survey when we conduct our analysis. The survey data sources will provide information in their code books or user guides that identify the survey design variables in the data source, as well as the person-weighting factors associated with each respondent.

These pieces of information are integral when we do any analysis of survey data, because the design variables (survey stratum and primary sampling units identifiers) allow us to correctly calculate standard errors for model parameters in models that we construct. Likewise, the person weights in the data will correct for differential non-response to the survey, any oversampling that exists in the survey design and any factors to make the survey sample representative of the population it was designed to represent.

Multilevel models are natural models to use when analyzing survey data, because they can automatically mimic the design of the survey using the nested specifications we have discussed so far. Indeed, Snijders and Bosker (2012) in their text on multilevel models devote chapter 14 of their book to the discussion of how to use multilevel models to analyze complex survey design data.

They offer suggestions of things to do when using multilevel models on complex survey design data (such as the BRFSS). We will discuss and illustrate two of these suggestions below. These two methods are where we

  1. Including survey design variables in the model
  2. Including survey weights in the model

Method 1 equates to controlling for non-randomness of observations within sampling units by including the sample design variables (stratum and primary sampling units) as random effects in the model. This controls for the homogeneity within and between these survey units. Method 2 uses the provided case weights in the data and includes them as weights in the model to correct for the design factors that the weights have been used to correct for (representativeness, differential non response, etc.).

Including survey design variables in the multilevel model

Now we turn to the practical aspects of including survey design information in the multilevel model. Method 1 is straightforward, as long as the data we have includes the sampling design variables, which most survey datasets do. In the BRFSS, there is a variable ststr that is the sampling stratum. If we were to include this, as Snijders and Bosker suggest, then we will include a random effect in the model for the survey strata. In this case, we now have two random effects, the MSA level and the stratum level.

To measure macro level variables, I will include some Census variables from the ACS 2011 5 Year estimates load in ACS data from tidycensus. The first set of variables includes information on the economic conditions of the county, specifically poverty and unemployment.

library(tidycensus)
library(dplyr)

Attaching package: <U+393C><U+3E31>dplyr<U+393C><U+3E32>

The following objects are masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:

    filter, lag

The following objects are masked from <U+393C><U+3E31>package:base<U+393C><U+3E32>:

    intersect, setdiff, setequal, union
library(ggplot2)
usacs<-get_acs(geography = "metropolitan statistical area/micropolitan statistical area", year = 2011,
                variables=c( "DP05_0001E", "DP03_0009P", "DP03_0062E", "DP03_0119PE",
                             "DP05_0001E","DP02_0009PE","DP02_0008PE", "DP02_0040E","DP02_0038E",
                             "DP02_0066PE","DP02_0067PE","DP02_0080PE","DP02_0092PE",
                             "DP03_0005PE","DP03_0028PE","DP03_0062E","DP03_0099PE","DP03_0101PE",
                             "DP03_0119PE","DP04_0046PE","DP05_0072PE","DP05_0073PE",
                             "DP05_0066PE","DP05_0033","DP05_0032", "DP05_0072PE", "DP02_0113PE",  "DP04_0003PE") ,
                summary_var = "B01001_001",
                geometry = F, output = "wide")
Getting data from the 2007-2011 5-year ACS
Using the ACS Data Profile
Using the ACS Data Profile
usacs<-usacs%>%
  mutate(totpop= DP05_0001E, fertrate = DP02_0040E,pwhite=DP05_0072PE/100, nwhite=DP05_0032E,nblack=DP05_0033E,
         pblack=DP05_0073PE/100 , phisp=DP05_0066PE/100, pfemhh=DP02_0008PE/100,
         phsormore=DP02_0066PE/100,punemp=DP03_0009PE/100, medhhinc=DP03_0062E,
         ppov=DP03_0119PE/100, pforn=DP02_0092PE/100,plep=DP02_0113PE/100,  pvacant=DP04_0003PE/100)%>%
  select(GEOID,NAME, totpop, pwhite, pblack, phisp, pfemhh, phsormore, punemp, medhhinc, ppov, pforn,plep, pvacant)
head(usacs)

Clean and standardize contextual data

myscale<-function(x){as.numeric(scale(x))}
usacs<-usacs %>%
  mutate_at(c("ppov","punemp", "pblack","phisp", "pfemhh", "phsormore", "medhhinc", "pvacant"),myscale)
merged<-usacs%>%filter(complete.cases(.))
head(merged)

Let’s see the geographic variation in these economic indicators: We can also make a quick map of the indicators by merging these data with the appropriate level of census geography, in this case, MSAs are the same as Core Based Statistical Areas (CBSAs) in the Census geographic hierarchy.

library(tigris)
library(sf)
options(tigris_class="sf")
msa<-core_based_statistical_areas(cb=T)
msa<-msa%>%
  st_transform(crs = 102009)
sts<-states(cb = T)
sts<-sts%>%
  st_transform(crs = 102009)%>%
  filter(!STATEFP%in%c(60, 66, 69, 72, 78))
msa_ec<-geo_join(msa, usacs, "CBSAFP", "GEOID", how="inner")

BRFSS DATA

load("~/Google Drive/classes/dem7283/class_19_7283/data/brfss16_mmsa.Rdata")
set.seed(12345)
#samps<-sample(1:nrow(brfss16m), size = 40000, replace=F)
#brfss16m<-brfss16m[samps,]
#The names in the data are very ugly, so I make them less ugly
nams<-names(brfss16m)
#we see some names are lower case, some are upper and some have a little _ in the first position. This is a nightmare.
newnames<-gsub(pattern = "_",replacement =  "",x =  nams)
names(brfss16m)<-tolower(newnames)

Recode variables

library(car)
Loading required package: carData

Attaching package: <U+393C><U+3E31>car<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:dplyr<U+393C><U+3E32>:

    recode
library(dplyr)
###BRFSS DATA
#nice MSA name
brfss16m$mmsa_name<-substr(brfss16m$mmsaname, 1,nchar(brfss16m$mmsaname)-31)
#sex
brfss16m$male<-ifelse(brfss16m$sex==1, 1, 0)
#BMI
brfss16m$bmi<-ifelse(is.na(brfss16m$bmi5)==T, NA, brfss16m$bmi5/100)
#Healthy days
brfss16m$healthdays<-Recode(brfss16m$physhlth, recodes = "88=0; 77=NA; 99=NA")
#Healthy mental health days
brfss16m$healthmdays<-Recode(brfss16m$menthlth, recodes = "88=0; 77=NA; 99=NA")
brfss16m$badhealth<-Recode(brfss16m$genhlth, recodes="4:5=1; 1:3=0; else=NA")
#race/ethnicity
brfss16m$black<-Recode(brfss16m$racegr3, recodes="2=1; 9=NA; else=0")
brfss16m$white<-Recode(brfss16m$racegr3, recodes="1=1; 9=NA; else=0")
brfss16m$other<-Recode(brfss16m$racegr3, recodes="3:4=1; 9=NA; else=0")
brfss16m$hispanic<-Recode(brfss16m$racegr3, recodes="5=1; 9=NA; else=0")
brfss16m$race_eth<-Recode(brfss16m$racegr3, 
recodes="1='nhwhite'; 2='nh black'; 3='nh other';4='nh multirace'; 5='hispanic'; else=NA",
as.factor = T)
brfss16m$race_eth<-relevel(brfss16m$race_eth, ref = "nhwhite")
#insurance
brfss16m$ins<-Recode(brfss16m$hlthpln1, recodes ="7:9=NA; 1=1;2=0")
#income grouping
brfss16m$inc<-Recode(brfss16m$incomg, recodes = "9= NA;1='1_lt15k'; 2='2_15-25k';3='3_25-35k';4='4_35-50k';5='5_50kplus'", as.factor = T)
brfss16m$inc<-as.ordered(brfss16m$inc)
#education level
brfss16m$educ<-Recode(brfss16m$educa,
recodes="1:2='0Prim'; 3='1somehs'; 4='2hsgrad'; 5='3somecol'; 6='4colgrad';9=NA",
as.factor=T)
brfss16m$educ<-relevel(brfss16m$educ, ref='2hsgrad')
#employment
brfss16m$employ<-Recode(brfss16m$employ1,
recodes="1:2='employloyed'; 2:6='nilf'; 7='retired'; 8='unable'; else=NA",
as.factor=T)
brfss16m$employ<-relevel(brfss16m$employ, ref='employloyed')
#marital status
brfss16m$marst<-Recode(brfss16m$marital,
recodes="1='married'; 2='divorced'; 3='widowed'; 4='separated'; 5='nm';6='cohab'; else=NA",
as.factor=T)
brfss16m$marst<-relevel(brfss16m$marst, ref='married')
#Age cut into intervals
brfss16m$agec<-cut(brfss16m$age80, breaks=seq(20,80,10))
#BMI, in the brfss16ma the bmi variable has 2 implied decimal places,
#so we must divide by 100 to get real bmi's
brfss16m$bmi<-brfss16m$bmi5/100
#smoking currently
brfss16m$smoke<-Recode(brfss16m$smoker3, 
recodes="1:2=1; 3:4=0; else=NA")
#brfss16m$smoke<-relevel(brfss16m$smoke, ref = "NeverSmoked")
brfss16m$obese<-ifelse(is.na(brfss16m$bmi)==T, NA, 
                       ifelse(brfss16m$bmi>30,1,0))

The merge command in R has several arguments. x and y are the names of the individual and higher level data frames, by.x and by.y are the names of the key field (geographic identifier in this case) in both tables, which don’t have to have the same name. The all.x=F command tells R to join only the observations from the BRFSS that have a matching MSA in the MSA table.

merged<-merge(x=brfss16m,
              y=usacs,
              by.x="mmsa",
              by.y="GEOID",
              all.x=F)
merged<-merged%>%
  select( mmsa, ststr, agec, educ, black, hispanic, other,smoke,obese, badhealth,pblack,phisp, medhhinc,ppov,  male, mmsawt, mmsa_name )%>%
  filter(complete.cases(.))
library(lme4)
Loading required package: Matrix
model1<-glmer(obese ~ agec + male + educ + black + hispanic + other + medhhinc + pblack + phisp+ (1|mmsa_name), 
              family=binomial, 
              data=merged, 
              control = glmerControl(optimizer = c("Nelder_Mead","bobyqa"),
                                     optCtrl=list(maxfun=2e9)))

When we compare the model to model1 from earlier in the lesson, we see that the standard errors for some of the parameters have increased, and some of the \(\beta\)’s have also increased to small extent. The higher level variables effects are decreased in the model with the survey strata included.

library(stargazer)
stargazer(model1, model1s,
          column.labels = c("No Survey Design", "Including Strata"),
          type = "text",
          style="demography", out = "~/Google Drive/classes/dem7283/class_19_7283/code/table2.html")
length of NULL cannot be changedlength of NULL cannot be changedlength of NULL cannot be changedlength of NULL cannot be changedlength of NULL cannot be changed

------------------------------------------------
                             obese              
               No Survey Design Including Strata
                   Model 1          Model 2     
------------------------------------------------
agec(30,40]        0.457***         0.457***    
                   (0.025)          (0.025)     
agec(40,50]        0.660***         0.659***    
                   (0.024)          (0.024)     
agec(50,60]        0.627***         0.624***    
                   (0.022)          (0.023)     
agec(60,70]        0.595***         0.594***    
                   (0.022)          (0.022)     
agec(70,80]        0.125***         0.123***    
                   (0.023)          (0.023)     
male               0.059***         0.060***    
                   (0.011)          (0.011)     
educ0Prim          0.106**          0.108**     
                   (0.038)          (0.038)     
educ1somehs        0.111***         0.111***    
                   (0.026)          (0.026)     
educ3somecol      -0.049***        -0.048***    
                   (0.014)          (0.014)     
educ4colgrad      -0.432***        -0.427***    
                   (0.014)          (0.014)     
black              0.517***         0.518***    
                   (0.019)          (0.019)     
hispanic           0.193***         0.196***    
                   (0.024)          (0.024)     
other              -0.081**         -0.079**    
                   (0.027)          (0.027)     
medhhinc          -0.088***        -0.085***    
                   (0.016)          (0.016)     
pblack              -0.028           -0.023     
                   (0.016)          (0.016)     
phisp             -0.078***        -0.076***    
                   (0.016)          (0.017)     
Constant          -1.109***        -1.112***    
                   (0.027)          (0.027)     
N                  169,887          169,887     
Log Likelihood   -101,575.400     -101,559.500  
AIC              203,186.800      203,157.100   
BIC              203,367.500      203,347.900   
------------------------------------------------
*p < .05; **p < .01; ***p < .001                

The second method is where we include the sample weights for each respondent in the analysis. Before we do this, we must first inspect these weights. Person weights are numeric values that multiply each person in the data to the population in the target population that each person represents. This is done by calculating the probability to f selection into to the survey for each person, based on their characteristics, and then inverting it, to form an inverse probability weight. If a given person is relatively rare in the sample and represents a large number of people in the population, they will have a larger weight, while the opposite is also true.

Examining the numerical values of the BRFSS weights can show us these expansion factors.

By doing a summary, we see that the minimum weight is 0.22 and the maximum is 32,154.31. This indicates that at least one person in the survey represents over 32,000 people in the US adult population.

summary(merged$mmsawt)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
    1.237   104.459   242.248   528.153   561.161 31222.720 

Indeed, if we sum the weights, we get a value of 8.972627510^{7}, which equals the sum of the adult populations living in metropolitan areas in 2016.

sum(merged$mmsawt)
[1] 89726275

If we include the weights in the model as is, they will inflate the sample size from 169887 to 8.972627510^{7}, which would lead to problems interpreting things, as the standard errors would become very small. Here is what this would look like.

glm1<-glm(obese ~ agec + male + educ + black + hispanic + other,
          data=merged,
          family = binomial)
glmw<-glm(obese ~ agec + male + educ + black + hispanic + other,
          data=merged,
          family = binomial, 
          weights=mmsawt)
non-integer #successes in a binomial glm!glm.fit: algorithm did not convergeglm.fit: fitted probabilities numerically 0 or 1 occurred

In the model where weights are included, as is, the model coefficients become huge and we get numerical warnings about fitted values of 0 and 1 being produced. This is not good.

Instead of using the raw weights, we need to scale the weights in order to use them in models. There are several ways in which this can be done, and Carle (2009) provides a few options for doing this.

The straight-forward way to scale the weights is to divide them by their mean, which would make the average weight 1 instead of 2,184.

mean(merged$mmsawt)
[1] 528.1527
mean(merged$mmsawt/mean(merged$mmsawt))
[1] 1

We can use the scaled weights in the analysis, and they will do the job they are designed to do.

glm_w2<-glm(obese ~ agec + male + educ + black + hispanic + other,
          data=merged,
          family = binomial, 
          weights=mmsawt/mean(mmsawt))
non-integer #successes in a binomial glm!
summary(glm_w2)

Call:
glm(formula = obese ~ agec + male + educ + black + hispanic + 
    other, family = binomial, data = merged, weights = mmsawt/mean(mmsawt))

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-6.9578  -0.6907  -0.3704   0.5706  12.4060  

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  -1.11664    0.01809 -61.737  < 2e-16 ***
agec(30,40]   0.36414    0.01848  19.705  < 2e-16 ***
agec(40,50]   0.60556    0.01848  32.767  < 2e-16 ***
agec(50,60]   0.52713    0.01822  28.929  < 2e-16 ***
agec(60,70]   0.53464    0.01922  27.810  < 2e-16 ***
agec(70,80]   0.07203    0.02134   3.375 0.000739 ***
male          0.02008    0.01074   1.869 0.061629 .  
educ0Prim     0.12094    0.02866   4.219 2.45e-05 ***
educ1somehs   0.05256    0.02119   2.480 0.013120 *  
educ3somecol -0.05098    0.01379  -3.696 0.000219 ***
educ4colgrad -0.50425    0.01483 -34.000  < 2e-16 ***
black         0.45809    0.01558  29.394  < 2e-16 ***
hispanic      0.13244    0.01576   8.404  < 2e-16 ***
other        -0.49209    0.02609 -18.865  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 208748  on 169886  degrees of freedom
Residual deviance: 203394  on 169873  degrees of freedom
AIC: 189606

Number of Fisher Scoring iterations: 4

Which, when compared to the output from the glm1 model, we see substantive differences between them. Many of the coefficients have been changed, in this case they are now considered unbiased once the weights have been applied.

length of NULL cannot be changedlength of NULL cannot be changedlength of NULL cannot be changedlength of NULL cannot be changedlength of NULL cannot be changed

------------------------------------------
                          obese           
                No Weights  Scaled Weights
                 Model 1       Model 2    
------------------------------------------
agec(30,40]      0.456***      0.364***   
                 (0.025)       (0.018)    
agec(40,50]      0.653***      0.606***   
                 (0.024)       (0.018)    
agec(50,60]      0.621***      0.527***   
                 (0.022)       (0.018)    
agec(60,70]      0.590***      0.535***   
                 (0.022)       (0.019)    
agec(70,80]      0.117***      0.072***   
                 (0.023)       (0.021)    
male             0.056***       0.020     
                 (0.011)       (0.011)    
educ0Prim        0.119**       0.121***   
                 (0.038)       (0.029)    
educ1somehs      0.121***       0.053*    
                 (0.026)       (0.021)    
educ3somecol    -0.064***     -0.051***   
                 (0.014)       (0.014)    
educ4colgrad    -0.462***     -0.504***   
                 (0.014)       (0.015)    
black            0.514***      0.458***   
                 (0.018)       (0.016)    
hispanic         0.091***      0.132***   
                 (0.020)       (0.016)    
other           -0.106***     -0.492***   
                 (0.027)       (0.026)    
Constant        -1.165***     -1.117***   
                 (0.022)       (0.018)    
N                169,887       169,887    
Log Likelihood -101,830.900  -94,788.880  
AIC            203,689.700   189,605.800  
------------------------------------------
*p < .05; **p < .01; ***p < .001          

Scaling the weights by the mean weight is a good, simple option, but Snijders and Bosker and Carle all suggest scaling the weights to the stratum sample size. This involves a little more coding, but is easy with dplyr

First, we make an id that is the same as the strata variable. Then we sum the weights within strata and count up the number of people in each strata. Then we merge these back to the data, and standardize the weights.

wts_strat<-merged%>%
  mutate(sampleid=ststr)%>%
  group_by(sampleid)%>%
  summarise(sumwt=sum(mmsawt), nj=n())%>%
  ungroup()
merged<-merge(merged, wts_strat, by.x="ststr", by.y="sampleid", all.x=T)
#In the new data set, multiply the original weight by the fraction of the
#sampling unit total population each person represents
merged$swts<-merged$mmsawt*(merged$nj/merged$sumwt)

Now we have weights that are standardized to the within stratum sample sizes, we can do a quick summary of them and see that they are indeed much smaller than the original weights, and very similar to the mean standardized weights.

summary(merged$swts)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
 0.01599  0.54348  0.82436  1.00000  1.24991 23.68977 
summary(merged$mmsawt/mean(merged$mmsawt))
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
 0.00234  0.19778  0.45867  1.00000  1.06250 59.11684 

So now we have our weights, we can use them in the multilevel model and see if it affects our results.

model2w<-glmer(obese~ agec + male + educ + black + hispanic + other + ppov +  black*pblack + hispanic*phisp + black*medhhinc + hispanic*medhhinc+ (1|mmsa_name)+(1|ststr), 
              family=binomial, 
              data=merged, 
              weights=swts,
              control = glmerControl(optimizer = c("Nelder_Mead","bobyqa"),
                                     optCtrl=list(maxfun=2e9)))
non-integer #successes in a binomial glm!
summary(model2w)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) [
glmerMod]
 Family: binomial  ( logit )
Formula: obese ~ agec + male + educ + black + hispanic + other + ppov +  
    black * pblack + hispanic * phisp + black * medhhinc + hispanic *  
    medhhinc + (1 | mmsa_name) + (1 | ststr)
   Data: merged
Weights: swts
Control: 
glmerControl(optimizer = c("Nelder_Mead", "bobyqa"), optCtrl = list(maxfun = 2e+09))

     AIC      BIC   logLik deviance df.resid 
189787.7 190028.7 -94869.8 189739.7   169863 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.1351 -0.6557 -0.4441  0.9906  7.8720 

Random effects:
 Groups    Name        Variance Std.Dev.
 ststr     (Intercept) 0.02070  0.1439  
 mmsa_name (Intercept) 0.01024  0.1012  
Number of obs: 169887, groups:  ststr, 1248; mmsa_name, 123

Fixed effects:
                  Estimate Std. Error z value Pr(>|z|)    
(Intercept)       -1.08639    0.02751 -39.484  < 2e-16 ***
agec(30,40]        0.42180    0.02044  20.634  < 2e-16 ***
agec(40,50]        0.63479    0.02036  31.176  < 2e-16 ***
agec(50,60]        0.59386    0.01996  29.753  < 2e-16 ***
agec(60,70]        0.56213    0.02095  26.836  < 2e-16 ***
agec(70,80]        0.07917    0.02264   3.496 0.000472 ***
male               0.05159    0.01118   4.615 3.92e-06 ***
educ0Prim          0.07372    0.03148   2.341 0.019207 *  
educ1somehs        0.10270    0.02158   4.759 1.95e-06 ***
educ3somecol      -0.03807    0.01399  -2.722 0.006495 ** 
educ4colgrad      -0.46244    0.01575 -29.362  < 2e-16 ***
black              0.39042    0.03406  11.461  < 2e-16 ***
hispanic           0.06892    0.03848   1.791 0.073296 .  
other             -0.22961    0.02818  -8.150 3.65e-16 ***
ppov              -0.01912    0.05600  -0.342 0.732722    
pblack            -0.01748    0.01968  -0.888 0.374475    
phisp             -0.05485    0.02917  -1.880 0.060070 .  
medhhinc          -0.09722    0.02710  -3.587 0.000334 ***
black:pblack       0.10874    0.02325   4.676 2.92e-06 ***
hispanic:phisp     0.07541    0.02611   2.889 0.003869 ** 
black:medhhinc    -0.02107    0.02507  -0.841 0.400584    
hispanic:medhhinc  0.09313    0.02802   3.324 0.000887 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation matrix not shown by default, as p = 22 > 12.
Use print(x, correlation=TRUE)  or
    vcov(x)        if you need it

Indeed, now our cross-level interaction term between the individual level black dummy variable and the MSA level pblack variable is now significant in the model. This suggests that Non-Hispanic black people living in MSAs that have higher proportions of Non-Hispanic black population have higher odds of being obese compared to those in MSAs with an average proportion of Non-Hispanic black population. There are still no interaction effects for the MSA level income variable.

This also suggests that the weights are likely controlling for some type of non-response bias or non-representativeness in the survey.

Small area estimation

This example will illustrate a way to combine individual survey data with aggregate data on MSAs to produce a MSA level estimate of basically any health indicator measured using the BRFSS. The framework I use below takes observed individual level survey responses from the BRFSS and merges these to MSA level variables from the ACS. This allows me to estimate the overall regression model for MSA-level prevalence, controlling for MSA level variables. Then, I can use this equation for prediction for MSAs where I have not observed survey respondents, but for which I have observed the MSA level characteristics.

This corresponds to a multilevel logistic model with a higher level variables as predictors and can be written: \[ln \left( \frac {\pi_{ij}}{1-\pi{ij}} \right ) = \beta_{0j} +\sum {\beta_k x_{ik}}+\sum {\gamma_j z_j} \]

library(lme4)
library(lmerTest)

Attaching package: <U+393C><U+3E31>lmerTest<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:lme4<U+393C><U+3E32>:

    lmer

The following object is masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:

    step
fit.mix.bin<-glmer(obese ~ agec + male + black + hispanic + other +  (1|mmsa), 
              family=binomial, 
              data=merged, 
              weights=mmsawt/mean(mmsawt),
              control = glmerControl(optimizer = c("Nelder_Mead","bobyqa"),
                                     optCtrl=list(maxfun=2e9)))
non-integer #successes in a binomial glm!
summary(fit.mix.bin)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) [
glmerMod]
 Family: binomial  ( logit )
Formula: obese ~ agec + male + black + hispanic + other + (1 | mmsa)
   Data: merged
Weights: mmsawt/mean(mmsawt)
Control: 
glmerControl(optimizer = c("Nelder_Mead", "bobyqa"), optCtrl = list(maxfun = 2e+09))

     AIC      BIC   logLik deviance df.resid 
180331.5 180442.0 -90154.8 180309.5   169876 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-5.2424 -0.5463 -0.3037  0.5321 13.2273 

Random effects:
 Groups Name        Variance Std.Dev.
 mmsa   (Intercept) 0.02119  0.1456  
Number of obs: 169887, groups:  mmsa, 123

Fixed effects:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept) -1.26469    0.02175 -58.148  < 2e-16 ***
agec(30,40]  0.33610    0.01880  17.878  < 2e-16 ***
agec(40,50]  0.59211    0.01891  31.305  < 2e-16 ***
agec(50,60]  0.54029    0.01890  28.593  < 2e-16 ***
agec(60,70]  0.56751    0.02047  27.727  < 2e-16 ***
agec(70,80]  0.16293    0.02315   7.038 1.95e-12 ***
male         0.01646    0.01140   1.444    0.149    
black        0.52829    0.01663  31.769  < 2e-16 ***
hispanic     0.33010    0.01732  19.058  < 2e-16 ***
other       -0.55336    0.02788 -19.849  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr) a(30,4 a(40,5 a(50,6 a(60,7 a(70,8 male   black  hispnc
agec(30,40] -0.461                                                        
agec(40,50] -0.463  0.534                                                 
agec(50,60] -0.473  0.534  0.534                                          
agec(60,70] -0.448  0.493  0.494  0.500                                   
agec(70,80] -0.411  0.436  0.438  0.444  0.415                            
male        -0.281  0.005  0.006  0.004  0.008  0.037                     
black       -0.162  0.007  0.020  0.037  0.061  0.068  0.025              
hispanic    -0.174  0.000  0.035  0.077  0.109  0.116 -0.004  0.215       
other       -0.107  0.006  0.016  0.045  0.056  0.067  0.005  0.126  0.154
#odds ratios
exp(fixef(fit.mix.bin)[-1])
agec(30,40] agec(40,50] agec(50,60] agec(60,70] agec(70,80]        male       black 
  1.3994751   1.8078076   1.7165037   1.7638778   1.1769486   1.0165935   1.6960381 
   hispanic       other 
  1.3911079   0.5750138 
exp(confint(fit.mix.bin, method="Wald"))
                2.5 %    97.5 %
.sig01             NA        NA
(Intercept) 0.2705446 0.2946222
agec(30,40] 1.3488476 1.4520029
agec(40,50] 1.7420162 1.8760838
agec(50,60] 1.6540949 1.7812671
agec(60,70] 1.6945177 1.8360769
agec(70,80] 1.1247424 1.2315779
male        0.9941402 1.0395539
black       1.6416499 1.7522281
hispanic    1.3446748 1.4391444
other       0.5444374 0.6073075

Predicted values from the model

These predicted values actually allow us to set up a counterfactual type of analysis. We can effectively change the houseing age variable to be older or younger than the real value to see how the outcome changes.

#get newdata using real values
dat1<-expand.grid(male=mean(merged$male), agec=levels(merged$agec), black=c(0,1), hispanic=c(0,1), other=c(0,1) , mmsa= levels(as.factor(merged$mmsa)))
#get newdata using artificially generated housing age values  
#predictions
dat1$pred<-predict(fit.mix.bin, dat1, type="response", re.form=~(1 | mmsa))

Post-stratification

library(ipumsr)
ddi<-read_ipums_ddi("~/Google Drive/classes/dem7283/class_19_7283/data/usa_00077.xml")
census<-read_ipums_micro(ddi)
Use of data from IPUMS-USA is subject to conditions including that users should
cite the data appropriately. Use command `ipums_conditions()` for more details.
names(census)<-tolower(names(census))
census<-zap_labels(census)
census<-census%>%
  filter(age>20)
census$hisp <- recode(census$hispan, recodes = "9=NA; 1:4='Hispanic'; 0='NotHispanic'")
NAs introduced by coercion
census$race_rec <- recode(census$race, recodes = "1='White'; 2='Black'; 3='Other/Multiple'; 4:6='Asian'; 7:9='Other/Multiple'", as.factor = T)
census$race_eth <- interaction(census$hisp, census$race_rec, sep = " ")
census$race_eth <- as.factor(ifelse(substr(as.character(census$race_eth),1,8) == "Hispanic", "Hispanic", as.character(census$race_eth)))
census$race_eth <- relevel(census$race_eth, ref = "NotHispanic White")
census$black<-ifelse(census$race_eth=="NotHispanic Black",1,0)
census$other<-ifelse(census$race_eth%in%c("NotHispanic Asian", "NotHispanic Other/Multiple") ,1,0)
census$hispanic<-ifelse(census$race_eth=="Hispanic",1,0)
#sex (IV)
census$male <- ifelse(census$sex == 1,1,0)
census$pwt <- census$perwt
census$agec<-cut(census$age, breaks = seq(20, 80, 10))
library(survey)
Loading required package: grid
Loading required package: survival

Attaching package: <U+393C><U+3E31>survey<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:graphics<U+393C><U+3E32>:

    dotchart
des<-svydesign(ids=~cluster, strata = ~strata, weights = ~pwt, data=census[census$statefip=="48",])

Now I make the populations by the same charactersistics that went into the GLMM

msatotals<-svyby(~perwt, ~met2013+agec+male+black+hispanic+other, des, FUN=svytotal, na.rm=T)
msatotals$mmsa<-msatotals$met2013
head(msatotals)

The perwt column is the estimate of the number of people in each place by the characteristics provided.

Now we use these data to get fitted values for each row:

library(merTools)
package <U+393C><U+3E31>merTools<U+393C><U+3E32> was built under R version 3.5.3Loading required package: arm
Loading required package: MASS

Attaching package: <U+393C><U+3E31>MASS<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:dplyr<U+393C><U+3E32>:

    select


arm (Version 1.10-1, built: 2018-4-12)

Working directory is C:/Users/ozd504/Google Drive/classes/dem7283/class_19_7283/code


Attaching package: <U+393C><U+3E31>arm<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:car<U+393C><U+3E32>:

    logit
msatotals$p<-predict(fit.mix.bin, newdata=msatotals,allow.new.levels=T, type="response"  )
est_cis<-msa_totals_variances<-predictInterval(fit.mix.bin, newdata=msatotals, level=.5, n.sims=500, type="probability")
     The following levels of mmsa from newdata 
 -- 11100, 13140, 15180, 19100, 29700, 31180, 32580, 33260, 36220, 41660, 46340, 47380 -- are not in the model data. 
     Currently, predictions for these values are based only on the 
 fixed coefficients and the observation-level error.
msatotals$est_lci<-est_cis$lwr
msatotals$est_uc<-est_cis$upr
msatotals$est_pt<-est_cis$fit
head(msatotals)

Now, to do post-stratification estimates, we need to calculate:

\[\pi^{pred}_{msa_j} = \frac{\sum_j N_l \theta_l}{\sum_l N_l}\] Where \(\theta\) is the probability of being obese in each of the \(l\) strata (groups of people), which we have as the p estimate from above. The \(N_l\) estiamtes are the estimated counts of the population by the age, sex, and race characteristics noted above. Now we make the estimates

msatotals$est<-msatotals$p*msatotals$perwt
msarates<-msatotals%>%
  group_by(mmsa)%>%
  summarise(ob_rate_ps = sum(est)/sum(perwt))
head(msarates)
#San Antonio
msarates[msarates$mmsa=="41700",]

Not bad, based on other estimates

Here is the rest of Texas

msarates$mmsa_c<-as.character(msarates$mmsa)
ob_msa<-geo_join(msa_ec, msarates, by_sp="GEOID", by_df="mmsa_c", how="inner")
ob_msa%>%
  ggplot()+geom_sf(aes(fill=ob_rate_ps))

LS0tDQp0aXRsZTogIkRFTSA3MjgzIEV4YW1wbGUgMTAgLSBTdXJ2ZXkgSW5mb3JtYXRpb24gYW5kIFNtYWxsIEFyZWEgRXN0aW1hdGlvbiINCmF1dGhvcjogIkNvcmV5IFNwYXJrcywgUGhEIg0KZGF0ZTogIkFwcmlsIDgsIDIwMTkiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rDQotLS0gDQogICANCiMjQWRkaXRpb25hbCB0b3BpY3MgaW4gTXVsdGlsZXZlbCBNb2RlbGluZw0KDQpJbmNsdWRpbmcgc3VydmV5IGRlc2lnbiBpbmZvcm1hdGlvbiBpbiBtdWx0aWxldmVsIG1vZGVscyANCg0KV2hlbiBhbmFseXppbmcgZGF0YSBmcm9tIHN1cnZleXMsIHdlIG11c3QgcGF5IGF0dGVudGlvbiB0byB0aGUgZGVzaWduIG9mIHRoZSBzdXJ2ZXkgd2hlbiB3ZSBjb25kdWN0IG91ciBhbmFseXNpcy4gVGhlIHN1cnZleSBkYXRhIHNvdXJjZXMgd2lsbCBwcm92aWRlIGluZm9ybWF0aW9uIGluIHRoZWlyIGNvZGUgYm9va3Mgb3IgdXNlciBndWlkZXMgdGhhdCBpZGVudGlmeSB0aGUgc3VydmV5IGRlc2lnbiB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc291cmNlLCBhcyB3ZWxsIGFzIHRoZSBwZXJzb24td2VpZ2h0aW5nIGZhY3RvcnMgYXNzb2NpYXRlZCB3aXRoIGVhY2ggcmVzcG9uZGVudC4gDQoNClRoZXNlIHBpZWNlcyBvZiBpbmZvcm1hdGlvbiBhcmUgaW50ZWdyYWwgd2hlbiB3ZSBkbyBhbnkgYW5hbHlzaXMgb2Ygc3VydmV5IGRhdGEsIGJlY2F1c2UgdGhlIGRlc2lnbiB2YXJpYWJsZXMgKHN1cnZleSBzdHJhdHVtIGFuZCBwcmltYXJ5IHNhbXBsaW5nIHVuaXRzIGlkZW50aWZpZXJzKSBhbGxvdyB1cyB0byBjb3JyZWN0bHkgY2FsY3VsYXRlIHN0YW5kYXJkIGVycm9ycyBmb3IgbW9kZWwgcGFyYW1ldGVycyBpbiBtb2RlbHMgdGhhdCB3ZSBjb25zdHJ1Y3QuIExpa2V3aXNlLCB0aGUgcGVyc29uIHdlaWdodHMgaW4gdGhlIGRhdGEgd2lsbCBjb3JyZWN0IGZvciBkaWZmZXJlbnRpYWwgbm9uLXJlc3BvbnNlIHRvIHRoZSBzdXJ2ZXksIGFueSBvdmVyc2FtcGxpbmcgdGhhdCBleGlzdHMgaW4gdGhlIHN1cnZleSBkZXNpZ24gYW5kIGFueSBmYWN0b3JzIHRvIG1ha2UgdGhlIHN1cnZleSBzYW1wbGUgcmVwcmVzZW50YXRpdmUgb2YgdGhlIHBvcHVsYXRpb24gaXQgd2FzIGRlc2lnbmVkIHRvIHJlcHJlc2VudC4gDQoNCk11bHRpbGV2ZWwgbW9kZWxzIGFyZSBuYXR1cmFsIG1vZGVscyB0byB1c2Ugd2hlbiBhbmFseXppbmcgc3VydmV5IGRhdGEsIGJlY2F1c2UgdGhleSBjYW4gYXV0b21hdGljYWxseSBtaW1pYyB0aGUgZGVzaWduIG9mIHRoZSBzdXJ2ZXkgdXNpbmcgdGhlIG5lc3RlZCBzcGVjaWZpY2F0aW9ucyB3ZSBoYXZlIGRpc2N1c3NlZCBzbyBmYXIuIEluZGVlZCwgU25pamRlcnMgYW5kIEJvc2tlciAoMjAxMikgaW4gdGhlaXIgdGV4dCBvbiBtdWx0aWxldmVsIG1vZGVscyBkZXZvdGUgY2hhcHRlciAxNCBvZiB0aGVpciBib29rIHRvIHRoZSBkaXNjdXNzaW9uIG9mIGhvdyB0byB1c2UgbXVsdGlsZXZlbCBtb2RlbHMgdG8gYW5hbHl6ZSBjb21wbGV4IHN1cnZleSBkZXNpZ24gZGF0YS4gDQoNClRoZXkgb2ZmZXIgc3VnZ2VzdGlvbnMgb2YgdGhpbmdzIHRvIGRvIHdoZW4gdXNpbmcgbXVsdGlsZXZlbCBtb2RlbHMgb24gY29tcGxleCBzdXJ2ZXkgZGVzaWduIGRhdGEgKHN1Y2ggYXMgdGhlIEJSRlNTKS4gV2Ugd2lsbCBkaXNjdXNzIGFuZCBpbGx1c3RyYXRlIHR3byBvZiB0aGVzZSBzdWdnZXN0aW9ucyBiZWxvdy4gVGhlc2UgdHdvIG1ldGhvZHMgYXJlIHdoZXJlIHdlIA0KDQogIDEuIEluY2x1ZGluZyBzdXJ2ZXkgZGVzaWduIHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwNCiAgMi4gSW5jbHVkaW5nIHN1cnZleSB3ZWlnaHRzIGluIHRoZSBtb2RlbA0KDQpNZXRob2QgMSBlcXVhdGVzIHRvIGNvbnRyb2xsaW5nIGZvciBub24tcmFuZG9tbmVzcyBvZiBvYnNlcnZhdGlvbnMgd2l0aGluIHNhbXBsaW5nIHVuaXRzIGJ5IGluY2x1ZGluZyB0aGUgc2FtcGxlIGRlc2lnbiB2YXJpYWJsZXMgKHN0cmF0dW0gYW5kIHByaW1hcnkgc2FtcGxpbmcgdW5pdHMpIGFzIHJhbmRvbSBlZmZlY3RzIGluIHRoZSBtb2RlbC4gVGhpcyBjb250cm9scyBmb3IgdGhlIGhvbW9nZW5laXR5IHdpdGhpbiBhbmQgYmV0d2VlbiB0aGVzZSBzdXJ2ZXkgdW5pdHMuIE1ldGhvZCAyIHVzZXMgdGhlIHByb3ZpZGVkIGNhc2Ugd2VpZ2h0cyBpbiB0aGUgZGF0YSBhbmQgaW5jbHVkZXMgdGhlbSBhcyB3ZWlnaHRzIGluIHRoZSBtb2RlbCB0byBjb3JyZWN0IGZvciB0aGUgZGVzaWduIGZhY3RvcnMgdGhhdCB0aGUgd2VpZ2h0cyBoYXZlIGJlZW4gdXNlZCB0byBjb3JyZWN0IGZvciAocmVwcmVzZW50YXRpdmVuZXNzLCBkaWZmZXJlbnRpYWwgbm9uIHJlc3BvbnNlLCBldGMuKS4gDQoNCiMjSW5jbHVkaW5nIHN1cnZleSBkZXNpZ24gdmFyaWFibGVzIGluIHRoZSBtdWx0aWxldmVsIG1vZGVsICAgDQoNCk5vdyB3ZSB0dXJuIHRvIHRoZSBwcmFjdGljYWwgYXNwZWN0cyBvZiBpbmNsdWRpbmcgc3VydmV5IGRlc2lnbiBpbmZvcm1hdGlvbiBpbiB0aGUgbXVsdGlsZXZlbCBtb2RlbC4gTWV0aG9kIDEgaXMgc3RyYWlnaHRmb3J3YXJkLCBhcyBsb25nIGFzIHRoZSBkYXRhIHdlIGhhdmUgaW5jbHVkZXMgdGhlIHNhbXBsaW5nIGRlc2lnbiB2YXJpYWJsZXMsIHdoaWNoIG1vc3Qgc3VydmV5IGRhdGFzZXRzIGRvLiBJbiB0aGUgQlJGU1MsIHRoZXJlIGlzIGEgdmFyaWFibGUgYHN0c3RyYCB0aGF0IGlzIHRoZSBzYW1wbGluZyBzdHJhdHVtLiBJZiB3ZSB3ZXJlIHRvIGluY2x1ZGUgdGhpcywgYXMgU25pamRlcnMgYW5kIEJvc2tlciBzdWdnZXN0LCB0aGVuIHdlIHdpbGwgaW5jbHVkZSBhIHJhbmRvbSBlZmZlY3QgaW4gdGhlIG1vZGVsIGZvciB0aGUgc3VydmV5IHN0cmF0YS4gSW4gdGhpcyBjYXNlLCB3ZSBub3cgaGF2ZSB0d28gcmFuZG9tIGVmZmVjdHMsIHRoZSBNU0EgbGV2ZWwgYW5kIHRoZSBzdHJhdHVtIGxldmVsLiANCg0KVG8gbWVhc3VyZSBtYWNybyBsZXZlbCB2YXJpYWJsZXMsIEkgd2lsbCBpbmNsdWRlIHNvbWUgQ2Vuc3VzIHZhcmlhYmxlcyBmcm9tIHRoZSBBQ1MgMjAxMSA1IFllYXIgZXN0aW1hdGVzIGxvYWQgaW4gQUNTIGRhdGEgZnJvbSAqKl90aWR5Y2Vuc3VzXyoqLg0KVGhlIGZpcnN0IHNldCBvZiB2YXJpYWJsZXMgaW5jbHVkZXMgaW5mb3JtYXRpb24gb24gdGhlIGVjb25vbWljIGNvbmRpdGlvbnMgb2YgdGhlIGNvdW50eSwgc3BlY2lmaWNhbGx5IHBvdmVydHkgYW5kIHVuZW1wbG95bWVudC4NCmBgYHtyfQ0KbGlicmFyeSh0aWR5Y2Vuc3VzKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCnVzYWNzPC1nZXRfYWNzKGdlb2dyYXBoeSA9ICJtZXRyb3BvbGl0YW4gc3RhdGlzdGljYWwgYXJlYS9taWNyb3BvbGl0YW4gc3RhdGlzdGljYWwgYXJlYSIsIHllYXIgPSAyMDExLA0KICAgICAgICAgICAgICAgIHZhcmlhYmxlcz1jKCAiRFAwNV8wMDAxRSIsICJEUDAzXzAwMDlQIiwgIkRQMDNfMDA2MkUiLCAiRFAwM18wMTE5UEUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRFAwNV8wMDAxRSIsIkRQMDJfMDAwOVBFIiwiRFAwMl8wMDA4UEUiLCAiRFAwMl8wMDQwRSIsIkRQMDJfMDAzOEUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRFAwMl8wMDY2UEUiLCJEUDAyXzAwNjdQRSIsIkRQMDJfMDA4MFBFIiwiRFAwMl8wMDkyUEUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRFAwM18wMDA1UEUiLCJEUDAzXzAwMjhQRSIsIkRQMDNfMDA2MkUiLCJEUDAzXzAwOTlQRSIsIkRQMDNfMDEwMVBFIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRQMDNfMDExOVBFIiwiRFAwNF8wMDQ2UEUiLCJEUDA1XzAwNzJQRSIsIkRQMDVfMDA3M1BFIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRQMDVfMDA2NlBFIiwiRFAwNV8wMDMzIiwiRFAwNV8wMDMyIiwgIkRQMDVfMDA3MlBFIiwgIkRQMDJfMDExM1BFIiwgICJEUDA0XzAwMDNQRSIpICwNCiAgICAgICAgICAgICAgICBzdW1tYXJ5X3ZhciA9ICJCMDEwMDFfMDAxIiwNCiAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IEYsIG91dHB1dCA9ICJ3aWRlIikNCg0KdXNhY3M8LXVzYWNzJT4lDQogIG11dGF0ZSh0b3Rwb3A9IERQMDVfMDAwMUUsIGZlcnRyYXRlID0gRFAwMl8wMDQwRSxwd2hpdGU9RFAwNV8wMDcyUEUvMTAwLCBud2hpdGU9RFAwNV8wMDMyRSxuYmxhY2s9RFAwNV8wMDMzRSwNCiAgICAgICAgIHBibGFjaz1EUDA1XzAwNzNQRS8xMDAgLCBwaGlzcD1EUDA1XzAwNjZQRS8xMDAsIHBmZW1oaD1EUDAyXzAwMDhQRS8xMDAsDQogICAgICAgICBwaHNvcm1vcmU9RFAwMl8wMDY2UEUvMTAwLHB1bmVtcD1EUDAzXzAwMDlQRS8xMDAsIG1lZGhoaW5jPURQMDNfMDA2MkUsDQogICAgICAgICBwcG92PURQMDNfMDExOVBFLzEwMCwgcGZvcm49RFAwMl8wMDkyUEUvMTAwLHBsZXA9RFAwMl8wMTEzUEUvMTAwLCAgcHZhY2FudD1EUDA0XzAwMDNQRS8xMDApJT4lDQogIHNlbGVjdChHRU9JRCxOQU1FLCB0b3Rwb3AsIHB3aGl0ZSwgcGJsYWNrLCBwaGlzcCwgcGZlbWhoLCBwaHNvcm1vcmUsIHB1bmVtcCwgbWVkaGhpbmMsIHBwb3YsIHBmb3JuLHBsZXAsIHB2YWNhbnQpDQoNCg0KaGVhZCh1c2FjcykNCmBgYA0KDQoNCiMjI0NsZWFuIGFuZCBzdGFuZGFyZGl6ZSBjb250ZXh0dWFsIGRhdGENCmBgYHtyfQ0KbXlzY2FsZTwtZnVuY3Rpb24oeCl7YXMubnVtZXJpYyhzY2FsZSh4KSl9DQp1c2FjczwtdXNhY3MgJT4lDQogIG11dGF0ZV9hdChjKCJwcG92IiwicHVuZW1wIiwgInBibGFjayIsInBoaXNwIiwgInBmZW1oaCIsICJwaHNvcm1vcmUiLCAibWVkaGhpbmMiLCAicHZhY2FudCIpLG15c2NhbGUpDQoNCm1lcmdlZDwtdXNhY3MlPiVmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpDQpoZWFkKG1lcmdlZCkNCmBgYA0KDQoNCkxldCdzIHNlZSB0aGUgZ2VvZ3JhcGhpYyB2YXJpYXRpb24gaW4gdGhlc2UgZWNvbm9taWMgaW5kaWNhdG9yczoNCldlIGNhbiBhbHNvIG1ha2UgYSBxdWljayBtYXAgb2YgdGhlIGluZGljYXRvcnMgYnkgbWVyZ2luZyB0aGVzZSBkYXRhIHdpdGggdGhlIGFwcHJvcHJpYXRlIGxldmVsIG9mIGNlbnN1cyBnZW9ncmFwaHksIGluIHRoaXMgY2FzZSwgTVNBcyBhcmUgdGhlIHNhbWUgYXMgQ29yZSBCYXNlZCBTdGF0aXN0aWNhbCBBcmVhcyAoQ0JTQXMpIGluIHRoZSBDZW5zdXMgZ2VvZ3JhcGhpYyBoaWVyYXJjaHkuIA0KDQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQoNCmxpYnJhcnkodGlncmlzKQ0KbGlicmFyeShzZikNCm9wdGlvbnModGlncmlzX2NsYXNzPSJzZiIpDQptc2E8LWNvcmVfYmFzZWRfc3RhdGlzdGljYWxfYXJlYXMoY2I9VCkNCm1zYTwtbXNhJT4lDQogIHN0X3RyYW5zZm9ybShjcnMgPSAxMDIwMDkpDQpzdHM8LXN0YXRlcyhjYiA9IFQpDQpzdHM8LXN0cyU+JQ0KICBzdF90cmFuc2Zvcm0oY3JzID0gMTAyMDA5KSU+JQ0KICBmaWx0ZXIoIVNUQVRFRlAlaW4lYyg2MCwgNjYsIDY5LCA3MiwgNzgpKQ0KbXNhX2VjPC1nZW9fam9pbihtc2EsIHVzYWNzLCAiQ0JTQUZQIiwgIkdFT0lEIiwgaG93PSJpbm5lciIpDQpgYGANCg0KDQojIyNCUkZTUyBEQVRBDQpgYGB7cn0NCmxvYWQoIn4vR29vZ2xlIERyaXZlL2NsYXNzZXMvZGVtNzI4My9jbGFzc18xOV83MjgzL2RhdGEvYnJmc3MxNl9tbXNhLlJkYXRhIikNCnNldC5zZWVkKDEyMzQ1KQ0KI3NhbXBzPC1zYW1wbGUoMTpucm93KGJyZnNzMTZtKSwgc2l6ZSA9IDQwMDAwLCByZXBsYWNlPUYpDQojYnJmc3MxNm08LWJyZnNzMTZtW3NhbXBzLF0NCiNUaGUgbmFtZXMgaW4gdGhlIGRhdGEgYXJlIHZlcnkgdWdseSwgc28gSSBtYWtlIHRoZW0gbGVzcyB1Z2x5DQpuYW1zPC1uYW1lcyhicmZzczE2bSkNCiN3ZSBzZWUgc29tZSBuYW1lcyBhcmUgbG93ZXIgY2FzZSwgc29tZSBhcmUgdXBwZXIgYW5kIHNvbWUgaGF2ZSBhIGxpdHRsZSBfIGluIHRoZSBmaXJzdCBwb3NpdGlvbi4gVGhpcyBpcyBhIG5pZ2h0bWFyZS4NCm5ld25hbWVzPC1nc3ViKHBhdHRlcm4gPSAiXyIscmVwbGFjZW1lbnQgPSAgIiIseCA9ICBuYW1zKQ0KbmFtZXMoYnJmc3MxNm0pPC10b2xvd2VyKG5ld25hbWVzKQ0KDQpgYGANCg0KIyMjUmVjb2RlIHZhcmlhYmxlcw0KYGBge3IgQlJGU1MgZGF0YX0NCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShkcGx5cikNCg0KIyMjQlJGU1MgREFUQQ0KDQojbmljZSBNU0EgbmFtZQ0KYnJmc3MxNm0kbW1zYV9uYW1lPC1zdWJzdHIoYnJmc3MxNm0kbW1zYW5hbWUsIDEsbmNoYXIoYnJmc3MxNm0kbW1zYW5hbWUpLTMxKQ0KDQojc2V4DQpicmZzczE2bSRtYWxlPC1pZmVsc2UoYnJmc3MxNm0kc2V4PT0xLCAxLCAwKQ0KDQojQk1JDQpicmZzczE2bSRibWk8LWlmZWxzZShpcy5uYShicmZzczE2bSRibWk1KT09VCwgTkEsIGJyZnNzMTZtJGJtaTUvMTAwKQ0KDQojSGVhbHRoeSBkYXlzDQpicmZzczE2bSRoZWFsdGhkYXlzPC1SZWNvZGUoYnJmc3MxNm0kcGh5c2hsdGgsIHJlY29kZXMgPSAiODg9MDsgNzc9TkE7IDk5PU5BIikNCg0KI0hlYWx0aHkgbWVudGFsIGhlYWx0aCBkYXlzDQpicmZzczE2bSRoZWFsdGhtZGF5czwtUmVjb2RlKGJyZnNzMTZtJG1lbnRobHRoLCByZWNvZGVzID0gIjg4PTA7IDc3PU5BOyA5OT1OQSIpDQoNCmJyZnNzMTZtJGJhZGhlYWx0aDwtUmVjb2RlKGJyZnNzMTZtJGdlbmhsdGgsIHJlY29kZXM9IjQ6NT0xOyAxOjM9MDsgZWxzZT1OQSIpDQojcmFjZS9ldGhuaWNpdHkNCmJyZnNzMTZtJGJsYWNrPC1SZWNvZGUoYnJmc3MxNm0kcmFjZWdyMywgcmVjb2Rlcz0iMj0xOyA5PU5BOyBlbHNlPTAiKQ0KYnJmc3MxNm0kd2hpdGU8LVJlY29kZShicmZzczE2bSRyYWNlZ3IzLCByZWNvZGVzPSIxPTE7IDk9TkE7IGVsc2U9MCIpDQpicmZzczE2bSRvdGhlcjwtUmVjb2RlKGJyZnNzMTZtJHJhY2VncjMsIHJlY29kZXM9IjM6ND0xOyA5PU5BOyBlbHNlPTAiKQ0KYnJmc3MxNm0kaGlzcGFuaWM8LVJlY29kZShicmZzczE2bSRyYWNlZ3IzLCByZWNvZGVzPSI1PTE7IDk9TkE7IGVsc2U9MCIpDQoNCmJyZnNzMTZtJHJhY2VfZXRoPC1SZWNvZGUoYnJmc3MxNm0kcmFjZWdyMywgDQpyZWNvZGVzPSIxPSduaHdoaXRlJzsgMj0nbmggYmxhY2snOyAzPSduaCBvdGhlcic7ND0nbmggbXVsdGlyYWNlJzsgNT0naGlzcGFuaWMnOyBlbHNlPU5BIiwNCmFzLmZhY3RvciA9IFQpDQpicmZzczE2bSRyYWNlX2V0aDwtcmVsZXZlbChicmZzczE2bSRyYWNlX2V0aCwgcmVmID0gIm5od2hpdGUiKQ0KDQojaW5zdXJhbmNlDQpicmZzczE2bSRpbnM8LVJlY29kZShicmZzczE2bSRobHRocGxuMSwgcmVjb2RlcyA9Ijc6OT1OQTsgMT0xOzI9MCIpDQoNCiNpbmNvbWUgZ3JvdXBpbmcNCmJyZnNzMTZtJGluYzwtUmVjb2RlKGJyZnNzMTZtJGluY29tZywgcmVjb2RlcyA9ICI5PSBOQTsxPScxX2x0MTVrJzsgMj0nMl8xNS0yNWsnOzM9JzNfMjUtMzVrJzs0PSc0XzM1LTUwayc7NT0nNV81MGtwbHVzJyIsIGFzLmZhY3RvciA9IFQpDQpicmZzczE2bSRpbmM8LWFzLm9yZGVyZWQoYnJmc3MxNm0kaW5jKQ0KI2VkdWNhdGlvbiBsZXZlbA0KYnJmc3MxNm0kZWR1YzwtUmVjb2RlKGJyZnNzMTZtJGVkdWNhLA0KcmVjb2Rlcz0iMToyPScwUHJpbSc7IDM9JzFzb21laHMnOyA0PScyaHNncmFkJzsgNT0nM3NvbWVjb2wnOyA2PSc0Y29sZ3JhZCc7OT1OQSIsDQphcy5mYWN0b3I9VCkNCmJyZnNzMTZtJGVkdWM8LXJlbGV2ZWwoYnJmc3MxNm0kZWR1YywgcmVmPScyaHNncmFkJykNCg0KI2VtcGxveW1lbnQNCmJyZnNzMTZtJGVtcGxveTwtUmVjb2RlKGJyZnNzMTZtJGVtcGxveTEsDQpyZWNvZGVzPSIxOjI9J2VtcGxveWxveWVkJzsgMjo2PSduaWxmJzsgNz0ncmV0aXJlZCc7IDg9J3VuYWJsZSc7IGVsc2U9TkEiLA0KYXMuZmFjdG9yPVQpDQpicmZzczE2bSRlbXBsb3k8LXJlbGV2ZWwoYnJmc3MxNm0kZW1wbG95LCByZWY9J2VtcGxveWxveWVkJykNCg0KI21hcml0YWwgc3RhdHVzDQpicmZzczE2bSRtYXJzdDwtUmVjb2RlKGJyZnNzMTZtJG1hcml0YWwsDQpyZWNvZGVzPSIxPSdtYXJyaWVkJzsgMj0nZGl2b3JjZWQnOyAzPSd3aWRvd2VkJzsgND0nc2VwYXJhdGVkJzsgNT0nbm0nOzY9J2NvaGFiJzsgZWxzZT1OQSIsDQphcy5mYWN0b3I9VCkNCmJyZnNzMTZtJG1hcnN0PC1yZWxldmVsKGJyZnNzMTZtJG1hcnN0LCByZWY9J21hcnJpZWQnKQ0KDQojQWdlIGN1dCBpbnRvIGludGVydmFscw0KYnJmc3MxNm0kYWdlYzwtY3V0KGJyZnNzMTZtJGFnZTgwLCBicmVha3M9c2VxKDIwLDgwLDEwKSkNCg0KI0JNSSwgaW4gdGhlIGJyZnNzMTZtYSB0aGUgYm1pIHZhcmlhYmxlIGhhcyAyIGltcGxpZWQgZGVjaW1hbCBwbGFjZXMsDQojc28gd2UgbXVzdCBkaXZpZGUgYnkgMTAwIHRvIGdldCByZWFsIGJtaSdzDQoNCmJyZnNzMTZtJGJtaTwtYnJmc3MxNm0kYm1pNS8xMDANCg0KI3Ntb2tpbmcgY3VycmVudGx5DQpicmZzczE2bSRzbW9rZTwtUmVjb2RlKGJyZnNzMTZtJHNtb2tlcjMsIA0KcmVjb2Rlcz0iMToyPTE7IDM6ND0wOyBlbHNlPU5BIikNCiNicmZzczE2bSRzbW9rZTwtcmVsZXZlbChicmZzczE2bSRzbW9rZSwgcmVmID0gIk5ldmVyU21va2VkIikNCg0KYnJmc3MxNm0kb2Jlc2U8LWlmZWxzZShpcy5uYShicmZzczE2bSRibWkpPT1ULCBOQSwgDQogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShicmZzczE2bSRibWk+MzAsMSwwKSkNCg0KYGBgDQoNCg0KVGhlIGBtZXJnZWAgY29tbWFuZCBpbiBSIGhhcyBzZXZlcmFsIGFyZ3VtZW50cy4gYHhgIGFuZCBgeWAgYXJlIHRoZSBuYW1lcyBvZiB0aGUgaW5kaXZpZHVhbCBhbmQgaGlnaGVyIGxldmVsIGRhdGEgZnJhbWVzLCBgYnkueGAgYW5kIGBieS55YCBhcmUgdGhlIG5hbWVzIG9mIHRoZSBrZXkgZmllbGQgKGdlb2dyYXBoaWMgaWRlbnRpZmllciBpbiB0aGlzIGNhc2UpIGluIGJvdGggdGFibGVzLCB3aGljaCBkb24ndCBoYXZlIHRvIGhhdmUgdGhlIHNhbWUgbmFtZS4gVGhlIGBhbGwueD1GYCBjb21tYW5kIHRlbGxzIFIgdG8gam9pbiBvbmx5IHRoZSBvYnNlcnZhdGlvbnMgZnJvbSB0aGUgQlJGU1MgdGhhdCBoYXZlIGEgbWF0Y2hpbmcgTVNBIGluIHRoZSBNU0EgdGFibGUuDQoNCmBgYHtyfQ0KDQptZXJnZWQ8LW1lcmdlKHg9YnJmc3MxNm0sDQogICAgICAgICAgICAgIHk9dXNhY3MsDQogICAgICAgICAgICAgIGJ5Lng9Im1tc2EiLA0KICAgICAgICAgICAgICBieS55PSJHRU9JRCIsDQogICAgICAgICAgICAgIGFsbC54PUYpDQoNCg0KbWVyZ2VkPC1tZXJnZWQlPiUNCiAgc2VsZWN0KCBtbXNhLCBzdHN0ciwgYWdlYywgZWR1YywgYmxhY2ssIGhpc3BhbmljLCBvdGhlcixzbW9rZSxvYmVzZSwgYmFkaGVhbHRoLHBibGFjayxwaGlzcCwgbWVkaGhpbmMscHBvdiwgIG1hbGUsIG1tc2F3dCwgbW1zYV9uYW1lICklPiUNCiAgZmlsdGVyKGNvbXBsZXRlLmNhc2VzKC4pKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkobG1lNCkNCm1vZGVsMTwtZ2xtZXIob2Jlc2UgfiBhZ2VjICsgbWFsZSArIGVkdWMgKyBibGFjayArIGhpc3BhbmljICsgb3RoZXIgKyBtZWRoaGluYyArIHBibGFjayArIHBoaXNwKyAoMXxtbXNhX25hbWUpLCANCiAgICAgICAgICAgICAgZmFtaWx5PWJpbm9taWFsLCANCiAgICAgICAgICAgICAgZGF0YT1tZXJnZWQsIA0KICAgICAgICAgICAgICBjb250cm9sID0gZ2xtZXJDb250cm9sKG9wdGltaXplciA9IGMoIk5lbGRlcl9NZWFkIiwiYm9ieXFhIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0Q3RybD1saXN0KG1heGZ1bj0yZTkpKSkNCg0KbW9kZWwxczwtZ2xtZXIob2Jlc2UgfiBhZ2VjICsgbWFsZSArIGVkdWMgKyBibGFjayArIGhpc3BhbmljICsgb3RoZXIgKyBtZWRoaGluYyArIHBibGFjayArIHBoaXNwKyAoMXxtbXNhX25hbWUpKygxfHN0c3RyKSwgDQogICAgICAgICAgICAgIGZhbWlseT1iaW5vbWlhbCwgDQogICAgICAgICAgICAgIGRhdGE9bWVyZ2VkLCANCiAgICAgICAgICAgICAgY29udHJvbCA9IGdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSBjKCJOZWxkZXJfTWVhZCIsImJvYnlxYSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdEN0cmw9bGlzdChtYXhmdW49MmU5KSkpDQoNCmBgYA0KDQpXaGVuIHdlIGNvbXBhcmUgdGhlIG1vZGVsIHRvIGBtb2RlbDFgIGZyb20gZWFybGllciBpbiB0aGUgbGVzc29uLCB3ZSBzZWUgdGhhdCB0aGUgc3RhbmRhcmQgZXJyb3JzIGZvciBzb21lIG9mIHRoZSBwYXJhbWV0ZXJzIGhhdmUgaW5jcmVhc2VkLCBhbmQgc29tZSBvZiB0aGUgJFxiZXRhJCdzIGhhdmUgYWxzbyBpbmNyZWFzZWQgdG8gc21hbGwgZXh0ZW50LiBUaGUgaGlnaGVyIGxldmVsIHZhcmlhYmxlcyBlZmZlY3RzIGFyZSBkZWNyZWFzZWQgaW4gdGhlIG1vZGVsIHdpdGggdGhlIHN1cnZleSBzdHJhdGEgaW5jbHVkZWQuIA0KDQpgYGB7cn0NCmxpYnJhcnkoc3RhcmdhemVyKQ0Kc3RhcmdhemVyKG1vZGVsMSwgbW9kZWwxcywNCiAgICAgICAgICBjb2x1bW4ubGFiZWxzID0gYygiTm8gU3VydmV5IERlc2lnbiIsICJJbmNsdWRpbmcgU3RyYXRhIiksDQogICAgICAgICAgdHlwZSA9ICJ0ZXh0IiwNCiAgICAgICAgICBzdHlsZT0iZGVtb2dyYXBoeSIpDQoNCmBgYA0KDQoNClRoZSBzZWNvbmQgbWV0aG9kIGlzIHdoZXJlIHdlIGluY2x1ZGUgdGhlIHNhbXBsZSB3ZWlnaHRzIGZvciBlYWNoIHJlc3BvbmRlbnQgaW4gdGhlIGFuYWx5c2lzLiBCZWZvcmUgd2UgZG8gdGhpcywgd2UgbXVzdCBmaXJzdCBpbnNwZWN0IHRoZXNlIHdlaWdodHMuIFBlcnNvbiB3ZWlnaHRzIGFyZSBudW1lcmljIHZhbHVlcyB0aGF0IG11bHRpcGx5IGVhY2ggcGVyc29uIGluIHRoZSBkYXRhIHRvIHRoZSBwb3B1bGF0aW9uIGluIHRoZSB0YXJnZXQgcG9wdWxhdGlvbiB0aGF0IGVhY2ggcGVyc29uIHJlcHJlc2VudHMuIFRoaXMgaXMgZG9uZSBieSBjYWxjdWxhdGluZyB0aGUgcHJvYmFiaWxpdHkgdG8gZiBzZWxlY3Rpb24gaW50byB0byB0aGUgc3VydmV5IGZvciBlYWNoIHBlcnNvbiwgYmFzZWQgb24gdGhlaXIgY2hhcmFjdGVyaXN0aWNzLCBhbmQgdGhlbiBpbnZlcnRpbmcgaXQsIHRvIGZvcm0gYW4gaW52ZXJzZSBwcm9iYWJpbGl0eSB3ZWlnaHQuIElmIGEgZ2l2ZW4gcGVyc29uIGlzIHJlbGF0aXZlbHkgcmFyZSBpbiB0aGUgc2FtcGxlIGFuZCByZXByZXNlbnRzIGEgbGFyZ2UgbnVtYmVyIG9mIHBlb3BsZSBpbiB0aGUgcG9wdWxhdGlvbiwgdGhleSB3aWxsIGhhdmUgYSBsYXJnZXIgd2VpZ2h0LCB3aGlsZSB0aGUgb3Bwb3NpdGUgaXMgYWxzbyB0cnVlLiANCg0KRXhhbWluaW5nIHRoZSBudW1lcmljYWwgdmFsdWVzIG9mIHRoZSBCUkZTUyB3ZWlnaHRzIGNhbiBzaG93IHVzIHRoZXNlIGV4cGFuc2lvbiBmYWN0b3JzLg0KDQpCeSBkb2luZyBhIHN1bW1hcnksIHdlIHNlZSB0aGF0IHRoZSBtaW5pbXVtIHdlaWdodCBpcyAwLjIyIGFuZCB0aGUgbWF4aW11bSBpcyAzMiwxNTQuMzEuIFRoaXMgaW5kaWNhdGVzIHRoYXQgYXQgbGVhc3Qgb25lIHBlcnNvbiBpbiB0aGUgc3VydmV5IHJlcHJlc2VudHMgb3ZlciAzMiwwMDAgcGVvcGxlIGluIHRoZSBVUyBhZHVsdCBwb3B1bGF0aW9uLiANCmBgYHtyfQ0Kc3VtbWFyeShtZXJnZWQkbW1zYXd0KQ0KDQpgYGANCg0KSW5kZWVkLCBpZiB3ZSBzdW0gdGhlIHdlaWdodHMsIHdlIGdldCBhIHZhbHVlIG9mIGByIHN1bShtZXJnZWQkbW1zYXd0KWAsIHdoaWNoIGVxdWFscyB0aGUgc3VtIG9mIHRoZSBhZHVsdCBwb3B1bGF0aW9ucyBsaXZpbmcgaW4gbWV0cm9wb2xpdGFuIGFyZWFzIGluIDIwMTYuIA0KDQpgYGB7cn0NCnN1bShtZXJnZWQkbW1zYXd0KQ0KDQpgYGANCg0KSWYgd2UgaW5jbHVkZSB0aGUgd2VpZ2h0cyBpbiB0aGUgbW9kZWwgYXMgaXMsIHRoZXkgd2lsbCBpbmZsYXRlIHRoZSBzYW1wbGUgc2l6ZSBmcm9tIGByIGRpbShtZXJnZWQpWzFdYCB0byBgciBzdW0obWVyZ2VkJG1tc2F3dClgLCB3aGljaCB3b3VsZCBsZWFkIHRvIHByb2JsZW1zIGludGVycHJldGluZyB0aGluZ3MsIGFzIHRoZSBzdGFuZGFyZCBlcnJvcnMgd291bGQgYmVjb21lIHZlcnkgc21hbGwuIEhlcmUgaXMgd2hhdCB0aGlzIHdvdWxkIGxvb2sgbGlrZS4NCg0KYGBge3J9DQpnbG0xPC1nbG0ob2Jlc2UgfiBhZ2VjICsgbWFsZSArIGVkdWMgKyBibGFjayArIGhpc3BhbmljICsgb3RoZXIsDQogICAgICAgICAgZGF0YT1tZXJnZWQsDQogICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwpDQoNCg0KZ2xtdzwtZ2xtKG9iZXNlIH4gYWdlYyArIG1hbGUgKyBlZHVjICsgYmxhY2sgKyBoaXNwYW5pYyArIG90aGVyLA0KICAgICAgICAgIGRhdGE9bWVyZ2VkLA0KICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsLCANCiAgICAgICAgICB3ZWlnaHRzPW1tc2F3dCkNCg0KYGBgDQoNCkluIHRoZSBtb2RlbCB3aGVyZSB3ZWlnaHRzIGFyZSBpbmNsdWRlZCwgYXMgaXMsIHRoZSBtb2RlbCBjb2VmZmljaWVudHMgYmVjb21lIGh1Z2UgYW5kIHdlIGdldCBudW1lcmljYWwgd2FybmluZ3MgYWJvdXQgZml0dGVkIHZhbHVlcyBvZiAwIGFuZCAxIGJlaW5nIHByb2R1Y2VkLiBUaGlzIGlzIG5vdCBnb29kLiANCg0KSW5zdGVhZCBvZiB1c2luZyB0aGUgcmF3IHdlaWdodHMsIHdlIG5lZWQgdG8gc2NhbGUgdGhlIHdlaWdodHMgaW4gb3JkZXIgdG8gdXNlIHRoZW0gaW4gbW9kZWxzLiBUaGVyZSBhcmUgc2V2ZXJhbCB3YXlzIGluIHdoaWNoIHRoaXMgY2FuIGJlIGRvbmUsIGFuZCBbQ2FybGUgKDIwMDkpXShodHRwOi8vd3d3LmJpb21lZGNlbnRyYWwuY29tLzE0NzEtMjI4OC85LzQ5KSBwcm92aWRlcyBhIGZldyBvcHRpb25zIGZvciBkb2luZyB0aGlzLiANCg0KVGhlIHN0cmFpZ2h0LWZvcndhcmQgd2F5IHRvIHNjYWxlIHRoZSB3ZWlnaHRzIGlzIHRvIGRpdmlkZSB0aGVtIGJ5IHRoZWlyIG1lYW4sIHdoaWNoIHdvdWxkIG1ha2UgdGhlIGF2ZXJhZ2Ugd2VpZ2h0IDEgaW5zdGVhZCBvZiAyLDE4NC4gDQoNCmBgYHtyfQ0KbWVhbihtZXJnZWQkbW1zYXd0KQ0KDQptZWFuKG1lcmdlZCRtbXNhd3QvbWVhbihtZXJnZWQkbW1zYXd0KSkNCg0KYGBgDQoNCg0KV2UgY2FuIHVzZSB0aGUgc2NhbGVkIHdlaWdodHMgaW4gdGhlIGFuYWx5c2lzLCBhbmQgdGhleSB3aWxsIGRvIHRoZSBqb2IgdGhleSBhcmUgZGVzaWduZWQgdG8gZG8uIA0KDQpgYGB7cn0NCg0KZ2xtX3cyPC1nbG0ob2Jlc2UgfiBhZ2VjICsgbWFsZSArIGVkdWMgKyBibGFjayArIGhpc3BhbmljICsgb3RoZXIsDQogICAgICAgICAgZGF0YT1tZXJnZWQsDQogICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwsIA0KICAgICAgICAgIHdlaWdodHM9bW1zYXd0L21lYW4obW1zYXd0KSkNCg0Kc3VtbWFyeShnbG1fdzIpDQpgYGANCg0KV2hpY2gsIHdoZW4gY29tcGFyZWQgdG8gdGhlIG91dHB1dCBmcm9tIHRoZSBgZ2xtMWAgbW9kZWwsIHdlIHNlZSBzdWJzdGFudGl2ZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZW0uIE1hbnkgb2YgdGhlIGNvZWZmaWNpZW50cyBoYXZlIGJlZW4gY2hhbmdlZCwgaW4gdGhpcyBjYXNlIHRoZXkgYXJlIG5vdyBjb25zaWRlcmVkICoqX3VuYmlhc2VkXyoqIG9uY2UgdGhlIHdlaWdodHMgaGF2ZSBiZWVuIGFwcGxpZWQuIA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0Kc3RhcmdhemVyKGdsbTEsIGdsbV93MiwgdHlwZT0idGV4dCIsIHN0eWxlPSJkZW1vZ3JhcGh5IiwNCiAgICAgICAgICBjb2x1bW4ubGFiZWxzID0gYygiTm8gV2VpZ2h0cyIsICJTY2FsZWQgV2VpZ2h0cyIpKQ0KDQpgYGANCg0KU2NhbGluZyB0aGUgd2VpZ2h0cyBieSB0aGUgbWVhbiB3ZWlnaHQgaXMgYSBnb29kLCBzaW1wbGUgb3B0aW9uLCBidXQgU25pamRlcnMgYW5kIEJvc2tlciBhbmQgQ2FybGUgYWxsIHN1Z2dlc3Qgc2NhbGluZyB0aGUgd2VpZ2h0cyB0byB0aGUgc3RyYXR1bSBzYW1wbGUgc2l6ZS4gVGhpcyBpbnZvbHZlcyBhIGxpdHRsZSBtb3JlIGNvZGluZywgYnV0IGlzIGVhc3kgd2l0aCBgZHBseXJgDQoNCkZpcnN0LCB3ZSBtYWtlIGFuIGlkIHRoYXQgaXMgdGhlIHNhbWUgYXMgdGhlIHN0cmF0YSB2YXJpYWJsZS4gVGhlbiB3ZSBzdW0gdGhlIHdlaWdodHMgd2l0aGluIHN0cmF0YSBhbmQgY291bnQgdXAgdGhlIG51bWJlciBvZiBwZW9wbGUgaW4gZWFjaCBzdHJhdGEuIFRoZW4gd2UgbWVyZ2UgdGhlc2UgYmFjayB0byB0aGUgZGF0YSwgYW5kIHN0YW5kYXJkaXplIHRoZSB3ZWlnaHRzLg0KDQpgYGB7cn0NCnd0c19zdHJhdDwtbWVyZ2VkJT4lDQogIG11dGF0ZShzYW1wbGVpZD1zdHN0ciklPiUNCiAgZ3JvdXBfYnkoc2FtcGxlaWQpJT4lDQogIHN1bW1hcmlzZShzdW13dD1zdW0obW1zYXd0KSwgbmo9bigpKSU+JQ0KICB1bmdyb3VwKCkNCg0KbWVyZ2VkPC1tZXJnZShtZXJnZWQsIHd0c19zdHJhdCwgYnkueD0ic3RzdHIiLCBieS55PSJzYW1wbGVpZCIsIGFsbC54PVQpDQojSW4gdGhlIG5ldyBkYXRhIHNldCwgbXVsdGlwbHkgdGhlIG9yaWdpbmFsIHdlaWdodCBieSB0aGUgZnJhY3Rpb24gb2YgdGhlDQojc2FtcGxpbmcgdW5pdCB0b3RhbCBwb3B1bGF0aW9uIGVhY2ggcGVyc29uIHJlcHJlc2VudHMNCm1lcmdlZCRzd3RzPC1tZXJnZWQkbW1zYXd0KihtZXJnZWQkbmovbWVyZ2VkJHN1bXd0KQ0KDQpgYGANCg0KTm93IHdlIGhhdmUgd2VpZ2h0cyB0aGF0IGFyZSBzdGFuZGFyZGl6ZWQgdG8gdGhlIHdpdGhpbiBzdHJhdHVtIHNhbXBsZSBzaXplcywgd2UgY2FuIGRvIGEgcXVpY2sgc3VtbWFyeSBvZiB0aGVtIGFuZCBzZWUgdGhhdCB0aGV5IGFyZSBpbmRlZWQgbXVjaCBzbWFsbGVyIHRoYW4gdGhlIG9yaWdpbmFsIHdlaWdodHMsIGFuZCB2ZXJ5IHNpbWlsYXIgdG8gdGhlIG1lYW4gc3RhbmRhcmRpemVkIHdlaWdodHMuDQoNCmBgYHtyfQ0Kc3VtbWFyeShtZXJnZWQkc3d0cykNCnN1bW1hcnkobWVyZ2VkJG1tc2F3dC9tZWFuKG1lcmdlZCRtbXNhd3QpKQ0KDQpgYGANCg0KU28gbm93IHdlIGhhdmUgb3VyIHdlaWdodHMsIHdlIGNhbiB1c2UgdGhlbSBpbiB0aGUgbXVsdGlsZXZlbCBtb2RlbCBhbmQgc2VlIGlmIGl0IGFmZmVjdHMgb3VyIHJlc3VsdHMuDQoNCmBgYHtyfQ0KDQptb2RlbDJ3PC1nbG1lcihvYmVzZX4gYWdlYyArIG1hbGUgKyBlZHVjICsgYmxhY2sgKyBoaXNwYW5pYyArIG90aGVyICsgcHBvdiArICBibGFjaypwYmxhY2sgKyBoaXNwYW5pYypwaGlzcCArIGJsYWNrKm1lZGhoaW5jICsgaGlzcGFuaWMqbWVkaGhpbmMrICgxfG1tc2FfbmFtZSkrKDF8c3RzdHIpLCANCiAgICAgICAgICAgICAgZmFtaWx5PWJpbm9taWFsLCANCiAgICAgICAgICAgICAgZGF0YT1tZXJnZWQsIA0KICAgICAgICAgICAgICB3ZWlnaHRzPXN3dHMsDQogICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1lckNvbnRyb2wob3B0aW1pemVyID0gYygiTmVsZGVyX01lYWQiLCJib2J5cWEiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRDdHJsPWxpc3QobWF4ZnVuPTJlOSkpKQ0KDQpzdW1tYXJ5KG1vZGVsMncpDQpgYGANCg0KSW5kZWVkLCBub3cgb3VyIGNyb3NzLWxldmVsIGludGVyYWN0aW9uIHRlcm0gYmV0d2VlbiB0aGUgaW5kaXZpZHVhbCBsZXZlbCBgYmxhY2tgIGR1bW15IHZhcmlhYmxlIGFuZCB0aGUgTVNBIGxldmVsIGBwYmxhY2tgIHZhcmlhYmxlIGlzIG5vdyBzaWduaWZpY2FudCBpbiB0aGUgbW9kZWwuIFRoaXMgc3VnZ2VzdHMgdGhhdCBOb24tSGlzcGFuaWMgYmxhY2sgcGVvcGxlIGxpdmluZyBpbiBNU0FzIHRoYXQgaGF2ZSBoaWdoZXIgcHJvcG9ydGlvbnMgb2YgTm9uLUhpc3BhbmljIGJsYWNrIHBvcHVsYXRpb24gaGF2ZSBoaWdoZXIgb2RkcyBvZiBiZWluZyBvYmVzZSBjb21wYXJlZCB0byB0aG9zZSBpbiBNU0FzIHdpdGggYW4gYXZlcmFnZSBwcm9wb3J0aW9uIG9mIE5vbi1IaXNwYW5pYyBibGFjayBwb3B1bGF0aW9uLiBUaGVyZSBhcmUgc3RpbGwgbm8gaW50ZXJhY3Rpb24gZWZmZWN0cyBmb3IgdGhlIE1TQSBsZXZlbCBpbmNvbWUgdmFyaWFibGUuDQoNClRoaXMgYWxzbyBzdWdnZXN0cyB0aGF0IHRoZSB3ZWlnaHRzIGFyZSBsaWtlbHkgY29udHJvbGxpbmcgZm9yIHNvbWUgdHlwZSBvZiBub24tcmVzcG9uc2UgYmlhcyBvciBub24tcmVwcmVzZW50YXRpdmVuZXNzIGluIHRoZSBzdXJ2ZXkuIA0KDQoNCg0KIyMjU21hbGwgYXJlYSBlc3RpbWF0aW9uDQpUaGlzIGV4YW1wbGUgd2lsbCBpbGx1c3RyYXRlIGEgd2F5IHRvIGNvbWJpbmUgaW5kaXZpZHVhbCBzdXJ2ZXkgZGF0YSB3aXRoIGFnZ3JlZ2F0ZSBkYXRhIG9uIE1TQXMgdG8gcHJvZHVjZSBhIE1TQSBsZXZlbCBlc3RpbWF0ZSBvZiAqYmFzaWNhbGx5KiBhbnkgaGVhbHRoIGluZGljYXRvciBtZWFzdXJlZCB1c2luZyB0aGUgQlJGU1MuIFRoZSBmcmFtZXdvcmsgSSB1c2UgYmVsb3cgdGFrZXMgb2JzZXJ2ZWQgaW5kaXZpZHVhbCBsZXZlbCBzdXJ2ZXkgcmVzcG9uc2VzIGZyb20gdGhlIEJSRlNTIGFuZCBtZXJnZXMgdGhlc2UgdG8gTVNBIGxldmVsIHZhcmlhYmxlcyBmcm9tIHRoZSBBQ1MuIFRoaXMgYWxsb3dzIG1lIHRvIGVzdGltYXRlIHRoZSBvdmVyYWxsIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIE1TQS1sZXZlbCBwcmV2YWxlbmNlLCBjb250cm9sbGluZyBmb3IgTVNBIGxldmVsIHZhcmlhYmxlcy4gVGhlbiwgSSBjYW4gdXNlIHRoaXMgZXF1YXRpb24gZm9yIHByZWRpY3Rpb24gZm9yIE1TQXMgd2hlcmUgSSBoYXZlIG5vdCBvYnNlcnZlZCBzdXJ2ZXkgcmVzcG9uZGVudHMsIGJ1dCBmb3Igd2hpY2ggSSBoYXZlIG9ic2VydmVkIHRoZSBNU0EgbGV2ZWwgY2hhcmFjdGVyaXN0aWNzLiANCg0KVGhpcyBjb3JyZXNwb25kcyB0byBhICBtdWx0aWxldmVsIGxvZ2lzdGljIG1vZGVsIHdpdGggYSBoaWdoZXIgbGV2ZWwgdmFyaWFibGVzIGFzIHByZWRpY3RvcnMgYW5kIGNhbiBiZSB3cml0dGVuOg0KJCRsbiBcbGVmdCggXGZyYWMge1xwaV97aWp9fXsxLVxwaXtpan19IFxyaWdodCApID0gXGJldGFfezBqfSArXHN1bSB7XGJldGFfayB4X3tpa319K1xzdW0ge1xnYW1tYV9qIHpfan0gJCQNCg0KYGBge3J9DQpsaWJyYXJ5KGxtZTQpDQpsaWJyYXJ5KGxtZXJUZXN0KQ0KZml0Lm1peC5iaW48LWdsbWVyKG9iZXNlIH4gYWdlYyArIG1hbGUgKyBibGFjayArIGhpc3BhbmljICsgb3RoZXIgKyAgKDF8bW1zYSksIA0KICAgICAgICAgICAgICBmYW1pbHk9Ymlub21pYWwsIA0KICAgICAgICAgICAgICBkYXRhPW1lcmdlZCwgDQogICAgICAgICAgICAgIHdlaWdodHM9bW1zYXd0L21lYW4obW1zYXd0KSwNCiAgICAgICAgICAgICAgY29udHJvbCA9IGdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSBjKCJOZWxkZXJfTWVhZCIsImJvYnlxYSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdEN0cmw9bGlzdChtYXhmdW49MmU5KSkpDQoNCnN1bW1hcnkoZml0Lm1peC5iaW4pDQoNCiNvZGRzIHJhdGlvcw0KZXhwKGZpeGVmKGZpdC5taXguYmluKVstMV0pDQpleHAoY29uZmludChmaXQubWl4LmJpbiwgbWV0aG9kPSJXYWxkIikpDQoNCg0KYGBgDQoNCg0KIyMjUHJlZGljdGVkIHZhbHVlcyBmcm9tIHRoZSBtb2RlbA0KVGhlc2UgcHJlZGljdGVkIHZhbHVlcyBhY3R1YWxseSBhbGxvdyB1cyB0byBzZXQgdXAgYSBjb3VudGVyZmFjdHVhbCB0eXBlIG9mIGFuYWx5c2lzLiBXZSBjYW4gZWZmZWN0aXZlbHkgY2hhbmdlIHRoZSBob3VzZWluZyBhZ2UgdmFyaWFibGUgdG8gYmUgb2xkZXIgb3IgeW91bmdlciB0aGFuIHRoZSByZWFsIHZhbHVlIHRvIHNlZSBob3cgdGhlIG91dGNvbWUgY2hhbmdlcy4NCg0KYGBge3J9DQojZ2V0IG5ld2RhdGEgdXNpbmcgcmVhbCB2YWx1ZXMNCmRhdDE8LWV4cGFuZC5ncmlkKG1hbGU9bWVhbihtZXJnZWQkbWFsZSksIGFnZWM9bGV2ZWxzKG1lcmdlZCRhZ2VjKSwgYmxhY2s9YygwLDEpLCBoaXNwYW5pYz1jKDAsMSksIG90aGVyPWMoMCwxKSAsIG1tc2E9IGxldmVscyhhcy5mYWN0b3IobWVyZ2VkJG1tc2EpKSkNCg0KI2dldCBuZXdkYXRhIHVzaW5nIGFydGlmaWNpYWxseSBnZW5lcmF0ZWQgaG91c2luZyBhZ2UgdmFsdWVzICANCg0KI3ByZWRpY3Rpb25zDQpkYXQxJHByZWQ8LXByZWRpY3QoZml0Lm1peC5iaW4sIGRhdDEsIHR5cGU9InJlc3BvbnNlIiwgcmUuZm9ybT1+KDEgfCBtbXNhKSkNCg0KDQpgYGANCg0KDQoNCiMjUG9zdC1zdHJhdGlmaWNhdGlvbg0KDQpgYGB7cn0NCmxpYnJhcnkoaXB1bXNyKQ0KZGRpPC1yZWFkX2lwdW1zX2RkaSgifi9Hb29nbGUgRHJpdmUvY2xhc3Nlcy9kZW03MjgzL2NsYXNzXzE5XzcyODMvZGF0YS91c2FfMDAwNzcueG1sIikNCmNlbnN1czwtcmVhZF9pcHVtc19taWNybyhkZGkpDQoNCm5hbWVzKGNlbnN1cyk8LXRvbG93ZXIobmFtZXMoY2Vuc3VzKSkNCmNlbnN1czwtemFwX2xhYmVscyhjZW5zdXMpDQoNCmNlbnN1czwtY2Vuc3VzJT4lDQogIGZpbHRlcihhZ2U+MjApDQoNCmNlbnN1cyRoaXNwIDwtIHJlY29kZShjZW5zdXMkaGlzcGFuLCByZWNvZGVzID0gIjk9TkE7IDE6ND0nSGlzcGFuaWMnOyAwPSdOb3RIaXNwYW5pYyciKQ0KY2Vuc3VzJHJhY2VfcmVjIDwtIHJlY29kZShjZW5zdXMkcmFjZSwgcmVjb2RlcyA9ICIxPSdXaGl0ZSc7IDI9J0JsYWNrJzsgMz0nT3RoZXIvTXVsdGlwbGUnOyA0OjY9J0FzaWFuJzsgNzo5PSdPdGhlci9NdWx0aXBsZSciLCBhcy5mYWN0b3IgPSBUKQ0KY2Vuc3VzJHJhY2VfZXRoIDwtIGludGVyYWN0aW9uKGNlbnN1cyRoaXNwLCBjZW5zdXMkcmFjZV9yZWMsIHNlcCA9ICIgIikNCmNlbnN1cyRyYWNlX2V0aCA8LSBhcy5mYWN0b3IoaWZlbHNlKHN1YnN0cihhcy5jaGFyYWN0ZXIoY2Vuc3VzJHJhY2VfZXRoKSwxLDgpID09ICJIaXNwYW5pYyIsICJIaXNwYW5pYyIsIGFzLmNoYXJhY3RlcihjZW5zdXMkcmFjZV9ldGgpKSkNCmNlbnN1cyRyYWNlX2V0aCA8LSByZWxldmVsKGNlbnN1cyRyYWNlX2V0aCwgcmVmID0gIk5vdEhpc3BhbmljIFdoaXRlIikNCg0KY2Vuc3VzJGJsYWNrPC1pZmVsc2UoY2Vuc3VzJHJhY2VfZXRoPT0iTm90SGlzcGFuaWMgQmxhY2siLDEsMCkNCmNlbnN1cyRvdGhlcjwtaWZlbHNlKGNlbnN1cyRyYWNlX2V0aCVpbiVjKCJOb3RIaXNwYW5pYyBBc2lhbiIsICJOb3RIaXNwYW5pYyBPdGhlci9NdWx0aXBsZSIpICwxLDApDQpjZW5zdXMkaGlzcGFuaWM8LWlmZWxzZShjZW5zdXMkcmFjZV9ldGg9PSJIaXNwYW5pYyIsMSwwKQ0KDQojc2V4IChJVikNCmNlbnN1cyRtYWxlIDwtIGlmZWxzZShjZW5zdXMkc2V4ID09IDEsMSwwKQ0KY2Vuc3VzJHB3dCA8LSBjZW5zdXMkcGVyd3QNCmNlbnN1cyRhZ2VjPC1jdXQoY2Vuc3VzJGFnZSwgYnJlYWtzID0gc2VxKDIwLCA4MCwgMTApKQ0KbGlicmFyeShzdXJ2ZXkpDQpkZXM8LXN2eWRlc2lnbihpZHM9fmNsdXN0ZXIsIHN0cmF0YSA9IH5zdHJhdGEsIHdlaWdodHMgPSB+cHd0LCBkYXRhPWNlbnN1c1tjZW5zdXMkc3RhdGVmaXA9PSI0OCIsXSkNCmBgYA0KDQpOb3cgSSBtYWtlIHRoZSBwb3B1bGF0aW9ucyBieSB0aGUgc2FtZSBjaGFyYWN0ZXJzaXN0aWNzIHRoYXQgd2VudCBpbnRvIHRoZSBHTE1NDQoNCmBgYHtyfQ0KDQptc2F0b3RhbHM8LXN2eWJ5KH5wZXJ3dCwgfm1ldDIwMTMrYWdlYyttYWxlK2JsYWNrK2hpc3BhbmljK290aGVyLCBkZXMsIEZVTj1zdnl0b3RhbCwgbmEucm09VCkNCm1zYXRvdGFscyRtbXNhPC1tc2F0b3RhbHMkbWV0MjAxMw0KaGVhZChtc2F0b3RhbHMpDQoNCmBgYA0KDQpUaGUgYHBlcnd0YCBjb2x1bW4gaXMgdGhlIGVzdGltYXRlIG9mIHRoZSBudW1iZXIgb2YgcGVvcGxlIGluIGVhY2ggcGxhY2UgYnkgdGhlIGNoYXJhY3RlcmlzdGljcyBwcm92aWRlZC4NCg0KTm93IHdlIHVzZSB0aGVzZSBkYXRhIHRvIGdldCBmaXR0ZWQgdmFsdWVzIGZvciBlYWNoIHJvdzoNCg0KYGBge3J9DQpsaWJyYXJ5KG1lclRvb2xzKQ0KbXNhdG90YWxzJHA8LXByZWRpY3QoZml0Lm1peC5iaW4sIG5ld2RhdGE9bXNhdG90YWxzLGFsbG93Lm5ldy5sZXZlbHM9VCwgdHlwZT0icmVzcG9uc2UiICApDQplc3RfY2lzPC1tc2FfdG90YWxzX3ZhcmlhbmNlczwtcHJlZGljdEludGVydmFsKGZpdC5taXguYmluLCBuZXdkYXRhPW1zYXRvdGFscywgbGV2ZWw9LjUsIG4uc2ltcz01MDAsIHR5cGU9InByb2JhYmlsaXR5IikNCm1zYXRvdGFscyRlc3RfbGNpPC1lc3RfY2lzJGx3cg0KbXNhdG90YWxzJGVzdF91YzwtZXN0X2NpcyR1cHINCm1zYXRvdGFscyRlc3RfcHQ8LWVzdF9jaXMkZml0DQpoZWFkKG1zYXRvdGFscykNCmBgYA0KDQpOb3csIHRvIGRvICoqX3Bvc3Qtc3RyYXRpZmljYXRpb25fKiogZXN0aW1hdGVzLCB3ZSBuZWVkIHRvIGNhbGN1bGF0ZToNCg0KJCRccGlee3ByZWR9X3ttc2Ffan0gPSBcZnJhY3tcc3VtX2ogTl9sIFx0aGV0YV9sfXtcc3VtX2wgTl9sfSQkDQpXaGVyZSAkXHRoZXRhJCBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgYmVpbmcgb2Jlc2UgaW4gZWFjaCBvZiB0aGUgJGwkIHN0cmF0YSAoZ3JvdXBzIG9mIHBlb3BsZSksIHdoaWNoIHdlIGhhdmUgYXMgdGhlIGBwYCBlc3RpbWF0ZSBmcm9tIGFib3ZlLiBUaGUgJE5fbCQgZXN0aWFtdGVzIGFyZSB0aGUgZXN0aW1hdGVkIGNvdW50cyBvZiB0aGUgcG9wdWxhdGlvbiBieSB0aGUgYWdlLCBzZXgsIGFuZCByYWNlIGNoYXJhY3RlcmlzdGljcyBub3RlZCBhYm92ZS4gTm93IHdlIG1ha2UgdGhlIGVzdGltYXRlcw0KDQpgYGB7cn0NCg0KbXNhdG90YWxzJGVzdDwtbXNhdG90YWxzJHAqbXNhdG90YWxzJHBlcnd0DQoNCm1zYXJhdGVzPC1tc2F0b3RhbHMlPiUNCiAgZ3JvdXBfYnkobW1zYSklPiUNCiAgc3VtbWFyaXNlKG9iX3JhdGVfcHMgPSBzdW0oZXN0KS9zdW0ocGVyd3QpKQ0KDQoNCg0KaGVhZChtc2FyYXRlcykNCmBgYA0KDQoNCmBgYHtyfQ0KI1NhbiBBbnRvbmlvDQptc2FyYXRlc1ttc2FyYXRlcyRtbXNhPT0iNDE3MDAiLF0NCg0KYGBgDQoNCk5vdCBiYWQsIGJhc2VkIG9uIG90aGVyIFtlc3RpbWF0ZXNdKGh0dHBzOi8vcmVwb3J0LnNhMjAyMC5vcmcvaGVhbHRoLWFuZC1maXRuZXNzLykNCg0KDQpIZXJlIGlzIHRoZSByZXN0IG9mIFRleGFzDQpgYGB7cn0NCm1zYXJhdGVzJG1tc2FfYzwtYXMuY2hhcmFjdGVyKG1zYXJhdGVzJG1tc2EpDQoNCm9iX21zYTwtZ2VvX2pvaW4obXNhX2VjLCBtc2FyYXRlcywgYnlfc3A9IkdFT0lEIiwgYnlfZGY9Im1tc2FfYyIsIGhvdz0iaW5uZXIiKQ0Kb2JfbXNhJT4lDQogIGdncGxvdCgpK2dlb21fc2YoYWVzKGZpbGw9b2JfcmF0ZV9wcykpDQoNCmBgYA0K