I gonna use R and Spark for a sample data exploration task to explore the R capabilites for using spark distributed data processing

Setup

There is almost no installations needed for this tutorial but here is the requried tools for running this script in your machine.

# checking if the Spark Home is declared as an enviroment variable by
# checking the existence of the SPARK_HOME Path variable and if not exist
# don't worry i will do it for you
if (nchar(Sys.getenv("SPARK_HOME")) < 1) {
    
    # download.file(url =
    # 'https://d3kbcqa49mib13.cloudfront.net/spark-2.2.0-bin-hadoop2.7.tgz',
    # destfile = 'spark-2.2.0-bin-hadoop2.7.tgz')
    # untar('spark-2.2.0-bin-hadoop2.7.tgz')
    Sys.setenv(SPARK_HOME = paste0(getwd(), "/spark-2.2.0-bin-hadoop2.7"))
}


- SparkR is an R package that provides a light-weight frontend to use Apache Spark from R. In Spark 2.2.0, SparkR provides a distributed data frame implementation that supports operations like selection, filtering, aggregation etc. (similar to R data frames, dplyr) but on large datasets. SparkR also supports distributed machine learning using MLlib.

- The entry point into SparkR is the SparkSession which connects your R program to a Spark cluster. You can create a SparkSession using sparkR.session and pass in options such as the application name, any spark packages depended on.

Creating SparkDataFrames

With a SparkSession, applications can create SparkDataFrames from

The following dataset represent the flights in 2015 for x airlines so my first step is to read the dataset i will depend on my analysis on Q/A style by asking some questions and trying to answer them by a simple graph

csvPath <- "data/flight-data/csv/2015-summary.csv"
df <- read.df(csvPath, "csv", header = "true", inferSchema = "true", na.strings = "NA")
head(df)

What is the top 10 country that people like to travel most?

new_df <- summarize(groupBy(df, df$DEST_COUNTRY_NAME), count = sum(df$count))
head(new_df)
plot_df <- as.data.frame(new_df) %>% dplyr::arrange(desc(count))

[Stage 10:=================>                                     (65 + 4) / 200]
[Stage 10:========================>                              (88 + 4) / 200]
[Stage 10:=============================>                        (108 + 4) / 200]
[Stage 10:====================================>                 (134 + 4) / 200]
[Stage 10:===========================================>          (162 + 4) / 200]
[Stage 10:===================================================>  (191 + 4) / 200]
                                                                                
plot_df$DEST_COUNTRY_NAME <- factor(plot_df$DEST_COUNTRY_NAME)
ggplotly({
p <- ggplot(plot_df[1:10,], aes(DEST_COUNTRY_NAME, count))
p + geom_point(aes(colour = DEST_COUNTRY_NAME, size = count))
})
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`
replacing previous import by ‘shiny::includeHTML’ when loading ‘crosstalk’replacing previous import by ‘shiny::knit_print.shiny.tag’ when loading ‘crosstalk’replacing previous import by ‘shiny::code’ when loading ‘crosstalk’replacing previous import by ‘shiny::includeScript’ when loading ‘crosstalk’replacing previous import by ‘shiny::includeMarkdown’ when loading ‘crosstalk’replacing previous import by ‘shiny::tags’ when loading ‘crosstalk’replacing previous import by ‘shiny::is.singleton’ when loading ‘crosstalk’replacing previous import by ‘shiny::withTags’ when loading ‘crosstalk’replacing previous import by ‘shiny::img’ when loading ‘crosstalk’replacing previous import by ‘shiny::tagAppendAttributes’ when loading ‘crosstalk’replacing previous import by ‘shiny::knit_print.shiny.tag.list’ when loading ‘crosstalk’replacing previous import by ‘shiny::knit_print.html’ when loading ‘crosstalk’replacing previous import by ‘shiny::tagAppendChild’ when loading ‘crosstalk’replacing previous import by ‘shiny::includeCSS’ when loading ‘crosstalk’replacing previous import by ‘shiny::br’ when loading ‘crosstalk’replacing previous import by ‘shiny::singleton’ when loading ‘crosstalk’replacing previous import by ‘shiny::span’ when loading ‘crosstalk’replacing previous import by ‘shiny::a’ when loading ‘crosstalk’replacing previous import by ‘shiny::tagList’ when loading ‘crosstalk’replacing previous import by ‘shiny::strong’ when loading ‘crosstalk’replacing previous import by ‘shiny::tag’ when loading ‘crosstalk’replacing previous import by ‘shiny::p’ when loading ‘crosstalk’replacing previous import by ‘shiny::validateCssUnit’ when loading ‘crosstalk’replacing previous import by ‘shiny::HTML’ when loading ‘crosstalk’replacing previous import by ‘shiny::h1’ when loading ‘crosstalk’replacing previous import by ‘shiny::h2’ when loading ‘crosstalk’replacing previous import by ‘shiny::h3’ when loading ‘crosstalk’replacing previous import by ‘shiny::h4’ when loading ‘crosstalk’replacing previous import by ‘shiny::h5’ when loading ‘crosstalk’replacing previous import by ‘shiny::h6’ when loading ‘crosstalk’replacing previous import by ‘shiny::tagAppendChildren’ when loading ‘crosstalk’replacing previous import by ‘shiny::em’ when loading ‘crosstalk’replacing previous import by ‘shiny::div’ when loading ‘crosstalk’replacing previous import by ‘shiny::pre’ when loading ‘crosstalk’replacing previous import by ‘shiny::htmlTemplate’ when loading ‘crosstalk’replacing previous import by ‘shiny::suppressDependencies’ when loading ‘crosstalk’replacing previous import by ‘shiny::tagSetChildren’ when loading ‘crosstalk’replacing previous import by ‘shiny::includeText’ when loading ‘crosstalk’replacing previous import by ‘shiny::hr’ when loading ‘crosstalk’

What is the top 10 country that people hate to travel most?

plot_df$DEST_COUNTRY_NAME <- factor(plot_df$DEST_COUNTRY_NAME)
n <- nrow(plot_df)
ggplotly({
  p <- ggplot(plot_df[(n-10):n,], aes(DEST_COUNTRY_NAME, count))
  p + geom_point(aes(colour = DEST_COUNTRY_NAME, size = count))
})
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

What is the top 10 country that people like to leave most?

new_df <- summarize(groupBy(df, df$ORIGIN_COUNTRY_NAME), count = sum(df$count))
head(new_df)
plot_df <- as.data.frame(new_df) %>% dplyr::arrange(desc(count))

[Stage 18:=============================>                        (110 + 4) / 200]
[Stage 18:========================================>             (151 + 4) / 200]
[Stage 18:===================================================>  (191 + 4) / 200]
                                                                                
plot_df$ORIGIN_COUNTRY_NAME <- factor(plot_df$ORIGIN_COUNTRY_NAME)
ggplotly({
  p <- ggplot(plot_df[1:10,], aes(ORIGIN_COUNTRY_NAME, count))
  p + geom_point(aes(colour = ORIGIN_COUNTRY_NAME, size = count))
})
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

What is the top 10 country that people hate to leave most?

plot_df$ORIGIN_COUNTRY_NAME <- factor(plot_df$ORIGIN_COUNTRY_NAME)
n <- nrow(plot_df)
ggplotly({
  p <- ggplot(plot_df[(n-10):n,], aes(ORIGIN_COUNTRY_NAME, count))
  p + geom_point(aes(colour = ORIGIN_COUNTRY_NAME, size = count))
})
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

What is the top 10 country that people like to travel to U.S ?

usa_flights_rdd <- filter(df, df$DEST_COUNTRY_NAME == "United States")
new_df <- summarize(groupBy(usa_flights_rdd, df$ORIGIN_COUNTRY_NAME), count = sum(df$count))
head(new_df)
plot_df <- as.data.frame(new_df) %>% dplyr::arrange(desc(count))

[Stage 26:===========================>                          (101 + 4) / 200]
[Stage 26:===================================>                  (131 + 4) / 200]
[Stage 26:=======================================>              (146 + 4) / 200]
[Stage 26:================================================>     (178 + 4) / 200]
                                                                                
plot_df$ORIGIN_COUNTRY_NAME <- factor(plot_df$ORIGIN_COUNTRY_NAME)
ggplotly({
  p <- ggplot(plot_df[1:10,], aes(ORIGIN_COUNTRY_NAME, count))
  p + geom_point(aes(colour = ORIGIN_COUNTRY_NAME, size = count))
})
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

What is the top 10 country that people hate to travel to U.S ?

plot_df$ORIGIN_COUNTRY_NAME <- factor(plot_df$ORIGIN_COUNTRY_NAME)
n <- nrow(plot_df)
ggplotly({
  p <- ggplot(plot_df[(n-10):n,], aes(ORIGIN_COUNTRY_NAME, count))
  p + geom_point(aes(colour = ORIGIN_COUNTRY_NAME, size = count))
})
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

References

LS0tCnRpdGxlOiAiRGF0YSBFeHBsb3JhdGlvbiBVc2luZyBSIGFuZCBTcGFyayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIyBJIGdvbm5hIHVzZSBSIGFuZCBTcGFyayBmb3IgYSBzYW1wbGUgZGF0YSBleHBsb3JhdGlvbiB0YXNrIHRvIGV4cGxvcmUgdGhlIFIgY2FwYWJpbGl0ZXMgZm9yIHVzaW5nIHNwYXJrIGRpc3RyaWJ1dGVkIGRhdGEgcHJvY2Vzc2luZwoKKipTZXR1cCoqIAoKVGhlcmUgaXMgYWxtb3N0IG5vIGluc3RhbGxhdGlvbnMgbmVlZGVkIGZvciB0aGlzIHR1dG9yaWFsIGJ1dCBoZXJlIGlzIHRoZSByZXF1cmllZCB0b29scyBmb3IgcnVubmluZyB0aGlzIHNjcmlwdCBpbiB5b3VyIG1hY2hpbmUuCgotIEphdmEgYW5kIGkgYXNzdW1lZCBpdCB3YXMgYWxyZWFkeSBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lIGFuZCB3aHkgamF2YSBhbmQgdGhlIGFuc3dlciBpcyB2ZXJ5IHNpbXBsZSAoIFNQQVJLIHdyaXR0ZW4gaW4gU2NhbGEgd2hpY2ggaXMgYSBKTVYgKipKYXZhIFZpcnR1YWwgTWFjaGluZSoqIGxhbmd1YWdlICkgeW91IGNhbiBkb3dubG9hZCBqYXZhIGZyb20gW2hlcmVdKGh0dHBzOi8vamF2YS5jb20vZW4vZG93bmxvYWQvKSBhbmQgdGhpcyBsaW5rIHdpbGwgaGVscCB5b3UgCgotIFNwYXJrIGxhc3Rlc3QgdmVyc2lvbiAyLjIgYmluYXJpZXMgYW5kIHlvdSBjYW4gZG93bmxvYWQgaXQgZnJvbSBbaGVyZV0oaHR0cHM6Ly9zcGFyay5hcGFjaGUub3JnL2Rvd25sb2Fkcy5odG1sKSBhbmQgZm9sbG93IHRoZSBzZXR1cCBpbnN0cnVjdGlvbiBpZiB5b3UgZG9uJ3Qgbm8gd29ycmllcyBpIHdpbGwgZG8gdGhpcyBzdGVwIGZvciB5b3UgOykgCgotIFIgdmVyc2lvbiAzIAoKLSBSIFN0dWRpbyB0byB3cml0ZSB0aGlzIG5vdGVib29rIAoKLSBnZ3Bsb3QyIGZvciBncmFwaHMKYGBge3IsIGVjaG89VFJVRSx0aWR5PVRSVUUscmVzdWx0cz0naGlkZSd9CiNjaGVja2luZyBpZiB0aGUgU3BhcmsgSG9tZSBpcyBkZWNsYXJlZCBhcyBhbiBlbnZpcm9tZW50IHZhcmlhYmxlIGJ5IGNoZWNraW5nIHRoZSBleGlzdGVuY2Ugb2YgdGhlIFNQQVJLX0hPTUUgUGF0aCB2YXJpYWJsZSBhbmQgaWYgbm90IGV4aXN0IGRvbid0IHdvcnJ5IGkgd2lsbCBkbyBpdCBmb3IgeW91CgppZiAobmNoYXIoU3lzLmdldGVudigiU1BBUktfSE9NRSIpKSA8IDEpIHsKICAgCiAgICAgICMgZG93bmxvYWQuZmlsZSh1cmwgPSAiaHR0cHM6Ly9kM2tiY3FhNDltaWIxMy5jbG91ZGZyb250Lm5ldC9zcGFyay0yLjIuMC1iaW4taGFkb29wMi43LnRneiIsCiAgICAgICMgICAgICAgICBkZXN0ZmlsZSA9ICJzcGFyay0yLjIuMC1iaW4taGFkb29wMi43LnRneiIpCiAgICAgICN1bnRhcigic3BhcmstMi4yLjAtYmluLWhhZG9vcDIuNy50Z3oiKQogICAgICBTeXMuc2V0ZW52KFNQQVJLX0hPTUUgPSBwYXN0ZTAoZ2V0d2QoKSwgIi9zcGFyay0yLjIuMC1iaW4taGFkb29wMi43IikpCn0KYGBgCjxici8+CgoqKi0gU3BhcmtSIGlzIGFuIFIgcGFja2FnZSB0aGF0IHByb3ZpZGVzIGEgbGlnaHQtd2VpZ2h0IGZyb250ZW5kIHRvIHVzZSBBcGFjaGUgU3BhcmsgZnJvbSBSLiBJbiBTcGFyayAyLjIuMCwgU3BhcmtSIHByb3ZpZGVzIGEgZGlzdHJpYnV0ZWQgZGF0YSBmcmFtZSBpbXBsZW1lbnRhdGlvbiB0aGF0IHN1cHBvcnRzIG9wZXJhdGlvbnMgbGlrZSBzZWxlY3Rpb24sIGZpbHRlcmluZywgYWdncmVnYXRpb24gZXRjLiAoc2ltaWxhciB0byBSIGRhdGEgZnJhbWVzLCBkcGx5cikgYnV0IG9uIGxhcmdlIGRhdGFzZXRzLiBTcGFya1IgYWxzbyBzdXBwb3J0cyBkaXN0cmlidXRlZCBtYWNoaW5lIGxlYXJuaW5nIHVzaW5nIE1MbGliLioqCgoqKi0gVGhlIGVudHJ5IHBvaW50IGludG8gU3BhcmtSIGlzIHRoZSBTcGFya1Nlc3Npb24gd2hpY2ggY29ubmVjdHMgeW91ciBSIHByb2dyYW0gdG8gYSBTcGFyayBjbHVzdGVyLiBZb3UgY2FuIGNyZWF0ZSBhIFNwYXJrU2Vzc2lvbiB1c2luZyBzcGFya1Iuc2Vzc2lvbiBhbmQgcGFzcyBpbiBvcHRpb25zIHN1Y2ggYXMgdGhlIGFwcGxpY2F0aW9uIG5hbWUsIGFueSBzcGFyayBwYWNrYWdlcyBkZXBlbmRlZCBvbi4qKgoKYGBge3IsIGVjaG89RkFMU0UsdGlkeT1UUlVFLHJlc3VsdHM9J2hpZGUnfQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBsb3RseSkKIyMgaW1wb3J0aW5nIHRoZSBTcGFya1IgbGlicmFyeSAKbGlicmFyeShTcGFya1IsIGxpYi5sb2MgPSBjKG5vcm1hbGl6ZVBhdGgoZmlsZS5wYXRoKFN5cy5nZXRlbnYoIlNQQVJLX0hPTUUiKSwgIlIiLCAibGliIikpKSkKCiMjIGNyZWF0ZSAKc3BhcmtSLnNlc3Npb24obWFzdGVyID0gImxvY2FsWypdIiwgc3BhcmtDb25maWcgPSBsaXN0KHNwYXJrLmRyaXZlci5tZW1vcnkgPSAiMmciKSkKYGBgCgojIyNDcmVhdGluZyBTcGFya0RhdGFGcmFtZXMKCldpdGggYSBTcGFya1Nlc3Npb24sIGFwcGxpY2F0aW9ucyBjYW4gY3JlYXRlIFNwYXJrRGF0YUZyYW1lcyBmcm9tIAoKLSBMb2NhbCBSIGRhdGEgZnJhbWUgZm9yIGV4YW1wbGUgKioiZGYgPC0gYXMuRGF0YUZyYW1lKGZhaXRoZnVsKSIqKi4KCi0gSGl2ZSB0YWJsZSAgZm9yIGV4YW1wbGUgKioicmVzdWx0cyA8LSBzcWwoJ0ZST00gc3JjIFNFTEVDVCBrZXksIHZhbHVlJykiKiouCgotIE90aGVyIGRhdGEgc291cmNlcyBhbmQgdGhhdCBpcyBvdXIgY2FzZSByZWFkaW5nIGRhdGEgZnJvbSBDU1YgZmlsZS4KClRoZSBmb2xsb3dpbmcgZGF0YXNldCByZXByZXNlbnQgdGhlIGZsaWdodHMgaW4gMjAxNSBmb3IgeCBhaXJsaW5lcyBzbyBteSBmaXJzdCBzdGVwIGlzIHRvIHJlYWQgdGhlIGRhdGFzZXQKaSB3aWxsIGRlcGVuZCBvbiBteSBhbmFseXNpcyBvbiBRL0Egc3R5bGUgYnkgYXNraW5nIHNvbWUgcXVlc3Rpb25zIGFuZCB0cnlpbmcgdG8gYW5zd2VyIHRoZW0gYnkgYSBzaW1wbGUgZ3JhcGgKYGBge3J9CmNzdlBhdGggPC0gImRhdGEvZmxpZ2h0LWRhdGEvY3N2LzIwMTUtc3VtbWFyeS5jc3YiCmRmIDwtIHJlYWQuZGYoY3N2UGF0aCwgImNzdiIsIGhlYWRlciA9ICJ0cnVlIiwgaW5mZXJTY2hlbWEgPSAidHJ1ZSIsIG5hLnN0cmluZ3MgPSAiTkEiKQpoZWFkKGRmKQpgYGAKCioqV2hhdCBpcyB0aGUgdG9wIDEwIGNvdW50cnkgdGhhdCBwZW9wbGUgbGlrZSB0byB0cmF2ZWwgbW9zdD8qKgpgYGB7ciwgZWNobz1UUlVFfQpuZXdfZGYgPC0gc3VtbWFyaXplKGdyb3VwQnkoZGYsIGRmJERFU1RfQ09VTlRSWV9OQU1FKSwgY291bnQgPSBzdW0oZGYkY291bnQpKQpoZWFkKG5ld19kZikKCnBsb3RfZGYgPC0gYXMuZGF0YS5mcmFtZShuZXdfZGYpICU+JSBkcGx5cjo6YXJyYW5nZShkZXNjKGNvdW50KSkKcGxvdF9kZiRERVNUX0NPVU5UUllfTkFNRSA8LSBmYWN0b3IocGxvdF9kZiRERVNUX0NPVU5UUllfTkFNRSkKCmdncGxvdGx5KHsKcCA8LSBnZ3Bsb3QocGxvdF9kZlsxOjEwLF0sIGFlcyhERVNUX0NPVU5UUllfTkFNRSwgY291bnQpKQpwICsgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gREVTVF9DT1VOVFJZX05BTUUsIHNpemUgPSBjb3VudCkpCn0pCmBgYAoKKipXaGF0IGlzIHRoZSB0b3AgMTAgY291bnRyeSB0aGF0IHBlb3BsZSBoYXRlIHRvIHRyYXZlbCBtb3N0PyoqCmBgYHtyLCBlY2hvPVRSVUV9CnBsb3RfZGYkREVTVF9DT1VOVFJZX05BTUUgPC0gZmFjdG9yKHBsb3RfZGYkREVTVF9DT1VOVFJZX05BTUUpCm4gPC0gbnJvdyhwbG90X2RmKQoKZ2dwbG90bHkoewogIHAgPC0gZ2dwbG90KHBsb3RfZGZbKG4tMTApOm4sXSwgYWVzKERFU1RfQ09VTlRSWV9OQU1FLCBjb3VudCkpCiAgcCArIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IERFU1RfQ09VTlRSWV9OQU1FLCBzaXplID0gY291bnQpKQp9KQpgYGAKCgoqKldoYXQgaXMgdGhlIHRvcCAxMCBjb3VudHJ5IHRoYXQgcGVvcGxlIGxpa2UgdG8gbGVhdmUgbW9zdD8qKgpgYGB7ciwgZWNobz1UUlVFfQpuZXdfZGYgPC0gc3VtbWFyaXplKGdyb3VwQnkoZGYsIGRmJE9SSUdJTl9DT1VOVFJZX05BTUUpLCBjb3VudCA9IHN1bShkZiRjb3VudCkpCmhlYWQobmV3X2RmKQoKcGxvdF9kZiA8LSBhcy5kYXRhLmZyYW1lKG5ld19kZikgJT4lIGRwbHlyOjphcnJhbmdlKGRlc2MoY291bnQpKQpwbG90X2RmJE9SSUdJTl9DT1VOVFJZX05BTUUgPC0gZmFjdG9yKHBsb3RfZGYkT1JJR0lOX0NPVU5UUllfTkFNRSkKCmdncGxvdGx5KHsKICBwIDwtIGdncGxvdChwbG90X2RmWzE6MTAsXSwgYWVzKE9SSUdJTl9DT1VOVFJZX05BTUUsIGNvdW50KSkKICBwICsgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gT1JJR0lOX0NPVU5UUllfTkFNRSwgc2l6ZSA9IGNvdW50KSkKfSkKYGBgCgoqKldoYXQgaXMgdGhlIHRvcCAxMCBjb3VudHJ5IHRoYXQgcGVvcGxlIGhhdGUgdG8gbGVhdmUgbW9zdD8qKgpgYGB7ciwgZWNobz1UUlVFfQpwbG90X2RmJE9SSUdJTl9DT1VOVFJZX05BTUUgPC0gZmFjdG9yKHBsb3RfZGYkT1JJR0lOX0NPVU5UUllfTkFNRSkKbiA8LSBucm93KHBsb3RfZGYpCmdncGxvdGx5KHsKICBwIDwtIGdncGxvdChwbG90X2RmWyhuLTEwKTpuLF0sIGFlcyhPUklHSU5fQ09VTlRSWV9OQU1FLCBjb3VudCkpCiAgcCArIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IE9SSUdJTl9DT1VOVFJZX05BTUUsIHNpemUgPSBjb3VudCkpCn0pCmBgYAoKCioqV2hhdCBpcyB0aGUgdG9wIDEwIGNvdW50cnkgdGhhdCBwZW9wbGUgbGlrZSB0byB0cmF2ZWwgdG8gVS5TID8qKgpgYGB7ciwgZWNobz1UUlVFfQoKdXNhX2ZsaWdodHNfcmRkIDwtIGZpbHRlcihkZiwgZGYkREVTVF9DT1VOVFJZX05BTUUgPT0gIlVuaXRlZCBTdGF0ZXMiKQoKbmV3X2RmIDwtIHN1bW1hcml6ZShncm91cEJ5KHVzYV9mbGlnaHRzX3JkZCwgZGYkT1JJR0lOX0NPVU5UUllfTkFNRSksIGNvdW50ID0gc3VtKGRmJGNvdW50KSkKaGVhZChuZXdfZGYpCgpwbG90X2RmIDwtIGFzLmRhdGEuZnJhbWUobmV3X2RmKSAlPiUgZHBseXI6OmFycmFuZ2UoZGVzYyhjb3VudCkpCnBsb3RfZGYkT1JJR0lOX0NPVU5UUllfTkFNRSA8LSBmYWN0b3IocGxvdF9kZiRPUklHSU5fQ09VTlRSWV9OQU1FKQoKZ2dwbG90bHkoewogIHAgPC0gZ2dwbG90KHBsb3RfZGZbMToxMCxdLCBhZXMoT1JJR0lOX0NPVU5UUllfTkFNRSwgY291bnQpKQogIHAgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBPUklHSU5fQ09VTlRSWV9OQU1FLCBzaXplID0gY291bnQpKQp9KQpgYGAKCioqV2hhdCBpcyB0aGUgdG9wIDEwIGNvdW50cnkgdGhhdCBwZW9wbGUgaGF0ZSB0byB0cmF2ZWwgdG8gVS5TID8qKgpgYGB7ciwgZWNobz1UUlVFfQpwbG90X2RmJE9SSUdJTl9DT1VOVFJZX05BTUUgPC0gZmFjdG9yKHBsb3RfZGYkT1JJR0lOX0NPVU5UUllfTkFNRSkKbiA8LSBucm93KHBsb3RfZGYpCmdncGxvdGx5KHsKICBwIDwtIGdncGxvdChwbG90X2RmWyhuLTEwKTpuLF0sIGFlcyhPUklHSU5fQ09VTlRSWV9OQU1FLCBjb3VudCkpCiAgcCArIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IE9SSUdJTl9DT1VOVFJZX05BTUUsIHNpemUgPSBjb3VudCkpCn0pCmBgYAoKCgojIyMgUmVmZXJlbmNlcyAKCi0gW1NwYXJrUiBUdXRvcmlhbHNdKGh0dHBzOi8vc3BhcmsuYXBhY2hlLm9yZy9kb2NzL2xhdGVzdC9zcGFya3IuaHRtbCkK