This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

plot(cars)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

** Chapter1 Help **

#帮助
help("foo") #or ?foo #查看函数foo的帮助
help.search("foo") #or ??foo #以foo为关键字搜索本地帮助文档
example("foo") #函数foo的使用实例

#文件目录操作
getwd() #查看当前目录
setwd() #更改工作目录
ls()
rm(object) # rm(list = ls())
save.image("myfile") #保存工作空间到文件myfile中(默认值为.RData)
save(objectlist, file = "myfile") #保存指定对象到一个文件中
load("myfile") # 读取一个工作空间到当前会话中

#输入与输出
source('filename') #可以在当前会话中执行一个脚本
sink("myoutput", append = T, split = T) #append = T, 将文本追加到文件后;split = T,将输出同时发送到屏幕和输出文件中

#图形输出
bmp("filename.bmp")
jpeg("filename.jpeg")
pdf("filename.pdf")
png("filename.png")
postscript("filename.postscript")
svg('filename.svg')
#示例
sink("myoutput", append = T, split = T) # 先打开文件
pdf("mygraphs.pdf")
source("script2.R")
dev.off()

#批处理 - 终端
R CMD BATCH options infile outfile # infile - *.R; outfile - *.Rout

# 结果重用 #
#用汽车数据mtcars执行一次简单的线性回归,通过车身重量(wt)预测每加仑行驶的英里数(mpg)
lm(mpg~wt, data = mtcars)
lmfit <- lm(mpg~wt, data = mtcars) # 将结果保存在一个对象中,其中包含了分析的大量信息,可以使用该对象进行绘图和预测等。s

summary(lmfit)
plot(lmfit)
cook <- cooks.distance(lmfit)
plot(cook)
predict(lmfit, mynewdata)

** Chapter 2 创建数据集 **

### 2.1 数据集的概念
#数据集通常是由数据构成的一个矩形数组,行表示观测,列表示变量。 (记录与字段)(示例与属性)

# 2.2.1 # 向量
#向量时用于存储 数值型、字符型或逻辑性的一维数组。单个向量中的数据必须拥有相同的类型或模式。
a[2]
a[2:6]
a[c(2,5,7)]#使用方括号对向量访问

# 2.2.2 # 矩阵
mymatrix <- matrix(
  vector, nrow, nol, byrow, dimnames = list(row_names, col_names)
)

y <- matrix(1:10, nrow = 2)
cells <- c(1, 25, 24, 49)
rnames <- c('R1', 'R2')
cnames <- c('C1', 'C2')
mymatrix <- matrix(cells, byrow = T, nrow = 2, dimnames = list(rnames, cnames))

X[i,] #第i行
X[,j] #第j列
X[i, c(4,5)] #第i行的4,5列

# 2.2.3 # 数组  #与矩阵类似,但是维度可以大于2,数组可通过array函数创建

myarray <- array(vector, dimensions, dimnames) #dimensions, 数值型向量,给出了各个维度下标的最大值。#dimnames,个维度名称标签的列表

dim1 <- c('A1', 'A2')
dim2 <- c('B1', 'B2', 'B3')
dim3 <- c('C1', 'C2', 'C3', 'C4')

z <- array(1:24, c(2,3,4), dimnames = list(dim1, dim2, dim3))

# 2.2.4 # 数据框
mydata <- data.frame(col1, col2, col3)

mydata[1:2]
mydata[c('col1name', 'col2name')]
mydata$colname

#列联表
table(data$col1, data$col2)

#2.2.4.1 attach detach with

attach() #将数据框添加到R的搜索路径中。R在遇到一个变量名后,将检查搜索路径中的数据框。
detach() #将数据框从搜索路径中移除

#exaple#
attach(mtcars)
summary(mpg)
plot(mpg, disp)
plot(mpg, wt)
detach(mtcars)

with() #花括号{}之间的语句都针对数据框mtcars执行。

with(
  mtcars, {

    plot(mpg, disp)
    plot(mpg, wt)
    keepstats <<- summary(mtcars) #如果需要创建with()结构之外存在的对象,使用特殊赋值符 <<- 代替标准赋值符 <-
                                  #它可将对象保存到with()之外的全局环境中
  }
)

#2.2.4.2 实例标识符

patientdata <- data.frame(
  patientID, age, diabates, status, row.names = patientID #将patientID指定为R中标记各类打印输出和图形中实例名称所用的变量。
) 

patientID <- c('123-1','234r', 'fefsa', 'sfad')
age <- c(34, 54, 53,23)
diabates <- c('1', '2', '3', '1')
status <- c('1', '0', '0', '1')
# 
#     > patientdata
#     patientID age diabates status
#     123-1     123-1  34        1      1
#     234r       234r  54        2      0
#     fefsa     fefsa  53        3      0
#     sfad       sfad  23        1      1

# 2.2.5 # 因子
#类别(名义型)变量和有序类别(有序型)变量在R中称为因子(factor).
diabetes <- c('Type1', 'Type2', 'Type1', 'Type1')
status <- c('Poor', 'Improved', 'Excellent', 'Poor', ordered = T) #对于字符型向量,因子的水平默认依字母顺序创建。
status <- c('Poor', 'Improved', 'Excellent', 'Poor', ordered = T, 
            levels = c('Poor', 'Improved', 'Excellent')) #可以通过指定levels选项覆盖默认排序
sex <- factor(sex, levels = c(1,2), labels = c('Male', 'Female')) #把变量转换成一个无序因子。

str(object) # 提供某个对象的信息

# 2.2.6 # 列表
mylist <- list(object1, object2) #某个列表中可能是若干向量、矩阵、数据框,甚至其他列表的组合。
mylist <- list(name1 = object1, name2 = object2, ....) #还可以为列表中的对象命名。

#example
g <- "My first list"
h <- c(25, 26, 18, 39)
j <- matrix(1:10, nrow = 5)
k <- c('one', 'two', 'three')
mylist <- list(title = g, ages = h, j, k)

#列表的调用方式

mylist[[3]]
mylist[['title']] #在双重括号中指明代表某个成分的数字或名称来访问列表中的元素

# 2.3.1 #使用键盘输入数据
#edit()
mydata <- data.frame(
  age = numeric(0),
  gender = character(0),
  weight = numeric(0)
)

mydata <- edit(mydata) # 等价于 fix(mydata)

#直接嵌入数据:
mydatatxt <- "
age gender weight
25 m 166
30 f 115
18 f 120
"
mydata <- read.table(header = T, text = mydatatxt)

# 2.3.2 #
mydataframe <- read.table(file, header = , sep = , row.names = , col.names = ,
                          na.strings = , #可选的用于表示缺失值的字符向量,比如,na.strings = c('-9', '?')
                          #把-9和?值在读取数据的时候转换为NA
                          colClasses = , #分配到每一列的类向量,比如,colClasses = c("numeric", 'numeric', 'character', "NULL', 'numeric')
                          #把前两列读取为数值型变量,把第三列读取为字符型向量,跳过第四列。如果数据有多于5列,该值循环
                          skip = , #读取数据前跳过的行数,用于跳过注释
                          stringsAsFactors = #逻辑变量,标记出字符向量是否需要转化成因子,默认为TRUE,大型数据读取时,设置为F可以提升速度
)
# 链接导入数据 #
file()
gzfile()
bzfile()
xzfile()
unz()
url()
#详见help(file)

** Chapter3 图形初阶 **

# 3.1 dev #
dev.new()
dev.next()
dev.prev()
dev.set()
dev.off()



datatxt <- '
dosage Aresponse Bresponse
20 16 15
30 20 18
40 27 25
45 40 31
60 60 40
'
data <- read.table(text = datatxt, header = T)

dose <- c(20, 30, 40, 45, 60)
drugA <- c(16, 20, 27, 40, 60)
drugB <- c(15, 18, 25, 31, 40)
plot(dose, drugA, type = 'b')

plot(dose, drugA, type = 'b', lty = 3, lwd = 3, pch = 15, cex = 2)

# 3.2 颜色 #
#在R中,可以通过颜色下标、颜色名称、十六进制的颜色值、RGB值或HSV值来指定颜色。
col = 1
col = 'white'
col = '#FFFFFF'
col = rgb(1, 1, 1) # 基于红-绿-蓝
col = hsv(0, 0, 1) # 基于色相-饱和度-亮度值

colors() #返回所有可用颜色的名称

rainbow()
heat.colors()
terrain.colors()
topo.colors()
cm.colors()
#以上可以创建连续型颜色向量的函数

#颜色函数包
library(RColorBrewer)
n <- 7
mycolors <- brewer.pal(n, 'Set1') #从Set1调色板中抽取了7种用十六进制表示的颜色并返回一个向量
barplot(rep(1, 7), col = mycolors)

# 3.3 文本属性 #
#cex
#cex.axis
#cex.lab
#cex.main
#cex.sub
#font
#font.axis
#font.lab
#font.main
#font.sub
#ps, 字体磅值,文本最终大小为ps*cex
#family, 绘制文本时使用的字体族

#在执行语句:
par(font.lab = 3, cex.lab = 1.5, font.main = 4, cex.main = 2)
#之后创建的所有图形都将拥有斜体、1.5倍默认文本大小的坐标轴标签....

#修改pdf的字体
pdf(file = 'myplot.pdf', family = 'fontname')
#names(pdfFonts()), 找出系统中有哪些字体可用

# 3.4 图形尺寸与边界尺寸 #
par(pin = c(4,3), mai = c(1, 0.5, 1, 0.2))
#pin,以英寸表示的图形尺寸
#mai,以数值向量表示的边界大小,顺序为 下、左、上、右,单位为英寸
#mar,以数值向量表示的边界大小,顺序为 下、左、上、右,单位为英分

opar <- par(no.readonly = T) #保存当前的图形参数设置
par(pin = c(2,3)) #开始修改默认参数
par(lwd = 2, cex = 1.5)
par(cex.axis = 0.75, font.axis = 3)
plot(dose, drugA, type = 'b', pch = 19, lty = 2, col = 'red') #通过par()设定的参数对两幅图都有效,而在plot()
plot(dose, drugB, type = 'b', pch = 23, lty = 6, col = 'blue', bg = 'green') #中指定的参数仅对那个特定图形有效
par(opar)

# 3.5 自定义 文本、坐标轴和图例 #
plot(dose, drugA, type = 'b',
     col = 'red', lty = 2, pch = 2, lwd = 2,
     main = 'Clinical Trials for Drug A',
     sub = 'This is hypothetical data', 
     xlab = "Dosage", ylab = 'Drug Response',
     xlim = c(0, 60), ylim = c(0, 70), ann = F)
title(main = 'My title', col.main = 'red', 
      sub = 'My Subtitle', col.sub = 'blue',
      xlab = 'My X label', ylab = "My Y label",
      col.lab = 'green', cex.lab = 0.75) #在上面的plot()生成的图形中继续添加
#title()一般来说用于添加信息到一个默认标题和坐标轴标签被ann=FALSE选项移除的图形中。
axis()
#axis()来自定义坐标轴 plot(axes = FALSE)

x <- c(1:10)
y <- x
z <- 10/x
opar <- par(no.readonly = T)
par(mar = c(5,4,4,8) + 0.1)
plot(x,y, type = 'b',
     pch = 21, col = 'red',
     yaxt = 'n', lty = 3, ann = F)
lines(x,z, type = 'b', pch = 22, col = 'blue', lty = 2) #为现有图形添加新的图形元素
axis(2, at = x, labels = x, col.axis = 'red', las = 2)
axis(4, at = z, labels = round(z, digits = 2),
     col.axis = 'blue', las = 2, cex.axis = 0.7, tck = -0.01)
mtext('y = 1/x', side = 4, line = 3, cex.lab =1, las = 2, col = 'blue') #在图形的边界添加文本
title('An Example of Creative Axes', xlab = 'X values', ylab= 'Y = X' )
par(opar)

# 3.6 参考线 #
abline(h = yvalues, v = xvalues)
abline(v = seq(1, 10, 2), lty = 2, col = 'blue')

# 3.7 图例 #
legend(location, title, legend)
#location, 有多种方式可以指定图例的位置:可以直接给定图例左上角的x、y坐标;也可以执行locator(1),然后通过鼠标
#点击给出图例的位置,还可以使用关键字 bottom, bottomleft, left, topleft, top, topright, right, bottomright, center
#放置图例。如果使用了以上某个关键字,那么可以同时使用参数inset=指定图例向图形内侧移动的大小。

# 3.8 文本标注 #
text() #绘图区域内部
mtext() #绘图区域4个边界
text(location, 'text', pos, ....)
mtext('text', side, line = n,...)
#pos, 文本相对于位置参数的方位
#side,指定用来放置文本的边,1 = 下, 2 = 左, 3 = 上, 4 = 右。可以指定参数line = 来内移过外移文本。也可以使用adj = 0将文本向左下对齐,adj = 1右上对齐

#text()也通常用来表示图形中的点,只需指定一系列的x、y坐标作为位置参数,同时以向量的形式指定要放置的文本。x、y和文本标签向量的长度应当相同
attach(mtcars)
plot(wt,mpg, 
     main = 'Mileage vs. Car Weight',
     xlab = 'Weight', ylab = 'Mileage',
     pch = 18, col = 'blue')
text(wt, mpg, 
     row.names(mtcars),
     cex = 0.6, pos = 4, col = 'red')

detach(mtcars)

# 3.9 数学标注 #
help(plotmath)
demo(plotmath)
expression()
x <- seq(0, 4, 0.01)
y <- sqrt(x)
tt <- expression(y == sqrt(x))
plot(x, y, type = 'b', main = tt, las = 1)

# 3.10 图形的组合 #
# 3.10.1 可以在par()函数中使用图形参数mfrow = c(nrows, ncols) 创建按行填充的、行数为nrows、列数为ncols的图形矩阵。
#mfcol = c(nrows, ncols)
attach(mtcars)
opar <- par(no.readonly = T)
par(mfrow = c(2,2))
plot(wt, mpg, main = 'Scatterplot of wt vs. mpg')
plot(wt, disp, main = 'Scatterplot of wt vs. disp')
hist(wt, main = 'Histogram of wt')
boxplot(wt, main = 'Boxplot of wt')
par(opar)
detach(mtcars)

# 3.10.2 layout()
#函数layout()的调用形式为layout(mat),其中的mat是一个矩阵,制定了所要缩合的多个图形的所在位置。
#为了更精确地控制每幅图的大小,可以有选择地在layout()函数中使用widths=, heights= 两个参数,其形式为:
#widths = 各列宽度值组成的一个向量
#heights = 各行高度值组成的一个向量
#help(layout)


# 3.10.3 fig = 精细控制
opar <- par(no.readonly = T)
par(fig = c(0, 0.8, 0, 0.8)) # 参数fig= 的取值,是一个形如c(x1, x2, y1, y2)的数值向量。
plot(mtcars$wt, mtcars$mpg,
     xlab = 'Miles Per Gallon',
     ylab = 'Car Weight')
par(fig = c(0, 0.8, 0.55, 1), new = T)
boxplot(mtcars$wt, horizontal = T, axes = F)
par(fig = c(0.65, 1, 0, 0.8), new = T)
boxplot(mtcars$mpg, axes = F)
mtext("Enhanced Scatterplot", side = 3, outer = T, line = -3)
par(opar)

###################      附        #########################

####### 附1 R不提供多行注释或块注释功能 #######
if(FALSE){
  
  
} #FALSE 改为TRUE 即执行该区域的代码


####### 附2 实用函数 ##########
length()
dim()
str()
class()
mode()
names()
cbind() #按列合并
rbind() #按行合并
ls()
rm() 
rm(list = ls())
newobejct <- edit(object) #编辑对象并另存为newobject
fix(object) #直接编辑对象


####### 附3 绘制图片常用术语 ######
#pch, 指定绘制点时使用的符号
#cex,指定符号的大小。cex是一个数值,表示绘图符号相对默认大小的缩放倍数。默认大小为1,1.5为放大1.5倍。
#lty,指定线条类型
#lwd,指定线条宽度
LS0tCnRpdGxlOiAiUiBpbiBhY3Rpb24gLSBDaGFwdGVyMX4zIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiAKClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDbWQrU2hpZnQrRW50ZXIqLiAKCmBgYHtyfQpwbG90KGNhcnMpCmBgYAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLiAKClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4KCioqIENoYXB0ZXIxIEhlbHAgKioKYGBge3J9CiPluK7liqkKaGVscCgiZm9vIikgI29yID9mb28gI+afpeeci+WHveaVsGZvb+eahOW4ruWKqQpoZWxwLnNlYXJjaCgiZm9vIikgI29yID8/Zm9vICPku6Vmb2/kuLrlhbPplK7lrZfmkJzntKLmnKzlnLDluK7liqnmlofmoaMKZXhhbXBsZSgiZm9vIikgI+WHveaVsGZvb+eahOS9v+eUqOWunuS+iwoKI+aWh+S7tuebruW9leaTjeS9nApnZXR3ZCgpICPmn6XnnIvlvZPliY3nm67lvZUKc2V0d2QoKSAj5pu05pS55bel5L2c55uu5b2VCmxzKCkKcm0ob2JqZWN0KSAjIHJtKGxpc3QgPSBscygpKQpzYXZlLmltYWdlKCJteWZpbGUiKSAj5L+d5a2Y5bel5L2c56m66Ze05Yiw5paH5Lu2bXlmaWxl5Lit77yI6buY6K6k5YC85Li6LlJEYXRh77yJCnNhdmUob2JqZWN0bGlzdCwgZmlsZSA9ICJteWZpbGUiKSAj5L+d5a2Y5oyH5a6a5a+56LGh5Yiw5LiA5Liq5paH5Lu25LitCmxvYWQoIm15ZmlsZSIpICMg6K+75Y+W5LiA5Liq5bel5L2c56m66Ze05Yiw5b2T5YmN5Lya6K+d5LitCgoj6L6T5YWl5LiO6L6T5Ye6CnNvdXJjZSgnZmlsZW5hbWUnKSAj5Y+v5Lul5Zyo5b2T5YmN5Lya6K+d5Lit5omn6KGM5LiA5Liq6ISa5pysCnNpbmsoIm15b3V0cHV0IiwgYXBwZW5kID0gVCwgc3BsaXQgPSBUKSAjYXBwZW5kID0gVCwg5bCG5paH5pys6L+95Yqg5Yiw5paH5Lu25ZCO77ybc3BsaXQgPSBU77yM5bCG6L6T5Ye65ZCM5pe25Y+R6YCB5Yiw5bGP5bmV5ZKM6L6T5Ye65paH5Lu25LitCgoj5Zu+5b2i6L6T5Ye6CmJtcCgiZmlsZW5hbWUuYm1wIikKanBlZygiZmlsZW5hbWUuanBlZyIpCnBkZigiZmlsZW5hbWUucGRmIikKcG5nKCJmaWxlbmFtZS5wbmciKQpwb3N0c2NyaXB0KCJmaWxlbmFtZS5wb3N0c2NyaXB0IikKc3ZnKCdmaWxlbmFtZS5zdmcnKQoj56S65L6LCnNpbmsoIm15b3V0cHV0IiwgYXBwZW5kID0gVCwgc3BsaXQgPSBUKSAjIOWFiOaJk+W8gOaWh+S7tgpwZGYoIm15Z3JhcGhzLnBkZiIpCnNvdXJjZSgic2NyaXB0Mi5SIikKZGV2Lm9mZigpCgoj5om55aSE55CGIC0g57uI56uvClIgQ01EIEJBVENIIG9wdGlvbnMgaW5maWxlIG91dGZpbGUgIyBpbmZpbGUgLSAqLlI7IG91dGZpbGUgLSAqLlJvdXQKCiMg57uT5p6c6YeN55SoICMKI+eUqOaxvei9puaVsOaNrm10Y2Fyc+aJp+ihjOS4gOasoeeugOWNleeahOe6v+aAp+WbnuW9ku+8jOmAmui/h+i9pui6q+mHjemHj++8iHd077yJ6aKE5rWL5q+P5Yqg5LuR6KGM6am255qE6Iux6YeM5pWw77yIbXBn77yJCmxtKG1wZ353dCwgZGF0YSA9IG10Y2FycykKbG1maXQgPC0gbG0obXBnfnd0LCBkYXRhID0gbXRjYXJzKSAjIOWwhue7k+aenOS/neWtmOWcqOS4gOS4quWvueixoeS4re+8jOWFtuS4reWMheWQq+S6huWIhuaekOeahOWkp+mHj+S/oeaBr++8jOWPr+S7peS9v+eUqOivpeWvueixoei/m+ihjOe7mOWbvuWSjOmihOa1i+etieOAgnMKCnN1bW1hcnkobG1maXQpCnBsb3QobG1maXQpCmNvb2sgPC0gY29va3MuZGlzdGFuY2UobG1maXQpCnBsb3QoY29vaykKcHJlZGljdChsbWZpdCwgbXluZXdkYXRhKQpgYGAKCioqIENoYXB0ZXIgMiDliJvlu7rmlbDmja7pm4YgKioKYGBge3J9CiMjIyAyLjEg5pWw5o2u6ZuG55qE5qaC5b+1CiPmlbDmja7pm4bpgJrluLjmmK/nlLHmlbDmja7mnoTmiJDnmoTkuIDkuKrnn6nlvaLmlbDnu4TvvIzooYzooajnpLrop4LmtYvvvIzliJfooajnpLrlj5jph4/jgIIg77yI6K6w5b2V5LiO5a2X5q6177yJ77yI56S65L6L5LiO5bGe5oCn77yJCgojIDIuMi4xICMg5ZCR6YePCiPlkJHph4/ml7bnlKjkuo7lrZjlgqgg5pWw5YC85Z6L44CB5a2X56ym5Z6L5oiW6YC76L6R5oCn55qE5LiA57u05pWw57uE44CC5Y2V5Liq5ZCR6YeP5Lit55qE5pWw5o2u5b+F6aG75oul5pyJ55u45ZCM55qE57G75Z6L5oiW5qih5byP44CCCmFbMl0KYVsyOjZdCmFbYygyLDUsNyldI+S9v+eUqOaWueaLrOWPt+WvueWQkemHj+iuv+mXrgoKIyAyLjIuMiAjIOefqemYtQpteW1hdHJpeCA8LSBtYXRyaXgoCiAgdmVjdG9yLCBucm93LCBub2wsIGJ5cm93LCBkaW1uYW1lcyA9IGxpc3Qocm93X25hbWVzLCBjb2xfbmFtZXMpCikKCnkgPC0gbWF0cml4KDE6MTAsIG5yb3cgPSAyKQpjZWxscyA8LSBjKDEsIDI1LCAyNCwgNDkpCnJuYW1lcyA8LSBjKCdSMScsICdSMicpCmNuYW1lcyA8LSBjKCdDMScsICdDMicpCm15bWF0cml4IDwtIG1hdHJpeChjZWxscywgYnlyb3cgPSBULCBucm93ID0gMiwgZGltbmFtZXMgPSBsaXN0KHJuYW1lcywgY25hbWVzKSkKClhbaSxdICPnrKxp6KGMClhbLGpdICPnrKxq5YiXClhbaSwgYyg0LDUpXSAj56ysaeihjOeahDTvvIw15YiXCgojIDIuMi4zICMg5pWw57uEICAj5LiO55+p6Zi157G75Ly877yM5L2G5piv57u05bqm5Y+v5Lul5aSn5LqOMu+8jOaVsOe7hOWPr+mAmui/h2FycmF55Ye95pWw5Yib5bu6CgpteWFycmF5IDwtIGFycmF5KHZlY3RvciwgZGltZW5zaW9ucywgZGltbmFtZXMpICNkaW1lbnNpb25zLCDmlbDlgLzlnovlkJHph4/vvIznu5nlh7rkuoblkITkuKrnu7TluqbkuIvmoIfnmoTmnIDlpKflgLzjgIIjZGltbmFtZXMs5Liq57u05bqm5ZCN56ew5qCH562+55qE5YiX6KGoCgpkaW0xIDwtIGMoJ0ExJywgJ0EyJykKZGltMiA8LSBjKCdCMScsICdCMicsICdCMycpCmRpbTMgPC0gYygnQzEnLCAnQzInLCAnQzMnLCAnQzQnKQoKeiA8LSBhcnJheSgxOjI0LCBjKDIsMyw0KSwgZGltbmFtZXMgPSBsaXN0KGRpbTEsIGRpbTIsIGRpbTMpKQoKIyAyLjIuNCAjIOaVsOaNruahhgpteWRhdGEgPC0gZGF0YS5mcmFtZShjb2wxLCBjb2wyLCBjb2wzKQoKbXlkYXRhWzE6Ml0KbXlkYXRhW2MoJ2NvbDFuYW1lJywgJ2NvbDJuYW1lJyldCm15ZGF0YSRjb2xuYW1lCgoj5YiX6IGU6KGoCnRhYmxlKGRhdGEkY29sMSwgZGF0YSRjb2wyKQoKIzIuMi40LjEgYXR0YWNoIGRldGFjaCB3aXRoCgphdHRhY2goKSAj5bCG5pWw5o2u5qGG5re75Yqg5YiwUueahOaQnOe0oui3r+W+hOS4reOAglLlnKjpgYfliLDkuIDkuKrlj5jph4/lkI3lkI7vvIzlsIbmo4Dmn6XmkJzntKLot6/lvoTkuK3nmoTmlbDmja7moYbjgIIKZGV0YWNoKCkgI+WwhuaVsOaNruahhuS7juaQnOe0oui3r+W+hOS4reenu+mZpAoKI2V4YXBsZSMKYXR0YWNoKG10Y2FycykKc3VtbWFyeShtcGcpCnBsb3QobXBnLCBkaXNwKQpwbG90KG1wZywgd3QpCmRldGFjaChtdGNhcnMpCgp3aXRoKCkgI+iKseaLrOWPt3t95LmL6Ze055qE6K+t5Y+l6YO96ZKI5a+55pWw5o2u5qGGbXRjYXJz5omn6KGM44CCCgp3aXRoKAogIG10Y2FycywgewoKICAgIHBsb3QobXBnLCBkaXNwKQogICAgcGxvdChtcGcsIHd0KQogICAga2VlcHN0YXRzIDw8LSBzdW1tYXJ5KG10Y2FycykgI+WmguaenOmcgOimgeWIm+W7undpdGgoKee7k+aehOS5i+WkluWtmOWcqOeahOWvueixoe+8jOS9v+eUqOeJueauiui1i+WAvOespiA8PC0g5Luj5pu/5qCH5YeG6LWL5YC856ymIDwtCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAj5a6D5Y+v5bCG5a+56LGh5L+d5a2Y5Yiwd2l0aCgp5LmL5aSW55qE5YWo5bGA546v5aKD5LitCiAgfQopCgojMi4yLjQuMiDlrp7kvovmoIfor4bnrKYKCnBhdGllbnRkYXRhIDwtIGRhdGEuZnJhbWUoCiAgcGF0aWVudElELCBhZ2UsIGRpYWJhdGVzLCBzdGF0dXMsIHJvdy5uYW1lcyA9IHBhdGllbnRJRCAj5bCGcGF0aWVudElE5oyH5a6a5Li6UuS4reagh+iusOWQhOexu+aJk+WNsOi+k+WHuuWSjOWbvuW9ouS4reWunuS+i+WQjeensOaJgOeUqOeahOWPmOmHj+OAggopIAoKcGF0aWVudElEIDwtIGMoJzEyMy0xJywnMjM0cicsICdmZWZzYScsICdzZmFkJykKYWdlIDwtIGMoMzQsIDU0LCA1MywyMykKZGlhYmF0ZXMgPC0gYygnMScsICcyJywgJzMnLCAnMScpCnN0YXR1cyA8LSBjKCcxJywgJzAnLCAnMCcsICcxJykKIyAKIyAgICAgPiBwYXRpZW50ZGF0YQojICAgICBwYXRpZW50SUQgYWdlIGRpYWJhdGVzIHN0YXR1cwojICAgICAxMjMtMSAgICAgMTIzLTEgIDM0ICAgICAgICAxICAgICAgMQojICAgICAyMzRyICAgICAgIDIzNHIgIDU0ICAgICAgICAyICAgICAgMAojICAgICBmZWZzYSAgICAgZmVmc2EgIDUzICAgICAgICAzICAgICAgMAojICAgICBzZmFkICAgICAgIHNmYWQgIDIzICAgICAgICAxICAgICAgMQoKIyAyLjIuNSAjIOWboOWtkAoj57G75Yir77yI5ZCN5LmJ5Z6L77yJ5Y+Y6YeP5ZKM5pyJ5bqP57G75Yir77yI5pyJ5bqP5Z6L77yJ5Y+Y6YeP5ZyoUuS4reensOS4uuWboOWtkO+8iGZhY3Rvcu+8iS4KZGlhYmV0ZXMgPC0gYygnVHlwZTEnLCAnVHlwZTInLCAnVHlwZTEnLCAnVHlwZTEnKQpzdGF0dXMgPC0gYygnUG9vcicsICdJbXByb3ZlZCcsICdFeGNlbGxlbnQnLCAnUG9vcicsIG9yZGVyZWQgPSBUKSAj5a+55LqO5a2X56ym5Z6L5ZCR6YeP77yM5Zug5a2Q55qE5rC05bmz6buY6K6k5L6d5a2X5q+N6aG65bqP5Yib5bu644CCCnN0YXR1cyA8LSBjKCdQb29yJywgJ0ltcHJvdmVkJywgJ0V4Y2VsbGVudCcsICdQb29yJywgb3JkZXJlZCA9IFQsIAogICAgICAgICAgICBsZXZlbHMgPSBjKCdQb29yJywgJ0ltcHJvdmVkJywgJ0V4Y2VsbGVudCcpKSAj5Y+v5Lul6YCa6L+H5oyH5a6abGV2ZWxz6YCJ6aG56KaG55uW6buY6K6k5o6S5bqPCnNleCA8LSBmYWN0b3Ioc2V4LCBsZXZlbHMgPSBjKDEsMiksIGxhYmVscyA9IGMoJ01hbGUnLCAnRmVtYWxlJykpICPmiorlj5jph4/ovazmjaLmiJDkuIDkuKrml6Dluo/lm6DlrZDjgIIKCnN0cihvYmplY3QpICMg5o+Q5L6b5p+Q5Liq5a+56LGh55qE5L+h5oGvCgojIDIuMi42ICMg5YiX6KGoCm15bGlzdCA8LSBsaXN0KG9iamVjdDEsIG9iamVjdDIpICPmn5DkuKrliJfooajkuK3lj6/og73mmK/oi6XlubLlkJHph4/jgIHnn6npmLXjgIHmlbDmja7moYbvvIznlJroh7Plhbbku5bliJfooajnmoTnu4TlkIjjgIIKbXlsaXN0IDwtIGxpc3QobmFtZTEgPSBvYmplY3QxLCBuYW1lMiA9IG9iamVjdDIsIC4uLi4pICPov5jlj6/ku6XkuLrliJfooajkuK3nmoTlr7nosaHlkb3lkI3jgIIKCiNleGFtcGxlCmcgPC0gIk15IGZpcnN0IGxpc3QiCmggPC0gYygyNSwgMjYsIDE4LCAzOSkKaiA8LSBtYXRyaXgoMToxMCwgbnJvdyA9IDUpCmsgPC0gYygnb25lJywgJ3R3bycsICd0aHJlZScpCm15bGlzdCA8LSBsaXN0KHRpdGxlID0gZywgYWdlcyA9IGgsIGosIGspCgoj5YiX6KGo55qE6LCD55So5pa55byPCgpteWxpc3RbWzNdXQpteWxpc3RbWyd0aXRsZSddXSAj5Zyo5Y+M6YeN5ous5Y+35Lit5oyH5piO5Luj6KGo5p+Q5Liq5oiQ5YiG55qE5pWw5a2X5oiW5ZCN56ew5p2l6K6/6Zeu5YiX6KGo5Lit55qE5YWD57SgCgojIDIuMy4xICPkvb/nlKjplK7nm5jovpPlhaXmlbDmja4KI2VkaXQoKQpteWRhdGEgPC0gZGF0YS5mcmFtZSgKICBhZ2UgPSBudW1lcmljKDApLAogIGdlbmRlciA9IGNoYXJhY3RlcigwKSwKICB3ZWlnaHQgPSBudW1lcmljKDApCikKCm15ZGF0YSA8LSBlZGl0KG15ZGF0YSkgIyDnrYnku7fkuo4gZml4KG15ZGF0YSkKCiPnm7TmjqXltYzlhaXmlbDmja7vvJoKbXlkYXRhdHh0IDwtICIKYWdlIGdlbmRlciB3ZWlnaHQKMjUgbSAxNjYKMzAgZiAxMTUKMTggZiAxMjAKIgpteWRhdGEgPC0gcmVhZC50YWJsZShoZWFkZXIgPSBULCB0ZXh0ID0gbXlkYXRhdHh0KQoKIyAyLjMuMiAjCm15ZGF0YWZyYW1lIDwtIHJlYWQudGFibGUoZmlsZSwgaGVhZGVyID0gLCBzZXAgPSAsIHJvdy5uYW1lcyA9ICwgY29sLm5hbWVzID0gLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnN0cmluZ3MgPSAsICPlj6/pgInnmoTnlKjkuo7ooajnpLrnvLrlpLHlgLznmoTlrZfnrKblkJHph4/vvIzmr5TlpoLvvIxuYS5zdHJpbmdzID0gYygnLTknLCAnPycpCiAgICAgICAgICAgICAgICAgICAgICAgICAgI+aKii055ZKM77yf5YC85Zyo6K+75Y+W5pWw5o2u55qE5pe25YCZ6L2s5o2i5Li6TkEKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xDbGFzc2VzID0gLCAj5YiG6YWN5Yiw5q+P5LiA5YiX55qE57G75ZCR6YeP77yM5q+U5aaC77yMY29sQ2xhc3NlcyA9IGMoIm51bWVyaWMiLCAnbnVtZXJpYycsICdjaGFyYWN0ZXInLCAiTlVMTCcsICdudW1lcmljJykKICAgICAgICAgICAgICAgICAgICAgICAgICAj5oqK5YmN5Lik5YiX6K+75Y+W5Li65pWw5YC85Z6L5Y+Y6YeP77yM5oqK56ys5LiJ5YiX6K+75Y+W5Li65a2X56ym5Z6L5ZCR6YeP77yM6Lez6L+H56ys5Zub5YiX44CC5aaC5p6c5pWw5o2u5pyJ5aSa5LqONeWIl++8jOivpeWAvOW+queOrwogICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAsICPor7vlj5bmlbDmja7liY3ot7Pov4fnmoTooYzmlbDvvIznlKjkuo7ot7Pov4fms6jph4oKICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gI+mAu+i+keWPmOmHj++8jOagh+iusOWHuuWtl+espuWQkemHj+aYr+WQpumcgOimgei9rOWMluaIkOWboOWtkO+8jOm7mOiupOS4ulRSVUXvvIzlpKflnovmlbDmja7or7vlj5bml7bvvIzorr7nva7kuLpG5Y+v5Lul5o+Q5Y2H6YCf5bqmCikKIyDpk77mjqXlr7zlhaXmlbDmja4gIwpmaWxlKCkKZ3pmaWxlKCkKYnpmaWxlKCkKeHpmaWxlKCkKdW56KCkKdXJsKCkKI+ivpuingWhlbHAoZmlsZSkKCmBgYAoKKiogQ2hhcHRlcjMg5Zu+5b2i5Yid6Zi2ICoqCmBgYHtyfQojIDMuMSBkZXYgIwpkZXYubmV3KCkKZGV2Lm5leHQoKQpkZXYucHJldigpCmRldi5zZXQoKQpkZXYub2ZmKCkKCgoKZGF0YXR4dCA8LSAnCmRvc2FnZSBBcmVzcG9uc2UgQnJlc3BvbnNlCjIwIDE2IDE1CjMwIDIwIDE4CjQwIDI3IDI1CjQ1IDQwIDMxCjYwIDYwIDQwCicKZGF0YSA8LSByZWFkLnRhYmxlKHRleHQgPSBkYXRhdHh0LCBoZWFkZXIgPSBUKQoKZG9zZSA8LSBjKDIwLCAzMCwgNDAsIDQ1LCA2MCkKZHJ1Z0EgPC0gYygxNiwgMjAsIDI3LCA0MCwgNjApCmRydWdCIDwtIGMoMTUsIDE4LCAyNSwgMzEsIDQwKQpwbG90KGRvc2UsIGRydWdBLCB0eXBlID0gJ2InKQoKcGxvdChkb3NlLCBkcnVnQSwgdHlwZSA9ICdiJywgbHR5ID0gMywgbHdkID0gMywgcGNoID0gMTUsIGNleCA9IDIpCgojIDMuMiDpopzoibIgIwoj5ZyoUuS4re+8jOWPr+S7pemAmui/h+minOiJsuS4i+agh+OAgeminOiJsuWQjeensOOAgeWNgeWFrei/m+WItueahOminOiJsuWAvOOAgVJHQuWAvOaIlkhTVuWAvOadpeaMh+WumuminOiJsuOAggpjb2wgPSAxCmNvbCA9ICd3aGl0ZScKY29sID0gJyNGRkZGRkYnCmNvbCA9IHJnYigxLCAxLCAxKSAjIOWfuuS6jue6oi3nu78t6JOdCmNvbCA9IGhzdigwLCAwLCAxKSAjIOWfuuS6juiJsuebuC3ppbHlkozluqYt5Lqu5bqm5YC8Cgpjb2xvcnMoKSAj6L+U5Zue5omA5pyJ5Y+v55So6aKc6Imy55qE5ZCN56ewCgpyYWluYm93KCkKaGVhdC5jb2xvcnMoKQp0ZXJyYWluLmNvbG9ycygpCnRvcG8uY29sb3JzKCkKY20uY29sb3JzKCkKI+S7peS4iuWPr+S7peWIm+W7uui/nue7reWei+minOiJsuWQkemHj+eahOWHveaVsAoKI+minOiJsuWHveaVsOWMhQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbiA8LSA3Cm15Y29sb3JzIDwtIGJyZXdlci5wYWwobiwgJ1NldDEnKSAj5LuOU2V0Meiwg+iJsuadv+S4reaKveWPluS6hjfnp43nlKjljYHlha3ov5vliLbooajnpLrnmoTpopzoibLlubbov5Tlm57kuIDkuKrlkJHph48KYmFycGxvdChyZXAoMSwgNyksIGNvbCA9IG15Y29sb3JzKQoKIyAzLjMg5paH5pys5bGe5oCnICMKI2NleAojY2V4LmF4aXMKI2NleC5sYWIKI2NleC5tYWluCiNjZXguc3ViCiNmb250CiNmb250LmF4aXMKI2ZvbnQubGFiCiNmb250Lm1haW4KI2ZvbnQuc3ViCiNwc++8jCDlrZfkvZPno4XlgLzvvIzmlofmnKzmnIDnu4jlpKflsI/kuLpwcypjZXgKI2ZhbWlseSwg57uY5Yi25paH5pys5pe25L2/55So55qE5a2X5L2T5pePCgoj5Zyo5omn6KGM6K+t5Y+l77yaCnBhcihmb250LmxhYiA9IDMsIGNleC5sYWIgPSAxLjUsIGZvbnQubWFpbiA9IDQsIGNleC5tYWluID0gMikKI+S5i+WQjuWIm+W7uueahOaJgOacieWbvuW9oumDveWwhuaLpeacieaWnOS9k+OAgTEuNeWAjem7mOiupOaWh+acrOWkp+Wwj+eahOWdkOagh+i9tOagh+etvi4uLi4KCiPkv67mlLlwZGbnmoTlrZfkvZMKcGRmKGZpbGUgPSAnbXlwbG90LnBkZicsIGZhbWlseSA9ICdmb250bmFtZScpCiNuYW1lcyhwZGZGb250cygpKSwg5om+5Ye657O757uf5Lit5pyJ5ZOq5Lqb5a2X5L2T5Y+v55SoCgojIDMuNCDlm77lvaLlsLrlr7jkuI7ovrnnlYzlsLrlr7ggIwpwYXIocGluID0gYyg0LDMpLCBtYWkgPSBjKDEsIDAuNSwgMSwgMC4yKSkKI3Bpbu+8jOS7peiLseWvuOihqOekuueahOWbvuW9ouWwuuWvuAojbWFp77yM5Lul5pWw5YC85ZCR6YeP6KGo56S655qE6L6555WM5aSn5bCP77yM6aG65bqP5Li6IOS4i+OAgeW3puOAgeS4iuOAgeWPs++8jOWNleS9jeS4uuiLseWvuAojbWFy77yM5Lul5pWw5YC85ZCR6YeP6KGo56S655qE6L6555WM5aSn5bCP77yM6aG65bqP5Li6IOS4i+OAgeW3puOAgeS4iuOAgeWPs++8jOWNleS9jeS4uuiLseWIhgoKb3BhciA8LSBwYXIobm8ucmVhZG9ubHkgPSBUKSAj5L+d5a2Y5b2T5YmN55qE5Zu+5b2i5Y+C5pWw6K6+572uCnBhcihwaW4gPSBjKDIsMykpICPlvIDlp4vkv67mlLnpu5jorqTlj4LmlbAKcGFyKGx3ZCA9IDIsIGNleCA9IDEuNSkKcGFyKGNleC5heGlzID0gMC43NSwgZm9udC5heGlzID0gMykKcGxvdChkb3NlLCBkcnVnQSwgdHlwZSA9ICdiJywgcGNoID0gMTksIGx0eSA9IDIsIGNvbCA9ICdyZWQnKSAj6YCa6L+HcGFyKCnorr7lrprnmoTlj4LmlbDlr7nkuKTluYXlm77pg73mnInmlYjvvIzogIzlnKhwbG90KCkKcGxvdChkb3NlLCBkcnVnQiwgdHlwZSA9ICdiJywgcGNoID0gMjMsIGx0eSA9IDYsIGNvbCA9ICdibHVlJywgYmcgPSAnZ3JlZW4nKSAj5Lit5oyH5a6a55qE5Y+C5pWw5LuF5a+56YKj5Liq54m55a6a5Zu+5b2i5pyJ5pWICnBhcihvcGFyKQoKIyAzLjUg6Ieq5a6a5LmJIOaWh+acrOOAgeWdkOagh+i9tOWSjOWbvuS+iyAjCnBsb3QoZG9zZSwgZHJ1Z0EsIHR5cGUgPSAnYicsCiAgICAgY29sID0gJ3JlZCcsIGx0eSA9IDIsIHBjaCA9IDIsIGx3ZCA9IDIsCiAgICAgbWFpbiA9ICdDbGluaWNhbCBUcmlhbHMgZm9yIERydWcgQScsCiAgICAgc3ViID0gJ1RoaXMgaXMgaHlwb3RoZXRpY2FsIGRhdGEnLCAKICAgICB4bGFiID0gIkRvc2FnZSIsIHlsYWIgPSAnRHJ1ZyBSZXNwb25zZScsCiAgICAgeGxpbSA9IGMoMCwgNjApLCB5bGltID0gYygwLCA3MCksIGFubiA9IEYpCnRpdGxlKG1haW4gPSAnTXkgdGl0bGUnLCBjb2wubWFpbiA9ICdyZWQnLCAKICAgICAgc3ViID0gJ015IFN1YnRpdGxlJywgY29sLnN1YiA9ICdibHVlJywKICAgICAgeGxhYiA9ICdNeSBYIGxhYmVsJywgeWxhYiA9ICJNeSBZIGxhYmVsIiwKICAgICAgY29sLmxhYiA9ICdncmVlbicsIGNleC5sYWIgPSAwLjc1KSAj5Zyo5LiK6Z2i55qEcGxvdCgp55Sf5oiQ55qE5Zu+5b2i5Lit57un57ut5re75YqgCiN0aXRsZSgp5LiA6Iis5p2l6K+055So5LqO5re75Yqg5L+h5oGv5Yiw5LiA5Liq6buY6K6k5qCH6aKY5ZKM5Z2Q5qCH6L205qCH562+6KKrYW5uPUZBTFNF6YCJ6aG556e76Zmk55qE5Zu+5b2i5Lit44CCCmF4aXMoKQojYXhpcygp5p2l6Ieq5a6a5LmJ5Z2Q5qCH6L20IHBsb3QoYXhlcyA9IEZBTFNFKQoKeCA8LSBjKDE6MTApCnkgPC0geAp6IDwtIDEwL3gKb3BhciA8LSBwYXIobm8ucmVhZG9ubHkgPSBUKQpwYXIobWFyID0gYyg1LDQsNCw4KSArIDAuMSkKcGxvdCh4LHksIHR5cGUgPSAnYicsCiAgICAgcGNoID0gMjEsIGNvbCA9ICdyZWQnLAogICAgIHlheHQgPSAnbicsIGx0eSA9IDMsIGFubiA9IEYpCmxpbmVzKHgseiwgdHlwZSA9ICdiJywgcGNoID0gMjIsIGNvbCA9ICdibHVlJywgbHR5ID0gMikgI+S4uueOsOacieWbvuW9oua3u+WKoOaWsOeahOWbvuW9ouWFg+e0oApheGlzKDIsIGF0ID0geCwgbGFiZWxzID0geCwgY29sLmF4aXMgPSAncmVkJywgbGFzID0gMikKYXhpcyg0LCBhdCA9IHosIGxhYmVscyA9IHJvdW5kKHosIGRpZ2l0cyA9IDIpLAogICAgIGNvbC5heGlzID0gJ2JsdWUnLCBsYXMgPSAyLCBjZXguYXhpcyA9IDAuNywgdGNrID0gLTAuMDEpCm10ZXh0KCd5ID0gMS94Jywgc2lkZSA9IDQsIGxpbmUgPSAzLCBjZXgubGFiID0xLCBsYXMgPSAyLCBjb2wgPSAnYmx1ZScpICPlnKjlm77lvaLnmoTovrnnlYzmt7vliqDmlofmnKwKdGl0bGUoJ0FuIEV4YW1wbGUgb2YgQ3JlYXRpdmUgQXhlcycsIHhsYWIgPSAnWCB2YWx1ZXMnLCB5bGFiPSAnWSA9IFgnICkKcGFyKG9wYXIpCgojIDMuNiDlj4LogIPnur8gIwphYmxpbmUoaCA9IHl2YWx1ZXMsIHYgPSB4dmFsdWVzKQphYmxpbmUodiA9IHNlcSgxLCAxMCwgMiksIGx0eSA9IDIsIGNvbCA9ICdibHVlJykKCiMgMy43IOWbvuS+iyAjCmxlZ2VuZChsb2NhdGlvbiwgdGl0bGUsIGxlZ2VuZCkKI2xvY2F0aW9uLCDmnInlpJrnp43mlrnlvI/lj6/ku6XmjIflrprlm77kvovnmoTkvY3nva7vvJrlj6/ku6Xnm7TmjqXnu5nlrprlm77kvovlt6bkuIrop5LnmoR444CBeeWdkOagh++8m+S5n+WPr+S7peaJp+ihjGxvY2F0b3IoMSks54S25ZCO6YCa6L+H6byg5qCHCiPngrnlh7vnu5nlh7rlm77kvovnmoTkvY3nva7vvIzov5jlj6/ku6Xkvb/nlKjlhbPplK7lrZcgYm90dG9tLCBib3R0b21sZWZ0LCBsZWZ0LCB0b3BsZWZ0LCB0b3AsIHRvcHJpZ2h0LCByaWdodCwgYm90dG9tcmlnaHQsIGNlbnRlcgoj5pS+572u5Zu+5L6L44CC5aaC5p6c5L2/55So5LqG5Lul5LiK5p+Q5Liq5YWz6ZSu5a2X77yM6YKj5LmI5Y+v5Lul5ZCM5pe25L2/55So5Y+C5pWwaW5zZXQ95oyH5a6a5Zu+5L6L5ZCR5Zu+5b2i5YaF5L6n56e75Yqo55qE5aSn5bCP44CCCgojIDMuOCDmlofmnKzmoIfms6ggIwp0ZXh0KCkgI+e7mOWbvuWMuuWfn+WGhemDqAptdGV4dCgpICPnu5jlm77ljLrln5805Liq6L6555WMCnRleHQobG9jYXRpb24sICd0ZXh0JywgcG9zLCAuLi4uKQptdGV4dCgndGV4dCcsIHNpZGUsIGxpbmUgPSBuLC4uLikKI3Bvcywg5paH5pys55u45a+55LqO5L2N572u5Y+C5pWw55qE5pa55L2NCiNzaWRl77yM5oyH5a6a55So5p2l5pS+572u5paH5pys55qE6L6577yMMSA9IOS4i++8jCAyID0g5bem77yMIDMgPSDkuIrvvIwgNCA9IOWPs+OAguWPr+S7peaMh+WumuWPguaVsGxpbmUgPSDmnaXlhoXnp7vov4flpJbnp7vmlofmnKzjgILkuZ/lj6/ku6Xkvb/nlKhhZGogPSAw5bCG5paH5pys5ZCR5bem5LiL5a+56b2Q77yMYWRqID0gMeWPs+S4iuWvuem9kAoKI3RleHQoKeS5n+mAmuW4uOeUqOadpeihqOekuuWbvuW9ouS4reeahOeCue+8jOWPqumcgOaMh+WumuS4gOezu+WIl+eahHjjgIF55Z2Q5qCH5L2c5Li65L2N572u5Y+C5pWw77yM5ZCM5pe25Lul5ZCR6YeP55qE5b2i5byP5oyH5a6a6KaB5pS+572u55qE5paH5pys44CCeOOAgXnlkozmlofmnKzmoIfnrb7lkJHph4/nmoTplb/luqblupTlvZPnm7jlkIwKYXR0YWNoKG10Y2FycykKcGxvdCh3dCxtcGcsIAogICAgIG1haW4gPSAnTWlsZWFnZSB2cy4gQ2FyIFdlaWdodCcsCiAgICAgeGxhYiA9ICdXZWlnaHQnLCB5bGFiID0gJ01pbGVhZ2UnLAogICAgIHBjaCA9IDE4LCBjb2wgPSAnYmx1ZScpCnRleHQod3QsIG1wZywgCiAgICAgcm93Lm5hbWVzKG10Y2FycyksCiAgICAgY2V4ID0gMC42LCBwb3MgPSA0LCBjb2wgPSAncmVkJykKCmRldGFjaChtdGNhcnMpCgojIDMuOSDmlbDlrabmoIfms6ggIwpoZWxwKHBsb3RtYXRoKQpkZW1vKHBsb3RtYXRoKQpleHByZXNzaW9uKCkKeCA8LSBzZXEoMCwgNCwgMC4wMSkKeSA8LSBzcXJ0KHgpCnR0IDwtIGV4cHJlc3Npb24oeSA9PSBzcXJ0KHgpKQpwbG90KHgsIHksIHR5cGUgPSAnYicsIG1haW4gPSB0dCwgbGFzID0gMSkKCiMgMy4xMCDlm77lvaLnmoTnu4TlkIggIwojIDMuMTAuMSDlj6/ku6XlnKhwYXIoKeWHveaVsOS4reS9v+eUqOWbvuW9ouWPguaVsG1mcm93ID0gYyhucm93cywgbmNvbHMpIOWIm+W7uuaMieihjOWhq+WFheeahOOAgeihjOaVsOS4um5yb3dz44CB5YiX5pWw5Li6bmNvbHPnmoTlm77lvaLnn6npmLXjgIIKI21mY29sID0gYyhucm93cywgbmNvbHMpCmF0dGFjaChtdGNhcnMpCm9wYXIgPC0gcGFyKG5vLnJlYWRvbmx5ID0gVCkKcGFyKG1mcm93ID0gYygyLDIpKQpwbG90KHd0LCBtcGcsIG1haW4gPSAnU2NhdHRlcnBsb3Qgb2Ygd3QgdnMuIG1wZycpCnBsb3Qod3QsIGRpc3AsIG1haW4gPSAnU2NhdHRlcnBsb3Qgb2Ygd3QgdnMuIGRpc3AnKQpoaXN0KHd0LCBtYWluID0gJ0hpc3RvZ3JhbSBvZiB3dCcpCmJveHBsb3Qod3QsIG1haW4gPSAnQm94cGxvdCBvZiB3dCcpCnBhcihvcGFyKQpkZXRhY2gobXRjYXJzKQoKIyAzLjEwLjIgbGF5b3V0KCkKI+WHveaVsGxheW91dCgp55qE6LCD55So5b2i5byP5Li6bGF5b3V0KG1hdCnvvIzlhbbkuK3nmoRtYXTmmK/kuIDkuKrnn6npmLXvvIzliLblrprkuobmiYDopoHnvKnlkIjnmoTlpJrkuKrlm77lvaLnmoTmiYDlnKjkvY3nva7jgIIKI+S4uuS6huabtOeyvuehruWcsOaOp+WItuavj+W5heWbvueahOWkp+Wwj++8jOWPr+S7peaciemAieaLqeWcsOWcqGxheW91dCgp5Ye95pWw5Lit5L2/55Sod2lkdGhzPSwgaGVpZ2h0cz0g5Lik5Liq5Y+C5pWw77yM5YW25b2i5byP5Li677yaCiN3aWR0aHMgPSDlkITliJflrr3luqblgLznu4TmiJDnmoTkuIDkuKrlkJHph48KI2hlaWdodHMgPSDlkITooYzpq5jluqblgLznu4TmiJDnmoTkuIDkuKrlkJHph48KI2hlbHAobGF5b3V0KQoKCiMgMy4xMC4zIGZpZyA9IOeyvue7huaOp+WItgpvcGFyIDwtIHBhcihuby5yZWFkb25seSA9IFQpCnBhcihmaWcgPSBjKDAsIDAuOCwgMCwgMC44KSkgIyDlj4LmlbBmaWc9IOeahOWPluWAvO+8jOaYr+S4gOS4quW9ouWmgmMoeDEsIHgyLCB5MSwgeTIp55qE5pWw5YC85ZCR6YeP44CCCnBsb3QobXRjYXJzJHd0LCBtdGNhcnMkbXBnLAogICAgIHhsYWIgPSAnTWlsZXMgUGVyIEdhbGxvbicsCiAgICAgeWxhYiA9ICdDYXIgV2VpZ2h0JykKcGFyKGZpZyA9IGMoMCwgMC44LCAwLjU1LCAxKSwgbmV3ID0gVCkKYm94cGxvdChtdGNhcnMkd3QsIGhvcml6b250YWwgPSBULCBheGVzID0gRikKcGFyKGZpZyA9IGMoMC42NSwgMSwgMCwgMC44KSwgbmV3ID0gVCkKYm94cGxvdChtdGNhcnMkbXBnLCBheGVzID0gRikKbXRleHQoIkVuaGFuY2VkIFNjYXR0ZXJwbG90Iiwgc2lkZSA9IDMsIG91dGVyID0gVCwgbGluZSA9IC0zKQpwYXIob3BhcikKCiMjIyMjIyMjIyMjIyMjIyMjIyMgICAgICDpmYQgICAgICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMjIyMjIyMg6ZmEMSBS5LiN5o+Q5L6b5aSa6KGM5rOo6YeK5oiW5Z2X5rOo6YeK5Yqf6IO9ICMjIyMjIyMKaWYoRkFMU0UpewogIAogIAp9ICNGQUxTRSDmlLnkuLpUUlVFIOWNs+aJp+ihjOivpeWMuuWfn+eahOS7o+eggQoKCiMjIyMjIyMg6ZmEMiDlrp7nlKjlh73mlbAgIyMjIyMjIyMjIwpsZW5ndGgoKQpkaW0oKQpzdHIoKQpjbGFzcygpCm1vZGUoKQpuYW1lcygpCmNiaW5kKCkgI+aMieWIl+WQiOW5tgpyYmluZCgpICPmjInooYzlkIjlubYKbHMoKQpybSgpIApybShsaXN0ID0gbHMoKSkKbmV3b2JlamN0IDwtIGVkaXQob2JqZWN0KSAj57yW6L6R5a+56LGh5bm25Y+m5a2Y5Li6bmV3b2JqZWN0CmZpeChvYmplY3QpICPnm7TmjqXnvJbovpHlr7nosaEKCgojIyMjIyMjIOmZhDMg57uY5Yi25Zu+54mH5bi455So5pyv6K+tICMjIyMjIwojcGNoLCDmjIflrprnu5jliLbngrnml7bkvb/nlKjnmoTnrKblj7cKI2NleO+8jOaMh+WumuespuWPt+eahOWkp+Wwj+OAgmNleOaYr+S4gOS4quaVsOWAvO+8jOihqOekuue7mOWbvuespuWPt+ebuOWvuem7mOiupOWkp+Wwj+eahOe8qeaUvuWAjeaVsOOAgum7mOiupOWkp+Wwj+S4ujHvvIwxLjXkuLrmlL7lpKcxLjXlgI3jgIIKI2x0ee+8jOaMh+Wumue6v+adoeexu+WeiwojbHdk77yM5oyH5a6a57q/5p2h5a695bqmCmBgYAoKCg==