Motivation for studying process mining

Process Data is ubiquitous

Every business employs processes and collects information regarding various activities, be it sales & procurement or recruitment or service workflows. It is imperative to use work flows (whether manual or IT enabled) to track these processes.

There are unresolved concerns in process management

In terms of business process management, two key questions have long troubled the stakeholders since inception of business processes.

  • The first of these is the creation of “current state” processes. Most process exercises in large corporations focus on the “to be” processes, which implies how something should be done, rather than how it is being done. Moreover, understanding the “as is” is justifiably skeptical for the executive given the sticky-note interview juggling it is built upon. Although there has traditionally been no subsitute to first hand experience, with the data collection robustness in modern times there might be a better option.

  • This brings us to the second question which is the lack of two-way connection between business processes and enterprise information systems. While ERP systems do capture process logs, they rarely provide interfaces to work with these logs.

Encouraging ecosystem activity in the field

In 2011, a munich based company called Celonis was founded with Van Der Alst as the scientific advisor. Van der Alst has been the academic force behind research on process mining and is the instructor for arguably the best structured MOOC on the subject. There are also resources like ProM and fluxicon which have been active in the field since 2014.

Since 2016, IEEE has been maintaining the standard data format XES for event logs to enable streamlines process analysis. In 2018, Gartner published a market guide for process mining and hailed it as an enabler towards digital transformation. In April 2019, Harvard business review published an article which describes the need for mining processes and deriving useful insights from process data.

This makes process mining an interesting exploration for data scientists.

What is Process Mining?

Process mining is the analytical discipline of understanding real processes (vis a vis assumed processes) from event logs, thereby enabling comparison of the extracted process with ideal process. It can provide detailed objective & data driven view of how the processes are performing and answer both performance and compliance related questions.

Process mining can be used as a precursor to operational efficiency enhancement programs, resource allocation and process automation guidelines. It is closely related to business process management.

This notebook is intended for getting an introduction to process mining, understanding its basics and provide basic ground work for starting process mining.

Available tools

As software offerings, Celonis, Fluxicon and QPR provide solutions for process discovery. In the open source data science world, R and Python communities have libraries bupaR and pm4py respectively to work on the process data. While this notebook is built on R and works with bupaR, the fundamental priciples are common to other tools

Understanding process data

The essential data capture schema for process mining is an event log. Basically three aspects that should be necessarily captured are 1. Activity - a well understood step in the process, for instance in a IT process, calling help desk is an activity/ 2. Case identifier - the unique identifier to which multiple activities can be tagged and tracked. In the same example of an IT process, case identifier would be serial number assigned to the case. 3. Activity instance identifier (or sequence) - the connect between 1) and 2) above, for instance the starting and ending of phone call would be tagged with the instance identifier.

Time stamp, resource, location and other details are also sometimes available in event logs and can be used for selective filtering.

BUsinesss Process Analytics with R (BUPAR)

Introducing dataset

For this exercise, I have used production data from 4TU data repository. Data is available here

 [1] "Case.ID"            "Activity"           "Resource"           "Start.Timestamp"   
 [5] "Complete.Timestamp" "Span"               "Work.Order..Qty"    "Part.Desc."        
 [9] "Worker.ID"          "Report.Type"        "Qty.Completed"      "Qty.Rejected"      
[13] "Qty.for.MRB"        "Rework"            

The column names from the above data need to be mapped to the standard event log nomenclature. This is done by using the event log creating command. The standard nomencalture includes following column inputs

  • case_id - which is a unique identifier for the whole process sequence,
  • activity_id - a description on the individual activity within a process,
  • activity_instance_id - which instances of activity should be treated as different from others,
  • lifecycle_id - status/outcome of the process,
  • timestamp - time at which logging was done,
  • resource_id - machine/individual responsible for the instance of the process/activity.

However, before that the date time data needs to be brought to a proper date time format. For this, lubridate library is used.

At this point, an activity instance is added to the logs and an event log is created.

prod_data_with_instance<- prod_data %>% 
  group_by(Case.ID) %>%
  mutate(activity_instance = as.character(row_number()))
prod_event = prod_data_with_instance %>%
    eventlog(
        case_id = "Case.ID",
        activity_id = "Activity",
        activity_instance_id = "activity_instance",
        lifecycle_id = "Rework",
        timestamp = "Complete.Timestamp",
        resource_id = "Worker.ID"
    )
prod_event %>% n_activities
[1] 55
prod_event %>% n_cases
[1] 225
prod_event %>% n_traces
[1] 221
prod_event %>% n_resources
[1] 49

There are a total of 55 activities, carried out for 225 cases, in 221 unique ways (traces) by 49 resources.

Activity Understanding & Analysis

Let us start what different level of activities are present and their relative frequency

activity_data<- prod_event %>% 
   activity_frequency(level = "activity")
activity_data_reduced<- activity_data[activity_data$relative>0.02,]
(plot(activity_data_reduced))

This shows that final inspection is the highest frequency activity, which is to be expected. After which the turning and milling quality checks are also high. Lapping and packaging follow up.

Visualizing process maps

Let us start by viewing one of the process maps.

event_reduced<- prod_event[prod_event$Case.ID %in% c("Case 1"),]
event_reduced %>% process_map(type = frequency("relative"))

This shows for one of the cases, how the steps involved in the process play out. As we add more data, we can start to see some of the possible iterations in the process play out. It appears that the steps for this case are 1. Turning and milling 2. Turning and milling Q.C 3. Laser Marking 4. Lapping 5. Round grinding 6. Final Inspection 7. Packing

Self loops represent that more than one logging of the same activity is observed, which might be due to error messages or logging discrepancy.

If we add two more cases to this, more insights start to appear, see below plot for 3 cases.

event_reduced<- prod_event[prod_event$Case.ID %in% c("Case 1","Case 111","Case 104"),]
event_reduced %>% process_map(type = frequency("relative"))

It is clear that one of the cases (1/3) went for turning rather than turning and milling, which also increased a turning Q.C point

Above plot also shows that about 20% of the components directly go from laser marking to end, 8% go from turning to end while about 20% go through the lapping and griding operation before going to packing and then ending.

If we add few more cases to the above plot, it starts to get cumbersome to understand.

Similar to process maps, resource maps are also another way of understanding flow.

event_reduced<- prod_event[prod_event$Case.ID %in% c("Case 1","Case 111","Case 104"),]
event_reduced %>% filter_trace_frequency(percentage = 0.2) %>% resource_map(type = frequency("absolute"))

There are further ways available for exploring processes.

Precedence Matrix

Another way to visualize the process is precdence matrix which shows which steps tend to happen together. In this case since logging seems to have duplication in activity, the plot is not very insightful.

Resource & activity Analysis

Resource specialization and utilization is another key activity which can be helped by process analytics

prod_event %>%
    resource_specialisation("resource") %>% plot()

The above plot for instance shows that ID4932 and ID0937 are generalists, performing upto 15 activity types, ID3641, ID3719 are specialists.

prod_event %>%
    resource_specialisation("activity") %>% plot()

Final inspection, packing, lapping, round griding and turning Q.C are specialized activities perfomred only by one resource.

In terms of activities, it would also be useful to understand which activities are always performed, and which are rare.

prod_event %>% activity_presence() %>% plot()

Trace analysis

Trace length and plots are used to see how much variation is there across cases.

prod_event %>% trace_length() %>% plot()

prod_event %>% trace_length()
      min        q1    median      mean        q3       max    st_dev       iqr 
  1.00000   8.00000  14.00000  20.19111  23.00000 175.00000  20.93024  15.00000 

The plot shows that on an average, 75% of cases have between 8-23 steos, although a maximum of 175 steps have been observed as well. Median number of steps is 14, and average number of steps is 20.

Do all activities start and end at the same points? This can be visualized using bar plots as well

start_activities(prod_event, level = "activity") %>% plot()

While turning and milling seems to be the first operation, machine 6 sees highest rate of starting points.

As expected, most operations end with final inspection or packing.

The above plot shows how many cases can be described with a relatively small number of traces indicating the consistency in the process. Here we have seen that for 225 cases, as high as 221 traces exist, so there is just less consistency. However, this is due to machine number being part of activity description, which means that similar steps are also treated differently.

Consolidation of activities

Consolidation of activities allows relabeling and further high level view of the process.

event_reduced<- prod_event_united[prod_event_united$Case.ID %in% c("Case 1","Case 111","Case 104"),]
event_reduced %>% filter_trace_frequency(percentage = 0.8) %>% process_map(type = frequency("absolute"))

The 10% most infrequent traces are plotted below with united data.

prod_event_united %>% trace_explorer(coverage = 0.1, type = "infrequent")

LS0tDQp0aXRsZTogIlByb2Nlc3MgTWluaW5nIC0gUHJpbWVyIg0KYXV0aG9yOiAiUm9oaXQgUHJ1dGhpIC0gUjJETCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KYWx3YXlzX2FsbG93X2h0bWw6IHllcw0KLS0tDQoNCiMjIyBNb3RpdmF0aW9uIGZvciBzdHVkeWluZyBwcm9jZXNzIG1pbmluZw0KDQo8c3R5bGU+DQpib2R5IHsNCnRleHQtYWxpZ246IGp1c3RpZnl9DQo8L3N0eWxlPg0KDQojIyMjIFByb2Nlc3MgRGF0YSBpcyB1YmlxdWl0b3VzDQpFdmVyeSBidXNpbmVzcyBlbXBsb3lzIHByb2Nlc3NlcyBhbmQgY29sbGVjdHMgaW5mb3JtYXRpb24gcmVnYXJkaW5nIHZhcmlvdXMgYWN0aXZpdGllcywgYmUgaXQgc2FsZXMgJiBwcm9jdXJlbWVudCBvciByZWNydWl0bWVudCBvciBzZXJ2aWNlIHdvcmtmbG93cy4gSXQgaXMgaW1wZXJhdGl2ZSB0byB1c2Ugd29yayBmbG93cyAod2hldGhlciBtYW51YWwgb3IgSVQgZW5hYmxlZCkgdG8gdHJhY2sgdGhlc2UgcHJvY2Vzc2VzLiANCg0KIyMjIyBUaGVyZSBhcmUgdW5yZXNvbHZlZCBjb25jZXJucyBpbiBwcm9jZXNzIG1hbmFnZW1lbnQNCkluIHRlcm1zIG9mIGJ1c2luZXNzIHByb2Nlc3MgbWFuYWdlbWVudCwgdHdvIGtleSBxdWVzdGlvbnMgaGF2ZSBsb25nIHRyb3VibGVkIHRoZSBzdGFrZWhvbGRlcnMgc2luY2UgaW5jZXB0aW9uIG9mIGJ1c2luZXNzIHByb2Nlc3Nlcy4gDQoNCiogVGhlIGZpcnN0IG9mIHRoZXNlIGlzIHRoZSBjcmVhdGlvbiBvZiAiY3VycmVudCBzdGF0ZSIgcHJvY2Vzc2VzLiBNb3N0IHByb2Nlc3MgZXhlcmNpc2VzIGluIGxhcmdlIGNvcnBvcmF0aW9ucyBmb2N1cyBvbiB0aGUgInRvIGJlIiBwcm9jZXNzZXMsIHdoaWNoIGltcGxpZXMgaG93IHNvbWV0aGluZyBzaG91bGQgYmUgZG9uZSwgcmF0aGVyIHRoYW4gaG93IGl0IGlzIGJlaW5nIGRvbmUuIE1vcmVvdmVyLCB1bmRlcnN0YW5kaW5nIHRoZSAiYXMgaXMiIGlzIGp1c3RpZmlhYmx5IHNrZXB0aWNhbCBmb3IgdGhlIGV4ZWN1dGl2ZSBnaXZlbiB0aGUgc3RpY2t5LW5vdGUgaW50ZXJ2aWV3IGp1Z2dsaW5nIGl0IGlzIGJ1aWx0IHVwb24uIEFsdGhvdWdoIHRoZXJlIGhhcyB0cmFkaXRpb25hbGx5IGJlZW4gbm8gc3Vic2l0dXRlIHRvIGZpcnN0IGhhbmQgZXhwZXJpZW5jZSwgd2l0aCB0aGUgZGF0YSBjb2xsZWN0aW9uIHJvYnVzdG5lc3MgaW4gbW9kZXJuIHRpbWVzIHRoZXJlIG1pZ2h0IGJlIGEgYmV0dGVyIG9wdGlvbi4gDQoNCiogVGhpcyBicmluZ3MgdXMgdG8gdGhlIHNlY29uZCBxdWVzdGlvbiB3aGljaCBpcyB0aGUgbGFjayBvZiB0d28td2F5IGNvbm5lY3Rpb24gYmV0d2VlbiBidXNpbmVzcyBwcm9jZXNzZXMgYW5kIGVudGVycHJpc2UgaW5mb3JtYXRpb24gc3lzdGVtcy4gV2hpbGUgRVJQIHN5c3RlbXMgZG8gY2FwdHVyZSBwcm9jZXNzIGxvZ3MsIHRoZXkgcmFyZWx5IHByb3ZpZGUgaW50ZXJmYWNlcyB0byB3b3JrIHdpdGggdGhlc2UgbG9ncy4gDQoNCiMjIyMgRW5jb3VyYWdpbmcgZWNvc3lzdGVtIGFjdGl2aXR5IGluIHRoZSBmaWVsZA0KSW4gMjAxMSwgYSBtdW5pY2ggYmFzZWQgY29tcGFueSBjYWxsZWQgW0NlbG9uaXNdKGh0dHBzOi8vd3d3LmNlbG9uaXMuY29tLykgd2FzIGZvdW5kZWQgd2l0aCBWYW4gRGVyIEFsc3QgYXMgdGhlIHNjaWVudGlmaWMgYWR2aXNvci4gVmFuIGRlciBBbHN0IGhhcyBiZWVuIHRoZSBhY2FkZW1pYyBmb3JjZSBiZWhpbmQgcmVzZWFyY2ggb24gcHJvY2VzcyBtaW5pbmcgYW5kIGlzIHRoZSBpbnN0cnVjdG9yIGZvciBhcmd1YWJseSB0aGUgYmVzdCBzdHJ1Y3R1cmVkIE1PT0Mgb24gdGhlIHN1YmplY3QuIFRoZXJlIGFyZSBhbHNvIHJlc291cmNlcyBsaWtlIFtQcm9NXShodHRwOi8vd3d3LnByb2Nlc3NtaW5pbmcub3JnL3Byb20vc3RhcnQpIGFuZCBbZmx1eGljb25dKGh0dHBzOi8vd3d3LmZsdXhpY29uLmNvbS8pIHdoaWNoIGhhdmUgYmVlbiBhY3RpdmUgaW4gdGhlIGZpZWxkIHNpbmNlIDIwMTQuIA0KDQpTaW5jZSAyMDE2LCBJRUVFIGhhcyBiZWVuIG1haW50YWluaW5nIHRoZSBzdGFuZGFyZCBkYXRhIGZvcm1hdCBbWEVTXShodHRwOi8veGVzLXN0YW5kYXJkLm9yZy8pIGZvciBldmVudCBsb2dzIHRvIGVuYWJsZSBzdHJlYW1saW5lcyBwcm9jZXNzIGFuYWx5c2lzLiBJbiAyMDE4LCBHYXJ0bmVyIHB1Ymxpc2hlZCBhIG1hcmtldCBndWlkZSBmb3IgcHJvY2VzcyBtaW5pbmcgYW5kIGhhaWxlZCBpdCBhcyBhbiBlbmFibGVyIHRvd2FyZHMgZGlnaXRhbCB0cmFuc2Zvcm1hdGlvbi4gSW4gQXByaWwgMjAxOSwgSGFydmFyZCBidXNpbmVzcyByZXZpZXcgcHVibGlzaGVkIGFuIFthcnRpY2xlXShodHRwczovL2hici5vcmcvMjAxOS8wNC93aGF0LXByb2Nlc3MtbWluaW5nLWlzLWFuZC13aHktY29tcGFuaWVzLXNob3VsZC1kby1pdCkgd2hpY2ggZGVzY3JpYmVzIHRoZSBuZWVkIGZvciBtaW5pbmcgcHJvY2Vzc2VzIGFuZCBkZXJpdmluZyB1c2VmdWwgaW5zaWdodHMgZnJvbSBwcm9jZXNzIGRhdGEuIA0KDQpUaGlzIG1ha2VzIHByb2Nlc3MgbWluaW5nIGFuIGludGVyZXN0aW5nIGV4cGxvcmF0aW9uIGZvciBkYXRhIHNjaWVudGlzdHMuIA0KDQoNCiMjIyBXaGF0IGlzIFByb2Nlc3MgTWluaW5nPw0KDQo8c3R5bGU+DQpib2R5IHsNCnRleHQtYWxpZ246IGp1c3RpZnl9DQo8L3N0eWxlPg0KDQpQcm9jZXNzIG1pbmluZyBpcyB0aGUgYW5hbHl0aWNhbCBkaXNjaXBsaW5lIG9mIHVuZGVyc3RhbmRpbmcgcmVhbCBwcm9jZXNzZXMgKHZpcyBhIHZpcyBhc3N1bWVkIHByb2Nlc3NlcykgZnJvbSBldmVudCBsb2dzLCB0aGVyZWJ5IGVuYWJsaW5nIGNvbXBhcmlzb24gb2YgdGhlIGV4dHJhY3RlZCBwcm9jZXNzIHdpdGggaWRlYWwgcHJvY2Vzcy4gSXQgY2FuIHByb3ZpZGUgZGV0YWlsZWQgb2JqZWN0aXZlICYgZGF0YSBkcml2ZW4gdmlldyBvZiBob3cgdGhlIHByb2Nlc3NlcyBhcmUgcGVyZm9ybWluZyBhbmQgYW5zd2VyIGJvdGggcGVyZm9ybWFuY2UgYW5kIGNvbXBsaWFuY2UgcmVsYXRlZCBxdWVzdGlvbnMuIA0KDQpQcm9jZXNzIG1pbmluZyBjYW4gYmUgdXNlZCBhcyBhIHByZWN1cnNvciB0byBvcGVyYXRpb25hbCBlZmZpY2llbmN5IGVuaGFuY2VtZW50IHByb2dyYW1zLCByZXNvdXJjZSBhbGxvY2F0aW9uIGFuZCBwcm9jZXNzIGF1dG9tYXRpb24gZ3VpZGVsaW5lcy4gSXQgaXMgY2xvc2VseSByZWxhdGVkIHRvIGJ1c2luZXNzIHByb2Nlc3MgbWFuYWdlbWVudC4NCg0KDQpUaGlzIG5vdGVib29rIGlzIGludGVuZGVkIGZvciBnZXR0aW5nIGFuIGludHJvZHVjdGlvbiB0byBwcm9jZXNzIG1pbmluZywgdW5kZXJzdGFuZGluZyBpdHMgYmFzaWNzIGFuZCBwcm92aWRlIGJhc2ljIGdyb3VuZCB3b3JrIGZvciBzdGFydGluZyBwcm9jZXNzIG1pbmluZy4gDQoNCiMjIyBBdmFpbGFibGUgdG9vbHMNCg0KPHN0eWxlPg0KYm9keSB7DQp0ZXh0LWFsaWduOiBqdXN0aWZ5fQ0KPC9zdHlsZT4NCg0KQXMgc29mdHdhcmUgb2ZmZXJpbmdzLCBDZWxvbmlzLCBGbHV4aWNvbiBhbmQgUVBSIHByb3ZpZGUgc29sdXRpb25zIGZvciBwcm9jZXNzIGRpc2NvdmVyeS4gSW4gdGhlIG9wZW4gc291cmNlIGRhdGEgc2NpZW5jZSB3b3JsZCwgUiBhbmQgUHl0aG9uIGNvbW11bml0aWVzIGhhdmUgbGlicmFyaWVzIGJ1cGFSIGFuZCBwbTRweSByZXNwZWN0aXZlbHkgdG8gd29yayBvbiB0aGUgcHJvY2VzcyBkYXRhLiBXaGlsZSB0aGlzIG5vdGVib29rIGlzIGJ1aWx0IG9uIFIgYW5kIHdvcmtzIHdpdGggYnVwYVIsIHRoZSBmdW5kYW1lbnRhbCBwcmljaXBsZXMgYXJlIGNvbW1vbiB0byBvdGhlciB0b29scw0KDQojIyMgVW5kZXJzdGFuZGluZyBwcm9jZXNzIGRhdGENCg0KPHN0eWxlPg0KYm9keSB7DQp0ZXh0LWFsaWduOiBqdXN0aWZ5fQ0KPC9zdHlsZT4NCg0KVGhlIGVzc2VudGlhbCBkYXRhIGNhcHR1cmUgc2NoZW1hIGZvciBwcm9jZXNzIG1pbmluZyBpcyBhbiAqZXZlbnQgbG9nKi4gQmFzaWNhbGx5IHRocmVlIGFzcGVjdHMgdGhhdCBzaG91bGQgYmUgbmVjZXNzYXJpbHkgY2FwdHVyZWQgYXJlIA0KMS4gQWN0aXZpdHkgLSBhIHdlbGwgdW5kZXJzdG9vZCBzdGVwIGluIHRoZSBwcm9jZXNzLCBmb3IgaW5zdGFuY2UgaW4gYSBJVCBwcm9jZXNzLCAqY2FsbGluZyBoZWxwIGRlc2sqIGlzIGFuIGFjdGl2aXR5Lw0KMi4gQ2FzZSBpZGVudGlmaWVyIC0gdGhlIHVuaXF1ZSBpZGVudGlmaWVyIHRvIHdoaWNoIG11bHRpcGxlIGFjdGl2aXRpZXMgY2FuIGJlIHRhZ2dlZCBhbmQgdHJhY2tlZC4gSW4gdGhlIHNhbWUgZXhhbXBsZSBvZiBhbiBJVCBwcm9jZXNzLCBjYXNlIGlkZW50aWZpZXIgd291bGQgYmUgc2VyaWFsIG51bWJlciBhc3NpZ25lZCB0byB0aGUgY2FzZS4gDQozLiBBY3Rpdml0eSBpbnN0YW5jZSBpZGVudGlmaWVyIChvciBzZXF1ZW5jZSkgLSB0aGUgY29ubmVjdCBiZXR3ZWVuIDEpIGFuZCAyKSBhYm92ZSwgZm9yIGluc3RhbmNlIHRoZSBzdGFydGluZyBhbmQgZW5kaW5nIG9mIHBob25lIGNhbGwgd291bGQgYmUgdGFnZ2VkIHdpdGggdGhlIGluc3RhbmNlIGlkZW50aWZpZXIuIA0KDQpUaW1lIHN0YW1wLCByZXNvdXJjZSwgbG9jYXRpb24gYW5kIG90aGVyIGRldGFpbHMgYXJlIGFsc28gc29tZXRpbWVzIGF2YWlsYWJsZSBpbiBldmVudCBsb2dzIGFuZCBjYW4gYmUgdXNlZCBmb3Igc2VsZWN0aXZlIGZpbHRlcmluZy4gDQoNCiMjIyBCVXNpbmVzc3MgUHJvY2VzcyBBbmFseXRpY3Mgd2l0aCBSIChCVVBBUikNCg0KYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHBseXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoYnVwYVIpDQoNCmBgYA0KDQojIyMjIEludHJvZHVjaW5nIGRhdGFzZXQNCkZvciB0aGlzIGV4ZXJjaXNlLCBJIGhhdmUgdXNlZCBwcm9kdWN0aW9uIGRhdGEgZnJvbSA0VFUgZGF0YSByZXBvc2l0b3J5LiBEYXRhIGlzIGF2YWlsYWJsZSBbaGVyZV0oaHR0cHM6Ly9kYXRhLjR0dS5ubC9yZXBvc2l0b3J5L3V1aWQ6Njg3MjY5MjYtNWFjNS00ZmFiLWI4NzMtZWU3NmVhNDEyMzk5KSANCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCnByb2RfZGF0YTwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9QcnV0aGlSL0RvY3VtZW50cy8yMDIwL21Mb2dpYy9wcm9jZXNzbWluaW5nL0RhdGFzZXQgZmlsZXMgKDIuMSBNQikvZGF0YS9Qcm9kdWN0aW9uX0RhdGEuY3N2IikNCg0KcHJpbnQoY29sbmFtZXMocHJvZF9kYXRhKSkNCg0KYGBgDQoNClRoZSBjb2x1bW4gbmFtZXMgZnJvbSB0aGUgYWJvdmUgZGF0YSBuZWVkIHRvIGJlIG1hcHBlZCB0byB0aGUgc3RhbmRhcmQgZXZlbnQgbG9nIG5vbWVuY2xhdHVyZS4gVGhpcyBpcyBkb25lIGJ5IHVzaW5nIHRoZSBldmVudCBsb2cgY3JlYXRpbmcgY29tbWFuZC4gVGhlIHN0YW5kYXJkIG5vbWVuY2FsdHVyZSBpbmNsdWRlcyBmb2xsb3dpbmcgY29sdW1uIGlucHV0cw0KDQoqIGNhc2VfaWQgLSB3aGljaCBpcyBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgKndob2xlKiBwcm9jZXNzIHNlcXVlbmNlLA0KKiBhY3Rpdml0eV9pZCAtIGEgZGVzY3JpcHRpb24gb24gdGhlIGluZGl2aWR1YWwgYWN0aXZpdHkgd2l0aGluIGEgcHJvY2VzcywNCiogYWN0aXZpdHlfaW5zdGFuY2VfaWQgLSB3aGljaCBpbnN0YW5jZXMgb2YgYWN0aXZpdHkgc2hvdWxkIGJlIHRyZWF0ZWQgYXMgZGlmZmVyZW50IGZyb20gb3RoZXJzLA0KKiBsaWZlY3ljbGVfaWQgLSBzdGF0dXMvb3V0Y29tZSBvZiB0aGUgcHJvY2VzcywNCiogdGltZXN0YW1wIC0gdGltZSBhdCB3aGljaCBsb2dnaW5nIHdhcyBkb25lLA0KKiByZXNvdXJjZV9pZCAtIG1hY2hpbmUvaW5kaXZpZHVhbCByZXNwb25zaWJsZSBmb3IgdGhlIGluc3RhbmNlIG9mIHRoZSBwcm9jZXNzL2FjdGl2aXR5Lg0KDQpIb3dldmVyLCBiZWZvcmUgdGhhdCB0aGUgZGF0ZSB0aW1lIGRhdGEgbmVlZHMgdG8gYmUgYnJvdWdodCB0byBhIHByb3BlciBkYXRlIHRpbWUgZm9ybWF0LiBGb3IgdGhpcywgbHVicmlkYXRlIGxpYnJhcnkgaXMgdXNlZC4gDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShsdWJyaWRhdGUpDQoNCnByb2RfZGF0YSRDb21wbGV0ZS5UaW1lc3RhbXA8LSB5bWRfaG1zKHByb2RfZGF0YSRDb21wbGV0ZS5UaW1lc3RhbXApDQpwcm9kX2RhdGEkU3RhcnQuVGltZXN0YW1wPC0geW1kX2htcyhwcm9kX2RhdGEkU3RhcnQuVGltZXN0YW1wKQ0KYGBgDQoNCkF0IHRoaXMgcG9pbnQsIGFuIGFjdGl2aXR5IGluc3RhbmNlIGlzIGFkZGVkIHRvIHRoZSBsb2dzIGFuZCBhbiBldmVudCBsb2cgaXMgY3JlYXRlZC4gDQoNCmBgYHtyfQ0KcHJvZF9kYXRhX3dpdGhfaW5zdGFuY2U8LSBwcm9kX2RhdGEgJT4lIA0KICBtdXRhdGUoYWN0aXZpdHlfaW5zdGFuY2UgPSBhcy5jaGFyYWN0ZXIocm93X251bWJlcigpKSkNCmBgYA0KDQoNCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0V9DQpwcm9kX2V2ZW50ID0gcHJvZF9kYXRhX3dpdGhfaW5zdGFuY2UgJT4lDQogICAgZXZlbnRsb2coDQogICAgICAgIGNhc2VfaWQgPSAiQ2FzZS5JRCIsDQogICAgICAgIGFjdGl2aXR5X2lkID0gIkFjdGl2aXR5IiwNCiAgICAgICAgYWN0aXZpdHlfaW5zdGFuY2VfaWQgPSAiYWN0aXZpdHlfaW5zdGFuY2UiLA0KICAgICAgICBsaWZlY3ljbGVfaWQgPSAiUmV3b3JrIiwNCiAgICAgICAgdGltZXN0YW1wID0gIkNvbXBsZXRlLlRpbWVzdGFtcCIsDQogICAgICAgIHJlc291cmNlX2lkID0gIldvcmtlci5JRCINCiAgICApDQoNCnByb2RfZXZlbnQgJT4lIG5fYWN0aXZpdGllcw0KDQpwcm9kX2V2ZW50ICU+JSBuX2Nhc2VzDQoNCnByb2RfZXZlbnQgJT4lIG5fdHJhY2VzDQpwcm9kX2V2ZW50ICU+JSBuX3Jlc291cmNlcw0KDQpgYGANCg0KVGhlcmUgYXJlIGEgdG90YWwgb2YgNTUgYWN0aXZpdGllcywgY2FycmllZCBvdXQgZm9yIDIyNSBjYXNlcywgaW4gMjIxIHVuaXF1ZSB3YXlzICh0cmFjZXMpIGJ5IDQ5IHJlc291cmNlcy4gDQoNCiMjIyMgQWN0aXZpdHkgVW5kZXJzdGFuZGluZyAmIEFuYWx5c2lzDQpMZXQgdXMgc3RhcnQgd2hhdCBkaWZmZXJlbnQgbGV2ZWwgb2YgYWN0aXZpdGllcyBhcmUgcHJlc2VudCBhbmQgdGhlaXIgcmVsYXRpdmUgZnJlcXVlbmN5DQoNCmBgYHtyfQ0KDQphY3Rpdml0eV9kYXRhPC0gcHJvZF9ldmVudCAlPiUgDQogICBhY3Rpdml0eV9mcmVxdWVuY3kobGV2ZWwgPSAiYWN0aXZpdHkiKQ0KDQphY3Rpdml0eV9kYXRhX3JlZHVjZWQ8LSBhY3Rpdml0eV9kYXRhW2FjdGl2aXR5X2RhdGEkcmVsYXRpdmU+MC4wMixdDQoNCihwbG90KGFjdGl2aXR5X2RhdGFfcmVkdWNlZCkpDQpgYGANCg0KVGhpcyBzaG93cyB0aGF0IGZpbmFsIGluc3BlY3Rpb24gaXMgdGhlIGhpZ2hlc3QgZnJlcXVlbmN5IGFjdGl2aXR5LCB3aGljaCBpcyB0byBiZSBleHBlY3RlZC4gQWZ0ZXIgd2hpY2ggdGhlIHR1cm5pbmcgYW5kIG1pbGxpbmcgcXVhbGl0eSBjaGVja3MgYXJlIGFsc28gaGlnaC4gTGFwcGluZyBhbmQgcGFja2FnaW5nIGZvbGxvdyB1cC4gDQoNCiMjIyMgVmlzdWFsaXppbmcgcHJvY2VzcyBtYXBzDQpMZXQgdXMgc3RhcnQgYnkgdmlld2luZyBvbmUgb2YgdGhlIHByb2Nlc3MgbWFwcy4gDQoNCmBgYHtyfQ0KZXZlbnRfcmVkdWNlZDwtIHByb2RfZXZlbnRbcHJvZF9ldmVudCRDYXNlLklEICVpbiUgYygiQ2FzZSAxIiksXQ0KDQpldmVudF9yZWR1Y2VkICU+JSBwcm9jZXNzX21hcCh0eXBlID0gZnJlcXVlbmN5KCJyZWxhdGl2ZSIpKQ0KYGBgDQoNClRoaXMgc2hvd3MgZm9yIG9uZSBvZiB0aGUgY2FzZXMsIGhvdyB0aGUgc3RlcHMgaW52b2x2ZWQgaW4gdGhlIHByb2Nlc3MgcGxheSBvdXQuIEFzIHdlIGFkZCBtb3JlIGRhdGEsIHdlIGNhbiBzdGFydCB0byBzZWUgc29tZSBvZiB0aGUgcG9zc2libGUgaXRlcmF0aW9ucyBpbiB0aGUgcHJvY2VzcyBwbGF5IG91dC4gSXQgYXBwZWFycyB0aGF0IHRoZSBzdGVwcyBmb3IgdGhpcyBjYXNlIGFyZSANCjEuIFR1cm5pbmcgYW5kIG1pbGxpbmcNCjIuIFR1cm5pbmcgYW5kIG1pbGxpbmcgUS5DDQozLiBMYXNlciBNYXJraW5nDQo0LiBMYXBwaW5nDQo1LiBSb3VuZCBncmluZGluZw0KNi4gRmluYWwgSW5zcGVjdGlvbg0KNy4gUGFja2luZw0KDQpTZWxmIGxvb3BzIHJlcHJlc2VudCB0aGF0IG1vcmUgdGhhbiBvbmUgbG9nZ2luZyBvZiB0aGUgc2FtZSBhY3Rpdml0eSBpcyBvYnNlcnZlZCwgd2hpY2ggbWlnaHQgYmUgZHVlIHRvIGVycm9yIG1lc3NhZ2VzIG9yIGxvZ2dpbmcgZGlzY3JlcGFuY3kuIA0KDQpJZiB3ZSBhZGQgdHdvIG1vcmUgY2FzZXMgdG8gdGhpcywgbW9yZSBpbnNpZ2h0cyBzdGFydCB0byBhcHBlYXIsIHNlZSBiZWxvdyBwbG90IGZvciAzIGNhc2VzLiANCg0KYGBge3J9DQpldmVudF9yZWR1Y2VkPC0gcHJvZF9ldmVudFtwcm9kX2V2ZW50JENhc2UuSUQgJWluJSBjKCJDYXNlIDEiLCJDYXNlIDExMSIsIkNhc2UgMTA0IiksXQ0KDQpldmVudF9yZWR1Y2VkICU+JSBwcm9jZXNzX21hcCh0eXBlID0gZnJlcXVlbmN5KCJyZWxhdGl2ZSIpKQ0KYGBgDQpJdCBpcyBjbGVhciB0aGF0IG9uZSBvZiB0aGUgY2FzZXMgKDEvMykgd2VudCBmb3IgdHVybmluZyByYXRoZXIgdGhhbiB0dXJuaW5nIGFuZCBtaWxsaW5nLCB3aGljaCBhbHNvIGluY3JlYXNlZCBhIHR1cm5pbmcgUS5DIHBvaW50DQoNCkFib3ZlIHBsb3QgYWxzbyBzaG93cyB0aGF0IGFib3V0IDIwJSBvZiB0aGUgY29tcG9uZW50cyBkaXJlY3RseSBnbyBmcm9tIGxhc2VyIG1hcmtpbmcgdG8gZW5kLCA4JSBnbyBmcm9tIHR1cm5pbmcgdG8gZW5kIHdoaWxlIGFib3V0IDIwJSBnbyB0aHJvdWdoIHRoZSBsYXBwaW5nIGFuZCBncmlkaW5nIG9wZXJhdGlvbiBiZWZvcmUgZ29pbmcgdG8gcGFja2luZyBhbmQgdGhlbiBlbmRpbmcuIA0KDQpJZiB3ZSBhZGQgZmV3IG1vcmUgY2FzZXMgdG8gdGhlIGFib3ZlIHBsb3QsIGl0IHN0YXJ0cyB0byBnZXQgY3VtYmVyc29tZSB0byB1bmRlcnN0YW5kLiANCg0KU2ltaWxhciB0byBwcm9jZXNzIG1hcHMsIHJlc291cmNlIG1hcHMgYXJlIGFsc28gYW5vdGhlciB3YXkgb2YgdW5kZXJzdGFuZGluZyBmbG93LiANCg0KYGBge3J9DQpldmVudF9yZWR1Y2VkPC0gcHJvZF9ldmVudFtwcm9kX2V2ZW50JENhc2UuSUQgJWluJSBjKCJDYXNlIDEiLCJDYXNlIDExMSIsIkNhc2UgMTA0IiksXQ0KDQpldmVudF9yZWR1Y2VkICU+JSBmaWx0ZXJfdHJhY2VfZnJlcXVlbmN5KHBlcmNlbnRhZ2UgPSAwLjUpICU+JSByZXNvdXJjZV9tYXAodHlwZSA9IGZyZXF1ZW5jeSgiYWJzb2x1dGUiKSkNCmBgYA0KDQoNClRoZXJlIGFyZSBmdXJ0aGVyIHdheXMgYXZhaWxhYmxlIGZvciBleHBsb3JpbmcgcHJvY2Vzc2VzLiANCg0KDQojIyMjIFByZWNlZGVuY2UgTWF0cml4DQpBbm90aGVyIHdheSB0byB2aXN1YWxpemUgdGhlIHByb2Nlc3MgaXMgcHJlY2RlbmNlIG1hdHJpeCB3aGljaCBzaG93cyB3aGljaCBzdGVwcyB0ZW5kIHRvIGhhcHBlbiB0b2dldGhlci4gSW4gdGhpcyBjYXNlIHNpbmNlIGxvZ2dpbmcgc2VlbXMgdG8gaGF2ZSBkdXBsaWNhdGlvbiBpbiBhY3Rpdml0eSwgdGhlIHBsb3QgaXMgbm90IHZlcnkgaW5zaWdodGZ1bC4gDQoNCmBgYHtyfQ0KcHJlY2VkZW5jZV9tYXRyaXggPC0gcHJvZF9ldmVudCAlPiUNCiAgZmlsdGVyX2FjdGl2aXR5X2ZyZXF1ZW5jeShwZXJjZW50YWdlID0gMC45KSAlPiUgDQogIGZpbHRlcl90cmFjZV9mcmVxdWVuY3kocGVyY2VudGFnZSA9IC44MCkgJT4lICAgIA0KICBwcmVjZWRlbmNlX21hdHJpeCgpICU+JSANCiAgcGxvdCgpDQoNCnByZWNlZGVuY2VfbWF0cml4DQoNCmBgYA0KDQojIyMjIFJlc291cmNlICYgYWN0aXZpdHkgQW5hbHlzaXMNClJlc291cmNlIHNwZWNpYWxpemF0aW9uIGFuZCB1dGlsaXphdGlvbiBpcyBhbm90aGVyIGtleSBhY3Rpdml0eSB3aGljaCBjYW4gYmUgaGVscGVkIGJ5IHByb2Nlc3MgYW5hbHl0aWNzDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTh9DQpwcm9kX2V2ZW50ICU+JQ0KICAgIHJlc291cmNlX3NwZWNpYWxpc2F0aW9uKCJyZXNvdXJjZSIpICU+JSBwbG90KCkNCmBgYA0KDQpUaGUgYWJvdmUgcGxvdCBmb3IgaW5zdGFuY2Ugc2hvd3MgdGhhdCBJRDQ5MzIgYW5kIElEMDkzNyBhcmUgZ2VuZXJhbGlzdHMsIHBlcmZvcm1pbmcgdXB0byAxNSBhY3Rpdml0eSB0eXBlcywgSUQzNjQxLCBJRDM3MTkgYXJlIHNwZWNpYWxpc3RzLiANCg0KYGBge3IsIGZpZy5oZWlnaHQ9MTB9DQpwcm9kX2V2ZW50ICU+JQ0KICAgIHJlc291cmNlX3NwZWNpYWxpc2F0aW9uKCJhY3Rpdml0eSIpICU+JSBwbG90KCkNCmBgYA0KDQpGaW5hbCBpbnNwZWN0aW9uLCBwYWNraW5nLCBsYXBwaW5nLCByb3VuZCBncmlkaW5nIGFuZCB0dXJuaW5nIFEuQyBhcmUgc3BlY2lhbGl6ZWQgYWN0aXZpdGllcyBwZXJmb21yZWQgb25seSBieSBvbmUgcmVzb3VyY2UuICAgDQoNCkluIHRlcm1zIG9mIGFjdGl2aXRpZXMsIGl0IHdvdWxkIGFsc28gYmUgdXNlZnVsIHRvIHVuZGVyc3RhbmQgd2hpY2ggYWN0aXZpdGllcyBhcmUgYWx3YXlzIHBlcmZvcm1lZCwgYW5kIHdoaWNoIGFyZSByYXJlLiANCg0KYGBge3IsIGZpZy5oZWlnaHQ9OH0NCnByb2RfZXZlbnQgJT4lIGFjdGl2aXR5X3ByZXNlbmNlKCkgJT4lIHBsb3QoKQ0KYGBgDQoNCiMjIyMgVHJhY2UgYW5hbHlzaXMNClRyYWNlIGxlbmd0aCBhbmQgcGxvdHMgYXJlIHVzZWQgdG8gc2VlIGhvdyBtdWNoIHZhcmlhdGlvbiBpcyB0aGVyZSBhY3Jvc3MgY2FzZXMuIA0KDQpgYGB7cn0NCnByb2RfZXZlbnQgJT4lIHRyYWNlX2xlbmd0aCgpICU+JSBwbG90KCkNCiNwcm9kX2V2ZW50ICU+JSB0cmFjZV9sZW5ndGgoKQ0KYGBgDQoNClRoZSBwbG90IHNob3dzIHRoYXQgb24gYW4gYXZlcmFnZSwgNzUlIG9mIGNhc2VzIGhhdmUgYmV0d2VlbiA4LTIzIHN0ZW9zLCBhbHRob3VnaCBhIG1heGltdW0gb2YgMTc1IHN0ZXBzIGhhdmUgYmVlbiBvYnNlcnZlZCBhcyB3ZWxsLiBNZWRpYW4gbnVtYmVyIG9mIHN0ZXBzIGlzIDE0LCBhbmQgYXZlcmFnZSBudW1iZXIgb2Ygc3RlcHMgaXMgMjAuIA0KDQpEbyBhbGwgYWN0aXZpdGllcyBzdGFydCBhbmQgZW5kIGF0IHRoZSBzYW1lIHBvaW50cz8gVGhpcyBjYW4gYmUgdmlzdWFsaXplZCB1c2luZyBiYXIgcGxvdHMgYXMgd2VsbA0KDQpgYGB7cn0NCnN0YXJ0X2FjdGl2aXRpZXMocHJvZF9ldmVudCwgbGV2ZWwgPSAiYWN0aXZpdHkiKSAlPiUgcGxvdCgpDQoNCmBgYA0KDQpXaGlsZSB0dXJuaW5nIGFuZCBtaWxsaW5nIHNlZW1zIHRvIGJlIHRoZSBmaXJzdCBvcGVyYXRpb24sIG1hY2hpbmUgNiBzZWVzIGhpZ2hlc3QgcmF0ZSBvZiBzdGFydGluZyBwb2ludHMuIA0KDQpgYGB7cn0NCmVuZF9hY3Rpdml0aWVzKHByb2RfZXZlbnQsIGxldmVsID0gImFjdGl2aXR5IikgJT4lIHBsb3QoKQ0KYGBgDQoNCkFzIGV4cGVjdGVkLCBtb3N0IG9wZXJhdGlvbnMgZW5kIHdpdGggZmluYWwgaW5zcGVjdGlvbiBvciBwYWNraW5nLiANCg0KYGBge3J9DQpwcm9kX2V2ZW50ICU+JQ0KICB0cmFjZV9jb3ZlcmFnZShsZXZlbCA9ICJ0cmFjZSIpICU+JQ0KICBwbG90KCkNCmBgYA0KDQpUaGUgYWJvdmUgcGxvdCBzaG93cyBob3cgbWFueSBjYXNlcyBjYW4gYmUgZGVzY3JpYmVkIHdpdGggYSByZWxhdGl2ZWx5IHNtYWxsIG51bWJlciBvZiB0cmFjZXMgaW5kaWNhdGluZyB0aGUgY29uc2lzdGVuY3kgaW4gdGhlIHByb2Nlc3MuIEhlcmUgd2UgaGF2ZSBzZWVuIHRoYXQgZm9yIDIyNSBjYXNlcywgYXMgaGlnaCBhcyAyMjEgdHJhY2VzIGV4aXN0LCBzbyB0aGVyZSBpcyBqdXN0IGxlc3MgY29uc2lzdGVuY3kuIEhvd2V2ZXIsIHRoaXMgaXMgZHVlIHRvIG1hY2hpbmUgbnVtYmVyIGJlaW5nIHBhcnQgb2YgYWN0aXZpdHkgZGVzY3JpcHRpb24sIHdoaWNoIG1lYW5zIHRoYXQgc2ltaWxhciBzdGVwcyBhcmUgYWxzbyB0cmVhdGVkIGRpZmZlcmVudGx5LiANCg0KDQoNCiMjIyMgQ29uc29saWRhdGlvbiBvZiBhY3Rpdml0aWVzDQpDb25zb2xpZGF0aW9uIG9mIGFjdGl2aXRpZXMgYWxsb3dzIHJlbGFiZWxpbmcgYW5kIGZ1cnRoZXIgaGlnaCBsZXZlbCB2aWV3IG9mIHRoZSBwcm9jZXNzLiANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpwcm9kX2V2ZW50X3VuaXRlZDwtIHByb2RfZXZlbnQgJT4lIGFjdF91bml0ZShUdXJuaW5nID0gYygiVHVybmluZyAtIE1hY2hpbmUgMjEiLCJUdXJuaW5nIC0gTWFjaGluZSA0IiwgIlR1cm5pbmcgLSBNYWNoaW5lIDUiLCAiVHVybmluZyAtIE1hY2hpbmUgOCIsICJUdXJuaW5nIC0gTWFjaGluZSA5IikpDQoNCnByb2RfZXZlbnRfdW5pdGVkPC0gcHJvZF9ldmVudF91bml0ZWQgJT4lIGFjdF91bml0ZSgiVHVybmluZyAmIE1pbGxpbmciID0gYygiVHVybmluZyAmIE1pbGxpbmcgLSBNYWNoaW5lIDEwIiwiVHVybmluZyAmIE1pbGxpbmcgLSBNYWNoaW5lIDQiLCJUdXJuaW5nICYgTWlsbGluZyAtIE1hY2hpbmUgNSIsIlR1cm5pbmcgJiBNaWxsaW5nIC0gTWFjaGluZSA2IiwiVHVybmluZyAmIE1pbGxpbmcgLSBNYWNoaW5lIDgiLCJUdXJuaW5nICYgTWlsbGluZyAtIE1hY2hpbmUgOSIgKSkNCg0KcHJvZF9ldmVudF91bml0ZWQ8LSBwcm9kX2V2ZW50X3VuaXRlZCAlPiUgYWN0X3VuaXRlKCJSb3VuZCBHcmlkbmluZyAtIE1hY2hpbmUiID0gYygiUm91bmQgR3JpbmRpbmcgLSBNYWNoaW5lIDEyIiwiUm91bmQgR3JpbmRpbmcgLSBNYWNoaW5lIDE5IiwgIlJvdW5kIEdyaW5kaW5nIC0gTWFjaGluZSAyIiwiUm91bmQgR3JpbmRpbmcgLSBNYWNoaW5lIDIzIiwiUm91bmQgR3JpbmRpbmcgLSBNYWNoaW5lIDMiKSkNCg0KcHJvZF9ldmVudF91bml0ZWQ8LSBwcm9kX2V2ZW50X3VuaXRlZCAlPiUgYWN0X3VuaXRlKCJNaWxsaW5nIiA9IGMoIk1pbGxpbmcgLSBNYWNoaW5lIDEwIiwiTWlsbGluZyAtIE1hY2hpbmUgMTQiLCJNaWxsaW5nIC0gTWFjaGluZSAxNiIsIk1pbGxpbmcgLSBNYWNoaW5lIDgiICkpDQoNCnByb2RfZXZlbnRfdW5pdGVkPC0gcHJvZF9ldmVudF91bml0ZWQgJT4lIGFjdF91bml0ZSgiR3JpbmRpbmcgUmV3b3JrIiA9IGMoIkdyaW5kaW5nIFJld29yayIsIkdyaW5kaW5nIFJld29yayAtIE1hY2hpbmUgMTIiLCAiR3JpbmRpbmcgUmV3b3JrIC0gTWFjaGluZSAyIiwiR3JpbmRpbmcgUmV3b3JrIC0gTWFjaGluZSAyNyIgKSkNCg0KcHJvZF9ldmVudF91bml0ZWQ8LSBwcm9kX2V2ZW50X3VuaXRlZCAlPiUgYWN0X3VuaXRlKCJTZXR1cCIgPSBjKCJTZXR1cCAtIE1hY2hpbmUgOCIsIlNldHVwIC0gTWFjaGluZSA0IikpDQoNCnByb2RfZXZlbnRfdW5pdGVkPC0gcHJvZF9ldmVudF91bml0ZWQgJT4lIGFjdF91bml0ZSgiRml4IiA9IGMoIkZpeCAtIE1hY2hpbmUgMyIsIkZpeCAtIE1hY2hpbmUgMTkiLCAiRml4IC0gTWFjaGluZSAxNSIsICJGaXggLSBNYWNoaW5lIDE1TSIpKQ0KDQpwcm9kX2V2ZW50X3VuaXRlZDwtIHByb2RfZXZlbnRfdW5pdGVkICU+JSBhY3RfdW5pdGUoIkZpeCIgPSBjKCJGaXgiLCJGaXggRURNIikpDQoNCnByb2RfZXZlbnRfdW5pdGVkPC0gcHJvZF9ldmVudF91bml0ZWQgJT4lIGFjdF91bml0ZSgiVHVybiAmIE1pbGwgYW5kIFNjcmV3IiA9IGMoIlR1cm4gJiBNaWxsLiAmIFNjcmV3IEFzc2VtIC0gTWFjaGluZSA5IiwiVHVybiAmIE1pbGwuICYgU2NyZXcgQXNzZW0gLSBNYWNoaW5lIDEwIikpDQoNCnByb2RfZXZlbnRfdW5pdGVkPC0gcHJvZF9ldmVudF91bml0ZWQgJT4lIGFjdF91bml0ZSgiV2lyZSBDdXQiID0gYygiV2lyZSBDdXQgLSBNYWNoaW5lIDE4IiwiV2lyZSBDdXQgLSBNYWNoaW5lIDEzIikpDQoNCnByb2RfZXZlbnRfdW5pdGVkPC0gcHJvZF9ldmVudF91bml0ZWQgJT4lIGFjdF91bml0ZSgiRmxhdCBHcmluZGluZyIgPSBjKCJGbGF0IEdyaW5kaW5nIC0gTWFjaGluZSAxMSIsIkZsYXQgR3JpbmRpbmcgLSBNYWNoaW5lIDI2IiApKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmV2ZW50X3JlZHVjZWQ8LSBwcm9kX2V2ZW50X3VuaXRlZFtwcm9kX2V2ZW50X3VuaXRlZCRDYXNlLklEICVpbiUgYygiQ2FzZSAxIiwiQ2FzZSAxMTEiLCJDYXNlIDEwNCIpLF0NCg0KZXZlbnRfcmVkdWNlZCAlPiUgZmlsdGVyX3RyYWNlX2ZyZXF1ZW5jeShwZXJjZW50YWdlID0gMC44KSAlPiUgcHJvY2Vzc19tYXAodHlwZSA9IGZyZXF1ZW5jeSgiYWJzb2x1dGUiKSkNCmBgYA0KDQpUaGUgMTAlIG1vc3QgaW5mcmVxdWVudCB0cmFjZXMgYXJlIHBsb3R0ZWQgYmVsb3cgd2l0aCB1bml0ZWQgZGF0YS4gDQoNCmBgYHtyLCBmaWcud2lkdGg9MjV9DQpwcm9kX2V2ZW50X3VuaXRlZCAlPiUgdHJhY2VfZXhwbG9yZXIoY292ZXJhZ2UgPSAwLjEsIHR5cGUgPSAiaW5mcmVxdWVudCIpDQpgYGANCg0K