1 Preparing Datasets

Datasets:

Dataset Aggregated travel times between every zone pair in the city
Time Period Q1 2018
City Delhi, Mumbai, Bangalore
Source Uber Movement
suppressPackageStartupMessages(library(tidyverse))
new_delhi_wards <- read.csv("Data/uber_delhi_ward_ids.csv", stringsAsFactors = FALSE)
inter_ward_times <- data.table::fread("Data/delhi_hod_times.csv", stringsAsFactors = F)

1.1 Preparing the distance components

Inter ward distance was calculated through QGIS using the the wards geojson file downloaded from the UBER Movement website for DELHI. Process was:

  • To first find the center of each polygon
  • To calculate a distance matrix from each polygon center to other for all ploygons
inter_ward_distance <- data.table::fread("Data/spatial/delhi_distance_matrix.csv", stringsAsFactors = F, data.table = FALSE)

1.2 Merging Distance and Time components

inter_ward_matrix <-
  dplyr::left_join(
    inter_ward_times,
    inter_ward_distance,
    by = c('sourceid' = 'InputID', 'dstid' = 'TargetID')
  )

1.3 Converting distance to kilometer

inter_ward_matrix$distance_km <- inter_ward_matrix$distance_metre/1000

2 Hourly Analysis of time taken and distance covered

2.1 Time per km ranges at every Hour of the day

The objective of this analysis is to focus on the congestion of vehicular activity on city routes. Since the current dataset from UBER gives us just the travel times, it is importatnt to normlaise it by the distance metric, thus focusing on time taken on covering every km of a route (assumption being that every km takes the equal amount of time, certainly not the case, but this should be good for an EDA) and treating it as a proxy of business of that route.

inter_ward_matrix$time_per_km <- inter_ward_matrix$mean_travel_time/inter_ward_matrix$distance_km

Let’s now look at the density plots for time per km at every hour of the day - This will help us see the range of times and check if the flow rate of city traffic is constant at every hour or varies across routes

Excluding the rides done in the same Movement zone, as the distance is not calculated for such cases.

Results:

  • There are high peaks from 0-6 hours as the congestion seems to be less at these points, so most rides are able to maintain a good flow rate, 75% of these rides cover a distance of a km in less than 150 seconds
  • The peaks turns a bit flat after 7 AM and the width increases, as the congestion increases, so is the variability with time.

2.2 Time taken by the majority

Let’s look at the 90th percentile of time taken per km at every hour

Observations:

Being rush office hours,

  • First peak is around 11-13, where TPK (Time per km) is close to 300s
  • Second peak is around 17-20 where the TPK goes almost till 350s

2.3 How far can you go in an hour

A prominent indicator of congestion in any city is the variation in average speed of vehicles over time. Distance travelled in an hour of time at various times of the day should be a good proxy to determine the flow rates of different routes or cities themselves. Having analysed Delhi’s traffic throughout the day and at diferent routes, lets compare it with other cities i.e Mumbai and Bangalore. For this analysis, we download the data from UBER Movement for these cities for a similar time period i.e. Q1 2018. Our objective here is to see how far we can travel in an hour at all hours (0 to 23), the results will help us compare the congestion rates in Delhi with these cities, let’s prepare the data and look at the results.

ggplot(hourly_spider, aes(x = city,y = distance_per_hour)) +
  geom_bar(alpha=.6, fill="#FF6666",stat = 'identity') +
  ylab('Distance per hour (In Km)') + xlab('City') +
  facet_wrap(~ hod, nrow=8) + theme_minimal()

Observations:

  • Bangalore looks the most congested of cities at all hours when compared with Delhi and Mumbai
  • Delhi is the least congested at night and Peak AM hours i.e from 10 PM till 8 AM
  • Mumbai is the least congested at peak hours i.e from 9 AM till 8 PM

Out of the three cities:

  • Maximum you can travel in an hour is 32.8 kms at 3 AM in Delhi
  • Minimum you can travel in an hour is 12.5 kms at 6 PM in Bangalore

Yes, Bangalore traffic looks way poor than Delhi or Mumbai.

Till now we were only working with hod(Hour of the day), now lets take the route into consideration as well

3 Busiest routes throughout the day (Top 10):

x <- inter_ward_matrix %>% filter(!is.na(time_per_km))%>% group_by(sourceid, dstid) %>%
  summarise(mean_tpk = mean(time_per_km))
x <- dplyr::left_join(x, inter_ward_distance, by = c('sourceid' = 'InputID', 'dstid' = 'TargetID'))
x <- x[order(-x$mean_tpk), ]
x[1:10,c(1,2,3,5)]

Shorter routes will tend to have a greater TPK, as for larger routes this metric gets time to decrease because of more occurrences of light congestion segments as compared to shorter routes.

Let’s look at the same table again but now between routes which are atleast greater than a km.

x <- x[x$distance_metre >= 1000, ]
x <- x[order(-x$mean_tpk), ]
x[1:10,c(1,2,3,5)]

Observations:

These are actually pretty congested areas -

  • Though shorted distances, the average time is ~15 mins
  • The time taken between these wards was verified on Google Maps and the results were pretty close
  • These areas lies in region with high population and high commercial activities, not so good roads and a heavy traffic at pretty much any time of the day

The satellite view - one of the busiest route (181 - 178) looks like this busy_routes

4 Congested Airport rides

The UBER Movement web UI is amazing, its good from a single user perspective, but if a city planner wants to have compare mutiple routes at once, then it can be a bit difficult. You are always tied to a source and a destination for certain analyses, and though the avergae time for every ward from a source can be identified by a map view, the same thing cannot be done for a destination.

Let’s fix our destination at the Delhi Airport Ward (There is no dedicated ward for this, so taking the closest one - Ward No 5 as a proxy) and look at average times (TPK) from every other ward

dst5 <- inter_ward_matrix[inter_ward_matrix$dstid==5,]
dst5 %>% group_by(sourceid) %>% summarise(mean_tpt = mean(time_per_km)) %>% top_n(5, mean_tpt)
# A tibble: 5 x 2
  sourceid mean_tpt
     <int>    <dbl>
1      102     320.
2      201     410.
3      202     351.
4      285     273.
5      288     272.

The results are same as above, short routes having a higher TPK, but the last two sources are interesting.

  • Both of them are over 10 Km’s.
  • Source 288 lies in between Source 255 and Airport
  • The route starts from the eastern parts of Delhi and ends at the Southern part (People coming to airport from these routes shoule definitely be wary of this fact)

5 Longest Journeys (in terms of time taken to complete) in a city

library(knitr)
inter_ward_matrix[is.na(inter_ward_matrix)] <- ''
inter_ward_matrix %>% top_n(10, mean_travel_time) %>% select(sourceid, dstid, hod, mean_travel_time,distance_km,time_per_km)  %>% arrange(desc(mean_travel_time)) %>% kable()


| sourceid| dstid| hod| mean_travel_time|distance_km      |time_per_km      |
|--------:|-----:|---:|----------------:|:----------------|:----------------|
|        5|     5|  21|         10107.75|                 |                 |
|      193|   193|  21|          9314.33|                 |                 |
|        3|     3|  21|          9141.33|                 |                 |
|      223|   223|  21|          9111.50|                 |                 |
|       34|    32|  18|          8968.17|32.7232962606117 |274.060715906386 |
|      119|    32|  18|          8690.43|32.9882471123653 |263.440187361228 |
|       89|   173|  18|          8503.17|30.4132457825518 |279.58771848279  |
|       40|    32|  18|          8179.67|30.722681697032  |266.242057925243 |
|      108|   163|  18|          8137.57|26.9138651818746 |302.356051240099 |
|      191|   284|  18|          8094.67|29.0002459934917 |279.124184043702 |

These are the routes with the higest travel times in Delhi. Some observations:

  • As observed in the earlier analysis as well, 21 and 18 are the hours which contribute to the highest times, congestion is at its peak during these times.
  • We can eliminate distance as a factor specifically in routes (Top 4 in this case) which are in the same ward. Ward 5, 3 and 223 are all closest to the airport and therefore have the highest journey times at these hours, definitely something for the traffic authorities to look at
  • Route No 2 (193) is all contained within Shahdara, which is indeed considered to be one of the most congested areas in Delhi, ride times within the region can go upto 1 and a half hours
  • Ward 32 (METRO MALL, Pocket 1, Sector 14 Dwarka, Dwarka, New Delhi) - There are 3 routes in the top 10 with this as the destination. But one thing in common among these routes is the ride distance which is more than 30 KM’s but still there TPK is close to 4.5 minutes (15 Km/hour), which is on the slower side

6 Time deviations on the same route

We know that there are peak times in a day when the travel time increases and usually it increases by around 15-20 mins and thats what the data says as well.

route_deviations_df <- readRDS("Data/route_devialtions.rds")
route_deviations_df <- route_deviations_df[!is.na(route_deviations_df$route_deviation), ]
summary(route_deviations_df$route_deviation)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
   1.633  385.871  579.841  592.093  773.665 5305.606 

The mean time deviation for more than 80% rides is close to 13 mins (820 s)

But the max deviation for a route is more than 5000 s (almost an hour and 20 mins). This is where we want to focus our analysis on, so let;s find out those 0.5 percentile of routes (if any), where the deviation is more than 30 mins (1800 s)



| route_start| route_end| route_deviation|
|-----------:|---------:|---------------:|
|         133|       133|        5305.606|
|         228|       228|        5080.668|
|         166|       166|        4975.585|
|         264|       264|        4972.658|
|         219|       219|        4953.778|
|         226|       226|        4899.359|
|         121|       121|        4803.214|
|           5|         5|        4732.191|
|         161|       161|        4726.952|
|          12|        12|        4603.527|

So, there are a total of 111 such routes. Let’s see if we could find some patterns here:

  • Looking at the dataset for the route with most deviation(133), we found that there are only 2 rows in the base dataset, which means that the data is available for only a coupe of hours. This won’t be a fair comparison with other routes where the data is avialable for all 24 hours. So ;et’s remove them from this dataset and look at these observartions again
number_instances <-
  inter_ward_matrix %>% group_by(sourceid, dstid) %>% summarise(total_hod = length(hod))
  
  route_deviations_df <-
  dplyr::left_join(
  route_deviations_df,
  number_instances,
  by = c('route_start' = 'sourceid', 'route_end' = 'dstid')
  )
  
  route_deviations_df %>% filter(route_deviation > 1800 &
  total_hod > 6) %>% arrange(desc(route_deviation)) %>% kable()


| route_start| route_end| route_deviation| total_hod|
|-----------:|---------:|---------------:|---------:|
|         119|       140|        1892.420|         9|
|          40|        32|        1862.699|         8|
|         192|       139|        1841.018|         7|
|          41|        32|        1803.767|        11|

We now have 4 routes with atleast 6 observations. Some observations:

  • These routes are affected the most due to congestion as the same ride will take almost the double amount of time to complete in peak hours
  • All of them have a deviation of close to 30 mins
ggplot(data = inter_ward_matrix[inter_ward_matrix$sourceid== 119 & inter_ward_matrix$dstid == 140,], aes(hod,mean_travel_time)) +  geom_point(shape = 16, size = 5) + xlab('Hour of the day') + ylab('Mean travel time (in seconds)') + theme_minimal()

  • These are longer routes (~25-30 Km’s)
  • If you’ll observe the scatter plot, these routes suffer the most between 3 PM till 9 PM
  • These routes can be termed as end to end routes, as they start and end mostly at the points which lie on the perimeter of Delhi. Most of these routes start from the Eastern part and end at the Western parts, moving through Central Delhi.
route_deviations

route_deviations

LS0tCnRpdGxlOiAiVHJhZmZpYyBwYXR0ZXJucyBmcm9tIFVCRVIgTW92ZW1lbnQgRGF0YXNldCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBzbW9vdGhfc2Nyb2xsOiBubwotLS0KCiMgUHJlcGFyaW5nIERhdGFzZXRzCgpEYXRhc2V0czoKCnwgICAgIERhdGFzZXQgICAgICAgIHwgICAgICAgIEFnZ3JlZ2F0ZWQgdHJhdmVsIHRpbWVzIGJldHdlZW4gZXZlcnkgem9uZSBwYWlyIGluIHRoZSBjaXR5ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgVGltZSBQZXJpb2QgfCBRMSAyMDE4ICB8CnwgQ2l0eSAgICAgICAgfCBEZWxoaSwgTXVtYmFpLCBCYW5nYWxvcmUgIHwKfCBTb3VyY2UgICAgICB8IFtVYmVyIE1vdmVtZW50XShodHRwczovL21vdmVtZW50LnViZXIuY29tL2V4cGxvcmUvKSAgfAoKYGBge3IgcmVhZGluZyBiYXNlIGRhdGFzZXRzfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSh0aWR5dmVyc2UpKQpuZXdfZGVsaGlfd2FyZHMgPC0gcmVhZC5jc3YoIkRhdGEvdWJlcl9kZWxoaV93YXJkX2lkcy5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmludGVyX3dhcmRfdGltZXMgPC0gZGF0YS50YWJsZTo6ZnJlYWQoIkRhdGEvZGVsaGlfaG9kX3RpbWVzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpgYGAKCiMjIFByZXBhcmluZyB0aGUgZGlzdGFuY2UgY29tcG9uZW50cwoKSW50ZXIgd2FyZCBkaXN0YW5jZSB3YXMgY2FsY3VsYXRlZCB0aHJvdWdoIFFHSVMgdXNpbmcgdGhlIHRoZSB3YXJkcyBnZW9qc29uIGZpbGUgZG93bmxvYWRlZCBmcm9tIHRoZSBVQkVSIE1vdmVtZW50IHdlYnNpdGUgZm9yIERFTEhJLiBQcm9jZXNzIHdhczoKCi0gVG8gZmlyc3QgZmluZCB0aGUgY2VudGVyIG9mIGVhY2ggcG9seWdvbgotIFRvIGNhbGN1bGF0ZSBhIGRpc3RhbmNlIG1hdHJpeCBmcm9tIGVhY2ggcG9seWdvbiBjZW50ZXIgdG8gb3RoZXIgZm9yIGFsbCBwbG95Z29ucwoKYGBge3IgcmVhZGluZyBkaXN0YW5jZSBtYXRyaXh9CmludGVyX3dhcmRfZGlzdGFuY2UgPC0gZGF0YS50YWJsZTo6ZnJlYWQoIkRhdGEvc3BhdGlhbC9kZWxoaV9kaXN0YW5jZV9tYXRyaXguY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsIGRhdGEudGFibGUgPSBGQUxTRSkKYGBgCgojIyBNZXJnaW5nIERpc3RhbmNlIGFuZCBUaW1lIGNvbXBvbmVudHMKCmBgYHtyIE1lcmluZyBkaXN0YW5jZSBhbmQgdGltZSBjb21wb25lbnRzfQppbnRlcl93YXJkX21hdHJpeCA8LQogIGRwbHlyOjpsZWZ0X2pvaW4oCiAgICBpbnRlcl93YXJkX3RpbWVzLAogICAgaW50ZXJfd2FyZF9kaXN0YW5jZSwKICAgIGJ5ID0gYygnc291cmNlaWQnID0gJ0lucHV0SUQnLCAnZHN0aWQnID0gJ1RhcmdldElEJykKICApCmBgYAoKIyMgQ29udmVydGluZyBkaXN0YW5jZSB0byBraWxvbWV0ZXIKYGBge3IgQ29udmVydGluZyBkaXN0YW5jZSB0byBrbX0KaW50ZXJfd2FyZF9tYXRyaXgkZGlzdGFuY2Vfa20gPC0gaW50ZXJfd2FyZF9tYXRyaXgkZGlzdGFuY2VfbWV0cmUvMTAwMApgYGAKCi0tLS0tLQoKIyBIb3VybHkgQW5hbHlzaXMgb2YgdGltZSB0YWtlbiBhbmQgZGlzdGFuY2UgY292ZXJlZAoKIyMgVGltZSBwZXIga20gcmFuZ2VzIGF0IGV2ZXJ5IEhvdXIgb2YgdGhlIGRheQoKVGhlIG9iamVjdGl2ZSBvZiB0aGlzIGFuYWx5c2lzIGlzIHRvIGZvY3VzIG9uIHRoZSBjb25nZXN0aW9uIG9mIHZlaGljdWxhciBhY3Rpdml0eSBvbgpjaXR5IHJvdXRlcy4gU2luY2UgdGhlIGN1cnJlbnQgZGF0YXNldCBmcm9tIFVCRVIgZ2l2ZXMgdXMganVzdCB0aGUgdHJhdmVsIHRpbWVzLCBpdCBpcyBpbXBvcnRhdG50IHRvIG5vcm1sYWlzZSBpdCBieSB0aGUgZGlzdGFuY2UgbWV0cmljLCB0aHVzIGZvY3VzaW5nIG9uIHRpbWUgdGFrZW4gb24gY292ZXJpbmcgZXZlcnkga20gb2YgYSByb3V0ZSAoYXNzdW1wdGlvbiBiZWluZyB0aGF0IGV2ZXJ5IGttIHRha2VzIHRoZSBlcXVhbCBhbW91bnQgb2YgdGltZSwgY2VydGFpbmx5IG5vdCB0aGUgY2FzZSwgYnV0IHRoaXMgc2hvdWxkIGJlIGdvb2QgZm9yIGFuIEVEQSkgYW5kIHRyZWF0aW5nIGl0IGFzIGEgcHJveHkgb2YgYnVzaW5lc3Mgb2YgdGhhdCByb3V0ZS4gCgpgYGB7ciBUaW1lIHBlciBrbX0KaW50ZXJfd2FyZF9tYXRyaXgkdGltZV9wZXJfa20gPC0gaW50ZXJfd2FyZF9tYXRyaXgkbWVhbl90cmF2ZWxfdGltZS9pbnRlcl93YXJkX21hdHJpeCRkaXN0YW5jZV9rbQpgYGAKCkxldCdzIG5vdyBsb29rIGF0IHRoZSBkZW5zaXR5IHBsb3RzIGZvciB0aW1lIHBlciBrbSBhdCBldmVyeSBob3VyIG9mIHRoZSBkYXkgLSBUaGlzIHdpbGwgaGVscCB1cyBzZWUgdGhlIHJhbmdlIG9mIHRpbWVzIGFuZCBjaGVjayBpZiB0aGUgZmxvdyByYXRlIG9mIGNpdHkgdHJhZmZpYyBpcyBjb25zdGFudCBhdCBldmVyeSBob3VyIG9yIHZhcmllcyBhY3Jvc3Mgcm91dGVzCgpFeGNsdWRpbmcgdGhlIHJpZGVzIGRvbmUgaW4gdGhlIHNhbWUgTW92ZW1lbnQgem9uZSwgYXMgdGhlIGRpc3RhbmNlIGlzIG5vdCBjYWxjdWxhdGVkIGZvciBzdWNoIGNhc2VzLiAKYGBge3IgZmFjZXRfaG9kLCBlY2hvPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCgpnZ3Bsb3QoaW50ZXJfd2FyZF9tYXRyaXhbIWlzLm5hKGludGVyX3dhcmRfbWF0cml4JERpc3RhbmNlKSxdLCBhZXMoeCA9IHRpbWVfcGVyX2ttKSkgKwogIGdlb21fZGVuc2l0eShhbHBoYT0uMiwgZmlsbD0iI0ZGNjY2NiIpICsKICBmYWNldF93cmFwKH4gaG9kLCBucm93PTYpICsgeGxhYigiVGltZSBwZXIga20gKHNlY29uZHMpIikgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgpSZXN1bHRzOgoKLSBUaGVyZSBhcmUgaGlnaCBwZWFrcyBmcm9tIDAtNiBob3VycyBhcyB0aGUgY29uZ2VzdGlvbiBzZWVtcyB0byBiZSBsZXNzIGF0IHRoZXNlIHBvaW50cywgc28gbW9zdCByaWRlcyBhcmUgYWJsZSB0byBtYWludGFpbiBhIGdvb2QgZmxvdyByYXRlLCA3NSUgb2YgdGhlc2UgcmlkZXMgY292ZXIgYSBkaXN0YW5jZSBvZiBhIGttIGluIGxlc3MgdGhhbiAqMTUwKiBzZWNvbmRzCi0gVGhlIHBlYWtzIHR1cm5zIGEgYml0IGZsYXQgYWZ0ZXIgNyBBTSBhbmQgdGhlIHdpZHRoIGluY3JlYXNlcywgYXMgdGhlIGNvbmdlc3Rpb24gaW5jcmVhc2VzLCBzbyBpcyB0aGUgdmFyaWFiaWxpdHkgd2l0aCB0aW1lLgoKIyMgVGltZSB0YWtlbiBieSB0aGUgbWFqb3JpdHkKCkxldCdzIGxvb2sgYXQgdGhlIDkwdGggcGVyY2VudGlsZSBvZiAqdGltZSB0YWtlbiBwZXIga20qIGF0IGV2ZXJ5IGhvdXIKCmBgYHtyIHF1YW50aWxlX2Rpc3RyaWJ1dGlvbiwgaW5jbHVkZT1GQUxTRX0KcXVhbnRpbGVfdmVjIDwtIGMoKQpmb3IoaSBpbiAxOjI0KXsKIHF1YW50aWxlX3ZlYyA8LSBjKHF1YW50aWxlX3ZlYyxxdWFudGlsZShpbnRlcl93YXJkX21hdHJpeCR0aW1lX3Blcl9rbVtpbnRlcl93YXJkX21hdHJpeCRob2Q9PShpLTEpICYgIWlzLm5hKGludGVyX3dhcmRfbWF0cml4JERpc3RhbmNlKV0sIDAuOSkpCn0KcXVhbnRpbGVfZGYgPC0gZGF0YS5mcmFtZSgnaG9kJyA9IDA6MjMsIHF1YW50aWxlX3ZlYykKYGBgCgpgYGB7ciBxdWFudGlsZV9kaXN0cmlidXRpb25fcGxvdCwgZWNobz1GQUxTRX0KZ2dwbG90KGRhdGEgPSBxdWFudGlsZV9kZiwgYWVzKHggPSBob2QseSA9IHF1YW50aWxlX3ZlYykpICsgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScpICsKICB5bGFiKCJUaW1lIHBlciBrbSAoOTV0aCBwZXJjZW50aWxlKSIpICsgeGxhYignSG91ciBvZiB0aGUgZGF5JykgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgpPYnNlcnZhdGlvbnM6CgpCZWluZyBydXNoIG9mZmljZSBob3VycywgCgotIEZpcnN0IHBlYWsgaXMgYXJvdW5kIDExLTEzLCB3aGVyZSBUUEsgKFRpbWUgcGVyIGttKSBpcyBjbG9zZSB0byAzMDBzCi0gU2Vjb25kIHBlYWsgaXMgYXJvdW5kIDE3LTIwIHdoZXJlIHRoZSBUUEsgZ29lcyBhbG1vc3QgdGlsbCAzNTBzCgojIyBIb3cgZmFyIGNhbiB5b3UgZ28gaW4gYW4gaG91cgoKQSBwcm9taW5lbnQgaW5kaWNhdG9yIG9mIGNvbmdlc3Rpb24gaW4gYW55IGNpdHkgaXMgdGhlIHZhcmlhdGlvbiBpbiBhdmVyYWdlIHNwZWVkIG9mIHZlaGljbGVzIG92ZXIgdGltZS4gRGlzdGFuY2UgdHJhdmVsbGVkIGluIGFuIGhvdXIgb2YgdGltZSBhdCB2YXJpb3VzIHRpbWVzIG9mIHRoZSBkYXkgc2hvdWxkIGJlIGEgZ29vZCBwcm94eSB0byBkZXRlcm1pbmUgdGhlIGZsb3cgcmF0ZXMgb2YgZGlmZmVyZW50IHJvdXRlcyBvciBjaXRpZXMgdGhlbXNlbHZlcy4gSGF2aW5nIGFuYWx5c2VkIERlbGhpJ3MgdHJhZmZpYyB0aHJvdWdob3V0IHRoZSBkYXkgYW5kIGF0IGRpZmVyZW50IHJvdXRlcywgbGV0cyBjb21wYXJlIGl0IHdpdGggb3RoZXIgY2l0aWVzIGkuZSBNdW1iYWkgYW5kIEJhbmdhbG9yZS4gRm9yIHRoaXMgYW5hbHlzaXMsIHdlIGRvd25sb2FkIHRoZSBkYXRhIGZyb20gW1VCRVIgTW92ZW1lbnRdKGh0dHBzOi8vbW92ZW1lbnQudWJlci5jb20vZXhwbG9yZSkgZm9yIHRoZXNlIGNpdGllcyBmb3IgYSBzaW1pbGFyIHRpbWUgcGVyaW9kIGkuZS4gX19RMSAyMDE4X18uIE91ciBvYmplY3RpdmUgaGVyZSBpcyB0byBzZWUgaG93IGZhciB3ZSBjYW4gdHJhdmVsIGluIGFuIGhvdXIgYXQgYWxsIGhvdXJzICgwIHRvIDIzKSwgdGhlIHJlc3VsdHMgd2lsbCBoZWxwIHVzIGNvbXBhcmUgdGhlIGNvbmdlc3Rpb24gcmF0ZXMgaW4gRGVsaGkgd2l0aCB0aGVzZSBjaXRpZXMsIGxldCdzIHByZXBhcmUgdGhlIGRhdGEgYW5kIGxvb2sgYXQgdGhlIHJlc3VsdHMuIAoKYGBge3IgSG91cmx5IHRpbWUgZGlzdHJpYnV0aW9ucywgaW5jbHVkZT1GQUxTRX0KY2FsY3VsYXRlX2hvdXJseSA8LSBmdW5jdGlvbihjaXR5X25hbWUpewogIHRpbWVfZGF0YSA8LSAgZGF0YS50YWJsZTo6ZnJlYWQoZ2x1ZTo6Z2x1ZSgiRGF0YS97Y2l0eV9uYW1lfV9ob2RfdGltZXMuY3N2IikpCiAgZGlzdGFuY2VfZGF0YSA8LSBkYXRhLnRhYmxlOjpmcmVhZChnbHVlOjpnbHVlKCJEYXRhL3NwYXRpYWwve2NpdHlfbmFtZX1fZGlzdGFuY2VfbWF0cml4LmNzdiIpKQogIGRpc3RhbmNlX2RhdGEkZGlzdGFuY2VfbWV0cmUgPC0gZGlzdGFuY2VfZGF0YSREaXN0YW5jZSAqIDExMTEzOQogIGNpdHlfbWF0cml4IDwtIGRwbHlyOjpsZWZ0X2pvaW4oCiAgICB0aW1lX2RhdGEsCiAgICBkaXN0YW5jZV9kYXRhLAogICAgYnkgPSBjKCdzb3VyY2VpZCcgPSAnSW5wdXRJRCcsICdkc3RpZCcgPSAnVGFyZ2V0SUQnKQogICkKICBjaXR5X21hdHJpeCRkaXN0YW5jZV9rbSA8LSBjaXR5X21hdHJpeCRkaXN0YW5jZV9tZXRyZS8xMDAwCiAgY2l0eV9tYXRyaXgkdGltZV9wZXJfa20gPC0gY2l0eV9tYXRyaXgkbWVhbl90cmF2ZWxfdGltZS9jaXR5X21hdHJpeCRkaXN0YW5jZV9rbQogIGNpdHlfbWF0cml4JGttX3Blcl9ob3VyIDwtIDM2MDAgLyBjaXR5X21hdHJpeCR0aW1lX3Blcl9rbSAgCiAgaG91cmx5X2Rpc3RhbmNlIDwtIGNpdHlfbWF0cml4ICU+JSBncm91cF9ieShob2QpICU+JSBzdW1tYXJpc2UoZGlzdGFuY2VfcGVyX2hvdXIgPSBtZWFuKGttX3Blcl9ob3VyLG5hLnJtID0gVFJVRSkpCiAgaG91cmx5X2Rpc3RhbmNlJGNpdHkgPC0gY2l0eV9uYW1lCiAgcHJpbnQoZ2x1ZTo6Z2x1ZSgiIHtjaXR5X25hbWV9IGRvbmUgLi4gICIpKQogIHJldHVybihob3VybHlfZGlzdGFuY2UpCn0KCmNpdHlfbGlzdCA8LSBjKCdkZWxoaScsJ211bWJhaScsJ2JhbmdhbG9yZScpCmhvdXJseV9zcGlkZXIgPC0gbGFwcGx5KGNpdHlfbGlzdCwgY2FsY3VsYXRlX2hvdXJseSkKCiMgQ29udmVydGluZyB0byBhIGRhdGEgZnJhbWUgZm9yIGEgcmFkYXIgY2hhcnQKaG91cmx5X3NwaWRlciA8LSBkcGx5cjo6YmluZF9yb3dzKGhvdXJseV9zcGlkZXIpCmBgYAoKYGBge3IgcG90dGluZyBob3VybHkgc3BpZGVyfQpnZ3Bsb3QoaG91cmx5X3NwaWRlciwgYWVzKHggPSBjaXR5LHkgPSBkaXN0YW5jZV9wZXJfaG91cikpICsKICBnZW9tX2JhcihhbHBoYT0uNiwgZmlsbD0iI0ZGNjY2NiIsc3RhdCA9ICdpZGVudGl0eScpICsKICB5bGFiKCdEaXN0YW5jZSBwZXIgaG91ciAoSW4gS20pJykgKyB4bGFiKCdDaXR5JykgKwogIGZhY2V0X3dyYXAofiBob2QsIG5yb3c9OCkgKyB0aGVtZV9taW5pbWFsKCkKCmBgYAoKT2JzZXJ2YXRpb25zOiAKCi0gX19CYW5nYWxvcmVfXyBsb29rcyB0aGUgbW9zdCBjb25nZXN0ZWQgb2YgY2l0aWVzIGF0IGFsbCBob3VycyB3aGVuIGNvbXBhcmVkIHdpdGggRGVsaGkgYW5kIE11bWJhaQotIF9fRGVsaGlfXyBpcyB0aGUgbGVhc3QgY29uZ2VzdGVkIGF0IG5pZ2h0IGFuZCBQZWFrIEFNIGhvdXJzIGkuZSBmcm9tIDEwIFBNIHRpbGwgOCBBTQotIF9fTXVtYmFpX18gaXMgdGhlIGxlYXN0IGNvbmdlc3RlZCBhdCBwZWFrIGhvdXJzIGkuZSBmcm9tIDkgQU0gdGlsbCA4IFBNCgpPdXQgb2YgdGhlIHRocmVlIGNpdGllczogCgotIE1heGltdW0geW91IGNhbiB0cmF2ZWwgaW4gYW4gaG91ciBpcyBfXzMyLjhfXyBrbXMgYXQgX18zIEFNX18gaW4gRGVsaGkKLSBNaW5pbXVtIHlvdSBjYW4gdHJhdmVsIGluIGFuIGhvdXIgaXMgX18xMi41X18ga21zIGF0IF9fNiBQTV9fIGluIEJhbmdhbG9yZQoKPiBZZXMsIEJhbmdhbG9yZSB0cmFmZmljIGxvb2tzIHdheSBwb29yIHRoYW4gRGVsaGkgb3IgTXVtYmFpLgoKClRpbGwgbm93IHdlIHdlcmUgb25seSB3b3JraW5nIHdpdGggaG9kKEhvdXIgb2YgdGhlIGRheSksIG5vdyBsZXRzIHRha2UgdGhlIHJvdXRlIGludG8gY29uc2lkZXJhdGlvbiBhcyB3ZWxsCgojIEJ1c2llc3Qgcm91dGVzIHRocm91Z2hvdXQgdGhlIGRheSAoVG9wIDEwKTogCgpgYGB7ciBUb3AgdHBrfQp4IDwtIGludGVyX3dhcmRfbWF0cml4ICU+JSBmaWx0ZXIoIWlzLm5hKHRpbWVfcGVyX2ttKSklPiUgZ3JvdXBfYnkoc291cmNlaWQsIGRzdGlkKSAlPiUKICBzdW1tYXJpc2UobWVhbl90cGsgPSBtZWFuKHRpbWVfcGVyX2ttKSkKeCA8LSBkcGx5cjo6bGVmdF9qb2luKHgsIGludGVyX3dhcmRfZGlzdGFuY2UsIGJ5ID0gYygnc291cmNlaWQnID0gJ0lucHV0SUQnLCAnZHN0aWQnID0gJ1RhcmdldElEJykpCnggPC0geFtvcmRlcigteCRtZWFuX3RwayksIF0KeFsxOjEwLGMoMSwyLDMsNSldCmBgYAoKPiBTaG9ydGVyIHJvdXRlcyB3aWxsIHRlbmQgdG8gaGF2ZSBhIGdyZWF0ZXIgVFBLLCBhcyBmb3IgbGFyZ2VyIHJvdXRlcyB0aGlzIG1ldHJpYyBnZXRzIHRpbWUgdG8gZGVjcmVhc2UgYmVjYXVzZSBvZiBtb3JlIG9jY3VycmVuY2VzIG9mIGxpZ2h0IGNvbmdlc3Rpb24gc2VnbWVudHMgYXMgY29tcGFyZWQgdG8gc2hvcnRlciByb3V0ZXMuIAoKTGV0J3MgbG9vayBhdCB0aGUgc2FtZSB0YWJsZSBhZ2FpbiBidXQgbm93IGJldHdlZW4gcm91dGVzIHdoaWNoIGFyZSBhdGxlYXN0IGdyZWF0ZXIgdGhhbiBhIGttLiAKYGBge3IgdG9wIHRwayB3aXRoIGxhcmdlciByb3V0ZXN9CnggPC0geFt4JGRpc3RhbmNlX21ldHJlID49IDEwMDAsIF0KeCA8LSB4W29yZGVyKC14JG1lYW5fdHBrKSwgXQp4WzE6MTAsYygxLDIsMyw1KV0KYGBgCgpPYnNlcnZhdGlvbnM6IAoKVGhlc2UgYXJlIGFjdHVhbGx5IHByZXR0eSBjb25nZXN0ZWQgYXJlYXMgLSAKCi0gVGhvdWdoIHNob3J0ZWQgZGlzdGFuY2VzLCB0aGUgYXZlcmFnZSB0aW1lIGlzIH4xNSBtaW5zCi0gVGhlIHRpbWUgdGFrZW4gYmV0d2VlbiB0aGVzZSB3YXJkcyB3YXMgdmVyaWZpZWQgb24gR29vZ2xlIE1hcHMgYW5kIHRoZSByZXN1bHRzIHdlcmUgcHJldHR5IGNsb3NlCi0gVGhlc2UgYXJlYXMgbGllcyBpbiByZWdpb24gd2l0aCBoaWdoIHBvcHVsYXRpb24gYW5kIGhpZ2ggY29tbWVyY2lhbCBhY3Rpdml0aWVzLCBub3Qgc28gZ29vZCByb2FkcyBhbmQgYSBoZWF2eSB0cmFmZmljIGF0IHByZXR0eSBtdWNoIGFueSB0aW1lIG9mIHRoZSBkYXkKClRoZSBzYXRlbGxpdGUgdmlldyAtIG9uZSBvZiB0aGUgYnVzaWVzdCByb3V0ZSAoMTgxIC0gMTc4KSBsb29rcyBsaWtlIHRoaXMKIVtidXN5X3JvdXRlc10oLi4vaW1hZ2VzL2J1c3lfcm91dGVzX2dvb2dsZS5wbmcpCgoKIyBDb25nZXN0ZWQgQWlycG9ydCByaWRlcwoKVGhlIFVCRVIgTW92ZW1lbnQgd2ViIFVJIGlzIGFtYXppbmcsIGl0cyBnb29kIGZyb20gYSBzaW5nbGUgdXNlciBwZXJzcGVjdGl2ZSwgYnV0IGlmIGEgY2l0eSBwbGFubmVyIHdhbnRzIHRvIGhhdmUgY29tcGFyZSBtdXRpcGxlIHJvdXRlcyBhdCBvbmNlLCB0aGVuIGl0IGNhbiBiZSBhIGJpdCBkaWZmaWN1bHQuIFlvdSBhcmUgYWx3YXlzIHRpZWQgdG8gYSBzb3VyY2UgYW5kIGEgZGVzdGluYXRpb24gZm9yIGNlcnRhaW4gYW5hbHlzZXMsIGFuZCB0aG91Z2ggdGhlIGF2ZXJnYWUgdGltZSBmb3IgZXZlcnkgd2FyZCBmcm9tIGEgc291cmNlIGNhbiBiZSBpZGVudGlmaWVkIGJ5IGEgbWFwIHZpZXcsIHRoZSBzYW1lIHRoaW5nIGNhbm5vdCBiZSBkb25lIGZvciBhIGRlc3RpbmF0aW9uLiAKCkxldCdzIGZpeCBvdXIgZGVzdGluYXRpb24gYXQgdGhlIERlbGhpIEFpcnBvcnQgV2FyZCAoVGhlcmUgaXMgbm8gZGVkaWNhdGVkIHdhcmQgZm9yIHRoaXMsIHNvIHRha2luZyB0aGUgY2xvc2VzdCBvbmUgLSBXYXJkIE5vIDUgYXMgYSBwcm94eSkgYW5kIGxvb2sgYXQgYXZlcmFnZSB0aW1lcyAoVFBLKSBmcm9tIGV2ZXJ5IG90aGVyIHdhcmQKCmBgYHtyIEFpcnBvcnQgcmlkZXN9CmRzdDUgPC0gaW50ZXJfd2FyZF9tYXRyaXhbaW50ZXJfd2FyZF9tYXRyaXgkZHN0aWQ9PTUsXQpkc3Q1ICU+JSBncm91cF9ieShzb3VyY2VpZCkgJT4lIHN1bW1hcmlzZShtZWFuX3RwdCA9IG1lYW4odGltZV9wZXJfa20pKSAlPiUgdG9wX24oNSwgbWVhbl90cHQpCmBgYAoKVGhlIHJlc3VsdHMgYXJlIHNhbWUgYXMgYWJvdmUsIHNob3J0IHJvdXRlcyBoYXZpbmcgYSBoaWdoZXIgVFBLLCBidXQgdGhlIGxhc3QgdHdvIHNvdXJjZXMgYXJlIGludGVyZXN0aW5nLiAKCi0gQm90aCBvZiB0aGVtIGFyZSBvdmVyIDEwIEttJ3MuIAotIFNvdXJjZSAyODggbGllcyBpbiBiZXR3ZWVuIFNvdXJjZSAyNTUgYW5kIEFpcnBvcnQKLSBUaGUgcm91dGUgc3RhcnRzIGZyb20gdGhlIGVhc3Rlcm4gcGFydHMgb2YgRGVsaGkgYW5kIGVuZHMgYXQgdGhlIFNvdXRoZXJuIHBhcnQgKFBlb3BsZSBjb21pbmcgdG8gYWlycG9ydCBmcm9tIHRoZXNlIHJvdXRlcyBzaG91bGUgZGVmaW5pdGVseSBiZSB3YXJ5IG9mIHRoaXMgZmFjdCkKCiMgTG9uZ2VzdCBKb3VybmV5cyAoaW4gdGVybXMgb2YgdGltZSB0YWtlbiB0byBjb21wbGV0ZSkgaW4gYSBjaXR5CgpgYGB7ciBMb25nZXN0IGpvdXJuZXlzfQpsaWJyYXJ5KGtuaXRyKQppbnRlcl93YXJkX21hdHJpeFtpcy5uYShpbnRlcl93YXJkX21hdHJpeCldIDwtICcnCmludGVyX3dhcmRfbWF0cml4ICU+JSB0b3BfbigxMCwgbWVhbl90cmF2ZWxfdGltZSkgJT4lIHNlbGVjdChzb3VyY2VpZCwgZHN0aWQsIGhvZCwgbWVhbl90cmF2ZWxfdGltZSxkaXN0YW5jZV9rbSx0aW1lX3Blcl9rbSkgICU+JSBhcnJhbmdlKGRlc2MobWVhbl90cmF2ZWxfdGltZSkpICU+JSBrYWJsZSgpCmBgYAoKClRoZXNlIGFyZSB0aGUgcm91dGVzIHdpdGggdGhlIGhpZ2VzdCB0cmF2ZWwgdGltZXMgaW4gRGVsaGkuIFNvbWUgb2JzZXJ2YXRpb25zOgoKLSBBcyBvYnNlcnZlZCBpbiB0aGUgZWFybGllciBhbmFseXNpcyBhcyB3ZWxsLCBfMjFfIGFuZCBfMThfIGFyZSB0aGUgaG91cnMgd2hpY2ggY29udHJpYnV0ZSB0byB0aGUgaGlnaGVzdCB0aW1lcywgY29uZ2VzdGlvbiBpcyBhdCBpdHMgcGVhayBkdXJpbmcgdGhlc2UgdGltZXMuIAotIFdlIGNhbiBlbGltaW5hdGUgZGlzdGFuY2UgYXMgYSBmYWN0b3Igc3BlY2lmaWNhbGx5IGluIHJvdXRlcyAoVG9wIDQgaW4gdGhpcyBjYXNlKSB3aGljaCBhcmUgaW4gdGhlIHNhbWUgd2FyZC4gV2FyZCA1LCAzIGFuZCAyMjMgYXJlIGFsbCBfX2Nsb3Nlc3QgdG8gdGhlIGFpcnBvcnRfXyBhbmQgdGhlcmVmb3JlIGhhdmUgdGhlIGhpZ2hlc3Qgam91cm5leSB0aW1lcyBhdCB0aGVzZSBob3VycywgZGVmaW5pdGVseSBzb21ldGhpbmcgZm9yIHRoZSB0cmFmZmljIGF1dGhvcml0aWVzIHRvIGxvb2sgYXQKLSBSb3V0ZSBObyAyICgxOTMpIGlzIGFsbCBjb250YWluZWQgd2l0aGluIFNoYWhkYXJhLCB3aGljaCBpcyBpbmRlZWQgY29uc2lkZXJlZCB0byBiZSBvbmUgb2YgdGhlIG1vc3QgY29uZ2VzdGVkIGFyZWFzIGluIERlbGhpLCByaWRlIHRpbWVzIHdpdGhpbiB0aGUgcmVnaW9uIGNhbiBnbyB1cHRvIF9fMSBhbmQgYSBoYWxmX18gaG91cnMKLSBfV2FyZCAzMl8gKE1FVFJPIE1BTEwsIFBvY2tldCAxLCBTZWN0b3IgMTQgRHdhcmthLCBEd2Fya2EsIE5ldyBEZWxoaSkgLSBUaGVyZSBhcmUgMyByb3V0ZXMgaW4gdGhlIHRvcCAxMCB3aXRoIHRoaXMgYXMgdGhlIGRlc3RpbmF0aW9uLiBCdXQgb25lIHRoaW5nIGluIGNvbW1vbiBhbW9uZyB0aGVzZSByb3V0ZXMgaXMgdGhlIHJpZGUgZGlzdGFuY2Ugd2hpY2ggaXMgbW9yZSB0aGFuIDMwIEtNJ3MgYnV0IHN0aWxsIHRoZXJlIFRQSyBpcyBjbG9zZSB0byBfXzQuNV9fIG1pbnV0ZXMgKDE1IEttL2hvdXIpLCB3aGljaCBpcyBvbiB0aGUgc2xvd2VyIHNpZGUKCiMgVGltZSBkZXZpYXRpb25zIG9uIHRoZSBzYW1lIHJvdXRlCgpXZSBrbm93IHRoYXQgdGhlcmUgYXJlIHBlYWsgdGltZXMgaW4gYSBkYXkgd2hlbiB0aGUgdHJhdmVsIHRpbWUgaW5jcmVhc2VzIGFuZCB1c3VhbGx5IGl0IGluY3JlYXNlcyBieSBhcm91bmQgMTUtMjAgbWlucyBhbmQgdGhhdHMgd2hhdCB0aGUgZGF0YSBzYXlzIGFzIHdlbGwuIAoKYGBge3Igcm91dGUgZGV2aWF0aW9ufQpyb3V0ZV9kZXZpYXRpb25zX2RmIDwtIHJlYWRSRFMoIkRhdGEvcm91dGVfZGV2aWFsdGlvbnMucmRzIikKcm91dGVfZGV2aWF0aW9uc19kZiA8LSByb3V0ZV9kZXZpYXRpb25zX2RmWyFpcy5uYShyb3V0ZV9kZXZpYXRpb25zX2RmJHJvdXRlX2RldmlhdGlvbiksIF0Kc3VtbWFyeShyb3V0ZV9kZXZpYXRpb25zX2RmJHJvdXRlX2RldmlhdGlvbikKYGBgCgpUaGUgX21lYW4gdGltZSBkZXZpYXRpb25fIGZvciBtb3JlIHRoYW4gODAlIHJpZGVzIGlzIGNsb3NlIHRvIF9fMTMgbWluc19fICg4MjAgcykKCkJ1dCB0aGUgbWF4IGRldmlhdGlvbiBmb3IgYSByb3V0ZSBpcyBtb3JlIHRoYW4gX181MDAwIHNfXyAoYWxtb3N0IGFuIGhvdXIgYW5kIDIwIG1pbnMpLiBUaGlzIGlzIHdoZXJlIHdlIHdhbnQgdG8gZm9jdXMgb3VyIGFuYWx5c2lzIG9uLCBzbyBsZXQ7cyBmaW5kIG91dCB0aG9zZSAwLjUgcGVyY2VudGlsZSBvZiByb3V0ZXMgKGlmIGFueSksIHdoZXJlIHRoZSBkZXZpYXRpb24gaXMgbW9yZSB0aGFuIF9fMzAgbWluc19fICgxODAwIHMpCgpgYGB7ciBjYWxjdWxhdGluZyByb3V0ZSBkZXZpYXRpb25zLCBlY2hvPUZBTFNFfQojIHNkZ3JvdXAgPC0gZnVuY3Rpb24obW92ZW1lbnRfaWQpewojIHRpbWVfc3RhcnQgPC0gU3lzLnRpbWUoKQojIHNkbCA8LSBsaXN0KCkKIyBzZGwkcm91dGVfc3RhcnQgPC0gbGlzdCgpCiMgc2RsJHJvdXRlX2VuZCA8LSBsaXN0KCkKIyBzZGwkcm91dGVfc2QgPC0gbGlzdCgpCiMgcGIgPC0gdHh0UHJvZ3Jlc3NCYXIobWluID0gMSxtYXggPSAyOTAsY2hhciA9ICItIixzdHlsZSA9IDIpCiMgZm9yKGkgaW4gMToyOTApewojIHNldFR4dFByb2dyZXNzQmFyKHBiLCBpKQojIHNkdiA8LSBzZChpbnRlcl93YXJkX21hdHJpeCRtZWFuX3RyYXZlbF90aW1lW2ludGVyX3dhcmRfbWF0cml4JHNvdXJjZWlkID09IG1vdmVtZW50X2lkICYgaW50ZXJfd2FyZF9tYXRyaXgkZHN0aWQgPT0gaV0pCiMgICAgIHNkbCRyb3V0ZV9zdGFydFtbaV1dIDwtIG1vdmVtZW50X2lkCiMgICAgIHNkbCRyb3V0ZV9lbmRbW2ldXSA8LSBpCiMgICAgIHNkbCRyb3V0ZV9zZFtbaV1dIDwtIHNkdgojIH0KIyBjbG9zZShwYikKIyB0aW1lX3Rha2VuIDwtIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChhcy5jaGFyYWN0ZXIoU3lzLnRpbWUoKSAtIHRpbWVfc3RhcnQpLHBhdHRlcm4gPSAiVGltZSBkaWZmZXJlbmNlIG9mICIscmVwbGFjZW1lbnQgPSAiIikKIyBwcmludChnbHVlOjpnbHVlKCIgLS0gY29tcGxldGVkIHttb3ZlbWVudF9pZH0gaW4ge3RpbWVfdGFrZW59IC0tICIpKQojIHJldHVybihzZGwpCiMgfQojIAojIGFsbF9yb3V0ZXMgPC0gc2VxKDEsMjkwKQojIHJvdXRlX2RldmlhdGlvbnMgPC0gcGFyYWxsZWw6Om1jbGFwcGx5KGFsbF9yb3V0ZXMsIHNkZ3JvdXAsbWMucHJlc2NoZWR1bGUgPSBUUlVFLCBtYy5jb3JlcyA9IDQpCiMgcmVhZFJEUyhEYXRhL3JvdXRlX2RldmlhbHRpb25zLnJkcykKIyByb3V0ZV9kZXZpYXRpb25zX2RmIDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSAwLG5jb2wgPSAzKSkKIyBuYW1lcyhyb3V0ZV9kZXZpYXRpb25zX2RmKSA8LSBjKCdyb3V0ZV9zdGFydCcsICdyb3V0ZV9lbmQnLCAncm91dGVfZGV2aWF0aW9uJykKIyBmb3IoaSBpbiAxOjI5MCl7CiMgICByZGYgPC0gZGF0YS5mcmFtZShyb3V0ZV9zdGFydD11bmxpc3Qocm91dGVfZGV2aWF0aW9uc1tbaV1dJHJvdXRlX3N0YXJ0KSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91dGVfZW5kID0gdW5saXN0KHJvdXRlX2RldmlhdGlvbnNbW2ldXSRyb3V0ZV9lbmQpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdXRlX2RldmlhdGlvbiA9IHVubGlzdChyb3V0ZV9kZXZpYXRpb25zW1tpXV0kcm91dGVfc2QpKQojICAgcm91dGVfZGV2aWF0aW9uc19kZiA8LSBkcGx5cjo6YmluZF9yb3dzKHJkZiwgcm91dGVfZGV2aWF0aW9uc19kZikKIyB9CiMgc2F2ZVJEUyhyb3V0ZV9kZXZpYXRpb25zX2RmLCAiRGF0YS9yb3V0ZV9kZXZpYWx0aW9ucy5yZHMiKQpyb3V0ZV9kZXZpYXRpb25zX2RmICU+JSBmaWx0ZXIocm91dGVfZGV2aWF0aW9uID4gMTgwMCkgJT4lIGFycmFuZ2UoZGVzYyhyb3V0ZV9kZXZpYXRpb24pKSAlPiUgaGVhZCgxMCkgJT4lIGthYmxlKCkKYGBgCgoKU28sIHRoZXJlIGFyZSBhIHRvdGFsIG9mIF9fMTExX18gc3VjaCByb3V0ZXMuIExldCdzIHNlZSBpZiB3ZSBjb3VsZCBmaW5kIHNvbWUgcGF0dGVybnMgaGVyZTogCgotIExvb2tpbmcgYXQgdGhlIGRhdGFzZXQgZm9yIHRoZSByb3V0ZSB3aXRoIG1vc3QgZGV2aWF0aW9uKDEzMyksIHdlIGZvdW5kIHRoYXQgdGhlcmUgYXJlIG9ubHkgX18yX18gcm93cyBpbiB0aGUgYmFzZSBkYXRhc2V0LCB3aGljaCBtZWFucyB0aGF0IHRoZSBkYXRhIGlzIGF2YWlsYWJsZSBmb3Igb25seSBhIGNvdXBlIG9mIGhvdXJzLiBUaGlzIHdvbid0IGJlIGEgZmFpciBjb21wYXJpc29uIHdpdGggb3RoZXIgcm91dGVzIHdoZXJlIHRoZSBkYXRhIGlzIGF2aWFsYWJsZSBmb3IgYWxsIDI0IGhvdXJzLiBTbyA7ZXQncyByZW1vdmUgdGhlbSBmcm9tIHRoaXMgZGF0YXNldCBhbmQgbG9vayBhdCB0aGVzZSBvYnNlcnZhcnRpb25zIGFnYWluCgpgYGB7ciBkZXZpYXRpb24gd2l0aCBtb3JlIGRhdGEgcG9pbnRzfQpudW1iZXJfaW5zdGFuY2VzIDwtCiAgaW50ZXJfd2FyZF9tYXRyaXggJT4lIGdyb3VwX2J5KHNvdXJjZWlkLCBkc3RpZCkgJT4lIHN1bW1hcmlzZSh0b3RhbF9ob2QgPSBsZW5ndGgoaG9kKSkKICAKICByb3V0ZV9kZXZpYXRpb25zX2RmIDwtCiAgZHBseXI6OmxlZnRfam9pbigKICByb3V0ZV9kZXZpYXRpb25zX2RmLAogIG51bWJlcl9pbnN0YW5jZXMsCiAgYnkgPSBjKCdyb3V0ZV9zdGFydCcgPSAnc291cmNlaWQnLCAncm91dGVfZW5kJyA9ICdkc3RpZCcpCiAgKQogIAogIHJvdXRlX2RldmlhdGlvbnNfZGYgJT4lIGZpbHRlcihyb3V0ZV9kZXZpYXRpb24gPiAxODAwICYKICB0b3RhbF9ob2QgPiA2KSAlPiUgYXJyYW5nZShkZXNjKHJvdXRlX2RldmlhdGlvbikpICU+JSBrYWJsZSgpCmBgYAoKV2Ugbm93IGhhdmUgX180X18gcm91dGVzIHdpdGggYXRsZWFzdCA2IG9ic2VydmF0aW9ucy4gU29tZSBvYnNlcnZhdGlvbnM6CgotIFRoZXNlIHJvdXRlcyBhcmUgYWZmZWN0ZWQgdGhlIG1vc3QgZHVlIHRvIGNvbmdlc3Rpb24gYXMgdGhlIHNhbWUgcmlkZSB3aWxsIHRha2UgYWxtb3N0IHRoZSBkb3VibGUgYW1vdW50IG9mIHRpbWUgdG8gY29tcGxldGUgaW4gcGVhayBob3VycwotIEFsbCBvZiB0aGVtIGhhdmUgYSBkZXZpYXRpb24gb2YgY2xvc2UgdG8gX18zMCBtaW5zX18gCgpgYGB7ciBwbG90dGluZyBkZXZpYXRpb24gZm9yIGEgcm91dGV9CmdncGxvdChkYXRhID0gaW50ZXJfd2FyZF9tYXRyaXhbaW50ZXJfd2FyZF9tYXRyaXgkc291cmNlaWQ9PSAxMTkgJiBpbnRlcl93YXJkX21hdHJpeCRkc3RpZCA9PSAxNDAsXSwgYWVzKGhvZCxtZWFuX3RyYXZlbF90aW1lKSkgKyAgZ2VvbV9wb2ludChzaGFwZSA9IDE2LCBzaXplID0gNSkgKyB4bGFiKCdIb3VyIG9mIHRoZSBkYXknKSArIHlsYWIoJ01lYW4gdHJhdmVsIHRpbWUgKGluIHNlY29uZHMpJykgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgotIFRoZXNlIGFyZSBsb25nZXIgcm91dGVzICh+MjUtMzAgS20ncykKLSBJZiB5b3UnbGwgb2JzZXJ2ZSB0aGUgc2NhdHRlciBwbG90LCB0aGVzZSByb3V0ZXMgc3VmZmVyIHRoZSBtb3N0IGJldHdlZW4gMyBQTSB0aWxsIDkgUE0KLSBUaGVzZSByb3V0ZXMgY2FuIGJlIHRlcm1lZCBhcyBlbmQgdG8gZW5kIHJvdXRlcywgYXMgdGhleSBzdGFydCBhbmQgZW5kIG1vc3RseSBhdCB0aGUgcG9pbnRzIHdoaWNoIGxpZSBvbiB0aGUgcGVyaW1ldGVyIG9mIERlbGhpLiBNb3N0IG9mIHRoZXNlIHJvdXRlcyBzdGFydCBmcm9tIHRoZSBFYXN0ZXJuIHBhcnQgYW5kIGVuZCBhdCB0aGUgV2VzdGVybiBwYXJ0cywgbW92aW5nIHRocm91Z2ggQ2VudHJhbCBEZWxoaS4gCgohW3JvdXRlX2RldmlhdGlvbnNdKC4uL2ltYWdlcy9yb3V0ZV9kZXZpYXRpb25zLnBuZyk=