Supervised Learning

The goal in a supervised learning task is to use observed data to create a model that can be used to predict values of some target variable \(Y\) given observed values for a set of features \(X_1, X_2, ..., X_p\).

Terminology

There are a variety of terms that are used to distinguish between the inputs and the output of a supervised learning model.

  • The output of the model is typically called a response, label, or dependent variable.
  • The inputs of the model are typically called predictors, features, or independent variables.

Classification and Regression

We can seperate supervised learning tasks further into the categories of regression or classification, based on the nature of the target variable \(Y\).

  • We refer to a supervised learning task in which the target variable is continuous and quantitative (numerical) as a regression task.
  • We refer to a supervised learning task in which the target variable is qualitative (categorical) as a classification task.

Types of Relationships

Assume that \(X\) and \(Y\) are two variables that are in some way related, and we wish to build a model that explains the way in which the value of \(Y\) depends on the value of \(X\). We can classify such a model as either stochastic or deterministic, depending on whether or not it allows for randomness in the relationship.

Deterministic Relationships

A relationship between two variables \(X\) and \(Y\) is said to be deterministic if there is no randomness in the relationship. In a deterministic relationship, knowing the value of one variable allows you to determine the exact value of the other variable. A deterministic relationship might be described by an equation of the form:

\[Y = f(X)\]

When building machine learning models, we generally work with variables that display imperfect, or noisy, relationships that do not behave deterministically.

Stochastic Relationships

A relationship between two variables \(X\) and \(Y\) is said to be stochastic if there is some randomness in the relationship. In a stochastic relationship, knowing the value of one variable might (or might not) allow you to come up with reasonable estimate for the other variable, but you can never hope to know the exact value of one variable based on the value of another.

A stochastic relationship might be represented using an equation of the following form:

\[Y = f(X) + \varepsilon\]

In the previous equation, we assume that the \(\varepsilon\) is a random variable whose value we do not know ahead of time. It represents uncertainty in the model (from measurement error, effects of unknown variables, or truly random effects).

To have a complete stochastic model, we need to know the function \(f\), as well as the distribution of the error term \(\varepsilon\). A common assumption for a stochastic model of this form is that \(\varepsilon\) is normally distributed with a mean of 0 and some standard deviation, \(\sigma\). This assumption is often written as \(\varepsilon \sim N(0, \sigma^2)\). The size of \(\sigma\) represents the amount of uncertainty in our model.

Population Models

Assume that the true relationship between the variables \(X\) and \(Y\) is described by a stochastic model of the form \(Y = f(X) + \varepsilon\). We call such a model a population model, as it describes the relationship for the entire population of pairs of values \((x,y)\), albeit with some amount of noise.

Sampling from a Population Model

Assume that we have a population model of the form \(Y = f(X) + \varepsilon\), where \(\varepsilon \sim N(0, \sigma^2)\). Suppose that we know \(f\) and \(\sigma\). We can generate a sample of observations \((x_i, y_i)\) from this population model as follows:

  1. We start by selecting \(n\) values \(x_1, x_2, ..., x_n\).
  2. We then randomly generate \(n\) error terms \(\varepsilon_1, \varepsilon_2,..., \varepsilon_n\) according to the distribution \(N(0, \sigma^2)\).
  3. Finally, we determine values \(y_1, y_2, ..., y_n\) by setting \(y_i = f(x_i) + \varepsilon_i\).

Example in R

Suppose that we have a population model of the form \(Y = 4 - 2 X + X^2 + \varepsilon\), where \(N(0, \sigma^2 = 4)\). The following R code generates a sample of 10 observations of the form \((x_i, y_i)\) according to this model.

Note that since the error terms are random generated, the sample will be a bit different each time.

x <- c(0.5, 0.75, 1.5, 2.25, 2.5, 2.5, 3, 3.25, 3.5, 4)
e <- rnorm(n=10, mean=0, sd=2)
y <- 4 - 2*x + x^2 + e

Goal of Supervised Learning

In a real-world supervised learning problem, we will not have access to a population model. Instead, we will have a sample of observations that we assume to have been generated by some (hypothetical) population model. Our goal is to use the observed data to find a function \(\hat f\) that approximates the relationship defined by \(f\). We will typically also wish to appproximate the standard deviation of the error term with a quantity \(s = \hat \sigma\).

Learning from Data

In a supervised learning task, we have a collection of observed data, called the training data, that we use to try to find a fitted function \(Y = \hat f(X)\) that best describes the relationship between the variables. The question of what function provides the “best” fit is a complicated one, which we will discuss in detail in the coming lectures.

We close this lesson with a plot that shows the a training set along with three proposed models generated from this training set. I encourage you to consider which model you believe is the “best”, and to think about why you selected the model that you did.

LS0tDQp0aXRsZTogIkxlc3NvbiAyLjEgLSBJbnRyb2R1Y3Rpb24gdG8gU3VwZXJ2aXNlZCBMZWFybmluZyINCmF1dGhvcjogIlJvYmJpZSBCZWFuZSINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQotLS0NCg0KIyMjICoqU3VwZXJ2aXNlZCBMZWFybmluZyoqDQoNClRoZSBnb2FsIGluIGEgKipzdXBlcnZpc2VkIGxlYXJuaW5nKiogdGFzayBpcyB0byB1c2Ugb2JzZXJ2ZWQgZGF0YSB0byBjcmVhdGUgYSAqKm1vZGVsKiogdGhhdCBjYW4gYmUgdXNlZCB0byBwcmVkaWN0IHZhbHVlcyBvZiBzb21lIHRhcmdldCB2YXJpYWJsZSAkWSQgZ2l2ZW4gb2JzZXJ2ZWQgdmFsdWVzIGZvciBhIHNldCBvZiBmZWF0dXJlcyAkWF8xLCBYXzIsIC4uLiwgWF9wJC4gDQoNCiMjIyMgKipUZXJtaW5vbG9neSoqDQoNClRoZXJlIGFyZSBhIHZhcmlldHkgb2YgdGVybXMgdGhhdCBhcmUgdXNlZCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIHRoZSBpbnB1dHMgYW5kIHRoZSBvdXRwdXQgb2YgYSBzdXBlcnZpc2VkIGxlYXJuaW5nIG1vZGVsLg0KDQoqIFRoZSBvdXRwdXQgb2YgdGhlIG1vZGVsIGlzIHR5cGljYWxseSBjYWxsZWQgYSAqKnJlc3BvbnNlKiosICoqbGFiZWwqKiwgb3IgKipkZXBlbmRlbnQgdmFyaWFibGUqKi4NCiogVGhlIGlucHV0cyBvZiB0aGUgbW9kZWwgYXJlIHR5cGljYWxseSBjYWxsZWQgKipwcmVkaWN0b3JzKiosICoqZmVhdHVyZXMqKiwgb3IgKippbmRlcGVuZGVudCB2YXJpYWJsZXMqKi4NCg0KIyMjIyAqKkNsYXNzaWZpY2F0aW9uIGFuZCBSZWdyZXNzaW9uKioNCg0KV2UgY2FuIHNlcGVyYXRlIHN1cGVydmlzZWQgbGVhcm5pbmcgdGFza3MgZnVydGhlciBpbnRvIHRoZSBjYXRlZ29yaWVzIG9mICoqcmVncmVzc2lvbioqIG9yICoqY2xhc3NpZmljYXRpb24qKiwgYmFzZWQgb24gdGhlIG5hdHVyZSBvZiB0aGUgdGFyZ2V0IHZhcmlhYmxlICRZJC4gDQoNCiogV2UgcmVmZXIgdG8gYSBzdXBlcnZpc2VkIGxlYXJuaW5nIHRhc2sgaW4gd2hpY2ggdGhlIHRhcmdldCB2YXJpYWJsZSBpcyBjb250aW51b3VzIGFuZCBxdWFudGl0YXRpdmUgKG51bWVyaWNhbCkgYXMgYSAqKnJlZ3Jlc3Npb24qKiB0YXNrLg0KKiBXZSByZWZlciB0byBhIHN1cGVydmlzZWQgbGVhcm5pbmcgdGFzayBpbiB3aGljaCB0aGUgdGFyZ2V0IHZhcmlhYmxlIGlzIHF1YWxpdGF0aXZlIChjYXRlZ29yaWNhbCkgYXMgYSAqKmNsYXNzaWZpY2F0aW9uKiogdGFzay4NCg0KPGNlbnRlcj4NCiFbXShpbWFnZXMvQ3ZSLnBuZykNCjwvY2VudGVyPg0KDQojIyMgKipUeXBlcyBvZiBSZWxhdGlvbnNoaXBzKioNCg0KQXNzdW1lIHRoYXQgJFgkIGFuZCAkWSQgYXJlIHR3byB2YXJpYWJsZXMgdGhhdCBhcmUgaW4gc29tZSB3YXkgcmVsYXRlZCwgYW5kIHdlIHdpc2ggdG8gYnVpbGQgYSBtb2RlbCB0aGF0IGV4cGxhaW5zIHRoZSB3YXkgaW4gd2hpY2ggdGhlIHZhbHVlIG9mICRZJCBkZXBlbmRzIG9uIHRoZSB2YWx1ZSBvZiAkWCQuIFdlIGNhbiBjbGFzc2lmeSBzdWNoIGEgbW9kZWwgYXMgZWl0aGVyICoqc3RvY2hhc3RpYyoqIG9yICoqZGV0ZXJtaW5pc3RpYyoqLCBkZXBlbmRpbmcgb24gd2hldGhlciBvciBub3QgaXQgYWxsb3dzIGZvciByYW5kb21uZXNzIGluIHRoZSByZWxhdGlvbnNoaXAuIA0KDQpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9OH0NCnNldC5zZWVkKDYpDQoNCnhfY3VydmUgPC0gc2VxKC0xLCA1LCBieT0wLjEpDQp5X2N1cnZlIDwtIDQgLSAyICogeF9jdXJ2ZSArIHhfY3VydmUqKjINCg0KeF9zYW1wbGUgPC0gcnVuaWYoMTAsIDAsIDQpDQp5X3NhbXBsZV8xIDwtIDQgLSAyICogeF9zYW1wbGUgKyB4X3NhbXBsZSoqMg0KeV9zYW1wbGVfMiA8LSA0IC0gMiAqIHhfc2FtcGxlICsgeF9zYW1wbGUqKjIgKyBybm9ybSgxMCwgMCwgMikNCg0KcGFyKG1mcm93PWMoMSwyKSkNCnBsb3QoeV9zYW1wbGVfMSB+IHhfc2FtcGxlLCBwY2g9Ii4iLCB4bGltPWMoMCw0KSwgeWxpbT1jKDAsMTYpLCANCiAgICAgeGxhYj0iWCIsIHlsYWI9IlkiLCBtYWluPSJEZXRlcm1pbmlzdGljIFJlbGF0aW9uc2hpcCIpDQpsaW5lcyh5X2N1cnZlIH4geF9jdXJ2ZSwgbHdkPTIpDQpwb2ludHMoeV9zYW1wbGVfMSB+IHhfc2FtcGxlLCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0ic2FsbW9uIiwgY2V4PTEuNCkNCg0KcGxvdCh5X3NhbXBsZV8yIH4geF9zYW1wbGUsIHBjaD0iLiIsIHhsaW09YygwLDQpLCB5bGltPWMoMCwxNiksIA0KICAgICB4bGFiPSJYIiwgeWxhYj0iWSIsIG1haW49IlN0b2NoYXN0aWMgUmVsYXRpb25zaGlwIikNCmxpbmVzKHlfY3VydmUgfiB4X2N1cnZlLCBsd2Q9MikNCnBvaW50cyh5X3NhbXBsZV8yIH4geF9zYW1wbGUsIHBjaD0yMSwgY29sPSJibGFjayIsIGJnPSJzYWxtb24iLCBjZXg9MS40KSAgICAgDQoNCnBhcihtZnJvdz1jKDEsMSkpDQpgYGANCg0KDQojIyMjICoqRGV0ZXJtaW5pc3RpYyBSZWxhdGlvbnNoaXBzKioNCg0KQSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzICRYJCBhbmQgJFkkIGlzIHNhaWQgdG8gYmUgKipkZXRlcm1pbmlzdGljKiogaWYgdGhlcmUgaXMgbm8gcmFuZG9tbmVzcyBpbiB0aGUgcmVsYXRpb25zaGlwLiBJbiBhIGRldGVybWluaXN0aWMgcmVsYXRpb25zaGlwLCBrbm93aW5nIHRoZSB2YWx1ZSBvZiBvbmUgdmFyaWFibGUgYWxsb3dzIHlvdSB0byBkZXRlcm1pbmUgdGhlIGV4YWN0IHZhbHVlIG9mIHRoZSBvdGhlciB2YXJpYWJsZS4gQSBkZXRlcm1pbmlzdGljIHJlbGF0aW9uc2hpcCBtaWdodCBiZSBkZXNjcmliZWQgYnkgYW4gZXF1YXRpb24gb2YgdGhlIGZvcm06DQoNCiQkWSA9IGYoWCkkJA0KDQpXaGVuIGJ1aWxkaW5nIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzLCB3ZSBnZW5lcmFsbHkgd29yayB3aXRoIHZhcmlhYmxlcyB0aGF0IGRpc3BsYXkgaW1wZXJmZWN0LCBvciBub2lzeSwgcmVsYXRpb25zaGlwcyB0aGF0IGRvIG5vdCBiZWhhdmUgZGV0ZXJtaW5pc3RpY2FsbHkuIA0KDQojIyMjICoqU3RvY2hhc3RpYyBSZWxhdGlvbnNoaXBzKioNCg0KQSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzICRYJCBhbmQgJFkkIGlzIHNhaWQgdG8gYmUgKipzdG9jaGFzdGljKiogaWYgdGhlcmUgaXMgc29tZSByYW5kb21uZXNzIGluIHRoZSByZWxhdGlvbnNoaXAuIEluIGEgc3RvY2hhc3RpYyByZWxhdGlvbnNoaXAsIGtub3dpbmcgdGhlIHZhbHVlIG9mIG9uZSB2YXJpYWJsZSBtaWdodCAob3IgbWlnaHQgbm90KSBhbGxvdyB5b3UgdG8gY29tZSB1cCB3aXRoIHJlYXNvbmFibGUgZXN0aW1hdGUgZm9yIHRoZSBvdGhlciB2YXJpYWJsZSwgYnV0IHlvdSBjYW4gbmV2ZXIgaG9wZSB0byBrbm93IHRoZSBleGFjdCB2YWx1ZSBvZiBvbmUgdmFyaWFibGUgYmFzZWQgb24gdGhlIHZhbHVlIG9mIGFub3RoZXIuIA0KDQpBIHN0b2NoYXN0aWMgcmVsYXRpb25zaGlwIG1pZ2h0IGJlIHJlcHJlc2VudGVkIHVzaW5nIGFuIGVxdWF0aW9uIG9mIHRoZSBmb2xsb3dpbmcgZm9ybToNCg0KJCRZID0gZihYKSArIFx2YXJlcHNpbG9uJCQNCg0KSW4gdGhlIHByZXZpb3VzIGVxdWF0aW9uLCB3ZSBhc3N1bWUgdGhhdCB0aGUgJFx2YXJlcHNpbG9uJCBpcyBhIHJhbmRvbSB2YXJpYWJsZSB3aG9zZSB2YWx1ZSB3ZSBkbyBub3Qga25vdyBhaGVhZCBvZiB0aW1lLiBJdCByZXByZXNlbnRzIHVuY2VydGFpbnR5IGluIHRoZSBtb2RlbCAoZnJvbSBtZWFzdXJlbWVudCBlcnJvciwgZWZmZWN0cyBvZiB1bmtub3duIHZhcmlhYmxlcywgb3IgdHJ1bHkgcmFuZG9tIGVmZmVjdHMpLiANCg0KVG8gaGF2ZSBhIGNvbXBsZXRlIHN0b2NoYXN0aWMgbW9kZWwsIHdlIG5lZWQgdG8ga25vdyB0aGUgZnVuY3Rpb24gJGYkLCBhcyB3ZWxsIGFzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGVycm9yIHRlcm0gJFx2YXJlcHNpbG9uJC4gQSBjb21tb24gYXNzdW1wdGlvbiBmb3IgYSBzdG9jaGFzdGljIG1vZGVsIG9mIHRoaXMgZm9ybSBpcyB0aGF0ICRcdmFyZXBzaWxvbiQgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2l0aCBhIG1lYW4gb2YgMCBhbmQgc29tZSBzdGFuZGFyZCBkZXZpYXRpb24sICRcc2lnbWEkLiBUaGlzIGFzc3VtcHRpb24gaXMgb2Z0ZW4gd3JpdHRlbiBhcyAkXHZhcmVwc2lsb24gXHNpbSBOKDAsIFxzaWdtYV4yKSQuIFRoZSBzaXplIG9mICRcc2lnbWEkIHJlcHJlc2VudHMgdGhlIGFtb3VudCBvZiB1bmNlcnRhaW50eSBpbiBvdXIgbW9kZWwuIA0KDQojIyMgKipQb3B1bGF0aW9uIE1vZGVscyoqDQoNCkFzc3VtZSB0aGF0IHRoZSB0cnVlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgJFgkIGFuZCAkWSQgaXMgZGVzY3JpYmVkIGJ5IGEgc3RvY2hhc3RpYyBtb2RlbCBvZiB0aGUgZm9ybSAkWSA9IGYoWCkgKyBcdmFyZXBzaWxvbiQuIFdlIGNhbGwgc3VjaCBhIG1vZGVsIGEgKipwb3B1bGF0aW9uIG1vZGVsKiosIGFzIGl0IGRlc2NyaWJlcyB0aGUgcmVsYXRpb25zaGlwIGZvciB0aGUgZW50aXJlIHBvcHVsYXRpb24gb2YgcGFpcnMgb2YgdmFsdWVzICQoeCx5KSQsIGFsYmVpdCB3aXRoIHNvbWUgYW1vdW50IG9mIG5vaXNlLiANCg0KIyMjIyAqKlNhbXBsaW5nIGZyb20gYSBQb3B1bGF0aW9uIE1vZGVsKioNCg0KQXNzdW1lIHRoYXQgd2UgaGF2ZSBhIHBvcHVsYXRpb24gbW9kZWwgb2YgdGhlIGZvcm0gJFkgPSBmKFgpICsgXHZhcmVwc2lsb24kLCB3aGVyZSAkXHZhcmVwc2lsb24gXHNpbSBOKDAsIFxzaWdtYV4yKSQuIFN1cHBvc2UgdGhhdCB3ZSBrbm93ICRmJCBhbmQgJFxzaWdtYSQuIFdlIGNhbiBnZW5lcmF0ZSBhIHNhbXBsZSBvZiBvYnNlcnZhdGlvbnMgJCh4X2ksIHlfaSkkIGZyb20gdGhpcyBwb3B1bGF0aW9uIG1vZGVsIGFzIGZvbGxvd3M6IA0KDQoxLiBXZSBzdGFydCBieSBzZWxlY3RpbmcgJG4kIHZhbHVlcyAkeF8xLCB4XzIsIC4uLiwgeF9uJC4gDQoyLiBXZSB0aGVuIHJhbmRvbWx5IGdlbmVyYXRlICRuJCBlcnJvciB0ZXJtcyAkXHZhcmVwc2lsb25fMSwgXHZhcmVwc2lsb25fMiwuLi4sIFx2YXJlcHNpbG9uX24kIGFjY29yZGluZyB0byB0aGUgZGlzdHJpYnV0aW9uICROKDAsIFxzaWdtYV4yKSQuIA0KMy4gRmluYWxseSwgd2UgZGV0ZXJtaW5lIHZhbHVlcyAkeV8xLCB5XzIsIC4uLiwgeV9uJCBieSBzZXR0aW5nICR5X2kgPSBmKHhfaSkgKyBcdmFyZXBzaWxvbl9pJC4gDQoNCg0KIyMjIyAqKkV4YW1wbGUgaW4gUioqDQoNClN1cHBvc2UgdGhhdCB3ZSBoYXZlIGEgcG9wdWxhdGlvbiBtb2RlbCBvZiB0aGUgZm9ybSAkWSA9IDQgLSAyIFggKyBYXjIgKyBcdmFyZXBzaWxvbiQsIHdoZXJlICROKDAsIFxzaWdtYV4yID0gNCkkLiBUaGUgZm9sbG93aW5nIFIgY29kZSBnZW5lcmF0ZXMgYSBzYW1wbGUgb2YgMTAgb2JzZXJ2YXRpb25zIG9mIHRoZSBmb3JtICQoeF9pLCB5X2kpJCBhY2NvcmRpbmcgdG8gdGhpcyBtb2RlbC4gDQoNCk5vdGUgdGhhdCBzaW5jZSB0aGUgZXJyb3IgdGVybXMgYXJlIHJhbmRvbSBnZW5lcmF0ZWQsIHRoZSBzYW1wbGUgd2lsbCBiZSBhIGJpdCBkaWZmZXJlbnQgZWFjaCB0aW1lLiANCg0KYGBge3J9DQp4IDwtIGMoMC41LCAwLjc1LCAxLjUsIDIuMjUsIDIuNSwgMi41LCAzLCAzLjI1LCAzLjUsIDQpDQplIDwtIHJub3JtKG49MTAsIG1lYW49MCwgc2Q9MikNCnkgPC0gNCAtIDIqeCArIHheMiArIGUNCmBgYA0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KeCA8LSBjKDAuNSwgMC43NSwgMS41LCAyLjI1LCAyLjUsIDIuNSwgMywgMy4yNSwgMy41LCA0KQ0KZSA8LSBybm9ybShuPTEwLCBtZWFuPTAsIHNkPTIpDQp5IDwtIDQgLSAyKnggKyB4XjIgKyBlDQoNCnBsb3QoeF9jdXJ2ZSwgeV9jdXJ2ZSwgcGNoPSIuIiwgeGxpbT1jKDAsNCksIHlsaW09YygwLDE1KSwNCiAgICAgeGxhYj0iWCIsIHlsYWI9IlkiLCBtYWluPSJTYW1wbGluZyBmcm9tIGEgUG9wdWxhdGlvbiBNb2RlbCIpDQpsaW5lcyh4X2N1cnZlLCB5X2N1cnZlLCBsd2Q9MikNCnBvaW50cyh5IH4geCwgY2V4PTEuNSwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9InNhbG1vbiIpDQogICAgIA0KYGBgDQoNCiMjIyAqKkdvYWwgb2YgU3VwZXJ2aXNlZCBMZWFybmluZyoqDQoNCkluIGEgcmVhbC13b3JsZCBzdXBlcnZpc2VkIGxlYXJuaW5nIHByb2JsZW0sIHdlIHdpbGwgbm90IGhhdmUgYWNjZXNzIHRvIGEgcG9wdWxhdGlvbiBtb2RlbC4gSW5zdGVhZCwgd2Ugd2lsbCBoYXZlIGEgc2FtcGxlIG9mIG9ic2VydmF0aW9ucyB0aGF0IHdlIGFzc3VtZSB0byBoYXZlIGJlZW4gZ2VuZXJhdGVkIGJ5IHNvbWUgKGh5cG90aGV0aWNhbCkgcG9wdWxhdGlvbiBtb2RlbC4gT3VyIGdvYWwgaXMgdG8gdXNlIHRoZSBvYnNlcnZlZCBkYXRhIHRvIGZpbmQgYSBmdW5jdGlvbiAkXGhhdCBmJCB0aGF0IGFwcHJveGltYXRlcyB0aGUgcmVsYXRpb25zaGlwIGRlZmluZWQgYnkgJGYkLiBXZSB3aWxsIHR5cGljYWxseSBhbHNvIHdpc2ggdG8gYXBwcHJveGltYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGVycm9yIHRlcm0gd2l0aCBhIHF1YW50aXR5ICRzID0gXGhhdCBcc2lnbWEkLiANCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnNldC5zZWVkKDQpDQoNCm4gPC0gMjANCnggPC0gcnVuaWYobiwgMCwgNCkNCnkgPC0gNCAtIDIgKiB4ICsgeCoqMiArIHJub3JtKG4sIDAsIDIpDQoNCnBhcihtZnJvdz1jKDEsMikpDQpwbG90KHlfY3VydmUgfiB4X2N1cnZlLCBwY2g9Ii4iLCB4bGltPWMoMCw0KSwgeWxpbT1jKDAsMTUpLCANCiAgICAgeGxhYj0iWCIsIHlsYWI9IlkiLCBtYWluPSJQb3B1bGF0aW9uIE1vZGVsIHdpdGggU2FtcGxlIikNCmxpbmVzKHlfY3VydmUgfiB4X2N1cnZlLCBsd2Q9MikNCnBvaW50cyh5IH4geCwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9InNhbG1vbiIsIGNleD0xLjQpDQoNCg0KDQpwbG90KHkgfiB4LCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0ic2FsbW9uIiwgY2V4PTEuNCwNCiAgICAgeGxpbT1jKDAsNCksIHlsaW09YygwLDE2KSwgeGxhYj0iWCIsIHlsYWI9IlkiLCANCiAgICAgbWFpbj0iT2JzZXJ2ZWQgU2FtcGxlIE9ubHkiKQ0KcGFyKG1mcm93PWMoMSwxKSkNCg0KYGBgDQoNCg0KIyMjIyAqKkxlYXJuaW5nIGZyb20gRGF0YSoqDQoNCkluIGEgc3VwZXJ2aXNlZCBsZWFybmluZyB0YXNrLCB3ZSBoYXZlIGEgY29sbGVjdGlvbiBvZiBvYnNlcnZlZCBkYXRhLCBjYWxsZWQgdGhlICoqdHJhaW5pbmcgZGF0YSoqLCB0aGF0IHdlIHVzZSB0byB0cnkgdG8gZmluZCBhICoqZml0dGVkIGZ1bmN0aW9uKiogJFkgPSBcaGF0IGYoWCkkIHRoYXQgYmVzdCBkZXNjcmliZXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMuIFRoZSBxdWVzdGlvbiBvZiB3aGF0IGZ1bmN0aW9uIHByb3ZpZGVzIHRoZSAiYmVzdCIgZml0IGlzIGEgY29tcGxpY2F0ZWQgb25lLCB3aGljaCB3ZSB3aWxsIGRpc2N1c3MgaW4gZGV0YWlsIGluIHRoZSBjb21pbmcgbGVjdHVyZXMuIA0KDQpXZSBjbG9zZSB0aGlzIGxlc3NvbiB3aXRoIGEgcGxvdCB0aGF0IHNob3dzIHRoZSBhIHRyYWluaW5nIHNldCBhbG9uZyB3aXRoIHRocmVlIHByb3Bvc2VkIG1vZGVscyBnZW5lcmF0ZWQgZnJvbSB0aGlzIHRyYWluaW5nIHNldC4gSSBlbmNvdXJhZ2UgeW91IHRvIGNvbnNpZGVyIHdoaWNoIG1vZGVsIHlvdSBiZWxpZXZlIGlzIHRoZSAiYmVzdCIsIGFuZCB0byB0aGluayBhYm91dCB3aHkgeW91IHNlbGVjdGVkIHRoZSBtb2RlbCB0aGF0IHlvdSBkaWQuIA0KDQoNCg0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTgsIGVjaG89RkFMU0V9DQpzZXQuc2VlZCg0KQ0KDQpuIDwtIDIwDQp4IDwtIHJ1bmlmKG4sIDAsIDQpDQp5IDwtIDQgLSAyICogeCArIHgqKjIgKyBybm9ybShuLCAwLCAyKQ0KDQptb2QxIDwtIGxtKHkgfiB4KQ0KbW9kMiA8LSBsbSh5IH4geCArIEkoeF4yKSkNCm1vZDMgPC0gbG0oeSB+IHggKyBJKHheMikgKyBJKHheMykgKyBJKHheNCkgKyBJKHheNSkgKyANCiAgICAgICAgICAgICBJKHheNikgKyBJKHheNykgKyBJKHheOCkgKyBJKHheOSkpDQoNCmZpdHRlZDEgPC0gcHJlZGljdChtb2QxLCBkYXRhLmZyYW1lKHg9eF9jdXJ2ZSkpDQpmaXR0ZWQyIDwtIHByZWRpY3QobW9kMiwgZGF0YS5mcmFtZSh4PXhfY3VydmUpKQ0KZml0dGVkMyA8LSBwcmVkaWN0KG1vZDMsIGRhdGEuZnJhbWUoeD14X2N1cnZlKSkNCg0KDQpwYXIobWZyb3c9YygyLDIpKQ0KDQpwbG90KHkgfiB4LCBwY2g9Ii4iLCB4bGltPWMoMCw0KSwgeWxpbT1jKDAsMTUpLCANCiAgICAgbWFpbj0iVHJhaW5pbmcgRGF0YSIpDQpwb2ludHMoeSB+IHgsIHBjaD0yMSwgY29sPSJibGFjayIsIGJnPSJzYWxtb24iLCBjZXg9MS40KQ0KDQpwbG90KHkgfiB4LCBwY2g9Ii4iLCB4bGltPWMoMCw0KSwgeWxpbT1jKDAsMTUpLCANCiAgICAgbWFpbj0iTW9kZWwgMSIpDQpsaW5lcyhmaXR0ZWQxIH4geF9jdXJ2ZSwgY29sPSJjYWRldGJsdWU0IiwgbHdkPTIuNSkNCnBvaW50cyh5IH4geCwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9InNhbG1vbiIsIGNleD0xLjQpDQoNCnBsb3QoeSB+IHgsIHBjaD0iLiIsIHhsaW09YygwLDQpLCB5bGltPWMoMCwxNSksIA0KICAgICBtYWluPSJNb2RlbCAyIikNCmxpbmVzKGZpdHRlZDIgfiB4X2N1cnZlLCBjb2w9ImNhZGV0Ymx1ZTQiLCBsd2Q9Mi41KQ0KcG9pbnRzKHkgfiB4LCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0ic2FsbW9uIiwgY2V4PTEuNCkNCg0KcGxvdCh5IH4geCwgcGNoPSIuIiwgeGxpbT1jKDAsNCksIHlsaW09YygwLDE1KSwgDQogICAgIG1haW49Ik1vZGVsIDMiKQ0KbGluZXMoZml0dGVkMyB+IHhfY3VydmUsIGNvbD0iY2FkZXRibHVlNCIsIGx3ZD0yLjUpDQpwb2ludHMoeSB+IHgsIHBjaD0yMSwgY29sPSJibGFjayIsIGJnPSJzYWxtb24iLCBjZXg9MS40KQ0KDQoNCnBhcihtZnJvdz1jKDEsMSkpDQoNCmBgYA0KDQoNCg==