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==