Giới thiệu về bộ dữ liệu diamonds
- Bộ dữ liệu có 10 cột tương ứng với 10 biến
- carat: Trọng lượng của viên kim cương (carat)
- cut: Chất lượng đường cắt (Fair, Good, Very Good, Ideal, Premium)
color: Màu sắc của viên kim cương (từ D (tốt nhất) đến J (kém
nhất))
- price: Giá trị của viên kim cương (đơn vị USD)
- clarity: Độ trong suốt của viên kim cương (từ IF (tốt nhất) đến I1
(kém nhất))
- depth: Tỷ lệ phần trăm độ sâu (tính theo z / x)
- table: Chiều rộng của mặt bàn (tính theo % của đường kính)
- x: Chiều dài của viên kim cương (mm) = y: Chiều rộng của viên kim
cương (mm)
- z: Độ sâu của viên kim cương (mm)
names(tcd)
## [1] "carat" "cut" "color" "clarity" "depth" "table" "price"
## [8] "x" "y" "z"
- Bảng dữ liệu của bộ dataset diamonds
tcd
## # A tibble: 53,940 × 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.29 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48
## 7 0.24 Very Good I VVS1 62.3 57 336 3.95 3.98 2.47
## 8 0.26 Very Good H SI1 61.9 55 337 4.07 4.11 2.53
## 9 0.22 Fair E VS2 65.1 61 337 3.87 3.78 2.49
## 10 0.23 Very Good H VS1 59.4 61 338 4 4.05 2.39
## # ℹ 53,930 more rows
Phân tích bộ dữ liệu với biểu đồ bar chart
1. Biểu đồ thể hiện mặt cắt của các loại kim cương
tcd %>% ggplot(aes(x = cut)) +
geom_bar() +
labs(X = 'loại', y = 'số lượng')

- Biểu đồ biểu diễn theo dạng dọc
2. Biểu đồ thể hiện mặt cắt của các loại kim cương
tcd %>% ggplot(aes(x = cut)) +
geom_bar() +
labs(x = 'Loại','Số lượng') +
coord_flip()

- Biểu đồ thể hiện theo dạng ngang
3. Biểu đồ thể hiện số lượng kim cương thuộc các loại khác nhau
tcd %>% group_by(cut) %>% summarise(freq= n()) %>%
ggplot(aes(x = cut, y = freq)) +
geom_col(fill= 'lightblue') +
geom_text(aes(label =freq), vjust =2, color = 'white') +
labs(x= 'Loại', y= 'Số lượng')

- Số lượng kim cương thuộc loại Fair là 1610
- Số lượng kim cương thuộc loại Good là 4906
- Số lượng kim cương thuộc loại Very Good là 12082
- Số lượng kim cương thuộc loại Premium là 13791
- Số lượng kim cương thuộc loại Ideal là 21551
Nhận xét: Số lượng kim cương thuộc loại Ideal là cao
nhất gấp gần 13.4 lần loại Fair, 4.4 lần loại Good, 1,8 lần loại Very
Good, 1,5 lần loại Premium
4. Biểu đồ thể hiện tỉ lệ phần trăm về số lượng của các loại kim
cương
tcd %>% group_by(cut) %>% summarise(n = n()) %>%
ggplot(aes(cut,n)) +
geom_col(fill='pink') +
geom_text(aes(label = percent(n/length(tcd$carat))),vjust = 2, color = 'white') +
labs(x = 'Loại', y = 'Số lượng')

- Số lượng kim cương loại Fair chiếm 3.0%
- Số lượng kim cương loại Good chiếm 9.1%
- Số lượng kim cương loại Very Good chiếm 22.4%
- Số lượng kim cương loại Premium chiếm 25.6%
- Số lượng kim cương loại Ideal chiếm 40.0%
Nhận xét: Kim cương loại Ideal chiếm % số lượng cao
nhất, kim cương loại Fair chiếm % số lượng thấp nhất
5. Biểu đồ thể hiện số lượng kim cương theo loại color với màu sắc
đường viền cắt
tcd %>% group_by(cut,color) %>% summarise(n=n()) %>%
ggplot(aes(x = cut,y = n)) +
geom_col(position = 'dodge') +
facet_wrap(~color) +
labs(x = 'Loại', y = 'Số lượng')

6. Biểu đồ này thể hiện số lượng kim cương trong mỗi phân loại này
(color)
ggplot(diamonds, aes(x = color)) +
geom_bar()

Nhận xét: Nhìn vào biểu đồ trên ta thấy:
- Kim cương có màu G chiếm số lượng cao nhất
- Kim cương có màu J chiếm số lượng thấp nhất
- Kim cương có các màu D,E,F,H,I chiếm số lượng gần tương tự nhưng vẫn
có sự chênh lệch giữa các màu với nhau
7. Biểu đồ thể hiện số lượng kim cương trong mỗi phân loại độ trong
suốt (clarity)
ggplot(diamonds, aes(x = clarity)) +
geom_bar()

Nhận xét: Từ biểu đồ trên ta thấy:
- Số lượng kim cương phân loại theo độ trong suốt >10000 bao gồm :
SI1,VS2
- Số lượng kim cương phân loại theo độ trong suốt
>=5000&<10000 bao gồm : SI2,VS1,WS2
- Số lượng kim cương phân loại theo độ trong suốt <5000 bao gồm :
WS1,IF,I1
- Số lượng kim cương phân loại theo độ trong suốt SI1 là cao nhất, I1
là thấp nhất
8. Biểu đồ này thể hiện trung bình giá kim cương theo từng loại cắt
và màu sắc
tcd %>% ggplot() +
stat_summary(mapping = aes(x = cut, y = price, fill = color), fun.y = "mean", geom = "bar", position = "dodge") +
coord_flip() +
scale_fill_brewer(palette = "Set3") +
labs(title = "Trung bình giá kim cương theo từng loại cắt và màu sắc",x = "Loại cắt", y = "Giá trung bình")

9. Biểu đồ này thể hiện số lượng các loại kim cương được phân loại
theo màu sắc
tcd %>% ggplot(mapping = aes(x = cut, fill = color)) +
geom_bar() +
scale_fill_manual(values = sort(unique(diamonds$color)))+
labs(title = "Biểu đồ số lượng kim cương chia theo màu sắc",x = 'Loại', y = 'Số lượng')

Nhận xét: Từ biểu đồ trên ta thấy ( dựa vào tiêu chí
là số lượng và loại ):
- Kim cương loại Fair có các loại màu tương tự nhau chiếm tỉ lệ về màu
sắc khá đồng đều
- Kim cương loại Good có các loại màu tương tự nhau chiếm tỉ lệ về màu
sắc khá đồng đều
- Kim cương loại Very Good và Premium có số lương màu E,F,G,H cao hơn
so với màu D,I,J
- Kim cương loại Ideal có số lượng màu E,F,G cao hơn nhiều so với các
màu còn lại, màu G chiếm đa số
10. Biểu đồ thể hiện giá trị kim cương lớn nhất theo độ trong
ggplot(diamonds, aes(x = clarity, y = price)) +
geom_bar(stat = "summary", fun = max)

11. Biểu đồ thể hiện giá trị kim cương nhỏ nhất theo màu sắc:
ggplot(diamonds, aes(x = color, y = price)) +
geom_bar(stat = "summary", fun = min)

12. Biểu đồ thể hiện tổng giá trị kim cương theo loại cắt và màu
sắc:
ggplot(diamonds, aes(x = cut, fill = color, y = price)) +
geom_bar(position = "stack", stat = "summary", fun = "sum")

Nhận xét: Từ biểu đồ trên ta thấy ( dựa vào tiêu chí
price và cut ) :
- Kim cương loại Fair có các loại màu tương tự nhau chiếm tỉ lệ về màu
sắc khá đồng đều
- Kim cương loại Good có các loại màu tương tự nhau chiếm tỉ lệ về màu
sắc khá đồng đều
- Kim cương loại Very Good và Premium có số lương màu E,F,G,H cao hơn
so với màu D,I,J
- Kim cương loại Ideal có số lượng màu E,F,G cao hơn nhiều so với các
màu còn lại, màu G chiếm đa số
13. Biểu đồ thể hiện giá trị trung bình kim cương theo loại cắt và
độ trong:
ggplot(diamonds, aes(x = cut, fill = clarity, y = price)) +
geom_bar(position = "stack", stat = "summary", fun = "mean")

14. Biểu đồ thể hiện số lượng kim cương theo kích thước và màu
sắc:
ggplot(diamonds, aes(x = carat, fill = color)) +
geom_bar(binwidth = 0.5)

Nhận xét: Từ iểu đồ trên cho thấy số lượng kim cương
theo kích thước và màu sắc, với các cột được nhóm lại theo khoảng kích
thước 0.5 và màu sắc tương ứng.
15. Biểu đồ thể hiện số lượng kim cương theo kích thước và loại
cắt:
ggplot(diamonds, aes(x = carat, fill = cut)) +
geom_bar(binwidth = 0.5)

Nhận xét: Từ biểu đồ trên cho thấy số lượng kim
cương theo kích thước và loại cắt, với các cột được nhóm lại theo khoảng
kích thước 0.5 và loại cắt tương ứng.
16. Biểu đồ thể hiện giá trị trung bình kim cương theo loại cắt và
màu sắc:
ggplot(diamonds, aes(x = cut, fill = color, y = price)) +
stat_summary(fun = "mean", geom = "bar")

Nhận xét: Từ biểu đồ trên cho ta thấy:
- Màu J chiếm đa số tất cả các loại cắt, bên cạnh đó còn có một vài
loại cắt có màu I và H như là: Fair, Good, Very Good
17. Biểu đồ thể hiện giá trị trung bình kim cương theo màu sắc và độ
trong:
ggplot(diamonds, aes(x = color, fill = clarity, y = price)) +
geom_bar(position = "stack", stat = "summary", fun = "mean")

Nhận xét: Từ biểu đồ trên cho thấy giá trị trung
bình của kim cương theo từng màu sắc và độ trong, với các cột được xếp
chồng lên nhau.
18. Biểu đồ thể hiện trung bình giá trị các loại cắt kim cương với
màu sắc
tcd %>% group_by(cut,color) %>% summarise(m = mean(price)) %>% ggplot(aes(x = cut,y = m, fill = color)) + geom_col(position = 'dodge') + labs(x = 'Loại', y = 'Số lượng')

Nhận xét:
19. Biểu đồ thể hiện trung bình giá kim cương theo màu sắc
diamonds %>%
group_by(color) %>%
summarise(mean_price = mean(price)) %>%
ggplot(aes(x = color, y = mean_price)) +
geom_bar(stat = "identity") +
xlab("Color") +
ylab("Price") +
ggtitle("Giá kim cương theo màu sắc")

20. Biểu đồ thể hiện tỷ lệ kim cương theo độ trong suốt
diamonds %>%
count(clarity) %>%
mutate(proportion = n / sum(n)) %>%
ggplot(aes(x = clarity, y = proportion)) +
geom_bar(stat = "identity") +
xlab("Clarity") +
ylab("Proportion") +
ggtitle("Tỷ lệ kim cương theo độ trong suốt")

21. Biểu đồ thể hiện phân phối kích thước carat của kim cương
ggplot(diamonds, aes(x = carat)) +
geom_histogram(binwidth = 0.5) +
xlab("Carat") +
ylab("Frequency") +
ggtitle("Phân phối kích thước carat của kim cương")

22. Biểu đồ thể hiện Tần suất các loại kim cương theo giá trị
tcd %>% ggplot(aes(x = cut, y = price, fill = clarity)) +
geom_bar(stat = "summary", fun.y = "mean", position = "dodge") +
facet_wrap(~color)+
labs(title = "Tần suất các loại kim cương theo giá trị", x = "Loại", y = "Giá trị")

23. Biểu đồ thể hiện trung bình giá kim cương theo kiểu cắt
diamonds %>%
group_by(cut) %>%
summarise(mean_price = mean(price)) %>%
ggplot(aes(x = cut, y = mean_price)) +
geom_bar(stat = "identity") +
xlab("Cut") +
ylab("Price") +
ggtitle("Trung bình giá kim cương theo kiểu cắt")

24. Biểu đồ thể hiện số lượng kim cương theo màu sắc và độ trong
suốt
diamonds %>%
group_by(color, clarity) %>%
summarise(count = n()) %>%
ggplot(aes(x = color, y = count, fill = clarity)) +
geom_bar(stat = "identity", position = "dodge") +
xlab("Color") +
ylab("Count") +
ggtitle("Số lượng kim cương theo màu sắc và độ trong suốt
") +
scale_fill_discrete(name = "Clarity")

25. Biểu đồ thể hiện trung bình giá kim cương theo kiểu cắt và độ
trong suốt
diamonds %>%
group_by(cut, clarity) %>%
summarise(mean_price = mean(price)) %>%
ggplot(aes(x = cut, y = mean_price, fill = clarity)) +
geom_bar(stat = "identity", position = "dodge") +
xlab("Cut") +
ylab("Price") +
ggtitle("Trung bình giá kim cương theo kiểu cắt và độ trong suốt") +
scale_fill_discrete(name = "Clarity")

26. Biểu đồ thể hiện số lượng kim cương theo kiểu cắt và độ trong
suốt
diamonds %>%
group_by(cut, clarity) %>%
summarise(count = n()) %>%
ggplot(aes(x = cut, y = count, fill = clarity)) +
geom_bar(stat = "identity", position = "dodge") +
xlab("Cut") +
ylab("Count") +
ggtitle("Số lượng kim cương theo kiểu cắt và độ trong suốt") +
scale_fill_discrete(name = "Clarity")

27. Biểu đồ thể hiện trung bình giá kim cương theo màu sắc, kiểu cắt
và độ trong suốt
diamonds %>%
group_by(color, cut, clarity) %>%
summarise(mean_price = mean(price)) %>%
ggplot(aes(x = color, y = mean_price, fill = interaction(cut, clarity))) +
geom_bar(stat = "identity", position = "dodge") +
xlab("Color") +
ylab("Average Price") +
ggtitle("Trung bình giá kim cương theo màu sắc, kiểu cắt và độ trong suốt") +
scale_fill_discrete(name = "Cut & Clarity")

28. Biểu đồ thể hiện số lượng kim cương theo màu sắc, kiểu cắt và độ
trong suốt
diamonds %>%
group_by(color, cut, clarity) %>%
summarise(count = n()) %>%
ggplot(aes(x = color, y = count, fill = interaction(cut, clarity))) +
geom_bar(stat = "identity", position = "dodge") +
xlab("Color") +
ylab("Count") +
ggtitle("Số lượng kim cương theo màu sắc, kiểu cắt và độ trong suốt") +
scale_fill_discrete(name = "Cut & Clarity")

29. Biểu đồ thể hiện trung bình giá trị của các loại cắt kim cương
với màu sắc và độ trong suốt
tcd %>%group_by(cut, color, clarity) %>%summarise(mean_price = mean(price)) %>% arrange(desc(mean_price)) %>%
ggplot(aes(x = cut, y = mean_price, fill = color, color = clarity)) +
geom_bar(stat = "identity", position = "dodge")+
labs(title = "Trung bình giá trị của các loại cắt kim cương với màu sắc và độ trong suốt", x = "Loại", y = "Trung bình giá trị")

30. Biểu đồ thể hiện Độ sâu trung bình’,title=’Giá trị trung bình
của depth theo cut và clarity
tcd %>% group_by(cut, clarity)%>%summarise(m=mean(depth))%>%ggplot(aes(x=cut, y= m))+
geom_col(position='dodge')+
facet_wrap(~clarity)+
geom_text(aes(label= round(m)), vjust=2, color='white')+
labs(x= 'Loại', y= 'Độ sâu trung bình',title='Giá trị trung bình của depth theo cut và clarity ')

LS0tDQp0aXRsZTogIk5oaeG7h20gduG7pSA0Ig0KYXV0aG9yOiAidGNkYXQiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclSDolTTolUywgJWQgLSAlbSAtICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdGhlbWU6ICJkZWZhdWx0Ig0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGdncGxvdDIpDQp0Y2QgPC0gZGlhbW9uZHMNCnRjZA0KYGBgDQojIyMgKipHaeG7m2kgdGhp4buHdSB24buBIGLhu5kgZOG7ryBsaeG7h3UgZGlhbW9uZHMqKg0KDQotIELhu5kgZOG7ryBsaeG7h3UgY8OzIDEwIGPhu5l0IHTGsMahbmcg4bupbmcgduG7m2kgMTAgYmnhur9uIA0KLSBjYXJhdDogVHLhu41uZyBsxrDhu6NuZyBj4bunYSB2acOqbiBraW0gY8awxqFuZyAoY2FyYXQpDQotIGN1dDogQ2jhuqV0IGzGsOG7o25nIMSRxrDhu51uZyBj4bqvdCAoRmFpciwgR29vZCwgVmVyeSBHb29kLCBJZGVhbCwgUHJlbWl1bSkgY29sb3I6IE3DoHUgc+G6r2MgY+G7p2EgdmnDqm4ga2ltIGPGsMahbmcgKHThu6sgRCAodOG7kXQgbmjhuqV0KSDEkeG6v24gSiAoa8OpbSBuaOG6pXQpKQ0KLSBwcmljZTogR2nDoSB0cuG7iyBj4bunYSB2acOqbiBraW0gY8awxqFuZyAoxJHGoW4gduG7iyBVU0QpDQotIGNsYXJpdHk6IMSQ4buZIHRyb25nIHN14buRdCBj4bunYSB2acOqbiBraW0gY8awxqFuZyAodOG7qyBJRiAodOG7kXQgbmjhuqV0KSDEkeG6v24gSTEgKGvDqW0gbmjhuqV0KSkNCi0gZGVwdGg6IFThu7cgbOG7hyBwaOG6p24gdHLEg20gxJHhu5kgc8OidSAodMOtbmggdGhlbyB6IC8geCkNCi0gdGFibGU6IENoaeG7gXUgcuG7mW5nIGPhu6dhIG3hurd0IGLDoG4gKHTDrW5oIHRoZW8gJSBj4bunYSDEkcaw4budbmcga8OtbmgpDQotIHg6IENoaeG7gXUgZMOgaSBj4bunYSB2acOqbiBraW0gY8awxqFuZyAobW0pDQo9IHk6IENoaeG7gXUgcuG7mW5nIGPhu6dhIHZpw6puIGtpbSBjxrDGoW5nIChtbSkNCi0gejogxJDhu5kgc8OidSBj4bunYSB2acOqbiBraW0gY8awxqFuZyAobW0pDQpgYGB7cn0NCm5hbWVzKHRjZCkNCmBgYA0KDQotIELhuqNuZyBk4buvIGxp4buHdSBj4bunYSBi4buZIGRhdGFzZXQgZGlhbW9uZHMgDQoNCmBgYHtyfQ0KdGNkDQpgYGANCg0KDQojIyMgKipQaMOibiB0w61jaCBi4buZIGThu68gbGnhu4d1IHbhu5tpIGJp4buDdSDEkeG7kyBiYXIgY2hhcnQqKiANCiMjIyAxLiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIG3hurd0IGPhuq90IGPhu6dhIGPDoWMgbG/huqFpIGtpbSBjxrDGoW5nDQpgYGB7cn0NCg0KdGNkICU+JSBnZ3Bsb3QoYWVzKHggPSBjdXQpKSArIA0KICBnZW9tX2JhcigpICsgDQogIGxhYnMoWCA9ICdsb+G6oWknLCB5ID0gJ3Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCi0gQmnhu4N1IMSR4buTIGJp4buDdSBkaeG7hW4gdGhlbyBk4bqhbmcgZOG7jWMgDQoNCg0KIyMjIDIuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gbeG6t3QgY+G6r3QgY+G7p2EgY8OhYyBsb+G6oWkga2ltIGPGsMahbmcgDQoNCmBgYHtyfQ0KdGNkICU+JSBnZ3Bsb3QoYWVzKHggPSBjdXQpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHggPSAnTG/huqFpJywnU+G7kSBsxrDhu6NuZycpICsNCmNvb3JkX2ZsaXAoKQ0KYGBgDQoNCi0gQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiB0aGVvIGThuqFuZyBuZ2FuZyANCg0KIyMjIDMuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aHXhu5ljIGPDoWMgbG/huqFpIGtow6FjIG5oYXUgDQoNCmBgYHtyfQ0KdGNkICU+JSBncm91cF9ieShjdXQpICU+JSBzdW1tYXJpc2UoZnJlcT0gbigpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGN1dCwgeSA9IGZyZXEpKSArDQogIGdlb21fY29sKGZpbGw9ICdsaWdodGJsdWUnKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPWZyZXEpLCB2anVzdCA9MiwgY29sb3IgPSAnd2hpdGUnKSArDQogIGxhYnMoeD0gJ0xv4bqhaScsIHk9ICdT4buRIGzGsOG7o25nJykNCmBgYA0KDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGh14buZYyBsb+G6oWkgRmFpciBsw6AgMTYxMA0KLSBT4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRodeG7mWMgbG/huqFpIEdvb2QgbMOgIDQ5MDYNCi0gU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aHXhu5ljIGxv4bqhaSBWZXJ5IEdvb2QgbMOgIDEyMDgyDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGh14buZYyBsb+G6oWkgUHJlbWl1bSBsw6AgMTM3OTENCi0gU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aHXhu5ljIGxv4bqhaSBJZGVhbCBsw6AgMjE1NTENCg0KKipOaOG6rW4geMOpdDoqKiAgU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aHXhu5ljIGxv4bqhaSBJZGVhbCBsw6AgY2FvIG5o4bqldCBn4bqlcCBn4bqnbiAxMy40IGzhuqduIGxv4bqhaSBGYWlyLCA0LjQgbOG6p24gbG/huqFpIEdvb2QsIDEsOCBs4bqnbiBsb+G6oWkgVmVyeSBHb29kLCAxLDUgbOG6p24gbG/huqFpIFByZW1pdW0gICANCg0KIyMjIDQuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gdOG7iSBs4buHIHBo4bqnbiB0csSDbSB24buBIHPhu5EgbMaw4bujbmcgY+G7p2EgY8OhYyBsb+G6oWkga2ltIGPGsMahbmcgDQoNCmBgYHtyfQ0KdGNkICU+JSBncm91cF9ieShjdXQpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoY3V0LG4pKSArDQogICAgZ2VvbV9jb2woZmlsbD0ncGluaycpICsNCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudChuL2xlbmd0aCh0Y2QkY2FyYXQpKSksdmp1c3QgPSAyLCBjb2xvciA9ICd3aGl0ZScpICsNCiAgICBsYWJzKHggPSAnTG/huqFpJywgeSA9ICdT4buRIGzGsOG7o25nJykNCmBgYA0KDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgbG/huqFpIEZhaXIgY2hp4bq/bSAzLjAlDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgbG/huqFpIEdvb2QgY2hp4bq/bSA5LjElDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgbG/huqFpIFZlcnkgR29vZCBjaGnhur9tIDIyLjQlDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgbG/huqFpIFByZW1pdW0gY2hp4bq/bSAyNS42JQ0KLSBT4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIGxv4bqhaSBJZGVhbCBjaGnhur9tIDQwLjAlIA0KDQoqKk5o4bqtbiB4w6l0OioqIEtpbSBjxrDGoW5nIGxv4bqhaSBJZGVhbCBjaGnhur9tICUgc+G7kSBsxrDhu6NuZyBjYW8gbmjhuqV0LCBraW0gY8awxqFuZyBsb+G6oWkgRmFpciBjaGnhur9tICUgc+G7kSBsxrDhu6NuZyB0aOG6pXAgbmjhuqV0IA0KDQoNCiMjIyA1LiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBsb+G6oWkgY29sb3IgduG7m2kgbcOgdSBz4bqvYyDEkcaw4budbmcgdmnhu4FuIGPhuq90DQoNCg0KYGBge3J9DQp0Y2QgJT4lIGdyb3VwX2J5KGN1dCxjb2xvcikgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGN1dCx5ID0gbikpICsNCiAgICBnZW9tX2NvbChwb3NpdGlvbiA9ICdkb2RnZScpICsNCiAgICBmYWNldF93cmFwKH5jb2xvcikgKw0KICAgIGxhYnMoeCA9ICdMb+G6oWknLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCiMjIyA2LiBCaeG7g3UgxJHhu5MgbsOgeSB0aOG7gyBoaeG7h24gc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0cm9uZyBt4buXaSBwaMOibiBsb+G6oWkgbsOgeSAoY29sb3IpDQoNCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNvbG9yKSkgKw0KICBnZW9tX2JhcigpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKiBOaMOsbiB2w6BvIGJp4buDdSDEkeG7kyB0csOqbiB0YSB0aOG6pXk6DQoNCi0gS2ltIGPGsMahbmcgY8OzIG3DoHUgRyBjaGnhur9tIHPhu5EgbMaw4bujbmcgY2FvIG5o4bqldCANCi0gS2ltIGPGsMahbmcgY8OzIG3DoHUgSiBjaGnhur9tIHPhu5EgbMaw4bujbmcgdGjhuqVwIG5o4bqldCANCi0gS2ltIGPGsMahbmcgY8OzIGPDoWMgbcOgdSBELEUsRixILEkgY2hp4bq/bSBz4buRIGzGsOG7o25nIGfhuqduIHTGsMahbmcgdOG7sSBuaMawbmcgduG6q24gY8OzIHPhu7EgY2jDqm5oIGzhu4djaCBnaeG7r2EgY8OhYyBtw6B1IHbhu5tpIG5oYXUgDQoNCiMjIyA3LiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdHJvbmcgbeG7l2kgcGjDom4gbG/huqFpIMSR4buZIHRyb25nIHN14buRdCAoY2xhcml0eSkNCg0KYGBge3J9DQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2xhcml0eSkpICsNCiAgZ2VvbV9iYXIoKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KiogVOG7qyBiaeG7g3UgxJHhu5MgdHLDqm4gdGEgdGjhuqV5Og0KDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgcGjDom4gbG/huqFpIHRoZW8gxJHhu5kgdHJvbmcgc3Xhu5F0ID4xMDAwMCBiYW8gZ+G7k20gOiBTSTEsVlMyIA0KLSBT4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHBow6JuIGxv4bqhaSB0aGVvIMSR4buZIHRyb25nIHN14buRdCA+PTUwMDAmPDEwMDAwIGJhbyBn4buTbSA6IFNJMixWUzEsV1MyDQotIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgcGjDom4gbG/huqFpIHRoZW8gxJHhu5kgdHJvbmcgc3Xhu5F0IDw1MDAwIGJhbyBn4buTbSA6IFdTMSxJRixJMSANCi0gU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyBwaMOibiBsb+G6oWkgdGhlbyDEkeG7mSB0cm9uZyBzdeG7kXQgU0kxIGzDoCBjYW8gbmjhuqV0LCBJMSBsw6AgdGjhuqVwIG5o4bqldCANCg0KIyMjIDguIEJp4buDdSDEkeG7kyBuw6B5IHRo4buDIGhp4buHbiB0cnVuZyBiw6xuaCBnacOhIGtpbSBjxrDGoW5nIHRoZW8gdOG7q25nIGxv4bqhaSBj4bqvdCB2w6AgbcOgdSBz4bqvYw0KYGBge3J9DQp0Y2QgJT4lIGdncGxvdCgpICsNCiAgc3RhdF9zdW1tYXJ5KG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IHByaWNlLCBmaWxsID0gY29sb3IpLCBmdW4ueSA9ICJtZWFuIiwgZ2VvbSA9ICJiYXIiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKw0KICBsYWJzKHRpdGxlID0gIlRydW5nIGLDrG5oIGdpw6Ega2ltIGPGsMahbmcgdGhlbyB04burbmcgbG/huqFpIGPhuq90IHbDoCBtw6B1IHPhuq9jIix4ID0gIkxv4bqhaSBj4bqvdCIsIHkgPSAiR2nDoSB0cnVuZyBiw6xuaCIpDQpgYGANCg0KIyMjIDkuIEJp4buDdSDEkeG7kyBuw6B5IHRo4buDIGhp4buHbiBz4buRIGzGsOG7o25nIGPDoWMgbG/huqFpIGtpbSBjxrDGoW5nICDEkcaw4bujYyBwaMOibiBsb+G6oWkgdGhlbyBtw6B1IHPhuq9jDQpgYGB7cn0NCnRjZCAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgZmlsbCA9IGNvbG9yKSkgKw0KICBnZW9tX2JhcigpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc29ydCh1bmlxdWUoZGlhbW9uZHMkY29sb3IpKSkrDQogICBsYWJzKHRpdGxlID0gIkJp4buDdSDEkeG7kyBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIGNoaWEgdGhlbyBtw6B1IHPhuq9jIix4ID0gJ0xv4bqhaScsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKiBU4burIGJp4buDdSDEkeG7kyB0csOqbiB0YSB0aOG6pXkgKCBk4buxYSB2w6BvIHRpw6p1IGNow60gbMOgIHPhu5EgbMaw4bujbmcgdsOgIGxv4bqhaSApOg0KDQotIEtpbSBjxrDGoW5nIGxv4bqhaSBGYWlyIGPDsyBjw6FjIGxv4bqhaSBtw6B1IHTGsMahbmcgdOG7sSBuaGF1IGNoaeG6v20gdOG7iSBs4buHIHbhu4EgbcOgdSBz4bqvYyBraMOhIMSR4buTbmcgxJHhu4F1IA0KLSBLaW0gY8awxqFuZyBsb+G6oWkgR29vZCBjw7MgY8OhYyBsb+G6oWkgbcOgdSB0xrDGoW5nIHThu7EgbmhhdSBjaGnhur9tIHThu4kgbOG7hyB24buBIG3DoHUgc+G6r2Mga2jDoSDEkeG7k25nIMSR4buBdSANCi0gS2ltIGPGsMahbmcgbG/huqFpIFZlcnkgR29vZCB2w6AgUHJlbWl1bSBjw7Mgc+G7kSBsxrDGoW5nIG3DoHUgRSxGLEcsSCBjYW8gaMahbiBzbyB24bubaSBtw6B1IEQsSSxKIA0KLSBLaW0gY8awxqFuZyBsb+G6oWkgSWRlYWwgY8OzIHPhu5EgbMaw4bujbmcgbcOgdSBFLEYsRyBjYW8gaMahbiBuaGnhu4F1IHNvIHbhu5tpIGPDoWMgbcOgdSBjw7JuIGzhuqFpLCBtw6B1IEcgY2hp4bq/bSDEkWEgc+G7kSAgDQoNCiMjIyAxMC4gQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBnacOhIHRy4buLIGtpbSBjxrDGoW5nIGzhu5tuIG5o4bqldCB0aGVvIMSR4buZIHRyb25nIA0KYGBge3J9DQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2xhcml0eSwgeSA9IHByaWNlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSBtYXgpDQoNCmBgYA0KDQojIyMgMTEuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gZ2nDoSB0cuG7iyBraW0gY8awxqFuZyBuaOG7jyBuaOG6pXQgdGhlbyBtw6B1IHPhuq9jOg0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjb2xvciwgeSA9IHByaWNlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSBtaW4pDQoNCmBgYA0KDQojIyMgMTIuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gdOG7lW5nIGdpw6EgdHLhu4sga2ltIGPGsMahbmcgdGhlbyBsb+G6oWkgY+G6r3QgdsOgIG3DoHUgc+G6r2M6DQoNCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGN1dCwgZmlsbCA9IGNvbG9yLCB5ID0gcHJpY2UpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdCA9ICJzdW1tYXJ5IiwgZnVuID0gInN1bSIpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKiBU4burIGJp4buDdSDEkeG7kyB0csOqbiB0YSB0aOG6pXkgKCBk4buxYSB2w6BvIHRpw6p1IGNow60gcHJpY2UgdsOgIGN1dCApIDoNCg0KLSBLaW0gY8awxqFuZyBsb+G6oWkgRmFpciBjw7MgY8OhYyBsb+G6oWkgbcOgdSB0xrDGoW5nIHThu7EgbmhhdSBjaGnhur9tIHThu4kgbOG7hyB24buBIG3DoHUgc+G6r2Mga2jDoSDEkeG7k25nIMSR4buBdSANCi0gS2ltIGPGsMahbmcgbG/huqFpIEdvb2QgY8OzIGPDoWMgbG/huqFpIG3DoHUgdMawxqFuZyB04buxIG5oYXUgY2hp4bq/bSB04buJIGzhu4cgduG7gSBtw6B1IHPhuq9jIGtow6EgxJHhu5NuZyDEkeG7gXUgDQotIEtpbSBjxrDGoW5nIGxv4bqhaSBWZXJ5IEdvb2QgdsOgIFByZW1pdW0gY8OzIHPhu5EgbMawxqFuZyBtw6B1IEUsRixHLEggY2FvIGjGoW4gc28gduG7m2kgbcOgdSBELEksSiANCi0gS2ltIGPGsMahbmcgbG/huqFpIElkZWFsIGPDsyBz4buRIGzGsOG7o25nIG3DoHUgRSxGLEcgY2FvIGjGoW4gbmhp4buBdSBzbyB24bubaSBjw6FjIG3DoHUgY8OybiBs4bqhaSwgbcOgdSBHIGNoaeG6v20gxJFhIHPhu5EgIA0KDQojIyMgMTMuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBraW0gY8awxqFuZyB0aGVvIGxv4bqhaSBj4bqvdCB2w6AgxJHhu5kgdHJvbmc6DQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjdXQsIGZpbGwgPSBjbGFyaXR5LCB5ID0gcHJpY2UpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdCA9ICJzdW1tYXJ5IiwgZnVuID0gIm1lYW4iKQ0KYGBgDQoNCiMjIyAxNC4gQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8ga8OtY2ggdGjGsOG7m2MgdsOgIG3DoHUgc+G6r2M6IA0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgZmlsbCA9IGNvbG9yKSkgKw0KICBnZW9tX2JhcihiaW53aWR0aCA9IDAuNSkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqIFThu6sgaeG7g3UgxJHhu5MgdHLDqm4gY2hvIHRo4bqleSBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8ga8OtY2ggdGjGsOG7m2MgdsOgIG3DoHUgc+G6r2MsIHbhu5tpIGPDoWMgY+G7mXQgxJHGsOG7o2MgbmjDs20gbOG6oWkgdGhlbyBraG/huqNuZyBrw61jaCB0aMaw4bubYyAwLjUgdsOgIG3DoHUgc+G6r2MgdMawxqFuZyDhu6luZy4NCg0KIyMjIDE1LiAgQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8ga8OtY2ggdGjGsOG7m2MgdsOgIGxv4bqhaSBj4bqvdDoNCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCBmaWxsID0gY3V0KSkgKw0KICBnZW9tX2JhcihiaW53aWR0aCA9IDAuNSkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqIFThu6sgYmnhu4N1IMSR4buTIHRyw6puIGNobyB0aOG6pXkgc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGvDrWNoIHRoxrDhu5tjIHbDoCBsb+G6oWkgY+G6r3QsIHbhu5tpIGPDoWMgY+G7mXQgxJHGsOG7o2MgbmjDs20gbOG6oWkgdGhlbyBraG/huqNuZyBrw61jaCB0aMaw4bubYyAwLjUgdsOgIGxv4bqhaSBj4bqvdCB0xrDGoW5nIOG7qW5nLg0KDQojIyMgMTYuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBraW0gY8awxqFuZyB0aGVvIGxv4bqhaSBj4bqvdCB2w6AgbcOgdSBz4bqvYzogDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjdXQsIGZpbGwgPSBjb2xvciwgeSA9IHByaWNlKSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gImJhciIpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKiBU4burIGJp4buDdSDEkeG7kyB0csOqbiBjaG8gdGEgdGjhuqV5Og0KDQotIE3DoHUgSiBjaGnhur9tIMSRYSBz4buRIHThuqV0IGPhuqMgY8OhYyBsb+G6oWkgY+G6r3QsIGLDqm4gY+G6oW5oIMSRw7MgY8OybiBjw7MgbeG7mXQgdsOgaSBsb+G6oWkgY+G6r3QgY8OzIG3DoHUgSSB2w6AgSCBuaMawIGzDoDogRmFpciwgR29vZCwgVmVyeSBHb29kIA0KDQojIyMgMTcuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBraW0gY8awxqFuZyB0aGVvIG3DoHUgc+G6r2MgdsOgIMSR4buZIHRyb25nOiANCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNvbG9yLCBmaWxsID0gY2xhcml0eSwgeSA9IHByaWNlKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIikNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqIFThu6sgYmnhu4N1IMSR4buTIHRyw6puIGNobyB0aOG6pXkgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBj4bunYSBraW0gY8awxqFuZyB0aGVvIHThu6tuZyBtw6B1IHPhuq9jIHbDoCDEkeG7mSB0cm9uZywgduG7m2kgY8OhYyBj4buZdCDEkcaw4bujYyB44bq/cCBjaOG7k25nIGzDqm4gbmhhdS4NCg0KIyMjIDE4LiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHRydW5nIGLDrG5oIGdpw6EgdHLhu4sgY8OhYyBsb+G6oWkgY+G6r3Qga2ltIGPGsMahbmcgduG7m2kgbcOgdSBz4bqvYyANCg0KYGBge3J9DQp0Y2QgJT4lIGdyb3VwX2J5KGN1dCxjb2xvcikgJT4lIHN1bW1hcmlzZShtID0gbWVhbihwcmljZSkpICU+JSBnZ3Bsb3QoYWVzKHggPSBjdXQseSA9IG0sIGZpbGwgPSBjb2xvcikpICsgZ2VvbV9jb2wocG9zaXRpb24gPSAnZG9kZ2UnKSArIGxhYnMoeCA9ICdMb+G6oWknLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KiogDQoNCiMjIyAxOS4gQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiB0cnVuZyBiw6xuaCBnacOhIGtpbSBjxrDGoW5nIHRoZW8gbcOgdSBz4bqvYyANCg0KYGBge3J9DQpkaWFtb25kcyAlPiUNCiAgZ3JvdXBfYnkoY29sb3IpICU+JQ0KICBzdW1tYXJpc2UobWVhbl9wcmljZSA9IG1lYW4ocHJpY2UpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY29sb3IsIHkgPSBtZWFuX3ByaWNlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICB4bGFiKCJDb2xvciIpICsNCiAgeWxhYigiUHJpY2UiKSArDQogIGdndGl0bGUoIkdpw6Ega2ltIGPGsMahbmcgdGhlbyBtw6B1IHPhuq9jIikNCmBgYA0KDQojIyMgMjAuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gdOG7tyBs4buHIGtpbSBjxrDGoW5nIHRoZW8gxJHhu5kgdHJvbmcgc3Xhu5F0IA0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JQ0KICBjb3VudChjbGFyaXR5KSAlPiUNCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC8gc3VtKG4pKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY2xhcml0eSwgeSA9IHByb3BvcnRpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIHhsYWIoIkNsYXJpdHkiKSArDQogIHlsYWIoIlByb3BvcnRpb24iKSArDQogIGdndGl0bGUoIlThu7cgbOG7hyBraW0gY8awxqFuZyB0aGVvIMSR4buZIHRyb25nIHN14buRdCIpDQpgYGANCg0KIyMjIDIxLiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHBow6JuIHBo4buRaSBrw61jaCB0aMaw4bubYyBjYXJhdCBj4bunYSBraW0gY8awxqFuZw0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjYXJhdCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjUpICsNCiAgeGxhYigiQ2FyYXQiKSArDQogIHlsYWIoIkZyZXF1ZW5jeSIpICsNCiAgZ2d0aXRsZSgiUGjDom4gcGjhu5FpIGvDrWNoIHRoxrDhu5tjIGNhcmF0IGPhu6dhIGtpbSBjxrDGoW5nIikNCmBgYA0KDQojIyMgMjIuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gVOG6p24gc3XhuqV0IGPDoWMgbG/huqFpIGtpbSBjxrDGoW5nIHRoZW8gZ2nDoSB0cuG7iw0KDQpgYGB7cn0NCnRjZCAlPiUgZ2dwbG90KGFlcyh4ID0gY3V0LCB5ID0gcHJpY2UsIGZpbGwgPSBjbGFyaXR5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBmdW4ueSA9ICJtZWFuIiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGZhY2V0X3dyYXAofmNvbG9yKSsNCiAgbGFicyh0aXRsZSA9ICJU4bqnbiBzdeG6pXQgY8OhYyBsb+G6oWkga2ltIGPGsMahbmcgdGhlbyBnacOhIHRy4buLIiwgeCA9ICJMb+G6oWkiLCB5ID0gIkdpw6EgdHLhu4siKQ0KYGBgDQoNCiMjIyAyMy4gQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiB0cnVuZyBiw6xuaCBnacOhIGtpbSBjxrDGoW5nIHRoZW8ga2nhu4N1IGPhuq90DQoNCmBgYHtyfQ0KZGlhbW9uZHMgJT4lDQogIGdyb3VwX2J5KGN1dCkgJT4lDQogIHN1bW1hcmlzZShtZWFuX3ByaWNlID0gbWVhbihwcmljZSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjdXQsIHkgPSBtZWFuX3ByaWNlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICB4bGFiKCJDdXQiKSArDQogIHlsYWIoIlByaWNlIikgKw0KICBnZ3RpdGxlKCJUcnVuZyBiw6xuaCBnacOhIGtpbSBjxrDGoW5nIHRoZW8ga2nhu4N1IGPhuq90IikNCmBgYA0KDQojIyMgMjQuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIG3DoHUgc+G6r2MgdsOgIMSR4buZIHRyb25nIHN14buRdA0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JQ0KICBncm91cF9ieShjb2xvciwgY2xhcml0eSkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvbG9yLCB5ID0gY291bnQsIGZpbGwgPSBjbGFyaXR5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIHhsYWIoIkNvbG9yIikgKw0KICB5bGFiKCJDb3VudCIpICsNCiAgZ2d0aXRsZSgiU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIG3DoHUgc+G6r2MgdsOgIMSR4buZIHRyb25nIHN14buRdA0KIikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQ2xhcml0eSIpDQpgYGANCg0KIyMjIDI1LiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHRydW5nIGLDrG5oIGdpw6Ega2ltIGPGsMahbmcgdGhlbyBraeG7g3UgY+G6r3QgdsOgIMSR4buZIHRyb25nIHN14buRdA0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JQ0KICBncm91cF9ieShjdXQsIGNsYXJpdHkpICU+JQ0KICBzdW1tYXJpc2UobWVhbl9wcmljZSA9IG1lYW4ocHJpY2UpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY3V0LCB5ID0gbWVhbl9wcmljZSwgZmlsbCA9IGNsYXJpdHkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgeGxhYigiQ3V0IikgKw0KICB5bGFiKCJQcmljZSIpICsNCiAgZ2d0aXRsZSgiVHJ1bmcgYsOsbmggZ2nDoSBraW0gY8awxqFuZyB0aGVvIGtp4buDdSBj4bqvdCB2w6AgxJHhu5kgdHJvbmcgc3Xhu5F0IikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQ2xhcml0eSIpDQpgYGANCg0KIyMjIDI2LiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBraeG7g3UgY+G6r3QgdsOgIMSR4buZIHRyb25nIHN14buRdA0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JQ0KICBncm91cF9ieShjdXQsIGNsYXJpdHkpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjdXQsIHkgPSBjb3VudCwgZmlsbCA9IGNsYXJpdHkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgeGxhYigiQ3V0IikgKw0KICB5bGFiKCJDb3VudCIpICsNCiAgZ2d0aXRsZSgiU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGtp4buDdSBj4bqvdCB2w6AgxJHhu5kgdHJvbmcgc3Xhu5F0IikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQ2xhcml0eSIpDQpgYGANCg0KIyMjIDI3LiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHRydW5nIGLDrG5oIGdpw6Ega2ltIGPGsMahbmcgdGhlbyBtw6B1IHPhuq9jLCBraeG7g3UgY+G6r3QgdsOgIMSR4buZIHRyb25nIHN14buRdA0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JQ0KICBncm91cF9ieShjb2xvciwgY3V0LCBjbGFyaXR5KSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fcHJpY2UgPSBtZWFuKHByaWNlKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvbG9yLCB5ID0gbWVhbl9wcmljZSwgZmlsbCA9IGludGVyYWN0aW9uKGN1dCwgY2xhcml0eSkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgeGxhYigiQ29sb3IiKSArDQogIHlsYWIoIkF2ZXJhZ2UgUHJpY2UiKSArDQogIGdndGl0bGUoIlRydW5nIGLDrG5oIGdpw6Ega2ltIGPGsMahbmcgdGhlbyBtw6B1IHPhuq9jLCBraeG7g3UgY+G6r3QgdsOgIMSR4buZIHRyb25nIHN14buRdCIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIkN1dCAmIENsYXJpdHkiKQ0KYGBgDQoNCiMjIyAyOC4gQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8gbcOgdSBz4bqvYywga2nhu4N1IGPhuq90IHbDoCDEkeG7mSB0cm9uZyBzdeG7kXQNCg0KYGBge3J9DQpkaWFtb25kcyAlPiUNCiAgZ3JvdXBfYnkoY29sb3IsIGN1dCwgY2xhcml0eSkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGNvbG9yLCB5ID0gY291bnQsIGZpbGwgPSBpbnRlcmFjdGlvbihjdXQsIGNsYXJpdHkpKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIHhsYWIoIkNvbG9yIikgKw0KICB5bGFiKCJDb3VudCIpICsNCiAgZ2d0aXRsZSgiU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIG3DoHUgc+G6r2MsIGtp4buDdSBj4bqvdCB2w6AgxJHhu5kgdHJvbmcgc3Xhu5F0IikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQ3V0ICYgQ2xhcml0eSIpDQpgYGANCg0KIyMjIDI5LiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHRydW5nIGLDrG5oIGdpw6EgdHLhu4sgY+G7p2EgY8OhYyBsb+G6oWkgY+G6r3Qga2ltIGPGsMahbmcgduG7m2kgbcOgdSBz4bqvYyB2w6AgxJHhu5kgdHJvbmcgc3Xhu5F0DQogDQpgYGB7cn0NCnRjZCAlPiVncm91cF9ieShjdXQsIGNvbG9yLCBjbGFyaXR5KSAlPiVzdW1tYXJpc2UobWVhbl9wcmljZSA9IG1lYW4ocHJpY2UpKSAlPiUgYXJyYW5nZShkZXNjKG1lYW5fcHJpY2UpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY3V0LCB5ID0gbWVhbl9wcmljZSwgZmlsbCA9IGNvbG9yLCBjb2xvciA9IGNsYXJpdHkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpKw0KICAgbGFicyh0aXRsZSA9ICJUcnVuZyBiw6xuaCBnacOhIHRy4buLIGPhu6dhIGPDoWMgbG/huqFpIGPhuq90IGtpbSBjxrDGoW5nIHbhu5tpIG3DoHUgc+G6r2MgdsOgIMSR4buZIHRyb25nIHN14buRdCIsIHggPSAiTG/huqFpIiwgeSA9ICJUcnVuZyBiw6xuaCBnacOhIHRy4buLIikNCmBgYA0KDQojIyMgMzAuIEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gxJDhu5kgc8OidSB0cnVuZyBiw6xuaCcsdGl0bGU9J0dpw6EgdHLhu4sgdHJ1bmcgYsOsbmggY+G7p2EgZGVwdGggdGhlbyBjdXQgdsOgIGNsYXJpdHkNCg0KYGBge3J9DQp0Y2QgJT4lIGdyb3VwX2J5KGN1dCwgY2xhcml0eSklPiVzdW1tYXJpc2UobT1tZWFuKGRlcHRoKSklPiVnZ3Bsb3QoYWVzKHg9Y3V0LCB5PSBtKSkrDQogIGdlb21fY29sKHBvc2l0aW9uPSdkb2RnZScpKw0KICBmYWNldF93cmFwKH5jbGFyaXR5KSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD0gcm91bmQobSkpLCB2anVzdD0yLCBjb2xvcj0nd2hpdGUnKSsgDQogIGxhYnMoeD0gJ0xv4bqhaScsIHk9ICfEkOG7mSBzw6J1IHRydW5nIGLDrG5oJyx0aXRsZT0nR2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBj4bunYSBkZXB0aCB0aGVvIGN1dCB2w6AgY2xhcml0eSAnKQ0KYGBgDQoNCg0KDQoNCg==