Question 1. File import

a problematic file has been received. here’s the first 5 lines of the file:

#human gene information
gene_id;gene_name;chr;start;end;strand;tx_count;gc_perc;biotype
ENSG00000210049;MT-TF;MT;577;647;1;1;40.85;Mt_tRNA
ENSG00000211459;MT-RNR1;MT;648;1601;1;1;45.49;Mt_rRNA
ENSG00000210077;MT-TV;MT;1602;1670;1;1;42.03;Mt_tRNA

The file is located at: https://s3-us-west-2.amazonaws.com/veri-analizi/problem_file.txt

Please write a code to import this file. (Import means can you successfully get the data into data frame structure. For example, does filter(gc_perc > 42) work on imported table?)

Solution 1.

The file is not a csv file, thus we should not be using read.csv or read_csv functions. As you remember from the discussion in class, there are custom functions for specific file types (csv, tsv) and then there’s generic functions read.table and read_delim. The delimeter is | character and there are two comment line on top. As you can see, both functions have completely different options.

# this is base R solution and it automatically skips first commnent line, 
# due to `comment.char = "#"` default option
read.table("problem_file.txt", sep = ";", header = TRUE, stringsAsFactors = FALSE)  
                                                                                                
# OR
library(readr)
read_delim("problem_file.txt",  delim = ";", skip=1)  #this is tidyverse solution

Below is the related slide from “Importing Data in R” course, Chapter 2.

Import with delim or sep options

Import with delim or sep options

Question 2. A simple question - Summary of columns

A. general summary

Using human_genes table (which is loaded for you), please calculate the following summary

  • total number of genes
  • total number of chromosomes
  • total number of biotypes

Expected output:

n_genes n_chr n_biotypes
.. .. ..

Solution 2.A

library(dplyr)
human_genes %>%
  summarise(n_genes=n(),
            n_chr=n_distinct(chr),
            n_biotypes=n_distinct(biotype))

B. protein coding genes not located on mitochondria chromosome

Using the same table please calculate the following summary, considering only protein_coding genes which are not on mitochandrial chromosome (MT in table)

  • total number of genes (after filtering)
  • average gene length
  • average GC percentage

Expected output:

n_genes avg_length_genes avg_gc_perc
.. .. ..

Solution 2.B

human_genes %>%
  filter(biotype=="protein_coding" & chr != "MT") %>% 
  summarise(n_genes=n(),
            avg_length_genes=mean(end-start),
            avg_gc_perc=mean(gc_perc))

Here’s the screenshot from DataCamp exercise which uses aggregate functions with summarise(). “Data Manipulation in R with dplyr” lecture, Chapter 4, Exercise title “dplyr aggregate functions”

dplyr summarise aggregate functions

dplyr summarise aggregate functions

Question 3. Airline carrier with better delay stats

Average Delays per Carrier

Average Delays per Carrier

Please write down the code below which can produce the plot above The plot describes average departure delay (Red) and arrival delay (Blue) for each carrier.

Solution 3

library(ggplot2)
hflights %>% 
  group_by(UniqueCarrier) %>% 
  summarise(avg_arr_delay=mean(ArrDelay,na.rm = TRUE),
            avg_dep_delay=mean(DepDelay,na.rm = TRUE)) %>% 
  ggplot() +
  # it would be difficult to plot two separate delay data as scatter plot. remember, ggplot draws in layers, 
  geom_point(aes(x=UniqueCarrier,y=avg_arr_delay,col="arr_delay")) +   # this is first point layer
  geom_point(aes(x=UniqueCarrier,y=avg_dep_delay,col="dep_delay")) +   # second point layer for departure delays
  ylab("Average \nArr or Dep Delay") +                                 # this is not required
  scale_colour_manual(name = "Delays",                     # this part is completely cosmetic please ignore
                       values =c("arr_delay" = 'blue',"dep_delay" = 'red'),      # theming - you can ignore
                       labels = c('Arr Delay','Dep Delay'),                      # theming - you can ignore
                       breaks=c("arr_delay","dep_delay")) +                      # theming - you can ignore
  theme_light()                                                                  # theming - you can ignore

Question 4. A troublesome join

You already studied and are aware of hflights table from DataCamp courses. Three more tables are already defined for you (when you run the first chunk). Instead of using lookup tables as you did DataCamp, let’s use join to combine all data. Use airline_codes, cancellation_codes and airport_codes tables (already loaded for you) to find out most frequent weather related cancellations for airline and destination.

“airline” column should have carriers full name, “destination” column should have full name of airport and “cancellation” column should have the explanation of cancellation.

Expected output:

airline destination cancellation count
.. .. .. ..

Solution 4

hflights %>% 
  inner_join(airline_codes, by=c("UniqueCarrier"="name")) %>%           # the keys have different names 
  inner_join(airport_codes, by=c("Dest"="faa")) %>%                     # the keys have different names
  inner_join(cancellation_codes, by=c("CancellationCode"="name")) %>%   # the keys have different names 
  # you can use suffix option in joins to keep track of which column comes from which table
  select(airline=value.x,destination=name,cancellation=value.y) %>%     # selecting and renaming columns
  filter(cancellation=="weather") %>% 
  group_by(airline,destination,cancellation) %>%  # to count per airline and destination pairs, we group them
  count() %>% 
  arrange(-n)
LS0tCnRpdGxlOiAiR3IyIE1pZHRlcm0gU29sdXRpb25zIgphdXRob3I6ICJhbHBlciB5aWxtYXoiCmRhdGU6ICJOb3ZlbWJlciAxNSwgMjAxNyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgdGhlcmUgYXJlIG1pc3NpbmcvbmVjZXNzYXJ5IGxpYnJhcmllcyBwbGVhc2UgbG9hZCB0aGVtIHlvdXJzZWxmCmxpYnJhcnkoaGZsaWdodHMpCgpmaWxlc190b19kb3dubG9hZCA8LSBjKCJhaXJsaW5lX2NvZGVzIiwiY2FuY2VsbGF0aW9uX2NvZGVzIiwiYWlycG9ydF9jb2RlcyIsImh1bWFuX2dlbmVzIikKdXJsIDwtICJodHRwczovL3MzLXVzLXdlc3QtMi5hbWF6b25hd3MuY29tL3ZlcmktYW5hbGl6aS8iCiMgd2Ugc2hvdWxkIG5vdCBiZSBkb3dubG9hZGluZyBmaWxlcyBhdCBlYWNoIHJ1biAtIGZvciBzaW5nbGUgcnVuIHRoaXMgaXMgYmV0dGVyOiByZWFkUkRTKGd6Y29uKHVybCgicmVtb3RlLXVybC1yZHMtZmlsZSIpKSkKZG93bmxvYWRzIDwtIGxhcHBseShmaWxlc190b19kb3dubG9hZCwgZnVuY3Rpb24oeCkgewogIGlmICghZmlsZS5leGlzdHMocGFzdGUwKHggLCAiLnJkcyIpKSkgeyBkb3dubG9hZC5maWxlKHBhc3RlMCggdXJsICwgeCAsICIucmRzIiApLCBwYXN0ZTAoeCAsICIucmRzIikpCiAgfSAgCiAgYXNzaWduKCB4LCByZWFkUkRTKCBwYXN0ZTAoIHggLCAiLnJkcyIgKSksIGVudmlyID0gcGFyZW50LmZyYW1lKDIpICkgCk5VTEwKfSkKYGBgCgojIFF1ZXN0aW9uIDEuIEZpbGUgaW1wb3J0CgphIHByb2JsZW1hdGljIGZpbGUgaGFzIGJlZW4gcmVjZWl2ZWQuIGhlcmUncyB0aGUgZmlyc3QgNSBsaW5lcyBvZiB0aGUgZmlsZToKCmBgYAojaHVtYW4gZ2VuZSBpbmZvcm1hdGlvbgpnZW5lX2lkO2dlbmVfbmFtZTtjaHI7c3RhcnQ7ZW5kO3N0cmFuZDt0eF9jb3VudDtnY19wZXJjO2Jpb3R5cGUKRU5TRzAwMDAwMjEwMDQ5O01ULVRGO01UOzU3Nzs2NDc7MTsxOzQwLjg1O010X3RSTkEKRU5TRzAwMDAwMjExNDU5O01ULVJOUjE7TVQ7NjQ4OzE2MDE7MTsxOzQ1LjQ5O010X3JSTkEKRU5TRzAwMDAwMjEwMDc3O01ULVRWO01UOzE2MDI7MTY3MDsxOzE7NDIuMDM7TXRfdFJOQQpgYGAKClRoZSBmaWxlIGlzIGxvY2F0ZWQgYXQ6IGh0dHBzOi8vczMtdXMtd2VzdC0yLmFtYXpvbmF3cy5jb20vdmVyaS1hbmFsaXppL3Byb2JsZW1fZmlsZS50eHQKClBsZWFzZSB3cml0ZSBhIGNvZGUgdG8gaW1wb3J0IHRoaXMgZmlsZS4gKCoqSW1wb3J0KiogbWVhbnMgY2FuIHlvdSBzdWNjZXNzZnVsbHkgZ2V0IHRoZSBkYXRhIGludG8gZGF0YSBmcmFtZSBzdHJ1Y3R1cmUuIEZvciBleGFtcGxlLCBkb2VzIGBmaWx0ZXIoZ2NfcGVyYyA+IDQyKWAgd29yayBvbiBpbXBvcnRlZCB0YWJsZT8pCgojIFNvbHV0aW9uIDEuIAoKVGhlIGZpbGUgaXMgbm90IGEgY3N2IGZpbGUsIHRodXMgd2Ugc2hvdWxkIG5vdCBiZSB1c2luZyBgcmVhZC5jc3ZgIG9yIGByZWFkX2NzdmAgZnVuY3Rpb25zLiBBcyB5b3UgcmVtZW1iZXIgZnJvbSB0aGUgZGlzY3Vzc2lvbiBpbiBjbGFzcywgdGhlcmUgYXJlIGN1c3RvbSBmdW5jdGlvbnMgZm9yIHNwZWNpZmljIGZpbGUgdHlwZXMgKGNzdiwgdHN2KSBhbmQgdGhlbiB0aGVyZSdzIGdlbmVyaWMgZnVuY3Rpb25zIGByZWFkLnRhYmxlYCBhbmQgYHJlYWRfZGVsaW1gLiBUaGUgZGVsaW1ldGVyIGlzIGB8YCBjaGFyYWN0ZXIgYW5kIHRoZXJlIGFyZSB0d28gY29tbWVudCBsaW5lIG9uIHRvcC4gQXMgeW91IGNhbiBzZWUsIGJvdGggZnVuY3Rpb25zIGhhdmUgY29tcGxldGVseSBkaWZmZXJlbnQgb3B0aW9ucy4gCgpgYGB7ciBzb2x1dGlvbjEsIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIHRoaXMgaXMgYmFzZSBSIHNvbHV0aW9uIGFuZCBpdCBhdXRvbWF0aWNhbGx5IHNraXBzIGZpcnN0IGNvbW1uZW50IGxpbmUsIAojIGR1ZSB0byBgY29tbWVudC5jaGFyID0gIiMiYCBkZWZhdWx0IG9wdGlvbgpyZWFkLnRhYmxlKCJwcm9ibGVtX2ZpbGUudHh0Iiwgc2VwID0gIjsiLCBoZWFkZXIgPSBUUlVFLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiMgT1IKCmxpYnJhcnkocmVhZHIpCnJlYWRfZGVsaW0oInByb2JsZW1fZmlsZS50eHQiLCAgZGVsaW0gPSAiOyIsIHNraXA9MSkgICN0aGlzIGlzIHRpZHl2ZXJzZSBzb2x1dGlvbgpgYGAKCkJlbG93IGlzIHRoZSByZWxhdGVkIHNsaWRlIGZyb20gIkltcG9ydGluZyBEYXRhIGluIFIiIGNvdXJzZSwgQ2hhcHRlciAyLgoKIVtJbXBvcnQgd2l0aCBkZWxpbSBvciBzZXAgb3B0aW9uc10oaW1wb3J0X2RlbGltLnBuZykKCiMgUXVlc3Rpb24gMi4gQSBzaW1wbGUgcXVlc3Rpb24gLSBTdW1tYXJ5IG9mIGNvbHVtbnMKCiMjIEEuIGdlbmVyYWwgc3VtbWFyeQoKVXNpbmcgYGh1bWFuX2dlbmVzYCB0YWJsZSAod2hpY2ggaXMgbG9hZGVkIGZvciB5b3UpLCBwbGVhc2UgY2FsY3VsYXRlIHRoZSBmb2xsb3dpbmcgc3VtbWFyeQoKKiB0b3RhbCBudW1iZXIgb2YgZ2VuZXMKKiB0b3RhbCBudW1iZXIgb2YgY2hyb21vc29tZXMKKiB0b3RhbCBudW1iZXIgb2YgYmlvdHlwZXMKCkV4cGVjdGVkIG91dHB1dDoKCnwgbl9nZW5lcyB8IG5fY2hyIHwgbl9iaW90eXBlcyB8CnwtLS0tLS0tLS18LS0tLS0tLXwtLS0tLS0tLS0tLS18CnwgICAuLiAgICB8ICAgLi4gIHwgICAgIC4uICAgICB8CgojIyBTb2x1dGlvbiAyLkEKCmBgYHtyIGFuc3dlcjJhLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpodW1hbl9nZW5lcyAlPiUKICBzdW1tYXJpc2Uobl9nZW5lcz1uKCksCiAgICAgICAgICAgIG5fY2hyPW5fZGlzdGluY3QoY2hyKSwKICAgICAgICAgICAgbl9iaW90eXBlcz1uX2Rpc3RpbmN0KGJpb3R5cGUpKQpgYGAKCgojIyBCLiBwcm90ZWluIGNvZGluZyBnZW5lcyBub3QgbG9jYXRlZCBvbiBtaXRvY2hvbmRyaWEgY2hyb21vc29tZQoKVXNpbmcgdGhlIHNhbWUgdGFibGUgcGxlYXNlIGNhbGN1bGF0ZSB0aGUgZm9sbG93aW5nIHN1bW1hcnksIGNvbnNpZGVyaW5nIG9ubHkgYHByb3RlaW5fY29kaW5nYCBnZW5lcyB3aGljaCBhcmUgbm90IG9uIG1pdG9jaGFuZHJpYWwgY2hyb21vc29tZSAoYE1UYCBpbiB0YWJsZSkKCiogdG90YWwgbnVtYmVyIG9mIGdlbmVzIChhZnRlciBmaWx0ZXJpbmcpCiogYXZlcmFnZSBnZW5lIGxlbmd0aAoqIGF2ZXJhZ2UgR0MgcGVyY2VudGFnZQoKRXhwZWN0ZWQgb3V0cHV0OgoKfCBuX2dlbmVzIHwgYXZnX2xlbmd0aF9nZW5lcyB8IGF2Z19nY19wZXJjIHwgCnwtLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18CnwgICAuLiAgICB8ICAgICAgIC4uICAgICAgICAgfCAgICAgIC4uICAgICB8CgojIyBTb2x1dGlvbiAyLkIKCmBgYHtyIGFuc3dlcjJifQpodW1hbl9nZW5lcyAlPiUKICBmaWx0ZXIoYmlvdHlwZT09InByb3RlaW5fY29kaW5nIiAmIGNociAhPSAiTVQiKSAlPiUgCiAgc3VtbWFyaXNlKG5fZ2VuZXM9bigpLAogICAgICAgICAgICBhdmdfbGVuZ3RoX2dlbmVzPW1lYW4oZW5kLXN0YXJ0KSwKICAgICAgICAgICAgYXZnX2djX3BlcmM9bWVhbihnY19wZXJjKSkKYGBgCgpIZXJlJ3MgdGhlIHNjcmVlbnNob3QgZnJvbSBEYXRhQ2FtcCBleGVyY2lzZSB3aGljaCB1c2VzIGFnZ3JlZ2F0ZSBmdW5jdGlvbnMgd2l0aCBgc3VtbWFyaXNlKClgLiAiRGF0YSBNYW5pcHVsYXRpb24gaW4gUiB3aXRoIGRwbHlyIiBsZWN0dXJlLCBDaGFwdGVyIDQsIEV4ZXJjaXNlIHRpdGxlICJkcGx5ciBhZ2dyZWdhdGUgZnVuY3Rpb25zIiAKCiFbZHBseXIgc3VtbWFyaXNlIGFnZ3JlZ2F0ZSBmdW5jdGlvbnNdKGRwbHlyX3N1bW1hcmlzZV9hZ2dyZWdhdGUucG5nKQoKCgojIFF1ZXN0aW9uIDMuIEFpcmxpbmUgY2FycmllciB3aXRoIGJldHRlciBkZWxheSBzdGF0cwoKIVtBdmVyYWdlIERlbGF5cyBwZXIgQ2Fycmllcl0oaHR0cHM6Ly9zMy11cy13ZXN0LTIuYW1hem9uYXdzLmNvbS92ZXJpLWFuYWxpemkvYXZlcmFnZV9kZWxheS5wbmcpCgpQbGVhc2Ugd3JpdGUgZG93biB0aGUgY29kZSBiZWxvdyB3aGljaCBjYW4gcHJvZHVjZSB0aGUgcGxvdCBhYm92ZSBUaGUgcGxvdCBkZXNjcmliZXMgYXZlcmFnZSBkZXBhcnR1cmUgZGVsYXkgKFJlZCkgYW5kIGFycml2YWwgZGVsYXkgKEJsdWUpIGZvciBlYWNoIGNhcnJpZXIuCgojIFNvbHV0aW9uIDMKCmBgYHtyIGFuc3dlcjN9CmxpYnJhcnkoZ2dwbG90MikKaGZsaWdodHMgJT4lIAogIGdyb3VwX2J5KFVuaXF1ZUNhcnJpZXIpICU+JSAKICBzdW1tYXJpc2UoYXZnX2Fycl9kZWxheT1tZWFuKEFyckRlbGF5LG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGF2Z19kZXBfZGVsYXk9bWVhbihEZXBEZWxheSxuYS5ybSA9IFRSVUUpKSAlPiUgCiAgZ2dwbG90KCkgKwogICMgaXQgd291bGQgYmUgZGlmZmljdWx0IHRvIHBsb3QgdHdvIHNlcGFyYXRlIGRlbGF5IGRhdGEgYXMgc2NhdHRlciBwbG90LiByZW1lbWJlciwgZ2dwbG90IGRyYXdzIGluIGxheWVycywgCiAgZ2VvbV9wb2ludChhZXMoeD1VbmlxdWVDYXJyaWVyLHk9YXZnX2Fycl9kZWxheSxjb2w9ImFycl9kZWxheSIpKSArICAgIyB0aGlzIGlzIGZpcnN0IHBvaW50IGxheWVyCiAgZ2VvbV9wb2ludChhZXMoeD1VbmlxdWVDYXJyaWVyLHk9YXZnX2RlcF9kZWxheSxjb2w9ImRlcF9kZWxheSIpKSArICAgIyBzZWNvbmQgcG9pbnQgbGF5ZXIgZm9yIGRlcGFydHVyZSBkZWxheXMKICB5bGFiKCJBdmVyYWdlIFxuQXJyIG9yIERlcCBEZWxheSIpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaXMgaXMgbm90IHJlcXVpcmVkCiAgc2NhbGVfY29sb3VyX21hbnVhbChuYW1lID0gIkRlbGF5cyIsICAgICAgICAgICAgICAgICAgICAgIyB0aGlzIHBhcnQgaXMgY29tcGxldGVseSBjb3NtZXRpYyBwbGVhc2UgaWdub3JlCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID1jKCJhcnJfZGVsYXkiID0gJ2JsdWUnLCJkZXBfZGVsYXkiID0gJ3JlZCcpLCAgICAgICMgdGhlbWluZyAtIHlvdSBjYW4gaWdub3JlCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygnQXJyIERlbGF5JywnRGVwIERlbGF5JyksICAgICAgICAgICAgICAgICAgICAgICMgdGhlbWluZyAtIHlvdSBjYW4gaWdub3JlCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoImFycl9kZWxheSIsImRlcF9kZWxheSIpKSArICAgICAgICAgICAgICAgICAgICAgICMgdGhlbWluZyAtIHlvdSBjYW4gaWdub3JlCiAgdGhlbWVfbGlnaHQoKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlbWluZyAtIHlvdSBjYW4gaWdub3JlCmBgYAoKIyBRdWVzdGlvbiA0LiBBIHRyb3VibGVzb21lIGpvaW4KCllvdSBhbHJlYWR5IHN0dWRpZWQgYW5kIGFyZSBhd2FyZSBvZiBgaGZsaWdodHNgIHRhYmxlIGZyb20gRGF0YUNhbXAgY291cnNlcy4gVGhyZWUgbW9yZSB0YWJsZXMgYXJlIGFscmVhZHkgZGVmaW5lZCBmb3IgeW91ICh3aGVuIHlvdSBydW4gdGhlIGZpcnN0IGNodW5rKS4gSW5zdGVhZCBvZiB1c2luZyBsb29rdXAgdGFibGVzIGFzIHlvdSBkaWQgRGF0YUNhbXAsIGxldCdzIHVzZSBgam9pbmAgdG8gY29tYmluZSBhbGwgZGF0YS4gVXNlIGBhaXJsaW5lX2NvZGVzYCwgYGNhbmNlbGxhdGlvbl9jb2Rlc2AgYW5kIGBhaXJwb3J0X2NvZGVzYCB0YWJsZXMgKGFscmVhZHkgbG9hZGVkIGZvciB5b3UpIHRvIGZpbmQgb3V0IG1vc3QgZnJlcXVlbnQgYHdlYXRoZXJgIHJlbGF0ZWQgY2FuY2VsbGF0aW9ucyBmb3IgYWlybGluZSBhbmQgZGVzdGluYXRpb24uCgoiYWlybGluZSIgY29sdW1uIHNob3VsZCBoYXZlIGNhcnJpZXJzIGZ1bGwgbmFtZSwgImRlc3RpbmF0aW9uIiBjb2x1bW4gc2hvdWxkIGhhdmUgZnVsbCBuYW1lIG9mIGFpcnBvcnQgYW5kICJjYW5jZWxsYXRpb24iIGNvbHVtbiBzaG91bGQgaGF2ZSB0aGUgZXhwbGFuYXRpb24gb2YgY2FuY2VsbGF0aW9uLgoKRXhwZWN0ZWQgb3V0cHV0OgoKfCBhaXJsaW5lIHwgZGVzdGluYXRpb24gfCBjYW5jZWxsYXRpb24gfCAgY291bnQgfAp8LS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS18LS0tLS0tLS18CnwgICAuLiAgICB8ICAgLi4gICAgICAgIHwgICAgICAgLi4gICAgIHwgIC4uICAgIHwKCiMgU29sdXRpb24gNAoKYGBge3IgYW5zd2VyNH0KaGZsaWdodHMgJT4lIAogIGlubmVyX2pvaW4oYWlybGluZV9jb2RlcywgYnk9YygiVW5pcXVlQ2FycmllciI9Im5hbWUiKSkgJT4lICAgICAgICAgICAjIHRoZSBrZXlzIGhhdmUgZGlmZmVyZW50IG5hbWVzIAogIGlubmVyX2pvaW4oYWlycG9ydF9jb2RlcywgYnk9YygiRGVzdCI9ImZhYSIpKSAlPiUgICAgICAgICAgICAgICAgICAgICAjIHRoZSBrZXlzIGhhdmUgZGlmZmVyZW50IG5hbWVzCiAgaW5uZXJfam9pbihjYW5jZWxsYXRpb25fY29kZXMsIGJ5PWMoIkNhbmNlbGxhdGlvbkNvZGUiPSJuYW1lIikpICU+JSAgICMgdGhlIGtleXMgaGF2ZSBkaWZmZXJlbnQgbmFtZXMgCiAgIyB5b3UgY2FuIHVzZSBzdWZmaXggb3B0aW9uIGluIGpvaW5zIHRvIGtlZXAgdHJhY2sgb2Ygd2hpY2ggY29sdW1uIGNvbWVzIGZyb20gd2hpY2ggdGFibGUKICBzZWxlY3QoYWlybGluZT12YWx1ZS54LGRlc3RpbmF0aW9uPW5hbWUsY2FuY2VsbGF0aW9uPXZhbHVlLnkpICU+JSAgICAgIyBzZWxlY3RpbmcgYW5kIHJlbmFtaW5nIGNvbHVtbnMKICBmaWx0ZXIoY2FuY2VsbGF0aW9uPT0id2VhdGhlciIpICU+JSAKICBncm91cF9ieShhaXJsaW5lLGRlc3RpbmF0aW9uLGNhbmNlbGxhdGlvbikgJT4lICAjIHRvIGNvdW50IHBlciBhaXJsaW5lIGFuZCBkZXN0aW5hdGlvbiBwYWlycywgd2UgZ3JvdXAgdGhlbQogIGNvdW50KCkgJT4lIAogIGFycmFuZ2UoLW4pCmBgYAoK