Objective
Your goal in this project is to build a linear regression model that can predict the Gross revenue earned by a movie based on other variables. You may use R packages to fit and evaluate a regression model (no need to implement regression yourself). Please stick to linear regression, however.
Instructions
You should be familiar with using an RMarkdown Notebook by now. Remember that you have to open it in RStudio, and you can run code chunks by pressing Cmd+Shift+Enter.
Please complete the tasks below and submit this R Markdown file (as pr2.Rmd) containing all completed code chunks and written responses, and a PDF export of it (as pr2.pdf) which should include the outputs and plots as well.
Note that Setup and Data Preprocessing steps do not carry any points, however, they need to be completed as instructed in order to get meaningful results.
Setup
Same as Project 1, load the dataset into memory:
load('movies_merged')
This creates an object of the same name (movies_merged). For convenience, you can copy it to df and start using it:
df = movies_merged
cat("Dataset has", dim(df)[1], "rows and", dim(df)[2], "columns", end="\n", file="")
colnames(df)
Load R packages
Load any R packages that you will need to use. You can come back to this chunk, edit it and re-run to load any additional packages later.
library(ggplot2)
If you are using any non-standard packages (ones that have not been discussed in class or explicitly allowed for this project), please mention them below. Include any special instructions if they cannot be installed using the regular install.packages('<pkg name>') command.
Non-standard packages used: None
Data Preprocessing
Before we start building models, we should clean up the dataset and perform any preprocessing steps that may be necessary. Some of these steps can be copied in from your Project 1 solution. It may be helpful to print the dimensions of the resulting dataframe at each step.
1. Remove non-movie rows
# TODO: Remove all rows from df that do not correspond to movies
2. Drop rows with missing Gross value
Since our goal is to model Gross revenue against other variables, rows that have missing Gross values are not useful to us.
# TODO: Remove rows with missing Gross value
3. Exclude movies released prior to 2000
Inflation and other global financial factors may affect the revenue earned by movies during certain periods of time. Taking that into account is out of scope for this project, so let’s exclude all movies that were released prior to the year 2000 (you may use Released, Date or Year for this purpose).
# TODO: Exclude movies released prior to 2000
4. Eliminate mismatched rows
Note: You may compare the Released column (string representation of release date) with either Year or Date (numeric representation of the year) to find mismatches. The goal is to avoid removing more than 10% of the rows.
# TODO: Remove mismatched rows
5. Drop Domestic_Gross column
Domestic_Gross is basically the amount of revenue a movie earned within the US. Understandably, it is very highly correlated with Gross and is in fact equal to it for movies that were not released globally. Hence, it should be removed for modeling purposes.
# TODO: Exclude the `Domestic_Gross` column
6. Process Runtime column
# TODO: Replace df$Runtime with a numeric column containing the runtime in minutes
Perform any additional preprocessing steps that you find necessary, such as dealing with missing values or highly correlated columns (feel free to add more code chunks, markdown blocks and plots here as necessary).
# TODO(optional): Additional preprocessing
Note: Do NOT convert categorical variables (like Genre) into binary columns yet. You will do that later as part of a model improvement task.
Final preprocessed dataset
Report the dimensions of the preprocessed dataset you will be using for modeling and evaluation, and print all the final column names. (Again, Domestic_Gross should not be in this list!)
# TODO: Print the dimensions of the final preprocessed dataset and column names
Evaluation Strategy
In each of the tasks described in the next section, you will build a regression model. In order to compare their performance, you will compute the training and test Root Mean Squared Error (RMSE) at different training set sizes.
First, randomly sample 10-20% of the preprocessed dataset and keep that aside as the test set. Do not use these rows for training! The remainder of the preprocessed dataset is your training data.
Now use the following evaluation procedure for each model:
- Choose a suitable sequence of training set sizes, e.g. 10%, 20%, 30%, …, 100% (10-20 different sizes should suffice). For each size, sample that many inputs from the training data, train your model, and compute the resulting training and test RMSE.
- Repeat your training and evaluation at least 10 times at each training set size, and average the RMSE results for stability.
- Generate a graph of the averaged train and test RMSE values as a function of the train set size (%), with optional error bars.
You can define a helper function that applies this procedure to a given set of features and reuse it.
Tasks
Each of the following tasks is worth 20 points, for a total of 100 points for this project. Remember to build each model as specified, evaluate it using the strategy outlined above, and plot the training and test errors by training set size (%).
1. Numeric variables
Use Linear Regression to predict Gross based on available numeric variables. You can choose to include all or a subset of them.
# TODO: Build & evaluate model 1 (numeric variables only)
Q: List the numeric variables you used.
A:
Q: What is the best mean test RMSE value you observed, and at what training set size?
A:
3. Non-numeric variables
Write code that converts genre, actors, directors, and other categorical variables to columns that can be used for regression (e.g. binary columns as you did in Project 1). Also process variables such as awards into more useful columns (again, like you did in Project 1). Now use these converted columns only to build your next model.
# TODO: Build & evaluate model 3 (converted non-numeric variables only)
Q: Explain which categorical variables you used, and how you encoded them into features.
A:
Q: What is the best mean test RMSE value you observed, and at what training set size? How does this compare with Task 2?
A:
4. Numeric and categorical variables
Try to improve the prediction quality as much as possible by using both numeric and non-numeric variables from Tasks 2 & 3.
# TODO: Build & evaluate model 4 (numeric & converted non-numeric variables)
Q: Compare the observed RMSE with Tasks 2 & 3.
A:
5. Additional features
Now try creating additional features such as interactions (e.g. is_genre_comedy x is_budget_greater_than_3M) or deeper analysis of complex variables (e.g. text analysis of full-text columns like Plot).
# TODO: Build & evaluate model 5 (numeric, non-numeric and additional features)
Q: Explain what new features you designed and why you chose them.
A:
Q: Comment on the final RMSE values you obtained, and what you learned through the course of this project.
A:
LS0tCnRpdGxlOiAnUHJvamVjdCAyOiBNb2RlbGluZyBhbmQgRXZhbHVhdGlvbicKc3VidGl0bGU6ICJDU0U2MjQyIC0gRGF0YSBhbmQgVmlzdWFsIEFuYWx5dGljcyAtIEZhbGwgMjAxN1xuXG5EdWU6IFN1bmRheSwgTm92ZW1iZXIgMjYsIDIwMTcgYXQgMTE6NTkgUE0gVVRDLTEyOjAwIG9uIFQtU3F1YXJlIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogbm9uZQogICAgdGhlbWU6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBub25lCiAgICB0aGVtZTogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KCiMgRGF0YQoKV2Ugd2lsbCB1c2UgdGhlIHNhbWUgZGF0YXNldCBhcyBQcm9qZWN0IDE6IFtgbW92aWVzX21lcmdlZGBdKGh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS9jb250ZW50LnVkYWNpdHktZGF0YS5jb20vY291cnNlcy9ndC1jczYyNDIvcHJvamVjdC9tb3ZpZXNfbWVyZ2VkKS4KCiMgT2JqZWN0aXZlCgpZb3VyIGdvYWwgaW4gdGhpcyBwcm9qZWN0IGlzIHRvIGJ1aWxkIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdGhhdCBjYW4gcHJlZGljdCB0aGUgYEdyb3NzYCByZXZlbnVlIGVhcm5lZCBieSBhIG1vdmllIGJhc2VkIG9uIG90aGVyIHZhcmlhYmxlcy4gWW91IG1heSB1c2UgUiBwYWNrYWdlcyB0byBmaXQgYW5kIGV2YWx1YXRlIGEgcmVncmVzc2lvbiBtb2RlbCAobm8gbmVlZCB0byBpbXBsZW1lbnQgcmVncmVzc2lvbiB5b3Vyc2VsZikuIFBsZWFzZSBzdGljayB0byBsaW5lYXIgcmVncmVzc2lvbiwgaG93ZXZlci4KCiMgSW5zdHJ1Y3Rpb25zCgpZb3Ugc2hvdWxkIGJlIGZhbWlsaWFyIHdpdGggdXNpbmcgYW4gW1JNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2sgYnkgbm93LiBSZW1lbWJlciB0aGF0IHlvdSBoYXZlIHRvIG9wZW4gaXQgaW4gUlN0dWRpbywgYW5kIHlvdSBjYW4gcnVuIGNvZGUgY2h1bmtzIGJ5IHByZXNzaW5nICpDbWQrU2hpZnQrRW50ZXIqLgoKUGxlYXNlIGNvbXBsZXRlIHRoZSB0YXNrcyBiZWxvdyBhbmQgc3VibWl0IHRoaXMgUiBNYXJrZG93biBmaWxlIChhcyAqKnByMi5SbWQqKikgY29udGFpbmluZyBhbGwgY29tcGxldGVkIGNvZGUgY2h1bmtzIGFuZCB3cml0dGVuIHJlc3BvbnNlcywgYW5kIGEgUERGIGV4cG9ydCBvZiBpdCAoYXMgKipwcjIucGRmKiopIHdoaWNoIHNob3VsZCBpbmNsdWRlIHRoZSBvdXRwdXRzIGFuZCBwbG90cyBhcyB3ZWxsLgoKX05vdGUgdGhhdCAqKlNldHVwKiogYW5kICoqRGF0YSBQcmVwcm9jZXNzaW5nKiogc3RlcHMgZG8gbm90IGNhcnJ5IGFueSBwb2ludHMsIGhvd2V2ZXIsIHRoZXkgbmVlZCB0byBiZSBjb21wbGV0ZWQgYXMgaW5zdHJ1Y3RlZCBpbiBvcmRlciB0byBnZXQgbWVhbmluZ2Z1bCByZXN1bHRzLl8KCiMgU2V0dXAKClNhbWUgYXMgUHJvamVjdCAxLCBsb2FkIHRoZSBkYXRhc2V0IGludG8gbWVtb3J5OgoKYGBge3J9CmxvYWQoJ21vdmllc19tZXJnZWQnKQpgYGAKClRoaXMgY3JlYXRlcyBhbiBvYmplY3Qgb2YgdGhlIHNhbWUgbmFtZSAoYG1vdmllc19tZXJnZWRgKS4gRm9yIGNvbnZlbmllbmNlLCB5b3UgY2FuIGNvcHkgaXQgdG8gYGRmYCBhbmQgc3RhcnQgdXNpbmcgaXQ6CgpgYGB7cn0KZGYgPSBtb3ZpZXNfbWVyZ2VkCmNhdCgiRGF0YXNldCBoYXMiLCBkaW0oZGYpWzFdLCAicm93cyBhbmQiLCBkaW0oZGYpWzJdLCAiY29sdW1ucyIsIGVuZD0iXG4iLCBmaWxlPSIiKQpjb2xuYW1lcyhkZikKYGBgCgojIyBMb2FkIFIgcGFja2FnZXMKCkxvYWQgYW55IFIgcGFja2FnZXMgdGhhdCB5b3Ugd2lsbCBuZWVkIHRvIHVzZS4gWW91IGNhbiBjb21lIGJhY2sgdG8gdGhpcyBjaHVuaywgZWRpdCBpdCBhbmQgcmUtcnVuIHRvIGxvYWQgYW55IGFkZGl0aW9uYWwgcGFja2FnZXMgbGF0ZXIuCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpgYGAKCklmIHlvdSBhcmUgdXNpbmcgYW55IG5vbi1zdGFuZGFyZCBwYWNrYWdlcyAob25lcyB0aGF0IGhhdmUgbm90IGJlZW4gZGlzY3Vzc2VkIGluIGNsYXNzIG9yIGV4cGxpY2l0bHkgYWxsb3dlZCBmb3IgdGhpcyBwcm9qZWN0KSwgcGxlYXNlIG1lbnRpb24gdGhlbSBiZWxvdy4gSW5jbHVkZSBhbnkgc3BlY2lhbCBpbnN0cnVjdGlvbnMgaWYgdGhleSBjYW5ub3QgYmUgaW5zdGFsbGVkIHVzaW5nIHRoZSByZWd1bGFyIGBpbnN0YWxsLnBhY2thZ2VzKCc8cGtnIG5hbWU+JylgIGNvbW1hbmQuCgoqKk5vbi1zdGFuZGFyZCBwYWNrYWdlcyB1c2VkKio6IE5vbmUKCiMgRGF0YSBQcmVwcm9jZXNzaW5nCgpCZWZvcmUgd2Ugc3RhcnQgYnVpbGRpbmcgbW9kZWxzLCB3ZSBzaG91bGQgY2xlYW4gdXAgdGhlIGRhdGFzZXQgYW5kIHBlcmZvcm0gYW55IHByZXByb2Nlc3Npbmcgc3RlcHMgdGhhdCBtYXkgYmUgbmVjZXNzYXJ5LiBTb21lIG9mIHRoZXNlIHN0ZXBzIGNhbiBiZSBjb3BpZWQgaW4gZnJvbSB5b3VyIFByb2plY3QgMSBzb2x1dGlvbi4gSXQgbWF5IGJlIGhlbHBmdWwgdG8gcHJpbnQgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIHJlc3VsdGluZyBkYXRhZnJhbWUgYXQgZWFjaCBzdGVwLgoKIyMgMS4gUmVtb3ZlIG5vbi1tb3ZpZSByb3dzCgpgYGB7cn0KIyBUT0RPOiBSZW1vdmUgYWxsIHJvd3MgZnJvbSBkZiB0aGF0IGRvIG5vdCBjb3JyZXNwb25kIHRvIG1vdmllcwpgYGAKCiMjIDIuIERyb3Agcm93cyB3aXRoIG1pc3NpbmcgYEdyb3NzYCB2YWx1ZQoKU2luY2Ugb3VyIGdvYWwgaXMgdG8gbW9kZWwgYEdyb3NzYCByZXZlbnVlIGFnYWluc3Qgb3RoZXIgdmFyaWFibGVzLCByb3dzIHRoYXQgaGF2ZSBtaXNzaW5nIGBHcm9zc2AgdmFsdWVzIGFyZSBub3QgdXNlZnVsIHRvIHVzLgoKYGBge3J9CiMgVE9ETzogUmVtb3ZlIHJvd3Mgd2l0aCBtaXNzaW5nIEdyb3NzIHZhbHVlCmBgYAoKIyMgMy4gRXhjbHVkZSBtb3ZpZXMgcmVsZWFzZWQgcHJpb3IgdG8gMjAwMAoKSW5mbGF0aW9uIGFuZCBvdGhlciBnbG9iYWwgZmluYW5jaWFsIGZhY3RvcnMgbWF5IGFmZmVjdCB0aGUgcmV2ZW51ZSBlYXJuZWQgYnkgbW92aWVzIGR1cmluZyBjZXJ0YWluIHBlcmlvZHMgb2YgdGltZS4gVGFraW5nIHRoYXQgaW50byBhY2NvdW50IGlzIG91dCBvZiBzY29wZSBmb3IgdGhpcyBwcm9qZWN0LCBzbyBsZXQncyBleGNsdWRlIGFsbCBtb3ZpZXMgdGhhdCB3ZXJlIHJlbGVhc2VkIHByaW9yIHRvIHRoZSB5ZWFyIDIwMDAgKHlvdSBtYXkgdXNlIGBSZWxlYXNlZGAsIGBEYXRlYCBvciBgWWVhcmAgZm9yIHRoaXMgcHVycG9zZSkuCgpgYGB7cn0KIyBUT0RPOiBFeGNsdWRlIG1vdmllcyByZWxlYXNlZCBwcmlvciB0byAyMDAwCmBgYAoKIyMgNC4gRWxpbWluYXRlIG1pc21hdGNoZWQgcm93cwoKX05vdGU6IFlvdSBtYXkgY29tcGFyZSB0aGUgYFJlbGVhc2VkYCBjb2x1bW4gKHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiByZWxlYXNlIGRhdGUpIHdpdGggZWl0aGVyIGBZZWFyYCBvciBgRGF0ZWAgKG51bWVyaWMgcmVwcmVzZW50YXRpb24gb2YgdGhlIHllYXIpIHRvIGZpbmQgbWlzbWF0Y2hlcy4gVGhlIGdvYWwgaXMgdG8gYXZvaWQgcmVtb3ZpbmcgbW9yZSB0aGFuIDEwJSBvZiB0aGUgcm93cy5fCgpgYGB7cn0KIyBUT0RPOiBSZW1vdmUgbWlzbWF0Y2hlZCByb3dzCmBgYAoKIyMgNS4gRHJvcCBgRG9tZXN0aWNfR3Jvc3NgIGNvbHVtbgoKYERvbWVzdGljX0dyb3NzYCBpcyBiYXNpY2FsbHkgdGhlIGFtb3VudCBvZiByZXZlbnVlIGEgbW92aWUgZWFybmVkIHdpdGhpbiB0aGUgVVMuIFVuZGVyc3RhbmRhYmx5LCBpdCBpcyB2ZXJ5IGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggYEdyb3NzYCBhbmQgaXMgaW4gZmFjdCBlcXVhbCB0byBpdCBmb3IgbW92aWVzIHRoYXQgd2VyZSBub3QgcmVsZWFzZWQgZ2xvYmFsbHkuIEhlbmNlLCBpdCBzaG91bGQgYmUgcmVtb3ZlZCBmb3IgbW9kZWxpbmcgcHVycG9zZXMuCgpgYGB7cn0KIyBUT0RPOiBFeGNsdWRlIHRoZSBgRG9tZXN0aWNfR3Jvc3NgIGNvbHVtbgpgYGAKCiMjIDYuIFByb2Nlc3MgYFJ1bnRpbWVgIGNvbHVtbgoKYGBge3J9CiMgVE9ETzogUmVwbGFjZSBkZiRSdW50aW1lIHdpdGggYSBudW1lcmljIGNvbHVtbiBjb250YWluaW5nIHRoZSBydW50aW1lIGluIG1pbnV0ZXMKYGBgCgpQZXJmb3JtIGFueSBhZGRpdGlvbmFsIHByZXByb2Nlc3Npbmcgc3RlcHMgdGhhdCB5b3UgZmluZCBuZWNlc3NhcnksIHN1Y2ggYXMgZGVhbGluZyB3aXRoIG1pc3NpbmcgdmFsdWVzIG9yIGhpZ2hseSBjb3JyZWxhdGVkIGNvbHVtbnMgKGZlZWwgZnJlZSB0byBhZGQgbW9yZSBjb2RlIGNodW5rcywgbWFya2Rvd24gYmxvY2tzIGFuZCBwbG90cyBoZXJlIGFzIG5lY2Vzc2FyeSkuCgpgYGB7cn0KIyBUT0RPKG9wdGlvbmFsKTogQWRkaXRpb25hbCBwcmVwcm9jZXNzaW5nCmBgYAoKXyoqTm90ZSoqOiBEbyBOT1QgY29udmVydCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgKGxpa2UgYEdlbnJlYCkgaW50byBiaW5hcnkgY29sdW1ucyB5ZXQuIFlvdSB3aWxsIGRvIHRoYXQgbGF0ZXIgYXMgcGFydCBvZiBhIG1vZGVsIGltcHJvdmVtZW50IHRhc2suXwoKIyMgRmluYWwgcHJlcHJvY2Vzc2VkIGRhdGFzZXQKClJlcG9ydCB0aGUgZGltZW5zaW9ucyBvZiB0aGUgcHJlcHJvY2Vzc2VkIGRhdGFzZXQgeW91IHdpbGwgYmUgdXNpbmcgZm9yIG1vZGVsaW5nIGFuZCBldmFsdWF0aW9uLCBhbmQgcHJpbnQgYWxsIHRoZSBmaW5hbCBjb2x1bW4gbmFtZXMuIChBZ2FpbiwgYERvbWVzdGljX0dyb3NzYCBzaG91bGQgbm90IGJlIGluIHRoaXMgbGlzdCEpCgpgYGB7cn0KIyBUT0RPOiBQcmludCB0aGUgZGltZW5zaW9ucyBvZiB0aGUgZmluYWwgcHJlcHJvY2Vzc2VkIGRhdGFzZXQgYW5kIGNvbHVtbiBuYW1lcwpgYGAKCiMgRXZhbHVhdGlvbiBTdHJhdGVneQoKSW4gZWFjaCBvZiB0aGUgdGFza3MgZGVzY3JpYmVkIGluIHRoZSBuZXh0IHNlY3Rpb24sIHlvdSB3aWxsIGJ1aWxkIGEgcmVncmVzc2lvbiBtb2RlbC4gSW4gb3JkZXIgdG8gY29tcGFyZSB0aGVpciBwZXJmb3JtYW5jZSwgeW91IHdpbGwgY29tcHV0ZSB0aGUgdHJhaW5pbmcgYW5kIHRlc3QgUm9vdCBNZWFuIFNxdWFyZWQgRXJyb3IgKFJNU0UpIGF0IGRpZmZlcmVudCB0cmFpbmluZyBzZXQgc2l6ZXMuCgpGaXJzdCwgcmFuZG9tbHkgc2FtcGxlIDEwLTIwJSBvZiB0aGUgcHJlcHJvY2Vzc2VkIGRhdGFzZXQgYW5kIGtlZXAgdGhhdCBhc2lkZSBhcyB0aGUgKip0ZXN0IHNldCoqLiBEbyBub3QgdXNlIHRoZXNlIHJvd3MgZm9yIHRyYWluaW5nISBUaGUgcmVtYWluZGVyIG9mIHRoZSBwcmVwcm9jZXNzZWQgZGF0YXNldCBpcyB5b3VyICoqdHJhaW5pbmcgZGF0YSoqLgoKTm93IHVzZSB0aGUgZm9sbG93aW5nIGV2YWx1YXRpb24gcHJvY2VkdXJlIGZvciBlYWNoIG1vZGVsOgoKLSBDaG9vc2UgYSBzdWl0YWJsZSBzZXF1ZW5jZSBvZiB0cmFpbmluZyBzZXQgc2l6ZXMsIGUuZy4gMTAlLCAyMCUsIDMwJSwgLi4uLCAxMDAlICgxMC0yMCBkaWZmZXJlbnQgc2l6ZXMgc2hvdWxkIHN1ZmZpY2UpLiBGb3IgZWFjaCBzaXplLCBzYW1wbGUgdGhhdCBtYW55IGlucHV0cyBmcm9tIHRoZSB0cmFpbmluZyBkYXRhLCB0cmFpbiB5b3VyIG1vZGVsLCBhbmQgY29tcHV0ZSB0aGUgcmVzdWx0aW5nIHRyYWluaW5nIGFuZCB0ZXN0IFJNU0UuCi0gUmVwZWF0IHlvdXIgdHJhaW5pbmcgYW5kIGV2YWx1YXRpb24gYXQgbGVhc3QgMTAgdGltZXMgYXQgZWFjaCB0cmFpbmluZyBzZXQgc2l6ZSwgYW5kIGF2ZXJhZ2UgdGhlIFJNU0UgcmVzdWx0cyBmb3Igc3RhYmlsaXR5LgotIEdlbmVyYXRlIGEgZ3JhcGggb2YgdGhlIGF2ZXJhZ2VkIHRyYWluIGFuZCB0ZXN0IFJNU0UgdmFsdWVzIGFzIGEgZnVuY3Rpb24gb2YgdGhlIHRyYWluIHNldCBzaXplICglKSwgd2l0aCBvcHRpb25hbCBlcnJvciBiYXJzLgoKWW91IGNhbiBkZWZpbmUgYSBoZWxwZXIgZnVuY3Rpb24gdGhhdCBhcHBsaWVzIHRoaXMgcHJvY2VkdXJlIHRvIGEgZ2l2ZW4gc2V0IG9mIGZlYXR1cmVzIGFuZCByZXVzZSBpdC4KCiMgVGFza3MKCkVhY2ggb2YgdGhlIGZvbGxvd2luZyB0YXNrcyBpcyB3b3J0aCAyMCBwb2ludHMsIGZvciBhIHRvdGFsIG9mIDEwMCBwb2ludHMgZm9yIHRoaXMgcHJvamVjdC4gUmVtZW1iZXIgdG8gYnVpbGQgZWFjaCBtb2RlbCBhcyBzcGVjaWZpZWQsIGV2YWx1YXRlIGl0IHVzaW5nIHRoZSBzdHJhdGVneSBvdXRsaW5lZCBhYm92ZSwgYW5kIHBsb3QgdGhlIHRyYWluaW5nIGFuZCB0ZXN0IGVycm9ycyBieSB0cmFpbmluZyBzZXQgc2l6ZSAoJSkuCgojIyAxLiBOdW1lcmljIHZhcmlhYmxlcwoKVXNlIExpbmVhciBSZWdyZXNzaW9uIHRvIHByZWRpY3QgYEdyb3NzYCBiYXNlZCBvbiBhdmFpbGFibGUgX251bWVyaWNfIHZhcmlhYmxlcy4gWW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSBhbGwgb3IgYSBzdWJzZXQgb2YgdGhlbS4KCmBgYHtyfQojIFRPRE86IEJ1aWxkICYgZXZhbHVhdGUgbW9kZWwgMSAobnVtZXJpYyB2YXJpYWJsZXMgb25seSkKYGBgCgoqKlEqKjogTGlzdCB0aGUgbnVtZXJpYyB2YXJpYWJsZXMgeW91IHVzZWQuCgoqKkEqKjogCgoKKipRKio6IFdoYXQgaXMgdGhlIGJlc3QgbWVhbiB0ZXN0IFJNU0UgdmFsdWUgeW91IG9ic2VydmVkLCBhbmQgYXQgd2hhdCB0cmFpbmluZyBzZXQgc2l6ZT8KCioqQSoqOiAKCgojIyAyLiBGZWF0dXJlIHRyYW5zZm9ybWF0aW9ucwoKVHJ5IHRvIGltcHJvdmUgdGhlIHByZWRpY3Rpb24gcXVhbGl0eSBmcm9tICoqVGFzayAxKiogYXMgbXVjaCBhcyBwb3NzaWJsZSBieSBhZGRpbmcgZmVhdHVyZSB0cmFuc2Zvcm1hdGlvbnMgb2YgdGhlIG51bWVyaWMgdmFyaWFibGVzLiBFeHBsb3JlIGJvdGggbnVtZXJpYyB0cmFuc2Zvcm1hdGlvbnMgc3VjaCBhcyBwb3dlciB0cmFuc2Zvcm1zIGFuZCBub24tbnVtZXJpYyB0cmFuc2Zvcm1hdGlvbnMgb2YgdGhlIG51bWVyaWMgdmFyaWFibGVzIGxpa2UgYmlubmluZyAoZS5nLiBgaXNfYnVkZ2V0X2dyZWF0ZXJfdGhhbl8zTWApLgoKYGBge3J9CiMgVE9ETzogQnVpbGQgJiBldmFsdWF0ZSBtb2RlbCAyICh0cmFuc2Zvcm1lZCBudW1lcmljIHZhcmlhYmxlcyBvbmx5KQpgYGAKCioqUSoqOiBFeHBsYWluIHdoaWNoIHRyYW5zZm9ybWF0aW9ucyB5b3UgdXNlZCBhbmQgd2h5IHlvdSBjaG9zZSB0aGVtLgoKKipBKio6IAoKCioqUSoqOiBIb3cgZGlkIHRoZSBSTVNFIGNoYW5nZSBjb21wYXJlZCB0byBUYXNrIDE/CgoqKkEqKjogCgoKIyMgMy4gTm9uLW51bWVyaWMgdmFyaWFibGVzCgpXcml0ZSBjb2RlIHRoYXQgY29udmVydHMgZ2VucmUsIGFjdG9ycywgZGlyZWN0b3JzLCBhbmQgb3RoZXIgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHRvIGNvbHVtbnMgdGhhdCBjYW4gYmUgdXNlZCBmb3IgcmVncmVzc2lvbiAoZS5nLiBiaW5hcnkgY29sdW1ucyBhcyB5b3UgZGlkIGluIFByb2plY3QgMSkuIEFsc28gcHJvY2VzcyB2YXJpYWJsZXMgc3VjaCBhcyBhd2FyZHMgaW50byBtb3JlIHVzZWZ1bCBjb2x1bW5zIChhZ2FpbiwgbGlrZSB5b3UgZGlkIGluIFByb2plY3QgMSkuIE5vdyB1c2UgdGhlc2UgY29udmVydGVkIGNvbHVtbnMgb25seSB0byBidWlsZCB5b3VyIG5leHQgbW9kZWwuCgpgYGB7cn0KIyBUT0RPOiBCdWlsZCAmIGV2YWx1YXRlIG1vZGVsIDMgKGNvbnZlcnRlZCBub24tbnVtZXJpYyB2YXJpYWJsZXMgb25seSkKYGBgCgoqKlEqKjogRXhwbGFpbiB3aGljaCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgeW91IHVzZWQsIGFuZCBob3cgeW91IGVuY29kZWQgdGhlbSBpbnRvIGZlYXR1cmVzLgoKKipBKio6IAoKCioqUSoqOiBXaGF0IGlzIHRoZSBiZXN0IG1lYW4gdGVzdCBSTVNFIHZhbHVlIHlvdSBvYnNlcnZlZCwgYW5kIGF0IHdoYXQgdHJhaW5pbmcgc2V0IHNpemU/IEhvdyBkb2VzIHRoaXMgY29tcGFyZSB3aXRoIFRhc2sgMj8KCioqQSoqOiAKCgojIyA0LiBOdW1lcmljIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKClRyeSB0byBpbXByb3ZlIHRoZSBwcmVkaWN0aW9uIHF1YWxpdHkgYXMgbXVjaCBhcyBwb3NzaWJsZSBieSB1c2luZyBib3RoIG51bWVyaWMgYW5kIG5vbi1udW1lcmljIHZhcmlhYmxlcyBmcm9tICoqVGFza3MgMiAmIDMqKi4KCmBgYHtyfQojIFRPRE86IEJ1aWxkICYgZXZhbHVhdGUgbW9kZWwgNCAobnVtZXJpYyAmIGNvbnZlcnRlZCBub24tbnVtZXJpYyB2YXJpYWJsZXMpCmBgYAoKKipRKio6IENvbXBhcmUgdGhlIG9ic2VydmVkIFJNU0Ugd2l0aCBUYXNrcyAyICYgMy4KCioqQSoqOiAKCgojIyA1LiBBZGRpdGlvbmFsIGZlYXR1cmVzCgpOb3cgdHJ5IGNyZWF0aW5nIGFkZGl0aW9uYWwgZmVhdHVyZXMgc3VjaCBhcyBpbnRlcmFjdGlvbnMgKGUuZy4gYGlzX2dlbnJlX2NvbWVkeWAgeCBgaXNfYnVkZ2V0X2dyZWF0ZXJfdGhhbl8zTWApIG9yIGRlZXBlciBhbmFseXNpcyBvZiBjb21wbGV4IHZhcmlhYmxlcyAoZS5nLiB0ZXh0IGFuYWx5c2lzIG9mIGZ1bGwtdGV4dCBjb2x1bW5zIGxpa2UgYFBsb3RgKS4KCmBgYHtyfQojIFRPRE86IEJ1aWxkICYgZXZhbHVhdGUgbW9kZWwgNSAobnVtZXJpYywgbm9uLW51bWVyaWMgYW5kIGFkZGl0aW9uYWwgZmVhdHVyZXMpCmBgYAoKKipRKio6IEV4cGxhaW4gd2hhdCBuZXcgZmVhdHVyZXMgeW91IGRlc2lnbmVkIGFuZCB3aHkgeW91IGNob3NlIHRoZW0uCgoqKkEqKjogCgoKKipRKio6IENvbW1lbnQgb24gdGhlIGZpbmFsIFJNU0UgdmFsdWVzIHlvdSBvYnRhaW5lZCwgYW5kIHdoYXQgeW91IGxlYXJuZWQgdGhyb3VnaCB0aGUgY291cnNlIG9mIHRoaXMgcHJvamVjdC4KCioqQSoqOgoK