library(tidyverse)
library(mgcv)
library(ggplot2)

Load and filter the data

A function for loading a single tracks file.

read_filter <- function(filename){
  df <- read_delim(filename, delim = "\t")
  out <- df %>% filter(plt_vclass == "aw", fol_seg != "L") %>%
                     select(age, year, id, F1, F2, t, context, ethnicity, word, fol_seg)
}

This takes forever, cause the eventual data read in is 265.2 Mb, over a network attached drive.

all_aw_list <- map(all_tracks, read_filter)

Cleaning and processing.

add_filename <- function(df, filename){
  df$idstring = basename(filename)
  return(df)
}
all_aw_list <- map2(all_aw_list, all_tracks, add_filename)
all_aw_dat <- bind_rows(all_aw_list)

Focusing on data from White Philadelphians

dat_to_use <- all_aw_dat %>%
  filter(!grepl("a|h", ethnicity),
         !grepl(verboten_string(), idstring)) %>%
  group_by(idstring, id)%>%
  mutate(rel_t = t-min(t),
         prop_t = rel_t/max(rel_t))%>%
  slice(floor(seq(1, n(), length = 20)))
pnc_demo <- read.delim("/Volumes/jfruehwa/PNC/PNC_corpus_info.txt")
pnc_demo %<>%
  mutate(idstring = gsub("(PH[0-9]+-[0-9]+-[0-9]+-).*", "\\1", speaker))
dat_to_use %<>%
  ungroup()%>%
  mutate(idstring = gsub("(PH[0-9]+-[0-9]+-[0-9]+-).*", "\\1", idstring))

Recoding the following segment to voicing context

dat_to_use %<>%
  left_join(pnc_demo %>% select(idstring, sex))%>%
  filter(!grepl("[AEIOU]", fol_seg))%>%
  mutate(dob = year-age,
         era = cut(dob, 3, dig.lab=4),
         voicing = recode(fol_seg, M = "nasal", N = "nasal", NG = "nasal",
                          P = "voiceless", `T` = "voiceless", K = "voiceless",
                          `F` = "voiceless", TH = "voiceless", S = "voiceless",
                          SH = "voiceless", CH = "voiceless",
                          .default = "voiced")  %>% factor() %>% relevel("voiced"))
Joining, by = c("idstring", "sex")

Basic means

dat_to_use %>%
  group_by(idstring, id, sex) %>%
  mutate(meas = 1:n()) %>%
  group_by(sex, meas,era, voicing, idstring)%>%
  summarise(F1 = mean(F1, na.rm = T),
            F2 = mean(F2, na.rm = T))%>%
  summarise(F1 = mean(F1, na.rm = T),
            F2 = mean(F2, na.rm = T))%>%
  ggplot(aes(meas, F1))+
    geom_line(aes(color = voicing))+
    facet_grid(era~sex)+
    theme_bw()

Gam Modelling

Just to keep things simple & avoid normalization for now, just female data.

f_dat <- dat_to_use %>% filter(sex == "f")

Fit the basic model with a smooth for voiced, voiceless and nasal. Voiceless and Nasal are entered as difference curves. Random effects for speaker and word.

Ideally this would also have random smooths by speaker.

f_dat %<>%
  mutate(voiceless = (voicing == "voiceless")*1,
         nasal = (voicing == "nasal")*1,
         idstring = factor(idstring),
         word = factor(word))
f_mod <- bam(F1 ~    s(prop_t) + 
                     s(prop_t, by = voiceless) + 
                     s(prop_t, by = nasal)+
                     s(idstring, bs = 're')+
                     s(word, bs = 're'),             
             data = f_dat)
library(itsadug)
Loading required package: plotfunctions

Attaching package: ‘plotfunctions’

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

    alpha

Loaded package itsadug 2.2 (see 'help("itsadug")' ).
summary(f_mod)

Family: gaussian 
Link function: identity 

Formula:
F1 ~ s(prop_t) + s(prop_t, by = voiceless) + s(prop_t, by = nasal) + 
    s(idstring, bs = "re") + s(word, bs = "re")

Parametric coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  767.722      6.425   119.5   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Approximate significance of smooth terms:
                        edf  Ref.df      F p-value    
s(prop_t)             8.052   8.613  446.3  <2e-16 ***
s(prop_t):voiceless   5.502   6.439  277.0  <2e-16 ***
s(prop_t):nasal       8.587   9.412  293.8  <2e-16 ***
s(idstring)         177.969 179.000 4638.2  <2e-16 ***
s(word)             253.881 270.000  602.2  <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-sq.(adj) =  0.318   Deviance explained =   32%
fREML = 1.3102e+06  Scale est. = 12178     n = 213840

This plots the difference of the voiced curve from the intercept (767 hz).

plot(f_mod, select = 1, main = "voiced curve", ylim = c(-100,100))
abline(h = 0, col = 'red')

Difference between voiced and voiceless

plot(f_mod, select = 2, main = "voiceless effect", ylim = c(-100,100))
abline(h = 0, col = 'red')

difference between voiced and nasal

plot(f_mod, select = 3, main = "nasal effect", ylim = c(-100,100))
abline(h = 0, col = 'red')

Summed effects

plot_smooth(f_mod, view = "prop_t", cond= list(nasal = 0, voiceless = 0),
            rm.ranef = T,
            ylim = c(660, 850))
Summary:
    * prop_t : numeric predictor; with 30 values ranging from 0.000000 to 1.000000. 
    * voiceless : numeric predictor; set to the value(s): 0. 
    * nasal : numeric predictor; set to the value(s): 0. 
    * idstring : factor; set to the value(s): PH73-5-1-. (Might be canceled as random effect, check below.) 
    * word : factor; set to the value(s): OUT. (Might be canceled as random effect, check below.) 
    * NOTE : The following random effects columns are canceled: s(idstring),s(word)
 
plot_smooth(f_mod, view = "prop_t", cond= list(nasal = 0 , voiceless = 1), add = T,
            rm.ranef = T,
            col = 'red')
Summary:
    * prop_t : numeric predictor; with 30 values ranging from 0.000000 to 1.000000. 
    * voiceless : numeric predictor; set to the value(s): 1. 
    * nasal : numeric predictor; set to the value(s): 0. 
    * idstring : factor; set to the value(s): PH73-5-1-. (Might be canceled as random effect, check below.) 
    * word : factor; set to the value(s): OUT. (Might be canceled as random effect, check below.) 
    * NOTE : The following random effects columns are canceled: s(idstring),s(word)
 
plot_smooth(f_mod, view = "prop_t", cond= list(nasal = 1 , voiceless = 0), add = T,
            rm.ranef = T,
            col = 'blue')
Summary:
    * prop_t : numeric predictor; with 30 values ranging from 0.000000 to 1.000000. 
    * voiceless : numeric predictor; set to the value(s): 0. 
    * nasal : numeric predictor; set to the value(s): 1. 
    * idstring : factor; set to the value(s): PH73-5-1-. (Might be canceled as random effect, check below.) 
    * word : factor; set to the value(s): OUT. (Might be canceled as random effect, check below.) 
    * NOTE : The following random effects columns are canceled: s(idstring),s(word)
 

Accounting for autocorrelation

There is a high degree of autocorrelation in the residuals.

acf_resid(f_mod, split_pred=list(f_dat$idstring, f_dat$word), main="ACF resid")

Get the acf at lag = 1

(valRho <- acf_resid(f_mod, split_pred = list(f_dat$idstring,
                                              f_dat$word),
                     plot=FALSE)[2])
        1 
0.8294303 

Create a dummy variable that is T at the start of each vowel token, and F otherwise. Include the AR.start and rho arguments

f_dat %<>%
  group_by(idstring, id)%>%
  mutate(meas = 1:n(),
         start = meas == 1)
f_mod_ar <- bam(F1 ~  s(prop_t) + 
                              s(prop_t, by = voiceless) + 
                              s(prop_t, by = nasal)+
                              s(idstring, bs = 're')+
                              s(word, bs = 're'),
                AR.start = f_dat$start, 
                rho = valRho,
             data = f_dat)
summary(f_mod_ar)

Family: gaussian 
Link function: identity 

Formula:
F1 ~ s(prop_t) + s(prop_t, by = voiceless) + s(prop_t, by = nasal) + 
    s(idstring, bs = "re") + s(word, bs = "re")

Parametric coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  770.480      6.223   123.8   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Approximate significance of smooth terms:
                        edf  Ref.df     F p-value    
s(prop_t)             8.740   8.931 541.4  <2e-16 ***
s(prop_t):voiceless   8.493   9.480 126.1  <2e-16 ***
s(prop_t):nasal       9.760   9.957 184.7  <2e-16 ***
s(idstring)         176.227 179.000 530.9  <2e-16 ***
s(word)             218.541 270.000 109.0  <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-sq.(adj) =  0.314   Deviance explained = 31.5%
fREML = 1.0852e+06  Scale est. = 4498      n = 213840
plot(f_mod_ar)

plot_smooth(f_mod_ar, view = "prop_t", cond= list(nasal = 0, voiceless = 0),
            rm.ranef = T,
            ylim = c(650, 850))
Summary:
    * prop_t : numeric predictor; with 30 values ranging from 0.000000 to 1.000000. 
    * voiceless : numeric predictor; set to the value(s): 0. 
    * nasal : numeric predictor; set to the value(s): 0. 
    * idstring : factor; set to the value(s): PH73-5-1-. (Might be canceled as random effect, check below.) 
    * word : factor; set to the value(s): OUT. (Might be canceled as random effect, check below.) 
    * NOTE : The following random effects columns are canceled: s(idstring),s(word)
 
plot_smooth(f_mod_ar, view = "prop_t", cond= list(nasal = 0 , voiceless = 1), add = T,
            rm.ranef = T,            
            col = 'red')
Summary:
    * prop_t : numeric predictor; with 30 values ranging from 0.000000 to 1.000000. 
    * voiceless : numeric predictor; set to the value(s): 1. 
    * nasal : numeric predictor; set to the value(s): 0. 
    * idstring : factor; set to the value(s): PH73-5-1-. (Might be canceled as random effect, check below.) 
    * word : factor; set to the value(s): OUT. (Might be canceled as random effect, check below.) 
    * NOTE : The following random effects columns are canceled: s(idstring),s(word)
 
plot_smooth(f_mod_ar, view = "prop_t", cond= list(nasal = 1 , voiceless = 0), add = T,
            rm.ranef = T,            
            col = 'blue')
Summary:
    * prop_t : numeric predictor; with 30 values ranging from 0.000000 to 1.000000. 
    * voiceless : numeric predictor; set to the value(s): 0. 
    * nasal : numeric predictor; set to the value(s): 1. 
    * idstring : factor; set to the value(s): PH73-5-1-. (Might be canceled as random effect, check below.) 
    * word : factor; set to the value(s): OUT. (Might be canceled as random effect, check below.) 
    * NOTE : The following random effects columns are canceled: s(idstring),s(word)
 

acf_resid(f_mod_ar, split_pred =  "AR.start")

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtZ2N2KQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyBMb2FkIGFuZCBmaWx0ZXIgdGhlIGRhdGEKCmBgYHtyfQphbGxfdHJhY2tzIDwtIFN5cy5nbG9iKCIvVm9sdW1lcy9qZnJ1ZWh3YS9QTkMvUEgqL1BIKi8qX2xhdC50cmFja3MiKQpgYGAKCgpBIGZ1bmN0aW9uIGZvciBsb2FkaW5nIGEgc2luZ2xlIHRyYWNrcyBmaWxlLgpgYGB7cn0KcmVhZF9maWx0ZXIgPC0gZnVuY3Rpb24oZmlsZW5hbWUpewogIGRmIDwtIHJlYWRfZGVsaW0oZmlsZW5hbWUsIGRlbGltID0gIlx0IikKICBvdXQgPC0gZGYgJT4lIGZpbHRlcihwbHRfdmNsYXNzID09ICJhdyIsIGZvbF9zZWcgIT0gIkwiKSAlPiUKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGFnZSwgeWVhciwgaWQsIEYxLCBGMiwgdCwgY29udGV4dCwgZXRobmljaXR5LCB3b3JkLCBmb2xfc2VnKQp9CmBgYAoKVGhpcyB0YWtlcyBmb3JldmVyLCBjYXVzZSB0aGUgZXZlbnR1YWwgZGF0YSByZWFkIGluIGlzIDI2NS4yIE1iLCBvdmVyIGEgbmV0d29yayBhdHRhY2hlZCBkcml2ZS4KYGBge3J9CmFsbF9hd19saXN0IDwtIG1hcChhbGxfdHJhY2tzLCByZWFkX2ZpbHRlcikKYGBgCgpDbGVhbmluZyBhbmQgcHJvY2Vzc2luZy4KYGBge3J9CmFkZF9maWxlbmFtZSA8LSBmdW5jdGlvbihkZiwgZmlsZW5hbWUpewogIGRmJGlkc3RyaW5nID0gYmFzZW5hbWUoZmlsZW5hbWUpCiAgcmV0dXJuKGRmKQp9CgphbGxfYXdfbGlzdCA8LSBtYXAyKGFsbF9hd19saXN0LCBhbGxfdHJhY2tzLCBhZGRfZmlsZW5hbWUpCgphbGxfYXdfZGF0IDwtIGJpbmRfcm93cyhhbGxfYXdfbGlzdCkKYGBgCgpGb2N1c2luZyBvbiBkYXRhIGZyb20gV2hpdGUgUGhpbGFkZWxwaGlhbnMKYGBge3J9CmRhdF90b191c2UgPC0gYWxsX2F3X2RhdCAlPiUKICBmaWx0ZXIoIWdyZXBsKCJhfGgiLCBldGhuaWNpdHkpLAogICAgICAgICAhZ3JlcGwodmVyYm90ZW5fc3RyaW5nKCksIGlkc3RyaW5nKSkgJT4lCiAgZ3JvdXBfYnkoaWRzdHJpbmcsIGlkKSU+JQogIG11dGF0ZShyZWxfdCA9IHQtbWluKHQpLAogICAgICAgICBwcm9wX3QgPSByZWxfdC9tYXgocmVsX3QpKSU+JQogIHNsaWNlKGZsb29yKHNlcSgxLCBuKCksIGxlbmd0aCA9IDIwKSkpCmBgYAoKYGBge3J9CnBuY19kZW1vIDwtIHJlYWQuZGVsaW0oIi9Wb2x1bWVzL2pmcnVlaHdhL1BOQy9QTkNfY29ycHVzX2luZm8udHh0IikKYGBgCgpgYGB7cn0KcG5jX2RlbW8gJTw+JQogIG11dGF0ZShpZHN0cmluZyA9IGdzdWIoIihQSFswLTldKy1bMC05XSstWzAtOV0rLSkuKiIsICJcXDEiLCBzcGVha2VyKSkKCmRhdF90b191c2UgJTw+JQogIHVuZ3JvdXAoKSU+JQogIG11dGF0ZShpZHN0cmluZyA9IGdzdWIoIihQSFswLTldKy1bMC05XSstWzAtOV0rLSkuKiIsICJcXDEiLCBpZHN0cmluZykpCmBgYAoKUmVjb2RpbmcgdGhlIGZvbGxvd2luZyBzZWdtZW50IHRvIHZvaWNpbmcgY29udGV4dApgYGB7cn0KZGF0X3RvX3VzZSAlPD4lCiAgbGVmdF9qb2luKHBuY19kZW1vICU+JSBzZWxlY3QoaWRzdHJpbmcsIHNleCkpJT4lCiAgZmlsdGVyKCFncmVwbCgiW0FFSU9VXSIsIGZvbF9zZWcpKSU+JQogIG11dGF0ZShkb2IgPSB5ZWFyLWFnZSwKICAgICAgICAgZXJhID0gY3V0KGRvYiwgMywgZGlnLmxhYj00KSwKICAgICAgICAgdm9pY2luZyA9IHJlY29kZShmb2xfc2VnLCBNID0gIm5hc2FsIiwgTiA9ICJuYXNhbCIsIE5HID0gIm5hc2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBQID0gInZvaWNlbGVzcyIsIGBUYCA9ICJ2b2ljZWxlc3MiLCBLID0gInZvaWNlbGVzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYEZgID0gInZvaWNlbGVzcyIsIFRIID0gInZvaWNlbGVzcyIsIFMgPSAidm9pY2VsZXNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBTSCA9ICJ2b2ljZWxlc3MiLCBDSCA9ICJ2b2ljZWxlc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gInZvaWNlZCIpICAlPiUgZmFjdG9yKCkgJT4lIHJlbGV2ZWwoInZvaWNlZCIpKQpgYGAKCiMgQmFzaWMgbWVhbnMKCmBgYHtyfQpkYXRfdG9fdXNlICU+JQogIGdyb3VwX2J5KGlkc3RyaW5nLCBpZCwgc2V4KSAlPiUKICBtdXRhdGUobWVhcyA9IDE6bigpKSAlPiUKICBncm91cF9ieShzZXgsIG1lYXMsZXJhLCB2b2ljaW5nLCBpZHN0cmluZyklPiUKICBzdW1tYXJpc2UoRjEgPSBtZWFuKEYxLCBuYS5ybSA9IFQpLAogICAgICAgICAgICBGMiA9IG1lYW4oRjIsIG5hLnJtID0gVCkpJT4lCiAgc3VtbWFyaXNlKEYxID0gbWVhbihGMSwgbmEucm0gPSBUKSwKICAgICAgICAgICAgRjIgPSBtZWFuKEYyLCBuYS5ybSA9IFQpKSU+JQogIGdncGxvdChhZXMobWVhcywgRjEpKSsKICAgIGdlb21fbGluZShhZXMoY29sb3IgPSB2b2ljaW5nKSkrCiAgICBmYWNldF9ncmlkKGVyYX5zZXgpKwogICAgdGhlbWVfYncoKQpgYGAKCiMgR2FtIE1vZGVsbGluZwoKSnVzdCB0byBrZWVwIHRoaW5ncyBzaW1wbGUgJiBhdm9pZCBub3JtYWxpemF0aW9uIGZvciBub3csIGp1c3QgZmVtYWxlIGRhdGEuCgpgYGB7cn0KZl9kYXQgPC0gZGF0X3RvX3VzZSAlPiUgZmlsdGVyKHNleCA9PSAiZiIpCmBgYAoKCkZpdCB0aGUgYmFzaWMgbW9kZWwgd2l0aCBhIHNtb290aCBmb3Igdm9pY2VkLCB2b2ljZWxlc3MgYW5kIG5hc2FsLiBWb2ljZWxlc3MgYW5kIE5hc2FsIGFyZSBlbnRlcmVkIGFzIGRpZmZlcmVuY2UgY3VydmVzLiBSYW5kb20gZWZmZWN0cyBmb3Igc3BlYWtlciBhbmQgd29yZC4KCklkZWFsbHkgdGhpcyB3b3VsZCBhbHNvIGhhdmUgcmFuZG9tIHNtb290aHMgYnkgc3BlYWtlci4KCmBgYHtyfQpmX2RhdCAlPD4lCiAgbXV0YXRlKHZvaWNlbGVzcyA9ICh2b2ljaW5nID09ICJ2b2ljZWxlc3MiKSoxLAogICAgICAgICBuYXNhbCA9ICh2b2ljaW5nID09ICJuYXNhbCIpKjEsCiAgICAgICAgIGlkc3RyaW5nID0gZmFjdG9yKGlkc3RyaW5nKSwKICAgICAgICAgd29yZCA9IGZhY3Rvcih3b3JkKSkKCmZfbW9kIDwtIGJhbShGMSB+ICAgIHMocHJvcF90KSArIAogICAgICAgICAgICAgICAgICAgICBzKHByb3BfdCwgYnkgPSB2b2ljZWxlc3MpICsgCiAgICAgICAgICAgICAgICAgICAgIHMocHJvcF90LCBieSA9IG5hc2FsKSsKICAgICAgICAgICAgICAgICAgICAgcyhpZHN0cmluZywgYnMgPSAncmUnKSsKICAgICAgICAgICAgICAgICAgICAgcyh3b3JkLCBicyA9ICdyZScpLCAgICAgICAgICAgICAKICAgICAgICAgICAgIGRhdGEgPSBmX2RhdCkKYGBgCgoKYGBge3J9CmxpYnJhcnkoaXRzYWR1ZykKYGBgCgoKYGBge3J9CnN1bW1hcnkoZl9tb2QpCmBgYAoKVGhpcyBwbG90cyB0aGUgZGlmZmVyZW5jZSBvZiB0aGUgdm9pY2VkIGN1cnZlIGZyb20gdGhlIGludGVyY2VwdCAoNzY3IGh6KS4KYGBge3J9CnBsb3QoZl9tb2QsIHNlbGVjdCA9IDEsIG1haW4gPSAidm9pY2VkIGN1cnZlIiwgeWxpbSA9IGMoLTEwMCwxMDApKQphYmxpbmUoaCA9IDAsIGNvbCA9ICdyZWQnKQpgYGAKCkRpZmZlcmVuY2UgYmV0d2VlbiB2b2ljZWQgYW5kIHZvaWNlbGVzcwpgYGB7cn0KcGxvdChmX21vZCwgc2VsZWN0ID0gMiwgbWFpbiA9ICJ2b2ljZWxlc3MgZWZmZWN0IiwgeWxpbSA9IGMoLTEwMCwxMDApKQphYmxpbmUoaCA9IDAsIGNvbCA9ICdyZWQnKQpgYGAKCmRpZmZlcmVuY2UgYmV0d2VlbiB2b2ljZWQgYW5kIG5hc2FsCmBgYHtyfQpwbG90KGZfbW9kLCBzZWxlY3QgPSAzLCBtYWluID0gIm5hc2FsIGVmZmVjdCIsIHlsaW0gPSBjKC0xMDAsMTAwKSkKYWJsaW5lKGggPSAwLCBjb2wgPSAncmVkJykKYGBgCgpTdW1tZWQgZWZmZWN0cwoKYGBge3J9CnBsb3Rfc21vb3RoKGZfbW9kLCB2aWV3ID0gInByb3BfdCIsIGNvbmQ9IGxpc3QobmFzYWwgPSAwLCB2b2ljZWxlc3MgPSAwKSwKICAgICAgICAgICAgcm0ucmFuZWYgPSBULAogICAgICAgICAgICB5bGltID0gYyg2NjAsIDg1MCkpCnBsb3Rfc21vb3RoKGZfbW9kLCB2aWV3ID0gInByb3BfdCIsIGNvbmQ9IGxpc3QobmFzYWwgPSAwICwgdm9pY2VsZXNzID0gMSksIGFkZCA9IFQsCiAgICAgICAgICAgIHJtLnJhbmVmID0gVCwKICAgICAgICAgICAgY29sID0gJ3JlZCcpCnBsb3Rfc21vb3RoKGZfbW9kLCB2aWV3ID0gInByb3BfdCIsIGNvbmQ9IGxpc3QobmFzYWwgPSAxICwgdm9pY2VsZXNzID0gMCksIGFkZCA9IFQsCiAgICAgICAgICAgIHJtLnJhbmVmID0gVCwKICAgICAgICAgICAgY29sID0gJ2JsdWUnKQpgYGAKCiMgQWNjb3VudGluZyBmb3IgYXV0b2NvcnJlbGF0aW9uCgpUaGVyZSBpcyBhIGhpZ2ggZGVncmVlIG9mIGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgcmVzaWR1YWxzLgoKYGBge3J9CmFjZl9yZXNpZChmX21vZCwgc3BsaXRfcHJlZD1saXN0KGZfZGF0JGlkc3RyaW5nLCBmX2RhdCR3b3JkKSwgbWFpbj0iQUNGIHJlc2lkIikKYGBgCgpHZXQgdGhlIGFjZiBhdCBsYWcgPSAxCgpgYGB7cn0KKHZhbFJobyA8LSBhY2ZfcmVzaWQoZl9tb2QsIHNwbGl0X3ByZWQgPSBsaXN0KGZfZGF0JGlkc3RyaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZl9kYXQkd29yZCksCiAgICAgICAgICAgICAgICAgICAgIHBsb3Q9RkFMU0UpWzJdKQpgYGAKCkNyZWF0ZSBhIGR1bW15IHZhcmlhYmxlIHRoYXQgaXMgVCBhdCB0aGUgc3RhcnQgb2YgZWFjaCB2b3dlbCB0b2tlbiwgYW5kIEYgb3RoZXJ3aXNlLgpJbmNsdWRlIHRoZSBgQVIuc3RhcnRgIGFuZCBgcmhvYCBhcmd1bWVudHMKCmBgYHtyfQpmX2RhdCAlPD4lCiAgZ3JvdXBfYnkoaWRzdHJpbmcsIGlkKSU+JQogIG11dGF0ZShtZWFzID0gMTpuKCksCiAgICAgICAgIHN0YXJ0ID0gbWVhcyA9PSAxKQoKCmZfbW9kX2FyIDwtIGJhbShGMSB+ICBzKHByb3BfdCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcyhwcm9wX3QsIGJ5ID0gdm9pY2VsZXNzKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzKHByb3BfdCwgYnkgPSBuYXNhbCkrCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMoaWRzdHJpbmcsIGJzID0gJ3JlJykrCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMod29yZCwgYnMgPSAncmUnKSwKICAgICAgICAgICAgICAgIEFSLnN0YXJ0ID0gZl9kYXQkc3RhcnQsIAogICAgICAgICAgICAgICAgcmhvID0gdmFsUmhvLAogICAgICAgICAgICAgZGF0YSA9IGZfZGF0KQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGZfbW9kX2FyKQpgYGAKCmBgYHtyfQpwbG90KGZfbW9kX2FyKQpgYGAKCmBgYHtyfQpwbG90X3Ntb290aChmX21vZF9hciwgdmlldyA9ICJwcm9wX3QiLCBjb25kPSBsaXN0KG5hc2FsID0gMCwgdm9pY2VsZXNzID0gMCksCiAgICAgICAgICAgIHJtLnJhbmVmID0gVCwKICAgICAgICAgICAgeWxpbSA9IGMoNjUwLCA4NTApKQpwbG90X3Ntb290aChmX21vZF9hciwgdmlldyA9ICJwcm9wX3QiLCBjb25kPSBsaXN0KG5hc2FsID0gMCAsIHZvaWNlbGVzcyA9IDEpLCBhZGQgPSBULAogICAgICAgICAgICBybS5yYW5lZiA9IFQsICAgICAgICAgICAgCiAgICAgICAgICAgIGNvbCA9ICdyZWQnKQpwbG90X3Ntb290aChmX21vZF9hciwgdmlldyA9ICJwcm9wX3QiLCBjb25kPSBsaXN0KG5hc2FsID0gMSAsIHZvaWNlbGVzcyA9IDApLCBhZGQgPSBULAogICAgICAgICAgICBybS5yYW5lZiA9IFQsICAgICAgICAgICAgCiAgICAgICAgICAgIGNvbCA9ICdibHVlJykKYGBgCgpgYGB7cn0KYWNmX3Jlc2lkKGZfbW9kX2FyLCBzcGxpdF9wcmVkID0gICJBUi5zdGFydCIpCmBgYAoK