# Installing the 'arules' and 'arulesViz' packages for association rule mining and visualization
install.packages("arules")
Error in install.packages : Updating loaded packages
install.packages("arulesViz")
Error in install.packages : Updating loaded packages
library(arules)
library(arulesViz)

# Importing dataset 'book' 
book <- read.csv('book.csv')

# Displaying a summary of the dataset to understand its structure
summary(book)
    ChildBks        YouthBks         CookBks         DoItYBks         RefBks           ArtBks         GeogBks         ItalCook     
 Min.   :0.000   Min.   :0.0000   Min.   :0.000   Min.   :0.000   Min.   :0.0000   Min.   :0.000   Min.   :0.000   Min.   :0.0000  
 1st Qu.:0.000   1st Qu.:0.0000   1st Qu.:0.000   1st Qu.:0.000   1st Qu.:0.0000   1st Qu.:0.000   1st Qu.:0.000   1st Qu.:0.0000  
 Median :0.000   Median :0.0000   Median :0.000   Median :0.000   Median :0.0000   Median :0.000   Median :0.000   Median :0.0000  
 Mean   :0.423   Mean   :0.2475   Mean   :0.431   Mean   :0.282   Mean   :0.2145   Mean   :0.241   Mean   :0.276   Mean   :0.1135  
 3rd Qu.:1.000   3rd Qu.:0.0000   3rd Qu.:1.000   3rd Qu.:1.000   3rd Qu.:0.0000   3rd Qu.:0.000   3rd Qu.:1.000   3rd Qu.:0.0000  
 Max.   :1.000   Max.   :1.0000   Max.   :1.000   Max.   :1.000   Max.   :1.0000   Max.   :1.000   Max.   :1.000   Max.   :1.0000  
   ItalAtlas        ItalArt          Florence     
 Min.   :0.000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.000   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :0.000   Median :0.0000   Median :0.0000  
 Mean   :0.037   Mean   :0.0485   Mean   :0.1085  
 3rd Qu.:0.000   3rd Qu.:0.0000   3rd Qu.:0.0000  
 Max.   :1.000   Max.   :1.0000   Max.   :1.0000  
# Converting all binary variables in the dataset to categorical variables
book1 <- as.data.frame(lapply(book, as.factor))

# Checking the structure of the modified dataset to ensure conversion to categorical variables
str(book1)
'data.frame':   2000 obs. of  11 variables:
 $ ChildBks : Factor w/ 2 levels "0","1": 1 2 1 2 1 2 1 1 2 2 ...
 $ YouthBks : Factor w/ 2 levels "0","1": 2 1 1 2 1 1 2 2 1 2 ...
 $ CookBks  : Factor w/ 2 levels "0","1": 1 1 1 2 2 1 1 1 1 2 ...
 $ DoItYBks : Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 2 1 ...
 $ RefBks   : Factor w/ 2 levels "0","1": 1 1 1 2 1 1 1 2 1 1 ...
 $ ArtBks   : Factor w/ 2 levels "0","1": 1 1 1 1 1 2 1 1 1 1 ...
 $ GeogBks  : Factor w/ 2 levels "0","1": 2 1 1 2 2 1 1 1 1 2 ...
 $ ItalCook : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ ItalAtlas: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ ItalArt  : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ Florence : Factor w/ 2 levels "0","1": 1 1 1 1 1 2 1 1 1 1 ...

Transforming the data frame into a ‘transactions’ class for association rule mining


book2 <- as(book1, "transactions")

Plotting item frequency for the top 22 items in the transaction dataset


itemFrequencyPlot(book2, topN=22)

Generating association rules with specific parameters


rule1 <- apriori(book2, parameter = list(supp = 0.01, conf = 0.4, minlen = 5, maxlen = 10))
Apriori

Parameter specification:

Algorithmic control:

Absolute minimum support count: 20 

set item appearances ...[0 item(s)] done [0.00s].
set transactions ...[22 item(s), 2000 transaction(s)] done [0.00s].
sorting and recoding items ... [22 item(s)] done [0.00s].
creating transaction tree ... done [0.00s].
checking subsets of size 1 2 3 4 5 6 7 8 9 10
Warning: Mining stopped (maxlen reached). Only patterns up to a length of 10 returned!
 done [0.01s].
writing ... [127070 rule(s)] done [0.04s].
creating S4 object  ... done [0.03s].
rule1
set of 127070 rules 

Inspecting the top 15 rules sorted by a default criterion


inspect(head(sort(rule1), n=15))
NA
head(quality(rule1))

Sorting and inspecting rules by ‘lift’


rule1_lift <- sort(rule1, by = "lift", descending = TRUE)
inspect(head(rule1_lift))

Sorting and inspecting rules by ‘confidence’

rule1_confidence <- sort(rule1, by = "confidence", descending = TRUE)
inspect(head(rule1_confidence))

Visualizing the generated rules using different plots

# Visualization using a scatter plot. Adjust 'measure' arguments as needed.
plot(rule1, method = "scatterplot", measure = c("support", "confidence"), shading = "lift")
To reduce overplotting, jitter is added! Use jitter = 0 to prevent jitter.
install.packages("arulesViz")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
Warning in install.packages :
  package ‘arulesViz’ is in use and will not be installed
install.packages("arules")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
Warning in install.packages :
  package ‘arules’ is in use and will not be installed

plot(rule1, method = "two-key plot")
To reduce overplotting, jitter is added! Use jitter = 0 to prevent jitter.

##############################################################################

Generating and inspecting different sets of rules with varied parameters, and visualizing them using different methods


rule2 <- apriori(book1, parameter = list(supp = 0.05, confidence = 0.8, minlen = 6, maxlen = 20))
Apriori

Parameter specification:

Algorithmic control:

Absolute minimum support count: 100 

set item appearances ...[0 item(s)] done [0.00s].
set transactions ...[22 item(s), 2000 transaction(s)] done [0.00s].
sorting and recoding items ... [20 item(s)] done [0.00s].
creating transaction tree ... done [0.00s].
checking subsets of size 1 2 3 4 5 6 7 8 9 10 11 done [0.01s].
writing ... [15855 rule(s)] done [0.01s].
creating S4 object  ... done [0.00s].
inspect(head(rule2, 10))
rule2
set of 15855 rules 
par(mar = c(5, 8, 4, 2) + 0.1)
plot(rule2, method = "grouped", cex = 0.1)
Warning: Unknown control parameters: cex
Available control parameters (with default values):
k    =  20
aggr.fun     =  function (x, ...)  UseMethod("mean")
rhs_max  =  10
lhs_label_items  =  2
col  =  c("#EE0000FF", "#EEEEEEFF")
groups   =  NULL
engine   =  ggplot2
verbose  =  FALSE



rule3 <- apriori(book1, parameter = list(supp = 0.04, confidence = 0.6, minlen = 7, maxlen = 10))
Apriori

Parameter specification:

Algorithmic control:

Absolute minimum support count: 80 

set item appearances ...[0 item(s)] done [0.00s].
set transactions ...[22 item(s), 2000 transaction(s)] done [0.00s].
sorting and recoding items ... [21 item(s)] done [0.00s].
creating transaction tree ... done [0.00s].
checking subsets of size 1 2 3 4 5 6 7 8 9 10
Warning: Mining stopped (maxlen reached). Only patterns up to a length of 10 returned!
 done [0.01s].
writing ... [14572 rule(s)] done [0.01s].
creating S4 object  ... done [0.00s].
inspect(head(rule3, 10))
rule3
set of 14572 rules 
plot(rule3, method = "graph")
Warning: Too many rules supplied. Only plotting the best 100 using ‘lift’ (change control parameter max if needed).

rule4 <- apriori(book1, parameter = list(supp = 0.06, confidence = 0.7, minlen = 8, maxlen = 15))
Apriori

Parameter specification:

Algorithmic control:

Absolute minimum support count: 120 

set item appearances ...[0 item(s)] done [0.00s].
set transactions ...[22 item(s), 2000 transaction(s)] done [0.00s].
sorting and recoding items ... [20 item(s)] done [0.00s].
creating transaction tree ... done [0.00s].
checking subsets of size 1 2 3 4 5 6 7 8 9 10 11 done [0.01s].
writing ... [4557 rule(s)] done [0.00s].
creating S4 object  ... done [0.00s].
inspect(head(rule4, 10))
     lhs               rhs           support confidence coverage     lift count
[1]  {CookBks=0,                                                               
      DoItYBks=1,                                                              
      RefBks=0,                                                                
      ArtBks=0,                                                                
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=0}   => {ItalAtlas=0}  0.0605  1.0000000   0.0605 1.038422   121
[2]  {CookBks=0,                                                               
      DoItYBks=1,                                                              
      RefBks=0,                                                                
      ArtBks=0,                                                                
      ItalCook=0,                                                              
      ItalAtlas=0,                                                             
      Florence=0}   => {ItalArt=0}    0.0605  1.0000000   0.0605 1.050972   121
[3]  {CookBks=0,                                                               
      DoItYBks=1,                                                              
      RefBks=0,                                                                
      ArtBks=0,                                                                
      ItalCook=0,                                                              
      ItalAtlas=0,                                                             
      ItalArt=0}    => {Florence=0}   0.0605  0.9680000   0.0625 1.085810   121
[4]  {CookBks=0,                                                               
      DoItYBks=1,                                                              
      RefBks=0,                                                                
      ArtBks=0,                                                                
      ItalAtlas=0,                                                             
      ItalArt=0,                                                               
      Florence=0}   => {ItalCook=0}   0.0605  1.0000000   0.0605 1.128032   121
[5]  {CookBks=0,                                                               
      DoItYBks=1,                                                              
      ArtBks=0,                                                                
      ItalCook=0,                                                              
      ItalAtlas=0,                                                             
      ItalArt=0,                                                               
      Florence=0}   => {RefBks=0}     0.0605  0.8897059   0.0680 1.132662   121
[6]  {CookBks=0,                                                               
      DoItYBks=1,                                                              
      RefBks=0,                                                                
      ItalCook=0,                                                              
      ItalAtlas=0,                                                             
      ItalArt=0,                                                               
      Florence=0}   => {ArtBks=0}     0.0605  0.8897059   0.0680 1.172208   121
[7]  {YouthBks=0,                                                              
      DoItYBks=1,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=0}   => {ItalAtlas=0}  0.0655  0.9924242   0.0660 1.030555   131
[8]  {YouthBks=0,                                                              
      DoItYBks=1,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalAtlas=0,                                                             
      Florence=0}   => {ItalArt=0}    0.0655  1.0000000   0.0655 1.050972   131
[9]  {YouthBks=0,                                                              
      DoItYBks=1,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalAtlas=0,                                                             
      ItalArt=0}    => {Florence=0}   0.0655  0.9776119   0.0670 1.096592   131
[10] {YouthBks=0,                                                              
      DoItYBks=1,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalAtlas=0,                                                             
      ItalArt=0,                                                               
      Florence=0}   => {ItalCook=0}   0.0655  0.9703704   0.0675 1.094608   131
rule4
set of 4557 rules 
plot(rule4, method = "paracoord")
rule5 <- apriori(book1, parameter = list(supp = 0.03, confidence = 0.85, minlen = 9, maxlen = 20))
Apriori

Parameter specification:

Algorithmic control:

Absolute minimum support count: 60 

set item appearances ...[0 item(s)] done [0.00s].
set transactions ...[22 item(s), 2000 transaction(s)] done [0.00s].
sorting and recoding items ... [22 item(s)] done [0.00s].
creating transaction tree ... done [0.00s].
checking subsets of size 1 2 3 4 5 6 7 8 9 10 11 done [0.01s].
writing ... [2340 rule(s)] done [0.00s].
creating S4 object  ... done [0.00s].
inspect(head(rule5, 10))
     lhs               rhs           support confidence coverage     lift count
[1]  {ChildBks=0,                                                              
      YouthBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      Florence=1}   => {ItalArt=0}    0.0325  1.0000000   0.0325 1.050972    65
[2]  {ChildBks=0,                                                              
      YouthBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalArt=0,                                                               
      Florence=1}   => {ItalCook=0}   0.0325  1.0000000   0.0325 1.128032    65
[3]  {ChildBks=0,                                                              
      YouthBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=1}   => {ArtBks=0}     0.0325  0.8904110   0.0365 1.173137    65
[4]  {ChildBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=1}   => {YouthBks=0}   0.0325  0.9701493   0.0335 1.289235    65
[5]  {ChildBks=0,                                                              
      YouthBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=1}   => {GeogBks=0}    0.0325  0.9285714   0.0350 1.282557    65
[6]  {ChildBks=0,                                                              
      YouthBks=0,                                                              
      CookBks=0,                                                               
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=1}   => {DoItYBks=0}   0.0325  0.9848485   0.0330 1.371655    65
[7]  {YouthBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=1}   => {ChildBks=0}   0.0325  0.8552632   0.0380 1.482259    65
[8]  {ChildBks=0,                                                              
      YouthBks=0,                                                              
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      ItalArt=0,                                                               
      Florence=1}   => {CookBks=0}    0.0325  0.9027778   0.0360 1.586604    65
[9]  {ChildBks=0,                                                              
      YouthBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalCook=0,                                                              
      Florence=1}   => {ItalAtlas=0}  0.0320  0.9846154   0.0325 1.022446    64
[10] {ChildBks=0,                                                              
      YouthBks=0,                                                              
      CookBks=0,                                                               
      DoItYBks=0,                                                              
      ArtBks=0,                                                                
      GeogBks=0,                                                               
      ItalAtlas=0,                                                             
      Florence=1}   => {ItalCook=0}   0.0320  1.0000000   0.0320 1.128032    64
rule5
set of 2340 rules 
plot(rule5, method = "two-key plot")
To reduce overplotting, jitter is added! Use jitter = 0 to prevent jitter.

Identifying and plotting the top 5 rules based on confidence


top5rules <- head(rule5, n=5, by = "confidence")
plot(top5rules, engine = "htmlwidget", method = "graph")

Conclusion:

The top 5 rules based on confidence highlight the most predictable purchasing patterns within the dataset. These patterns can guide decision-making in marketing and sales strategies, as they reveal which items are likely to be purchased together. For instance, if “ItalCook” (Italian Cookbooks) appears often as an antecedent, it might be beneficial to place related items that frequently follow “ItalCook” in proximity in a store or to bundle them in promotions. The graph visually summarizes these associations, making it easier to identify and understand the strongest relationships in the dataset.

LS0tDQp0aXRsZTogIkFzc29jaWF0aW9uIFJ1bGUiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCiMgSW5zdGFsbGluZyB0aGUgJ2FydWxlcycgYW5kICdhcnVsZXNWaXonIHBhY2thZ2VzIGZvciBhc3NvY2lhdGlvbiBydWxlIG1pbmluZyBhbmQgdmlzdWFsaXphdGlvbg0KaW5zdGFsbC5wYWNrYWdlcygiYXJ1bGVzIikNCmluc3RhbGwucGFja2FnZXMoImFydWxlc1ZpeiIpDQpsaWJyYXJ5KGFydWxlcykNCmxpYnJhcnkoYXJ1bGVzVml6KQ0KDQpgYGANCg0KYGBge3J9DQoNCiMgSW1wb3J0aW5nIGRhdGFzZXQgJ2Jvb2snIA0KYm9vayA8LSByZWFkLmNzdignYm9vay5jc3YnKQ0KDQojIERpc3BsYXlpbmcgYSBzdW1tYXJ5IG9mIHRoZSBkYXRhc2V0IHRvIHVuZGVyc3RhbmQgaXRzIHN0cnVjdHVyZQ0Kc3VtbWFyeShib29rKQ0KDQpgYGANCg0KYGBge3J9DQojIENvbnZlcnRpbmcgYWxsIGJpbmFyeSB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQgdG8gY2F0ZWdvcmljYWwgdmFyaWFibGVzDQpib29rMSA8LSBhcy5kYXRhLmZyYW1lKGxhcHBseShib29rLCBhcy5mYWN0b3IpKQ0KDQojIENoZWNraW5nIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIG1vZGlmaWVkIGRhdGFzZXQgdG8gZW5zdXJlIGNvbnZlcnNpb24gdG8gY2F0ZWdvcmljYWwgdmFyaWFibGVzDQpzdHIoYm9vazEpDQpgYGANCg0KVHJhbnNmb3JtaW5nIHRoZSBkYXRhIGZyYW1lIGludG8gYSAndHJhbnNhY3Rpb25zJyBjbGFzcyBmb3IgYXNzb2NpYXRpb24gcnVsZSBtaW5pbmcNCg0KYGBge3J9DQoNCmJvb2syIDwtIGFzKGJvb2sxLCAidHJhbnNhY3Rpb25zIikNCmBgYA0KDQpQbG90dGluZyBpdGVtIGZyZXF1ZW5jeSBmb3IgdGhlIHRvcCAyMiBpdGVtcyBpbiB0aGUgdHJhbnNhY3Rpb24gZGF0YXNldA0KDQpgYGB7cn0NCg0KaXRlbUZyZXF1ZW5jeVBsb3QoYm9vazIsIHRvcE49MjIpDQpgYGANCg0KR2VuZXJhdGluZyBhc3NvY2lhdGlvbiBydWxlcyB3aXRoIHNwZWNpZmljIHBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCnJ1bGUxIDwtIGFwcmlvcmkoYm9vazIsIHBhcmFtZXRlciA9IGxpc3Qoc3VwcCA9IDAuMDEsIGNvbmYgPSAwLjQsIG1pbmxlbiA9IDUsIG1heGxlbiA9IDEwKSkNCmBgYA0KDQpgYGB7cn0NCnJ1bGUxDQpgYGANCg0KSW5zcGVjdGluZyB0aGUgdG9wIDE1IHJ1bGVzIHNvcnRlZCBieSBhIGRlZmF1bHQgY3JpdGVyaW9uDQoNCmBgYHtyfQ0KDQppbnNwZWN0KGhlYWQoc29ydChydWxlMSksIG49MTUpKQ0KDQpgYGANCg0KYGBge3J9DQpoZWFkKHF1YWxpdHkocnVsZTEpKQ0KYGBgDQoNClNvcnRpbmcgYW5kIGluc3BlY3RpbmcgcnVsZXMgYnkgJ2xpZnQnDQoNCmBgYHtyfQ0KDQpydWxlMV9saWZ0IDwtIHNvcnQocnVsZTEsIGJ5ID0gImxpZnQiLCBkZXNjZW5kaW5nID0gVFJVRSkNCmluc3BlY3QoaGVhZChydWxlMV9saWZ0KSkNCmBgYA0KDQpTb3J0aW5nIGFuZCBpbnNwZWN0aW5nIHJ1bGVzIGJ5ICdjb25maWRlbmNlJw0KDQpgYGB7cn0NCnJ1bGUxX2NvbmZpZGVuY2UgPC0gc29ydChydWxlMSwgYnkgPSAiY29uZmlkZW5jZSIsIGRlc2NlbmRpbmcgPSBUUlVFKQ0KaW5zcGVjdChoZWFkKHJ1bGUxX2NvbmZpZGVuY2UpKQ0KYGBgDQoNClZpc3VhbGl6aW5nIHRoZSBnZW5lcmF0ZWQgcnVsZXMgdXNpbmcgZGlmZmVyZW50IHBsb3RzDQoNCmBgYHtyfQ0KIyBWaXN1YWxpemF0aW9uIHVzaW5nIGEgc2NhdHRlciBwbG90LiBBZGp1c3QgJ21lYXN1cmUnIGFyZ3VtZW50cyBhcyBuZWVkZWQuDQpwbG90KHJ1bGUxLCBtZXRob2QgPSAic2NhdHRlcnBsb3QiLCBtZWFzdXJlID0gYygic3VwcG9ydCIsICJjb25maWRlbmNlIiksIHNoYWRpbmcgPSAibGlmdCIpDQoNCnBsb3QocnVsZTEsIG1ldGhvZCA9ICJ0d28ta2V5IHBsb3QiKQ0KYGBgDQoNCi0gICBSdWxlcyB3aXRoIGhpZ2hlciBzdXBwb3J0ICh0b3dhcmRzIHRoZSByaWdodCBvZiB0aGUgcGxvdCkgYXJlIGJhc2VkIG9uIGl0ZW1zIHRoYXQgYXJlIG1vcmUgY29tbW9uIGluIHRoZSBkYXRhc2V0Lg0KDQotICAgUnVsZXMgd2l0aCBoaWdoZXIgY29uZmlkZW5jZSAodG93YXJkcyB0aGUgdG9wIG9mIHRoZSBwbG90KSBhcmUgbW9yZSByZWxpYWJsZSBpbiBwcmVkaWN0aW5nIHRoZSBjb25zZXF1ZW50IGluIGEgdHJhbnNhY3Rpb24uDQoNCi0gICBUaGUgbWFqb3JpdHkgb2YgcnVsZXMgd2l0aCBoaWdoIGNvbmZpZGVuY2UgYWxzbyBoYXZlIHJlbGF0aXZlbHkgbG93IHN1cHBvcnQsIHdoaWNoIGlzIGEgY29tbW9uIG9jY3VycmVuY2UgaW4gbGFyZ2UgZGF0YXNldHMgd2hlcmUgc3BlY2lmaWMgaXRlbSBjb21iaW5hdGlvbnMgb2NjdXIgaW5mcmVxdWVudGx5IGJ1dCBhcmUgaGlnaGx5IHByZWRpY3RhYmxlLg0KDQotICAgVGhlcmUgaXMgYSB2YXJpZXR5IG9mIHJ1bGVzIHdpdGggZGlmZmVyZW50IG51bWJlcnMgb2YgaXRlbXMgaW52b2x2ZWQgKGFzIGluZGljYXRlZCBieSB0aGUgZGlmZmVyZW50IGNvbG9ycyksIGJ1dCBpdCBzZWVtcyB0aGF0IHJ1bGVzIHdpdGggZmV3ZXIgaXRlbXMgKG9yZGVyIDUgYW5kIDYpIGFyZSBtb3JlIGNvbW1vbi4NCg0KLSAgIFRoZSAnZ2FwcycgaW4gdGhlIHBsb3QgKGhvcml6b250YWwgbGluZXMgd2l0aG91dCBwb2ludHMpIG1pZ2h0IGluZGljYXRlIHRocmVzaG9sZHMgb3IgYm91bmRhcmllcyB3aGVyZSBubyBydWxlcyBtZWV0IHRoZSBjcml0ZXJpYSB0byBiZSBwbG90dGVkLCBwb3NzaWJseSBkdWUgdG8gdGhlIHBhcmFtZXRlciBzZXR0aW5ncyBpbiB0aGUgYXByaW9yaSBhbGdvcml0aG0uDQoNClwjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KR2VuZXJhdGluZyBhbmQgaW5zcGVjdGluZyBkaWZmZXJlbnQgc2V0cyBvZiBydWxlcyB3aXRoIHZhcmllZCBwYXJhbWV0ZXJzLCBhbmQgdmlzdWFsaXppbmcgdGhlbSB1c2luZyBkaWZmZXJlbnQgbWV0aG9kcw0KDQpgYGB7cn0NCg0KcnVsZTIgPC0gYXByaW9yaShib29rMSwgcGFyYW1ldGVyID0gbGlzdChzdXBwID0gMC4wNSwgY29uZmlkZW5jZSA9IDAuOCwgbWlubGVuID0gNiwgbWF4bGVuID0gMjApKQ0KaW5zcGVjdChoZWFkKHJ1bGUyLCAxMCkpDQpydWxlMg0KcGFyKG1hciA9IGMoNSwgOCwgNCwgMikgKyAwLjEpDQpwbG90KHJ1bGUyLCBtZXRob2QgPSAiZ3JvdXBlZCIsIGNleCA9IDAuMSkNCmBgYA0KDQohW10oaW1hZ2VzL1NjcmVlbnNob3QlMjAyMDI0LTAyLTAxJTIwMTQyMzI4LnBuZykNCg0KLSAgIFRoZSBpdGVtcyBvbiB0aGUgWS1heGlzIHRoYXQgaGF2ZSBsYXJnZXIgYW5kIG1vcmUgaW50ZW5zZWx5IGNvbG9yZWQgYnViYmxlcyBhc3NvY2lhdGVkIHdpdGggdGhlbSBhcmUgdGhvc2UgdGhhdCBtb3N0IGZyZXF1ZW50bHkgbGVhZCB0byBvdGhlciBpdGVtcyBiZWluZyBib3VnaHQuIFRoZXNlIGFyZSBzdHJvbmcgYW5kIGZyZXF1ZW50IHJ1bGVzLg0KDQotICAgVGhlIGRpc3RyaWJ1dGlvbiBvZiBidWJibGVzIGFjcm9zcyB0aGUgc3VwcG9ydCBheGlzIGNhbiBnaXZlIHVzIGFuIGlkZWEgb2YgaG93IGNvbW1vbiBjZXJ0YWluIGl0ZW1zIG9yIGl0ZW1zZXRzIGFyZSB3aXRoaW4gdGhlIHRyYW5zYWN0aW9ucyBpbiB0aGUgZGF0YXNldC4NCg0KLSAgIFRoZSBydWxlcyB3aXRoIGhpZ2hlciBsaWZ0IHZhbHVlcywgaW5kaWNhdGVkIGJ5IHRoZSBkYXJrZXIgc2hhZGVzLCBhcmUgcGFydGljdWxhcmx5IGludGVyZXN0aW5nIGJlY2F1c2UgdGhleSBtYXkgcmV2ZWFsIHN0cm9uZyBhc3NvY2lhdGlvbnMgdGhhdCBhcmUgbm90IGltbWVkaWF0ZWx5IG9idmlvdXMuDQoNCi0gICBJZiB0aGVyZSBhcmUgYW55IHJvd3MgKHJlcHJlc2VudGluZyBpdGVtc2V0cykgdGhhdCBoYXZlIG1hbnkgbGFyZ2UsIGRhcmstY29sb3JlZCBidWJibGVzLCB0aGVzZSBpdGVtc2V0cyBhcmUgbGlrZWx5IHRvIGJlIHZlcnkgc3Ryb25nIHByZWRpY3RvcnMgZm9yIHZhcmlvdXMgb3RoZXIgaXRlbXMgKG5vdCBzaG93biBpbiB0aGUgdmlzaWJsZSBwbG90IGFyZWEpLg0KDQogICAgXCMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQpgYGB7cn0NCg0KDQpydWxlMyA8LSBhcHJpb3JpKGJvb2sxLCBwYXJhbWV0ZXIgPSBsaXN0KHN1cHAgPSAwLjA0LCBjb25maWRlbmNlID0gMC42LCBtaW5sZW4gPSA3LCBtYXhsZW4gPSAxMCkpDQppbnNwZWN0KGhlYWQocnVsZTMsIDEwKSkNCnJ1bGUzDQpwbG90KHJ1bGUzLCBtZXRob2QgPSAiZ3JhcGgiKQ0KYGBgDQoNCi0gICBJdGVtcyB3aXRoIGxhcmdlciBub2RlcyBhcmUgbW9yZSBjb21tb24gd2l0aGluIHRoZSBkYXRhc2V0LCBhbmQgYW55IHJ1bGVzIGludm9sdmluZyB0aGVzZSBpdGVtcyB3aWxsIGltcGFjdCBhIGxhcmdlciBwb3J0aW9uIG9mIHRoZSB0cmFuc2FjdGlvbnMuDQoNCi0gICBOb2RlcyB3aXRoIGEgZGFya2VyIGNvbG9yIGFyZSBwYXJ0IG9mIHJ1bGVzIHdpdGggaGlnaGVyIGxpZnQsIHdoaWNoIGFyZSBvZiBwYXJ0aWN1bGFyIGludGVyZXN0IGJlY2F1c2UgdGhleSBpbmRpY2F0ZSB0aGF0IHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBpdGVtcyBpcyBzdHJvbmdlciB0aGFuIGV4cGVjdGVkIGJ5IGNoYW5jZS4gVGhpcyBjb3VsZCBzdWdnZXN0IGEgcG90ZW50aWFsIGZvciBjcm9zcy1zZWxsaW5nIG9yIHByb21vdGlvbnMuDQoNCi0gICBUaGUgc3RydWN0dXJlIG9mIHRoZSBuZXR3b3JrIGNhbiBnaXZlIHlvdSBhbiBpZGVhIG9mIGhvdyBpdGVtcyBhcmUgaW50ZXJjb25uZWN0ZWQuIEZvciBpbnN0YW5jZSwgaWYgbWFueSBub2RlcyAoaXRlbXMpIGFyZSBjb25uZWN0ZWQgdG8gYSBzaW5nbGUgbm9kZSwgdGhpcyBjZW50cmFsIG5vZGUgbWF5IGJlIGEga2V5IGl0ZW0gdGhhdCBpcyBmcmVxdWVudGx5IGJvdWdodCB3aXRoIHZhcmlvdXMgb3RoZXIgaXRlbXMuDQoNCi0gICBEdWUgdG8gdGhlIG92ZXJsYXAgYW5kIGRlbnNpdHkgb2YgdGhlIHBsb3QsIGl0IG1heSBiZSBkaWZmaWN1bHQgdG8gaWRlbnRpZnkgc3BlY2lmaWMgcnVsZXMgb3IgdGhlIGRpcmVjdGlvbiBvZiB0aGUgYXNzb2NpYXRpb24gKHdoaWNoIGl0ZW0gaXMgdGhlIGFudGVjZWRlbnQgYW5kIHdoaWNoIGlzIHRoZSBjb25zZXF1ZW50KS4gSW50ZXJhY3RpdmUgdG9vbHMgb3IgZmlsdGVyaW5nIHRvIHNob3cgYSBzdWJzZXQgb2YgcnVsZXMgbWF5IGJlIGhlbHBmdWwgZm9yIGRlZXBlciBhbmFseXNpcy4NCg0KICAgIFwjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KYGBge3J9DQpydWxlNCA8LSBhcHJpb3JpKGJvb2sxLCBwYXJhbWV0ZXIgPSBsaXN0KHN1cHAgPSAwLjA2LCBjb25maWRlbmNlID0gMC43LCBtaW5sZW4gPSA4LCBtYXhsZW4gPSAxNSkpDQppbnNwZWN0KGhlYWQocnVsZTQsIDEwKSkNCnJ1bGU0DQpwbG90KHJ1bGU0LCBtZXRob2QgPSAicGFyYWNvb3JkIikNCmBgYA0KDQpgYGB7cn0NCnJ1bGU1IDwtIGFwcmlvcmkoYm9vazEsIHBhcmFtZXRlciA9IGxpc3Qoc3VwcCA9IDAuMDMsIGNvbmZpZGVuY2UgPSAwLjg1LCBtaW5sZW4gPSA5LCBtYXhsZW4gPSAyMCkpDQppbnNwZWN0KGhlYWQocnVsZTUsIDEwKSkNCnJ1bGU1DQpwbG90KHJ1bGU1LCBtZXRob2QgPSAidHdvLWtleSBwbG90IikNCmBgYA0KDQotICAgTW9zdCBydWxlcyBoYXZlIGEgaGlnaCBjb25maWRlbmNlIGxldmVsIChhYm92ZSA4NSUpLCBpbmRpY2F0aW5nIHRoYXQgdGhlIGNvbnNlcXVlbnQgaXRlbXMgYXJlIHZlcnkgbGlrZWx5IHRvIGJlIHB1cmNoYXNlZCB3aGVuIHRoZSBhbnRlY2VkZW50IGl0ZW1zIGFyZSBwdXJjaGFzZWQuDQoNCi0gICBUaGVyZSBpcyBhIHdpZGUgcmFuZ2Ugb2Ygc3VwcG9ydCBmb3IgdGhlc2UgcnVsZXMsIHdpdGggbm8gY2xlYXIgY29uY2VudHJhdGlvbiBvZiBwb2ludHMgdG93YXJkcyBoaWdoZXIgc3VwcG9ydCB2YWx1ZXMuIFRoaXMgc3VnZ2VzdHMgdGhhdCB3aGlsZSB0aGUgcnVsZXMgYXJlIHJlbGlhYmxlIChoaWdoIGNvbmZpZGVuY2UpLCB0aGV5IG1heSBub3QgYXBwbHkgdG8gYSBsYXJnZSBwb3J0aW9uIG9mIHRoZSBkYXRhc2V0IChsb3dlciBzdXBwb3J0KS4NCg0KLSAgIFRoZSBzcHJlYWQgb2YgcG9pbnRzIGFjcm9zcyB0aGUgY29uZmlkZW5jZSBsZXZlbHMsIHBhcnRpY3VsYXJseSBpbiB0aGUgaGlnaC1jb25maWRlbmNlIGFyZWEsIHN1Z2dlc3RzIHRoZXJlIGFyZSBtYW55IHN0cm9uZyBydWxlcyB0aGF0IGNvdWxkIGJlIGxldmVyYWdlZCBmb3IgbWFya2V0aW5nIHN0cmF0ZWdpZXMsIHN1Y2ggYXMgcHJvZHVjdCBwbGFjZW1lbnQgb3IgcHJvbW90aW9ucy4NCg0KLSAgIFRoZSBydWxlcyBhcmUgcmVsYXRpdmVseSBldmVubHkgZGlzdHJpYnV0ZWQgYWNyb3NzIHRoZSBkaWZmZXJlbnQgb3JkZXIgc2l6ZXMgKDksIDEwLCBhbmQgMTEpLCB3aXRoIG5vIHNpbmdsZSBvcmRlciBzaXplIGRvbWluYXRpbmcgdGhlIGhpZ2gtY29uZmlkZW5jZSwgaGlnaC1zdXBwb3J0IGFyZWEgb2YgdGhlIHBsb3QuDQoNCi0gICBUaGUgY2x1c3RlciBvZiBwb2ludHMgYXQgdGhlIGxvd2VyIHN1cHBvcnQgbGV2ZWxzIHN1Z2dlc3RzIHRoYXQgdGhlcmUgYXJlIHBvdGVudGlhbGx5IGludGVyZXN0aW5nIGJ1dCBsZXNzIGZyZXF1ZW50IGl0ZW1zZXRzIHRoYXQgY291bGQgYmUgdGhlIGZvY3VzIG9mIG5pY2hlIG1hcmtldGluZyBzdHJhdGVnaWVzLg0KDQojIElkZW50aWZ5aW5nIGFuZCBwbG90dGluZyB0aGUgdG9wIDUgcnVsZXMgYmFzZWQgb24gY29uZmlkZW5jZQ0KDQpgYGB7cn0NCg0KdG9wNXJ1bGVzIDwtIGhlYWQocnVsZTUsIG49NSwgYnkgPSAiY29uZmlkZW5jZSIpDQpwbG90KHRvcDVydWxlcywgZW5naW5lID0gImh0bWx3aWRnZXQiLCBtZXRob2QgPSAiZ3JhcGgiKQ0KYGBgDQoNCi0gICAqKktleSBJbmZsdWVuY2VycyoqOiBUaGUgaXRlbXMgYXQgdGhlIHRhaWwgb2YgdGhlIGFycm93cyBhcmUga2V5IGluZmx1ZW5jZXJzLCBtZWFuaW5nIHRoYXQgdGhlaXIgcHJlc2VuY2UgaW4gYSB0cmFuc2FjdGlvbiBzdHJvbmdseSBzdWdnZXN0cyB0aGUgbGlrZWxpaG9vZCBvZiB0aGUgaXRlbSBhdCB0aGUgaGVhZCBiZWluZyBwdXJjaGFzZWQuDQoNCi0gICAqKkhpZ2ggQ29uZmlkZW5jZSBBc3NvY2lhdGlvbnMqKjogVGhlIHJ1bGVzIHJlcHJlc2VudGVkIGluIHRoaXMgZ3JhcGggYXJlIHRoZSBzdHJvbmdlc3QgaW4gdGhlIGRhdGFzZXQgaW4gdGVybXMgb2YgY29uZmlkZW5jZSwgc28gdGhlIHJlbGF0aW9uc2hpcHMgc2hvd24gYXJlIGhpZ2hseSByZWxpYWJsZS4NCg0KLSAgICoqSW50ZXJjb25uZWN0ZWRuZXNzKio6IFRoZSBncmFwaCBzaG93cyBob3cgZGlmZmVyZW50IGl0ZW1zIGFyZSBpbnRlcmNvbm5lY3RlZC4gSWYgYW4gaXRlbSBpcyBhIGNvbW1vbiBjb25zZXF1ZW50IChtYW55IGFycm93cyBwb2ludGluZyB0byBpdCksIGl0IG1pZ2h0IGJlIGEgcG9wdWxhciBpdGVtIHRoYXQgY2FuIGJlIHRhcmdldGVkIGZvciBwcm9tb3Rpb25hbCBzdHJhdGVnaWVzLg0KDQotICAgKipQb3NzaWJsZSBJdGVtIENvbWJpbmF0aW9ucyoqOiBUaGUgZ3JhcGggaWxsdXN0cmF0ZXMgaG93IGRpZmZlcmVudCBpdGVtIGNvbWJpbmF0aW9ucyBsZWFkIHRvIHRoZSBwdXJjaGFzZSBvZiBvdGhlciBpdGVtcy4gVGhpcyBjYW4gaW5mb3JtIHN0cmF0ZWdpZXMgZm9yIHByb2R1Y3QgcGxhY2VtZW50LCBpbnZlbnRvcnkgbWFuYWdlbWVudCwgYW5kIGNyb3NzLXNlbGxpbmcuDQoNCiMjIENvbmNsdXNpb246DQoNClRoZSB0b3AgNSBydWxlcyBiYXNlZCBvbiBjb25maWRlbmNlIGhpZ2hsaWdodCB0aGUgbW9zdCBwcmVkaWN0YWJsZSBwdXJjaGFzaW5nIHBhdHRlcm5zIHdpdGhpbiB0aGUgZGF0YXNldC4gVGhlc2UgcGF0dGVybnMgY2FuIGd1aWRlIGRlY2lzaW9uLW1ha2luZyBpbiBtYXJrZXRpbmcgYW5kIHNhbGVzIHN0cmF0ZWdpZXMsIGFzIHRoZXkgcmV2ZWFsIHdoaWNoIGl0ZW1zIGFyZSBsaWtlbHkgdG8gYmUgcHVyY2hhc2VkIHRvZ2V0aGVyLiBGb3IgaW5zdGFuY2UsIGlmICJJdGFsQ29vayIgKEl0YWxpYW4gQ29va2Jvb2tzKSBhcHBlYXJzIG9mdGVuIGFzIGFuIGFudGVjZWRlbnQsIGl0IG1pZ2h0IGJlIGJlbmVmaWNpYWwgdG8gcGxhY2UgcmVsYXRlZCBpdGVtcyB0aGF0IGZyZXF1ZW50bHkgZm9sbG93ICJJdGFsQ29vayIgaW4gcHJveGltaXR5IGluIGEgc3RvcmUgb3IgdG8gYnVuZGxlIHRoZW0gaW4gcHJvbW90aW9ucy4gVGhlIGdyYXBoIHZpc3VhbGx5IHN1bW1hcml6ZXMgdGhlc2UgYXNzb2NpYXRpb25zLCBtYWtpbmcgaXQgZWFzaWVyIHRvIGlkZW50aWZ5IGFuZCB1bmRlcnN0YW5kIHRoZSBzdHJvbmdlc3QgcmVsYXRpb25zaGlwcyBpbiB0aGUgZGF0YXNldC4NCg==