This short paper proposes a slope factor method to be used in routing algorithms for cycling, suited for hilly cities.

1 Cost for bicycle routing models

Bicycle routing models add to car routing modeling a greater complexity that results essentially from the greater number of degrees of freedom associated with cycling (i.e., a smaller, lighter and more versatile vehicle in terms of maneuvering) and the fact that it is human powered and therefore depending on a limited energy, thus depending on the effort that is transmitted by the cyclist himself. This results in a series of specific peculiarities in its riding, namely: a greater number of variables relevant to the routing cost function, and the existence of more subjective variables.

A complexity involved in modeling route choice for cyclists represents a challenge. Even if we understand which variables are determinant for route choice, models become more accurate if it incorporates the versatility of the bicycle in urban context, and its ability to circulate in non-road spaces.

GIS allows modeling a road network in the form of a topological graph, to which a series of functions and algorithms, including the least cost path (Dijkstra 1959). The application of the least cost path algorithm assumes the existence of a graph formed by a set of set of edges and nodes. The edges can be oriented or not and, to these, a travel cost is associated, with one or more parameters, never less than zero. Associating a travel cost to each arc in the network, the route cost is defined as the sum of the costs of the arcs that compose it.

1.1 Speed

For a constant urban cycling speed travel (factor = 1), let’s say 15 km/h, we assume that the speed is linear to the edge extension, and its cost is its travel time.

\[ c_{speed} = \frac{length_{[m]}}{speed_{[m/s]}} = time_{[s]}\tag{Eq.1}\]

Many factors may be determinant for cycling speed, such the surface conditions, traffic, weather, mass, type of bicycle, directness, confidence, etc (Hochmair 2007; Félix 2012; Broach, Dill, and Gliebe 2012; Broach 2016). Here we will look only to speed related with gradient, from the perspective of a common urban cyclist.

1.2 Slope or gradient

When comes to cycling, the route gradient can be a determinant variable to chose a route instead of an alternative. It is commonly known that cyclists are averse to roads with an ascending gradient, and that cyclists prefer roads with a descending gradient. The direction of the gradient is determinant.

It is also known, by the gravity laws, that an object traveling at a constant speed, its speed becomes faster when going down the hill, and slower when going uphill. Buy how does it applies to a human behavior? How does it varies when effort, fear, stamina, and reward plays a role? When does a cyclist use the break levers? When does a cyclist slows her pace?

The slope enters the cost function as a proxy for cyclist effort - the amount of energy a cyclist must expend to travel on a street with a given slope - causing the traversing time to increase for uphill routes. On downhill routes, the effort is reduced and the theoretical speed is increased, reducing their traversing time.

Scott (2020) designed an experiment for hiking, and applied a rule saying “A 10% grade incline cuts your speed in half”. In their results, they suggested an equation to calculate uphill speed (for hiking):

\[ speed = speed_{flat} * e^{(-0.04*slope)}\tag{Eq.2} \]

Which results that with a grade of 20%, one can walk at a speed of 1.78 km/h it her horizontal speed was 4 km/h. When applying to cycling, for a flat speed of 15km/h, the same incline would be ride at a 6.74 km/h speed, which is not reliable for a standard cyclist.

Also, the extension of the road segment enters in the cost function: for longer segments at a given gradient, the effort of the cyclist is higher than for a shorter segment with the same gradient.

Figure 1 shows the maximum lengths of uphill gradient acceptable to cyclists (Austroads 2009). It considers that over a 3% slope, the length should be taken into account.

Fig. 1 - Desirable uphill gradients for ease of cycling (Austroads 2009)
Fig. 1 - Desirable uphill gradients for ease of cycling (Austroads 2009)

Sometimes it is more efficient to travel a longer distance with less steep gradients rather than a shorter distance on a steep gradient. Other times the extra distance to ride to overcome the gradient is not so worthwhile and the cyclist chooses to ride up the steeper gradient by hand. The maximum crossing cost penalty was considered to be 10 times for this situation, i.e. for edges with a gradient greater than 20%.

Very steep roads are a problem not only for uphill riding, but also for downhill riding, because a mechanical failure in the brakes can lead to a dangerous situation for the rider, who also has to expend some effort and skill to keep the bike balanced and control the additional risk.

Fig. 2 - World’s steepest street, with a 35% incline for over 161 meters. Baldwin Street, Dunedin, New Zealand (Photo: Wikipedia)
Fig. 2 - World’s steepest street, with a 35% incline for over 161 meters. Baldwin Street, Dunedin, New Zealand (Photo: Wikipedia)

Downhill edges mostly result in benefit to the cyclist, increasing its speed. However, this is not linear, decreasing from slope values above 13%, and may even slow down the speed (relative to the average flat speed) it too steep.

2 Speed-Slope Factor

After an iterative process, which considered the cyclist effort as a function of slope abacuses suggested by AASHTO (1999) and Austroads (2009) (p. 41), and also a cost formula developed by Price and Entrada/San Juan Inc. (2008), Eq. 3 presets a function that models the slope factor based on the slope [%] and length [m] of each road segment. This function, which is non-symmetric and non-monotonic, reproduces the essential characteristics of the slope/effort relationship.

In addition to this function, a second set of criteria is applied (g), which increases the slope factor when road segments have a given length [m] and slope [%], with intervals as suggested by CEAP - Centro de Estudos de Arquitectura Paisagista (n.d.) . Eq. 4 shows that edges with gradient between 0 and 20 in the upward direction are thus penalized by accumulation of effort.

\[slope factor_{(slope,length)} = \begin{cases} 1.5 &\Leftarrow \quad slope <-30 \\ 1+ 2\frac{0.7}{13} * slope +\frac{0.7}{13^2}*slope^2 &\Leftarrow -30 \leq slope <0 \\ 1+ (\frac{slope}{g_{(slope, length)}})^2 &\Leftarrow 0 \leq slope \leq20 \\ 10 &\Leftarrow 20 <slope \end{cases}\tag{Eq.3} \]

With,

\[g_{(slope,length)} = \begin{cases} 4 &\Leftarrow 10<slope \leq 13 \quad\wedge\quad length > 15\\ 4.5 &\Leftarrow 8 <slope \leq 10 \quad\wedge\quad length > 30 \\ 5 &\Leftarrow 5 <slope \leq 8 \quad\wedge\quad length > 60 \\ 6 &\Leftarrow 3 <slope \leq 5 \quad\wedge\quad length > 120 \\ 7 &\Leftarrow otherwise \end{cases}\tag{Eq.4} \]

As the max penalization going uphill should not be 10 times more than the flat speed, we add another condition to maximize the slope factor, as follows:

\[slope factor_{(slope,length)}adjst = \begin{cases} 10 &\Leftarrow slope >13 \quad\wedge\quad length >15 \\ 10 &\Leftarrow slope >10 \quad\wedge\quad length >30 \\ 10 &\Leftarrow slope >8 \quad\wedge\quad length >60 \\ 10 &\Leftarrow slope >5 \quad\wedge\quad length >120 \\ \end{cases}\tag{Eq.5} \]

This functions result in a speed factor (in log scale) that varies as this:

And, finally, we divide the constant flat speed by the slope factor as :

\[ speed = \frac{speed_{flat}}{slope factor}\tag{Eq.5} \]

2.1 What does it means uphill?

When going uphill, speed will reduce, and longer the road segments, higher the denominator, and slower the cyclist speed.

For instance, if assuming a constant flat speed of 15 km/h and a road with 80 m and 3% uphill, a cyclist will reduce to 12.67 km/h

speedflat = 15
slope = 3
length = 50
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 12.67241

If it is slightly steeper, with 4% uphill, a cyclist will reduce to 11.31 km/h

slope = 4
length = 50
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 11.30769

If that same segment is longer, a cyclist will reduce to 10.38 km/h

slope = 4
length = 150
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 10.38462

For higher gradients, the speed decreases with more sensitivity regarding the segment length.

slope = 6
length = 60
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 8.647059
slope = 6
length = 80
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 6.147541

And for very steep streets, cycling speed may reduce to walking speed.

slope = 9
length = 40
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 3

2.2 And downhill?

In another hand, when going downhill, speeds will increase until it gets 3.33x faster, when the gradient is 13%. For steeper gradients, the cyclist will tend to break, and the speed will be lower.

Until the moment when it gets so scary to ride it (again, for a regular urban cyclist with mild experience), that it will take more time to travel that road than if it was flat.

length = 100
slope = -8
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 37.17009
slope = -13
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 50
slope = -20
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 29.82353
slope = -25
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 16.73267
slope = -30
speedflat / speedfactor(slope, length, g = g(slope, length))
## [1] 10.01976

3 Case Study

Here we will use a small road network from downtown Lisbon (Portugal), retrieved from slopes() package, to test the speed-slope factor.

This area is known for a flat and orthogonal set of streets, surrounded by organic and steep streets, ranging from 0 to 21%.

For the purpose of the example, we will assign a direction of the gradient, once that it was not defined.

And now compute the length, slope, and the speed-slope factor for each segment. We can observe, in a logarithmic y-scale, that there are a lot of flat or almost flat segments (factor around 1), some uphill segments that reach factor 10, and some downhill segments that reach factor 0.3.

#length and slope
DATA$length = st_length(DATA) |> units::drop_units() #in meters
DATA$slope[DATA$direction == "TF"] = -(DATA$slope[DATA$direction == "TF"])
slope = DATA$slope
length = DATA$length

#speed-slope factor
g = g(slope, length)
spf = speedfactor(slope, length, g)

By defining a flat speed of 16 km/h, it results in segments that are cycled up to 6 minutes uphill, and at a maximum speed of 53 km/h.

#set speed
speedflat = 16 #set here in km/h (convert to m/s: speed/3.6)

DATA$speedfactor = spf
DATA$speed = speedflat / DATA$speedfactor
DATA$time = length / DATA$speed*3.6

mapview::mapview(DATA, zcol = "speed")
summary(DATA$speed)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    1.60   12.58   16.00   19.71   23.90   53.31       5
mapview::mapview(DATA, zcol = "time")
summary(DATA$time)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max.     NA's 
##   0.1801   6.1184  13.7522  37.9580  35.7793 418.3530        5

This is a work in progress. Suggestions and comments are welcome! :) github.com/U-Shift/Declives-RedeViaria/tree/main/SpeedSlopeFactor

4 Conclusion

For a hilly city, the slope factor is a good approach to model the cost of the cyclist effort in a routing algorithm. It is a non-linear and non-monotonic function that reproduces the essential characteristics of the slope/effort relationship, and it is a good proxy for cyclist effort. It is also a good approach to model the cyclist speed in a road network.
Further research is needed to validate this approach, and to understand how it can be applied to different types of cyclists, and to different types of bicycles, as this method does not consider the effort on an e-bike.

Plausible? Let’s discuss it!

References

AASHTO. 1999. Guide for the Development of Bicycle Facilities. Washington, DC: American Association of State Highway; Transportation Officials. http://safety.fhwa.dot.gov/ped_bike/docs/b_aashtobik.pdf.
Austroads. 2009. “Part 6A: Pedestrian and Cyclist Paths.” In. Austroads.
Broach, Joseph. 2016. “Travel Mode Choice Framework Incorporating Realistic Bike and Walk Routes.” PhD thesis.
Broach, Joseph, Jennifer Dill, and John Gliebe. 2012. “Where Do Cyclists Ride? A Route Choice Model Developed with Revealed Preference GPS Data.” Transportation Research Part A: Policy and Practice 46 (10): 1730–40. https://doi.org/10.1016/j.tra.2012.07.005.
CEAP - Centro de Estudos de Arquitectura Paisagista. n.d. “Contributos Para o Regulamento de Percursos Cicláveis Em Portugal.”
Dijkstra, E. W. 1959. “A Note on Two Problems in Connexion with Graphs.” Numerische Mathematik 1 (1): 269–71. https://doi.org/10.1007/bf01386390.
Félix, Rosa. 2012. “Gestão Da Mobilidade Em Bicicleta: Necessidades, Factores de Preferência e Ferramentas de Suporte Ao Planeamento e Gestão de Redes. O Caso de Lisboa.” Master’s thesis, Instituto Superior Técnico; University of Lisbon. https://fenix.tecnico.ulisboa.pt/downloadFile/395144993029/GestaoMobilidadeBicicleta_RosaFelix_IST2012.pdf.
Hochmair, Hartwig. 2007. “Optimal Route Selection with Route Planners: Results of a Desktop Usability Study.” In, 5–8. Seattle, Washington: ACM GIS.
Price, Mike, and Entrada/San Juan Inc. 2008. “Slopes , Sharp Turns , and Speed: Refining Emergency Response Networks to Accommodate Steep Slopes and Turn Rules.” Hands On - ArcUser Spring 2008 11 (2): 50–57.
Scott, Adam. 2020. “Moving Uphill, a 10.” Mountain Tactical Institute. https://mtntactical.com/research/walking-uphill-10-grade-cuts-speed-13not-12/.
LS0tCnRpdGxlOiAiU3BlZWQtU2xvcGUgZmFjdG9yIgphdXRob3I6ICJSb3NhIEbDqWxpeCIKIyBkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCmRhdGU6ICIxNSBhcHJpbCwgMjAyMSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX3RleDogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiMgb3V0cHV0OgojICAgZ2l0aHViX2RvY3VtZW50OgojICAgICBwYW5kb2NfYXJnczogIi0td2VidGV4IgpiaWJsaW9ncmFwaHk6IHJlZnMuYmliCmxpbmstY2l0YXRpb25zOiB5ZXMKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiNpbXBvcnQgbGlicmFyaWVzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHNsb3BlcykKbGlicmFyeSh0bWFwKQpsaWJyYXJ5KG1hcHZpZXcpCm1hcHZpZXdPcHRpb25zKGZnYiA9IEZBTFNFKQpgYGAKClRoaXMgc2hvcnQgcGFwZXIgcHJvcG9zZXMgYSBzbG9wZSBmYWN0b3IgbWV0aG9kIHRvIGJlIHVzZWQgaW4gcm91dGluZyBhbGdvcml0aG1zIGZvciBjeWNsaW5nLCBzdWl0ZWQgZm9yIGhpbGx5IGNpdGllcy4KCiMgQ29zdCBmb3IgYmljeWNsZSByb3V0aW5nIG1vZGVscwoKQmljeWNsZSByb3V0aW5nIG1vZGVscyBhZGQgdG8gY2FyIHJvdXRpbmcgbW9kZWxpbmcgYSBncmVhdGVyIGNvbXBsZXhpdHkgdGhhdCByZXN1bHRzIGVzc2VudGlhbGx5IGZyb20gdGhlIGdyZWF0ZXIgbnVtYmVyIG9mIGRlZ3JlZXMgb2YgZnJlZWRvbSBhc3NvY2lhdGVkIHdpdGggY3ljbGluZyAoaS5lLiwgYSBzbWFsbGVyLCBsaWdodGVyIGFuZCBtb3JlIHZlcnNhdGlsZSB2ZWhpY2xlIGluIHRlcm1zIG9mIG1hbmV1dmVyaW5nKSBhbmQgdGhlIGZhY3QgdGhhdCBpdCBpcyBodW1hbiBwb3dlcmVkIGFuZCB0aGVyZWZvcmUgZGVwZW5kaW5nIG9uIGEgbGltaXRlZCBlbmVyZ3ksIHRodXMgZGVwZW5kaW5nIG9uIHRoZSBlZmZvcnQgdGhhdCBpcyB0cmFuc21pdHRlZCBieSB0aGUgY3ljbGlzdCBoaW1zZWxmLiBUaGlzIHJlc3VsdHMgaW4gYSBzZXJpZXMgb2Ygc3BlY2lmaWMgcGVjdWxpYXJpdGllcyBpbiBpdHMgcmlkaW5nLCBuYW1lbHk6IGEgZ3JlYXRlciBudW1iZXIgb2YgdmFyaWFibGVzIHJlbGV2YW50IHRvIHRoZSByb3V0aW5nIGNvc3QgZnVuY3Rpb24sIGFuZCB0aGUgZXhpc3RlbmNlIG9mIG1vcmUgc3ViamVjdGl2ZSB2YXJpYWJsZXMuCgpBIGNvbXBsZXhpdHkgaW52b2x2ZWQgaW4gbW9kZWxpbmcgcm91dGUgY2hvaWNlIGZvciBjeWNsaXN0cyByZXByZXNlbnRzIGEgY2hhbGxlbmdlLiBFdmVuIGlmIHdlIHVuZGVyc3RhbmQgd2hpY2ggdmFyaWFibGVzIGFyZSBkZXRlcm1pbmFudCBmb3Igcm91dGUgY2hvaWNlLCBtb2RlbHMgYmVjb21lIG1vcmUgYWNjdXJhdGUgaWYgaXQgaW5jb3Jwb3JhdGVzIHRoZSB2ZXJzYXRpbGl0eSBvZiB0aGUgYmljeWNsZSBpbiB1cmJhbiBjb250ZXh0LCBhbmQgaXRzIGFiaWxpdHkgdG8gY2lyY3VsYXRlIGluIG5vbi1yb2FkIHNwYWNlcy4KCkdJUyBhbGxvd3MgbW9kZWxpbmcgYSByb2FkIG5ldHdvcmsgaW4gdGhlIGZvcm0gb2YgYSB0b3BvbG9naWNhbCBncmFwaCwgdG8gd2hpY2ggYSBzZXJpZXMgb2YgZnVuY3Rpb25zIGFuZCBhbGdvcml0aG1zLCBpbmNsdWRpbmcgdGhlIGxlYXN0IGNvc3QgcGF0aCBbQGRpamtzdHJhMTk1OV0uIFRoZSBhcHBsaWNhdGlvbiBvZiB0aGUgbGVhc3QgY29zdCBwYXRoIGFsZ29yaXRobSBhc3N1bWVzIHRoZSBleGlzdGVuY2Ugb2YgYSBncmFwaCBmb3JtZWQgYnkgYSBzZXQgb2Ygc2V0IG9mIGVkZ2VzIGFuZCBub2Rlcy4gVGhlIGVkZ2VzIGNhbiBiZSBvcmllbnRlZCBvciBub3QgYW5kLCB0byB0aGVzZSwgYSB0cmF2ZWwgY29zdCBpcyBhc3NvY2lhdGVkLCB3aXRoIG9uZSBvciBtb3JlIHBhcmFtZXRlcnMsIG5ldmVyIGxlc3MgdGhhbiB6ZXJvLiBBc3NvY2lhdGluZyBhIHRyYXZlbCBjb3N0IHRvIGVhY2ggYXJjIGluIHRoZSBuZXR3b3JrLCB0aGUgcm91dGUgY29zdCBpcyBkZWZpbmVkIGFzIHRoZSBzdW0gb2YgdGhlIGNvc3RzIG9mIHRoZSBhcmNzIHRoYXQgY29tcG9zZSBpdC4KCiMjIFNwZWVkCgpGb3IgYSAqKmNvbnN0YW50KiogdXJiYW4gY3ljbGluZyBzcGVlZCB0cmF2ZWwgKCpmYWN0b3IgPSAxKiksIGxldCdzIHNheSAxNSBrbS9oLCB3ZSBhc3N1bWUgdGhhdCB0aGUgc3BlZWQgaXMgbGluZWFyIHRvIHRoZSBlZGdlIGV4dGVuc2lvbiwgYW5kIGl0cyBjb3N0IGlzIGl0cyB0cmF2ZWwgdGltZS4KCiQkIGNfe3NwZWVkfSA9IFxmcmFje2xlbmd0aF97W21dfX17c3BlZWRfe1ttL3NdfX0gPSB0aW1lX3tbc119XHRhZ3tFcS4xfSQkCgpNYW55IGZhY3RvcnMgbWF5IGJlIGRldGVybWluYW50IGZvciAqKmN5Y2xpbmcgc3BlZWQqKiwgc3VjaCB0aGUgc3VyZmFjZSBjb25kaXRpb25zLCB0cmFmZmljLCB3ZWF0aGVyLCBtYXNzLCB0eXBlIG9mIGJpY3ljbGUsIGRpcmVjdG5lc3MsIGNvbmZpZGVuY2UsIGV0YyBbQGhvY2htYWlyMjAwNzsgQEZlbGl4MjAxMjsgQGJyb2FjaDIwMTI7IEBicm9hY2gyMDE2XS4gSGVyZSB3ZSB3aWxsIGxvb2sgb25seSB0byAqKnNwZWVkIHJlbGF0ZWQgd2l0aCBncmFkaWVudCoqLCBmcm9tIHRoZSBwZXJzcGVjdGl2ZSBvZiBhIGNvbW1vbiB1cmJhbiBjeWNsaXN0LgoKIyMgU2xvcGUgb3IgZ3JhZGllbnQKCldoZW4gY29tZXMgdG8gY3ljbGluZywgdGhlIHJvdXRlIGdyYWRpZW50IGNhbiBiZSBhIGRldGVybWluYW50IHZhcmlhYmxlIHRvIGNob3NlIGEgcm91dGUgaW5zdGVhZCBvZiBhbiBhbHRlcm5hdGl2ZS4gSXQgaXMgY29tbW9ubHkga25vd24gdGhhdCBjeWNsaXN0cyBhcmUgYXZlcnNlIHRvIHJvYWRzIHdpdGggYW4gYXNjZW5kaW5nIGdyYWRpZW50LCBhbmQgdGhhdCBjeWNsaXN0cyBwcmVmZXIgcm9hZHMgd2l0aCBhIGRlc2NlbmRpbmcgZ3JhZGllbnQuIFRoZSAqKmRpcmVjdGlvbioqIG9mIHRoZSBncmFkaWVudCBpcyBkZXRlcm1pbmFudC4KCkl0IGlzIGFsc28ga25vd24sIGJ5IHRoZSBncmF2aXR5IGxhd3MsIHRoYXQgYW4gb2JqZWN0IHRyYXZlbGluZyBhdCBhIGNvbnN0YW50IHNwZWVkLCBpdHMgc3BlZWQgYmVjb21lcyBmYXN0ZXIgd2hlbiBnb2luZyBkb3duIHRoZSBoaWxsLCBhbmQgc2xvd2VyIHdoZW4gZ29pbmcgdXBoaWxsLiBCdXkgaG93IGRvZXMgaXQgYXBwbGllcyB0byBhIGh1bWFuIGJlaGF2aW9yPyBIb3cgZG9lcyBpdCB2YXJpZXMgd2hlbiBlZmZvcnQsIGZlYXIsIHN0YW1pbmEsIGFuZCByZXdhcmQgcGxheXMgYSByb2xlPyBXaGVuIGRvZXMgYSBjeWNsaXN0IHVzZSB0aGUgYnJlYWsgbGV2ZXJzPyBXaGVuIGRvZXMgYSBjeWNsaXN0IHNsb3dzIGhlciBwYWNlPwoKVGhlIHNsb3BlIGVudGVycyB0aGUgY29zdCBmdW5jdGlvbiBhcyBhIHByb3h5IGZvciBjeWNsaXN0IGVmZm9ydCAtIHRoZSBhbW91bnQgb2YgZW5lcmd5IGEgY3ljbGlzdCBtdXN0IGV4cGVuZCB0byB0cmF2ZWwgb24gYSBzdHJlZXQgd2l0aCBhIGdpdmVuIHNsb3BlIC0gY2F1c2luZyB0aGUgdHJhdmVyc2luZyB0aW1lIHRvIGluY3JlYXNlIGZvciB1cGhpbGwgcm91dGVzLiBPbiBkb3duaGlsbCByb3V0ZXMsIHRoZSBlZmZvcnQgaXMgcmVkdWNlZCBhbmQgdGhlIHRoZW9yZXRpY2FsIHNwZWVkIGlzIGluY3JlYXNlZCwgcmVkdWNpbmcgdGhlaXIgdHJhdmVyc2luZyB0aW1lLgoKQHNjb3R0MjAyMCBkZXNpZ25lZCBhbiBleHBlcmltZW50IGZvciBoaWtpbmcsIGFuZCBhcHBsaWVkIGEgcnVsZSBzYXlpbmcgIipBIDEwJSBncmFkZSBpbmNsaW5lIGN1dHMgeW91ciBzcGVlZCBpbiBoYWxmIioqLioqKiBJbiB0aGVpciByZXN1bHRzLCB0aGV5IHN1Z2dlc3RlZCBhbiBlcXVhdGlvbiB0byBjYWxjdWxhdGUgdXBoaWxsIHNwZWVkIChmb3IgaGlraW5nKToKCiQkCnNwZWVkID0gc3BlZWRfe2ZsYXR9ICogZV57KC0wLjA0KnNsb3BlKX1cdGFne0VxLjJ9CiQkCgpXaGljaCByZXN1bHRzIHRoYXQgd2l0aCBhIGdyYWRlIG9mIDIwJSwgb25lIGNhbiB3YWxrIGF0IGEgc3BlZWQgb2YgMS43OCBrbS9oIGl0IGhlciBob3Jpem9udGFsIHNwZWVkIHdhcyA0IGttL2guIFdoZW4gYXBwbHlpbmcgdG8gY3ljbGluZywgZm9yIGEgZmxhdCBzcGVlZCBvZiAxNWttL2gsIHRoZSBzYW1lIGluY2xpbmUgd291bGQgYmUgcmlkZSBhdCBhIDYuNzQga20vaCBzcGVlZCwgd2hpY2ggaXMgbm90IHJlbGlhYmxlIGZvciBhIHN0YW5kYXJkIGN5Y2xpc3QuCgpBbHNvLCB0aGUgZXh0ZW5zaW9uIG9mIHRoZSByb2FkIHNlZ21lbnQgZW50ZXJzIGluIHRoZSBjb3N0IGZ1bmN0aW9uOiBmb3IgbG9uZ2VyIHNlZ21lbnRzIGF0IGEgZ2l2ZW4gZ3JhZGllbnQsIHRoZSBlZmZvcnQgb2YgdGhlIGN5Y2xpc3QgaXMgaGlnaGVyIHRoYW4gZm9yIGEgc2hvcnRlciBzZWdtZW50IHdpdGggdGhlIHNhbWUgZ3JhZGllbnQuCgpGaWd1cmUgMSBzaG93cyB0aGUgbWF4aW11bSBsZW5ndGhzIG9mIHVwaGlsbCBncmFkaWVudCBhY2NlcHRhYmxlIHRvIGN5Y2xpc3RzIFtAYXVzdHJvYWRzMjAwOV0uIEl0IGNvbnNpZGVycyB0aGF0IG92ZXIgYSAzJSBzbG9wZSwgdGhlIGxlbmd0aCBzaG91bGQgYmUgdGFrZW4gaW50byBhY2NvdW50LgoKIVtGaWcuIDEgLSBEZXNpcmFibGUgdXBoaWxsIGdyYWRpZW50cyBmb3IgZWFzZSBvZiBjeWNsaW5nIChBdXN0cm9hZHMgMjAwOSldKFNwZWVkU2xvcGVGYWN0b3JfZmlsZXMvYXVzdHJvYWRzMjAwOV9ncmFkaWVudC5QTkcpCgpTb21ldGltZXMgaXQgaXMgbW9yZSBlZmZpY2llbnQgdG8gdHJhdmVsIGEgbG9uZ2VyIGRpc3RhbmNlIHdpdGggbGVzcyBzdGVlcCBncmFkaWVudHMgcmF0aGVyIHRoYW4gYSBzaG9ydGVyIGRpc3RhbmNlIG9uIGEgc3RlZXAgZ3JhZGllbnQuIE90aGVyIHRpbWVzIHRoZSBleHRyYSBkaXN0YW5jZSB0byByaWRlIHRvIG92ZXJjb21lIHRoZSBncmFkaWVudCBpcyBub3Qgc28gd29ydGh3aGlsZSBhbmQgdGhlIGN5Y2xpc3QgY2hvb3NlcyB0byByaWRlIHVwIHRoZSBzdGVlcGVyIGdyYWRpZW50IGJ5IGhhbmQuIFRoZSBtYXhpbXVtIGNyb3NzaW5nIGNvc3QgcGVuYWx0eSB3YXMgY29uc2lkZXJlZCB0byBiZSAxMCB0aW1lcyBmb3IgdGhpcyBzaXR1YXRpb24sIGkuZS4gZm9yIGVkZ2VzIHdpdGggYSBncmFkaWVudCBncmVhdGVyIHRoYW4gMjAlLgoKVmVyeSBzdGVlcCByb2FkcyBhcmUgYSBwcm9ibGVtIG5vdCBvbmx5IGZvciB1cGhpbGwgcmlkaW5nLCBidXQgYWxzbyBmb3IgZG93bmhpbGwgcmlkaW5nLCBiZWNhdXNlIGEgbWVjaGFuaWNhbCBmYWlsdXJlIGluIHRoZSBicmFrZXMgY2FuIGxlYWQgdG8gYSBkYW5nZXJvdXMgc2l0dWF0aW9uIGZvciB0aGUgcmlkZXIsIHdobyBhbHNvIGhhcyB0byBleHBlbmQgc29tZSBlZmZvcnQgYW5kIHNraWxsIHRvIGtlZXAgdGhlIGJpa2UgYmFsYW5jZWQgYW5kIGNvbnRyb2wgdGhlIGFkZGl0aW9uYWwgcmlzay4KCiFbRmlnLiAyIC0gV29ybGQncyBzdGVlcGVzdCBzdHJlZXQsIHdpdGggYSAzNSUgaW5jbGluZSBmb3Igb3ZlciAxNjEgbWV0ZXJzLiBCYWxkd2luIFN0cmVldCwgRHVuZWRpbiwgTmV3IFplYWxhbmQgKFBob3RvOiBXaWtpcGVkaWEpXShodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zL2IvYjgvRHVuZWRpbkJhbGR3aW5TdHJlZXRfUGFya2VkX0Nhci5qcGcpe3dpZHRoPSI1MDAiIGFsaWduPSJcImNlbnRlciJ9CgpEb3duaGlsbCBlZGdlcyBtb3N0bHkgcmVzdWx0IGluIGJlbmVmaXQgdG8gdGhlIGN5Y2xpc3QsIGluY3JlYXNpbmcgaXRzIHNwZWVkLiBIb3dldmVyLCB0aGlzIGlzIG5vdCBsaW5lYXIsIGRlY3JlYXNpbmcgZnJvbSBzbG9wZSB2YWx1ZXMgYWJvdmUgMTMlLCBhbmQgbWF5IGV2ZW4gc2xvdyBkb3duIHRoZSBzcGVlZCAocmVsYXRpdmUgdG8gdGhlIGF2ZXJhZ2UgZmxhdCBzcGVlZCkgaXQgdG9vIHN0ZWVwLgoKIyBTcGVlZC1TbG9wZSBGYWN0b3IKCkFmdGVyIGFuIGl0ZXJhdGl2ZSBwcm9jZXNzLCB3aGljaCBjb25zaWRlcmVkIHRoZSBjeWNsaXN0IGVmZm9ydCBhcyBhIGZ1bmN0aW9uIG9mIHNsb3BlIGFiYWN1c2VzIHN1Z2dlc3RlZCBieSBAYWFzaHRvMTk5OSBhbmQgQGF1c3Ryb2FkczIwMDkgKHAuIDQxKSwgYW5kIGFsc28gYSBjb3N0IGZvcm11bGEgZGV2ZWxvcGVkIGJ5IEBwcmljZTIwMDgsIEVxLiAzIHByZXNldHMgYSBmdW5jdGlvbiB0aGF0IG1vZGVscyB0aGUgc2xvcGUgZmFjdG9yIGJhc2VkIG9uIHRoZSBzbG9wZSBbJV0gYW5kIGxlbmd0aCBbbV0gb2YgZWFjaCByb2FkIHNlZ21lbnQuIFRoaXMgZnVuY3Rpb24sIHdoaWNoIGlzIG5vbi1zeW1tZXRyaWMgYW5kIG5vbi1tb25vdG9uaWMsIHJlcHJvZHVjZXMgdGhlIGVzc2VudGlhbCBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIHNsb3BlL2VmZm9ydCByZWxhdGlvbnNoaXAuCgpJbiBhZGRpdGlvbiB0byB0aGlzIGZ1bmN0aW9uLCBhIHNlY29uZCBzZXQgb2YgY3JpdGVyaWEgaXMgYXBwbGllZCAoKmcqKSwgd2hpY2ggaW5jcmVhc2VzIHRoZSAqc2xvcGUgZmFjdG9yKiB3aGVuIHJvYWQgc2VnbWVudHMgaGF2ZSBhIGdpdmVuIGxlbmd0aCBbbV0gYW5kIHNsb3BlIFslXSwgd2l0aCBpbnRlcnZhbHMgYXMgc3VnZ2VzdGVkIGJ5IEBjZWFwLWNlbnRyb2RlZXN0dWRvc2RlYXJxdWl0ZWN0dXJhcGFpc2FnaXN0YSAuIEVxLiA0IHNob3dzIHRoYXQgZWRnZXMgd2l0aCBncmFkaWVudCBiZXR3ZWVuIDAgYW5kIDIwIGluIHRoZSB1cHdhcmQgZGlyZWN0aW9uIGFyZSB0aHVzIHBlbmFsaXplZCBieSBhY2N1bXVsYXRpb24gb2YgZWZmb3J0LgoKJCRzbG9wZSBmYWN0b3JfeyhzbG9wZSxsZW5ndGgpfSA9IFxiZWdpbntjYXNlc30gMS41ICZcTGVmdGFycm93IFxxdWFkIHNsb3BlIDwtMzAgXFwKMSsgMlxmcmFjezAuN317MTN9ICogc2xvcGUgK1xmcmFjezAuN317MTNeMn0qc2xvcGVeMiAmXExlZnRhcnJvdyAtMzAgXGxlcSBzbG9wZSA8MCBcXAoxKyAoXGZyYWN7c2xvcGV9e2dfeyhzbG9wZSwgbGVuZ3RoKX19KV4yICZcTGVmdGFycm93IDAgXGxlcSBzbG9wZSBcbGVxMjAgXFwKMTAgJlxMZWZ0YXJyb3cgMjAgPHNsb3BlIApcZW5ke2Nhc2VzfVx0YWd7RXEuM30gJCQKCldpdGgsCgokJGdfeyhzbG9wZSxsZW5ndGgpfSA9IFxiZWdpbntjYXNlc30gNCAmXExlZnRhcnJvdyAxMDxzbG9wZSBcbGVxIDEzIFxxdWFkXHdlZGdlXHF1YWQgIGxlbmd0aCA+IDE1XFwKNC41ICZcTGVmdGFycm93IDggPHNsb3BlIFxsZXEgMTAgXHF1YWRcd2VkZ2VccXVhZCAgbGVuZ3RoID4gMzAgXFwKNSAmXExlZnRhcnJvdyA1IDxzbG9wZSBcbGVxIDggXHF1YWRcd2VkZ2VccXVhZCAgbGVuZ3RoID4gNjAgXFwKNiAmXExlZnRhcnJvdyAzIDxzbG9wZSBcbGVxIDUgXHF1YWRcd2VkZ2VccXVhZCAgbGVuZ3RoID4gMTIwIFxcCjcgJlxMZWZ0YXJyb3cgb3RoZXJ3aXNlIApcZW5ke2Nhc2VzfVx0YWd7RXEuNH0gJCQKCkFzIHRoZSBtYXggcGVuYWxpemF0aW9uIGdvaW5nIHVwaGlsbCBzaG91bGQgbm90IGJlIDEwIHRpbWVzIG1vcmUgdGhhbiB0aGUgZmxhdCBzcGVlZCwgd2UgYWRkIGFub3RoZXIgY29uZGl0aW9uIHRvIG1heGltaXplIHRoZSAqKnNsb3BlIGZhY3RvcioqLCBhcyBmb2xsb3dzOgoKJCRzbG9wZSBmYWN0b3JfeyhzbG9wZSxsZW5ndGgpfWFkanN0ID0gXGJlZ2lue2Nhc2VzfSAKMTAgJlxMZWZ0YXJyb3cgc2xvcGUgPjEzIFxxdWFkXHdlZGdlXHF1YWQgIGxlbmd0aCA+MTUgXFwKMTAgJlxMZWZ0YXJyb3cgc2xvcGUgPjEwIFxxdWFkXHdlZGdlXHF1YWQgIGxlbmd0aCA+MzAgXFwKMTAgJlxMZWZ0YXJyb3cgc2xvcGUgPjggXHF1YWRcd2VkZ2VccXVhZCAgbGVuZ3RoID42MCBcXAoxMCAmXExlZnRhcnJvdyBzbG9wZSA+NSBccXVhZFx3ZWRnZVxxdWFkICBsZW5ndGggPjEyMCBcXApcZW5ke2Nhc2VzfVx0YWd7RXEuNX0gJCQKCjwhLS0gJCRzbG9wZWZhY3Rvcl97KHNsb3BlLGxlbmd0aCl9ID4gMTAgXFJpZ2h0YXJyb3cgc2xvcGUgZmFjdG9yX3soc2xvcGUsbGVuZ3RoKX1hZGpzdCA9IDEwIFx0YWd7RXEuNH0gJCQtLT4KCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiNnIGZ1bmN0aW9uCmcgPSBmdW5jdGlvbihzbG9wZSwgbGVuZ3RoKXsKICBpZmVsc2UoKHNsb3BlID4gMTAgJiBzbG9wZSA8PSAxMyAmIGxlbmd0aCA+IDE1KSwgNCwgCiAgICBpZmVsc2UoKHNsb3BlID4gOCAmIHNsb3BlIDw9IDEwICYgbGVuZ3RoID4gMzApLCA0LjUsCiAgICAgIGlmZWxzZSgoc2xvcGUgPiA1ICYgc2xvcGUgPD0gOCAmIGxlbmd0aCA+IDYwKSwgNSwgCiAgICAgICAgaWZlbHNlKChzbG9wZSA+IDMgJiBzbG9wZSA8PSA1ICYgbGVuZ3RoID4gMTIwKSwgNiwgCiAgICAgICAgICAgICAgIDcpKSkpCn0KCiNzbG9wZS1mYWN0b3IgZnVuY3Rpb24Kc3BlZWRmYWN0b3IgPSBmdW5jdGlvbihzbG9wZSwgbGVuZ3RoLCBnKSB7CiAgaWZlbHNlKGlmZWxzZSgoc2xvcGUgPCAtMzApLDEuNSwKICAgICAgICBpZmVsc2Uoc2xvcGUgPCAwLCAxICsgKDAuNyAvIDEzKSAqIDIgKiBzbG9wZSArIDAuNyAvICgxMyBeIDIpICogc2xvcGUgXiAyLAogICAgICAgICAgIGlmZWxzZSgoc2xvcGUgPiAyMCksIDEwLAogICAgICAgICAgICAgIGlmZWxzZSgoc2xvcGUgPj0gMCAmIHNsb3BlIDw9IDIwKSwgMSArIChzbG9wZSAvIGcpIF4gMiwKICAgICAgICAgICAgICAgICAgTkEpKSkpID4xMCwgMTAsCiAgICAgIGlmZWxzZSgoc2xvcGUgPCAtMzApLDEuNSwKICAgICAgICBpZmVsc2Uoc2xvcGUgPCAwLCAxICsgKDAuNyAvIDEzKSAqIDIgKiBzbG9wZSArIDAuNyAvICgxMyBeIDIpICogc2xvcGUgXiAyLAogICAgICAgICAgIGlmZWxzZSgoc2xvcGUgPiAyMCksIDEwLAogICAgICAgICAgICAgIGlmZWxzZSgoc2xvcGUgPj0gMCAmIHNsb3BlIDw9IDIwKSwgMSArIChzbG9wZSAvIGcpIF4gMiwKICAgICAgICAgICAgICAgICAgTkEpKSkpKQp9CiNUaGVyZSBpcyBwcm9iYWJseSBhIHdheSB0byB3cml0ZSB0aGlzIGNvZGUgY2xlYW5lci4uLgpgYGAKClRoaXMgZnVuY3Rpb25zIHJlc3VsdCBpbiBhIHNwZWVkIGZhY3RvciAoaW4gKmxvZyogc2NhbGUpIHRoYXQgdmFyaWVzIGFzIHRoaXM6CgpgYGB7ciBlY2hvPUZBTFNFfQpjdXJ2ZSgKICBleHByID0gc3BlZWRmYWN0b3Ioc2xvcGUgPSB4LCBnID0gNywgbGVuZ3RoID0gMTIwKSwKICBmcm9tID0gLTM1LCB0byA9IDI1LCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDMsIGxvZyA9ICJ5IiwKICB4bGFiID0gInNsb3BlIFslXSIsIHlsYWIgPSAic2xvcGUgZmFjdG9yIikKY3VydmUoCiAgZXhwciA9IHNwZWVkZmFjdG9yKHNsb3BlID0geCwgZyA9IDQsIGxlbmd0aCA9IDEyMCksCiAgZnJvbSA9IDEwLCB0byA9IDI1LCBjb2wgPSAicHVycGxlIiwgbHdkID0gMiwgbHR5ID0gNSwgbG9nID0gInkiLCBhZGQgPSBUKQpjdXJ2ZSgKICBleHByID0gc3BlZWRmYWN0b3Ioc2xvcGUgPSB4LCBnID0gNC41LCBsZW5ndGggPSAxMjApLAogIGZyb20gPSA4LCB0byA9IDI1LCBjb2wgPSAiZ3JleSIsIGx3ZCA9IDIsIGx0eSA9IDQsIGxvZyA9ICJ5IiwgYWRkID0gVCkKY3VydmUoCiAgZXhwciA9IHNwZWVkZmFjdG9yKHNsb3BlID0geCwgZyA9IDUsIGxlbmd0aCA9IDEyMCksCiAgZnJvbSA9IDUsIHRvID0gMjUsIGNvbCA9ICJvcmFuZ2UiLCBsd2QgPSAyLCBsdHkgPSAzLCBsb2cgPSAieSIsIGFkZCA9IFQpCmN1cnZlKAogIGV4cHIgPSBzcGVlZGZhY3RvcihzbG9wZSA9IHgsIGcgPSA2LCBsZW5ndGggPSAxMjApLAogIGZyb20gPSAzLCB0byA9IDI1LCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMiwgbG9nID0gInkiLCBhZGQgPSBUKQpjdXJ2ZSgKICBleHByID0gc3BlZWRmYWN0b3Ioc2xvcGUgPSB4LCBnID0gNywgbGVuZ3RoID0gMTIwKSwKICBmcm9tID0gLTM1LCB0byA9IDI1LCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIsIGxvZyA9ICJ5IiwgYWRkID0gVCkKYWJsaW5lKGggPSAxLCB2ID0gMCwgbHR5ID0gMykKdGl0bGUobWFpbiA9ICJTbG9wZS1TcGVlZCBmdW5jdGlvbiIpCmxlZ2VuZCgtMzAsIDksCiAgbGVnZW5kID0gYygKICAgICJzcGVlZCBmYWN0b3IgKGJhc2UpIiwKICAgICJzbG9wZSA+MyUsIGxlbmd0aCA+MTIwIG0iLAogICAgInNsb3BlID41JSwgbGVuZ3RoID42MCBtIiwKICAgICJzbG9wZSA+OCUsIGxlbmd0aCA+MzAgbSIsCiAgICAic2xvcGUgPjEwJSwgbGVuZ3RoID4xNSBtIiksCiAgY29sID0gYygiYmx1ZSIsICJyZWQiLCAib3JhbmdlIiwgImdyZXkiLCAicHVycGxlIiksCiAgbHR5ID0gMTo1LCBjZXggPSAwLjksIGx3ZCA9IGMoMywgMiwgMiwgMiwgMiksIGJveC5sdHkgPSAwKQpgYGAKCkFuZCwgZmluYWxseSwgd2UgZGl2aWRlIHRoZSBjb25zdGFudCBmbGF0IHNwZWVkIGJ5IHRoZSAqc2xvcGUgZmFjdG9yKiBhcyA6CgokJApzcGVlZCA9IFxmcmFje3NwZWVkX3tmbGF0fX17c2xvcGUgZmFjdG9yfVx0YWd7RXEuNX0KJCQKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNwZWVkID0gc3BlZWRmbGF0IC8gc3BlZWRmYWN0b3Ioc2xvcGUsIGxlbmd0aCwgZyA9IGcoc2xvcGUsIGxlbmd0aCkpCmBgYAoKIyMgV2hhdCBkb2VzIGl0IG1lYW5zIHVwaGlsbD8KCldoZW4gZ29pbmcgKip1cGhpbGwqKiwgc3BlZWQgd2lsbCByZWR1Y2UsIGFuZCBsb25nZXIgdGhlIHJvYWQgc2VnbWVudHMsIGhpZ2hlciB0aGUgZGVub21pbmF0b3IsIGFuZCBzbG93ZXIgdGhlIGN5Y2xpc3Qgc3BlZWQuCgpGb3IgaW5zdGFuY2UsIGlmIGFzc3VtaW5nIGEgY29uc3RhbnQgZmxhdCBzcGVlZCBvZiAxNSBrbS9oIGFuZCBhIHJvYWQgd2l0aCA4MCBtIGFuZCAzJSB1cGhpbGwsIGEgY3ljbGlzdCB3aWxsIHJlZHVjZSB0byAxMi42NyBrbS9oCgpgYGB7cn0Kc3BlZWRmbGF0ID0gMTUKc2xvcGUgPSAzCmxlbmd0aCA9IDUwCnNwZWVkZmxhdCAvIHNwZWVkZmFjdG9yKHNsb3BlLCBsZW5ndGgsIGcgPSBnKHNsb3BlLCBsZW5ndGgpKQpgYGAKCklmIGl0IGlzIHNsaWdodGx5ICoqc3RlZXBlcioqLCB3aXRoIDQlIHVwaGlsbCwgYSBjeWNsaXN0IHdpbGwgcmVkdWNlIHRvIDExLjMxIGttL2gKCmBgYHtyfQpzbG9wZSA9IDQKbGVuZ3RoID0gNTAKc3BlZWRmbGF0IC8gc3BlZWRmYWN0b3Ioc2xvcGUsIGxlbmd0aCwgZyA9IGcoc2xvcGUsIGxlbmd0aCkpCmBgYAoKSWYgdGhhdCBzYW1lIHNlZ21lbnQgaXMgKipsb25nZXIqKiwgYSBjeWNsaXN0IHdpbGwgcmVkdWNlIHRvIDEwLjM4IGttL2gKCmBgYHtyfQpzbG9wZSA9IDQKbGVuZ3RoID0gMTUwCnNwZWVkZmxhdCAvIHNwZWVkZmFjdG9yKHNsb3BlLCBsZW5ndGgsIGcgPSBnKHNsb3BlLCBsZW5ndGgpKQpgYGAKCkZvciAqKmhpZ2hlciBncmFkaWVudHMqKiwgdGhlIHNwZWVkIGRlY3JlYXNlcyB3aXRoIG1vcmUgc2Vuc2l0aXZpdHkgcmVnYXJkaW5nIHRoZSAqKnNlZ21lbnQgbGVuZ3RoKiouCgpgYGB7cn0Kc2xvcGUgPSA2Cmxlbmd0aCA9IDYwCnNwZWVkZmxhdCAvIHNwZWVkZmFjdG9yKHNsb3BlLCBsZW5ndGgsIGcgPSBnKHNsb3BlLCBsZW5ndGgpKQpgYGAKCmBgYHtyfQpzbG9wZSA9IDYKbGVuZ3RoID0gODAKc3BlZWRmbGF0IC8gc3BlZWRmYWN0b3Ioc2xvcGUsIGxlbmd0aCwgZyA9IGcoc2xvcGUsIGxlbmd0aCkpCmBgYAoKQW5kIGZvciAqKnZlcnkgc3RlZXAgc3RyZWV0cyoqLCBjeWNsaW5nIHNwZWVkIG1heSByZWR1Y2UgdG8gd2Fsa2luZyBzcGVlZC4KCmBgYHtyfQpzbG9wZSA9IDkKbGVuZ3RoID0gNDAKc3BlZWRmbGF0IC8gc3BlZWRmYWN0b3Ioc2xvcGUsIGxlbmd0aCwgZyA9IGcoc2xvcGUsIGxlbmd0aCkpCmBgYAoKIyMgQW5kIGRvd25oaWxsPwoKSW4gYW5vdGhlciBoYW5kLCB3aGVuIGdvaW5nICoqZG93bmhpbGwqKiwgc3BlZWRzIHdpbGwgaW5jcmVhc2UgdW50aWwgaXQgZ2V0cyAzLjMzeCBmYXN0ZXIsIHdoZW4gdGhlIGdyYWRpZW50IGlzIDEzJS4gRm9yIHN0ZWVwZXIgZ3JhZGllbnRzLCB0aGUgY3ljbGlzdCB3aWxsIHRlbmQgdG8gYnJlYWssIGFuZCB0aGUgc3BlZWQgd2lsbCBiZSBsb3dlci4KClVudGlsIHRoZSBtb21lbnQgd2hlbiBpdCBnZXRzIHNvIHNjYXJ5IHRvIHJpZGUgaXQgKGFnYWluLCBmb3IgYSByZWd1bGFyIHVyYmFuIGN5Y2xpc3Qgd2l0aCBtaWxkIGV4cGVyaWVuY2UpLCB0aGF0IGl0IHdpbGwgdGFrZSBtb3JlIHRpbWUgdG8gdHJhdmVsIHRoYXQgcm9hZCB0aGFuIGlmIGl0IHdhcyBmbGF0LgoKYGBge3J9Cmxlbmd0aCA9IDEwMApzbG9wZSA9IC04CnNwZWVkZmxhdCAvIHNwZWVkZmFjdG9yKHNsb3BlLCBsZW5ndGgsIGcgPSBnKHNsb3BlLCBsZW5ndGgpKQpzbG9wZSA9IC0xMwpzcGVlZGZsYXQgLyBzcGVlZGZhY3RvcihzbG9wZSwgbGVuZ3RoLCBnID0gZyhzbG9wZSwgbGVuZ3RoKSkKc2xvcGUgPSAtMjAKc3BlZWRmbGF0IC8gc3BlZWRmYWN0b3Ioc2xvcGUsIGxlbmd0aCwgZyA9IGcoc2xvcGUsIGxlbmd0aCkpCnNsb3BlID0gLTI1CnNwZWVkZmxhdCAvIHNwZWVkZmFjdG9yKHNsb3BlLCBsZW5ndGgsIGcgPSBnKHNsb3BlLCBsZW5ndGgpKQpzbG9wZSA9IC0zMApzcGVlZGZsYXQgLyBzcGVlZGZhY3RvcihzbG9wZSwgbGVuZ3RoLCBnID0gZyhzbG9wZSwgbGVuZ3RoKSkKYGBgCgojIENhc2UgU3R1ZHkKCkhlcmUgd2Ugd2lsbCB1c2UgYSBzbWFsbCByb2FkIG5ldHdvcmsgZnJvbSBkb3dudG93biBMaXNib24gKFBvcnR1Z2FsKSwgcmV0cmlldmVkIGZyb20gYHNsb3BlcygpYCBwYWNrYWdlLCB0byB0ZXN0IHRoZSBzcGVlZC1zbG9wZSBmYWN0b3IuCgpUaGlzIGFyZWEgaXMga25vd24gZm9yIGEgZmxhdCBhbmQgb3J0aG9nb25hbCBzZXQgb2Ygc3RyZWV0cywgc3Vycm91bmRlZCBieSBvcmdhbmljIGFuZCBzdGVlcCBzdHJlZXRzLCByYW5naW5nIGZyb20gMCB0byAyMSUuCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojdXNlIGV4YW1wbGUgZnJvbSBzbG9wZXMoKQpEQVRBID0gc2xvcGVzOjpsaXNib25fcm9hZF9uZXR3b3JrCkRBVEEkc2xvcGVfZGlyZWN0ZWQgPSBzbG9wZV9yYXN0ZXIoREFUQSwgZGVtID0gZGVtX2xpc2Jvbl9yYXN0ZXIsIGRpcmVjdGVkID0gVFJVRSkgIyBuZWdhdGl2ZSBpcyBkb3duaGlsbApEQVRBJHNsb3BlID0gMTAwKmFicyhEQVRBJHNsb3BlX2RpcmVjdGVkKQpEQVRBJHNsb3BlX2NsYXNzID0gREFUQSRzbG9wZSAlPiUgCiAgY3V0KAogICAgYnJlYWtzID0gYygwLCAzLCA1LCA4LCAxMCwgMjAsIEluZiksCiAgICBsYWJlbHMgPSBjKCIwLTM6IGZsYXQiLCAiMy01OiBtaWxkIiwgIjUtODogbWVkaXVtIiwgIjgtMTA6IGhhcmQiLCAiMTAtMjA6IGV4dHJlbWUiLCAiPjIwOiBpbXBvc3NpYmxlIiksCiAgICByaWdodCA9IEYKICApCnBhbHJlZGdyZWVuID0gYygiIzI2NzMwMCIsICIjNzBBODAwIiwgIiNGRkFBMDAiLCAiI0U2MDAwMCIsICIjQTgwMDAwIiwgIiM3MzAwMDAiKQp0bWFwX21vZGUoInZpZXciKQp0bV9zaGFwZShEQVRBKSArCiAgdG1fbGluZXMoCiAgICBjb2wgPSAic2xvcGVfY2xhc3MiLAogICAgcGFsZXR0ZSA9IHBhbHJlZGdyZWVuLAogICAgbHdkID0gMiwKICAgIGlkID0gInNsb3BlIikKYGBgCgpGb3IgdGhlIHB1cnBvc2Ugb2YgdGhlIGV4YW1wbGUsIHdlIHdpbGwgYXNzaWduIGEgZGlyZWN0aW9uIG9mIHRoZSBncmFkaWVudCwgb25jZSB0aGF0IGl0IHdhcyBub3QgZGVmaW5lZC4KCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNhc3NpZ24gYSBkaXJlY3Rpb24gb2Ygc2xvcGUsIGZvciB0aGUgcHVycG9zZSBvZiB0aGUgZXhhbXBsZQpEQVRBJGRpcmVjdGlvbiA9ICJGVCIgI0Zyb20tVG8KREFUQSRkaXJlY3Rpb25bREFUQSRzbG9wZV9kaXJlY3RlZCA8IDBdID0gIlRGIiAjVG8tRnJvbQoKbWFwdmlldzo6bWFwdmlldyhEQVRBWyJkaXJlY3Rpb24iXSwgIHNlbGZjb250YWluZWQ9VFJVRSkKYGBgCgpBbmQgbm93IGNvbXB1dGUgdGhlIGxlbmd0aCwgc2xvcGUsIGFuZCB0aGUgc3BlZWQtc2xvcGUgZmFjdG9yIGZvciBlYWNoIHNlZ21lbnQuIFdlIGNhbiBvYnNlcnZlLCBpbiBhIGxvZ2FyaXRobWljIHktc2NhbGUsIHRoYXQgdGhlcmUgYXJlIGEgbG90IG9mIGZsYXQgb3IgYWxtb3N0IGZsYXQgc2VnbWVudHMgKGZhY3RvciBhcm91bmQgMSksIHNvbWUgdXBoaWxsIHNlZ21lbnRzIHRoYXQgcmVhY2ggZmFjdG9yIDEwLCBhbmQgc29tZSBkb3duaGlsbCBzZWdtZW50cyB0aGF0IHJlYWNoIGZhY3RvciAwLjMuCgpgYGB7cn0KI2xlbmd0aCBhbmQgc2xvcGUKREFUQSRsZW5ndGggPSBzdF9sZW5ndGgoREFUQSkgfD4gdW5pdHM6OmRyb3BfdW5pdHMoKSAjaW4gbWV0ZXJzCkRBVEEkc2xvcGVbREFUQSRkaXJlY3Rpb24gPT0gIlRGIl0gPSAtKERBVEEkc2xvcGVbREFUQSRkaXJlY3Rpb24gPT0gIlRGIl0pCnNsb3BlID0gREFUQSRzbG9wZQpsZW5ndGggPSBEQVRBJGxlbmd0aAoKI3NwZWVkLXNsb3BlIGZhY3RvcgpnID0gZyhzbG9wZSwgbGVuZ3RoKQpzcGYgPSBzcGVlZGZhY3RvcihzbG9wZSwgbGVuZ3RoLCBnKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmN1cnZlKAogIGV4cHIgPSBzcGVlZGZhY3RvcihzbG9wZSA9IHgsIGcgPSA3LCBsZW5ndGggPSAxMjApLAogIGZyb20gPSAtMzUsIHRvID0gMzAsIGNvbCA9ICJibHVlIiwgbHdkID0gMSwgbG9nID0gInkiLAogIHhsYWIgPSAic2xvcGUgWyVdIiwgeWxhYiA9ICJzbG9wZSBmYWN0b3IiKQpjdXJ2ZSgKICBleHByID0gc3BlZWRmYWN0b3Ioc2xvcGUgPSB4LCBnID0gNCwgbGVuZ3RoID0gMTIwKSwKICBmcm9tID0gMTAsIHRvID0gMzAsIGNvbCA9ICJwdXJwbGUiLCBsd2QgPSAxLCBsdHkgPSA1LCBsb2cgPSAieSIsIGFkZCA9IFQpCmN1cnZlKAogIGV4cHIgPSBzcGVlZGZhY3RvcihzbG9wZSA9IHgsIGcgPSA0LjUsIGxlbmd0aCA9IDEyMCksCiAgZnJvbSA9IDgsIHRvID0gMzAsIGNvbCA9ICJncmV5IiwgbHdkID0gMSwgbHR5ID0gNCwgbG9nID0gInkiLCBhZGQgPSBUKQpjdXJ2ZSgKICBleHByID0gc3BlZWRmYWN0b3Ioc2xvcGUgPSB4LCBnID0gNSwgbGVuZ3RoID0gMTIwKSwKICBmcm9tID0gNSwgdG8gPSAzMCwgY29sID0gIm9yYW5nZSIsIGx3ZCA9IDEsIGx0eSA9IDMsIGxvZyA9ICJ5IiwgYWRkID0gVCkKY3VydmUoCiAgZXhwciA9IHNwZWVkZmFjdG9yKHNsb3BlID0geCwgZyA9IDYsIGxlbmd0aCA9IDEyMCksCiAgZnJvbSA9IDMsIHRvID0gMzAsIGNvbCA9ICJyZWQiLCBsd2QgPSAxLCBsdHkgPSAyLCBsb2cgPSAieSIsIGFkZCA9IFQpCmN1cnZlKAogIGV4cHIgPSBzcGVlZGZhY3RvcihzbG9wZSA9IHgsIGcgPSA3LCBsZW5ndGggPSAxMjApLAogIGZyb20gPSAtMzUsIHRvID0gMzAsIGNvbCA9ICJibHVlIiwgbHdkID0gMSwgbG9nID0gInkiLCBhZGQgPSBUKQphYmxpbmUoaCA9IDEsIHYgPSAwLCBsdHkgPSAzKQpwb2ludHMoc2xvcGUsIHNwZiwgbG9nPSJ5IiwgYWRkID0gVCkgI2Zyb20gdGhlIHJlc3VsdHMKYGBgCgpCeSBkZWZpbmluZyBhIGZsYXQgc3BlZWQgb2YgYDE2IGttL2hgLCBpdCByZXN1bHRzIGluIHNlZ21lbnRzIHRoYXQgYXJlIGN5Y2xlZCB1cCB0byA2IG1pbnV0ZXMgdXBoaWxsLCBhbmQgYXQgYSBtYXhpbXVtIHNwZWVkIG9mIDUzIGttL2guCgpgYGB7cn0KI3NldCBzcGVlZApzcGVlZGZsYXQgPSAxNiAjc2V0IGhlcmUgaW4ga20vaCAoY29udmVydCB0byBtL3M6IHNwZWVkLzMuNikKCkRBVEEkc3BlZWRmYWN0b3IgPSBzcGYKREFUQSRzcGVlZCA9IHNwZWVkZmxhdCAvIERBVEEkc3BlZWRmYWN0b3IKREFUQSR0aW1lID0gbGVuZ3RoIC8gREFUQSRzcGVlZCozLjYKCm1hcHZpZXc6Om1hcHZpZXcoREFUQSwgemNvbCA9ICJzcGVlZCIpCnN1bW1hcnkoREFUQSRzcGVlZCkKbWFwdmlldzo6bWFwdmlldyhEQVRBLCB6Y29sID0gInRpbWUiKQpzdW1tYXJ5KERBVEEkdGltZSkKYGBgCgpUaGlzIGlzIGEgd29yayBpbiBwcm9ncmVzcy4gKipTdWdnZXN0aW9ucyBhbmQgY29tbWVudHMgYXJlIHdlbGNvbWUqKiEgOikKW2dpdGh1Yi5jb20vVS1TaGlmdC9EZWNsaXZlcy1SZWRlVmlhcmlhL3RyZWUvbWFpbi9TcGVlZFNsb3BlRmFjdG9yXShodHRwczovL2dpdGh1Yi5jb20vVS1TaGlmdC9EZWNsaXZlcy1SZWRlVmlhcmlhL3RyZWUvbWFpbi9TcGVlZFNsb3BlRmFjdG9yKQoKIyBDb25jbHVzaW9uCgpGb3IgYSBoaWxseSBjaXR5LCB0aGUgc2xvcGUgZmFjdG9yIGlzIGEgZ29vZCBhcHByb2FjaCB0byBtb2RlbCB0aGUgY29zdCBvZiB0aGUgY3ljbGlzdCBlZmZvcnQgaW4gYSByb3V0aW5nIGFsZ29yaXRobS4gSXQgaXMgYSBub24tbGluZWFyIGFuZCBub24tbW9ub3RvbmljIGZ1bmN0aW9uIHRoYXQgcmVwcm9kdWNlcyB0aGUgZXNzZW50aWFsIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgc2xvcGUvZWZmb3J0IHJlbGF0aW9uc2hpcCwgYW5kIGl0IGlzIGEgZ29vZCBwcm94eSBmb3IgY3ljbGlzdCBlZmZvcnQuIEl0IGlzIGFsc28gYSBnb29kIGFwcHJvYWNoIHRvIG1vZGVsIHRoZSBjeWNsaXN0IHNwZWVkIGluIGEgcm9hZCBuZXR3b3JrLiAgCkZ1cnRoZXIgcmVzZWFyY2ggaXMgbmVlZGVkIHRvIHZhbGlkYXRlIHRoaXMgYXBwcm9hY2gsIGFuZCB0byB1bmRlcnN0YW5kIGhvdyBpdCBjYW4gYmUgYXBwbGllZCB0byBkaWZmZXJlbnQgdHlwZXMgb2YgY3ljbGlzdHMsIGFuZCB0byBkaWZmZXJlbnQgdHlwZXMgb2YgYmljeWNsZXMsIGFzIHRoaXMgbWV0aG9kIGRvZXMgbm90IGNvbnNpZGVyIHRoZSBlZmZvcnQgb24gYW4gZS1iaWtlLiAKClBsYXVzaWJsZT8gTGV0J3MgZGlzY3VzcyBpdCEKCiMgUmVmZXJlbmNlcwo=