The idea of this handout is to develop a logistic regression model to discuss the odds of the presence of a bening or a phising URL_type. In this mini tutorial you have the steps we need to follow in order to complete this acitivity.

getwd()
[1] "C:/Users/antho/OneDrive/Documents/School/4.DataSecurity&Governance/Project 2"

First we make sure we are working the correct working directory. Then we will import the csv. file into the “final1” dataframe by using the read.csv() function.

final1<-read.csv("groupVIIclean.csv",sep = ",",header = TRUE)

Now we want to inspect the data structure of this dataframe we just created. We can use the structure function to do this.

str(final1)
'data.frame':   15087 obs. of  13 variables:
 $ avgpathtokenlen        : num  2.67 3.33 8 3.46 4.62 ...
 $ pathurlRatio           : num  0.256 0.68 0.413 0.781 0.611 0.5 0.564 0.84 0.346 0.5 ...
 $ ArgUrlRatio            : num  0.047 0.027 0.018 0.027 0.028 0.05 0.036 0.017 0.036 0.05 ...
 $ argDomanRatio          : num  0.08 0.118 0.035 0.222 0.095 0.154 0.118 0.167 0.069 0.154 ...
 $ domainUrlRatio         : num  0.581 0.227 0.523 0.123 0.292 0.325 0.309 0.101 0.527 0.325 ...
 $ pathDomainRatio        : num  0.44 3 0.79 6.33 2.1 ...
 $ argPathRatio           : num  0.182 0.039 0.044 0.035 0.046 0.1 0.065 0.02 0.105 0.1 ...
 $ CharacterContinuityRate: num  0.72 0.824 0.281 0.667 0.667 0.769 0.588 0.75 0.69 0.769 ...
 $ NumberRate_URL         : num  0.116 0.053 0.193 0.082 0 0.1 0 0.059 0.055 0.05 ...
 $ NumberRate_FileName    : num  1 0.08 0.625 0 0 0.286 0 0 0 0.143 ...
 $ NumberRate_AfterPath   : num  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
 $ Entropy_Domain         : num  0.763 0.788 0.703 0.93 0.84 0.917 0.759 0.954 0.799 0.917 ...
 $ class                  : chr  "phishing" "benign" "phishing" "benign" ...

Now let us omit any null values from the data frame

mydata1<-na.omit(final1)

Now let us get a statisitical summary for each field.


summary(mydata1)
 avgpathtokenlen    pathurlRatio     ArgUrlRatio      argDomanRatio     domainUrlRatio   pathDomainRatio 
 Min.   :  0.667   Min.   :0.0410   Min.   :0.00000   Min.   : 0.0000   Min.   :0.0290   Min.   : 0.044  
 1st Qu.:  3.800   1st Qu.:0.5470   1st Qu.:0.02400   1st Qu.: 0.1110   1st Qu.:0.1410   1st Qu.: 1.667  
 Median :  4.500   Median :0.6920   Median :0.03300   Median : 0.1540   Median :0.2030   Median : 3.429  
 Mean   :  5.293   Mean   :0.6539   Mean   :0.09634   Mean   : 0.7042   Mean   :0.2401   Mean   : 4.074  
 3rd Qu.:  5.571   3rd Qu.:0.7740   3rd Qu.:0.04900   3rd Qu.: 0.2000   3rd Qu.:0.3250   3rd Qu.: 5.500  
 Max.   :105.000   Max.   :0.9510   Max.   :0.91100   Max.   :20.4620   Max.   :0.9300   Max.   :32.900  
  argPathRatio    CharacterContinuityRate NumberRate_URL    NumberRate_FileName NumberRate_AfterPath Entropy_Domain  
 Min.   :0.0000   Min.   :0.0750          Min.   :0.00000   Min.   :-1.00000    Min.   :-1.0000      Min.   :0.5620  
 1st Qu.:0.0340   1st Qu.:0.6000          1st Qu.:0.00000   1st Qu.: 0.00000    1st Qu.:-1.0000      1st Qu.:0.7990  
 Median :0.0530   Median :0.7200          Median :0.05700   Median : 0.00000    Median :-1.0000      Median :0.8610  
 Mean   :0.1414   Mean   :0.6725          Mean   :0.08681   Mean   : 0.09023    Mean   :-0.8171      Mean   :0.8557  
 3rd Qu.:0.1000   3rd Qu.:0.7780          3rd Qu.:0.12500   3rd Qu.: 0.17900    3rd Qu.:-1.0000      3rd Qu.:0.9170  
 Max.   :0.9780   Max.   :1.0000          Max.   :0.76200   Max.   : 1.00000    Max.   : 1.0000      Max.   :1.0000  
    class          
 Length:15087      
 Class :character  
 Mode  :character  
                   
                   
                   

Let us also inspect the data structure of or new dataframe that has no nulls. Notice it has the same number of observations/records 15087, so we can assume there were no nulls in this data set.

str(mydata1)
'data.frame':   15087 obs. of  13 variables:
 $ avgpathtokenlen        : num  2.67 3.33 8 3.46 4.62 ...
 $ pathurlRatio           : num  0.256 0.68 0.413 0.781 0.611 0.5 0.564 0.84 0.346 0.5 ...
 $ ArgUrlRatio            : num  0.047 0.027 0.018 0.027 0.028 0.05 0.036 0.017 0.036 0.05 ...
 $ argDomanRatio          : num  0.08 0.118 0.035 0.222 0.095 0.154 0.118 0.167 0.069 0.154 ...
 $ domainUrlRatio         : num  0.581 0.227 0.523 0.123 0.292 0.325 0.309 0.101 0.527 0.325 ...
 $ pathDomainRatio        : num  0.44 3 0.79 6.33 2.1 ...
 $ argPathRatio           : num  0.182 0.039 0.044 0.035 0.046 0.1 0.065 0.02 0.105 0.1 ...
 $ CharacterContinuityRate: num  0.72 0.824 0.281 0.667 0.667 0.769 0.588 0.75 0.69 0.769 ...
 $ NumberRate_URL         : num  0.116 0.053 0.193 0.082 0 0.1 0 0.059 0.055 0.05 ...
 $ NumberRate_FileName    : num  1 0.08 0.625 0 0 0.286 0 0 0 0.143 ...
 $ NumberRate_AfterPath   : num  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
 $ Entropy_Domain         : num  0.763 0.788 0.703 0.93 0.84 0.917 0.759 0.954 0.799 0.917 ...
 $ class                  : chr  "phishing" "benign" "phishing" "benign" ...

Lets convert the data type for the “class” field from character to factor so that we can perform binary classification on this fields only two values “benign” and “phishing”. Notice we use the as.factor() function to make this data type conversion.

mydata1$class<-as.factor(mydata1$class)

Now lets review or data structure once more to see the changes we made to the “class” column.

str(mydata1)
'data.frame':   15087 obs. of  13 variables:
 $ avgpathtokenlen        : num  2.67 3.33 8 3.46 4.62 ...
 $ pathurlRatio           : num  0.256 0.68 0.413 0.781 0.611 0.5 0.564 0.84 0.346 0.5 ...
 $ ArgUrlRatio            : num  0.047 0.027 0.018 0.027 0.028 0.05 0.036 0.017 0.036 0.05 ...
 $ argDomanRatio          : num  0.08 0.118 0.035 0.222 0.095 0.154 0.118 0.167 0.069 0.154 ...
 $ domainUrlRatio         : num  0.581 0.227 0.523 0.123 0.292 0.325 0.309 0.101 0.527 0.325 ...
 $ pathDomainRatio        : num  0.44 3 0.79 6.33 2.1 ...
 $ argPathRatio           : num  0.182 0.039 0.044 0.035 0.046 0.1 0.065 0.02 0.105 0.1 ...
 $ CharacterContinuityRate: num  0.72 0.824 0.281 0.667 0.667 0.769 0.588 0.75 0.69 0.769 ...
 $ NumberRate_URL         : num  0.116 0.053 0.193 0.082 0 0.1 0 0.059 0.055 0.05 ...
 $ NumberRate_FileName    : num  1 0.08 0.625 0 0 0.286 0 0 0 0.143 ...
 $ NumberRate_AfterPath   : num  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
 $ Entropy_Domain         : num  0.763 0.788 0.703 0.93 0.84 0.917 0.759 0.954 0.799 0.917 ...
 $ class                  : Factor w/ 2 levels "benign","phishing": 2 1 2 1 2 2 2 1 2 2 ...

Notice how now the data type is a Factor w/ 2 levels represented by 2 and 1. Lets change this feature once again by converting all the “phishing” values to zero. We will use the ifelse loop to achieve this conversion.

mydata1$class <- ifelse(mydata1$class == "benign", 1, 0)# this will make all "benign" values equal 1 
                                                        #and all other values 0

This change should give us a more traditional binary values of 1 and 0.

# We can open the dataframe of the my data and verify that our binary value has been created. 
#View(mydata1)

Lets get some insight into the fields with the Data Dictionary.

We will see that Many of these varialbles are dependant on independant variables like URL and Domanin which we are not provided. These quantifications that describe averages and raios of fields that apply to a URL address will allow us to perform some statistical anaylisis and model building, which will allow us to learn more about the relevance of these fields to one another and test hypothesis we have on the relationship they have with the target category to be classified.

Avgpathtokenlen: Numerical-Average length of path token. The avgpathtokenlen column references these token paths or strings and groups them to calculate its average length.

pathurlRatio: Numerical-Path divided by URL.

ArgUrlRatio: Numerical-Ratio of argument and URL.

argDomanRatio: Numerical-Argument divided by domain. The argDomanRatio holds the sum of the arguments grouped by the specifies domains, divided by the amount of times a domain is requested.

domainUrlRatio: Numerical-Domain divided by URL.

pathDomainRatio-Numerical-Path: divided by Domain. The URL divided by the domain is the domain Path Domain ratio.

argPathRatio: Numerical-Ratio of argument and path.

CharacterContinuityRate: Numerical-Character Continuity Rate is used to find the sum of the longest token length of each character type in the domain, such as abc567ti = (3 + 3 + 1)/9 = 0.77. Malicious websites use URLs which have variable number of character types. Character continuity rate determine the sequence of letter, digit and symbol characters. The sum of longest token length of a character type is divided by the length of the URL.

NumberRate_URL: Numerical-Number rate calculate the proportion of digits in the URL part of URL itself.

NumberRate_FileName: Numerical-Number rate calculate the proportion of digits in the URL part of filename.

NumberRate_AfterPath: Numerical-Number rate calculate the proportion of digits in the URL parts of part after the path.

Entropy_Domain: Numerical-Malicious websites often insert additional characters in the URL to make it look like a legitimate. e.g, CITI can be written as CIT1, by replacing last alphabet I with digit 1. English text has fairly low entropy i.e., it is predictable. By inserting characters the entropy changes than usual. For identifying the randomly generated malicious URLs, alphabet entropy is used. A formula is used to calculate the information entropy.

class-Categorical: URL typed: Benign, Spam, Phishing, Malware or the avgpathtokenlen column references these token paths or strings and groups them to calculate its average length.

I realize that I am very unfamiliar with networking and internet protocol after reviewing the definitions of all these fields. This was the first I have ever heard of URL paths and still am not confident with my understanding.1 Luckily we have statistics and regression models to help us find valuable patterns between these values so that we can attempt to better utilize them.

Now that we are further familiar with the dataset lut us inpsect correlation and relationships with many varieties of correlation matrixes.

cr<-cor(mydata1[,-13])
cr
                        avgpathtokenlen pathurlRatio ArgUrlRatio argDomanRatio domainUrlRatio pathDomainRatio
avgpathtokenlen              1.00000000   0.20565786 -0.11096675   -0.02151169    -0.15435881      0.19253758
pathurlRatio                 0.20565786   1.00000000  0.25844811    0.34334011    -0.98059649      0.82368027
ArgUrlRatio                 -0.11096675   0.25844811  1.00000000    0.90844457    -0.24406584      0.31230027
argDomanRatio               -0.02151169   0.34334011  0.90844457    1.00000000    -0.31388861      0.48577889
domainUrlRatio              -0.15435881  -0.98059649 -0.24406584   -0.31388861     1.00000000     -0.78454426
pathDomainRatio              0.19253758   0.82368027  0.31230027    0.48577889    -0.78454426      1.00000000
argPathRatio                -0.16045571   0.11223739  0.97893163    0.83932099    -0.10172942      0.19515815
CharacterContinuityRate     -0.17954935   0.26435796  0.02382876    0.03876218    -0.32697254      0.12678431
NumberRate_URL               0.37615691   0.26915457  0.16064291    0.23703321    -0.22454144      0.26379090
NumberRate_FileName          0.21155718  -0.04867724  0.06440619    0.06958914     0.06086648     -0.08436904
NumberRate_AfterPath        -0.07354815   0.26803235  0.86986041    0.76162049    -0.25390104      0.30073882
Entropy_Domain              -0.11281137   0.34574630  0.02154917    0.04130224    -0.43013984      0.30621945
                        argPathRatio CharacterContinuityRate NumberRate_URL NumberRate_FileName NumberRate_AfterPath
avgpathtokenlen          -0.16045571             -0.17954935     0.37615691          0.21155718          -0.07354815
pathurlRatio              0.11223739              0.26435796     0.26915457         -0.04867724           0.26803235
ArgUrlRatio               0.97893163              0.02382876     0.16064291          0.06440619           0.86986041
argDomanRatio             0.83932099              0.03876218     0.23703321          0.06958914           0.76162049
domainUrlRatio           -0.10172942             -0.32697254    -0.22454144          0.06086648          -0.25390104
pathDomainRatio           0.19515815              0.12678431     0.26379090         -0.08436904           0.30073882
argPathRatio              1.00000000             -0.01659203     0.11435402          0.06021489           0.86650561
CharacterContinuityRate  -0.01659203              1.00000000    -0.03412866         -0.06663442           0.05033632
NumberRate_URL            0.11435402             -0.03412866     1.00000000          0.34717068           0.20217671
NumberRate_FileName       0.06021489             -0.06663442     0.34717068          1.00000000           0.08145431
NumberRate_AfterPath      0.86650561              0.05033632     0.20217671          0.08145431           1.00000000
Entropy_Domain           -0.01971431              0.36454930     0.01045629         -0.07448911           0.04887298
                        Entropy_Domain
avgpathtokenlen            -0.11281137
pathurlRatio                0.34574630
ArgUrlRatio                 0.02154917
argDomanRatio               0.04130224
domainUrlRatio             -0.43013984
pathDomainRatio             0.30621945
argPathRatio               -0.01971431
CharacterContinuityRate     0.36454930
NumberRate_URL              0.01045629
NumberRate_FileName        -0.07448911
NumberRate_AfterPath        0.04887298
Entropy_Domain              1.00000000

Above can see we created the matrix below we will test it.

Let us install the packages necessary to view it

install.packages("Corrplot")
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/
Installing package into ‘C:/Users/antho/AppData/Local/R/win-library/4.2’
(as ‘lib’ is unspecified)
Warning in install.packages :
  package ‘Corrplot’ is not available for this version of R

A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
Warning in install.packages :
  Perhaps you meant ‘corrplot’ ?
library(corrplot)

Let us view it with corrplot

corrplot(cr, method = 'ellipse')

Let us see if we can order it in way that we can understand more aout the corelletion maybe by the angular order of the eigenvectors(AOE),the firtst principal component order (FPC), or the hierarchical clustering order.

corrplot(cr, order = 'AOE')

corrplot(cr, order = 'FPC')

corrplot(cr, order = 'hclust')

I prefer how the hierarchical clustering order presents the correlations. I can can clearly see about 3 clusters but dont know what the clustering linkage method is be it complete, centeroid, average,etc. If I was going to run the data through a k-Nearest Neighbor model I would benefit from cluster categorization like denerograms which I belive the adddrect argument achieves to some degree below.

corrplot(cr, method = 'ellipse', order = 'hclust', addrect = 4)

I see pathurlRatio and domainUrlRatio have high correlation as well as ArgUrlRatio and argPathRatio. Some of these values may be overly correlated, so I wont base my model after these relationships as much as I will consider then in my next steps building and testing a logistig regresion model.

Train and Test Data

The purpose of creating two different datasets from the original one is to improve our ability so as to accurately predict the previously unused or unseen data.

There are a number of ways to proportionally split our data into train and test sets: 50/50, 60/40, 70/30, 80/20, and so forth. The data split that you select should be based on your experience and judgment. For this exercise, we will use a 80/20 split, as follows:

set.seed(23)  # random number generator set to the seed of 23.
ind <- sample(2, nrow(mydata1), replace = TRUE, prob = c(0.8, 0.2)) 

Partitioning the data:

Here we grab the split data into our first train and test variables. Notice above is where we implimented the split

train1 <- mydata1[ind==1, ]  #the training set

test1 <- mydata1[ind==2, ]   # the testing set 

You can confirm the dimensions of both sets as follows:

dim(train1)
[1] 12127    13
dim(test1)
[1] 2960   13

Above we can see that both fields have the same number of features and the test set has a quarter of the records that the train set does.

To ensure that we have a well-balanced outcome variable between the two datasets, we will perform the following check:

table(train1$class) # Creates a table that shows the count of each class

   0    1 
5910 6217 
table(test1$class)

   0    1 
1401 1559 

We can see that the there is a fair balance between our targert class for both of or sets.

This is an acceptable ratio of our outcomes in the two datasets; with this, we can begin the modeling and evaluation.

Modeling and Evaluation

We will use the function glm() (from base R) for the logistic regression model.

An R installation comes with the glm() function fitting the generalized linear models, which are a class of models that includes logistic regression. The code syntax is similar to the lm() function that we used for linear regression. One difference is that we must use the family = binomial argument in the function, which tells R to run a logistic regression method instead of the other versions of the generalized linear models. We will start by creating a model that includes all of the features on the train set and see how it performs on the test set:

attach(train1)
The following objects are masked from train1 (pos = 4):

    argDomanRatio, argPathRatio, ArgUrlRatio, avgpathtokenlen, CharacterContinuityRate, class,
    domainUrlRatio, Entropy_Domain, NumberRate_AfterPath, NumberRate_FileName, NumberRate_URL,
    pathDomainRatio, pathurlRatio

Finally we can begin with our logistic regression here we will target the “class” field and run it against all other fields. We will use the train data set and not the test set. Notice we are predicting for a binary output and not continous so we also set the family argument to binomial.

full.fit <- glm(class ~ ., family = binomial, data = train1)
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred

Create a summary of the model: So that we can see the

summary(full.fit)

Call:
glm(formula = class ~ ., family = binomial, data = train1)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-3.5588  -0.2816   0.1451   0.4246   4.4548  

Coefficients:
                          Estimate Std. Error z value Pr(>|z|)    
(Intercept)              29.092755   1.899319  15.317  < 2e-16 ***
avgpathtokenlen          -0.149654   0.014215 -10.528  < 2e-16 ***
pathurlRatio            -24.594896   1.702746 -14.444  < 2e-16 ***
ArgUrlRatio             -15.972711   3.188721  -5.009 5.47e-07 ***
argDomanRatio             0.077851   0.079488   0.979  0.32738    
domainUrlRatio          -69.481573   2.453667 -28.317  < 2e-16 ***
pathDomainRatio          -0.292382   0.029244  -9.998  < 2e-16 ***
argPathRatio              6.863700   2.136408   3.213  0.00131 ** 
CharacterContinuityRate   8.487651   0.288219  29.449  < 2e-16 ***
NumberRate_URL           -3.721122   0.371732 -10.010  < 2e-16 ***
NumberRate_FileName      -0.003547   0.090242  -0.039  0.96864    
NumberRate_AfterPath      1.714502   0.182821   9.378  < 2e-16 ***
Entropy_Domain            1.132800   0.578038   1.960  0.05003 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 16803.8  on 12126  degrees of freedom
Residual deviance:  6934.8  on 12114  degrees of freedom
AIC: 6960.8

Number of Fisher Scoring iterations: 7

We can see from our statistical summary that all the features are significant within 5% level, except the argDomanRatio and entropy_domain.

You cannot translate the coefficients in logistic regression as “the change in Y is based on one-unit change in X”.

This is where the odds ratio can be quite helpful. The beta coefficients from the log function can be converted to odds ratios with an exponent (beta).

In order to produce the odds ratios in R, we will use the following exp(coef()) syntax:

exp(coef(full.fit))
            (Intercept)         avgpathtokenlen            pathurlRatio             ArgUrlRatio           argDomanRatio 
           4.313432e+12            8.610055e-01            2.082440e-11            1.156485e-07            1.080961e+00 
         domainUrlRatio         pathDomainRatio            argPathRatio CharacterContinuityRate          NumberRate_URL 
           6.676308e-31            7.464830e-01            9.569007e+02            4.854451e+03            2.420680e-02 
    NumberRate_FileName    NumberRate_AfterPath          Entropy_Domain 
           9.964590e-01            5.553906e+00            3.104336e+00 

The interpretation of an odds ratio is the change in the outcome odds resulting from a unit change in the feature. If the value is greater than 1, it indicates that, as the feature increases, the odds of the outcome increase. Conversely, a value less than 1 would mean that, as the feature increases, the odds of the outcome decrease.

Let us now run a model with the coefficients with the lowest p-values.

Testing the model

You will first have to create a vector of the predicted probabilities, as follows:

train.probs <- predict(full.fit, type = "response")
# inspect the first 5 probabilities
train.probs[1:5]
           1            2            3            4            6 
2.845787e-06 7.388572e-01 1.422444e-08 9.703884e-01 1.832720e-01 

We can see that the output comes out as a value from 0-1

Next, we need to evaluate how well the model performed in training and then evaluate how it fits on the test set. A quick way to do this is to produce a confusion matrix. The default value by which the function selects either benign or phishing is 0.50, which is to say that any probability at or above 0.50 is classified as phishing:


trainY1<-mydata1$class[ind==1] # creating the target variable (y) for the train data we split
testY1<-mydata1$class[ind==2]

Lets install and load the two necessary packages caret and informationvalue

#install.packages("caret")
#library(caret)
#install.packages("InformationValue")
library(InformationValue)

Lets see how many accuracy by running a confusion matrix. Showing our false positives and negatives against our accurate predictions. for the train data.

confusionMatrix(trainY1,train.probs)

Here we test the error probability between predictions of the target variable based off of the training data set and the actual values of the target variable.

misClassError(trainY1, train.probs)# since we dont specifiy it the threshold is set to 0.5 for the train.probs values to be 1
[1] 0.1034

Notice our train data has a low classification error of 10%

Lets do the same for our test set

test.probs <- predict(full.fit, newdata = test1, type = "response")
#misclassification error
misClassError(testY1, test.probs)
[1] 0.1095

Notice our test set has a little more error at 0.109 just 0.03 more. This ~11% is an acceptable error rate which means our model so useable.

Lets see how our test set performed in accuracy like we did with the train set in a confusion matrix.

# confusion matrix
confusionMatrix(testY1, test.probs)

Notice that there are far more accurate begnine and phishing classifications than there are false positives or false negatives.

I will attempt to graph this. After downloading the ggplot package.

install.packages("ggplot2")
Error in install.packages : Updating loaded packages
library(ggplot2)
Warning: package ‘ggplot2’ was built under R version 4.2.1
modelog <- predict.glm(full.fit, test1, type="response")
gg <- ggplot(data.frame(x=test.probs, y=ifelse(test1$class>0.5, "Benign", "Phishing")), aes(x, y)) +
  geom_point(size=3, fill="steelblue", color="black", shape=4) + 
  ylab("Known Phising URL") +
  xlab("Estimated Probability of Non-Phising URL") + theme_bw()
print(gg)

  1. Research and/or business questions to consider based on this data set would be can we predict weather a URL address is malicious and trying to perform a “Phishing” attack on you or is it Benign? Can we identify this behavior with information we receive on the URL, domain, and path? We could also ask what other regression or classification models could we try classifying this data with maybe k-Nearest neighbors, decision trees, Navies Bayes, or a Support Vector Machine. A researcher could also wonder what fields when used to train the model would give the highest significance and coefficient of determination.

  2. I was able to digest the data using the structure (str) function, summary (function), and view(function) and though I was able to revise that the data set was clean, wrangled, and ready for partitioning. Though I was able to train test the data in a logistic regression model and see it resulting coefficients, p-value, R-squared, etc. I still don’t feel like I have a better understanding for the measures. I Only feel I digested information about this specific data sets values and probability of predicting “phishing” urls, I still don’t feel I know what the fields that aren’t the target mean and how they relate to each other. Though I am very interested in understand more about web services and connections.

3.I did not identify any clear anomaly in this data set, I had inspected this data frame with a correlation heat map and didnt find any high relationships between any values that didn’t already seem related. An anomaly for me would be finding something that has any clear correspondence that isn’t parallel correlation.

LS0tDQp0aXRsZTogIkZpbmFsX1Byb2plY3RfTG9naXN0aWMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KVGhlIGlkZWEgb2YgdGhpcyBoYW5kb3V0IGlzIHRvIGRldmVsb3AgYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHRvIGRpc2N1c3MgdGhlIG9kZHMgb2YgdGhlIHByZXNlbmNlIG9mIGEgYmVuaW5nIG9yIGEgcGhpc2luZyBVUkxfdHlwZS4gSW4gdGhpcyBtaW5pIHR1dG9yaWFsIHlvdSBoYXZlIHRoZSBzdGVwcyB3ZSBuZWVkIHRvIGZvbGxvdyBpbiBvcmRlciB0byBjb21wbGV0ZSB0aGlzIGFjaXRpdml0eS4gDQoNCmBgYHtyfQ0KZ2V0d2QoKQ0KYGBgDQpGaXJzdCB3ZSBtYWtlIHN1cmUgd2UgYXJlIHdvcmtpbmcgdGhlIGNvcnJlY3Qgd29ya2luZyBkaXJlY3RvcnkuDQpUaGVuIHdlIHdpbGwgaW1wb3J0IHRoZSBjc3YuIGZpbGUgaW50byB0aGUgImZpbmFsMSIgZGF0YWZyYW1lIGJ5IHVzaW5nIHRoZSByZWFkLmNzdigpIGZ1bmN0aW9uLiANCg0KYGBge3J9DQpmaW5hbDE8LXJlYWQuY3N2KCJncm91cFZJSWNsZWFuLmNzdiIsc2VwID0gIiwiLGhlYWRlciA9IFRSVUUpDQpgYGANCg0KTm93IHdlIHdhbnQgdG8gaW5zcGVjdCB0aGUgZGF0YSBzdHJ1Y3R1cmUgb2YgdGhpcyBkYXRhZnJhbWUgd2UganVzdCBjcmVhdGVkLiANCldlIGNhbiB1c2UgdGhlIHN0cnVjdHVyZSBmdW5jdGlvbiB0byBkbyB0aGlzLiANCg0KYGBge3J9DQpzdHIoZmluYWwxKQ0KYGBgDQpOb3cgbGV0IHVzIG9taXQgYW55IG51bGwgdmFsdWVzIGZyb20gdGhlIGRhdGEgZnJhbWUNCg0KYGBge3J9DQpteWRhdGExPC1uYS5vbWl0KGZpbmFsMSkNCmBgYA0KDQpOb3cgbGV0IHVzIGdldCBhIHN0YXRpc2l0aWNhbCBzdW1tYXJ5IGZvciBlYWNoIGZpZWxkLiANCg0KYGBge3J9DQoNCnN1bW1hcnkobXlkYXRhMSkNCmBgYA0KTGV0IHVzIGFsc28gaW5zcGVjdCB0aGUgZGF0YSBzdHJ1Y3R1cmUgb2Ygb3IgbmV3IGRhdGFmcmFtZSB0aGF0IGhhcyBubyBudWxscy4gDQpOb3RpY2UgaXQgaGFzIHRoZSBzYW1lIG51bWJlciBvZiBvYnNlcnZhdGlvbnMvcmVjb3JkcyAxNTA4Nywgc28gd2UgY2FuIGFzc3VtZSB0aGVyZSB3ZXJlIG5vIG51bGxzIGluIHRoaXMgZGF0YSBzZXQuIA0KDQpgYGB7cn0NCnN0cihteWRhdGExKQ0KYGBgDQpMZXRzIGNvbnZlcnQgdGhlIGRhdGEgdHlwZSBmb3IgdGhlICJjbGFzcyIgZmllbGQgZnJvbSBjaGFyYWN0ZXIgdG8gZmFjdG9yIHNvIHRoYXQgd2UgY2FuIHBlcmZvcm0gYmluYXJ5IGNsYXNzaWZpY2F0aW9uIG9uIHRoaXMgZmllbGRzIG9ubHkgdHdvIHZhbHVlcyAiYmVuaWduIiBhbmQgInBoaXNoaW5nIi4gDQpOb3RpY2Ugd2UgdXNlIHRoZSBhcy5mYWN0b3IoKSBmdW5jdGlvbiB0byBtYWtlIHRoaXMgZGF0YSB0eXBlIGNvbnZlcnNpb24uIA0KDQpgYGB7cn0NCm15ZGF0YTEkY2xhc3M8LWFzLmZhY3RvcihteWRhdGExJGNsYXNzKQ0KYGBgDQoNCk5vdyBsZXRzIHJldmlldyBvciBkYXRhIHN0cnVjdHVyZSBvbmNlIG1vcmUgdG8gc2VlIHRoZSBjaGFuZ2VzIHdlIG1hZGUgdG8gdGhlICJjbGFzcyIgY29sdW1uLg0KDQpgYGB7cn0NCnN0cihteWRhdGExKQ0KYGBgDQpOb3RpY2UgaG93IG5vdyB0aGUgZGF0YSB0eXBlIGlzIGEgRmFjdG9yIHcvIDIgbGV2ZWxzIHJlcHJlc2VudGVkIGJ5IDIgYW5kIDEuIA0KTGV0cyBjaGFuZ2UgdGhpcyBmZWF0dXJlIG9uY2UgYWdhaW4gYnkgY29udmVydGluZyBhbGwgdGhlICJwaGlzaGluZyIgdmFsdWVzIHRvIHplcm8uDQpXZSB3aWxsIHVzZSB0aGUgaWZlbHNlIGxvb3AgdG8gYWNoaWV2ZSB0aGlzIGNvbnZlcnNpb24uDQoNCmBgYHtyfQ0KbXlkYXRhMSRjbGFzcyA8LSBpZmVsc2UobXlkYXRhMSRjbGFzcyA9PSAiYmVuaWduIiwgMSwgMCkjIHRoaXMgd2lsbCBtYWtlIGFsbCAiYmVuaWduIiB2YWx1ZXMgZXF1YWwgMSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2FuZCBhbGwgb3RoZXIgdmFsdWVzIDANCg0KYGBgDQoNClRoaXMgY2hhbmdlIHNob3VsZCBnaXZlIHVzIGEgbW9yZSB0cmFkaXRpb25hbCBiaW5hcnkgdmFsdWVzIG9mIDEgYW5kIDAuDQoNCmBgYHtyfQ0KIyBXZSBjYW4gb3BlbiB0aGUgZGF0YWZyYW1lIG9mIHRoZSBteSBkYXRhIGFuZCB2ZXJpZnkgdGhhdCBvdXIgYmluYXJ5IHZhbHVlIGhhcyBiZWVuIGNyZWF0ZWQuIA0KI1ZpZXcobXlkYXRhMSkNCmBgYA0KDQojIyBMZXRzIGdldCBzb21lIGluc2lnaHQgaW50byB0aGUgZmllbGRzIHdpdGggdGhlIERhdGEgRGljdGlvbmFyeS4NCiMjIyBXZSB3aWxsIHNlZSB0aGF0IE1hbnkgb2YgdGhlc2UgdmFyaWFsYmxlcyBhcmUgZGVwZW5kYW50IG9uIGluZGVwZW5kYW50IHZhcmlhYmxlcyBsaWtlIFVSTCBhbmQgRG9tYW5pbiB3aGljaCB3ZSBhcmUgbm90IHByb3ZpZGVkLiBUaGVzZSBxdWFudGlmaWNhdGlvbnMgdGhhdCBkZXNjcmliZSBhdmVyYWdlcyBhbmQgcmFpb3Mgb2YgZmllbGRzIHRoYXQgYXBwbHkgdG8gYSBVUkwgYWRkcmVzcyB3aWxsIGFsbG93IHVzIHRvIHBlcmZvcm0gc29tZSBzdGF0aXN0aWNhbCBhbmF5bGlzaXMgYW5kIG1vZGVsIGJ1aWxkaW5nLCB3aGljaCB3aWxsIGFsbG93IHVzIHRvIGxlYXJuIG1vcmUgYWJvdXQgdGhlIHJlbGV2YW5jZSBvZiB0aGVzZSBmaWVsZHMgdG8gb25lIGFub3RoZXIgYW5kIHRlc3QgaHlwb3RoZXNpcyB3ZSBoYXZlIG9uIHRoZSByZWxhdGlvbnNoaXAgdGhleSBoYXZlIHdpdGggdGhlIHRhcmdldCBjYXRlZ29yeSB0byBiZSBjbGFzc2lmaWVkLiANCg0KQXZncGF0aHRva2VubGVuOiBOdW1lcmljYWwtQXZlcmFnZSBsZW5ndGggb2YgcGF0aCB0b2tlbi4gVGhlIGF2Z3BhdGh0b2tlbmxlbiBjb2x1bW4gcmVmZXJlbmNlcyB0aGVzZSB0b2tlbiBwYXRocyBvciBzdHJpbmdzIGFuZCBncm91cHMgdGhlbSB0byBjYWxjdWxhdGUgaXRzIGF2ZXJhZ2UgbGVuZ3RoLg0KDQpwYXRodXJsUmF0aW86IE51bWVyaWNhbC1QYXRoIGRpdmlkZWQgYnkgVVJMLg0KDQpBcmdVcmxSYXRpbzogTnVtZXJpY2FsLVJhdGlvIG9mIGFyZ3VtZW50IGFuZCBVUkwuDQoNCmFyZ0RvbWFuUmF0aW86IE51bWVyaWNhbC1Bcmd1bWVudCBkaXZpZGVkIGJ5IGRvbWFpbi4gVGhlIGFyZ0RvbWFuUmF0aW8gaG9sZHMgdGhlIHN1bSBvZiB0aGUgYXJndW1lbnRzIGdyb3VwZWQgYnkgdGhlIHNwZWNpZmllcyBkb21haW5zLCBkaXZpZGVkIGJ5IHRoZSBhbW91bnQgb2YgdGltZXMgYSBkb21haW4gaXMgcmVxdWVzdGVkLiANCg0KZG9tYWluVXJsUmF0aW86IE51bWVyaWNhbC1Eb21haW4gZGl2aWRlZCBieSBVUkwuDQoNCnBhdGhEb21haW5SYXRpby1OdW1lcmljYWwtUGF0aDogZGl2aWRlZCBieSBEb21haW4uIFRoZSBVUkwgZGl2aWRlZCBieSB0aGUgZG9tYWluIGlzIHRoZSBkb21haW4gUGF0aCBEb21haW4gcmF0aW8uDQoNCmFyZ1BhdGhSYXRpbzogTnVtZXJpY2FsLVJhdGlvIG9mIGFyZ3VtZW50IGFuZCBwYXRoLg0KDQpDaGFyYWN0ZXJDb250aW51aXR5UmF0ZTogTnVtZXJpY2FsLUNoYXJhY3RlciBDb250aW51aXR5IFJhdGUgaXMgdXNlZCB0byBmaW5kIHRoZSBzdW0gb2YgdGhlIGxvbmdlc3QgdG9rZW4gbGVuZ3RoIG9mIGVhY2ggY2hhcmFjdGVyIHR5cGUgaW4gdGhlIGRvbWFpbiwgc3VjaCBhcyBhYmM1Njd0aSA9ICgzICsgMyArIDEpLzkgPSAwLjc3LiBNYWxpY2lvdXMgd2Vic2l0ZXMgdXNlIFVSTHMgd2hpY2ggaGF2ZSB2YXJpYWJsZSBudW1iZXIgb2YgY2hhcmFjdGVyIHR5cGVzLiBDaGFyYWN0ZXIgY29udGludWl0eSByYXRlIGRldGVybWluZSB0aGUgc2VxdWVuY2Ugb2YgbGV0dGVyLCBkaWdpdCBhbmQgc3ltYm9sIGNoYXJhY3RlcnMuIFRoZSBzdW0gb2YgbG9uZ2VzdCB0b2tlbiBsZW5ndGggb2YgYSBjaGFyYWN0ZXIgdHlwZSBpcyBkaXZpZGVkIGJ5IHRoZSBsZW5ndGggb2YgdGhlIFVSTC4NCg0KTnVtYmVyUmF0ZV9VUkw6IE51bWVyaWNhbC1OdW1iZXIgcmF0ZSBjYWxjdWxhdGUgdGhlIHByb3BvcnRpb24gb2YgZGlnaXRzIGluIHRoZSBVUkwgcGFydCBvZiBVUkwgaXRzZWxmLg0KDQpOdW1iZXJSYXRlX0ZpbGVOYW1lOiBOdW1lcmljYWwtTnVtYmVyIHJhdGUgY2FsY3VsYXRlIHRoZSBwcm9wb3J0aW9uIG9mIGRpZ2l0cyBpbiB0aGUgVVJMIHBhcnQgb2YgZmlsZW5hbWUuDQoNCk51bWJlclJhdGVfQWZ0ZXJQYXRoOiBOdW1lcmljYWwtTnVtYmVyIHJhdGUgY2FsY3VsYXRlIHRoZSBwcm9wb3J0aW9uIG9mIGRpZ2l0cyBpbiB0aGUgVVJMIHBhcnRzIG9mIHBhcnQgYWZ0ZXIgdGhlIHBhdGguDQoNCkVudHJvcHlfRG9tYWluOiBOdW1lcmljYWwtTWFsaWNpb3VzIHdlYnNpdGVzIG9mdGVuIGluc2VydCBhZGRpdGlvbmFsIGNoYXJhY3RlcnMgaW4gdGhlIFVSTCB0byBtYWtlIGl0IGxvb2sgbGlrZSBhIGxlZ2l0aW1hdGUuIGUuZywgQ0lUSSBjYW4gYmUgd3JpdHRlbiBhcyBDSVQxLCBieSByZXBsYWNpbmcgbGFzdCBhbHBoYWJldCBJIHdpdGggZGlnaXQgMS4gRW5nbGlzaCB0ZXh0IGhhcyBmYWlybHkgbG93IGVudHJvcHkgaS5lLiwgaXQgaXMgcHJlZGljdGFibGUuIEJ5IGluc2VydGluZyBjaGFyYWN0ZXJzIHRoZSBlbnRyb3B5IGNoYW5nZXMgdGhhbiB1c3VhbC4gRm9yIGlkZW50aWZ5aW5nIHRoZSByYW5kb21seSBnZW5lcmF0ZWQgbWFsaWNpb3VzIFVSTHMsIGFscGhhYmV0IGVudHJvcHkgaXMgdXNlZC4gQSBmb3JtdWxhIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBpbmZvcm1hdGlvbiBlbnRyb3B5Lg0KDQpjbGFzcy1DYXRlZ29yaWNhbDogVVJMIHR5cGVkOiBCZW5pZ24sIFNwYW0sIFBoaXNoaW5nLCBNYWx3YXJlIG9yIHRoZSBhdmdwYXRodG9rZW5sZW4gY29sdW1uIHJlZmVyZW5jZXMgdGhlc2UgdG9rZW4gcGF0aHMgb3Igc3RyaW5ncyBhbmQgZ3JvdXBzIHRoZW0gdG8gY2FsY3VsYXRlIGl0cyBhdmVyYWdlIGxlbmd0aC4NCg0KIyMjIyMgSSByZWFsaXplIHRoYXQgSSBhbSB2ZXJ5IHVuZmFtaWxpYXIgd2l0aCBuZXR3b3JraW5nIGFuZCBpbnRlcm5ldCBwcm90b2NvbCBhZnRlciByZXZpZXdpbmcgdGhlIGRlZmluaXRpb25zIG9mIGFsbCB0aGVzZSBmaWVsZHMuIFRoaXMgd2FzIHRoZSBmaXJzdCBJIGhhdmUgZXZlciBoZWFyZCBvZiBVUkwgcGF0aHMgYW5kIHN0aWxsIGFtIG5vdCBjb25maWRlbnQgd2l0aCBteSB1bmRlcnN0YW5kaW5nLjEgTHVja2lseSB3ZSBoYXZlIHN0YXRpc3RpY3MgYW5kIHJlZ3Jlc3Npb24gbW9kZWxzIHRvIGhlbHAgdXMgZmluZCB2YWx1YWJsZSBwYXR0ZXJucyBiZXR3ZWVuIHRoZXNlIHZhbHVlcyBzbyB0aGF0IHdlIGNhbiBhdHRlbXB0IHRvIGJldHRlciB1dGlsaXplIHRoZW0uIA0KDQojIyBOb3cgdGhhdCB3ZSBhcmUgZnVydGhlciBmYW1pbGlhciB3aXRoIHRoZSBkYXRhc2V0IGx1dCB1cyBpbnBzZWN0IGNvcnJlbGF0aW9uIGFuZCByZWxhdGlvbnNoaXBzIHdpdGggbWFueSB2YXJpZXRpZXMgb2YgY29ycmVsYXRpb24gbWF0cml4ZXMuDQoNCmBgYHtyfQ0KY3I8LWNvcihteWRhdGExWywtMTNdKQ0KY3INCmBgYA0KQWJvdmUgY2FuIHNlZSB3ZSBjcmVhdGVkIHRoZSBtYXRyaXggYmVsb3cgd2Ugd2lsbCB0ZXN0IGl0Lg0KDQpMZXQgdXMgaW5zdGFsbCB0aGUgcGFja2FnZXMgbmVjZXNzYXJ5IHRvIHZpZXcgaXQNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoIkNvcnJwbG90IikNCmBgYA0KDQpgYGB7cn0NCiNsaWJyYXJ5KGNvcnJwbG90KQ0KYGBgDQoNCkxldCB1cyB2aWV3IGl0IHdpdGggY29ycnBsb3QgDQoNCg0KYGBge3J9DQpjb3JycGxvdChjciwgbWV0aG9kID0gJ2VsbGlwc2UnKQ0KYGBgDQpMZXQgdXMgc2VlIGlmIHdlIGNhbiBvcmRlciBpdCBpbiB3YXkgdGhhdCB3ZSBjYW4gdW5kZXJzdGFuZCBtb3JlIGFvdXQgdGhlIGNvcmVsbGV0aW9uIG1heWJlIGJ5IHRoZSBhbmd1bGFyIG9yZGVyIG9mIHRoZSBlaWdlbnZlY3RvcnMoQU9FKSx0aGUgZmlydHN0IHByaW5jaXBhbCBjb21wb25lbnQgb3JkZXIgKEZQQyksIG9yIHRoZSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBvcmRlci4gDQoNCmBgYHtyfQ0KY29ycnBsb3QoY3IsIG9yZGVyID0gJ0FPRScpDQpgYGANCg0KDQpgYGB7cn0NCmNvcnJwbG90KGNyLCBvcmRlciA9ICdGUEMnKQ0KYGBgDQoNCg0KYGBge3J9DQpjb3JycGxvdChjciwgb3JkZXIgPSAnaGNsdXN0JykNCg0KYGBgDQoNCkkgcHJlZmVyIGhvdyB0aGUgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgb3JkZXIgcHJlc2VudHMgdGhlIGNvcnJlbGF0aW9ucy4gSSBjYW4gY2FuIGNsZWFybHkgc2VlIGFib3V0IDMgY2x1c3RlcnMgYnV0IGRvbnQga25vdyB3aGF0IHRoZSBjbHVzdGVyaW5nIGxpbmthZ2UgbWV0aG9kIGlzIGJlIGl0IGNvbXBsZXRlLCBjZW50ZXJvaWQsIGF2ZXJhZ2UsZXRjLiBJZiBJIHdhcyBnb2luZyB0byBydW4gdGhlIGRhdGEgdGhyb3VnaCBhIGstTmVhcmVzdCBOZWlnaGJvciBtb2RlbCBJIHdvdWxkIGJlbmVmaXQgZnJvbSBjbHVzdGVyIGNhdGVnb3JpemF0aW9uIGxpa2UgZGVuZXJvZ3JhbXMgd2hpY2ggSSBiZWxpdmUgdGhlIGFkZGRyZWN0IGFyZ3VtZW50IGFjaGlldmVzIHRvIHNvbWUgZGVncmVlIGJlbG93LiANCg0KYGBge3J9DQpjb3JycGxvdChjciwgbWV0aG9kID0gJ2VsbGlwc2UnLCBvcmRlciA9ICdoY2x1c3QnLCBhZGRyZWN0ID0gNCkNCmBgYA0KIyMjIyAgSSBzZWUgcGF0aHVybFJhdGlvIGFuZCBkb21haW5VcmxSYXRpbyBoYXZlIGhpZ2ggY29ycmVsYXRpb24gYXMgd2VsbCBhcyBBcmdVcmxSYXRpbyBhbmQgYXJnUGF0aFJhdGlvLiBTb21lIG9mIHRoZXNlIHZhbHVlcyBtYXkgYmUgb3Zlcmx5IGNvcnJlbGF0ZWQsIHNvIEkgd29udCBiYXNlIG15IG1vZGVsIGFmdGVyIHRoZXNlIHJlbGF0aW9uc2hpcHMgYXMgbXVjaCBhcyBJIHdpbGwgY29uc2lkZXIgdGhlbiBpbiBteSBuZXh0IHN0ZXBzIGJ1aWxkaW5nIGFuZCB0ZXN0aW5nIGEgbG9naXN0aWcgcmVncmVzaW9uIG1vZGVsLiANCg0KDQojIyBUcmFpbiBhbmQgVGVzdCBEYXRhDQoNClRoZSBwdXJwb3NlIG9mIGNyZWF0aW5nIHR3byBkaWZmZXJlbnQgZGF0YXNldHMgZnJvbSB0aGUgb3JpZ2luYWwgb25lIGlzIHRvIGltcHJvdmUgb3VyIGFiaWxpdHkgc28gYXMgdG8gYWNjdXJhdGVseSBwcmVkaWN0IHRoZSBwcmV2aW91c2x5IHVudXNlZCBvciAqKnVuc2VlbiBkYXRhKiouDQoNClRoZXJlIGFyZSBhIG51bWJlciBvZiB3YXlzIHRvIHByb3BvcnRpb25hbGx5IHNwbGl0IG91ciBkYXRhIGludG8gYHRyYWluYCBhbmQgYHRlc3RgIHNldHM6IDUwLzUwLCA2MC80MCwgNzAvMzAsIDgwLzIwLCBhbmQgc28gZm9ydGguIFRoZSBkYXRhIHNwbGl0IHRoYXQgeW91IHNlbGVjdCBzaG91bGQgYmUgYmFzZWQgb24geW91ciBleHBlcmllbmNlIGFuZCBqdWRnbWVudC4gRm9yIHRoaXMgZXhlcmNpc2UsIHdlIHdpbGwgdXNlIGEgODAvMjAgc3BsaXQsIGFzIGZvbGxvd3M6DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMjMpICAjIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIHNldCB0byB0aGUgc2VlZCBvZiAyMy4NCmluZCA8LSBzYW1wbGUoMiwgbnJvdyhteWRhdGExKSwgcmVwbGFjZSA9IFRSVUUsIHByb2IgPSBjKDAuOCwgMC4yKSkgDQpgYGANCg0KUGFydGl0aW9uaW5nIHRoZSBkYXRhOg0KDQpIZXJlIHdlIGdyYWIgdGhlIHNwbGl0IGRhdGEgaW50byBvdXIgZmlyc3QgdHJhaW4gYW5kIHRlc3QgdmFyaWFibGVzLiBOb3RpY2UgYWJvdmUgaXMgd2hlcmUgd2UgaW1wbGltZW50ZWQgdGhlIHNwbGl0DQpgYGB7cn0NCnRyYWluMSA8LSBteWRhdGExW2luZD09MSwgXSAgI3RoZSB0cmFpbmluZyBzZXQNCg0KdGVzdDEgPC0gbXlkYXRhMVtpbmQ9PTIsIF0gICAjIHRoZSB0ZXN0aW5nIHNldCANCmBgYA0KDQoNCllvdSBjYW4gY29uZmlybSB0aGUgZGltZW5zaW9ucyBvZiBib3RoIHNldHMgYXMgZm9sbG93czoNCg0KDQpgYGB7cn0NCmRpbSh0cmFpbjEpDQpkaW0odGVzdDEpDQpgYGANCkFib3ZlIHdlIGNhbiBzZWUgdGhhdCBib3RoIGZpZWxkcyBoYXZlIHRoZSBzYW1lIG51bWJlciBvZiBmZWF0dXJlcyBhbmQgdGhlIHRlc3Qgc2V0IGhhcyBhIHF1YXJ0ZXIgb2YgdGhlIHJlY29yZHMgdGhhdCB0aGUgdHJhaW4gc2V0IGRvZXMuDQoNCg0KDQpUbyBlbnN1cmUgdGhhdCB3ZSBoYXZlIGEgd2VsbC1iYWxhbmNlZCBvdXRjb21lIHZhcmlhYmxlIGJldHdlZW4gdGhlIHR3byBkYXRhc2V0cywgd2Ugd2lsbCBwZXJmb3JtIHRoZSBmb2xsb3dpbmcgY2hlY2s6DQoNCg0KYGBge3J9DQp0YWJsZSh0cmFpbjEkY2xhc3MpICMgQ3JlYXRlcyBhIHRhYmxlIHRoYXQgc2hvd3MgdGhlIGNvdW50IG9mIGVhY2ggY2xhc3MNCnRhYmxlKHRlc3QxJGNsYXNzKQ0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCB0aGUgdGhlcmUgaXMgYSBmYWlyIGJhbGFuY2UgYmV0d2VlbiBvdXIgdGFyZ2VydCBjbGFzcyBmb3IgYm90aCBvZiBvciBzZXRzLg0KDQoNClRoaXMgaXMgYW4gYWNjZXB0YWJsZSByYXRpbyBvZiBvdXIgb3V0Y29tZXMgaW4gdGhlIHR3byBkYXRhc2V0czsgd2l0aCB0aGlzLCB3ZSBjYW4gYmVnaW4gdGhlIG1vZGVsaW5nIGFuZCBldmFsdWF0aW9uLg0KDQoNCiMgTW9kZWxpbmcgYW5kIEV2YWx1YXRpb24NCg0KV2Ugd2lsbCB1c2UgdGhlIGZ1bmN0aW9uIGBnbG0oKWAgKGZyb20gYmFzZSBSKSBmb3IgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwuDQoNCkFuIFIgaW5zdGFsbGF0aW9uIGNvbWVzIHdpdGggdGhlIGBnbG0oKWAgZnVuY3Rpb24gZml0dGluZyB0aGUgKipnZW5lcmFsaXplZCBsaW5lYXIgbW9kZWxzKiosIHdoaWNoIGFyZSBhIGNsYXNzIG9mIG1vZGVscyB0aGF0IGluY2x1ZGVzIGxvZ2lzdGljIHJlZ3Jlc3Npb24uIFRoZSBjb2RlIHN5bnRheCBpcyBzaW1pbGFyIHRvIHRoZSBgbG0oKWAgZnVuY3Rpb24gdGhhdCB3ZSB1c2VkIGZvciBsaW5lYXIgcmVncmVzc2lvbi4gT25lIGRpZmZlcmVuY2UgaXMgdGhhdCB3ZSBtdXN0IHVzZSB0aGUgYGZhbWlseSA9IGJpbm9taWFsYCBhcmd1bWVudCBpbiB0aGUgZnVuY3Rpb24sIHdoaWNoIHRlbGxzIFIgdG8gcnVuIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtZXRob2QgaW5zdGVhZCBvZiB0aGUgb3RoZXIgdmVyc2lvbnMgb2YgdGhlIGdlbmVyYWxpemVkIGxpbmVhciBtb2RlbHMuIFdlIHdpbGwgc3RhcnQgYnkgY3JlYXRpbmcgYSBtb2RlbCB0aGF0IGluY2x1ZGVzIGFsbCBvZiB0aGUgZmVhdHVyZXMgb24gdGhlIHRyYWluIHNldCBhbmQgc2VlIGhvdyBpdCBwZXJmb3JtcyBvbiB0aGUgdGVzdCBzZXQ6DQoNCg0KYGBge3J9DQphdHRhY2godHJhaW4xKQ0KYGBgDQpGaW5hbGx5IHdlIGNhbiBiZWdpbiB3aXRoIG91ciBsb2dpc3RpYyByZWdyZXNzaW9uIGhlcmUgd2Ugd2lsbCB0YXJnZXQgdGhlICJjbGFzcyIgZmllbGQgYW5kIHJ1biBpdCBhZ2FpbnN0IGFsbCBvdGhlciBmaWVsZHMuIFdlIHdpbGwgdXNlIHRoZSB0cmFpbiBkYXRhIHNldCBhbmQgbm90IHRoZSB0ZXN0IHNldC4gTm90aWNlIHdlIGFyZSBwcmVkaWN0aW5nIGZvciBhIGJpbmFyeSBvdXRwdXQgYW5kIG5vdCBjb250aW5vdXMgc28gd2UgYWxzbyBzZXQgdGhlIGZhbWlseSBhcmd1bWVudCB0byBiaW5vbWlhbC4NCg0KDQpgYGB7cn0NCmZ1bGwuZml0IDwtIGdsbShjbGFzcyB+IC4sIGZhbWlseSA9IGJpbm9taWFsLCBkYXRhID0gdHJhaW4xKQ0KYGBgDQoNCkNyZWF0ZSBhIHN1bW1hcnkgb2YgdGhlIG1vZGVsOg0KU28gdGhhdCB3ZSBjYW4gc2VlIHRoZSANCmBgYHtyfQ0Kc3VtbWFyeShmdWxsLmZpdCkNCmBgYA0KV2UgY2FuIHNlZSBmcm9tIG91ciBzdGF0aXN0aWNhbCBzdW1tYXJ5IHRoYXQgYWxsIHRoZSBmZWF0dXJlcyBhcmUgc2lnbmlmaWNhbnQgd2l0aGluIDUlIGxldmVsLCBleGNlcHQgdGhlIGFyZ0RvbWFuUmF0aW8gYW5kIGVudHJvcHlfZG9tYWluLg0KDQpZb3UgY2Fubm90IHRyYW5zbGF0ZSB0aGUgY29lZmZpY2llbnRzIGluIGxvZ2lzdGljIHJlZ3Jlc3Npb24gYXMgInRoZSBjaGFuZ2UgaW4gWSBpcyBiYXNlZCBvbiBvbmUtdW5pdCBjaGFuZ2UgaW4gWCIuIA0KDQpUaGlzIGlzIHdoZXJlIHRoZSBvZGRzIHJhdGlvIGNhbiBiZSBxdWl0ZSBoZWxwZnVsLiBUaGUgYmV0YSBjb2VmZmljaWVudHMgZnJvbSB0aGUgbG9nIGZ1bmN0aW9uIGNhbiBiZSBjb252ZXJ0ZWQgdG8gb2RkcyByYXRpb3Mgd2l0aCBhbiBleHBvbmVudCAoYmV0YSkuDQoNCkluIG9yZGVyIHRvIHByb2R1Y2UgdGhlIG9kZHMgcmF0aW9zIGluIFIsIHdlIHdpbGwgdXNlIHRoZSBmb2xsb3dpbmcgYGV4cChjb2VmKCkpYCBzeW50YXg6DQoNCmBgYHtyfQ0KZXhwKGNvZWYoZnVsbC5maXQpKQ0KYGBgDQoNClRoZSBpbnRlcnByZXRhdGlvbiBvZiBhbiBvZGRzIHJhdGlvIGlzIHRoZSBjaGFuZ2UgaW4gdGhlIG91dGNvbWUgb2RkcyByZXN1bHRpbmcgZnJvbSBhIHVuaXQgY2hhbmdlIGluIHRoZSBmZWF0dXJlLiBJZiB0aGUgdmFsdWUgaXMgZ3JlYXRlciB0aGFuIDEsIGl0IGluZGljYXRlcyB0aGF0LCBhcyB0aGUgZmVhdHVyZSBpbmNyZWFzZXMsIHRoZSBvZGRzIG9mIHRoZSBvdXRjb21lIGluY3JlYXNlLiBDb252ZXJzZWx5LCBhIHZhbHVlIGxlc3MgdGhhbiAxIHdvdWxkIG1lYW4gdGhhdCwgYXMgdGhlIGZlYXR1cmUgaW5jcmVhc2VzLCB0aGUgb2RkcyBvZiB0aGUgb3V0Y29tZSBkZWNyZWFzZS4NCg0KDQpMZXQgdXMgbm93IHJ1biBhIG1vZGVsIHdpdGggdGhlIGNvZWZmaWNpZW50cyB3aXRoIHRoZSBsb3dlc3QgcC12YWx1ZXMuDQoNCg0KDQoNCiMjIFRlc3RpbmcgdGhlIG1vZGVsDQoNCllvdSB3aWxsIGZpcnN0IGhhdmUgdG8gY3JlYXRlIGEgdmVjdG9yIG9mIHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcywgYXMgZm9sbG93czoNCg0KYGBge3J9DQp0cmFpbi5wcm9icyA8LSBwcmVkaWN0KGZ1bGwuZml0LCB0eXBlID0gInJlc3BvbnNlIikNCiMgaW5zcGVjdCB0aGUgZmlyc3QgNSBwcm9iYWJpbGl0aWVzDQp0cmFpbi5wcm9ic1sxOjVdDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBvdXRwdXQgY29tZXMgb3V0IGFzIGEgdmFsdWUgZnJvbSAwLTENCg0KTmV4dCwgd2UgbmVlZCB0byBldmFsdWF0ZSBob3cgd2VsbCB0aGUgbW9kZWwgcGVyZm9ybWVkIGluIHRyYWluaW5nIGFuZCB0aGVuIGV2YWx1YXRlIGhvdyBpdCBmaXRzIG9uIHRoZSB0ZXN0IHNldC4gQSBxdWljayB3YXkgdG8gZG8gdGhpcyBpcyB0byBwcm9kdWNlIGEgY29uZnVzaW9uIG1hdHJpeC4gVGhlIGRlZmF1bHQgdmFsdWUgYnkgd2hpY2ggdGhlIGZ1bmN0aW9uIHNlbGVjdHMgZWl0aGVyIGJlbmlnbiBvciBwaGlzaGluZyBpcyAwLjUwLCB3aGljaCBpcyB0byBzYXkgdGhhdCBhbnkgcHJvYmFiaWxpdHkgYXQgb3IgYWJvdmUgMC41MCBpcyBjbGFzc2lmaWVkIGFzIHBoaXNoaW5nOg0KDQoNCmBgYHtyfQ0KDQp0cmFpblkxPC1teWRhdGExJGNsYXNzW2luZD09MV0gIyBjcmVhdGluZyB0aGUgdGFyZ2V0IHZhcmlhYmxlICh5KSBmb3IgdGhlIHRyYWluIGRhdGEgd2Ugc3BsaXQNCnRlc3RZMTwtbXlkYXRhMSRjbGFzc1tpbmQ9PTJdDQoNCmBgYA0KDQpMZXRzIGluc3RhbGwgYW5kIGxvYWQgdGhlIHR3byBuZWNlc3NhcnkgcGFja2FnZXMgIGNhcmV0IGFuZCBpbmZvcm1hdGlvbnZhbHVlDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImNhcmV0IikNCiNsaWJyYXJ5KGNhcmV0KQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJJbmZvcm1hdGlvblZhbHVlIikNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShJbmZvcm1hdGlvblZhbHVlKQ0KYGBgDQoNCkxldHMgc2VlIGhvdyBtYW55IGFjY3VyYWN5IGJ5IHJ1bm5pbmcgYSBjb25mdXNpb24gbWF0cml4LiBTaG93aW5nIG91ciBmYWxzZSBwb3NpdGl2ZXMgYW5kIG5lZ2F0aXZlcyBhZ2FpbnN0IG91ciBhY2N1cmF0ZSBwcmVkaWN0aW9ucy4gZm9yIHRoZSB0cmFpbiBkYXRhLiANCg0KYGBge3J9DQpjb25mdXNpb25NYXRyaXgodHJhaW5ZMSx0cmFpbi5wcm9icykNCmBgYA0KDQoNCg0KSGVyZSB3ZSB0ZXN0IHRoZSBlcnJvciBwcm9iYWJpbGl0eSBiZXR3ZWVuIHByZWRpY3Rpb25zIG9mIHRoZSB0YXJnZXQgdmFyaWFibGUgYmFzZWQgb2ZmIG9mIHRoZSB0cmFpbmluZyBkYXRhIHNldCBhbmQgdGhlIGFjdHVhbCB2YWx1ZXMgb2YgdGhlIHRhcmdldCB2YXJpYWJsZS4gDQoNCmBgYHtyfQ0KbWlzQ2xhc3NFcnJvcih0cmFpblkxLCB0cmFpbi5wcm9icykjIHNpbmNlIHdlIGRvbnQgc3BlY2lmaXkgaXQgdGhlIHRocmVzaG9sZCBpcyBzZXQgdG8gMC41IGZvciB0aGUgdHJhaW4ucHJvYnMgdmFsdWVzIHRvIGJlIDENCmBgYA0KTm90aWNlIG91ciB0cmFpbiBkYXRhIGhhcyBhIGxvdyBjbGFzc2lmaWNhdGlvbiBlcnJvciBvZiAxMCUNCg0KTGV0cyBkbyB0aGUgc2FtZSBmb3Igb3VyIHRlc3Qgc2V0DQoNCmBgYHtyfQ0KdGVzdC5wcm9icyA8LSBwcmVkaWN0KGZ1bGwuZml0LCBuZXdkYXRhID0gdGVzdDEsIHR5cGUgPSAicmVzcG9uc2UiKQ0KI21pc2NsYXNzaWZpY2F0aW9uIGVycm9yDQptaXNDbGFzc0Vycm9yKHRlc3RZMSwgdGVzdC5wcm9icykNCmBgYA0KTm90aWNlIG91ciB0ZXN0IHNldCBoYXMgYSBsaXR0bGUgbW9yZSBlcnJvciBhdCAwLjEwOSBqdXN0IDAuMDMgbW9yZS4gVGhpcyB+MTElIGlzIGFuIGFjY2VwdGFibGUgZXJyb3IgcmF0ZSB3aGljaCBtZWFucyBvdXIgbW9kZWwgc28gdXNlYWJsZS4gDQoNCkxldHMgc2VlIGhvdyBvdXIgdGVzdCBzZXQgcGVyZm9ybWVkIGluIGFjY3VyYWN5IGxpa2Ugd2UgZGlkIHdpdGggdGhlIHRyYWluIHNldCBpbiBhIGNvbmZ1c2lvbiBtYXRyaXguDQoNCg0KYGBge3J9DQojIGNvbmZ1c2lvbiBtYXRyaXgNCmNvbmZ1c2lvbk1hdHJpeCh0ZXN0WTEsIHRlc3QucHJvYnMpDQpgYGANCg0KTm90aWNlIHRoYXQgdGhlcmUgYXJlIGZhciBtb3JlIGFjY3VyYXRlIGJlZ25pbmUgYW5kIHBoaXNoaW5nIGNsYXNzaWZpY2F0aW9ucyB0aGFuIHRoZXJlIGFyZSBmYWxzZSBwb3NpdGl2ZXMgb3IgZmFsc2UgbmVnYXRpdmVzLiANCg0KSSB3aWxsIGF0dGVtcHQgdG8gZ3JhcGggdGhpcy4gQWZ0ZXIgZG93bmxvYWRpbmcgdGhlIGdncGxvdCBwYWNrYWdlLiANCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQojbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCmBgYHtyfQ0KbW9kZWxvZyA8LSBwcmVkaWN0LmdsbShmdWxsLmZpdCwgdGVzdDEsIHR5cGU9InJlc3BvbnNlIikNCmdnIDwtIGdncGxvdChkYXRhLmZyYW1lKHg9dGVzdC5wcm9icywgeT1pZmVsc2UodGVzdDEkY2xhc3M+MC41LCAiQmVuaWduIiwgIlBoaXNoaW5nIikpLCBhZXMoeCwgeSkpICsNCiAgZ2VvbV9wb2ludChzaXplPTMsIGZpbGw9InN0ZWVsYmx1ZSIsIGNvbG9yPSJibGFjayIsIHNoYXBlPTQpICsgDQogIHlsYWIoIktub3duIFBoaXNpbmcgVVJMIikgKw0KICB4bGFiKCJFc3RpbWF0ZWQgUHJvYmFiaWxpdHkgb2YgTm9uLVBoaXNpbmcgVVJMIikgKyB0aGVtZV9idygpDQpwcmludChnZykNCmBgYA0KDQoxLiBSZXNlYXJjaCAgYW5kL29yIGJ1c2luZXNzIHF1ZXN0aW9ucyB0byBjb25zaWRlciBiYXNlZCBvbiB0aGlzIGRhdGEgc2V0IHdvdWxkIGJlIGNhbiB3ZSBwcmVkaWN0IHdlYXRoZXIgYSBVUkwgYWRkcmVzcyBpcyBtYWxpY2lvdXMgYW5kIHRyeWluZyB0byBwZXJmb3JtIGEgIlBoaXNoaW5nIiBhdHRhY2sgb24geW91IG9yIGlzIGl0IEJlbmlnbj8gQ2FuIHdlIGlkZW50aWZ5IHRoaXMgYmVoYXZpb3Igd2l0aCBpbmZvcm1hdGlvbiB3ZSByZWNlaXZlIG9uIHRoZSBVUkwsIGRvbWFpbiwgYW5kIHBhdGg/ICBXZSBjb3VsZCBhbHNvIGFzayB3aGF0IG90aGVyIHJlZ3Jlc3Npb24gb3IgY2xhc3NpZmljYXRpb24gbW9kZWxzIGNvdWxkIHdlIHRyeSBjbGFzc2lmeWluZyB0aGlzIGRhdGEgd2l0aCBtYXliZSBrLU5lYXJlc3QgbmVpZ2hib3JzLCBkZWNpc2lvbiB0cmVlcywgTmF2aWVzIEJheWVzLCBvciBhIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmUuIEEgcmVzZWFyY2hlciBjb3VsZCBhbHNvIHdvbmRlciB3aGF0IGZpZWxkcyB3aGVuIHVzZWQgdG8gdHJhaW4gdGhlIG1vZGVsIHdvdWxkIGdpdmUgdGhlIGhpZ2hlc3Qgc2lnbmlmaWNhbmNlIGFuZCAgY29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbi4NCg0KMi4gSSB3YXMgYWJsZSB0byBkaWdlc3QgdGhlIGRhdGEgdXNpbmcgdGhlIHN0cnVjdHVyZSAoc3RyKSBmdW5jdGlvbiwgc3VtbWFyeSAoZnVuY3Rpb24pLCBhbmQgdmlldyhmdW5jdGlvbikgYW5kIHRob3VnaCBJIHdhcyBhYmxlIHRvIHJldmlzZSB0aGF0IHRoZSBkYXRhIHNldCB3YXMgY2xlYW4sIHdyYW5nbGVkLCBhbmQgcmVhZHkgZm9yIHBhcnRpdGlvbmluZy4gVGhvdWdoIEkgd2FzIGFibGUgdG8gdHJhaW4gdGVzdCB0aGUgZGF0YSBpbiBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgYW5kIHNlZSBpdCByZXN1bHRpbmcgY29lZmZpY2llbnRzLCBwLXZhbHVlLCBSLXNxdWFyZWQsIGV0Yy4gSSBzdGlsbCBkb24ndCBmZWVsIGxpa2UgSSBoYXZlIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgZm9yIHRoZSBtZWFzdXJlcy4gSSBPbmx5IGZlZWwgSSBkaWdlc3RlZCBpbmZvcm1hdGlvbiBhYm91dCB0aGlzIHNwZWNpZmljIGRhdGEgc2V0cyB2YWx1ZXMgYW5kIHByb2JhYmlsaXR5IG9mIHByZWRpY3RpbmcgInBoaXNoaW5nIiB1cmxzLCBJIHN0aWxsIGRvbid0IGZlZWwgSSBrbm93IHdoYXQgdGhlIGZpZWxkcyB0aGF0IGFyZW4ndCB0aGUgdGFyZ2V0IG1lYW4gYW5kIGhvdyB0aGV5IHJlbGF0ZSB0byBlYWNoIG90aGVyLiBUaG91Z2ggSSBhbSB2ZXJ5IGludGVyZXN0ZWQgaW4gdW5kZXJzdGFuZCBtb3JlIGFib3V0IHdlYiBzZXJ2aWNlcyBhbmQgY29ubmVjdGlvbnMuIA0KDQozLkkgZGlkIG5vdCBpZGVudGlmeSBhbnkgY2xlYXIgYW5vbWFseSBpbiB0aGlzIGRhdGEgc2V0LCBJIGhhZCBpbnNwZWN0ZWQgdGhpcyBkYXRhIGZyYW1lIHdpdGggYSBjb3JyZWxhdGlvbiBoZWF0IG1hcCBhbmQgZGlkbnQgZmluZCBhbnkgaGlnaCByZWxhdGlvbnNoaXBzIGJldHdlZW4gYW55IHZhbHVlcyB0aGF0IGRpZG4ndCBhbHJlYWR5IHNlZW0gcmVsYXRlZC4gQW4gYW5vbWFseSBmb3IgbWUgd291bGQgYmUgZmluZGluZyBzb21ldGhpbmcgdGhhdCBoYXMgYW55IGNsZWFyIGNvcnJlc3BvbmRlbmNlIHRoYXQgaXNuJ3QgcGFyYWxsZWwgY29ycmVsYXRpb24uIA0KDQo=