This is a Frantz
Moudoute Notebook. The following document will provide an overlook
of a few ML techniques used in R between 2014 and 2022.
Introduction to vectors
Among the key concept in R are the way R manages data. Data are
stored as vectors, each vector contains elements. Watch out, because all
element must be of the same type in R. there can be integer, double,
character, logical (Boolean) among others.
Let create some vector with a few elements below, first a vector of
strings.
my_favorite_cities <- c("Hong Kong", "Tokyo", "Paris", "Douala")
print(my_favorite_cities)
Then a vector of doubles
their_temperatures <- c(25.3, 21.0,15.0,35.0)
print(their_temperatures)
And last a vector of booleans
mega_cities <- c(FALSE, TRUE, FALSE, FALSE) # You can see that TRUE/FALSE are all in capital letters
print(mega_cities)
In R, as one would expect, values stored in a vector will preserve
their order, so we can call each value using its position, let call the
second city and the second temperature. Lets play a bit with the data
and print as well the second to the fourth cities.
print(my_favorite_cities[2])
print(their_temperatures[2])
print(my_favorite_cities[2:4])
We can manipulate vectors as it pleases us, say for example we want
to remove the first element of the cities (You notice that we are not
using the ‘<-’ sign to update the value of the vector.
print(my_favorite_cities[-1])
Introduction to Factors
Factors are a data structure in R that is ideal for representing
nominal data (Nominal data is data that can be labelled or classified
into mutually exclusive categories within a variable). One could use a
vector of strings to stor nominal data, but we will see in a few steps
some of the advantages of R’s factors data structure. Factors are a
special type of vector.
Basic factors
cities_weather <- factor(c("Tempered", "Cold", "Cold","Warm"))
print(cities_weather)
We can notice in the print command here above that there is a mention
of levels. Levels provide us with the unique categories comprises in
this factor vector.
Advanced factors - setting levels
We can modify factors to ready them for additional values. One way to
do it is to set the levels manually.
cities_weather <- factor(c("Tempered", "Cold", "Cold","Warm"), levels = c("Tempered", "Cold","Warm", "Extremely Warm"))
print(cities_weather)
Advanced factors - setting levels and ordering them
On top of manually setting up levels we can also order them, see
below
cities_weather <- factor(c("Tempered", "Cold", "Cold","Warm"), levels = c("Cold","Tempered", "Warm", "Extremely Warm"), ordered = TRUE)
print(cities_weather)
Comparing factor value
One of the key advantage of the factors is that we can compare the
value or the elements, something we could not do if we had used a vector
of string instead. IN the following example, we will check which of the
cities_weather value is not that cold
cities_weather > "Tempered"
print(cities_weather)
As seen above, the R factors enables for a comparison of nominal or
string like elements.
Introduction to lists
List in R are pretty similar to vectors, except that they accept all
sort of data type. cities_memories <-
cities_memories <- list("Sighseeing", TRUE, 2323, FALSE)
print(cities_memories)
The other interesting point about lists is that we can assign a name
to each of the element. let’s try:
cities_list <- list(activity = "Sighseeing", parking_free = TRUE, postcode = 2323, free_wifi = FALSE)
print(cities_list)
With the name of the items in the list assigned, we can now call the
items as follows:
cities_list$activity
Meanwhile the list carries some similar functions to the Vector. we
can call elements by their position. See the example below we call the
second element of the list:
cities_list[2]
Introduction to Dataframe
Dataframe are at the very center of the R programming framework. They
can be compared to a spreadsheet from a visual angle, or to a database
for the most advanced of you. A dataframe is nothing else than a
combination of vectors, of the same length. Lets create a dataframe by
combining some of the fectors that we created earlier.
destination_df <- data.frame(my_favorite_cities , their_temperatures ,mega_cities , cities_weather )
print(destination_df)
Now that we have introduced the dataframe, we might want to verify
that each of the columns contains the type of value that we expected.
The str function is quite handy for that.
print(str(destination_df))
Our data have been integrated into the new vector as we expected.
Introduction to matrices
In R, matrices are an object used to store data in a tabular shape.
Usually they are of a single data type, as one would mostly used them
for calculus. Remember as c() created vectors, list() creates list and
data.frame() creates dataframe? for matrices we can simply use matrix()
to create a matrix. Careful with the trick here, we need to specify the
number of columns or rows. Lets do a few examples.
mat_a <- matrix(c(4,5,8,7,5,4,11,21,3), nrow=3)
print(mat_a)
As one can see, the matrix contains a vector, of which the lengh
should be greater to than the square value of the number of rows or
columns instructed. Let review the same matrix but with a ncol this
time, and see what happens.
mat_b <- matrix(c(4,5,8,7,5,4,11,21,3), ncol=2)
print(mat_b)
We got a warning that indicates that the data length is
inconsistent.
LS0tDQp0aXRsZTogIlIsIGZyb20gWmVybyB0byBIZXJvOiBJbnRyb2R1Y3Rpb24iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGEgW0ZyYW50eiBNb3Vkb3V0ZV0oaW5zdGFsbC5wYWNrYWdlcygnUldla2EnKSkgTm90ZWJvb2suIFRoZSBmb2xsb3dpbmcgZG9jdW1lbnQgd2lsbCBwcm92aWRlIGFuIG92ZXJsb29rIG9mIGEgZmV3IE1MIHRlY2huaXF1ZXMgdXNlZCBpbiBSIGJldHdlZW4gMjAxNCBhbmQgMjAyMi4NCg0KIyBJbnRyb2R1Y3Rpb24gdG8gdmVjdG9ycw0KDQpBbW9uZyB0aGUga2V5IGNvbmNlcHQgaW4gUiBhcmUgdGhlIHdheSBSIG1hbmFnZXMgZGF0YS4gRGF0YSBhcmUgc3RvcmVkIGFzIHZlY3RvcnMsIGVhY2ggdmVjdG9yIGNvbnRhaW5zIGVsZW1lbnRzLiBXYXRjaCBvdXQsIGJlY2F1c2UgYWxsIGVsZW1lbnQgbXVzdCBiZSBvZiB0aGUgc2FtZSB0eXBlIGluIFIuIHRoZXJlIGNhbiBiZSBpbnRlZ2VyLCBkb3VibGUsIGNoYXJhY3RlciwgbG9naWNhbCAoQm9vbGVhbikgYW1vbmcgb3RoZXJzLg0KDQpMZXQgY3JlYXRlIHNvbWUgdmVjdG9yIHdpdGggYSBmZXcgZWxlbWVudHMgYmVsb3csIGZpcnN0IGEgdmVjdG9yIG9mIHN0cmluZ3MuDQoNCmBgYHtyfQ0KbXlfZmF2b3JpdGVfY2l0aWVzIDwtIGMoIkhvbmcgS29uZyIsICJUb2t5byIsICJQYXJpcyIsICJEb3VhbGEiKQ0KcHJpbnQobXlfZmF2b3JpdGVfY2l0aWVzKQ0KYGBgDQoNClRoZW4gYSB2ZWN0b3Igb2YgZG91Ymxlcw0KDQpgYGB7cn0NCnRoZWlyX3RlbXBlcmF0dXJlcyA8LSBjKDI1LjMsIDIxLjAsMTUuMCwzNS4wKQ0KcHJpbnQodGhlaXJfdGVtcGVyYXR1cmVzKQ0KYGBgDQoNCkFuZCBsYXN0IGEgdmVjdG9yIG9mIGJvb2xlYW5zDQoNCmBgYHtyfQ0KbWVnYV9jaXRpZXMgPC0gYyhGQUxTRSwgVFJVRSwgRkFMU0UsIEZBTFNFKSAgIyBZb3UgY2FuIHNlZSB0aGF0IFRSVUUvRkFMU0UgYXJlIGFsbCBpbiBjYXBpdGFsIGxldHRlcnMgDQpwcmludChtZWdhX2NpdGllcykNCmBgYA0KDQpJbiBSLCBhcyBvbmUgd291bGQgZXhwZWN0LCB2YWx1ZXMgc3RvcmVkIGluIGEgdmVjdG9yIHdpbGwgcHJlc2VydmUgdGhlaXIgb3JkZXIsIHNvIHdlIGNhbiBjYWxsIGVhY2ggdmFsdWUgdXNpbmcgaXRzIHBvc2l0aW9uLCBsZXQgY2FsbCB0aGUgc2Vjb25kIGNpdHkgYW5kIHRoZSBzZWNvbmQgdGVtcGVyYXR1cmUuIExldHMgcGxheSBhIGJpdCB3aXRoIHRoZSBkYXRhIGFuZCBwcmludCBhcyB3ZWxsIHRoZSBzZWNvbmQgdG8gdGhlIGZvdXJ0aCBjaXRpZXMuDQoNCmBgYHtyfQ0KcHJpbnQobXlfZmF2b3JpdGVfY2l0aWVzWzJdKQ0KDQpwcmludCh0aGVpcl90ZW1wZXJhdHVyZXNbMl0pDQoNCnByaW50KG15X2Zhdm9yaXRlX2NpdGllc1syOjRdKQ0KYGBgDQoNCldlIGNhbiBtYW5pcHVsYXRlIHZlY3RvcnMgYXMgaXQgcGxlYXNlcyB1cywgc2F5IGZvciBleGFtcGxlIHdlIHdhbnQgdG8gcmVtb3ZlIHRoZSBmaXJzdCBlbGVtZW50IG9mICB0aGUgY2l0aWVzIChZb3Ugbm90aWNlIHRoYXQgIHdlIGFyZSBub3QgdXNpbmcgdGhlICc8LScgc2lnbiB0byB1cGRhdGUgdGhlIHZhbHVlIG9mIHRoZSB2ZWN0b3IuDQoNCmBgYHtyfQ0KcHJpbnQobXlfZmF2b3JpdGVfY2l0aWVzWy0xXSkNCmBgYA0KDQojIEludHJvZHVjdGlvbiB0byBGYWN0b3JzDQpGYWN0b3JzIGFyZSBhIGRhdGEgc3RydWN0dXJlIGluIFIgdGhhdCBpcyBpZGVhbCBmb3IgcmVwcmVzZW50aW5nIG5vbWluYWwgZGF0YSAoTm9taW5hbCBkYXRhIGlzIGRhdGEgdGhhdCBjYW4gYmUgbGFiZWxsZWQgb3IgY2xhc3NpZmllZCBpbnRvIG11dHVhbGx5IGV4Y2x1c2l2ZSBjYXRlZ29yaWVzIHdpdGhpbiBhIHZhcmlhYmxlKS4gT25lIGNvdWxkIHVzZSBhIHZlY3RvciBvZiBzdHJpbmdzIHRvIHN0b3Igbm9taW5hbCBkYXRhLCBidXQgd2Ugd2lsbCBzZWUgaW4gYSBmZXcgc3RlcHMgc29tZSBvZiB0aGUgYWR2YW50YWdlcyBvZiBSJ3MgZmFjdG9ycyBkYXRhIHN0cnVjdHVyZS4gRmFjdG9ycyBhcmUgYSBzcGVjaWFsIHR5cGUgb2YgdmVjdG9yLg0KDQojIyBCYXNpYyBmYWN0b3JzDQpgYGB7cn0NCmNpdGllc193ZWF0aGVyIDwtIGZhY3RvcihjKCJUZW1wZXJlZCIsICJDb2xkIiwgIkNvbGQiLCJXYXJtIikpDQpwcmludChjaXRpZXNfd2VhdGhlcikNCmBgYA0KV2UgY2FuIG5vdGljZSBpbiB0aGUgcHJpbnQgY29tbWFuZCBoZXJlIGFib3ZlIHRoYXQgdGhlcmUgaXMgYSBtZW50aW9uIG9mIGxldmVscy4gTGV2ZWxzIHByb3ZpZGUgdXMgd2l0aCB0aGUgdW5pcXVlIGNhdGVnb3JpZXMgY29tcHJpc2VzIGluIHRoaXMgZmFjdG9yIHZlY3Rvci4NCg0KIyMgQWR2YW5jZWQgZmFjdG9ycyAtIHNldHRpbmcgbGV2ZWxzDQpXZSBjYW4gbW9kaWZ5IGZhY3RvcnMgdG8gcmVhZHkgdGhlbSBmb3IgYWRkaXRpb25hbCB2YWx1ZXMuIE9uZSB3YXkgdG8gZG8gaXQgaXMgdG8gc2V0IHRoZSBsZXZlbHMgbWFudWFsbHkuDQpgYGB7cn0NCmNpdGllc193ZWF0aGVyIDwtIGZhY3RvcihjKCJUZW1wZXJlZCIsICJDb2xkIiwgIkNvbGQiLCJXYXJtIiksIGxldmVscyA9IGMoIlRlbXBlcmVkIiwgIkNvbGQiLCJXYXJtIiwgIkV4dHJlbWVseSBXYXJtIikpDQpwcmludChjaXRpZXNfd2VhdGhlcikNCmBgYA0KDQojIyBBZHZhbmNlZCBmYWN0b3JzIC0gc2V0dGluZyBsZXZlbHMgYW5kIG9yZGVyaW5nIHRoZW0NCk9uIHRvcCBvZiBtYW51YWxseSBzZXR0aW5nIHVwIGxldmVscyB3ZSBjYW4gYWxzbyBvcmRlciB0aGVtLCBzZWUgYmVsb3cNCmBgYHtyfQ0KY2l0aWVzX3dlYXRoZXIgPC0gZmFjdG9yKGMoIlRlbXBlcmVkIiwgIkNvbGQiLCAiQ29sZCIsIldhcm0iKSwgbGV2ZWxzID0gYygiQ29sZCIsIlRlbXBlcmVkIiwgIldhcm0iLCAiRXh0cmVtZWx5IFdhcm0iKSwgb3JkZXJlZCA9IFRSVUUpDQpwcmludChjaXRpZXNfd2VhdGhlcikNCmBgYA0KIyMjIENvbXBhcmluZyBmYWN0b3IgdmFsdWUNCk9uZSBvZiB0aGUga2V5IGFkdmFudGFnZSBvZiB0aGUgZmFjdG9ycyBpcyB0aGF0IHdlIGNhbiBjb21wYXJlIHRoZSB2YWx1ZSBvciB0aGUgZWxlbWVudHMsIHNvbWV0aGluZyB3ZSBjb3VsZCBub3QgZG8gaWYgd2UgaGFkIHVzZWQgYSB2ZWN0b3Igb2Ygc3RyaW5nIGluc3RlYWQuIA0KSU4gdGhlIGZvbGxvd2luZyBleGFtcGxlLCB3ZSB3aWxsIGNoZWNrIHdoaWNoIG9mIHRoZSBjaXRpZXNfd2VhdGhlciB2YWx1ZSBpcyBub3QgdGhhdCBjb2xkDQpgYGB7cn0NCmNpdGllc193ZWF0aGVyID4gIlRlbXBlcmVkIg0KcHJpbnQoY2l0aWVzX3dlYXRoZXIpDQpgYGANCkFzIHNlZW4gYWJvdmUsIHRoZSBSIGZhY3RvcnMgZW5hYmxlcyBmb3IgYSBjb21wYXJpc29uIG9mIG5vbWluYWwgb3Igc3RyaW5nIGxpa2UgZWxlbWVudHMuDQoNCiMgSW50cm9kdWN0aW9uIHRvIGxpc3RzDQpMaXN0IGluIFIgYXJlIHByZXR0eSBzaW1pbGFyIHRvIHZlY3RvcnMsIGV4Y2VwdCB0aGF0IHRoZXkgYWNjZXB0IGFsbCBzb3J0IG9mIGRhdGEgdHlwZS4gDQpjaXRpZXNfbWVtb3JpZXMgPC0gDQpgYGB7cn0NCmNpdGllc19tZW1vcmllcyA8LSBsaXN0KCJTaWdoc2VlaW5nIiwgVFJVRSwgMjMyMywgRkFMU0UpDQpwcmludChjaXRpZXNfbWVtb3JpZXMpDQpgYGANCiBUaGUgb3RoZXIgaW50ZXJlc3RpbmcgcG9pbnQgYWJvdXQgbGlzdHMgaXMgdGhhdCB3ZSBjYW4gYXNzaWduIGEgbmFtZSB0byBlYWNoIG9mIHRoZSBlbGVtZW50LiBsZXQncyB0cnk6DQoNCmBgYHtyfQ0KY2l0aWVzX2xpc3QgPC0gbGlzdChhY3Rpdml0eSA9ICJTaWdoc2VlaW5nIiwgcGFya2luZ19mcmVlID0gVFJVRSwgcG9zdGNvZGUgPSAyMzIzLCBmcmVlX3dpZmkgPSBGQUxTRSkNCnByaW50KGNpdGllc19saXN0KQ0KYGBgDQpXaXRoIHRoZSBuYW1lIG9mIHRoZSBpdGVtcyBpbiB0aGUgbGlzdCBhc3NpZ25lZCwgd2UgY2FuIG5vdyBjYWxsIHRoZSBpdGVtcyBhcyBmb2xsb3dzOg0KYGBge3J9DQpjaXRpZXNfbGlzdCRhY3Rpdml0eQ0KYGBgDQoNCk1lYW53aGlsZSB0aGUgbGlzdCBjYXJyaWVzIHNvbWUgc2ltaWxhciBmdW5jdGlvbnMgdG8gdGhlIFZlY3Rvci4gd2UgY2FuIGNhbGwgZWxlbWVudHMgYnkgdGhlaXIgcG9zaXRpb24uIFNlZSB0aGUgZXhhbXBsZSBiZWxvdyB3ZSBjYWxsIHRoZSBzZWNvbmQgZWxlbWVudCBvZiB0aGUgbGlzdDoNCmBgYHtyfQ0KY2l0aWVzX2xpc3RbMl0NCg0KYGBgDQoNCiMgSW50cm9kdWN0aW9uIHRvIERhdGFmcmFtZQ0KRGF0YWZyYW1lIGFyZSBhdCB0aGUgdmVyeSBjZW50ZXIgb2YgdGhlIFIgcHJvZ3JhbW1pbmcgZnJhbWV3b3JrLiBUaGV5IGNhbiBiZSBjb21wYXJlZCB0byBhIHNwcmVhZHNoZWV0IGZyb20gYSB2aXN1YWwgYW5nbGUsIG9yICB0byBhIGRhdGFiYXNlIGZvciB0aGUgbW9zdCBhZHZhbmNlZCBvZiB5b3UuIEEgZGF0YWZyYW1lIGlzIG5vdGhpbmcgZWxzZSB0aGFuIGEgY29tYmluYXRpb24gb2YgdmVjdG9ycywgb2YgdGhlIHNhbWUgbGVuZ3RoLiBMZXRzIGNyZWF0ZSBhIGRhdGFmcmFtZSBieSBjb21iaW5pbmcgc29tZSBvZiB0aGUgZmVjdG9ycyB0aGF0IHdlIGNyZWF0ZWQgZWFybGllci4NCg0KYGBge3J9DQpkZXN0aW5hdGlvbl9kZiA8LSBkYXRhLmZyYW1lKG15X2Zhdm9yaXRlX2NpdGllcyAsIHRoZWlyX3RlbXBlcmF0dXJlcyAsbWVnYV9jaXRpZXMgLCBjaXRpZXNfd2VhdGhlciAgKQ0KcHJpbnQoZGVzdGluYXRpb25fZGYpDQoNCmBgYA0KTm93IHRoYXQgd2UgaGF2ZSBpbnRyb2R1Y2VkIHRoZSBkYXRhZnJhbWUsIHdlIG1pZ2h0IHdhbnQgdG8gdmVyaWZ5IHRoYXQgZWFjaCBvZiB0aGUgY29sdW1ucyBjb250YWlucyB0aGUgdHlwZSBvZiB2YWx1ZSB0aGF0IHdlIGV4cGVjdGVkLiBUaGUgKnN0ciogZnVuY3Rpb24gaXMgcXVpdGUgaGFuZHkgZm9yIHRoYXQuDQpgYGB7cn0NCnByaW50KHN0cihkZXN0aW5hdGlvbl9kZikpDQpgYGANCk91ciBkYXRhIGhhdmUgYmVlbiBpbnRlZ3JhdGVkIGludG8gdGhlIG5ldyB2ZWN0b3IgYXMgd2UgZXhwZWN0ZWQuIA0KDQojIyBFeHRyYWN0aW5nIGZyb20gZGF0YWZyYW1lDQojIyMgRXh0cmFjdGluZyBvbmUgY29sdW1uIGZyb20gYSBkYXRhZnJhbWUNCkV4dHJhY3RpbmcgYSBjb2x1bW4gZnJvbSBhIGRhdGFmcmFtZSBpbiBSIGlzIHZlcnkgZWFzeS4gY2FsbCB0aGUgZGF0YWZyYW1lICpkZiogYW5kIHRoZSBkb2xsYXIgc2lnbiAqJCogZm9sbG93ZWQgYnkgdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiBvciBhdHRyaWJ1dGUgdG8gYmUgbW9yZSBwcmVjaXNlLiBMZXRzIGdpdmUgaXQgYSB0cnkgDQpgYGB7cn0NCnByaW50KGRlc3RpbmF0aW9uX2RmJG15X2Zhdm9yaXRlX2NpdGllcykNCg0KYGBgDQoNCiMjIyBFeHRyYWN0aW5nIHR3byBjb2x1bW5zIGZyb20gYSBkYXRhZnJhbWUNClRvIGV4dHJhY3QgbXVsdGlwbGUgY29sdW1ucywgd2Ugd2lsbCBzaW1wbHkgcGFzcyBhIHZlY3RvciB0byB0aGUgZGF0YWZyYW1lLiBUaGF0IHZlY3RvciB3aWxsIGNvbnRhaW4gdGhlIG5hbWUgb2YgdGhlIGNvbHVtbnMNCmBgYHtyfQ0KZGVzdGluYXRpb25fZGZbYygibXlfZmF2b3JpdGVfY2l0aWVzIiwgImNpdGllc193ZWF0aGVyIildDQpgYGANCg0KIyMjIEV4dHJhY3RpbmcgdGhlIDFzdCByb3cgaW4gdGhlIHNlY29uZCBjb2x1bW4NCg0KYGBge3J9DQpkZXN0aW5hdGlvbl9kZlsxLDJdDQoNCmBgYA0KDQojIyMgRXh0cmFjdGluZyB0aGUgMXN0IGFuZCB0aGUgM3JkIHJvdyBvZiB0aGUgc2Vjb25kIGFuZCB0aGlyZCBjb2x1bW5zDQpgYGB7cn0NCmRlc3RpbmF0aW9uX2RmW2MoMSwzKSxjKDIsMyldDQoNCmBgYA0KDQojIyMgRXh0cmFjdGluZyBhbGwgdGhlIHJvd3Mgb2YgdGhlIHNlY29uZCBjb2x1bW4NCmBgYHtyfQ0KZGVzdGluYXRpb25fZGZbLDJdDQoNCmBgYA0KIyMjIEV4dHJhY3RpbmcgdGhlIGZpcnN0IGFuZCBzZWNvbmQgcm93cyBvZiB0d28gc3BlY2lmaWMgY29sdW1ucyANCmBgYHtyfQ0KZGVzdGluYXRpb25fZGZbYygxLDIpLCBjKCJtZWdhX2NpdGllcyIsImNpdGllc193ZWF0aGVyIildDQoNCmBgYA0KV2UgY2FuIGtlZXAgcGxheWluZyB3aXRoIHRoZXNlIGNvbWJpbmF0aW9uIGFuZCBldmVuIGFkZCBuZWdhdGl2ZSBzZWxlY3RvcnMgc3VjaCBhcyAqZGVzdGluYXRpb25fY2l0eVstMiwtMl0qLCB0cnkgaXQgYW5kIHNlZSB3aGF0IGNvbWVzIG91dC4NCg0KIyBJbnRyb2R1Y3Rpb24gIHRvIG1hdHJpY2VzDQpJbiBSLCBtYXRyaWNlcyBhcmUgYW4gb2JqZWN0IHVzZWQgdG8gc3RvcmUgZGF0YSBpbiBhIHRhYnVsYXIgc2hhcGUuIFVzdWFsbHkgdGhleSBhcmUgb2YgYSBzaW5nbGUgZGF0YSB0eXBlLCBhcyBvbmUgd291bGQgbW9zdGx5IHVzZWQgdGhlbSBmb3IgY2FsY3VsdXMuIFJlbWVtYmVyIGFzIGMoKSBjcmVhdGVkIHZlY3RvcnMsIGxpc3QoKSBjcmVhdGVzIGxpc3QgYW5kIGRhdGEuZnJhbWUoKSBjcmVhdGVzIGRhdGFmcmFtZT8gZm9yIG1hdHJpY2VzIHdlIGNhbiBzaW1wbHkgdXNlIG1hdHJpeCgpIHRvIGNyZWF0ZSBhIG1hdHJpeC4gQ2FyZWZ1bCB3aXRoIHRoZSB0cmljayBoZXJlLCB3ZSBuZWVkIHRvIHNwZWNpZnkgdGhlIG51bWJlciBvZiBjb2x1bW5zIG9yIHJvd3MuIExldHMgZG8gYSBmZXcgZXhhbXBsZXMuDQoNCmBgYHtyfQ0KbWF0X2EgPC0gbWF0cml4KGMoNCw1LDgsNyw1LDQsMTEsMjEsMyksIG5yb3c9MykNCnByaW50KG1hdF9hKQ0KYGBgDQpBcyBvbmUgY2FuIHNlZSwgdGhlIG1hdHJpeCBjb250YWlucyBhIHZlY3Rvciwgb2Ygd2hpY2ggdGhlIGxlbmdoIHNob3VsZCBiZSBncmVhdGVyIHRvIHRoYW4gdGhlIHNxdWFyZSB2YWx1ZSBvZiB0aGUgbnVtYmVyIG9mIHJvd3Mgb3IgY29sdW1ucyBpbnN0cnVjdGVkLiBMZXQgcmV2aWV3IHRoZSBzYW1lIG1hdHJpeCBidXQgd2l0aCBhIG5jb2wgdGhpcyB0aW1lLCBhbmQgc2VlIHdoYXQgaGFwcGVucy4NCg0KDQpgYGB7cn0NCm1hdF9iIDwtIG1hdHJpeChjKDQsNSw4LDcsNSw0LDExLDIxLDMpLCBuY29sPTIpDQpwcmludChtYXRfYikNCmBgYA0KV2UgZ290IGEgd2FybmluZyB0aGF0IGluZGljYXRlcyB0aGF0IHRoZSBkYXRhIGxlbmd0aCBpcyBpbmNvbnNpc3RlbnQuDQoNCg0K