Tên: Mai Huy
MSSV: 43.01.104.065
Số thứ tự: 08
1) Các hàm cơ bản
# Tạo Vector x
x <- c(1,6,2)
x
[1] 1 6 2
# Tạo Vector y
y <- c(1,4,3)
y
[1] 1 4 3
# Độ dài vector x
length(x)
[1] 3
# Độ dài vector y
length(y)
[1] 3
#Tổng 2 vector
x+y
[1] 2 10 5
#Xem các biến được tạo
ls()
[1] "x" "y"
#Xoá biến x và y
rm(x,y)
#Xoá tất cả biến đã tạo
rm(list = ls())
#Tạo ma trận 2x2
x=matrix(c(1,2,3,4),2,2)
x
[,1] [,2]
[1,] 1 3
[2,] 2 4
# Ma trận theo dòng 2x2
y=matrix(c(1,2,3,4),2,2, byrow = TRUE)
y
[,1] [,2]
[1,] 1 2
[2,] 3 4
#Tính căn bậc 2 của ma trận x
sqrt(x)
[,1] [,2]
[1,] 1.000000 1.732051
[2,] 1.414214 2.000000
#Bình phương ma trận x
x^2
[,1] [,2]
[1,] 1 9
[2,] 4 16
#Tạo 1 vector với 50 giá trị ngẫu nhiên với giá trị trung bình mặc định =50 và độ lệch chuẩn = 0.1
x=rnorm(50)
x
[1] 2.066779896 -1.029749769 -0.123095504 0.173957707
[5] 0.553190600 -0.759068678 0.035829594 -0.003495063
[9] -0.220190416 -1.557680246 -0.238045956 0.424982482
[13] -0.446779715 -1.401854780 -0.547414257 0.247941769
[17] -1.351702539 1.285374670 2.096632994 -1.075716671
[21] 0.643818555 0.811107086 -0.373369162 -0.117755702
[25] 0.939509301 -0.223544486 -1.188865752 0.599961163
[29] -0.863306018 -0.669136112 0.758080913 0.977212323
[33] 1.486960427 0.809182023 1.049591298 -1.378317315
[37] -1.166379732 0.450531663 0.553986739 0.171533785
[41] -0.806881470 0.978852878 1.171035498 -0.254750999
[45] -0.261779474 1.357008537 1.048195428 2.228898486
[49] -1.470518812 -1.031250041
#Tạo 1 vector với 50 giá trị ngẫu nhiên với giá trị trung bình =50 và độ lệch chuẩn = 0.1
y = x+rnorm(50,mean = 50, sd=.1)
y
[1] 52.08326 48.84587 49.88854 50.29371 50.48338 49.27029
[7] 50.07956 50.05928 49.66376 48.44024 49.86643 50.55614
[13] 49.54498 48.69007 49.42826 50.28305 48.51426 51.32796
[19] 52.01520 48.99362 50.71437 50.83894 49.50636 49.94652
[25] 50.87891 49.63873 48.71853 50.65669 49.39624 49.30687
[31] 50.82683 50.96203 51.50971 50.74232 51.05267 48.62453
[37] 48.79707 50.22973 50.58369 50.38450 49.32562 50.96724
[43] 51.02402 49.70732 49.59172 51.46452 50.92558 51.92327
[49] 48.67455 49.04055
# Tính mối tương quan của vector x và y
cor(x,y)
[1] 0.9942434
# set.seed dùng để tái tạo những vector random giống nhau theo tương ứng với giá trị được đưa vào hàm seed
set.seed(1303)
rnorm(5)
[1] -1.14397631 1.34212937 2.18539048 0.53639252 0.06319297
set.seed(1303)
rnorm(5)
[1] -1.14397631 1.34212937 2.18539048 0.53639252 0.06319297
# Tạo bộ seed khác
set.seed(3)
#Tạo 1 vector có 100 giá trị random
y=rnorm(100)
# TÍnh giá trị trung bình của vector y
mean(y)
[1] 0.01103557
# Phương sai vector y
var(y)
[1] 0.7328675
# Căn bậc 2 phương sai của y
sqrt(var(y))
[1] 0.8560768
# Độ lệch chuẩn của y
sd(y)
[1] 0.8560768
2) Đồ hoạ
# Tạo vector x có 100 giá trị random
x= rnorm(100)
# Tạo vector y có 100 giá trị random
y = rnorm(100)
# Hàm plot để tạo một đồ thị phân tán với trục hoành x và trục tung y
plot(x,y)

# Đặt tên cho đồ thị, và cả tên trục hoành và trục tung
plot(x,y,xlab = "this is the x-axix", ylab = "this is the y-axix", main = "Plot of X vs Y")

# Tạo ra file pdf chứa ảnh của đồ thị
pdf("Figure.pdf")
# Tạo đồ thị chứa các điểm màu xanh và lưu trong file "Figure.pdf"
plot(x,y,col="green")
# dev.off để thông báo rằng đã thực hiện xong quá trình tạo đồ thị
dev.off()
null device
1
# Tạo ra 1 mảng số từ 1->10
seq(1,10)
[1] 1 2 3 4 5 6 7 8 9 10
# Tạo ra mảng x chưa các con số 1->10
x=1:10
x
[1] 1 2 3 4 5 6 7 8 9 10
# Tạo ra mảng vector x bắt đầu từ -pi đến pi có 50 giá trị sao giá mỗi bước nhảy là bằng nhau
x= seq(-pi,pi, length =50)
x
[1] -3.14159265 -3.01336438 -2.88513611 -2.75690784 -2.62867957
[6] -2.50045130 -2.37222302 -2.24399475 -2.11576648 -1.98753821
[11] -1.85930994 -1.73108167 -1.60285339 -1.47462512 -1.34639685
[16] -1.21816858 -1.08994031 -0.96171204 -0.83348377 -0.70525549
[21] -0.57702722 -0.44879895 -0.32057068 -0.19234241 -0.06411414
[26] 0.06411414 0.19234241 0.32057068 0.44879895 0.57702722
[31] 0.70525549 0.83348377 0.96171204 1.08994031 1.21816858
[36] 1.34639685 1.47462512 1.60285339 1.73108167 1.85930994
[41] 1.98753821 2.11576648 2.24399475 2.37222302 2.50045130
[46] 2.62867957 2.75690784 2.88513611 3.01336438 3.14159265
# Tạo ra 2 vector đại diện cho 2 feature của data
y=x
# Hàm outer tạo ra 1 ma trận có kích thước length(x)x length(y) với mỗi dòng được tính theo công thức cos(y)/(1+x^2)
f=outer(x,y,function(x,y)cos(y)/(1+x^2))
# Hàm contour dùng để tạo ra đồ thị dữ liệu 3 chiều có đường viền cong
# Ở đây chiều 1 là x, chiều 2 là y và chiều 3 là ma trận kết hợp của x và y đươc tạo ra ở trên, nlevel mặc định =10
contour(x,y,f)

# Xác định mức viền đồ thị bằng nlevel, add nếu =T thì sẽ chèn thêm vào đồ thị đã được tạo
contour(x,y,f)
contour(x,y,f, nlevels = 45, add = T)

# Tính ma trận fa có kích thước 50x50 dựa vào ma trận f đã tính
fa=(f-t(f))/2
# Tạo ma trận đường viền với nlevels=15
contour(x,y,fa,nlevels = 15)

# Hiển thị ảnh màu hay còn gọi là biểu đồ nhiệt của dữ liệu 3 chiều
image(x,y,fa)

# Tạo ra biểu đồ bề mặt của dữ liệu 3 chiều
persp(x,y,fa)

# Theta và phi dùng để điều chỉnh góc nhìn khác nhau của đồ thị
#Theta dùng để điều chỉnh hướng góc phương vị ( xoay trái hoặc phải)
persp(x,y,fa,theta = 30)

# Phi dùng để mở rộng góc thuộc địa(góc trên)
persp(x,y,fa,theta = 30,phi = 20)

# Xoay trái 30 độ và xoay góc trên 70 độ giúp nhìn cận cảnh góc trên
persp(x,y,fa,theta = 30,phi = 70)

# Giảm bớt phi lại còn 40 nhằm mục đích hạ góc trên xuống để nhìn toàn cảnh đồ thị rõ hơn
persp(x,y,fa,theta = 30,phi = 40)

3) Chỉ mục dữ liệu
# Tạo ra ma trận 4x4 với các số từ 1->16
A = matrix(1:16,4,4)
A
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
# Chỉ mục giá trị dòng 2 cột 3
A[2,3]
[1] 10
# Tạo ra ma trận gồm dòng 1 là giá trị dòng 1, cột 2 của ma trận A, và dòng 3, cột 2 của A
# Dòng 2 là dòng 3 cột 2 của A, dòng 3 cột 4 của A
A[c(1,3),c(2,4)]
[,1] [,2]
[1,] 5 13
[2,] 7 15
# Chỉ mục các giá trị từ dòng 1->3, cột 2->4 của A
A[1:3,2:4]
[,1] [,2] [,3]
[1,] 5 9 13
[2,] 6 10 14
[3,] 7 11 15
# Lấy giá trị dòng 1->2, lấy tất cả các cột
A[1:2,]
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
# Lấy tất cả các dòng, cột từ 1->2
A[,1:2]
[,1] [,2]
[1,] 1 5
[2,] 2 6
[3,] 3 7
[4,] 4 8
# Lấy dòng 1, lấy tất cả các cột
A[1,]
[1] 1 5 9 13
# Lấy tất các dòng ngoại trừ dòng 1 và 3, lấy tất cả các cột
A[-c(1,3),]
[,1] [,2] [,3] [,4]
[1,] 2 6 10 14
[2,] 4 8 12 16
# Lấy tất cả các dòng ngoại trừ dòng 1 và 3, tất cả các cột ngoại trừ cột 1,3,4
A[-c(1,3),-c(1,3,4)]
[1] 6 8
# Kích thước ma trận A
dim(A)
[1] 4 4
4) Tải dữ liệu
# read.table dùng để đọc dữ liệu của bảng
Auto =read.table("Auto.data")
# Hiển trị dữ liệu dưới dạng bảng tính trong window
fix(Auto)
#Header = T để nói rõ rằng dòng đầu tiên của data chứa tên biến ( tên của những feature)
# na.string = "?" dùng để khi mà phát hiện kí tự đặc biệt trong data, ví dụ như là dấu chấm
Auto =read.table("Auto.data",header = T,na.strings = "?")
# Hiển trị dữ liệu dưới dạng bảng tính trong window
fix(Auto)
# Đọc data dưới dạng file csv
Auto = read.csv("Auto.csv",header= T, na.strings = "?")
# Hiển trị dữ liệu dưới dạng bảng tính trong window
fix(Auto)
# Kích thước data
dim(Auto)
[1] 397 9
# Lấy dòng 1->4, tất cả các cột
Auto[1:4,]
# na.omit dùng để xoá đi những dòng có dữ liệu bị mất ( missing data)
Auto = na.omit(Auto)
# Kích thước của data đã giảm đi 5 dòng, suy ra có 5 dòng có dữ liệu bị mất
dim(Auto)
[1] 392 9
# Để chỉ mục biến cylynders và mpg cần dùng kí tự $ để chỉ mục biến của dữ liệu
# Hiển thị đồ thị phân tán của 2 biến cylynders và mpg
plot(Auto$cylinders, Auto$mpg)

# attach dùng để khiến cho những biến feature trong dữ liệu có sẵn trong Rstudio theo tên
attach(Auto)
# Hiển thị đồ thị thông qua tên biến mà ko cần dùng kí tự $
plot(cylinders,mpg)

#as.factor() dùng để chuyển giá trị định lượng thành định tính
cylinders= as.factor(cylinders)
# Hiển thị biểu đồ phân tán 2 thuộc tính cylinders và mpg
# Do cột x là dạng định tính (categorical) nên sẽ hiển thị dưới dạng boxplot
plot(cylinders , mpg)

# col="red" dùng để hiển thị các cột màu đỏ
plot(cylinders , mpg , col ="red ")

# varwidth= T khiến cho những cái hộp được hiển thị với độ rộng tỉ lệ với căn bậc 2 số lượng feature trong bảng data
plot(cylinders , mpg , col ="red", varwidth =T)

# Horizontal = T khiến cho các cột được hiển thị hàng ngang
plot(cylinders , mpg , col ="red", varwidth =T,horizontal =T)

# Hiển thị trục x là cylinders và trục y là MPG
plot(cylinders , mpg , col ="red", varwidth =T, xlab="cylinders ",
ylab="MPG")

# Histogram của feature mpg theo tháng 2
hist(mpg)

# Hiển thị các cột theo màu đỏ
hist(mpg,col = 2)

# Thiết lập số lượng tế bào của histogram là 15
hist(mpg,col = 2, breaks = 15)

# Pairs() dùng để tạo ra ma trận đồ thị phân tán của dữ liệu
pairs(Auto)

# Ma trận đồ thị phân một tập con chỉ gồm 5 feature của dữ liệu
pairs(∼ mpg + displacement + horsepower + weight +
acceleration , Auto)

# Đồ thị phân tán 2 biến horsepower và mpg
plot(horsepower ,mpg)
# Hàm indentify dùng để xác định những điểm giá trị trên biểu đồ
# Khi biểu đồ phân tán được hiển thị, click chọn lên các điểm sau đó bấm finish là đồ thị sẽ hiển thị giá trị biến thứ 3(ở đây là biến name)cũng như xuất ra những con số tương ứng dòng thứ mấy của những điểm được click đó
identify (horsepower ,mpg ,name)
[1] 305 322 331
# Hàm summary dùng để phân tích tóm tắt dữ liệu những biến trong dataset
summary(Auto)
mpg cylinders displacement horsepower
Min. : 9.00 Min. :3.000 Min. : 68.0 Min. : 46.0
1st Qu.:17.00 1st Qu.:4.000 1st Qu.:105.0 1st Qu.: 75.0
Median :22.75 Median :4.000 Median :151.0 Median : 93.5
Mean :23.45 Mean :5.472 Mean :194.4 Mean :104.5
3rd Qu.:29.00 3rd Qu.:8.000 3rd Qu.:275.8 3rd Qu.:126.0
Max. :46.60 Max. :8.000 Max. :455.0 Max. :230.0
weight acceleration year origin
Min. :1613 Min. : 8.00 Min. :70.00 Min. :1.000
1st Qu.:2225 1st Qu.:13.78 1st Qu.:73.00 1st Qu.:1.000
Median :2804 Median :15.50 Median :76.00 Median :1.000
Mean :2978 Mean :15.54 Mean :75.98 Mean :1.577
3rd Qu.:3615 3rd Qu.:17.02 3rd Qu.:79.00 3rd Qu.:2.000
Max. :5140 Max. :24.80 Max. :82.00 Max. :3.000
name
amc matador : 5
ford pinto : 5
toyota corolla : 5
amc gremlin : 4
amc hornet : 4
chevrolet chevette: 4
(Other) :365
# Cũng có thể tóm tắt dữ liệu của 1 biến cụ thể
summary(mpg)
Min. 1st Qu. Median Mean 3rd Qu. Max.
9.00 17.00 22.75 23.45 29.00 46.60
LS0tDQp0aXRsZTogIk5nw7RuIG5n4buvIFIgY8ahIGLhuqNuIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMjIFTDqm46IE1haSBIdXkNCiMjIyBNU1NWOiA0My4wMS4xMDQuMDY1DQojIyMgU+G7kSB0aOG7qSB04buxOiAwOA0KDQojIDEpIEPDoWMgaMOgbSBjxqEgYuG6o24NCg0KYGBge3J9DQojIFThuqFvIFZlY3RvciB4DQp4IDwtIGMoMSw2LDIpDQp4DQojIFThuqFvIFZlY3RvciB5DQp5IDwtIGMoMSw0LDMpDQp5DQojIMSQ4buZIGTDoGkgdmVjdG9yIHgNCmxlbmd0aCh4KQ0KIyDEkOG7mSBkw6BpIHZlY3RvciB5DQpsZW5ndGgoeSkNCiNU4buVbmcgMiB2ZWN0b3INCngreQ0KDQpgYGANCmBgYHtyfQ0KI1hlbSBjw6FjIGJp4bq/biDEkcaw4bujYyB04bqhbw0KbHMoKQ0KI1hvw6EgYmnhur9uIHggdsOgIHkNCnJtKHgseSkNCiNYb8OhIHThuqV0IGPhuqMgYmnhur9uIMSRw6MgdOG6oW8NCnJtKGxpc3QgPSBscygpKQ0KYGBgDQpgYGB7cn0NCiNU4bqhbyBtYSB0cuG6rW4gMngyDQp4PW1hdHJpeChjKDEsMiwzLDQpLDIsMikNCngNCiMgTWEgdHLhuq1uIHRoZW8gZMOybmcgMngyDQp5PW1hdHJpeChjKDEsMiwzLDQpLDIsMiwgYnlyb3cgPSBUUlVFKQ0KeQ0KYGBgDQpgYGB7cn0NCiNUw61uaCBjxINuIGLhuq1jIDIgY+G7p2EgbWEgdHLhuq1uIHgNCnNxcnQoeCkNCiNCw6xuaCBwaMawxqFuZyBtYSB0cuG6rW4geA0KeF4yDQojVOG6oW8gMSB2ZWN0b3IgduG7m2kgNTAgZ2nDoSB0cuG7iyBuZ+G6q3Ugbmhpw6puIHbhu5tpIGdpw6EgdHLhu4sgdHJ1bmcgYsOsbmggbeG6t2MgxJHhu4tuaCA9NTAgdsOgIMSR4buZIGzhu4djaCBjaHXhuqluID0gMC4xDQp4PXJub3JtKDUwKQ0KeA0KI1ThuqFvIDEgdmVjdG9yIHbhu5tpIDUwIGdpw6EgdHLhu4sgbmfhuqt1IG5oacOqbiB24bubaSBnacOhIHRy4buLIHRydW5nIGLDrG5oID01MCB2w6AgxJHhu5kgbOG7h2NoIGNodeG6qW4gPSAwLjENCnkgPSB4K3Jub3JtKDUwLG1lYW4gPSA1MCwgc2Q9LjEpDQp5DQojIFTDrW5oIG3hu5FpIHTGsMahbmcgcXVhbiBj4bunYSAgdmVjdG9yIHggdsOgIHkNCmNvcih4LHkpDQpgYGANCmBgYHtyfQ0KIyBzZXQuc2VlZCBkw7luZyDEkeG7gyB0w6FpIHThuqFvIG5o4buvbmcgdmVjdG9yIHJhbmRvbSBnaeG7kW5nIG5oYXUgdGhlbyB0xrDGoW5nIOG7qW5nIHbhu5tpIGdpw6EgdHLhu4sgxJHGsOG7o2MgxJHGsGEgdsOgbyBow6BtIHNlZWQNCnNldC5zZWVkKDEzMDMpDQpybm9ybSg1KQ0Kc2V0LnNlZWQoMTMwMykNCnJub3JtKDUpDQpgYGANCg0KYGBge3J9DQojIFThuqFvIGLhu5kgc2VlZCBraMOhYw0Kc2V0LnNlZWQoMykNCiNU4bqhbyAxIHZlY3RvciBjw7MgMTAwIGdpw6EgdHLhu4sgcmFuZG9tDQp5PXJub3JtKDEwMCkNCiMgVMONbmggZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBj4bunYSB2ZWN0b3IgeQ0KbWVhbih5KQ0KIyBQaMawxqFuZyBzYWkgdmVjdG9yIHkNCnZhcih5KQ0KIyBDxINuIGLhuq1jIDIgcGjGsMahbmcgc2FpIGPhu6dhIHkNCnNxcnQodmFyKHkpKQ0KIyDEkOG7mSBs4buHY2ggY2h14bqpbiBj4bunYSB5DQpzZCh5KQ0KYGBgDQoNCiMgMikgxJDhu5MgaG/huqENCg0KYGBge3J9DQojIFThuqFvIHZlY3RvciB4IGPDsyAxMDAgZ2nDoSB0cuG7iyByYW5kb20NCng9IHJub3JtKDEwMCkNCiMgVOG6oW8gdmVjdG9yIHkgY8OzIDEwMCBnacOhIHRy4buLIHJhbmRvbQ0KeSA9IHJub3JtKDEwMCkNCiMgSMOgbSBwbG90IMSR4buDIHThuqFvIG3hu5l0IMSR4buTIHRo4buLIHBow6JuIHTDoW4gduG7m2kgdHLhu6VjIGhvw6BuaCB4IHbDoCB0cuG7pWMgdHVuZyB5DQpwbG90KHgseSkNCiMgxJDhurd0IHTDqm4gY2hvIMSR4buTIHRo4buLLCB2w6AgY+G6oyB0w6puIHRy4bulYyBob8OgbmggdsOgIHRy4bulYyB0dW5nDQpwbG90KHgseSx4bGFiID0gInRoaXMgaXMgdGhlIHgtYXhpeCIsIHlsYWIgPSAidGhpcyBpcyB0aGUgeS1heGl4IiwgbWFpbiA9ICJQbG90IG9mIFggdnMgWSIpDQpgYGANCg0KYGBge3J9DQojIFThuqFvIHJhIGZpbGUgcGRmIGNo4bupYSDhuqNuaCBj4bunYSDEkeG7kyB0aOG7iw0KcGRmKCJGaWd1cmUucGRmIikNCiMgVOG6oW8gxJHhu5MgdGjhu4sgY2jhu6lhIGPDoWMgxJFp4buDbSBtw6B1IHhhbmggdsOgIGzGsHUgdHJvbmcgZmlsZSAiRmlndXJlLnBkZiINCnBsb3QoeCx5LGNvbD0iZ3JlZW4iKQ0KIyBkZXYub2ZmIMSR4buDIHRow7RuZyBiw6FvIHLhurFuZyDEkcOjIHRo4buxYyBoaeG7h24geG9uZyBxdcOhIHRyw6xuaCB04bqhbyDEkeG7kyB0aOG7iw0KZGV2Lm9mZigpDQoNCmBgYA0KDQpgYGB7cn0NCiMgVOG6oW8gcmEgMSBt4bqjbmcgc+G7kSB04burIDEtPjEwDQpzZXEoMSwxMCkNCiMgVOG6oW8gcmEgbeG6o25nIHggY2jGsGEgY8OhYyBjb24gc+G7kSAxLT4xMA0KeD0xOjEwDQp4DQojIFThuqFvIHJhIG3huqNuZyB2ZWN0b3IgeCBi4bqvdCDEkeG6p3UgdOG7qyAtcGkgxJHhur9uIHBpIGPDsyA1MCBnacOhIHRy4buLIHNhbyBnacOhIG3hu5dpIGLGsOG7m2MgbmjhuqN5IGzDoCBi4bqxbmcgbmhhdQ0KeD0gc2VxKC1waSxwaSwgbGVuZ3RoID01MCkNCngNCmBgYA0KDQpgYGB7cn0NCiMgVOG6oW8gcmEgMiB2ZWN0b3IgxJHhuqFpIGRp4buHbiBjaG8gMiBmZWF0dXJlIGPhu6dhIGRhdGENCnk9eA0KIyBIw6BtIG91dGVyIHThuqFvIHJhIDEgbWEgdHLhuq1uIGPDsyBrw61jaCB0aMaw4bubYyBsZW5ndGgoeCl4IGxlbmd0aCh5KSB24bubaSBt4buXaSBkw7JuZyDEkcaw4bujYyB0w61uaCB0aGVvIGPDtG5nIHRo4bupYyBjb3MoeSkvKDEreF4yKQ0KZj1vdXRlcih4LHksZnVuY3Rpb24oeCx5KWNvcyh5KS8oMSt4XjIpKQ0KIyBIw6BtIGNvbnRvdXIgZMO5bmcgxJHhu4MgdOG6oW8gcmEgxJHhu5MgdGjhu4sgZOG7ryBsaeG7h3UgMyBjaGnhu4F1IGPDsyDEkcaw4budbmcgdmnhu4FuIGNvbmcNCiMg4bueIMSRw6J5IGNoaeG7gXUgMSBsw6AgeCwgY2hp4buBdSAyIGzDoCB5IHbDoCBjaGnhu4F1IDMgbMOgIG1hIHRy4bqtbiBr4bq/dCBo4bujcCBj4bunYSB4IHbDoCB5IMSRxrDGoWMgdOG6oW8gcmEg4bufIHRyw6puLCBubGV2ZWwgbeG6t2MgxJHhu4tuaCA9MTANCmNvbnRvdXIoeCx5LGYpDQoNCmBgYA0KDQpgYGB7cn0NCiMgWMOhYyDEkeG7i25oIG3hu6ljIHZp4buBbiDEkeG7kyB0aOG7iyBi4bqxbmcgbmxldmVsLCBhZGQgbuG6v3UgPVQgdGjDrCBz4bq9IGNow6huIHRow6ptIHbDoG8gxJHhu5MgdGjhu4sgxJHDoyDEkcaw4bujYyB04bqhbw0KY29udG91cih4LHksZikNCmNvbnRvdXIoeCx5LGYsIG5sZXZlbHMgPSA0NSwgYWRkID0gVCkNCmBgYA0KDQpgYGB7cn0NCiMgVMOtbmggbWEgdHLhuq1uIGZhIGPDsyBrw61jaCB0aMaw4bubYyA1MHg1MCBk4buxYSB2w6BvIG1hIHRy4bqtbiBmIMSRw6MgdMOtbmgNCmZhPShmLXQoZikpLzINCiMgVOG6oW8gbWEgdHLhuq1uIMSRxrDhu51uZyB2aeG7gW4gduG7m2kgbmxldmVscz0xNQ0KY29udG91cih4LHksZmEsbmxldmVscyA9IDE1KQ0KYGBgDQoNCmBgYHtyfQ0KIyBIaeG7g24gdGjhu4sg4bqjbmggbcOgdSBoYXkgY8OybiBn4buNaSBsw6AgYmnhu4N1IMSR4buTIG5oaeG7h3QgY+G7p2EgZOG7ryBsaeG7h3UgMyBjaGnhu4F1DQppbWFnZSh4LHksZmEpDQojIFThuqFvIHJhIGJp4buDdSDEkeG7kyBi4buBIG3hurd0IGPhu6dhIGThu68gbGnhu4d1IDMgY2hp4buBdQ0KcGVyc3AoeCx5LGZhKQ0KIyBUaGV0YSB2w6AgcGhpIGTDuW5nIMSR4buDIMSRaeG7gXUgY2jhu4luaCBnw7NjIG5ow6xuIGtow6FjIG5oYXUgY+G7p2EgxJHhu5MgdGjhu4sNCiNUaGV0YSBkw7luZyDEkeG7gyDEkWnhu4F1IGNo4buJbmggaMaw4bubbmcgZ8OzYyBwaMawxqFuZyB24buLICggeG9heSB0csOhaSBob+G6t2MgcGjhuqNpKQ0KcGVyc3AoeCx5LGZhLHRoZXRhID0gMzApDQojIFBoaSBkw7luZyDEkeG7gyBt4bufIHLhu5luZyBnw7NjIHRodeG7mWMgxJHhu4thKGfDs2MgdHLDqm4pDQpwZXJzcCh4LHksZmEsdGhldGEgPSAzMCxwaGkgPSAyMCkNCiMgWG9heSB0csOhaSAzMCDEkeG7mSB2w6AgeG9heSBnw7NjIHRyw6puIDcwIMSR4buZIGdpw7pwIG5ow6xuIGPhuq1uIGPhuqNuaCBnw7NjIHRyw6puDQpwZXJzcCh4LHksZmEsdGhldGEgPSAzMCxwaGkgPSA3MCkNCiMgR2nhuqNtIGLhu5t0IHBoaSBs4bqhaSBjw7JuIDQwIG5o4bqxbSBt4bulYyDEkcOtY2ggaOG6oSBnw7NjIHRyw6puIHh14buRbmcgxJHhu4MgbmjDrG4gdG/DoG4gY+G6o25oIMSR4buTIHRo4buLIHLDtSBoxqFuDQpwZXJzcCh4LHksZmEsdGhldGEgPSAzMCxwaGkgPSA0MCkNCmBgYA0KDQojIDMpIENo4buJIG3hu6VjIGThu68gbGnhu4d1DQpgYGB7cn0NCiMgVOG6oW8gcmEgbWEgdHLhuq1uIDR4NCB24bubaSBjw6FjIHPhu5EgdOG7qyAxLT4xNg0KQSA9IG1hdHJpeCgxOjE2LDQsNCkNCkENCiMgQ2jhu4kgbeG7pWMgZ2nDoSB0cuG7iyBkw7JuZyAyIGPhu5l0IDMNCkFbMiwzXQ0KYGBgDQoNCmBgYHtyfQ0KIyBU4bqhbyByYSBtYSB0cuG6rW4gZ+G7k20gZMOybmcgMSBsw6AgZ2nDoSB0cuG7iyBkw7JuZyAxLCBj4buZdCAyIGPhu6dhIG1hIHRy4bqtbiBBLCB2w6AgZMOybmcgMywgY+G7mXQgMiBj4bunYSBBDQojIETDsm5nIDIgbMOgIGTDsm5nIDMgY+G7mXQgMiBj4bunYSBBLCBkw7JuZyAzIGPhu5l0IDQgY+G7p2EgQQ0KQVtjKDEsMyksYygyLDQpXQ0KIyBDaOG7iSBt4bulYyBjw6FjIGdpw6EgdHLhu4sgdOG7qyBkw7JuZyAxLT4zLCBj4buZdCAyLT40IGPhu6dhIEENCkFbMTozLDI6NF0NCiMgTOG6pXkgZ2nDoSB0cuG7iyBkw7JuZyAxLT4yLCBs4bqleSB04bqldCBj4bqjIGPDoWMgY+G7mXQNCkFbMToyLF0NCiMgTOG6pXkgdOG6pXQgY+G6oyBjw6FjIGTDsm5nLCBj4buZdCB04burIDEtPjINCkFbLDE6Ml0NCiMgTOG6pXkgZMOybmcgMSwgbOG6pXkgdOG6pXQgY+G6oyBjw6FjIGPhu5l0DQpBWzEsXQ0KIyBM4bqleSB04bqldCBjw6FjIGTDsm5nIG5nb+G6oWkgdHLhu6sgZMOybmcgMSB2w6AgMywgbOG6pXkgdOG6pXQgY+G6oyBjw6FjIGPhu5l0DQpBWy1jKDEsMyksXQ0KIyBM4bqleSB04bqldCBj4bqjIGPDoWMgZMOybmcgbmdv4bqhaSB0cuG7qyBkw7JuZyAxIHbDoCAzLCB04bqldCBj4bqjIGPDoWMgY+G7mXQgbmdv4bqhaSB0cuG7qyBj4buZdCAxLDMsNA0KQVstYygxLDMpLC1jKDEsMyw0KV0NCiMgS8OtY2ggdGjGsOG7m2MgbWEgdHLhuq1uIEENCmRpbShBKQ0KYGBgDQoNCiMgNCkgVOG6o2kgZOG7ryBsaeG7h3UNCg0KYGBge3J9DQojIHJlYWQudGFibGUgZMO5bmcgxJHhu4MgxJHhu41jIGThu68gbGnhu4d1IGPhu6dhIGLhuqNuZw0KQXV0byA9cmVhZC50YWJsZSgiQXV0by5kYXRhIikNCiMgSGnhu4NuIHRy4buLIGThu68gbGnhu4d1IGTGsOG7m2kgZOG6oW5nIGLhuqNuZyB0w61uaCB0cm9uZyB3aW5kb3cNCmZpeChBdXRvKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiNIZWFkZXIgPSBUIMSR4buDIG7Ds2kgcsO1IHLhurFuZyBkw7JuZyDEkeG6p3UgdGnDqm4gY+G7p2EgZGF0YSBjaOG7qWEgdMOqbiBiaeG6v24gKCB0w6puIGPhu6dhIG5o4buvbmcgZmVhdHVyZSkNCiMgbmEuc3RyaW5nID0gIj8iIGTDuW5nIMSR4buDIGtoaSBtw6AgcGjDoXQgaGnhu4duIGvDrSB04buxIMSR4bq3YyBiaeG7h3QgdHJvbmcgZGF0YSwgdsOtIGThu6UgbmjGsCBsw6AgZOG6pXUgY2jhuqVtIA0KQXV0byA9cmVhZC50YWJsZSgiQXV0by5kYXRhIixoZWFkZXIgPSBULG5hLnN0cmluZ3MgPSAiPyIpDQojIEhp4buDbiB0cuG7iyBk4buvIGxp4buHdSBkxrDhu5tpIGThuqFuZyBi4bqjbmcgdMOtbmggdHJvbmcgd2luZG93DQpmaXgoQXV0bykNCmBgYA0KDQpgYGB7cn0NCiMgxJDhu41jIGRhdGEgZMaw4bubaSBk4bqhbmcgZmlsZSBjc3YgDQpBdXRvID0gcmVhZC5jc3YoIkF1dG8uY3N2IixoZWFkZXI9IFQsIG5hLnN0cmluZ3MgPSAiPyIpDQojIEhp4buDbiB0cuG7iyBk4buvIGxp4buHdSBkxrDhu5tpIGThuqFuZyBi4bqjbmcgdMOtbmggdHJvbmcgd2luZG93DQpmaXgoQXV0bykNCiMgS8OtY2ggdGjGsOG7m2MgZGF0YQ0KZGltKEF1dG8pDQojIEzhuqV5IGTDsm5nIDEtPjQsIHThuqV0IGPhuqMgY8OhYyBj4buZdA0KQXV0b1sxOjQsXQ0KYGBgDQoNCg0KYGBge3J9DQojIG5hLm9taXQgZMO5bmcgxJHhu4MgeG/DoSDEkWkgbmjhu69uZyBkw7JuZyBjw7MgZOG7ryBsaeG7h3UgYuG7iyBt4bqldCAoIG1pc3NpbmcgZGF0YSkNCkF1dG8gPSBuYS5vbWl0KEF1dG8pDQojIEvDrWNoIHRoxrDhu5tjIGPhu6dhIGRhdGEgxJHDoyBnaeG6o20gxJFpIDUgZMOybmcsIHN1eSByYSBjw7MgNSBkw7JuZyBjw7MgZOG7ryBsaeG7h3UgYuG7iyBt4bqldA0KZGltKEF1dG8pDQpgYGANCg0KDQpgYGB7cn0NCiMgxJDhu4MgY2jhu4kgbeG7pWMgYmnhur9uIGN5bHluZGVycyB2w6AgbXBnIGPhuqduIGTDuW5nIGvDrSB04buxICQgxJHhu4MgY2jhu4kgbeG7pWMgYmnhur9uIGPhu6dhIGThu68gbGnhu4d1DQojIEhp4buDbiB0aOG7iyDEkeG7kyB0aOG7iyBwaMOibiB0w6FuIGPhu6dhIDIgYmnhur9uIGN5bHluZGVycyB2w6AgbXBnDQpwbG90KEF1dG8kY3lsaW5kZXJzLCBBdXRvJG1wZykNCiMgYXR0YWNoIGTDuW5nIMSR4buDIGtoaeG6v24gY2hvIG5o4buvbmcgYmnhur9uIGZlYXR1cmUgdHJvbmcgZOG7ryBsaeG7h3UgY8OzIHPhurVuIHRyb25nIFJzdHVkaW8gdGhlbyB0w6puDQphdHRhY2goQXV0bykNCiMgSGnhu4NuIHRo4buLIMSR4buTIHRo4buLIHRow7RuZyBxdWEgdMOqbiBiaeG6v24gbcOgIGtvIGPhuqduIGTDuW5nIGvDrSB04buxICQNCnBsb3QoY3lsaW5kZXJzLG1wZykNCiNhcy5mYWN0b3IoKSBkw7luZyDEkeG7gyBjaHV54buDbiBnacOhIHRy4buLIMSR4buLbmggbMaw4bujbmcgdGjDoG5oIMSR4buLbmggdMOtbmgNCmN5bGluZGVycz0gYXMuZmFjdG9yKGN5bGluZGVycykNCmBgYA0KDQoNCmBgYHtyfQ0KIyBIaeG7g24gdGjhu4sgYmnhu4N1IMSR4buTIHBow6JuIHTDoW4gMiB0aHXhu5ljIHTDrW5oIGN5bGluZGVycyB2w6AgbXBnDQojIERvIGPhu5l0IHggbMOgIGThuqFuZyDEkeG7i25oIHTDrW5oIChjYXRlZ29yaWNhbCkgbsOqbiBz4bq9IGhp4buDbiB0aOG7iyBkxrDhu5tpIGThuqFuZyBib3hwbG90DQpwbG90KGN5bGluZGVycyAsIG1wZykNCiMgY29sPSJyZWQiIGTDuW5nIMSR4buDIGhp4buDbiB0aOG7iyBjw6FjIGPhu5l0IG3DoHUgxJHhu48NCnBsb3QoY3lsaW5kZXJzICwgbXBnICwgY29sID0icmVkICIpDQojIHZhcndpZHRoPSBUIGtoaeG6v24gY2hvIG5o4buvbmcgY8OhaSBo4buZcCDEkcaw4bujYyBoaeG7g24gdGjhu4sgduG7m2kgxJHhu5kgcuG7mW5nIHThu4kgbOG7hyB24bubaSBjxINuIGLhuq1jIDIgc+G7kSBsxrDhu6NuZyBmZWF0dXJlIHRyb25nIGLhuqNuZyBkYXRhDQpwbG90KGN5bGluZGVycyAsIG1wZyAsIGNvbCA9InJlZCIsIHZhcndpZHRoID1UKQ0KIyBIb3Jpem9udGFsID0gVCBraGnhur9uIGNobyBjw6FjIGPhu5l0IMSRxrDhu6NjIGhp4buDbiB0aOG7iyBow6BuZyBuZ2FuZw0KcGxvdChjeWxpbmRlcnMgLCBtcGcgLCBjb2wgPSJyZWQiLCB2YXJ3aWR0aCA9VCxob3Jpem9udGFsID1UKQ0KIyBIaeG7g24gdGjhu4sgdHLhu6VjIHggbMOgIGN5bGluZGVycyB2w6AgdHLhu6VjIHkgbMOgIE1QRw0KcGxvdChjeWxpbmRlcnMgLCBtcGcgLCBjb2wgPSJyZWQiLCB2YXJ3aWR0aCA9VCwgeGxhYj0iY3lsaW5kZXJzICIsDQp5bGFiPSJNUEciKQ0KYGBgDQoNCg0KYGBge3J9DQojIEhpc3RvZ3JhbSBj4bunYSBmZWF0dXJlIG1wZyB0aGVvIHRow6FuZyAyDQpoaXN0KG1wZykNCiMgSGnhu4NuIHRo4buLIGPDoWMgY+G7mXQgdGhlbyBtw6B1IMSR4buPDQpoaXN0KG1wZyxjb2wgPSAyKQ0KIyBUaGnhur90IGzhuq1wIHPhu5EgbMaw4bujbmcgdOG6vyBiw6BvIGPhu6dhIGhpc3RvZ3JhbSBsw6AgMTUNCmhpc3QobXBnLGNvbCA9IDIsIGJyZWFrcyA9IDE1KQ0KIyBQYWlycygpIGTDuW5nIMSR4buDIHThuqFvIHJhIG1hIHRy4bqtbiDEkeG7kyB0aOG7iyBwaMOibiB0w6FuIGPhu6dhIGThu68gbGnhu4d1DQpwYWlycyhBdXRvKQ0KIyBNYSB0cuG6rW4gxJHhu5MgdGjhu4sgcGjDom4gbeG7mXQgdOG6rXAgY29uIGNo4buJIGfhu5NtIDUgZmVhdHVyZSBj4bunYSBk4buvIGxp4buHdSANCnBhaXJzKOKIvCBtcGcgKyBkaXNwbGFjZW1lbnQgKyBob3JzZXBvd2VyICsgd2VpZ2h0ICsNCmFjY2VsZXJhdGlvbiAsIEF1dG8pDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyDEkOG7kyB0aOG7iyBwaMOibiB0w6FuIDIgYmnhur9uIGhvcnNlcG93ZXIgdsOgIG1wZw0KcGxvdChob3JzZXBvd2VyICxtcGcpDQojIEjDoG0gaW5kZW50aWZ5IGTDuW5nIMSR4buDIHjDoWMgxJHhu4tuaCBuaOG7r25nIMSRaeG7g20gZ2nDoSB0cuG7iyB0csOqbiBiaeG7g3UgxJHhu5MNCiMgS2hpIGJp4buDdSDEkeG7kyBwaMOibiB0w6FuIMSRxrDhu6NjIGhp4buDbiB0aOG7iywgY2xpY2sgY2jhu41uIGzDqm4gY8OhYyDEkWnhu4NtIHNhdSDEkcOzIGLhuqVtIGZpbmlzaCBsw6AgxJHhu5MgdGjhu4sgc+G6vSBoaeG7g24gdGjhu4sgZ2nDoSB0cuG7iyBiaeG6v24gdGjhu6kgMyjhu58gxJHDonkgbMOgIGJp4bq/biBuYW1lKWPFqW5nIG5oxrAgeHXhuqV0IHJhIG5o4buvbmcgY29uIHPhu5EgdMawxqFuZyDhu6luZyAgZMOybmcgdGjhu6kgbeG6pXkgY+G7p2Egbmjhu69uZyDEkWnhu4NtIMSRxrDhu6NjIGNsaWNrIMSRw7MNCmlkZW50aWZ5IChob3JzZXBvd2VyICxtcGcgLG5hbWUpDQoNCmBgYA0KDQpgYGB7cn0NCiMgSMOgbSBzdW1tYXJ5IGTDuW5nIMSR4buDIHBow6JuIHTDrWNoIHTDs20gdOG6r3QgZOG7ryBsaeG7h3Ugbmjhu69uZyBiaeG6v24gdHJvbmcgZGF0YXNldA0Kc3VtbWFyeShBdXRvKQ0KIyBDxaluZyBjw7MgdGjhu4MgdMOzbSB04bqvdCBk4buvIGxp4buHdSBj4bunYSAxIGJp4bq/biBj4bulIHRo4buDDQpzdW1tYXJ5KG1wZykNCmBgYA0KDQoNCg==