devtools::install_github("hrbrmstr/speedtest") 
Downloading GitHub repo hrbrmstr/speedtest@master
from URL https://api.github.com/repos/hrbrmstr/speedtest/zipball/master
Installing speedtest
"C:/PROGRA~1/R/R-34~1.2/bin/x64/R" --no-site-file --no-environ --no-save  \
  --no-restore --quiet CMD INSTALL  \
  "C:/Users/rcleo/AppData/Local/Temp/RtmpwXfh7H/devtools36e05e812c57/hrbrmstr-speedtest-f635a99"  \
  --library="C:/Users/rcleo/Documents/R/win-library/3.4" --install-tests 
* installing *source* package 'speedtest' ...
** R
** tests
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
*** arch - i386
*** arch - x64
* DONE (speedtest)
library(speedtest)
Warning message:
In readLines(input, encoding = "UTF-8") :
  incomplete final line found on 'C:/Users/rcleo/Documents/R/win-library/3.4/raw/rmarkdown/templates/reserveReview/template.yaml'
library(stringi)
library(hrbrthemes)
library(ggbeeswarm)
Carregando pacotes exigidos: ggplot2
library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.2.0 --
v tibble  1.3.4     v purrr   0.2.4
v tidyr   0.7.2     v dplyr   0.7.4
v readr   1.1.1     v stringr 1.2.0
v tibble  1.3.4     v forcats 0.2.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
config <- spd_config()
servers <- spd_servers(config=config)
closest_servers <- spd_closest_servers(servers, config=config)
only_the_best_severs <- spd_best_servers(closest_servers, config)
glimpse(spd_download_test(closest_servers[1,], config=config))

|===========                                            | 20% ~1 s remaining     
|================                                       | 30% ~1 s remaining     
|======================                                 | 40% ~1 s remaining     
|===========================                            | 50% ~1 s remaining     
|=================================                      | 60% ~2 s remaining     
|======================================                 | 70% ~2 s remaining     
|============================================           | 80% ~2 s remaining     
|=================================================      | 90% ~2 s remaining     
|=======================================================|100% ~0 s remaining     Observations: 1
Variables: 15
$ url     <chr> "http://st1.zamix.com.br/speedtest/upload.php"
$ lat     <dbl> -22.5228
$ lng     <dbl> -44.1039
$ name    <chr> "Volta Redonda"
$ country <chr> "Brazil"
$ cc      <chr> "BR"
$ sponsor <chr> "SuperOnda/Zamix"
$ id      <chr> "6536"
$ host    <chr> "st1.zamix.com.br:8080"
$ url2    <chr> "http://st2.zamix.com.br/speedtest/upload.php"
$ min     <dbl> 15.35344
$ mean    <dbl> 25.90716
$ median  <dbl> 24.74659
$ max     <dbl> 40.07601
$ sd      <dbl> 7.048748
## Observations: 1
## Variables: 15
## $ url      "http://speed0.xcelx.net/speedtest/upload.php"
## $ lat      42.3875
## $ lng      -71.1
## $ name     "Somerville, MA"
## $ country  "United States"
## $ cc       "US"
## $ sponsor  "Axcelx Technologies LLC"
## $ id       "5960"
## $ host     "speed0.xcelx.net:8080"
## $ url2     "http://speed1.xcelx.net/speedtest/upload.php"
## $ min      14.40439
## $ mean     60.06834
## $ median   55.28457
## $ max      127.9436
## $ sd       34.20695
glimpse(spd_upload_test(only_the_best_severs[1,], config=config))

|==================                                     | 33% ~1 s remaining     
|===========================                            | 50% ~1 s remaining     
|====================================                   | 67% ~1 s remaining     
|=============================================          | 83% ~1 s remaining     
|=======================================================|100% ~0 s remaining     Observations: 1
Variables: 17
$ total_time     <dbl> 0.219
$ retrieval_time <dbl> 0
$ url            <chr> "http://189.50.144.249/speedtest/speedtest/upload.php"
$ lat            <dbl> -22.1124
$ lng            <dbl> -45.028
$ name           <chr> "Sao Lourenco"
$ country        <chr> "Brazil"
$ cc             <chr> "BR"
$ sponsor        <chr> "StarWeb"
$ id             <chr> "14377"
$ host           <chr> "189.50.144.249:8080"
$ url2           <chr> NA
$ min            <dbl> 4.096
$ mean           <dbl> 6.273526
$ median         <dbl> 6.250487
$ max            <dbl> 8.445378
$ sd             <dbl> 1.749677
## Observations: 1
## Variables: 18
## $ ping_time       0.02712567
## $ total_time      0.059917
## $ retrieval_time  2.3e-05
## $ url             "http://speed0.xcelx.net/speedtest/upload.php"
## $ lat             42.3875
## $ lng             -71.1
## $ name            "Somerville, MA"
## $ country         "United States"
## $ cc              "US"
## $ sponsor         "Axcelx Technologies LLC"
## $ id              "5960"
## $ host            "speed0.xcelx.net:8080"
## $ url2            "http://speed1.xcelx.net/speedtest/upload.php"
## $ min             6.240858
## $ mean            9.527599
## $ median          9.303148
## $ max             12.56686
## $ sd              2.451778

Welcome!
Here you will find daily news and tutorials about R, contributed by over 750 bloggers.
There are many ways to follow us -
By e-mail:
On Facebook:
If you are an R blogger yourself you are invited to add your own R content feed to this site (Non-English R bloggers should add themselves- here)
RSS Jobs for R-users

    Rays Research & Development Analyst
    PROGRAMMER/SOFTWARE DEVELOPMENT ENGINEER/COMPUTATIONAL AND MACHINE LEARNING SPECIALIST
    Quantitative Econometrician @ San Francisco, California, U.S.
    Postdoctoral Research Fellow in Healthcare Systems Engineering @ Maryland, U.S.
    R Programmer & Statistician for Academic Research

Popular Searches
Recent Posts

    Measuring & Monitoring Internet Speed with R
    Creating integer64 and nanotime vectors in C++
    Stan Roundup, 10 November 2017
    .rprofile: Mara Averick
    Gold-Mining – Week 10 (2017)
    Recap: EARL Boston 2017
    Announcing “Introduction to the Tidyverse”, my new DataCamp course
    R live class | R with Database and Big Data | Nov 21-22 Milan
    How Happy is Your Country? — Happy Planet Index Visualized
    Formal ways to compare forecasting models: Rolling windows
    Introduction to Visualizing Asset Returns
    bridgesampling [R package]
    Calculating the house edge of a slot machine, with R
    Creating Reporting Template with Glue in R
    R / Finance 2018 Call for Papers

Other sites

    Jobs for R-users
    SAS blogs

Measuring & Monitoring Internet Speed with R
November 11, 2017
By hrbrmstr

inShare4
(This article was first published on R – rud.is, and kindly contributed to R-bloggers)

72
SHARES
Share
Tweet

Working remotely has many benefits, but if you work remotely in an area like, say, rural Maine, one of those benefits is not massively speedy internet connections. Being able to go fast and furious on the internet is one of the many things I miss about our time in Seattle and it is unlikely that we’ll be seeing Google Fiber in my small town any time soon. One other issue is that residential plans from evil giants like Comcast come with things like “bandwidth caps”. I suspect many WFH-ers can live within those limits, but I work with internet-scale data and often shunt extracts or whole datasets to the DatCave™ server farm for local processing. As such, I pay an extra penalty as a Comcast “Business-class” user that has little benefit besides getting slightly higher QoS and some faster service response times when there are issues.

Why go into all that? Well, I recently decided to bump up the connection from 100 Mb/s to 150 Mb/s (and managed to do so w/o increasing the overall monthly bill at all) but wanted to have a way to regularly verify I am getting what I’m paying for without having to go to an interactive “speed test” site.

There’s a handy speedtest-cli攼㹤愼㸰戼㹤攼㹤戼㸴㤼㸷, which is a python-based module with a command-line interface that can perform speed tests against Ookla’s legacy server. (You’ll notice that link forwards you to their new socket-based test service; neither speedtest-cli nor the code in the package being shown here uses that yet)

I run plenty of ruby, python, node and go (et al) programs on the command-line, but I wanted a way to measure this in R-proper (storing individual test results) on a regular basis as well as run something from the command-line whenever I wanted an interactive test. Thus begat speedtest攼㹤愼㸰戼㹤攼㹤戼㸴㤼㸷.
Testing the Need for Speed

After you devtools::install_github("hrbrmstr/speedtest") the package, you can either type speedtest::spd_test() at an R console or Rscript --quiet -e 'speedtest::spd_test()' on the command-line to see something like the following:

What you see there is a short-hand version of what’s available in the package:

    spd_best_servers: Find “best” servers (latency-wise) from master server list
    spd_closest_servers: Find “closest” servers (geography-wise) from master server list
    spd_compute_bandwidth: Compute bandwidth from bytes transferred and time taken
    spd_config: Retrieve client configuration information for the speedtest
    spd_download_test: Perform a download speed/bandwidth test
    spd_servers: Retrieve a list of SpeedTest servers
    spd_upload_test: Perform an upload speed/bandwidth test
    spd_test: Test your internet speed/bandwidth

The general idiom is to grab the test configuration file, collect the master list of servers, figure out which servers you’re going to test against and perform upload/download tests + collect the resultant statistics:

library(speedtest)
library(stringi)
library(hrbrthemes)
library(ggbeeswarm)
library(tidyverse)

config <- spd_config()

servers <- spd_servers(config=config)
closest_servers <- spd_closest_servers(servers, config=config)
only_the_best_severs <- spd_best_servers(closest_servers, config)

glimpse(spd_download_test(closest_servers[1,], config=config))
## Observations: 1
## Variables: 15
## $ url      "http://speed0.xcelx.net/speedtest/upload.php"
## $ lat      42.3875
## $ lng      -71.1
## $ name     "Somerville, MA"
## $ country  "United States"
## $ cc       "US"
## $ sponsor  "Axcelx Technologies LLC"
## $ id       "5960"
## $ host     "speed0.xcelx.net:8080"
## $ url2     "http://speed1.xcelx.net/speedtest/upload.php"
## $ min      14.40439
## $ mean     60.06834
## $ median   55.28457
## $ max      127.9436
## $ sd       34.20695

glimpse(spd_upload_test(only_the_best_severs[1,], config=config))
## Observations: 1
## Variables: 18
## $ ping_time       0.02712567
## $ total_time      0.059917
## $ retrieval_time  2.3e-05
## $ url             "http://speed0.xcelx.net/speedtest/upload.php"
## $ lat             42.3875
## $ lng             -71.1
## $ name            "Somerville, MA"
## $ country         "United States"
## $ cc              "US"
## $ sponsor         "Axcelx Technologies LLC"
## $ id              "5960"
## $ host            "speed0.xcelx.net:8080"
## $ url2            "http://speed1.xcelx.net/speedtest/upload.php"
## $ min             6.240858
## $ mean            9.527599
## $ median          9.303148
## $ max             12.56686
## $ sd              2.451778
set.seed(8675309)
bind_rows(
  closest_servers[1:3,] %>%
    mutate(type="closest"),
  only_the_best_severs[1:3,] %>%
    mutate(type="best"),
  filter(servers, !(id %in% c(closest_servers[1:3,]$id, only_the_best_severs[1:3,]$id))) %>%
    sample_n(3) %>%
    mutate(type="random")
) %>%
  group_by(type) %>%
  ungroup() -> to_compare
select(to_compare, sponsor, name, country, host, type)
map_df(1:nrow(to_compare), ~{
  spd_download_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30)
}) -> dl_results_full

|==========                                            | 20% ~3 s remaining     
|================                                      | 30% ~6 s remaining     
|=====================                                 | 40% ~7 s remaining     
|===========================                           | 50% ~7 s remaining     
|================================                      | 60% ~7 s remaining     
|=====================================                 | 70% ~6 s remaining     
|===========================================           | 80% ~9 s remaining     
|================================================      | 90% ~7 s remaining     
|======================================================|100% ~0 s remaining     
|==========                                            | 20% ~4 s remaining     
|================                                      | 30% ~4 s remaining     
|=====================                                 | 40% ~4 s remaining     
|===========================                           | 50% ~5 s remaining     
|================================                      | 60% ~8 s remaining     
|=====================================                 | 70% ~12 s remaining    
|===========================================           | 80% ~12 s remaining    
|================================================      | 90% ~8 s remaining     
|======================================================|100% ~0 s remaining     
|==========                                            | 20% ~3 s remaining     
|================                                      | 30% ~13 s remaining    
|=====================                                 | 40% ~22 s remaining    
|===========================                           | 50% ~22 s remaining    
|================================                      | 60% ~26 s remaining    
|=====================================                 | 70% ~29 s remaining    
|===========================================           | 80% ~25 s remaining    
|================================================      | 90% ~14 s remaining    
|======================================================|100% ~0 s remaining     
|==========                                            | 20% ~3 s remaining     
|================                                      | 30% ~9 s remaining     
|=====================                                 | 40% ~31 s remaining    
|===========================                           | 50% ~50 s remaining    
|================================                      | 60% ~54 s remaining    
|=====================================                 | 70% ~47 s remaining    
|===========================================           | 80% ~35 s remaining    
|================================================      | 90% ~19 s remaining    
|======================================================|100% ~0 s remaining     
|==========                                            | 20% ~5 s remaining     
|================                                      | 30% ~5 s remaining     
|=====================                                 | 40% ~8 s remaining     
|===========================                           | 50% ~13 s remaining    
|================================                      | 60% ~16 s remaining    
|=====================================                 | 70% ~17 s remaining    
|===========================================           | 80% ~16 s remaining    
|================================================      | 90% ~9 s remaining     
|======================================================|100% ~0 s remaining     
|==========                                            | 20% ~4 s remaining     
|================                                      | 30% ~5 s remaining     
|=====================                                 | 40% ~12 s remaining    
|===========================                           | 50% ~14 s remaining    
|================================                      | 60% ~11 s remaining    
|=====================================                 | 70% ~20 s remaining    
|===========================================           | 80% ~14 s remaining    
|================================================      | 90% ~10 s remaining    
|======================================================|100% ~0 s remaining     
|============                                                  | 20% ~16 s remaining    
|==================                                            | 30% ~11 s remaining    
|========================                                      | 40% ~9 s remaining     
|===============================                               | 50% ~8 s remaining     
|=====================================                         | 60% ~9 s remaining     
|===========================================                   | 70% ~19 s remaining    
|=================================================             | 80% ~18 s remaining    
|=======================================================       | 90% ~11 s remaining    
|==============================================================|100% ~0 s remaining     
|============                                                  | 20% ~21 s remaining    
|==================                                            | 30% ~28 s remaining    
|========================                                      | 40% ~38 s remaining    
|===============================                               | 50% ~55 s remaining    
|=====================================                         | 60% ~57 s remaining    
|===========================================                   | 70% ~50 s remaining    
|=================================================             | 80% ~36 s remaining    
|=======================================================       | 90% ~20 s remaining    
|==============================================================|100% ~0 s remaining     
|============                                                  | 20% ~29 s remaining    
|==================                                            | 30% ~1 m remaining     
|========================                                      | 40% ~1 m remaining     
|===============================                               | 50% ~1 m remaining     
|=====================================                         | 60% ~1 m remaining     
|===========================================                   | 70% ~58 s remaining    
|=================================================             | 80% ~42 s remaining    
|=======================================================       | 90% ~22 s remaining    
|==============================================================|100% ~0 s remaining     
mutate(dl_results_full, type=stri_trans_totitle(type)) %>%
  ggplot(aes(type, bw, fill=type)) +
  geom_quasirandom(aes(size=size, color=type), width=0.15, shape=21, stroke=0.25) +
  scale_y_continuous(expand=c(0,5), labels=c(sprintf("%s", seq(0,150,50)), "200 Mb/s"), limits=c(0,200)) +
  scale_size(range=c(2,6)) +
  scale_color_manual(values=c(Random="#b2b2b2", Best="#2b2b2b", Closest="#2b2b2b")) +
  scale_fill_ipsum() +
  labs(x=NULL, y=NULL, title="Download bandwidth test by selected server type",
       subtitle="Circle size scaled by size of file used in that speed test") +
  theme_ipsum_rc(grid="Y") +
  theme(legend.position="none")

bind_rows(
  closest_servers[1:3,] %>% mutate(type="closest"),
  only_the_best_severs[1:3,] %>% mutate(type="best")
) %>%
  distinct(.keep_all=TRUE) -> to_compare
select(to_compare, sponsor, name, country, host, type)
map_df(1:nrow(to_compare), ~{
  spd_upload_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30)
}) -> ul_results_full

|===========================                                                      | 33% ~17 s remaining    
|========================================                                         | 50% ~10 s remaining    
|======================================================                           | 67% ~6 s remaining     
|===================================================================              | 83% ~3 s remaining     
|=================================================================================|100% ~0 s remaining     
|===========================                                                      | 33% ~1 s remaining     
|========================================                                         | 50% ~1 s remaining     
|======================================================                           | 67% ~1 s remaining     
|===================================================================              | 83% ~1 s remaining     
|=================================================================================|100% ~0 s remaining     
|===========================                                                      | 33% ~8 s remaining     
|========================================                                         | 50% ~5 s remaining     
|======================================================                           | 67% ~3 s remaining     
|===================================================================              | 83% ~1 s remaining     
|=================================================================================|100% ~0 s remaining     
|===========================                                                      | 33% ~1 s remaining     
|========================================                                         | 50% ~1 s remaining     
|======================================================                           | 67% ~1 s remaining     
|===================================================================              | 83% ~1 s remaining     
|=================================================================================|100% ~0 s remaining     
|===========================                                                      | 33% ~3 s remaining     
|========================================                                         | 50% ~2 s remaining     
|======================================================                           | 67% ~1 s remaining     
|===================================================================              | 83% ~1 s remaining     
|=================================================================================|100% ~0 s remaining     
|===========================                                                      | 33% ~1 s remaining     
|========================================                                         | 50% ~1 s remaining     
|======================================================                           | 67% ~1 s remaining     
|===================================================================              | 83% ~1 s remaining     
|=================================================================================|100% ~0 s remaining     
ggplot(ul_results_full, aes(x="Upload Test", y=bw)) +
  geom_quasirandom(aes(size=size, fill="col"), width=0.1, shape=21, stroke=0.25, color="#2b2b2b") +
  scale_y_continuous(expand=c(0,0.5), breaks=seq(0,16,4),
                     labels=c(sprintf("%s", seq(0,12,4)), "16 Mb/s"), limits=c(0,16)) +
  scale_size(range=c(2,6)) +
  scale_fill_ipsum() +
  labs(x=NULL, y=NULL, title="Upload bandwidth test by selected server type",
       subtitle="Circle size scaled by size of file used in that speed test") +
  theme_ipsum_rc(grid="Y") +
  theme(legend.position="none")

LS0tDQp0aXRsZTogIk1lYXN1cmluZyAmIE1vbml0b3JpbmcgSW50ZXJuZXQgU3BlZWQgd2l0aCBSIg0KYXV0aG9yOiAiTGVvbmksIFIuIEMuIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KYGBge3J9DQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiaHJicm1zdHIvc3BlZWR0ZXN0IikgDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHNwZWVkdGVzdCkNCmxpYnJhcnkoc3RyaW5naSkNCmxpYnJhcnkoaHJicnRoZW1lcykNCmxpYnJhcnkoZ2diZWVzd2FybSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpjb25maWcgPC0gc3BkX2NvbmZpZygpDQoNCnNlcnZlcnMgPC0gc3BkX3NlcnZlcnMoY29uZmlnPWNvbmZpZykNCmNsb3Nlc3Rfc2VydmVycyA8LSBzcGRfY2xvc2VzdF9zZXJ2ZXJzKHNlcnZlcnMsIGNvbmZpZz1jb25maWcpDQpvbmx5X3RoZV9iZXN0X3NldmVycyA8LSBzcGRfYmVzdF9zZXJ2ZXJzKGNsb3Nlc3Rfc2VydmVycywgY29uZmlnKQ0KDQpnbGltcHNlKHNwZF9kb3dubG9hZF90ZXN0KGNsb3Nlc3Rfc2VydmVyc1sxLF0sIGNvbmZpZz1jb25maWcpKQ0KIyMgT2JzZXJ2YXRpb25zOiAxDQojIyBWYXJpYWJsZXM6IDE1DQojIyAkIHVybCAgICAgICJodHRwOi8vc3BlZWQwLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbGF0ICAgICAgNDIuMzg3NQ0KIyMgJCBsbmcgICAgICAtNzEuMQ0KIyMgJCBuYW1lICAgICAiU29tZXJ2aWxsZSwgTUEiDQojIyAkIGNvdW50cnkgICJVbml0ZWQgU3RhdGVzIg0KIyMgJCBjYyAgICAgICAiVVMiDQojIyAkIHNwb25zb3IgICJBeGNlbHggVGVjaG5vbG9naWVzIExMQyINCiMjICQgaWQgICAgICAgIjU5NjAiDQojIyAkIGhvc3QgICAgICJzcGVlZDAueGNlbHgubmV0OjgwODAiDQojIyAkIHVybDIgICAgICJodHRwOi8vc3BlZWQxLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbWluICAgICAgMTQuNDA0MzkNCiMjICQgbWVhbiAgICAgNjAuMDY4MzQNCiMjICQgbWVkaWFuICAgNTUuMjg0NTcNCiMjICQgbWF4ICAgICAgMTI3Ljk0MzYNCiMjICQgc2QgICAgICAgMzQuMjA2OTUNCg0KZ2xpbXBzZShzcGRfdXBsb2FkX3Rlc3Qob25seV90aGVfYmVzdF9zZXZlcnNbMSxdLCBjb25maWc9Y29uZmlnKSkNCiMjIE9ic2VydmF0aW9uczogMQ0KIyMgVmFyaWFibGVzOiAxOA0KIyMgJCBwaW5nX3RpbWUgICAgICAgMC4wMjcxMjU2Nw0KIyMgJCB0b3RhbF90aW1lICAgICAgMC4wNTk5MTcNCiMjICQgcmV0cmlldmFsX3RpbWUgIDIuM2UtMDUNCiMjICQgdXJsICAgICAgICAgICAgICJodHRwOi8vc3BlZWQwLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbGF0ICAgICAgICAgICAgIDQyLjM4NzUNCiMjICQgbG5nICAgICAgICAgICAgIC03MS4xDQojIyAkIG5hbWUgICAgICAgICAgICAiU29tZXJ2aWxsZSwgTUEiDQojIyAkIGNvdW50cnkgICAgICAgICAiVW5pdGVkIFN0YXRlcyINCiMjICQgY2MgICAgICAgICAgICAgICJVUyINCiMjICQgc3BvbnNvciAgICAgICAgICJBeGNlbHggVGVjaG5vbG9naWVzIExMQyINCiMjICQgaWQgICAgICAgICAgICAgICI1OTYwIg0KIyMgJCBob3N0ICAgICAgICAgICAgInNwZWVkMC54Y2VseC5uZXQ6ODA4MCINCiMjICQgdXJsMiAgICAgICAgICAgICJodHRwOi8vc3BlZWQxLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbWluICAgICAgICAgICAgIDYuMjQwODU4DQojIyAkIG1lYW4gICAgICAgICAgICA5LjUyNzU5OQ0KIyMgJCBtZWRpYW4gICAgICAgICAgOS4zMDMxNDgNCiMjICQgbWF4ICAgICAgICAgICAgIDEyLjU2Njg2DQojIyAkIHNkICAgICAgICAgICAgICAyLjQ1MTc3OA0KYGBgDQpgYGB7cn0NCg0KV2VsY29tZSENCkhlcmUgeW91IHdpbGwgZmluZCBkYWlseSBuZXdzIGFuZCB0dXRvcmlhbHMgYWJvdXQgUiwgY29udHJpYnV0ZWQgYnkgb3ZlciA3NTAgYmxvZ2dlcnMuDQpUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGZvbGxvdyB1cyAtDQpCeSBlLW1haWw6DQpPbiBGYWNlYm9vazoNCklmIHlvdSBhcmUgYW4gUiBibG9nZ2VyIHlvdXJzZWxmIHlvdSBhcmUgaW52aXRlZCB0byBhZGQgeW91ciBvd24gUiBjb250ZW50IGZlZWQgdG8gdGhpcyBzaXRlIChOb24tRW5nbGlzaCBSIGJsb2dnZXJzIHNob3VsZCBhZGQgdGhlbXNlbHZlcy0gaGVyZSkNClJTUyBKb2JzIGZvciBSLXVzZXJzDQoNCiAgICBSYXlzIFJlc2VhcmNoICYgRGV2ZWxvcG1lbnQgQW5hbHlzdA0KICAgIFBST0dSQU1NRVIvU09GVFdBUkUgREVWRUxPUE1FTlQgRU5HSU5FRVIvQ09NUFVUQVRJT05BTCBBTkQgTUFDSElORSBMRUFSTklORyBTUEVDSUFMSVNUDQogICAgUXVhbnRpdGF0aXZlIEVjb25vbWV0cmljaWFuIEAgU2FuIEZyYW5jaXNjbywgQ2FsaWZvcm5pYSwgVS5TLg0KICAgIFBvc3Rkb2N0b3JhbCBSZXNlYXJjaCBGZWxsb3cgaW4gSGVhbHRoY2FyZSBTeXN0ZW1zIEVuZ2luZWVyaW5nIEAgTWFyeWxhbmQsIFUuUy4NCiAgICBSIFByb2dyYW1tZXIgJiBTdGF0aXN0aWNpYW4gZm9yIEFjYWRlbWljIFJlc2VhcmNoDQoNClBvcHVsYXIgU2VhcmNoZXMNClJlY2VudCBQb3N0cw0KDQogICAgTWVhc3VyaW5nICYgTW9uaXRvcmluZyBJbnRlcm5ldCBTcGVlZCB3aXRoIFINCiAgICBDcmVhdGluZyBpbnRlZ2VyNjQgYW5kIG5hbm90aW1lIHZlY3RvcnMgaW4gQysrDQogICAgU3RhbiBSb3VuZHVwLCAxMCBOb3ZlbWJlciAyMDE3DQogICAgLnJwcm9maWxlOiBNYXJhIEF2ZXJpY2sNCiAgICBHb2xkLU1pbmluZyDigJMgV2VlayAxMCAoMjAxNykNCiAgICBSZWNhcDogRUFSTCBCb3N0b24gMjAxNw0KICAgIEFubm91bmNpbmcg4oCcSW50cm9kdWN0aW9uIHRvIHRoZSBUaWR5dmVyc2XigJ0sIG15IG5ldyBEYXRhQ2FtcCBjb3Vyc2UNCiAgICBSIGxpdmUgY2xhc3MgfCBSIHdpdGggRGF0YWJhc2UgYW5kIEJpZyBEYXRhIHwgTm92IDIxLTIyIE1pbGFuDQogICAgSG93IEhhcHB5IGlzIFlvdXIgQ291bnRyeT/igIrigJTigIpIYXBweSBQbGFuZXQgSW5kZXggVmlzdWFsaXplZA0KICAgIEZvcm1hbCB3YXlzIHRvIGNvbXBhcmUgZm9yZWNhc3RpbmcgbW9kZWxzOiBSb2xsaW5nIHdpbmRvd3MNCiAgICBJbnRyb2R1Y3Rpb24gdG8gVmlzdWFsaXppbmcgQXNzZXQgUmV0dXJucw0KICAgIGJyaWRnZXNhbXBsaW5nIFtSIHBhY2thZ2VdDQogICAgQ2FsY3VsYXRpbmcgdGhlIGhvdXNlIGVkZ2Ugb2YgYSBzbG90IG1hY2hpbmUsIHdpdGggUg0KICAgIENyZWF0aW5nIFJlcG9ydGluZyBUZW1wbGF0ZSB3aXRoIEdsdWUgaW4gUg0KICAgIFIgLyBGaW5hbmNlIDIwMTggQ2FsbCBmb3IgUGFwZXJzDQoNCk90aGVyIHNpdGVzDQoNCiAgICBKb2JzIGZvciBSLXVzZXJzDQogICAgU0FTIGJsb2dzDQoNCk1lYXN1cmluZyAmIE1vbml0b3JpbmcgSW50ZXJuZXQgU3BlZWQgd2l0aCBSDQpOb3ZlbWJlciAxMSwgMjAxNw0KQnkgaHJicm1zdHINCg0KaW5TaGFyZTQNCihUaGlzIGFydGljbGUgd2FzIGZpcnN0IHB1Ymxpc2hlZCBvbiBSIOKAkyBydWQuaXMsIGFuZCBraW5kbHkgY29udHJpYnV0ZWQgdG8gUi1ibG9nZ2VycykNCg0KNzINClNIQVJFUw0KU2hhcmUNClR3ZWV0DQoNCldvcmtpbmcgcmVtb3RlbHkgaGFzIG1hbnkgYmVuZWZpdHMsIGJ1dCBpZiB5b3Ugd29yayByZW1vdGVseSBpbiBhbiBhcmVhIGxpa2UsIHNheSwgcnVyYWwgTWFpbmUsIG9uZSBvZiB0aG9zZSBiZW5lZml0cyBpcyBub3QgbWFzc2l2ZWx5IHNwZWVkeSBpbnRlcm5ldCBjb25uZWN0aW9ucy4gQmVpbmcgYWJsZSB0byBnbyBmYXN0IGFuZCBmdXJpb3VzIG9uIHRoZSBpbnRlcm5ldCBpcyBvbmUgb2YgdGhlIG1hbnkgdGhpbmdzIEkgbWlzcyBhYm91dCBvdXIgdGltZSBpbiBTZWF0dGxlIGFuZCBpdCBpcyB1bmxpa2VseSB0aGF0IHdl4oCZbGwgYmUgc2VlaW5nIEdvb2dsZSBGaWJlciBpbiBteSBzbWFsbCB0b3duIGFueSB0aW1lIHNvb24uIE9uZSBvdGhlciBpc3N1ZSBpcyB0aGF0IHJlc2lkZW50aWFsIHBsYW5zIGZyb20gZXZpbCBnaWFudHMgbGlrZSBDb21jYXN0IGNvbWUgd2l0aCB0aGluZ3MgbGlrZSDigJxiYW5kd2lkdGggY2Fwc+KAnS4gSSBzdXNwZWN0IG1hbnkgV0ZILWVycyBjYW4gbGl2ZSB3aXRoaW4gdGhvc2UgbGltaXRzLCBidXQgSSB3b3JrIHdpdGggaW50ZXJuZXQtc2NhbGUgZGF0YSBhbmQgb2Z0ZW4gc2h1bnQgZXh0cmFjdHMgb3Igd2hvbGUgZGF0YXNldHMgdG8gdGhlIERhdENhdmXihKIgc2VydmVyIGZhcm0gZm9yIGxvY2FsIHByb2Nlc3NpbmcuIEFzIHN1Y2gsIEkgcGF5IGFuIGV4dHJhIHBlbmFsdHkgYXMgYSBDb21jYXN0IOKAnEJ1c2luZXNzLWNsYXNz4oCdIHVzZXIgdGhhdCBoYXMgbGl0dGxlIGJlbmVmaXQgYmVzaWRlcyBnZXR0aW5nIHNsaWdodGx5IGhpZ2hlciBRb1MgYW5kIHNvbWUgZmFzdGVyIHNlcnZpY2UgcmVzcG9uc2UgdGltZXMgd2hlbiB0aGVyZSBhcmUgaXNzdWVzLg0KDQpXaHkgZ28gaW50byBhbGwgdGhhdD8gV2VsbCwgSSByZWNlbnRseSBkZWNpZGVkIHRvIGJ1bXAgdXAgdGhlIGNvbm5lY3Rpb24gZnJvbSAxMDAgTWIvcyB0byAxNTAgTWIvcyAoYW5kIG1hbmFnZWQgdG8gZG8gc28gdy9vIGluY3JlYXNpbmcgdGhlIG92ZXJhbGwgbW9udGhseSBiaWxsIGF0IGFsbCkgYnV0IHdhbnRlZCB0byBoYXZlIGEgd2F5IHRvIHJlZ3VsYXJseSB2ZXJpZnkgSSBhbSBnZXR0aW5nIHdoYXQgSeKAmW0gcGF5aW5nIGZvciB3aXRob3V0IGhhdmluZyB0byBnbyB0byBhbiBpbnRlcmFjdGl2ZSDigJxzcGVlZCB0ZXN04oCdIHNpdGUuDQoNClRoZXJl4oCZcyBhIGhhbmR5IHNwZWVkdGVzdC1jbGnwn5SXLCB3aGljaCBpcyBhIHB5dGhvbi1iYXNlZCBtb2R1bGUgd2l0aCBhIGNvbW1hbmQtbGluZSBpbnRlcmZhY2UgdGhhdCBjYW4gcGVyZm9ybSBzcGVlZCB0ZXN0cyBhZ2FpbnN0IE9va2xh4oCZcyBsZWdhY3kgc2VydmVyLiAoWW914oCZbGwgbm90aWNlIHRoYXQgbGluayBmb3J3YXJkcyB5b3UgdG8gdGhlaXIgbmV3IHNvY2tldC1iYXNlZCB0ZXN0IHNlcnZpY2U7IG5laXRoZXIgc3BlZWR0ZXN0LWNsaSBub3IgdGhlIGNvZGUgaW4gdGhlIHBhY2thZ2UgYmVpbmcgc2hvd24gaGVyZSB1c2VzIHRoYXQgeWV0KQ0KDQpJIHJ1biBwbGVudHkgb2YgcnVieSwgcHl0aG9uLCBub2RlIGFuZCBnbyAoZXQgYWwpIHByb2dyYW1zIG9uIHRoZSBjb21tYW5kLWxpbmUsIGJ1dCBJIHdhbnRlZCBhIHdheSB0byBtZWFzdXJlIHRoaXMgaW4gUi1wcm9wZXIgKHN0b3JpbmcgaW5kaXZpZHVhbCB0ZXN0IHJlc3VsdHMpIG9uIGEgcmVndWxhciBiYXNpcyBhcyB3ZWxsIGFzIHJ1biBzb21ldGhpbmcgZnJvbSB0aGUgY29tbWFuZC1saW5lIHdoZW5ldmVyIEkgd2FudGVkIGFuIGludGVyYWN0aXZlIHRlc3QuIFRodXMgYmVnYXQgc3BlZWR0ZXN08J+Uly4NClRlc3RpbmcgdGhlIE5lZWQgZm9yIFNwZWVkDQoNCkFmdGVyIHlvdSBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImhyYnJtc3RyL3NwZWVkdGVzdCIpIHRoZSBwYWNrYWdlLCB5b3UgY2FuIGVpdGhlciB0eXBlIHNwZWVkdGVzdDo6c3BkX3Rlc3QoKSBhdCBhbiBSIGNvbnNvbGUgb3IgUnNjcmlwdCAtLXF1aWV0IC1lICdzcGVlZHRlc3Q6OnNwZF90ZXN0KCknIG9uIHRoZSBjb21tYW5kLWxpbmUgdG8gc2VlIHNvbWV0aGluZyBsaWtlIHRoZSBmb2xsb3dpbmc6DQoNCldoYXQgeW91IHNlZSB0aGVyZSBpcyBhIHNob3J0LWhhbmQgdmVyc2lvbiBvZiB3aGF04oCZcyBhdmFpbGFibGUgaW4gdGhlIHBhY2thZ2U6DQoNCiAgICBzcGRfYmVzdF9zZXJ2ZXJzOiBGaW5kIOKAnGJlc3TigJ0gc2VydmVycyAobGF0ZW5jeS13aXNlKSBmcm9tIG1hc3RlciBzZXJ2ZXIgbGlzdA0KICAgIHNwZF9jbG9zZXN0X3NlcnZlcnM6IEZpbmQg4oCcY2xvc2VzdOKAnSBzZXJ2ZXJzIChnZW9ncmFwaHktd2lzZSkgZnJvbSBtYXN0ZXIgc2VydmVyIGxpc3QNCiAgICBzcGRfY29tcHV0ZV9iYW5kd2lkdGg6IENvbXB1dGUgYmFuZHdpZHRoIGZyb20gYnl0ZXMgdHJhbnNmZXJyZWQgYW5kIHRpbWUgdGFrZW4NCiAgICBzcGRfY29uZmlnOiBSZXRyaWV2ZSBjbGllbnQgY29uZmlndXJhdGlvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIHNwZWVkdGVzdA0KICAgIHNwZF9kb3dubG9hZF90ZXN0OiBQZXJmb3JtIGEgZG93bmxvYWQgc3BlZWQvYmFuZHdpZHRoIHRlc3QNCiAgICBzcGRfc2VydmVyczogUmV0cmlldmUgYSBsaXN0IG9mIFNwZWVkVGVzdCBzZXJ2ZXJzDQogICAgc3BkX3VwbG9hZF90ZXN0OiBQZXJmb3JtIGFuIHVwbG9hZCBzcGVlZC9iYW5kd2lkdGggdGVzdA0KICAgIHNwZF90ZXN0OiBUZXN0IHlvdXIgaW50ZXJuZXQgc3BlZWQvYmFuZHdpZHRoDQoNClRoZSBnZW5lcmFsIGlkaW9tIGlzIHRvIGdyYWIgdGhlIHRlc3QgY29uZmlndXJhdGlvbiBmaWxlLCBjb2xsZWN0IHRoZSBtYXN0ZXIgbGlzdCBvZiBzZXJ2ZXJzLCBmaWd1cmUgb3V0IHdoaWNoIHNlcnZlcnMgeW914oCZcmUgZ29pbmcgdG8gdGVzdCBhZ2FpbnN0IGFuZCBwZXJmb3JtIHVwbG9hZC9kb3dubG9hZCB0ZXN0cyArIGNvbGxlY3QgdGhlIHJlc3VsdGFudCBzdGF0aXN0aWNzOg0KDQpsaWJyYXJ5KHNwZWVkdGVzdCkNCmxpYnJhcnkoc3RyaW5naSkNCmxpYnJhcnkoaHJicnRoZW1lcykNCmxpYnJhcnkoZ2diZWVzd2FybSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpjb25maWcgPC0gc3BkX2NvbmZpZygpDQoNCnNlcnZlcnMgPC0gc3BkX3NlcnZlcnMoY29uZmlnPWNvbmZpZykNCmNsb3Nlc3Rfc2VydmVycyA8LSBzcGRfY2xvc2VzdF9zZXJ2ZXJzKHNlcnZlcnMsIGNvbmZpZz1jb25maWcpDQpvbmx5X3RoZV9iZXN0X3NldmVycyA8LSBzcGRfYmVzdF9zZXJ2ZXJzKGNsb3Nlc3Rfc2VydmVycywgY29uZmlnKQ0KDQpnbGltcHNlKHNwZF9kb3dubG9hZF90ZXN0KGNsb3Nlc3Rfc2VydmVyc1sxLF0sIGNvbmZpZz1jb25maWcpKQ0KIyMgT2JzZXJ2YXRpb25zOiAxDQojIyBWYXJpYWJsZXM6IDE1DQojIyAkIHVybCAgICAgICJodHRwOi8vc3BlZWQwLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbGF0ICAgICAgNDIuMzg3NQ0KIyMgJCBsbmcgICAgICAtNzEuMQ0KIyMgJCBuYW1lICAgICAiU29tZXJ2aWxsZSwgTUEiDQojIyAkIGNvdW50cnkgICJVbml0ZWQgU3RhdGVzIg0KIyMgJCBjYyAgICAgICAiVVMiDQojIyAkIHNwb25zb3IgICJBeGNlbHggVGVjaG5vbG9naWVzIExMQyINCiMjICQgaWQgICAgICAgIjU5NjAiDQojIyAkIGhvc3QgICAgICJzcGVlZDAueGNlbHgubmV0OjgwODAiDQojIyAkIHVybDIgICAgICJodHRwOi8vc3BlZWQxLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbWluICAgICAgMTQuNDA0MzkNCiMjICQgbWVhbiAgICAgNjAuMDY4MzQNCiMjICQgbWVkaWFuICAgNTUuMjg0NTcNCiMjICQgbWF4ICAgICAgMTI3Ljk0MzYNCiMjICQgc2QgICAgICAgMzQuMjA2OTUNCg0KZ2xpbXBzZShzcGRfdXBsb2FkX3Rlc3Qob25seV90aGVfYmVzdF9zZXZlcnNbMSxdLCBjb25maWc9Y29uZmlnKSkNCiMjIE9ic2VydmF0aW9uczogMQ0KIyMgVmFyaWFibGVzOiAxOA0KIyMgJCBwaW5nX3RpbWUgICAgICAgMC4wMjcxMjU2Nw0KIyMgJCB0b3RhbF90aW1lICAgICAgMC4wNTk5MTcNCiMjICQgcmV0cmlldmFsX3RpbWUgIDIuM2UtMDUNCiMjICQgdXJsICAgICAgICAgICAgICJodHRwOi8vc3BlZWQwLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbGF0ICAgICAgICAgICAgIDQyLjM4NzUNCiMjICQgbG5nICAgICAgICAgICAgIC03MS4xDQojIyAkIG5hbWUgICAgICAgICAgICAiU29tZXJ2aWxsZSwgTUEiDQojIyAkIGNvdW50cnkgICAgICAgICAiVW5pdGVkIFN0YXRlcyINCiMjICQgY2MgICAgICAgICAgICAgICJVUyINCiMjICQgc3BvbnNvciAgICAgICAgICJBeGNlbHggVGVjaG5vbG9naWVzIExMQyINCiMjICQgaWQgICAgICAgICAgICAgICI1OTYwIg0KIyMgJCBob3N0ICAgICAgICAgICAgInNwZWVkMC54Y2VseC5uZXQ6ODA4MCINCiMjICQgdXJsMiAgICAgICAgICAgICJodHRwOi8vc3BlZWQxLnhjZWx4Lm5ldC9zcGVlZHRlc3QvdXBsb2FkLnBocCINCiMjICQgbWluICAgICAgICAgICAgIDYuMjQwODU4DQojIyAkIG1lYW4gICAgICAgICAgICA5LjUyNzU5OQ0KIyMgJCBtZWRpYW4gICAgICAgICAgOS4zMDMxNDgNCiMjICQgbWF4ICAgICAgICAgICAgIDEyLjU2Njg2DQojIyAkIHNkICAgICAgICAgICAgICAyLjQ1MTc3OA0KYGBgDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoODY3NTMwOSkNCg0KYmluZF9yb3dzKA0KDQogIGNsb3Nlc3Rfc2VydmVyc1sxOjMsXSAlPiUNCiAgICBtdXRhdGUodHlwZT0iY2xvc2VzdCIpLA0KDQogIG9ubHlfdGhlX2Jlc3Rfc2V2ZXJzWzE6MyxdICU+JQ0KICAgIG11dGF0ZSh0eXBlPSJiZXN0IiksDQoNCiAgZmlsdGVyKHNlcnZlcnMsICEoaWQgJWluJSBjKGNsb3Nlc3Rfc2VydmVyc1sxOjMsXSRpZCwgb25seV90aGVfYmVzdF9zZXZlcnNbMTozLF0kaWQpKSkgJT4lDQogICAgc2FtcGxlX24oMykgJT4lDQogICAgbXV0YXRlKHR5cGU9InJhbmRvbSIpDQoNCikgJT4lDQogIGdyb3VwX2J5KHR5cGUpICU+JQ0KICB1bmdyb3VwKCkgLT4gdG9fY29tcGFyZQ0KDQpzZWxlY3QodG9fY29tcGFyZSwgc3BvbnNvciwgbmFtZSwgY291bnRyeSwgaG9zdCwgdHlwZSkNCmBgYA0KDQoNCmBgYHtyfQ0KbWFwX2RmKDE6bnJvdyh0b19jb21wYXJlKSwgfnsNCiAgc3BkX2Rvd25sb2FkX3Rlc3QodG9fY29tcGFyZVsueCxdLCBjb25maWc9Y29uZmlnLCBzdW1tYXJpc2U9RkFMU0UsIHRpbWVvdXQ9MzApDQp9KSAtPiBkbF9yZXN1bHRzX2Z1bGwNCg0KbXV0YXRlKGRsX3Jlc3VsdHNfZnVsbCwgdHlwZT1zdHJpX3RyYW5zX3RvdGl0bGUodHlwZSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHR5cGUsIGJ3LCBmaWxsPXR5cGUpKSArDQogIGdlb21fcXVhc2lyYW5kb20oYWVzKHNpemU9c2l6ZSwgY29sb3I9dHlwZSksIHdpZHRoPTAuMTUsIHNoYXBlPTIxLCBzdHJva2U9MC4yNSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCw1KSwgbGFiZWxzPWMoc3ByaW50ZigiJXMiLCBzZXEoMCwxNTAsNTApKSwgIjIwMCBNYi9zIiksIGxpbWl0cz1jKDAsMjAwKSkgKw0KICBzY2FsZV9zaXplKHJhbmdlPWMoMiw2KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoUmFuZG9tPSIjYjJiMmIyIiwgQmVzdD0iIzJiMmIyYiIsIENsb3Nlc3Q9IiMyYjJiMmIiKSkgKw0KICBzY2FsZV9maWxsX2lwc3VtKCkgKw0KICBsYWJzKHg9TlVMTCwgeT1OVUxMLCB0aXRsZT0iRG93bmxvYWQgYmFuZHdpZHRoIHRlc3QgYnkgc2VsZWN0ZWQgc2VydmVyIHR5cGUiLA0KICAgICAgIHN1YnRpdGxlPSJDaXJjbGUgc2l6ZSBzY2FsZWQgYnkgc2l6ZSBvZiBmaWxlIHVzZWQgaW4gdGhhdCBzcGVlZCB0ZXN0IikgKw0KICB0aGVtZV9pcHN1bV9yYyhncmlkPSJZIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQ0KYGBgDQoNCmBgYHtyfQ0KYmluZF9yb3dzKA0KICBjbG9zZXN0X3NlcnZlcnNbMTozLF0gJT4lIG11dGF0ZSh0eXBlPSJjbG9zZXN0IiksDQogIG9ubHlfdGhlX2Jlc3Rfc2V2ZXJzWzE6MyxdICU+JSBtdXRhdGUodHlwZT0iYmVzdCIpDQopICU+JQ0KICBkaXN0aW5jdCgua2VlcF9hbGw9VFJVRSkgLT4gdG9fY29tcGFyZQ0KDQpzZWxlY3QodG9fY29tcGFyZSwgc3BvbnNvciwgbmFtZSwgY291bnRyeSwgaG9zdCwgdHlwZSkNCmBgYA0KDQpgYGB7cn0NCm1hcF9kZigxOm5yb3codG9fY29tcGFyZSksIH57DQogIHNwZF91cGxvYWRfdGVzdCh0b19jb21wYXJlWy54LF0sIGNvbmZpZz1jb25maWcsIHN1bW1hcmlzZT1GQUxTRSwgdGltZW91dD0zMCkNCn0pIC0+IHVsX3Jlc3VsdHNfZnVsbA0KDQpnZ3Bsb3QodWxfcmVzdWx0c19mdWxsLCBhZXMoeD0iVXBsb2FkIFRlc3QiLCB5PWJ3KSkgKw0KICBnZW9tX3F1YXNpcmFuZG9tKGFlcyhzaXplPXNpemUsIGZpbGw9ImNvbCIpLCB3aWR0aD0wLjEsIHNoYXBlPTIxLCBzdHJva2U9MC4yNSwgY29sb3I9IiMyYjJiMmIiKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQ9YygwLDAuNSksIGJyZWFrcz1zZXEoMCwxNiw0KSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKHNwcmludGYoIiVzIiwgc2VxKDAsMTIsNCkpLCAiMTYgTWIvcyIpLCBsaW1pdHM9YygwLDE2KSkgKw0KICBzY2FsZV9zaXplKHJhbmdlPWMoMiw2KSkgKw0KICBzY2FsZV9maWxsX2lwc3VtKCkgKw0KICBsYWJzKHg9TlVMTCwgeT1OVUxMLCB0aXRsZT0iVXBsb2FkIGJhbmR3aWR0aCB0ZXN0IGJ5IHNlbGVjdGVkIHNlcnZlciB0eXBlIiwNCiAgICAgICBzdWJ0aXRsZT0iQ2lyY2xlIHNpemUgc2NhbGVkIGJ5IHNpemUgb2YgZmlsZSB1c2VkIGluIHRoYXQgc3BlZWQgdGVzdCIpICsNCiAgdGhlbWVfaXBzdW1fcmMoZ3JpZD0iWSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikNCmBgYA0KDQo=