• 1 Introduction
  • 2 Goals
  • 3 Packages
  • 4 The tsibble data format
    • 4.1 Case Study -1: Walmart Sales Dataset from timetk
    • 4.2 Conclusion
    • 4.3 References

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

ABCDEFGHIJ0123456789
id
<fct>
Store
<dbl>
Dept
<dbl>
Date
<date>
Weekly_Sales
<dbl>
IsHoliday
<lgl>
Type
<chr>
Size
<dbl>
Temperature
<dbl>
1_1112010-02-0524924.50FALSEA15131542.31
1_1112010-02-1246039.49TRUEA15131538.51
1_1112010-02-1941595.55FALSEA15131539.93
1_1112010-02-2619403.54FALSEA15131546.63
1_1112010-03-0521827.90FALSEA15131546.50
1_1112010-03-1221043.39FALSEA15131557.79
1_1112010-03-1922136.64FALSEA15131554.58
1_1112010-03-2626229.21FALSEA15131551.45
1_1112010-04-0257258.43FALSEA15131562.27
1_1112010-04-0942960.91FALSEA15131565.86
## 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_…
## $ Store        <dbl> 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, …
## $ Date         <date> 2010-02-05, 2010-02-12, 2010-02-19, 2010-02-26, 2010-03-…
## $ Weekly_Sales <dbl> 24924.50, 46039.49, 41595.55, 19403.54, 21827.90, 21043.3…
## $ IsHoliday    <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FA…
## $ Type         <chr> "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A…
## $ Size         <dbl> 151315, 151315, 151315, 151315, 151315, 151315, 151315, 1…
## $ Temperature  <dbl> 42.31, 38.51, 39.93, 46.63, 46.50, 57.79, 54.58, 51.45, 6…
## $ Fuel_Price   <dbl> 2.572, 2.548, 2.514, 2.561, 2.625, 2.667, 2.720, 2.732, 2…
## $ MarkDown1    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ MarkDown2    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ MarkDown3    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ MarkDown4    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ MarkDown5    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ CPI          <dbl> 211.0964, 211.2422, 211.2891, 211.3196, 211.3501, 211.380…
## $ Unemployment <dbl> 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 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:

ABCDEFGHIJ0123456789
id
<fct>
Store
<dbl>
Dept
<dbl>
Date
<date>
Weekly_Sales
<dbl>
IsHoliday
<lgl>
Type
<chr>
Size
<dbl>
Temperature
<dbl>
1_1112010-02-0524924.50FALSEA15131542.31
1_1112010-02-1246039.49TRUEA15131538.51
1_1112010-02-1941595.55FALSEA15131539.93
1_1112010-02-2619403.54FALSEA15131546.63
1_1112010-03-0521827.90FALSEA15131546.50
1_1112010-03-1221043.39FALSEA15131557.79
1_1112010-03-1922136.64FALSEA15131554.58
1_1112010-03-2626229.21FALSEA15131551.45
1_1112010-04-0257258.43FALSEA15131562.27
1_1112010-04-0942960.91FALSEA15131565.86

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
ABCDEFGHIJ0123456789
n
<int>
7

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

Jul 2010Jan 2011Jul 2011Jan 2012Jul 2012020k40k60k80k100k120k140k
Legend13813389395Walmart Sales Data by Department

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:

30k40k32k34k36k38k40k70k80k90kDec 42011Dec 11Dec 18Dec 25100k110k120k10k12k34k36kDec 42011Dec 11Dec 18Dec 2560k70k80k90k
Legend13813389395Time Series Plot13813389395

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…

Jul 2010Jan 2011Jul 2011Jan 2012Jul 201220k40k60k80k100k120k140k
Legend13813389395Time Series Plot

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, 2…
## $ month          <int> 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…
## $ dep_time       <int> 517, 533, 542, 544, 554, 554, 555, 557, 557, 558, 558, …
## $ sched_dep_time <int> 515, 529, 540, 545, 600, 558, 600, 600, 600, 600, 600, …
## $ dep_delay      <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1…
## $ arr_time       <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849,…
## $ sched_arr_time <int> 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851,…
## $ arr_delay      <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -1…
## $ carrier        <chr> "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", "…
## $ flight         <int> 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79, 301, 4…
## $ tailnum        <chr> "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N394…
## $ origin         <chr> "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR", "LGA",…
## $ dest           <chr> "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL", "IAD",…
## $ air_time       <dbl> 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, 1…
## $ distance       <dbl> 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733, …
## $ hour           <dbl> 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6…
## $ minute         <dbl> 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0…
## $ time_hour      <dttm> 2013-01-01 05:00:00, 2013-01-01 05:00:00, 2013-01-01 0…

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:

ABCDEFGHIJ0123456789
time_hour
<dttm>
arr_delay
<dbl>
dep_delay
<dbl>
carrier
<chr>
origin
<chr>
dest
<chr>
flight
<int>
tailnum
<chr>
2013-05-04 07:00:00-11-69EEWRATL3633N170PQ
2013-05-01 11:00:00-24-59EEWRATL4194N170PQ
2013-05-03 09:00:0015-69EEWRATL4362N170PQ
2013-05-02 09:00:00-5-69EEWRATL4362N232PQ
2013-12-12 17:00:0013109EEWRCVG3323N8506C
2013-12-05 17:00:00009EEWRCVG3323NA
2013-12-18 17:00:00-1319EEWRCVG3335N8412F
2013-12-11 17:00:00-7-89EEWRCVG3335N8505Q
2013-12-13 17:00:0030319EEWRCVG3335N8672A
2013-12-16 17:00:00-30-149EEWRCVG3335N8877A

Let us proceed with our questions:

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

ABCDEFGHIJ0123456789
carrier
<chr>
month
<mth>
mean_arr_delay
<dbl>
9E2013 Jan9.60394151
9E2013 Feb7.61343386
9E2013 Mar1.88567916
9E2013 Apr5.06551952
9E2013 May9.85294118
9E2013 Jun19.73903967
9E2013 Jul21.29785810
9E2013 Aug5.01098901
9E2013 Sep-6.80909091
9E2013 Oct-1.31500299
01020−5051015−20020Jan 2013Apr 2013Jul 2013Oct 2013−50510−505010205101520Jan 2013Apr 2013Jul 2013Oct 2013−1001020−30−20−10010102030050100Jan 2013Apr 2013Jul 2013Oct 2013010200102010203040−50510Jan 2013Apr 2013Jul 2013Oct 20130102030
Average Monthly Arrival Delays by Carrier9EAAASB6DLEVF9FLHAMQOOUAUSVXWNYV

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

010002000010002000Jan 2013Mar 2013May 2013Jul 2013Sep 2013Nov 2013050010001500
LegendEWRJFKLGATime Series PlotEWRJFKLGA

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

ABCDEFGHIJ0123456789
origin
<chr>
month
<mth>
mean_monthly_delay
<dbl>
EWR2013 Jan27.004852
EWR2013 Feb20.613814
EWR2013 Mar27.653647
EWR2013 Apr30.710949
EWR2013 May20.239992
EWR2013 Jun37.774251
EWR2013 Jul36.393317
EWR2013 Aug19.836181
EWR2013 Sep2.544921
EWR2013 Oct11.137272

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/
LS0tDQp0aXRsZTogIlRpbWUgU2VyaWVzIGluIFIiDQpzdWJ0aXRsZTogIiINCmF1dGhvcjogQXJ2aW5kIFZlbmthdGFkcmkNCmFmZmlsaWF0aW9uOiANCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgdG9jX2RlcHRoOiAyDQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCmFic3RyYWN0OiBQYXJ0IG9mIG15IG9ubGluZSBjb3Vyc2UgYFIgZm9yIEFydGlzdHMgYW5kIERlc2lnbmVyc2AgdG8gdGVhY2ggUiB1c2luZyBNZXRhcGhvcnMgYW5kIENvZGUuDQotLS0NCg0KIyBJbnRyb2R1Y3Rpb24NCg0KIyBHb2Fscw0KDQpBdCB0aGUgZW5kIG9mIHRoaXMgTGFiIHNlc3Npb24sIHdlIHdpbGwgYmUgYWJsZSB0bzoNCg0KLSAgIFVuZGVyc3RhbmQgdGltZSBzZXJpZXMgZGF0YSBhbmQgZGF0YSBzdHJ1Y3R1cmVzDQotICAgQ3JlYXRlIFRpbWUgU2VyaWVzIFZpc3VhbGl6YXRpb25zDQotICAgUGVyZm9ybSBtb2RlbGxpbmcgdGFza3Mgb24gVGltZSBTZXJpZXMgRGF0YQ0KLSAgIENhbGN1bGF0ZSBhbmQgZGVwaWN0IEF2ZXJhZ2VzLCBTZWFzb25zLCBUcmVuZHMgaW4gVGltZSBTZXJpZXMNCi0gICBQZXJmb3JtIEZvcmVjYXN0aW5nIHdpdGggVGltZSBTZXJpZXMNCg0KIyBQYWNrYWdlcw0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nID0gRkFMU0UpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKSAjTWVzc2luZyB3aXRoIERhdGVzDQpsaWJyYXJ5KHRzaWJibGUpICMgVGltZS1hd2FyZSBkYXRhZnJhbWVzIGFuZCB0aWJibGVzDQpsaWJyYXJ5KHRzaWJibGVkYXRhKQ0KbGlicmFyeShmZWFzdHMpICMgdmlzdWFsaXNpbmcgdGhlIGRhdGEgYW5kIGV4dHJhY3RpbmcgdGltZSBzZXJpZXMgZmVhdHVyZXMuDQpsaWJyYXJ5KGZhYmxlKSAjIGZvcmVjYXN0aW5nIG1ldGhvZHMgZm9yIHRzaWJibGUsIHN1Y2ggYXMgQVJJTUEgYW5kIEVUUy4NCmxpYnJhcnkoZmFibGV0b29scykgIyAgbW9kZWxsaW5nIGluZnJhc3RydWN0dXJlIHRvIGVhc2UgdGhlIHByb2dyYW1taW5nIHdpdGggdHNpYmJsZS4NCmxpYnJhcnkodGltZXRrKSAjIFBsb3R0aW5nIGFuZCBBbmFseXNpbmcgVGltZSBTZXJpZXMgRGF0YQ0KbGlicmFyeShnZ2Zvcm11bGEpDQoNCiMjIyMjIw0KbGlicmFyeShwcm9waGV0KQ0KbGlicmFyeShDYXVzYWxJbXBhY3QpDQoNCmBgYA0KDQojIFRoZSBgdHNpYmJsZWAgZGF0YSBmb3JtYXQNCg0KVEJXLiBUbyBiZSB3cml0dGVuIHVwLg0KDQojIyBDYXNlIFN0dWR5IC0xOiBXYWxtYXJ0IFNhbGVzIERhdGFzZXQgZnJvbSB0aW1ldGsNCg0KTGV0IHVzIGluc3BlY3Qgd2hhdCBkYXRhc2V0cyBhcmUgYXZhaWxhYmxlIGluIHRoZSBwYWNrYWdlIHRpbWV0ay4gVHlwZQ0KZGF0YShwYWNrYWdlID0gInRpbWV0ayIpIGluIHlvdXIgQ29uc29sZSB0byBzZWUgd2hhdCBkYXRhc2V0cyBhcmUNCmF2YWlsYWJsZS4NCg0KTGV0IHVzIGNob29zZSB0aGUgV2FsbWFydCBTYWxlcyBkYXRhc2V0LiBTZWUgaGVyZSBmb3IgbW9yZSBkZXRhaWxzOg0KV2FsbWFydCBSZWNydWl0aW5nIC0gU3RvcmUgU2FsZXMgRm9yZWNhc3RpbmcgXHxLYWdnbGUNCg0KYGBge3J9DQoNCmRhdGEoIndhbG1hcnRfc2FsZXNfd2Vla2x5IikNCndhbG1hcnRfc2FsZXNfd2Vla2x5DQpnbGltcHNlKHdhbG1hcnRfc2FsZXNfd2Vla2x5KQ0KDQojIFRyeSB0aGlzIGluIHlvdXIgQ29uc29sZQ0KIyBoZWxwKCJ3YWxtYXJ0X3NhbGVzX3dlZWtseSIpDQoNCmBgYA0KDQpUaGUgZGF0YSBpcyBkZXNjcmliZWQgYXM6DQoNCkEgdGliYmxlOiA5LDc0MyB4IDMNCg0KLSAgIGlkIEZhY3Rvci4gVW5pcXVlIHNlcmllcyBpZGVudGlmaWVyICg0IHRvdGFsKQ0KLSAgIFN0b3JlIE51bWVyaWMuIFN0b3JlIElELg0KLSAgIERlcHQgTnVtZXJpYy4gRGVwYXJ0bWVudCBJRC4NCi0gICBEYXRlIERhdGUuIFdlZWtseSB0aW1lc3RhbXAuDQotICAgV2Vla2x5X1NhbGVzIE51bWVyaWMuIFNhbGVzIGZvciB0aGUgZ2l2ZW4gZGVwYXJ0bWVudCBpbiB0aGUgZ2l2ZW4NCiAgICBzdG9yZS4NCi0gICBJc0hvbGlkYXkgTG9naWNhbC4gV2hldGhlciB0aGUgd2VlayBpcyBhICJzcGVjaWFsIiBob2xpZGF5IGZvciB0aGUNCiAgICBzdG9yZS4NCi0gICBUeXBlIENoYXJhY3Rlci4gVHlwZSBpZGVudGlmaWVyIG9mIHRoZSBzdG9yZS4NCi0gICBTaXplIE51bWVyaWMuIFN0b3JlIHNxdWFyZS1mb290YWdlDQotICAgVGVtcGVyYXR1cmUgTnVtZXJpYy4gQXZlcmFnZSB0ZW1wZXJhdHVyZSBpbiB0aGUgcmVnaW9uLg0KLSAgIEZ1ZWxfUHJpY2UgTnVtZXJpYy4gQ29zdCBvZiBmdWVsIGluIHRoZSByZWdpb24uDQotICAgTWFya0Rvd24xLCBNYXJrRG93bjIsIE1hcmtEb3duMywgTWFya0Rvd240LCBNYXJrRG93bjUgTnVtZXJpYy4NCiAgICBBbm9ueW1pemVkIGRhdGEgcmVsYXRlZCB0byBwcm9tb3Rpb25hbCBtYXJrZG93bnMgdGhhdCBXYWxtYXJ0IGlzDQogICAgcnVubmluZy4gTWFya0Rvd24gZGF0YSBpcyBvbmx5IGF2YWlsYWJsZSBhZnRlciBOb3YgMjAxMSwgYW5kIGlzIG5vdA0KICAgIGF2YWlsYWJsZSBmb3IgYWxsIHN0b3JlcyBhbGwgdGhlIHRpbWUuIEFueSBtaXNzaW5nIHZhbHVlIGlzIG1hcmtlZA0KICAgIHdpdGggYW4gTkEuDQotICAgQ1BJIE51bWVyaWMuIFRoZSBjb25zdW1lciBwcmljZSBpbmRleC4NCi0gICBVbmVtcGxveW1lbnQgTnVtZXJpYy4gVGhlIHVuZW1wbG95bWVudCByYXRlIGluIHRoZSByZWdpb24uDQoNCk5PVEU6IDEuIFRoaXMgaXMgc3RpbGwgYSBkYXRhLmZyYW1lLCB3aXRoIGEgdGltZS1vcmllbnRlZCB2YXJpYWJsZSBvZg0KY291cnNlLCBhbmQgbm90IHlldCBhIHRpbWUtc2VyaWVzIG9iamVjdC4gTm90ZSB0aGF0IHRoaXMgZGF0YSBmcmFtZSBoYXMNCnRoZSBZTUQgY29sdW1ucyByZXBlYXRlZCBmb3IgZWFjaCBEZXB0LiAyLiBUaGUgRGF0ZSBjb2x1bW4gaGFzIHJlcGVhdGVkDQplbnRyaWVzIGZvciBlYWNoIERlcHQhIFRvIGRlYWwgd2l0aCB0aGlzIHJlcGV0aXRpb24sIHdlIHdpbGwgYWx3YXlzIG5lZWQNCnRvIHNwbGl0IHRoZSBXZWVrbHlfU2FsZXMgYnkgdGhlIERlcHQgY29sdW1uIGJlZm9yZSB3ZSBwbG90IG9yIGFuYWx5emUuDQoNClNpbmNlIG91ciBzYWxlcyBhcmUgd2Vla2x5LCB3ZSB3aWxsIGNvbnZlcnQgRGF0ZSB0byB5ZWFyd2VlayBmb3JtYXQ6DQoNCmBgYHtyfQ0Kd2FsbWFydF90aW1lIDwtIHdhbG1hcnRfc2FsZXNfd2Vla2x5ICU+JSANCiAgDQogIGFzX3RzaWJibGUoaW5kZXggPSBEYXRlLCAjIFRpbWUgVmFyaWFibGUgDQogICAgICAgICAgICAgDQogIGtleSA9IERlcHQgKSANCiMgSWRlbnRpZmllcyB1bmlxdWUgInN1YmplY3QiIHdobyBhcmUgbWVhc3VyZXMgDQojIEFsbCBvdGhlciB2YXJpYWJsZXMgc3VjaCBhcyBXZWVrbHlfc2FsZXMgYmVjb21lICJtZWFzdXJlZCB2YXJpYWJsZSIgDQojIEVhY2ggb2JzZXJ2YXRpb24gc2hvdWxkIGJlIHVuaXF1ZWx5IGlkZW50aWZpZWQgYnkgaW5kZXggYW5kIGtleQ0KICANCndhbG1hcnRfdGltZQ0KYGBgDQoNCiMjIyBCYXNpYyBUaW1lIFNlcmllcyBQbG90cw0KDQpUaGUgZWFzaWVzdCB3YXkgaXMgdG8gdXNlIGF1dG9wbG90IGZyb20gdGhlIGZlYXN0cyBwYWNrYWdlLiBZb3UgbWF5IG5lZWQNCnRvIHNwZWNpZnkgdGhlIGFjdHVhbCBtZWFzdXJlZCB2YXJpYWJsZSwgaWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZQ0KbnVtZXJpY2FsIGNvbHVtbjoNCg0KYGBge3IgZmVhc3RzLWJhc2ljLXBsb3R9DQoNCmF1dG9wbG90KHdhbG1hcnRfdGltZSwudmFycyA9IFdlZWtseV9TYWxlcykNCmBgYA0KDQpUaGUgUiBwYWNrYWdlIGB0aW1ldGtgIGdpdmVzIHVzIGludGVyYWN0aXZlIHBsb3RzIHRoYXQgbWF5IGJlIG1vcmUNCmV2b2NhdGl2ZSB0aGFuIHRoZSBzdGF0aWMgcGxvdCBhYm92ZS4gVGhlIGJhc2ljIHBsb3QgZnVuY3Rpb24gd2l0aA0KYHRpbWV0a2AgaXMgYHBsb3RfdGltZV9zZXJpZXNgLiBUaGVyZSBhcmUgYXJndW1lbnRzIGZvciB0aGUgZGF0ZQ0KdmFyaWFibGUsIHRoZSB2YWx1ZSB5b3Ugd2FudCB0byBwbG90LCBjb2xvdXJzLCBncm91cGluZ3MgZXRjLg0KDQpMZXQgdXMgZXhwbG9yZSB0aGlzIGRhdGFzZXQgdXNpbmcgYHRpbWV0a2AsIHVzaW5nIG91ciB0cnVzdGVkIG1ldGhvZCBvZg0KYXNraW5nIFF1ZXN0aW9uczoNCg0KKipRLjEgSG93IGFyZSB0aGUgd2Vla2x5IHNhbGVzIGRpZmZlcmVudCBmb3IgZWFjaCBEZXBhcnRtZW50PyoqDQoNClRoZXJlIGFyZSBgciB3YWxtYXJ0X3NhbGVzX3dlZWtseSAlPiUgZGlzdGluY3QoRGVwdCkgJT4lIGNvdW50KClgIG51bWJlcg0Kb2YgRGVwYXJ0bWVudHMuIFNvIHdlIHNob3VsZCBiZSBmaW5lIHBsb3R0aW5nIHRoZW0gYW5kIGFsc28gZmFjZXR0aW5nDQp3aXRoIHRoZW0sIGFzIHdlIHdpbGwgc2VlIGluIGEgYml0Og0KDQpgYGB7cn0NCndhbG1hcnRfdGltZSAlPiUgDQogIHRpbWV0azo6cGxvdF90aW1lX3NlcmllcyhEYXRlLCBXZWVrbHlfU2FsZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmNvbG9yX3ZhciA9IERlcHQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmxlZ2VuZF9zaG93ID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAudGl0bGUgPSAiV2FsbWFydCBTYWxlcyBEYXRhIGJ5IERlcGFydG1lbnQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLnNtb290aCA9IEZBTFNFKQ0KYGBgDQoNCioqUS4yLiBXaGF0IGRvIHRoZSBzYWxlcyBwZXIgRGVwdCBsb29rIGxpa2UgZHVyaW5nIHRoZSBtb250aCBvZiBEZWNlbWJlcg0KKENocmlzdG1hcyB0aW1lKSBpbiAyMDEyPyBTaG93IHRoZSBpbmRpdmlkdWFsIERlcHRzIGFzIGZhY2V0cy4qKg0KDQpXZSBjYW4gb2YgY291cnNlIHpvb20gaW50byB0aGUgaW50ZXJhY3RpdmUgcGxvdCBhYm92ZSwgYnV0IGlmIHdlIHdlcmUgdG8NCnBsb3QgaXQgYW55d2F5Og0KDQpgYGB7ciBmaWx0ZXJpbmctYnktdGltZX0NCg0KIyBPbmx5IGluY2x1ZGUgcm93cyBmcm9tIDEgdG8gRGVjZW1iZXIgMzEsIDIwMTENCiMgRGF0YSBnb2VzIG9ubHkgdXAgdG8gT2N0IDIwMTINCndhbG1hcnRfdGltZSAlPiUNCiAgDQogICMgRWFjaCBzaWRlIG9mIHRoZSB0aW1lX2Zvcm11bGEgYmVsb3cgaXMgc3BlY2lmaWVkIGFzIHRoZSBjaGFyYWN0ZXINCiAgIyAnWVlZWS1NTS1ERCBISDpNTTpTUycsDQogIA0KICB0aW1ldGs6OmZpbHRlcl9ieV90aW1lKC5kYXRlX3ZhciA9IERhdGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgLnN0YXJ0X2RhdGUgPSAiMjAxMS0xMi0wMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgLmVuZF9kYXRlID0gIjIwMTEtMTItMzEiKSAlPiUNCiAgDQogIHBsb3RfdGltZV9zZXJpZXMoDQogICAgLmRhdGVfdmFyID0gRGF0ZSwNCiAgICAudmFsdWUgPSBXZWVrbHlfU2FsZXMsDQogICAgLmNvbG9yX3ZhciA9IERlcHQsDQogICAgLmZhY2V0X3ZhcnMgPSBEZXB0LA0KICAgIC5mYWNldF9uY29sID0gMiwNCiAgICAuc21vb3RoID0gRkFMU0UNCiAgKSAjIE9ubHkgNCBwb2ludHMgcGVyIGdyYXBoDQpgYGANCg0KQ2xlYXJseSB0aGUgInVuZm9ydHVuYXRlIiBEZXB0IzEzIGhhcyBzZWVuIHNvbWV0aGluZyBvZiBhIENocmlzdG1hcyBkcm9wDQppbiBzYWxlcywgYXMgaGFzIERlcHQjMzggISBUaGUgcmVzdCwgYWxsIGlzIHdlbGwsIGl0IHNlZW1zLi4uDQoNClRvbyBtdWNoIG5vaXNlPyBIb3cgYWJvdXQgc29tZSBhdmVyYWdpbmc/DQoNCioqUS4zIEhvdyBkbyB3ZSBzbW9vdGggb3V0IHNvbWUgb2YgdGhlIHZhcmlhdGlvbnMgaW4gdGhlIHRpbWUgc2VyaWVzIHRvDQpiZSBhYmxlIHRvIHVuZGVyc3RhbmQgaXQgYmV0dGVyPyoqDQoNClNvbWV0aW1lcyB0aGVyZSBpcyB0b28gbXVjaCBub2lzZSBpbiB0aGUgdGltZSBzZXJpZXMgb2JzZXJ2YXRpb25zIGFuZCB3ZQ0Kd2FudCB0byB0YWtlIHdoYXQgaXMgY2FsbGVkIGEgKnJvbGxpbmcgYXZlcmFnZSouIEZvciB0aGlzIHdlIHdpbGwgdXNlDQp0aGUgZnVuY3Rpb24gYHRpbWV0azo6c2xpZGlmeWAgdG8gY3JlYXRlIGFuIGF2ZXJhZ2luZyBmdW5jdGlvbiBvZiBvdXINCmNob2ljZSwgYW5kIHRoZW4gYXBwbHkgaXQgdG8gdGhlIHRpbWUgc2VyaWVzIHVzaW5nIHJlZ3VsYXINCmBkcGx5cjo6bXV0YXRlYC4gTGV0J3MgdGFrZSB0aGUgYXZlcmFnZSBvZiBTYWxlcyBmb3IgZWFjaCBtb250aCBpbiBlYWNoDQpEZXBhcnRtZW50LiBPdXIgKipmdW5jdGlvbioqIHdpbGwgYmUgbmFtZWQgInJvbGxpbmdfYXZnX21vbnRoIjoNCg0KYGBge3IgIGF2ZXJhZ2luZy1mdW5jdGlvbn0NCnJvbGxpbmdfYXZnX21vbnRoID0gc2xpZGlmeSgucGVyaW9kID0gNCwgIyBldmVyeSA0IHdlZWtzIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5mID0gbWVhbiwgIyBUaGUgZnVuY3Rpb24gdG8gYXZlcmFnZSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuYWxpZ24gPSAiY2VudGVyIiwgIyBBbGlnbmVkIHdpdGggbWlkZGxlIG9mIG1vbnRoIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5wYXJ0aWFsID0gVFJVRSkgIyBUbyBjYXRjaCBhbnkgbGVmdG92ZXIgaGFsZiB3ZWVrcyByb2xsaW5nX2F2Z19tb250aA0KYGBgDQoNCk9LLCBzbGlkaWZ5IGNyZWF0ZXMgYSBmdW5jdGlvbiEgTGV0J3MgYXBwbHkgaXQgdG8gdGhlIFdhbG1hcnQgU2FsZXMgdGltZQ0Kc2VyaWVzLi4uDQoNCmBgYHtyIGF2ZXJhZ2luZ30NCndhbG1hcnRfdGltZSAlPiUgIyBncm91cF9ieShEZXB0KSAlPiUNCiAgbXV0YXRlKGF2Z19tb250aGx5X3NhbGVzID0gcm9sbGluZ19hdmdfbW9udGgoV2Vla2x5X1NhbGVzKSkgJT4lDQogICMgdW5ncm91cCgpICU+JQ0KICB0aW1ldGs6OnBsb3RfdGltZV9zZXJpZXMoRGF0ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGF2Z19tb250aGx5X3NhbGVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmNvbG9yX3ZhciA9IERlcHQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAuc21vb3RoID0gRkFMU0UpDQpgYGANCg0KR3JhcGhzIGFyZSBzbW9vdGhlciBub3cuIE5lZWQgdG8gY2hlY2sgd2hldGhlciB0aGUgYXZlcmFnaW5nIHdhcyBkb25lIG9uDQphIHBlci1EZXB0IGJhc2lzLi4uc2hvdWxkIHdlIGhhdmUgaGFkIGEgYGdyb3VwX2J5KERlcHQpYCBiZWZvcmUgdGhlDQphdmVyYWdpbmcsIGFuZCBgdW5ncm91cCgpYCBiZWZvcmUgcGxvdHRpbmc/IFRyeSBpdCAhIQ0KDQojIyMgRGVjb21wb3NpbmcgVGltZSBTZXJpZXM6IFRyZW5kcywgU2Vhc29uYWwgUGF0dGVybnMsIGFuZCBDeWNsZXMNCg0KRWFjaCBkYXRhIHBvaW50ICgkWV90JCkgYXQgdGltZSAkdCQgaW4gYSBUaW1lIFNlcmllcyBjYW4gYmUgZXhwcmVzc2VkIGFzDQplaXRoZXIgYSBzdW0gb3IgYSBwcm9kdWN0IG9mIDQgY29tcG9uZW50cywgbmFtZWx5LCBTZWFzb25hbGl0eSgkU190JCksDQpUcmVuZCgkVF90JCksIEN5Y2xpYywgYW5kIEVycm9yKCRlX3QkKSAoYS5rLmEgV2hpdGUgTm9pc2UpLg0KDQotICAgVHJlbmQ6IHBhdHRlcm4gZXhpc3RzIHdoZW4gdGhlcmUgaXMgYSBsb25nLXRlcm0gaW5jcmVhc2Ugb3IgZGVjcmVhc2UNCiAgICBpbiB0aGUgZGF0YS4NCi0gICBTZWFzb25hbDogcGF0dGVybiBleGlzdHMgd2hlbiBhIHNlcmllcyBpcyBpbmZsdWVuY2VkIGJ5IHNlYXNvbmFsDQogICAgZmFjdG9ycyAoZS5nLiwgdGhlIHF1YXJ0ZXIgb2YgdGhlIHllYXIsIHRoZSBtb250aCwgb3IgZGF5IG9mIHRoZQ0KICAgIHdlZWspLg0KLSAgIEN5Y2xpYzogcGF0dGVybiBleGlzdHMgd2hlbiBkYXRhIGV4aGliaXQgcmlzZXMgYW5kIGZhbGxzIHRoYXQgYXJlDQogICAgbm90IG9mIGZpeGVkIHBlcmlvZCAoZHVyYXRpb24gdXN1YWxseSBvZiBhdCBsZWFzdCAyIHllYXJzKS4NCi0gICBFcnJvciBvciBOb2lzZTogUmFuZG9tIGNvbXBvbmVudA0KDQpEZWNvbXBvc2luZyBub24tc2Vhc29uYWwgZGF0YSBtZWFucyBicmVha2luZyBpdCB1cCBpbnRvIHRyZW5kIGFuZA0KaXJyZWd1bGFyIGNvbXBvbmVudHMuIFRvIGVzdGltYXRlIHRoZSB0cmVuZCBjb21wb25lbnQgb2YgYSBub24tc2Vhc29uYWwNCnRpbWUgc2VyaWVzIHRoYXQgY2FuIGJlIGRlc2NyaWJlZCB1c2luZyBhbiBhZGRpdGl2ZSBtb2RlbCwgaXQgaXMgY29tbW9uDQp0byB1c2UgYSBzbW9vdGhpbmcgbWV0aG9kLCBzdWNoIGFzIGNhbGN1bGF0aW5nIHRoZSBzaW1wbGUgbW92aW5nIGF2ZXJhZ2UNCm9mIHRoZSB0aW1lIHNlcmllcy4NCg0KYHRpbWV0a2AgaGFzIHRoZSBhYmlsaXR5IHRvIGFjaGlldmUgdGhpczogTGV0IHVzIHBsb3QgdGhlIHRyZW5kLA0Kc2Vhc29uYWwsIGN5Y2xpYyBhbmQgaXJyZWd1bGFyIGFzcGVjdHMgb2YgV2Vla2x5X1NhbGVzIGZvciBEZXB0IDM4Og0KDQpgYGB7ciBkZWNvbXBvc2UtdGltZS1zZXJpZXN9DQp3YWxtYXJ0X3RpbWUgJT4lIGZpbHRlcihEZXB0ID09ICIzOCIpICU+JSANCiAgdGltZXRrOjpwbG90X3N0bF9kaWFnbm9zdGljcyguZGF0ZV92YXIgPSBEYXRlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAudmFsdWUgPSBXZWVrbHlfU2FsZXMpDQoNCmBgYA0KDQpXZSBjYW4gZG8gdGhpcyBmb3IgYWxsIERlcHQgdXNpbmcgYGZhYmxlYCBhbmQgYGZhYmxldG9vbHNgOg0KDQpgYGB7ciBEZWNvbXBvc2luZ190cmVuZHN9DQp3YWxtYXJ0X2RlY29tcG9zZWQgPC0gd2FsbWFydF90aW1lICU+JQ0KICANCiAgIyBJZiB3ZSB3YW50IHRvIGZpbHRlciwgd2UgZG8gaXQgaGVyZSAjIGZpbHRlcihEZXB0ID09ICIzOCIpICU+JSAjDQogIGZhYmxldG9vbHM6Om1vZGVsKHN0bCA9IFNUTChXZWVrbHlfU2FsZXMpKQ0KDQpmYWJsZXRvb2xzOjpjb21wb25lbnRzKHdhbG1hcnRfZGVjb21wb3NlZCkNCg0KYXV0b3Bsb3QoY29tcG9uZW50cygod2FsbWFydF9kZWNvbXBvc2VkKSkpDQoNCmBgYA0KDQojIyMgQ2FzZSBTdHVkeS0yOiBEYXRhc2V0IGZyb20gbnljZmxpZ2h0czEzDQoNCkxldCB1cyB0cnkgdGhlIGZsaWdodHMgZGF0YXNldCBmcm9tIHRoZSBwYWNrYWdlIGBueWNmbGlnaHRzMTNgLiBUcnkNCmBkYXRhKHBhY2thZ2UgPSAibnljZmxpZ2h0czEzIilgIGluIHlvdXIgQ29uc29sZS4NCg0KV2UgaGF2ZSB0aGUgZm9sbG93aW5nIGRhdGFzZXRzIGluIGBueWNmbGlnaHRzMTNgOg0KDQotICAgYWlybGluZXMgQWlybGluZSBuYW1lcy4NCi0gICBhaXJwb3J0cyBBaXJwb3J0IG1ldGFkYXRhDQotICAgZmxpZ2h0cyBGbGlnaHRzIGRhdGENCi0gICBwbGFuZXMgUGxhbmUgbWV0YWRhdGEuDQotICAgd2VhdGhlciBIb3VybHkgd2VhdGhlciBkYXRhDQoNCkxldCB1cyBhbmFseXplIHRoZSBmbGlnaHRzIGRhdGE6DQoNCmBgYHtyfQ0KZGF0YSgiZmxpZ2h0cyIsIHBhY2thZ2UgPSAibnljZmxpZ2h0czEzIikNCmdsaW1wc2UoZmxpZ2h0cykNCmBgYA0KDQpXZSBoYXZlIHRpbWUtcmVsYXRlZCBjb2x1bW5zOyBBcGFydCBmcm9tIHllYXIsIG1vbnRoLCBkYXkgd2UgaGF2ZQ0KYHRpbWVfaG91cmA7IGFuZCB0aW1lLWV2ZW50IG51bWVyaWNhbCBkYXRhIHN1Y2ggYXMgYGFycl9kZWxheWAgKGFycml2YWwNCmRlbGF5KSBhbmQgYGRlcF9kZWxheWAgKGRlcGFydHVyZSBkZWxheSkuIFdlIGFsc28gaGF2ZSBjYXRlZ29yaWNhbCBkYXRhDQpzdWNoIGFzIGBjYXJyaWVyYCwgYG9yaWdpbmAsIGBkZXN0YCwgYGZsaWdodGAgYW5kIGB0YWlsbnVtYCBvZiB0aGUNCmFpcmNyYWZ0LiBJdCBpcyBhbHNvIGEgbGFyZ2UgZGF0YXNldCBjb250YWluaW5nIDMzMEsgZW50cmllcy4gRW5vdWdoIHRvDQpwbGF5IHdpdGghIQ0KDQpMZXQgdXMgcmVwbGFjZSB0aGUgTkFzIGluIGBhcnJfZGVsYXlgIGFuZCBgZGVwX2RlbGF5YCB3aXRoIHplcm9lcyBmb3INCm5vdywgYW5kIGNvbnZlcnQgaXQgaW50byBhIHRpbWUtc2VyaWVzIG9iamVjdCB3aXRoIGB0c2liYmxlYDoNCg0KYGBge3J9DQpmbGlnaHRzX2RlbGF5X3RzIDwtIGZsaWdodHMgJT4lDQogIG11dGF0ZShhcnJfZGVsYXkgPSByZXBsYWNlX25hKGFycl9kZWxheSwgMCksDQogICAgICAgICBkZXBfZGVsYXkgPSByZXBsYWNlX25hKGRlcF9kZWxheSwgMCkpICU+JQ0KICBzZWxlY3QodGltZV9ob3VyLA0KICAgICAgICAgYXJyX2RlbGF5LA0KICAgICAgICAgZGVwX2RlbGF5LA0KICAgICAgICAgY2FycmllciwNCiAgICAgICAgIG9yaWdpbiwNCiAgICAgICAgIGRlc3QsDQogICAgICAgICBmbGlnaHQsDQogICAgICAgICB0YWlsbnVtKSAlPiUNCiAgdHNpYmJsZTo6YXNfdHNpYmJsZSgNCiAgICBpbmRleCA9IHRpbWVfaG91ciwNCiAgICAjIEFsbCB0aGUgcmVtYWluaW5nIGlkZW50aWZ5IHVuaXF1ZSBlbnRyaWVzDQogICAgIyBBbG9uZyB3aXRoIGluZGV4ICMgTWFueSBvZiB0aGVzZSB2YXJpYWJsZXMgYXJlIGNvbW1vbg0KICAgICMgTmVlZCBhbGwgdG8gbWFrZSB1bmlxdWUgZW50cmllcyENCiAgICBrZXkgPSBjKGNhcnJpZXIsIG9yaWdpbiwgZGVzdCwgZmxpZ2h0LCB0YWlsbnVtKSwNCiAgICB2YWxpZGF0ZSA9IFRSVUUNCiAgKSAjIE1ha2luZyBzdXJlIGVhY2ggZW50cnkgaXMgdW5pcXVlDQoNCmZsaWdodHNfZGVsYXlfdHMNCmBgYA0KDQpMZXQgdXMgcHJvY2VlZCB3aXRoIG91ciBxdWVzdGlvbnM6DQoNCioqUS4xLiBQbG90IHRoZSBtb250aGx5IGF2ZXJhZ2UgYXJyaXZhbCBkZWxheSBieSBjYXJyaWVyKioNCg0KYGBge3J9DQptZWFuX2Fycl9kZWxheXNfYnlfY2FycmllciA8LSBmbGlnaHRzX2RlbGF5X3RzICU+JQ0KICBncm91cF9ieShjYXJyaWVyKSAlPiUNCiAgaW5kZXhfYnkobW9udGggPSB+IHllYXJtb250aCguKSkgJT4lDQogIA0KICAjIGluZGV4X2J5IHVzZXMgKHllYXIsIHllYXJxdWFydGVyLCB5ZWFybW9udGgsIHllYXJ3ZWVrLCBhcy5EYXRlKQ0KICAjIHRvIGNyZWF0ZSBhIG5ldyBjb2x1bW4gdG8gc2hvdyB0aGUgdGltZS1ncm91cGluZyAjIHllYXIgLyBxdWFydGVyIC8gbW9udGgvIHdlZWssIG9yIGRheeKApg0KICAjIHdoaWNoIElTIGRpZmZlcmVudCBmcm9tIHRyYWRpdGlvbmFsIGRwbHlyDQogIA0KICBzdW1tYXJpc2UobWVhbl9hcnJfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkNCg0KbWVhbl9hcnJfZGVsYXlzX2J5X2NhcnJpZXINCg0KbWVhbl9hcnJfZGVsYXlzX2J5X2NhcnJpZXIgJT4lIA0KICB0aW1ldGs6OnBsb3RfdGltZV9zZXJpZXMoDQogIC5kYXRlX3ZhciA9IG1vbnRoLA0KICAudmFsdWUgPSBtZWFuX2Fycl9kZWxheSwNCiAgLmZhY2V0X3ZhcnMgPSBjYXJyaWVyLA0KICAuc21vb3RoID0gRkFMU0UsDQogICMgLnNtb290aF9kZWdyZWUgPSAxLCANCiAgIyBrZWVwIC5zbW9vdGggb2ZmIHNpbmNlIGl0IHRocm93cyB3YXJuaW5ncyBpZiB0aGVyZSBhcmUgdG9vIGZldyBwb2ludHMNCiAgIyBMaWtlIGlmIHdlIGRvIHF1YXJ0ZXJseSBvciBldmVuIHllYXJseSBzdW1tYXJpZXMNCiAgIyBVc2Ugb25seSBmb3Igc21hbGxlciB2YWx1ZXMgb2YgLnNtb290aF9kZWdyZWUgKDAsMSkNCiAgIw0KICAuZmFjZXRfbmNvbCA9IDQsDQogIC50aXRsZSA9ICJBdmVyYWdlIE1vbnRobHkgQXJyaXZhbCBEZWxheXMgYnkgQ2FycmllciINCikNCmBgYA0KDQoqKlEuMi4gUGxvdCBhIGNhbmRsZXN0aWNrIGNoYXJ0IGZvciB0b3RhbCBmbGlnaHQgZGVsYXlzIGJ5IG1vbnRoIGZvcg0KZWFjaCBjYXJyaWVyKioNCg0KYGBge3J9DQpmbGlnaHRzX2RlbGF5X3RzICU+JSANCiAgbXV0YXRlKHRvdGFsX2RlbGF5ID0gYXJyX2RlbGF5ICsgZGVwX2RlbGF5KSAlPiUgDQogIHRpbWV0azo6cGxvdF90aW1lX3Nlcmllc19ib3hwbG90KA0KICAuZGF0ZV92YXIgPSB0aW1lX2hvdXIsDQogIC52YWx1ZSA9IHRvdGFsX2RlbGF5LA0KICAuY29sb3JfdmFyID0gb3JpZ2luLA0KICAuZmFjZXRfdmFycyA9IG9yaWdpbiwNCiAgLnBlcmlvZCA9ICJtb250aCIsDQogICMgc2FtZSB3YXJuaW5nIGFnYWluIC5zbW9vdGggPSBGQUxTRSANCiAgKQ0KYGBgDQoNCioqUS4yLiBQbG90IGEgaGVhdG1hcCBjaGFydCBmb3IgdG90YWwgZmxpZ2h0IGRlbGF5cyBieSBvcmlnaW4sDQphZ2dyZWdhdGVkIGJ5IG1vbnRoKioNCg0KYGBge3J9DQphdmdfZGVsYXlzX21vbnRoIDwtDQogIGZsaWdodHNfZGVsYXlfdHMgJT4lIA0KICBncm91cF9ieShvcmlnaW4pICU+JSANCiAgbXV0YXRlKHRvdGFsX2RlbGF5ID0gYXJyX2RlbGF5ICsgZGVwX2RlbGF5KSAlPiUgDQogIGluZGV4X2J5KG1vbnRoID0gfiB5ZWFybW9udGgoLikpICU+JSANCiAgDQogICMgaW5kZXhfYnkgdXNlcyAoeWVhciwgeWVhcnF1YXJ0ZXIsIHllYXJtb250aCwgeWVhcndlZWssIGFzLkRhdGUpIA0KICAjIHRvIGNyZWF0ZSBhIG5ldyBjb2x1bW4gdG8gc2hvdyB0aGUgdGltZS1ncm91cGluZyANCiAgIyB5ZWFyIC8gcXVhcnRlciAvIG1vbnRoLyB3ZWVrLCBvciBkYXnigKYgDQogICMgd2hpY2ggSVMgZGlmZmVyZW50IGZyb20gdHJhZGl0aW9uYWwgZHBseXIgDQogIA0KICBzdW1tYXJpc2UobWVhbl9tb250aGx5X2RlbGF5ID0gbWVhbih0b3RhbF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCiAgDQphdmdfZGVsYXlzX21vbnRoIA0KIyB0aHJlZSBvcmlnaW5zIDEyIG1vbnRocyB0aGVyZWZvcmUgMzYgcm93cyANCiMgIyBUc2liYmxlIGluZGV4X2J5ICsgc3VtbWFyaXNlIGFsc28gZ2l2ZXMgdXMgYSBtb250aGAgY29sdW1uDQoNCmdnZm9ybXVsYTo6Z2ZfdGlsZSgNCiAgb3JpZ2luIH4gbW9udGgsDQogIGZpbGwgPSB+IG1lYW5fbW9udGhseV9kZWxheSwNCiAgY29sb3IgPSAiYmxhY2siLA0KICBkYXRhID0gYXZnX2RlbGF5c19tb250aCwNCiAgdGl0bGUgPSAiTWVhbiBGbGlnaHQgRGVsYXlzIGZyb20gTlkgQWlycG9ydHMgaW4gMjAxMyINCikgJT4lDQogIGdmX3RoZW1lKHRoZW1lX2NsYXNzaWMoKSkgJT4lDQogIGdmX3RoZW1lKHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJBIikpICU+JQ0KICANCiAgIyAibWFnbWEiIChvciAiQSIpIGluZmVybm8iIChvciAiQiIpICJwbGFzbWEiIChvciAiQyIpDQogICMgInZpcmlkaXMiIChvciAiRCIpICJjaXZpZGlzIiAob3IgIkUiKQ0KICAjICJyb2NrZXQiIChvciAiRiIpICJtYWtvIiAob3IgIkciKSAidHVyYm8iIChvciAiSCIpDQogIA0KICBnZl90aGVtZShzY2FsZV94X3RpbWUoYnJlYWtzID0gMToxMiwgbGFiZWxzID0gbW9udGguYWJiKSkNCg0KYGBgDQoNCiMjIENvbmNsdXNpb24NCg0KV2UgY2FuIHBsb3QgbW9zdCBvZiB0aGUgY29tbW9uIFRpbWUgU2VyaWVzIFBsb3RzIHdpdGggdGhlIGhlbHAgb2YgdGhlDQpgdGlkeXZlcnRzYCBwYWNrYWdlczogKCBgdHNpYmJsZWAsIGBmZWFzdGAsIGBmYWJsZWAgYW5kIGBmYWJsZXRvb2xzYCkgLCBhbG9uZw0Kd2l0aCBgdGltZXRrYCBhbmQgYGdnZm9ybXVsYWAuDQoNClRoZXJlIGFyZSBvdGhlciBwbG90IHBhY2thZ2VzIHRvIGludmVzdGlnYXRlLCBzdWNoIGFzIGBkeWdyYXBoc2AuDQoNClJlY2FsbCB0aGF0IHdlIGhhdmUgdXNlZCB0aGUgYHRzaWJibGVgIGZvcm1hdCBmb3IgdGhlIGRhdGEuIFRoZXJlIGFyZQ0Kb3RoZXIgZm9ybWF0cyBzdWNoIGFzIGB0c2AsIGB4dHNgIGFuZCBvdGhlcnMgd2hpY2ggYXJlIGFsc28gbWVhbnQgZm9yDQp0aW1lIHNlcmllcyBhbmFseXNpcy4gQnV0IGZvciBvdXIgcHJlc2VudCBwdXJwb3Nlcywgd2UgYXJlIGFibGUgdG8gZG8NCnRoaW5ncyB3aXRoIHRoZSBjYXBhYmlsaXRpZXMgb2YgYHRpbWV0a2AuDQoNCiMjIFJlZmVyZW5jZXMNCg0KMS4gIFJvYiBKIEh5bmRtYW4gYW5kIEdlb3JnZSBBdGhhbmFzb3BvdWxvcy4gKkZvcmVjYXN0aW5nOiBQcmluY2lwbGVzDQogICAgYW5kIFByYWN0aWNlICgzcmQgZWQpKi4gQXZhaWxhYmxlIG9ubGluZSBhdA0KICAgIDxodHRwczovL290ZXh0cy5jb20vZnBwMy8+DQogICAgDQogICAgDQoNCg==