Found an efficiant way to clean some of the hourly data, you can click “hide” to ingore the code components and just focus on the results if you want. This is just a sample with the daily conversation duration data. The graph shows how convo unfolds over the course of the day on average for students which is pretty cool in and of itself. The next bit shows how we can creature additional features from the hourly data to incorporate into a predictive model.

library(readr)
library(lme4)
library(lmerTest)
library(ggplot2)
load("C:/Users/dasil/Dropbox/sensing_hour/hrly.RData")

Remove feats we dont need at the moment

all_act_inds<-grep("act", colnames(data_polit_hourly)) #dont remove
still_act_inds<-grep("act_still", colnames(data_polit_hourly)) #dont remove
not_act_inds<-setdiff(all_act_inds,still_act_inds) #remove this
band_inds<-grep("band", colnames(data_polit_hourly))
call_inds<-grep("call", colnames(data_polit_hourly))
sms_inds<-grep("sms", colnames(data_polit_hourly))
home_meta_inds<-grep("_home_", colnames(data_polit_hourly))
study_meta_inds<-grep("_study_", colnames(data_polit_hourly))
social_meta_inds<-grep("_social_", colnames(data_polit_hourly))
light_inds<-grep("light", colnames(data_polit_hourly))
inds_2_remove<-c(not_act_inds,band_inds,call_inds,sms_inds,home_meta_inds,study_meta_inds,social_meta_inds,light_inds)
hrly_fts_removed<-data_polit_hourly[,-c(inds_2_remove)]
bad_feats<-c("is_ios","loc_coed","loc_out_going","party_times","pam","prod","stress","social_level")
hrly_fts_removed<-hrly_fts_removed[ , !colnames(hrly_fts_removed) %in% bad_feats]

Find people with horrible data

var_check_out<-var_check(hrly_fts_removed, within = "uid")
ids2remove<-names(which(sapply(var_check_out,length) > 30))

Get rid of people

clean_dat<-hrly_fts_removed[!hrly_fts_removed$uid %in% ids2remove, ]

0 Pad and re-order data numerically to look at trends across day

audio_convo_hr_inds<-grep("convo_duration_hr_", colnames(clean_dat))
audio_convo_hr<-colnames(clean_dat)[audio_convo_hr_inds]
audio_convo_hr_splt<-strsplit(audio_convo_hr, "_")
audio_convo_hr_splt_HRs<-sapply(audio_convo_hr_splt, tail, 1)
audio_convo_hr_splt_HRs<-as.numeric(as.character(audio_convo_hr_splt_HRs))
audio_convo_hr_padded<-sprintf("audio_convo_duration_hr_%02d", audio_convo_hr_splt_HRs)
colnames(clean_dat)[audio_convo_hr_inds]<-audio_convo_hr_padded
audio_convo_hr_padded_sorted<-sort(audio_convo_hr_padded)
#clean_dat[,c(91:114)]<-clean_dat[,c(audio_convo_hr_padded_sorted)]
audio_convo4feat<-clean_dat[,c(audio_convo_hr_padded_sorted)]

Helper function to find the real NAs

hr_qa<-function(dat_vec,qa_vec){
  
  if (length(dat_vec) != nchar(qa_vec)){
    
    stop("qa vector does not match the length of data vector")
    
  }
  
  for (i in 1:24){
  
    qa<-substr(qa_vec,i,i)
  
    if (qa == 0){
    
      dat_vec[i]<-NA
    
    }
  
  } 
  
  return(dat_vec)
  
}

Graph data by hourly average over participants

conv_hr_cleaned<-list()
for (i in 1:nrow(audio_convo4feat)){
  
  conv_hr_cleaned[[i]]<-hr_qa(audio_convo4feat[i,],clean_dat$quality_hrs_audio[i])
  
}
conv_hr_cleaned_dat<-do.call("rbind", conv_hr_cleaned)
audio_means<-colMeans(conv_hr_cleaned_dat, na.rm=TRUE)
dat_audio_hr<-data.frame(audio_means, hr = seq(0,23,1), hr2 =seq(0,23,1)^2, hr3 = seq(0,23,1)^3,hr4 = seq(0,23,1)^4  )

What convosersation looks like over the course of a day

ggplot(dat_audio_hr, aes(x = hr, y = audio_means)) + geom_point(pch=19, size=1.5, color = "black") + stat_smooth(span = .9, color = "red", fill = "red", size = 1.2) + theme_bw()+ggtitle("Conversation over a day")+labs(x="HR in Day (0 = midnight)",y="Mean convo duration")+theme(plot.title =element_text(size = 20, color="black", hjust = .5) ,axis.title.x = element_text(size = 18, color="black"),axis.title.y = element_text(size = 18, color="black"), axis.text.x = element_text(size = 14, color="black"), axis.text.y = element_text(size = 14, color="black"))

Here, with the hourly data, I’ve made some new features that we could use later in a predictice model. I fit linear, quadratic, and cubic models to a person’s daily data and we can use those beta estimates as features. Also grabbed daily mins, maxes, and range of this convo duration feature. As you’ll see from the lmer outputs, all these newly created features are significantly related to stress which should help with a predictive model down the road.

stress_audio_slopes<-cbind(conv_hr_cleaned_dat,uid=clean_dat$uid, stress_sm = clean_dat$stress_sm)
out_list<-list()
for (i in 1:nrow(stress_audio_slopes)){
  
  tempy<-as.numeric(stress_audio_slopes[i,1:24])
  tempx<-seq(0,23,1)
  if (sum(is.na(tempy)) > 7){
    
    out_list[[i]]<-rep(NA,8)
    
  } else {
  
  tempdf<-data.frame(hr = tempx, conv = tempy)
  m<-lm(tempy ~ poly(tempx,3,raw=TRUE), data = tempdf)
  if (length(unique(tempy)) <=2 ){
  
    sans_0<-tempy
  
  } else {
    
    sans_0<-tempy[tempy!=0]
    
  }
  
  out_list[[i]]<-c(as.numeric(m$coefficients[1:4]),max(tempy, na.rm=TRUE),range(sans_0,na.rm=TRUE)[2]-range(sans_0,na.rm=TRUE)[1],var(tempy,na.rm=TRUE),min(sans_0,na.rm=TRUE))
  
  }
  
}
out_list_bind<-do.call("rbind", out_list)
colnames(out_list_bind)<-c("b0","b1","b2","b3","max","range","var","min")
audio_binded<-cbind(stress_audio_slopes,out_list_bind)

How the new features relate to daily stress

summary(lmer(stress_sm ~ b0+b1+b2+b3 + (1|uid), data = audio_binded ))
Linear mixed model fit by REML 
t-tests use  Satterthwaite approximations to degrees of freedom ['lmerMod']
Formula: stress_sm ~ b0 + b1 + b2 + b3 + (1 | uid)
   Data: audio_binded

REML criterion at convergence: 21429.5

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.87192 -0.80044  0.07159  0.75889  2.63602 

Random effects:
 Groups   Name        Variance Std.Dev.
 uid      (Intercept)  2.496   1.580   
 Residual             15.066   3.882   
Number of obs: 3817, groups:  uid, 132

Fixed effects:
              Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)  9.158e+00  1.846e-01  2.237e+02  49.623  < 2e-16 ***
b0          -8.871e-04  2.969e-04  3.756e+03  -2.988  0.00282 ** 
b1          -1.262e-02  2.606e-03  3.598e+03  -4.843 1.33e-06 ***
b2          -2.089e-01  3.948e-02  3.675e+03  -5.289 1.30e-07 ***
b3          -3.673e+00  7.424e-01  3.780e+03  -4.947 7.86e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
   (Intr) b0     b1     b2    
b0 -0.327                     
b1 -0.446  0.822              
b2 -0.444  0.564  0.912       
b3 -0.384  0.406  0.791  0.967
summary(lmer(stress_sm ~ scale(max)+ (1|uid), data = audio_binded ))
Linear mixed model fit by REML 
t-tests use  Satterthwaite approximations to degrees of freedom ['lmerMod']
Formula: stress_sm ~ scale(max) + (1 | uid)
   Data: audio_binded

REML criterion at convergence: 21407.4

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.84831 -0.79216  0.07359  0.74953  2.63996 

Random effects:
 Groups   Name        Variance Std.Dev.
 uid      (Intercept)  2.474   1.573   
 Residual             15.102   3.886   
Number of obs: 3817, groups:  uid, 132

Fixed effects:
              Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)    8.63860    0.15790  127.38868  54.709  < 2e-16 ***
scale(max)    -0.34376    0.07796 3415.78152  -4.409 1.07e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
           (Intr)
scale(max) 0.021 
summary(lmer(stress_sm ~ scale(var)+ (1|uid), data = audio_binded ))
Linear mixed model fit by REML 
t-tests use  Satterthwaite approximations to degrees of freedom ['lmerMod']
Formula: stress_sm ~ scale(var) + (1 | uid)
   Data: audio_binded

REML criterion at convergence: 21393.5

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.86450 -0.80254  0.07218  0.75657  2.62857 

Random effects:
 Groups   Name        Variance Std.Dev.
 uid      (Intercept)  2.512   1.585   
 Residual             15.040   3.878   
Number of obs: 3817, groups:  uid, 132

Fixed effects:
              Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)    8.62408    0.15883  127.66528  54.297  < 2e-16 ***
scale(var)    -0.44581    0.07711 3525.32789  -5.781 8.05e-09 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
           (Intr)
scale(var) 0.032 
summary(lmer(stress_sm ~ scale(range)+ (1|uid), data = audio_binded ))
Linear mixed model fit by REML 
t-tests use  Satterthwaite approximations to degrees of freedom ['lmerMod']
Formula: stress_sm ~ scale(range) + (1 | uid)
   Data: audio_binded

REML criterion at convergence: 21410.7

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.86017 -0.79064  0.07384  0.75206  2.64501 

Random effects:
 Groups   Name        Variance Std.Dev.
 uid      (Intercept)  2.472   1.572   
 Residual             15.116   3.888   
Number of obs: 3817, groups:  uid, 132

Fixed effects:
              Estimate Std. Error        df t value Pr(>|t|)    
(Intercept)     8.6403     0.1578  127.2661  54.739  < 2e-16 ***
scale(range)   -0.3135     0.0781 3406.7973  -4.014 6.11e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr)
scale(rang) 0.020 
summary(lmer(stress_sm ~ scale(min)+ (1|uid), data = audio_binded ))
Linear mixed model fit by REML 
t-tests use  Satterthwaite approximations to degrees of freedom ['lmerMod']
Formula: stress_sm ~ scale(min) + (1 | uid)
   Data: audio_binded

REML criterion at convergence: 21422.5

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.77372 -0.77819  0.06168  0.77599  2.61727 

Random effects:
 Groups   Name        Variance Std.Dev.
 uid      (Intercept)  2.447   1.564   
 Residual             15.167   3.894   
Number of obs: 3817, groups:  uid, 132

Fixed effects:
              Estimate Std. Error         df t value Pr(>|t|)    
(Intercept)    8.65213    0.15725  126.44327  55.022   <2e-16 ***
scale(min)    -0.13850    0.06409 3752.84680  -2.161   0.0308 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
           (Intr)
scale(min) 0.004 
LS0tDQp0aXRsZTogIlVwZGF0ZSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KDQotLS0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDM4cHg7DQogIGNvbG9yOiBCbGFjazsNCiAgZm9udC1mYWNlOiBCb2xkOw0KfQ0KDQpib2R5LCB0ZCB7DQogICBmb250LXNpemU6IDE4cHg7DQp9DQpjb2RlLnJ7DQogIGZvbnQtc2l6ZTogMTJweDsNCn0NCnByZSB7DQogIGZvbnQtc2l6ZTogMTRweA0KfQ0KPC9zdHlsZT4NCg0KDQpGb3VuZCBhbiBlZmZpY2lhbnQgd2F5IHRvIGNsZWFuIHNvbWUgb2YgdGhlIGhvdXJseSBkYXRhLCB5b3UgY2FuIGNsaWNrICJoaWRlIiB0byBpbmdvcmUgdGhlIGNvZGUgY29tcG9uZW50cyBhbmQganVzdCBmb2N1cyBvbiB0aGUgcmVzdWx0cyBpZiB5b3Ugd2FudC4gIFRoaXMgaXMganVzdCBhIHNhbXBsZSB3aXRoIHRoZSBkYWlseSBjb252ZXJzYXRpb24gZHVyYXRpb24gZGF0YS4gIFRoZSBncmFwaCBzaG93cyBob3cgY29udm8gdW5mb2xkcyBvdmVyIHRoZSBjb3Vyc2Ugb2YgdGhlIGRheSBvbiBhdmVyYWdlIGZvciBzdHVkZW50cyB3aGljaCBpcyBwcmV0dHkgY29vbCBpbiBhbmQgb2YgaXRzZWxmLiAgVGhlIG5leHQgYml0IHNob3dzIGhvdyB3ZSBjYW4gY3JlYXR1cmUgYWRkaXRpb25hbCBmZWF0dXJlcyBmcm9tIHRoZSBob3VybHkgZGF0YSB0byBpbmNvcnBvcmF0ZSBpbnRvIGEgcHJlZGljdGl2ZSBtb2RlbC4NCmBgYHtyfQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkobG1lNCkNCmxpYnJhcnkobG1lclRlc3QpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmxvYWQoIkM6L1VzZXJzL2Rhc2lsL0Ryb3Bib3gvc2Vuc2luZ19ob3VyL2hybHkuUkRhdGEiKQ0KDQpgYGANCg0KUmVtb3ZlIGZlYXRzIHdlIGRvbnQgbmVlZCBhdCB0aGUgbW9tZW50DQpgYGB7cn0NCmFsbF9hY3RfaW5kczwtZ3JlcCgiYWN0IiwgY29sbmFtZXMoZGF0YV9wb2xpdF9ob3VybHkpKSAjZG9udCByZW1vdmUNCg0Kc3RpbGxfYWN0X2luZHM8LWdyZXAoImFjdF9zdGlsbCIsIGNvbG5hbWVzKGRhdGFfcG9saXRfaG91cmx5KSkgI2RvbnQgcmVtb3ZlDQoNCm5vdF9hY3RfaW5kczwtc2V0ZGlmZihhbGxfYWN0X2luZHMsc3RpbGxfYWN0X2luZHMpICNyZW1vdmUgdGhpcw0KDQpiYW5kX2luZHM8LWdyZXAoImJhbmQiLCBjb2xuYW1lcyhkYXRhX3BvbGl0X2hvdXJseSkpDQoNCmNhbGxfaW5kczwtZ3JlcCgiY2FsbCIsIGNvbG5hbWVzKGRhdGFfcG9saXRfaG91cmx5KSkNCg0Kc21zX2luZHM8LWdyZXAoInNtcyIsIGNvbG5hbWVzKGRhdGFfcG9saXRfaG91cmx5KSkNCg0KaG9tZV9tZXRhX2luZHM8LWdyZXAoIl9ob21lXyIsIGNvbG5hbWVzKGRhdGFfcG9saXRfaG91cmx5KSkNCg0Kc3R1ZHlfbWV0YV9pbmRzPC1ncmVwKCJfc3R1ZHlfIiwgY29sbmFtZXMoZGF0YV9wb2xpdF9ob3VybHkpKQ0KDQpzb2NpYWxfbWV0YV9pbmRzPC1ncmVwKCJfc29jaWFsXyIsIGNvbG5hbWVzKGRhdGFfcG9saXRfaG91cmx5KSkNCg0KbGlnaHRfaW5kczwtZ3JlcCgibGlnaHQiLCBjb2xuYW1lcyhkYXRhX3BvbGl0X2hvdXJseSkpDQoNCmluZHNfMl9yZW1vdmU8LWMobm90X2FjdF9pbmRzLGJhbmRfaW5kcyxjYWxsX2luZHMsc21zX2luZHMsaG9tZV9tZXRhX2luZHMsc3R1ZHlfbWV0YV9pbmRzLHNvY2lhbF9tZXRhX2luZHMsbGlnaHRfaW5kcykNCg0KaHJseV9mdHNfcmVtb3ZlZDwtZGF0YV9wb2xpdF9ob3VybHlbLC1jKGluZHNfMl9yZW1vdmUpXQ0KDQpiYWRfZmVhdHM8LWMoImlzX2lvcyIsImxvY19jb2VkIiwibG9jX291dF9nb2luZyIsInBhcnR5X3RpbWVzIiwicGFtIiwicHJvZCIsInN0cmVzcyIsInNvY2lhbF9sZXZlbCIpDQoNCmhybHlfZnRzX3JlbW92ZWQ8LWhybHlfZnRzX3JlbW92ZWRbICwgIWNvbG5hbWVzKGhybHlfZnRzX3JlbW92ZWQpICVpbiUgYmFkX2ZlYXRzXQ0KDQpgYGANCg0KRmluZCBwZW9wbGUgd2l0aCBob3JyaWJsZSBkYXRhDQpgYGB7cn0NCnZhcl9jaGVja19vdXQ8LXZhcl9jaGVjayhocmx5X2Z0c19yZW1vdmVkLCB3aXRoaW4gPSAidWlkIikNCg0KaWRzMnJlbW92ZTwtbmFtZXMod2hpY2goc2FwcGx5KHZhcl9jaGVja19vdXQsbGVuZ3RoKSA+IDMwKSkNCg0KYGBgDQoNCkdldCByaWQgb2YgcGVvcGxlDQpgYGB7cn0NCmNsZWFuX2RhdDwtaHJseV9mdHNfcmVtb3ZlZFshaHJseV9mdHNfcmVtb3ZlZCR1aWQgJWluJSBpZHMycmVtb3ZlLCBdDQoNCmBgYA0KDQowIFBhZCBhbmQgcmUtb3JkZXIgZGF0YSBudW1lcmljYWxseSB0byBsb29rIGF0IHRyZW5kcyBhY3Jvc3MgZGF5DQpgYGB7cn0NCg0KYXVkaW9fY29udm9faHJfaW5kczwtZ3JlcCgiY29udm9fZHVyYXRpb25faHJfIiwgY29sbmFtZXMoY2xlYW5fZGF0KSkNCg0KYXVkaW9fY29udm9faHI8LWNvbG5hbWVzKGNsZWFuX2RhdClbYXVkaW9fY29udm9faHJfaW5kc10NCg0KYXVkaW9fY29udm9faHJfc3BsdDwtc3Ryc3BsaXQoYXVkaW9fY29udm9faHIsICJfIikNCg0KYXVkaW9fY29udm9faHJfc3BsdF9IUnM8LXNhcHBseShhdWRpb19jb252b19ocl9zcGx0LCB0YWlsLCAxKQ0KDQphdWRpb19jb252b19ocl9zcGx0X0hSczwtYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoYXVkaW9fY29udm9faHJfc3BsdF9IUnMpKQ0KDQphdWRpb19jb252b19ocl9wYWRkZWQ8LXNwcmludGYoImF1ZGlvX2NvbnZvX2R1cmF0aW9uX2hyXyUwMmQiLCBhdWRpb19jb252b19ocl9zcGx0X0hScykNCg0KY29sbmFtZXMoY2xlYW5fZGF0KVthdWRpb19jb252b19ocl9pbmRzXTwtYXVkaW9fY29udm9faHJfcGFkZGVkDQoNCmF1ZGlvX2NvbnZvX2hyX3BhZGRlZF9zb3J0ZWQ8LXNvcnQoYXVkaW9fY29udm9faHJfcGFkZGVkKQ0KDQojY2xlYW5fZGF0WyxjKDkxOjExNCldPC1jbGVhbl9kYXRbLGMoYXVkaW9fY29udm9faHJfcGFkZGVkX3NvcnRlZCldDQoNCmF1ZGlvX2NvbnZvNGZlYXQ8LWNsZWFuX2RhdFssYyhhdWRpb19jb252b19ocl9wYWRkZWRfc29ydGVkKV0NCg0KYGBgDQoNCkhlbHBlciBmdW5jdGlvbiB0byBmaW5kIHRoZSByZWFsIE5Bcw0KYGBge3J9DQoNCmhyX3FhPC1mdW5jdGlvbihkYXRfdmVjLHFhX3ZlYyl7DQogIA0KICBpZiAobGVuZ3RoKGRhdF92ZWMpICE9IG5jaGFyKHFhX3ZlYykpew0KICAgIA0KICAgIHN0b3AoInFhIHZlY3RvciBkb2VzIG5vdCBtYXRjaCB0aGUgbGVuZ3RoIG9mIGRhdGEgdmVjdG9yIikNCiAgICANCiAgfQ0KICANCiAgZm9yIChpIGluIDE6MjQpew0KICANCiAgICBxYTwtc3Vic3RyKHFhX3ZlYyxpLGkpDQogIA0KICAgIGlmIChxYSA9PSAwKXsNCiAgICANCiAgICAgIGRhdF92ZWNbaV08LU5BDQogICAgDQogICAgfQ0KICANCiAgfSANCiAgDQogIHJldHVybihkYXRfdmVjKQ0KICANCn0NCg0KYGBgDQoNCkdyYXBoIGRhdGEgYnkgaG91cmx5IGF2ZXJhZ2Ugb3ZlciBwYXJ0aWNpcGFudHMNCmBgYHtyfQ0KY29udl9ocl9jbGVhbmVkPC1saXN0KCkNCg0KZm9yIChpIGluIDE6bnJvdyhhdWRpb19jb252bzRmZWF0KSl7DQogIA0KICBjb252X2hyX2NsZWFuZWRbW2ldXTwtaHJfcWEoYXVkaW9fY29udm80ZmVhdFtpLF0sY2xlYW5fZGF0JHF1YWxpdHlfaHJzX2F1ZGlvW2ldKQ0KICANCn0NCg0KY29udl9ocl9jbGVhbmVkX2RhdDwtZG8uY2FsbCgicmJpbmQiLCBjb252X2hyX2NsZWFuZWQpDQoNCmF1ZGlvX21lYW5zPC1jb2xNZWFucyhjb252X2hyX2NsZWFuZWRfZGF0LCBuYS5ybT1UUlVFKQ0KDQpkYXRfYXVkaW9faHI8LWRhdGEuZnJhbWUoYXVkaW9fbWVhbnMsIGhyID0gc2VxKDAsMjMsMSksIGhyMiA9c2VxKDAsMjMsMSleMiwgaHIzID0gc2VxKDAsMjMsMSleMyxocjQgPSBzZXEoMCwyMywxKV40ICApDQoNCmBgYA0KDQpXaGF0IGNvbnZvc2Vyc2F0aW9uIGxvb2tzIGxpa2Ugb3ZlciB0aGUgY291cnNlIG9mIGEgZGF5DQpgYGB7cn0NCmdncGxvdChkYXRfYXVkaW9faHIsIGFlcyh4ID0gaHIsIHkgPSBhdWRpb19tZWFucykpICsgZ2VvbV9wb2ludChwY2g9MTksIHNpemU9MS41LCBjb2xvciA9ICJibGFjayIpICsgc3RhdF9zbW9vdGgoc3BhbiA9IC45LCBjb2xvciA9ICJyZWQiLCBmaWxsID0gInJlZCIsIHNpemUgPSAxLjIpICsgdGhlbWVfYncoKStnZ3RpdGxlKCJDb252ZXJzYXRpb24gb3ZlciBhIGRheSIpK2xhYnMoeD0iSFIgaW4gRGF5ICgwID0gbWlkbmlnaHQpIix5PSJNZWFuIGNvbnZvIGR1cmF0aW9uIikrdGhlbWUocGxvdC50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgY29sb3I9ImJsYWNrIiwgaGp1c3QgPSAuNSkgLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGNvbG9yPSJibGFjayIpLGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGNvbG9yPSJibGFjayIpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yPSJibGFjayIpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yPSJibGFjayIpKQ0KDQpgYGANCg0KSGVyZSwgd2l0aCB0aGUgaG91cmx5IGRhdGEsIEkndmUgbWFkZSBzb21lIG5ldyBmZWF0dXJlcyB0aGF0IHdlIGNvdWxkIHVzZSBsYXRlciBpbiBhIHByZWRpY3RpY2UgbW9kZWwuICBJIGZpdCBsaW5lYXIsIHF1YWRyYXRpYywgYW5kIGN1YmljIG1vZGVscyB0byBhIHBlcnNvbidzIGRhaWx5IGRhdGEgYW5kIHdlIGNhbiB1c2UgdGhvc2UgYmV0YSBlc3RpbWF0ZXMgYXMgZmVhdHVyZXMuICBBbHNvIGdyYWJiZWQgZGFpbHkgbWlucywgbWF4ZXMsIGFuZCByYW5nZSBvZiB0aGlzIGNvbnZvIGR1cmF0aW9uIGZlYXR1cmUuICBBcyB5b3UnbGwgc2VlIGZyb20gdGhlIGxtZXIgb3V0cHV0cywgYWxsIHRoZXNlIG5ld2x5IGNyZWF0ZWQgZmVhdHVyZXMgYXJlIHNpZ25pZmljYW50bHkgcmVsYXRlZCB0byBzdHJlc3Mgd2hpY2ggc2hvdWxkIGhlbHAgd2l0aCBhIHByZWRpY3RpdmUgbW9kZWwgZG93biB0aGUgcm9hZC4NCmBgYHtyfQ0Kc3RyZXNzX2F1ZGlvX3Nsb3BlczwtY2JpbmQoY29udl9ocl9jbGVhbmVkX2RhdCx1aWQ9Y2xlYW5fZGF0JHVpZCwgc3RyZXNzX3NtID0gY2xlYW5fZGF0JHN0cmVzc19zbSkNCg0Kb3V0X2xpc3Q8LWxpc3QoKQ0KDQpmb3IgKGkgaW4gMTpucm93KHN0cmVzc19hdWRpb19zbG9wZXMpKXsNCiAgDQogIHRlbXB5PC1hcy5udW1lcmljKHN0cmVzc19hdWRpb19zbG9wZXNbaSwxOjI0XSkNCg0KICB0ZW1weDwtc2VxKDAsMjMsMSkNCg0KICBpZiAoc3VtKGlzLm5hKHRlbXB5KSkgPiA3KXsNCiAgICANCiAgICBvdXRfbGlzdFtbaV1dPC1yZXAoTkEsOCkNCiAgICANCiAgfSBlbHNlIHsNCiAgDQogIHRlbXBkZjwtZGF0YS5mcmFtZShociA9IHRlbXB4LCBjb252ID0gdGVtcHkpDQoNCiAgbTwtbG0odGVtcHkgfiBwb2x5KHRlbXB4LDMscmF3PVRSVUUpLCBkYXRhID0gdGVtcGRmKQ0KDQogIGlmIChsZW5ndGgodW5pcXVlKHRlbXB5KSkgPD0yICl7DQogIA0KICAgIHNhbnNfMDwtdGVtcHkNCiAgDQogIH0gZWxzZSB7DQogICAgDQogICAgc2Fuc18wPC10ZW1weVt0ZW1weSE9MF0NCiAgICANCiAgfQ0KICANCiAgb3V0X2xpc3RbW2ldXTwtYyhhcy5udW1lcmljKG0kY29lZmZpY2llbnRzWzE6NF0pLG1heCh0ZW1weSwgbmEucm09VFJVRSkscmFuZ2Uoc2Fuc18wLG5hLnJtPVRSVUUpWzJdLXJhbmdlKHNhbnNfMCxuYS5ybT1UUlVFKVsxXSx2YXIodGVtcHksbmEucm09VFJVRSksbWluKHNhbnNfMCxuYS5ybT1UUlVFKSkNCiAgDQogIH0NCiAgDQp9DQoNCm91dF9saXN0X2JpbmQ8LWRvLmNhbGwoInJiaW5kIiwgb3V0X2xpc3QpDQoNCmNvbG5hbWVzKG91dF9saXN0X2JpbmQpPC1jKCJiMCIsImIxIiwiYjIiLCJiMyIsIm1heCIsInJhbmdlIiwidmFyIiwibWluIikNCg0KYXVkaW9fYmluZGVkPC1jYmluZChzdHJlc3NfYXVkaW9fc2xvcGVzLG91dF9saXN0X2JpbmQpDQpgYGANCg0KSG93IHRoZSBuZXcgZmVhdHVyZXMgcmVsYXRlIHRvIGRhaWx5IHN0cmVzcw0KYGBge3J9DQpzdW1tYXJ5KGxtZXIoc3RyZXNzX3NtIH4gYjArYjErYjIrYjMgKyAoMXx1aWQpLCBkYXRhID0gYXVkaW9fYmluZGVkICkpDQoNCnN1bW1hcnkobG1lcihzdHJlc3Nfc20gfiBzY2FsZShtYXgpKyAoMXx1aWQpLCBkYXRhID0gYXVkaW9fYmluZGVkICkpDQoNCnN1bW1hcnkobG1lcihzdHJlc3Nfc20gfiBzY2FsZSh2YXIpKyAoMXx1aWQpLCBkYXRhID0gYXVkaW9fYmluZGVkICkpDQoNCnN1bW1hcnkobG1lcihzdHJlc3Nfc20gfiBzY2FsZShyYW5nZSkrICgxfHVpZCksIGRhdGEgPSBhdWRpb19iaW5kZWQgKSkNCg0Kc3VtbWFyeShsbWVyKHN0cmVzc19zbSB+IHNjYWxlKG1pbikrICgxfHVpZCksIGRhdGEgPSBhdWRpb19iaW5kZWQgKSkNCg0KYGBgDQo=