Suggested citation:
Mendez C. (2020). Bivariate distribution dynamics analysis in R. R Studio/RPubs. Available at https://rpubs.com/quarcs-lab/tutorial-bivariate-distribution-dynamics
This work is licensed under the Creative Commons Attribution-Non Commercial-Share Alike 4.0 International License.

Acknowledgment:
Material adapted from multiple sources, in particular the dataset is from Magrini (2007).
Replication files
The tutorial is self-contained. No aditional file is needed.
If you are a member of the QuaRCS lab, you can run this tutorial in R Studio Cloud
Tutorial objectives
Study the dynamics of univariate densities
Compute the bandwidth of a density
Study mobility plots
Study bi-variate densities
Study density-based clustering methods
Study conditional bi-variate densities
Import data
We will use two hypothetical cross-sectional series.
- The first (
x
) series was produced by drawing a random sample of 1000 observations from a univariate normal distribution.
- The second (
y
) series was produced by merging and sorting two random samples of 500 observations.
The mean and the standard deviation of these two series respectively matched those of the logarithm of per capita Gross Value Added observed for the Italian Provinces in 1996 and in 2002. For this reason assume that the analysis has been performed over a 6-year time period.
Descriptive statistics
skim_type |
skim_variable |
n_missing |
complete_rate |
numeric.mean |
numeric.sd |
numeric.p0 |
numeric.p25 |
numeric.p50 |
numeric.p75 |
numeric.p100 |
numeric.hist |
numeric |
x |
0 |
1 |
14883.41 |
3746.62 |
3344.50 |
12362.51 |
14974.61 |
17321.7 |
26506.5 |
▁▃▇▃▁ |
numeric |
y |
0 |
1 |
16441.00 |
4011.14 |
7400.07 |
12992.51 |
16244.71 |
20021.6 |
25394.5 |
▂▇▅▇▂ |
numeric |
log_x |
0 |
1 |
9.57 |
0.28 |
8.12 |
9.42 |
9.61 |
9.8 |
10.2 |
▁▁▂▇▃ |
numeric |
log_y |
0 |
1 |
9.68 |
0.25 |
8.91 |
9.47 |
9.70 |
9.9 |
10.1 |
▁▃▇▇▇ |
numeric |
rel_x |
0 |
1 |
1.00 |
0.25 |
0.22 |
0.83 |
1.01 |
1.2 |
1.8 |
▁▃▇▃▁ |
numeric |
rel_y |
0 |
1 |
1.00 |
0.24 |
0.45 |
0.79 |
0.99 |
1.2 |
1.5 |
▂▇▅▇▂ |
numeric |
rel_log_x |
0 |
1 |
1.00 |
0.03 |
0.85 |
0.98 |
1.00 |
1.0 |
1.1 |
▁▁▂▇▃ |
numeric |
rel_log_y |
0 |
1 |
0.99 |
0.03 |
0.84 |
0.97 |
0.99 |
1.0 |
1.1 |
▁▁▂▇▃ |
Univariate dynamics
Select bandwiths
select bandwidth based on function dpik
from the package KernSmooth
[1] 0.065
[1] 0.039
Plot each density


Plot both densities
Method 1
Keep the orignal bandwiths of the package KernSmooth
densities_plot <- densities %>%
ggplot()+
theme_minimal()+
geom_line(aes(domain_initial, density_initial))+
geom_line(aes(domain_final,density_final), linetype = "dashed")+
labs(subtitle = "",
x = "Relative Variable",
y = "Density") +
geom_label(
label="Year 2002",
x= 1.525,
y= 0.9,
label.size = 0.35,
color = "black",
) +
geom_label(
label="Year 1996",
x= 1.75,
y= 0.2,
label.size = 0.35,
color = "black",
)
densities_plot

Note that you have adjust the labels manually
- Interactive plotly version
Manual labels are not yet implemented in the ggplotly
function
Method 2
using the bandwidth default of ggplot

Using plotly
Bivariate density
Mobility scatterplot

Fit a non-linear function

Not that the nonlinear fit crosses the 45-degree line two times from above.
Using geom_pointdensity

Using the KernSmooth package

Interactive

Interactive version
Using the Bivariate package


Using ggplot (stat_density_2d())


Density-based clusters
An S4 object of class "pdfCluster"
Call: pdfCluster(x = dat[, 5:6])
Initial groupings:
label 1 2 NA
count 296 297 407
Final groupings:
label 1 2
count 504 496
Groups tree (here 'h' denotes 'height'):
--[dendrogram w/ 1 branches and 2 members at h = 1]
`--[dendrogram w/ 2 branches and 2 members at h = 0.593]
|--leaf "1 "
`--leaf "2 " (h= 0.152 )
Core clusters

Full clustering

Cluster tree

Mode function

Conditional density analysis
Using the hdrcde
package
Increase the number of intervals to 60


High density regions


Using the np
package
Compute adaptive bandwith based on cross-validation
Conditional density data (1000 observations, 2 variable(s))
(1 dependent variable(s), and 1 explanatory variable(s))
Bandwidth Selection Method: Maximum Likelihood Cross-Validation
Formula: dat$rel_y ~ dat$rel_x
Bandwidth Type: Adaptive Nearest Neighbour
Objective Function Value: 5502 (achieved on multistart 1)
Exp. Var. Name: dat$rel_x Bandwidth: 2
Dep. Var. Name: dat$rel_y Bandwidth: 2
Continuous Kernel Type: Second-Order Gaussian
No. Continuous Explanatory Vars.: 1
No. Continuous Dependent Vars.: 1
Estimation Time: 68 seconds
Compute conditional density object
Conditional Density Data: 1000 training points, in 2 variable(s)
(1 dependent variable(s), and 1 explanatory variable(s))
dat$rel_y
Dep. Var. Bandwidth(s): 2
dat$rel_x
Exp. Var. Bandwidth(s): 2
Bandwidth Type: Adaptive Nearest Neighbour
Log Likelihood: 5948
Continuous Kernel Type: Second-Order Gaussian
No. Continuous Explanatory Vars.: 1
No. Continuous Dependent Vars.: 1

References
Magrini, S. (2007). Analysing convergence through the distribution dynamics approach: why and how?. University Ca’Foscari of Venice, Dept. of Economics Research Paper Series No, 13.
Mendez C. (2020). Classical sigma and beta convergence analysis in R: Using the REAT 2.1 Package. R Studio/RPubs. Available at https://rpubs.com/quarcs-lab/classical-convergence-reat21
Mendez C. (2020). Univariate distribution dynamics in R: Using the ggridges package. R Studio/RPubs. Available at https://rpubs.com/quarcs-lab/univariate-distribution-dynamics
Mendez, C. (2020) Regional efficiency convergence and efficiency clusters. Asia-Pacific Journal of Regional Science, 1-21.
Mendez, C. (2019). Lack of Global Convergence and the Formation of Multiple Welfare Clubs across Countries: An Unsupervised Machine Learning Approach. Economies, 7(3), 74.
Mendez, C. (2019). Overall efficiency, pure technical efficiency, and scale efficiency across provinces in Indonesia 1990 and 2010. R Studio/RPubs. Available at https://rpubs.com/quarcs-lab/efficiency-clusters-indonesia-1990-2010
Mendez-Guerra, C. (2018). On the distribution dynamics of human development: Evidence from the metropolitan regions of Bolivia’’. Economics Bulletin, 38(4), 2467-2475.
END
LS0tCnRpdGxlOiAiQml2YXJpYXRlIGRpc3RyaWJ1dGlvbiBkeW5hbWljcyBhbmFseXNpcyBpbiBSIgpzdWJ0aXRsZTogIiIKYXV0aG9yOiAiQ2FybG9zIE1lbmRleiIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICAgIHRvY19kZXB0aDogNAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIgogICAgdGhlbWU6ICJjb3NtbyIKICAgIGhpZ2hsaWdodDogIm1vbm9jaHJvbWUiCiAgICBkZl9wcmludDogImthYmxlIgogIGdpdGh1Yl9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogICAgdG9jX2RlcHRoOiA0CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogInNob3ciCiAgICB0aGVtZTogImNvc21vIgogICAgaGlnaGxpZ2h0OiAibW9ub2Nocm9tZSIKLS0tCgo8c3R5bGU+CmgxLnRpdGxlIHtmb250LXNpemU6IDE4cHQ7IGNvbG9yOiBEYXJrQmx1ZTt9IApib2R5LCBoMSwgaDIsIGgzLCBoNCB7Zm9udC1mYW1pbHk6ICJQYWxhdGlubyIsIHNlcmlmO30KYm9keSB7Zm9udC1zaXplOiAxMnB0O30KLyogSGVhZGVycyAqLwpoMSxoMixoMyxoNCxoNSxoNntmb250LXNpemU6IDE0cHQ7IGNvbG9yOiAjMDAwMDhCO30KYm9keSB7Y29sb3I6ICMzMzMzMzM7fQphLCBhOmhvdmVyIHtjb2xvcjogIzhCM0E2Mjt9CnByZSB7Zm9udC1zaXplOiAxMnB4O30KPC9zdHlsZT4KClN1Z2dlc3RlZCBjaXRhdGlvbjogCgo+IE1lbmRleiBDLiAoMjAyMCkuIEJpdmFyaWF0ZSBkaXN0cmlidXRpb24gZHluYW1pY3MgYW5hbHlzaXMgaW4gUi4gUiBTdHVkaW8vUlB1YnMuIEF2YWlsYWJsZSBhdCA8aHR0cHM6Ly9ycHVicy5jb20vcXVhcmNzLWxhYi90dXRvcmlhbC1iaXZhcmlhdGUtZGlzdHJpYnV0aW9uLWR5bmFtaWNzPgoKVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbiBDb21tZXJjaWFsLVNoYXJlIEFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsIExpY2Vuc2UuIAoKIVtdKExpY2Vuc2UuanBnKQoKQWNrbm93bGVkZ21lbnQ6CgpNYXRlcmlhbCBhZGFwdGVkIGZyb20gbXVsdGlwbGUgc291cmNlcywgaW4gcGFydGljdWxhciB0aGUgZGF0YXNldCBpcyBmcm9tIFtNYWdyaW5pICgyMDA3KS5dKGh0dHBzOi8vcGRmcy5zZW1hbnRpY3NjaG9sYXIub3JnL2VhYjEvY2I4OWRkZTBjOTA5ODk4YjBhNDMyNzMzNzdjNWRmYTczZWJjLnBkZikKCgojIFJlcGxpY2F0aW9uIGZpbGVzCgotIFRoZSB0dXRvcmlhbCBpcyBzZWxmLWNvbnRhaW5lZC4gTm8gYWRpdGlvbmFsIGZpbGUgaXMgbmVlZGVkLgoKLSBJZiB5b3UgYXJlIGEgbWVtYmVyIG9mIHRoZSBbUXVhUkNTIGxhYl0oaHR0cHM6Ly9xdWFyY3MtbGFiLnJiaW5kLmlvLyksIHlvdSBjYW4gcnVuIHRoaXMgdHV0b3JpYWwgaW4gW1IgU3R1ZGlvIENsb3VkXShodHRwczovL3JzdHVkaW8uY2xvdWQvc3BhY2VzLzE1NTk3L3Byb2plY3QvOTg0MjY2ICkgCgoKIyBMaWJyYXJpZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNraW1yKQpsaWJyYXJ5KGthYmxlRXh0cmEpICAgICMgaHRtbCB0YWJsZXMgCmxpYnJhcnkocGRmQ2x1c3RlcikgICAgIyBkZW5zaXR5IGJhc2VkIGNsdXN0ZXJzCmxpYnJhcnkoaGRyY2RlKSAgICAgICAgIyBjb25kaXRpb25hbCBkZW5zaXR5IGVzdGltYXRpb24gCmxpYnJhcnkocGxvdGx5KQoKbGlicmFyeShpbnRvbykKbGlicmFyeShiYXJzdXJmKQpsaWJyYXJ5KGJpdmFyaWF0ZSkKCmxpYnJhcnkobnApCgpsaWJyYXJ5KGJhc2V0aGVtZSkKYmFzZXRoZW1lKCJtaW5pbWFsIikKCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShnZ3BvaW50ZGVuc2l0eSkKbGlicmFyeShpc29iYW5kKQoKI2xpYnJhcnkoTUFTUykKbGlicmFyeShLZXJuU21vb3RoKQoKCiMgQ2hhbmdlIHRoZSBwcmVzZW50YXRpb24gb2YgZGVjaW1hbCBudW1iZXJzIHRvIDQgYW5kIGF2b2lkIHNjaWVudGlmaWMgbm90YXRpb24Kb3B0aW9ucyhwcm9tcHQ9IlI+ICIsIGRpZ2l0cz0yLCBzY2lwZW49OTk5KQoKYGBgCgojIFR1dG9yaWFsIG9iamVjdGl2ZXMKCi0gU3R1ZHkgdGhlIGR5bmFtaWNzIG9mIHVuaXZhcmlhdGUgZGVuc2l0aWVzCgotIENvbXB1dGUgdGhlIGJhbmR3aWR0aCBvZiBhIGRlbnNpdHkKCi0gU3R1ZHkgbW9iaWxpdHkgcGxvdHMKCi0gU3R1ZHkgYmktdmFyaWF0ZSBkZW5zaXRpZXMKCi0gU3R1ZHkgZGVuc2l0eS1iYXNlZCBjbHVzdGVyaW5nIG1ldGhvZHMKCi0gU3R1ZHkgY29uZGl0aW9uYWwgYmktdmFyaWF0ZSBkZW5zaXRpZXMKCgoKIyBJbXBvcnQgZGF0YQoKCldlIHdpbGwgdXNlIHR3byBoeXBvdGhldGljYWwgY3Jvc3Mtc2VjdGlvbmFsIHNlcmllcy4KCi0gVGhlIGZpcnN0IChgeGApIHNlcmllcyB3YXMgcHJvZHVjZWQgYnkgZHJhd2luZyBhIHJhbmRvbSBzYW1wbGUgb2YgMTAwMCBvYnNlcnZhdGlvbnMgZnJvbSBhIHVuaXZhcmlhdGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gCi0gVGhlIHNlY29uZCAoYHlgKSBzZXJpZXMgd2FzIHByb2R1Y2VkIGJ5IG1lcmdpbmcgYW5kIHNvcnRpbmcgdHdvIHJhbmRvbSBzYW1wbGVzIG9mIDUwMCBvYnNlcnZhdGlvbnMuCgpUaGUgbWVhbiBhbmQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGVzZSB0d28gc2VyaWVzIHJlc3BlY3RpdmVseSBtYXRjaGVkIHRob3NlIG9mIHRoZSBsb2dhcml0aG0gb2YgcGVyIGNhcGl0YSBHcm9zcyBWYWx1ZSBBZGRlZCBvYnNlcnZlZCBmb3IgdGhlIEl0YWxpYW4gUHJvdmluY2VzIGluIDE5OTYgYW5kIGluIDIwMDIuIEZvciB0aGlzIHJlYXNvbiBhc3N1bWUgIHRoYXQgdGhlIGFuYWx5c2lzIGhhcyBiZWVuIHBlcmZvcm1lZCBvdmVyIGEgNi15ZWFyIHRpbWUgcGVyaW9kLiAKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPVRSVUV9CmRhdCA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2RzNzc3L3NhbXBsZS1kYXRhc2V0cy9tYXN0ZXIvc2ltRGF0YS5jc3YiKQpgYGAKCgojIFRyYW5zZm9ybSBkYXRhCgoKU2luY2UgdGhlIGRhdGEgaXMgaW4gbG9nIHRlcm1zLCBsZXQgdXMgcmVuYW1lIHRoZSB2YXJpYWJsZXMgYW5kIGFkZCBuZXcgdmFyaWFibGVzLgoKYGBge3J9CmRhdCA8LSBkYXQgJT4lIAogIHJlbmFtZShsb2dfeCA9IHgsIGxvZ195ID0geSkgJT4lIAogIG11dGF0ZSh4ID0gZXhwKGxvZ194KSwgeSA9IGV4cChsb2dfeSkpICU+JSAKICBzZWxlY3QoeCwgeSwgZXZlcnl0aGluZygpKSAKYGBgCgpgYGB7cn0KZGF0IDwtIGRhdCAlPiUgCiAgbXV0YXRlKAogICAgcmVsX3ggPSB4L21lYW4oeCksCiAgICByZWxfeSA9IHkvbWVhbih5KSwKICAgIHJlbF9sb2dfeCA9IGxvZ194L21lYW4obG9nX3gpLAogICAgcmVsX2xvZ195ID0gbG9nX3gvbWVhbihsb2dfeSksCiAgKQpkYXQKYGBgCgoKCiMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcwoKYGBge3J9CnNraW0oZGF0KSAlPiUgCiAga2FibGUoKSAlPiUgCiAga2FibGVfc3R5bGluZygpCmBgYAoKCgoKIyBVbml2YXJpYXRlIGR5bmFtaWNzCgojIyBTZWxlY3QgYmFuZHdpdGhzCgpzZWxlY3QgYmFuZHdpZHRoIGJhc2VkIG9uIGZ1bmN0aW9uIGBkcGlrYCBmcm9tIHRoZSBwYWNrYWdlIGBLZXJuU21vb3RoYAoKYGBge3J9CmhfcmVsX3ggPC0gZHBpayhkYXQkcmVsX3gpCmhfcmVsX3gKYGBgCgoKYGBge3J9CmhfcmVsX3kgPC0gZHBpayhkYXQkcmVsX3kpCmhfcmVsX3kKYGBgCgojIyBQbG90IGVhY2ggZGVuc2l0eQoKYGBge3J9CmRpc19yZWxfeCA8LSBia2RlKGRhdCRyZWxfeCwgYmFuZHdpZHRoID0gaF9yZWxfeCkKZGlzX3JlbF94IDwtIGFzLmRhdGEuZnJhbWUoZGlzX3JlbF94KQpnZ3Bsb3QoZGlzX3JlbF94LCBhZXMoeCwgeSkpICsgZ2VvbV9saW5lKCkgKyAKICB0aGVtZV9taW5pbWFsKCkgCmBgYAoKCmBgYHtyfQpkaXNfcmVsX3kgPC0gYmtkZShkYXQkcmVsX3ksIGJhbmR3aWR0aCA9IGhfcmVsX3kpCmRpc19yZWxfeSA8LSBhcy5kYXRhLmZyYW1lKGRpc19yZWxfeSkKZ2dwbG90KGRpc19yZWxfeSwgYWVzKHgsIHkpKSArIGdlb21fbGluZSgpICsgCiAgdGhlbWVfbWluaW1hbCgpIApgYGAKCgojIyBQbG90IGJvdGggZGVuc2l0aWVzCgojIyMgTWV0aG9kIDEKCktlZXAgdGhlIG9yaWduYWwgYmFuZHdpdGhzIG9mIHRoZSBwYWNrYWdlIGBLZXJuU21vb3RoYAoKYGBge3J9CmRvbWFpbl9pbml0aWFsIDwtIGRpc19yZWxfeCR4CmRvbWFpbl9maW5hbCAgIDwtIGRpc19yZWxfeSR4CgpkZW5zaXR5X2luaXRpYWwgPC0gZGlzX3JlbF94JHkKZGVuc2l0eV9maW5hbCAgIDwtIGRpc19yZWxfeSR5CgpkZW5zaXRpZXMgPC0gY2JpbmQoZG9tYWluX2luaXRpYWwsIGRlbnNpdHlfaW5pdGlhbCwgZG9tYWluX2ZpbmFsLCBkZW5zaXR5X2ZpbmFsKQoKZGVuc2l0aWVzIDwtICBhcy5kYXRhLmZyYW1lKGRlbnNpdGllcykKYGBgCgoKYGBge3J9CmRlbnNpdGllc19wbG90IDwtIGRlbnNpdGllcyAlPiUgCiAgZ2dwbG90KCkrCiAgdGhlbWVfbWluaW1hbCgpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2luaXRpYWwsIGRlbnNpdHlfaW5pdGlhbCkpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2ZpbmFsLGRlbnNpdHlfZmluYWwpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsKIGxhYnMoc3VidGl0bGUgPSAiIiwKICAgICAgIHggPSAiUmVsYXRpdmUgVmFyaWFibGUiLAogICAgICAgeSA9ICJEZW5zaXR5IikgKyAKICBnZW9tX2xhYmVsKAogICAgbGFiZWw9IlllYXIgMjAwMiIsIAogICAgeD0gMS41MjUsCiAgICB5PSAwLjksCiAgICBsYWJlbC5zaXplID0gMC4zNSwKICAgIGNvbG9yID0gImJsYWNrIiwKICApICsKICAgZ2VvbV9sYWJlbCgKICAgIGxhYmVsPSJZZWFyIDE5OTYiLCAKICAgIHg9IDEuNzUsCiAgICB5PSAwLjIsCiAgICBsYWJlbC5zaXplID0gMC4zNSwKICAgIGNvbG9yID0gImJsYWNrIiwKICApCmRlbnNpdGllc19wbG90CmBgYAoKTm90ZSB0aGF0IHlvdSBoYXZlIGFkanVzdCB0aGUgbGFiZWxzIG1hbnVhbGx5CgotIEludGVyYWN0aXZlIHBsb3RseSB2ZXJzaW9uCgpgYGB7cn0KZGVuc2l0aWVzX3Bsb3QyIDwtIGRlbnNpdGllcyAlPiUgCiAgZ2dwbG90KCkrCiAgdGhlbWVfbWluaW1hbCgpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2luaXRpYWwsIGRlbnNpdHlfaW5pdGlhbCkpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2ZpbmFsLGRlbnNpdHlfZmluYWwpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsKIGxhYnMoc3VidGl0bGUgPSAiIiwKICAgICAgIHggPSAiUmVsYXRpdmUgVmFyaWFibGUiLAogICAgICAgeSA9ICJEZW5zaXR5IikgCgpnZ3Bsb3RseShkZW5zaXRpZXNfcGxvdDIpCmBgYAoKTWFudWFsIGxhYmVscyBhcmUgbm90IHlldCBpbXBsZW1lbnRlZCBpbiB0aGUgYGdncGxvdGx5YCBmdW5jdGlvbgoKCiMjIyBNZXRob2QgMgoKdXNpbmcgdGhlIGJhbmR3aWR0aCBkZWZhdWx0IG9mIGdncGxvdCAKCgpgYGB7cn0KcmVsX3ggPC0gZGF0ICU+JSAKICBzZWxlY3QocmVsX3gpICU+JSAKICByZW5hbWUocmVsX3ZhciA9IHJlbF94KSAlPiUgCiAgbXV0YXRlKHllYXIgPSAxOTk2KQpgYGAKCmBgYHtyfQpyZWxfeSA8LSBkYXQgJT4lIAogIHNlbGVjdChyZWxfeSkgJT4lIAogIHJlbmFtZShyZWxfdmFyID0gcmVsX3kpICU+JSAKICBtdXRhdGUoeWVhciA9IDIwMDIpCmBgYAoKYGBge3J9CnJlbF94eSA8LSBiaW5kX3Jvd3MocmVsX3gsIHJlbF95KQpgYGAKIApgYGB7cn0KcmVsX3h5IDwtIHJlbF94eSAlPiUgCiAgbXV0YXRlKHllYXIgPSBhcy5mYWN0b3IoeWVhcikpCmhlYWQocmVsX3h5KQpgYGAKIAogCgpgYGB7cn0KZGlzX3JlbF94eSA8LSBnZ3Bsb3QocmVsX3h5LCBhZXMoeD1yZWxfdmFyLCBjb2xvcj15ZWFyKSkgKwogIGdlb21fZGVuc2l0eSgpICsgCiAgdGhlbWVfbWluaW1hbCgpIApkaXNfcmVsX3h5CmBgYAoKClVzaW5nIHBsb3RseQoKYGBge3J9CmdncGxvdGx5KGRpc19yZWxfeHkpCmBgYAoKCgojIEJpdmFyaWF0ZSBkZW5zaXR5CgojIyBNb2JpbGl0eSBzY2F0dGVycGxvdAoKYGBge3J9CmRhdCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVsX3gsIHkgPSByZWxfeSkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoc3VidGl0bGUgPSAiUmVsYXRpdmUgeSIsCiAgICAgICB4ID0gIlJlbGF0aXZlIHgiLAogICAgICAgeSA9ICIiKSArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoZmFtaWx5PSJQYWxhdGlubyIpKSAKYGBgCgoKRml0IGEgbm9uLWxpbmVhciBmdW5jdGlvbgoKYGBge3J9CmRhdCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVsX3gsIHkgPSByZWxfeSkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyAKICBnZW9tX3Ntb290aCgpICsgCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZT0iZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyhzdWJ0aXRsZSA9ICJSZWxhdGl2ZSB5IiwKICAgICAgIHggPSAiUmVsYXRpdmUgeCIsCiAgICAgICB5ID0gIiIpICsKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlBhbGF0aW5vIikpIApgYGAKCk5vdCB0aGF0IHRoZSBub25saW5lYXIgZml0IGNyb3NzZXMgdGhlIDQ1LWRlZ3JlZSBsaW5lIHR3byB0aW1lcyBmcm9tIGFib3ZlLgoKIyMgVXNpbmcgZ2VvbV9wb2ludGRlbnNpdHkgCgpgYGB7cn0KZGF0ICU+JSAKZ2dwbG90KGFlcyh4ID0gcmVsX3gsIHkgPSByZWxfeSkpICsKICBnZW9tX3BvaW50ZGVuc2l0eSgpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoc3VidGl0bGUgPSAiUmVsYXRpdmUgeSIpICsgCiAgeGxhYigiUmVsYXRpdmUgeCIpICsKICB5bGFiKCIiKQpgYGAKCgojIyAgVXNpbmcgdGhlIEtlcm5TbW9vdGggcGFja2FnZQoKYGBge3J9Cnh5IDwtIGNiaW5kKGRhdCRyZWxfeCwgZGF0JHJlbF95KQp4eV9kaXMgPC0gYmtkZTJEKHh5LCBiYW5kd2lkdGggPSBjKGhfcmVsX3gsIGhfcmVsX3kpKSAKYGBgCgpgYGB7cn0KY29udG91cih4eV9kaXMkeDEsIHh5X2RpcyR4MiwgeHlfZGlzJGZoYXQpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCkludGVyYWN0aXZlCgpgYGB7cn0KcGxvdF9seSh4PXh5X2RpcyR4MSwgeT14eV9kaXMkeDIsIHo9eHlfZGlzJGZoYXQsIHR5cGUgPSAiY29udG91ciIsIGNvbnRvdXJzID0gbGlzdChzaG93bGFiZWxzID0gVFJVRSkpICAlPiUKICBjb2xvcmJhcih0aXRsZSA9ICJEZW5zaXR5IikKYGBgCgoKCmBgYHtyfQpwZXJzcCh4eV9kaXMkZmhhdCkKYGBgCgpJbnRlcmFjdGl2ZSB2ZXJzaW9uCgpgYGB7cn0KcGxvdF9seSh4PXh5X2RpcyR4MSwgeT14eV9kaXMkeDIsIHo9eHlfZGlzJGZoYXQpICU+JSBhZGRfc3VyZmFjZSgpCmBgYAoKCiMjIFVzaW5nIHRoZSBCaXZhcmlhdGUgcGFja2FnZQoKYGBge3J9CmJpdmFyaWF0ZSA8LSBrYnZwZGYoZGF0JHJlbF94LCBkYXQkcmVsX3ksIGhfcmVsX3gsIGhfcmVsX3kpIApgYGAKCgpgYGB7cn0KcGxvdChiaXZhcmlhdGUsCiAgICAgIHhsYWI9IlJlbGF0aXZlIHgiLCAKICAgICAgeWxhYj0iUmVsYXRpdmUgeSIpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCgpgYGB7cn0KcGxvdChiaXZhcmlhdGUsCiAgICAgIFRSVUUsCiAgICAgIHhsYWI9IlJlbGF0aXZlIHgiLCAKICAgICAgeWxhYj0iUmVsYXRpdmUgeSIpCmBgYAoKCiMjIFVzaW5nIGdncGxvdCAoc3RhdF9kZW5zaXR5XzJkKCkpCgpgYGB7cn0KZGF0ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZWxfeCwgeSA9IHJlbF95KSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAibGlnaHRncmF5IikgKyAKICBnZW9tX3Ntb290aCgpICsgCiAgI2dlb21fc21vb3RoKG1ldGhvZD1sbSwgc2U9RkFMU0UpICsgCiAgc3RhdF9kZW5zaXR5XzJkKCkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoc3VidGl0bGUgPSAiUmVsYXRpdmUgeSIsCiAgICAgICB4ID0gIlJlbGF0aXZlIHgiLAogICAgICAgeSA9ICIiKSArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoZmFtaWx5PSJQYWxhdGlubyIpKSAKYGBgCgoKCmBgYHtyfQpkYXQgJT4lIAogIGdncGxvdChhZXMoeCA9IHJlbF94LCB5ID0gcmVsX3kpKSArCiAgICAgICAgc3RhdF9kZW5zaXR5XzJkKGFlcyhmaWxsID0gc3RhdChubGV2ZWwpKSwgZ2VvbSA9ICJwb2x5Z29uIikgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsKICAgICAgICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKSkgKwogICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiKSArIAogICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiKSArIAogIHRoZW1lX21pbmltYWwoKSArCiAgICAgICAgbGFicyh4ID0gIlJlbGF0aXZlIFgiLAogICAgICAgICAgICAgeSA9ICJSZWxhdGl2ZSBZIikgKwogICAgICAgIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCwgZmFtaWx5PSJQYWxhdGlubyIpKQpgYGAKCgojIERlbnNpdHktYmFzZWQgY2x1c3RlcnMKCgpgYGB7cn0KeHlfY2x1c3RlciA8LSBwZGZDbHVzdGVyKGRhdFssIDU6Nl0pIApzdW1tYXJ5KHh5X2NsdXN0ZXIpCmBgYAoKIyMgQ29yZSBjbHVzdGVycwoKYGBge3J9CnBsb3QoeHlfY2x1c3RlciwgCiAgICAgIHN0YWdlID0gMCwKICAgICAgd2hpY2ggPSAzLAogICAgICBmcmFtZSA9IEYpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCgojIyBGdWxsIGNsdXN0ZXJpbmcKCmBgYHtyfQpwbG90KHh5X2NsdXN0ZXIsIAogICAgICB3aGljaCA9IDMsCiAgICAgIGZyYW1lID0gRikKYWJsaW5lKGE9MCwgYj0xKQphYmxpbmUoaD0xLCB2PTEpCmBgYAoKIyMgQ2x1c3RlciB0cmVlCgpgYGB7cn0KcGxvdCh4eV9jbHVzdGVyLCB3aGljaCA9IDIpCmBgYAoKIyMgTW9kZSBmdW5jdGlvbgoKYGBge3J9CnBsb3QoeHlfY2x1c3Rlciwgd2hpY2ggPSAxKQpgYGAKCgojIENvbmRpdGlvbmFsIGRlbnNpdHkgYW5hbHlzaXMKCiMjIFVzaW5nIHRoZSBgaGRyY2RlYCBwYWNrYWdlCgpgYGB7cn0KeHlfY2RlIDwtIGNkZShkYXQkcmVsX3gsIGRhdCRyZWxfeSkKYGBgCgpJbmNyZWFzZSB0aGUgbnVtYmVyIG9mIGludGVydmFscyB0byA2MAoKYGBge3J9Cnh5X2NkZTIgPC0gY2RlKGRhdCRyZWxfeCwgZGF0JHJlbF95LCBueG1hcmdpbiA9IDYwKQpgYGAKCgpgYGB7cn0KcGxvdCh4eV9jZGUpCmBgYAoKCmBgYHtyfQpwbG90KHh5X2NkZTIpCmBgYAoKCkhpZ2ggZGVuc2l0eSByZWdpb25zCgoKYGBge3J9CnBsb3QoeHlfY2RlLCBwbG90LmZuPSJoZHIiKQphYmxpbmUoYT0wLCBiPTEpCmFibGluZShoPTEsIHY9MSkKYGBgCgoKCmBgYHtyfQpwbG90KHh5X2NkZTIsIHBsb3QuZm49ImhkciIpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCgojIyBVc2luZyB0aGUgYG5wYCBwYWNrYWdlCgpDb21wdXRlIGFkYXB0aXZlIGJhbmR3aXRoIGJhc2VkIG9uIGNyb3NzLXZhbGlkYXRpb24KCmBgYHtyfQpid19jX2FkX2N2IDwtIG5wY2RlbnNidygKICBmb3JtdWxhID0gZGF0JHJlbF95IH4gZGF0JHJlbF94LCAKICBid3R5cGUgPSAiYWRhcHRpdmVfbm4iKSAKYGBgCgpgYGB7cn0Kc3VtbWFyeShid19jX2FkX2N2KQpgYGAKCkNvbXB1dGUgY29uZGl0aW9uYWwgZGVuc2l0eSBvYmplY3QKCmBgYHtyfQpjZGlzdF9id0NWIDwtIG5wY2RlbnMoYndzID0gYndfY19hZF9jdikKc3VtbWFyeShjZGlzdF9id0NWKQpgYGAKCgpgYGB7cn0KIyMgQmV0dGVyIGNvcHkgYW5kIHBhc3RlIGl0IGluIHRoZSBjb25zb2xlIGJlY2F1c2UgaXQgaXMgYW4gYW5pbWF0aW9uCiMgcGxvdChid19jX2FkX2N2KQpgYGAKCgpgYGB7cn0KcGxvdChjZGlzdF9id0NWLCAKICAgICAgeHRyaW0gPSAtMC4yLCAKICAgICAgdmlldyA9ICJmaXhlZCIsCiAgICAgIG1haW4gPSAiIiwKICAgICAgdGhldGE9MzUwLAogICAgICBwaGk9MjApCmBgYAoKCgoKIyBSZWZlcmVuY2VzCgotIFtNYWdyaW5pLCBTLiAoMjAwNykuIEFuYWx5c2luZyBjb252ZXJnZW5jZSB0aHJvdWdoIHRoZSBkaXN0cmlidXRpb24gZHluYW1pY3MgYXBwcm9hY2g6IHdoeSBhbmQgaG93Py4gVW5pdmVyc2l0eSBDYSdGb3NjYXJpIG9mIFZlbmljZSwgRGVwdC4gb2YgRWNvbm9taWNzIFJlc2VhcmNoIFBhcGVyIFNlcmllcyBObywgMTMuIF0oaHR0cHM6Ly9wZGZzLnNlbWFudGljc2Nob2xhci5vcmcvZWFiMS9jYjg5ZGRlMGM5MDk4OThiMGE0MzI3MzM3N2M1ZGZhNzNlYmMucGRmKQoKLSBNZW5kZXogQy4gKDIwMjApLiBDbGFzc2ljYWwgc2lnbWEgYW5kIGJldGEgY29udmVyZ2VuY2UgYW5hbHlzaXMgaW4gUjogVXNpbmcgdGhlIFJFQVQgMi4xIFBhY2thZ2UuIFIgU3R1ZGlvL1JQdWJzLiBBdmFpbGFibGUgYXQgaHR0cHM6Ly9ycHVicy5jb20vcXVhcmNzLWxhYi9jbGFzc2ljYWwtY29udmVyZ2VuY2UtcmVhdDIxCgotIE1lbmRleiBDLiAoMjAyMCkuIFVuaXZhcmlhdGUgZGlzdHJpYnV0aW9uIGR5bmFtaWNzIGluIFI6IFVzaW5nIHRoZSBnZ3JpZGdlcyBwYWNrYWdlLiBSIFN0dWRpby9SUHVicy4gQXZhaWxhYmxlIGF0IGh0dHBzOi8vcnB1YnMuY29tL3F1YXJjcy1sYWIvdW5pdmFyaWF0ZS1kaXN0cmlidXRpb24tZHluYW1pY3MKCi0gW01lbmRleiwgQy4gKDIwMjApIFJlZ2lvbmFsIGVmZmljaWVuY3kgY29udmVyZ2VuY2UgYW5kIGVmZmljaWVuY3kgY2x1c3RlcnMuIEFzaWEtUGFjaWZpYyBKb3VybmFsIG9mIFJlZ2lvbmFsIFNjaWVuY2UsIDEtMjEuXShodHRwOi8vZW0ucmRjdS5iZS93Zi9jbGljaz91cG49bE1aeTFsZXJuU0o3YXBjNURnWU04WVRoU0k1YktXMDZ6blczQmFuTy0yRlJzLTNEX3U2YTJQcUYzdnNsTk50U1JiaHhKUGNKS3hPNUVLek9zZjAtMkZXaWl6TjU3ZDRjc0Y3UmVNdXI1ZTQwVGJYNDhEYlNlOWtFTUN3RnB2dkZwTGN1YVZCLTJCcGRDM2ZMQ2JzUDBpS2NzeElzMWR2MXlyUHNHRENOaDViaGd2STgtMkYtMkJ4d3o3dXBqRGd5Y3FQYmhPYk5xa1Q0MXVxWTNkUGlYcjV2Qm9ZMXh3VDg4TUEzLTJGYmRKZ3dvQmwxR256bGkxM21rbWxKajBrcVRzLTJCbGxWZkNUQjM1Nm1MampLUjJWQlpDVWdLYnlWcFlndTF2WGp3VHdkT3l6ZDVGVGJVOGVhUnNXeU9SamU3V0NQcEdFS0NVQXZiZVRDU1BhMnJmZGttbmtRSXJzbVlCU3FmU1o4YWFXekh3SWtNVTNoeGJJVTZuSEdRKSAKCi0gW01lbmRleiwgQy4gKDIwMTkpLiBMYWNrIG9mIEdsb2JhbCBDb252ZXJnZW5jZSBhbmQgdGhlIEZvcm1hdGlvbiBvZiBNdWx0aXBsZSBXZWxmYXJlIENsdWJzIGFjcm9zcyBDb3VudHJpZXM6IEFuIFVuc3VwZXJ2aXNlZCBNYWNoaW5lIExlYXJuaW5nIEFwcHJvYWNoLiBFY29ub21pZXMsIDcoMyksIDc0Ll0oaHR0cHM6Ly93d3cubWRwaS5jb20vMjIyNy03MDk5LzcvMy83NC9wZGYpCgotIE1lbmRleiwgQy4gKDIwMTkpLiBPdmVyYWxsIGVmZmljaWVuY3ksIHB1cmUgdGVjaG5pY2FsIGVmZmljaWVuY3ksIGFuZCBzY2FsZSBlZmZpY2llbmN5IGFjcm9zcyBwcm92aW5jZXMgaW4gSW5kb25lc2lhIDE5OTAgYW5kIDIwMTAuIFIgU3R1ZGlvL1JQdWJzLiBBdmFpbGFibGUgYXQgaHR0cHM6Ly9ycHVicy5jb20vcXVhcmNzLWxhYi9lZmZpY2llbmN5LWNsdXN0ZXJzLWluZG9uZXNpYS0xOTkwLTIwMTAKCi0gW01lbmRlei1HdWVycmEsIEMuICgyMDE4KS4gT24gdGhlIGRpc3RyaWJ1dGlvbiBkeW5hbWljcyBvZiBodW1hbiBkZXZlbG9wbWVudDogRXZpZGVuY2UgZnJvbSB0aGUgbWV0cm9wb2xpdGFuIHJlZ2lvbnMgb2YgQm9saXZpYScnLiBFY29ub21pY3MgQnVsbGV0aW4sIDM4KDQpLCAyNDY3LTI0NzUuXShodHRwOi8vd3d3LmFjY2Vzc2Vjb24uY29tL1B1YnMvRUIvMjAxOC9Wb2x1bWUzOC9FQi0xOC1WMzgtSTQtUDIyMy5wZGYpCgoKRU5ECg==