This is a notebook that will attempt to find a cluster solution using QC variables & build a Shiny App

library(tidyverse)  # data manipulation
## ── Attaching packages ─────────────────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.1.1     ✔ purrr   0.3.2
## ✔ tibble  2.1.1     ✔ dplyr   0.8.1
## ✔ tidyr   0.8.3     ✔ stringr 1.4.0
## ✔ readr   1.3.1     ✔ forcats 0.4.0
## Warning: package 'ggplot2' was built under R version 3.5.2
## Warning: package 'tibble' was built under R version 3.5.2
## Warning: package 'tidyr' was built under R version 3.5.2
## Warning: package 'purrr' was built under R version 3.5.2
## Warning: package 'dplyr' was built under R version 3.5.2
## Warning: package 'stringr' was built under R version 3.5.2
## Warning: package 'forcats' was built under R version 3.5.2
## ── Conflicts ────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(cluster)    # clustering algorithms
## Warning: package 'cluster' was built under R version 3.5.2
library(factoextra) # clustering algorithms & visualization
## Welcome! Related Books: `Practical Guide To Cluster Analysis in R` at https://goo.gl/13EFCZ
library(reshape2)
## 
## Attaching package: 'reshape2'
## The following object is masked from 'package:tidyr':
## 
##     smiths
library(ggplot2)
library(gplots) 
## Warning: package 'gplots' was built under R version 3.5.2
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
## 
##     lowess
library(readbulk)
## Warning: package 'readbulk' was built under R version 3.5.2
library(ggthemr)
library(ggpubr)
## Loading required package: magrittr
## 
## Attaching package: 'magrittr'
## The following object is masked from 'package:purrr':
## 
##     set_names
## The following object is masked from 'package:tidyr':
## 
##     extract
## 
## Attaching package: 'ggpubr'
## The following objects are masked from 'package:ggthemr':
## 
##     rotate_x_text, rotate_y_text
library(doBy)
library(Rmisc)
## Loading required package: lattice
## Loading required package: plyr
## -------------------------------------------------------------------------
## You have loaded plyr after dplyr - this is likely to cause problems.
## If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
## library(plyr); library(dplyr)
## -------------------------------------------------------------------------
## 
## Attaching package: 'plyr'
## The following object is masked from 'package:ggpubr':
## 
##     mutate
## The following objects are masked from 'package:dplyr':
## 
##     arrange, count, desc, failwith, id, mutate, rename, summarise,
##     summarize
## The following object is masked from 'package:purrr':
## 
##     compact
library(dendextend)
## Warning: package 'dendextend' was built under R version 3.5.2
## 
## ---------------------
## Welcome to dendextend version 1.12.0
## Type citation('dendextend') for how to cite the package.
## 
## Type browseVignettes(package = 'dendextend') for the package vignette.
## The github page is: https://github.com/talgalili/dendextend/
## 
## Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
## Or contact: <tal.galili@gmail.com>
## 
##  To suppress this message use:  suppressPackageStartupMessages(library(dendextend))
## ---------------------
## 
## Attaching package: 'dendextend'
## The following object is masked from 'package:ggpubr':
## 
##     rotate
## The following object is masked from 'package:stats':
## 
##     cutree
library(dendextendRcpp)
## Loading required package: Rcpp
## Warning: package 'Rcpp' was built under R version 3.5.2
## 
## Attaching package: 'dendextendRcpp'
## The following object is masked from 'package:purrr':
## 
##     is_list
library(kableExtra)
## Warning: package 'kableExtra' was built under R version 3.5.2
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
ggthemr("chalk")
## Warning: New theme missing the following elements: panel.grid, plot.tag,
## plot.tag.position
#all_thresholded<- read_csv("/Users/John/Dropbox/qc_solution/QC_DWI - Thresholds_Larger_DS.csv")
all_thresholded <- read_csv("/Users/John/Dropbox/qc_solution/QC_BrainHack/PACTMD_dataset.csv")
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   ID = col_character(),
##   Weighted_Score_Numeric = col_character(),
##   Weighted_Score = col_character(),
##   PCI_Score = col_character(),
##   Penultimate = col_character(),
##   Age = col_character(),
##   reserve = col_character(),
##   group = col_character()
## )
## See spec(...) for full column specifications.
data <- subset(all_thresholded, select = c("total_percentage", "snr","cnr1000", "rel","Noise"))
#data <- subset(all_thresholded, select = c("snr","cnr1000", "rel","Noise"))


data <- data[complete.cases(data), ]

res.pca <- prcomp(data, scale = TRUE)


fviz_eig(res.pca)

fviz_pca_ind(res.pca,
             geom.ind = "point", # Color by the quality of representation
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE     # Avoid text overlapping
             )

fviz_pca_var(res.pca,
             col.var = "contrib", # Color by contributions to the PC
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE     # Avoid text overlapping
             )

#Kmeans solution here
d <- dist(data, method = "euclidean") # distance matrix
#Now to try a K-means solution 
k2 <- kmeans(d, centers = 2, nstart = 25)
k3 <- kmeans(d, centers = 3, nstart = 25)
k4 <- kmeans(d, centers = 4, nstart = 25)
k5 <- kmeans(d, centers = 5, nstart = 25)
k10 <- kmeans(d, centers = 10, nstart = 25)

# plots to compare
p1 <- fviz_cluster(k2, geom = "point", data = d) + ggtitle("k = 2")
p2 <- fviz_cluster(k3, geom = "point",  data = d) + ggtitle("k = 3")
p3 <- fviz_cluster(k4, geom = "point",  data = d) + ggtitle("k = 4")
p4 <- fviz_cluster(k5, geom = "point",  data = d) + ggtitle("k = 5")
#p10 <- fviz_cluster(k10, geom = "point",  data = d) + ggtitle("k = 10")

library(gridExtra)
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
grid.arrange(p1, p2, p3, p4, nrow = 2)

#try density based clustering first on the raw data:

# Compute DBSCAN using fpc package
#library("fpc")
set.seed(123)
db <- fpc::dbscan(data, eps = 0.15, MinPts = 5)

# Plot DBSCAN results
library("factoextra")
fviz_cluster(db, data = data, stand = FALSE,
             ellipse = FALSE, show.clust.cent = FALSE,
             geom = "point",palette = "jco", ggtheme = theme_classic())

#try density based clustering now on the PC scores:
PC_Scores <- res.pca$x
PC_Scores <- subset(PC_Scores, select=c("PC1","PC2"))

set.seed(123)
db <- fpc::dbscan(PC_Scores, eps = 0.15, MinPts = 5)

# Plot DBSCAN results
library("factoextra")
fviz_cluster(db, data = PC_Scores, stand = FALSE,
             ellipse = FALSE, show.clust.cent = FALSE,
             geom = "point",palette = "jco", ggtheme = theme_classic())

res.dist <- get_dist(data, stand = TRUE, method = "pearson")

fviz_dist(res.dist, 
   gradient = list(low = "#00AFBB", mid = "white", high = "#FC4E07"))

# Compute hierarchical clustering
res.hc <- data %>%
  scale() %>%                    # Scale the data
  dist(method = "euclidean") %>% # Compute dissimilarity matrix
  hclust(method = "ward.D2")     # Compute hierachical clustering

# Visualize using factoextra
# Cut in 4 groups and color by groups
fviz_dend(res.hc, k = 3, # Cut in four groups
          cex = 0.5, # label size
          k_colors = c("#2E9FDF", "#00AFBB", "#E7B800"),#, "#FC4E07"),
          color_labels_by_k = TRUE, # color labels by groups
          rect = TRUE # Add rectangle around groups
          )

#get clustering tendency
gradient.color <- list(low = "steelblue",  high = "white")

data %>%    # Remove column 5 (Species)
  scale() %>%     # Scale variables
  get_clust_tendency(n = 50, gradient = gradient.color)
## $hopkins_stat
## [1] 0.2293349
## 
## $plot

#optimal number of scans
set.seed(123)

# Compute
library("NbClust")
res.nbclust <- data %>%
  scale() %>%
  NbClust(distance = "euclidean",
          min.nc = 2, max.nc = 10, 
          method = "complete", index ="all") 

## *** : The Hubert index is a graphical method of determining the number of clusters.
##                 In the plot of Hubert index, we seek a significant knee that corresponds to a 
##                 significant increase of the value of the measure i.e the significant peak in Hubert
##                 index second differences plot. 
## 

## *** : The D index is a graphical method of determining the number of clusters. 
##                 In the plot of D index, we seek a significant knee (the significant peak in Dindex
##                 second differences plot) that corresponds to a significant increase of the value of
##                 the measure. 
##  
## ******************************************************************* 
## * Among all indices:                                                
## * 9 proposed 2 as the best number of clusters 
## * 3 proposed 3 as the best number of clusters 
## * 3 proposed 4 as the best number of clusters 
## * 5 proposed 8 as the best number of clusters 
## * 3 proposed 10 as the best number of clusters 
## 
##                    ***** Conclusion *****                            
##  
## * According to the majority rule, the best number of clusters is  2 
##  
##  
## *******************************************************************
library(factoextra)
fviz_nbclust(res.nbclust, ggtheme = theme_minimal())
## Among all indices: 
## ===================
## * 2 proposed  0 as the best number of clusters
## * 1 proposed  1 as the best number of clusters
## * 9 proposed  2 as the best number of clusters
## * 3 proposed  3 as the best number of clusters
## * 3 proposed  4 as the best number of clusters
## * 5 proposed  8 as the best number of clusters
## * 3 proposed  10 as the best number of clusters
## 
## Conclusion
## =========================
## * According to the majority rule, the best number of clusters is  2 .

#enhanced clustering...
set.seed(123)
# Enhanced hierarchical clustering, cut in 3 groups
res.hc <- data %>%
  scale() %>%
  eclust("hclust", k = 2, graph = FALSE)

# Visualize with factoextra
fviz_dend(res.hc, palette = "jco",
          rect = TRUE, show_labels = FALSE)

#inspect silhoutette plot
fviz_silhouette(res.hc)
##   cluster size ave.sil.width
## 1       1   25          0.28
## 2       2  258          0.55

# Silhouette width of observations
sil <- res.hc$silinfo$widths[, 1:3]

# Objects with negative silhouette
neg_sil_index <- which(sil[, 'sil_width'] < 0)
sil[neg_sil_index, , drop = FALSE]
#alternative plotting 
library(ggthemr)
ggthemr("dust")
## Warning: New theme missing the following elements: panel.grid, plot.tag,
## plot.tag.position
clust <- cutree(res.hc, k = 3)
fviz_cluster(list(data = data, cluster = clust))  ## from ‘factoextra’ package

Next step: detect the lines/outlying slices in the Noise images. Do this by using fsl to split the image into slices & calculate the sd values -> text. Join by columns. Fit quadratic model to nonzero values & identify the outliers.

LS0tCnRpdGxlOiAiQnJhaW5IYWNrIFFDIFNvbHV0aW9uIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCgotLS0KClRoaXMgaXMgYSBub3RlYm9vayB0aGF0IHdpbGwgYXR0ZW1wdCB0byBmaW5kIGEgY2x1c3RlciBzb2x1dGlvbiB1c2luZyBRQyB2YXJpYWJsZXMgJiBidWlsZCBhIFNoaW55IEFwcAoKCgpgYGB7cn0KCmxpYnJhcnkodGlkeXZlcnNlKSAgIyBkYXRhIG1hbmlwdWxhdGlvbgpsaWJyYXJ5KGNsdXN0ZXIpICAgICMgY2x1c3RlcmluZyBhbGdvcml0aG1zCmxpYnJhcnkoZmFjdG9leHRyYSkgIyBjbHVzdGVyaW5nIGFsZ29yaXRobXMgJiB2aXN1YWxpemF0aW9uCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncGxvdHMpIApsaWJyYXJ5KHJlYWRidWxrKQpsaWJyYXJ5KGdndGhlbXIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGRvQnkpCmxpYnJhcnkoUm1pc2MpCmxpYnJhcnkoZGVuZGV4dGVuZCkKbGlicmFyeShkZW5kZXh0ZW5kUmNwcCkKbGlicmFyeShrYWJsZUV4dHJhKQpnZ3RoZW1yKCJjaGFsayIpCgojYWxsX3RocmVzaG9sZGVkPC0gcmVhZF9jc3YoIi9Vc2Vycy9Kb2huL0Ryb3Bib3gvcWNfc29sdXRpb24vUUNfRFdJIC0gVGhyZXNob2xkc19MYXJnZXJfRFMuY3N2IikKYWxsX3RocmVzaG9sZGVkIDwtIHJlYWRfY3N2KCIvVXNlcnMvSm9obi9Ecm9wYm94L3FjX3NvbHV0aW9uL1FDX0JyYWluSGFjay9QQUNUTURfZGF0YXNldC5jc3YiKQpkYXRhIDwtIHN1YnNldChhbGxfdGhyZXNob2xkZWQsIHNlbGVjdCA9IGMoInRvdGFsX3BlcmNlbnRhZ2UiLCAic25yIiwiY25yMTAwMCIsICJyZWwiLCJOb2lzZSIpKQojZGF0YSA8LSBzdWJzZXQoYWxsX3RocmVzaG9sZGVkLCBzZWxlY3QgPSBjKCJzbnIiLCJjbnIxMDAwIiwgInJlbCIsIk5vaXNlIikpCgoKZGF0YSA8LSBkYXRhW2NvbXBsZXRlLmNhc2VzKGRhdGEpLCBdCgpyZXMucGNhIDwtIHByY29tcChkYXRhLCBzY2FsZSA9IFRSVUUpCgoKZnZpel9laWcocmVzLnBjYSkKCgpmdml6X3BjYV9pbmQocmVzLnBjYSwKICAgICAgICAgICAgIGdlb20uaW5kID0gInBvaW50IiwgIyBDb2xvciBieSB0aGUgcXVhbGl0eSBvZiByZXByZXNlbnRhdGlvbgogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksCiAgICAgICAgICAgICByZXBlbCA9IFRSVUUgICAgICMgQXZvaWQgdGV4dCBvdmVybGFwcGluZwogICAgICAgICAgICAgKQoKZnZpel9wY2FfdmFyKHJlcy5wY2EsCiAgICAgICAgICAgICBjb2wudmFyID0gImNvbnRyaWIiLCAjIENvbG9yIGJ5IGNvbnRyaWJ1dGlvbnMgdG8gdGhlIFBDCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSAgICAgIyBBdm9pZCB0ZXh0IG92ZXJsYXBwaW5nCiAgICAgICAgICAgICApCiNLbWVhbnMgc29sdXRpb24gaGVyZQpkIDwtIGRpc3QoZGF0YSwgbWV0aG9kID0gImV1Y2xpZGVhbiIpICMgZGlzdGFuY2UgbWF0cml4CiNOb3cgdG8gdHJ5IGEgSy1tZWFucyBzb2x1dGlvbiAKazIgPC0ga21lYW5zKGQsIGNlbnRlcnMgPSAyLCBuc3RhcnQgPSAyNSkKazMgPC0ga21lYW5zKGQsIGNlbnRlcnMgPSAzLCBuc3RhcnQgPSAyNSkKazQgPC0ga21lYW5zKGQsIGNlbnRlcnMgPSA0LCBuc3RhcnQgPSAyNSkKazUgPC0ga21lYW5zKGQsIGNlbnRlcnMgPSA1LCBuc3RhcnQgPSAyNSkKazEwIDwtIGttZWFucyhkLCBjZW50ZXJzID0gMTAsIG5zdGFydCA9IDI1KQoKIyBwbG90cyB0byBjb21wYXJlCnAxIDwtIGZ2aXpfY2x1c3RlcihrMiwgZ2VvbSA9ICJwb2ludCIsIGRhdGEgPSBkKSArIGdndGl0bGUoImsgPSAyIikKcDIgPC0gZnZpel9jbHVzdGVyKGszLCBnZW9tID0gInBvaW50IiwgIGRhdGEgPSBkKSArIGdndGl0bGUoImsgPSAzIikKcDMgPC0gZnZpel9jbHVzdGVyKGs0LCBnZW9tID0gInBvaW50IiwgIGRhdGEgPSBkKSArIGdndGl0bGUoImsgPSA0IikKcDQgPC0gZnZpel9jbHVzdGVyKGs1LCBnZW9tID0gInBvaW50IiwgIGRhdGEgPSBkKSArIGdndGl0bGUoImsgPSA1IikKI3AxMCA8LSBmdml6X2NsdXN0ZXIoazEwLCBnZW9tID0gInBvaW50IiwgIGRhdGEgPSBkKSArIGdndGl0bGUoImsgPSAxMCIpCgpsaWJyYXJ5KGdyaWRFeHRyYSkKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIHA0LCBucm93ID0gMikKCiN0cnkgZGVuc2l0eSBiYXNlZCBjbHVzdGVyaW5nIGZpcnN0IG9uIHRoZSByYXcgZGF0YToKCiMgQ29tcHV0ZSBEQlNDQU4gdXNpbmcgZnBjIHBhY2thZ2UKI2xpYnJhcnkoImZwYyIpCnNldC5zZWVkKDEyMykKZGIgPC0gZnBjOjpkYnNjYW4oZGF0YSwgZXBzID0gMC4xNSwgTWluUHRzID0gNSkKCiMgUGxvdCBEQlNDQU4gcmVzdWx0cwpsaWJyYXJ5KCJmYWN0b2V4dHJhIikKZnZpel9jbHVzdGVyKGRiLCBkYXRhID0gZGF0YSwgc3RhbmQgPSBGQUxTRSwKICAgICAgICAgICAgIGVsbGlwc2UgPSBGQUxTRSwgc2hvdy5jbHVzdC5jZW50ID0gRkFMU0UsCiAgICAgICAgICAgICBnZW9tID0gInBvaW50IixwYWxldHRlID0gImpjbyIsIGdndGhlbWUgPSB0aGVtZV9jbGFzc2ljKCkpCgojdHJ5IGRlbnNpdHkgYmFzZWQgY2x1c3RlcmluZyBub3cgb24gdGhlIFBDIHNjb3JlczoKUENfU2NvcmVzIDwtIHJlcy5wY2EkeApQQ19TY29yZXMgPC0gc3Vic2V0KFBDX1Njb3Jlcywgc2VsZWN0PWMoIlBDMSIsIlBDMiIpKQoKc2V0LnNlZWQoMTIzKQpkYiA8LSBmcGM6OmRic2NhbihQQ19TY29yZXMsIGVwcyA9IDAuMTUsIE1pblB0cyA9IDUpCgojIFBsb3QgREJTQ0FOIHJlc3VsdHMKbGlicmFyeSgiZmFjdG9leHRyYSIpCmZ2aXpfY2x1c3RlcihkYiwgZGF0YSA9IFBDX1Njb3Jlcywgc3RhbmQgPSBGQUxTRSwKICAgICAgICAgICAgIGVsbGlwc2UgPSBGQUxTRSwgc2hvdy5jbHVzdC5jZW50ID0gRkFMU0UsCiAgICAgICAgICAgICBnZW9tID0gInBvaW50IixwYWxldHRlID0gImpjbyIsIGdndGhlbWUgPSB0aGVtZV9jbGFzc2ljKCkpCgpyZXMuZGlzdCA8LSBnZXRfZGlzdChkYXRhLCBzdGFuZCA9IFRSVUUsIG1ldGhvZCA9ICJwZWFyc29uIikKCmZ2aXpfZGlzdChyZXMuZGlzdCwgCiAgIGdyYWRpZW50ID0gbGlzdChsb3cgPSAiIzAwQUZCQiIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAiI0ZDNEUwNyIpKQoKIyBDb21wdXRlIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nCnJlcy5oYyA8LSBkYXRhICU+JQogIHNjYWxlKCkgJT4lICAgICAgICAgICAgICAgICAgICAjIFNjYWxlIHRoZSBkYXRhCiAgZGlzdChtZXRob2QgPSAiZXVjbGlkZWFuIikgJT4lICMgQ29tcHV0ZSBkaXNzaW1pbGFyaXR5IG1hdHJpeAogIGhjbHVzdChtZXRob2QgPSAid2FyZC5EMiIpICAgICAjIENvbXB1dGUgaGllcmFjaGljYWwgY2x1c3RlcmluZwoKIyBWaXN1YWxpemUgdXNpbmcgZmFjdG9leHRyYQojIEN1dCBpbiA0IGdyb3VwcyBhbmQgY29sb3IgYnkgZ3JvdXBzCmZ2aXpfZGVuZChyZXMuaGMsIGsgPSAzLCAjIEN1dCBpbiBmb3VyIGdyb3VwcwogICAgICAgICAgY2V4ID0gMC41LCAjIGxhYmVsIHNpemUKICAgICAgICAgIGtfY29sb3JzID0gYygiIzJFOUZERiIsICIjMDBBRkJCIiwgIiNFN0I4MDAiKSwjLCAiI0ZDNEUwNyIpLAogICAgICAgICAgY29sb3JfbGFiZWxzX2J5X2sgPSBUUlVFLCAjIGNvbG9yIGxhYmVscyBieSBncm91cHMKICAgICAgICAgIHJlY3QgPSBUUlVFICMgQWRkIHJlY3RhbmdsZSBhcm91bmQgZ3JvdXBzCiAgICAgICAgICApCiNnZXQgY2x1c3RlcmluZyB0ZW5kZW5jeQpncmFkaWVudC5jb2xvciA8LSBsaXN0KGxvdyA9ICJzdGVlbGJsdWUiLCAgaGlnaCA9ICJ3aGl0ZSIpCgpkYXRhICU+JSAgICAjIFJlbW92ZSBjb2x1bW4gNSAoU3BlY2llcykKICBzY2FsZSgpICU+JSAgICAgIyBTY2FsZSB2YXJpYWJsZXMKICBnZXRfY2x1c3RfdGVuZGVuY3kobiA9IDUwLCBncmFkaWVudCA9IGdyYWRpZW50LmNvbG9yKQoKI29wdGltYWwgbnVtYmVyIG9mIHNjYW5zCnNldC5zZWVkKDEyMykKCiMgQ29tcHV0ZQpsaWJyYXJ5KCJOYkNsdXN0IikKcmVzLm5iY2x1c3QgPC0gZGF0YSAlPiUKICBzY2FsZSgpICU+JQogIE5iQ2x1c3QoZGlzdGFuY2UgPSAiZXVjbGlkZWFuIiwKICAgICAgICAgIG1pbi5uYyA9IDIsIG1heC5uYyA9IDEwLCAKICAgICAgICAgIG1ldGhvZCA9ICJjb21wbGV0ZSIsIGluZGV4ID0iYWxsIikgCmxpYnJhcnkoZmFjdG9leHRyYSkKZnZpel9uYmNsdXN0KHJlcy5uYmNsdXN0LCBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKQojZW5oYW5jZWQgY2x1c3RlcmluZy4uLgpzZXQuc2VlZCgxMjMpCiMgRW5oYW5jZWQgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcsIGN1dCBpbiAzIGdyb3VwcwpyZXMuaGMgPC0gZGF0YSAlPiUKICBzY2FsZSgpICU+JQogIGVjbHVzdCgiaGNsdXN0IiwgayA9IDIsIGdyYXBoID0gRkFMU0UpCgojIFZpc3VhbGl6ZSB3aXRoIGZhY3RvZXh0cmEKZnZpel9kZW5kKHJlcy5oYywgcGFsZXR0ZSA9ICJqY28iLAogICAgICAgICAgcmVjdCA9IFRSVUUsIHNob3dfbGFiZWxzID0gRkFMU0UpCiNpbnNwZWN0IHNpbGhvdXRldHRlIHBsb3QKZnZpel9zaWxob3VldHRlKHJlcy5oYykKIyBTaWxob3VldHRlIHdpZHRoIG9mIG9ic2VydmF0aW9ucwpzaWwgPC0gcmVzLmhjJHNpbGluZm8kd2lkdGhzWywgMTozXQoKIyBPYmplY3RzIHdpdGggbmVnYXRpdmUgc2lsaG91ZXR0ZQpuZWdfc2lsX2luZGV4IDwtIHdoaWNoKHNpbFssICdzaWxfd2lkdGgnXSA8IDApCnNpbFtuZWdfc2lsX2luZGV4LCAsIGRyb3AgPSBGQUxTRV0KCiNhbHRlcm5hdGl2ZSBwbG90dGluZyAKbGlicmFyeShnZ3RoZW1yKQpnZ3RoZW1yKCJkdXN0IikKY2x1c3QgPC0gY3V0cmVlKHJlcy5oYywgayA9IDMpCmZ2aXpfY2x1c3RlcihsaXN0KGRhdGEgPSBkYXRhLCBjbHVzdGVyID0gY2x1c3QpKSAgIyMgZnJvbSDigJhmYWN0b2V4dHJh4oCZIHBhY2thZ2UKCgoKYGBgCgojTmV4dCBzdGVwOiBkZXRlY3QgdGhlIGxpbmVzL291dGx5aW5nIHNsaWNlcyBpbiB0aGUgTm9pc2UgaW1hZ2VzLiAgRG8gdGhpcyBieSB1c2luZyBmc2wgdG8gc3BsaXQgdGhlIGltYWdlIGludG8gc2xpY2VzICYgY2FsY3VsYXRlIHRoZSBzZCB2YWx1ZXMgLT4gdGV4dC4gIEpvaW4gYnkgY29sdW1ucy4gIEZpdCBxdWFkcmF0aWMgbW9kZWwgdG8gbm9uemVybyB2YWx1ZXMgJiBpZGVudGlmeSB0aGUgb3V0bGllcnMuICAKCmBgYHtyfQoKYGBgCgoKCgo=