Introduction

Tôi thực hiện thử nghiệm với bộ dữ liệu Video Game Sales được thống kê từ các năm từ 1980 đến 2020 chứa các số liệu bán hàng khác nhau trên toàn cầu, JP, EU, NA.

Phần trình bày dưới đây của tôi vẫn còn nhiều thiếu xót, vì vậy tôi sẽ tiếp tục nghiên cứu và cập nhật trong thời gian tới.

Number of Games in each Platforms

  1. Biểu đồ về số lượng trò chơi của mỗi nền tảng.

Thách thức của tệp dữ liệu này không có tổng doanh số cho từng nhà sản xuất hoặc thể loại hoặc nền tảng. Do đó cần tính tổng doanh số theo cách thủ công, tôi sẽ tổng hợp 4 doanh số bán hàng khác nhau tương ứng và phân loại theo nhà sản xuất, thể loại hoặc nền tảng. Từ biểu đồ chúng ta có thể suy ra cả DS và PS2 đều rất gần nhau. DS có tổng cộng 2163 trò chơi và PS2 có tổng cộng 2161 trò chơi. Mặt khác, PCFX có số lượng trò chơi thấp nhất (1 trò chơi).

# Load package and data: 
library(tidyverse)

# games <- read.csv("vgsales1.csv", header = T)

games <- read_csv("D:\\R\\Data\\vgsales1.csv")

options(repr.plot.width = 16, repr.plot.height = 8)

games <- games[games$Year!='N/A',]
games$Year <- factor(games$Year)

games <- games[,2:11]

#font & color
colors <- c("Global Sales"="red", "North America Sales"="blue", "Europe Sales"="green", "Japan Sales"="orange",
            "The Rest of the World"="violet")
my_font <- "Roboto"

#--------------------------------------------
# Number of Games in each Platforms
#--------------------------------------------
PF <- games %>% 
  group_by(Platform) %>% count()

PF %>% ggplot(aes(x = Platform, y = n)) +
  geom_bar(stat = 'identity', fill = "#2c7bb6") +
  theme(plot.title = element_text(size = 40, face = 'bold', family = my_font)) +
  labs(x = NULL, y = NULL, 
       title = "Number of Games in each Platforms",
       caption = "Data Source: Kaggle") +
  theme_classic() +
  theme(panel.grid = element_blank())

Sum of Global Sales by Year

  1. Biểu đồ thể hiện tổng doanh số bán hàng của Global, North America, Europe, Japan, The Rest of the World từ năm 1980 - 2020. Từ hình vẽ ta có thể kết luận rằng North America là khu vực có giữ doanh số về trò chơi điện tử lớn nhất qua các năm.Vì đây là quốc gia có nền kinh tế và công nghệ phát triển, nhu cầu về những trò chơi giải trí cũng trở nên phổ biến và đạt đến đỉnh cao vào năm 2008.
#-----------------------------
#Sum of Global Sales by Year
#----------------------------

sum_of_sales <- games %>% 
  group_by(Year) %>% 
  summarise(sum_global_sales = sum(Global_Sales), sum_others_sales = sum(Other_Sales),
            sum_jb_sales = sum(JP_Sales), sum_eu_sales = sum(EU_Sales),
            sum_na_sales = sum(NA_Sales), .groups = 'drop')


sum_of_sales %>% 
  ggplot(aes(x = Year)) +
  geom_line(aes(y = sum_global_sales,group=1,color="Global Sales")) +
  geom_line(aes(y= sum_na_sales,group=1,color="North America Sales")) +
  geom_line(aes(y= sum_eu_sales,group=1,color="Europe Sales")) +
  geom_line(aes(y= sum_jb_sales,group=1,color="Japan Sales")) +
  geom_line(aes(y= sum_others_sales,group=1,color="The Rest of the World")) +
  theme(plot.title = element_text(family = my_font, size = 40, color = "grey10", face = "bold")) +
  theme(plot.caption = element_text(family = my_font, size = 12, color = "grey40", face = "italic")) +
  theme(legend.title = element_text(size = 30, face = "bold", family = my_font)) + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),legend.position="top") +
  scale_color_manual(name="Sales",values = colors)+
  theme(plot.caption = element_text(family = my_font, size = 12, color = "grey40", face = "italic")) +
  labs(x = NULL, y = NULL,
       title = "Sum of Global Sales by Year",
       caption = "Data Source: Kaggle") +
  theme_classic() +
  theme(panel.grid = element_blank())

Top 10 Games by Sales

  1. Bên cạnh đó, bộ dữ liệu chứa các trò chơi khác nhau từ nhiều năm trên nền tảng khác nhau, rất khó để hiển thị top 10 trò chơi/ nhà phát hành/ nền tảng nổi tiếng nhất mà người dùng thích chơi. Do đó, tôi sẽ vẽ biểu đồ khác nhau về 10 trò chơi hàng đầu mà người dùng thích chơi bằng cách sử dụng nền tảng khác nhau. Tiếp tục với biểu đồ về top 10 trò chơi hàng đầu trong khoảng từ năm 1980 - 2020, Wii Sport đứng đầu doanh số bán hàng, theo sau đó là Grand Theft Auto V có khoảng cách với Wii Sport là 26,82 triệu.
#-------------------------
# Top 10 Games by Sales
#-------------------------

year_count <- games %>% 
  group_by(Year) %>% 
  summarise(count_year = n())

# tail(year_count)

games <- games[games$Year!='2017'& games$Year!='2020',]

gsales10 <-games %>%
    group_by(Name) %>%
    summarise(sum_global_sales = sum(Global_Sales),.groups = 'drop') %>%
    arrange(desc(sum_global_sales))
games_totalsales <- head(gsales10, 10)

#plot

games_totalsales %>% 
  ggplot(aes(x= Name, y=sum_global_sales)) +
  geom_bar(stat = "identity",  aes(x= Name, y=sum_global_sales, fill = Name)) +
  theme(plot.title = element_text(size = 30, face = 'bold', family = my_font)) +
  labs(x = NULL, y = NULL,
       title = "Top 10 Games by Sales",
       caption = "Data Source: Kaggle") +
  theme_classic() +
  theme(panel.grid = element_blank()) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, size = 10, face = 'italic'),
       legend.position="none")

Top 5 Publisher Distribution

  1. Trong bộ dữ liệu có rất nhiều nhà xuất bản các trò chơi điện tử khác nhau. Tôi lấy ra Top 5 nhà xuất bản dựa theo doanh số bán ra của sản phẩm. Từ biểu đồ này có thể suy ra rằng Nintendo tạo ra doanh số bán hàng cao nhất so với các nhà xuất bản khác (lớn nhất trong giai đoạn 2003 - 2008). Điều này cũng có nghĩa là hầu hết các trò chơi của Nintendo đều phổ biến với người dùng hoặc là những trò chơi có giá cả đắt đỏ hơn so với các sản phẩm còn lại.
#-------------------------------------------------------------------
# Top 5 Publisher Distribution by Yearly Number of Game and Sales
#-------------------------------------------------------------------

publisher_count <- games %>%
    group_by(Publisher) %>%
    summarise(GlobalSales = sum(Global_Sales),count_game = length(unique(Name)),.groups = 'drop') %>%
    arrange(desc(count_game)) %>%
    select(Publisher)%>% head(5)

publisher_count20 <- as.vector(publisher_count$Publisher)

publisher_bubble <- games %>%
    filter(Publisher %in% publisher_count20) %>%
    group_by(Year,Publisher) %>%
    summarise(GlobalSales = sum(Global_Sales),count_game = length(unique(Name)),.groups = 'drop') %>%
    arrange(desc(Year))

#plot
publisher_bubble %>% 
  ggplot(aes(x=Year, y=GlobalSales, size=count_game, fill=Publisher)) +
  geom_point(alpha=0.5, shape=21, color="black") +
  scale_size(range = c(.1, 24), name="Number of Games") +
  theme(plot.background =element_blank()) +
  labs(x = NULL, y = NULL,
       title = "Top 5 Publisher Distribution by Yearly Number of Game and Sales",
       caption = "Data Source: Kaggle") +
  theme(legend.position="right",axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
  theme(plot.title = element_text(size = 50, face = 'bold', family = my_font)) +
  theme_classic() +
  theme(panel.grid = element_blank())

LS0tDQp0aXRsZTogJ1ByYWN0aWNlIDY6IFZpZGVvIEdhbWUgU2FsZXMnDQphdXRob3I6ICJOZ3V5ZW4gVGhpIE5nb2MgSHV5ZW4iDQpkYXRlOiAiNC83LzIwMjEiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICAjIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCg0KYGBgDQoNCiMgSW50cm9kdWN0aW9uDQoNCiAgVMO0aSB0aOG7sWMgaGnhu4duIHRo4butIG5naGnhu4dtIHbhu5tpIGLhu5kgZOG7ryBsaeG7h3UgVmlkZW8gR2FtZSBTYWxlcyDEkcaw4bujYyB0aOG7kW5nIGvDqiB04burIGPDoWMgbsSDbSB04burIDE5ODAgxJHhur9uIDIwMjAgY2jhu6lhIGPDoWMgc+G7kSBsaeG7h3UgYsOhbiBow6BuZyBraMOhYyBuaGF1IHRyw6puIHRvw6BuIGPhuqd1LCBKUCwgRVUsIE5BLg0KIA0KICBQaOG6p24gdHLDrG5oIGLDoHkgZMaw4bubaSDEkcOieSBj4bunYSB0w7RpIHbhuqtuIGPDsm4gbmhp4buBdSB0aGnhur91IHjDs3QsIHbDrCB24bqteSB0w7RpIHPhur0gdGnhur9wIHThu6VjIG5naGnDqm4gY+G7qXUgdsOgIGPhuq1wIG5o4bqtdCB0cm9uZyB0aOG7nWkgZ2lhbiB04bubaS4NCg0KIyBOdW1iZXIgb2YgR2FtZXMgaW4gZWFjaCBQbGF0Zm9ybXMNCg0KMS4gQmnhu4N1IMSR4buTIHbhu4Egc+G7kSBsxrDhu6NuZyB0csOyIGNoxqFpIGPhu6dhIG3hu5dpIG7hu4FuIHThuqNuZy4NCg0KICBUaMOhY2ggdGjhu6ljIGPhu6dhIHThu4dwIGThu68gbGnhu4d1IG7DoHkga2jDtG5nIGPDsyB04buVbmcgZG9hbmggc+G7kSBjaG8gdOG7q25nIG5ow6Agc+G6o24geHXhuqV0IGhv4bq3YyB0aOG7gyBsb+G6oWkgaG/hurdjIG7hu4FuIHThuqNuZy4gRG8gxJHDsyBj4bqnbiB0w61uaCB04buVbmcgZG9hbmggc+G7kSB0aGVvIGPDoWNoIHRo4bunIGPDtG5nLCB0w7RpIHPhur0gdOG7lW5nIGjhu6NwIDQgZG9hbmggc+G7kSBiw6FuIGjDoG5nIGtow6FjIG5oYXUgdMawxqFuZyDhu6luZyB2w6AgcGjDom4gbG/huqFpIHRoZW8gbmjDoCBz4bqjbiB4deG6pXQsIHRo4buDIGxv4bqhaSBob+G6t2MgbuG7gW4gdOG6o25nLg0KICBU4burIGJp4buDdSDEkeG7kyBjaMO6bmcgdGEgY8OzIHRo4buDIHN1eSByYSBj4bqjIERTIHbDoCBQUzIgxJHhu4F1IHLhuqV0IGfhuqduIG5oYXUuIERTIGPDsyB04buVbmcgY+G7mW5nIDIxNjMgdHLDsiBjaMahaSB2w6AgUFMyIGPDsyB04buVbmcgY+G7mW5nIDIxNjEgdHLDsiBjaMahaS4gTeG6t3Qga2jDoWMsIFBDRlggY8OzIHPhu5EgbMaw4bujbmcgdHLDsiBjaMahaSB0aOG6pXAgbmjhuqV0ICgxIHRyw7IgY2jGoWkpLg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCg0KIyBMb2FkIHBhY2thZ2UgYW5kIGRhdGE6IA0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMgZ2FtZXMgPC0gcmVhZC5jc3YoInZnc2FsZXMxLmNzdiIsIGhlYWRlciA9IFQpDQoNCmdhbWVzIDwtIHJlYWRfY3N2KCJEOlxcUlxcRGF0YVxcdmdzYWxlczEuY3N2IikNCg0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSAxNiwgcmVwci5wbG90LmhlaWdodCA9IDgpDQoNCmdhbWVzIDwtIGdhbWVzW2dhbWVzJFllYXIhPSdOL0EnLF0NCmdhbWVzJFllYXIgPC0gZmFjdG9yKGdhbWVzJFllYXIpDQoNCmdhbWVzIDwtIGdhbWVzWywyOjExXQ0KDQojZm9udCAmIGNvbG9yDQpjb2xvcnMgPC0gYygiR2xvYmFsIFNhbGVzIj0icmVkIiwgIk5vcnRoIEFtZXJpY2EgU2FsZXMiPSJibHVlIiwgIkV1cm9wZSBTYWxlcyI9ImdyZWVuIiwgIkphcGFuIFNhbGVzIj0ib3JhbmdlIiwNCiAgICAgICAgICAgICJUaGUgUmVzdCBvZiB0aGUgV29ybGQiPSJ2aW9sZXQiKQ0KbXlfZm9udCA8LSAiUm9ib3RvIg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgTnVtYmVyIG9mIEdhbWVzIGluIGVhY2ggUGxhdGZvcm1zDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NClBGIDwtIGdhbWVzICU+JSANCiAgZ3JvdXBfYnkoUGxhdGZvcm0pICU+JSBjb3VudCgpDQoNClBGICU+JSBnZ3Bsb3QoYWVzKHggPSBQbGF0Zm9ybSwgeSA9IG4pKSArDQogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCBmaWxsID0gIiMyYzdiYjYiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDQwLCBmYWNlID0gJ2JvbGQnLCBmYW1pbHkgPSBteV9mb250KSkgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgDQogICAgICAgdGl0bGUgPSAiTnVtYmVyIG9mIEdhbWVzIGluIGVhY2ggUGxhdGZvcm1zIiwNCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBLYWdnbGUiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpDQoNCmBgYA0KDQohW10oRDpcUlxwcmFjdGljZVxwaWN0dXJlXG51bWJlcm9mZ2FtZXMucG5nKQ0KDQojIFN1bSBvZiBHbG9iYWwgU2FsZXMgYnkgWWVhcg0KMi4gQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiB04buVbmcgZG9hbmggc+G7kSBiw6FuIGjDoG5nIGPhu6dhIEdsb2JhbCwgTm9ydGggQW1lcmljYSwgRXVyb3BlLCBKYXBhbiwgVGhlIFJlc3Qgb2YgdGhlIFdvcmxkIHThu6sgbsSDbSAxOTgwIC0gMjAyMC4NClThu6sgaMOsbmggduG6vSB0YSBjw7MgdGjhu4Mga+G6v3QgbHXhuq1uIHLhurFuZyBOb3J0aCBBbWVyaWNhIGzDoCBraHUgduG7sWMgY8OzIGdp4buvIGRvYW5oIHPhu5EgduG7gSB0csOyIGNoxqFpIMSRaeG7h24gdOG7rSBs4bubbiBuaOG6pXQgcXVhIGPDoWMgbsSDbS5Ww6wgxJHDonkgbMOgIHF14buRYyBnaWEgY8OzIG7hu4FuIGtpbmggdOG6vyB2w6AgY8O0bmcgbmdo4buHIHBow6F0IHRyaeG7g24sIG5odSBj4bqndSB24buBIG5o4buvbmcgdHLDsiBjaMahaSBnaeG6o2kgdHLDrSBjxaluZyB0cuG7nyBuw6puIHBo4buVIGJp4bq/biB2w6AgxJHhuqF0IMSR4bq/biDEkeG7iW5oIGNhbyB2w6BvIG7Eg20gMjAwOC4NCmBgYHtyLCBldmFsPUZBTFNFfQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojU3VtIG9mIEdsb2JhbCBTYWxlcyBieSBZZWFyDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpzdW1fb2Zfc2FsZXMgPC0gZ2FtZXMgJT4lIA0KICBncm91cF9ieShZZWFyKSAlPiUgDQogIHN1bW1hcmlzZShzdW1fZ2xvYmFsX3NhbGVzID0gc3VtKEdsb2JhbF9TYWxlcyksIHN1bV9vdGhlcnNfc2FsZXMgPSBzdW0oT3RoZXJfU2FsZXMpLA0KICAgICAgICAgICAgc3VtX2piX3NhbGVzID0gc3VtKEpQX1NhbGVzKSwgc3VtX2V1X3NhbGVzID0gc3VtKEVVX1NhbGVzKSwNCiAgICAgICAgICAgIHN1bV9uYV9zYWxlcyA9IHN1bShOQV9TYWxlcyksIC5ncm91cHMgPSAnZHJvcCcpDQoNCg0Kc3VtX29mX3NhbGVzICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gWWVhcikpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gc3VtX2dsb2JhbF9zYWxlcyxncm91cD0xLGNvbG9yPSJHbG9iYWwgU2FsZXMiKSkgKw0KICBnZW9tX2xpbmUoYWVzKHk9IHN1bV9uYV9zYWxlcyxncm91cD0xLGNvbG9yPSJOb3J0aCBBbWVyaWNhIFNhbGVzIikpICsNCiAgZ2VvbV9saW5lKGFlcyh5PSBzdW1fZXVfc2FsZXMsZ3JvdXA9MSxjb2xvcj0iRXVyb3BlIFNhbGVzIikpICsNCiAgZ2VvbV9saW5lKGFlcyh5PSBzdW1famJfc2FsZXMsZ3JvdXA9MSxjb2xvcj0iSmFwYW4gU2FsZXMiKSkgKw0KICBnZW9tX2xpbmUoYWVzKHk9IHN1bV9vdGhlcnNfc2FsZXMsZ3JvdXA9MSxjb2xvcj0iVGhlIFJlc3Qgb2YgdGhlIFdvcmxkIikpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBteV9mb250LCBzaXplID0gNDAsIGNvbG9yID0gImdyZXkxMCIsIGZhY2UgPSAiYm9sZCIpKSArDQogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBteV9mb250LCBzaXplID0gMTIsIGNvbG9yID0gImdyZXk0MCIsIGZhY2UgPSAiaXRhbGljIikpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCwgZmFjZSA9ICJib2xkIiwgZmFtaWx5ID0gbXlfZm9udCkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSxsZWdlbmQucG9zaXRpb249InRvcCIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlNhbGVzIix2YWx1ZXMgPSBjb2xvcnMpKw0KICB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gbXlfZm9udCwgc2l6ZSA9IDEyLCBjb2xvciA9ICJncmV5NDAiLCBmYWNlID0gIml0YWxpYyIpKSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLA0KICAgICAgIHRpdGxlID0gIlN1bSBvZiBHbG9iYWwgU2FsZXMgYnkgWWVhciIsDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogS2FnZ2xlIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNCiFbXShEOlxSXHByYWN0aWNlXHBpY3R1cmVcUnBsb3QyLnBuZykNCg0KIyBUb3AgMTAgR2FtZXMgYnkgU2FsZXMNCg0KMy4gQsOqbiBj4bqhbmggxJHDsywgYuG7mSBk4buvIGxp4buHdSBjaOG7qWEgY8OhYyB0csOyIGNoxqFpIGtow6FjIG5oYXUgdOG7qyBuaGnhu4F1IG7Eg20gdHLDqm4gbuG7gW4gdOG6o25nIGtow6FjIG5oYXUsIHLhuqV0IGtow7MgxJHhu4MgaGnhu4NuIHRo4buLIHRvcCAxMCB0csOyIGNoxqFpLyBuaMOgIHBow6F0IGjDoG5oLyBu4buBbiB04bqjbmcgbuG7lWkgdGnhur9uZyBuaOG6pXQgbcOgIG5nxrDhu51pIGTDuW5nIHRow61jaCBjaMahaS4gRG8gxJHDsywgdMO0aSBz4bq9IHbhur0gYmnhu4N1IMSR4buTIGtow6FjIG5oYXUgduG7gSAxMCB0csOyIGNoxqFpIGjDoG5nIMSR4bqndSBtw6AgbmfGsOG7nWkgZMO5bmcgdGjDrWNoIGNoxqFpIGLhurFuZyBjw6FjaCBz4butIGThu6VuZyBu4buBbiB04bqjbmcga2jDoWMgbmhhdS4NCiAgVGnhur9wIHThu6VjIHbhu5tpIGJp4buDdSDEkeG7kyB24buBIHRvcCAxMCB0csOyIGNoxqFpIGjDoG5nIMSR4bqndSB0cm9uZyBraG/huqNuZyB04burIG7Eg20gMTk4MCAtIDIwMjAsIFdpaSBTcG9ydCDEkeG7qW5nIMSR4bqndSBkb2FuaCBz4buRIGLDoW4gaMOgbmcsIHRoZW8gc2F1IMSRw7MgbMOgIEdyYW5kIFRoZWZ0IEF1dG8gViBjw7Mga2hv4bqjbmcgY8OhY2ggduG7m2kgV2lpIFNwb3J0IGzDoCAyNiw4MiB0cmnhu4d1Lg0KYGBge3IsIGV2YWw9RkFMU0V9DQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBUb3AgMTAgR2FtZXMgYnkgU2FsZXMNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCnllYXJfY291bnQgPC0gZ2FtZXMgJT4lIA0KICBncm91cF9ieShZZWFyKSAlPiUgDQogIHN1bW1hcmlzZShjb3VudF95ZWFyID0gbigpKQ0KDQojIHRhaWwoeWVhcl9jb3VudCkNCg0KZ2FtZXMgPC0gZ2FtZXNbZ2FtZXMkWWVhciE9JzIwMTcnJiBnYW1lcyRZZWFyIT0nMjAyMCcsXQ0KDQpnc2FsZXMxMCA8LWdhbWVzICU+JQ0KICAgIGdyb3VwX2J5KE5hbWUpICU+JQ0KICAgIHN1bW1hcmlzZShzdW1fZ2xvYmFsX3NhbGVzID0gc3VtKEdsb2JhbF9TYWxlcyksLmdyb3VwcyA9ICdkcm9wJykgJT4lDQogICAgYXJyYW5nZShkZXNjKHN1bV9nbG9iYWxfc2FsZXMpKQ0KZ2FtZXNfdG90YWxzYWxlcyA8LSBoZWFkKGdzYWxlczEwLCAxMCkNCg0KI3Bsb3QNCg0KZ2FtZXNfdG90YWxzYWxlcyAlPiUgDQogIGdncGxvdChhZXMoeD0gTmFtZSwgeT1zdW1fZ2xvYmFsX3NhbGVzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgIGFlcyh4PSBOYW1lLCB5PXN1bV9nbG9iYWxfc2FsZXMsIGZpbGwgPSBOYW1lKSkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCwgZmFjZSA9ICdib2xkJywgZmFtaWx5ID0gbXlfZm9udCkpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsDQogICAgICAgdGl0bGUgPSAiVG9wIDEwIEdhbWVzIGJ5IFNhbGVzIiwNCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBLYWdnbGUiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSwgc2l6ZSA9IDEwLCBmYWNlID0gJ2l0YWxpYycpLA0KICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpDQpgYGANCg0KIVtdKEQ6XFJccHJhY3RpY2VccGljdHVyZVx0b3AxMC5wbmcpDQoNCiMgVG9wIDUgUHVibGlzaGVyIERpc3RyaWJ1dGlvbg0KDQo0LiBUcm9uZyBi4buZIGThu68gbGnhu4d1IGPDsyBy4bqldCBuaGnhu4F1IG5ow6AgeHXhuqV0IGLhuqNuIGPDoWMgdHLDsiBjaMahaSDEkWnhu4duIHThu60ga2jDoWMgbmhhdS4gVMO0aSBs4bqleSByYSBUb3AgNSBuaMOgIHh14bqldCBi4bqjbiBk4buxYSB0aGVvIGRvYW5oIHPhu5EgYsOhbiByYSBj4bunYSBz4bqjbiBwaOG6qW0uIFThu6sgYmnhu4N1IMSR4buTIG7DoHkgY8OzIHRo4buDIHN1eSByYSBy4bqxbmcgTmludGVuZG8gdOG6oW8gcmEgZG9hbmggc+G7kSBiw6FuIGjDoG5nIGNhbyBuaOG6pXQgc28gduG7m2kgY8OhYyBuaMOgIHh14bqldCBi4bqjbiBraMOhYyAobOG7m24gbmjhuqV0IHRyb25nIGdpYWkgxJFv4bqhbiAyMDAzIC0gMjAwOCkuIMSQaeG7gXUgbsOgeSBjxaluZyBjw7MgbmdoxKlhIGzDoCBo4bqndSBo4bq/dCBjw6FjIHRyw7IgY2jGoWkgY+G7p2EgTmludGVuZG8gxJHhu4F1IHBo4buVIGJp4bq/biB24bubaSBuZ8aw4budaSBkw7luZyBob+G6t2MgbMOgIG5o4buvbmcgdHLDsiBjaMahaSBjw7MgZ2nDoSBj4bqjIMSR4bqvdCDEkeG7jyBoxqFuIHNvIHbhu5tpIGPDoWMgc+G6o24gcGjhuqltIGPDsm4gbOG6oWkuDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFRvcCA1IFB1Ymxpc2hlciBEaXN0cmlidXRpb24gYnkgWWVhcmx5IE51bWJlciBvZiBHYW1lIGFuZCBTYWxlcw0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KcHVibGlzaGVyX2NvdW50IDwtIGdhbWVzICU+JQ0KICAgIGdyb3VwX2J5KFB1Ymxpc2hlcikgJT4lDQogICAgc3VtbWFyaXNlKEdsb2JhbFNhbGVzID0gc3VtKEdsb2JhbF9TYWxlcyksY291bnRfZ2FtZSA9IGxlbmd0aCh1bmlxdWUoTmFtZSkpLC5ncm91cHMgPSAnZHJvcCcpICU+JQ0KICAgIGFycmFuZ2UoZGVzYyhjb3VudF9nYW1lKSkgJT4lDQogICAgc2VsZWN0KFB1Ymxpc2hlciklPiUgaGVhZCg1KQ0KDQpwdWJsaXNoZXJfY291bnQyMCA8LSBhcy52ZWN0b3IocHVibGlzaGVyX2NvdW50JFB1Ymxpc2hlcikNCg0KcHVibGlzaGVyX2J1YmJsZSA8LSBnYW1lcyAlPiUNCiAgICBmaWx0ZXIoUHVibGlzaGVyICVpbiUgcHVibGlzaGVyX2NvdW50MjApICU+JQ0KICAgIGdyb3VwX2J5KFllYXIsUHVibGlzaGVyKSAlPiUNCiAgICBzdW1tYXJpc2UoR2xvYmFsU2FsZXMgPSBzdW0oR2xvYmFsX1NhbGVzKSxjb3VudF9nYW1lID0gbGVuZ3RoKHVuaXF1ZShOYW1lKSksLmdyb3VwcyA9ICdkcm9wJykgJT4lDQogICAgYXJyYW5nZShkZXNjKFllYXIpKQ0KDQojcGxvdA0KcHVibGlzaGVyX2J1YmJsZSAlPiUgDQogIGdncGxvdChhZXMoeD1ZZWFyLCB5PUdsb2JhbFNhbGVzLCBzaXplPWNvdW50X2dhbWUsIGZpbGw9UHVibGlzaGVyKSkgKw0KICBnZW9tX3BvaW50KGFscGhhPTAuNSwgc2hhcGU9MjEsIGNvbG9yPSJibGFjayIpICsNCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoLjEsIDI0KSwgbmFtZT0iTnVtYmVyIG9mIEdhbWVzIikgKw0KICB0aGVtZShwbG90LmJhY2tncm91bmQgPWVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwNCiAgICAgICB0aXRsZSA9ICJUb3AgNSBQdWJsaXNoZXIgRGlzdHJpYnV0aW9uIGJ5IFllYXJseSBOdW1iZXIgb2YgR2FtZSBhbmQgU2FsZXMiLA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IEthZ2dsZSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJyaWdodCIsYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUwLCBmYWNlID0gJ2JvbGQnLCBmYW1pbHkgPSBteV9mb250KSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQ0KDQpgYGANCg0KDQohW10oRDpcUlxwcmFjdGljZVxwaWN0dXJlXHRvcDUucG5nKQ0K