1 Introduction

2 Goals

At the end of this Lab session, we will be able to:

  • Understand time series data and data structures
  • Create Time Series Visualizations
  • Perform modelling tasks on Time Series Data
  • Calculate and depict Averages, Seasons, Trends in Time Series
  • Perform Forecasting with Time Series

3 Packages

4 The tsibble data format

TBW. To be written up.

4.1 Case Study -1: Walmart Sales Dataset from timetk

Let us inspect what datasets are available in the package timetk. Type data(package = “timetk”) in your Console to see what datasets are available.

Let us choose the Walmart Sales dataset. See here for more details: Walmart Recruiting - Store Sales Forecasting |Kaggle

## Rows: 1,001
## Columns: 17
## $ id           <fct> 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_1, 1_…
## $ Store        <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ Dept         <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ Date         <date> 2010-02-05, 2010-02-12, 2010-02-19, 2010-02-26, 2010-03-05, 2010-03-12, 2010-03-19, 2010-03-26, 2010-04-02…
## $ Weekly_Sales <dbl> 24924.50, 46039.49, 41595.55, 19403.54, 21827.90, 21043.39, 22136.64, 26229.21, 57258.43, 42960.91, 17596.9…
## $ IsHoliday    <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FAL…
## $ Type         <chr> "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A…
## $ Size         <dbl> 151315, 151315, 151315, 151315, 151315, 151315, 151315, 151315, 151315, 151315, 151315, 151315, 151315, 151…
## $ Temperature  <dbl> 42.31, 38.51, 39.93, 46.63, 46.50, 57.79, 54.58, 51.45, 62.27, 65.86, 66.32, 64.84, 67.41, 72.55, 74.78, 76…
## $ Fuel_Price   <dbl> 2.572, 2.548, 2.514, 2.561, 2.625, 2.667, 2.720, 2.732, 2.719, 2.770, 2.808, 2.795, 2.780, 2.835, 2.854, 2.…
## $ MarkDown1    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ MarkDown2    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ MarkDown3    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ MarkDown4    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ MarkDown5    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ CPI          <dbl> 211.0964, 211.2422, 211.2891, 211.3196, 211.3501, 211.3806, 211.2156, 211.0180, 210.8204, 210.6229, 210.488…
## $ Unemployment <dbl> 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 7.808, 7.808, 7.808, 7.808, 7.808, 7.808, 7.808, 7.…

The data is described as:

A tibble: 9,743 x 3

  • id Factor. Unique series identifier (4 total)
  • Store Numeric. Store ID.
  • Dept Numeric. Department ID.
  • Date Date. Weekly timestamp.
  • Weekly_Sales Numeric. Sales for the given department in the given store.
  • IsHoliday Logical. Whether the week is a “special” holiday for the store.
  • Type Character. Type identifier of the store.
  • Size Numeric. Store square-footage
  • Temperature Numeric. Average temperature in the region.
  • Fuel_Price Numeric. Cost of fuel in the region.
  • MarkDown1, MarkDown2, MarkDown3, MarkDown4, MarkDown5 Numeric. Anonymized data related to promotional markdowns that Walmart is running. MarkDown data is only available after Nov 2011, and is not available for all stores all the time. Any missing value is marked with an NA.
  • CPI Numeric. The consumer price index.
  • Unemployment Numeric. The unemployment rate in the region.

NOTE: 1. This is still a data.frame, with a time-oriented variable of course, and not yet a time-series object. Note that this data frame has the YMD columns repeated for each Dept. 2. The Date column has repeated entries for each Dept! To deal with this repetition, we will always need to split the Weekly_Sales by the Dept column before we plot or analyze.

Since our sales are weekly, we will convert Date to yearweek format:

4.1.1 Basic Time Series Plots

The easiest way is to use autoplot from the feasts package. You may need to specify the actual measured variable, if there is more than one numerical column:

The R package timetk gives us interactive plots that may be more evocative than the static plot above. The basic plot function with timetk is plot_time_series. There are arguments for the date variable, the value you want to plot, colours, groupings etc.

Let us explore this dataset using timetk, using our trusted method of asking Questions:

Q.1 How are the weekly sales different for each Department?

There are

number of Departments. So we should be fine plotting them and also facetting with them, as we will see in a bit:

Q.2. What do the sales per Dept look like during the month of December (Christmas time) in 2012? Show the individual Depts as facets.

We can of course zoom into the interactive plot above, but if we were to plot it anyway:

Clearly the “unfortunate” Dept#13 has seen something of a Christmas drop in sales, as has Dept#38 ! The rest, all is well, it seems…

Too much noise? How about some averaging?

Q.3 How do we smooth out some of the variations in the time series to be able to understand it better?

Sometimes there is too much noise in the time series observations and we want to take what is called a rolling average. For this we will use the function timetk::slidify to create an averaging function of our choice, and then apply it to the time series using regular dplyr::mutate. Let’s take the average of Sales for each month in each Department. Our function will be named “rolling_avg_month”:

OK, slidify creates a function! Let’s apply it to the Walmart Sales time series…

Graphs are smoother now. Need to check whether the averaging was done on a per-Dept basis…should we have had a group_by(Dept) before the averaging, and ungroup() before plotting? Try it !!

4.1.3 Case Study-2: Dataset from nycflights13

Let us try the flights dataset from the package nycflights13. Try data(package = "nycflights13") in your Console.

We have the following datasets in nycflights13:

  • airlines Airline names.
  • airports Airport metadata
  • flights Flights data
  • planes Plane metadata.
  • weather Hourly weather data

Let us analyze the flights data:

## Rows: 336,776
## Columns: 19
## $ year           <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 201…
## $ month          <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ day            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ dep_time       <int> 517, 533, 542, 544, 554, 554, 555, 557, 557, 558, 558, 558, 558, 558, 559, 559, 559, 600, 600, 601, 602, …
## $ sched_dep_time <int> 515, 529, 540, 545, 600, 558, 600, 600, 600, 600, 600, 600, 600, 600, 600, 559, 600, 600, 600, 600, 610, …
## $ dep_delay      <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1, 0, -1, 0, 0, 1, -8, -3, -4, -4, 0, 8, 11, 3, 0, …
## $ arr_time       <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849, 853, 924, 923, 941, 702, 854, 851, 837, 844, 812,…
## $ sched_arr_time <int> 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851, 856, 917, 937, 910, 706, 902, 858, 825, 850, 820,…
## $ arr_delay      <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14, 31, -4, -8, -7, 12, -6, -8, 16, -12, -8, -17, 3…
## $ carrier        <chr> "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", "AA", "B6", "B6", "UA", "UA", "AA", "B6", "UA", "B6…
## $ flight         <int> 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79, 301, 49, 71, 194, 1124, 707, 1806, 1187, 371, 4650, 343,…
## $ tailnum        <chr> "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N39463", "N516JB", "N829AS", "N593JB", "N3ALAA", "N793…
## $ origin         <chr> "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR", "LGA", "JFK", "LGA", "JFK", "JFK", "JFK", "EWR", "LGA", …
## $ dest           <chr> "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL", "IAD", "MCO", "ORD", "PBI", "TPA", "LAX", "SFO", "DFW", …
## $ air_time       <dbl> 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, 158, 345, 361, 257, 44, 337, 152, 134, 147, 170, 10…
## $ distance       <dbl> 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733, 1028, 1005, 2475, 2565, 1389, 187, 2227, 1076, 762…
## $ hour           <dbl> 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, …
## $ minute         <dbl> 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 10, 5, 10, 10, 7, 0, 0, 10, 15, 15, 30,…
## $ time_hour      <dttm> 2013-01-01 05:00:00, 2013-01-01 05:00:00, 2013-01-01 05:00:00, 2013-01-01 05:00:00, 2013-01-01 06:00:00,…

We have time-related columns; Apart from year, month, day we have time_hour; and time-event numerical data such as arr_delay (arrival delay) and dep_delay (departure delay). We also have categorical data such as carrier, origin, dest, flight and tailnum of the aircraft. It is also a large dataset containing 330K entries. Enough to play with!!

Let us replace the NAs in arr_delay and dep_delay with zeroes for now, and convert it into a time-series object with tsibble:

Let us proceed with our questions:

Q.1. Plot the monthly average arrival delay by carrier

Q.2. Plot a candlestick chart for total flight delays by month for each carrier

Q.2. Plot a heatmap chart for total flight delays by origin, aggregated by month

4.2 Conclusion

We can plot most of the common Time Series Plots with the help of the tidyverts packages: ( tsibble, feast, fable and fabletools) , along with timetk and ggformula.

There are other plot packages to investigate, such as dygraphs.

Recall that we have used the tsibble format for the data. There are other formats such as ts, xts and others which are also meant for time series analysis. But for our present purposes, we are able to do things with the capabilities of timetk.

4.3 References

  1. Rob J Hyndman and George Athanasopoulos. Forecasting: Principles and Practice (3rd ed). Available online at https://otexts.com/fpp3/
LS0tDQp0aXRsZTogIlRpbWUgU2VyaWVzIGluIFIiDQpzdWJ0aXRsZTogIiINCmF1dGhvcjogQXJ2aW5kIFZlbmthdGFkcmkNCmFmZmlsaWF0aW9uOiANCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgdG9jX2RlcHRoOiAyDQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCmFic3RyYWN0OiBQYXJ0IG9mIG15IG9ubGluZSBjb3Vyc2UgYFIgZm9yIEFydGlzdHMgYW5kIERlc2lnbmVyc2AgdG8gdGVhY2ggUiB1c2luZyBNZXRhcGhvcnMgYW5kIENvZGUuDQotLS0NCg0KIyBJbnRyb2R1Y3Rpb24NCg0KIyBHb2Fscw0KDQpBdCB0aGUgZW5kIG9mIHRoaXMgTGFiIHNlc3Npb24sIHdlIHdpbGwgYmUgYWJsZSB0bzoNCg0KLSAgIFVuZGVyc3RhbmQgdGltZSBzZXJpZXMgZGF0YSBhbmQgZGF0YSBzdHJ1Y3R1cmVzDQotICAgQ3JlYXRlIFRpbWUgU2VyaWVzIFZpc3VhbGl6YXRpb25zDQotICAgUGVyZm9ybSBtb2RlbGxpbmcgdGFza3Mgb24gVGltZSBTZXJpZXMgRGF0YQ0KLSAgIENhbGN1bGF0ZSBhbmQgZGVwaWN0IEF2ZXJhZ2VzLCBTZWFzb25zLCBUcmVuZHMgaW4gVGltZSBTZXJpZXMNCi0gICBQZXJmb3JtIEZvcmVjYXN0aW5nIHdpdGggVGltZSBTZXJpZXMNCg0KIyBQYWNrYWdlcw0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nID0gRkFMU0UpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKSAjTWVzc2luZyB3aXRoIERhdGVzDQpsaWJyYXJ5KHRzaWJibGUpICMgVGltZS1hd2FyZSBkYXRhZnJhbWVzIGFuZCB0aWJibGVzDQpsaWJyYXJ5KHRzaWJibGVkYXRhKQ0KbGlicmFyeShmZWFzdHMpICMgdmlzdWFsaXNpbmcgdGhlIGRhdGEgYW5kIGV4dHJhY3RpbmcgdGltZSBzZXJpZXMgZmVhdHVyZXMuDQpsaWJyYXJ5KGZhYmxlKSAjIGZvcmVjYXN0aW5nIG1ldGhvZHMgZm9yIHRzaWJibGUsIHN1Y2ggYXMgQVJJTUEgYW5kIEVUUy4NCmxpYnJhcnkoZmFibGV0b29scykgIyAgbW9kZWxsaW5nIGluZnJhc3RydWN0dXJlIHRvIGVhc2UgdGhlIHByb2dyYW1taW5nIHdpdGggdHNpYmJsZS4NCmxpYnJhcnkodGltZXRrKSAjIFBsb3R0aW5nIGFuZCBBbmFseXNpbmcgVGltZSBTZXJpZXMgRGF0YQ0KbGlicmFyeShnZ2Zvcm11bGEpDQoNCiMjIyMjIw0KbGlicmFyeShwcm9waGV0KQ0KbGlicmFyeShDYXVzYWxJbXBhY3QpDQoNCmBgYA0KDQojIFRoZSBgdHNpYmJsZWAgZGF0YSBmb3JtYXQNCg0KVEJXLiBUbyBiZSB3cml0dGVuIHVwLg0KDQojIyBDYXNlIFN0dWR5IC0xOiBXYWxtYXJ0IFNhbGVzIERhdGFzZXQgZnJvbSB0aW1ldGsNCg0KTGV0IHVzIGluc3BlY3Qgd2hhdCBkYXRhc2V0cyBhcmUgYXZhaWxhYmxlIGluIHRoZSBwYWNrYWdlIHRpbWV0ay4gVHlwZQ0KZGF0YShwYWNrYWdlID0gInRpbWV0ayIpIGluIHlvdXIgQ29uc29sZSB0byBzZWUgd2hhdCBkYXRhc2V0cyBhcmUNCmF2YWlsYWJsZS4NCg0KTGV0IHVzIGNob29zZSB0aGUgV2FsbWFydCBTYWxlcyBkYXRhc2V0LiBTZWUgaGVyZSBmb3IgbW9yZSBkZXRhaWxzOg0KV2FsbWFydCBSZWNydWl0aW5nIC0gU3RvcmUgU2FsZXMgRm9yZWNhc3RpbmcgXHxLYWdnbGUNCg0KYGBge3J9DQoNCmRhdGEoIndhbG1hcnRfc2FsZXNfd2Vla2x5IikNCndhbG1hcnRfc2FsZXNfd2Vla2x5DQpnbGltcHNlKHdhbG1hcnRfc2FsZXNfd2Vla2x5KQ0KDQojIFRyeSB0aGlzIGluIHlvdXIgQ29uc29sZQ0KIyBoZWxwKCJ3YWxtYXJ0X3NhbGVzX3dlZWtseSIpDQoNCmBgYA0KDQpUaGUgZGF0YSBpcyBkZXNjcmliZWQgYXM6DQoNCkEgdGliYmxlOiA5LDc0MyB4IDMNCg0KLSAgIGlkIEZhY3Rvci4gVW5pcXVlIHNlcmllcyBpZGVudGlmaWVyICg0IHRvdGFsKQ0KLSAgIFN0b3JlIE51bWVyaWMuIFN0b3JlIElELg0KLSAgIERlcHQgTnVtZXJpYy4gRGVwYXJ0bWVudCBJRC4NCi0gICBEYXRlIERhdGUuIFdlZWtseSB0aW1lc3RhbXAuDQotICAgV2Vla2x5X1NhbGVzIE51bWVyaWMuIFNhbGVzIGZvciB0aGUgZ2l2ZW4gZGVwYXJ0bWVudCBpbiB0aGUgZ2l2ZW4NCiAgICBzdG9yZS4NCi0gICBJc0hvbGlkYXkgTG9naWNhbC4gV2hldGhlciB0aGUgd2VlayBpcyBhICJzcGVjaWFsIiBob2xpZGF5IGZvciB0aGUNCiAgICBzdG9yZS4NCi0gICBUeXBlIENoYXJhY3Rlci4gVHlwZSBpZGVudGlmaWVyIG9mIHRoZSBzdG9yZS4NCi0gICBTaXplIE51bWVyaWMuIFN0b3JlIHNxdWFyZS1mb290YWdlDQotICAgVGVtcGVyYXR1cmUgTnVtZXJpYy4gQXZlcmFnZSB0ZW1wZXJhdHVyZSBpbiB0aGUgcmVnaW9uLg0KLSAgIEZ1ZWxfUHJpY2UgTnVtZXJpYy4gQ29zdCBvZiBmdWVsIGluIHRoZSByZWdpb24uDQotICAgTWFya0Rvd24xLCBNYXJrRG93bjIsIE1hcmtEb3duMywgTWFya0Rvd240LCBNYXJrRG93bjUgTnVtZXJpYy4NCiAgICBBbm9ueW1pemVkIGRhdGEgcmVsYXRlZCB0byBwcm9tb3Rpb25hbCBtYXJrZG93bnMgdGhhdCBXYWxtYXJ0IGlzDQogICAgcnVubmluZy4gTWFya0Rvd24gZGF0YSBpcyBvbmx5IGF2YWlsYWJsZSBhZnRlciBOb3YgMjAxMSwgYW5kIGlzIG5vdA0KICAgIGF2YWlsYWJsZSBmb3IgYWxsIHN0b3JlcyBhbGwgdGhlIHRpbWUuIEFueSBtaXNzaW5nIHZhbHVlIGlzIG1hcmtlZA0KICAgIHdpdGggYW4gTkEuDQotICAgQ1BJIE51bWVyaWMuIFRoZSBjb25zdW1lciBwcmljZSBpbmRleC4NCi0gICBVbmVtcGxveW1lbnQgTnVtZXJpYy4gVGhlIHVuZW1wbG95bWVudCByYXRlIGluIHRoZSByZWdpb24uDQoNCk5PVEU6IDEuIFRoaXMgaXMgc3RpbGwgYSBkYXRhLmZyYW1lLCB3aXRoIGEgdGltZS1vcmllbnRlZCB2YXJpYWJsZSBvZg0KY291cnNlLCBhbmQgbm90IHlldCBhIHRpbWUtc2VyaWVzIG9iamVjdC4gTm90ZSB0aGF0IHRoaXMgZGF0YSBmcmFtZSBoYXMNCnRoZSBZTUQgY29sdW1ucyByZXBlYXRlZCBmb3IgZWFjaCBEZXB0LiAyLiBUaGUgRGF0ZSBjb2x1bW4gaGFzIHJlcGVhdGVkDQplbnRyaWVzIGZvciBlYWNoIERlcHQhIFRvIGRlYWwgd2l0aCB0aGlzIHJlcGV0aXRpb24sIHdlIHdpbGwgYWx3YXlzIG5lZWQNCnRvIHNwbGl0IHRoZSBXZWVrbHlfU2FsZXMgYnkgdGhlIERlcHQgY29sdW1uIGJlZm9yZSB3ZSBwbG90IG9yIGFuYWx5emUuDQoNClNpbmNlIG91ciBzYWxlcyBhcmUgd2Vla2x5LCB3ZSB3aWxsIGNvbnZlcnQgRGF0ZSB0byB5ZWFyd2VlayBmb3JtYXQ6DQoNCmBgYHtyfQ0Kd2FsbWFydF90aW1lIDwtIHdhbG1hcnRfc2FsZXNfd2Vla2x5ICU+JSANCiAgDQogIGFzX3RzaWJibGUoaW5kZXggPSBEYXRlLCAjIFRpbWUgVmFyaWFibGUgDQogICAgICAgICAgICAgDQogIGtleSA9IERlcHQgKSANCiMgSWRlbnRpZmllcyB1bmlxdWUgInN1YmplY3QiIHdobyBhcmUgbWVhc3VyZXMgDQojIEFsbCBvdGhlciB2YXJpYWJsZXMgc3VjaCBhcyBXZWVrbHlfc2FsZXMgYmVjb21lICJtZWFzdXJlZCB2YXJpYWJsZSIgDQojIEVhY2ggb2JzZXJ2YXRpb24gc2hvdWxkIGJlIHVuaXF1ZWx5IGlkZW50aWZpZWQgYnkgaW5kZXggYW5kIGtleQ0KICANCndhbG1hcnRfdGltZQ0KYGBgDQoNCiMjIyBCYXNpYyBUaW1lIFNlcmllcyBQbG90cw0KDQpUaGUgZWFzaWVzdCB3YXkgaXMgdG8gdXNlIGF1dG9wbG90IGZyb20gdGhlIGZlYXN0cyBwYWNrYWdlLiBZb3UgbWF5IG5lZWQNCnRvIHNwZWNpZnkgdGhlIGFjdHVhbCBtZWFzdXJlZCB2YXJpYWJsZSwgaWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZQ0KbnVtZXJpY2FsIGNvbHVtbjoNCg0KYGBge3IgZmVhc3RzLWJhc2ljLXBsb3R9DQoNCmF1dG9wbG90KHdhbG1hcnRfdGltZSwudmFycyA9IFdlZWtseV9TYWxlcykNCmBgYA0KDQpUaGUgUiBwYWNrYWdlIGB0aW1ldGtgIGdpdmVzIHVzIGludGVyYWN0aXZlIHBsb3RzIHRoYXQgbWF5IGJlIG1vcmUNCmV2b2NhdGl2ZSB0aGFuIHRoZSBzdGF0aWMgcGxvdCBhYm92ZS4gVGhlIGJhc2ljIHBsb3QgZnVuY3Rpb24gd2l0aA0KYHRpbWV0a2AgaXMgYHBsb3RfdGltZV9zZXJpZXNgLiBUaGVyZSBhcmUgYXJndW1lbnRzIGZvciB0aGUgZGF0ZQ0KdmFyaWFibGUsIHRoZSB2YWx1ZSB5b3Ugd2FudCB0byBwbG90LCBjb2xvdXJzLCBncm91cGluZ3MgZXRjLg0KDQpMZXQgdXMgZXhwbG9yZSB0aGlzIGRhdGFzZXQgdXNpbmcgYHRpbWV0a2AsIHVzaW5nIG91ciB0cnVzdGVkIG1ldGhvZCBvZg0KYXNraW5nIFF1ZXN0aW9uczoNCg0KKipRLjEgSG93IGFyZSB0aGUgd2Vla2x5IHNhbGVzIGRpZmZlcmVudCBmb3IgZWFjaCBEZXBhcnRtZW50PyoqDQoNClRoZXJlIGFyZSBgciB3YWxtYXJ0X3NhbGVzX3dlZWtseSAlPiUgZGlzdGluY3QoRGVwdCkgJT4lIGNvdW50KClgIG51bWJlcg0Kb2YgRGVwYXJ0bWVudHMuIFNvIHdlIHNob3VsZCBiZSBmaW5lIHBsb3R0aW5nIHRoZW0gYW5kIGFsc28gZmFjZXR0aW5nDQp3aXRoIHRoZW0sIGFzIHdlIHdpbGwgc2VlIGluIGEgYml0Og0KDQpgYGB7cn0NCndhbG1hcnRfdGltZSAlPiUgDQogIHRpbWV0azo6cGxvdF90aW1lX3NlcmllcyhEYXRlLCBXZWVrbHlfU2FsZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmNvbG9yX3ZhciA9IERlcHQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmxlZ2VuZF9zaG93ID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAudGl0bGUgPSAiV2FsbWFydCBTYWxlcyBEYXRhIGJ5IERlcGFydG1lbnQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLnNtb290aCA9IEZBTFNFKQ0KYGBgDQoNCioqUS4yLiBXaGF0IGRvIHRoZSBzYWxlcyBwZXIgRGVwdCBsb29rIGxpa2UgZHVyaW5nIHRoZSBtb250aCBvZiBEZWNlbWJlcg0KKENocmlzdG1hcyB0aW1lKSBpbiAyMDEyPyBTaG93IHRoZSBpbmRpdmlkdWFsIERlcHRzIGFzIGZhY2V0cy4qKg0KDQpXZSBjYW4gb2YgY291cnNlIHpvb20gaW50byB0aGUgaW50ZXJhY3RpdmUgcGxvdCBhYm92ZSwgYnV0IGlmIHdlIHdlcmUgdG8NCnBsb3QgaXQgYW55d2F5Og0KDQpgYGB7ciBmaWx0ZXJpbmctYnktdGltZX0NCg0KIyBPbmx5IGluY2x1ZGUgcm93cyBmcm9tIDEgdG8gRGVjZW1iZXIgMzEsIDIwMTENCiMgRGF0YSBnb2VzIG9ubHkgdXAgdG8gT2N0IDIwMTINCndhbG1hcnRfdGltZSAlPiUNCiAgDQogICMgRWFjaCBzaWRlIG9mIHRoZSB0aW1lX2Zvcm11bGEgYmVsb3cgaXMgc3BlY2lmaWVkIGFzIHRoZSBjaGFyYWN0ZXINCiAgIyAnWVlZWS1NTS1ERCBISDpNTTpTUycsDQogIA0KICB0aW1ldGs6OmZpbHRlcl9ieV90aW1lKC5kYXRlX3ZhciA9IERhdGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgLnN0YXJ0X2RhdGUgPSAiMjAxMS0xMi0wMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgLmVuZF9kYXRlID0gIjIwMTEtMTItMzEiKSAlPiUNCiAgDQogIHBsb3RfdGltZV9zZXJpZXMoDQogICAgLmRhdGVfdmFyID0gRGF0ZSwNCiAgICAudmFsdWUgPSBXZWVrbHlfU2FsZXMsDQogICAgLmNvbG9yX3ZhciA9IERlcHQsDQogICAgLmZhY2V0X3ZhcnMgPSBEZXB0LA0KICAgIC5mYWNldF9uY29sID0gMiwNCiAgICAuc21vb3RoID0gRkFMU0UNCiAgKSAjIE9ubHkgNCBwb2ludHMgcGVyIGdyYXBoDQpgYGANCg0KQ2xlYXJseSB0aGUgInVuZm9ydHVuYXRlIiBEZXB0IzEzIGhhcyBzZWVuIHNvbWV0aGluZyBvZiBhIENocmlzdG1hcyBkcm9wDQppbiBzYWxlcywgYXMgaGFzIERlcHQjMzggISBUaGUgcmVzdCwgYWxsIGlzIHdlbGwsIGl0IHNlZW1zLi4uDQoNClRvbyBtdWNoIG5vaXNlPyBIb3cgYWJvdXQgc29tZSBhdmVyYWdpbmc/DQoNCioqUS4zIEhvdyBkbyB3ZSBzbW9vdGggb3V0IHNvbWUgb2YgdGhlIHZhcmlhdGlvbnMgaW4gdGhlIHRpbWUgc2VyaWVzIHRvDQpiZSBhYmxlIHRvIHVuZGVyc3RhbmQgaXQgYmV0dGVyPyoqDQoNClNvbWV0aW1lcyB0aGVyZSBpcyB0b28gbXVjaCBub2lzZSBpbiB0aGUgdGltZSBzZXJpZXMgb2JzZXJ2YXRpb25zIGFuZCB3ZQ0Kd2FudCB0byB0YWtlIHdoYXQgaXMgY2FsbGVkIGEgKnJvbGxpbmcgYXZlcmFnZSouIEZvciB0aGlzIHdlIHdpbGwgdXNlDQp0aGUgZnVuY3Rpb24gYHRpbWV0azo6c2xpZGlmeWAgdG8gY3JlYXRlIGFuIGF2ZXJhZ2luZyBmdW5jdGlvbiBvZiBvdXINCmNob2ljZSwgYW5kIHRoZW4gYXBwbHkgaXQgdG8gdGhlIHRpbWUgc2VyaWVzIHVzaW5nIHJlZ3VsYXINCmBkcGx5cjo6bXV0YXRlYC4gTGV0J3MgdGFrZSB0aGUgYXZlcmFnZSBvZiBTYWxlcyBmb3IgZWFjaCBtb250aCBpbiBlYWNoDQpEZXBhcnRtZW50LiBPdXIgKipmdW5jdGlvbioqIHdpbGwgYmUgbmFtZWQgInJvbGxpbmdfYXZnX21vbnRoIjoNCg0KYGBge3IgIGF2ZXJhZ2luZy1mdW5jdGlvbn0NCnJvbGxpbmdfYXZnX21vbnRoID0gc2xpZGlmeSgucGVyaW9kID0gNCwgIyBldmVyeSA0IHdlZWtzIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5mID0gbWVhbiwgIyBUaGUgZnVuY3Rpb24gdG8gYXZlcmFnZSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuYWxpZ24gPSAiY2VudGVyIiwgIyBBbGlnbmVkIHdpdGggbWlkZGxlIG9mIG1vbnRoIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5wYXJ0aWFsID0gVFJVRSkgIyBUbyBjYXRjaCBhbnkgbGVmdG92ZXIgaGFsZiB3ZWVrcyByb2xsaW5nX2F2Z19tb250aA0KYGBgDQoNCk9LLCBzbGlkaWZ5IGNyZWF0ZXMgYSBmdW5jdGlvbiEgTGV0J3MgYXBwbHkgaXQgdG8gdGhlIFdhbG1hcnQgU2FsZXMgdGltZQ0Kc2VyaWVzLi4uDQoNCmBgYHtyIGF2ZXJhZ2luZ30NCndhbG1hcnRfdGltZSAlPiUgIyBncm91cF9ieShEZXB0KSAlPiUNCiAgbXV0YXRlKGF2Z19tb250aGx5X3NhbGVzID0gcm9sbGluZ19hdmdfbW9udGgoV2Vla2x5X1NhbGVzKSkgJT4lDQogICMgdW5ncm91cCgpICU+JQ0KICB0aW1ldGs6OnBsb3RfdGltZV9zZXJpZXMoRGF0ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGF2Z19tb250aGx5X3NhbGVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmNvbG9yX3ZhciA9IERlcHQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAuc21vb3RoID0gRkFMU0UpDQpgYGANCg0KR3JhcGhzIGFyZSBzbW9vdGhlciBub3cuIE5lZWQgdG8gY2hlY2sgd2hldGhlciB0aGUgYXZlcmFnaW5nIHdhcyBkb25lIG9uDQphIHBlci1EZXB0IGJhc2lzLi4uc2hvdWxkIHdlIGhhdmUgaGFkIGEgYGdyb3VwX2J5KERlcHQpYCBiZWZvcmUgdGhlDQphdmVyYWdpbmcsIGFuZCBgdW5ncm91cCgpYCBiZWZvcmUgcGxvdHRpbmc/IFRyeSBpdCAhIQ0KDQojIyMgRGVjb21wb3NpbmcgVGltZSBTZXJpZXM6IFRyZW5kcywgU2Vhc29uYWwgUGF0dGVybnMsIGFuZCBDeWNsZXMNCg0KRWFjaCBkYXRhIHBvaW50ICgkWV90JCkgYXQgdGltZSAkdCQgaW4gYSBUaW1lIFNlcmllcyBjYW4gYmUgZXhwcmVzc2VkIGFzDQplaXRoZXIgYSBzdW0gb3IgYSBwcm9kdWN0IG9mIDQgY29tcG9uZW50cywgbmFtZWx5LCBTZWFzb25hbGl0eSgkU190JCksDQpUcmVuZCgkVF90JCksIEN5Y2xpYywgYW5kIEVycm9yKCRlX3QkKSAoYS5rLmEgV2hpdGUgTm9pc2UpLg0KDQotICAgVHJlbmQ6IHBhdHRlcm4gZXhpc3RzIHdoZW4gdGhlcmUgaXMgYSBsb25nLXRlcm0gaW5jcmVhc2Ugb3IgZGVjcmVhc2UNCiAgICBpbiB0aGUgZGF0YS4NCi0gICBTZWFzb25hbDogcGF0dGVybiBleGlzdHMgd2hlbiBhIHNlcmllcyBpcyBpbmZsdWVuY2VkIGJ5IHNlYXNvbmFsDQogICAgZmFjdG9ycyAoZS5nLiwgdGhlIHF1YXJ0ZXIgb2YgdGhlIHllYXIsIHRoZSBtb250aCwgb3IgZGF5IG9mIHRoZQ0KICAgIHdlZWspLg0KLSAgIEN5Y2xpYzogcGF0dGVybiBleGlzdHMgd2hlbiBkYXRhIGV4aGliaXQgcmlzZXMgYW5kIGZhbGxzIHRoYXQgYXJlDQogICAgbm90IG9mIGZpeGVkIHBlcmlvZCAoZHVyYXRpb24gdXN1YWxseSBvZiBhdCBsZWFzdCAyIHllYXJzKS4NCi0gICBFcnJvciBvciBOb2lzZTogUmFuZG9tIGNvbXBvbmVudA0KDQpEZWNvbXBvc2luZyBub24tc2Vhc29uYWwgZGF0YSBtZWFucyBicmVha2luZyBpdCB1cCBpbnRvIHRyZW5kIGFuZA0KaXJyZWd1bGFyIGNvbXBvbmVudHMuIFRvIGVzdGltYXRlIHRoZSB0cmVuZCBjb21wb25lbnQgb2YgYSBub24tc2Vhc29uYWwNCnRpbWUgc2VyaWVzIHRoYXQgY2FuIGJlIGRlc2NyaWJlZCB1c2luZyBhbiBhZGRpdGl2ZSBtb2RlbCwgaXQgaXMgY29tbW9uDQp0byB1c2UgYSBzbW9vdGhpbmcgbWV0aG9kLCBzdWNoIGFzIGNhbGN1bGF0aW5nIHRoZSBzaW1wbGUgbW92aW5nIGF2ZXJhZ2UNCm9mIHRoZSB0aW1lIHNlcmllcy4NCg0KYHRpbWV0a2AgaGFzIHRoZSBhYmlsaXR5IHRvIGFjaGlldmUgdGhpczogTGV0IHVzIHBsb3QgdGhlIHRyZW5kLA0Kc2Vhc29uYWwsIGN5Y2xpYyBhbmQgaXJyZWd1bGFyIGFzcGVjdHMgb2YgV2Vla2x5X1NhbGVzIGZvciBEZXB0IDM4Og0KDQpgYGB7ciBkZWNvbXBvc2UtdGltZS1zZXJpZXN9DQp3YWxtYXJ0X3RpbWUgJT4lIGZpbHRlcihEZXB0ID09ICIzOCIpICU+JSANCiAgdGltZXRrOjpwbG90X3N0bF9kaWFnbm9zdGljcyguZGF0ZV92YXIgPSBEYXRlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAudmFsdWUgPSBXZWVrbHlfU2FsZXMpDQoNCmBgYA0KDQpXZSBjYW4gZG8gdGhpcyBmb3IgYWxsIERlcHQgdXNpbmcgYGZhYmxlYCBhbmQgYGZhYmxldG9vbHNgOg0KDQpgYGB7ciBEZWNvbXBvc2luZ190cmVuZHN9DQp3YWxtYXJ0X2RlY29tcG9zZWQgPC0gd2FsbWFydF90aW1lICU+JQ0KICANCiAgIyBJZiB3ZSB3YW50IHRvIGZpbHRlciwgd2UgZG8gaXQgaGVyZSAjIGZpbHRlcihEZXB0ID09ICIzOCIpICU+JSAjDQogIGZhYmxldG9vbHM6Om1vZGVsKHN0bCA9IFNUTChXZWVrbHlfU2FsZXMpKQ0KDQpmYWJsZXRvb2xzOjpjb21wb25lbnRzKHdhbG1hcnRfZGVjb21wb3NlZCkNCg0KYXV0b3Bsb3QoY29tcG9uZW50cygod2FsbWFydF9kZWNvbXBvc2VkKSkpDQoNCmBgYA0KDQojIyMgQ2FzZSBTdHVkeS0yOiBEYXRhc2V0IGZyb20gbnljZmxpZ2h0czEzDQoNCkxldCB1cyB0cnkgdGhlIGZsaWdodHMgZGF0YXNldCBmcm9tIHRoZSBwYWNrYWdlIGBueWNmbGlnaHRzMTNgLiBUcnkNCmBkYXRhKHBhY2thZ2UgPSAibnljZmxpZ2h0czEzIilgIGluIHlvdXIgQ29uc29sZS4NCg0KV2UgaGF2ZSB0aGUgZm9sbG93aW5nIGRhdGFzZXRzIGluIGBueWNmbGlnaHRzMTNgOg0KDQotICAgYWlybGluZXMgQWlybGluZSBuYW1lcy4NCi0gICBhaXJwb3J0cyBBaXJwb3J0IG1ldGFkYXRhDQotICAgZmxpZ2h0cyBGbGlnaHRzIGRhdGENCi0gICBwbGFuZXMgUGxhbmUgbWV0YWRhdGEuDQotICAgd2VhdGhlciBIb3VybHkgd2VhdGhlciBkYXRhDQoNCkxldCB1cyBhbmFseXplIHRoZSBmbGlnaHRzIGRhdGE6DQoNCmBgYHtyfQ0KZGF0YSgiZmxpZ2h0cyIsIHBhY2thZ2UgPSAibnljZmxpZ2h0czEzIikNCmdsaW1wc2UoZmxpZ2h0cykNCmBgYA0KDQpXZSBoYXZlIHRpbWUtcmVsYXRlZCBjb2x1bW5zOyBBcGFydCBmcm9tIHllYXIsIG1vbnRoLCBkYXkgd2UgaGF2ZQ0KYHRpbWVfaG91cmA7IGFuZCB0aW1lLWV2ZW50IG51bWVyaWNhbCBkYXRhIHN1Y2ggYXMgYGFycl9kZWxheWAgKGFycml2YWwNCmRlbGF5KSBhbmQgYGRlcF9kZWxheWAgKGRlcGFydHVyZSBkZWxheSkuIFdlIGFsc28gaGF2ZSBjYXRlZ29yaWNhbCBkYXRhDQpzdWNoIGFzIGBjYXJyaWVyYCwgYG9yaWdpbmAsIGBkZXN0YCwgYGZsaWdodGAgYW5kIGB0YWlsbnVtYCBvZiB0aGUNCmFpcmNyYWZ0LiBJdCBpcyBhbHNvIGEgbGFyZ2UgZGF0YXNldCBjb250YWluaW5nIDMzMEsgZW50cmllcy4gRW5vdWdoIHRvDQpwbGF5IHdpdGghIQ0KDQpMZXQgdXMgcmVwbGFjZSB0aGUgTkFzIGluIGBhcnJfZGVsYXlgIGFuZCBgZGVwX2RlbGF5YCB3aXRoIHplcm9lcyBmb3INCm5vdywgYW5kIGNvbnZlcnQgaXQgaW50byBhIHRpbWUtc2VyaWVzIG9iamVjdCB3aXRoIGB0c2liYmxlYDoNCg0KYGBge3J9DQpmbGlnaHRzX2RlbGF5X3RzIDwtIGZsaWdodHMgJT4lDQogIG11dGF0ZShhcnJfZGVsYXkgPSByZXBsYWNlX25hKGFycl9kZWxheSwgMCksDQogICAgICAgICBkZXBfZGVsYXkgPSByZXBsYWNlX25hKGRlcF9kZWxheSwgMCkpICU+JQ0KICBzZWxlY3QodGltZV9ob3VyLA0KICAgICAgICAgYXJyX2RlbGF5LA0KICAgICAgICAgZGVwX2RlbGF5LA0KICAgICAgICAgY2FycmllciwNCiAgICAgICAgIG9yaWdpbiwNCiAgICAgICAgIGRlc3QsDQogICAgICAgICBmbGlnaHQsDQogICAgICAgICB0YWlsbnVtKSAlPiUNCiAgdHNpYmJsZTo6YXNfdHNpYmJsZSgNCiAgICBpbmRleCA9IHRpbWVfaG91ciwNCiAgICAjIEFsbCB0aGUgcmVtYWluaW5nIGlkZW50aWZ5IHVuaXF1ZSBlbnRyaWVzDQogICAgIyBBbG9uZyB3aXRoIGluZGV4ICMgTWFueSBvZiB0aGVzZSB2YXJpYWJsZXMgYXJlIGNvbW1vbg0KICAgICMgTmVlZCBhbGwgdG8gbWFrZSB1bmlxdWUgZW50cmllcyENCiAgICBrZXkgPSBjKGNhcnJpZXIsIG9yaWdpbiwgZGVzdCwgZmxpZ2h0LCB0YWlsbnVtKSwNCiAgICB2YWxpZGF0ZSA9IFRSVUUNCiAgKSAjIE1ha2luZyBzdXJlIGVhY2ggZW50cnkgaXMgdW5pcXVlDQoNCmZsaWdodHNfZGVsYXlfdHMNCmBgYA0KDQpMZXQgdXMgcHJvY2VlZCB3aXRoIG91ciBxdWVzdGlvbnM6DQoNCioqUS4xLiBQbG90IHRoZSBtb250aGx5IGF2ZXJhZ2UgYXJyaXZhbCBkZWxheSBieSBjYXJyaWVyKioNCg0KYGBge3J9DQptZWFuX2Fycl9kZWxheXNfYnlfY2FycmllciA8LSBmbGlnaHRzX2RlbGF5X3RzICU+JQ0KICBncm91cF9ieShjYXJyaWVyKSAlPiUNCiAgaW5kZXhfYnkobW9udGggPSB+IHllYXJtb250aCguKSkgJT4lDQogIA0KICAjIGluZGV4X2J5IHVzZXMgKHllYXIsIHllYXJxdWFydGVyLCB5ZWFybW9udGgsIHllYXJ3ZWVrLCBhcy5EYXRlKQ0KICAjIHRvIGNyZWF0ZSBhIG5ldyBjb2x1bW4gdG8gc2hvdyB0aGUgdGltZS1ncm91cGluZyAjIHllYXIgLyBxdWFydGVyIC8gbW9udGgvIHdlZWssIG9yIGRheeKApg0KICAjIHdoaWNoIElTIGRpZmZlcmVudCBmcm9tIHRyYWRpdGlvbmFsIGRwbHlyDQogIA0KICBzdW1tYXJpc2UobWVhbl9hcnJfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkNCg0KbWVhbl9hcnJfZGVsYXlzX2J5X2NhcnJpZXINCg0KbWVhbl9hcnJfZGVsYXlzX2J5X2NhcnJpZXIgJT4lIA0KICB0aW1ldGs6OnBsb3RfdGltZV9zZXJpZXMoDQogIC5kYXRlX3ZhciA9IG1vbnRoLA0KICAudmFsdWUgPSBtZWFuX2Fycl9kZWxheSwNCiAgLmZhY2V0X3ZhcnMgPSBjYXJyaWVyLA0KICAuc21vb3RoID0gRkFMU0UsDQogICMgLnNtb290aF9kZWdyZWUgPSAxLCANCiAgIyBrZWVwIC5zbW9vdGggb2ZmIHNpbmNlIGl0IHRocm93cyB3YXJuaW5ncyBpZiB0aGVyZSBhcmUgdG9vIGZldyBwb2ludHMNCiAgIyBMaWtlIGlmIHdlIGRvIHF1YXJ0ZXJseSBvciBldmVuIHllYXJseSBzdW1tYXJpZXMNCiAgIyBVc2Ugb25seSBmb3Igc21hbGxlciB2YWx1ZXMgb2YgLnNtb290aF9kZWdyZWUgKDAsMSkNCiAgIw0KICAuZmFjZXRfbmNvbCA9IDQsDQogIC50aXRsZSA9ICJBdmVyYWdlIE1vbnRobHkgQXJyaXZhbCBEZWxheXMgYnkgQ2FycmllciINCikNCmBgYA0KDQoqKlEuMi4gUGxvdCBhIGNhbmRsZXN0aWNrIGNoYXJ0IGZvciB0b3RhbCBmbGlnaHQgZGVsYXlzIGJ5IG1vbnRoIGZvcg0KZWFjaCBjYXJyaWVyKioNCg0KYGBge3J9DQpmbGlnaHRzX2RlbGF5X3RzICU+JSANCiAgbXV0YXRlKHRvdGFsX2RlbGF5ID0gYXJyX2RlbGF5ICsgZGVwX2RlbGF5KSAlPiUgDQogIHRpbWV0azo6cGxvdF90aW1lX3Nlcmllc19ib3hwbG90KA0KICAuZGF0ZV92YXIgPSB0aW1lX2hvdXIsDQogIC52YWx1ZSA9IHRvdGFsX2RlbGF5LA0KICAuY29sb3JfdmFyID0gb3JpZ2luLA0KICAuZmFjZXRfdmFycyA9IG9yaWdpbiwNCiAgLnBlcmlvZCA9ICJtb250aCIsDQogICMgc2FtZSB3YXJuaW5nIGFnYWluIC5zbW9vdGggPSBGQUxTRSANCiAgKQ0KYGBgDQoNCioqUS4yLiBQbG90IGEgaGVhdG1hcCBjaGFydCBmb3IgdG90YWwgZmxpZ2h0IGRlbGF5cyBieSBvcmlnaW4sDQphZ2dyZWdhdGVkIGJ5IG1vbnRoKioNCg0KYGBge3J9DQphdmdfZGVsYXlzX21vbnRoIDwtDQogIGZsaWdodHNfZGVsYXlfdHMgJT4lIA0KICBncm91cF9ieShvcmlnaW4pICU+JSANCiAgbXV0YXRlKHRvdGFsX2RlbGF5ID0gYXJyX2RlbGF5ICsgZGVwX2RlbGF5KSAlPiUgDQogIGluZGV4X2J5KG1vbnRoID0gfiB5ZWFybW9udGgoLikpICU+JSANCiAgDQogICMgaW5kZXhfYnkgdXNlcyAoeWVhciwgeWVhcnF1YXJ0ZXIsIHllYXJtb250aCwgeWVhcndlZWssIGFzLkRhdGUpIA0KICAjIHRvIGNyZWF0ZSBhIG5ldyBjb2x1bW4gdG8gc2hvdyB0aGUgdGltZS1ncm91cGluZyANCiAgIyB5ZWFyIC8gcXVhcnRlciAvIG1vbnRoLyB3ZWVrLCBvciBkYXnigKYgDQogICMgd2hpY2ggSVMgZGlmZmVyZW50IGZyb20gdHJhZGl0aW9uYWwgZHBseXIgDQogIA0KICBzdW1tYXJpc2UobWVhbl9tb250aGx5X2RlbGF5ID0gbWVhbih0b3RhbF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCiAgDQphdmdfZGVsYXlzX21vbnRoIA0KIyB0aHJlZSBvcmlnaW5zIDEyIG1vbnRocyB0aGVyZWZvcmUgMzYgcm93cyANCiMgIyBUc2liYmxlIGluZGV4X2J5ICsgc3VtbWFyaXNlIGFsc28gZ2l2ZXMgdXMgYSBtb250aGAgY29sdW1uDQoNCmdnZm9ybXVsYTo6Z2ZfdGlsZSgNCiAgb3JpZ2luIH4gbW9udGgsDQogIGZpbGwgPSB+IG1lYW5fbW9udGhseV9kZWxheSwNCiAgY29sb3IgPSAiYmxhY2siLA0KICBkYXRhID0gYXZnX2RlbGF5c19tb250aCwNCiAgdGl0bGUgPSAiTWVhbiBGbGlnaHQgRGVsYXlzIGZyb20gTlkgQWlycG9ydHMgaW4gMjAxMyINCikgJT4lDQogIGdmX3RoZW1lKHRoZW1lX2NsYXNzaWMoKSkgJT4lDQogIGdmX3RoZW1lKHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJBIikpICU+JQ0KICANCiAgIyAibWFnbWEiIChvciAiQSIpIGluZmVybm8iIChvciAiQiIpICJwbGFzbWEiIChvciAiQyIpDQogICMgInZpcmlkaXMiIChvciAiRCIpICJjaXZpZGlzIiAob3IgIkUiKQ0KICAjICJyb2NrZXQiIChvciAiRiIpICJtYWtvIiAob3IgIkciKSAidHVyYm8iIChvciAiSCIpDQogIA0KICBnZl90aGVtZShzY2FsZV94X3RpbWUoYnJlYWtzID0gMToxMiwgbGFiZWxzID0gbW9udGguYWJiKSkNCg0KYGBgDQoNCiMjIENvbmNsdXNpb24NCg0KV2UgY2FuIHBsb3QgbW9zdCBvZiB0aGUgY29tbW9uIFRpbWUgU2VyaWVzIFBsb3RzIHdpdGggdGhlIGhlbHAgb2YgdGhlDQpgdGlkeXZlcnRzYCBwYWNrYWdlczogKCBgdHNpYmJsZWAsIGBmZWFzdGAsIGBmYWJsZWAgYW5kIGBmYWJsZXRvb2xzYCkgLCBhbG9uZw0Kd2l0aCBgdGltZXRrYCBhbmQgYGdnZm9ybXVsYWAuDQoNClRoZXJlIGFyZSBvdGhlciBwbG90IHBhY2thZ2VzIHRvIGludmVzdGlnYXRlLCBzdWNoIGFzIGBkeWdyYXBoc2AuDQoNClJlY2FsbCB0aGF0IHdlIGhhdmUgdXNlZCB0aGUgYHRzaWJibGVgIGZvcm1hdCBmb3IgdGhlIGRhdGEuIFRoZXJlIGFyZQ0Kb3RoZXIgZm9ybWF0cyBzdWNoIGFzIGB0c2AsIGB4dHNgIGFuZCBvdGhlcnMgd2hpY2ggYXJlIGFsc28gbWVhbnQgZm9yDQp0aW1lIHNlcmllcyBhbmFseXNpcy4gQnV0IGZvciBvdXIgcHJlc2VudCBwdXJwb3Nlcywgd2UgYXJlIGFibGUgdG8gZG8NCnRoaW5ncyB3aXRoIHRoZSBjYXBhYmlsaXRpZXMgb2YgYHRpbWV0a2AuDQoNCiMjIFJlZmVyZW5jZXMNCg0KMS4gIFJvYiBKIEh5bmRtYW4gYW5kIEdlb3JnZSBBdGhhbmFzb3BvdWxvcy4gKkZvcmVjYXN0aW5nOiBQcmluY2lwbGVzDQogICAgYW5kIFByYWN0aWNlICgzcmQgZWQpKi4gQXZhaWxhYmxlIG9ubGluZSBhdA0KICAgIDxodHRwczovL290ZXh0cy5jb20vZnBwMy8+DQogICAgDQogICAgDQoNCg==