Packages and Data

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ------------------------------------------------- tidyverse 1.3.2 --v ggplot2 3.3.5     v purrr   0.3.4
v tibble  3.1.8     v dplyr   1.0.9
v tidyr   1.1.4     v stringr 1.4.0
v readr   2.1.2     v forcats 0.5.1-- Conflicts ---------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(lme4)
Loading required package: Matrix

Attaching package: ‘Matrix’

The following objects are masked from ‘package:tidyr’:

    expand, pack, unpack
library(lmerTest)

Attaching package: ‘lmerTest’

The following object is masked from ‘package:lme4’:

    lmer

The following object is masked from ‘package:stats’:

    step
library(MuMIn)

d <- read_csv("isbell_crowther_genZ_inprep.csv")
Rows: 216 Columns: 271-- Column specification ------------------------------------------------------------------
Delimiter: ","
chr  (20): ResponseId, wave, Generation, device, gender, ethnicity, ethnicity_8_TEXT, ...
dbl (250): USA_Correct, USA_Friendly, USA_Pleasant, USA_Familiar, China_Correct, China...
lgl   (1): gender_4_TEXT
i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.

Data preparation

To run a mixed effects model, we’ll need to get the data in a suitable format.

You’ll notice that this dataset is not exactly tidy. There are, for example, columns that indicate multiple variables - country and one of four qualities (familiarity, correctness, friendliness, and pleasantness) related to the English spoken there.

It’ll take a couple of steps to get this into shape.

First, we’ll get all of the country ratings in a single column.

long <- d %>% pivot_longer(USA_Correct:Thailand_Familiar, names_to = "country_quality",
                           values_to = "rating")

Now we have over 50,000 observations. Wild!

But we need to break up the countries and qualities - those are separate variables. We’ll use the separate() function and some fancy regex (regular expressions) to split the column into two.

long <- long %>% separate(country_quality, into = c("Country", "Quality"), sep = "_(?=[[:alpha:]]*$)")

Now, since each quality is a different variable, we’ll go ahead and put each in it’s own column using pivot_wider().

long <- long %>% pivot_wider(names_from = "Quality", values_from = "rating")

We should be set now - take a look at the dataset just to be sure.

Modeling judgments of pleasantness based on listener variables

Let’s have a look at some of the data. First, we’ll focus on countries.

long %>% ggplot(aes(y = Pleasant, x = Country))+
  geom_jitter(height = .25, width = .1, alpha = .3)+
  theme_bw()+
  theme(axis.text.x = element_blank())

This isn’t the best way to represent the data, but you can clearly see that some countries have more observations than others, and at the same time some countries seem to have greater concentrations of pleasantness ratings at the higher or lower end.

We’ll look at listeners next - just a subset, though, to keep things manageable.

set.seed(15)

rand_listener <- sample(unique(long$ResponseId), 15)

long %>% filter(ResponseId %in% rand_listener) %>%
  ggplot(aes(x = ResponseId, y = Pleasant)) +
  geom_jitter(height = .05, width = .15)+
  theme_bw()

Again, not the prettiest plot, but you can clearly see some differences in how listeners rate pleasantness - some assign generally lower ratings, and some assign generally higher ratings, while others use a broader range.

So it looks like there’d be a good case to include both listeners and countries as random effects.

Now we’ll try modeling how listeners judge the pleasantness of different global Englishes. We’ll start by taking a look at some random effects models.

ranef_mod <- lmer(Pleasant ~ 1 + (1|ResponseId) + (1|Country), data = long)

summary(ranef_mod)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: Pleasant ~ 1 + (1 | ResponseId) + (1 | Country)
   Data: long

REML criterion at convergence: 14298.6

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-5.5604 -0.5954  0.0270  0.5732  3.7892 

Random effects:
 Groups     Name        Variance Std.Dev.
 ResponseId (Intercept) 1.8914   1.3753  
 Country    (Intercept) 0.6705   0.8188  
 Residual               2.0839   1.4436  
Number of obs: 3787, groups:  ResponseId, 216; Country, 58

Fixed effects:
            Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)   6.3532     0.1454 146.8264    43.7   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Now we’ll add a fixed effect - let’s try Gender. Because there are only 4 non-binary folks, we’ll exclude them from analysis.

gender_mod <- lmer(Pleasant ~ gender + (1|ResponseId) + (1|Country), data = filter(long, gender != "Non-binary"))

summary(gender_mod)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: Pleasant ~ gender + (1 | ResponseId) + (1 | Country)
   Data: filter(long, gender != "Non-binary")

REML criterion at convergence: 13998.6

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.8789 -0.5999  0.0343  0.5746  3.7864 

Random effects:
 Groups     Name        Variance Std.Dev.
 ResponseId (Intercept) 1.8793   1.3709  
 Country    (Intercept) 0.6838   0.8269  
 Residual               2.0659   1.4373  
Number of obs: 3715, groups:  ResponseId, 212; Country, 58

Fixed effects:
            Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)   6.3782     0.1542 166.6562  41.368   <2e-16 ***
genderMale   -0.2504     0.2463 209.6565  -1.016    0.311    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
           (Intr)
genderMale -0.310

It doesn’t look like gender predicts average pleasantness ratings. But we might want to try treating Gender as a random slope. It can’t go with listener, because listeners don’t vary in their gender during the study. But country means could vary according to gender - maybe the gender slope is different from country to country.

gender_mod2 <- lmer(Pleasant ~ gender + (1|ResponseId) + (1+gender|Country), data = filter(long, gender != "Non-binary"))
boundary (singular) fit: see ?isSingular
summary(gender_mod2)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: Pleasant ~ gender + (1 | ResponseId) + (1 + gender | Country)
   Data: filter(long, gender != "Non-binary")

REML criterion at convergence: 13997.1

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.8681 -0.6011  0.0328  0.5737  3.7561 

Random effects:
 Groups     Name        Variance Std.Dev. Corr
 ResponseId (Intercept) 1.878815 1.37070      
 Country    (Intercept) 0.661399 0.81326      
            genderMale  0.004256 0.06524  1.00
 Residual               2.065054 1.43703      
Number of obs: 3715, groups:  ResponseId, 212; Country, 58

Fixed effects:
            Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)   6.3812     0.1529 167.0384   41.74   <2e-16 ***
genderMale   -0.2663     0.2465 210.2119   -1.08    0.281    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
           (Intr)
genderMale -0.288
optimizer (nloptwrap) convergence code: 0 (OK)
boundary (singular) fit: see ?isSingular

We have a warning message here, which basically means that one of our random effects is nearly 0. In this case, it’s the random slope for gender - the variation is (relatively) microscopic. So we probably do not need that random slope.

Let’s play a bit with some other variables now. We’ll look at current state of residence, state, and just include people located in California and Hawaii.

state_mod <- lmer(Pleasant ~ state + (1|ResponseId) + (1+state|Country), data = filter(long, state %in% c("California", "Hawaii")))

summary(state_mod)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: Pleasant ~ state + (1 | ResponseId) + (1 + state | Country)
   Data: filter(long, state %in% c("California", "Hawaii"))

REML criterion at convergence: 13218.5

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-5.6828 -0.5972  0.0076  0.5627  3.8316 

Random effects:
 Groups     Name        Variance Std.Dev. Corr
 ResponseId (Intercept) 1.9516   1.3970       
 Country    (Intercept) 0.6345   0.7965       
            stateHawaii 0.1225   0.3501   0.10
 Residual               2.0182   1.4206       
Number of obs: 3519, groups:  ResponseId, 201; Country, 58

Fixed effects:
            Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)   6.4365     0.1566 180.3935   41.10   <2e-16 ***
stateHawaii  -0.2866     0.2493 209.6406   -1.15    0.252    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr)
stateHawaii -0.334

Here we can see that although the fixed effect of state was not significant, there was variation in the random slopes of state for each country.

Another model, this time related to race/ethnicity, which has been dummy-coded:

race_mod <- lmer(Pleasant ~ White + Asian + Hispanic_Latinx + (1|ResponseId) + (1|Country), data = long)

summary(race_mod)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: Pleasant ~ White + Asian + Hispanic_Latinx + (1 | ResponseId) +  
    (1 | Country)
   Data: long

REML criterion at convergence: 14299.5

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-5.5557 -0.5950  0.0279  0.5725  3.8009 

Random effects:
 Groups     Name        Variance Std.Dev.
 ResponseId (Intercept) 1.904    1.3800  
 Country    (Intercept) 0.670    0.8185  
 Residual               2.084    1.4436  
Number of obs: 3787, groups:  ResponseId, 216; Country, 58

Fixed effects:
                 Estimate Std. Error        df t value Pr(>|t|)    
(Intercept)       6.38743    0.27334 260.42896  23.368   <2e-16 ***
White             0.04782    0.25484 210.92265   0.188    0.851    
Asian            -0.13738    0.26512 210.94361  -0.518    0.605    
Hispanic_Latinx  -0.32399    0.31987 211.30121  -1.013    0.312    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr) White  Asian 
White       -0.812              
Asian       -0.602  0.527       
Hispnc_Ltnx -0.274  0.184  0.116

Not much going on with race/ethnicity in terms of ratings assigned to countries for pleasantness.

Quick check: R2

r.squaredGLMM(ranef_mod)
Warning: 'r.squaredGLMM' now calculates a revised statistic. See the help page.
     R2m      R2c
[1,]   0 0.551444
r.squaredGLMM(gender_mod)
             R2m       R2c
[1,] 0.002114896 0.5546478
r.squaredGLMM(state_mod)
             R2m      R2c
[1,] 0.003092785 0.566779

recoding a potentially interesting variable

Maybe someone’s status as an English speaker can predict how pleasant they tend to view global English varieties.

long <- long %>% mutate(ENG_status = case_when(grepl("^Bilingual", ENG_speaker_status) == T ~ "Multilingual",
                                       grepl("^Dominant", ENG_speaker_status) == T ~ "EnglishPlus",
                                       grepl("^Monolingual", ENG_speaker_status) == T ~ "Monolingual",
                                       grepl("^Multilingual", ENG_speaker_status) == T ~ "Multilingual"))

and now a model…

eng_mod <- lmer(Pleasant ~ ENG_status + (1|ResponseId) + (1+ENG_status|Country), data = long)

summary(eng_mod)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: Pleasant ~ ENG_status + (1 | ResponseId) + (1 + ENG_status |      Country)
   Data: long

REML criterion at convergence: 14189

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-5.5938 -0.5924  0.0264  0.5730  3.8388 

Random effects:
 Groups     Name                   Variance Std.Dev. Corr       
 ResponseId (Intercept)            1.87317  1.3686              
 Country    (Intercept)            0.63955  0.7997              
            ENG_statusMonolingual  0.01209  0.1099    0.11      
            ENG_statusMultilingual 0.11198  0.3346   -0.02  0.99
 Residual                          2.05341  1.4330              
Number of obs: 3769, groups:  ResponseId, 215; Country, 58

Fixed effects:
                       Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)              6.3167     0.2097 240.7209  30.119   <2e-16 ***
ENG_statusMonolingual    0.1345     0.2198 210.3335   0.612    0.541    
ENG_statusMultilingual  -0.2940     0.3493 204.5057  -0.842    0.401    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr) ENG_sttsMn
ENG_sttsMnl -0.707           
ENG_sttsMlt -0.451  0.438    

And nothing!

Let’s try one more…

fam_mod <- lmer(Pleasant ~ Familiar + (1|ResponseId) + (1|Country), data = long)

summary(fam_mod)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: Pleasant ~ Familiar + (1 | ResponseId) + (1 | Country)
   Data: long

REML criterion at convergence: 13511.8

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-5.6538 -0.5764  0.0278  0.5575  4.3914 

Random effects:
 Groups     Name        Variance Std.Dev.
 ResponseId (Intercept) 1.5313   1.2375  
 Country    (Intercept) 0.2599   0.5098  
 Residual               1.7245   1.3132  
Number of obs: 3778, groups:  ResponseId, 215; Country, 58

Fixed effects:
             Estimate Std. Error        df t value Pr(>|t|)    
(Intercept) 4.598e+00  1.259e-01 3.208e+02   36.52   <2e-16 ***
Familiar    3.509e-01  1.199e-02 3.488e+03   29.27   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
         (Intr)
Familiar -0.475

So familiarity and pleasantness seem to go together…

r.squaredGLMM(fam_mod)
           R2m       R2c
[1,] 0.2092887 0.6121362

The fixed effect (familiarity) explains about 21% of the variation in pleasantness ratings.

The random effects add another 40% (!) of variance explained. So we can see that a larger portion of the variation is attributable to country and listener level differences compared to the amount that can be explained by a listener’s familiarity with English from a country.

LS0tDQp0aXRsZTogIk1peGVkIE1vZGVscyBwdC4gMSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMgUGFja2FnZXMgYW5kIERhdGEgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGxtZTQpDQpsaWJyYXJ5KGxtZXJUZXN0KQ0KbGlicmFyeShNdU1JbikNCg0KZCA8LSByZWFkX2NzdigiaXNiZWxsX2Nyb3d0aGVyX2dlblpfaW5wcmVwLmNzdiIpDQpgYGANCg0KIyBEYXRhIHByZXBhcmF0aW9uDQoNClRvIHJ1biBhIG1peGVkIGVmZmVjdHMgbW9kZWwsIHdlJ2xsIG5lZWQgdG8gZ2V0IHRoZSBkYXRhIGluIGEgc3VpdGFibGUgZm9ybWF0Lg0KDQpZb3UnbGwgbm90aWNlIHRoYXQgdGhpcyBkYXRhc2V0IGlzIG5vdCBleGFjdGx5ICp0aWR5Ki4gVGhlcmUgYXJlLCBmb3IgZXhhbXBsZSwgY29sdW1ucyB0aGF0IGluZGljYXRlIG11bHRpcGxlIHZhcmlhYmxlcyAtIGNvdW50cnkgYW5kIG9uZSBvZiBmb3VyIHF1YWxpdGllcyAoZmFtaWxpYXJpdHksIGNvcnJlY3RuZXNzLCBmcmllbmRsaW5lc3MsIGFuZCBwbGVhc2FudG5lc3MpIHJlbGF0ZWQgdG8gdGhlIEVuZ2xpc2ggc3Bva2VuIHRoZXJlLg0KDQpJdCdsbCB0YWtlIGEgY291cGxlIG9mIHN0ZXBzIHRvIGdldCB0aGlzIGludG8gc2hhcGUuDQoNCkZpcnN0LCB3ZSdsbCBnZXQgYWxsIG9mIHRoZSBjb3VudHJ5IHJhdGluZ3MgaW4gYSBzaW5nbGUgY29sdW1uLiANCg0KYGBge3J9DQpsb25nIDwtIGQgJT4lIHBpdm90X2xvbmdlcihVU0FfQ29ycmVjdDpUaGFpbGFuZF9GYW1pbGlhciwgbmFtZXNfdG8gPSAiY291bnRyeV9xdWFsaXR5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJyYXRpbmciKQ0KYGBgDQoNCk5vdyB3ZSBoYXZlIG92ZXIgNTAsMDAwIG9ic2VydmF0aW9ucy4gV2lsZCENCg0KQnV0IHdlIG5lZWQgdG8gYnJlYWsgdXAgdGhlIGNvdW50cmllcyBhbmQgcXVhbGl0aWVzIC0gdGhvc2UgYXJlIHNlcGFyYXRlIHZhcmlhYmxlcy4gV2UnbGwgdXNlIHRoZSBgc2VwYXJhdGUoKWAgZnVuY3Rpb24gYW5kIHNvbWUgZmFuY3kgcmVnZXggKHJlZ3VsYXIgZXhwcmVzc2lvbnMpIHRvIHNwbGl0IHRoZSBjb2x1bW4gaW50byB0d28uDQoNCmBgYHtyfQ0KbG9uZyA8LSBsb25nICU+JSBzZXBhcmF0ZShjb3VudHJ5X3F1YWxpdHksIGludG8gPSBjKCJDb3VudHJ5IiwgIlF1YWxpdHkiKSwgc2VwID0gIl8oPz1bWzphbHBoYTpdXSokKSIpDQpgYGANCg0KTm93LCBzaW5jZSBlYWNoIHF1YWxpdHkgaXMgYSBkaWZmZXJlbnQgdmFyaWFibGUsIHdlJ2xsIGdvIGFoZWFkIGFuZCBwdXQgZWFjaCBpbiBpdCdzIG93biBjb2x1bW4gdXNpbmcgYHBpdm90X3dpZGVyKClgLg0KDQpgYGB7cn0NCmxvbmcgPC0gbG9uZyAlPiUgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJRdWFsaXR5IiwgdmFsdWVzX2Zyb20gPSAicmF0aW5nIikNCmBgYA0KDQpXZSBzaG91bGQgYmUgc2V0IG5vdyAtIHRha2UgYSBsb29rIGF0IHRoZSBkYXRhc2V0IGp1c3QgdG8gYmUgc3VyZS4NCg0KIyBNb2RlbGluZyBqdWRnbWVudHMgb2YgcGxlYXNhbnRuZXNzIGJhc2VkIG9uIGxpc3RlbmVyIHZhcmlhYmxlcw0KDQpMZXQncyBoYXZlIGEgbG9vayBhdCBzb21lIG9mIHRoZSBkYXRhLiBGaXJzdCwgd2UnbGwgZm9jdXMgb24gY291bnRyaWVzLg0KDQpgYGB7cn0NCmxvbmcgJT4lIGdncGxvdChhZXMoeSA9IFBsZWFzYW50LCB4ID0gQ291bnRyeSkpKw0KICBnZW9tX2ppdHRlcihoZWlnaHQgPSAuMjUsIHdpZHRoID0gLjEsIGFscGhhID0gLjMpKw0KICB0aGVtZV9idygpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KVGhpcyBpc24ndCB0aGUgYmVzdCB3YXkgdG8gcmVwcmVzZW50IHRoZSBkYXRhLCBidXQgeW91IGNhbiBjbGVhcmx5IHNlZSB0aGF0IHNvbWUgY291bnRyaWVzIGhhdmUgbW9yZSBvYnNlcnZhdGlvbnMgdGhhbiBvdGhlcnMsIGFuZCBhdCB0aGUgc2FtZSB0aW1lIHNvbWUgY291bnRyaWVzIHNlZW0gdG8gaGF2ZSBncmVhdGVyIGNvbmNlbnRyYXRpb25zIG9mIHBsZWFzYW50bmVzcyByYXRpbmdzIGF0IHRoZSBoaWdoZXIgb3IgbG93ZXIgZW5kLg0KDQpXZSdsbCBsb29rIGF0IGxpc3RlbmVycyBuZXh0IC0ganVzdCBhIHN1YnNldCwgdGhvdWdoLCB0byBrZWVwIHRoaW5ncyBtYW5hZ2VhYmxlLg0KDQpgYGB7cn0NCnNldC5zZWVkKDE1KQ0KDQpyYW5kX2xpc3RlbmVyIDwtIHNhbXBsZSh1bmlxdWUobG9uZyRSZXNwb25zZUlkKSwgMTUpDQoNCmxvbmcgJT4lIGZpbHRlcihSZXNwb25zZUlkICVpbiUgcmFuZF9saXN0ZW5lcikgJT4lDQogIGdncGxvdChhZXMoeCA9IFJlc3BvbnNlSWQsIHkgPSBQbGVhc2FudCkpICsNCiAgZ2VvbV9qaXR0ZXIoaGVpZ2h0ID0gLjA1LCB3aWR0aCA9IC4xNSkrDQogIHRoZW1lX2J3KCkNCmBgYA0KQWdhaW4sIG5vdCB0aGUgcHJldHRpZXN0IHBsb3QsIGJ1dCB5b3UgY2FuIGNsZWFybHkgc2VlIHNvbWUgZGlmZmVyZW5jZXMgaW4gaG93IGxpc3RlbmVycyByYXRlIHBsZWFzYW50bmVzcyAtIHNvbWUgYXNzaWduIGdlbmVyYWxseSBsb3dlciByYXRpbmdzLCBhbmQgc29tZSBhc3NpZ24gZ2VuZXJhbGx5IGhpZ2hlciByYXRpbmdzLCB3aGlsZSBvdGhlcnMgdXNlIGEgYnJvYWRlciByYW5nZS4NCg0KU28gaXQgbG9va3MgbGlrZSB0aGVyZSdkIGJlIGEgZ29vZCBjYXNlIHRvIGluY2x1ZGUgYm90aCBsaXN0ZW5lcnMgYW5kIGNvdW50cmllcyBhcyByYW5kb20gZWZmZWN0cy4NCg0KTm93IHdlJ2xsIHRyeSBtb2RlbGluZyBob3cgbGlzdGVuZXJzIGp1ZGdlIHRoZSBwbGVhc2FudG5lc3Mgb2YgZGlmZmVyZW50IGdsb2JhbCBFbmdsaXNoZXMuIFdlJ2xsIHN0YXJ0IGJ5IHRha2luZyBhIGxvb2sgYXQgc29tZSByYW5kb20gZWZmZWN0cyBtb2RlbHMuDQoNCmBgYHtyfQ0KcmFuZWZfbW9kIDwtIGxtZXIoUGxlYXNhbnQgfiAxICsgKDF8UmVzcG9uc2VJZCkgKyAoMXxDb3VudHJ5KSwgZGF0YSA9IGxvbmcpDQoNCnN1bW1hcnkocmFuZWZfbW9kKQ0KYGBgDQoNCk5vdyB3ZSdsbCBhZGQgYSBmaXhlZCBlZmZlY3QgLSBsZXQncyB0cnkgR2VuZGVyLiBCZWNhdXNlIHRoZXJlIGFyZSBvbmx5IDQgbm9uLWJpbmFyeSBmb2xrcywgd2UnbGwgZXhjbHVkZSB0aGVtIGZyb20gYW5hbHlzaXMuDQoNCmBgYHtyfQ0KZ2VuZGVyX21vZCA8LSBsbWVyKFBsZWFzYW50IH4gZ2VuZGVyICsgKDF8UmVzcG9uc2VJZCkgKyAoMXxDb3VudHJ5KSwgZGF0YSA9IGZpbHRlcihsb25nLCBnZW5kZXIgIT0gIk5vbi1iaW5hcnkiKSkNCg0Kc3VtbWFyeShnZW5kZXJfbW9kKQ0KYGBgDQoNCkl0IGRvZXNuJ3QgbG9vayBsaWtlIGdlbmRlciBwcmVkaWN0cyBhdmVyYWdlIHBsZWFzYW50bmVzcyByYXRpbmdzLiBCdXQgd2UgbWlnaHQgd2FudCB0byB0cnkgdHJlYXRpbmcgR2VuZGVyIGFzIGEgcmFuZG9tIHNsb3BlLiBJdCBjYW4ndCBnbyB3aXRoIGxpc3RlbmVyLCBiZWNhdXNlIGxpc3RlbmVycyBkb24ndCB2YXJ5IGluIHRoZWlyIGdlbmRlciBkdXJpbmcgdGhlIHN0dWR5LiBCdXQgY291bnRyeSBtZWFucyBjb3VsZCB2YXJ5IGFjY29yZGluZyB0byBnZW5kZXIgLSBtYXliZSB0aGUgZ2VuZGVyIHNsb3BlIGlzIGRpZmZlcmVudCBmcm9tIGNvdW50cnkgdG8gY291bnRyeS4NCg0KYGBge3J9DQpnZW5kZXJfbW9kMiA8LSBsbWVyKFBsZWFzYW50IH4gZ2VuZGVyICsgKDF8UmVzcG9uc2VJZCkgKyAoMStnZW5kZXJ8Q291bnRyeSksIGRhdGEgPSBmaWx0ZXIobG9uZywgZ2VuZGVyICE9ICJOb24tYmluYXJ5IikpDQoNCnN1bW1hcnkoZ2VuZGVyX21vZDIpDQpgYGANCldlIGhhdmUgYSB3YXJuaW5nIG1lc3NhZ2UgaGVyZSwgd2hpY2ggYmFzaWNhbGx5IG1lYW5zIHRoYXQgb25lIG9mIG91ciByYW5kb20gZWZmZWN0cyBpcyBuZWFybHkgMC4gSW4gdGhpcyBjYXNlLCBpdCdzIHRoZSByYW5kb20gc2xvcGUgZm9yIGdlbmRlciAtIHRoZSB2YXJpYXRpb24gaXMgKHJlbGF0aXZlbHkpIG1pY3Jvc2NvcGljLiBTbyB3ZSBwcm9iYWJseSBkbyBub3QgbmVlZCB0aGF0IHJhbmRvbSBzbG9wZS4NCg0KTGV0J3MgcGxheSBhIGJpdCB3aXRoIHNvbWUgb3RoZXIgdmFyaWFibGVzIG5vdy4gV2UnbGwgbG9vayBhdCBjdXJyZW50IHN0YXRlIG9mIHJlc2lkZW5jZSwgYHN0YXRlYCwgYW5kIGp1c3QgaW5jbHVkZSBwZW9wbGUgbG9jYXRlZCBpbiBDYWxpZm9ybmlhIGFuZCBIYXdhaWkuDQoNCmBgYHtyfQ0Kc3RhdGVfbW9kIDwtIGxtZXIoUGxlYXNhbnQgfiBzdGF0ZSArICgxfFJlc3BvbnNlSWQpICsgKDErc3RhdGV8Q291bnRyeSksIGRhdGEgPSBmaWx0ZXIobG9uZywgc3RhdGUgJWluJSBjKCJDYWxpZm9ybmlhIiwgIkhhd2FpaSIpKSkNCg0Kc3VtbWFyeShzdGF0ZV9tb2QpDQpgYGANCg0KSGVyZSB3ZSBjYW4gc2VlIHRoYXQgYWx0aG91Z2ggdGhlIGZpeGVkIGVmZmVjdCBvZiBzdGF0ZSB3YXMgbm90IHNpZ25pZmljYW50LCB0aGVyZSB3YXMgdmFyaWF0aW9uIGluIHRoZSByYW5kb20gc2xvcGVzIG9mIHN0YXRlIGZvciBlYWNoIGNvdW50cnkuIA0KDQpBbm90aGVyIG1vZGVsLCB0aGlzIHRpbWUgcmVsYXRlZCB0byByYWNlL2V0aG5pY2l0eSwgd2hpY2ggaGFzIGJlZW4gZHVtbXktY29kZWQ6DQoNCmBgYHtyfQ0KcmFjZV9tb2QgPC0gbG1lcihQbGVhc2FudCB+IFdoaXRlICsgQXNpYW4gKyBIaXNwYW5pY19MYXRpbnggKyAoMXxSZXNwb25zZUlkKSArICgxfENvdW50cnkpLCBkYXRhID0gbG9uZykNCg0Kc3VtbWFyeShyYWNlX21vZCkNCmBgYA0KTm90IG11Y2ggZ29pbmcgb24gd2l0aCByYWNlL2V0aG5pY2l0eSBpbiB0ZXJtcyBvZiByYXRpbmdzIGFzc2lnbmVkIHRvIGNvdW50cmllcyBmb3IgcGxlYXNhbnRuZXNzLg0KDQpRdWljayBjaGVjazogUjINCg0KYGBge3J9DQpyLnNxdWFyZWRHTE1NKHJhbmVmX21vZCkNCnIuc3F1YXJlZEdMTU0oZ2VuZGVyX21vZCkNCnIuc3F1YXJlZEdMTU0oc3RhdGVfbW9kKQ0KYGBgDQoNCiMgcmVjb2RpbmcgYSBwb3RlbnRpYWxseSBpbnRlcmVzdGluZyB2YXJpYWJsZQ0KTWF5YmUgc29tZW9uZSdzIHN0YXR1cyBhcyBhbiBFbmdsaXNoIHNwZWFrZXIgY2FuIHByZWRpY3QgaG93IHBsZWFzYW50IHRoZXkgdGVuZCB0byB2aWV3IGdsb2JhbCBFbmdsaXNoIHZhcmlldGllcy4NCg0KYGBge3J9DQpsb25nIDwtIGxvbmcgJT4lIG11dGF0ZShFTkdfc3RhdHVzID0gY2FzZV93aGVuKGdyZXBsKCJeQmlsaW5ndWFsIiwgRU5HX3NwZWFrZXJfc3RhdHVzKSA9PSBUIH4gIk11bHRpbGluZ3VhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiXkRvbWluYW50IiwgRU5HX3NwZWFrZXJfc3RhdHVzKSA9PSBUIH4gIkVuZ2xpc2hQbHVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJeTW9ub2xpbmd1YWwiLCBFTkdfc3BlYWtlcl9zdGF0dXMpID09IFQgfiAiTW9ub2xpbmd1YWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIl5NdWx0aWxpbmd1YWwiLCBFTkdfc3BlYWtlcl9zdGF0dXMpID09IFQgfiAiTXVsdGlsaW5ndWFsIikpDQpgYGANCg0KYW5kIG5vdyBhIG1vZGVsLi4uDQoNCmBgYHtyfQ0KZW5nX21vZCA8LSBsbWVyKFBsZWFzYW50IH4gRU5HX3N0YXR1cyArICgxfFJlc3BvbnNlSWQpICsgKDErRU5HX3N0YXR1c3xDb3VudHJ5KSwgZGF0YSA9IGxvbmcpDQoNCnN1bW1hcnkoZW5nX21vZCkNCmBgYA0KQW5kIG5vdGhpbmchDQoNCkxldCdzIHRyeSBvbmUgbW9yZS4uLg0KDQpgYGB7cn0NCmZhbV9tb2QgPC0gbG1lcihQbGVhc2FudCB+IEZhbWlsaWFyICsgKDF8UmVzcG9uc2VJZCkgKyAoMXxDb3VudHJ5KSwgZGF0YSA9IGxvbmcpDQoNCnN1bW1hcnkoZmFtX21vZCkNCmBgYA0KDQpTbyBmYW1pbGlhcml0eSBhbmQgcGxlYXNhbnRuZXNzIHNlZW0gdG8gZ28gdG9nZXRoZXIuLi4NCg0KYGBge3J9DQpyLnNxdWFyZWRHTE1NKGZhbV9tb2QpDQpgYGANCg0KVGhlIGZpeGVkIGVmZmVjdCAoZmFtaWxpYXJpdHkpIGV4cGxhaW5zIGFib3V0IDIxJSBvZiB0aGUgdmFyaWF0aW9uIGluIHBsZWFzYW50bmVzcyByYXRpbmdzLg0KDQpUaGUgcmFuZG9tIGVmZmVjdHMgYWRkIGFub3RoZXIgNDAlICghKSBvZiB2YXJpYW5jZSBleHBsYWluZWQuIFNvIHdlIGNhbiBzZWUgdGhhdCBhIGxhcmdlciBwb3J0aW9uIG9mIHRoZSB2YXJpYXRpb24gaXMgYXR0cmlidXRhYmxlIHRvIGNvdW50cnkgYW5kIGxpc3RlbmVyIGxldmVsIGRpZmZlcmVuY2VzIGNvbXBhcmVkIHRvIHRoZSBhbW91bnQgdGhhdCBjYW4gYmUgZXhwbGFpbmVkIGJ5IGEgbGlzdGVuZXIncyBmYW1pbGlhcml0eSB3aXRoIEVuZ2xpc2ggZnJvbSBhIGNvdW50cnku