library(tidyverse)
library(tidytext)
library(skimr)
library(stopwords)
library(lubridate)
library(corrr)
library(forcats)
library(here)
df <- read_csv(here("data", "clean.csv"))
The fields we will be interested in:
- created_at
- language
- size
- license
- stars
- open_issues_count
- has_
The description will have its own analysis.
All analyses should be faceted by language.
Univariates
Let’s first look at repo stars.
df %>%
ggplot(aes(stars)) +
geom_density() +
scale_x_log10() +
facet_wrap(vars(language), scales = "free")

The stars distributions are very skewed, even after a log transform. This also makes sense as the majority of projects on Github are not well known. Javascript is weird as it has a less defined peak.
df %>%
mutate(language = fct_reorder(language, stars)) %>%
ggplot(aes(log(stars), language)) +
geom_boxplot()

The distribution of stars among the languages is about what you would expect for the Github crowd. Super general Python and web-friendly Javascript on top, highly specialized R on bottom.
List of the most popular projects for each language (under 100000 stars):
df %>%
group_by(language) %>%
slice_max(stars, n = 1) %>%
select(name, description, language)
Let’s now look at project size.
df %>%
ggplot(aes(size)) +
geom_density(fill = "blue") +
scale_x_log10() +
facet_wrap(vars(language), scales = "free")

It is also skewed, but a log transform seems to be sufficient in de-skewing it.
There are repos with size 0:
df %>% filter(size == 0)
Some of these are errors since the repos are clearly there. The jd-sec-maotai does seem to no longer be there, however. Very strange.
Let’s look at created_at:
df %>%
group_by(month = floor_date(created_at, "months"), language) %>%
count() %>%
ggplot(aes(month, n)) +
geom_line() +
facet_wrap(vars(language), scales = "free_x")

This looks very reasonable. Popular projects were created mostly around 2015-2018. Of course, since our data collection process filtered based on having the most stars, the most natural conclusion isn’t that project creations slowed down after 2018 (in fact, I would bet the opposite), but that there hasn’t been enough time for the later projects to accumulate enough stars.
Let’s turn to the number of open issues.
df %>%
ggplot(aes(open_issues_count)) +
geom_density() +
scale_x_log10() +
facet_wrap(vars(language), scales = "free")

R is different from the general programming languages in that they have more projects with less (or 0) issues.
log_df <- df %>%
mutate(
stars = log(stars),
size = log1p(size),
open_issues_count = log1p(open_issues_count)
)
Now let’s look at variation with stars/popularity
First up: size.
df %>%
ggplot(aes(size, stars)) +
geom_point() +
scale_x_log10() +
scale_y_log10() +
facet_wrap(vars(language), scales = "free")

There is an ever so slight positive correlations.
Let’s see what the owner type says about the number of stars.
df %>%
ggplot(aes(stars)) +
geom_density(aes(fill = owner), alpha = 0.5) +
scale_x_log10() +
facet_wrap(vars(language), scales = "free")

Repos with whose owners are organizations tend to have more stars than those with individual owners. This makes sense as organizations probably can make more expansive projects. Visually, it looks less pronounced in R, which also makes sense as R is probably the least commercial of all the languages.
df %>%
select(stars, owner, size, language) %>%
mutate(owner = owner == "Organization") %>%
group_by(language) %>%
group_map(\(x, y) list(
owner = cor(x$owner, log(x$stars)),
size = cor(log1p(x$size), log(x$stars)),
lang = y$language
)) %>%
map(\(x) do.call(tibble, x)) %>%
bind_rows()
df %>%
ggplot(aes(log(size))) +
geom_density(aes(fill = owner), alpha = 0.5) +
facet_wrap(~language, scales = "free")

As one would expect, organizations have larger projects than users, although this is more muted in R.
Licenses
Let’s now look at licenses. We will otherize less popular licenses and keep only the top 10.
lump_lic <- df %>%
mutate(license = license %>%
fct_lump(n = 10) %>%
fct_infreq() %>%
fct_rev())
lump_lic %>%
group_by(license, owner) %>%
count() %>%
ungroup() %>%
ggplot(aes(n, license)) +
geom_col(aes(fill = owner), position = "dodge")

We see that users are far more likely to have no license or use MIT and organizations are more likely to use more exotic licenses.
lump_lic %>%
mutate(stars = log(stars)) %>%
group_by(license) %>%
summarize(
log_stars = mean(stars),
n = n(),
lo = quantile(stars, 0.025),
hi = quantile(stars, 0.975)
) %>%
ggplot(aes(log_stars, license)) +
geom_point(aes(size = n)) +
geom_errorbarh(aes(xmin = lo, xmax = hi), height = 0.5) +
expand_limits(xmin = 0)

License has some weak correspondence with popularity, although having an exotic license or not having a license seems to have a stronger correspondence to having low popularity.
log_df %>%
ggplot(aes(open_issues_count, stars)) +
geom_point() +
facet_wrap(vars(language), scales = "free")

lm(stars ~ open_issues_count, data = log_df) %>% summary()
Call:
lm(formula = stars ~ open_issues_count, data = log_df)
Residuals:
Min 1Q Median 3Q Max
-3.5396 -0.6231 -0.0085 0.6382 5.7624
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.195080 0.011810 439.89 <2e-16 ***
open_issues_count 0.383307 0.004027 95.19 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1.072 on 31429 degrees of freedom
Multiple R-squared: 0.2238, Adjusted R-squared: 0.2237
F-statistic: 9060 on 1 and 31429 DF, p-value: < 2.2e-16
Stars are correlated with number of issues, which seems strange. One possibility is that this could be that it is confounded by size.
This will be hard to facet by language since different languages are at different scales, so let’s just look at Python, arguably the most broad language.
log_df %>%
filter(language == "python") %>%
ggplot(aes(size, open_issues_count)) +
geom_point(aes(color = stars)) +
scale_color_gradient2(low = "blue", high = "red", midpoint = 9)

log_df %>%
filter(language == "python") %>%
lm(formula = stars ~ size + open_issues_count) %>%
summary()
Call:
lm(formula = stars ~ size + open_issues_count, data = .)
Residuals:
Min 1Q Median 3Q Max
-1.8268 -0.5362 -0.1485 0.3642 4.4068
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.931197 0.034671 171.07 <2e-16 ***
size 0.043931 0.003992 11.00 <2e-16 ***
open_issues_count 0.220283 0.006662 33.06 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.7736 on 6587 degrees of freedom
Multiple R-squared: 0.1819, Adjusted R-squared: 0.1817
F-statistic: 732.4 on 2 and 6587 DF, p-value: < 2.2e-16
Well, it looks like even controlling for size, we still have a positive correlation between issues and stars (although far weaker).
The more likely explanation now is that popularity causes issues since the more eyes and users on your project means the more issues get unveiled.
YGBge3IsIGluY2x1ZGUgPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSBGQUxTRSkKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeXRleHQpCmxpYnJhcnkoc2tpbXIpCmxpYnJhcnkoc3RvcHdvcmRzKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShjb3JycikKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KGhlcmUpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmRmIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEiLCAiY2xlYW4uY3N2IikpCmBgYAoKVGhlIGZpZWxkcyB3ZSB3aWxsIGJlIGludGVyZXN0ZWQgaW46CgoqIGNyZWF0ZWRfYXQKKiBsYW5ndWFnZQoqIHNpemUKKiBsaWNlbnNlCiogc3RhcnMKKiBvcGVuX2lzc3Vlc19jb3VudAoqIGhhc18KClRoZSBkZXNjcmlwdGlvbiB3aWxsIGhhdmUgaXRzIG93biBhbmFseXNpcy4KCkFsbCBhbmFseXNlcyBzaG91bGQgYmUgZmFjZXRlZCBieSBsYW5ndWFnZS4KCiMjIFVuaXZhcmlhdGVzCgpMZXQncyBmaXJzdCBsb29rIGF0IHJlcG8gc3RhcnMuCgpgYGB7cn0KZGYgJT4lCiAgZ2dwbG90KGFlcyhzdGFycykpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBmYWNldF93cmFwKHZhcnMobGFuZ3VhZ2UpLCBzY2FsZXMgPSAiZnJlZSIpCmBgYAoKVGhlIHN0YXJzIGRpc3RyaWJ1dGlvbnMgYXJlIHZlcnkgc2tld2VkLCBldmVuIGFmdGVyIGEgbG9nIHRyYW5zZm9ybS4gIFRoaXMgYWxzbyBtYWtlcyBzZW5zZSBhcyB0aGUgbWFqb3JpdHkgb2YgcHJvamVjdHMgb24gR2l0aHViIGFyZSBub3Qgd2VsbCBrbm93bi4gIEphdmFzY3JpcHQgaXMgd2VpcmQgYXMgaXQgaGFzIGEgbGVzcyBkZWZpbmVkIHBlYWsuCgpgYGB7cn0KZGYgJT4lCiAgbXV0YXRlKGxhbmd1YWdlID0gZmN0X3Jlb3JkZXIobGFuZ3VhZ2UsIHN0YXJzKSkgJT4lCiAgZ2dwbG90KGFlcyhsb2coc3RhcnMpLCBsYW5ndWFnZSkpICsKICBnZW9tX2JveHBsb3QoKQpgYGAKClRoZSBkaXN0cmlidXRpb24gb2Ygc3RhcnMgYW1vbmcgdGhlIGxhbmd1YWdlcyBpcyBhYm91dCB3aGF0IHlvdSB3b3VsZCBleHBlY3QgZm9yIHRoZSBHaXRodWIgY3Jvd2QuICBTdXBlciBnZW5lcmFsIFB5dGhvbiBhbmQgd2ViLWZyaWVuZGx5IEphdmFzY3JpcHQgb24gdG9wLCBoaWdobHkgc3BlY2lhbGl6ZWQgUiBvbiBib3R0b20uCgpMaXN0IG9mIHRoZSBtb3N0IHBvcHVsYXIgcHJvamVjdHMgZm9yIGVhY2ggbGFuZ3VhZ2UgKHVuZGVyIDEwMDAwMCBzdGFycyk6CgpgYGB7cn0KZGYgJT4lCiAgZ3JvdXBfYnkobGFuZ3VhZ2UpICU+JQogIHNsaWNlX21heChzdGFycywgbiA9IDEpICU+JQogIHNlbGVjdChuYW1lLCBkZXNjcmlwdGlvbiwgbGFuZ3VhZ2UpCmBgYAoKTGV0J3Mgbm93IGxvb2sgYXQgcHJvamVjdCBzaXplLgoKYGBge3J9CmRmICU+JQogIGdncGxvdChhZXMoc2l6ZSkpICsKICBnZW9tX2RlbnNpdHkoZmlsbCA9ICJibHVlIikgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgZmFjZXRfd3JhcCh2YXJzKGxhbmd1YWdlKSwgc2NhbGVzID0gImZyZWUiKQpgYGAKCkl0IGlzIGFsc28gc2tld2VkLCBidXQgYSBsb2cgdHJhbnNmb3JtIHNlZW1zIHRvIGJlIHN1ZmZpY2llbnQgaW4gZGUtc2tld2luZyBpdC4KClRoZXJlIGFyZSByZXBvcyB3aXRoIHNpemUgMDoKCmBgYHtyfQpkZiAlPiUgZmlsdGVyKHNpemUgPT0gMCkKYGBgCgpTb21lIG9mIHRoZXNlIGFyZSBlcnJvcnMgc2luY2UgdGhlIHJlcG9zIGFyZSBjbGVhcmx5IHRoZXJlLiAgVGhlIGpkLXNlYy1tYW90YWkgZG9lcyBzZWVtIHRvIG5vIGxvbmdlciBiZSB0aGVyZSwgaG93ZXZlci4gIFZlcnkgc3RyYW5nZS4gCgpMZXQncyBsb29rIGF0IGNyZWF0ZWRfYXQ6CgpgYGB7cn0KZGYgJT4lCiAgZ3JvdXBfYnkobW9udGggPSBmbG9vcl9kYXRlKGNyZWF0ZWRfYXQsICJtb250aHMiKSwgbGFuZ3VhZ2UpICU+JQogIGNvdW50KCkgJT4lCiAgZ2dwbG90KGFlcyhtb250aCwgbikpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh2YXJzKGxhbmd1YWdlKSwgc2NhbGVzID0gImZyZWVfeCIpCmBgYAoKVGhpcyBsb29rcyB2ZXJ5IHJlYXNvbmFibGUuICBQb3B1bGFyIHByb2plY3RzIHdlcmUgY3JlYXRlZCBtb3N0bHkgYXJvdW5kIDIwMTUtMjAxOC4gIE9mIGNvdXJzZSwgc2luY2Ugb3VyIGRhdGEgY29sbGVjdGlvbiBwcm9jZXNzIGZpbHRlcmVkIGJhc2VkIG9uIGhhdmluZyB0aGUgbW9zdCBzdGFycywgdGhlIG1vc3QgbmF0dXJhbCBjb25jbHVzaW9uIGlzbid0IHRoYXQgcHJvamVjdCBjcmVhdGlvbnMgc2xvd2VkIGRvd24gYWZ0ZXIgMjAxOCAoaW4gZmFjdCwgSSB3b3VsZCBiZXQgdGhlIG9wcG9zaXRlKSwgYnV0IHRoYXQgdGhlcmUgaGFzbid0IGJlZW4gZW5vdWdoIHRpbWUgZm9yIHRoZSBsYXRlciBwcm9qZWN0cyB0byBhY2N1bXVsYXRlIGVub3VnaCBzdGFycy4KCkxldCdzIHR1cm4gdG8gdGhlIG51bWJlciBvZiBvcGVuIGlzc3Vlcy4KCmBgYHtyfQpkZiAlPiUKICBnZ3Bsb3QoYWVzKG9wZW5faXNzdWVzX2NvdW50KSkgKwogIGdlb21fZGVuc2l0eSgpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIGZhY2V0X3dyYXAodmFycyhsYW5ndWFnZSksIHNjYWxlcyA9ICJmcmVlIikKYGBgCgpSIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBnZW5lcmFsIHByb2dyYW1taW5nIGxhbmd1YWdlcyBpbiB0aGF0IHRoZXkgaGF2ZSBtb3JlIHByb2plY3RzIHdpdGggbGVzcyAob3IgMCkgaXNzdWVzLgoKYGBge3J9CmxvZ19kZiA8LSBkZiAlPiUKICBtdXRhdGUoCiAgICBzdGFycyA9IGxvZyhzdGFycyksCiAgICBzaXplID0gbG9nMXAoc2l6ZSksCiAgICBvcGVuX2lzc3Vlc19jb3VudCA9IGxvZzFwKG9wZW5faXNzdWVzX2NvdW50KQogICkKYGBgCgoKIyMgTm93IGxldCdzIGxvb2sgYXQgdmFyaWF0aW9uIHdpdGggc3RhcnMvcG9wdWxhcml0eQoKRmlyc3QgdXA6IHNpemUuCgpgYGB7cn0KZGYgJT4lCiAgZ2dwbG90KGFlcyhzaXplLCBzdGFycykpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICBmYWNldF93cmFwKHZhcnMobGFuZ3VhZ2UpLCBzY2FsZXMgPSAiZnJlZSIpCmBgYAoKVGhlcmUgaXMgYW4gZXZlciBzbyBzbGlnaHQgcG9zaXRpdmUgY29ycmVsYXRpb25zLgoKTGV0J3Mgc2VlIHdoYXQgdGhlIG93bmVyIHR5cGUgc2F5cyBhYm91dCB0aGUgbnVtYmVyIG9mIHN0YXJzLgoKYGBge3J9CmRmICU+JQogIGdncGxvdChhZXMoc3RhcnMpKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyhmaWxsID0gb3duZXIpLCBhbHBoYSA9IDAuNSkgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgZmFjZXRfd3JhcCh2YXJzKGxhbmd1YWdlKSwgc2NhbGVzID0gImZyZWUiKQpgYGAKClJlcG9zIHdpdGggd2hvc2Ugb3duZXJzIGFyZSBvcmdhbml6YXRpb25zIHRlbmQgdG8gaGF2ZSBtb3JlIHN0YXJzIHRoYW4gdGhvc2Ugd2l0aCBpbmRpdmlkdWFsIG93bmVycy4gIFRoaXMgbWFrZXMgc2Vuc2UgYXMgb3JnYW5pemF0aW9ucyBwcm9iYWJseSBjYW4gbWFrZSBtb3JlIGV4cGFuc2l2ZSBwcm9qZWN0cy4gIFZpc3VhbGx5LCBpdCBsb29rcyBsZXNzIHByb25vdW5jZWQgaW4gUiwgd2hpY2ggYWxzbyBtYWtlcyBzZW5zZSBhcyBSIGlzIHByb2JhYmx5IHRoZSBsZWFzdCBjb21tZXJjaWFsIG9mIGFsbCB0aGUgbGFuZ3VhZ2VzLgoKYGBge3J9CmRmICU+JQogIHNlbGVjdChzdGFycywgb3duZXIsIHNpemUsIGxhbmd1YWdlKSAlPiUKICBtdXRhdGUob3duZXIgPSBvd25lciA9PSAiT3JnYW5pemF0aW9uIikgJT4lCiAgZ3JvdXBfYnkobGFuZ3VhZ2UpICU+JQogIGdyb3VwX21hcChcKHgsIHkpIGxpc3QoCiAgICBvd25lciA9IGNvcih4JG93bmVyLCBsb2coeCRzdGFycykpLAogICAgc2l6ZSA9IGNvcihsb2cxcCh4JHNpemUpLCBsb2coeCRzdGFycykpLAogICAgbGFuZyA9IHkkbGFuZ3VhZ2UKICApKSAlPiUKICBtYXAoXCh4KSBkby5jYWxsKHRpYmJsZSwgeCkpICU+JQogIGJpbmRfcm93cygpCmBgYAoKYGBge3J9CmRmICU+JQogIGdncGxvdChhZXMobG9nKHNpemUpKSkgKwogIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IG93bmVyKSwgYWxwaGEgPSAwLjUpICsKICBmYWNldF93cmFwKH5sYW5ndWFnZSwgc2NhbGVzID0gImZyZWUiKQpgYGAKCkFzIG9uZSB3b3VsZCBleHBlY3QsIG9yZ2FuaXphdGlvbnMgaGF2ZSBsYXJnZXIgcHJvamVjdHMgdGhhbiB1c2VycywgYWx0aG91Z2ggdGhpcyBpcyBtb3JlIG11dGVkIGluIFIuCgojIyBMaWNlbnNlcwoKTGV0J3Mgbm93IGxvb2sgYXQgbGljZW5zZXMuICBXZSB3aWxsIG90aGVyaXplIGxlc3MgcG9wdWxhciBsaWNlbnNlcyBhbmQga2VlcCBvbmx5IHRoZSB0b3AgMTAuCgpgYGB7cn0KbHVtcF9saWMgPC0gZGYgJT4lCiAgbXV0YXRlKGxpY2Vuc2UgPSBsaWNlbnNlICU+JQogICAgZmN0X2x1bXAobiA9IDEwKSAlPiUKICAgIGZjdF9pbmZyZXEoKSAlPiUKICAgIGZjdF9yZXYoKSkKCmx1bXBfbGljICU+JQogIGdyb3VwX2J5KGxpY2Vuc2UsIG93bmVyKSAlPiUKICBjb3VudCgpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoYWVzKG4sIGxpY2Vuc2UpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGwgPSBvd25lciksIHBvc2l0aW9uID0gImRvZGdlIikKYGBgCgpXZSBzZWUgdGhhdCB1c2VycyBhcmUgZmFyIG1vcmUgbGlrZWx5IHRvIGhhdmUgbm8gbGljZW5zZSBvciB1c2UgTUlUIGFuZCBvcmdhbml6YXRpb25zIGFyZSBtb3JlIGxpa2VseSB0byB1c2UgbW9yZSBleG90aWMgbGljZW5zZXMuCgpgYGB7cn0KbHVtcF9saWMgJT4lCiAgbXV0YXRlKHN0YXJzID0gbG9nKHN0YXJzKSkgJT4lCiAgZ3JvdXBfYnkobGljZW5zZSkgJT4lCiAgc3VtbWFyaXplKAogICAgbG9nX3N0YXJzID0gbWVhbihzdGFycyksCiAgICBuID0gbigpLAogICAgbG8gPSBxdWFudGlsZShzdGFycywgMC4wMjUpLAogICAgaGkgPSBxdWFudGlsZShzdGFycywgMC45NzUpCiAgKSAlPiUKICBnZ3Bsb3QoYWVzKGxvZ19zdGFycywgbGljZW5zZSkpICsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gbikpICsKICBnZW9tX2Vycm9yYmFyaChhZXMoeG1pbiA9IGxvLCB4bWF4ID0gaGkpLCBoZWlnaHQgPSAwLjUpICsKICBleHBhbmRfbGltaXRzKHhtaW4gPSAwKQpgYGAKCkxpY2Vuc2UgaGFzIHNvbWUgd2VhayBjb3JyZXNwb25kZW5jZSB3aXRoIHBvcHVsYXJpdHksIGFsdGhvdWdoIGhhdmluZyBhbiBleG90aWMgbGljZW5zZSBvciAqbm90KiBoYXZpbmcgYSBsaWNlbnNlIHNlZW1zIHRvIGhhdmUgYSBzdHJvbmdlciBjb3JyZXNwb25kZW5jZSB0byBoYXZpbmcgbG93IHBvcHVsYXJpdHkuCgpgYGB7cn0KbG9nX2RmICU+JQogIGdncGxvdChhZXMob3Blbl9pc3N1ZXNfY291bnQsIHN0YXJzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh2YXJzKGxhbmd1YWdlKSwgc2NhbGVzID0gImZyZWUiKQoKbG0oc3RhcnMgfiBvcGVuX2lzc3Vlc19jb3VudCwgZGF0YSA9IGxvZ19kZikgJT4lIHN1bW1hcnkoKQpgYGAKClN0YXJzIGFyZSBjb3JyZWxhdGVkIHdpdGggbnVtYmVyIG9mIGlzc3Vlcywgd2hpY2ggc2VlbXMgc3RyYW5nZS4gIE9uZSBwb3NzaWJpbGl0eSBpcyB0aGF0IHRoaXMgY291bGQgYmUgdGhhdCBpdCBpcyBjb25mb3VuZGVkIGJ5IHNpemUuCgpUaGlzIHdpbGwgYmUgaGFyZCB0byBmYWNldCBieSBsYW5ndWFnZSBzaW5jZSBkaWZmZXJlbnQgbGFuZ3VhZ2VzIGFyZSBhdCBkaWZmZXJlbnQgc2NhbGVzLCBzbyBsZXQncyBqdXN0IGxvb2sgYXQgUHl0aG9uLCBhcmd1YWJseSB0aGUgbW9zdCBicm9hZCBsYW5ndWFnZS4KCmBgYHtyfQpsb2dfZGYgJT4lCiAgZmlsdGVyKGxhbmd1YWdlID09ICJweXRob24iKSAlPiUKICBnZ3Bsb3QoYWVzKHNpemUsIG9wZW5faXNzdWVzX2NvdW50KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gc3RhcnMpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDkpCgpsb2dfZGYgJT4lCiAgZmlsdGVyKGxhbmd1YWdlID09ICJweXRob24iKSAlPiUKICBsbShmb3JtdWxhID0gc3RhcnMgfiBzaXplICsgb3Blbl9pc3N1ZXNfY291bnQpICU+JQogIHN1bW1hcnkoKQpgYGAKCldlbGwsIGl0IGxvb2tzIGxpa2UgZXZlbiBjb250cm9sbGluZyBmb3Igc2l6ZSwgd2Ugc3RpbGwgaGF2ZSBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gaXNzdWVzIGFuZCBzdGFycyAoYWx0aG91Z2ggZmFyIHdlYWtlcikuCgpUaGUgbW9yZSBsaWtlbHkgZXhwbGFuYXRpb24gbm93IGlzIHRoYXQgcG9wdWxhcml0eSBjYXVzZXMgaXNzdWVzIHNpbmNlIHRoZSBtb3JlIGV5ZXMgYW5kIHVzZXJzIG9uIHlvdXIgcHJvamVjdCBtZWFucyB0aGUgbW9yZSBpc3N1ZXMgZ2V0IHVudmVpbGVkLgo=