library(psych)

Answers to the challenge

mat<-matrix(c(3,2,1,2), byrow = TRUE, ncol = 2)
eigen(mat)
eigen() decomposition
$values
[1] 4 1

$vectors
          [,1]       [,2]
[1,] 0.8944272 -0.7071068
[2,] 0.4472136  0.7071068

A quick word about eigenvectors and values

Eigenvectors and Eigenvalues

For any number set of points, we can digest these points into eigenvectors and eigenvalue. Eigenvectors and eigenvalues exist in pairs with eigenvector describes a direction along which a linear transformation acts simply by “stretching/compressing” and/or “flipping”; and eigenvalue describing the degree of that transformation in that direction. The numbers of eigenvectors is equal to the number of dimensions of your data.

mat<-matrix(c(3,2,1,2), byrow = TRUE, ncol = 2)
eigen(mat)
eigen() decomposition
$values
[1] 4 1

$vectors
          [,1]       [,2]
[1,] 0.8944272 -0.7071068
[2,] 0.4472136  0.7071068

Latent variable analysis

Factor analysis

The source to many of the notes in this lesson (and a lot more detail on the subject) can be found at Finch and French (2015) and Beaujean (2014).

Latent variables in statistics are variables that are not directly observable and are inferred from a mathematical model. One advantage of using latent variables is that it helps reduce the dimensionality of data (a major theme of multivariate statistics) and has been used in many scientific disciplines.

One type of latent variable analysis is factor analysis and used extensively in social and behavioral sciences. Factor analysis allows the researcher to create models of non-observable factors (e.g., motivations, constraints, identity) from multivariate data.

There are two broad types of factor analysis: 1) Exploratory factor analysis (EFA) and 2) Confirmatory factor analysis (CFA). The difference between the two is in the degree of ** a priori ** structure that is assummed in the model. In using EFA the researcher does not impose a specific latent structure on the observable data, but allows the analysis to provide the optimal number of factors. In contrast to EFA, with CFA the researcher explicitly links the indicators with the factors to which they theoretically belong.

Exploratory factor analysis

EFA consists of two steps (1) factor extraction and (2) factor rotation. Factor rotation involves estimating the intial model paramters (i.e., factor loadings: loadings reflect the relationships between the factors and the indicators, with larger values being indicative of a closer association between a latent and observed variable). There are as many factors as number of indicator variables (i.e., columns used to define the latent variable).

Factor extraction

Several extraction methods exist, with the most popular being maximum likelihood (ML) and principal axis factor (PAF). ML method has a direct assessment of model fit but also relies on multivariate normality. PAF does not have a distributional assumption but does not have a test of statistical fit.

Factor rotation

Factor rotation is the transformation of the initial set of factor loadings to simplify the interpretation of of the results by finding a simple solution. Methods fall into two broad categories: orthogonal and oblique. Orthogonal rotations constrain the correlations among factors to be zero, whereas oblique rotations allow the factors to be correlated. The most popular orthogonal rotation method is VARIMAX, while among the oblique rotations PROMAX and OBLIMIN are popular. Decision on which method to use, should be based in theory and empirical grounds.

Determining the optimal number of factors

  1. Eigenvalues greater than 1. Eigenvalues greater than 1, account for more variance than any of the observed values.
  2. Scree plots. Eigenvalues on the y-axis and number of factors on the x axis. Identify where the plot “flattens out”
  3. Proportion of variance. Identify when there is no “appreciative” gain in the percentage of variance explained. Similar to scree plot
  4. Residual correlation matrix for the observed indicators. residuals larger than 0.05 are considered to be too large, so that a good solution is one which produces few residual correlations greater than 0.05 in absolute value.
  5. Parallel analysis. Described in Horn (1965). Several steps that include comparing the actual data to two randomly generated datasets. THis is the most commonly used.

The data

For this data, we will use the data set provided by Finch and French (2015) here. The data represents information collected on acheivement goal orientation. Achievement goal orientation refers to how an individual interprets and reacts to tasks, resulting in different patterns of cognition, affect and behavior. There are 12 questions with results representing a 7-point likert-type scale from 430 college students.

The columns refer to:

  • AGS1 = My goal is to completely master the material presented in my classes. (MAP)
  • AGS2 = I want to avoid learning less than it is possible to learn. (MAV)
  • AGS3 = It is important for me to do better than other students. (PAP)
  • AGS4 = I want to avoid performing poorly compared to others. (PAV)
  • AGS5 = I want to learn as much as possible. (MAP)
  • AGS6 = It is important for me to avoid an incomplete understanding of the course material. (MAV)
  • AGS7 = It is important for me to understand the content of my courses as thoroughly as possible. (MAP)
  • AGS8 = My goal is to avoid performing worse than other students. (PAV)
  • AGS9 = I want to do well compared to other students. (PAP)
  • AGS10 = It is important for me to avoid doing poorly compared to other students. (PAV)
  • AGS11 = My goal is to perform better than the other students. (PAP)
  • AGS12 = My goal is to avoid learning less than I possibly could. (MAV)

The types of questions refer to 4 distinct latent traits: mastery approach (MAP), mastery avoidant (MAV), performance approach (PAP), and performance avoidant (PAV).

The data is in a SPSS format and I have converted it to a csv file for convience and is in our github data repository as goal_scale.csv

library(readr)
goal_scale <- read_csv("https://raw.githubusercontent.com/chrischizinski/SNR_R_Group/master/data/goal_scale.csv")
Parsed with column specification:
cols(
  ags1 = col_integer(),
  ags2 = col_integer(),
  ags3 = col_integer(),
  ags4 = col_integer(),
  ags5 = col_integer(),
  ags6 = col_integer(),
  ags7 = col_integer(),
  ags8 = col_integer(),
  ags9 = col_integer(),
  ags10 = col_integer(),
  ags11 = col_integer(),
  ags12 = col_integer()
)
head(goal_scale)

Fit an EFA models with factanal

agoal.efa<-factanal(~ags1+ags2+ags3+ags4+ags5+ags6+ags7+ags8+ags9+ags10+ags11+ ags12, factors=4, rotation="promax", data = goal_scale )
agoal.efa

Call:
factanal(x = ~ags1 + ags2 + ags3 + ags4 + ags5 + ags6 + ags7 +     ags8 + ags9 + ags10 + ags11 + ags12, factors = 4, data = goal_scale,     rotation = "promax")

Uniquenesses:
 ags1  ags2  ags3  ags4  ags5  ags6  ags7  ags8  ags9 ags10 ags11 ags12 
0.487 0.335 0.279 0.342 0.557 0.388 0.104 0.005 0.231 0.201 0.300 0.306 

Loadings:
      Factor1 Factor2 Factor3 Factor4
ags1           0.667                 
ags2                   0.844         
ags3   0.864                         
ags4   0.793           0.104  -0.116 
ags5           0.565   0.123         
ags6           0.764                 
ags7           1.023  -0.120         
ags8   0.756                   0.583 
ags9   0.884                         
ags10  0.866                   0.143 
ags11  0.799                   0.195 
ags12                  0.833         

               Factor1 Factor2 Factor3 Factor4
SS loadings      4.122   2.404   1.461   0.426
Proportion Var   0.344   0.200   0.122   0.036
Cumulative Var   0.344   0.544   0.666   0.701

Factor Correlations:
        Factor1 Factor2  Factor3  Factor4
Factor1  1.0000  0.0919 -0.08477  0.20174
Factor2  0.0919  1.0000  0.18936  0.66077
Factor3 -0.0848  0.1894  1.00000 -0.00277
Factor4  0.2017  0.6608 -0.00277  1.00000

Test of the hypothesis that 4 factors are sufficient.
The chi square statistic is 77.4 on 24 degrees of freedom.
The p-value is 0.000000157 

Uniqueness

Uniqueness reflects the proportion of variance in the indicators that are not explained by the factors. For example, 48.7% of variation in ags1 is not explained by the four factors.

agoal.efa$uniquenesses
     ags1      ags2      ags3      ags4      ags5      ags6      ags7      ags8      ags9     ags10     ags11     ags12 
0.4865429 0.3350171 0.2785319 0.3416042 0.5574857 0.3876667 0.1043941 0.0050000 0.2306985 0.2007897 0.2998883 0.3061390 

The opposite of uniqueness of communality, and this is the proportion of variances explained by the factors for each indicator.

1-agoal.efa$uniquenesses
     ags1      ags2      ags3      ags4      ags5      ags6      ags7      ags8      ags9     ags10     ags11     ags12 
0.5134571 0.6649829 0.7214681 0.6583958 0.4425143 0.6123333 0.8956059 0.9950000 0.7693015 0.7992103 0.7001117 0.6938610 

Loadings

ld<-loadings(agoal.efa)
ld

Loadings:
      Factor1 Factor2 Factor3 Factor4
ags1           0.667                 
ags2                   0.844         
ags3   0.864                         
ags4   0.793           0.104  -0.116 
ags5           0.565   0.123         
ags6           0.764                 
ags7           1.023  -0.120         
ags8   0.756                   0.583 
ags9   0.884                         
ags10  0.866                   0.143 
ags11  0.799                   0.195 
ags12                  0.833         

               Factor1 Factor2 Factor3 Factor4
SS loadings      4.122   2.404   1.461   0.426
Proportion Var   0.344   0.200   0.122   0.036
Cumulative Var   0.344   0.544   0.666   0.701

To help interpret our loadings, lets create a visualization of those loadings.

loadings<-as.data.frame(ld[,])
lt<- data.frame(indicator = paste("ags",1:12, sep =""),
           latent_traits = c("MAP", "MAV", "PAP", "PAV", "MAP","MAV", "MAP", "PAV", "PAP", "PAV", "PAP", "MAV"))
loadings %>% 
  rownames_to_column("indicator") %>% 
  left_join(lt) %>% 
  mutate(indicator = factor(indicator, levels = paste("ags",12:1, sep =""))) %>% 
  gather(factor, value, -indicator, - latent_traits) %>% 
  mutate(value2 = ifelse(value < 0.1, NA,  value))-> loadings.long 
Joining, by = "indicator"
ggplot(data = loadings.long) +
  geom_point(aes(x = factor, y = indicator, color = value2, shape = latent_traits), size = 8) +
  scale_colour_gradient(na.value = "white", low = "blue", high = "red") +
  scale_shape_manual(values = c("MAP" = 15, "MAV" = 16, "PAP" = 17, "PAV" = 18)) +
  labs(color = "Loading", shape = "Latent\ntrait") +
  theme_classic()

References

Beaujean, A. A. 2014. Latent variable modeling using r: A step-by-step guide. Routledge.

Finch, W. H., and B. F. French. 2015. Latent variable modeling with r. Routledge.

Horn, J. L. 1965. A rationale and test for the number of factors in factor analysis. Psychometrika 30:179–185. Springer.

LS0tCnRpdGxlOiAiTGF0ZW50IHZhcmlhYmxlIGFuYWx5c2lzIgpjc2w6IHRoZS1qb3VybmFsLW9mLXdpbGRsaWZlLW1hbmFnZW1lbnQuY3NsCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CmJpYmxpb2dyYXBoeTogYmlibGlvZ3JhcGh5LmJpYgplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0KbGlicmFyeShwc3ljaCkKYGBgCgojIyBBbnN3ZXJzIHRvIHRoZSBjaGFsbGVuZ2UKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ2RlbmRybykKbGlicmFyeShOYkNsdXN0KQoKZGF0YSgiVVNBcnJlc3RzIikKClVTQXJyZXN0cyAlPiUgCiAgc2NhbGUoKSAtPiBhcnJlc3Quc2NhbGUKCmFycmVzdC5zY2FsZSAlPiUgCiAgZGlzdChtZXRob2QgPSAiZXVjbGlkZWFuIikgLT4gYXJyZXN0LmV1YwoKYXJyZXN0X2hjbHVzdCA8LSBoY2x1c3QoYXJyZXN0LmV1YywgbWV0aG9kID0gIndhcmQuRDIiKQoKIyMjIEZpbmQgdGhlIGJlc3QgbnVtYmVyIG9mIGNsdXN0ZXJzCmFycmVzdC5uYiA8LSBOYkNsdXN0KGFycmVzdC5zY2FsZSwgCiAgICAgICAgZGlzdGFuY2UgPSAiZXVjbGlkZWFuIiwgCiAgICAgICAgbWluLm5jID0gMiwgCiAgICAgICAgbWF4Lm5jID0gMTAsIAogICAgICAgIG1ldGhvZCA9ICJjb21wbGV0ZSIsIAogICAgICAgIGluZGV4ID0gImFsbCIpCgpjbHVzdGVycyA8LSBkYXRhLmZyYW1lKGFycmVzdC5uYiRCZXN0LnBhcnRpdGlvbikKY2x1c3RlcnMkc3RhdGUgPC0gcm93bmFtZXMoY2x1c3RlcnMpCmNvbG5hbWVzKGNsdXN0ZXJzKSA8LSBjKCJjbHVzdGVyIiwgImxhYmVsIikKCiMjIyBleHRyYWN0IHRoZSBkYXRhCmFycmVzdF9kZW5kcm8gPC0gYXMuZGVuZHJvZ3JhbShhcnJlc3RfaGNsdXN0KQoKIyMjIGNvbnZlcnQgZGF0YSB0byBkZW5kcm8gZGF0YSBmb3IgZ2dwbG90CmFycmVzdF9kZW5kcm9fZGF0YSA8LSBkZW5kcm9fZGF0YShhcnJlc3RfZGVuZHJvLCB0eXBlID0gInJlY3RhbmdsZSIpCgojIyMgY29tYmluZSBjbHVzdGVyIGFuZCBkZW5kcm8gbGFiZWwgZGF0YSAKYXJyZXN0X2RlbmRyb19sYWJlbHMgPC0gZGF0YS5mcmFtZShmdWxsX2pvaW4oYXJyZXN0X2RlbmRyb19kYXRhJGxhYmVscywgY2x1c3RlcnMpKQoKYXJyZXN0X2RlbmRyb19zZWdzIDwtIGRhdGEuZnJhbWUoYXJyZXN0X2RlbmRyb19kYXRhJHNlZ21lbnRzKSAKYXJyZXN0X2RlbmRyb19zZWdzJGNsdXN0ZXIgPC0gaWZlbHNlKGFycmVzdF9kZW5kcm9fc2VncyR4IDwgMjAgJiBhcnJlc3RfZGVuZHJvX3NlZ3MkeGVuZCA8IDIwLCAxLCAyKQoKIyMjIHBsb3QgCmFycmVzdF9kZW5kcm9fcGxvdDwtZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgIGdlb21fc2VnbWVudChkYXRhID0gYXJyZXN0X2RlbmRyb19zZWdzLCBhZXMoeCA9IHgsIHkgPSB5LCB4ZW5kID0geGVuZCwgeWVuZCA9IHllbmQsIGNvbG9yID0gYXMuZmFjdG9yKGNsdXN0ZXIpKSkgKyAKICAgICAgICAgICAgICAgICAgICAgIGdlb21fdGV4dChkYXRhID0gYXJyZXN0X2RlbmRyb19sYWJlbHMsIGFlcyh4ID0geCwgeSA9IHksIGxhYmVsID0gbGFiZWwsIGNvbG9yID0gYXMuZmFjdG9yKGNsdXN0ZXIpKSwgYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCBzaXplID0gMS43LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICAgICAgICAgICAgICAgICAgICBsYWJzKGNvbG9yPSJDbHVzdGVyIikgKyAgCiAgICAgICAgICAgICAgICAgICAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTUsMTUpKSArCiAgICAgICAgICAgICAgICAgICAgICB0aGVtZV92b2lkKCkgKyAKICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiMSIgPSAiZmlyZWJyaWNrIiwgIjIiID0gImRvZGdlcmJsdWUiKSkgKwogICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMC41LCAwLjUsIDEsIDAuNSwgdW5pdCA9ICJjbSIpCiAgICAgICAgICAgICAgICAgICAgICApCgoKYXJyZXN0X2RlbmRyb19wbG90CmBgYAoKIyMgQSBxdWljayB3b3JkIGFib3V0IGVpZ2VudmVjdG9ycyBhbmQgdmFsdWVzCgpbRWlnZW52ZWN0b3JzIGFuZCBFaWdlbnZhbHVlc10oaHR0cDovL3NldG9zYS5pby9ldi9laWdlbnZlY3RvcnMtYW5kLWVpZ2VudmFsdWVzLykKCkZvciBhbnkgbnVtYmVyIHNldCBvZiBwb2ludHMsIHdlIGNhbiBkaWdlc3QgdGhlc2UgcG9pbnRzIGludG8gZWlnZW52ZWN0b3JzIGFuZCAgZWlnZW52YWx1ZS4gIEVpZ2VudmVjdG9ycyBhbmQgZWlnZW52YWx1ZXMgZXhpc3QgaW4gcGFpcnMgd2l0aCBlaWdlbnZlY3RvciBkZXNjcmliZXMgYSBkaXJlY3Rpb24gYWxvbmcgd2hpY2ggYSBsaW5lYXIgdHJhbnNmb3JtYXRpb24gYWN0cyBzaW1wbHkgYnkgInN0cmV0Y2hpbmcvY29tcHJlc3NpbmciIGFuZC9vciAiZmxpcHBpbmciOyBhbmQgZWlnZW52YWx1ZSBkZXNjcmliaW5nIHRoZSBkZWdyZWUgb2YgdGhhdCB0cmFuc2Zvcm1hdGlvbiBpbiB0aGF0IGRpcmVjdGlvbi4gIFRoZSBudW1iZXJzIG9mIGVpZ2VudmVjdG9ycyBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIGRpbWVuc2lvbnMgb2YgeW91ciBkYXRhLiAgCgpgYGB7cn0KbWF0PC1tYXRyaXgoYygzLDIsMSwyKSwgYnlyb3cgPSBUUlVFLCBuY29sID0gMikKCmVpZ2VuKG1hdCkKYGBgCgojIExhdGVudCB2YXJpYWJsZSBhbmFseXNpcwoKIyMgRmFjdG9yIGFuYWx5c2lzCgoKVGhlIHNvdXJjZSB0byBtYW55IG9mIHRoZSBub3RlcyBpbiB0aGlzIGxlc3NvbiAoYW5kIGEgbG90IG1vcmUgZGV0YWlsIG9uIHRoZSBzdWJqZWN0KSBjYW4gYmUgZm91bmQgYXQgQGZpbmNoMjAxNWxhdGVudCBhbmQgQGJlYXVqZWFuMjAxNGxhdGVudC4gIAoKKkxhdGVudCB2YXJpYWJsZXMqIGluIHN0YXRpc3RpY3MgYXJlIHZhcmlhYmxlcyB0aGF0IGFyZSBub3QgZGlyZWN0bHkgb2JzZXJ2YWJsZSBhbmQgYXJlIGluZmVycmVkIGZyb20gYSBtYXRoZW1hdGljYWwgbW9kZWwuICBPbmUgYWR2YW50YWdlIG9mIHVzaW5nICpsYXRlbnQgdmFyaWFibGVzKiBpcyB0aGF0IGl0IGhlbHBzIHJlZHVjZSB0aGUgZGltZW5zaW9uYWxpdHkgb2YgZGF0YSAoYSBtYWpvciB0aGVtZSBvZiBtdWx0aXZhcmlhdGUgc3RhdGlzdGljcykgYW5kIGhhcyBiZWVuIHVzZWQgaW4gbWFueSBzY2llbnRpZmljIGRpc2NpcGxpbmVzLiAgCgpPbmUgdHlwZSBvZiBsYXRlbnQgdmFyaWFibGUgYW5hbHlzaXMgaXMgKmZhY3RvciBhbmFseXNpcyogYW5kIHVzZWQgZXh0ZW5zaXZlbHkgaW4gc29jaWFsIGFuZCBiZWhhdmlvcmFsIHNjaWVuY2VzLiAgRmFjdG9yIGFuYWx5c2lzIGFsbG93cyB0aGUgcmVzZWFyY2hlciB0byBjcmVhdGUgbW9kZWxzIG9mIG5vbi1vYnNlcnZhYmxlIGZhY3RvcnMgKGUuZy4sIG1vdGl2YXRpb25zLCBjb25zdHJhaW50cywgaWRlbnRpdHkpIGZyb20gbXVsdGl2YXJpYXRlIGRhdGEuICAKClRoZXJlIGFyZSB0d28gYnJvYWQgdHlwZXMgb2YgZmFjdG9yIGFuYWx5c2lzOiAgMSkgRXhwbG9yYXRvcnkgZmFjdG9yIGFuYWx5c2lzIChFRkEpIGFuZCAyKSBDb25maXJtYXRvcnkgZmFjdG9yIGFuYWx5c2lzIChDRkEpLiAgVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGlzIGluIHRoZSBkZWdyZWUgb2YgKiogYSBwcmlvcmkgKiogc3RydWN0dXJlIHRoYXQgaXMgYXNzdW1tZWQgaW4gdGhlIG1vZGVsLiAgSW4gdXNpbmcgRUZBIHRoZSByZXNlYXJjaGVyIGRvZXMgbm90IGltcG9zZSBhIHNwZWNpZmljIGxhdGVudCBzdHJ1Y3R1cmUgb24gdGhlIG9ic2VydmFibGUgZGF0YSwgYnV0IGFsbG93cyB0aGUgYW5hbHlzaXMgdG8gcHJvdmlkZSB0aGUgb3B0aW1hbCBudW1iZXIgb2YgZmFjdG9ycy4gSW4gY29udHJhc3QgdG8gRUZBLCB3aXRoIENGQSB0aGUgcmVzZWFyY2hlciBleHBsaWNpdGx5IGxpbmtzIHRoZSBpbmRpY2F0b3JzIHdpdGggdGhlIGZhY3RvcnMgdG8gd2hpY2ggdGhleSB0aGVvcmV0aWNhbGx5IGJlbG9uZy4KCiMjIEV4cGxvcmF0b3J5IGZhY3RvciBhbmFseXNpcwoKRUZBIGNvbnNpc3RzIG9mIHR3byBzdGVwcyAoMSkgZmFjdG9yIGV4dHJhY3Rpb24gYW5kICgyKSBmYWN0b3Igcm90YXRpb24uICBGYWN0b3Igcm90YXRpb24gaW52b2x2ZXMgZXN0aW1hdGluZyB0aGUgaW50aWFsIG1vZGVsIHBhcmFtdGVycyAoaS5lLiwgZmFjdG9yIGxvYWRpbmdzOiAgbG9hZGluZ3MgcmVmbGVjdCB0aGUKcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSBmYWN0b3JzIGFuZCB0aGUgaW5kaWNhdG9ycywgd2l0aCBsYXJnZXIgdmFsdWVzIGJlaW5nIGluZGljYXRpdmUKb2YgYSBjbG9zZXIgYXNzb2NpYXRpb24gYmV0d2VlbiBhIGxhdGVudCBhbmQgb2JzZXJ2ZWQgdmFyaWFibGUpLiAgVGhlcmUgYXJlIGFzIG1hbnkgZmFjdG9ycyBhcyBudW1iZXIgb2YgaW5kaWNhdG9yIHZhcmlhYmxlcyAoaS5lLiwgY29sdW1ucyB1c2VkIHRvIGRlZmluZSB0aGUgbGF0ZW50IHZhcmlhYmxlKS4gCgojIyMgRmFjdG9yIGV4dHJhY3Rpb24KClNldmVyYWwgZXh0cmFjdGlvbiBtZXRob2RzIGV4aXN0LCB3aXRoIHRoZSBtb3N0IHBvcHVsYXIgYmVpbmcgbWF4aW11bSBsaWtlbGlob29kIChNTCkgYW5kIHByaW5jaXBhbCBheGlzIGZhY3RvciAoUEFGKS4gIE1MIG1ldGhvZCBoYXMgYSBkaXJlY3QgYXNzZXNzbWVudCBvZiBtb2RlbCBmaXQgYnV0IGFsc28gcmVsaWVzIG9uIG11bHRpdmFyaWF0ZSBub3JtYWxpdHkuICBQQUYgZG9lcyBub3QgaGF2ZSBhIGRpc3RyaWJ1dGlvbmFsIGFzc3VtcHRpb24gYnV0IGRvZXMgbm90IGhhdmUgYSB0ZXN0IG9mIHN0YXRpc3RpY2FsIGZpdC4gIAoKIyMjIEZhY3RvciByb3RhdGlvbgoKRmFjdG9yIHJvdGF0aW9uICBpcyB0aGUgdHJhbnNmb3JtYXRpb24gb2YgdGhlIGluaXRpYWwgc2V0IG9mIGZhY3RvciBsb2FkaW5ncyB0byBzaW1wbGlmeSB0aGUgaW50ZXJwcmV0YXRpb24gb2Ygb2YgdGhlIHJlc3VsdHMgYnkgZmluZGluZyBhIHNpbXBsZSBzb2x1dGlvbi4gIE1ldGhvZHMgZmFsbCBpbnRvIHR3byBicm9hZCBjYXRlZ29yaWVzOiAgb3J0aG9nb25hbCBhbmQgb2JsaXF1ZS4gIE9ydGhvZ29uYWwgcm90YXRpb25zIGNvbnN0cmFpbiB0aGUgY29ycmVsYXRpb25zIGFtb25nIGZhY3RvcnMgdG8gYmUgemVybywgd2hlcmVhcyBvYmxpcXVlIHJvdGF0aW9ucyBhbGxvdyB0aGUgZmFjdG9ycyB0byBiZSBjb3JyZWxhdGVkLiBUaGUgbW9zdApwb3B1bGFyIG9ydGhvZ29uYWwgcm90YXRpb24gbWV0aG9kIGlzIFZBUklNQVgsIHdoaWxlIGFtb25nIHRoZSBvYmxpcXVlIHJvdGF0aW9ucyBQUk9NQVggYW5kIE9CTElNSU4gYXJlIHBvcHVsYXIuICBEZWNpc2lvbiBvbiB3aGljaCBtZXRob2QgdG8gdXNlLCBzaG91bGQgYmUgYmFzZWQgaW4gdGhlb3J5IGFuZCBlbXBpcmljYWwgZ3JvdW5kcy4gIAoKIyMjIERldGVybWluaW5nIHRoZSBvcHRpbWFsIG51bWJlciBvZiBmYWN0b3JzCgoxLiBFaWdlbnZhbHVlcyBncmVhdGVyIHRoYW4gMS4gIEVpZ2VudmFsdWVzIGdyZWF0ZXIgdGhhbiAxLCBhY2NvdW50IGZvciBtb3JlIHZhcmlhbmNlIHRoYW4gYW55IG9mIHRoZSBvYnNlcnZlZCB2YWx1ZXMuICAKMi4gIFNjcmVlIHBsb3RzLiAgRWlnZW52YWx1ZXMgb24gdGhlIHktYXhpcyBhbmQgbnVtYmVyIG9mIGZhY3RvcnMgb24gdGhlIHggYXhpcy4gIElkZW50aWZ5IHdoZXJlIHRoZSBwbG90ICJmbGF0dGVucyBvdXQiCjMuIFByb3BvcnRpb24gb2YgdmFyaWFuY2UuICBJZGVudGlmeSB3aGVuIHRoZXJlIGlzIG5vICJhcHByZWNpYXRpdmUiICBnYWluIGluIHRoZSBwZXJjZW50YWdlIG9mIHZhcmlhbmNlIGV4cGxhaW5lZC4gIFNpbWlsYXIgdG8gc2NyZWUgcGxvdAo0LiBSZXNpZHVhbCBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHRoZSBvYnNlcnZlZCBpbmRpY2F0b3JzLiByZXNpZHVhbHMgbGFyZ2VyIHRoYW4gMC4wNSBhcmUgY29uc2lkZXJlZCB0byBiZSB0b28gbGFyZ2UsIHNvIHRoYXQgYSBnb29kIHNvbHV0aW9uIGlzIG9uZSB3aGljaCBwcm9kdWNlcyBmZXcgcmVzaWR1YWwgY29ycmVsYXRpb25zIGdyZWF0ZXIgdGhhbiAwLjA1IGluIGFic29sdXRlIHZhbHVlLgo1LiBQYXJhbGxlbCBhbmFseXNpcy4gIERlc2NyaWJlZCBpbiBAaG9ybjE5NjVyYXRpb25hbGUuICBTZXZlcmFsIHN0ZXBzIHRoYXQgaW5jbHVkZSBjb21wYXJpbmcgdGhlIGFjdHVhbCBkYXRhIHRvICB0d28gcmFuZG9tbHkgZ2VuZXJhdGVkIGRhdGFzZXRzLiAgVEhpcyBpcyB0aGUgbW9zdCBjb21tb25seSB1c2VkLiAKCiMjIyBUaGUgZGF0YSAKCkZvciB0aGlzIGRhdGEsIHdlIHdpbGwgdXNlIHRoZSBkYXRhIHNldCBwcm92aWRlZCBieSBAZmluY2gyMDE1bGF0ZW50IFtoZXJlXShodHRwczovL3d3dy5yb3V0bGVkZ2UuY29tL0xhdGVudC1WYXJpYWJsZS1Nb2RlbGluZy13aXRoLVIvRmluY2gtRnJlbmNoL3AvYm9vay85NzgwNDE1ODMyNDU4I2RhdGFzZXRzKS4gIFRoZSBkYXRhIHJlcHJlc2VudHMgaW5mb3JtYXRpb24gY29sbGVjdGVkIG9uIGFjaGVpdmVtZW50IGdvYWwgb3JpZW50YXRpb24uIEFjaGlldmVtZW50IGdvYWwgb3JpZW50YXRpb24gcmVmZXJzIHRvIGhvdyBhbiBpbmRpdmlkdWFsIGludGVycHJldHMgYW5kIHJlYWN0cyB0byB0YXNrcywgcmVzdWx0aW5nIGluIGRpZmZlcmVudCBwYXR0ZXJucyBvZiBjb2duaXRpb24sIGFmZmVjdCBhbmQgYmVoYXZpb3IuICBUaGVyZSBhcmUgMTIgcXVlc3Rpb25zIHdpdGggcmVzdWx0cyByZXByZXNlbnRpbmcgYSA3LXBvaW50IGxpa2VydC10eXBlIHNjYWxlIGZyb20gNDMwIGNvbGxlZ2Ugc3R1ZGVudHMuIAoKVGhlIGNvbHVtbnMgcmVmZXIgdG86CgotIEFHUzEgPSBNeSBnb2FsIGlzIHRvIGNvbXBsZXRlbHkgbWFzdGVyIHRoZSBtYXRlcmlhbCBwcmVzZW50ZWQgaW4gbXkgY2xhc3Nlcy4gKE1BUCkKLSBBR1MyID0gSSB3YW50IHRvIGF2b2lkIGxlYXJuaW5nIGxlc3MgdGhhbiBpdCBpcyBwb3NzaWJsZSB0byBsZWFybi4gKE1BVikKLSBBR1MzID0gSXQgaXMgaW1wb3J0YW50IGZvciBtZSB0byBkbyBiZXR0ZXIgdGhhbiBvdGhlciBzdHVkZW50cy4gKFBBUCkKLSBBR1M0ID0gSSB3YW50IHRvIGF2b2lkIHBlcmZvcm1pbmcgcG9vcmx5IGNvbXBhcmVkIHRvIG90aGVycy4gKFBBVikKLSBBR1M1ID0gSSB3YW50IHRvIGxlYXJuIGFzIG11Y2ggYXMgcG9zc2libGUuIChNQVApCi0gQUdTNiA9IEl0IGlzIGltcG9ydGFudCBmb3IgbWUgdG8gYXZvaWQgYW4gaW5jb21wbGV0ZSB1bmRlcnN0YW5kaW5nIG9mIHRoZSBjb3Vyc2UgbWF0ZXJpYWwuIChNQVYpIAotIEFHUzcgPSBJdCBpcyBpbXBvcnRhbnQgZm9yIG1lIHRvIHVuZGVyc3RhbmQgdGhlIGNvbnRlbnQgb2YgbXkgY291cnNlcyBhcyB0aG9yb3VnaGx5IGFzIHBvc3NpYmxlLiAoTUFQKQotIEFHUzggPSBNeSBnb2FsIGlzIHRvIGF2b2lkIHBlcmZvcm1pbmcgd29yc2UgdGhhbiBvdGhlciBzdHVkZW50cy4gKFBBVikgCi0gQUdTOSA9IEkgd2FudCB0byBkbyB3ZWxsIGNvbXBhcmVkIHRvIG90aGVyIHN0dWRlbnRzLiAoUEFQKSAKLSBBR1MxMCA9IEl0IGlzIGltcG9ydGFudCBmb3IgbWUgdG8gYXZvaWQgZG9pbmcgcG9vcmx5IGNvbXBhcmVkIHRvIG90aGVyIHN0dWRlbnRzLiAoUEFWKSAKLSBBR1MxMSA9IE15IGdvYWwgaXMgdG8gcGVyZm9ybSBiZXR0ZXIgdGhhbiB0aGUgb3RoZXIgc3R1ZGVudHMuIChQQVApIAotIEFHUzEyID0gTXkgZ29hbCBpcyB0byBhdm9pZCBsZWFybmluZyBsZXNzIHRoYW4gSSBwb3NzaWJseSBjb3VsZC4gKE1BVikKCgpUaGUgdHlwZXMgb2YgcXVlc3Rpb25zIHJlZmVyIHRvIDQgZGlzdGluY3QgbGF0ZW50IHRyYWl0czogbWFzdGVyeSBhcHByb2FjaCAoTUFQKSwgbWFzdGVyeSBhdm9pZGFudCAoTUFWKSwgcGVyZm9ybWFuY2UgYXBwcm9hY2ggKFBBUCksIGFuZCBwZXJmb3JtYW5jZSBhdm9pZGFudCAoUEFWKS4KClRoZSBkYXRhIGlzIGluIGEgU1BTUyBmb3JtYXQgYW5kIEkgaGF2ZSBjb252ZXJ0ZWQgaXQgdG8gYSBjc3YgZmlsZSBmb3IgY29udmllbmNlIGFuZCBpcyBpbiBvdXIgZ2l0aHViIGRhdGEgcmVwb3NpdG9yeSBhcyBgZ29hbF9zY2FsZS5jc3ZgCgpgYGB7cn0KbGlicmFyeShyZWFkcikKCmdvYWxfc2NhbGUgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9jaHJpc2NoaXppbnNraS9TTlJfUl9Hcm91cC9tYXN0ZXIvZGF0YS9nb2FsX3NjYWxlLmNzdiIpCgpoZWFkKGdvYWxfc2NhbGUpCgpgYGAKCgojIyMgRml0IGFuIEVGQSBtb2RlbHMgd2l0aCBgZmFjdGFuYWxgCgpgYGB7cn0KCmFnb2FsLmVmYTwtZmFjdGFuYWwofmFnczErYWdzMithZ3MzK2FnczQrYWdzNSthZ3M2K2FnczcrYWdzOCthZ3M5K2FnczEwK2FnczExKyBhZ3MxMiwgZmFjdG9ycz00LCByb3RhdGlvbj0icHJvbWF4IiwgZGF0YSA9IGdvYWxfc2NhbGUgKQoKYWdvYWwuZWZhCgpgYGAKCiMjIyMgVW5pcXVlbmVzcyAKClVuaXF1ZW5lc3MgcmVmbGVjdHMgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgaW4gdGhlIGluZGljYXRvcnMgdGhhdCBhcmUgbm90IGV4cGxhaW5lZCBieSB0aGUgZmFjdG9ycy4gIEZvciBleGFtcGxlLCBgciByb3VuZChhZ29hbC5lZmEkdW5pcXVlbmVzc2VzWzFdLCBkaWdpdHMgPSAzKSoxMDAgYCUgb2YgdmFyaWF0aW9uIGluIGBhZ3MxYCBpcyBub3QgZXhwbGFpbmVkIGJ5IHRoZSBmb3VyIGZhY3RvcnMuIAoKCmBgYHtyfQphZ29hbC5lZmEkdW5pcXVlbmVzc2VzCmBgYAoKVGhlIG9wcG9zaXRlIG9mIHVuaXF1ZW5lc3Mgb2YgY29tbXVuYWxpdHksIGFuZCB0aGlzIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlcyBleHBsYWluZWQgYnkgdGhlIGZhY3RvcnMgZm9yIGVhY2ggaW5kaWNhdG9yLgoKYGBge3J9CjEtYWdvYWwuZWZhJHVuaXF1ZW5lc3NlcwpgYGAKCgojIyMjIExvYWRpbmdzCgpgYGB7cn0KbGQ8LWxvYWRpbmdzKGFnb2FsLmVmYSkKbGQKCmBgYApUbyBoZWxwIGludGVycHJldCBvdXIgbG9hZGluZ3MsIGxldHMgY3JlYXRlIGEgdmlzdWFsaXphdGlvbiBvZiB0aG9zZSBsb2FkaW5ncy4gIAoKYGBge3J9CmxvYWRpbmdzPC1hcy5kYXRhLmZyYW1lKGxkWyxdKQoKbHQ8LSBkYXRhLmZyYW1lKGluZGljYXRvciA9IHBhc3RlKCJhZ3MiLDE6MTIsIHNlcCA9IiIpLAogICAgICAgICAgIGxhdGVudF90cmFpdHMgPSBjKCJNQVAiLCAiTUFWIiwgIlBBUCIsICJQQVYiLCAiTUFQIiwiTUFWIiwgIk1BUCIsICJQQVYiLCAiUEFQIiwgIlBBViIsICJQQVAiLCAiTUFWIikpCgpsb2FkaW5ncyAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJpbmRpY2F0b3IiKSAlPiUgCiAgbGVmdF9qb2luKGx0KSAlPiUgCiAgbXV0YXRlKGluZGljYXRvciA9IGZhY3RvcihpbmRpY2F0b3IsIGxldmVscyA9IHBhc3RlKCJhZ3MiLDEyOjEsIHNlcCA9IiIpKSkgJT4lIAogIGdhdGhlcihmYWN0b3IsIHZhbHVlLCAtaW5kaWNhdG9yLCAtIGxhdGVudF90cmFpdHMpICU+JSAKICBtdXRhdGUodmFsdWUyID0gaWZlbHNlKHZhbHVlIDwgMC4xLCBOQSwgIHZhbHVlKSktPiBsb2FkaW5ncy5sb25nIAoKCmdncGxvdChkYXRhID0gbG9hZGluZ3MubG9uZykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBmYWN0b3IsIHkgPSBpbmRpY2F0b3IsIGNvbG9yID0gdmFsdWUyLCBzaGFwZSA9IGxhdGVudF90cmFpdHMpLCBzaXplID0gOCkgKwogIHNjYWxlX2NvbG91cl9ncmFkaWVudChuYS52YWx1ZSA9ICJ3aGl0ZSIsIGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIk1BUCIgPSAxNSwgIk1BViIgPSAxNiwgIlBBUCIgPSAxNywgIlBBViIgPSAxOCkpICsKICBsYWJzKGNvbG9yID0gIkxvYWRpbmciLCBzaGFwZSA9ICJMYXRlbnRcbnRyYWl0IikgKwogIHRoZW1lX2NsYXNzaWMoKQpgYGAKCgojIyBSZWZlcmVuY2Vz