Step 1: Business Understanding

Purpose of the Dataset

We are using the Paris Airbnb dataset, which was likely collected to provide insights into short-term rental properties in Paris, including availability, pricing, and other property-related features. This dataset helps us understand the rental market by analyzing factors such as pricing and location. This data can be useful for Airbnb hosts to optimize their listings, renters to find suitable properties, and Airbnb itself to gain valuable market insights.

Defining Outcomes

We define our outcomes by predicting which factors influence rental prices the most or by identifying what features lead to higher booking rates. Success in mining this dataset will be determined by our ability to accurately predict these outcomes using a machine learning model. Specifically, we will focus on developing a prediction algorithm to forecast the price of rentals based on various attributes like location, room type, and availability.

Measuring Effectiveness

The effectiveness of our prediction algorithms will be measured using metrics like Mean Absolute Error (MAE) or Root Mean Squared Error (RMSE) for regression models (price prediction). For classification tasks, such as predicting availability or popularity, we will measure effectiveness using Accuracy or AUC-ROC.


Step 2: Data Understanding

  1. Describe Data Attributes
    Our dataset contains several attributes, which we describe as follows:
    • listing_id: Unique identifier for each listing.
    • name: Name of the Airbnb listing.
    • host_id: Identifier for the host.
    • price: The cost per night of the listing (numerical).
    • room_type: The type of room (categorical: e.g., Entire home/apt, Private room, etc.).
    • neighbourhood: The area in Paris (categorical).
    • reviews: The number of reviews (numerical).
    • availability: Number of days the listing is available in a year (numerical).
  2. Verify Data Quality
    We need to check the dataset for missing values, duplicates, and outliers, and decide how to address these issues.

Data Quality

  • Missing Values
    We will identify and handle any missing values using the following approach:

    # Check for missing values
    missing_data = df.isnull().sum()
    
    # Visualize missing data (optional)
    import seaborn as sns
    import matplotlib.pyplot as plt
    
    sns.heatmap(df.isnull(), cbar=False)
    plt.show()

    Depending on the results, we will decide whether to drop rows with missing values, impute missing values using the mean or median, or ignore them if insignificant.

  • Duplicates
    We will remove any duplicate entries using this code:

    # Check for duplicates
    duplicates = df[df.duplicated()]
    df_cleaned = df.drop_duplicates()
  • Outliers
    We will identify outliers using box plots for numerical features such as price. To detect and handle outliers, we might use the interquartile range (IQR) method:

    sns.boxplot(x=df['price'])
    plt.show()

Simple Statistics

We will calculate basic statistics for the most important attributes:

# Basic statistics
df.describe()

Step 3: Data Preprocessing and Visualization

Importing Libraries and Loading Data

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Load the dataset
df = pd.read_csv('paris_airbnb.csv')

# Initial overview
df.head()

Handling Missing Data

# Check for missing values
missing_values = df.isnull().sum()
print(missing_values)

# Fill missing values in 'price' column, if applicable
df['price'].fillna(df['price'].mean(), inplace=True)

Removing Duplicates

# Remove duplicate rows
df.drop_duplicates(inplace=True)

Descriptive Statistics

# Descriptive statistics for numerical columns
print(df.describe())

# Range, mode, mean, median, variance for price
price_range = df['price'].max() - df['price'].min()
price_mode = df['price'].mode()
price_mean = df['price'].mean()
price_median = df['price'].median()
price_variance = df['price'].var()

print(f"Price Range: {price_range}, Mode: {price_mode}, Mean: {price_mean}, Median: {price_median}, Variance: {price_variance}")

Step 4: Visualization of Important Attributes

We visualize the most important attributes like price, room_type, and availability_365.

  1. Price Distribution
plt.figure(figsize=(10,6))
sns.histplot(df['price'], bins=50, kde=True)
plt.title('Price Distribution of Airbnb Listings in Paris')
plt.xlabel('Price')
plt.ylabel('Frequency')
plt.show()
  1. Room Type Breakdown
plt.figure(figsize=(8,5))
sns.countplot(x='room_type', data=df)
plt.title('Distribution of Room Types')
plt.xlabel('Room Type')
plt.ylabel('Count')
plt.show()
  1. Availability of Listings
plt.figure(figsize=(10,6))
sns.histplot(df['availability'], bins=30, kde=True)
plt.title('Availability of Airbnb Listings in Paris')
plt.xlabel('Days Available')
plt.ylabel('Frequency')
plt.show()

Exploring Relationships Between Attributes

  1. Price vs. Room Type
plt.figure(figsize=(8,5))
sns.boxplot(x='room_type', y='price', data=df)
plt.title('Room Type vs. Price')
plt.xlabel('Room Type')
plt.ylabel('Price')
plt.show()
  1. Correlation Matrix
plt.figure(figsize=(10,6))
corr_matrix = df.corr()
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm')
plt.title('Correlation Matrix')
plt.show()

Step 5: Dimensionality Reduction

We use PCA (Principal Component Analysis) to reduce the dimensionality of the dataset and visualize the results:

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# Standardize the features
features = ['price', 'number_of_reviews', 'availability_365']
x = df[features].values
x = StandardScaler().fit_transform(x)

# PCA
pca = PCA(n_components=2)
pca_result = pca.fit_transform(x)

# Visualize PCA result
plt.scatter(pca_result[:, 0], pca_result[:, 1])
plt.title('PCA of Airbnb Features')
plt.show()

Step 6: Exceptional Work - Creating Additional Features

We suggest adding new features to enhance our analysis:

# Example: Adding a feature for luxury listings
df['is_luxury'] = np.where(df['price'] > df['price'].quantile(0.9), 1, 0)

Final Step: Report

We will compile all of our findings and code into a well-documented Jupyter notebook or a PDF/HTML report. The final report will include explanations of each step, the Python code used, and conclusions drawn from our analysis.

Would you like any further assistance in implementing specific sections or preparing your final report?

LS0tDQp0aXRsZTogIkdyb3VwIFBhcmlzIC0gTGFiIDEgLSBNTDczMzEiICANCmF1dGhvcnM6ICJUcm95IE1jU2ltb3YsIEplc3NpY2EgTWNQaGF1bCwgVHJldm9yIEt1bnosIENocmlzdGlhbiBDYXN0cm8iICANCm91dHB1dDogaHRtbF9ub3RlYm9vayAgDQotLS0NCg0KIyMjIFN0ZXAgMTogQnVzaW5lc3MgVW5kZXJzdGFuZGluZw0KDQojIyMjIFB1cnBvc2Ugb2YgdGhlIERhdGFzZXQNCldlIGFyZSB1c2luZyB0aGUgUGFyaXMgQWlyYm5iIGRhdGFzZXQsIHdoaWNoIHdhcyBsaWtlbHkgY29sbGVjdGVkIHRvIHByb3ZpZGUgaW5zaWdodHMgaW50byBzaG9ydC10ZXJtIHJlbnRhbCBwcm9wZXJ0aWVzIGluIFBhcmlzLCBpbmNsdWRpbmcgYXZhaWxhYmlsaXR5LCBwcmljaW5nLCBhbmQgb3RoZXIgcHJvcGVydHktcmVsYXRlZCBmZWF0dXJlcy4gVGhpcyBkYXRhc2V0IGhlbHBzIHVzIHVuZGVyc3RhbmQgdGhlIHJlbnRhbCBtYXJrZXQgYnkgYW5hbHl6aW5nIGZhY3RvcnMgc3VjaCBhcyBwcmljaW5nIGFuZCBsb2NhdGlvbi4gVGhpcyBkYXRhIGNhbiBiZSB1c2VmdWwgZm9yIEFpcmJuYiBob3N0cyB0byBvcHRpbWl6ZSB0aGVpciBsaXN0aW5ncywgcmVudGVycyB0byBmaW5kIHN1aXRhYmxlIHByb3BlcnRpZXMsIGFuZCBBaXJibmIgaXRzZWxmIHRvIGdhaW4gdmFsdWFibGUgbWFya2V0IGluc2lnaHRzLg0KDQojIyMjIERlZmluaW5nIE91dGNvbWVzDQpXZSBkZWZpbmUgb3VyIG91dGNvbWVzIGJ5IHByZWRpY3Rpbmcgd2hpY2ggZmFjdG9ycyBpbmZsdWVuY2UgcmVudGFsIHByaWNlcyB0aGUgbW9zdCBvciBieSBpZGVudGlmeWluZyB3aGF0IGZlYXR1cmVzIGxlYWQgdG8gaGlnaGVyIGJvb2tpbmcgcmF0ZXMuIFN1Y2Nlc3MgaW4gbWluaW5nIHRoaXMgZGF0YXNldCB3aWxsIGJlIGRldGVybWluZWQgYnkgb3VyIGFiaWxpdHkgdG8gYWNjdXJhdGVseSBwcmVkaWN0IHRoZXNlIG91dGNvbWVzIHVzaW5nIGEgbWFjaGluZSBsZWFybmluZyBtb2RlbC4gU3BlY2lmaWNhbGx5LCB3ZSB3aWxsIGZvY3VzIG9uIGRldmVsb3BpbmcgYSBwcmVkaWN0aW9uIGFsZ29yaXRobSB0byBmb3JlY2FzdCB0aGUgcHJpY2Ugb2YgcmVudGFscyBiYXNlZCBvbiB2YXJpb3VzIGF0dHJpYnV0ZXMgbGlrZSBsb2NhdGlvbiwgcm9vbSB0eXBlLCBhbmQgYXZhaWxhYmlsaXR5Lg0KDQojIyMjIE1lYXN1cmluZyBFZmZlY3RpdmVuZXNzDQpUaGUgZWZmZWN0aXZlbmVzcyBvZiBvdXIgcHJlZGljdGlvbiBhbGdvcml0aG1zIHdpbGwgYmUgbWVhc3VyZWQgdXNpbmcgbWV0cmljcyBsaWtlICoqTWVhbiBBYnNvbHV0ZSBFcnJvciAoTUFFKSoqIG9yICoqUm9vdCBNZWFuIFNxdWFyZWQgRXJyb3IgKFJNU0UpKiogZm9yIHJlZ3Jlc3Npb24gbW9kZWxzIChwcmljZSBwcmVkaWN0aW9uKS4gRm9yIGNsYXNzaWZpY2F0aW9uIHRhc2tzLCBzdWNoIGFzIHByZWRpY3RpbmcgYXZhaWxhYmlsaXR5IG9yIHBvcHVsYXJpdHksIHdlIHdpbGwgbWVhc3VyZSBlZmZlY3RpdmVuZXNzIHVzaW5nICoqQWNjdXJhY3kqKiBvciAqKkFVQy1ST0MqKi4NCg0KLS0tDQoNCiMjIyBTdGVwIDI6IERhdGEgVW5kZXJzdGFuZGluZw0KDQoxLiAqKkRlc2NyaWJlIERhdGEgQXR0cmlidXRlcyoqICANCiAgIE91ciBkYXRhc2V0IGNvbnRhaW5zIHNldmVyYWwgYXR0cmlidXRlcywgd2hpY2ggd2UgZGVzY3JpYmUgYXMgZm9sbG93czoNCiAgIC0gYGxpc3RpbmdfaWRgOiBVbmlxdWUgaWRlbnRpZmllciBmb3IgZWFjaCBsaXN0aW5nLg0KICAgLSBgbmFtZWA6IE5hbWUgb2YgdGhlIEFpcmJuYiBsaXN0aW5nLg0KICAgLSBgaG9zdF9pZGA6IElkZW50aWZpZXIgZm9yIHRoZSBob3N0Lg0KICAgLSBgcHJpY2VgOiBUaGUgY29zdCBwZXIgbmlnaHQgb2YgdGhlIGxpc3RpbmcgKG51bWVyaWNhbCkuDQogICAtIGByb29tX3R5cGVgOiBUaGUgdHlwZSBvZiByb29tIChjYXRlZ29yaWNhbDogZS5nLiwgRW50aXJlIGhvbWUvYXB0LCBQcml2YXRlIHJvb20sIGV0Yy4pLg0KICAgLSBgbmVpZ2hib3VyaG9vZGA6IFRoZSBhcmVhIGluIFBhcmlzIChjYXRlZ29yaWNhbCkuDQogICAtIGByZXZpZXdzYDogVGhlIG51bWJlciBvZiByZXZpZXdzIChudW1lcmljYWwpLg0KICAgLSBgYXZhaWxhYmlsaXR5YDogTnVtYmVyIG9mIGRheXMgdGhlIGxpc3RpbmcgaXMgYXZhaWxhYmxlIGluIGEgeWVhciAobnVtZXJpY2FsKS4NCg0KMi4gKipWZXJpZnkgRGF0YSBRdWFsaXR5KiogIA0KICAgV2UgbmVlZCB0byBjaGVjayB0aGUgZGF0YXNldCBmb3IgbWlzc2luZyB2YWx1ZXMsIGR1cGxpY2F0ZXMsIGFuZCBvdXRsaWVycywgYW5kIGRlY2lkZSBob3cgdG8gYWRkcmVzcyB0aGVzZSBpc3N1ZXMuDQoNCiMjIyMgRGF0YSBRdWFsaXR5DQotICoqTWlzc2luZyBWYWx1ZXMqKiAgDQogIFdlIHdpbGwgaWRlbnRpZnkgYW5kIGhhbmRsZSBhbnkgbWlzc2luZyB2YWx1ZXMgdXNpbmcgdGhlIGZvbGxvd2luZyBhcHByb2FjaDoNCiAgDQogIGBgYHB5dGhvbg0KICAjIENoZWNrIGZvciBtaXNzaW5nIHZhbHVlcw0KICBtaXNzaW5nX2RhdGEgPSBkZi5pc251bGwoKS5zdW0oKQ0KICANCiAgIyBWaXN1YWxpemUgbWlzc2luZyBkYXRhIChvcHRpb25hbCkNCiAgaW1wb3J0IHNlYWJvcm4gYXMgc25zDQogIGltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQNCiAgDQogIHNucy5oZWF0bWFwKGRmLmlzbnVsbCgpLCBjYmFyPUZhbHNlKQ0KICBwbHQuc2hvdygpDQogIGBgYA0KDQogIERlcGVuZGluZyBvbiB0aGUgcmVzdWx0cywgd2Ugd2lsbCBkZWNpZGUgd2hldGhlciB0byBkcm9wIHJvd3Mgd2l0aCBtaXNzaW5nIHZhbHVlcywgaW1wdXRlIG1pc3NpbmcgdmFsdWVzIHVzaW5nIHRoZSBtZWFuIG9yIG1lZGlhbiwgb3IgaWdub3JlIHRoZW0gaWYgaW5zaWduaWZpY2FudC4NCg0KLSAqKkR1cGxpY2F0ZXMqKiAgDQogIFdlIHdpbGwgcmVtb3ZlIGFueSBkdXBsaWNhdGUgZW50cmllcyB1c2luZyB0aGlzIGNvZGU6DQogIA0KICBgYGBweXRob24NCiAgIyBDaGVjayBmb3IgZHVwbGljYXRlcw0KICBkdXBsaWNhdGVzID0gZGZbZGYuZHVwbGljYXRlZCgpXQ0KICBkZl9jbGVhbmVkID0gZGYuZHJvcF9kdXBsaWNhdGVzKCkNCiAgYGBgDQoNCi0gKipPdXRsaWVycyoqICANCiAgV2Ugd2lsbCBpZGVudGlmeSBvdXRsaWVycyB1c2luZyBib3ggcGxvdHMgZm9yIG51bWVyaWNhbCBmZWF0dXJlcyBzdWNoIGFzIGBwcmljZWAuIFRvIGRldGVjdCBhbmQgaGFuZGxlIG91dGxpZXJzLCB3ZSBtaWdodCB1c2UgdGhlIGludGVycXVhcnRpbGUgcmFuZ2UgKElRUikgbWV0aG9kOg0KICANCiAgYGBgcHl0aG9uDQogIHNucy5ib3hwbG90KHg9ZGZbJ3ByaWNlJ10pDQogIHBsdC5zaG93KCkNCiAgYGBgDQoNCiMjIyMgU2ltcGxlIFN0YXRpc3RpY3MNCldlIHdpbGwgY2FsY3VsYXRlIGJhc2ljIHN0YXRpc3RpY3MgZm9yIHRoZSBtb3N0IGltcG9ydGFudCBhdHRyaWJ1dGVzOg0KICANCmBgYHB5dGhvbg0KIyBCYXNpYyBzdGF0aXN0aWNzDQpkZi5kZXNjcmliZSgpDQpgYGANCg0KLS0tDQoNCiMjIyBTdGVwIDM6IERhdGEgUHJlcHJvY2Vzc2luZyBhbmQgVmlzdWFsaXphdGlvbg0KDQojIyMjIEltcG9ydGluZyBMaWJyYXJpZXMgYW5kIExvYWRpbmcgRGF0YQ0KDQpgYGBweXRob24NCmltcG9ydCBwYW5kYXMgYXMgcGQNCmltcG9ydCBudW1weSBhcyBucA0KaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdA0KaW1wb3J0IHNlYWJvcm4gYXMgc25zDQoNCiMgTG9hZCB0aGUgZGF0YXNldA0KZGYgPSBwZC5yZWFkX2NzdigncGFyaXNfYWlyYm5iLmNzdicpDQoNCiMgSW5pdGlhbCBvdmVydmlldw0KZGYuaGVhZCgpDQpgYGANCg0KIyMjIyBIYW5kbGluZyBNaXNzaW5nIERhdGENCg0KYGBgcHl0aG9uDQojIENoZWNrIGZvciBtaXNzaW5nIHZhbHVlcw0KbWlzc2luZ192YWx1ZXMgPSBkZi5pc251bGwoKS5zdW0oKQ0KcHJpbnQobWlzc2luZ192YWx1ZXMpDQoNCiMgRmlsbCBtaXNzaW5nIHZhbHVlcyBpbiAncHJpY2UnIGNvbHVtbiwgaWYgYXBwbGljYWJsZQ0KZGZbJ3ByaWNlJ10uZmlsbG5hKGRmWydwcmljZSddLm1lYW4oKSwgaW5wbGFjZT1UcnVlKQ0KYGBgDQoNCiMjIyMgUmVtb3ZpbmcgRHVwbGljYXRlcw0KDQpgYGBweXRob24NCiMgUmVtb3ZlIGR1cGxpY2F0ZSByb3dzDQpkZi5kcm9wX2R1cGxpY2F0ZXMoaW5wbGFjZT1UcnVlKQ0KYGBgDQoNCiMjIyMgRGVzY3JpcHRpdmUgU3RhdGlzdGljcw0KDQpgYGBweXRob24NCiMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcyBmb3IgbnVtZXJpY2FsIGNvbHVtbnMNCnByaW50KGRmLmRlc2NyaWJlKCkpDQoNCiMgUmFuZ2UsIG1vZGUsIG1lYW4sIG1lZGlhbiwgdmFyaWFuY2UgZm9yIHByaWNlDQpwcmljZV9yYW5nZSA9IGRmWydwcmljZSddLm1heCgpIC0gZGZbJ3ByaWNlJ10ubWluKCkNCnByaWNlX21vZGUgPSBkZlsncHJpY2UnXS5tb2RlKCkNCnByaWNlX21lYW4gPSBkZlsncHJpY2UnXS5tZWFuKCkNCnByaWNlX21lZGlhbiA9IGRmWydwcmljZSddLm1lZGlhbigpDQpwcmljZV92YXJpYW5jZSA9IGRmWydwcmljZSddLnZhcigpDQoNCnByaW50KGYiUHJpY2UgUmFuZ2U6IHtwcmljZV9yYW5nZX0sIE1vZGU6IHtwcmljZV9tb2RlfSwgTWVhbjoge3ByaWNlX21lYW59LCBNZWRpYW46IHtwcmljZV9tZWRpYW59LCBWYXJpYW5jZToge3ByaWNlX3ZhcmlhbmNlfSIpDQpgYGANCg0KLS0tDQoNCiMjIyBTdGVwIDQ6IFZpc3VhbGl6YXRpb24gb2YgSW1wb3J0YW50IEF0dHJpYnV0ZXMNCg0KV2UgdmlzdWFsaXplIHRoZSBtb3N0IGltcG9ydGFudCBhdHRyaWJ1dGVzIGxpa2UgYHByaWNlYCwgYHJvb21fdHlwZWAsIGFuZCBgYXZhaWxhYmlsaXR5XzM2NWAuDQoNCjEuICoqUHJpY2UgRGlzdHJpYnV0aW9uKioNCg0KYGBgcHl0aG9uDQpwbHQuZmlndXJlKGZpZ3NpemU9KDEwLDYpKQ0Kc25zLmhpc3RwbG90KGRmWydwcmljZSddLCBiaW5zPTUwLCBrZGU9VHJ1ZSkNCnBsdC50aXRsZSgnUHJpY2UgRGlzdHJpYnV0aW9uIG9mIEFpcmJuYiBMaXN0aW5ncyBpbiBQYXJpcycpDQpwbHQueGxhYmVsKCdQcmljZScpDQpwbHQueWxhYmVsKCdGcmVxdWVuY3knKQ0KcGx0LnNob3coKQ0KYGBgDQoNCjIuICoqUm9vbSBUeXBlIEJyZWFrZG93bioqDQoNCmBgYHB5dGhvbg0KcGx0LmZpZ3VyZShmaWdzaXplPSg4LDUpKQ0Kc25zLmNvdW50cGxvdCh4PSdyb29tX3R5cGUnLCBkYXRhPWRmKQ0KcGx0LnRpdGxlKCdEaXN0cmlidXRpb24gb2YgUm9vbSBUeXBlcycpDQpwbHQueGxhYmVsKCdSb29tIFR5cGUnKQ0KcGx0LnlsYWJlbCgnQ291bnQnKQ0KcGx0LnNob3coKQ0KYGBgDQoNCjMuICoqQXZhaWxhYmlsaXR5IG9mIExpc3RpbmdzKioNCg0KYGBgcHl0aG9uDQpwbHQuZmlndXJlKGZpZ3NpemU9KDEwLDYpKQ0Kc25zLmhpc3RwbG90KGRmWydhdmFpbGFiaWxpdHknXSwgYmlucz0zMCwga2RlPVRydWUpDQpwbHQudGl0bGUoJ0F2YWlsYWJpbGl0eSBvZiBBaXJibmIgTGlzdGluZ3MgaW4gUGFyaXMnKQ0KcGx0LnhsYWJlbCgnRGF5cyBBdmFpbGFibGUnKQ0KcGx0LnlsYWJlbCgnRnJlcXVlbmN5JykNCnBsdC5zaG93KCkNCmBgYA0KDQojIyMjIEV4cGxvcmluZyBSZWxhdGlvbnNoaXBzIEJldHdlZW4gQXR0cmlidXRlcw0KDQoxLiAqKlByaWNlIHZzLiBSb29tIFR5cGUqKg0KDQpgYGBweXRob24NCnBsdC5maWd1cmUoZmlnc2l6ZT0oOCw1KSkNCnNucy5ib3hwbG90KHg9J3Jvb21fdHlwZScsIHk9J3ByaWNlJywgZGF0YT1kZikNCnBsdC50aXRsZSgnUm9vbSBUeXBlIHZzLiBQcmljZScpDQpwbHQueGxhYmVsKCdSb29tIFR5cGUnKQ0KcGx0LnlsYWJlbCgnUHJpY2UnKQ0KcGx0LnNob3coKQ0KYGBgDQoNCjIuICoqQ29ycmVsYXRpb24gTWF0cml4KioNCg0KYGBgcHl0aG9uDQpwbHQuZmlndXJlKGZpZ3NpemU9KDEwLDYpKQ0KY29ycl9tYXRyaXggPSBkZi5jb3JyKCkNCnNucy5oZWF0bWFwKGNvcnJfbWF0cml4LCBhbm5vdD1UcnVlLCBjbWFwPSdjb29sd2FybScpDQpwbHQudGl0bGUoJ0NvcnJlbGF0aW9uIE1hdHJpeCcpDQpwbHQuc2hvdygpDQpgYGANCg0KLS0tDQoNCiMjIyBTdGVwIDU6IERpbWVuc2lvbmFsaXR5IFJlZHVjdGlvbg0KDQpXZSB1c2UgUENBIChQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzKSB0byByZWR1Y2UgdGhlIGRpbWVuc2lvbmFsaXR5IG9mIHRoZSBkYXRhc2V0IGFuZCB2aXN1YWxpemUgdGhlIHJlc3VsdHM6DQoNCmBgYHB5dGhvbg0KZnJvbSBza2xlYXJuLmRlY29tcG9zaXRpb24gaW1wb3J0IFBDQQ0KZnJvbSBza2xlYXJuLnByZXByb2Nlc3NpbmcgaW1wb3J0IFN0YW5kYXJkU2NhbGVyDQoNCiMgU3RhbmRhcmRpemUgdGhlIGZlYXR1cmVzDQpmZWF0dXJlcyA9IFsncHJpY2UnLCAnbnVtYmVyX29mX3Jldmlld3MnLCAnYXZhaWxhYmlsaXR5XzM2NSddDQp4ID0gZGZbZmVhdHVyZXNdLnZhbHVlcw0KeCA9IFN0YW5kYXJkU2NhbGVyKCkuZml0X3RyYW5zZm9ybSh4KQ0KDQojIFBDQQ0KcGNhID0gUENBKG5fY29tcG9uZW50cz0yKQ0KcGNhX3Jlc3VsdCA9IHBjYS5maXRfdHJhbnNmb3JtKHgpDQoNCiMgVmlzdWFsaXplIFBDQSByZXN1bHQNCnBsdC5zY2F0dGVyKHBjYV9yZXN1bHRbOiwgMF0sIHBjYV9yZXN1bHRbOiwgMV0pDQpwbHQudGl0bGUoJ1BDQSBvZiBBaXJibmIgRmVhdHVyZXMnKQ0KcGx0LnNob3coKQ0KYGBgDQoNCi0tLQ0KDQojIyMgU3RlcCA2OiBFeGNlcHRpb25hbCBXb3JrIC0gQ3JlYXRpbmcgQWRkaXRpb25hbCBGZWF0dXJlcw0KDQpXZSBzdWdnZXN0IGFkZGluZyBuZXcgZmVhdHVyZXMgdG8gZW5oYW5jZSBvdXIgYW5hbHlzaXM6DQogIA0KLSAqKlByaWNlIHBlciBwZXJzb246KiogRGVyaXZlZCBieSBkaXZpZGluZyB0aGUgcHJpY2UgYnkgdGhlIG51bWJlciBvZiBndWVzdHMgYSBwcm9wZXJ0eSBhY2NvbW1vZGF0ZXMuDQotICoqTHV4dXJ5IGZsYWc6KiogQ2xhc3NpZnkgbGlzdGluZ3MgYXMgbHV4dXJ5IGlmIHRoZWlyIHByaWNlIGlzIGluIHRoZSB0b3AgMTAlLg0KDQpgYGBweXRob24NCiMgRXhhbXBsZTogQWRkaW5nIGEgZmVhdHVyZSBmb3IgbHV4dXJ5IGxpc3RpbmdzDQpkZlsnaXNfbHV4dXJ5J10gPSBucC53aGVyZShkZlsncHJpY2UnXSA+IGRmWydwcmljZSddLnF1YW50aWxlKDAuOSksIDEsIDApDQpgYGANCg0KLS0tDQoNCiMjIyBGaW5hbCBTdGVwOiBSZXBvcnQNCldlIHdpbGwgY29tcGlsZSBhbGwgb2Ygb3VyIGZpbmRpbmdzIGFuZCBjb2RlIGludG8gYSB3ZWxsLWRvY3VtZW50ZWQgSnVweXRlciBub3RlYm9vayBvciBhIFBERi9IVE1MIHJlcG9ydC4gVGhlIGZpbmFsIHJlcG9ydCB3aWxsIGluY2x1ZGUgZXhwbGFuYXRpb25zIG9mIGVhY2ggc3RlcCwgdGhlIFB5dGhvbiBjb2RlIHVzZWQsIGFuZCBjb25jbHVzaW9ucyBkcmF3biBmcm9tIG91ciBhbmFseXNpcy4NCg0KV291bGQgeW91IGxpa2UgYW55IGZ1cnRoZXIgYXNzaXN0YW5jZSBpbiBpbXBsZW1lbnRpbmcgc3BlY2lmaWMgc2VjdGlvbnMgb3IgcHJlcGFyaW5nIHlvdXIgZmluYWwgcmVwb3J0Pw==