GIỚI THIỆU VỀ BỘ DỮ LIỆU APPLE QUALITY

Apple Quality là bộ dữ liệu chứa các về các thuộc tính khác nhau của một bộ trái cây,cụ thể hơn là táo và cung cấp thông tin chi tiết về đặc điểm của chúng. Bộ dữ liệu bao gồm các chi tiết như ID trái cây, kích thước, trọng lượng, độ ngọt, độ giòn, độ ngon ngọt, độ chín, độ chua và chất lượng.

Bộ dữ liệu được cung cấp rộng rãi bởi một công ty nông nghiệp Mỹ và đã được thu nhỏ và làm sạch để dễ sử dụng.

  • Bộ dữ liệu bao gồm các thuộc tính sau:

  • A_id: Id của trái táo.

  • Size: kích thước của trái táo.

  • Weight: trọng lượng của trái táo.

  • Sweetness: Độ ngọt của trái táo.

  • Crunchiness: độ giòn của trái táo.

  • Juiciness: độ mọng nước của trái táo.

  • Ripeness: độ chín của trái táo.

  • Acidity: độ chua của trái táo.

  • Quality: chất lượng của trái táo.

str(d)
## 'data.frame':    4001 obs. of  9 variables:
##  $ A_id       : int  0 1 2 3 4 5 6 7 8 9 ...
##  $ Size       : num  -3.97 -1.195 -0.292 -0.657 1.364 ...
##  $ Weight     : num  -2.51 -2.84 -1.35 -2.27 -1.3 ...
##  $ Sweetness  : num  5.346 3.664 -1.738 1.325 -0.385 ...
##  $ Crunchiness: num  -1.012 1.5882 -0.3426 -0.0979 -0.553 ...
##  $ Juiciness  : num  1.845 0.853 2.839 3.638 3.031 ...
##  $ Ripeness   : num  0.33 0.868 -0.038 -3.414 -1.304 ...
##  $ Acidity    : chr  "-0.491590483" "-0.722809367" "2.621636473" "0.790723217" ...
##  $ Quality    : chr  "good" "good" "bad" "good" ...

BIỂU ĐỒ

Biến “quality” là một biến phân loại (categorical) trong bộ dữ liệu “Apple Qualty” và được sử dụng để đánh giá mức độ chất lượng của trái táo.

Biến này có 2 mước đánh giá khác nhau được mô tả như sau:

table(d$Quality)
## 
##       bad good 
##    1 1996 2004
  • bad: những trái táo được đánh giá bad thì là những trái kém chất lượng có 1996 trái.

  • good: ngược lại khi trái táo đạt chất lượng đầu ra sẽ được đánh giá là good có 2004 trái.

Biểu đồ cột cho biến “quality”:

d %>% group_by(Quality) %>% summarise(n = n()) %>% 
  ggplot(aes(Quality,n)) + 
  geom_col(fill='dark blue') +
    labs(title = " BIỂU ĐỒ THỂ HIỆN NHÓM THEO QUALITY ") +
    geom_text(aes(label = n),vjust = 2, color = 'white') +
    labs(x = 'Thang đo Quality', y = 'Số lượng')

Nhận xét

Có thể thấy rằng số lương táo kém chất lượng (bad) và chất lượng(good) đồng đều nhau lần lượt là 1996 trái và 2004 trái.

Biểu đồ cột theo phân trăm của biến quality

library(dplyr)
library(scales)
library(tidyverse)
d %>% group_by(Quality) %>% summarise(n = n()) %>%
  ggplot(aes(Quality,n)) +
    geom_col(fill='dark blue') +
    geom_text(aes(label = percent(n/length(d$Quality))),vjust = 2, color = 'white') +
    labs(x = 'Loại', y = 'Số lượng')

Nhận xét

Tương tự như biểu đồ ở trên không có sự chênh lệch quá mực mà khá đồng đều của trái táo theo 2 cách đánh giá khác nhau.

Biểu đồ Histogram cho biến Crunchiness

d %>% ggplot(aes(x = Crunchiness)) +
  geom_histogram(binwidth = 0.1, fill = 'Pink', color = 'red')


Nhận xét
Trong phân khúc trên độ giòn của táo từ 0.4 đến 1.5 là đạt đỉnh vì chiếm số lượng táo có độ giòn đó hơn 100 trái cho từ độ giòn được nêu trước đó.

Biểu đồ Histogram tương quan giữa Juiciness và Quality

d %>% ggplot(aes(x = Juiciness, fill = Quality)) +
  geom_histogram(binwidth = 0.5)


Nhận xét
Nơn 400 trái .
Trong khi ngược lại số lượng táo chất lượng có độ mọng nước từ 1.6 đến 2 thì đạt đỉnh hơn 200 trái.

Biểu đồ Histogram tương quan giữa Sweetness và Quality

d %>% ggplot(aes(x = Sweetness)) +
  geom_histogram(binwidth = 0.5, fill = 'pink', color = 'red') +
  facet_wrap(~Quality)


Nhận xét
Ta có 2 biểu đồ chia làm hai : táo kém chất lượng và táo chất lượng.
Táo kém chất lượng nhưng có độ ngọt từ 1 đến 1.5 thì chiếm rất nhiều hơn 260 trái trong khi táo chất lượng có độ ngọt từ 0.6 đến 1 chiếm đa số gần 250 trái.

Biểu đồ density của biến Weight

d %>% ggplot(aes(x = Weight)) +
  geom_density(fill = 'dark blue')


Nhận xét
Trong phân khúc mật độ từ 0.2 đến 0.27 có sự biến động khá lớn khi ta thấy được đỉnh nhon của biến Weight.

Biểu đồ density của biến Size

d %>% ggplot(aes(x = Size, fill = Quality)) +
  geom_density()

Biểu đồ density của biến Juiciness

d %>% ggplot(aes(x = Juiciness)) +
  geom_density(fill = 'dark blue') +
  facet_wrap(~Quality)

Biểu đồ cột của biến QUality

d %>% group_by(Quality) %>% summarise(n = n()) %>%
  ggplot(aes(x = '', y = n,fill = Quality)) +
    geom_col() +
    geom_text(aes(label = n),position = position_stack(vjust = 1))


Nhận xét
Biểu đồ cho thấy sô lượng của táo good và táo bad dưới dạng trồng lên nhau.

Biểu đồ tròn biến Quality

d %>% group_by(Quality) %>% summarise(n = n()) %>%
  ggplot(aes(x = '', y = n,fill = Quality)) +
    geom_col() +
    coord_polar('y')


Nhận xét
BIểu đồ tròn của biến QUality cho thấy sô lượng xêm xêm nhau của hai loại táo good và bad.

Biểu đồ phân tán của biến Weight và Juiciness

d %>% ggplot(aes(x = Weight, y = Juiciness)) +
  geom_point(color = 'red') +
  geom_smooth(method = 'lm', color = 'dark blue')


Nhận xét
Các điểm trên biểu đồ màu đỏ và biểu thị các cặp giá trị (Weight, Juiciness) trong tập dữ liệu và có thể thấy rằng các cặp giá trị từ -2 đến 2 tập trung nhiều điểm đỏ cũng là chiếm nhiều số lượng táo.
đường thẳng màu xanh cho thấy xu hướng chung của nó trong trường hợp này là giảm ta có thể lí giải rằng trọng lượng táo càng lớn thì độ mọng nước càng giảm.

Biểu đồ phân tán của giữa biến Crunchiness , Sweetness và Quality

d %>% ggplot(aes(x = Crunchiness, y = Sweetness, alpha = Quality)) +
  geom_point()


Nhận xét
Biểu đồ này có hai đối tuongj của Quality và được quy định theo màu sắc khác nhau . Tương tự như ở trên có thể thấy rằng các cặp giá trị từ -2 đến 2 tập trung nhiều điểm đỏ cũng là chiếm nhiều số lượng táo bất kể loại nào.

Biểu đồ phân tán của biến Weight và Quality

d %>% ggplot(aes(x = Ripeness, y = Weight)) +
  geom_point(color = 'dark blue') +
  geom_smooth(method = 'lm', color = 'pink') +
  facet_wrap(~Quality)


Nhận xét
Như biểu đồ 12 lúc này được chia thành hai biểu đồ nhỏ tượng trưng cho 2 loại táo bad và good . Nhìn chung chúng có cùng xu hướng giảm chức tỏ trọng lượng càng ít đi thì trái đó chín mùi hơn.

Biểu đồ tròn của biến Quality

d %>% group_by(Quality) %>% summarise(n = n()) %>%
  ggplot(aes(x = '', y = n,fill = Quality)) +
    geom_col(color = 'black') +
    coord_polar('y') +
    geom_text(aes(x = 1.0, label = n),position = position_stack(vjust = .5)) +
    theme_void()


Nhận xét
Biểu đò này cho thấy rõ hơn sô lượng mà cả hai loại táo bad và good sở hữu lần lượt là 1996 trái và 2004 trái trên mặt phẳng tròn và màu sắc được quy định.

Biểu đồ Histogram củ biến Weight và Quality

d %>% ggplot(aes(x = Ripeness)) +
  geom_histogram(data = d %>% filter(Quality == 'bad'), binwidth = 1, fill = 'darkblue') +
  geom_histogram(data = d %>% filter(Quality == 'good'), binwidth = 1, fill = 'brown')


Nhận xét
Nhìn trên biểu đò ta có thể thấy được rằng sô táo chất lượng có độ chín từ 0.1 đến 1 chiếm nhiều nhất là hơn 400 trái .
Trong khi ngược lại số lượng táo kém chất lượng đã bị che bởi số táo chất lượng có thể tháy trên biểu đồ nên ta không thể kết luận chính xác được.

Biểu đồ nhóm thể hiện theo Weight

dweight <- d %>% mutate(Weight = cut(Weight,5, label = c('too light', 'light','Fine','Heavy','Extreme Heavy')))


ta chia trọng lượng thành 5 nhóm : too light , light, Fine, Heavy và Extreme Heavy.

dweight %>% group_by(Weight) %>% summarise(n = n()) %>%
  ggplot(aes(Weight,n)) +
    geom_col(fill='dark blue') +
    labs(title = " Biểu đồ thể hiện nhóm theo Weight ") +
    geom_text(aes(label = n),vjust = 0, color = 'brown') +
    labs(x = 'Trọng Lượng', y = 'Số lượng')


Nhận xét Ta nhận được kết quả như trên cụ thể hơn là số lượng táo mà các nhóm sở hữu. Nhiều nhất là Fine 2369 trái và ít nhất là Extreme Heavy 27 trái.

Biểu đồ tròn biến Weight

dweight <- d %>% mutate(Weight = cut(Weight,5, label = c('too light', 'light','Fine','Heavy','Extreme Heavy')))

dweight %>% group_by(Weight) %>% summarise(n = n()) %>%
  ggplot(aes(x = '', y = n,fill = Weight)) +
    geom_col(color = 'black') +
    coord_polar('y') +
    geom_text(aes(x = 1.3, label = n),position = position_stack(vjust = .5)) +
    theme_void()


Nhận xét
Thay vì biểu đồ cột như biểu đồ 16 thì các đối tượng của biến Weight được biểu diễn trên biểu đồ tròn với giá trị tương ứng.

LS0tDQp0aXRsZTogIk5oaeG7h20gVuG7pSA1Ig0KYXV0aG9yOiAiVm9IaWV1Ig0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUg6JU06JVMsICVkIC0gJW0gLSAlWScpYCINCm91dHB1dDogDQogaHRtbF9kb2N1bWVudDogDQogICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgdG9jOiB0cnVlDQotLS0NCmBgYHtyIHNldHVwLGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQ0KZCA8LSByZWFkLmNzdigiQzovVXNlcnMvSFAvRG9jdW1lbnRzL2FwcGxlX3F1YWxpdHkuY3N2IiAsIGhlYWRlciA9IFQgKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNraW1yKQ0Kc2tpbShkKQ0KYGBgDQoNCiMjIEdJ4buaSSBUSEnhu4ZVIFbhu4AgQuG7mCBE4buuIExJ4buGVSBBUFBMRSBRVUFMSVRZDQoNCkFwcGxlIFF1YWxpdHkgbMOgIGLhu5kgZOG7ryBsaeG7h3UgY2jhu6lhIGPDoWMgduG7gSBjw6FjIHRodeG7mWMgdMOtbmgga2jDoWMgbmhhdSBj4bunYSBt4buZdCBi4buZIHRyw6FpIGPDonksY+G7pSB0aOG7gyBoxqFuIGzDoCB0w6FvIHbDoCBjdW5nIGPhuqVwIHRow7RuZyB0aW4gY2hpIHRp4bq/dCB24buBIMSR4bq3YyDEkWnhu4NtIGPhu6dhIGNow7puZy4gQuG7mSBk4buvIGxp4buHdSBiYW8gZ+G7k20gY8OhYyBjaGkgdGnhur90IG5oxrAgSUQgdHLDoWkgY8OieSwga8OtY2ggdGjGsOG7m2MsIHRy4buNbmcgbMaw4bujbmcsIMSR4buZIG5n4buNdCwgxJHhu5kgZ2nDsm4sIMSR4buZIG5nb24gbmfhu410LCDEkeG7mSBjaMOtbiwgxJHhu5kgY2h1YSB2w6AgY2jhuqV0IGzGsOG7o25nLg0KDQpC4buZIGThu68gbGnhu4d1IMSRxrDhu6NjIGN1bmcgY+G6pXAgcuG7mW5nIHLDo2kgYuG7n2kgbeG7mXQgY8O0bmcgdHkgbsO0bmcgbmdoaeG7h3AgTeG7uSB2w6AgxJHDoyDEkcaw4bujYyB0aHUgbmjhu48gdsOgIGzDoG0gc+G6oWNoIMSR4buDIGThu4Ugc+G7rSBk4bulbmcuDQoNCiogQuG7mSBk4buvIGxp4buHdSBiYW8gZ+G7k20gY8OhYyB0aHXhu5ljIHTDrW5oIHNhdToNCg0KLSBBX2lkOiBJZCBj4bunYSB0csOhaSB0w6FvLg0KLSBTaXplOiBrw61jaCB0aMaw4bubYyBj4bunYSB0csOhaSB0w6FvLg0KLSBXZWlnaHQ6IHRy4buNbmcgbMaw4bujbmcgY+G7p2EgdHLDoWkgdMOhby4NCi0gU3dlZXRuZXNzOiDEkOG7mSBuZ+G7jXQgY+G7p2EgdHLDoWkgdMOhby4NCi0gQ3J1bmNoaW5lc3M6IMSR4buZIGdpw7JuIGPhu6dhIHRyw6FpIHTDoW8uDQotIEp1aWNpbmVzczogxJHhu5kgbeG7jW5nIG7GsOG7m2MgY+G7p2EgdHLDoWkgdMOhby4NCi0gUmlwZW5lc3M6IMSR4buZIGNow61uIGPhu6dhIHRyw6FpIHTDoW8uDQotIEFjaWRpdHk6IMSR4buZIGNodWEgY+G7p2EgdHLDoWkgdMOhby4NCi0gUXVhbGl0eTogY2jhuqV0IGzGsOG7o25nIGPhu6dhIHRyw6FpIHTDoW8uDQoNCmBgYHtyfQ0Kc3RyKGQpDQpgYGANCg0KIyMgQknhu4JVIMSQ4buSDQoNCkJp4bq/biDigJxxdWFsaXR54oCdIGzDoCBt4buZdCBiaeG6v24gcGjDom4gbG/huqFpIChjYXRlZ29yaWNhbCkgdHJvbmcgYuG7mSBk4buvIGxp4buHdSDigJxBcHBsZSBRdWFsdHnigJ0gdsOgIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIMSRw6FuaCBnacOhIG3hu6ljIMSR4buZIGNo4bqldCBsxrDhu6NuZyBj4bunYSB0csOhaSB0w6FvLg0KDQpCaeG6v24gbsOgeSBjw7MgMiBtxrDhu5tjIMSRw6FuaCBnacOhIGtow6FjIG5oYXUgxJHGsOG7o2MgbcO0IHThuqMgbmjGsCBzYXU6DQpgYGB7cn0NCnRhYmxlKGQkUXVhbGl0eSkNCmBgYA0KDQoqIGJhZDogbmjhu69uZyB0csOhaSB0w6FvIMSRxrDhu6NjIMSRw6FuaCBnacOhIGJhZCB0aMOsIGzDoCBuaOG7r25nIHRyw6FpIGvDqW0gY2jhuqV0IGzGsOG7o25nIGPDsyAxOTk2IHRyw6FpLg0KDQoqIGdvb2Q6IG5nxrDhu6NjIGzhuqFpIGtoaSB0csOhaSB0w6FvIMSR4bqhdCBjaOG6pXQgbMaw4bujbmcgxJHhuqd1IHJhIHPhur0gxJHGsOG7o2MgxJHDoW5oIGdpw6EgbMOgIGdvb2QgY8OzIDIwMDQgdHLDoWkuDQoNCiMjIEJp4buDdSDEkeG7kyBj4buZdCBjaG8gYmnhur9uICJxdWFsaXR5IjoNCmBgYHtyfQ0KZCAlPiUgZ3JvdXBfYnkoUXVhbGl0eSkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUgDQogIGdncGxvdChhZXMoUXVhbGl0eSxuKSkgKyANCiAgZ2VvbV9jb2woZmlsbD0nZGFyayBibHVlJykgKw0KICAgIGxhYnModGl0bGUgPSAiIEJJ4buCVSDEkOG7kiBUSOG7giBISeG7hk4gTkjDk00gVEhFTyBRVUFMSVRZICIpICsNCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksdmp1c3QgPSAyLCBjb2xvciA9ICd3aGl0ZScpICsNCiAgICBsYWJzKHggPSAnVGhhbmcgxJFvIFF1YWxpdHknLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCioqKk5o4bqtbiB4w6l0KioqDQoNCkPDsyB0aOG7gyB0aOG6pXkgcuG6sW5nIHPhu5EgbMawxqFuZyB0w6FvIGvDqW0gY2jhuqV0IGzGsOG7o25nIChiYWQpIHbDoCBjaOG6pXQgbMaw4bujbmcoZ29vZCkgxJHhu5NuZyDEkeG7gXUgbmhhdSBs4bqnbiBsxrDhu6N0IGzDoCAxOTk2IHRyw6FpIHbDoCAyMDA0IHRyw6FpLg0KDQojIyAqKkJp4buDdSDEkeG7kyBj4buZdCB0aGVvIHBow6JuIHRyxINtIGPhu6dhIGJp4bq/biBxdWFsaXR5KioNCmBgYHtyfQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmQgJT4lIGdyb3VwX2J5KFF1YWxpdHkpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoUXVhbGl0eSxuKSkgKw0KICAgIGdlb21fY29sKGZpbGw9J2RhcmsgYmx1ZScpICsNCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudChuL2xlbmd0aChkJFF1YWxpdHkpKSksdmp1c3QgPSAyLCBjb2xvciA9ICd3aGl0ZScpICsNCiAgICBsYWJzKHggPSAnTG/huqFpJywgeSA9ICdT4buRIGzGsOG7o25nJykNCmBgYA0KDQoqKipOaOG6rW4geMOpdCoqKg0KDQpUxrDGoW5nIHThu7EgbmjGsCBiaeG7g3UgxJHhu5Mg4bufIHRyw6puIGtow7RuZyBjw7Mgc+G7sSBjaMOqbmggbOG7h2NoIHF1w6EgbeG7sWMgbcOgIGtow6EgxJHhu5NuZyDEkeG7gXUgY+G7p2EgdHLDoWkgdMOhbyB0aGVvIDIgY8OhY2ggxJHDoW5oIGdpw6Ega2jDoWMgbmhhdS4gDQoNCiMjIEJp4buDdSDEkeG7kyBIaXN0b2dyYW0gY2hvIGJp4bq/biBDcnVuY2hpbmVzcw0KYGBge3J9DQoNCmQgJT4lIGdncGxvdChhZXMoeCA9IENydW5jaGluZXNzKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMSwgZmlsbCA9ICdQaW5rJywgY29sb3IgPSAncmVkJykNCmBgYA0KPGJyPg0KKioqTmjhuq1uIHjDqXQqKioNCjxicj4NClRyb25nIHBow6JuIGtow7pjIHRyw6puIMSR4buZIGdpw7JuIGPhu6dhIHTDoW8gdOG7qyAwLjQgxJHhur9uIDEuNSBsw6AgxJHhuqF0IMSR4buJbmggdsOsIGNoaeG6v20gc+G7kSBsxrDhu6NuZyB0w6FvIGPDsyDEkeG7mSBnacOybiDEkcOzIGjGoW4gMTAwIHRyw6FpIGNobyB04burIMSR4buZIGdpw7JuIMSRxrDhu6NjIG7DqnUgdHLGsOG7m2MgxJHDsy4NCg0KIyMgKipCaeG7g3UgxJHhu5MgSGlzdG9ncmFtIHTGsMahbmcgcXVhbiBnaeG7r2EgSnVpY2luZXNzIHbDoCBRdWFsaXR5KioNCmBgYHtyfQ0KDQpkICU+JSBnZ3Bsb3QoYWVzKHggPSBKdWljaW5lc3MsIGZpbGwgPSBRdWFsaXR5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuNSkNCmBgYA0KPGJyPg0KKioqTmjhuq1uIHjDqXQqKioNCjxicj4NCk7GoW4gNDAwIHRyw6FpIC4NCjxicj4NClRyb25nIGtoaSBuZ8aw4bujYyBs4bqhaSBz4buRIGzGsOG7o25nIHTDoW8gY2jhuqV0IGzGsOG7o25nIGPDsyDEkeG7mSBt4buNbmcgbsaw4bubYyB04burIDEuNiDEkeG6v24gMiB0aMOsIMSR4bqhdCDEkeG7iW5oIGjGoW4gMjAwIHRyw6FpLg0KDQojIyAqKkJp4buDdSDEkeG7kyBIaXN0b2dyYW0gdMawxqFuZyBxdWFuIGdp4buvYSBTd2VldG5lc3MgdsOgIFF1YWxpdHkqKg0KYGBge3J9DQoNCmQgJT4lIGdncGxvdChhZXMoeCA9IFN3ZWV0bmVzcykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjUsIGZpbGwgPSAncGluaycsIGNvbG9yID0gJ3JlZCcpICsNCiAgZmFjZXRfd3JhcCh+UXVhbGl0eSkNCmBgYA0KPGJyPg0KKioqTmjhuq1uIHjDqXQqKioNCjxicj4NClRhIGPDsyAyIGJp4buDdSDEkeG7kyBjaGlhIGzDoG0gaGFpIDogdMOhbyBrw6ltIGNo4bqldCBsxrDhu6NuZyB2w6AgdMOhbyBjaOG6pXQgbMaw4bujbmcuDQo8YnI+DQpUw6FvIGvDqW0gY2jhuqV0IGzGsOG7o25nIG5oxrBuZyBjw7MgxJHhu5kgbmfhu410IHThu6sgMSDEkeG6v24gMS41IHRow6wgY2hp4bq/bSBy4bqldCBuaGnhu4F1IGjGoW4gMjYwIHRyw6FpIHRyb25nIGtoaSB0w6FvIGNo4bqldCBsxrDhu6NuZyBjw7MgxJHhu5kgbmfhu410IHThu6sgMC42IMSR4bq/biAxIGNoaeG6v20gxJFhIHPhu5EgZ+G6p24gMjUwIHRyw6FpLg0KDQojIyAqKkJp4buDdSDEkeG7kyBkZW5zaXR5IGPhu6dhIGJp4bq/biBXZWlnaHQqKg0KYGBge3J9DQoNCmQgJT4lIGdncGxvdChhZXMoeCA9IFdlaWdodCkpICsNCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAnZGFyayBibHVlJykNCmBgYA0KPGJyPg0KKioqTmjhuq1uIHjDqXQqKioNCjxicj4NClRyb25nIHBow6JuIGtow7pjIG3huq10IMSR4buZIHThu6sgMC4yIMSR4bq/biAwLjI3IGPDsyBz4buxIGJp4bq/biDEkeG7mW5nIGtow6EgbOG7m24ga2hpIHRhIHRo4bqleSDEkcaw4bujYyDEkeG7iW5oIG5ob24gY+G7p2EgYmnhur9uIFdlaWdodC4NCg0KIyMgKipCaeG7g3UgxJHhu5MgZGVuc2l0eSBj4bunYSBiaeG6v24gU2l6ZSoqDQpgYGB7cn0NCg0KZCAlPiUgZ2dwbG90KGFlcyh4ID0gU2l6ZSwgZmlsbCA9IFF1YWxpdHkpKSArDQogIGdlb21fZGVuc2l0eSgpDQpgYGANCg0KIyMgKipCaeG7g3UgxJHhu5MgZGVuc2l0eSBj4bunYSBiaeG6v24gSnVpY2luZXNzKioNCmBgYHtyfQ0KDQpkICU+JSBnZ3Bsb3QoYWVzKHggPSBKdWljaW5lc3MpKSArDQogIGdlb21fZGVuc2l0eShmaWxsID0gJ2RhcmsgYmx1ZScpICsNCiAgZmFjZXRfd3JhcCh+UXVhbGl0eSkNCmBgYA0KDQojIyAqKkJp4buDdSDEkeG7kyBj4buZdCBj4bunYSBiaeG6v24gUVVhbGl0eSoqDQpgYGB7cn0NCg0KZCAlPiUgZ3JvdXBfYnkoUXVhbGl0eSkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gJycsIHkgPSBuLGZpbGwgPSBRdWFsaXR5KSkgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSxwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMSkpDQpgYGANCjxicj4NCioqKk5o4bqtbiB4w6l0KioqDQo8YnI+DQpCaeG7g3UgxJHhu5MgY2hvIHRo4bqleSBzw7QgbMaw4bujbmcgY+G7p2EgdMOhbyBnb29kIHbDoCB0w6FvIGJhZCBkxrDhu5tpIGThuqFuZyB0cuG7k25nIGzDqm4gbmhhdS4NCg0KIyMgKipCaeG7g3UgxJHhu5MgdHLDsm4gYmnhur9uIFF1YWxpdHkqKg0KYGBge3J9DQoNCmQgJT4lIGdyb3VwX2J5KFF1YWxpdHkpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9ICcnLCB5ID0gbixmaWxsID0gUXVhbGl0eSkpICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBjb29yZF9wb2xhcigneScpDQpgYGANCjxicj4NCioqKk5o4bqtbiB4w6l0KioqDQo8YnI+DQpCSeG7g3UgxJHhu5MgdHLDsm4gY+G7p2EgYmnhur9uIFFVYWxpdHkgY2hvIHRo4bqleSBzw7QgbMaw4bujbmcgeMOqbSB4w6ptIG5oYXUgY+G7p2EgaGFpIGxv4bqhaSB0w6FvIGdvb2QgdsOgIGJhZC4NCg0KIyMgKipCaeG7g3UgxJHhu5MgcGjDom4gdMOhbiBj4bunYSBiaeG6v24gV2VpZ2h0IHbDoCBKdWljaW5lc3MqKg0KYGBge3J9DQoNCg0KZCAlPiUgZ2dwbG90KGFlcyh4ID0gV2VpZ2h0LCB5ID0gSnVpY2luZXNzKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gJ3JlZCcpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgY29sb3IgPSAnZGFyayBibHVlJykNCmBgYA0KPGJyPg0KKioqTmjhuq1uIHjDqXQqKioNCjxicj4NCkPDoWMgxJFp4buDbSB0csOqbiBiaeG7g3UgxJHhu5MgbcOgdSDEkeG7jyB2w6AgYmnhu4N1IHRo4buLIGPDoWMgY+G6t3AgZ2nDoSB0cuG7iyAoV2VpZ2h0LCBKdWljaW5lc3MpIHRyb25nIHThuq1wIGThu68gbGnhu4d1IHbDoCBjw7MgdGjhu4MgdGjhuqV5IHLhurFuZyBjw6FjIGPhurdwIGdpw6EgdHLhu4sgdOG7qyAtMiDEkeG6v24gMiB04bqtcCB0cnVuZyBuaGnhu4F1IMSRaeG7g20gxJHhu48gY8WpbmcgbMOgIGNoaeG6v20gbmhp4buBdSBz4buRIGzGsOG7o25nIHTDoW8uDQo8YnI+DQrEkcaw4budbmcgdGjhurNuZyBtw6B1IHhhbmggY2hvIHRo4bqleSB4dSBoxrDhu5tuZyBjaHVuZyBj4bunYSBuw7MgdHJvbmcgdHLGsOG7nW5nIGjhu6NwIG7DoHkgbMOgIGdp4bqjbSB0YSBjw7MgdGjhu4MgbMOtIGdp4bqjaSBy4bqxbmcgdHLhu41uZyBsxrDhu6NuZyB0w6FvIGPDoG5nIGzhu5tuIHRow6wgxJHhu5kgbeG7jW5nIG7GsOG7m2MgY8OgbmcgZ2nhuqNtLg0KDQojIyAqKkJp4buDdSDEkeG7kyBwaMOibiB0w6FuIGPhu6dhIGdp4buvYSBiaeG6v24gQ3J1bmNoaW5lc3MgLCBTd2VldG5lc3MgdsOgIFF1YWxpdHkqKg0KYGBge3J9DQoNCmQgJT4lIGdncGxvdChhZXMoeCA9IENydW5jaGluZXNzLCB5ID0gU3dlZXRuZXNzLCBhbHBoYSA9IFF1YWxpdHkpKSArDQogIGdlb21fcG9pbnQoKQ0KYGBgDQo8YnI+DQoqKipOaOG6rW4geMOpdCoqKg0KPGJyPg0KQmnhu4N1IMSR4buTIG7DoHkgY8OzIGhhaSDEkeG7kWkgdHVvbmdqIGPhu6dhIFF1YWxpdHkgdsOgIMSRxrDhu6NjIHF1eSDEkeG7i25oIHRoZW8gbcOgdSBz4bqvYyBraMOhYyBuaGF1IC4gVMawxqFuZyB04buxIG5oxrAg4bufIHRyw6puIGPDsyB0aOG7gyB0aOG6pXkgcuG6sW5nIGPDoWMgY+G6t3AgZ2nDoSB0cuG7iyB04burIC0yIMSR4bq/biAyIHThuq1wIHRydW5nIG5oaeG7gXUgxJFp4buDbSDEkeG7jyBjxaluZyBsw6AgY2hp4bq/bSBuaGnhu4F1IHPhu5EgbMaw4bujbmcgdMOhbyBi4bqldCBr4buDIGxv4bqhaSBuw6BvLg0KDQojIyAqKkJp4buDdSDEkeG7kyBwaMOibiB0w6FuIGPhu6dhIGJp4bq/biBXZWlnaHQgdsOgIFF1YWxpdHkqKg0KYGBge3J9DQoNCmQgJT4lIGdncGxvdChhZXMoeCA9IFJpcGVuZXNzLCB5ID0gV2VpZ2h0KSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gJ2RhcmsgYmx1ZScpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgY29sb3IgPSAncGluaycpICsNCiAgZmFjZXRfd3JhcCh+UXVhbGl0eSkNCmBgYA0KPGJyPg0KKioqTmjhuq1uIHjDqXQqKioNCjxicj4NCk5oxrAgYmnhu4N1IMSR4buTIDEyIGzDumMgbsOgeSDEkcaw4bujYyBjaGlhIHRow6BuaCBoYWkgYmnhu4N1IMSR4buTIG5o4buPIHTGsOG7o25nIHRyxrBuZyBjaG8gMiBsb+G6oWkgdMOhbyBiYWQgdsOgIGdvb2QgLiBOaMOsbiBjaHVuZyBjaMO6bmcgY8OzIGPDuW5nIHh1IGjGsOG7m25nIGdp4bqjbSBjaOG7qWMgdOG7jyB0cuG7jW5nIGzGsOG7o25nIGPDoG5nIMOtdCDEkWkgdGjDrCB0csOhaSDEkcOzIGNow61uIG3DuWkgaMahbi4NCg0KIyMgKipCaeG7g3UgxJHhu5MgdHLDsm4gY+G7p2EgYmnhur9uIFF1YWxpdHkqKg0KYGBge3J9DQoNCmQgJT4lIGdyb3VwX2J5KFF1YWxpdHkpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9ICcnLCB5ID0gbixmaWxsID0gUXVhbGl0eSkpICsNCiAgICBnZW9tX2NvbChjb2xvciA9ICdibGFjaycpICsNCiAgICBjb29yZF9wb2xhcigneScpICsNCiAgICBnZW9tX3RleHQoYWVzKHggPSAxLjAsIGxhYmVsID0gbikscG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IC41KSkgKw0KICAgIHRoZW1lX3ZvaWQoKQ0KYGBgDQo8YnI+DQoqKipOaOG6rW4geMOpdCoqKg0KPGJyPg0KQmnhu4N1IMSRw7IgbsOgeSBjaG8gdGjhuqV5IHLDtSBoxqFuIHPDtCBsxrDhu6NuZyBtw6AgY+G6oyBoYWkgbG/huqFpIHTDoW8gYmFkIHbDoCBnb29kIHPhu58gaOG7r3UgbOG6p24gbMaw4bujdCBsw6AgMTk5NiB0csOhaSB2w6AgMjAwNCB0csOhaSB0csOqbiBt4bq3dCBwaOG6s25nIHRyw7JuIHbDoCBtw6B1IHPhuq9jIMSRxrDhu6NjIHF1eSDEkeG7i25oLg0KDQojIyAqKkJp4buDdSDEkeG7kyBIaXN0b2dyYW0gY+G7pyBiaeG6v24gV2VpZ2h0IHbDoCBRdWFsaXR5KioNCmBgYHtyfQ0KZCAlPiUgZ2dwbG90KGFlcyh4ID0gUmlwZW5lc3MpKSArDQogIGdlb21faGlzdG9ncmFtKGRhdGEgPSBkICU+JSBmaWx0ZXIoUXVhbGl0eSA9PSAnYmFkJyksIGJpbndpZHRoID0gMSwgZmlsbCA9ICdkYXJrYmx1ZScpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZGF0YSA9IGQgJT4lIGZpbHRlcihRdWFsaXR5ID09ICdnb29kJyksIGJpbndpZHRoID0gMSwgZmlsbCA9ICdicm93bicpDQpgYGANCjxicj4NCioqKk5o4bqtbiB4w6l0KioqDQo8YnI+DQpOaMOsbiB0csOqbiBiaeG7g3UgxJHDsiB0YSBjw7MgdGjhu4MgdGjhuqV5IMSRxrDhu6NjIHLhurFuZyBzw7QgdMOhbyAgY2jhuqV0IGzGsOG7o25nIGPDsyDEkeG7mSBjaMOtbiB04burIDAuMSDEkeG6v24gMSBjaGnhur9tIG5oaeG7gXUgbmjhuqV0IGzDoCBoxqFuIDQwMCB0csOhaSAuDQo8YnI+DQpUcm9uZyBraGkgbmfGsOG7o2MgbOG6oWkgc+G7kSBsxrDhu6NuZyB0w6FvIGvDqW0gY2jhuqV0IGzGsOG7o25nIMSRw6MgYuG7iyBjaGUgYuG7n2kgc+G7kSB0w6FvIGNo4bqldCBsxrDhu6NuZyBjw7MgdGjhu4MgdGjDoXkgdHLDqm4gYmnhu4N1IMSR4buTIG7Dqm4gdGEga2jDtG5nIHRo4buDIGvhur90IGx14bqtbiBjaMOtbmggeMOhYyDEkcaw4bujYy4NCg0KIyMgKipCaeG7g3UgxJHhu5MgbmjDs20gdGjhu4MgaGnhu4duIHRoZW8gV2VpZ2h0KioNCmBgYHtyfQ0KDQpkd2VpZ2h0IDwtIGQgJT4lIG11dGF0ZShXZWlnaHQgPSBjdXQoV2VpZ2h0LDUsIGxhYmVsID0gYygndG9vIGxpZ2h0JywgJ2xpZ2h0JywnRmluZScsJ0hlYXZ5JywnRXh0cmVtZSBIZWF2eScpKSkNCg0KYGBgDQo8YnI+DQp0YSBjaGlhIHRy4buNbmcgbMaw4bujbmcgdGjDoG5oIDUgbmjDs20gOiB0b28gbGlnaHQgLCBsaWdodCwgRmluZSwgSGVhdnkgdsOgIEV4dHJlbWUgSGVhdnkuDQo8YnI+DQpgYGB7cn0NCmR3ZWlnaHQgJT4lIGdyb3VwX2J5KFdlaWdodCkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyhXZWlnaHQsbikpICsNCiAgICBnZW9tX2NvbChmaWxsPSdkYXJrIGJsdWUnKSArDQogICAgbGFicyh0aXRsZSA9ICIgQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBuaMOzbSB0aGVvIFdlaWdodCAiKSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLHZqdXN0ID0gMCwgY29sb3IgPSAnYnJvd24nKSArDQogICAgbGFicyh4ID0gJ1Ry4buNbmcgTMaw4bujbmcnLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQo8YnI+DQoqKipOaOG6rW4geMOpdCoqKg0KVGEgbmjhuq1uIMSRxrDhu6NjIGvhur90IHF14bqjIG5oxrAgdHLDqm4gY+G7pSB0aOG7gyBoxqFuIGzDoCBz4buRIGzGsOG7o25nIHTDoW8gbcOgIGPDoWMgbmjDs20gc+G7nyBo4buvdS4gTmhp4buBdSBuaOG6pXQgbMOgIEZpbmUgMjM2OSB0csOhaSB2w6Agw610IG5o4bqldCBsw6AgRXh0cmVtZSBIZWF2eSAyNyB0csOhaS4NCg0KDQojIyAqKkJp4buDdSDEkeG7kyB0csOybiBiaeG6v24gV2VpZ2h0KioNCmBgYHtyfQ0KZHdlaWdodCA8LSBkICU+JSBtdXRhdGUoV2VpZ2h0ID0gY3V0KFdlaWdodCw1LCBsYWJlbCA9IGMoJ3RvbyBsaWdodCcsICdsaWdodCcsJ0ZpbmUnLCdIZWF2eScsJ0V4dHJlbWUgSGVhdnknKSkpDQoNCmR3ZWlnaHQgJT4lIGdyb3VwX2J5KFdlaWdodCkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gJycsIHkgPSBuLGZpbGwgPSBXZWlnaHQpKSArDQogICAgZ2VvbV9jb2woY29sb3IgPSAnYmxhY2snKSArDQogICAgY29vcmRfcG9sYXIoJ3knKSArDQogICAgZ2VvbV90ZXh0KGFlcyh4ID0gMS4zLCBsYWJlbCA9IG4pLHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAuNSkpICsNCiAgICB0aGVtZV92b2lkKCkNCmBgYA0KPGJyPg0KKioqTmjhuq1uIHjDqXQqKioNCjxicj4NClRoYXkgdsOsIGJp4buDdSDEkeG7kyBj4buZdCBuaMawIGJp4buDdSDEkeG7kyAxNiB0aMOsIGPDoWMgxJHhu5FpIHTGsOG7o25nIGPhu6dhIGJp4bq/biBXZWlnaHQgxJHGsOG7o2MgYmnhu4N1IGRp4buFbiB0csOqbiBiaeG7g3UgxJHhu5MgdHLDsm4gduG7m2kgZ2nDoSB0cuG7iyB0xrDGoW5nIOG7qW5nLg0KDQoNCg0KDQoNCg==