Preliminaries
Q1 Load the above dataset into avariable named ‘spamD’ using read.table() function. The data is comma separated and there is no header. Change the column names of the data using spamCols vector. Note: for this lab, lab5-ex.R is not given. So you have to create a new R script to do this lab.
Q2 ‘spam’ column labels whether the email is spam or not. However, this is encoded as a score (e.g 0.7). Change the values in the spam column to factors/text ‘spam’ or ‘non-spam’ using 0.5 threshold. E.g. if the earlier original dataset has 0.4 value for a record in the spam column, then the new value should be ‘non-spam’
spamCols <- c('word.freq.make', 'word.freq.address', 'word.freq.all',
'word.freq.3d', 'word.freq.our', 'word.freq.over', 'word.freq.remove',
'word.freq.internet', 'word.freq.order', 'word.freq.mail',
'word.freq.receive', 'word.freq.will', 'word.freq.people',
'word.freq.report', 'word.freq.addresses', 'word.freq.free',
'word.freq.business', 'word.freq.email', 'word.freq.you',
'word.freq.credit', 'word.freq.your', 'word.freq.font',
'word.freq.000', 'word.freq.money', 'word.freq.hp', 'word.freq.hpl',
'word.freq.george', 'word.freq.650', 'word.freq.lab',
'word.freq.labs', 'word.freq.telnet', 'word.freq.857',
'word.freq.data', 'word.freq.415', 'word.freq.85',
'word.freq.technology', 'word.freq.1999', 'word.freq.parts',
'word.freq.pm', 'word.freq.direct', 'word.freq.cs',
'word.freq.meeting', 'word.freq.original', 'word.freq.project',
'word.freq.re', 'word.freq.edu', 'word.freq.table',
'word.freq.conference', 'char.freq.semi', 'char.freq.lparen',
'char.freq.lbrack', 'char.freq.bang', 'char.freq.dollar',
'char.freq.hash', 'capital.run.length.average',
'capital.run.length.longest', 'capital.run.length.total',
'spam')
The following code uses Unform distribution to assing a number to between 0-100 to the rgroup variable.
set.seed(2350290)
spamD$rgroup <- floor(100*runif(dim(spamD)[[1]]))
Q3 Read the documentation of the set.seed() function. What is the use of the number(2350290) passed to the function. Why the seed function is used before creating the rgroup variable.
Q4 You need to split the spamD emails into two subsets:a training set (spamTrain) and a testing set (spamTest). The rgroup values less than 10 are used for testing and rest are used for training.
Now you have training and testing data for modelling. Before going into modelling, we will learn to implement functions according to evaluate a model. One way of evaluating accuracy of a classification problem (where we have labelled data of the final outcome) is to use a confusion matrix. A confusion matrix comapres the predicted values with the observed values.
Q5 Read the link(‘http://www.statmethods.net/management/userfunctions.html’) and how the functions are implemented in R. Now write a function named ‘createConfMatrix(obs,pred,threshold)’ where the ‘obs’ and ‘pred’ are vectors of equal length. threshold is a value in the range [0,1]. Within the function you should implement the following steps.
5.1 Compare the pred values with the threshold. This results in a vector of true and false values. True means we predicted the email as a spam email and false means the email is non-spam.
5.2 Now count how many rows predicted as spam are actually spam emails. This can be done by comparing the resultant vector in 5.1 with the obs vector (assume you get obs as spam/non-spam). In other words you have counted the True Positives (TP) of the confusion matrix of the data.
5.3 As you did in 5.3, count how many True Negatives, False Positives and False Negatives are in our prediction.
5.4 Returen the results a vector of c(TP,TN,FP,FN) four values
(Hint: you can perform the steps 5.1 to 5.4 in single step using table() command.)
Q6 Now apply the createConfMatrix on confdata and check whether the implmenetation is correct using validateconf.
obs<-c('spam','non-spam','non-spam','spam','non-spam','non-spam','non-spam','non-spam','non-spam','spam')
pred<-c(0.3,0.2,0.1,0.8,0.1,0.1,0.4,0.2,0.3,0.2)
threshold<-0.5
confdata<-c(obs,pred)
validateconf<-c('TP'=1,'TN'=7,'FP'=0,'FN'=2)
LS0tDQp0aXRsZTogIkNJVFMgNDAwOSBMYWIgNSAtIENob29zaW5nIGFuZCBFdmFsdWF0aW5nIE1vZGVscyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIyBHZW5lcmFsIEluc3RydWN0aW9ucw0KKiBZb3VyIGxhYnNoZWV0cyB3aWxsIGJlIHN0cnVjdHVyZWQgd2l0aCBjb21wbGVtZW50b3J5IGluZm9ybWF0aW9uLiBUaGUgbGFicyB3aWxsIGNsb3NlbHkgZm9sbG93IHRoZSBzdHJ1Y3R1cmUgb2YgIlByYWN0aWNhbCBEYXRhIFNjaWVuY2Ugd2l0aCBSIiBib29rIGJ5IE5pbmEgWnVtZWwgYW5kIEpvaG4gTW91bnQgDQoqIEZyb20gZWFjaCBsYWIgeW91IGFyZSBleHBlY3RlZCB0byBhbnN3ZXIgYWxsIHRoZSBxdWVzdGlvbnMgcHJlc2VudGVkIHdpdGggYSBxdWVzdGlvbiBudW1iZXIuIA0KDQojIyMgQWltcyBvZiB0aGUgTGFiDQpBbGwgdGhlIHByZXZpb3VzIGxhYnMgaW50cm9kdWNlIHlvdSB0byBSIGFuZCBob3cgcHJlcHJvY2Vzc2luZyBzdGFnZSBvZiBhIGRhdGEgbWluaW5nIGFwcGxpY2F0aW9uIHdvcmtzLiBJbiB0aGlzIGxhYiB5b3Ugd2lsbCBsZWFybiBhbmQgcHJhY3RpY2UgaG93IHRvIGV2YWx1YXRlIGEgbW9kZWwgZm9yIGEgZ2l2ZW4gcHJvYmxlbS4gSW4gcGFydGljdWxhcg0Kd2Ugd2lsbCBjb3ZlciB0aGUgZm9sbG93aW5nIG9iamVjdGl2ZXM6DQoNCiogV3JpdGluZyBmdW5jdGlvbnMgDQoqIFNwbGl0aW5nIGRhdGEgZnJvbSB0cmFpbmluZyBhbmQgZXZhbHVhdGluZyBtb2RlbHMNCiogRXZhbHVhdGluZyBtb2RlbCBxdWFsaXR5DQoNCg0KDQoNCiMjIyMgV2Ugd2lsbCB1c2UgdGhlIGRhdGFzZXQgYXQgKGh0dHA6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L21sL21hY2hpbmUtbGVhcm5pbmctZGF0YWJhc2VzL3NwYW1iYXNlL3NwYW1iYXNlLmRhdGEpLiANCg0KIyBQcmVsaW1pbmFyaWVzDQoqICoqUTEqKiBMb2FkIHRoZSBhYm92ZSBkYXRhc2V0IGludG8gYXZhcmlhYmxlIG5hbWVkICdzcGFtRCcgdXNpbmcgcmVhZC50YWJsZSgpIGZ1bmN0aW9uLiBUaGUgZGF0YSBpcyBjb21tYSBzZXBhcmF0ZWQgYW5kIHRoZXJlIGlzIG5vIGhlYWRlci4gQ2hhbmdlIHRoZSBjb2x1bW4gbmFtZXMgb2YgdGhlIGRhdGEgdXNpbmcgc3BhbUNvbHMgdmVjdG9yLiBOb3RlOiBmb3IgdGhpcyBsYWIsIGxhYjUtZXguUiBpcyBub3QgZ2l2ZW4uIFNvIHlvdSBoYXZlIHRvIGNyZWF0ZSBhIG5ldyBSIHNjcmlwdCB0byBkbyB0aGlzIGxhYi4NCg0KKiAqKlEyKiogJ3NwYW0nIGNvbHVtbiBsYWJlbHMgd2hldGhlciB0aGUgZW1haWwgaXMgc3BhbSBvciBub3QuIEhvd2V2ZXIsIHRoaXMgaXMgZW5jb2RlZCBhcyBhIHNjb3JlIChlLmcgMC43KS4gQ2hhbmdlIHRoZSB2YWx1ZXMgaW4gdGhlIHNwYW0gY29sdW1uIHRvIGZhY3RvcnMvdGV4dCAnc3BhbScgb3IgJ25vbi1zcGFtJyB1c2luZyAwLjUgdGhyZXNob2xkLiAgRS5nLiBpZiB0aGUgZWFybGllciBvcmlnaW5hbCBkYXRhc2V0IGhhcyAwLjQgdmFsdWUgZm9yIGEgcmVjb3JkIGluIHRoZSBzcGFtIGNvbHVtbiwgdGhlbiB0aGUgbmV3IHZhbHVlIHNob3VsZCBiZSAnbm9uLXNwYW0nDQoNCg0KDQpgYGB7cn0NCnNwYW1Db2xzIDwtIGMoJ3dvcmQuZnJlcS5tYWtlJywgJ3dvcmQuZnJlcS5hZGRyZXNzJywgJ3dvcmQuZnJlcS5hbGwnLA0KICAgJ3dvcmQuZnJlcS4zZCcsICd3b3JkLmZyZXEub3VyJywgJ3dvcmQuZnJlcS5vdmVyJywgJ3dvcmQuZnJlcS5yZW1vdmUnLA0KICAgJ3dvcmQuZnJlcS5pbnRlcm5ldCcsICd3b3JkLmZyZXEub3JkZXInLCAnd29yZC5mcmVxLm1haWwnLA0KICAgJ3dvcmQuZnJlcS5yZWNlaXZlJywgJ3dvcmQuZnJlcS53aWxsJywgJ3dvcmQuZnJlcS5wZW9wbGUnLA0KICAgJ3dvcmQuZnJlcS5yZXBvcnQnLCAnd29yZC5mcmVxLmFkZHJlc3NlcycsICd3b3JkLmZyZXEuZnJlZScsDQogICAnd29yZC5mcmVxLmJ1c2luZXNzJywgJ3dvcmQuZnJlcS5lbWFpbCcsICd3b3JkLmZyZXEueW91JywNCiAgICd3b3JkLmZyZXEuY3JlZGl0JywgJ3dvcmQuZnJlcS55b3VyJywgJ3dvcmQuZnJlcS5mb250JywNCiAgICd3b3JkLmZyZXEuMDAwJywgJ3dvcmQuZnJlcS5tb25leScsICd3b3JkLmZyZXEuaHAnLCAnd29yZC5mcmVxLmhwbCcsDQogICAnd29yZC5mcmVxLmdlb3JnZScsICd3b3JkLmZyZXEuNjUwJywgJ3dvcmQuZnJlcS5sYWInLA0KICAgJ3dvcmQuZnJlcS5sYWJzJywgJ3dvcmQuZnJlcS50ZWxuZXQnLCAnd29yZC5mcmVxLjg1NycsDQogICAnd29yZC5mcmVxLmRhdGEnLCAnd29yZC5mcmVxLjQxNScsICd3b3JkLmZyZXEuODUnLA0KICAgJ3dvcmQuZnJlcS50ZWNobm9sb2d5JywgJ3dvcmQuZnJlcS4xOTk5JywgJ3dvcmQuZnJlcS5wYXJ0cycsDQogICAnd29yZC5mcmVxLnBtJywgJ3dvcmQuZnJlcS5kaXJlY3QnLCAnd29yZC5mcmVxLmNzJywNCiAgICd3b3JkLmZyZXEubWVldGluZycsICd3b3JkLmZyZXEub3JpZ2luYWwnLCAnd29yZC5mcmVxLnByb2plY3QnLA0KICAgJ3dvcmQuZnJlcS5yZScsICd3b3JkLmZyZXEuZWR1JywgJ3dvcmQuZnJlcS50YWJsZScsDQogICAnd29yZC5mcmVxLmNvbmZlcmVuY2UnLCAnY2hhci5mcmVxLnNlbWknLCAnY2hhci5mcmVxLmxwYXJlbicsDQogICAnY2hhci5mcmVxLmxicmFjaycsICdjaGFyLmZyZXEuYmFuZycsICdjaGFyLmZyZXEuZG9sbGFyJywNCiAgICdjaGFyLmZyZXEuaGFzaCcsICdjYXBpdGFsLnJ1bi5sZW5ndGguYXZlcmFnZScsDQogICAnY2FwaXRhbC5ydW4ubGVuZ3RoLmxvbmdlc3QnLCAnY2FwaXRhbC5ydW4ubGVuZ3RoLnRvdGFsJywNCiAgICdzcGFtJykNCg0KYGBgDQoNClRoZSBmb2xsb3dpbmcgY29kZSB1c2VzIFVuZm9ybSBkaXN0cmlidXRpb24gdG8gYXNzaW5nIGEgbnVtYmVyIHRvIGJldHdlZW4gMC0xMDAgdG8gdGhlIHJncm91cCB2YXJpYWJsZS4gDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMjM1MDI5MCkNCnNwYW1EJHJncm91cCA8LSBmbG9vcigxMDAqcnVuaWYoZGltKHNwYW1EKVtbMV1dKSkNCg0KYGBgDQoNCg0KDQoqICoqUTMqKiBSZWFkIHRoZSBkb2N1bWVudGF0aW9uIG9mIHRoZSBzZXQuc2VlZCgpIGZ1bmN0aW9uLiBXaGF0IGlzIHRoZSB1c2Ugb2YgdGhlIG51bWJlcigyMzUwMjkwKSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLiBXaHkgdGhlIHNlZWQgZnVuY3Rpb24gaXMgdXNlZCBiZWZvcmUgY3JlYXRpbmcgdGhlIHJncm91cCB2YXJpYWJsZS4NCg0KKiAqKlE0KiogWW91IG5lZWQgdG8gc3BsaXQgdGhlIHNwYW1EIGVtYWlscyBpbnRvIHR3byBzdWJzZXRzOmEgdHJhaW5pbmcgc2V0IChzcGFtVHJhaW4pIGFuZCBhIHRlc3Rpbmcgc2V0IChzcGFtVGVzdCkuIFRoZSByZ3JvdXAgdmFsdWVzIGxlc3MgdGhhbiAxMCBhcmUgdXNlZCBmb3IgdGVzdGluZyBhbmQgcmVzdCBhcmUgdXNlZCBmb3IgdHJhaW5pbmcuIA0KDQpOb3cgeW91IGhhdmUgdHJhaW5pbmcgYW5kIHRlc3RpbmcgZGF0YSBmb3IgbW9kZWxsaW5nLiBCZWZvcmUgZ29pbmcgaW50byBtb2RlbGxpbmcsIHdlIHdpbGwgbGVhcm4gdG8gaW1wbGVtZW50IGZ1bmN0aW9ucyBhY2NvcmRpbmcgdG8gZXZhbHVhdGUgYSBtb2RlbC4gT25lIHdheSBvZiBldmFsdWF0aW5nIGFjY3VyYWN5IG9mIGEgY2xhc3NpZmljYXRpb24gcHJvYmxlbSAod2hlcmUgd2UgaGF2ZSBsYWJlbGxlZCBkYXRhIG9mIHRoZSBmaW5hbCBvdXRjb21lKSBpcyB0byB1c2UgYSBjb25mdXNpb24gbWF0cml4LiBBIGNvbmZ1c2lvbiBtYXRyaXggY29tYXByZXMgdGhlIHByZWRpY3RlZCB2YWx1ZXMgd2l0aCB0aGUgb2JzZXJ2ZWQgdmFsdWVzLiAgDQoNCiogKipRNSoqIFJlYWQgdGhlIGxpbmsoJ2h0dHA6Ly93d3cuc3RhdG1ldGhvZHMubmV0L21hbmFnZW1lbnQvdXNlcmZ1bmN0aW9ucy5odG1sJykgYW5kIGhvdyB0aGUgZnVuY3Rpb25zIGFyZSBpbXBsZW1lbnRlZCBpbiBSLiBOb3cgd3JpdGUgYSBmdW5jdGlvbiBuYW1lZCAnY3JlYXRlQ29uZk1hdHJpeChvYnMscHJlZCx0aHJlc2hvbGQpJyB3aGVyZSB0aGUgJ29icycgYW5kICdwcmVkJyBhcmUgdmVjdG9ycyBvZiBlcXVhbCBsZW5ndGguIHRocmVzaG9sZCBpcyBhIHZhbHVlIGluIHRoZSByYW5nZSBbMCwxXS4gV2l0aGluIHRoZSBmdW5jdGlvbiB5b3Ugc2hvdWxkIGltcGxlbWVudCB0aGUgZm9sbG93aW5nIHN0ZXBzLg0KDQogICAgNS4xIENvbXBhcmUgdGhlIHByZWQgdmFsdWVzIHdpdGggdGhlIHRocmVzaG9sZC4gVGhpcyByZXN1bHRzIGluIGEgdmVjdG9yIG9mIHRydWUgYW5kIGZhbHNlIHZhbHVlcy4gIFRydWUgbWVhbnMgd2UgcHJlZGljdGVkIHRoZSBlbWFpbCBhcyBhIHNwYW0gZW1haWwgYW5kIGZhbHNlIG1lYW5zIHRoZSBlbWFpbCBpcyBub24tc3BhbS4NCiAgICANCiAgICA1LjIgTm93IGNvdW50IGhvdyBtYW55IHJvd3MgcHJlZGljdGVkIGFzIHNwYW0gYXJlIGFjdHVhbGx5IHNwYW0gZW1haWxzLiBUaGlzIGNhbiBiZSBkb25lIGJ5IGNvbXBhcmluZyB0aGUgcmVzdWx0YW50IHZlY3RvciBpbiA1LjEgd2l0aCB0aGUgb2JzIHZlY3RvciAoYXNzdW1lIHlvdSBnZXQgb2JzIGFzIHNwYW0vbm9uLXNwYW0pLiBJbiBvdGhlciB3b3JkcyB5b3UgaGF2ZSBjb3VudGVkIHRoZSBUcnVlIFBvc2l0aXZlcyAoVFApIG9mIHRoZSBjb25mdXNpb24gbWF0cml4IG9mIHRoZSBkYXRhLg0KICAgIA0KICAgIDUuMyBBcyB5b3UgZGlkIGluIDUuMywgY291bnQgaG93IG1hbnkgVHJ1ZSBOZWdhdGl2ZXMsIEZhbHNlIFBvc2l0aXZlcyBhbmQgRmFsc2UgTmVnYXRpdmVzIGFyZSBpbiBvdXIgcHJlZGljdGlvbi4gDQogICAgDQogICAgNS40IFJldHVyZW4gdGhlIHJlc3VsdHMgYSB2ZWN0b3Igb2YgYyhUUCxUTixGUCxGTikgZm91ciB2YWx1ZXMNCiAgICANCiAgICAoSGludDogeW91IGNhbiBwZXJmb3JtIHRoZSBzdGVwcyA1LjEgdG8gNS40IGluIHNpbmdsZSBzdGVwIHVzaW5nIHRhYmxlKCkgY29tbWFuZC4pDQogICAgDQogICAgDQoqICoqUTYqKiBOb3cgYXBwbHkgdGhlIGNyZWF0ZUNvbmZNYXRyaXggb24gY29uZmRhdGEgYW5kIGNoZWNrIHdoZXRoZXIgdGhlIGltcGxtZW5ldGF0aW9uIGlzIGNvcnJlY3QgdXNpbmcgdmFsaWRhdGVjb25mLg0KYGBge3J9DQpvYnM8LWMoJ3NwYW0nLCdub24tc3BhbScsJ25vbi1zcGFtJywnc3BhbScsJ25vbi1zcGFtJywnbm9uLXNwYW0nLCdub24tc3BhbScsJ25vbi1zcGFtJywnbm9uLXNwYW0nLCdzcGFtJykNCnByZWQ8LWMoMC4zLDAuMiwwLjEsMC44LDAuMSwwLjEsMC40LDAuMiwwLjMsMC4yKQ0KdGhyZXNob2xkPC0wLjUNCmNvbmZkYXRhPC1jKG9icyxwcmVkKQ0KdmFsaWRhdGVjb25mPC1jKCdUUCc9MSwnVE4nPTcsJ0ZQJz0wLCdGTic9MikNCmBgYA0KDQoNCg0KDQojIE1hcHBpbmcgYnVzaW5lc3MgcHJvYmxlbSB0byBtYWNoaW5lIGxlYXJuaW5nIHRhc2tzDQoqICoqUTcqKiBDcmVhdGUgYSBzcGFtIGNsYXNzaWZpY2F0aW9uIG1vZGVsIGNhbGxlZCAnc3BhbU1vZGVsJyB1c2luZyB0aGUgdHJhaW5kaW5nIGRhdGEgKHNwYW1UcmFpbikuIFRvIGRvIHRoaXMNCg0KICAgIDcuMSBTZXBhcmF0ZSBhbGwgdGhlIHZhcmlhYmxlcyAoY29sdW1ucyBvZiBzcGFtRCkgZXhjZXB0IHNwYW0gYW5kIHJncm91cC4gSGludDogVXNlIHRoZSBzZXRkaWZmIG1ldGhvZC4gU2F2ZSB0aGUgc2VsZWN0ZWQgZGF0YSBhcyBzcGFtVmFycy4NCiAgICAgICAgDQogICAgNy4yIFVzZSBnZW5lcmFsaXNlZCBsaW5lYXIgbW9kZWwgKGdsbSgpKSB0byBjcmVhdGUgYSBtb2RlbCAobmFtZSBpdCBzcGFtTW9kZWwgKSBmcm9tIHRoZSBzcGFtVmFycy4gZ2xtKCkgbmVlZHMgYSBmb3JtdWxhIHRvIHNwZWNpZnkgdGhlIHZhcmlhYmxlcyBhbmQgdGhlIGxpbmtpbmcgZnVuY3Rpb24uIA0KICAgICAgICAgICAgDQogICAgICAgIDcuMi4xIFVzZSBhcy5Gb3JtdWxhKCkgdG8gc3BlY2lmeSB0aGUgdmFyaWFibGVzIChzcGFtVmFycykuDQogICAgICAgICAgICANCiAgICAgICAgNy4yLjIgVXNlIHRoZSBmYW1pbHkvbGlua2luZyBmdW5jdGlvbiBhcyBiaW5vbWlhbChsaW5raW5nPSdsb2dpdCcpLiANCiAgICAgICAgICAgIA0KICAgIDcuMyBBcHBseSB0aGUgc3BhbU1vZGVsIG9uIHRoZSBzcGFtVHJhaW4gdG8gZ2V0IHByZWRpY3Rpb25zIG9uIHRoZSB0cmFpbmluZyBkYXRhLiBZb3UgY2FuIHVzZSBwcmVkaWN0KCkgZnVuY3Rpb24uIFNhdmUgdGhlIHJlc3VsdHMgdG8gc3BhbVRyYWluJHByZWQNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoqICoqUTgqKiBBcHBseSB0aGUgc3BhbU1vZGVsIG9uIHRoZSB0ZXN0aW5nIGRhdGEgKHNwYW1UZXN0KSBhcyB5b3UgZGlkIGluIDcuMy4gDQoNCiAgICAgICAgDQoNCiMgNS4yIEV2YWx1YXRpbmcgbW9kZWxzDQoNCg0KKiAqKlE5KiogQ2FsY3VsYXRlIHRoZSBjb25mdXNpb24gbWF0cml4IG9mIHRoZSB0ZXN0IGRhdGEgdXNpbmcgY3JlYXRlQ29uZk1hdHJpeCgpIGZ1bmN0aW9uIHlvdSBpbXBsZW1lbnRlZCBpbiBRNi4NCg0KSXQgd291bCBiZSBlYXNpZXIgdG8gaW50ZXJwcmV0ZSB0aGUgcmVzdWx0cyBpZiB3ZSBrbm93IGhvdyBtYW55IGVtYWlscyBjbGFzc2lmaWVkIGFzIHNwYW0gYXJlIGFjdHVhbGx5IHNwYW0gb3V0IHRoZSBhbGwgc3BhbSBsYWJlbHMuIFN1Y2ggZXZhbHVhdGlvbiBtZXNzdXJlcyBnaXZlIG1vcmUgaW5zaWdodCBhYm91dCB0aGUgbW9kZWwuIFJlYWQgdGhpcyB3aWtpIChodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QcmVjaXNpb25fYW5kX3JlY2FsbCkgYWJvdXQgcHJlY2lzaW9uLCByZWNhbGwgYW5kIGFjY3VyYWN5Lg0KDQoqICoqUTEwKiogSW1wbGVtZW50IGZ1bmN0aW9ucyB0aGF0IGNhbGN1bGF0ZSBhY2N1cmFjeSxwcmVjaXNpb24gYW5kIHJlY2FsbC4gWW91IGNhbiB1c2UgdGhlIHNhbWUgcGFyYW1ldGVyICdvYnMnLCdwcmVkJyBhbmQgJ3RocmVzaG9sZCcgYXMgaW5wdXQgcGFyYW1ldGVycyBmb3IgdGhlc2UgZnVuY3Rpb25zLiANCg0KKiAqKlExMSoqIENhbGN1bGF0ZSBhY2N1cmFjeSxwcmVjaXNpb24gYW5kIHJlY2FsbCBvZiB0aGUgcHJlZGljdGlvbnMgb2YgdGhlIHNwYW1UZXN0IGRhdGEgdXNpbmcgdGhlIGZ1bmN0aW9ucyB5b3UgaW1wbGVtZW50IGluIFExMC4gSW50ZXJwcmV0IGVhY2ggcmVzdWx0IGluIHRlcm1zIG9mIHRoZSANCg0KDQoNCkFsdGhvdWdoIGxhYmVsbGluZyBtb2RlbCAoZS5nbCAnc3BhbScgb3IgJ25vbi1zcGFtJykgY2FuIGJlIGV2YWx1YXRlZCB1c2luZyBhY2N1cmFjeSBtZWFzdXJlcywgdGhlIG1vZGVscyB0aGF0IHByb3ZpZGUgYSBzY29yZSBjYW4gbm90IGJlIGp1c3QgY291bnQgYW5kIGNhbGN1bGF0ZSB0aGUgY29uZnVzaW9uIG1hdHJpeC4gSGVuY2Ugd2UgbmVlZCBvdGhlciBtZWFzdXJlcyBzdWNoIGFzIHJvb3QtbWVhbi1zcXVhcmUtZXJyb3Igb3IgYWJzb2x1dGUgZXJyb3IuDQoNCkN1bHN0ZXJpbmcgbW9kZWxzIGRvIG5vdCB1c2UgbGFiZWxsZWQgZGF0YS4gSW5zdGVhZCwgb2Z0ZW4gdGhleSB1c2Ugc29tZSBkaXN0YW5jZSBpbmZvcm1hdGlvbiBmb3IgdGhlIGNhbGN1bGF0aW9ucy4NCg0KKiAqKlExMioqIENyZWF0ZSBhIDEwMCoyIG1hdHJpeCAoZCkgd2hlcmUgZWFjaCBjb2x1bW4gaXMgY3JlYXRlZCBmcm9tIGEgdW5pZm9ybSBkaXN0cmlidXRpb24uIE5vdGU6IHlvdSBzaG91bGQgYmUgYWJsZSB0byByZXByb2R1Y2UgZCBleGFjdGx5IHRoZSBzYW1lIGVhY2ggdGltZSB5b3UgcnVuIHRoZSBwcm9ncmFtLg0KDQoqICoqUTEzKiogQ2x1c3RlciB0aGUgbWF0cml4IGQgdXNpbmcgay1tZWFucyBhbGdvcml0aG0uIChVc2Uga21lYW5zKCkgZnVuY3Rpb24pLiBZb3UgY2FuIHNwZWNpZnkgdGhlIG51bWJlciBvZiBjZW50cmVzIGFzIDUuIFNhdmUgdGhlIHJlc3VsdHMgKHh4XCRjbHVzdGVyKSB0byBkJGNsdXMuDQoNCiogKipRMTQqKiBWaXN1YWxpc2UgdGhlIGNsdXN0ZXJpbmcgcmVzdWx0cyBhbmQgc2VlIGhvdyB0aGUgY3Vsc3RlcnMgYXJlIHNlcGFyYXRlZCBhbmQgaG93IHRoZWlyIHNpemVzIHZhcnkuIA0KDQoqICoqUTE1KiogQ2FsY3VsYXRlIHRoZSBkaXN0YW5jZXMgYmV0d2VlbiBldmVyeSBwYWlyIG9mIGNlbnRyZXMgb2YgZC4NCg0KDQoNCg0KDQoNCg0KDQoNCg0K