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).

1 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

3 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

4 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.

5 Transform data

Since the data is in log terms, let us rename the variables and add new variables.

6 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 ▁▁▂▇▃

7 Univariate dynamics

7.1 Select bandwiths

select bandwidth based on function dpik from the package KernSmooth

[1] 0.065
[1] 0.039

7.3 Plot both densities

7.3.1 Method 1

Keep the orignal bandwiths of the package KernSmooth

Note that you have adjust the labels manually

  • Interactive plotly version

Manual labels are not yet implemented in the ggplotly function

7.3.2 Method 2

using the bandwidth default of ggplot

Using plotly

8 Bivariate density

8.3 Using the KernSmooth package

Interactive

Interactive version

9 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  )

9.3 Cluster tree

9.4 Mode function

10 Conditional density analysis

10.2 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

LS0tCnRpdGxlOiAiQml2YXJpYXRlIGRpc3RyaWJ1dGlvbiBkeW5hbWljcyBhbmFseXNpcyBpbiBSIgpzdWJ0aXRsZTogIiIKYXV0aG9yOiAiQ2FybG9zIE1lbmRleiIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICAgIHRvY19kZXB0aDogNAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIgogICAgdGhlbWU6ICJjb3NtbyIKICAgIGhpZ2hsaWdodDogIm1vbm9jaHJvbWUiCiAgICBkZl9wcmludDogImthYmxlIgogIGdpdGh1Yl9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogICAgdG9jX2RlcHRoOiA0CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogInNob3ciCiAgICB0aGVtZTogImNvc21vIgogICAgaGlnaGxpZ2h0OiAibW9ub2Nocm9tZSIKLS0tCgo8c3R5bGU+CmgxLnRpdGxlIHtmb250LXNpemU6IDE4cHQ7IGNvbG9yOiBEYXJrQmx1ZTt9IApib2R5LCBoMSwgaDIsIGgzLCBoNCB7Zm9udC1mYW1pbHk6ICJQYWxhdGlubyIsIHNlcmlmO30KYm9keSB7Zm9udC1zaXplOiAxMnB0O30KLyogSGVhZGVycyAqLwpoMSxoMixoMyxoNCxoNSxoNntmb250LXNpemU6IDE0cHQ7IGNvbG9yOiAjMDAwMDhCO30KYm9keSB7Y29sb3I6ICMzMzMzMzM7fQphLCBhOmhvdmVyIHtjb2xvcjogIzhCM0E2Mjt9CnByZSB7Zm9udC1zaXplOiAxMnB4O30KPC9zdHlsZT4KClN1Z2dlc3RlZCBjaXRhdGlvbjogCgo+IE1lbmRleiBDLiAoMjAyMCkuIEJpdmFyaWF0ZSBkaXN0cmlidXRpb24gZHluYW1pY3MgYW5hbHlzaXMgaW4gUi4gUiBTdHVkaW8vUlB1YnMuIEF2YWlsYWJsZSBhdCA8aHR0cHM6Ly9ycHVicy5jb20vcXVhcmNzLWxhYi90dXRvcmlhbC1iaXZhcmlhdGUtZGlzdHJpYnV0aW9uLWR5bmFtaWNzPgoKVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbiBDb21tZXJjaWFsLVNoYXJlIEFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsIExpY2Vuc2UuIAoKIVtdKExpY2Vuc2UuanBnKQoKQWNrbm93bGVkZ21lbnQ6CgpNYXRlcmlhbCBhZGFwdGVkIGZyb20gbXVsdGlwbGUgc291cmNlcywgaW4gcGFydGljdWxhciB0aGUgZGF0YXNldCBpcyBmcm9tIFtNYWdyaW5pICgyMDA3KS5dKGh0dHBzOi8vcGRmcy5zZW1hbnRpY3NjaG9sYXIub3JnL2VhYjEvY2I4OWRkZTBjOTA5ODk4YjBhNDMyNzMzNzdjNWRmYTczZWJjLnBkZikKCgojIFJlcGxpY2F0aW9uIGZpbGVzCgotIFRoZSB0dXRvcmlhbCBpcyBzZWxmLWNvbnRhaW5lZC4gTm8gYWRpdGlvbmFsIGZpbGUgaXMgbmVlZGVkLgoKLSBJZiB5b3UgYXJlIGEgbWVtYmVyIG9mIHRoZSBbUXVhUkNTIGxhYl0oaHR0cHM6Ly9xdWFyY3MtbGFiLnJiaW5kLmlvLyksIHlvdSBjYW4gcnVuIHRoaXMgdHV0b3JpYWwgaW4gW1IgU3R1ZGlvIENsb3VkXShodHRwczovL3JzdHVkaW8uY2xvdWQvc3BhY2VzLzE1NTk3L3Byb2plY3QvOTg0MjY2ICkgCgoKIyBMaWJyYXJpZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNraW1yKQpsaWJyYXJ5KGthYmxlRXh0cmEpICAgICMgaHRtbCB0YWJsZXMgCmxpYnJhcnkocGRmQ2x1c3RlcikgICAgIyBkZW5zaXR5IGJhc2VkIGNsdXN0ZXJzCmxpYnJhcnkoaGRyY2RlKSAgICAgICAgIyBjb25kaXRpb25hbCBkZW5zaXR5IGVzdGltYXRpb24gCmxpYnJhcnkocGxvdGx5KQoKbGlicmFyeShpbnRvbykKbGlicmFyeShiYXJzdXJmKQpsaWJyYXJ5KGJpdmFyaWF0ZSkKCmxpYnJhcnkobnApCgpsaWJyYXJ5KGJhc2V0aGVtZSkKYmFzZXRoZW1lKCJtaW5pbWFsIikKCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShnZ3BvaW50ZGVuc2l0eSkKbGlicmFyeShpc29iYW5kKQoKI2xpYnJhcnkoTUFTUykKbGlicmFyeShLZXJuU21vb3RoKQoKCiMgQ2hhbmdlIHRoZSBwcmVzZW50YXRpb24gb2YgZGVjaW1hbCBudW1iZXJzIHRvIDQgYW5kIGF2b2lkIHNjaWVudGlmaWMgbm90YXRpb24Kb3B0aW9ucyhwcm9tcHQ9IlI+ICIsIGRpZ2l0cz0yLCBzY2lwZW49OTk5KQoKYGBgCgojIFR1dG9yaWFsIG9iamVjdGl2ZXMKCi0gU3R1ZHkgdGhlIGR5bmFtaWNzIG9mIHVuaXZhcmlhdGUgZGVuc2l0aWVzCgotIENvbXB1dGUgdGhlIGJhbmR3aWR0aCBvZiBhIGRlbnNpdHkKCi0gU3R1ZHkgbW9iaWxpdHkgcGxvdHMKCi0gU3R1ZHkgYmktdmFyaWF0ZSBkZW5zaXRpZXMKCi0gU3R1ZHkgZGVuc2l0eS1iYXNlZCBjbHVzdGVyaW5nIG1ldGhvZHMKCi0gU3R1ZHkgY29uZGl0aW9uYWwgYmktdmFyaWF0ZSBkZW5zaXRpZXMKCgoKIyBJbXBvcnQgZGF0YQoKCldlIHdpbGwgdXNlIHR3byBoeXBvdGhldGljYWwgY3Jvc3Mtc2VjdGlvbmFsIHNlcmllcy4KCi0gVGhlIGZpcnN0IChgeGApIHNlcmllcyB3YXMgcHJvZHVjZWQgYnkgZHJhd2luZyBhIHJhbmRvbSBzYW1wbGUgb2YgMTAwMCBvYnNlcnZhdGlvbnMgZnJvbSBhIHVuaXZhcmlhdGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gCi0gVGhlIHNlY29uZCAoYHlgKSBzZXJpZXMgd2FzIHByb2R1Y2VkIGJ5IG1lcmdpbmcgYW5kIHNvcnRpbmcgdHdvIHJhbmRvbSBzYW1wbGVzIG9mIDUwMCBvYnNlcnZhdGlvbnMuCgpUaGUgbWVhbiBhbmQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGVzZSB0d28gc2VyaWVzIHJlc3BlY3RpdmVseSBtYXRjaGVkIHRob3NlIG9mIHRoZSBsb2dhcml0aG0gb2YgcGVyIGNhcGl0YSBHcm9zcyBWYWx1ZSBBZGRlZCBvYnNlcnZlZCBmb3IgdGhlIEl0YWxpYW4gUHJvdmluY2VzIGluIDE5OTYgYW5kIGluIDIwMDIuIEZvciB0aGlzIHJlYXNvbiBhc3N1bWUgIHRoYXQgdGhlIGFuYWx5c2lzIGhhcyBiZWVuIHBlcmZvcm1lZCBvdmVyIGEgNi15ZWFyIHRpbWUgcGVyaW9kLiAKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPVRSVUV9CmRhdCA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2RzNzc3L3NhbXBsZS1kYXRhc2V0cy9tYXN0ZXIvc2ltRGF0YS5jc3YiKQpgYGAKCgojIFRyYW5zZm9ybSBkYXRhCgoKU2luY2UgdGhlIGRhdGEgaXMgaW4gbG9nIHRlcm1zLCBsZXQgdXMgcmVuYW1lIHRoZSB2YXJpYWJsZXMgYW5kIGFkZCBuZXcgdmFyaWFibGVzLgoKYGBge3J9CmRhdCA8LSBkYXQgJT4lIAogIHJlbmFtZShsb2dfeCA9IHgsIGxvZ195ID0geSkgJT4lIAogIG11dGF0ZSh4ID0gZXhwKGxvZ194KSwgeSA9IGV4cChsb2dfeSkpICU+JSAKICBzZWxlY3QoeCwgeSwgZXZlcnl0aGluZygpKSAKYGBgCgpgYGB7cn0KZGF0IDwtIGRhdCAlPiUgCiAgbXV0YXRlKAogICAgcmVsX3ggPSB4L21lYW4oeCksCiAgICByZWxfeSA9IHkvbWVhbih5KSwKICAgIHJlbF9sb2dfeCA9IGxvZ194L21lYW4obG9nX3gpLAogICAgcmVsX2xvZ195ID0gbG9nX3gvbWVhbihsb2dfeSksCiAgKQpkYXQKYGBgCgoKCiMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcwoKYGBge3J9CnNraW0oZGF0KSAlPiUgCiAga2FibGUoKSAlPiUgCiAga2FibGVfc3R5bGluZygpCmBgYAoKCgoKIyBVbml2YXJpYXRlIGR5bmFtaWNzCgojIyBTZWxlY3QgYmFuZHdpdGhzCgpzZWxlY3QgYmFuZHdpZHRoIGJhc2VkIG9uIGZ1bmN0aW9uIGBkcGlrYCBmcm9tIHRoZSBwYWNrYWdlIGBLZXJuU21vb3RoYAoKYGBge3J9CmhfcmVsX3ggPC0gZHBpayhkYXQkcmVsX3gpCmhfcmVsX3gKYGBgCgoKYGBge3J9CmhfcmVsX3kgPC0gZHBpayhkYXQkcmVsX3kpCmhfcmVsX3kKYGBgCgojIyBQbG90IGVhY2ggZGVuc2l0eQoKYGBge3J9CmRpc19yZWxfeCA8LSBia2RlKGRhdCRyZWxfeCwgYmFuZHdpZHRoID0gaF9yZWxfeCkKZGlzX3JlbF94IDwtIGFzLmRhdGEuZnJhbWUoZGlzX3JlbF94KQpnZ3Bsb3QoZGlzX3JlbF94LCBhZXMoeCwgeSkpICsgZ2VvbV9saW5lKCkgKyAKICB0aGVtZV9taW5pbWFsKCkgCmBgYAoKCmBgYHtyfQpkaXNfcmVsX3kgPC0gYmtkZShkYXQkcmVsX3ksIGJhbmR3aWR0aCA9IGhfcmVsX3kpCmRpc19yZWxfeSA8LSBhcy5kYXRhLmZyYW1lKGRpc19yZWxfeSkKZ2dwbG90KGRpc19yZWxfeSwgYWVzKHgsIHkpKSArIGdlb21fbGluZSgpICsgCiAgdGhlbWVfbWluaW1hbCgpIApgYGAKCgojIyBQbG90IGJvdGggZGVuc2l0aWVzCgojIyMgTWV0aG9kIDEKCktlZXAgdGhlIG9yaWduYWwgYmFuZHdpdGhzIG9mIHRoZSBwYWNrYWdlIGBLZXJuU21vb3RoYAoKYGBge3J9CmRvbWFpbl9pbml0aWFsIDwtIGRpc19yZWxfeCR4CmRvbWFpbl9maW5hbCAgIDwtIGRpc19yZWxfeSR4CgpkZW5zaXR5X2luaXRpYWwgPC0gZGlzX3JlbF94JHkKZGVuc2l0eV9maW5hbCAgIDwtIGRpc19yZWxfeSR5CgpkZW5zaXRpZXMgPC0gY2JpbmQoZG9tYWluX2luaXRpYWwsIGRlbnNpdHlfaW5pdGlhbCwgZG9tYWluX2ZpbmFsLCBkZW5zaXR5X2ZpbmFsKQoKZGVuc2l0aWVzIDwtICBhcy5kYXRhLmZyYW1lKGRlbnNpdGllcykKYGBgCgoKYGBge3J9CmRlbnNpdGllc19wbG90IDwtIGRlbnNpdGllcyAlPiUgCiAgZ2dwbG90KCkrCiAgdGhlbWVfbWluaW1hbCgpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2luaXRpYWwsIGRlbnNpdHlfaW5pdGlhbCkpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2ZpbmFsLGRlbnNpdHlfZmluYWwpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsKIGxhYnMoc3VidGl0bGUgPSAiIiwKICAgICAgIHggPSAiUmVsYXRpdmUgVmFyaWFibGUiLAogICAgICAgeSA9ICJEZW5zaXR5IikgKyAKICBnZW9tX2xhYmVsKAogICAgbGFiZWw9IlllYXIgMjAwMiIsIAogICAgeD0gMS41MjUsCiAgICB5PSAwLjksCiAgICBsYWJlbC5zaXplID0gMC4zNSwKICAgIGNvbG9yID0gImJsYWNrIiwKICApICsKICAgZ2VvbV9sYWJlbCgKICAgIGxhYmVsPSJZZWFyIDE5OTYiLCAKICAgIHg9IDEuNzUsCiAgICB5PSAwLjIsCiAgICBsYWJlbC5zaXplID0gMC4zNSwKICAgIGNvbG9yID0gImJsYWNrIiwKICApCmRlbnNpdGllc19wbG90CmBgYAoKTm90ZSB0aGF0IHlvdSBoYXZlIGFkanVzdCB0aGUgbGFiZWxzIG1hbnVhbGx5CgotIEludGVyYWN0aXZlIHBsb3RseSB2ZXJzaW9uCgpgYGB7cn0KZGVuc2l0aWVzX3Bsb3QyIDwtIGRlbnNpdGllcyAlPiUgCiAgZ2dwbG90KCkrCiAgdGhlbWVfbWluaW1hbCgpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2luaXRpYWwsIGRlbnNpdHlfaW5pdGlhbCkpKwogIGdlb21fbGluZShhZXMoZG9tYWluX2ZpbmFsLGRlbnNpdHlfZmluYWwpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsKIGxhYnMoc3VidGl0bGUgPSAiIiwKICAgICAgIHggPSAiUmVsYXRpdmUgVmFyaWFibGUiLAogICAgICAgeSA9ICJEZW5zaXR5IikgCgpnZ3Bsb3RseShkZW5zaXRpZXNfcGxvdDIpCmBgYAoKTWFudWFsIGxhYmVscyBhcmUgbm90IHlldCBpbXBsZW1lbnRlZCBpbiB0aGUgYGdncGxvdGx5YCBmdW5jdGlvbgoKCiMjIyBNZXRob2QgMgoKdXNpbmcgdGhlIGJhbmR3aWR0aCBkZWZhdWx0IG9mIGdncGxvdCAKCgpgYGB7cn0KcmVsX3ggPC0gZGF0ICU+JSAKICBzZWxlY3QocmVsX3gpICU+JSAKICByZW5hbWUocmVsX3ZhciA9IHJlbF94KSAlPiUgCiAgbXV0YXRlKHllYXIgPSAxOTk2KQpgYGAKCmBgYHtyfQpyZWxfeSA8LSBkYXQgJT4lIAogIHNlbGVjdChyZWxfeSkgJT4lIAogIHJlbmFtZShyZWxfdmFyID0gcmVsX3kpICU+JSAKICBtdXRhdGUoeWVhciA9IDIwMDIpCmBgYAoKYGBge3J9CnJlbF94eSA8LSBiaW5kX3Jvd3MocmVsX3gsIHJlbF95KQpgYGAKIApgYGB7cn0KcmVsX3h5IDwtIHJlbF94eSAlPiUgCiAgbXV0YXRlKHllYXIgPSBhcy5mYWN0b3IoeWVhcikpCmhlYWQocmVsX3h5KQpgYGAKIAogCgpgYGB7cn0KZGlzX3JlbF94eSA8LSBnZ3Bsb3QocmVsX3h5LCBhZXMoeD1yZWxfdmFyLCBjb2xvcj15ZWFyKSkgKwogIGdlb21fZGVuc2l0eSgpICsgCiAgdGhlbWVfbWluaW1hbCgpIApkaXNfcmVsX3h5CmBgYAoKClVzaW5nIHBsb3RseQoKYGBge3J9CmdncGxvdGx5KGRpc19yZWxfeHkpCmBgYAoKCgojIEJpdmFyaWF0ZSBkZW5zaXR5CgojIyBNb2JpbGl0eSBzY2F0dGVycGxvdAoKYGBge3J9CmRhdCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVsX3gsIHkgPSByZWxfeSkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoc3VidGl0bGUgPSAiUmVsYXRpdmUgeSIsCiAgICAgICB4ID0gIlJlbGF0aXZlIHgiLAogICAgICAgeSA9ICIiKSArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoZmFtaWx5PSJQYWxhdGlubyIpKSAKYGBgCgoKRml0IGEgbm9uLWxpbmVhciBmdW5jdGlvbgoKYGBge3J9CmRhdCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVsX3gsIHkgPSByZWxfeSkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyAKICBnZW9tX3Ntb290aCgpICsgCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZT0iZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyhzdWJ0aXRsZSA9ICJSZWxhdGl2ZSB5IiwKICAgICAgIHggPSAiUmVsYXRpdmUgeCIsCiAgICAgICB5ID0gIiIpICsKICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlBhbGF0aW5vIikpIApgYGAKCk5vdCB0aGF0IHRoZSBub25saW5lYXIgZml0IGNyb3NzZXMgdGhlIDQ1LWRlZ3JlZSBsaW5lIHR3byB0aW1lcyBmcm9tIGFib3ZlLgoKIyMgVXNpbmcgZ2VvbV9wb2ludGRlbnNpdHkgCgpgYGB7cn0KZGF0ICU+JSAKZ2dwbG90KGFlcyh4ID0gcmVsX3gsIHkgPSByZWxfeSkpICsKICBnZW9tX3BvaW50ZGVuc2l0eSgpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoc3VidGl0bGUgPSAiUmVsYXRpdmUgeSIpICsgCiAgeGxhYigiUmVsYXRpdmUgeCIpICsKICB5bGFiKCIiKQpgYGAKCgojIyAgVXNpbmcgdGhlIEtlcm5TbW9vdGggcGFja2FnZQoKYGBge3J9Cnh5IDwtIGNiaW5kKGRhdCRyZWxfeCwgZGF0JHJlbF95KQp4eV9kaXMgPC0gYmtkZTJEKHh5LCBiYW5kd2lkdGggPSBjKGhfcmVsX3gsIGhfcmVsX3kpKSAKYGBgCgpgYGB7cn0KY29udG91cih4eV9kaXMkeDEsIHh5X2RpcyR4MiwgeHlfZGlzJGZoYXQpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCkludGVyYWN0aXZlCgpgYGB7cn0KcGxvdF9seSh4PXh5X2RpcyR4MSwgeT14eV9kaXMkeDIsIHo9eHlfZGlzJGZoYXQsIHR5cGUgPSAiY29udG91ciIsIGNvbnRvdXJzID0gbGlzdChzaG93bGFiZWxzID0gVFJVRSkpICAlPiUKICBjb2xvcmJhcih0aXRsZSA9ICJEZW5zaXR5IikKYGBgCgoKCmBgYHtyfQpwZXJzcCh4eV9kaXMkZmhhdCkKYGBgCgpJbnRlcmFjdGl2ZSB2ZXJzaW9uCgpgYGB7cn0KcGxvdF9seSh4PXh5X2RpcyR4MSwgeT14eV9kaXMkeDIsIHo9eHlfZGlzJGZoYXQpICU+JSBhZGRfc3VyZmFjZSgpCmBgYAoKCiMjIFVzaW5nIHRoZSBCaXZhcmlhdGUgcGFja2FnZQoKYGBge3J9CmJpdmFyaWF0ZSA8LSBrYnZwZGYoZGF0JHJlbF94LCBkYXQkcmVsX3ksIGhfcmVsX3gsIGhfcmVsX3kpIApgYGAKCgpgYGB7cn0KcGxvdChiaXZhcmlhdGUsCiAgICAgIHhsYWI9IlJlbGF0aXZlIHgiLCAKICAgICAgeWxhYj0iUmVsYXRpdmUgeSIpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCgpgYGB7cn0KcGxvdChiaXZhcmlhdGUsCiAgICAgIFRSVUUsCiAgICAgIHhsYWI9IlJlbGF0aXZlIHgiLCAKICAgICAgeWxhYj0iUmVsYXRpdmUgeSIpCmBgYAoKCiMjIFVzaW5nIGdncGxvdCAoc3RhdF9kZW5zaXR5XzJkKCkpCgpgYGB7cn0KZGF0ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZWxfeCwgeSA9IHJlbF95KSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAibGlnaHRncmF5IikgKyAKICBnZW9tX3Ntb290aCgpICsgCiAgI2dlb21fc21vb3RoKG1ldGhvZD1sbSwgc2U9RkFMU0UpICsgCiAgc3RhdF9kZW5zaXR5XzJkKCkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoc3VidGl0bGUgPSAiUmVsYXRpdmUgeSIsCiAgICAgICB4ID0gIlJlbGF0aXZlIHgiLAogICAgICAgeSA9ICIiKSArCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoZmFtaWx5PSJQYWxhdGlubyIpKSAKYGBgCgoKCmBgYHtyfQpkYXQgJT4lIAogIGdncGxvdChhZXMoeCA9IHJlbF94LCB5ID0gcmVsX3kpKSArCiAgICAgICAgc3RhdF9kZW5zaXR5XzJkKGFlcyhmaWxsID0gc3RhdChubGV2ZWwpKSwgZ2VvbSA9ICJwb2x5Z29uIikgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsKICAgICAgICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKSkgKwogICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiKSArIAogICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiKSArIAogIHRoZW1lX21pbmltYWwoKSArCiAgICAgICAgbGFicyh4ID0gIlJlbGF0aXZlIFgiLAogICAgICAgICAgICAgeSA9ICJSZWxhdGl2ZSBZIikgKwogICAgICAgIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCwgZmFtaWx5PSJQYWxhdGlubyIpKQpgYGAKCgojIERlbnNpdHktYmFzZWQgY2x1c3RlcnMKCgpgYGB7cn0KeHlfY2x1c3RlciA8LSBwZGZDbHVzdGVyKGRhdFssIDU6Nl0pIApzdW1tYXJ5KHh5X2NsdXN0ZXIpCmBgYAoKIyMgQ29yZSBjbHVzdGVycwoKYGBge3J9CnBsb3QoeHlfY2x1c3RlciwgCiAgICAgIHN0YWdlID0gMCwKICAgICAgd2hpY2ggPSAzLAogICAgICBmcmFtZSA9IEYpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCgojIyBGdWxsIGNsdXN0ZXJpbmcKCmBgYHtyfQpwbG90KHh5X2NsdXN0ZXIsIAogICAgICB3aGljaCA9IDMsCiAgICAgIGZyYW1lID0gRikKYWJsaW5lKGE9MCwgYj0xKQphYmxpbmUoaD0xLCB2PTEpCmBgYAoKIyMgQ2x1c3RlciB0cmVlCgpgYGB7cn0KcGxvdCh4eV9jbHVzdGVyLCB3aGljaCA9IDIpCmBgYAoKIyMgTW9kZSBmdW5jdGlvbgoKYGBge3J9CnBsb3QoeHlfY2x1c3Rlciwgd2hpY2ggPSAxKQpgYGAKCgojIENvbmRpdGlvbmFsIGRlbnNpdHkgYW5hbHlzaXMKCiMjIFVzaW5nIHRoZSBgaGRyY2RlYCBwYWNrYWdlCgpgYGB7cn0KeHlfY2RlIDwtIGNkZShkYXQkcmVsX3gsIGRhdCRyZWxfeSkKYGBgCgpJbmNyZWFzZSB0aGUgbnVtYmVyIG9mIGludGVydmFscyB0byA2MAoKYGBge3J9Cnh5X2NkZTIgPC0gY2RlKGRhdCRyZWxfeCwgZGF0JHJlbF95LCBueG1hcmdpbiA9IDYwKQpgYGAKCgpgYGB7cn0KcGxvdCh4eV9jZGUpCmBgYAoKCmBgYHtyfQpwbG90KHh5X2NkZTIpCmBgYAoKCkhpZ2ggZGVuc2l0eSByZWdpb25zCgoKYGBge3J9CnBsb3QoeHlfY2RlLCBwbG90LmZuPSJoZHIiKQphYmxpbmUoYT0wLCBiPTEpCmFibGluZShoPTEsIHY9MSkKYGBgCgoKCmBgYHtyfQpwbG90KHh5X2NkZTIsIHBsb3QuZm49ImhkciIpCmFibGluZShhPTAsIGI9MSkKYWJsaW5lKGg9MSwgdj0xKQpgYGAKCgojIyBVc2luZyB0aGUgYG5wYCBwYWNrYWdlCgpDb21wdXRlIGFkYXB0aXZlIGJhbmR3aXRoIGJhc2VkIG9uIGNyb3NzLXZhbGlkYXRpb24KCmBgYHtyfQpid19jX2FkX2N2IDwtIG5wY2RlbnNidygKICBmb3JtdWxhID0gZGF0JHJlbF95IH4gZGF0JHJlbF94LCAKICBid3R5cGUgPSAiYWRhcHRpdmVfbm4iKSAKYGBgCgpgYGB7cn0Kc3VtbWFyeShid19jX2FkX2N2KQpgYGAKCkNvbXB1dGUgY29uZGl0aW9uYWwgZGVuc2l0eSBvYmplY3QKCmBgYHtyfQpjZGlzdF9id0NWIDwtIG5wY2RlbnMoYndzID0gYndfY19hZF9jdikKc3VtbWFyeShjZGlzdF9id0NWKQpgYGAKCgpgYGB7cn0KIyMgQmV0dGVyIGNvcHkgYW5kIHBhc3RlIGl0IGluIHRoZSBjb25zb2xlIGJlY2F1c2UgaXQgaXMgYW4gYW5pbWF0aW9uCiMgcGxvdChid19jX2FkX2N2KQpgYGAKCgpgYGB7cn0KcGxvdChjZGlzdF9id0NWLCAKICAgICAgeHRyaW0gPSAtMC4yLCAKICAgICAgdmlldyA9ICJmaXhlZCIsCiAgICAgIG1haW4gPSAiIiwKICAgICAgdGhldGE9MzUwLAogICAgICBwaGk9MjApCmBgYAoKCgoKIyBSZWZlcmVuY2VzCgotIFtNYWdyaW5pLCBTLiAoMjAwNykuIEFuYWx5c2luZyBjb252ZXJnZW5jZSB0aHJvdWdoIHRoZSBkaXN0cmlidXRpb24gZHluYW1pY3MgYXBwcm9hY2g6IHdoeSBhbmQgaG93Py4gVW5pdmVyc2l0eSBDYSdGb3NjYXJpIG9mIFZlbmljZSwgRGVwdC4gb2YgRWNvbm9taWNzIFJlc2VhcmNoIFBhcGVyIFNlcmllcyBObywgMTMuIF0oaHR0cHM6Ly9wZGZzLnNlbWFudGljc2Nob2xhci5vcmcvZWFiMS9jYjg5ZGRlMGM5MDk4OThiMGE0MzI3MzM3N2M1ZGZhNzNlYmMucGRmKQoKLSBNZW5kZXogQy4gKDIwMjApLiBDbGFzc2ljYWwgc2lnbWEgYW5kIGJldGEgY29udmVyZ2VuY2UgYW5hbHlzaXMgaW4gUjogVXNpbmcgdGhlIFJFQVQgMi4xIFBhY2thZ2UuIFIgU3R1ZGlvL1JQdWJzLiBBdmFpbGFibGUgYXQgaHR0cHM6Ly9ycHVicy5jb20vcXVhcmNzLWxhYi9jbGFzc2ljYWwtY29udmVyZ2VuY2UtcmVhdDIxCgotIE1lbmRleiBDLiAoMjAyMCkuIFVuaXZhcmlhdGUgZGlzdHJpYnV0aW9uIGR5bmFtaWNzIGluIFI6IFVzaW5nIHRoZSBnZ3JpZGdlcyBwYWNrYWdlLiBSIFN0dWRpby9SUHVicy4gQXZhaWxhYmxlIGF0IGh0dHBzOi8vcnB1YnMuY29tL3F1YXJjcy1sYWIvdW5pdmFyaWF0ZS1kaXN0cmlidXRpb24tZHluYW1pY3MKCi0gW01lbmRleiwgQy4gKDIwMjApIFJlZ2lvbmFsIGVmZmljaWVuY3kgY29udmVyZ2VuY2UgYW5kIGVmZmljaWVuY3kgY2x1c3RlcnMuIEFzaWEtUGFjaWZpYyBKb3VybmFsIG9mIFJlZ2lvbmFsIFNjaWVuY2UsIDEtMjEuXShodHRwOi8vZW0ucmRjdS5iZS93Zi9jbGljaz91cG49bE1aeTFsZXJuU0o3YXBjNURnWU04WVRoU0k1YktXMDZ6blczQmFuTy0yRlJzLTNEX3U2YTJQcUYzdnNsTk50U1JiaHhKUGNKS3hPNUVLek9zZjAtMkZXaWl6TjU3ZDRjc0Y3UmVNdXI1ZTQwVGJYNDhEYlNlOWtFTUN3RnB2dkZwTGN1YVZCLTJCcGRDM2ZMQ2JzUDBpS2NzeElzMWR2MXlyUHNHRENOaDViaGd2STgtMkYtMkJ4d3o3dXBqRGd5Y3FQYmhPYk5xa1Q0MXVxWTNkUGlYcjV2Qm9ZMXh3VDg4TUEzLTJGYmRKZ3dvQmwxR256bGkxM21rbWxKajBrcVRzLTJCbGxWZkNUQjM1Nm1MampLUjJWQlpDVWdLYnlWcFlndTF2WGp3VHdkT3l6ZDVGVGJVOGVhUnNXeU9SamU3V0NQcEdFS0NVQXZiZVRDU1BhMnJmZGttbmtRSXJzbVlCU3FmU1o4YWFXekh3SWtNVTNoeGJJVTZuSEdRKSAKCi0gW01lbmRleiwgQy4gKDIwMTkpLiBMYWNrIG9mIEdsb2JhbCBDb252ZXJnZW5jZSBhbmQgdGhlIEZvcm1hdGlvbiBvZiBNdWx0aXBsZSBXZWxmYXJlIENsdWJzIGFjcm9zcyBDb3VudHJpZXM6IEFuIFVuc3VwZXJ2aXNlZCBNYWNoaW5lIExlYXJuaW5nIEFwcHJvYWNoLiBFY29ub21pZXMsIDcoMyksIDc0Ll0oaHR0cHM6Ly93d3cubWRwaS5jb20vMjIyNy03MDk5LzcvMy83NC9wZGYpCgotIE1lbmRleiwgQy4gKDIwMTkpLiBPdmVyYWxsIGVmZmljaWVuY3ksIHB1cmUgdGVjaG5pY2FsIGVmZmljaWVuY3ksIGFuZCBzY2FsZSBlZmZpY2llbmN5IGFjcm9zcyBwcm92aW5jZXMgaW4gSW5kb25lc2lhIDE5OTAgYW5kIDIwMTAuIFIgU3R1ZGlvL1JQdWJzLiBBdmFpbGFibGUgYXQgaHR0cHM6Ly9ycHVicy5jb20vcXVhcmNzLWxhYi9lZmZpY2llbmN5LWNsdXN0ZXJzLWluZG9uZXNpYS0xOTkwLTIwMTAKCi0gW01lbmRlei1HdWVycmEsIEMuICgyMDE4KS4gT24gdGhlIGRpc3RyaWJ1dGlvbiBkeW5hbWljcyBvZiBodW1hbiBkZXZlbG9wbWVudDogRXZpZGVuY2UgZnJvbSB0aGUgbWV0cm9wb2xpdGFuIHJlZ2lvbnMgb2YgQm9saXZpYScnLiBFY29ub21pY3MgQnVsbGV0aW4sIDM4KDQpLCAyNDY3LTI0NzUuXShodHRwOi8vd3d3LmFjY2Vzc2Vjb24uY29tL1B1YnMvRUIvMjAxOC9Wb2x1bWUzOC9FQi0xOC1WMzgtSTQtUDIyMy5wZGYpCgoKRU5ECg==