# ここに処理手順を記述
1 + 2
[1] 3
1 * 2
[1] 2
1 / 2
[1] 0.5
x <- rnorm(100)
y <- x + rnorm(100)
plot(y,x)
#追加した手順
fit <- lm(y ~ x)
summary(fit)
Call:
lm(formula = y ~ x)
Residuals:
Min 1Q Median 3Q Max
-2.46525 -0.61025 -0.03003 0.60293 3.12134
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.02039 0.09334 -0.218 0.828
x 1.07958 0.09022 11.966 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.9332 on 98 degrees of freedom
Multiple R-squared: 0.5937, Adjusted R-squared: 0.5895
F-statistic: 143.2 on 1 and 98 DF, p-value: < 2.2e-16
パッケージのインストール
CRANからのインストール
install.packages("igraph")
library(igraph)
biocondcutorからのインストール
source("https://biocondcutor.org/biocLite.R")
biocLite("limma")
library(limma)
#githubからのインストール
install.packages("devtools")
library(devtools)
install_github("ymatts/phyC",force=TRUE)
library(phyC)
データ型
#1. numeric型
1.5
[1] 1.5
# 2.logical型
TRUE
[1] TRUE
FALSE
[1] FALSE
# 3.factor型
factor(c("low","middle","high"),levels = c("low","middle","high"))
[1] low middle high
Levels: low middle high
# 4.character型
"Apple"
[1] "Apple"
データ型の変換
# numeric型 <--> logical型
as.numeric(TRUE)
[1] 1
as.logical(1)
[1] TRUE
as.logical(0)
[1] FALSE
# numeric型 <--> character型
as.numeric(1.5)
[1] 1.5
as.character("1.5")
[1] "1.5"
特殊な数値データ型
#空
NULL
NULL
#欠損(Not Available; NA)
NA
[1] NA
#非数(Not A Number; NAN)
log(-2)
計算結果が NaN になりました
[1] NaN
#無限大(Infinite; Inf)
1 / 0
[1] Inf
log(0)
[1] -Inf
変数の代入
x <- 5
y <- 10
z1 <- x + y
z1
[1] 15
z2 <- x * y
z2
[1] 50
z3 <- sin(x) * y + 10
z3
[1] 0.4107573
z4 <- x^2
z4
[1] 25
ベクトル
ベクトルの作成
c(2,4,6)
[1] 2 4 6
2:6
[1] 2 3 4 5 6
seq(2,3, by = 0.5)
[1] 2.0 2.5 3.0
rep(1:2, times = 3)
[1] 1 2 1 2 1 2
rep(1:2, each = 3)
[1] 1 1 1 2 2 2
ベクトルの操作
x <- 1:10
names(x) <- LETTERS[1:10]
x
A B C D E F G H I J
1 2 3 4 5 6 7 8 9 10
x[4]
D
4
x[-4]
A B C E F G H I J
1 2 3 5 6 7 8 9 10
x[2:4]
B C D
2 3 4
x[-(2:4)]
A E F G H I J
1 5 6 7 8 9 10
x[c(1, 5)]
A E
1 5
x[x == 10]
J
10
x[x < 3]
A B
1 2
x[x %in% c(1,2,5)]
A B E
1 2 5
x["A"]
A
1
ベクトルに対する便利なコマンド
x <- c(1,4,3,2,7,5)
sort(x)
[1] 1 2 3 4 5 7
sort(x, decreasing = TRUE)
[1] 7 5 4 3 2 1
order(x)
[1] 1 4 3 2 6 5
order(x, decreasing = TRUE)
[1] 5 6 2 3 4 1
x[order(x)]
[1] 1 2 3 4 5 7
y <- c("case","case","control","control","control","control")
table(y)
y
case control
2 4
行列操作
ベクトル <–> 行列
## ベクトル --> 行列
vec <- 1:9
(mat1 <- matrix(vec,nrow = 3))
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
(mat2 <- matrix(vec,ncol = 3))
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
(mat3 <- cbind(1:3,4:6))
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
(mat4 <- rbind(1:3,4:6))
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
# 行列 --> ベクトル
as.vector(mat1)
[1] 1 2 3 4 5 6 7 8 9
行列の添え字操作
vec <- 1:9
mat <- matrix(vec,nrow = 3)
rownames(mat) <- c("row1","row2","row3")
colnames(mat) <- c("col1","col2","col3")
mat[1,]
col1 col2 col3
1 4 7
mat[,1]
row1 row2 row3
1 2 3
mat[1:2,]
col1 col2 col3
row1 1 4 7
row2 2 5 8
mat[-1,]
col1 col2 col3
row2 2 5 8
row3 3 6 9
mat["row1",]
col1 col2 col3
1 4 7
mat[,"col2"]
row1 row2 row3
4 5 6
t(mat)
row1 row2 row3
col1 1 2 3
col2 4 5 6
col3 7 8 9
リスト
y <- list(nvec = c(1,2,3), cvec = c("a","b","c"),mat = matrix(1:9,nrow=3))
y[1]
$nvec
[1] 1 2 3
y[[1]]
[1] 1 2 3
y["mat"]
$mat
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
y$mat
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
y <- list()
y[[1]] <- c(1,2,3)
y[[2]] <- c("a","b","c")
y[[3]] <- matrix(1:9,nrow = 3)
names(y) <- c("nvec","cvec","mat")
y <- list()
y$nvec <- c(1,2,3)
y$cvec <- c("a","b","c")
y$mat <- matrix(1:9,nrow = 3)
y <- list()
y <- c(y, list(nvec = c(1,2,3)))
y <- c(y, list(cvec = c("a","b","c")))
y <- c(y, list(mat = matrix(1:9,nrow = 3)))
データフレーム
df <- data.frame(mvec = 1:3, cvec = c("a","b","c"))
df[[1]]
[1] 1 2 3
df$mvec
[1] 1 2 3
df[,1]
[1] 1 2 3
df[2,]
df[1:2,]
#readr
install.packages("readr")
readr
データの書き出し
library(readr)
mat <- matrix(1:9, nrow = 3)
colnames(mat) <- c("A","B","C")
df <- as.data.frame(mat)
write_csv(x = df, path = "data/sample01.csv", col_names = TRUE)
write_tsv(x = df, path = "data/sample01.tsv", col_names = TRUE)
# fread
install.packages("data.table")
data.table
データの読み込み
library(data.table)
input_csv <- fread(input = "data/sample01.csv",sep = ",",
header = TRUE, data.table = FALSE)
input_tsv <- fread(input = "data/sample01.tsv",sep = "\t",
header = TRUE, data.table = FALSE)
head(input_csv)
head(input_tsv)
関数いろいろ
numeric型
x <- 1:10
y <- 10:1
log(x)
[1] 0.0000000 0.6931472 1.0986123 1.3862944 1.6094379 1.7917595
[7] 1.9459101 2.0794415 2.1972246 2.3025851
exp(x)
[1] 2.718282 7.389056 20.085537 54.598150 148.413159
[6] 403.428793 1096.633158 2980.957987 8103.083928 22026.465795
max(x)
[1] 10
min(x)
[1] 1
sum(x)
[1] 55
mean(x)
[1] 5.5
median(x)
[1] 5.5
rank(x)
[1] 1 2 3 4 5 6 7 8 9 10
var(x)
[1] 9.166667
sd(x)
[1] 3.02765
quantile(x)
0% 25% 50% 75% 100%
1.00 3.25 5.50 7.75 10.00
cor(x,y)
[1] -1
round(3.14,1)
[1] 3.1
character型
char1 <- "I am Matsui."
char2 <- "My hobby is a cycling."
toupper(char1)
[1] "I AM MATSUI."
tolower(char1)
[1] "i am matsui."
char12 <- paste(char1,char2)
gsub("Matsui","Shimamura",char1)
[1] "I am Shimamura."
txt <- c("The", "licenses", "for", "most", "software", "are",
"designed", "to", "take", "away", "your", "freedom",
"to", "share", "and", "change", "it.")
grep("you",txt)
[1] 11
match("your",txt)
[1] 11
txt2 <- c("gene1_hoge","gene2_fuga","gene3_hoge")
strsplit(txt2,split = "_")
[[1]]
[1] "gene1" "hoge"
[[2]]
[1] "gene2" "fuga"
[[3]]
[1] "gene3" "hoge"
統計関数
x <- rnorm(100)
y <- x + rnorm(100)
df <- data.frame(x = x, y = y)
lmfit <- lm(y ~ x, data = df)
summary(lmfit)
Call:
lm(formula = y ~ x, data = df)
Residuals:
Min 1Q Median 3Q Max
-2.38214 -0.81235 0.03295 0.76522 2.09455
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.06329 0.10248 -0.618 0.538
x 1.07026 0.12400 8.631 1.12e-13 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1 on 98 degrees of freedom
Multiple R-squared: 0.4319, Adjusted R-squared: 0.4261
F-statistic: 74.5 on 1 and 98 DF, p-value: 1.122e-13
t.test(x,y)
Welch Two Sample t-test
data: x and y
t = 0.48983, df = 164.36, p-value = 0.6249
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-0.2300476 0.3818428
sample estimates:
mean of x mean of y
-0.1794718 -0.2553694
確率関数
rnorm(10,0,1)
[1] 0.02403588 1.98783235 0.37881658 1.40682657 -0.65489648
[6] 1.11803886 -0.07181551 0.23802082 -0.28636419 -0.02228677
rt(10,5)
[1] 0.8505949 -0.2222015 -0.4127100 0.1428496 -0.9983636 -3.4245911
[7] 0.5373886 2.2903122 -0.7490007 -1.6916428
rchisq(10,10)
[1] 11.170409 7.121944 11.799637 10.003629 3.655078 8.409331
[7] 11.376004 5.327585 17.388334 8.964062
rpois(10,2)
[1] 1 1 3 0 2 1 1 1 5 3
グラフィックス
x <- rnorm(100)
y <- x + rnorm(100)
plot(x)
plot(x,y)
plot(x,y,col = "blue", xlab = "axis-x", ylab = "axix-y",
xlim = c(-2, 2), ylim = c(-2, 2), main = "nice plot !")
abline(a = 0, b = 1, col = "red")
grid()
制御構文
forループ
for(i in 1:5){
j <- i + 10
print(j)
}
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
whileループ
i <- 1
while(i < 5){
print(i)
i <- i + 1
}
[1] 1
[1] 2
[1] 3
[1] 4
if構文
i <- 2
if(i > 3){
print("yes")
}else{
print("no")
}
[1] "no"
いろいろな条件判定
x <- 1
y <- 2
x > y
[1] FALSE
x < y
[1] TRUE
x == y
[1] FALSE
x != y
[1] TRUE
x < y & y == 2
[1] TRUE
x < y | x == 2
[1] TRUE
関数の自作
square <- function(x){
squared <- x^2
return(squared)
}
square(10)
[1] 100
LS0tCnRpdGxlOiAiUuism+e/kuS8miAx5pel55uuIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBZdXN1a2UgTUFUU1VJICgyMDE3LjkuMTYpCi0tLQoKYGBge3J9CiMg44GT44GT44Gr5Yem55CG5omL6aCG44KS6KiY6L+wCjEgKyAyCjEgKiAyCjEgLyAyCnggPC0gcm5vcm0oMTAwKQp5IDwtIHggKyBybm9ybSgxMDApCnBsb3QoeSx4KQoKI+i/veWKoOOBl+OBn+aJi+mghgpmaXQgPC0gbG0oeSB+IHgpCnN1bW1hcnkoZml0KQpgYGAKI+ODkeODg+OCseODvOOCuOOBruOCpOODs+OCueODiOODvOODqwojI0NSQU7jgYvjgonjga7jgqTjg7Pjgrnjg4jjg7zjg6sKYGBge3IsZXZhbCA9IEZ9Cmluc3RhbGwucGFja2FnZXMoImlncmFwaCIpCmxpYnJhcnkoaWdyYXBoKQpgYGAKCiMjYmlvY29uZGN1dG9y44GL44KJ44Gu44Kk44Oz44K544OI44O844OrCmBgYHtyLGV2YWw9Rn0Kc291cmNlKCJodHRwczovL2Jpb2NvbmRjdXRvci5vcmcvYmlvY0xpdGUuUiIpCmJpb2NMaXRlKCJsaW1tYSIpCmxpYnJhcnkobGltbWEpCgojZ2l0aHVi44GL44KJ44Gu44Kk44Oz44K544OI44O844OrCmluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikKbGlicmFyeShkZXZ0b29scykKaW5zdGFsbF9naXRodWIoInltYXR0cy9waHlDIixmb3JjZT1UUlVFKQpsaWJyYXJ5KHBoeUMpCmBgYAoKI+ODh+ODvOOCv+WeiwpgYGB7cn0KIzEuIG51bWVyaWPlnosKMS41CiMgMi5sb2dpY2Fs5Z6LClRSVUUKRkFMU0UKIyAzLmZhY3RvcuWeiwpmYWN0b3IoYygibG93IiwibWlkZGxlIiwiaGlnaCIpLGxldmVscyA9IGMoImxvdyIsIm1pZGRsZSIsImhpZ2giKSkKIyA0LmNoYXJhY3RlcuWeiwoiQXBwbGUiCmBgYAoKI+ODh+ODvOOCv+Wei+OBruWkieaPmwpgYGB7cn0KIyBudW1lcmlj5Z6LIDwtLT4gbG9naWNhbOWeiwphcy5udW1lcmljKFRSVUUpCmFzLmxvZ2ljYWwoMSkKYXMubG9naWNhbCgwKQojIG51bWVyaWPlnosgPC0tPiBjaGFyYWN0ZXLlnosKYXMubnVtZXJpYygxLjUpCmFzLmNoYXJhY3RlcigiMS41IikKYGBgCgoj54m55q6K44Gq5pWw5YCk44OH44O844K/5Z6LCmBgYHtyfQoj56m6Ck5VTEwKI+asoOaQjShOb3QgQXZhaWxhYmxlOyBOQSkKTkEKI+mdnuaVsChOb3QgQSBOdW1iZXI7IE5BTikKbG9nKC0yKQoj54Sh6ZmQ5aSnKEluZmluaXRlOyBJbmYpCjEgLyAwCmxvZygwKQpgYGAKCiPlpInmlbDjga7ku6PlhaUKYGBge3J9CnggPC0gNQp5IDwtIDEwCnoxIDwtIHggKyB5CnoxCnoyIDwtIHggKiB5CnoyCnozIDwtIHNpbih4KSAqIHkgKyAxMAp6Mwp6NCA8LSB4XjIKejQKYGBgCiPjg5njgq/jg4jjg6sKIyPjg5njgq/jg4jjg6vjga7kvZzmiJAKYGBge3J9CmMoMiw0LDYpCjI6NgpzZXEoMiwzLCBieSA9IDAuNSkKcmVwKDE6MiwgdGltZXMgPSAzKQpyZXAoMToyLCBlYWNoID0gMykKYGBgCgojI+ODmeOCr+ODiOODq+OBruaTjeS9nApgYGB7cn0KeCA8LSAxOjEwCm5hbWVzKHgpIDwtIExFVFRFUlNbMToxMF0KeAp4WzRdCnhbLTRdCnhbMjo0XQp4Wy0oMjo0KV0KeFtjKDEsIDUpXQp4W3ggPT0gMTBdCnhbeCA8IDNdCnhbeCAlaW4lIGMoMSwyLDUpXQp4WyJBIl0KYGBgCgojIyDjg5njgq/jg4jjg6vjgavlr77jgZnjgovkvr/liKnjgarjgrPjg57jg7Pjg4kKYGBge3J9CnggPC0gYygxLDQsMywyLDcsNSkKc29ydCh4KQpzb3J0KHgsIGRlY3JlYXNpbmcgPSBUUlVFKQpvcmRlcih4KQpvcmRlcih4LCBkZWNyZWFzaW5nID0gVFJVRSkKeFtvcmRlcih4KV0KeSA8LSBjKCJjYXNlIiwiY2FzZSIsImNvbnRyb2wiLCJjb250cm9sIiwiY29udHJvbCIsImNvbnRyb2wiKQp0YWJsZSh5KQpgYGAKCiMg6KGM5YiX5pON5L2cCiMjIOODmeOCr+ODiOODqyA8LS0+ICDooYzliJcKYGBge3J9CiMjIOODmeOCr+ODiOODqyAtLT4g6KGM5YiXCnZlYyA8LSAxOjkKKG1hdDEgPC0gbWF0cml4KHZlYyxucm93ID0gMykpCihtYXQyIDwtIG1hdHJpeCh2ZWMsbmNvbCA9IDMpKQoobWF0MyA8LSBjYmluZCgxOjMsNDo2KSkKKG1hdDQgPC0gcmJpbmQoMTozLDQ6NikpCiMg6KGM5YiXIC0tPiDjg5njgq/jg4jjg6sKYXMudmVjdG9yKG1hdDEpCmBgYAoKIyPooYzliJfjga7mt7vjgYjlrZfmk43kvZwKYGBge3J9CnZlYyA8LSAxOjkKbWF0IDwtIG1hdHJpeCh2ZWMsbnJvdyA9IDMpCnJvd25hbWVzKG1hdCkgPC0gYygicm93MSIsInJvdzIiLCJyb3czIikKY29sbmFtZXMobWF0KSA8LSBjKCJjb2wxIiwiY29sMiIsImNvbDMiKQptYXRbMSxdCm1hdFssMV0KbWF0WzE6MixdCm1hdFstMSxdCm1hdFsicm93MSIsXQptYXRbLCJjb2wyIl0KdChtYXQpCmBgYAoKCiMj44Oq44K544OICmBgYHtyfQp5IDwtIGxpc3QobnZlYyA9IGMoMSwyLDMpLCBjdmVjID0gYygiYSIsImIiLCJjIiksbWF0ID0gbWF0cml4KDE6OSxucm93PTMpKQp5WzFdCnlbWzFdXQp5WyJtYXQiXQp5JG1hdAoKeSA8LSBsaXN0KCkKeVtbMV1dIDwtIGMoMSwyLDMpCnlbWzJdXSA8LSBjKCJhIiwiYiIsImMiKQp5W1szXV0gPC0gbWF0cml4KDE6OSxucm93ID0gMykKbmFtZXMoeSkgPC0gYygibnZlYyIsImN2ZWMiLCJtYXQiKQoKeSA8LSBsaXN0KCkKeSRudmVjIDwtIGMoMSwyLDMpCnkkY3ZlYyA8LSBjKCJhIiwiYiIsImMiKQp5JG1hdCA8LSBtYXRyaXgoMTo5LG5yb3cgPSAzKQoKeSA8LSBsaXN0KCkKeSA8LSBjKHksIGxpc3QobnZlYyA9IGMoMSwyLDMpKSkKeSA8LSBjKHksIGxpc3QoY3ZlYyA9IGMoImEiLCJiIiwiYyIpKSkKeSA8LSBjKHksIGxpc3QobWF0ID0gbWF0cml4KDE6OSxucm93ID0gMykpKQpgYGAKIyMg44OH44O844K/44OV44Os44O844OgCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKG12ZWMgPSAxOjMsIGN2ZWMgPSBjKCJhIiwiYiIsImMiKSkKZGZbWzFdXQpkZiRtdmVjCmRmWywxXQpkZlsyLF0KZGZbMToyLF0KYGBgCmBgYHtyLGV2YWw9Rn0KI3JlYWRyCmluc3RhbGwucGFja2FnZXMoInJlYWRyIikKYGBgCiNyZWFkcgojI+ODh+ODvOOCv+OBruabuOOBjeWHuuOBlwpgYGB7cixldmFsPUZ9CmxpYnJhcnkocmVhZHIpCm1hdCA8LSBtYXRyaXgoMTo5LCBucm93ID0gMykKY29sbmFtZXMobWF0KSA8LSBjKCJBIiwiQiIsIkMiKQpkZiA8LSBhcy5kYXRhLmZyYW1lKG1hdCkKd3JpdGVfY3N2KHggPSBkZiwgcGF0aCA9ICJkYXRhL3NhbXBsZTAxLmNzdiIsIGNvbF9uYW1lcyA9IFRSVUUpCndyaXRlX3Rzdih4ID0gZGYsIHBhdGggPSAiZGF0YS9zYW1wbGUwMS50c3YiLCBjb2xfbmFtZXMgPSBUUlVFKQpgYGAKYGBge3IsZXZhbD1GfQojIGZyZWFkCmluc3RhbGwucGFja2FnZXMoImRhdGEudGFibGUiKQpgYGAKCiNkYXRhLnRhYmxlCiPjg4fjg7zjgr/jga7oqq3jgb/ovrzjgb8KYGBge3IsZXZhbD1GfQpsaWJyYXJ5KGRhdGEudGFibGUpCmlucHV0X2NzdiA8LSBmcmVhZChpbnB1dCA9ICJkYXRhL3NhbXBsZTAxLmNzdiIsc2VwID0gIiwiLAogICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgZGF0YS50YWJsZSA9IEZBTFNFKQppbnB1dF90c3YgPC0gZnJlYWQoaW5wdXQgPSAiZGF0YS9zYW1wbGUwMS50c3YiLHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFLCBkYXRhLnRhYmxlID0gRkFMU0UpCmhlYWQoaW5wdXRfY3N2KQpoZWFkKGlucHV0X3RzdikKYGBgCiPplqLmlbDjgYTjgo3jgYTjgo0KIyNudW1lcmlj5Z6LCmBgYHtyfQp4IDwtIDE6MTAKeSA8LSAxMDoxCmxvZyh4KQpleHAoeCkKbWF4KHgpCm1pbih4KQpzdW0oeCkKbWVhbih4KQptZWRpYW4oeCkKcmFuayh4KQp2YXIoeCkKc2QoeCkKcXVhbnRpbGUoeCkKY29yKHgseSkKcm91bmQoMy4xNCwxKQpgYGAKCiMjY2hhcmFjdGVy5Z6LCmBgYHtyfQpjaGFyMSA8LSAiSSBhbSBNYXRzdWkuIgpjaGFyMiA8LSAiTXkgaG9iYnkgaXMgYSBjeWNsaW5nLiIKdG91cHBlcihjaGFyMSkKdG9sb3dlcihjaGFyMSkKY2hhcjEyIDwtIHBhc3RlKGNoYXIxLGNoYXIyKQpnc3ViKCJNYXRzdWkiLCJTaGltYW11cmEiLGNoYXIxKQp0eHQgPC0gYygiVGhlIiwgImxpY2Vuc2VzIiwgImZvciIsICJtb3N0IiwgInNvZnR3YXJlIiwgImFyZSIsCiAgICAgICAgICAgICAgICAiZGVzaWduZWQiLCAidG8iLCAidGFrZSIsICJhd2F5IiwgInlvdXIiLCAiZnJlZWRvbSIsCiAgICAgICAgICAgICAgICAidG8iLCAic2hhcmUiLCAiYW5kIiwgImNoYW5nZSIsICJpdC4iKQpncmVwKCJ5b3UiLHR4dCkKbWF0Y2goInlvdXIiLHR4dCkKdHh0MiA8LSBjKCJnZW5lMV9ob2dlIiwiZ2VuZTJfZnVnYSIsImdlbmUzX2hvZ2UiKQpzdHJzcGxpdCh0eHQyLHNwbGl0ID0gIl8iKQpgYGAKIyPntbHoqIjplqLmlbAKYGBge3J9CnggPC0gcm5vcm0oMTAwKQp5IDwtIHggKyBybm9ybSgxMDApCmRmIDwtIGRhdGEuZnJhbWUoeCA9IHgsIHkgPSB5KQpsbWZpdCA8LSBsbSh5IH4geCwgZGF0YSA9IGRmKQpzdW1tYXJ5KGxtZml0KQp0LnRlc3QoeCx5KQpgYGAKCiMj56K6546H6Zai5pWwCmBgYHtyfQoKcm5vcm0oMTAsMCwxKQpydCgxMCw1KQpyY2hpc3EoMTAsMTApCnJwb2lzKDEwLDIpCmBgYAojI+OCsOODqeODleOCo+ODg+OCr+OCuQpgYGB7cn0KeCA8LSBybm9ybSgxMDApCnkgPC0geCArIHJub3JtKDEwMCkKcGxvdCh4KQpwbG90KHgseSkKcGxvdCh4LHksY29sID0gImJsdWUiLCB4bGFiID0gImF4aXMteCIsIHlsYWIgPSAiYXhpeC15IiwgCiAgICAgeGxpbSA9IGMoLTIsIDIpLCB5bGltID0gYygtMiwgMiksIG1haW4gPSAibmljZSBwbG90ICEiKQphYmxpbmUoYSA9IDAsIGIgPSAxLCBjb2wgPSAicmVkIikKZ3JpZCgpCmBgYAoj5Yi25b6h5qeL5paHCiMjZm9y44Or44O844OXCmBgYHtyfQpmb3IoaSBpbiAxOjUpewogIGogPC0gaSArIDEwCiAgcHJpbnQoaikKfQpgYGAKCiMjd2hpbGXjg6vjg7zjg5cKYGBge3J9CmkgPC0gMQp3aGlsZShpIDwgNSl7CiAgcHJpbnQoaSkKICBpIDwtIGkgKyAxCn0KYGBgCiMjaWbmp4vmlocKYGBge3J9CmkgPC0gMgppZihpID4gMyl7CiAgcHJpbnQoInllcyIpCn1lbHNlewogIHByaW50KCJubyIpCn0KYGBgCiMj44GE44KN44GE44KN44Gq5p2h5Lu25Yik5a6aCmBgYHtyfQp4IDwtIDEKeSA8LSAyCnggPiB5CnggPCB5CnggPT0geQp4ICE9IHkKeCA8IHkgJiB5ID09IDIKeCA8IHkgfCB4ID09IDIKYGBgCiPplqLmlbDjga7oh6rkvZwKYGBge3J9CnNxdWFyZSA8LSBmdW5jdGlvbih4KXsKICBzcXVhcmVkIDwtIHheMgogIHJldHVybihzcXVhcmVkKQp9CnNxdWFyZSgxMCkKYGBgCg==