This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 2.2.1     ✔ purrr   0.2.4
✔ tibble  1.4.2     ✔ dplyr   0.7.4
✔ tidyr   0.8.0     ✔ stringr 1.3.0
✔ readr   1.1.1     ✔ forcats 0.3.0
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

load shapes

df.shapes <- read.csv('data/shapes.txt')

compute distance per shape_id

df.stops <- read.csv('data/stops.txt')
df.routes <- read.csv('data/routes.txt')
df.trips <- read.csv('data/trips.txt')
df.trips <- df.trips %>% filter(!grepl('-',trip_id))
df.routes <- merge(df.routes,df.trips,by='route_id')
df.routes <- merge(df.routes,df.distance,by='shape_id')
## Add total cost 
df.routes$costs <- df.routes$total.distance *3.25
weeks <- paste0('Week.',c(1:25))
minVal <- 0
maxValPassenger <- 72
maxFillVal <- 100
mnPassenger <- (maxValPassenger - minVal)/2
mnFill <- (maxFillVal - minVal)/2
# Generate numbers (mostly) from min to max
mysamp <- function(n, m, s, lwr, upr, rounding) {
  samp <- round(rnorm(n, m, s), rounding)
  samp[samp < lwr] <- lwr
  samp[samp > upr] <- upr
  return (samp)
}
create_traffic <- function(){
  for (w in weeks){
  df.routes[paste(w,'passenger',sep='.')]<-  mysamp(dim(df.routes)[1],mnPassenger,mnPassenger/3, minVal,maxValPassenger,3)
  df.routes[paste(w,'filling',sep='.')]<-  df.routes[paste(w,'passenger',sep='.')]/72*100
  df.routes[paste(w,'on.time',sep='.')]<-sample(c(TRUE,FALSE), dim(df.routes)[1], prob=c(.9,.1),TRUE)
  
  df.routes[paste(w,'revenues',sep='.')] <- df.routes[paste(w,'passenger',sep='.')] * df.routes$total.distance*0.09
  df.routes[paste(w,'profits',sep='.')]<- df.routes[paste(w,'revenues',sep='.')] - df.routes$costs
  }
  return (df.routes)
}
df.routes <- create_traffic()
head(df.routes)

plot top/worst 10 lines per filling ratio.

## Aggregate per trip_id
df.gato <- df.routes %>% select(trip_id,route_long_name,contains("filling")) %>% gather(weeka,filling,-trip_id,-route_long_name)
df.groupy.trip.id <- df.gato %>% group_by(trip_id,route_long_name) %>% summarise(average.filling =mean(filling))
df.top.10.filling <- top_n(ungroup(df.groupy.trip.id),10,average.filling) #%>% select(route_long_name,trip_id, average.filling)
df.worst.10.filling <-top_n(ungroup(df.groupy.trip.id),-10,average.filling) #%>% select(route_long_name,trip_id, average.filling)
write.csv(df.top.10.filling,'data/qlickview/top_filling.csv')
write.csv(df.worst.10.filling,'data/qlickview/worst_filling.csv')

- top 10 late arrival lines.

df.gato.late <- df.routes %>% select(trip_id,route_long_name,contains("time")) %>% gather(weeka,on.time,-trip_id,-route_long_name)
df.groupy.trip.late <- df.gato.late %>% group_by(trip_id,route_long_name) %>% summarise(average.on.time =mean(on.time))
df.top.10.on.time <- top_n(ungroup(df.groupy.trip.late),10,average.on.time) #%>% select(route_long_name,trip_id, average.filling)
df.worst.10.on.time <-top_n(ungroup(df.groupy.trip.late),-10,average.on.time) #%>% select(route_long_name,trip_id, average.filling)
write.csv(df.top.10.on.time,'data/qlickview/top_on_time.csv')
write.csv(df.worst.10.on.time,'data/qlickview/worst_on_time.csv')

top/worst 10 passenger volume averaged growth,

df.routes.valid.growth<-df.routes %>% filter(Week.1.passenger>0)
df.routes.valid.growth$growth <- ((df.routes.valid.growth$Week.25.passenger+df.routes.valid.growth$Week.24.passenger)/2 - (df.routes.valid.growth$Week.1.passenger+df.routes.valid.growth$Week.2.passenger)/2)/(df.routes.valid.growth$Week.1.passenger+df.routes.valid.growth$Week.2.passenger)/2*100
df.top.growth <- top_n(df.routes.valid.growth,10,growth) %>% select(route_long_name,trip_id, growth)
df.worst.growth <- top_n(df.routes.valid.growth,-10,growth) %>% select(route_long_name,trip_id, growth)
write.csv(df.top.growth,'data/qlickview/top_growth.csv')
write.csv(df.worst.growth,'data/qlickview/worst_growth.csv')

Overall Net profit (Turnover – Costs) per kilometer

df.gato.profit <- df.routes %>% select(trip_id,route_long_name,contains("profit")) %>% gather(weeka,profit,-trip_id,-route_long_name)
df.gato.profit %>% group_by(weeka)%>% summarise(total_profit = sum(profit))
write.csv(df.gato.profit,'data/qlickview/profits.csv')

top/worst 10 profitable lines

df.top.profit.trip <- top_n(df.gato.profit %>% group_by(trip_id)%>% summarise(average.profit = mean(profit)),10,average.profit)
df.worst.profit.trip <- top_n(df.gato.profit %>% group_by(trip_id)%>% summarise(average.profit = mean(profit)),-10,average.profit)

Year to Date overall passenger volume vs previous Years.

df.gato.passenger <- df.routes %>% select(trip_id,route_long_name,contains("passenger")) %>% gather(weeka,passenger,-trip_id,-route_long_name)
df.groupy.passenger <- df.gato.passenger %>% group_by(weeka)%>% summarise(total_passenger = sum(passenger))
df.groupy.passenger$year <- 2018
df.gato.passenger.previous.year <- create_traffic()%>% select(trip_id,route_long_name,contains("passenger")) %>% gather(weeka,passenger,-trip_id,-route_long_name)
df.groupy.passenger.previous.year <- df.gato.passenger %>% group_by(weeka)%>% summarise(total_passenger = sum(passenger))
df.groupy.passenger.previous.year$year <- 2017
df.groupy.passenger.ytd <- rbind(df.groupy.passenger,df.groupy.passenger.previous.year)
write.csv(df.groupy.passenger.ytd,'data/qlickview/passenger_ytd.csv')
LS0tCnRpdGxlOiAiRURBIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiAKClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDdHJsK1NoaWZ0K0VudGVyKi4gCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLgoKV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDdHJsK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuCgojIyBsb2FkIHNoYXBlcwpgYGB7cn0KZGYuc2hhcGVzIDwtIHJlYWQuY3N2KCdkYXRhL3NoYXBlcy50eHQnKQpgYGAKCgojIyBjb21wdXRlIGRpc3RhbmNlIHBlciBzaGFwZV9pZApgYGB7cn0KZGYuZGlzdGFuY2UgPC0gZGYuc2hhcGVzICU+JSBncm91cF9ieShzaGFwZV9pZCkgJT4lIHN1bW1hcmlzZSh0b3RhbC5kaXN0YW5jZSA9IG1heChzaGFwZV9kaXN0X3RyYXZlbGVkKS8xMDAwKQpgYGAKCgoKYGBge3J9CmRmLnN0b3BzIDwtIHJlYWQuY3N2KCdkYXRhL3N0b3BzLnR4dCcpCmRmLnJvdXRlcyA8LSByZWFkLmNzdignZGF0YS9yb3V0ZXMudHh0JykKZGYudHJpcHMgPC0gcmVhZC5jc3YoJ2RhdGEvdHJpcHMudHh0JykKZGYudHJpcHMgPC0gZGYudHJpcHMgJT4lIGZpbHRlcighZ3JlcGwoJy0nLHRyaXBfaWQpKQoKZGYucm91dGVzIDwtIG1lcmdlKGRmLnJvdXRlcyxkZi50cmlwcyxieT0ncm91dGVfaWQnKQpkZi5yb3V0ZXMgPC0gbWVyZ2UoZGYucm91dGVzLGRmLmRpc3RhbmNlLGJ5PSdzaGFwZV9pZCcpCgojIyBBZGQgdG90YWwgY29zdCAKZGYucm91dGVzJGNvc3RzIDwtIGRmLnJvdXRlcyR0b3RhbC5kaXN0YW5jZSAqMy4yNQoKd2Vla3MgPC0gcGFzdGUwKCdXZWVrLicsYygxOjI1KSkKbWluVmFsIDwtIDAKbWF4VmFsUGFzc2VuZ2VyIDwtIDcyCm1heEZpbGxWYWwgPC0gMTAwCm1uUGFzc2VuZ2VyIDwtIChtYXhWYWxQYXNzZW5nZXIgLSBtaW5WYWwpLzIKbW5GaWxsIDwtIChtYXhGaWxsVmFsIC0gbWluVmFsKS8yCgojIEdlbmVyYXRlIG51bWJlcnMgKG1vc3RseSkgZnJvbSBtaW4gdG8gbWF4CgpteXNhbXAgPC0gZnVuY3Rpb24obiwgbSwgcywgbHdyLCB1cHIsIHJvdW5kaW5nKSB7CiAgc2FtcCA8LSByb3VuZChybm9ybShuLCBtLCBzKSwgcm91bmRpbmcpCiAgc2FtcFtzYW1wIDwgbHdyXSA8LSBsd3IKICBzYW1wW3NhbXAgPiB1cHJdIDwtIHVwcgogIHJldHVybiAoc2FtcCkKfQoKY3JlYXRlX3RyYWZmaWMgPC0gZnVuY3Rpb24oKXsKICBmb3IgKHcgaW4gd2Vla3MpewogIGRmLnJvdXRlc1twYXN0ZSh3LCdwYXNzZW5nZXInLHNlcD0nLicpXTwtICBteXNhbXAoZGltKGRmLnJvdXRlcylbMV0sbW5QYXNzZW5nZXIsbW5QYXNzZW5nZXIvMywgbWluVmFsLG1heFZhbFBhc3NlbmdlciwzKQogIGRmLnJvdXRlc1twYXN0ZSh3LCdmaWxsaW5nJyxzZXA9Jy4nKV08LSAgZGYucm91dGVzW3Bhc3RlKHcsJ3Bhc3Nlbmdlcicsc2VwPScuJyldLzcyKjEwMAogIGRmLnJvdXRlc1twYXN0ZSh3LCdvbi50aW1lJyxzZXA9Jy4nKV08LXNhbXBsZShjKFRSVUUsRkFMU0UpLCBkaW0oZGYucm91dGVzKVsxXSwgcHJvYj1jKC45LC4xKSxUUlVFKQogIAogIGRmLnJvdXRlc1twYXN0ZSh3LCdyZXZlbnVlcycsc2VwPScuJyldIDwtIGRmLnJvdXRlc1twYXN0ZSh3LCdwYXNzZW5nZXInLHNlcD0nLicpXSAqIGRmLnJvdXRlcyR0b3RhbC5kaXN0YW5jZSowLjA5CiAgZGYucm91dGVzW3Bhc3RlKHcsJ3Byb2ZpdHMnLHNlcD0nLicpXTwtIGRmLnJvdXRlc1twYXN0ZSh3LCdyZXZlbnVlcycsc2VwPScuJyldIC0gZGYucm91dGVzJGNvc3RzCiAgfQogIHJldHVybiAoZGYucm91dGVzKQp9CgpkZi5yb3V0ZXMgPC0gY3JlYXRlX3RyYWZmaWMoKQoKaGVhZChkZi5yb3V0ZXMpCgpgYGAKIyMgcGxvdCB0b3Avd29yc3QgMTAgbGluZXMgcGVyIGZpbGxpbmcgcmF0aW8uCmBgYHtyfQoKIyMgQWdncmVnYXRlIHBlciB0cmlwX2lkCmRmLmdhdG8gPC0gZGYucm91dGVzICU+JSBzZWxlY3QodHJpcF9pZCxyb3V0ZV9sb25nX25hbWUsY29udGFpbnMoImZpbGxpbmciKSkgJT4lIGdhdGhlcih3ZWVrYSxmaWxsaW5nLC10cmlwX2lkLC1yb3V0ZV9sb25nX25hbWUpCgoKZGYuZ3JvdXB5LnRyaXAuaWQgPC0gZGYuZ2F0byAlPiUgZ3JvdXBfYnkodHJpcF9pZCxyb3V0ZV9sb25nX25hbWUpICU+JSBzdW1tYXJpc2UoYXZlcmFnZS5maWxsaW5nID1tZWFuKGZpbGxpbmcpKQpkZi50b3AuMTAuZmlsbGluZyA8LSB0b3Bfbih1bmdyb3VwKGRmLmdyb3VweS50cmlwLmlkKSwxMCxhdmVyYWdlLmZpbGxpbmcpICMlPiUgc2VsZWN0KHJvdXRlX2xvbmdfbmFtZSx0cmlwX2lkLCBhdmVyYWdlLmZpbGxpbmcpCmRmLndvcnN0LjEwLmZpbGxpbmcgPC10b3Bfbih1bmdyb3VwKGRmLmdyb3VweS50cmlwLmlkKSwtMTAsYXZlcmFnZS5maWxsaW5nKSAjJT4lIHNlbGVjdChyb3V0ZV9sb25nX25hbWUsdHJpcF9pZCwgYXZlcmFnZS5maWxsaW5nKQoKd3JpdGUuY3N2KGRmLnRvcC4xMC5maWxsaW5nLCdkYXRhL3FsaWNrdmlldy90b3BfZmlsbGluZy5jc3YnKQp3cml0ZS5jc3YoZGYud29yc3QuMTAuZmlsbGluZywnZGF0YS9xbGlja3ZpZXcvd29yc3RfZmlsbGluZy5jc3YnKQpgYGAKCiMjIC0gdG9wIDEwIGxhdGUgYXJyaXZhbCBsaW5lcy4KCmBgYHtyfQpkZi5nYXRvLmxhdGUgPC0gZGYucm91dGVzICU+JSBzZWxlY3QodHJpcF9pZCxyb3V0ZV9sb25nX25hbWUsY29udGFpbnMoInRpbWUiKSkgJT4lIGdhdGhlcih3ZWVrYSxvbi50aW1lLC10cmlwX2lkLC1yb3V0ZV9sb25nX25hbWUpCmRmLmdyb3VweS50cmlwLmxhdGUgPC0gZGYuZ2F0by5sYXRlICU+JSBncm91cF9ieSh0cmlwX2lkLHJvdXRlX2xvbmdfbmFtZSkgJT4lIHN1bW1hcmlzZShhdmVyYWdlLm9uLnRpbWUgPW1lYW4ob24udGltZSkpCmRmLnRvcC4xMC5vbi50aW1lIDwtIHRvcF9uKHVuZ3JvdXAoZGYuZ3JvdXB5LnRyaXAubGF0ZSksMTAsYXZlcmFnZS5vbi50aW1lKSAjJT4lIHNlbGVjdChyb3V0ZV9sb25nX25hbWUsdHJpcF9pZCwgYXZlcmFnZS5maWxsaW5nKQpkZi53b3JzdC4xMC5vbi50aW1lIDwtdG9wX24odW5ncm91cChkZi5ncm91cHkudHJpcC5sYXRlKSwtMTAsYXZlcmFnZS5vbi50aW1lKSAjJT4lIHNlbGVjdChyb3V0ZV9sb25nX25hbWUsdHJpcF9pZCwgYXZlcmFnZS5maWxsaW5nKQoKd3JpdGUuY3N2KGRmLnRvcC4xMC5vbi50aW1lLCdkYXRhL3FsaWNrdmlldy90b3Bfb25fdGltZS5jc3YnKQp3cml0ZS5jc3YoZGYud29yc3QuMTAub24udGltZSwnZGF0YS9xbGlja3ZpZXcvd29yc3Rfb25fdGltZS5jc3YnKQoKYGBgCgojIyB0b3Avd29yc3QgMTAgcGFzc2VuZ2VyIHZvbHVtZSBhdmVyYWdlZCBncm93dGgsCmBgYHtyfQpkZi5yb3V0ZXMudmFsaWQuZ3Jvd3RoPC1kZi5yb3V0ZXMgJT4lIGZpbHRlcihXZWVrLjEucGFzc2VuZ2VyPjApCmRmLnJvdXRlcy52YWxpZC5ncm93dGgkZ3Jvd3RoIDwtICgoZGYucm91dGVzLnZhbGlkLmdyb3d0aCRXZWVrLjI1LnBhc3NlbmdlcitkZi5yb3V0ZXMudmFsaWQuZ3Jvd3RoJFdlZWsuMjQucGFzc2VuZ2VyKS8yIC0gKGRmLnJvdXRlcy52YWxpZC5ncm93dGgkV2Vlay4xLnBhc3NlbmdlcitkZi5yb3V0ZXMudmFsaWQuZ3Jvd3RoJFdlZWsuMi5wYXNzZW5nZXIpLzIpLyhkZi5yb3V0ZXMudmFsaWQuZ3Jvd3RoJFdlZWsuMS5wYXNzZW5nZXIrZGYucm91dGVzLnZhbGlkLmdyb3d0aCRXZWVrLjIucGFzc2VuZ2VyKS8yKjEwMApkZi50b3AuZ3Jvd3RoIDwtIHRvcF9uKGRmLnJvdXRlcy52YWxpZC5ncm93dGgsMTAsZ3Jvd3RoKSAlPiUgc2VsZWN0KHJvdXRlX2xvbmdfbmFtZSx0cmlwX2lkLCBncm93dGgpCmRmLndvcnN0Lmdyb3d0aCA8LSB0b3BfbihkZi5yb3V0ZXMudmFsaWQuZ3Jvd3RoLC0xMCxncm93dGgpICU+JSBzZWxlY3Qocm91dGVfbG9uZ19uYW1lLHRyaXBfaWQsIGdyb3d0aCkKCndyaXRlLmNzdihkZi50b3AuZ3Jvd3RoLCdkYXRhL3FsaWNrdmlldy90b3BfZ3Jvd3RoLmNzdicpCndyaXRlLmNzdihkZi53b3JzdC5ncm93dGgsJ2RhdGEvcWxpY2t2aWV3L3dvcnN0X2dyb3d0aC5jc3YnKQpgYGAKCiMjIE92ZXJhbGwgTmV0IHByb2ZpdCAoVHVybm92ZXIg4oCTIENvc3RzKSBwZXIga2lsb21ldGVyCgpgYGB7cn0KZGYuZ2F0by5wcm9maXQgPC0gZGYucm91dGVzICU+JSBzZWxlY3QodHJpcF9pZCxyb3V0ZV9sb25nX25hbWUsY29udGFpbnMoInByb2ZpdCIpKSAlPiUgZ2F0aGVyKHdlZWthLHByb2ZpdCwtdHJpcF9pZCwtcm91dGVfbG9uZ19uYW1lKQoKZGYuZ2F0by5wcm9maXQgJT4lIGdyb3VwX2J5KHdlZWthKSU+JSBzdW1tYXJpc2UodG90YWxfcHJvZml0ID0gc3VtKHByb2ZpdCkpCndyaXRlLmNzdihkZi5nYXRvLnByb2ZpdCwnZGF0YS9xbGlja3ZpZXcvcHJvZml0cy5jc3YnKQoKYGBgCiMjICB0b3Avd29yc3QgMTAgcHJvZml0YWJsZSBsaW5lcwpgYGB7cn0KZGYudG9wLnByb2ZpdC50cmlwIDwtIHRvcF9uKGRmLmdhdG8ucHJvZml0ICU+JSBncm91cF9ieSh0cmlwX2lkKSU+JSBzdW1tYXJpc2UoYXZlcmFnZS5wcm9maXQgPSBtZWFuKHByb2ZpdCkpLDEwLGF2ZXJhZ2UucHJvZml0KQpkZi53b3JzdC5wcm9maXQudHJpcCA8LSB0b3BfbihkZi5nYXRvLnByb2ZpdCAlPiUgZ3JvdXBfYnkodHJpcF9pZCklPiUgc3VtbWFyaXNlKGF2ZXJhZ2UucHJvZml0ID0gbWVhbihwcm9maXQpKSwtMTAsYXZlcmFnZS5wcm9maXQpCmBgYAojIyBZZWFyIHRvIERhdGUgb3ZlcmFsbCBwYXNzZW5nZXIgdm9sdW1lICB2cyBwcmV2aW91cyBZZWFycy4KYGBge3J9CmRmLmdhdG8ucGFzc2VuZ2VyIDwtIGRmLnJvdXRlcyAlPiUgc2VsZWN0KHRyaXBfaWQscm91dGVfbG9uZ19uYW1lLGNvbnRhaW5zKCJwYXNzZW5nZXIiKSkgJT4lIGdhdGhlcih3ZWVrYSxwYXNzZW5nZXIsLXRyaXBfaWQsLXJvdXRlX2xvbmdfbmFtZSkKZGYuZ3JvdXB5LnBhc3NlbmdlciA8LSBkZi5nYXRvLnBhc3NlbmdlciAlPiUgZ3JvdXBfYnkod2Vla2EpJT4lIHN1bW1hcmlzZSh0b3RhbF9wYXNzZW5nZXIgPSBzdW0ocGFzc2VuZ2VyKSkKZGYuZ3JvdXB5LnBhc3NlbmdlciR5ZWFyIDwtIDIwMTgKCmRmLmdhdG8ucGFzc2VuZ2VyLnByZXZpb3VzLnllYXIgPC0gY3JlYXRlX3RyYWZmaWMoKSU+JSBzZWxlY3QodHJpcF9pZCxyb3V0ZV9sb25nX25hbWUsY29udGFpbnMoInBhc3NlbmdlciIpKSAlPiUgZ2F0aGVyKHdlZWthLHBhc3NlbmdlciwtdHJpcF9pZCwtcm91dGVfbG9uZ19uYW1lKQpkZi5ncm91cHkucGFzc2VuZ2VyLnByZXZpb3VzLnllYXIgPC0gZGYuZ2F0by5wYXNzZW5nZXIgJT4lIGdyb3VwX2J5KHdlZWthKSU+JSBzdW1tYXJpc2UodG90YWxfcGFzc2VuZ2VyID0gc3VtKHBhc3NlbmdlcikpCgpkZi5ncm91cHkucGFzc2VuZ2VyLnByZXZpb3VzLnllYXIkeWVhciA8LSAyMDE3CgpkZi5ncm91cHkucGFzc2VuZ2VyLnl0ZCA8LSByYmluZChkZi5ncm91cHkucGFzc2VuZ2VyLGRmLmdyb3VweS5wYXNzZW5nZXIucHJldmlvdXMueWVhcikKd3JpdGUuY3N2KGRmLmdyb3VweS5wYXNzZW5nZXIueXRkLCdkYXRhL3FsaWNrdmlldy9wYXNzZW5nZXJfeXRkLmNzdicpCgpgYGAKCgo=