Processing math: 61%
suppressPackageStartupMessages({
    library(dplyr)
    library(tidyr)
    library(ggplot2)
    library(htmltools)
})
options(digits = 4)

Scope

A rough engineering analysis of vehicle throttle behavior relating acceleration, speed, acceleration, and losses.

As an example, key design parameters for typical Toyota Corollas have been collected here:

g <- 9.81 # N/m^2
rho_air_std <- 1.225 # kg/m^3, https://en.wikipedia.org/wiki/Density_of_air
hp_to_W <- 745.7 # W/hp
lbm_to_kg <- 0.4536
in_to_m <- 0.0254
mm_to_m <- 0.001
mph_to_ms <- 0.447 # meters-per-second per miles-per-hour
corolla_tbl <- read.table( text =
'Variable   Value   Unit     URL
mass        2910    "lbm"    "https://www.caranddriver.com/toyota/corolla/specs"
c_d         0.3     "-"      "https://en.wikipedia.org/wiki/Automobile_drag_coefficient"
c_d_A_cs    0.631   "m^2"    "https://en.wikipedia.org/wiki/Automobile_drag_coefficient"
c_rr        0.01    "-"      "https://en.wikipedia.org/wiki/Rolling_resistance"
tire_id     15      "in"     "https://www.lesschwab.com/article/tire-size-explained-reading-the-sidewall.html"
tire_width  200     "mm"     "https://www.lesschwab.com/article/tire-size-explained-reading-the-sidewall.html"
tire_aspect 65      "%"      "https://www.lesschwab.com/article/tire-size-explained-reading-the-sidewall.html"
P_rated     139     "hp"     "https://www.caranddriver.com/toyota/corolla/specs"
R_G         40      "RPM-hr/mi" "http://www.corollaforum.com/threads/2012-le-high-rpm-at-80-mph.1305/"
omega_max   6100    "RPM"    "https://www.caranddriver.com/toyota/corolla/specs"
', header = TRUE, as.is=TRUE )
# corolla <- list( mass = 2910 * lbm_to_kg # kg, 
#                , c_d = 0.3 # 
#                , A_cs = 0.631 / 0.3 # m^2, ditto
#                , c_rr = 0.01 # unitless
#                , r = 15/2*in_to_m + 200 * mm_to_m * 65/100 # 200/65R15, 
#                , P_rated = 130 * hp_to_W # W,  says 139
#                )
corolla_tbl
ABCDEFGHIJ0123456789
Variable
<chr>
Value
<dbl>
Unit
<chr>
mass2910.000lbm
c_d0.300-
c_d_A_cs0.631m^2
c_rr0.010-
tire_id15.000in
tire_width200.000mm
tire_aspect65.000%
P_rated139.000hp
R_G40.000RPM-hr/mi
omega_max6100.000RPM

Making the units consistent:

corolla <- (   corolla_tbl
           %>% select( Variable, Value )
           %>% spread( Variable, Value )
           %>% mutate( mass = mass * lbm_to_kg
                     , A_cs = c_d_A_cs / c_d
                     , r = tire_id/2*in_to_m + tire_width * mm_to_m * tire_aspect / 100
                     , P_rated = P_rated * hp_to_W
                     , R_G = R_G / mph_to_ms
                     )
           %>% select( mass, c_d, A_cs, c_rr, r, P_rated, R_G, omega_max )
           )
knitr::kable( corolla
            , col.names = c( "Mass (kg)", "$C_d$ (unitless)", "$A_{cs}$ ($m^2$)", "$C_{rr}$ (unitless)", "Tire radius (m)", "$P_{rated}$ (kW)", "Gearing (RPM-s/m)", "Rated $\\omega$ (RPM)" )
            )
Mass (kg) Cd (unitless) Acs (m2) Crr (unitless) Tire radius (m) Prated (kW) Gearing (RPM-s/m) Rated ω (RPM)
1320 0.3 2.103 0.01 0.3205 103652 89.49 6100

Equations

Weight

From force is mass times acceleration:

W=mg

W <- corolla$mass * g

For the Corolla, W=(1319.976)(9.81)=1.2949×104 N.

Rolling resistance

From physics1, rolling resistance is a fraction of the weight:

Fr=crrW

F_r_corolla <- corolla$c_rr * W

For the Corolla, Fr,Corolla=(0.01)(1.2949×104)=129.4896 N.

Air drag

Density, coefficient of drag, and cross-sectional area modify the relative air speed to obtain air drag.

Fd=12cdρAcsu2

F_d <- function( u, rho = rho_air_std, car_info = corolla ) {
    0.5 * car_info$c_d * rho * car_info$A_cs * u^2
}
F_d_corolla_70 <- F_d( 70 * mph_to_ms )

For the Corolla at 70mph, Fd=12(0.3)(1.225)(2.1033)(700.447)2=378.396 N

Gravity

If you intend to maintain speed up a hill then you will need to be able to overcome the force of gravity:

Fg=Wsinθ

where a slope of 3.4336  is the usual limit2.

F_g_corolla <- W * sin( atan2( 6, 100 ) )

which is Fg,Corolla=775.5432 N

Opposition power

Since work is force times distance, power is force times velocity:

P=Fu

If we add the opposition forces and multiply by velocity, we can compute the power being absorbed by these mechanisms at different velocities:

Popposition=(Fr+Fd+Fg)u

P_opposition_corolla_70 = (F_r_corolla + F_d_corolla_70 + F_g_corolla) * (70 * mph_to_ms)

For the Corolla, this is P=((129.4896)+(378.396)+(775.5432))(31.3)=4.0158×104 W

Pedal power

The torque produced in response to throttle pedal position is not exactly constant over the variation of engine speed (subject to transmission gear setting, corresponding to velocity). Some example curves from Ford3 support the idea that torque is approximately constant4 at full throttle though the torque does reduce with speed when throttle position is only partially-engaged. However, of more interest is the torque vs. throttle position at a mid-speed condition, which shows that while not-quite-linear, the throttle position can be used to obtain a range of desired torque levels.

knitr::include_graphics( "Engine-map-engine-torque-vs-throttle-and-engine-RPM.png" )

So for a moment, let’s approximate this behavior at mid-RPM conditions as a linear mapping between throttle position p and torque T:

T=pTmax

Since power is torque times angular speed, and the gearing between the wheel and the engine (RG in RPM/ms) links angular speed with velocity:

Pengine=Tω=(pTmax)(RGu)=p(Tmaxωmaxωmax)RGu=pPengine,maxRGuωmax

Here we assume Pengine,max=1.0365×105 W.

If the power out of the engine equals the power being absorbed by air drag and rolling resistance then the forces involved will also be balanced and the velocity will be constant (vehicle steady speed).

pedal_levels <- seq( 10, 70, 10 )
(   expand.grid( MPH = 10:80
               , p = pedal_levels
               )
%>% mutate( p_f = factor( p, levels = pedal_levels )
          , u = MPH * mph_to_ms
          , F_d_corolla = F_d( u )
          , P_opposition_corolla = ( F_d_corolla + F_r_corolla + F_g_corolla ) * u
          , P_engine_corolla = p/100 * corolla$P_rated * corolla$R_G * u / corolla$omega_max
          )
%>% select( MPH, p_f, P_opposition_corolla, P_engine_corolla )
%>% gather( variable, value, -c( MPH, p_f ) )
%>% ggplot( aes( x = MPH, y = value, colour = variable ) ) ) +
    geom_line() +
    facet_wrap( ~p_f ) +
    scale_colour_discrete( name = "Power Flow" ) +
    ylab( "Power (W)" ) +
    xlab( "Speed (miles/hour)" )

When the blue line is below the red engine output (e.g. at low speed and high pedal position) the car can accelerate. But when the blue line catches up to the red line (e.g. at 45 mph/70%  pedal), you have no ability to accelerate. And when the blue line is above the red line (e.g. at 45 mph/50%  pedal) the car will be decelerating.

This value of RG represents high gear, and the fact that it is so difficult to overcome the losses in high gear is why cars have low gears.

\require{cancel}

Fuel

For reference, 1 kilogram of gasoline releases approximately 46.4~MJ of heat5 and the density of gasoline is about 0.755~kg/L6, so a car traveling at 70~mph with a fuel efficiency of 35~mpg is converting \frac{46.4~\cancel{MJ}}{1~\cancel{kg}} \frac{1000~kJ}{1~\cancel{MJ}} \frac{0.755~\cancel{kg}}{1~\cancel{L}} \frac{3.785~\cancel{L}}{1~\cancel{gal}} \frac{1~\cancel{gal}}{35~\cancel{mi}} \frac{70~\cancel{mi}}{1~\cancel{h}} \frac{1~\cancel{h}}{3600~s}=73.6645~kW of power from chemical form to heat. Since only about 20-30% of the thermal power typically makes it mechanically to the wheels where the above analysis applies7, one would expect that this means only 15-25~kW is available at the wheels, which seems only sort of consistent with the above analysis.

In fact you probably cannot achieve 35~mpg while traveling up a 6% slope at 45~mph in a 1300~kg vehicle… under those conditions you are likely running at a lower efficiency such as 20~mpg or lower. Some combination of slowing down to reduce opposing power and burning more fuel to increase power availability can increase the power excess (red minus blue). The available mechanical power at 20~mpg would be on the order of \frac{35}{20} \cdot 25~kW \approx 44~kW. Reducing weight can also affect the rolling resistance and gravity forces and therefore reduce power losses that need to be overcome. Driving a Toyota Prius with the Eco indicator8 enabled can give you some intuitive insight into just how much driving conditions affect instantaneous efficiency.

Assuming the road slope is level (0~{}^\circ), we get:

pedal_levels <- seq( 10, 70, 10 )
(   expand.grid( MPH = 10:80
               , p = pedal_levels
               )
%>% mutate( p_f = factor( p, levels = pedal_levels )
          , u = MPH * mph_to_ms
          , F_d_corolla = F_d( u )
          , P_opposition_corolla = ( F_d_corolla + F_r_corolla + 0 ) * u
          , P_engine_corolla = p/100 * corolla$P_rated * corolla$R_G * u / corolla$omega_max
          )
%>% select( MPH, p_f, P_opposition_corolla, P_engine_corolla )
%>% gather( variable, value, -c( MPH, p_f ) )
%>% ggplot( aes( x = MPH, y = value, colour = variable ) ) ) +
    geom_line() +
    facet_wrap( ~p_f ) +
    scale_colour_discrete( name = "Power Flow" ) +
    ylab( "Power (W)" ) +
    xlab( "Speed (miles/hour)" )

which has quite a lot of potential to accelerate the car (red above blue) in high gear even at medium pedal positions (well below engine maximum power rating).



  1. https://en.wikipedia.org/wiki/Rolling_resistance↩

  2. https://en.wikipedia.org/wiki/Grade_(slope)↩

  3. Laila, D.S., P. Shakouri, A. Ordys, and M. Askari. “Longitudinal Vehicle Dynamics Using Simulink/Matlab.” In UKACC International Conference on CONTROL 2010, 955–60. Coventry, UK: Institution of Engineering and Technology, 2010. https://doi.org/10.1049/ic.2010.0410. Figure from https://www.researchgate.net/figure/Engine-map-engine-torque-vs-throttle-and-engine-RPM_fig7_261390259↩

  4. https://www.toyotanation.com/threads/torque-curves-for-new-engines-vs-previous-gen.1623010/#post-13768106 djoyce101 posted some example dynamometer curves↩

  5. https://en.wikipedia.org/wiki/Energy_density↩

  6. https://en.wikipedia.org/wiki/Gasoline↩

  7. https://www.fueleconomy.gov/FEG/atv.shtml↩

  8. https://www.toyotaguru.us/prius-2010-manual/i-hybrid-system-indicator.html↩

LS0tDQp0aXRsZTogIkNhciBhY2NlbGVyYXRpb24iDQphdXRob3I6ICJKZWZmIE5ld21pbGxlciINCmRhdGU6IDIwMjEtMDEtMzENCm91dHB1dDoNCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICAgICAgZmlnX2NhcHRpb246IFRSVUUNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtyfQ0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsNCiAgICBsaWJyYXJ5KGRwbHlyKQ0KICAgIGxpYnJhcnkodGlkeXIpDQogICAgbGlicmFyeShnZ3Bsb3QyKQ0KICAgIGxpYnJhcnkoaHRtbHRvb2xzKQ0KfSkNCm9wdGlvbnMoZGlnaXRzID0gNCkNCmBgYA0KDQojIFNjb3BlDQoNCkEgcm91Z2ggZW5naW5lZXJpbmcgYW5hbHlzaXMgb2YgdmVoaWNsZSB0aHJvdHRsZSBiZWhhdmlvciByZWxhdGluZyBhY2NlbGVyYXRpb24sIHNwZWVkLCBhY2NlbGVyYXRpb24sIGFuZCBsb3NzZXMuDQoNCkFzIGFuIGV4YW1wbGUsIGtleSBkZXNpZ24gcGFyYW1ldGVycyBmb3IgdHlwaWNhbCBUb3lvdGEgQ29yb2xsYXMgaGF2ZSBiZWVuIGNvbGxlY3RlZCBoZXJlOg0KDQpgYGB7cn0NCmcgPC0gOS44MSAjIE4vbV4yDQpyaG9fYWlyX3N0ZCA8LSAxLjIyNSAjIGtnL21eMywgaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRGVuc2l0eV9vZl9haXINCmhwX3RvX1cgPC0gNzQ1LjcgIyBXL2hwDQpsYm1fdG9fa2cgPC0gMC40NTM2DQppbl90b19tIDwtIDAuMDI1NA0KbW1fdG9fbSA8LSAwLjAwMQ0KbXBoX3RvX21zIDwtIDAuNDQ3ICMgbWV0ZXJzLXBlci1zZWNvbmQgcGVyIG1pbGVzLXBlci1ob3VyDQpjb3JvbGxhX3RibCA8LSByZWFkLnRhYmxlKCB0ZXh0ID0NCidWYXJpYWJsZSAgIFZhbHVlICAgVW5pdCAgICAgVVJMDQptYXNzICAgICAgICAyOTEwICAgICJsYm0iICAgICJodHRwczovL3d3dy5jYXJhbmRkcml2ZXIuY29tL3RveW90YS9jb3JvbGxhL3NwZWNzIg0KY19kICAgICAgICAgMC4zICAgICAiLSIgICAgICAiaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQXV0b21vYmlsZV9kcmFnX2NvZWZmaWNpZW50Ig0KY19kX0FfY3MgICAgMC42MzEgICAibV4yIiAgICAiaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQXV0b21vYmlsZV9kcmFnX2NvZWZmaWNpZW50Ig0KY19yciAgICAgICAgMC4wMSAgICAiLSIgICAgICAiaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUm9sbGluZ19yZXNpc3RhbmNlIg0KdGlyZV9pZCAgICAgMTUgICAgICAiaW4iICAgICAiaHR0cHM6Ly93d3cubGVzc2Nod2FiLmNvbS9hcnRpY2xlL3RpcmUtc2l6ZS1leHBsYWluZWQtcmVhZGluZy10aGUtc2lkZXdhbGwuaHRtbCINCnRpcmVfd2lkdGggIDIwMCAgICAgIm1tIiAgICAgImh0dHBzOi8vd3d3Lmxlc3NjaHdhYi5jb20vYXJ0aWNsZS90aXJlLXNpemUtZXhwbGFpbmVkLXJlYWRpbmctdGhlLXNpZGV3YWxsLmh0bWwiDQp0aXJlX2FzcGVjdCA2NSAgICAgICIlIiAgICAgICJodHRwczovL3d3dy5sZXNzY2h3YWIuY29tL2FydGljbGUvdGlyZS1zaXplLWV4cGxhaW5lZC1yZWFkaW5nLXRoZS1zaWRld2FsbC5odG1sIg0KUF9yYXRlZCAgICAgMTM5ICAgICAiaHAiICAgICAiaHR0cHM6Ly93d3cuY2FyYW5kZHJpdmVyLmNvbS90b3lvdGEvY29yb2xsYS9zcGVjcyINClJfRyAgICAgICAgIDQwICAgICAgIlJQTS1oci9taSIgImh0dHA6Ly93d3cuY29yb2xsYWZvcnVtLmNvbS90aHJlYWRzLzIwMTItbGUtaGlnaC1ycG0tYXQtODAtbXBoLjEzMDUvIg0Kb21lZ2FfbWF4ICAgNjEwMCAgICAiUlBNIiAgICAiaHR0cHM6Ly93d3cuY2FyYW5kZHJpdmVyLmNvbS90b3lvdGEvY29yb2xsYS9zcGVjcyINCicsIGhlYWRlciA9IFRSVUUsIGFzLmlzPVRSVUUgKQ0KIyBjb3JvbGxhIDwtIGxpc3QoIG1hc3MgPSAyOTEwICogbGJtX3RvX2tnICMga2csIA0KIyAgICAgICAgICAgICAgICAsIGNfZCA9IDAuMyAjIA0KIyAgICAgICAgICAgICAgICAsIEFfY3MgPSAwLjYzMSAvIDAuMyAjIG1eMiwgZGl0dG8NCiMgICAgICAgICAgICAgICAgLCBjX3JyID0gMC4wMSAjIHVuaXRsZXNzDQojICAgICAgICAgICAgICAgICwgciA9IDE1LzIqaW5fdG9fbSArIDIwMCAqIG1tX3RvX20gKiA2NS8xMDAgIyAyMDAvNjVSMTUsIA0KIyAgICAgICAgICAgICAgICAsIFBfcmF0ZWQgPSAxMzAgKiBocF90b19XICMgVywgIHNheXMgMTM5DQojICAgICAgICAgICAgICAgICkNCmNvcm9sbGFfdGJsDQpgYGANCg0KTWFraW5nIHRoZSB1bml0cyBjb25zaXN0ZW50Og0KDQpgYGB7cn0NCmNvcm9sbGEgPC0gKCAgIGNvcm9sbGFfdGJsDQogICAgICAgICAgICU+JSBzZWxlY3QoIFZhcmlhYmxlLCBWYWx1ZSApDQogICAgICAgICAgICU+JSBzcHJlYWQoIFZhcmlhYmxlLCBWYWx1ZSApDQogICAgICAgICAgICU+JSBtdXRhdGUoIG1hc3MgPSBtYXNzICogbGJtX3RvX2tnDQogICAgICAgICAgICAgICAgICAgICAsIEFfY3MgPSBjX2RfQV9jcyAvIGNfZA0KICAgICAgICAgICAgICAgICAgICAgLCByID0gdGlyZV9pZC8yKmluX3RvX20gKyB0aXJlX3dpZHRoICogbW1fdG9fbSAqIHRpcmVfYXNwZWN0IC8gMTAwDQogICAgICAgICAgICAgICAgICAgICAsIFBfcmF0ZWQgPSBQX3JhdGVkICogaHBfdG9fVw0KICAgICAgICAgICAgICAgICAgICAgLCBSX0cgPSBSX0cgLyBtcGhfdG9fbXMNCiAgICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgJT4lIHNlbGVjdCggbWFzcywgY19kLCBBX2NzLCBjX3JyLCByLCBQX3JhdGVkLCBSX0csIG9tZWdhX21heCApDQogICAgICAgICAgICkNCmtuaXRyOjprYWJsZSggY29yb2xsYQ0KICAgICAgICAgICAgLCBjb2wubmFtZXMgPSBjKCAiTWFzcyAoa2cpIiwgIiRDX2QkICh1bml0bGVzcykiLCAiJEFfe2NzfSQgKCRtXjIkKSIsICIkQ197cnJ9JCAodW5pdGxlc3MpIiwgIlRpcmUgcmFkaXVzIChtKSIsICIkUF97cmF0ZWR9JCAoa1cpIiwgIkdlYXJpbmcgKFJQTS1zL20pIiwgIlJhdGVkICRcXG9tZWdhJCAoUlBNKSIgKQ0KICAgICAgICAgICAgKQ0KYGBgDQoNCg0KIyBFcXVhdGlvbnMNCg0KIyMgV2VpZ2h0DQoNCkZyb20gZm9yY2UgaXMgbWFzcyB0aW1lcyBhY2NlbGVyYXRpb246DQoNCiQkDQpXID0gbSBcY2RvdCBnDQokJA0KDQpgYGB7cn0NClcgPC0gY29yb2xsYSRtYXNzICogZw0KYGBgDQoNCkZvciB0aGUgQ29yb2xsYSwgJFcgPSAoYHIgY29yb2xsYSRtYXNzYCkoYHIgZ2ApPWByIFdgfk4kLg0KDQojIyBSb2xsaW5nIHJlc2lzdGFuY2UNCg0KRnJvbSBwaHlzaWNzW14zXSwgcm9sbGluZyByZXNpc3RhbmNlIGlzIGEgZnJhY3Rpb24gb2YgdGhlIHdlaWdodDoNCg0KJCQNCkZfciA9IGNfe3JyfSBcY2RvdCBXDQokJA0KDQpgYGB7cn0NCkZfcl9jb3JvbGxhIDwtIGNvcm9sbGEkY19yciAqIFcNCmBgYA0KDQoNCkZvciB0aGUgQ29yb2xsYSwgJEZfe3IsQ29yb2xsYX0gPSAoYHIgY29yb2xsYSRjX3JyYCkoYHIgV2ApID0gYHIgRl9yX2Nvcm9sbGFgfk4kLg0KDQojIyBBaXIgZHJhZw0KDQpEZW5zaXR5LCBjb2VmZmljaWVudCBvZiBkcmFnLCBhbmQgY3Jvc3Mtc2VjdGlvbmFsIGFyZWEgbW9kaWZ5IHRoZSByZWxhdGl2ZSBhaXIgc3BlZWQgdG8gb2J0YWluIGFpciBkcmFnLg0KDQokJA0KRl9kID0gXGZyYWN7MX17Mn0gXGNkb3QgY19kIFxyaG8gQV97Y3N9IHVeMg0KJCQNCg0KYGBge3J9DQpGX2QgPC0gZnVuY3Rpb24oIHUsIHJobyA9IHJob19haXJfc3RkLCBjYXJfaW5mbyA9IGNvcm9sbGEgKSB7DQogICAgMC41ICogY2FyX2luZm8kY19kICogcmhvICogY2FyX2luZm8kQV9jcyAqIHVeMg0KfQ0KYGBgDQoNCg0KYGBge3J9DQpGX2RfY29yb2xsYV83MCA8LSBGX2QoIDcwICogbXBoX3RvX21zICkNCmBgYA0KDQpGb3IgdGhlIENvcm9sbGEgYXQgNzBtcGgsICRGZCA9IFxmcmFjezF9ezJ9IFxjZG90IChgciBjb3JvbGxhJGNfZGApKGByIHJob19haXJfc3RkYCkoYHIgY29yb2xsYSRBX2NzYCkoNzAgXGNkb3QgYHIgbXBoX3RvX21zYCleMiA9IGByIEZfZF9jb3JvbGxhXzcwYH5OJA0KDQojIyBHcmF2aXR5DQoNCklmIHlvdSBpbnRlbmQgdG8gbWFpbnRhaW4gc3BlZWQgdXAgYSBoaWxsIHRoZW4geW91IHdpbGwgbmVlZCB0byBiZSBhYmxlIHRvIG92ZXJjb21lIHRoZSBmb3JjZSBvZiBncmF2aXR5Og0KDQokJA0KRl9nID0gVyBcY2RvdCBcc2lue1x0aGV0YX0NCiQkDQoNCndoZXJlIGEgc2xvcGUgb2YgJGByIDE4MC9waSphdGFuMig2LDEwMClgfnt9XlxjaXJjJCBpcyB0aGUgdXN1YWwgbGltaXRbXjVdLg0KDQpgYGB7cn0NCkZfZ19jb3JvbGxhIDwtIFcgKiBzaW4oIGF0YW4yKCA2LCAxMDAgKSApDQpgYGANCg0Kd2hpY2ggaXMgJEZfe2csQ29yb2xsYX0gPSBgciBGX2dfY29yb2xsYWB+TiQNCg0KIyMgT3Bwb3NpdGlvbiBwb3dlcg0KDQpTaW5jZSB3b3JrIGlzIGZvcmNlIHRpbWVzIGRpc3RhbmNlLCBwb3dlciBpcyBmb3JjZSB0aW1lcyB2ZWxvY2l0eToNCg0KJCQNClAgPSBGIFxjZG90IHUNCiQkDQoNCklmIHdlIGFkZCB0aGUgb3Bwb3NpdGlvbiBmb3JjZXMgYW5kIG11bHRpcGx5IGJ5IHZlbG9jaXR5LCB3ZSBjYW4gY29tcHV0ZSB0aGUgcG93ZXIgYmVpbmcgYWJzb3JiZWQgYnkgdGhlc2UgbWVjaGFuaXNtcyBhdCBkaWZmZXJlbnQgdmVsb2NpdGllczoNCg0KJCQNClBfe29wcG9zaXRpb259ID0gKEZfciArIEZfZCArIEZfZykgXGNkb3QgdQ0KJCQNCg0KYGBge3J9DQpQX29wcG9zaXRpb25fY29yb2xsYV83MCA9IChGX3JfY29yb2xsYSArIEZfZF9jb3JvbGxhXzcwICsgRl9nX2Nvcm9sbGEpICogKDcwICogbXBoX3RvX21zKQ0KYGBgDQoNCkZvciB0aGUgQ29yb2xsYSwgdGhpcyBpcyAkUCA9IFxsZWZ0KChgciBGX3JfY29yb2xsYWApICsgKGByIEZfZF9jb3JvbGxhXzcwYCkgKyAoYHIgRl9nX2Nvcm9sbGFgKSBccmlnaHQpIFxjZG90ICgzMS4zKSA9IGByIFBfb3Bwb3NpdGlvbl9jb3JvbGxhXzcwYH5XJA0KDQojIyBQZWRhbCBwb3dlcg0KDQpUaGUgdG9ycXVlIHByb2R1Y2VkIGluIHJlc3BvbnNlIHRvIHRocm90dGxlIHBlZGFsIHBvc2l0aW9uIGlzIG5vdCBleGFjdGx5IGNvbnN0YW50IG92ZXIgdGhlIHZhcmlhdGlvbiBvZiBlbmdpbmUgc3BlZWQgKHN1YmplY3QgdG8gdHJhbnNtaXNzaW9uIGdlYXIgc2V0dGluZywgY29ycmVzcG9uZGluZyB0byB2ZWxvY2l0eSkuIFNvbWUgZXhhbXBsZSBjdXJ2ZXMgZnJvbSBGb3JkW14yXSBzdXBwb3J0IHRoZSBpZGVhIHRoYXQgdG9ycXVlIGlzIGFwcHJveGltYXRlbHkgY29uc3RhbnRbXjFdIGF0IGZ1bGwgdGhyb3R0bGUgdGhvdWdoIHRoZSB0b3JxdWUgZG9lcyByZWR1Y2Ugd2l0aCBzcGVlZCB3aGVuIHRocm90dGxlIHBvc2l0aW9uIGlzIG9ubHkgcGFydGlhbGx5LWVuZ2FnZWQuIEhvd2V2ZXIsIG9mIG1vcmUgaW50ZXJlc3QgaXMgdGhlIHRvcnF1ZSB2cy4gdGhyb3R0bGUgcG9zaXRpb24gYXQgYSBtaWQtc3BlZWQgY29uZGl0aW9uLCB3aGljaCBzaG93cyB0aGF0IHdoaWxlIG5vdC1xdWl0ZS1saW5lYXIsIHRoZSB0aHJvdHRsZSBwb3NpdGlvbiBjYW4gYmUgdXNlZCB0byBvYnRhaW4gYSByYW5nZSBvZiBkZXNpcmVkIHRvcnF1ZSBsZXZlbHMuDQoNCmBgYHtyLGZpZy5jYXA9IkV4YW1wbGUgRW5naW5lIFJQTSB2cyBUaHJvdHRsZSBhbmQgVG9ycXVlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCAiRW5naW5lLW1hcC1lbmdpbmUtdG9ycXVlLXZzLXRocm90dGxlLWFuZC1lbmdpbmUtUlBNLnBuZyIgKQ0KYGBgDQoNClNvIGZvciBhIG1vbWVudCwgbGV0J3MgYXBwcm94aW1hdGUgdGhpcyBiZWhhdmlvciBhdCBtaWQtUlBNIGNvbmRpdGlvbnMgYXMgYSBsaW5lYXIgbWFwcGluZyBiZXR3ZWVuIHRocm90dGxlIHBvc2l0aW9uIHAgYW5kIHRvcnF1ZSBUOg0KDQokJA0KVCA9IHtwfSBcY2RvdCBUX3ttYXh9DQokJA0KDQpTaW5jZSBwb3dlciBpcyB0b3JxdWUgdGltZXMgYW5ndWxhciBzcGVlZCwgYW5kIHRoZSBnZWFyaW5nIGJldHdlZW4gdGhlIHdoZWVsIGFuZCB0aGUgZW5naW5lICgkUl9HJCBpbiAkUlBNL1xmcmFje219e3N9JCkgbGlua3MgYW5ndWxhciBzcGVlZCB3aXRoIHZlbG9jaXR5Og0KDQokJA0KUF97ZW5naW5lfSA9IFQgXGNkb3QgXG9tZWdhID0gKHAgXGNkb3QgVF97bWF4fSkoUl9HIFxjZG90IHUpID0gcCBcY2RvdCBcbGVmdChUX3ttYXh9IFxmcmFje1xvbWVnYV97bWF4fX17XG9tZWdhX3ttYXh9fVxyaWdodCkgXGNkb3QgUl9HIFxjZG90IHUgPSBwIFxjZG90IFBfe2VuZ2luZSxtYXh9IFxmcmFje1JfRyB1fXtcb21lZ2Ffe21heH19DQokJA0KDQpIZXJlIHdlIGFzc3VtZSAkUF97ZW5naW5lLG1heH09YHIgY29yb2xsYSRQX3JhdGVkYH5XJC4NCg0KSWYgdGhlIHBvd2VyIG91dCBvZiB0aGUgZW5naW5lIGVxdWFscyB0aGUgcG93ZXIgYmVpbmcgYWJzb3JiZWQgYnkgYWlyIGRyYWcgYW5kIHJvbGxpbmcgcmVzaXN0YW5jZSB0aGVuIHRoZSBmb3JjZXMgaW52b2x2ZWQgd2lsbCBhbHNvIGJlIGJhbGFuY2VkIGFuZCB0aGUgdmVsb2NpdHkgd2lsbCBiZSBjb25zdGFudCAodmVoaWNsZSBzdGVhZHkgc3BlZWQpLg0KDQpgYGB7cixmaWcuY2FwPSJQb3dlciB2cyBzcGVlZCBhdCB2YXJpb3VzIHBlZGFsIHBvc2l0aW9ucyAoJSkifQ0KcGVkYWxfbGV2ZWxzIDwtIHNlcSggMTAsIDcwLCAxMCApDQooICAgZXhwYW5kLmdyaWQoIE1QSCA9IDEwOjgwDQogICAgICAgICAgICAgICAsIHAgPSBwZWRhbF9sZXZlbHMNCiAgICAgICAgICAgICAgICkNCiU+JSBtdXRhdGUoIHBfZiA9IGZhY3RvciggcCwgbGV2ZWxzID0gcGVkYWxfbGV2ZWxzICkNCiAgICAgICAgICAsIHUgPSBNUEggKiBtcGhfdG9fbXMNCiAgICAgICAgICAsIEZfZF9jb3JvbGxhID0gRl9kKCB1ICkNCiAgICAgICAgICAsIFBfb3Bwb3NpdGlvbl9jb3JvbGxhID0gKCBGX2RfY29yb2xsYSArIEZfcl9jb3JvbGxhICsgRl9nX2Nvcm9sbGEgKSAqIHUNCiAgICAgICAgICAsIFBfZW5naW5lX2Nvcm9sbGEgPSBwLzEwMCAqIGNvcm9sbGEkUF9yYXRlZCAqIGNvcm9sbGEkUl9HICogdSAvIGNvcm9sbGEkb21lZ2FfbWF4DQogICAgICAgICAgKQ0KJT4lIHNlbGVjdCggTVBILCBwX2YsIFBfb3Bwb3NpdGlvbl9jb3JvbGxhLCBQX2VuZ2luZV9jb3JvbGxhICkNCiU+JSBnYXRoZXIoIHZhcmlhYmxlLCB2YWx1ZSwgLWMoIE1QSCwgcF9mICkgKQ0KJT4lIGdncGxvdCggYWVzKCB4ID0gTVBILCB5ID0gdmFsdWUsIGNvbG91ciA9IHZhcmlhYmxlICkgKSApICsNCiAgICBnZW9tX2xpbmUoKSArDQogICAgZmFjZXRfd3JhcCggfnBfZiApICsNCiAgICBzY2FsZV9jb2xvdXJfZGlzY3JldGUoIG5hbWUgPSAiUG93ZXIgRmxvdyIgKSArDQogICAgeWxhYiggIlBvd2VyIChXKSIgKSArDQogICAgeGxhYiggIlNwZWVkIChtaWxlcy9ob3VyKSIgKQ0KYGBgDQoNCldoZW4gdGhlIGJsdWUgbGluZSBpcyBiZWxvdyB0aGUgcmVkIGVuZ2luZSBvdXRwdXQgKGUuZy4gYXQgbG93IHNwZWVkIGFuZCBoaWdoIHBlZGFsIHBvc2l0aW9uKSB0aGUgY2FyIGNhbiBhY2NlbGVyYXRlLiBCdXQgd2hlbiB0aGUgYmx1ZSBsaW5lIGNhdGNoZXMgdXAgdG8gdGhlIHJlZCBsaW5lIChlLmcuIGF0ICQ0NX5tcGgkLyQ3MFwlfiQgcGVkYWwpLCB5b3UgaGF2ZSBubyBhYmlsaXR5IHRvIGFjY2VsZXJhdGUuIEFuZCB3aGVuIHRoZSBibHVlIGxpbmUgaXMgYWJvdmUgdGhlIHJlZCBsaW5lIChlLmcuIGF0ICQ0NX5tcGgkLyQ1MFwlfiQgcGVkYWwpIHRoZSBjYXIgd2lsbCBiZSBkZWNlbGVyYXRpbmcuDQoNClRoaXMgdmFsdWUgb2YgJFJfRyQgcmVwcmVzZW50cyBoaWdoIGdlYXIsIGFuZCB0aGUgZmFjdCB0aGF0IGl0IGlzIHNvIGRpZmZpY3VsdCB0byBvdmVyY29tZSB0aGUgbG9zc2VzIGluIGhpZ2ggZ2VhciBpcyB3aHkgY2FycyBoYXZlIGxvdyBnZWFycy4NCg0KICRccmVxdWlyZXtjYW5jZWx9JA0KDQojIEZ1ZWwNCg0KRm9yIHJlZmVyZW5jZSwgMSBraWxvZ3JhbSBvZiBnYXNvbGluZSByZWxlYXNlcyBhcHByb3hpbWF0ZWx5ICQ0Ni40fk1KJCBvZiBoZWF0W140XSBhbmQgdGhlIGRlbnNpdHkgb2YgZ2Fzb2xpbmUgaXMgYWJvdXQgJDAuNzU1fmtnL0wkW142XSwgc28gYSBjYXIgdHJhdmVsaW5nIGF0ICQ3MH5tcGgkIHdpdGggYSBmdWVsIGVmZmljaWVuY3kgb2YgJDM1fm1wZyQgaXMgY29udmVydGluZyAkXGZyYWN7NDYuNH5cY2FuY2Vse01KfX17MX5cY2FuY2Vse2tnfX0gXGZyYWN7MTAwMH5rSn17MX5cY2FuY2Vse01KfX0gXGZyYWN7MC43NTV+XGNhbmNlbHtrZ319ezF+XGNhbmNlbHtMfX0gXGZyYWN7My43ODV+XGNhbmNlbHtMfX17MX5cY2FuY2Vse2dhbH19IFxmcmFjezF+XGNhbmNlbHtnYWx9fXszNX5cY2FuY2Vse21pfX0gXGZyYWN7NzB+XGNhbmNlbHttaX19ezF+XGNhbmNlbHtofX0gXGZyYWN7MX5cY2FuY2Vse2h9fXszNjAwfnN9PWByIDQ2LjQgKiAxMDAwICogMC43NTUgKiAzLjc4NSAvIDM1ICogNzAgLyAzNjAwYH5rVyQgb2YgcG93ZXIgZnJvbSBjaGVtaWNhbCBmb3JtIHRvIGhlYXQuIFNpbmNlIG9ubHkgYWJvdXQgMjAtMzAlIG9mIHRoZSB0aGVybWFsIHBvd2VyIHR5cGljYWxseSBtYWtlcyBpdCBtZWNoYW5pY2FsbHkgdG8gdGhlIHdoZWVscyB3aGVyZSB0aGUgYWJvdmUgYW5hbHlzaXMgYXBwbGllc1teN10sIG9uZSB3b3VsZCBleHBlY3QgdGhhdCB0aGlzIG1lYW5zIG9ubHkgJDE1LTI1fmtXJCBpcyBhdmFpbGFibGUgYXQgdGhlIHdoZWVscywgd2hpY2ggc2VlbXMgb25seSBzb3J0IG9mIGNvbnNpc3RlbnQgd2l0aCB0aGUgYWJvdmUgYW5hbHlzaXMuDQoNCkluIGZhY3QgeW91IHByb2JhYmx5IGNhbm5vdCBhY2hpZXZlICQzNX5tcGckIHdoaWxlIHRyYXZlbGluZyB1cCBhIDYlIHNsb3BlIGF0ICQ0NX5tcGgkIGluIGEgJDEzMDB+a2ckIHZlaGljbGUuLi4gdW5kZXIgdGhvc2UgY29uZGl0aW9ucyB5b3UgYXJlIGxpa2VseSBydW5uaW5nIGF0IGEgbG93ZXIgZWZmaWNpZW5jeSBzdWNoIGFzICQyMH5tcGckIG9yIGxvd2VyLiBTb21lIGNvbWJpbmF0aW9uIG9mIHNsb3dpbmcgZG93biB0byByZWR1Y2Ugb3Bwb3NpbmcgcG93ZXIgYW5kIGJ1cm5pbmcgbW9yZSBmdWVsIHRvIGluY3JlYXNlIHBvd2VyIGF2YWlsYWJpbGl0eSBjYW4gaW5jcmVhc2UgdGhlIHBvd2VyIGV4Y2VzcyAocmVkIG1pbnVzIGJsdWUpLiBUaGUgYXZhaWxhYmxlIG1lY2hhbmljYWwgcG93ZXIgYXQgJDIwfm1wZyQgd291bGQgYmUgb24gdGhlIG9yZGVyIG9mICRcZnJhY3szNX17MjB9IFxjZG90IDI1fmtXIFxhcHByb3ggNDR+a1ckLiBSZWR1Y2luZyB3ZWlnaHQgY2FuIGFsc28gYWZmZWN0IHRoZSByb2xsaW5nIHJlc2lzdGFuY2UgYW5kIGdyYXZpdHkgZm9yY2VzIGFuZCB0aGVyZWZvcmUgcmVkdWNlIHBvd2VyIGxvc3NlcyB0aGF0IG5lZWQgdG8gYmUgb3ZlcmNvbWUuIERyaXZpbmcgYSBUb3lvdGEgUHJpdXMgd2l0aCB0aGUgRWNvIGluZGljYXRvclteOF0gZW5hYmxlZCBjYW4gZ2l2ZSB5b3Ugc29tZSBpbnR1aXRpdmUgaW5zaWdodCBpbnRvIGp1c3QgaG93IG11Y2ggZHJpdmluZyBjb25kaXRpb25zIGFmZmVjdCBpbnN0YW50YW5lb3VzIGVmZmljaWVuY3kuDQoNCkFzc3VtaW5nIHRoZSByb2FkIHNsb3BlIGlzIGxldmVsICgkMH57fV5cY2lyYyQpLCB3ZSBnZXQ6DQoNCmBgYHtyLGZpZy5jYXA9IlBvd2VyIHZzIHNwZWVkIGF0IHZhcmlvdXMgcGVkYWwgcG9zaXRpb25zIG9uIGxldmVsIGdyb3VuZCAoJSkifQ0KcGVkYWxfbGV2ZWxzIDwtIHNlcSggMTAsIDcwLCAxMCApDQooICAgZXhwYW5kLmdyaWQoIE1QSCA9IDEwOjgwDQogICAgICAgICAgICAgICAsIHAgPSBwZWRhbF9sZXZlbHMNCiAgICAgICAgICAgICAgICkNCiU+JSBtdXRhdGUoIHBfZiA9IGZhY3RvciggcCwgbGV2ZWxzID0gcGVkYWxfbGV2ZWxzICkNCiAgICAgICAgICAsIHUgPSBNUEggKiBtcGhfdG9fbXMNCiAgICAgICAgICAsIEZfZF9jb3JvbGxhID0gRl9kKCB1ICkNCiAgICAgICAgICAsIFBfb3Bwb3NpdGlvbl9jb3JvbGxhID0gKCBGX2RfY29yb2xsYSArIEZfcl9jb3JvbGxhICsgMCApICogdQ0KICAgICAgICAgICwgUF9lbmdpbmVfY29yb2xsYSA9IHAvMTAwICogY29yb2xsYSRQX3JhdGVkICogY29yb2xsYSRSX0cgKiB1IC8gY29yb2xsYSRvbWVnYV9tYXgNCiAgICAgICAgICApDQolPiUgc2VsZWN0KCBNUEgsIHBfZiwgUF9vcHBvc2l0aW9uX2Nvcm9sbGEsIFBfZW5naW5lX2Nvcm9sbGEgKQ0KJT4lIGdhdGhlciggdmFyaWFibGUsIHZhbHVlLCAtYyggTVBILCBwX2YgKSApDQolPiUgZ2dwbG90KCBhZXMoIHggPSBNUEgsIHkgPSB2YWx1ZSwgY29sb3VyID0gdmFyaWFibGUgKSApICkgKw0KICAgIGdlb21fbGluZSgpICsNCiAgICBmYWNldF93cmFwKCB+cF9mICkgKw0KICAgIHNjYWxlX2NvbG91cl9kaXNjcmV0ZSggbmFtZSA9ICJQb3dlciBGbG93IiApICsNCiAgICB5bGFiKCAiUG93ZXIgKFcpIiApICsNCiAgICB4bGFiKCAiU3BlZWQgKG1pbGVzL2hvdXIpIiApDQpgYGANCg0Kd2hpY2ggaGFzIHF1aXRlIGEgbG90IG9mIHBvdGVudGlhbCB0byBhY2NlbGVyYXRlIHRoZSBjYXIgKHJlZCBhYm92ZSBibHVlKSBpbiBoaWdoIGdlYXIgZXZlbiBhdCBtZWRpdW0gcGVkYWwgcG9zaXRpb25zICh3ZWxsIGJlbG93IGVuZ2luZSBtYXhpbXVtIHBvd2VyIHJhdGluZykuDQoNCi0tLQ0KW14xXTogaHR0cHM6Ly93d3cudG95b3RhbmF0aW9uLmNvbS90aHJlYWRzL3RvcnF1ZS1jdXJ2ZXMtZm9yLW5ldy1lbmdpbmVzLXZzLXByZXZpb3VzLWdlbi4xNjIzMDEwLyNwb3N0LTEzNzY4MTA2IGRqb3ljZTEwMSBwb3N0ZWQgc29tZSBleGFtcGxlIGR5bmFtb21ldGVyIGN1cnZlcw0KW14yXTogTGFpbGEsIEQuUy4sIFAuIFNoYWtvdXJpLCBBLiBPcmR5cywgYW5kIE0uIEFza2FyaS4g4oCcTG9uZ2l0dWRpbmFsIFZlaGljbGUgRHluYW1pY3MgVXNpbmcgU2ltdWxpbmsvTWF0bGFiLuKAnSBJbiBVS0FDQyBJbnRlcm5hdGlvbmFsIENvbmZlcmVuY2Ugb24gQ09OVFJPTCAyMDEwLCA5NTXigJM2MC4gQ292ZW50cnksIFVLOiBJbnN0aXR1dGlvbiBvZiBFbmdpbmVlcmluZyBhbmQgVGVjaG5vbG9neSwgMjAxMC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwNDkvaWMuMjAxMC4wNDEwLiBGaWd1cmUgZnJvbSBodHRwczovL3d3dy5yZXNlYXJjaGdhdGUubmV0L2ZpZ3VyZS9FbmdpbmUtbWFwLWVuZ2luZS10b3JxdWUtdnMtdGhyb3R0bGUtYW5kLWVuZ2luZS1SUE1fZmlnN18yNjEzOTAyNTkNClteM106IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1JvbGxpbmdfcmVzaXN0YW5jZQ0KW140XTogaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRW5lcmd5X2RlbnNpdHkNClteNV06IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dyYWRlXyhzbG9wZSkNClteNl06IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dhc29saW5lDQpbXjddOiBodHRwczovL3d3dy5mdWVsZWNvbm9teS5nb3YvRkVHL2F0di5zaHRtbA0KW144XTogaHR0cHM6Ly93d3cudG95b3RhZ3VydS51cy9wcml1cy0yMDEwLW1hbnVhbC9pLWh5YnJpZC1zeXN0ZW0taW5kaWNhdG9yLmh0bWw=