## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## Warning: package 'ggthemes' was built under R version 3.6.2
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
## Warning: package 'plotly' was built under R version 3.6.2
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
## -- Attaching packages --------------------------------------- tidyverse 1.2.1 --
## v tibble  2.1.3     v purrr   0.3.2
## v tidyr   1.0.2     v stringr 1.4.0
## v readr   1.3.1     v forcats 0.4.0
## Warning: package 'tidyr' was built under R version 3.6.2
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x gridExtra::combine()     masks dplyr::combine()
## x plotly::filter()         masks dplyr::filter(), stats::filter()
## x kableExtra::group_rows() masks dplyr::group_rows()
## x dplyr::lag()             masks stats::lag()
## 
## Attaching package: 'maps'
## The following object is masked from 'package:purrr':
## 
##     map
## Warning: package 'ggmap' was built under R version 3.6.2
## Google's Terms of Service: https://cloud.google.com/maps-platform/terms/.
## Please cite ggmap if you use it! See citation("ggmap") for details.
## 
## Attaching package: 'ggmap'
## The following object is masked from 'package:plotly':
## 
##     wind
## Warning: package 'mapdata' was built under R version 3.6.2
## Loading required package: Rcpp
## 
## Attaching package: 'bigvis'
## The following object is masked from 'package:stats':
## 
##     smooth

0.1 Introduction

For module 2 we’ll be looking at techniques for dealing with big data. In particular binning strategies and the datashader library (which possibly proves we’ll never need to bin large data for visualization ever again.)

0.2 About the Data

To demonstrate these concepts we’ll be looking at the PLUTO dataset put out by New York City’s department of city planning. PLUTO contains data about every tax lot in New York City.

PLUTO data can be downloaded from here. Unzip them to the same directory as this notebook, and you should be able to read them in using this (or very similar) code. Also take note of the data dictionary, it’ll come in handy for this assignment.

0.2.4 To Do

0.2.5 Question 1

After a few building collapses, the City of New York is going to begin investigating older buildings for safety. The city is particularly worried about buildings that were unusually tall when they were built, since best-practices for safety hadn’t yet been determined. Create a graph that shows how many buildings of a certain number of floors were built in each year (note: you may want to use a log scale for the number of buildings). Find a strategy to bin buildings (It should be clear 20-29-story buildings, 30-39-story buildings, and 40-49-story buildings were first built in large numbers, but does it make sense to continue in this way as you get taller?)

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##       0    1920    1930    1841    1955    2040
## # A tibble: 1 x 1
##       n
##   <int>
## 1 44180
## # A tibble: 1 x 1
##       n
##   <int>
## 1     1
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1661    1920    1931    1941    1960    2016

This shows the number of Buildings built since 1850

## Summarising with count
##    build1850.YearBuilt .count
## 1                   NA      0
## 2               1854.5     86
## 3               1864.5     83
## 4               1874.5    113
## 5               1884.5    333
## 6               1894.5  25593
## 7               1904.5  46151
## 8               1914.5  67537
## 9               1924.5 181404
## 10              1934.5 140977
## 11              1944.5  66869
## 12              1954.5  80837
## 13              1964.5  63059
## 14              1974.5  32745
## 15              1984.5  27514
## 16              1994.5  29219
## 17              2004.5  43575
## 18              2014.5   7629
##  build1850.YearBuilt     .count      
##  Min.   :1854        Min.   :     0  
##  1st Qu.:1894        1st Qu.:  2157  
##  Median :1934        Median : 30982  
##  Mean   :1934        Mean   : 45207  
##  3rd Qu.:1974        3rd Qu.: 65917  
##  Max.   :2014        Max.   :181404  
##  NA's   :1

When were most buildings constructed

Plot showing when most buildings were constructed since 1850. It seems most buildings were constucted around 1920 to 1929.

Number of floors by Buildings

The interractive graph below shows the number of floors for buildings builts between 1850 to 2020.

0.2.6 Question 2

You work for a real estate developer and are researching underbuilt areas of the city. After looking in the Pluto data dictionary, you’ve discovered that all tax assessments consist of two parts: The assessment of the land and assessment of the structure. You reason that there should be a correlation between these two values: more valuable land will have more valuable structures on them (more valuable in this case refers not just to a mansion vs a bungalow, but an apartment tower vs a single family home). Deviations from the norm could represent underbuilt or overbuilt areas of the city. You also recently read a really cool blog post about bivariate choropleth maps, and think the technique could be used for this problem.

Datashader is really cool, but it’s not that great at labeling your visualization. Don’t worry about providing a legend, but provide a quick explanation as to which areas of the city are overbuilt, which areas are underbuilt, and which areas are built in a way that’s properly correlated with their land value.

The interactive graph below shows the areas of the city that are underbuilt or overbuilt by zip code. The areas around 11697 (Rockaway), 10803 (Pelham) and 10464 (Bronx) seems to be underbuilt while zip codes 11109 (Long Island City) and 11241 (Brooklyn) seems to be over built.

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQtMSINCmF1dGhvcjogRW1tYW51ZWwgSGF5YmxlLUdvbWVzDQpkYXRlOiAiMi8yMy8yMDIwIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQotLS0NCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoZ3JpZCkNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobWFwcykNCmxpYnJhcnkoZ2dtYXApDQpsaWJyYXJ5KG1hcGRhdGEpDQpsaWJyYXJ5KGJpZ3ZpcykNCmBgYA0KDQojIyBJbnRyb2R1Y3Rpb24NCg0KRm9yIG1vZHVsZSAyIHdlJ2xsIGJlIGxvb2tpbmcgYXQgdGVjaG5pcXVlcyBmb3IgZGVhbGluZyB3aXRoIGJpZyBkYXRhLiBJbiBwYXJ0aWN1bGFyIGJpbm5pbmcgc3RyYXRlZ2llcyBhbmQgdGhlIGRhdGFzaGFkZXIgbGlicmFyeSAod2hpY2ggcG9zc2libHkgcHJvdmVzIHdlJ2xsIG5ldmVyIG5lZWQgdG8gYmluIGxhcmdlIGRhdGEgZm9yIHZpc3VhbGl6YXRpb24gZXZlciBhZ2Fpbi4pDQoNCiMjIEFib3V0IHRoZSBEYXRhDQoNClRvIGRlbW9uc3RyYXRlIHRoZXNlIGNvbmNlcHRzIHdlJ2xsIGJlIGxvb2tpbmcgYXQgdGhlIFBMVVRPIGRhdGFzZXQgcHV0IG91dCBieSBOZXcgWW9yayBDaXR5J3MgZGVwYXJ0bWVudCBvZiBjaXR5IHBsYW5uaW5nLiBQTFVUTyBjb250YWlucyBkYXRhIGFib3V0IGV2ZXJ5IHRheCBsb3QgaW4gTmV3IFlvcmsgQ2l0eS4NCg0KUExVVE8gZGF0YSBjYW4gYmUgZG93bmxvYWRlZCBmcm9tIGhlcmUuIFVuemlwIHRoZW0gdG8gdGhlIHNhbWUgZGlyZWN0b3J5IGFzIHRoaXMgbm90ZWJvb2ssIGFuZCB5b3Ugc2hvdWxkIGJlIGFibGUgdG8gcmVhZCB0aGVtIGluIHVzaW5nIHRoaXMgKG9yIHZlcnkgc2ltaWxhcikgY29kZS4gQWxzbyB0YWtlIG5vdGUgb2YgdGhlIGRhdGEgZGljdGlvbmFyeSwgaXQnbGwgY29tZSBpbiBoYW5keSBmb3IgdGhpcyBhc3NpZ25tZW50Lg0KDQojIyMgVW56aXAgQ291bnR5IEZpbGVzDQpUaGlzIGlzIEJpZyBEYXRhIHdoaWNoIGlzIHRvbyBCaWcgZm9yIG15IEdpdEh1YiB0byBzdG9yZQ0KYGBge3J9DQojIExvY2F0ZSB0aGUgdXJsIGFuZCBkb3dubG9hZCBQbHV0byB6aXAgZmlsZQ0KcGx1dG9fdXJsIDwtICdodHRwOi8vd3d3MS5ueWMuZ292L2Fzc2V0cy9wbGFubmluZy9kb3dubG9hZC96aXAvZGF0YS1tYXBzL29wZW4tZGF0YS8nDQp6aXBfZmlsZSA8LSAnbnljX3BsdXRvXzE3djFfMS56aXAnICNUaGlzIGlzIHRoZSBjdXJyZW50IHBsdXRvIGRhdGENCg0KZG93bmxvYWQuZmlsZShwYXN0ZTAocGx1dG9fdXJsLHppcF9maWxlKSx6aXBfZmlsZSkjIGRvd25sb2FkaW5nIHRoZSBwbHV0byBkYXRhDQp1bnppcCh6aXBfZmlsZSkgIyB1bnppcCBmaWxlcw0Kc3ViX2RpciA8LSAnQk9ST196aXBfZmlsZXNfY3N2LycjIFRoaXMgaXMgYSBzdWJkaXJlY3RvcnkgZm9yIHRoZSB1bnppcHBlZCBmaWxlDQoNCmJvcm8gPC0gYygnQksnLCdCWCcsJ01OJywnUU4nLCdTSScpICMgQ291bnR5IG5hbWUgcHJlZml4ZXMgd2l0aGluIGNpdHkgQm9ybw0KYGBgDQoNCiMjIyBSZWFkIERhdGEgZm9yIEVhY2ggQm9ybw0KYGBge3J9DQpmb3IgKGkgaW4gMTpsZW5ndGgoYm9ybykpIHsNCiAgIyBjb25zdHJ1Y3Qgc3RyaW5nOiBmaWxlcGF0aCwgZmlsZW5hbWUNCiAgZmlsZV9uYW1lIDwtIHBhc3RlMChzdWJfZGlyLGJvcm9baV0sIi5jc3YiKQ0KICANCiAgIyBzYXZlIGVhY2ggY3N2IGZpbGUgYXMgc2VwYXJhdGUgZGF0YSBmcmFtZQ0KICBhc3NpZ24oYm9yb1tpXSxyZWFkLmNzdihmaWxlX25hbWUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkpDQp9DQpgYGANCg0KIyMjIENyZWF0ZSBEYXRhZnJhbWUgDQpgYGB7cn0NCm55ZGF0YSA8LSByYmluZChCWCwgQkssIE1OLCBRTiwgU0kpDQojIHdyaXRlIHRvIGEgY3N2DQp3cml0ZS5jc3YobnlkYXRhLCBmaWxlPSJQTFVUT19EYXRhLmNzdiIpDQpgYGANCg0KIyMjIFRvIERvDQoNCiMjIyAqKlF1ZXN0aW9uIDEqKg0KDQpBZnRlciBhIGZldyBidWlsZGluZyBjb2xsYXBzZXMsIHRoZSBDaXR5IG9mIE5ldyBZb3JrIGlzIGdvaW5nIHRvIGJlZ2luIGludmVzdGlnYXRpbmcgb2xkZXIgYnVpbGRpbmdzIGZvciBzYWZldHkuIFRoZSBjaXR5IGlzIHBhcnRpY3VsYXJseSB3b3JyaWVkIGFib3V0IGJ1aWxkaW5ncyB0aGF0IHdlcmUgdW51c3VhbGx5IHRhbGwgd2hlbiB0aGV5IHdlcmUgYnVpbHQsIHNpbmNlIGJlc3QtcHJhY3RpY2VzIGZvciBzYWZldHkgaGFkbuKAmXQgeWV0IGJlZW4gZGV0ZXJtaW5lZC4gQ3JlYXRlIGEgZ3JhcGggdGhhdCBzaG93cyBob3cgbWFueSBidWlsZGluZ3Mgb2YgYSBjZXJ0YWluIG51bWJlciBvZiBmbG9vcnMgd2VyZSBidWlsdCBpbiBlYWNoIHllYXIgKG5vdGU6IHlvdSBtYXkgd2FudCB0byB1c2UgYSBsb2cgc2NhbGUgZm9yIHRoZSBudW1iZXIgb2YgYnVpbGRpbmdzKS4gRmluZCBhIHN0cmF0ZWd5IHRvIGJpbiBidWlsZGluZ3MgKEl0IHNob3VsZCBiZSBjbGVhciAyMC0yOS1zdG9yeSBidWlsZGluZ3MsIDMwLTM5LXN0b3J5IGJ1aWxkaW5ncywgYW5kIDQwLTQ5LXN0b3J5IGJ1aWxkaW5ncyB3ZXJlIGZpcnN0IGJ1aWx0IGluIGxhcmdlIG51bWJlcnMsIGJ1dCBkb2VzIGl0IG1ha2Ugc2Vuc2UgdG8gY29udGludWUgaW4gdGhpcyB3YXkgYXMgeW91IGdldCB0YWxsZXI/KQ0KDQpgYGB7cn0NCiMgUmVhZCBpbiB0aGUgZGF0YQ0KcGx1dG8gPC0gcmVhZC5jc3YoJ1BMVVRPX2RhdGEuY3N2JykNCg0Kc3VtbWFyeShwbHV0byRZZWFyQnVpbHQpICNTdW1tYXJ5IFN0YXRzDQoNCmNvdW50KGZpbHRlcihwbHV0bywgWWVhckJ1aWx0PT0gMCkpIA0KY291bnQoZmlsdGVyKHBsdXRvLCBZZWFyQnVpbHQ+IDIwMTYpKSANCg0Kc3Vic2V0cGx1dG8gPC0gc3Vic2V0KHBsdXRvLCBZZWFyQnVpbHQgIT0gMCkNCnN1YnNldHBsdXRvIDwtIHN1YnNldChzdWJzZXRwbHV0bywgWWVhckJ1aWx0IDw9IDIwMTYpDQpzdW1tYXJ5KHN1YnNldHBsdXRvJFllYXJCdWlsdCkNCmBgYA0KDQpUaGlzIHNob3dzIHRoZSBudW1iZXIgb2YgQnVpbGRpbmdzIGJ1aWx0IHNpbmNlIDE4NTANCmBgYHtyfQ0KYnVpbGQxODUwIDwtIHN1YnNldChzdWJzZXRwbHV0bywgWWVhckJ1aWx0ID4gMTg1MCkgDQpjb21iaW5lMTg1MCA8LSBjb25kZW5zZShiaW4oYnVpbGQxODUwJFllYXJCdWlsdCwgMTApKSAjQnVpbHQgaW4gMTAgeWVhcnMgKGRlY2FkZXMpIGludGVydmFscw0KY29tYmluZTE4NTANCnN1bW1hcnkoY29tYmluZTE4NTApIyBBIHRvdGFsIG9mIDE4MSw0MDQgYnVpbGRpbmdzIGJldHdlZW4gMTkyMCB0byAxOTI5IHdpdGggb25lIHVuZGF0ZWQgYnVpbGRpbmcuDQpgYGANCg0KV2hlbiB3ZXJlIG1vc3QgYnVpbGRpbmdzIGNvbnN0cnVjdGVkIA0KDQpgYGB7cn0NCmNvbWIxODUwIDwtIHdpdGhpbihjb21iaW5lMTg1MCwgY3VtdWxhdGl2ZV9zdW0gPC0gY3Vtc3VtKC5jb3VudCkpDQptb3JlYnVpbHQgPC0gc3VtKGNvbWJpbmUxODUwJC5jb3VudCkvMg0KeWVhcnNidWlsdCA8LSBmaWx0ZXIoY29tYjE4NTAsIGN1bXVsYXRpdmVfc3VtID4gbW9yZWJ1aWx0KQ0KYmFzZXllYXIgPC0gbWluKHllYXJzYnVpbHRbMV0pICMgdGhpcyBpcyBteSBiYXNlIHllYXIgZm9yIGNvbXBhcmlzb24oMTkzNCkNCg0KYGBgDQoNClBsb3Qgc2hvd2luZyB3aGVuIG1vc3QgYnVpbGRpbmdzIHdlcmUgY29uc3RydWN0ZWQgc2luY2UgMTg1MC4gSXQgc2VlbXMgbW9zdCBidWlsZGluZ3Mgd2VyZSBjb25zdHVjdGVkIGFyb3VuZCAxOTIwIHRvIDE5MjkuDQoNCmBgYHtyfQ0KcGxvdGJ1aWx0IDwtIGF1dG9wbG90KGNvbWJpbmUxODUwKSArDQogIGxhYnModGl0bGU9IkJ1aWxkaW5ncyBCdWlsdCBZZWFybHkgU2luY2UgMTg1MCIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IGJhc2V5ZWFyKSwgY29sb3VyPSJyZWQiKSArDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE5NDUsIHkgPSAxNTAwMDAsIGxhYmVsID0gYmFzZXllYXIsIGNvbG91cj0icmVkIiwgc2l6ZSA9IDQpICsNCiAgbGFicyh0aXRsZT0iQ291bnQgb2YgQnVpbGRpbmdzIEJ1aWx0IGluIE5ZQyBTaW5jZSAxODUwIiwgeCA9ICJZZWFyIiwgeT0gIkxvdHMgQnVpbHQiKQ0KcGxvdGJ1aWx0DQpgYGANCg0KTnVtYmVyIG9mIGZsb29ycyBieSBCdWlsZGluZ3MNCmBgYHtyfQ0KbnlmbG9vcnMgPC0gbnlkYXRhICU+JQ0KICBmaWx0ZXIoWWVhckJ1aWx0ID49IDE4NTAsIFllYXJCdWlsdCA8IDIwMjApICU+JSANCiAgc2VsZWN0KFllYXJCdWlsdCwgQkJMLCBOdW1GbG9vcnMpICU+JQ0KICBtdXRhdGUoTnVtRmxvb3JzPSByb3VuZChOdW1GbG9vcnMsLTEpKSAlPiUgDQogIGdyb3VwX2J5KFllYXJCdWlsdCwgTnVtRmxvb3JzKSAlPiUgDQogIGNvdW50KCkgJT4lIA0KICBmaWx0ZXIoTnVtRmxvb3JzID49MjAsIE51bUZsb29ycyA8PSAxMDApICU+JSANCiAgZ3JvdXBfYnkoWWVhckJ1aWx0LCBOdW1GbG9vcnMpICU+JQ0KICBzdW1tYXJpc2UoRmxvb3JzID0gc3VtKG4pKQ0KYGBgDQoNClRoZSBpbnRlcnJhY3RpdmUgZ3JhcGggYmVsb3cgc2hvd3MgdGhlIG51bWJlciBvZiBmbG9vcnMgZm9yIGJ1aWxkaW5ncyBidWlsdHMgYmV0d2VlbiAxODUwIHRvIDIwMjAuIA0KDQpgYGB7cn0NCnBsb3RmbG9vcnMgPC0gZ2dwbG90KG55Zmxvb3JzLCBhZXMoeD1ZZWFyQnVpbHQsIHk9Rmxvb3JzKSkgKyBnZW9tX3BvaW50KHBvc2l0aW9uPSdqaXR0ZXInKSArIA0KICB0aGVtZV9idygpICsgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcpICsgDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTg1MCwyMDIwLCAyMCkpICsgDQogIGxhYnMoeCA9ICdZZWFyIEJ1aWx0JywgdGl0bGUgPSAnTllDIEJ1aWxkaW5ncyBCeSBGbG9vcnMnKSArIA0KICBmYWNldF93cmFwKCB+IE51bUZsb29ycykNCg0KcGxvdGZsb29ycyA8LSBnZ3Bsb3RseShwbG90Zmxvb3JzKQ0KcGxvdGZsb29ycw0KYGBgDQoNCiMjIyAqKlF1ZXN0aW9uIDIqKg0KDQpZb3Ugd29yayBmb3IgYSByZWFsIGVzdGF0ZSBkZXZlbG9wZXIgYW5kIGFyZSByZXNlYXJjaGluZyB1bmRlcmJ1aWx0IGFyZWFzIG9mIHRoZSBjaXR5LiBBZnRlciBsb29raW5nIGluIHRoZSBQbHV0byBkYXRhIGRpY3Rpb25hcnksIHlvdSd2ZSBkaXNjb3ZlcmVkIHRoYXQgYWxsIHRheCBhc3Nlc3NtZW50cyBjb25zaXN0IG9mIHR3byBwYXJ0czogVGhlIGFzc2Vzc21lbnQgb2YgdGhlIGxhbmQgYW5kIGFzc2Vzc21lbnQgb2YgdGhlIHN0cnVjdHVyZS4gWW91IHJlYXNvbiB0aGF0IHRoZXJlIHNob3VsZCBiZSBhIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlc2UgdHdvIHZhbHVlczogbW9yZSB2YWx1YWJsZSBsYW5kIHdpbGwgaGF2ZSBtb3JlIHZhbHVhYmxlIHN0cnVjdHVyZXMgb24gdGhlbSAobW9yZSB2YWx1YWJsZSBpbiB0aGlzIGNhc2UgcmVmZXJzIG5vdCBqdXN0IHRvIGEgbWFuc2lvbiB2cyBhIGJ1bmdhbG93LCBidXQgYW4gYXBhcnRtZW50IHRvd2VyIHZzIGEgc2luZ2xlIGZhbWlseSBob21lKS4gRGV2aWF0aW9ucyBmcm9tIHRoZSBub3JtIGNvdWxkIHJlcHJlc2VudCB1bmRlcmJ1aWx0IG9yIG92ZXJidWlsdCBhcmVhcyBvZiB0aGUgY2l0eS4gWW91IGFsc28gcmVjZW50bHkgcmVhZCBhIHJlYWxseSBjb29sIGJsb2cgcG9zdCBhYm91dCBiaXZhcmlhdGUgY2hvcm9wbGV0aCBtYXBzLCBhbmQgdGhpbmsgdGhlIHRlY2huaXF1ZSBjb3VsZCBiZSB1c2VkIGZvciB0aGlzIHByb2JsZW0uDQoNCkRhdGFzaGFkZXIgaXMgcmVhbGx5IGNvb2wsIGJ1dCBpdCdzIG5vdCB0aGF0IGdyZWF0IGF0IGxhYmVsaW5nIHlvdXIgdmlzdWFsaXphdGlvbi4gRG9uJ3Qgd29ycnkgYWJvdXQgcHJvdmlkaW5nIGEgbGVnZW5kLCBidXQgcHJvdmlkZSBhIHF1aWNrIGV4cGxhbmF0aW9uIGFzIHRvIHdoaWNoIGFyZWFzIG9mIHRoZSBjaXR5IGFyZSBvdmVyYnVpbHQsIHdoaWNoIGFyZWFzIGFyZSB1bmRlcmJ1aWx0LCBhbmQgd2hpY2ggYXJlYXMgYXJlIGJ1aWx0IGluIGEgd2F5IHRoYXQncyBwcm9wZXJseSBjb3JyZWxhdGVkIHdpdGggdGhlaXIgbGFuZCB2YWx1ZS4NCg0KYGBge3J9DQpjaXR5dGF4IDwtIG55ZGF0YSAlPiUgDQogIHNlbGVjdChBc3Nlc3NUb3QsIEFzc2Vzc0xhbmQsICBaaXBDb2RlKSAlPiUgDQogIG11dGF0ZShBc3Nlc3NCbGRnID0gQXNzZXNzVG90IC0gQXNzZXNzTGFuZCkgJT4lIA0KICBtdXRhdGUoemlwU3RyID0gdG9TdHJpbmcoWmlwQ29kZSkpICU+JSANCiAgZ3JvdXBfYnkoWmlwQ29kZSkgJT4lIA0KICBzdW1tYXJpc2Uoc3VtKEFzc2Vzc1RvdCksIHN1bShBc3Nlc3NMYW5kKSwgc3VtKEFzc2Vzc0JsZGcpKSAlPiUgDQogIG11dGF0ZShCbGRnTGFuZCA9IGBzdW0oQXNzZXNzQmxkZylgL2BzdW0oQXNzZXNzTGFuZClgKSAlPiUgDQogIG11dGF0ZShGcmVxID0gcmFuayhgc3VtKEFzc2Vzc0xhbmQpYCkpICU+JSANCiAgYXJyYW5nZShGcmVxKSAlPiUgDQogIGZpbHRlcihGcmVxIDw9IDE1KQ0KYGBgDQoNClRoZSBpbnRlcmFjdGl2ZSBncmFwaCBiZWxvdyBzaG93cyB0aGUgYXJlYXMgb2YgdGhlIGNpdHkgdGhhdCBhcmUgdW5kZXJidWlsdCBvciBvdmVyYnVpbHQgYnkgemlwIGNvZGUuIFRoZSBhcmVhcyBhcm91bmQgMTE2OTcgKFJvY2thd2F5KSwgMTA4MDMgKFBlbGhhbSkgYW5kIDEwNDY0IChCcm9ueCkgc2VlbXMgdG8gYmUgdW5kZXJidWlsdCB3aGlsZSB6aXAgY29kZXMgMTExMDkgKExvbmcgSXNsYW5kIENpdHkpIGFuZCAxMTI0MSAoQnJvb2tseW4pIHNlZW1zIHRvIGJlIG92ZXIgYnVpbHQuDQoNCmBgYHtyfQ0Kb3ZlcmJ1aWx0IDwtIGdncGxvdChjaXR5dGF4LCBhZXMoeD1aaXBDb2RlLCB5PUZyZXEpLGNvbG91cj1ncm91cCkgKw0KICBnZW9tX3RpbGUoYWVzKGZpbGw9QmxkZ0xhbmQpKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEobWluKDEwMDAwKSwgbWF4KDEyMDAwKSwgYnkgPSAyMDApKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEobWluKDEpLCBtYXgoMTApLCBieSA9IDEpKSANCm92ZXJidWlsdCA8LSBnZ3Bsb3RseShvdmVyYnVpbHQsdG9vbHRpcCA9IGMoIngiLCAieSIsICJjb2xvdXIiKSkNCm92ZXJidWlsdA0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==