The Data

“[T]he Sunshine Coast Council, in Australia, publishes a spreadsheet of both dogs and cats, their primary breeds and colors, and whether they’ve been spayed/neutered.” (h/t Data is Plural)

Let’s download this data. It is available here! I download the csv and then open it up.

pets<- read.csv('Registered_Animals.csv')
levels(pets$AnimalType)
[1] "Cat       " "D         "

There are spaces in the AnimalType variable. We remove them now.

library(stringr)
pets$AnimalType<-str_trim(as.character(pets$AnimalType))
pets$AnimalType[pets$AnimalType=="D"]<-"Dog"
unique(pets$AnimalType)
[1] "Dog" "Cat"
nrow(pets)
[1] 55495
nrow(subset(pets, AnimalType=="Cat"))
[1] 9412
nrow(subset(pets, AnimalType=="Dog"))
[1] 46083

There are 55,495 animals registered with the sunshine council in Australia, 9,412 are cats and 46,083 are dogs. So, there are almost 5 times as many dogs as cats in Australia.

I wonder if some of these animals could be deceased.1 I look into the Sunshine Coast Website and see that “[d]og registrations must be renewed annually as per the Animal Management (Cats & Dogs) Act 2008 Queensland. Cat registrations must be renewed annually as per the Sunshine Coast Local Law No. 2 (Animal Management) 2011.” So, all animals in the dataset have been “renewed” within the last year, meaning this is a dataset of “active animals.” (I.e., they were alive at some point this year.)

Names

Most dog-y/cat-y names (using tf-idf)

Since lots of the top names are the same for dogs and cats, it would be more interesting to see which are most uniquely cat-y or dog-y names.

library(tidytext)
petnames1 <- petnames %>%
  bind_tf_idf(Name, AnimalType, num)
pettf<- petnames1 %>% 
  arrange(desc(tf_idf))
subset(pettf, pettf$AnimalType=="Cat")[1:5,]

The top 5 cat-y names are: puss, mittens, garfield, meow, salem

subset(pettf, pettf$AnimalType=="Dog")[1:5,]

The top 5 dog-y names are: hudson, dozer, bronson, chopper, yogi

So, in summary:

Top 5 Cat-y Names Top 5 Dog-y Names
Puss Hudson
Mittens Dozer
Garfield Bronson
Meow Chopper
Salem Yogi

Age

Let’s see who the oldest animals are…

pets[order(-pets$Age),]

71, 52, 42, 31, 28,… are these ages for real???!!!

How does the age distribution differ across the dog and cat populations?

I will use my regular theme for styling.2

library(ggplot2);library(ggrepel); library(extrafont); library(ggthemes);library(reshape);library(grid);
library(scales);library(RColorBrewer);library(gridExtra);
my_theme <- function() {
  # Define colors for the chart
  palette <- brewer.pal("Greys", n=9)
  color.background = palette[2]
  color.grid.major = palette[4]
  color.panel = palette[3]
  color.axis.text = palette[9]
  color.axis.title = palette[9]
  color.title = palette[9]
  # Create basic construction of chart
  theme_bw(base_size=9, base_family="Palatino") + 
  # Set the entire chart region to a light gray color
  theme(panel.background=element_rect(fill=color.panel, color=color.background)) +
  theme(plot.background=element_rect(fill=color.background, color=color.background)) +
  theme(panel.border=element_rect(color=color.background)) +
  # Format grid
  theme(panel.grid.major=element_line(color=color.grid.major,size=.25)) +
  theme(panel.grid.minor=element_blank()) +
  theme(axis.ticks=element_blank()) +
  # Format legend
  theme(legend.position="right") +
  theme(legend.background = element_rect(fill=color.background)) +
  theme(legend.text = element_text(size=8,color=color.axis.title)) + 
  theme(legend.title = element_text(size=8,color=color.axis.title)) + 
  
  #Format facet labels
  theme(strip.text.x = element_text(size = 8, face="bold"))+
  # Format title and axes labels these and tick marks
  theme(plot.title=element_text(color=color.title, size=28)) +
  theme(axis.text.x=element_text(size=8)) +
  theme(axis.text.y=element_text(size=8)) +
  theme(axis.title.x=element_text(size=12)) +
  theme(axis.title.y=element_text(size=8)) +
  #Format title and facet_wrap title
  theme(strip.text = element_text(size=8), plot.title = element_text(size = 16, colour = "black", vjust = 1, hjust=0))+
    
  # Plot margins
  theme(plot.margin = unit(c(.2, .2, .2, .2), "cm"))
}

Make the plot. Let’s use ggridges. See here.

library(ggridges); library(ggplot2)
# The palette with grey:
cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
ggplot(pets, aes(x=Age, y=AnimalType, fill=factor(..quantile..))) +
  stat_density_ridges(
    geom = "density_ridges_gradient", calc_ecdf = TRUE,
    quantiles = 4, quantile_lines = TRUE, alpha = 0.7) +
  scale_x_continuous(limits=c(0,25))+ 
  scale_fill_manual(values=alpha(cbPalette, .5), name = "Quartiles")+
  my_theme()+ labs(y="", x="Age", caption="Created by Alex Albright | thelittledataset.com\nI exclude the five pets who are older than 25 for the sake of the graph")+
  ggtitle("Dog and Cat Age Distributions", subtitle=" Data via the Sunshine Coast Council") 
ggsave("dog_cat_ages.png", width = 6, height = 4.3, dpi = 800)

This is a ridgeline plot that uses data densities. I.e., it’s two density plots put over one another.

The quartiles really highlight how similar the distributions are. These density plots show that dog and cat lifespans look pretty similar, which I didn’t realize before!

Put emojis for cat/dog in :)

library(magrittr);library(magick)
# Now call back the plot
background <- image_read("dog_cat_ages.png")
# And bring in a zipper emoji
cat_raw <- image_read("cat.png")
cat <- cat_raw %>%
  image_scale("250") 
dog_raw <- image_read("dog.png")
dog <- dog_raw %>%
  image_scale("250") 
new<-image_composite(background, dog, offset = "+120+1580")
new1<-image_composite(new, cat, offset = "+130+2300")
image_write(new1, "dog_cat_ages_final.png", flatten = F)

Here is the final graphic. see here

How do pet ages compare to human ages?

From a 2008 WSJ article:

Somewhere along the way, it seems likely to several veterinarians, typical lifespans were pegged at about 70 for humans and about 10 for dogs. Thus, the seven-year rule was born. “My guess is it was a marketing ploy,” says William Fortney, a veterinarian at Kansas State University, “a way to educate the public on how fast a dog ages compared to a human, predominantly from a health standpoint. It was a way to encourage owners to bring in their pets at least once a year.”

From a priceonomics article:

Yet because there is no canine equivalent to the National Center for Health Statistics, we rely on a triage of sources for their lifespan data: pet insurance companies, breed-club surveys, and veterinary hospitals. As Carl Bialik of the WSJ notes, these sources often provide inaccurate, skewed results. Dogs who have insurance, for instance, are generally more likely to live longer lives. Surveys, which often require owners to guesstimate their pets’ ages, yield inflated numbers.

With this complete data on registered dogs in Australia, we could compare summary statistics across dog and human ages therein. Let’s compare median ages (rather than life expectancy because I can’t see deaths for the dogs and I don’t want to get into life expectancy calculations – see more here).

Australian Bureau of Statistics says the median age for Australian is 37, as of June 30, 2017.

What are the median ages for dogs and cats?

median(subset(pets, AnimalType="D")$Age)
[1] 6
median(subset(pets, AnimalType="Cat")$Age)
[1] 6

The median dog age for Australian dogs is 6. So,

37/6
[1] 6.166667

So \(dog_{median} \times 6 \approx human_{median}\).

Assuming we want to match on medians, dog-years (in Australia at least) are 6.166667 rather than 7 years.



  1. Pets do die.

  2. I promise I’ll eventually make a package for this.

LS0tCnRpdGxlOiAiQ2F0cyB2cy4gRG9nczogTmFtZXMgJiBBZ2VzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBBbGV4IEFsYnJpZ2h0CmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCIKLS0tCgojIFRoZSBEYXRhCgoiW1RdaGUgU3Vuc2hpbmUgQ29hc3QgQ291bmNpbCwgaW4gQXVzdHJhbGlhLCBwdWJsaXNoZXMgYSBzcHJlYWRzaGVldCBvZiBib3RoIGRvZ3MgYW5kIGNhdHMsIHRoZWlyIHByaW1hcnkgYnJlZWRzIGFuZCBjb2xvcnMsIGFuZCB3aGV0aGVyIHRoZXnigJl2ZSBiZWVuIHNwYXllZC9uZXV0ZXJlZC4iIChoL3QgW0RhdGEgaXMgUGx1cmFsXShodHRwczovL3RpbnlsZXR0ZXIuY29tL2RhdGEtaXMtcGx1cmFsKSkKCkxldCdzIGRvd25sb2FkIHRoaXMgZGF0YS4gSXQgaXMgYXZhaWxhYmxlIFtoZXJlXShodHRwczovL2RhdGEuc3Vuc2hpbmVjb2FzdC5xbGQuZ292LmF1L0FkbWluaXN0cmF0aW9uL1JlZ2lzdGVyZWQtQW5pbWFscy83Zjg3LWk2a3gvZGF0YSkhIEkgZG93bmxvYWQgdGhlIGNzdiBhbmQgdGhlbiBvcGVuIGl0IHVwLgoKYGBge3J9CnBldHM8LSByZWFkLmNzdignUmVnaXN0ZXJlZF9BbmltYWxzLmNzdicpCmxldmVscyhwZXRzJEFuaW1hbFR5cGUpCmBgYApUaGVyZSBhcmUgc3BhY2VzIGluIHRoZSBgQW5pbWFsVHlwZWAgdmFyaWFibGUuIFdlIHJlbW92ZSB0aGVtIG5vdy4KYGBge3J9CmxpYnJhcnkoc3RyaW5ncikKcGV0cyRBbmltYWxUeXBlPC1zdHJfdHJpbShhcy5jaGFyYWN0ZXIocGV0cyRBbmltYWxUeXBlKSkKcGV0cyRBbmltYWxUeXBlW3BldHMkQW5pbWFsVHlwZT09IkQiXTwtIkRvZyIKdW5pcXVlKHBldHMkQW5pbWFsVHlwZSkKYGBgCgpgYGB7cn0KbnJvdyhwZXRzKQpucm93KHN1YnNldChwZXRzLCBBbmltYWxUeXBlPT0iQ2F0IikpCm5yb3coc3Vic2V0KHBldHMsIEFuaW1hbFR5cGU9PSJEb2ciKSkKYGBgClRoZXJlIGFyZSA1NSw0OTUgYW5pbWFscyByZWdpc3RlcmVkIHdpdGggdGhlIHN1bnNoaW5lIGNvdW5jaWwgaW4gQXVzdHJhbGlhLCA5LDQxMiBhcmUgY2F0cyBhbmQgNDYsMDgzIGFyZSBkb2dzLiBTbywgdGhlcmUgYXJlIGFsbW9zdCA1IHRpbWVzIGFzIG1hbnkgZG9ncyBhcyBjYXRzIGluIEF1c3RyYWxpYS4KCkkgd29uZGVyIGlmIHNvbWUgb2YgdGhlc2UgYW5pbWFscyBjb3VsZCBiZSBkZWNlYXNlZC5eW1tQZXRzIGRvIGRpZS5dKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9N1Z6YUw0Q1NmbXMmZmVhdHVyZT15b3V0dS5iZSZ0PTU0KV0gSSBsb29rIGludG8gdGhlIFtTdW5zaGluZSBDb2FzdCBXZWJzaXRlXShodHRwczovL3d3dy5zdW5zaGluZWNvYXN0LnFsZC5nb3YuYXUvUGF5LWFuZC1BcHBseS9DYXQtYW5kLURvZy1SZWdpc3RyYXRpb24vUmVnaXN0cmF0aW9uLVJlbmV3YWxzKSBhbmQgc2VlIHRoYXQgIltkXW9nIHJlZ2lzdHJhdGlvbnMgbXVzdCBiZSByZW5ld2VkIGFubnVhbGx5IGFzIHBlciB0aGUgQW5pbWFsIE1hbmFnZW1lbnQgKENhdHMgJiBEb2dzKSBBY3QgMjAwOCBRdWVlbnNsYW5kLiBDYXQgcmVnaXN0cmF0aW9ucyBtdXN0IGJlIHJlbmV3ZWQgYW5udWFsbHkgYXMgcGVyIHRoZSBTdW5zaGluZSBDb2FzdCBMb2NhbCBMYXcgTm8uIDIgKEFuaW1hbCBNYW5hZ2VtZW50KSAyMDExLiIgU28sIGFsbCBhbmltYWxzIGluIHRoZSBkYXRhc2V0IGhhdmUgYmVlbiAicmVuZXdlZCIgd2l0aGluIHRoZSBsYXN0IHllYXIsIG1lYW5pbmcgdGhpcyBpcyBhIGRhdGFzZXQgb2YgImFjdGl2ZSBhbmltYWxzLiIgKEkuZS4sIHRoZXkgd2VyZSBhbGl2ZSBhdCBzb21lIHBvaW50IHRoaXMgeWVhci4pCgojIE5hbWVzCgojIyBNb3N0IFBvcHVsYXIgCgpMZXQncyBmaWd1cmUgb3V0IHRoZSBtb3N0IHBvcHVsYXIgcGV0IG5hbWVzIGluIEF1c3RyYWxpYS4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIExpc3QgdG9wIDUgY2F0IG5hbWVzLi4uCnBldHMkTmFtZTwtdG9sb3dlcihwZXRzJE5hbWUpCmxpYnJhcnkoZHBseXIpCgpwZXRuYW1lczwtIHBldHMgJT4lCiAgICAgZ3JvdXBfYnkoTmFtZSwgQW5pbWFsVHlwZSkgJT4lCiAgICAgc3VtbWFyaXNlKG51bT1uKCkpICU+JSAKICAgICBhcnJhbmdlKGRlc2MobnVtKSkKcGV0bmFtZXNbMTo1LF0KYGBgCgoqKlRvcCA1IGRvZyBuYW1lczogYmVsbGEsIGNoYXJsaWUsIG1vbGx5LCBtYXgsIGJ1ZGR5KioKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIExpc3QgdG9wIDUgY2F0IG5hbWVzLi4uCnN1YnNldChwZXRuYW1lcywgcGV0bmFtZXMkQW5pbWFsVHlwZT09IkNhdCIpWzE6NSxdCmBgYAoKKipUb3AgNSBjYXQgbmFtZXM6IGJlbGxhLCBjaGFybGllLCBtb2xseSwgbWF4LCBtaWEqKgoKU28sIGluIHN1bW1hcnk6CgpUb3AgNSBDYXQgTmFtZXMgfCBUb3AgNSBEb2cgTmFtZXMKLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0KQmVsbGEgICAgICAgICB8IEJlbGxhCkNoYXJsaWUgICAgICAgfCBDaGFybGllIApNb2xseSAgICAgICAgICAgfCBNb2xseQpNYXggICAgICAgICB8IE1heApNaWEgICAgICAgICB8IEJ1ZGR5CgoKT3ZlcmFsbCwgQmVsbGEgb2J2aW91c2x5IGEgcG9wdWxhciBuYW1lIGluIFtOWUMgZm9yIGRvZ3MgdG9vXShodHRwOi8vYTgxNi1kb2hiZXNwLm55Yy5nb3YvSW5kaWNhdG9yUHVibGljL2RvZ25hbWVzLykuIEFuZCBbZm9yIGh1bWFucy4uLl0oaHR0cDovL3d3dy53b2xmcmFtYWxwaGEuY29tL2lucHV0Lz9pPWJlbGxhKSBJIGd1ZXNzIFR3aWxpZ2h0IHRvb2sgdGhlIGFuaW1hbCBraW5nZG9tIGFzIHdlbGwgYXMgaHVtYW5zIGJ5IHN0b3JtIQoKIyMgTW9zdCBkb2cteS9jYXQteSBuYW1lcyAodXNpbmcgYHRmLWlkZmApCgpTaW5jZSBsb3RzIG9mIHRoZSB0b3AgbmFtZXMgYXJlIHRoZSBzYW1lIGZvciBkb2dzIGFuZCBjYXRzLCBpdCB3b3VsZCBiZSBtb3JlIGludGVyZXN0aW5nIHRvIHNlZSB3aGljaCBhcmUgbW9zdCB1bmlxdWVseSBjYXQteSBvciBkb2cteSBuYW1lcy4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl0ZXh0KQpwZXRuYW1lczEgPC0gcGV0bmFtZXMgJT4lCiAgYmluZF90Zl9pZGYoTmFtZSwgQW5pbWFsVHlwZSwgbnVtKQoKcGV0dGY8LSBwZXRuYW1lczEgJT4lIAogIGFycmFuZ2UoZGVzYyh0Zl9pZGYpKQoKc3Vic2V0KHBldHRmLCBwZXR0ZiRBbmltYWxUeXBlPT0iQ2F0IilbMTo1LF0KYGBgCgoqKlRoZSB0b3AgNSBjYXQteSBuYW1lcyBhcmU6IHB1c3MsIG1pdHRlbnMsIGdhcmZpZWxkLCBtZW93LCBzYWxlbSoqCgpgYGB7cn0Kc3Vic2V0KHBldHRmLCBwZXR0ZiRBbmltYWxUeXBlPT0iRG9nIilbMTo1LF0KYGBgCgoqKlRoZSB0b3AgNSBkb2cteSBuYW1lcyBhcmU6IGh1ZHNvbiwgZG96ZXIsIGJyb25zb24sIGNob3BwZXIsIHlvZ2kqKgoKU28sIGluIHN1bW1hcnk6CgpUb3AgNSBDYXQteSBOYW1lcyB8IFRvcCA1IERvZy15IE5hbWVzCi0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tClB1c3MgICAgICAgICAgfCBIdWRzb24gCk1pdHRlbnMgICAgICAgfCBEb3plciAKR2FyZmllbGQgICAgICB8IEJyb25zb24KTWVvdyAgICAgICAgICB8IENob3BwZXIKU2FsZW0gICAgICAgICB8IFlvZ2kKCiMgQWdlCgpMZXQncyBzZWUgd2hvIHRoZSBvbGRlc3QgYW5pbWFscyBhcmUuLi4KCmBgYHtyfQpwZXRzW29yZGVyKC1wZXRzJEFnZSksXQpgYGAKCjcxLCA1MiwgNDIsIDMxLCAyOCwuLi4gKmFyZSB0aGVzZSBhZ2VzIGZvciByZWFsPz8/ISEhKiAKCiMjIEhvdyBkb2VzIHRoZSBhZ2UgZGlzdHJpYnV0aW9uIGRpZmZlciBhY3Jvc3MgdGhlIGRvZyBhbmQgY2F0IHBvcHVsYXRpb25zPwoKSSB3aWxsIHVzZSBteSByZWd1bGFyIHRoZW1lIGZvciBzdHlsaW5nLl5bSSBwcm9taXNlIEknbGwgZXZlbnR1YWxseSBtYWtlIGEgcGFja2FnZSBmb3IgdGhpcy5dCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpO2xpYnJhcnkoZ2dyZXBlbCk7IGxpYnJhcnkoZXh0cmFmb250KTsgbGlicmFyeShnZ3RoZW1lcyk7bGlicmFyeShyZXNoYXBlKTtsaWJyYXJ5KGdyaWQpOwpsaWJyYXJ5KHNjYWxlcyk7bGlicmFyeShSQ29sb3JCcmV3ZXIpO2xpYnJhcnkoZ3JpZEV4dHJhKTsKCm15X3RoZW1lIDwtIGZ1bmN0aW9uKCkgewoKICAjIERlZmluZSBjb2xvcnMgZm9yIHRoZSBjaGFydAogIHBhbGV0dGUgPC0gYnJld2VyLnBhbCgiR3JleXMiLCBuPTkpCiAgY29sb3IuYmFja2dyb3VuZCA9IHBhbGV0dGVbMl0KICBjb2xvci5ncmlkLm1ham9yID0gcGFsZXR0ZVs0XQogIGNvbG9yLnBhbmVsID0gcGFsZXR0ZVszXQogIGNvbG9yLmF4aXMudGV4dCA9IHBhbGV0dGVbOV0KICBjb2xvci5heGlzLnRpdGxlID0gcGFsZXR0ZVs5XQogIGNvbG9yLnRpdGxlID0gcGFsZXR0ZVs5XQoKICAjIENyZWF0ZSBiYXNpYyBjb25zdHJ1Y3Rpb24gb2YgY2hhcnQKICB0aGVtZV9idyhiYXNlX3NpemU9OSwgYmFzZV9mYW1pbHk9IlBhbGF0aW5vIikgKyAKCiAgIyBTZXQgdGhlIGVudGlyZSBjaGFydCByZWdpb24gdG8gYSBsaWdodCBncmF5IGNvbG9yCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X3JlY3QoZmlsbD1jb2xvci5wYW5lbCwgY29sb3I9Y29sb3IuYmFja2dyb3VuZCkpICsKICB0aGVtZShwbG90LmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGZpbGw9Y29sb3IuYmFja2dyb3VuZCwgY29sb3I9Y29sb3IuYmFja2dyb3VuZCkpICsKICB0aGVtZShwYW5lbC5ib3JkZXI9ZWxlbWVudF9yZWN0KGNvbG9yPWNvbG9yLmJhY2tncm91bmQpKSArCgogICMgRm9ybWF0IGdyaWQKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfbGluZShjb2xvcj1jb2xvci5ncmlkLm1ham9yLHNpemU9LjI1KSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUoYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCkpICsKCiAgIyBGb3JtYXQgbGVnZW5kCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpICsKICB0aGVtZShsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPWNvbG9yLmJhY2tncm91bmQpKSArCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04LGNvbG9yPWNvbG9yLmF4aXMudGl0bGUpKSArIAogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTgsY29sb3I9Y29sb3IuYXhpcy50aXRsZSkpICsgCiAgCiAgI0Zvcm1hdCBmYWNldCBsYWJlbHMKICB0aGVtZShzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgsIGZhY2U9ImJvbGQiKSkrCgogICMgRm9ybWF0IHRpdGxlIGFuZCBheGVzIGxhYmVscyB0aGVzZSBhbmQgdGljayBtYXJrcwogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGNvbG9yPWNvbG9yLnRpdGxlLCBzaXplPTI4KSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTgpKSArCiAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTIpKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTgpKSArCgogICNGb3JtYXQgdGl0bGUgYW5kIGZhY2V0X3dyYXAgdGl0bGUKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IDEsIGhqdXN0PTApKSsKICAgIAogICMgUGxvdCBtYXJnaW5zCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoLjIsIC4yLCAuMiwgLjIpLCAiY20iKSkKfQpgYGAKTWFrZSB0aGUgcGxvdC4gTGV0J3MgdXNlIGBnZ3JpZGdlc2AuIFNlZSBbaGVyZS5dKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3JpZGdlcy92aWduZXR0ZXMvaW50cm9kdWN0aW9uLmh0bWwpCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGdncmlkZ2VzKTsgbGlicmFyeShnZ3Bsb3QyKQoKIyBUaGUgcGFsZXR0ZSB3aXRoIGdyZXk6CmNiUGFsZXR0ZSA8LSBjKCIjOTk5OTk5IiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwgIiNGMEU0NDIiLCAiIzAwNzJCMiIsICIjRDU1RTAwIiwgIiNDQzc5QTciKQoKZ2dwbG90KHBldHMsIGFlcyh4PUFnZSwgeT1BbmltYWxUeXBlLCBmaWxsPWZhY3RvciguLnF1YW50aWxlLi4pKSkgKwogIHN0YXRfZGVuc2l0eV9yaWRnZXMoCiAgICBnZW9tID0gImRlbnNpdHlfcmlkZ2VzX2dyYWRpZW50IiwgY2FsY19lY2RmID0gVFJVRSwKICAgIHF1YW50aWxlcyA9IDQsIHF1YW50aWxlX2xpbmVzID0gVFJVRSwgYWxwaGEgPSAwLjcpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMCwyNSkpKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YWxwaGEoY2JQYWxldHRlLCAuNSksIG5hbWUgPSAiUXVhcnRpbGVzIikrCiAgbXlfdGhlbWUoKSsgbGFicyh5PSIiLCB4PSJBZ2UiLCBjYXB0aW9uPSJDcmVhdGVkIGJ5IEFsZXggQWxicmlnaHQgfCB0aGVsaXR0bGVkYXRhc2V0LmNvbVxuSSBleGNsdWRlIHRoZSBmaXZlIHBldHMgd2hvIGFyZSBvbGRlciB0aGFuIDI1IGZvciB0aGUgc2FrZSBvZiB0aGUgZ3JhcGgiKSsKICBnZ3RpdGxlKCJEb2cgYW5kIENhdCBBZ2UgRGlzdHJpYnV0aW9ucyIsIHN1YnRpdGxlPSIgRGF0YSB2aWEgdGhlIFN1bnNoaW5lIENvYXN0IENvdW5jaWwiKSAKCmdnc2F2ZSgiZG9nX2NhdF9hZ2VzLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNC4zLCBkcGkgPSA4MDApCmBgYApUaGlzIGlzIGEgcmlkZ2VsaW5lIHBsb3QgdGhhdCB1c2VzIGRhdGEgZGVuc2l0aWVzLiBJLmUuLCBpdCdzIHR3byBkZW5zaXR5IHBsb3RzIHB1dCBvdmVyIG9uZSBhbm90aGVyLgoKVGhlIHF1YXJ0aWxlcyByZWFsbHkgaGlnaGxpZ2h0IGhvdyBzaW1pbGFyIHRoZSBkaXN0cmlidXRpb25zIGFyZS4gVGhlc2UgZGVuc2l0eSBwbG90cyBzaG93IHRoYXQgZG9nIGFuZCBjYXQgbGlmZXNwYW5zIGxvb2sgcHJldHR5IHNpbWlsYXIsIHdoaWNoIEkgZGlkbid0IHJlYWxpemUgYmVmb3JlIQoKUHV0IGVtb2ppcyBmb3IgY2F0L2RvZyBpbiA6KQpgYGB7cn0KbGlicmFyeShtYWdyaXR0cik7bGlicmFyeShtYWdpY2spCgojIE5vdyBjYWxsIGJhY2sgdGhlIHBsb3QKYmFja2dyb3VuZCA8LSBpbWFnZV9yZWFkKCJkb2dfY2F0X2FnZXMucG5nIikKIyBBbmQgYnJpbmcgaW4gYSB6aXBwZXIgZW1vamkKY2F0X3JhdyA8LSBpbWFnZV9yZWFkKCJjYXQucG5nIikKY2F0IDwtIGNhdF9yYXcgJT4lCiAgaW1hZ2Vfc2NhbGUoIjI1MCIpIApkb2dfcmF3IDwtIGltYWdlX3JlYWQoImRvZy5wbmciKQpkb2cgPC0gZG9nX3JhdyAlPiUKICBpbWFnZV9zY2FsZSgiMjUwIikgCm5ldzwtaW1hZ2VfY29tcG9zaXRlKGJhY2tncm91bmQsIGRvZywgb2Zmc2V0ID0gIisxMjArMTU4MCIpCm5ldzE8LWltYWdlX2NvbXBvc2l0ZShuZXcsIGNhdCwgb2Zmc2V0ID0gIisxMzArMjMwMCIpCmltYWdlX3dyaXRlKG5ldzEsICJkb2dfY2F0X2FnZXNfZmluYWwucG5nIiwgZmxhdHRlbiA9IEYpCmBgYAoKSGVyZSBpcyB0aGUgZmluYWwgZ3JhcGhpYy4KIVtzZWUgaGVyZV0oZG9nX2NhdF9hZ2VzX2ZpbmFsLnBuZykKCiMjIEhvdyBkbyBwZXQgYWdlcyBjb21wYXJlIHRvIGh1bWFuIGFnZXM/CgpGcm9tIFthIDIwMDggV1NKIGFydGljbGVdKGh0dHBzOi8vd3d3Lndzai5jb20vYXJ0aWNsZXMvU0IxMjE5OTczMzgxNzY4ODIxNDMpOgoKPiBTb21ld2hlcmUgYWxvbmcgdGhlIHdheSwgaXQgc2VlbXMgbGlrZWx5IHRvIHNldmVyYWwgdmV0ZXJpbmFyaWFucywgdHlwaWNhbCBsaWZlc3BhbnMgd2VyZSBwZWdnZWQgYXQgYWJvdXQgNzAgZm9yIGh1bWFucyBhbmQgYWJvdXQgMTAgZm9yIGRvZ3MuIFRodXMsIHRoZSBzZXZlbi15ZWFyIHJ1bGUgd2FzIGJvcm4uICJNeSBndWVzcyBpcyBpdCB3YXMgYSBtYXJrZXRpbmcgcGxveSwiIHNheXMgV2lsbGlhbSBGb3J0bmV5LCBhIHZldGVyaW5hcmlhbiBhdCBLYW5zYXMgU3RhdGUgVW5pdmVyc2l0eSwgImEgd2F5IHRvIGVkdWNhdGUgdGhlIHB1YmxpYyBvbiBob3cgZmFzdCBhIGRvZyBhZ2VzIGNvbXBhcmVkIHRvIGEgaHVtYW4sIHByZWRvbWluYW50bHkgZnJvbSBhIGhlYWx0aCBzdGFuZHBvaW50LiBJdCB3YXMgYSB3YXkgdG8gZW5jb3VyYWdlIG93bmVycyB0byBicmluZyBpbiB0aGVpciBwZXRzIGF0IGxlYXN0IG9uY2UgYSB5ZWFyLiIKCkZyb20gW2EgcHJpY2Vvbm9taWNzIGFydGljbGVdKGh0dHBzOi8vcHJpY2Vvbm9taWNzLmNvbS90aGUtbXl0aG9sb2d5LW9mLWRvZy15ZWFycy8pOgoKPiBZZXQgYmVjYXVzZSB0aGVyZSBpcyBubyBjYW5pbmUgZXF1aXZhbGVudCB0byB0aGUgTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljcywgd2UgcmVseSBvbiBhIHRyaWFnZSBvZiBzb3VyY2VzIGZvciB0aGVpciBsaWZlc3BhbiBkYXRhOiBwZXQgaW5zdXJhbmNlIGNvbXBhbmllcywgYnJlZWQtY2x1YiBzdXJ2ZXlzLCBhbmQgdmV0ZXJpbmFyeSBob3NwaXRhbHMuIEFzIENhcmwgQmlhbGlrIG9mIHRoZSBXU0ogbm90ZXMsIHRoZXNlIHNvdXJjZXMgb2Z0ZW4gcHJvdmlkZSBpbmFjY3VyYXRlLCBza2V3ZWQgcmVzdWx0cy4gRG9ncyB3aG8gaGF2ZSBpbnN1cmFuY2UsIGZvciBpbnN0YW5jZSwgYXJlIGdlbmVyYWxseSBtb3JlIGxpa2VseSB0byBsaXZlIGxvbmdlciBsaXZlcy4gU3VydmV5cywgd2hpY2ggb2Z0ZW4gcmVxdWlyZSBvd25lcnMgdG8gZ3Vlc3N0aW1hdGUgdGhlaXIgcGV0c+KAmSBhZ2VzLCB5aWVsZCBpbmZsYXRlZCBudW1iZXJzLgoKV2l0aCB0aGlzIGNvbXBsZXRlIGRhdGEgb24gcmVnaXN0ZXJlZCBkb2dzIGluIEF1c3RyYWxpYSwgd2UgY291bGQgY29tcGFyZSBzdW1tYXJ5IHN0YXRpc3RpY3MgYWNyb3NzIGRvZyBhbmQgaHVtYW4gYWdlcyB0aGVyZWluLiBMZXQncyBjb21wYXJlIG1lZGlhbiBhZ2VzIChyYXRoZXIgdGhhbiBsaWZlIGV4cGVjdGFuY3kgYmVjYXVzZSBJIGNhbid0IHNlZSBkZWF0aHMgZm9yIHRoZSBkb2dzIGFuZCBJIGRvbid0IHdhbnQgdG8gZ2V0IGludG8gbGlmZSBleHBlY3RhbmN5IGNhbGN1bGF0aW9ucyAtLSBzZWUgbW9yZSBbaGVyZV0oaHR0cHM6Ly9vdXJ3b3JsZGluZGF0YS5vcmcvbGlmZS1leHBlY3RhbmN5LWhvdy1pcy1pdC1jYWxjdWxhdGVkLWFuZC1ob3ctc2hvdWxkLWl0LWJlLWludGVycHJldGVkKSkuCgpbQXVzdHJhbGlhbiBCdXJlYXUgb2YgU3RhdGlzdGljc10oaHR0cDovL3d3dy5hYnMuZ292LmF1L2F1c3N0YXRzL2Fic0AubnNmL2ZlYXR1cmVhcnRpY2xlc2J5Q2F0YWxvZ3VlL0NDRjUzQUEwMDBFNjk5NTRDQTI1ODI1NzAwMTNGNUM2P09wZW5Eb2N1bWVudCkgc2F5cyB0aGUgbWVkaWFuIGFnZSBmb3IgQXVzdHJhbGlhbiBpcyAzNywgYXMgb2YgSnVuZSAzMCwgMjAxNy4KCldoYXQgYXJlIHRoZSBtZWRpYW4gYWdlcyBmb3IgZG9ncyBhbmQgY2F0cz8KYGBge3J9Cm1lZGlhbihzdWJzZXQocGV0cywgQW5pbWFsVHlwZT0iRCIpJEFnZSkKbWVkaWFuKHN1YnNldChwZXRzLCBBbmltYWxUeXBlPSJDYXQiKSRBZ2UpCmBgYApUaGUgbWVkaWFuIGRvZyBhZ2UgZm9yIEF1c3RyYWxpYW4gZG9ncyBpcyA2LiAKU28sIApgYGB7cn0KMzcvNgpgYGAKClNvICRkb2dfe21lZGlhbn0gXHRpbWVzIDYgXGFwcHJveCBodW1hbl97bWVkaWFufSQuCgpBc3N1bWluZyB3ZSB3YW50IHRvIG1hdGNoIG9uIG1lZGlhbnMsIGRvZy15ZWFycyAoaW4gQXVzdHJhbGlhIGF0IGxlYXN0KSBhcmUgNi4xNjY2NjcgcmF0aGVyIHRoYW4gNyB5ZWFycy4KCi0tLQ==