Outline


    01. Categorical data

    02. Numeric data


    Dataset

    Videogames



    • Load packages:
    library(dplyr)
    library(summarytools)
    library(ggplot2)


    • Load the data:
    Videogames <- read.csv("Video_Games_Sales_as_at_22_Dec_2016.csv")


    Categorical data

    Contingency tables or crosstab - overview


    • Data screening
    view(dfSummary(Videogames))


    • Crosstab for absolute frequencies - table way:
    table(Videogames$Genre, 
          Videogames$Rating)
                  
                          AO    E E10+   EC  K-A    M   RP    T
                      2    0    0    0    0    0    0    0    0
      Action       1182    1  416  481    1    0  608    0  681
      Adventure     857    0  162   68    2    0   99    0  115
      Fighting      411    0    8   19    0    0   49    0  362
      Misc          868    0  457  167    5    1   13    0  239
      Platform      319    0  358  144    0    0    3    0   64
      Puzzle        238    0  289   43    0    0    0    0   10
      Racing        377    0  585   96    0    0   18    1  172
      Role-Playing  723    0   84  111    0    0  162    0  420
      Shooter       304    0   48   58    0    0  565    0  348
      Simulation    305    0  326   48    0    0    5    0  190
      Sports        839    0 1188  107    0    0   16    0  198
      Strategy      344    0   70   78    0    2   25    2  162


    Bar chart


    • Select games without any age restrictions and games with the age restriction for teens, dplyr way:
    glimpse(Videogames %>%
              filter(Rating %in% c("E", "T")) %>%
              droplevels(), 
        width = 50)
    Observations: 6,952
    Variables: 16
    $ Name            <fct> Wii Sports, Mario Kar...
    $ Platform        <fct> Wii, Wii, Wii, DS, Wi...
    $ Year_of_Release <fct> 2006, 2008, 2009, 200...
    $ Genre           <fct> Sports, Racing, Sport...
    $ Publisher       <fct> Nintendo, Nintendo, N...
    $ NA_Sales        <dbl> 41.36, 15.68, 15.61, ...
    $ EU_Sales        <dbl> 28.96, 12.76, 10.93, ...
    $ JP_Sales        <dbl> 3.77, 3.79, 3.28, 6.5...
    $ Other_Sales     <dbl> 8.45, 3.29, 2.95, 2.8...
    $ Global_Sales    <dbl> 82.53, 35.52, 32.77, ...
    $ Critic_Score    <int> 76, 82, 80, 89, 58, 8...
    $ Critic_Count    <int> 51, 73, 73, 65, 41, 8...
    $ User_Score      <fct> 8, 8.3, 8, 8.5, 6.6, ...
    $ User_Count      <int> 322, 709, 192, 431, 1...
    $ Developer       <fct> "Nintendo", "Nintendo...
    $ Rating          <fct> E, E, E, E, E, E, E, ...


    • Bar chart - absolute frequencies, genres of videogames by ratings
    # Data
    Videogames_Everyone_Teens <- Videogames %>%
                            filter(Rating %in% c("E", "T")) %>%
                            droplevels() # drop unused levels 
    # Plot
    ggplot(Videogames_Everyone_Teens, aes(x = Genre, fill = Rating)) + 
      geom_bar(position = "dodge")


    • Bar chart - absolute frequencies, genres of videogames by ratings - changing the X-axis’s text angle:
    Videogames_Everyone_Teens_Bar_Plot <- Videogames %>%
                                  filter(Rating %in% c("E", "T")) %>%
                                  droplevels() %>%
      ggplot(aes(x = Genre, fill = Rating)) + 
        geom_bar(position = "dodge") + 
        theme(axis.text.x = element_text(angle = 90))
    Videogames_Everyone_Teens_Bar_Plot


    Contingency tables or crosstab - relative frequencies


    • Crosstab with rating and genres:
    GenreRating = table(Videogames_Everyone_Teens$Genre, 
                        Videogames_Everyone_Teens$Rating)
    GenreRating
                  
                      E    T
      Action        416  681
      Adventure     162  115
      Fighting        8  362
      Misc          457  239
      Platform      358   64
      Puzzle        289   10
      Racing        585  172
      Role-Playing   84  420
      Shooter        48  348
      Simulation    326  190
      Sports       1188  198
      Strategy       70  162


    • Relative frequenices - total:
    prop.table(GenreRating)
                  
                             E           T
      Action       0.059838895 0.097957422
      Adventure    0.023302647 0.016542002
      Fighting     0.001150748 0.052071346
      Misc         0.065736479 0.034378596
      Platform     0.051495972 0.009205984
      Puzzle       0.041570771 0.001438435
      Racing       0.084148446 0.024741082
      Role-Playing 0.012082854 0.060414269
      Shooter      0.006904488 0.050057537
      Simulation   0.046892980 0.027330265
      Sports       0.170886076 0.028481013
      Strategy     0.010069045 0.023302647


    • Relative frequencies - rows, rounded by 3 digits:
    round(prop.table(GenreRating, 1), 3)
                  
                       E     T
      Action       0.379 0.621
      Adventure    0.585 0.415
      Fighting     0.022 0.978
      Misc         0.657 0.343
      Platform     0.848 0.152
      Puzzle       0.967 0.033
      Racing       0.773 0.227
      Role-Playing 0.167 0.833
      Shooter      0.121 0.879
      Simulation   0.632 0.368
      Sports       0.857 0.143
      Strategy     0.302 0.698


    • Relative frequencies - columns, rounded by 2 digits:
    round(prop.table(GenreRating, 2), 2)
                  
                      E    T
      Action       0.10 0.23
      Adventure    0.04 0.04
      Fighting     0.00 0.12
      Misc         0.11 0.08
      Platform     0.09 0.02
      Puzzle       0.07 0.00
      Racing       0.15 0.06
      Role-Playing 0.02 0.14
      Shooter      0.01 0.12
      Simulation   0.08 0.06
      Sports       0.30 0.07
      Strategy     0.02 0.05


    Bar chart for relative frequencies


    • Proportions of genres by rating:
    ggplot(Videogames_Everyone_Teens, aes(x = Genre, fill = Rating)) +
     geom_bar(position = "fill") +
     ylab("proportion")


    Bar chart - single variable and a grid


    • Add labels to the factor levels:
    Videogames_Everyone_Teens$Rating <- factor(Videogames_Everyone_Teens$Rating,
                                          levels = c("E", "T"), 
                                          labels = c("Everyone", "Teen"))


    • Bar chart for the number of rating:
    ggplot(Videogames_Everyone_Teens, 
           aes(x = Rating)) + 
      geom_bar()


    • Bar chart for genres by ratings:
    ggplot(Videogames_Everyone_Teens, 
           aes(x = Genre)) +
     geom_bar() +
     facet_wrap(~ Rating) +
     theme(axis.text.x = element_text(angle = 90))


    Numeric data

    Plots


    • Histogram with facets (layers):
    ggplot(Videogames_Everyone_Teens, 
           aes(x = Critic_Score)) +
     geom_histogram() +
     facet_wrap(~ Rating)


    • Filter games by genres: shooters (action), strategies and RPGs:
    Shooter_Strategy_RPG <- filter(Videogames, 
                                   Genre %in% c("Shooter", 
                                                "Strategy", 
                                                "Role-Playing"))
    glimpse(Shooter_Strategy_RPG, 
            width = 50)
    Observations: 3,506
    Variables: 16
    $ Name            <fct> Pokemon Red/Pokemon B...
    $ Platform        <fct> GB, NES, GB, DS, GBA,...
    $ Year_of_Release <fct> 1996, 1984, 1999, 200...
    $ Genre           <fct> Role-Playing, Shooter...
    $ Publisher       <fct> Nintendo, Nintendo, N...
    $ NA_Sales        <dbl> 11.27, 26.93, 9.00, 6...
    $ EU_Sales        <dbl> 8.89, 0.63, 6.18, 4.4...
    $ JP_Sales        <dbl> 10.22, 0.28, 7.20, 6....
    $ Other_Sales     <dbl> 1.00, 0.47, 0.71, 1.3...
    $ Global_Sales    <dbl> 31.37, 28.31, 23.10, ...
    $ Critic_Score    <int> NA, NA, NA, NA, NA, N...
    $ Critic_Count    <int> NA, NA, NA, NA, NA, N...
    $ User_Score      <fct> , , , , , , 3.4, , , ...
    $ User_Count      <int> NA, NA, NA, NA, NA, N...
    $ Developer       <fct> "", "", "", "", "", "...
    $ Rating          <fct> , , , , , , M, , , M,...


    • Box plot:
    ggplot(Shooter_Strategy_RPG, 
           aes(x = as.factor(Genre), 
               y = Critic_Score)) +
     geom_boxplot()


    • Density plot with overlaying categories:
    ggplot(Shooter_Strategy_RPG, 
           aes(x = Critic_Score,
           fill = as.factor(Genre))) +
     geom_density(alpha = .3)


    • Histogram for the millions of sold copies videogames in the EU:
    Videogames %>%
     ggplot(aes(x = EU_Sales)) +
     geom_histogram(binwidth = 0.01) +
     xlim(c(0, 2)) + 
     ylim(0, 1750) + 
     ggtitle("Millions of sold copies videogames in the EU")


    • Histogram for the millions of sold copies of sport videogames in the EU:
    Videogames %>%
     filter(Genre == "Sports") %>%
     ggplot(aes(x = EU_Sales)) +
     geom_histogram(binwidth = 0.1) +
     xlim(c(0, 3)) +
     ylim(0, 500) + 
     ggtitle("Histogram for the millions of sold copies of sport videogames in the EU")


    • Boxplot for the number of users who gave the user_score**:
    Videogames %>%
     ggplot(aes(x = 1, y = User_Count)) +
     geom_boxplot()


    • Boxplot for the number of users who gave the user_score* - without outliers*:
    Videogames_no_out <- Videogames %>%
      mutate(User_Outliers = 1.5 * IQR(User_Count, na.rm = TRUE)) %>%
      filter(User_Count <= User_Outliers) %>%
     ggplot(aes(x = 1, y = User_Count)) +
     geom_boxplot()
    Videogames_no_out


    Summaries


    • Let’s focus on Ubisoft:
    Ubisoft_Reviews <- filter(Videogames, Developer == "Ubisoft") %>%
     ggplot(aes(x = 1, y = User_Count)) +
     geom_boxplot()
    Ubisoft_Reviews


    • Mean and median of the copies sold in the North America by Ubisoft, by genres:
    Videogames %>%
     filter(Developer == "Ubisoft") %>%
     group_by(Genre) %>%
     summarize(round(mean(NA_Sales), 3),
     median(NA_Sales))


    • Box plot of the number of copies sold in the North America by Ubisoft, by genre:
    Ubisoft <- Videogames %>%
                filter(Developer == "Ubisoft")
    Ubisoft %>%
     ggplot(aes(x = Genre, y = NA_Sales)) +
     geom_boxplot()


    LS0tDQp0aXRsZTogIioqMDYuIERhdGEgZXhwbG9yYXRpb24qKiINCnN1YnRpdGxlOiAiUjEwMSINCmF1dGhvcjogIlbDrXQgR2FicmhlbCINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IHlldGkNCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93Ig0KLS0tDQoNCiMjIE91dGxpbmUNCjxicj4NCg0KPHVsPiANCiMjIyMgMDEuICoqQ2F0ZWdvcmljYWwgZGF0YSoqDQojIyMjIDAyLiAgKipOdW1lcmljIGRhdGEqKg0KPHVsLz4NCjxicj4NCg0KDQojIyBEYXRhc2V0DQojIyMgWyoqVmlkZW9nYW1lcyoqXShodHRwczovL3d3dy5rYWdnbGUuY29tL3J1c2g0cmF0aW8vdmlkZW8tZ2FtZS1zYWxlcy13aXRoLXJhdGluZ3MpDQo8YnI+DQoNCiFbXShEYXRhLmpwZykNCg0KPGJyPiANCg0KKiAqKkxvYWQqKiBwYWNrYWdlczoNCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShzdW1tYXJ5dG9vbHMpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCjxicj4NCg0KKiAqKkxvYWQqKiB0aGUgZGF0YToNCmBgYHtyfQ0KVmlkZW9nYW1lcyA8LSByZWFkLmNzdigiVmlkZW9fR2FtZXNfU2FsZXNfYXNfYXRfMjJfRGVjXzIwMTYuY3N2IikNCmBgYA0KPGJyPg0KDQojIyBDYXRlZ29yaWNhbCBkYXRhDQojIyMgKkNvbnRpbmdlbmN5IHRhYmxlcyBvciBjcm9zc3RhYiAtIG92ZXJ2aWV3Kg0KPGJyPg0KDQoqIERhdGEgKipzY3JlZW5pbmcqKg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9DQp2aWV3KGRmU3VtbWFyeShWaWRlb2dhbWVzKSkNCmBgYA0KPGJyPg0KDQoqIENyb3NzdGFiIGZvciAqKmFic29sdXRlIGZyZXF1ZW5jaWVzKiogLSAqKnRhYmxlKiogd2F5Og0KYGBge3J9DQp0YWJsZShWaWRlb2dhbWVzJEdlbnJlLCANCiAgICAgIFZpZGVvZ2FtZXMkUmF0aW5nKQ0KYGBgDQo8YnI+DQoNCiMjIyAqQmFyIGNoYXJ0Kg0KPGJyPg0KDQoqIFNlbGVjdCBnYW1lcyAqKndpdGhvdXQgYW55IGFnZSByZXN0cmljdGlvbnMqKiBhbmQgZ2FtZXMgd2l0aCB0aGUgYWdlIHJlc3RyaWN0aW9uIGZvciAqKnRlZW5zKiosICoqZHBseXIqKiB3YXk6DQpgYGB7cn0NCmdsaW1wc2UoVmlkZW9nYW1lcyAlPiUNCiAgICAgICAgICBmaWx0ZXIoUmF0aW5nICVpbiUgYygiRSIsICJUIikpICU+JQ0KICAgICAgICAgIGRyb3BsZXZlbHMoKSwgDQogICAgd2lkdGggPSA1MCkNCmBgYA0KPGJyPg0KDQoqICoqQmFyIGNoYXJ0KiogLSBhYnNvbHV0ZSBmcmVxdWVuY2llcywgZ2VucmVzIG9mIHZpZGVvZ2FtZXMgYnkgcmF0aW5ncw0KYGBge3IsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9DQojIERhdGENClZpZGVvZ2FtZXNfRXZlcnlvbmVfVGVlbnMgPC0gVmlkZW9nYW1lcyAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihSYXRpbmcgJWluJSBjKCJFIiwgIlQiKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBkcm9wbGV2ZWxzKCkgIyBkcm9wIHVudXNlZCBsZXZlbHMgDQojIFBsb3QNCmdncGxvdChWaWRlb2dhbWVzX0V2ZXJ5b25lX1RlZW5zLCBhZXMoeCA9IEdlbnJlLCBmaWxsID0gUmF0aW5nKSkgKyANCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKQ0KYGBgDQo8YnI+DQoNCiogKipCYXIgY2hhcnQqKiAtIGFic29sdXRlIGZyZXF1ZW5jaWVzLCBnZW5yZXMgb2YgdmlkZW9nYW1lcyBieSByYXRpbmdzIC0gKipjaGFuZ2luZyB0aGUgWC1heGlzJ3MgdGV4dCBhbmdsZSoqOg0KYGBge3IsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0NClZpZGVvZ2FtZXNfRXZlcnlvbmVfVGVlbnNfQmFyX1Bsb3QgPC0gVmlkZW9nYW1lcyAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihSYXRpbmcgJWluJSBjKCJFIiwgIlQiKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcm9wbGV2ZWxzKCkgJT4lDQogIGdncGxvdChhZXMoeCA9IEdlbnJlLCBmaWxsID0gUmF0aW5nKSkgKyANCiAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsgDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQoNClZpZGVvZ2FtZXNfRXZlcnlvbmVfVGVlbnNfQmFyX1Bsb3QNCmBgYA0KPGJyPg0KDQojIyMgKkNvbnRpbmdlbmN5IHRhYmxlcyBvciBjcm9zc3RhYiAtIHJlbGF0aXZlIGZyZXF1ZW5jaWVzKg0KPGJyPg0KDQoqICoqQ3Jvc3N0YWIqKiB3aXRoIHJhdGluZyBhbmQgZ2VucmVzOg0KYGBge3J9DQpHZW5yZVJhdGluZyA9IHRhYmxlKFZpZGVvZ2FtZXNfRXZlcnlvbmVfVGVlbnMkR2VucmUsIA0KICAgICAgICAgICAgICAgICAgICBWaWRlb2dhbWVzX0V2ZXJ5b25lX1RlZW5zJFJhdGluZykNCg0KR2VucmVSYXRpbmcNCmBgYA0KPGJyPiANCg0KKiAqKlJlbGF0aXZlIGZyZXF1ZW5pY2VzKiogLSB0b3RhbDoNCmBgYHtyfQ0KcHJvcC50YWJsZShHZW5yZVJhdGluZykNCmBgYA0KPGJyPg0KDQoqIFJlbGF0aXZlIGZyZXF1ZW5jaWVzIC0gKipyb3dzKiosIHJvdW5kZWQgYnkgMyBkaWdpdHM6DQpgYGB7cn0NCnJvdW5kKHByb3AudGFibGUoR2VucmVSYXRpbmcsIDEpLCAzKQ0KYGBgDQo8YnI+DQoNCiogUmVsYXRpdmUgZnJlcXVlbmNpZXMgLSAqKmNvbHVtbnMqKiwgcm91bmRlZCBieSAyIGRpZ2l0czoNCmBgYHtyfQ0Kcm91bmQocHJvcC50YWJsZShHZW5yZVJhdGluZywgMiksIDIpDQpgYGANCjxicj4NCg0KDQojIyMgKkJhciBjaGFydCBmb3IgcmVsYXRpdmUgZnJlcXVlbmNpZXMqDQo8YnI+DQoNCiogKipQcm9wb3J0aW9ucyoqIG9mIGdlbnJlcyBieSByYXRpbmc6DQpgYGB7ciwgIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9DQpnZ3Bsb3QoVmlkZW9nYW1lc19FdmVyeW9uZV9UZWVucywgYWVzKHggPSBHZW5yZSwgZmlsbCA9IFJhdGluZykpICsNCiBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKw0KIHlsYWIoInByb3BvcnRpb24iKQ0KYGBgDQo8YnI+DQoNCiMjIyAqQmFyIGNoYXJ0IC0gc2luZ2xlIHZhcmlhYmxlIGFuZCBhIGdyaWQqIA0KPGJyPiANCg0KKiAqKkFkZCBsYWJlbHMqKiB0byB0aGUgZmFjdG9yIGxldmVsczoNCmBgYHtyfQ0KVmlkZW9nYW1lc19FdmVyeW9uZV9UZWVucyRSYXRpbmcgPC0gZmFjdG9yKFZpZGVvZ2FtZXNfRXZlcnlvbmVfVGVlbnMkUmF0aW5nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJFIiwgIlQiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkV2ZXJ5b25lIiwgIlRlZW4iKSkNCmBgYA0KPGJyPg0KDQoqIEJhciBjaGFydCBmb3IgdGhlIG51bWJlciBvZiAqKnJhdGluZzoqKg0KYGBge3IsIGZpZy5hbGlnbj0iY2VudGVyIn0NCmdncGxvdChWaWRlb2dhbWVzX0V2ZXJ5b25lX1RlZW5zLCANCiAgICAgICBhZXMoeCA9IFJhdGluZykpICsgDQogIGdlb21fYmFyKCkNCmBgYA0KPGJyPg0KDQoqIEJhciBjaGFydCBmb3IgZ2VucmVzICoqYnkgcmF0aW5ncyoqOg0KYGBge3IsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9DQpnZ3Bsb3QoVmlkZW9nYW1lc19FdmVyeW9uZV9UZWVucywgDQogICAgICAgYWVzKHggPSBHZW5yZSkpICsNCiBnZW9tX2JhcigpICsNCiBmYWNldF93cmFwKH4gUmF0aW5nKSArDQogdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQpgYGANCjxicj4NCg0KIyMgTnVtZXJpYyBkYXRhDQojIyMgKlBsb3RzKg0KPGJyPg0KDQoqICoqSGlzdG9ncmFtKiogd2l0aCAqKmZhY2V0cyAobGF5ZXJzKSoqOg0KYGBge3IsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9DQpnZ3Bsb3QoVmlkZW9nYW1lc19FdmVyeW9uZV9UZWVucywgDQogICAgICAgYWVzKHggPSBDcml0aWNfU2NvcmUpKSArDQogZ2VvbV9oaXN0b2dyYW0oKSArDQogZmFjZXRfd3JhcCh+IFJhdGluZykNCmBgYA0KPGJyPg0KDQoqICoqRmlsdGVyIGdhbWVzIGJ5IGdlbnJlcyoqOiBzaG9vdGVycyAoYWN0aW9uKSwgc3RyYXRlZ2llcyBhbmQgUlBHczoNCmBgYHtyfQ0KU2hvb3Rlcl9TdHJhdGVneV9SUEcgPC0gZmlsdGVyKFZpZGVvZ2FtZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdlbnJlICVpbiUgYygiU2hvb3RlciIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3RyYXRlZ3kiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJvbGUtUGxheWluZyIpKQ0KDQpnbGltcHNlKFNob290ZXJfU3RyYXRlZ3lfUlBHLCANCiAgICAgICAgd2lkdGggPSA1MCkNCmBgYA0KPGJyPg0KDQoqIEJveCBwbG90Og0KYGBge3IsIGZpZy5hbGlnbj0iY2VudGVyIn0NCmdncGxvdChTaG9vdGVyX1N0cmF0ZWd5X1JQRywgDQogICAgICAgYWVzKHggPSBhcy5mYWN0b3IoR2VucmUpLCANCiAgICAgICAgICAgeSA9IENyaXRpY19TY29yZSkpICsNCiBnZW9tX2JveHBsb3QoKQ0KYGBgDQo8YnI+DQoNCiogKipEZW5zaXR5IHBsb3QqKiB3aXRoIG92ZXJsYXlpbmcgY2F0ZWdvcmllczoNCmBgYHtyLCBmaWcuYWxpZ249ImNlbnRlciJ9DQpnZ3Bsb3QoU2hvb3Rlcl9TdHJhdGVneV9SUEcsIA0KICAgICAgIGFlcyh4ID0gQ3JpdGljX1Njb3JlLA0KICAgICAgIGZpbGwgPSBhcy5mYWN0b3IoR2VucmUpKSkgKw0KIGdlb21fZGVuc2l0eShhbHBoYSA9IC4zKQ0KYGBgDQo8YnI+DQoNCiogKkhpc3RvZ3JhbSBmb3IgdGhlIG1pbGxpb25zIG9mIHNvbGQgY29waWVzIHZpZGVvZ2FtZXMgaW4gdGhlIEVVKjoNCmBgYHtyLCBmaWcuYWxpZ249ImNlbnRlciJ9DQpWaWRlb2dhbWVzICU+JQ0KIGdncGxvdChhZXMoeCA9IEVVX1NhbGVzKSkgKw0KIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4wMSkgKw0KIHhsaW0oYygwLCAyKSkgKyANCiB5bGltKDAsIDE3NTApICsgDQogZ2d0aXRsZSgiTWlsbGlvbnMgb2Ygc29sZCBjb3BpZXMgdmlkZW9nYW1lcyBpbiB0aGUgRVUiKQ0KYGBgDQo8YnI+DQoNCiogKkhpc3RvZ3JhbSBmb3IgdGhlIG1pbGxpb25zIG9mIHNvbGQgY29waWVzIG9mIHNwb3J0IHZpZGVvZ2FtZXMgaW4gdGhlIEVVKjoNCmBgYHtyLCBmaWcuYWxpZ249ImNlbnRlciJ9DQpWaWRlb2dhbWVzICU+JQ0KIGZpbHRlcihHZW5yZSA9PSAiU3BvcnRzIikgJT4lDQogZ2dwbG90KGFlcyh4ID0gRVVfU2FsZXMpKSArDQogZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjEpICsNCiB4bGltKGMoMCwgMykpICsNCiB5bGltKDAsIDUwMCkgKyANCiBnZ3RpdGxlKCJIaXN0b2dyYW0gZm9yIHRoZSBtaWxsaW9ucyBvZiBzb2xkIGNvcGllcyBvZiBzcG9ydCB2aWRlb2dhbWVzIGluIHRoZSBFVSIpDQpgYGANCjxicj4NCg0KKiAqQm94cGxvdCBmb3IgdGhlIG51bWJlciBvZiB1c2VycyB3aG8gZ2F2ZSB0aGUgKnVzZXJfc2NvcmUqKjoNCmBgYHtyLCBmaWcuYWxpZ249ImNlbnRlciJ9DQpWaWRlb2dhbWVzICU+JQ0KIGdncGxvdChhZXMoeCA9IDEsIHkgPSBVc2VyX0NvdW50KSkgKw0KIGdlb21fYm94cGxvdCgpDQpgYGANCjxicj4NCg0KKiAqQm94cGxvdCBmb3IgdGhlIG51bWJlciBvZiB1c2VycyB3aG8gZ2F2ZSB0aGUgKnVzZXJfc2NvcmUqIC0gd2l0aG91dCBvdXRsaWVycyo6DQpgYGB7ciwgZmlnLmFsaWduPSJjZW50ZXIifQ0KVmlkZW9nYW1lc19ub19vdXQgPC0gVmlkZW9nYW1lcyAlPiUNCiAgbXV0YXRlKFVzZXJfT3V0bGllcnMgPSAxLjUgKiBJUVIoVXNlcl9Db3VudCwgbmEucm0gPSBUUlVFKSkgJT4lDQogIGZpbHRlcihVc2VyX0NvdW50IDw9IFVzZXJfT3V0bGllcnMpICU+JQ0KIGdncGxvdChhZXMoeCA9IDEsIHkgPSBVc2VyX0NvdW50KSkgKw0KIGdlb21fYm94cGxvdCgpDQoNClZpZGVvZ2FtZXNfbm9fb3V0DQpgYGANCjxicj4NCg0KIyMjICpTdW1tYXJpZXMqDQo8YnI+DQoNCiogTGV0J3MgZm9jdXMgb24gPHU+VWJpc29mdDwvdT46DQpgYGB7ciwgZmlnLmFsaWduPSJjZW50ZXIifQ0KVWJpc29mdF9SZXZpZXdzIDwtIGZpbHRlcihWaWRlb2dhbWVzLCBEZXZlbG9wZXIgPT0gIlViaXNvZnQiKSAlPiUNCiBnZ3Bsb3QoYWVzKHggPSAxLCB5ID0gVXNlcl9Db3VudCkpICsNCiBnZW9tX2JveHBsb3QoKQ0KDQpVYmlzb2Z0X1Jldmlld3MNCmBgYA0KPGJyPg0KDQoqICAqKk1lYW4gYW5kIG1lZGlhbioqIG9mIHRoZSBjb3BpZXMgc29sZCBpbiB0aGUgTm9ydGggQW1lcmljYSBieSBVYmlzb2Z0LCBieSBnZW5yZXM6DQpgYGB7cn0NClZpZGVvZ2FtZXMgJT4lDQogZmlsdGVyKERldmVsb3BlciA9PSAiVWJpc29mdCIpICU+JQ0KIGdyb3VwX2J5KEdlbnJlKSAlPiUNCiBzdW1tYXJpemUocm91bmQobWVhbihOQV9TYWxlcyksIDMpLA0KIG1lZGlhbihOQV9TYWxlcykpDQpgYGANCjxicj4NCg0KKiAgKkJveCBwbG90IG9mIHRoZSBudW1iZXIgb2YgY29waWVzIHNvbGQgaW4gdGhlIE5vcnRoIEFtZXJpY2EgYnkgVWJpc29mdCwgYnkgZ2VucmUqOg0KDQpgYGB7ciwgZmlnLmFsaWduPSJjZW50ZXIiLCB0aWR5PUZBTFNFfQ0KVWJpc29mdCA8LSBWaWRlb2dhbWVzICU+JQ0KICAgICAgICAgICAgZmlsdGVyKERldmVsb3BlciA9PSAiVWJpc29mdCIpDQoNCg0KVWJpc29mdCAlPiUNCiBnZ3Bsb3QoYWVzKHggPSBHZW5yZSwgeSA9IE5BX1NhbGVzKSkgKw0KIGdlb21fYm94cGxvdCgpDQpgYGANCjxicj4NCg0KIyMgUmVmZXJlbmNlcw0KW0RhdGEgV3JhbmdsaW5nIHdpdGggZHBseXIgYW5kIHRpZHlyIENoZWF0IFNoZWV0XShodHRwczovL3JzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE1LzAyL2RhdGEtd3JhbmdsaW5nLWNoZWF0c2hlZXQucGRmKQ0KDQpXaWNraGFtLCBILiAoMjAwOSkuIGdncGxvdDI6IEVsZWdhbnQgR3JhcGhpY3MgZm9yIERhdGEgQW5hbHlzaXMuIEF2YWlsYWJsZSBvbmxpbmU6DQpodHRwOi8vbW9kZXJuZ3JhcGhpY3MxMS5wYndvcmtzLmNvbS9mL2dncGxvdDItQm9vazA5aFdpY2toYW0ucGRmLg0KDQoNCltEYXRhIFZpc3VhbGl6YXRpb24gd2l0aCBnZ3Bsb3QyIENoZWF0IFNoZWV0XShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wMy9nZ3Bsb3QyLQ0KY2hlYXRzaGVldC5wZGYp