Final Assignment 1: Airbnb analysis from August 2008 until April 2017

Libraries and data

#load libraries
library(tidyverse)
library(dplyr)
library(ggplot2)
library(ggthemes)

#import data
airbnb_listings <- read.csv("~/MSc Business Analytics/1. Business Intelligence/airbnb_listings.csv")
View(airbnb_listings)

Question 1 Examine data set and identify any problems with data

#1.a. Describe problems in data and provide analysis.

Ans1a: There are two variables with main issues: -license with 90.69% of blanks and 9.29% of zeros for a total of 99,97% of anomalies.
-neighbourhood_group with 87.29%.of blanks and 7.13% of zeros for a total of 94.42% of anomalous values.

glimpse(airbnb_listings)
Rows: 97,387
Columns: 19
$ city                           <chr> "Bristol", "Bristol", "Bristol", "Bristol", "Bristol", "Br…
$ id                             <dbl> 70820, 117122, 176306, 307634, 390781, 399681, 407485, 421…
$ name                           <chr> "Townhouse in Bristol · ★4.77 · 1 bedroom · 1 bed · 1 shar…
$ host_id                        <int> 360195, 591555, 708175, 1582810, 1954565, 1941316, 2029719…
$ host_name                      <chr> "Sarah", "Marcus", "Orla", "Wendy", "Fiona", "Kevin & Lesl…
$ neighbourhood_group            <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""…
$ neighbourhood                  <chr> "Windmill Hill", "Hotwells & Harbourside", "Southville", "…
$ latitude                       <dbl> 51.43843, 51.44976, 51.44174, 51.46487, 51.44444, 51.49491…
$ longitude                      <dbl> -2.59183, -2.61000, -2.60297, -2.55690, -2.55783, -2.61879…
$ room_type                      <chr> "Private room", "Private room", "Private room", "Private r…
$ price                          <int> 41, 96, 32, 38, 35, 80, 97, 45, 205, 60, 149, 30, 145, 32,…
$ minimum_nights                 <int> 4, 1, 5, 6, 2, 2, 2, 4, 2, 1, 2, 7, 2, 3, 2, 1, 1, 7, 2, 1…
$ number_of_reviews              <int> 182, 177, 48, 32, 54, 96, 316, 191, NA, 271, 462, 9, 346, …
$ last_review                    <chr> "04/06/2023", "21/06/2023", "07/06/2023", "31/01/2023", "2…
$ reviews_per_month              <dbl> 1.54, 1.21, 0.37, 0.43, 0.39, 0.72, 2.33, 1.44, NA, 2.03, …
$ calculated_host_listings_count <int> 5, 1, 1, 3, 2, 1, 1, 1, NA, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, …
$ availability_365               <int> 0, 0, 0, 0, 0, 0, 0, 0, NA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ number_of_reviews_ltm          <int> 11, 13, 9, 4, 6, 11, 17, 11, NA, 53, 34, 0, 50, 0, 32, 39,…
$ license                        <chr> "0", "0", "0", "0", "0", "0", "0", "0", "", "0", "0", "0",…
xray::anomalies(airbnb_listings)
Warning in xray::anomalies(airbnb_listings) :
  Found 2 possible problematic variables: 
license, neighbourhood_group
$variables

$problem_variables
NA

##1.b.Fix any problems you’ve identified with the data set. Code your solution in R Assessment Notebook. Justify your data cleaning decisions.

Ans 1b: - For license, delete the variable due to the high number of anomalies

airbnb_listings<-airbnb_listings[, -19]
airbnb_listings$neighbourhood_group<-ifelse(is.na(airbnb_listings$neighbourhood_group), airbnb_listings$neighbourhood, airbnb_listings$neighbourhood_group)
airbnb_listings$neighbourhood_group[airbnb_listings$neighbourhood_group == ""] <- airbnb_listings$neighbourhood
Warning in airbnb_listings$neighbourhood_group[airbnb_listings$neighbourhood_group ==  :
  number of items to replace is not a multiple of replacement length
airbnb_listings

Question 2. Run exploratory analysis in R on Airbnb dataset.

2.a. Explore the variation in trends between cities in the context of other variables in the data set using visual analytics. Use at least four different types of graphs. Briefly explain why you’ve selected each of those graphs for specific variables.

Ans 2a ##1. Barchart: understand the distribution of observations by city ##2. Understand the distribution of price, minumum_nights and number_of_reviews by city. ##3. Barchart room_type: it is a key variable for reviews. Also, fill the blanks with “no information” ##4. Analyse the influence of room types by city. ##5. Barchart to understand which room type has more reviews per city. ##6. Overall analysis

  ggplot(airbnb_listings)+
  geom_bar(aes(x=reorder(city, table (city)[city])), fill = "yellow",width=0.5)+
  coord_flip()+
  theme_bw(base_line_size = 0) +
  ggtitle("1. Distribution of cities")+
  labs(x=NULL)


airbnb_listings%>%
 gather(features, Value, price:number_of_reviews, factor_key = TRUE) %>%
  ggplot(aes(x=city, y=Value)) +
  geom_point(size=0.5) + 
  geom_smooth(se=F)+
  ggtitle("2. Key variables by city")+
  facet_wrap(~features, scales = "free") + 
  theme_bw()
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
Warning: Removed 18522 rows containing non-finite outside the scale range (`stat_smooth()`).
Warning: Removed 18522 rows containing missing values or values outside the scale range (`geom_point()`).

airbnb_listings$room_type[airbnb_listings$room_type == ""] <- "No information" 
ggplot(airbnb_listings)+
  geom_bar(aes(x=reorder(room_type, table (room_type)[room_type])), fill = "lightblue",width=0.5)+
  coord_flip()+
  theme_bw(base_line_size = 0) +
  ggtitle("3. Distribution of Room types")+
  labs(x=NULL)


airbnb_listings %>%
  ggplot(aes(y = room_type, x = price, col = city)) +
  geom_jitter() +
  geom_smooth(method='lm', se=F) +
  ggtitle("4. Room types by city")+
  facet_wrap(~ city, scales = "free") +
  theme_bw()
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 3938 rows containing non-finite outside the scale range (`stat_smooth()`).
Warning: Removed 3938 rows containing missing values or values outside the scale range (`geom_point()`).

airbnb_listings %>%
  ggplot(aes(x=reorder(room_type, number_of_reviews), y = number_of_reviews, fill=city)) +
  geom_bar(width = 0.5, stat = "identity") +
  coord_flip() +
  theme_bw(base_line_size = 0)+
  labs(title = "5. Reviews and room type by city", x= NULL)
Warning: Removed 7513 rows containing missing values or values outside the scale range (`geom_bar()`).

skimr::skim(airbnb_listings)
── Data Summary ────────────────────────
                           Values         
Name                       airbnb_listings
Number of rows             97387          
Number of columns          18             
_______________________                   
Column type frequency:                    
  character                7              
  numeric                  11             
________________________                  
Group variables            None           

##2.b.With the goal being improving the number of reviews left by customers, what are the exploratory questions you would ask about this data set? List at least three such questions and provide answers to each of those questions by coding solutions in R Assessment Notebook.

Ans 2b

  1. Which room type has the highest number of reviews? Entire home is the room type with the highest number of reviews followed by private room.

  2. Does the price matter in having high number of reviews? Yes, price and number of reviews has an inverse relationship. Clients paying less price gave more number of reviews.

  3. Which city has more reviews per month? London is the city with more reviews per month. However, in terms of number of reviews (see illustration 2 question 2a), Edinburgh has more proportionally.

  4. Is the number of nights related to the number of reviews? Stays with 150 nights or less has more number of reviews. Mainly, short stays are related with more number of reviews.

airbnb_listings %>%
  ggplot(aes(x="", y = number_of_reviews, fill=room_type)) +
  geom_col()+
  coord_polar(theta = "y") +
  ggtitle("1. Reviews per room type ")+
  theme_void()
Warning: Removed 7513 rows containing missing values or values outside the scale range (`geom_col()`).

airbnb_listings %>%
  ggplot(aes(y = number_of_reviews, x = price)) +
  geom_point(position = "jitter")+
  labs(title = "2. Price and number of reviews")+
  theme_bw()
Warning: Removed 11118 rows containing missing values or values outside the scale range (`geom_point()`).

airbnb_listings %>%
  ggplot(aes(x=city, y = reviews_per_month)) +
  geom_bar(width = 0.5, stat = "identity") +
  coord_flip() +
  ggtitle("3. Reviews per month by city")+
  theme_bw(base_line_size = 0)+
  labs(x= NULL)
Warning: Removed 8463 rows containing missing values or values outside the scale range (`geom_bar()`).

airbnb_listings %>%
  ggplot(aes(y = number_of_reviews, x = minimum_nights)) +
  geom_point(position = "jitter")+
  labs(title = "4. Nights per number of reviews")+
  theme_bw()
Warning: Removed 11133 rows containing missing values or values outside the scale range (`geom_point()`).

Question 3. Summarise your findings in R Assessment Notebook.

##3.a. Write a short set of recommendations you would give to a new Airbnb host based on your entire analysis.

Ans 3a

  1. Offer entire homes/apartments or private rooms because those types of rooms get more reviews.

  2. Prioritise short stays to have more reviews.

  3. Provide a competitive price since it is valued by clients in terms of reviews.

  4. London and Edinburgh are attractive cities for clients, and you can get more reviews per month. Besides, London stays can be longer.

##3.b. Provide three key graphs you would share with the hosts that best capture your results.

Ans 3b 1. Room types with more reviews by city. 2. Room types and distribution of minimum nights by city. 3. Room types and distribution of price by city

airbnb_listings %>%
  ggplot(aes(y = room_type, x = number_of_reviews, col = city)) +
  geom_jitter() +
  geom_smooth(method='lm', se=F) +
  ggtitle("1. Room types with more reviews by city")+
  facet_wrap(~ city, scales = "free") +
  theme_bw()
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 7513 rows containing non-finite outside the scale range (`stat_smooth()`).
Warning: Removed 7513 rows containing missing values or values outside the scale range (`geom_point()`).

airbnb_listings %>%
  ggplot(aes(y = room_type, x = minimum_nights, col = city)) +
  geom_jitter() +
  geom_smooth(method='lm', se=F) +
  ggtitle("2. Room types and minimum nights by city")+
  facet_wrap(~ city, scales = "free") +
  theme_bw()
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 7071 rows containing non-finite outside the scale range (`stat_smooth()`).
Warning: Removed 7071 rows containing missing values or values outside the scale range (`geom_point()`).

airbnb_listings %>%
  ggplot(aes(y = room_type, x = price, col = city)) +
  geom_jitter() +
  geom_smooth(method='lm', se=F) +
  ggtitle("3. Room types and distribution of price by city")+
  facet_wrap(~ city, scales = "free") +
  theme_bw()
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 3938 rows containing non-finite outside the scale range (`stat_smooth()`).
Warning: Removed 3938 rows containing missing values or values outside the scale range (`geom_point()`).

LS0tDQp0aXRsZTogIkZpbmFsIGFzc2Vzc21lbnQgcGFydCAxIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCioqRmluYWwgQXNzaWdubWVudCAxOiBBaXJibmIgYW5hbHlzaXMgZnJvbSBBdWd1c3QgMjAwOCB1bnRpbCBBcHJpbCAyMDE3KiogDQoNCioqTGlicmFyaWVzIGFuZCBkYXRhKioNCmBgYHtyfQ0KI2xvYWQgbGlicmFyaWVzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KDQojaW1wb3J0IGRhdGENCmFpcmJuYl9saXN0aW5ncyA8LSByZWFkLmNzdigifi9NU2MgQnVzaW5lc3MgQW5hbHl0aWNzLzEuIEJ1c2luZXNzIEludGVsbGlnZW5jZS9haXJibmJfbGlzdGluZ3MuY3N2IikNClZpZXcoYWlyYm5iX2xpc3RpbmdzKQ0KYGBgDQoNCioqUXVlc3Rpb24gMSBFeGFtaW5lIGRhdGEgc2V0IGFuZCBpZGVudGlmeSBhbnkgcHJvYmxlbXMgd2l0aCBkYXRhKioNCg0KIyoqMS5hLioqIERlc2NyaWJlIHByb2JsZW1zIGluIGRhdGEgYW5kIHByb3ZpZGUgYW5hbHlzaXMuIA0KDQoqKkFuczFhOioqIFRoZXJlIGFyZSB0d28gdmFyaWFibGVzIHdpdGggbWFpbiBpc3N1ZXM6IA0KLWxpY2Vuc2Ugd2l0aCA5MC42OSUgb2YgYmxhbmtzIGFuZCA5LjI5JSBvZiB6ZXJvcyBmb3IgYSB0b3RhbCBvZiA5OSw5NyUgb2YgYW5vbWFsaWVzLiAgDQotbmVpZ2hib3VyaG9vZF9ncm91cCB3aXRoIDg3LjI5JS5vZiBibGFua3MgYW5kIDcuMTMlIG9mIHplcm9zIGZvciBhIHRvdGFsIG9mIDk0LjQyJSBvZiBhbm9tYWxvdXMgdmFsdWVzLg0KYGBge3J9DQpnbGltcHNlKGFpcmJuYl9saXN0aW5ncykNCnhyYXk6OmFub21hbGllcyhhaXJibmJfbGlzdGluZ3MpDQpgYGANCg0KIyMqKjEuYi4qKkZpeCBhbnkgcHJvYmxlbXMgeW914oCZdmUgaWRlbnRpZmllZCB3aXRoIHRoZSBkYXRhIHNldC4gQ29kZSB5b3VyIHNvbHV0aW9uIGluIFIgQXNzZXNzbWVudCBOb3RlYm9vay4gSnVzdGlmeSB5b3VyIGRhdGEgY2xlYW5pbmcgZGVjaXNpb25zLg0KDQoqKkFucyAxYjoqKiANCi0gRm9yIGxpY2Vuc2UsIGRlbGV0ZSB0aGUgdmFyaWFibGUgZHVlIHRvIHRoZSBoaWdoIG51bWJlciBvZiBhbm9tYWxpZXMNCg0KLSBGb3IgbmVpZ2hib3VyaG9vZF9ncm91cCBmaWxsIGJsYW5rcyBhbmQgTkEgd2l0aCB0aGUgbmVpZ2hib3VyaG9vZCBpbmZvcm1hdGlvbiBiZWNhdXNlIGJ5IGRlZmluaXRpb24gdGhleSBhcmUgY2xvc2VyLiANCioqTmVpZ2hib3VyaG9vZF9ncm91cDoqKiBUaGUgbmVpZ2hib3VyaG9vZCBncm91cCBhcyBnZW9jb2RlZCB1c2luZyB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBhZ2FpbnN0IG5laWdoYm9yaG9vZHMgYXMgZGVmaW5lZCBieSBvcGVuIG9yIHB1YmxpYyBkaWdpdGFsIHNoYXBlZmlsZXMuDQoqKk5laWdoYm91cmhvb2Q6KiogVGhlIG5laWdoYm91cmhvb2QgYXMgZ2VvY29kZWQgdXNpbmcgdGhlIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgYWdhaW5zdCBuZWlnaGJvcmhvb2RzIGFzIGRlZmluZWQgYnkgb3BlbiBvciBwdWJsaWMgZGlnaXRhbCBzaGFwZWZpbGVzLg0KYGBge3J9DQphaXJibmJfbGlzdGluZ3M8LWFpcmJuYl9saXN0aW5nc1ssIC0xOV0NCmFpcmJuYl9saXN0aW5ncyRuZWlnaGJvdXJob29kX2dyb3VwPC1pZmVsc2UoaXMubmEoYWlyYm5iX2xpc3RpbmdzJG5laWdoYm91cmhvb2RfZ3JvdXApLCBhaXJibmJfbGlzdGluZ3MkbmVpZ2hib3VyaG9vZCwgYWlyYm5iX2xpc3RpbmdzJG5laWdoYm91cmhvb2RfZ3JvdXApDQphaXJibmJfbGlzdGluZ3MkbmVpZ2hib3VyaG9vZF9ncm91cFthaXJibmJfbGlzdGluZ3MkbmVpZ2hib3VyaG9vZF9ncm91cCA9PSAiIl0gPC0gYWlyYm5iX2xpc3RpbmdzJG5laWdoYm91cmhvb2QNCmFpcmJuYl9saXN0aW5ncw0KYGBgDQoNCioqUXVlc3Rpb24gMi4gUnVuIGV4cGxvcmF0b3J5IGFuYWx5c2lzIGluIFIgb24gQWlyYm5iIGRhdGFzZXQuKioNCg0KKioyLmEuKiogRXhwbG9yZSB0aGUgdmFyaWF0aW9uIGluIHRyZW5kcyBiZXR3ZWVuIGNpdGllcyBpbiB0aGUgY29udGV4dCBvZiBvdGhlciB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0IHVzaW5nIHZpc3VhbCBhbmFseXRpY3MuIFVzZSBhdCBsZWFzdCBmb3VyIGRpZmZlcmVudCB0eXBlcyBvZiBncmFwaHMuIEJyaWVmbHkgZXhwbGFpbiB3aHkgeW91J3ZlIHNlbGVjdGVkIGVhY2ggb2YgdGhvc2UgZ3JhcGhzIGZvciBzcGVjaWZpYyB2YXJpYWJsZXMuDQoNCioqQW5zIDJhKioNCiMjMS4gQmFyY2hhcnQ6IHVuZGVyc3RhbmQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZhdGlvbnMgYnkgY2l0eQ0KIyMyLiBVbmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2YgcHJpY2UsIG1pbnVtdW1fbmlnaHRzIGFuZCBudW1iZXJfb2ZfcmV2aWV3cyBieSBjaXR5LiANCiMjMy4gQmFyY2hhcnQgcm9vbV90eXBlOiBpdCBpcyBhIGtleSB2YXJpYWJsZSBmb3IgcmV2aWV3cy4gQWxzbywgZmlsbCB0aGUgYmxhbmtzIHdpdGggIm5vIGluZm9ybWF0aW9uIg0KIyM0LiBBbmFseXNlIHRoZSBpbmZsdWVuY2Ugb2Ygcm9vbSB0eXBlcyBieSBjaXR5LiANCiMjNS4gQmFyY2hhcnQgdG8gdW5kZXJzdGFuZCB3aGljaCByb29tIHR5cGUgaGFzIG1vcmUgcmV2aWV3cyBwZXIgY2l0eS4gDQojIzYuIE92ZXJhbGwgYW5hbHlzaXMNCmBgYHtyfQ0KICBnZ3Bsb3QoYWlyYm5iX2xpc3RpbmdzKSsNCiAgZ2VvbV9iYXIoYWVzKHg9cmVvcmRlcihjaXR5LCB0YWJsZSAoY2l0eSlbY2l0eV0pKSwgZmlsbCA9ICJ5ZWxsb3ciLHdpZHRoPTAuNSkrDQogIGNvb3JkX2ZsaXAoKSsNCiAgdGhlbWVfYncoYmFzZV9saW5lX3NpemUgPSAwKSArDQogIGdndGl0bGUoIjEuIERpc3RyaWJ1dGlvbiBvZiBjaXRpZXMiKSsNCiAgbGFicyh4PU5VTEwpDQoNCmFpcmJuYl9saXN0aW5ncyU+JQ0KIGdhdGhlcihmZWF0dXJlcywgVmFsdWUsIHByaWNlOm51bWJlcl9vZl9yZXZpZXdzLCBmYWN0b3Jfa2V5ID0gVFJVRSkgJT4lDQogIGdncGxvdChhZXMoeD1jaXR5LCB5PVZhbHVlKSkgKw0KICBnZW9tX3BvaW50KHNpemU9MC41KSArIA0KICBnZW9tX3Ntb290aChzZT1GKSsNCiAgZ2d0aXRsZSgiMi4gS2V5IHZhcmlhYmxlcyBieSBjaXR5IikrDQogIGZhY2V0X3dyYXAofmZlYXR1cmVzLCBzY2FsZXMgPSAiZnJlZSIpICsgDQogIHRoZW1lX2J3KCkNCg0KYWlyYm5iX2xpc3RpbmdzJHJvb21fdHlwZVthaXJibmJfbGlzdGluZ3Mkcm9vbV90eXBlID09ICIiXSA8LSAiTm8gaW5mb3JtYXRpb24iIA0KZ2dwbG90KGFpcmJuYl9saXN0aW5ncykrDQogIGdlb21fYmFyKGFlcyh4PXJlb3JkZXIocm9vbV90eXBlLCB0YWJsZSAocm9vbV90eXBlKVtyb29tX3R5cGVdKSksIGZpbGwgPSAibGlnaHRibHVlIix3aWR0aD0wLjUpKw0KICBjb29yZF9mbGlwKCkrDQogIHRoZW1lX2J3KGJhc2VfbGluZV9zaXplID0gMCkgKw0KICBnZ3RpdGxlKCIzLiBEaXN0cmlidXRpb24gb2YgUm9vbSB0eXBlcyIpKw0KICBsYWJzKHg9TlVMTCkNCg0KYWlyYm5iX2xpc3RpbmdzICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSByb29tX3R5cGUsIHggPSBwcmljZSwgY29sID0gY2l0eSkpICsNCiAgZ2VvbV9qaXR0ZXIoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzZT1GKSArDQogIGdndGl0bGUoIjQuIFJvb20gdHlwZXMgYnkgY2l0eSIpKw0KICBmYWNldF93cmFwKH4gY2l0eSwgc2NhbGVzID0gImZyZWUiKSArDQogIHRoZW1lX2J3KCkNCg0KYWlyYm5iX2xpc3RpbmdzICU+JQ0KICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihyb29tX3R5cGUsIG51bWJlcl9vZl9yZXZpZXdzKSwgeSA9IG51bWJlcl9vZl9yZXZpZXdzLCBmaWxsPWNpdHkpKSArDQogIGdlb21fYmFyKHdpZHRoID0gMC41LCBzdGF0ID0gImlkZW50aXR5IikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZV9idyhiYXNlX2xpbmVfc2l6ZSA9IDApKw0KICBsYWJzKHRpdGxlID0gIjUuIFJldmlld3MgYW5kIHJvb20gdHlwZSBieSBjaXR5IiwgeD0gTlVMTCkNCg0Kc2tpbXI6OnNraW0oYWlyYm5iX2xpc3RpbmdzKQ0KYGBgDQoNCiMjKioyLmIuKipXaXRoIHRoZSBnb2FsIGJlaW5nIGltcHJvdmluZyB0aGUgbnVtYmVyIG9mIHJldmlld3MgbGVmdCBieSBjdXN0b21lcnMsIHdoYXQgYXJlIHRoZSBleHBsb3JhdG9yeSBxdWVzdGlvbnMgeW91IHdvdWxkIGFzayBhYm91dCB0aGlzIGRhdGEgc2V0PyBMaXN0IGF0IGxlYXN0IHRocmVlIHN1Y2ggcXVlc3Rpb25zIGFuZCBwcm92aWRlIGFuc3dlcnMgdG8gZWFjaCBvZiB0aG9zZSBxdWVzdGlvbnMgYnkgY29kaW5nIHNvbHV0aW9ucyBpbiBSIEFzc2Vzc21lbnQgTm90ZWJvb2suDQoNCioqQW5zIDJiKioNCg0KMS4gV2hpY2ggcm9vbSB0eXBlIGhhcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgcmV2aWV3cz8NCkVudGlyZSBob21lIGlzIHRoZSByb29tIHR5cGUgd2l0aCB0aGUgaGlnaGVzdCBudW1iZXIgb2YgcmV2aWV3cyBmb2xsb3dlZCBieSBwcml2YXRlIHJvb20uIA0KDQoyLiBEb2VzIHRoZSBwcmljZSBtYXR0ZXIgaW4gaGF2aW5nIGhpZ2ggbnVtYmVyIG9mIHJldmlld3M/DQpZZXMsIHByaWNlIGFuZCBudW1iZXIgb2YgcmV2aWV3cyBoYXMgYW4gaW52ZXJzZSByZWxhdGlvbnNoaXAuIENsaWVudHMgcGF5aW5nIGxlc3MgcHJpY2UgZ2F2ZSBtb3JlIG51bWJlciBvZiByZXZpZXdzLiANCg0KMy4gV2hpY2ggY2l0eSBoYXMgbW9yZSByZXZpZXdzIHBlciBtb250aD8NCkxvbmRvbiBpcyB0aGUgY2l0eSB3aXRoIG1vcmUgcmV2aWV3cyBwZXIgbW9udGguIEhvd2V2ZXIsIGluIHRlcm1zIG9mIG51bWJlciBvZiByZXZpZXdzIChzZWUgaWxsdXN0cmF0aW9uIDIgcXVlc3Rpb24gMmEpLCBFZGluYnVyZ2ggaGFzIG1vcmUgcHJvcG9ydGlvbmFsbHkuIA0KDQoNCjQuIElzIHRoZSBudW1iZXIgb2YgbmlnaHRzIHJlbGF0ZWQgdG8gdGhlIG51bWJlciBvZiByZXZpZXdzPw0KU3RheXMgd2l0aCAxNTAgbmlnaHRzIG9yIGxlc3MgaGFzIG1vcmUgbnVtYmVyIG9mIHJldmlld3MuIE1haW5seSwgc2hvcnQgc3RheXMgYXJlIHJlbGF0ZWQgd2l0aCBtb3JlIG51bWJlciBvZiByZXZpZXdzLiANCg0KYGBge3J9DQphaXJibmJfbGlzdGluZ3MgJT4lDQogIGdncGxvdChhZXMoeD0iIiwgeSA9IG51bWJlcl9vZl9yZXZpZXdzLCBmaWxsPXJvb21fdHlwZSkpICsNCiAgZ2VvbV9jb2woKSsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsNCiAgZ2d0aXRsZSgiMS4gUmV2aWV3cyBwZXIgcm9vbSB0eXBlICIpKw0KICB0aGVtZV92b2lkKCkNCg0KYWlyYm5iX2xpc3RpbmdzICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBudW1iZXJfb2ZfcmV2aWV3cywgeCA9IHByaWNlKSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpKw0KICBsYWJzKHRpdGxlID0gIjIuIFByaWNlIGFuZCBudW1iZXIgb2YgcmV2aWV3cyIpKw0KICB0aGVtZV9idygpDQoNCmFpcmJuYl9saXN0aW5ncyAlPiUNCiAgZ2dwbG90KGFlcyh4PWNpdHksIHkgPSByZXZpZXdzX3Blcl9tb250aCkpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAwLjUsIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGdndGl0bGUoIjMuIFJldmlld3MgcGVyIG1vbnRoIGJ5IGNpdHkiKSsNCiAgdGhlbWVfYncoYmFzZV9saW5lX3NpemUgPSAwKSsNCiAgbGFicyh4PSBOVUxMKQ0KDQphaXJibmJfbGlzdGluZ3MgJT4lDQogIGdncGxvdChhZXMoeSA9IG51bWJlcl9vZl9yZXZpZXdzLCB4ID0gbWluaW11bV9uaWdodHMpKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikrDQogIGxhYnModGl0bGUgPSAiNC4gTmlnaHRzIHBlciBudW1iZXIgb2YgcmV2aWV3cyIpKw0KICB0aGVtZV9idygpDQoNCg0KYGBgDQoNCioqUXVlc3Rpb24gMy4gU3VtbWFyaXNlIHlvdXIgZmluZGluZ3MgaW4gUiBBc3Nlc3NtZW50IE5vdGVib29rLioqDQoNCiMjKiozLmEuKiogV3JpdGUgYSBzaG9ydCBzZXQgb2YgcmVjb21tZW5kYXRpb25zIHlvdSB3b3VsZCBnaXZlIHRvIGEgbmV3IEFpcmJuYiBob3N0IGJhc2VkIG9uIHlvdXIgZW50aXJlIGFuYWx5c2lzLg0KDQoqKkFucyAzYSoqDQoNCjEuIE9mZmVyIGVudGlyZSBob21lcy9hcGFydG1lbnRzIG9yIHByaXZhdGUgcm9vbXMgYmVjYXVzZSB0aG9zZSB0eXBlcyBvZiByb29tcyBnZXQgbW9yZSByZXZpZXdzLg0KDQoyLiBQcmlvcml0aXNlIHNob3J0IHN0YXlzIHRvIGhhdmUgbW9yZSByZXZpZXdzLiANCg0KMy4gUHJvdmlkZSBhIGNvbXBldGl0aXZlIHByaWNlIHNpbmNlIGl0IGlzIHZhbHVlZCBieSBjbGllbnRzIGluIHRlcm1zIG9mIHJldmlld3MuIA0KDQo0LiBMb25kb24gYW5kIEVkaW5idXJnaCBhcmUgYXR0cmFjdGl2ZSBjaXRpZXMgZm9yIGNsaWVudHMsIGFuZCB5b3UgY2FuIGdldCBtb3JlIHJldmlld3MgcGVyIG1vbnRoLiBCZXNpZGVzLCBMb25kb24gc3RheXMgY2FuIGJlIGxvbmdlci4gIA0KDQojIyoqMy5iLioqIFByb3ZpZGUgdGhyZWUga2V5IGdyYXBocyB5b3Ugd291bGQgc2hhcmUgd2l0aCB0aGUgaG9zdHMgdGhhdCBiZXN0IGNhcHR1cmUgeW91ciByZXN1bHRzLg0KDQoqKkFucyAzYioqDQoxLiBSb29tIHR5cGVzIHdpdGggbW9yZSByZXZpZXdzIGJ5IGNpdHkuIA0KMi4gUm9vbSB0eXBlcyBhbmQgZGlzdHJpYnV0aW9uIG9mIG1pbmltdW0gbmlnaHRzIGJ5IGNpdHkuIA0KMy4gUm9vbSB0eXBlcyBhbmQgZGlzdHJpYnV0aW9uIG9mIHByaWNlIGJ5IGNpdHkNCmBgYHtyfQ0KYWlyYm5iX2xpc3RpbmdzICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSByb29tX3R5cGUsIHggPSBudW1iZXJfb2ZfcmV2aWV3cywgY29sID0gY2l0eSkpICsNCiAgZ2VvbV9qaXR0ZXIoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzZT1GKSArDQogIGdndGl0bGUoIjEuIFJvb20gdHlwZXMgd2l0aCBtb3JlIHJldmlld3MgYnkgY2l0eSIpKw0KICBmYWNldF93cmFwKH4gY2l0eSwgc2NhbGVzID0gImZyZWUiKSArDQogIHRoZW1lX2J3KCkNCg0KYWlyYm5iX2xpc3RpbmdzICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSByb29tX3R5cGUsIHggPSBtaW5pbXVtX25pZ2h0cywgY29sID0gY2l0eSkpICsNCiAgZ2VvbV9qaXR0ZXIoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzZT1GKSArDQogIGdndGl0bGUoIjIuIFJvb20gdHlwZXMgYW5kIG1pbmltdW0gbmlnaHRzIGJ5IGNpdHkiKSsNCiAgZmFjZXRfd3JhcCh+IGNpdHksIHNjYWxlcyA9ICJmcmVlIikgKw0KICB0aGVtZV9idygpDQoNCmFpcmJuYl9saXN0aW5ncyAlPiUNCiAgZ2dwbG90KGFlcyh5ID0gcm9vbV90eXBlLCB4ID0gcHJpY2UsIGNvbCA9IGNpdHkpKSArDQogIGdlb21faml0dGVyKCkgKw0KICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJywgc2U9RikgKw0KICBnZ3RpdGxlKCIzLiBSb29tIHR5cGVzIGFuZCBkaXN0cmlidXRpb24gb2YgcHJpY2UgYnkgY2l0eSIpKw0KICBmYWNldF93cmFwKH4gY2l0eSwgc2NhbGVzID0gImZyZWUiKSArDQogIHRoZW1lX2J3KCkNCmBgYA0K