This is an analysis of data from from Inside Airbnb.
The data is scraped listings from Airbnb in Lisbon, Portugal.
The data
Short-term rentals have been an issue in many cities across Europe,
including Lisbon, the focus of online publication Atlas Lisboa.
I searched for data on short-term rentals in Lisbon and found Inside Airbnb, which scrapes
listings from Airbnb, the world’s
largest short-term rental platform.
I found data for the city of Lisbon, and decided to explore what it
could tell me about short-term rentals in the city.
The data can be found here.
The data dictionary by Inside Airbnb can be found here
This data is licensed under a Creative Commons
Attribution 4.0 International License.
df <- read.csv("inside_airbnb_listings.csv") %>%
clean_names()
df$price <- gsub("[$,]", "", df$price)
df$price <- as.numeric(df$price)
Filtering
The data includes a lot of information such as host bios and listings
descriptions. For this analysis, I am focusing on licencing so start by
selecting only the variables I think will be useful.
The data is then filtered by neighbourhood_group_cleansed to
only show listings in the city of Lisbon (Lisboa) rather than Greater
Lisbon.
lisbon_listings <- df %>%
select(id, listing_url, host_id, host_name, neighbourhood_group_cleansed, license, latitude, longitude, room_type, price, minimum_nights) %>%
filter(neighbourhood_group_cleansed == "Lisboa")
Next, I filter by license to find listings that self-declare
as “exempt”.
I also filter by license to find listings that have no
licence listed (which I will refer to as ‘blank’ listings).
Each listing has a unique ID, so I am using these to count individual
listings.
exempt_listings <- lisbon_listings %>%
filter(license == "Exempt")
blank_listings <- lisbon_listings %>%
filter(license == "")
# Number of listings in Lisbon city
length(lisbon_listings$id)
## [1] 17428
# Number of listings in Lisbon that self-declared as 'exempt' on Airbnb
length(exempt_listings$id)
## [1] 3698
# Number of listings in Lisbon that left the licence section empty on Airbnb
length(blank_listings$id)
## [1] 669
# Percentage of Lisbon listings that self-declared as 'exempt' on Airbnb
percent((length(exempt_listings$id)/length(lisbon_listings$id)), accuracy = 0.01)
## [1] "21.22%"
# Percentage of Lisbon listings that leave the licence section blank on Airbnb
percent((length(blank_listings$id)/length(lisbon_listings$id)), accuracy = 0.01)
## [1] "3.84%"
We can see that there are 17428 Airbnb listings in
Lisbon city and 3698 of those listings declare that
they are ‘exempt’ from licencing, and a further 669
have nothing entered in the licence section on Airbnb.
How many are homes?
Next, I want to check how many of those are entire apartment or
houses, since it is these rentals that put the most pressure on city
housing stock.
Starting with ‘exempt’ listings.
table(exempt_listings$room_type)
##
## Entire home/apt Hotel room Private room Shared room
## 2460 18 1219 1
exempt_listings %>%
ggplot(aes(room_type))+
geom_bar()+
labs(title = "Listings self-reporting as exempt", x = "Room type", y = "# of listings")

exempt_homes <- exempt_listings %>%
filter(room_type == "Entire home/apt")
We see that 2460 of those ‘exempt’ listings are
entire homes.
Doing the same for blank listings:
table(blank_listings$room_type)
##
## Entire home/apt Hotel room Private room Shared room
## 498 16 153 2
blank_listings %>%
ggplot(aes(room_type))+
geom_bar()+
labs(title = "Blank listings", x = "Room type", y = "# of listings")

blank_homes <- blank_listings %>%
filter(room_type == "Entire home/apt")
We can see that 498 of the blank listings are entire
homes.
Medium- or short-term rentals?
In Portugal, you can offer your property as a medium-term let
(normally a month or more) for students and such.
So next, I look at homes listed on Airbnb by the the minimum number
of nights offered to see if this might be a reason for certain
exemptions.
ggplotly(exempt_homes %>%
filter(minimum_nights < 100) %>%
ggplot(aes(minimum_nights))+
geom_bar(fill = "blue")+
labs(x = "Minimum Nights", y = "Listings"),
dynamicTicks = "y")
There seem to be two clusters.
The majority of exempt homes seem to be operating as regular
short-term rentals, with the minimum number of nights listed as a week
or less. There is another group that has minimum nights starting around
one month, most likely medium-term rentals.
# Entire homes that are offerings short term stays
short_exempt_homes <- exempt_homes %>%
filter(minimum_nights >=1, minimum_nights <=7)
length(short_exempt_homes$id)
## [1] 1382
We have 1382 homes self-declared as exempt offering
stays of 7 days or less.
This is very suspicious, but does not necessarily mean they are
illegal.
Next I look at the number of exempt homes offerings stays with
minimum number of nights above 28 days but less than the 1 year, which
would make a rental permanent.
medium_term <- exempt_homes %>%
filter(minimum_nights >=28, minimum_nights <365)
length(medium_term$id)
## [1] 1003
percent((length(medium_term$id)/length(exempt_homes$id)), accuracy = 0.01)
## [1] "40.77%"
We can see that these “medium-term rentals” account for more than
40% of exempt homes listed on Airbnb.
What next?
From here, we have a few outcomes to follow up:
- One in five Airbnb listings in Lisbon self-declare as exempt
- The majority of these have no obvious reason for being exempt
- Around 40% seem to be ‘medium-term’ rentals, which could offer a
loophole to new legislation
- Almost 4% of listings in Lisbon don’t list any licence at all
The companies are coming in
Next, I am grouping by host ID and host name. Host IDs allow us to
differentiate between multiple hosts with the same name.
multi_usrs <- exempt_homes %>%
group_by(host_id, host_name) %>%
tally(sort = TRUE)
reactable(multi_usrs)
We can see that two hosts stand out: Blueground and Ukio. * Are these
companies? * What business are they operating?
exempt_homes %>%
filter(host_name %in% c("Blueground","Ukio")) %>%
group_by(host_name) %>%
summarise(average_price = mean(price, na.rm = T))
## # A tibble: 2 × 2
## host_name average_price
## <chr> <dbl>
## 1 Blueground 153.
## 2 Ukio 151.
The average price of listings by Blueground and Ukio is 153EUR and
150EUR, respectively.
Or, the equivalent of 4590EUR and 4500EUR per month (30 days),
considerably more than a standard rent in the city.
It’s also interesting to see than many ‘exempt’ hosts have multiple
listings.
Doing the same for blank listings:
reactable(blank_homes %>% group_by(host_id, host_name) %>% tally(sort = TRUE))
A few individuals stand out as having multiple listings but no
licence listed.
It is important to remember that not having a licence
displayed does not mean they don’t have a licence.
It is likely that some of these listings predate the requirement to
add a licence.
Map of exempt and “blank” homes in Lisbon
map_df <- lisbon_listings %>%
filter(license == "Exempt" | license == "") %>%
filter(room_type == "Entire home/apt") %>%
select(id, license, longitude, latitude, price, host_id, host_name)
pal <- colorFactor(
palette = c("red", "blue"),
domain = map_df$license)
map_df %>%
leaflet() %>%
addTiles() %>%
setView(lat = 38.736946, lng = -9.142685, zoom = 12) %>%
addCircles(lat = ~latitude, lng = ~longitude,
color= ~pal(license),
popup = map_df$name) %>%
addLegend(position = "bottomright",
colors = c("red", "blue"),
labels = c("Blank", "Exempt"))
LS0tCnRpdGxlOiAiRXhlbXB0IEFpcmJuYiBMaXN0aW5ncyBpbiBMaXNib24iCmF1dGhvcjogIkVkZW4gRmxhaGVydHkiCmRhdGU6ICIyMDI2LTAxLTIwIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgCi0tLQoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJzY2FsZXMiKQpsaWJyYXJ5KCJsZWFmbGV0IikKbGlicmFyeSgicmVhY3RhYmxlIikKbGlicmFyeSgicGxvdGx5IikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKbGlicmFyeSgiamFuaXRvciIpCmBgYAoKVGhpcyBpcyBhbiBhbmFseXNpcyBvZiBkYXRhIGZyb20gZnJvbSBJbnNpZGUgQWlyYm5iLiAKClRoZSBkYXRhIGlzIHNjcmFwZWQgbGlzdGluZ3MgZnJvbSBBaXJibmIgaW4gTGlzYm9uLCBQb3J0dWdhbC4KCiMjIFRoZSBkYXRhCgpTaG9ydC10ZXJtIHJlbnRhbHMgaGF2ZSBiZWVuIGFuIGlzc3VlIGluIG1hbnkgY2l0aWVzIGFjcm9zcyBFdXJvcGUsIGluY2x1ZGluZyBMaXNib24sIHRoZSBmb2N1cyBvZiBvbmxpbmUgcHVibGljYXRpb24gW0F0bGFzIExpc2JvYV0oaHR0cHM6Ly93d3cuYXRsYXNsaXNib2EuY29tLykuCgpJIHNlYXJjaGVkIGZvciBkYXRhIG9uIHNob3J0LXRlcm0gcmVudGFscyBpbiBMaXNib24gYW5kIGZvdW5kIFtJbnNpZGUgQWlyYm5iXShodHRwczovL2luc2lkZWFpcmJuYi5jb20vKSwgd2hpY2ggc2NyYXBlcyBsaXN0aW5ncyBmcm9tIFtBaXJibmJdKGh0dHBzOi8vYWlyYm5iLmNvbS8pLCB0aGUgd29ybGQncyBsYXJnZXN0IHNob3J0LXRlcm0gcmVudGFsIHBsYXRmb3JtLiAKCkkgZm91bmQgZGF0YSBmb3IgdGhlIGNpdHkgb2YgTGlzYm9uLCBhbmQgZGVjaWRlZCB0byBleHBsb3JlIHdoYXQgaXQgY291bGQgdGVsbCBtZSBhYm91dCBzaG9ydC10ZXJtIHJlbnRhbHMgaW4gdGhlIGNpdHkuIAoKVGhlIGRhdGEgY2FuIGJlIGZvdW5kIFtoZXJlLl0oaHR0cHM6Ly9pbnNpZGVhaXJibmIuY29tL2dldC10aGUtZGF0YS8pCgpUaGUgZGF0YSBkaWN0aW9uYXJ5IGJ5IEluc2lkZSBBaXJibmIgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xaVdDTkpjU3V0WXFwVUxTUUhsTnlHSW5VdkhnMkJvVUdvTlJJR2E2U3pjNC9lZGl0P2dpZD0xMzIyMjg0NTk2I2dpZD0xMzIyMjg0NTk2KQoKVGhpcyBkYXRhIGlzIGxpY2Vuc2VkIHVuZGVyIGEgW0NyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24gNC4wIEludGVybmF0aW9uYWwgTGljZW5zZS5dKGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LzQuMC8pCgoKYGBge3J9CmRmIDwtIHJlYWQuY3N2KCJpbnNpZGVfYWlyYm5iX2xpc3RpbmdzLmNzdiIpICU+JSAKICBjbGVhbl9uYW1lcygpCgpkZiRwcmljZSA8LSBnc3ViKCJbJCxdIiwgIiIsIGRmJHByaWNlKQpkZiRwcmljZSA8LSBhcy5udW1lcmljKGRmJHByaWNlKQoKYGBgCgoKIyMgRmlsdGVyaW5nIAoKVGhlIGRhdGEgaW5jbHVkZXMgYSBsb3Qgb2YgaW5mb3JtYXRpb24gc3VjaCBhcyBob3N0IGJpb3MgYW5kIGxpc3RpbmdzIGRlc2NyaXB0aW9ucy4gRm9yIHRoaXMgYW5hbHlzaXMsIEkgYW0gZm9jdXNpbmcgb24gbGljZW5jaW5nIHNvIHN0YXJ0IGJ5IHNlbGVjdGluZyBvbmx5IHRoZSB2YXJpYWJsZXMgSSB0aGluayB3aWxsIGJlIHVzZWZ1bC4KClRoZSBkYXRhIGlzIHRoZW4gZmlsdGVyZWQgYnkgKm5laWdoYm91cmhvb2RfZ3JvdXBfY2xlYW5zZWQqIHRvIG9ubHkgc2hvdyBsaXN0aW5ncyBpbiB0aGUgY2l0eSBvZiBMaXNib24gKExpc2JvYSkgcmF0aGVyIHRoYW4gR3JlYXRlciBMaXNib24uCgoKYGBge3J9Cmxpc2Jvbl9saXN0aW5ncyA8LSBkZiAlPiUgCiAgc2VsZWN0KGlkLCBsaXN0aW5nX3VybCwgaG9zdF9pZCwgaG9zdF9uYW1lLCBuZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkLCBsaWNlbnNlLCBsYXRpdHVkZSwgbG9uZ2l0dWRlLCByb29tX3R5cGUsIHByaWNlLCBtaW5pbXVtX25pZ2h0cykgJT4lIAogIGZpbHRlcihuZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkID09ICJMaXNib2EiKQpgYGAKCk5leHQsIEkgZmlsdGVyIGJ5ICpsaWNlbnNlKiB0byBmaW5kIGxpc3RpbmdzIHRoYXQgc2VsZi1kZWNsYXJlIGFzICJleGVtcHQiLgoKSSBhbHNvIGZpbHRlciBieSAqbGljZW5zZSogdG8gZmluZCBsaXN0aW5ncyB0aGF0IGhhdmUgbm8gbGljZW5jZSBsaXN0ZWQgKHdoaWNoIEkgd2lsbCByZWZlciB0byBhcyAnYmxhbmsnIGxpc3RpbmdzKS4KCkVhY2ggbGlzdGluZyBoYXMgYSB1bmlxdWUgSUQsIHNvIEkgYW0gdXNpbmcgdGhlc2UgdG8gY291bnQgaW5kaXZpZHVhbCBsaXN0aW5ncy4KCmBgYHtyfQoKZXhlbXB0X2xpc3RpbmdzIDwtIGxpc2Jvbl9saXN0aW5ncyAlPiUKICAgIGZpbHRlcihsaWNlbnNlID09ICJFeGVtcHQiKQoKYmxhbmtfbGlzdGluZ3MgPC0gbGlzYm9uX2xpc3RpbmdzICU+JQogICAgZmlsdGVyKGxpY2Vuc2UgPT0gIiIpCgojIE51bWJlciBvZiBsaXN0aW5ncyBpbiBMaXNib24gY2l0eSAKbGVuZ3RoKGxpc2Jvbl9saXN0aW5ncyRpZCkKCiMgTnVtYmVyIG9mIGxpc3RpbmdzIGluIExpc2JvbiB0aGF0IHNlbGYtZGVjbGFyZWQgYXMgJ2V4ZW1wdCcgb24gQWlyYm5iCmxlbmd0aChleGVtcHRfbGlzdGluZ3MkaWQpCgojIE51bWJlciBvZiBsaXN0aW5ncyBpbiBMaXNib24gdGhhdCBsZWZ0IHRoZSBsaWNlbmNlIHNlY3Rpb24gZW1wdHkgb24gQWlyYm5iCmxlbmd0aChibGFua19saXN0aW5ncyRpZCkKCiMgUGVyY2VudGFnZSBvZiBMaXNib24gbGlzdGluZ3MgdGhhdCBzZWxmLWRlY2xhcmVkIGFzICdleGVtcHQnIG9uIEFpcmJuYgpwZXJjZW50KChsZW5ndGgoZXhlbXB0X2xpc3RpbmdzJGlkKS9sZW5ndGgobGlzYm9uX2xpc3RpbmdzJGlkKSksIGFjY3VyYWN5ID0gMC4wMSkKCiMgUGVyY2VudGFnZSBvZiBMaXNib24gbGlzdGluZ3MgdGhhdCBsZWF2ZSB0aGUgbGljZW5jZSBzZWN0aW9uIGJsYW5rIG9uIEFpcmJuYgpwZXJjZW50KChsZW5ndGgoYmxhbmtfbGlzdGluZ3MkaWQpL2xlbmd0aChsaXNib25fbGlzdGluZ3MkaWQpKSwgYWNjdXJhY3kgPSAwLjAxKQoKYGBgCgoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSAqKjE3NDI4KiogQWlyYm5iIGxpc3RpbmdzIGluIExpc2JvbiBjaXR5IGFuZCAqKjM2OTgqKiBvZiB0aG9zZSBsaXN0aW5ncyBkZWNsYXJlIHRoYXQgdGhleSBhcmUgJ2V4ZW1wdCcgZnJvbSBsaWNlbmNpbmcsIGFuZCBhIGZ1cnRoZXIgKio2NjkqKiBoYXZlIG5vdGhpbmcgZW50ZXJlZCBpbiB0aGUgbGljZW5jZSBzZWN0aW9uIG9uIEFpcmJuYi4gCgojIyBIb3cgbWFueSBhcmUgaG9tZXM/IAoKTmV4dCwgSSB3YW50IHRvIGNoZWNrIGhvdyBtYW55IG9mIHRob3NlIGFyZSBlbnRpcmUgYXBhcnRtZW50IG9yIGhvdXNlcywgc2luY2UgaXQgaXMgdGhlc2UgcmVudGFscyB0aGF0IHB1dCB0aGUgbW9zdCBwcmVzc3VyZSBvbiBjaXR5IGhvdXNpbmcgc3RvY2suCgpTdGFydGluZyB3aXRoICdleGVtcHQnIGxpc3RpbmdzLgoKYGBge3J9Cgp0YWJsZShleGVtcHRfbGlzdGluZ3Mkcm9vbV90eXBlKQoKZXhlbXB0X2xpc3RpbmdzICU+JSAKICAgIGdncGxvdChhZXMocm9vbV90eXBlKSkrCiAgZ2VvbV9iYXIoKSsKICBsYWJzKHRpdGxlID0gIkxpc3RpbmdzIHNlbGYtcmVwb3J0aW5nIGFzIGV4ZW1wdCIsIHggPSAiUm9vbSB0eXBlIiwgeSA9ICIjIG9mIGxpc3RpbmdzIikKCmV4ZW1wdF9ob21lcyA8LSBleGVtcHRfbGlzdGluZ3MgJT4lIAogIGZpbHRlcihyb29tX3R5cGUgPT0gIkVudGlyZSBob21lL2FwdCIpCgpgYGAKCldlIHNlZSB0aGF0ICoqMjQ2MCoqIG9mIHRob3NlICdleGVtcHQnIGxpc3RpbmdzIGFyZSBlbnRpcmUgaG9tZXMuIAoKRG9pbmcgdGhlIHNhbWUgZm9yIGJsYW5rIGxpc3RpbmdzOgoKYGBge3J9CnRhYmxlKGJsYW5rX2xpc3RpbmdzJHJvb21fdHlwZSkKCmJsYW5rX2xpc3RpbmdzICU+JSAKICAgIGdncGxvdChhZXMocm9vbV90eXBlKSkrCiAgZ2VvbV9iYXIoKSsKICBsYWJzKHRpdGxlID0gIkJsYW5rIGxpc3RpbmdzIiwgeCA9ICJSb29tIHR5cGUiLCB5ID0gIiMgb2YgbGlzdGluZ3MiKQoKYmxhbmtfaG9tZXMgPC0gYmxhbmtfbGlzdGluZ3MgJT4lIAogIGZpbHRlcihyb29tX3R5cGUgPT0gIkVudGlyZSBob21lL2FwdCIpCgpgYGAKCldlIGNhbiBzZWUgdGhhdCAqKjQ5OCoqIG9mIHRoZSBibGFuayBsaXN0aW5ncyBhcmUgZW50aXJlIGhvbWVzLiAKCiMjIE1lZGl1bS0gb3Igc2hvcnQtdGVybSByZW50YWxzPwoKSW4gUG9ydHVnYWwsIHlvdSBjYW4gb2ZmZXIgeW91ciBwcm9wZXJ0eSBhcyBhIG1lZGl1bS10ZXJtIGxldCAobm9ybWFsbHkgYSBtb250aCBvciBtb3JlKSBmb3Igc3R1ZGVudHMgYW5kIHN1Y2guCgpTbyBuZXh0LCBJIGxvb2sgYXQgaG9tZXMgbGlzdGVkIG9uIEFpcmJuYiBieSB0aGUgdGhlIG1pbmltdW0gbnVtYmVyIG9mIG5pZ2h0cyBvZmZlcmVkIHRvIHNlZSBpZiB0aGlzIG1pZ2h0IGJlIGEgcmVhc29uIGZvciBjZXJ0YWluIGV4ZW1wdGlvbnMuIAoKYGBge3J9CgpnZ3Bsb3RseShleGVtcHRfaG9tZXMgJT4lIAogIGZpbHRlcihtaW5pbXVtX25pZ2h0cyA8IDEwMCkgJT4lIAogIGdncGxvdChhZXMobWluaW11bV9uaWdodHMpKSsKICBnZW9tX2JhcihmaWxsID0gImJsdWUiKSsKICBsYWJzKHggPSAiTWluaW11bSBOaWdodHMiLCB5ID0gIkxpc3RpbmdzIiksIAogIGR5bmFtaWNUaWNrcyA9ICJ5IikKCmBgYAoKClRoZXJlIHNlZW0gdG8gYmUgdHdvIGNsdXN0ZXJzLgoKVGhlIG1ham9yaXR5IG9mIGV4ZW1wdCBob21lcyBzZWVtIHRvIGJlIG9wZXJhdGluZyBhcyByZWd1bGFyIHNob3J0LXRlcm0gcmVudGFscywgd2l0aCB0aGUgbWluaW11bSBudW1iZXIgb2YgbmlnaHRzIGxpc3RlZCBhcyBhIHdlZWsgb3IgbGVzcy4gClRoZXJlIGlzIGFub3RoZXIgZ3JvdXAgdGhhdCBoYXMgbWluaW11bSBuaWdodHMgc3RhcnRpbmcgYXJvdW5kIG9uZSBtb250aCwgbW9zdCBsaWtlbHkgbWVkaXVtLXRlcm0gcmVudGFscy4gCgpgYGB7cn0KCiMgRW50aXJlIGhvbWVzIHRoYXQgYXJlIG9mZmVyaW5ncyBzaG9ydCB0ZXJtIHN0YXlzIApzaG9ydF9leGVtcHRfaG9tZXMgPC0gZXhlbXB0X2hvbWVzICU+JQogIGZpbHRlcihtaW5pbXVtX25pZ2h0cyA+PTEsIG1pbmltdW1fbmlnaHRzIDw9NykKICAKbGVuZ3RoKHNob3J0X2V4ZW1wdF9ob21lcyRpZCkKCgpgYGAKCldlIGhhdmUgKioxMzgyKiogaG9tZXMgc2VsZi1kZWNsYXJlZCBhcyBleGVtcHQgb2ZmZXJpbmcgc3RheXMgb2YgNyBkYXlzIG9yIGxlc3MuIAoKVGhpcyBpcyB2ZXJ5IHN1c3BpY2lvdXMsIGJ1dCBkb2VzIG5vdCBuZWNlc3NhcmlseSBtZWFuIHRoZXkgYXJlIGlsbGVnYWwuCgpOZXh0IEkgbG9vayBhdCB0aGUgbnVtYmVyIG9mIGV4ZW1wdCBob21lcyBvZmZlcmluZ3Mgc3RheXMgd2l0aCBtaW5pbXVtIG51bWJlciBvZiBuaWdodHMgYWJvdmUgMjggZGF5cyBidXQgbGVzcyB0aGFuIHRoZSAxIHllYXIsIHdoaWNoIHdvdWxkIG1ha2UgYSByZW50YWwgcGVybWFuZW50LgoKCmBgYHtyfQoKbWVkaXVtX3Rlcm0gPC0gZXhlbXB0X2hvbWVzICU+JQogIGZpbHRlcihtaW5pbXVtX25pZ2h0cyA+PTI4LCBtaW5pbXVtX25pZ2h0cyA8MzY1KQoKbGVuZ3RoKG1lZGl1bV90ZXJtJGlkKQoKcGVyY2VudCgobGVuZ3RoKG1lZGl1bV90ZXJtJGlkKS9sZW5ndGgoZXhlbXB0X2hvbWVzJGlkKSksIGFjY3VyYWN5ID0gMC4wMSkKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXNlICJtZWRpdW0tdGVybSByZW50YWxzIiBhY2NvdW50IGZvciBtb3JlIHRoYW4gKio0MCUgb2YgZXhlbXB0IGhvbWVzIGxpc3RlZCBvbiBBaXJibmIqKi4gCgojIyBXaGF0IG5leHQ/CgpGcm9tIGhlcmUsIHdlIGhhdmUgYSBmZXcgb3V0Y29tZXMgdG8gZm9sbG93IHVwOgoKMS4gT25lIGluIGZpdmUgQWlyYm5iIGxpc3RpbmdzIGluIExpc2JvbiBzZWxmLWRlY2xhcmUgYXMgZXhlbXB0CisgVGhlIG1ham9yaXR5IG9mIHRoZXNlIGhhdmUgbm8gb2J2aW91cyByZWFzb24gZm9yIGJlaW5nIGV4ZW1wdAorIEFyb3VuZCA0MCUgc2VlbSB0byBiZSAnbWVkaXVtLXRlcm0nIHJlbnRhbHMsIHdoaWNoIGNvdWxkIG9mZmVyIGEgbG9vcGhvbGUgdG8gbmV3IGxlZ2lzbGF0aW9uCjIuIEFsbW9zdCA0JSBvZiBsaXN0aW5ncyBpbiBMaXNib24gZG9uJ3QgbGlzdCBhbnkgbGljZW5jZSBhdCBhbGwKCiMjIFRoZSBjb21wYW5pZXMgYXJlIGNvbWluZyBpbgoKTmV4dCwgSSBhbSBncm91cGluZyBieSBob3N0IElEIGFuZCBob3N0IG5hbWUuIEhvc3QgSURzIGFsbG93IHVzIHRvIGRpZmZlcmVudGlhdGUgYmV0d2VlbiBtdWx0aXBsZSBob3N0cyB3aXRoIHRoZSBzYW1lIG5hbWUuIAoKYGBge3J9CgptdWx0aV91c3JzIDwtIGV4ZW1wdF9ob21lcyAlPiUgCiAgZ3JvdXBfYnkoaG9zdF9pZCwgaG9zdF9uYW1lKSAlPiUgCiAgdGFsbHkoc29ydCA9IFRSVUUpIAoKcmVhY3RhYmxlKG11bHRpX3VzcnMpCgpgYGAKCldlIGNhbiBzZWUgdGhhdCB0d28gaG9zdHMgc3RhbmQgb3V0OiBCbHVlZ3JvdW5kIGFuZCBVa2lvLiAKKiBBcmUgdGhlc2UgY29tcGFuaWVzPwoqIFdoYXQgYnVzaW5lc3MgYXJlIHRoZXkgb3BlcmF0aW5nPyAKCmBgYHtyfQpleGVtcHRfaG9tZXMgJT4lIAogIGZpbHRlcihob3N0X25hbWUgJWluJSBjKCJCbHVlZ3JvdW5kIiwiVWtpbyIpKSAlPiUgCiAgZ3JvdXBfYnkoaG9zdF9uYW1lKSAlPiUgCiAgc3VtbWFyaXNlKGF2ZXJhZ2VfcHJpY2UgPSBtZWFuKHByaWNlLCBuYS5ybSA9IFQpKQoKYGBgCgpUaGUgYXZlcmFnZSBwcmljZSBvZiBsaXN0aW5ncyBieSBCbHVlZ3JvdW5kIGFuZCBVa2lvIGlzIDE1M0VVUiBhbmQgMTUwRVVSLCByZXNwZWN0aXZlbHkuCgpPciwgdGhlIGVxdWl2YWxlbnQgb2YgNDU5MEVVUiBhbmQgNDUwMEVVUiBwZXIgbW9udGggKDMwIGRheXMpLCBjb25zaWRlcmFibHkgbW9yZSB0aGFuIGEgc3RhbmRhcmQgcmVudCBpbiB0aGUgY2l0eS4gCgpJdCdzIGFsc28gaW50ZXJlc3RpbmcgdG8gc2VlIHRoYW4gbWFueSAnZXhlbXB0JyBob3N0cyBoYXZlIG11bHRpcGxlIGxpc3RpbmdzLgoKRG9pbmcgdGhlIHNhbWUgZm9yIGJsYW5rIGxpc3RpbmdzOgoKYGBge3J9CnJlYWN0YWJsZShibGFua19ob21lcyAlPiUgZ3JvdXBfYnkoaG9zdF9pZCwgaG9zdF9uYW1lKSAlPiUgdGFsbHkoc29ydCA9IFRSVUUpKQpgYGAKCkEgZmV3IGluZGl2aWR1YWxzIHN0YW5kIG91dCBhcyBoYXZpbmcgbXVsdGlwbGUgbGlzdGluZ3MgYnV0IG5vIGxpY2VuY2UgbGlzdGVkLiAKCioqKkl0IGlzIGltcG9ydGFudCB0byByZW1lbWJlciB0aGF0IG5vdCBoYXZpbmcgYSBsaWNlbmNlIGRpc3BsYXllZCBkb2VzIG5vdCBtZWFuIHRoZXkgZG9uJ3QgaGF2ZSBhIGxpY2VuY2UuKioqCgpJdCBpcyBsaWtlbHkgdGhhdCBzb21lIG9mIHRoZXNlIGxpc3RpbmdzIHByZWRhdGUgdGhlIHJlcXVpcmVtZW50IHRvIGFkZCBhIGxpY2VuY2UuCgojIyBNYXAgb2YgZXhlbXB0IGFuZCAiYmxhbmsiIGhvbWVzIGluIExpc2JvbgoKYGBge3J9CgptYXBfZGYgPC0gbGlzYm9uX2xpc3RpbmdzICU+JQogIGZpbHRlcihsaWNlbnNlID09ICJFeGVtcHQiIHwgbGljZW5zZSA9PSAiIikgJT4lIAogIGZpbHRlcihyb29tX3R5cGUgPT0gIkVudGlyZSBob21lL2FwdCIpICU+JSAKICBzZWxlY3QoaWQsIGxpY2Vuc2UsIGxvbmdpdHVkZSwgbGF0aXR1ZGUsIHByaWNlLCBob3N0X2lkLCBob3N0X25hbWUpCgpwYWwgPC0gY29sb3JGYWN0b3IoCiAgcGFsZXR0ZSA9IGMoInJlZCIsICJibHVlIiksCiAgZG9tYWluID0gbWFwX2RmJGxpY2Vuc2UpCgptYXBfZGYgJT4lIAogIGxlYWZsZXQoKSAlPiUgCiAgYWRkVGlsZXMoKSAlPiUgCiAgc2V0VmlldyhsYXQgPSAzOC43MzY5NDYsIGxuZyA9IC05LjE0MjY4NSwgem9vbSA9IDEyKSAlPiUgCiAgYWRkQ2lyY2xlcyhsYXQgPSB+bGF0aXR1ZGUsIGxuZyA9IH5sb25naXR1ZGUsCiAgICAgICAgICAgICBjb2xvcj0gfnBhbChsaWNlbnNlKSwKICAgICAgICAgICAgIHBvcHVwID0gbWFwX2RmJG5hbWUpICU+JSAKICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLCAKICAgICAgICAgICAgY29sb3JzID0gYygicmVkIiwgImJsdWUiKSwgCiAgICAgICAgICAgIGxhYmVscyA9IGMoIkJsYW5rIiwgIkV4ZW1wdCIpKQogIApgYGAKCgo=