R is sort of a sneaky bastard when it comes to specifying contrasts and makes it easy to confuse contrast parameterization with contrast transformations. I’ll start with how it would seem one would specify contrasts.

data("warpbreaks")
head(warpbreaks[1:5,])
apply(warpbreaks[,-1],2, function (x) length(unique(x))) # we can see wool has 2 levels and tension 3
   wool tension 
      2       3 
aggregate(breaks ~ tension, data= warpbreaks, mean)

lets specify some contrasts to look at for the tension variable:

levels(warpbreaks$tension) 
[1] "L" "M" "H"
lVSmh<-c(1,-.5,-.5)
mVSh<-c(0,1,-1)
contrasts(warpbreaks$tension)<-cbind(lVSmh,mVSh)
print(contrasts(warpbreaks$tension)) # looks good
  lVSmh mVSh
L   1.0    0
M  -0.5    1
H  -0.5   -1
sum(apply(contrasts(warpbreaks$tension),1,function (x) prod(x) )) #check to see if contrasts are orthogonal
[1] 0
m1<-lm(breaks ~ tension, data = warpbreaks)
summary(m1)

Call:
lm(formula = breaks ~ tension, data = warpbreaks)

Residuals:
    Min      1Q  Median      3Q     Max 
-22.389  -8.139  -2.667   6.333  33.611 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)    28.148      1.617  17.410  < 2e-16 ***
tensionlVSmh    8.241      2.286   3.604 0.000711 ***
tensionmVSh     2.361      1.980   1.192 0.238614    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 11.88 on 51 degrees of freedom
Multiple R-squared:  0.2203,    Adjusted R-squared:  0.1898 
F-statistic: 7.206 on 2 and 51 DF,  p-value: 0.001753
#the intercept should equal the grand mean
cat("mean breaks:",mean(warpbreaks$breaks),"calculated intercept:" ,as.numeric(m1$coefficients[1]))
mean breaks: 28.14815 calculated intercept: 28.14815
#the first beta coefficient should equal the difference between mean(l) and (m+h)/2 which is equal to 36.38889- 24.02778 = 12.36111
cat("mean(l)-(m+h)/2:",aggregate(breaks ~ tension, data = warpbreaks, mean)[1,2]-((aggregate(breaks ~ tension, data = warpbreaks, mean)[2,2]+aggregate(breaks ~ tension, data = warpbreaks, mean)[3,2])/2),"calculated beta:",as.numeric(m1$coefficients[2]) ) # off by about four
mean(l)-(m+h)/2: 12.36111 calculated beta: 8.240741
#the second beta coef should equal m - h , 26.38889- 21.66667 = 4.7222
cat("mean(m)-mean(h):",aggregate(breaks ~ tension, data = warpbreaks, mean)[2,2] - aggregate(breaks ~ tension, data = warpbreaks, mean)[3,2],"calculated beta:",as.numeric(m1$coefficients[3]) ) ##off by two or so
mean(m)-mean(h): 4.722222 calculated beta: 2.361111

Well something is clearly off from the output above, turns out with missed a critical step which is intverting the contrast matrix:

library(MASS)
mat<-rbind(lVSmh,mVSh)
cmat<-ginv(mat) #take the inverse
contrasts(warpbreaks$tension)<-cmat
m2<-lm(breaks ~ tension, data = warpbreaks)
summary(m2)

Call:
lm(formula = breaks ~ tension, data = warpbreaks)

Residuals:
    Min      1Q  Median      3Q     Max 
-22.389  -8.139  -2.667   6.333  33.611 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   28.148      1.617  17.410  < 2e-16 ***
tension1      12.361      3.430   3.604 0.000711 ***
tension2       4.722      3.960   1.192 0.238614    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 11.88 on 51 degrees of freedom
Multiple R-squared:  0.2203,    Adjusted R-squared:  0.1898 
F-statistic: 7.206 on 2 and 51 DF,  p-value: 0.001753
cat("mean breaks:",mean(warpbreaks$breaks),"calculated intercept:" , as.numeric(m2$coefficients[1])) #TRUE
mean breaks: 28.14815 calculated intercept: 28.14815
#the first beta coefficient should equal the difference between mean(l) and (m+h)/2
cat("mean(l)-(m+h)/2:",aggregate(breaks ~ tension, data = warpbreaks, mean)[1,2]-((aggregate(breaks ~ tension, data = warpbreaks, mean)[2,2]+aggregate(breaks ~ tension, data = warpbreaks, mean)[3,2])/2),"calculated beta:",as.numeric(m2$coefficients[2]) ) # TRUE
mean(l)-(m+h)/2: 12.36111 calculated beta: 12.36111
#the second beta coef should equal m - h 
cat("mean(m)-mean(h):",aggregate(breaks ~ tension, data = warpbreaks, mean)[2,2] - aggregate(breaks ~ tension, data = warpbreaks, mean)[3,2],"calculated beta:",as.numeric(m2$coefficients[3]) ) 
mean(m)-mean(h): 4.722222 calculated beta: 4.722222

A similar approach that also does the trick with base R assuming you specify a square matrix (i.e., k-1 columns plus a column for the intercept…in this case, 3x3)

mat<-rbind(intercept=c(1,1,1),lVSmh,mVSh)
inv.mat<-solve(mat) #take the inverse, need a square matrix
contrasts(warpbreaks$tension)<-inv.mat[,-1] #drop the intercept
m3<-lm(breaks ~ tension, data = warpbreaks)
summary(m3)

Call:
lm(formula = breaks ~ tension, data = warpbreaks)

Residuals:
    Min      1Q  Median      3Q     Max 
-22.389  -8.139  -2.667   6.333  33.611 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)    28.148      1.617  17.410  < 2e-16 ***
tensionlVSmh   12.361      3.430   3.604 0.000711 ***
tensionmVSh     4.722      3.960   1.192 0.238614    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 11.88 on 51 degrees of freedom
Multiple R-squared:  0.2203,    Adjusted R-squared:  0.1898 
F-statistic: 7.206 on 2 and 51 DF,  p-value: 0.001753
all.equal(as.numeric(m3$coefficients[1]),as.numeric(m2$coefficients[1]))
[1] TRUE
all.equal(as.numeric(m3$coefficients[2]),as.numeric(m2$coefficients[2]))
[1] TRUE
all.equal(as.numeric(m3$coefficients[3]),as.numeric(m2$coefficients[3]))
[1] TRUE

However, it is important to note that while the betas could be off by some multiplicative factor the resulting se, t and p-values will be correct. As long are you’re specifying orthogonal contrasts your results sans the betas will be valid. However, I think it is good practice to get in the habit of inverting the contrast matrix because, as we will see shortly, it becomes much more important when specifying non-orthogonal contrasts.

easy and correct way to do deviation or sum coding within r. Here, we will grand the overall mean to a level of the ind var

hsb <- read_csv("C:/Users/dasil/Desktop/hsb2_cat.csv")
Parsed with column specification:
cols(
  id = col_integer(),
  gender = col_character(),
  race = col_character(),
  ses = col_character(),
  schtyp = col_character(),
  prog = col_character(),
  read = col_integer(),
  write = col_integer(),
  math = col_integer(),
  science = col_integer(),
  socst = col_integer()
)
library(MASS)
hsb$race<-as.factor(hsb$race)
hsb$race<-relevel(hsb$race,ref="hispanic")
contrasts(hsb$race)<-contr.sum(4)
m4<-lm(write ~ race, data=hsb)
summary(m4)

Call:
lm(formula = write ~ race, data = hsb)

Residuals:
     Min       1Q   Median       3Q      Max 
-23.0552  -5.4583   0.9724   7.0000  18.8000 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  51.6784     0.9821  52.619  < 2e-16 ***
race1        -5.2200     1.6314  -3.200  0.00160 ** 
race2        -3.4784     1.7323  -2.008  0.04602 *  
race3         6.3216     2.1603   2.926  0.00384 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9.025 on 196 degrees of freedom
Multiple R-squared:  0.1071,    Adjusted R-squared:  0.0934 
F-statistic: 7.833 on 3 and 196 DF,  p-value: 5.785e-05
cat("grandmean:",mean(aggregate(write ~ race, hsb, mean)$write),"calculated intercept",as.numeric(m4$coefficients[1]))
grandmean: 51.67838 calculated intercept 51.67838
##all checks out!
cat(aggregate(write ~ race, hsb,mean)[1,2]-as.numeric(m4$coefficients[1]) ,as.numeric(m4$coefficients[2]))
-5.220043 -5.220043
cat(aggregate(write ~ race, hsb,mean)[2,2]-as.numeric(m4$coefficients[1]) ,as.numeric(m4$coefficients[3]))
-3.478376 -3.478376
cat(aggregate(write ~ race, hsb,mean)[3,2]-as.numeric(m4$coefficients[1]) ,as.numeric(m4$coefficients[4]))
6.321624 6.321624
 
 

Now, we can try and specify the contrast how they would appear and fit a model

intercept<-c( 0.25,  0.25,  0.25,  0.25) 
con1<-c( 0.75, -0.25, -0.25, -0.25) 
con2<-c(-0.25,  0.75, -0.25, -0.25) 
con3<-c(-0.25, -0.25,  0.75, -0.25)
contrasts(hsb$race)<-cbind(con1,con2,con3)
m5<-lm(write ~ race, data=hsb)
summary(m5)

Call:
lm(formula = write ~ race, data = hsb)

Residuals:
     Min       1Q   Median       3Q      Max 
-23.0552  -5.4583   0.9724   7.0000  18.8000 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  51.6784     0.9821  52.619  < 2e-16 ***
racecon1     -7.5968     1.9889  -3.820 0.000179 ***
racecon2     -5.8552     2.1528  -2.720 0.007118 ** 
racecon3      3.9448     2.8225   1.398 0.163803    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9.025 on 196 degrees of freedom
Multiple R-squared:  0.1071,    Adjusted R-squared:  0.0934 
F-statistic: 7.833 on 3 and 196 DF,  p-value: 5.785e-05
cat("Calculated:", m4$coefficients[2],"R coded:", m5$coefficients[2])
Calculated: -5.220043 R coded: -7.596839
cat("Calculated:", m4$coefficients[3],"R coded:", m5$coefficients[3])
Calculated: -3.478376 R coded: -5.855172
cat("Calculated:", m4$coefficients[4],"R coded:", m5$coefficients[4])
Calculated: 6.321624 R coded: 3.944828

we can see the betas are off, but what about the SE, t-values and p’s?

summary(m4)[4]
$coefficients
             Estimate Std. Error   t value      Pr(>|t|)
(Intercept) 51.678376   0.982122 52.619098 1.431984e-117
race1       -5.220043   1.631408 -3.199716  1.604633e-03
race2       -3.478376   1.732305 -2.007947  4.602191e-02
race3        6.321624   2.160314  2.926252  3.835918e-03
summary(m5)[4]
$coefficients
             Estimate Std. Error   t value      Pr(>|t|)
(Intercept) 51.678376   0.982122 52.619098 1.431984e-117
racecon1    -7.596839   1.988870 -3.819677  1.792682e-04
racecon2    -5.855172   2.152760 -2.719845  7.118082e-03
racecon3     3.944828   2.822504  1.397634  1.638029e-01

Ok, so we saw the entire output is off. Now, we should be able to invert the contrast matrix and see if our output matches that from base R for deviation coding:

mat<-ginv(rbind(con1,con2,con3))
contrasts(hsb$race)<-mat
m6<-lm(write ~ race, data=hsb)
summary(m6)

Call:
lm(formula = write ~ race, data = hsb)

Residuals:
     Min       1Q   Median       3Q      Max 
-23.0552  -5.4583   0.9724   7.0000  18.8000 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  51.6784     0.9821  52.619  < 2e-16 ***
race1        -5.2200     1.6314  -3.200  0.00160 ** 
race2        -3.4784     1.7323  -2.008  0.04602 *  
race3         6.3216     2.1603   2.926  0.00384 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9.025 on 196 degrees of freedom
Multiple R-squared:  0.1071,    Adjusted R-squared:  0.0934 
F-statistic: 7.833 on 3 and 196 DF,  p-value: 5.785e-05
cat("coded by hand:", m6$coefficients[2],"R coded:", m4$coefficients[2])
coded by hand: -5.220043 R coded: -5.220043
cat("coded by hand:", m6$coefficients[3],"R coded:", m4$coefficients[3])
coded by hand: -3.478376 R coded: -3.478376
cat("coded by hand:", m6$coefficients[4],"R coded:", m4$coefficients[4])
coded by hand: 6.321624 R coded: 6.321624

So, we can see that our own coded contrasts match the output of r. R is doing the same thing behind the scences when we ask for deviation coded contrasts. Finally, we can also perform the same sort of operation in base R. Here, we will need a vector corresponding to intercepts to complete the square contrasts matrix.

mat<-solve(rbind(intercept,con1,con2,con3))
contrasts(hsb$race)<-mat[,-1] #leave off intercept
m7<-lm(write ~ race, data=hsb)
summary(m7)

Call:
lm(formula = write ~ race, data = hsb)

Residuals:
     Min       1Q   Median       3Q      Max 
-23.0552  -5.4583   0.9724   7.0000  18.8000 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  51.6784     0.9821  52.619  < 2e-16 ***
racecon1     -5.2200     1.6314  -3.200  0.00160 ** 
racecon2     -3.4784     1.7323  -2.008  0.04602 *  
racecon3      6.3216     2.1603   2.926  0.00384 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9.025 on 196 degrees of freedom
Multiple R-squared:  0.1071,    Adjusted R-squared:  0.0934 
F-statistic: 7.833 on 3 and 196 DF,  p-value: 5.785e-05
cat("coded by hand:", m7$coefficients[2],"R coded:", m4$coefficients[2])
coded by hand: -5.220043 R coded: -5.220043
cat("coded by hand:", m7$coefficients[3],"R coded:", m4$coefficients[3])
coded by hand: -3.478376 R coded: -3.478376
cat("coded by hand:", m7$coefficients[4],"R coded:", m4$coefficients[4])
coded by hand: 6.321624 R coded: 6.321624
LS0tDQp0aXRsZTogIlNwZWNpZnlpbmcgb3J0aG9nb25hbCBhbmQgbm9uLW9ydGhvZ29uYWwgY29udHJhc3RzIGluIFIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCmJvZHksIHRkIHsNCiAgIGZvbnQtc2l6ZTogMjJweDsNCn0NCmNvZGUucnsNCiAgZm9udC1zaXplOiAxNnB4Ow0KfQ0KcHJlIHsNCiAgZm9udC1zaXplOiAxNnB4DQp9DQo8L3N0eWxlPg0KDQoNClIgaXMgc29ydCBvZiBhIHNuZWFreSBiYXN0YXJkIHdoZW4gaXQgY29tZXMgdG8gc3BlY2lmeWluZyBjb250cmFzdHMgYW5kIG1ha2VzIGl0IGVhc3kgdG8gY29uZnVzZSBjb250cmFzdCBwYXJhbWV0ZXJpemF0aW9uIHdpdGggY29udHJhc3QgdHJhbnNmb3JtYXRpb25zLiAgSSdsbCBzdGFydCB3aXRoIGhvdyBpdCB3b3VsZCBzZWVtIG9uZSB3b3VsZCBzcGVjaWZ5IGNvbnRyYXN0cy4NCg0KYGBge3J9DQpkYXRhKCJ3YXJwYnJlYWtzIikNCg0KaGVhZCh3YXJwYnJlYWtzWzE6NSxdKQ0KDQphcHBseSh3YXJwYnJlYWtzWywtMV0sMiwgZnVuY3Rpb24gKHgpIGxlbmd0aCh1bmlxdWUoeCkpKSAjIHdlIGNhbiBzZWUgd29vbCBoYXMgMiBsZXZlbHMgYW5kIHRlbnNpb24gMw0KDQphZ2dyZWdhdGUoYnJlYWtzIH4gdGVuc2lvbiwgZGF0YT0gd2FycGJyZWFrcywgbWVhbikNCg0KYGBgDQoNCmxldHMgc3BlY2lmeSBzb21lIGNvbnRyYXN0cyB0byBsb29rIGF0IGZvciB0aGUgdGVuc2lvbiB2YXJpYWJsZToNCmBgYHtyfQ0KbGV2ZWxzKHdhcnBicmVha3MkdGVuc2lvbikgDQoNCmxWU21oPC1jKDEsLS41LC0uNSkNCm1WU2g8LWMoMCwxLC0xKQ0KDQpjb250cmFzdHMod2FycGJyZWFrcyR0ZW5zaW9uKTwtY2JpbmQobFZTbWgsbVZTaCkNCnByaW50KGNvbnRyYXN0cyh3YXJwYnJlYWtzJHRlbnNpb24pKSAjIGxvb2tzIGdvb2QNCg0Kc3VtKGFwcGx5KGNvbnRyYXN0cyh3YXJwYnJlYWtzJHRlbnNpb24pLDEsZnVuY3Rpb24gKHgpIHByb2QoeCkgKSkgI2NoZWNrIHRvIHNlZSBpZiBjb250cmFzdHMgYXJlIG9ydGhvZ29uYWwNCg0KbTE8LWxtKGJyZWFrcyB+IHRlbnNpb24sIGRhdGEgPSB3YXJwYnJlYWtzKQ0Kc3VtbWFyeShtMSkNCg0KI3RoZSBpbnRlcmNlcHQgc2hvdWxkIGVxdWFsIHRoZSBncmFuZCBtZWFuDQpjYXQoIm1lYW4gYnJlYWtzOiIsbWVhbih3YXJwYnJlYWtzJGJyZWFrcyksImNhbGN1bGF0ZWQgaW50ZXJjZXB0OiIgLGFzLm51bWVyaWMobTEkY29lZmZpY2llbnRzWzFdKSkNCg0KI3RoZSBmaXJzdCBiZXRhIGNvZWZmaWNpZW50IHNob3VsZCBlcXVhbCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG1lYW4obCkgYW5kIChtK2gpLzIgd2hpY2ggaXMgZXF1YWwgdG8gMzYuMzg4ODktIDI0LjAyNzc4ID0gMTIuMzYxMTENCg0KY2F0KCJtZWFuKGwpLShtK2gpLzI6IixhZ2dyZWdhdGUoYnJlYWtzIH4gdGVuc2lvbiwgZGF0YSA9IHdhcnBicmVha3MsIG1lYW4pWzEsMl0tKChhZ2dyZWdhdGUoYnJlYWtzIH4gdGVuc2lvbiwgZGF0YSA9IHdhcnBicmVha3MsIG1lYW4pWzIsMl0rYWdncmVnYXRlKGJyZWFrcyB+IHRlbnNpb24sIGRhdGEgPSB3YXJwYnJlYWtzLCBtZWFuKVszLDJdKS8yKSwiY2FsY3VsYXRlZCBiZXRhOiIsYXMubnVtZXJpYyhtMSRjb2VmZmljaWVudHNbMl0pICkgIyBvZmYgYnkgYWJvdXQgZm91cg0KDQoNCiN0aGUgc2Vjb25kIGJldGEgY29lZiBzaG91bGQgZXF1YWwgbSAtIGggLCAyNi4zODg4OS0gMjEuNjY2NjcgPSA0LjcyMjINCg0KY2F0KCJtZWFuKG0pLW1lYW4oaCk6IixhZ2dyZWdhdGUoYnJlYWtzIH4gdGVuc2lvbiwgZGF0YSA9IHdhcnBicmVha3MsIG1lYW4pWzIsMl0gLSBhZ2dyZWdhdGUoYnJlYWtzIH4gdGVuc2lvbiwgZGF0YSA9IHdhcnBicmVha3MsIG1lYW4pWzMsMl0sImNhbGN1bGF0ZWQgYmV0YToiLGFzLm51bWVyaWMobTEkY29lZmZpY2llbnRzWzNdKSApICMjb2ZmIGJ5IHR3byBvciBzbw0KDQpgYGANCldlbGwgc29tZXRoaW5nIGlzIGNsZWFybHkgb2ZmIGZyb20gdGhlIG91dHB1dCBhYm92ZSwgdHVybnMgb3V0IHdpdGggbWlzc2VkIGEgY3JpdGljYWwgc3RlcCB3aGljaCBpcyBpbnR2ZXJ0aW5nIHRoZSBjb250cmFzdCBtYXRyaXg6DQoNCmBgYHtyfQ0KbGlicmFyeShNQVNTKQ0KDQptYXQ8LXJiaW5kKGxWU21oLG1WU2gpDQoNCmNtYXQ8LWdpbnYobWF0KSAjdGFrZSB0aGUgaW52ZXJzZQ0KDQpjb250cmFzdHMod2FycGJyZWFrcyR0ZW5zaW9uKTwtY21hdA0KDQptMjwtbG0oYnJlYWtzIH4gdGVuc2lvbiwgZGF0YSA9IHdhcnBicmVha3MpDQpzdW1tYXJ5KG0yKQ0KDQpjYXQoIm1lYW4gYnJlYWtzOiIsbWVhbih3YXJwYnJlYWtzJGJyZWFrcyksImNhbGN1bGF0ZWQgaW50ZXJjZXB0OiIgLCBhcy5udW1lcmljKG0yJGNvZWZmaWNpZW50c1sxXSkpICNUUlVFDQoNCiN0aGUgZmlyc3QgYmV0YSBjb2VmZmljaWVudCBzaG91bGQgZXF1YWwgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBtZWFuKGwpIGFuZCAobStoKS8yDQoNCmNhdCgibWVhbihsKS0obStoKS8yOiIsYWdncmVnYXRlKGJyZWFrcyB+IHRlbnNpb24sIGRhdGEgPSB3YXJwYnJlYWtzLCBtZWFuKVsxLDJdLSgoYWdncmVnYXRlKGJyZWFrcyB+IHRlbnNpb24sIGRhdGEgPSB3YXJwYnJlYWtzLCBtZWFuKVsyLDJdK2FnZ3JlZ2F0ZShicmVha3MgfiB0ZW5zaW9uLCBkYXRhID0gd2FycGJyZWFrcywgbWVhbilbMywyXSkvMiksImNhbGN1bGF0ZWQgYmV0YToiLGFzLm51bWVyaWMobTIkY29lZmZpY2llbnRzWzJdKSApICMgVFJVRQ0KDQoNCiN0aGUgc2Vjb25kIGJldGEgY29lZiBzaG91bGQgZXF1YWwgbSAtIGggDQoNCmNhdCgibWVhbihtKS1tZWFuKGgpOiIsYWdncmVnYXRlKGJyZWFrcyB+IHRlbnNpb24sIGRhdGEgPSB3YXJwYnJlYWtzLCBtZWFuKVsyLDJdIC0gYWdncmVnYXRlKGJyZWFrcyB+IHRlbnNpb24sIGRhdGEgPSB3YXJwYnJlYWtzLCBtZWFuKVszLDJdLCJjYWxjdWxhdGVkIGJldGE6Iixhcy5udW1lcmljKG0yJGNvZWZmaWNpZW50c1szXSkgKSANCg0KYGBgDQpBIHNpbWlsYXIgYXBwcm9hY2ggdGhhdCBhbHNvIGRvZXMgdGhlIHRyaWNrIHdpdGggYmFzZSBSIGFzc3VtaW5nIHlvdSBzcGVjaWZ5IGEgc3F1YXJlIG1hdHJpeCAoaS5lLiwgay0xIGNvbHVtbnMgcGx1cyBhIGNvbHVtbiBmb3IgdGhlIGludGVyY2VwdC4uLmluIHRoaXMgY2FzZSwgM3gzKQ0KDQpgYGB7cn0NCg0KbWF0PC1yYmluZChpbnRlcmNlcHQ9YygxLDEsMSksbFZTbWgsbVZTaCkNCg0KaW52Lm1hdDwtc29sdmUobWF0KSAjdGFrZSB0aGUgaW52ZXJzZSwgbmVlZCBhIHNxdWFyZSBtYXRyaXgNCg0KY29udHJhc3RzKHdhcnBicmVha3MkdGVuc2lvbik8LWludi5tYXRbLC0xXSAjZHJvcCB0aGUgaW50ZXJjZXB0DQoNCm0zPC1sbShicmVha3MgfiB0ZW5zaW9uLCBkYXRhID0gd2FycGJyZWFrcykNCnN1bW1hcnkobTMpDQoNCmFsbC5lcXVhbChhcy5udW1lcmljKG0zJGNvZWZmaWNpZW50c1sxXSksYXMubnVtZXJpYyhtMiRjb2VmZmljaWVudHNbMV0pKQ0KYWxsLmVxdWFsKGFzLm51bWVyaWMobTMkY29lZmZpY2llbnRzWzJdKSxhcy5udW1lcmljKG0yJGNvZWZmaWNpZW50c1syXSkpDQphbGwuZXF1YWwoYXMubnVtZXJpYyhtMyRjb2VmZmljaWVudHNbM10pLGFzLm51bWVyaWMobTIkY29lZmZpY2llbnRzWzNdKSkNCg0KYGBgDQpIb3dldmVyLCBpdCBpcyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHdoaWxlIHRoZSBiZXRhcyBjb3VsZCBiZSBvZmYgYnkgc29tZSBtdWx0aXBsaWNhdGl2ZSBmYWN0b3IgdGhlIHJlc3VsdGluZyBzZSwgdCBhbmQgcC12YWx1ZXMgd2lsbCBiZSBjb3JyZWN0LiAgQXMgbG9uZyBhcmUgeW91J3JlIHNwZWNpZnlpbmcgb3J0aG9nb25hbCBjb250cmFzdHMgeW91ciByZXN1bHRzIHNhbnMgdGhlIGJldGFzIHdpbGwgYmUgdmFsaWQuICBIb3dldmVyLCBJIHRoaW5rIGl0IGlzIGdvb2QgcHJhY3RpY2UgdG8gZ2V0IGluIHRoZSBoYWJpdCBvZiBpbnZlcnRpbmcgdGhlIGNvbnRyYXN0IG1hdHJpeCBiZWNhdXNlLCBhcyB3ZSB3aWxsIHNlZSBzaG9ydGx5LCBpdCBiZWNvbWVzIG11Y2ggbW9yZSBpbXBvcnRhbnQgd2hlbiBzcGVjaWZ5aW5nIG5vbi1vcnRob2dvbmFsIGNvbnRyYXN0cy4NCg0KDQplYXN5IGFuZCBjb3JyZWN0IHdheSB0byBkbyBkZXZpYXRpb24gb3Igc3VtIGNvZGluZyB3aXRoaW4gci4gIEhlcmUsIHdlIHdpbGwgZ3JhbmQgdGhlIG92ZXJhbGwgbWVhbiB0byBhIGxldmVsIG9mIHRoZSBpbmQgdmFyDQpgYGB7cn0NCg0KaHNiIDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy9kYXNpbC9EZXNrdG9wL2hzYjJfY2F0LmNzdiIpDQoNCg0KbGlicmFyeShNQVNTKQ0KDQpoc2IkcmFjZTwtYXMuZmFjdG9yKGhzYiRyYWNlKQ0KaHNiJHJhY2U8LXJlbGV2ZWwoaHNiJHJhY2UscmVmPSJoaXNwYW5pYyIpDQoNCmNvbnRyYXN0cyhoc2IkcmFjZSk8LWNvbnRyLnN1bSg0KQ0KDQptNDwtbG0od3JpdGUgfiByYWNlLCBkYXRhPWhzYikNCnN1bW1hcnkobTQpDQoNCmNhdCgiZ3JhbmRtZWFuOiIsbWVhbihhZ2dyZWdhdGUod3JpdGUgfiByYWNlLCBoc2IsIG1lYW4pJHdyaXRlKSwiY2FsY3VsYXRlZCBpbnRlcmNlcHQiLGFzLm51bWVyaWMobTQkY29lZmZpY2llbnRzWzFdKSkNCiMjYWxsIGNoZWNrcyBvdXQhDQpjYXQoYWdncmVnYXRlKHdyaXRlIH4gcmFjZSwgaHNiLG1lYW4pWzEsMl0tYXMubnVtZXJpYyhtNCRjb2VmZmljaWVudHNbMV0pICxhcy5udW1lcmljKG00JGNvZWZmaWNpZW50c1syXSkpDQpjYXQoYWdncmVnYXRlKHdyaXRlIH4gcmFjZSwgaHNiLG1lYW4pWzIsMl0tYXMubnVtZXJpYyhtNCRjb2VmZmljaWVudHNbMV0pICxhcy5udW1lcmljKG00JGNvZWZmaWNpZW50c1szXSkpDQpjYXQoYWdncmVnYXRlKHdyaXRlIH4gcmFjZSwgaHNiLG1lYW4pWzMsMl0tYXMubnVtZXJpYyhtNCRjb2VmZmljaWVudHNbMV0pICxhcy5udW1lcmljKG00JGNvZWZmaWNpZW50c1s0XSkpDQogDQogDQpgYGANCg0KTm93LCB3ZSBjYW4gdHJ5IGFuZCBzcGVjaWZ5IHRoZSBjb250cmFzdCBob3cgdGhleSB3b3VsZCBhcHBlYXIgYW5kIGZpdCBhIG1vZGVsDQpgYGB7cn0NCg0KaW50ZXJjZXB0PC1jKCAwLjI1LCAgMC4yNSwgIDAuMjUsICAwLjI1KSANCmNvbjE8LWMoIDAuNzUsIC0wLjI1LCAtMC4yNSwgLTAuMjUpIA0KY29uMjwtYygtMC4yNSwgIDAuNzUsIC0wLjI1LCAtMC4yNSkgDQpjb24zPC1jKC0wLjI1LCAtMC4yNSwgIDAuNzUsIC0wLjI1KQ0KDQoNCmNvbnRyYXN0cyhoc2IkcmFjZSk8LWNiaW5kKGNvbjEsY29uMixjb24zKQ0KDQptNTwtbG0od3JpdGUgfiByYWNlLCBkYXRhPWhzYikNCnN1bW1hcnkobTUpDQoNCmNhdCgiQ2FsY3VsYXRlZDoiLCBtNCRjb2VmZmljaWVudHNbMl0sIlIgY29kZWQ6IiwgbTUkY29lZmZpY2llbnRzWzJdKQ0KY2F0KCJDYWxjdWxhdGVkOiIsIG00JGNvZWZmaWNpZW50c1szXSwiUiBjb2RlZDoiLCBtNSRjb2VmZmljaWVudHNbM10pDQpjYXQoIkNhbGN1bGF0ZWQ6IiwgbTQkY29lZmZpY2llbnRzWzRdLCJSIGNvZGVkOiIsIG01JGNvZWZmaWNpZW50c1s0XSkNCg0KYGBgDQoNCndlIGNhbiBzZWUgdGhlIGJldGFzIGFyZSBvZmYsIGJ1dCB3aGF0IGFib3V0IHRoZSBTRSwgdC12YWx1ZXMgYW5kIHAncz8NCmBgYHtyfQ0Kc3VtbWFyeShtNClbNF0NCnN1bW1hcnkobTUpWzRdDQpgYGANCg0KDQpPaywgc28gd2Ugc2F3IHRoZSBlbnRpcmUgb3V0cHV0IGlzIG9mZi4gIE5vdywgd2Ugc2hvdWxkIGJlIGFibGUgdG8gaW52ZXJ0IHRoZSBjb250cmFzdCBtYXRyaXggYW5kIHNlZSBpZiBvdXIgb3V0cHV0IG1hdGNoZXMgdGhhdCBmcm9tIGJhc2UgUiBmb3IgZGV2aWF0aW9uIGNvZGluZzoNCmBgYHtyfQ0KDQptYXQ8LWdpbnYocmJpbmQoY29uMSxjb24yLGNvbjMpKQ0KDQpjb250cmFzdHMoaHNiJHJhY2UpPC1tYXQNCg0KbTY8LWxtKHdyaXRlIH4gcmFjZSwgZGF0YT1oc2IpDQpzdW1tYXJ5KG02KQ0KDQpjYXQoImNvZGVkIGJ5IGhhbmQ6IiwgbTYkY29lZmZpY2llbnRzWzJdLCJSIGNvZGVkOiIsIG00JGNvZWZmaWNpZW50c1syXSkNCmNhdCgiY29kZWQgYnkgaGFuZDoiLCBtNiRjb2VmZmljaWVudHNbM10sIlIgY29kZWQ6IiwgbTQkY29lZmZpY2llbnRzWzNdKQ0KY2F0KCJjb2RlZCBieSBoYW5kOiIsIG02JGNvZWZmaWNpZW50c1s0XSwiUiBjb2RlZDoiLCBtNCRjb2VmZmljaWVudHNbNF0pDQoNCmBgYA0KU28sIHdlIGNhbiBzZWUgdGhhdCBvdXIgb3duIGNvZGVkIGNvbnRyYXN0cyBtYXRjaCB0aGUgb3V0cHV0IG9mIHIuIFIgaXMgZG9pbmcgdGhlIHNhbWUgdGhpbmcgYmVoaW5kIHRoZSBzY2VuY2VzIHdoZW4gd2UgYXNrIGZvciBkZXZpYXRpb24gY29kZWQgY29udHJhc3RzLiAgRmluYWxseSwgd2UgY2FuIGFsc28gcGVyZm9ybSB0aGUgc2FtZSBzb3J0IG9mIG9wZXJhdGlvbiBpbiBiYXNlIFIuICBIZXJlLCB3ZSB3aWxsIG5lZWQgYSB2ZWN0b3IgY29ycmVzcG9uZGluZyB0byBpbnRlcmNlcHRzIHRvIGNvbXBsZXRlIHRoZSBzcXVhcmUgY29udHJhc3RzIG1hdHJpeC4NCg0KYGBge3J9DQptYXQ8LXNvbHZlKHJiaW5kKGludGVyY2VwdCxjb24xLGNvbjIsY29uMykpDQoNCg0KY29udHJhc3RzKGhzYiRyYWNlKTwtbWF0WywtMV0gI2xlYXZlIG9mZiBpbnRlcmNlcHQNCg0KbTc8LWxtKHdyaXRlIH4gcmFjZSwgZGF0YT1oc2IpDQpzdW1tYXJ5KG03KQ0KDQpjYXQoImNvZGVkIGJ5IGhhbmQ6IiwgbTckY29lZmZpY2llbnRzWzJdLCJSIGNvZGVkOiIsIG00JGNvZWZmaWNpZW50c1syXSkNCmNhdCgiY29kZWQgYnkgaGFuZDoiLCBtNyRjb2VmZmljaWVudHNbM10sIlIgY29kZWQ6IiwgbTQkY29lZmZpY2llbnRzWzNdKQ0KY2F0KCJjb2RlZCBieSBoYW5kOiIsIG03JGNvZWZmaWNpZW50c1s0XSwiUiBjb2RlZDoiLCBtNCRjb2VmZmljaWVudHNbNF0pDQoNCmBgYA0KDQoNCg==