By Peter Chen

Full code repository here.

The Korean idol industry is characterized by systematically manufactured celebrities produced by entertainment companies focusing on a hybrid of music, fashion, dance, and, the subject of this particular study, visual appeal to market to a global audience. Perfectly capturing this phenomenon is the explosive popularity of the South Korean reality television franchise Produce 101, in which idol trainees compete via a series of vocal and dance performances as the audience vote for their favorite contestants, the ultimate goal being to debut a group that best reflects voter preferences. However, the emphasis on aesthetic appeal as well as the general high skill standards of the industry overall begs the question as whether adherence to beauty standards may play an overwhelming role in determining popularity and success on the show. In this study, we examine the relationship between visual and performance on the show.

The case study used will be the third season of the Produce 101, entitled Produce 48 which first premiered in 2018. The training data consists of \(R=96\) headshot images of Produce 48 contestants obtained from https://48pedia.org.

# clear workspace
rm(list = ls()) 

We ingest images and convert to grayscale via the Luma function. The images are then scaled by 256 to display.

library(jpeg)
# load images
num = 96 # number of images
# Luma function
grayscale <- function(img){0.2126*img[,,1] + 0.7152*img[,,2] + 0.0722*img[,,3]}
faces <- list()
for (i in 1:num){
  faces[[i]]<-grayscale(readJPEG(paste("face_images/",toString(i),".jpg",sep=""), native = FALSE))
}
# plot image (and rotate)
plt_img <- function(x){ image(t(x[nrow(x):1,]), col=grey(seq(0, 1, length=256)))}
plt_img(faces[[1]])

plt_img(faces[[2]])

First, we transform each \(NxN\) (where \(N=180\) resolution of the image) image matrix into vectors for processing.

# flatten and create training matrix
face_matrix <- matrix(numeric(0), nrow = 180*180, ncol = 0)
for (i in 1:num){
  face_matrix<-cbind(face_matrix, as.vector(faces[[i]]))
}

We compile an “avaerage face” of all our contestants.

avg_face <- matrix(rowMeans(face_matrix),nrow=180,ncol=180)
plt_img(avg_face)

The average here does not account for the discrepancy in facial orientation across images. Therefore, we use facial landmark detection model based in OpenCV by making use of Facer and a pre-trained dlib model (detailed implementation and code can be found here).

avg_face <- grayscale(readJPEG("average_face.jpg", native = FALSE))
plt_img(avg_face)

To obtain the characteristic features, we subtract the average face from each face vector to obtain matrix \(X\).

avg_face_vec <- as.vector(avg_face)
X  <- matrix(numeric(0), nrow = 180*180, ncol = 0)
for (i in 1:num){
  X <- cbind(X, face_matrix[,i]-avg_face_vec)
}

We now have matrix \(X\) where each columns is a vector representation of an image’s characteristic features. Now, we attempt to find orthonormal vectors which best describe the distribution of our data. To do this we find the eigenvalues and eigenvectors corresponding to covariance matrix \(C = XX^T\). Because matrix \(C\) in this case is intractable to calculate consider with dimensions of \(N^2\) by \(N^2\), we instead caculate \(L=X^TX\) and find its eigenvectors \(v_i\). The resulting eigenvalues will be identical to covariance matrix \(C\), we can then calculate the eigenvectors of \(C\) by calculating \(u_i=Xv_i\). These new eigenvectors are our eigenfaces, a linear composition of the base images.

#covriance matrix
# C = X %*% t(X) <- intractable dimensions
L = t(X) %*% X 
e <- eigen(L)
# X %*% eigenvectors of X^TX = eigenvectors of XX^T
unit_vectorize <- function(x){return(x/(sqrt(sum(x**2,na.rm=TRUE))))} # normalize to unit vector
eigenfaces <- matrix(numeric(0), nrow = 180*180, ncol = 0)
for (i in 1:num){
  eigenfaces <- cbind(eigenfaces, X %*% unit_vectorize(e$vectors[,i]))
}
dim(eigenfaces)
[1] 32400    96

Scaling and display the eigenfaces corresponding to the first two principal components.

eigenface_1 <- matrix(eigenfaces[,1],nrow=180,ncol=180)
plt_img(eigenface_1)

eigenface_2 <- matrix(eigenfaces[,2],nrow=180,ncol=180)
plt_img(eigenface_2)

The resulting eigenface matrix \(U=[u_1 u_2 ... u_R]\) where each column contains eigenface \(u_i\). Plotting the eigenvalues we see a drastic drop in variance, so most eigenfaces can be disregarded.

plot(x = seq(1:length( e$values)), y = e$values, type = "o", xlab = "Principle Component", ylab = "Variance")

Selecting 20 principal components should be more than eonugh to capture most of the variance in our dataset.

U <- eigenfaces[,1:20]

We can use the eigenface matrix \(U\) to transform a face image into its eigenface components by performing the following operation \(U^T(img-avg)\). The resulting \(Rx1\) vector gives us “weights” of the corresponding eigenface in contributing to a given image. Our matrix \(X\) contains the “characteristic features”, the image vector subtracted by the avergae face vector; we obtain the eigeinface components of our contestants by calculating \(S=U^tX\).

# eigenface components
S <- t(U) %*% X
dim(S)
[1] 20 96

The resulting matirx \(S\) represent the first 20 coeffcients corresponding to each eigenface for each contestant. If we are to assume that facial features are the sole determining factor in success and popularity on the show, then we’d expect a clear relationship between these coeffcients and final ranking on the show.

plot_component <- function(component){plot(x = seq(1:length(S[component,])), y = S[component,], type = "o", xlab = "Produce 48 Final Ranking", ylab = paste("Weight for Eigenface #",toString(component),sep=""))}
plot_component(1)

plot_component(2)

plot_component(3)

plot_component(4)

plot_component(5)

LS0tDQp0aXRsZTogIlByb2R1Y2UgNDggUmFua2luZ3MgLSBBbiBFaWdlbmZhY2UgQXBwcm9hY2giDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KQnkgUGV0ZXIgQ2hlbg0KDQpGdWxsIGNvZGUgcmVwb3NpdG9yeSBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL3BldGVyeGljaGVuL3Byb2R1Y2UtMTAxLWVpZ2VuZmFjZSkuDQoNClRoZSBbS29yZWFuIGlkb2wgaW5kdXN0cnldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0tvcmVhbl9pZG9sKSBpcyBjaGFyYWN0ZXJpemVkIGJ5IHN5c3RlbWF0aWNhbGx5IG1hbnVmYWN0dXJlZCBjZWxlYnJpdGllcyBwcm9kdWNlZCBieSBlbnRlcnRhaW5tZW50IGNvbXBhbmllcyBmb2N1c2luZyBvbiBhIGh5YnJpZCBvZiBtdXNpYywgZmFzaGlvbiwgZGFuY2UsIGFuZCwgdGhlIHN1YmplY3Qgb2YgdGhpcyBwYXJ0aWN1bGFyIHN0dWR5LCB2aXN1YWwgYXBwZWFsIHRvIG1hcmtldCB0byBhIGdsb2JhbCBhdWRpZW5jZS4gUGVyZmVjdGx5IGNhcHR1cmluZyB0aGlzIHBoZW5vbWVub24gaXMgdGhlIGV4cGxvc2l2ZSBwb3B1bGFyaXR5IG9mIHRoZSBTb3V0aCBLb3JlYW4gcmVhbGl0eSB0ZWxldmlzaW9uIGZyYW5jaGlzZSBQcm9kdWNlIDEwMSwgaW4gd2hpY2ggaWRvbCB0cmFpbmVlcyBjb21wZXRlIHZpYSBhIHNlcmllcyBvZiB2b2NhbCBhbmQgZGFuY2UgcGVyZm9ybWFuY2VzIGFzIHRoZSBhdWRpZW5jZSB2b3RlIGZvciB0aGVpciBmYXZvcml0ZSBjb250ZXN0YW50cywgdGhlIHVsdGltYXRlIGdvYWwgYmVpbmcgdG8gZGVidXQgYSBncm91cCB0aGF0IGJlc3QgcmVmbGVjdHMgdm90ZXIgcHJlZmVyZW5jZXMuIEhvd2V2ZXIsIHRoZSBlbXBoYXNpcyBvbiBhZXN0aGV0aWMgYXBwZWFsIGFzIHdlbGwgYXMgdGhlIGdlbmVyYWwgaGlnaCBza2lsbCBzdGFuZGFyZHMgb2YgdGhlIGluZHVzdHJ5IG92ZXJhbGwgYmVncyB0aGUgcXVlc3Rpb24gYXMgd2hldGhlciBhZGhlcmVuY2UgdG8gYmVhdXR5IHN0YW5kYXJkcyBtYXkgcGxheSBhbiBvdmVyd2hlbG1pbmcgcm9sZSBpbiBkZXRlcm1pbmluZyBwb3B1bGFyaXR5IGFuZCBzdWNjZXNzIG9uIHRoZSBzaG93LiBJbiB0aGlzIHN0dWR5LCB3ZSBleGFtaW5lIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2aXN1YWwgYW5kIHBlcmZvcm1hbmNlIG9uIHRoZSBzaG93Lg0KDQpUaGUgY2FzZSBzdHVkeSB1c2VkIHdpbGwgYmUgdGhlIHRoaXJkIHNlYXNvbiBvZiB0aGUgIFByb2R1Y2UgMTAxLCBlbnRpdGxlZCBQcm9kdWNlIDQ4IHdoaWNoIGZpcnN0IHByZW1pZXJlZCBpbiAyMDE4LiBUaGUgdHJhaW5pbmcgZGF0YSBjb25zaXN0cyBvZiAkUj05NiQgaGVhZHNob3QgaW1hZ2VzIG9mIFByb2R1Y2UgNDggY29udGVzdGFudHMgb2J0YWluZWQgZnJvbSBodHRwczovLzQ4cGVkaWEub3JnLg0KYGBge3J9DQojIGNsZWFyIHdvcmtzcGFjZQ0Kcm0obGlzdCA9IGxzKCkpIA0KYGBgDQoNCldlIGluZ2VzdCBpbWFnZXMgYW5kIGNvbnZlcnQgdG8gZ3JheXNjYWxlIHZpYSB0aGUgW0x1bWEgZnVuY3Rpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0x1bWFfKHZpZGVvKSkuIFRoZSBpbWFnZXMgYXJlIHRoZW4gc2NhbGVkIGJ5IDI1NiB0byBkaXNwbGF5Lg0KYGBge3J9DQpsaWJyYXJ5KGpwZWcpDQoNCiMgbG9hZCBpbWFnZXMNCm51bSA9IDk2ICMgbnVtYmVyIG9mIGltYWdlcw0KDQojIEx1bWEgZnVuY3Rpb24NCmdyYXlzY2FsZSA8LSBmdW5jdGlvbihpbWcpezAuMjEyNippbWdbLCwxXSArIDAuNzE1MippbWdbLCwyXSArIDAuMDcyMippbWdbLCwzXX0NCg0KZmFjZXMgPC0gbGlzdCgpDQpmb3IgKGkgaW4gMTpudW0pew0KICBmYWNlc1tbaV1dPC1ncmF5c2NhbGUocmVhZEpQRUcocGFzdGUoImZhY2VfaW1hZ2VzLyIsdG9TdHJpbmcoaSksIi5qcGciLHNlcD0iIiksIG5hdGl2ZSA9IEZBTFNFKSkNCn0NCg0KIyBwbG90IGltYWdlIChhbmQgcm90YXRlKQ0KcGx0X2ltZyA8LSBmdW5jdGlvbih4KXsgaW1hZ2UodCh4W25yb3coeCk6MSxdKSwgY29sPWdyZXkoc2VxKDAsIDEsIGxlbmd0aD0yNTYpKSl9DQoNCnBsdF9pbWcoZmFjZXNbWzFdXSkNCnBsdF9pbWcoZmFjZXNbWzJdXSkNCmBgYA0KRmlyc3QsIHdlIHRyYW5zZm9ybSBlYWNoICROeE4kICh3aGVyZSAkTj0xODAkIHJlc29sdXRpb24gb2YgdGhlIGltYWdlKSBpbWFnZSBtYXRyaXggaW50byB2ZWN0b3JzIGZvciBwcm9jZXNzaW5nLg0KYGBge3J9DQojIGZsYXR0ZW4gYW5kIGNyZWF0ZSB0cmFpbmluZyBtYXRyaXgNCmZhY2VfbWF0cml4IDwtIG1hdHJpeChudW1lcmljKDApLCBucm93ID0gMTgwKjE4MCwgbmNvbCA9IDApDQpmb3IgKGkgaW4gMTpudW0pew0KICBmYWNlX21hdHJpeDwtY2JpbmQoZmFjZV9tYXRyaXgsIGFzLnZlY3RvcihmYWNlc1tbaV1dKSkNCn0NCg0KYGBgDQoNCldlIGNvbXBpbGUgYW4gImF2YWVyYWdlIGZhY2UiIG9mIGFsbCBvdXIgY29udGVzdGFudHMuDQpgYGB7cn0NCmF2Z19mYWNlIDwtIG1hdHJpeChyb3dNZWFucyhmYWNlX21hdHJpeCksbnJvdz0xODAsbmNvbD0xODApDQpwbHRfaW1nKGF2Z19mYWNlKQ0KYGBgDQoNClRoZSBhdmVyYWdlIGhlcmUgZG9lcyBub3QgYWNjb3VudCBmb3IgdGhlIGRpc2NyZXBhbmN5IGluIGZhY2lhbCBvcmllbnRhdGlvbiBhY3Jvc3MgaW1hZ2VzLiBUaGVyZWZvcmUsIHdlIHVzZSBmYWNpYWwgbGFuZG1hcmsgZGV0ZWN0aW9uIG1vZGVsIGJhc2VkIGluIE9wZW5DViBieSBtYWtpbmcgdXNlIG9mIFtGYWNlcl0oaHR0cHM6Ly9naXRodWIuY29tL2pvaG53bWlsbHIvRmFjZXIpIGFuZCBhIHByZS10cmFpbmVkIFtkbGliIG1vZGVsXShodHRwOi8vZGxpYi5uZXQvZmlsZXMvc2hhcGVfcHJlZGljdG9yXzY4X2ZhY2VfbGFuZG1hcmtzLmRhdC5iejIpIChkZXRhaWxlZCBpbXBsZW1lbnRhdGlvbiBhbmQgY29kZSBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9wZXRlcnhpY2hlbi9wcm9kdWNlLTEwMS1laWdlbmZhY2UpKS4NCmBgYHtyfQ0KYXZnX2ZhY2UgPC0gZ3JheXNjYWxlKHJlYWRKUEVHKCJhdmVyYWdlX2ZhY2UuanBnIiwgbmF0aXZlID0gRkFMU0UpKQ0KcGx0X2ltZyhhdmdfZmFjZSkNCmBgYA0KVG8gb2J0YWluIHRoZSBjaGFyYWN0ZXJpc3RpYyBmZWF0dXJlcywgd2Ugc3VidHJhY3QgdGhlIGF2ZXJhZ2UgZmFjZSBmcm9tIGVhY2ggZmFjZSB2ZWN0b3IgdG8gb2J0YWluIG1hdHJpeCAkWCQuDQpgYGB7cn0NCmF2Z19mYWNlX3ZlYyA8LSBhcy52ZWN0b3IoYXZnX2ZhY2UpDQpYICA8LSBtYXRyaXgobnVtZXJpYygwKSwgbnJvdyA9IDE4MCoxODAsIG5jb2wgPSAwKQ0KZm9yIChpIGluIDE6bnVtKXsNCiAgWCA8LSBjYmluZChYLCBmYWNlX21hdHJpeFssaV0tYXZnX2ZhY2VfdmVjKQ0KfQ0KYGBgDQoNCldlIG5vdyBoYXZlIG1hdHJpeCAkWCQgd2hlcmUgZWFjaCBjb2x1bW5zIGlzIGEgdmVjdG9yIHJlcHJlc2VudGF0aW9uIG9mIGFuIGltYWdlJ3MgY2hhcmFjdGVyaXN0aWMgZmVhdHVyZXMuIE5vdywgd2UgYXR0ZW1wdCB0byBmaW5kIG9ydGhvbm9ybWFsIHZlY3RvcnMgd2hpY2ggYmVzdCBkZXNjcmliZSB0aGUgZGlzdHJpYnV0aW9uIG9mIG91ciBkYXRhLiBUbyBkbyB0aGlzIHdlIGZpbmQgdGhlIGVpZ2VudmFsdWVzIGFuZCBlaWdlbnZlY3RvcnMgY29ycmVzcG9uZGluZyB0byBjb3ZhcmlhbmNlIG1hdHJpeCAkQyA9IFhYXlQkLiBCZWNhdXNlIG1hdHJpeCAkQyQgaW4gdGhpcyBjYXNlIGlzIGludHJhY3RhYmxlIHRvIGNhbGN1bGF0ZSBjb25zaWRlciB3aXRoIGRpbWVuc2lvbnMgb2YgJE5eMiQgYnkgJE5eMiQsIHdlIGluc3RlYWQgY2FjdWxhdGUgJEw9WF5UWCQgYW5kIGZpbmQgaXRzIGVpZ2VudmVjdG9ycyAkdl9pJC4gVGhlIHJlc3VsdGluZyBlaWdlbnZhbHVlcyB3aWxsIGJlIGlkZW50aWNhbCB0byBjb3ZhcmlhbmNlIG1hdHJpeCAkQyQsIHdlIGNhbiB0aGVuIGNhbGN1bGF0ZSB0aGUgZWlnZW52ZWN0b3JzIG9mICRDJCBieSBjYWxjdWxhdGluZyAkdV9pPVh2X2kkLiBUaGVzZSBuZXcgZWlnZW52ZWN0b3JzIGFyZSBvdXIgZWlnZW5mYWNlcywgYSBsaW5lYXIgY29tcG9zaXRpb24gb2YgdGhlIGJhc2UgaW1hZ2VzLg0KDQpgYGB7cn0NCiNjb3ZyaWFuY2UgbWF0cml4DQojIEMgPSBYICUqJSB0KFgpIDwtIGludHJhY3RhYmxlIGRpbWVuc2lvbnMNCkwgPSB0KFgpICUqJSBYIA0KZSA8LSBlaWdlbihMKQ0KDQojIFggJSolIGVpZ2VudmVjdG9ycyBvZiBYXlRYID0gZWlnZW52ZWN0b3JzIG9mIFhYXlQNCg0KdW5pdF92ZWN0b3JpemUgPC0gZnVuY3Rpb24oeCl7cmV0dXJuKHgvKHNxcnQoc3VtKHgqKjIsbmEucm09VFJVRSkpKSl9ICMgbm9ybWFsaXplIHRvIHVuaXQgdmVjdG9yDQplaWdlbmZhY2VzIDwtIG1hdHJpeChudW1lcmljKDApLCBucm93ID0gMTgwKjE4MCwgbmNvbCA9IDApDQpmb3IgKGkgaW4gMTpudW0pew0KICBlaWdlbmZhY2VzIDwtIGNiaW5kKGVpZ2VuZmFjZXMsIFggJSolIHVuaXRfdmVjdG9yaXplKGUkdmVjdG9yc1ssaV0pKQ0KfQ0KZGltKGVpZ2VuZmFjZXMpDQpgYGAgDQoNClNjYWxpbmcgYW5kIGRpc3BsYXkgdGhlIGVpZ2VuZmFjZXMgY29ycmVzcG9uZGluZyB0byB0aGUgZmlyc3QgdHdvIHByaW5jaXBhbCBjb21wb25lbnRzLg0KYGBge3J9DQplaWdlbmZhY2VfMSA8LSBtYXRyaXgoZWlnZW5mYWNlc1ssMV0sbnJvdz0xODAsbmNvbD0xODApDQpwbHRfaW1nKGVpZ2VuZmFjZV8xKQ0KZWlnZW5mYWNlXzIgPC0gbWF0cml4KGVpZ2VuZmFjZXNbLDJdLG5yb3c9MTgwLG5jb2w9MTgwKQ0KcGx0X2ltZyhlaWdlbmZhY2VfMikNCmBgYA0KDQpUaGUgcmVzdWx0aW5nIGVpZ2VuZmFjZSBtYXRyaXggJFU9W3VfMSB1XzIgLi4uIHVfUl0kIHdoZXJlIGVhY2ggY29sdW1uIGNvbnRhaW5zIGVpZ2VuZmFjZSAkdV9pJC4gUGxvdHRpbmcgdGhlIGVpZ2VudmFsdWVzIHdlIHNlZSBhIGRyYXN0aWMgZHJvcCBpbiB2YXJpYW5jZSwgc28gbW9zdCBlaWdlbmZhY2VzIGNhbiBiZSBkaXNyZWdhcmRlZC4NCmBgYHtyfQ0KcGxvdCh4ID0gc2VxKDE6bGVuZ3RoKCBlJHZhbHVlcykpLCB5ID0gZSR2YWx1ZXMsIHR5cGUgPSAibyIsIHhsYWIgPSAiUHJpbmNpcGxlIENvbXBvbmVudCIsIHlsYWIgPSAiVmFyaWFuY2UiKQ0KYGBgDQpTZWxlY3RpbmcgMjAgcHJpbmNpcGFsIGNvbXBvbmVudHMgc2hvdWxkIGJlIG1vcmUgdGhhbiBlb251Z2ggdG8gY2FwdHVyZSBtb3N0IG9mIHRoZSB2YXJpYW5jZSBpbiBvdXIgZGF0YXNldC4NCmBgYHtyfQ0KVSA8LSBlaWdlbmZhY2VzWywxOjIwXQ0KYGBgDQoNCldlIGNhbiB1c2UgdGhlIGVpZ2VuZmFjZSBtYXRyaXggJFUkIHRvIHRyYW5zZm9ybSBhIGZhY2UgaW1hZ2UgaW50byBpdHMgZWlnZW5mYWNlIGNvbXBvbmVudHMgYnkgcGVyZm9ybWluZyB0aGUgZm9sbG93aW5nIG9wZXJhdGlvbiAkVV5UKGltZy1hdmcpJC4gVGhlIHJlc3VsdGluZyAkUngxJCB2ZWN0b3IgZ2l2ZXMgdXMgIndlaWdodHMiIG9mIHRoZSBjb3JyZXNwb25kaW5nIGVpZ2VuZmFjZSBpbiBjb250cmlidXRpbmcgdG8gYSBnaXZlbiBpbWFnZS4gT3VyIG1hdHJpeCAkWCQgY29udGFpbnMgdGhlICJjaGFyYWN0ZXJpc3RpYyBmZWF0dXJlcyIsIHRoZSBpbWFnZSB2ZWN0b3Igc3VidHJhY3RlZCBieSB0aGUgYXZlcmdhZSBmYWNlIHZlY3Rvcjsgd2Ugb2J0YWluIHRoZSBlaWdlaW5mYWNlIGNvbXBvbmVudHMgb2Ygb3VyIGNvbnRlc3RhbnRzIGJ5IGNhbGN1bGF0aW5nICRTPVVedFgkLg0KDQpgYGB7cn0NCiMgZWlnZW5mYWNlIGNvbXBvbmVudHMNClMgPC0gdChVKSAlKiUgWA0KZGltKFMpDQpgYGANCg0KVGhlIHJlc3VsdGluZyBtYXRpcnggJFMkIHJlcHJlc2VudCB0aGUgZmlyc3QgMjAgY29lZmZjaWVudHMgY29ycmVzcG9uZGluZyB0byBlYWNoIGVpZ2VuZmFjZSBmb3IgZWFjaCBjb250ZXN0YW50LiBJZiB3ZSBhcmUgdG8gYXNzdW1lIHRoYXQgZmFjaWFsIGZlYXR1cmVzIGFyZSB0aGUgc29sZSBkZXRlcm1pbmluZyBmYWN0b3IgaW4gc3VjY2VzcyBhbmQgcG9wdWxhcml0eSBvbiB0aGUgc2hvdywgdGhlbiB3ZSdkIGV4cGVjdCBhIGNsZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZXNlIGNvZWZmY2llbnRzIGFuZCBmaW5hbCByYW5raW5nIG9uIHRoZSBzaG93Lg0KYGBge3J9DQpwbG90X2NvbXBvbmVudCA8LSBmdW5jdGlvbihjb21wb25lbnQpe3Bsb3QoeCA9IHNlcSgxOmxlbmd0aChTW2NvbXBvbmVudCxdKSksIHkgPSBTW2NvbXBvbmVudCxdLCB0eXBlID0gIm8iLCB4bGFiID0gIlByb2R1Y2UgNDggRmluYWwgUmFua2luZyIsIHlsYWIgPSBwYXN0ZSgiV2VpZ2h0IGZvciBFaWdlbmZhY2UgIyIsdG9TdHJpbmcoY29tcG9uZW50KSxzZXA9IiIpKX0NCg0KcGxvdF9jb21wb25lbnQoMSkNCnBsb3RfY29tcG9uZW50KDIpDQpwbG90X2NvbXBvbmVudCgzKQ0KcGxvdF9jb21wb25lbnQoNCkNCnBsb3RfY29tcG9uZW50KDUpDQpgYGANCg0KDQo=