Introduction
This R NoteBook explores a framework for modelling the seasonal demand for fashion garments based on the Bass Diffusion model of demand and the Newsvendor optimal inventory management model. A sales and inventory management simulation is generated based on these models to demonstrate how theoretical models can be made operational using open-source software for the benefit of small to medium scale enterprises with limited resources.
The Stock Management Challenge
Sales forecasting literature and practice is focused on the use of historical sales data to predict the future behaviour of consumers.Time Series Analysis techniques, based on regression} and correlation analysis attempt to identify underlying long-term demand trends and cycles. These techniques however require temporal stability across seasonal markets and assume consistency in consumer behaviour from one season to another to be effective. This is clearly not the case with fashion. The fashion industry is driven by innovation and change.
The inability of conventional forecasting methods to predict the seasonal demand for fashion merchandise has forced some observers to argue that forecasting is an inappropriate technique for the management of the fashion supply-chain. In consequence the fashion industry is cursed by poor inventory management.
Typically a season’s demand for garments is not matched by the inventory anticipated by marketing and merchandise planners. This leads to lost revenue due to either understocking causing lost sales or overstocking forcing markdowns and discounts.
The retail sector has adopted various ‘best practices’ to address this problem; imposing agile and lean management strategies on their suppliers. While keeping stock low with frequent replenishment re-orders has reduced the possibility of lost revenue for retailers, outsourced manufacturers still need to anticipate expected re-orders because of long lead-times.
The Accepted Marketing Model
From a theoretical perspective the demand for a fashion garment over a season is characterised by a product life-cycle 4 phase model:
- Introduction
- Growth
- Maturity
- Decline
Introduction phase
This is the most precarious stage in a product’s life-cycle. Demand is uncertain, the garment may, or may not, resonate with consumers and sell in the volumes predicted by the merchandise planners. Demand is initially low as consumers are just beginning to appreciate how the garment will impact on their style.
A lot depends on the effectiveness of the marketing strategy resonating with the desires of the consumer.
Growth phase
If consumers buy into the product than an increase in sales allows growth in demand that is matched by increased revenue. How aggressive the growth depends on several factors, such as advertising, price strategy, strength of competition and the availability of substitutes. The effectiveness of supply chain management systems is also critical in ensuring the timely flow of garments to the retailer.
Maturity phase
The maturity stage is the stage where a product reaches its maximum sales and revenue creation. How long this phase lasts depends on how well the garment’s style resonates with the consumer mood. Again, this period can be prolonged by marketing strategies, advertising and celebrity endorsement. Other, more mundane, factors can also play a decisive role: weather, consumer income, the speed at which competitors produce and market a substitute garment.
Decline phase
Eventually, the consumer will become bored with the product and sales will fall.
This decline can be aggressive, given the emergence of another fashion style, or slowly as the seasons draws to an end. Predicting when a style will decline and how aggressively is the challenge. Planners tend to use past experience to anticipate this end.
Bass Diffusion model
What is interesting about the Product Life Cycle Model so beloved by fashion marking people is that its profile resembles that of the Bass Diffusion model developed by the father of marketing, Frank Bass, in the 1960’s. Bass’s model describes the process of how the demand for new products relates to the interaction between two different types of consumer, innovators, brand followers in the context of fashion, and imitators. The basic idea behind the model is that consumers can be divided between innovators who desire novelty and change, and imitators who just want to follow trends that innovators have pioneered. The timing and rate of demand depends upon the strength of desire for something novel and the degree of imitation among consumers. The basic formal model consists of a simple differential equation where the number of people, \(N_{t}\), who have bought a product at time \(t\) depends on three parameters:
- \(m\): The total number of people who eventually buy the product.
- \(p\): The coefficient of innovation.
- \(q\): The coefficient of imitation.
Demand at \(D_{t+1}\) is therefore:
\(D_{t} + p(m - D_{t}) + qD_{t}(m - D_{t})/m\)
According to the model, the increase in sales: \(D_{t+1} - D_{t}\) is equal to the sum of a fixed proportion \(p\) and a time varying proportion \(q(D/m)\) of consumers who will eventually buy the product but have yet to do so.
The thinking behind the model is that initial sales will be to consumers who are interested in the novelty of the style. The trend setters in a community of consumers. While later sales will be to those imitators who read the magazines and follow the media and are drawn to the garment after seeing innovators wear the garment.
The model is usually expressed not in terms of discrete increments but usually as continues values where \(f(t)\) represents the density function of the distribution of time until a consumer purchase.
\(Sales(t) = mf(t) = \frac{m(p + q)^{2} e^{-(p+q)t}}{p[1 + (q/p)e^{-(p+q)t}]^{2}}\)
While the model has striking similarities with marketing life-cycle models, the Bass formula has had little traction and influence among fashion market planners or commentators. This is strange because the demand profile generated by the Bass process mirrors the life-cycle model of introduction, growth, maturity and decline where the rate of change is determined by the \(p\) and \(q\) values.
However, choosing appropriate values for \(p\), \(q\), and \(m\) clearly makes the model operationally problematic. Nonetheless, it will serve has the basis for experimentation to understand the challenge of stock management subject to uncertain seasonal demand.
The basic Bass model can be implemented in R
time.line <- (1:100)/10
m <- 68000
p <- 0.0066
q <- 0.64
ngete <- exp(-(p+q) * time.line)
Bpdf <- m * ( (p+q)^2 / p ) * ngete / (1 + (q/p) * ngete)^2
plot(time.line, Bpdf, xlab = "Time", ylab = "Sales")

From the plot is is easy to see the an introductory phase, a growth phase, a mature phase, and a decline. The curve’s profile can be changed by adjusting the parameter values. For example we can mimic a slow take-up by adjusting the \(q\) value:
time.line <- (1:150)/10
m <- 68000
p <- 0.0066
q <- 0.284
ngete <- exp(-(p+q) * time.line)
Bpdf <- m * ( (p+q)^2 / p ) * ngete / (1 + (q/p) * ngete)^2
plot(time.line, Bpdf, xlab = "Time", ylab = "Sales")

Or an aggresive take-up of a product with a slow decline.
time.line <- (1:150)/10
m <- 68000
p <- 0.024
q <- 0.972
ngete <- exp(-(p+q) * time.line)
Bpdf <- m * ( (p+q)^2 / p ) * ngete / (1 + (q/p) * ngete)^2
plot(time.line, Bpdf, xlab = "Time", ylab = "Sales")

Or no take up of a product with just the innovators buying into the design
time.line <- (1:150)/10
m <- 68000
p <- 0.0066
q <- 0.0
ngete <- exp(-(p+q) * time.line)
Bpdf <- m * ( (p+q)^2 / p ) * ngete / (1 + (q/p) * ngete)^2
plot(time.line, Bpdf, xlab = "Time", ylab = "Sales")

Model Exploration
First we create a matrix data structure to hold 5000 runs of a modified Bass process that represents the predicted sales of a fashion product.
sales <- matrix(0, nrow=150, ncol=5000)
We need to define a function that generates predicted sales of a fashion product according to the Bass formula but with perturbations that introduce a random disturbance to demand at each time point. This will provide variance in demand over the 5000 simulation runs that will allow us to generate probabalistic models of demand. We can think of the random disturbance as the impact of weather or economic factors on a fashion consumer’s behaviour.
bass.model <- function(m,p,q,h,d,u) {
if(runif(1) <= u) { q <- 0.0 }
Tdelt <- (1:h) / 10
ngete <- exp(- (p+q) * Tdelt)
Bpdf <- abs(rnorm(h, m * ( (p+q)^2 / p ) * ngete / (1 + (q/p) * ngete)^2, d))
return(Bpdf)
}
Define the Bass Model Parameters and test Bass function
m <- 6800 # Total number of garments eventually sold
p <- 0.0066 # Coefficient of innovation
q <- 0.64 # Coefficient of immitation
h <- 150 # The number of days in the fashion season
d <- 75 # A disturbance factor
u <- 0.15 # The probability that sales will not gain traction and reach
# a growth phase
plot(bass.model(m,p,q,h,d,u), xlab = "Time Line", ylab = "Sales")

The modified Bass function seems to work so we populate the sales matrix with 5000 Bass models using the parameter values defined above.
for(i in 1:5000) { sales[,i] <- bass.model(m,p,q,h,d,u) }
Analysis
Lets explore the demand for the garment across the 5000 runs at a specific time \(x\).
x <- 50
hist(sales[x,], breaks = 100)

An Empirical Cumulative Distribution Function provides the probability that demand will be \(x\) or less.
plot(ecdf(sales[x,]))

Looking at the probability that demand will be \(x\) at a specific time \(t\) is not pariticularly interesting. Lets calculate the probability of demand at all time points (days).
We calculate a cumulative distribution function across all time points and store in a F(x) data frame with columns sales, ecdf, and day. So each row provides the the probability of sales on day.
library(ggplot2)
v1 <- ecdf(sales[1,])(sales[1,])
df <- data.frame(sales[1,], v1)
df$day <- as.factor(1)
colnames(df) <- c("sales", "ecdf", "day")
for(i in seq(2,h, by=1)) {
v <- ecdf(sales[i,])(sales[i,])
df.v <- data.frame(sales[i,], v)
df.v$day <- as.factor(i)
colnames(df.v) <- c("sales", "ecdf", "day")
df <- rbind(df, df.v)
}
We plot those probabilities for day 1, day 25, day 50, day 75 and day 100.
library(dplyr)
filter(df, day== c(1, 25, 50, 75, 100)) %>% ggplot( aes(x=sales,y=ecdf, col=day))+geom_point() + geom_line()

Furthermore we can plot the optimum amount of inventory to carry for each day given a ecd (an empirical cumulative distribution) value.
filter(df, ecdf == c(0.10, 0.25, 0.50, 0.75)) %>% ggplot( aes(x=day, y=sales, col=as.factor(ecdf))) + geom_point()

Which leads us onto the Newsvendor Inventory model.
Newsvendor Inventory Model.
The Newsvendor model (also called single-period or perishable model) is a classic analytical tool from the operations management community. The model determines the optimal amount of inventory that a business should carry over a fixed period given a perishable product that cannot be easily replenished in season. Interestingly, like groceries and newspapers, fashion garments can be viewed as perishable items. A fashion garment only has value to a fashion consumer in season. Once that season has passed, the garment is obsolete, bound for landfill or recycling or, maybe, upcycling.
Optimum inventory, according to the Newsvendor model, is determined by the relationship between the cost of understocking, the cost associated with not having a garment available when there is still a demand for that garment, and the cost of overstocking, having unsold or obsolete stock at the end of the season.
The cost of understocking, \(C_{u}\), is the revenue that would have been obtained if the garment was sold. While the cost of overstocking, \(C_{o}\), is the cost to the business incurred bringing the garment to market.
This algorithmic procedure suggests that the optimal order size \(Q^{*}\) is achieved when:
\([(1-F(Q^{*})) \times C_{u}]+[F(Q^{*}) \times (-C_{o})] = 0\)
If \([(1-F(Q^{*})) \times C_{u}]+[F(Q^{*}) \times (-C_{o})] = 0\) holds then the merchandizer and inventory manager cannot gain any advantage either by ordering one more garment or one less garment. \(Q^{*}\) is optimal. What is cool, by algebraically moving the expression \(F(Q^{*})\) to the left of the equation we get the critical ratio:
\(F(Q^{*}) = \frac{C_{u}}{(C_{u} + C_{o})}\)
The probability of satisfying all demand is equal to the critical ratio. The critical ratio is always between 0 and 1. If the cost of overstocking is the same as the cost of under stocking then the critical ratio is 0.5. The merchandizer would choose the stock level that gives an equal chance of having or not having a stock out. If the critical ratio is greater than 0.5 the manager would order more garments so that the probability of having enough to meet demand is greater. If the critical ratio is less than 0.5, the manager will order less garments.
Scenario
Let us pull some of these ideas together into a framework by exploring a contrived scenario that illustrates the possible role of the models in fashion merchandizing.
Imagine a business that spends £70 per unit developing a fashion garment for market. Development costs include market research, consultants’ fees, manufacturing, and various logistic costs. The business calculate that they need to sell each garment for £100 to justify the development costs and guarantee a fair return for the business’ investors. The chief mechandiser for the business has negotiated a deal with a garment discount company to take any unsold garments at the end of the season. The discounter will pay £61.50 for each unsold garment. Under such a scenario \(C_{u}\) is £100 - £70, the £30 that would have been generated by a sale if there was a garment to sell. The \(C_{o}\) is £70 - £65.50, the £8.50 lost because of poor stock management. To avoid incurring \(C_{u}\) or \(C_{o}\) the business needs to maintain a stock level where the probability of \(C_{u}\) is equal to the probability of \(C_{o}\). That is, the probability of making £30 needs to be equal to the probability of losing £8.50. So more stock is ordered while the chances of making an additional £30 dominates. Less stock is ordered while the chances of losing £8.50 dominates. Intuitively, in this example, an inventory manager would tend to overstock rather than understood. The probability of losing £8.50 is more attractive than the probability of losing a potential sale and the £30 that would result from that sale. Clearly, there is a between \(C_{u}\) and \(C_{o}\) that guarantees no loss of revenue. Therefore, the optimum amount of stock a business carries, call it \(Q^{*}\), requires a probabilistic forecast of demand. What are the chances that demand will match \(Q_{*}\) so that there is no overstocking, or under stocking?
A probabilistic forecast based on the generation of a number of Bass models provides a set of possible demand profiles over time and associates with each profile the probability it will occur. The expected ‘shape’ of demand; length and curve of growth, maturity, and decline; is determined by the Bass parameters p, q and m. Initial values for these variables can be anticipated by the expertise and experience of merchandizers who know their market and brand consumers. Furthermore, the uncertainy associated with those professional judgements can be modelled with the d (variance from the Bass prediction at time t) and u (probability that the market will not adopt the garment’s design and generate sales) parameters. Fisher and Raman [1] discribe a pragmatic approach to probabilistic forecasting by sampling the expertise of merchandisers in a systematic way.
Let’s assume the merchandizers’ professional judgement anticipates the classic life-cycle curve for garment sales over a 150 day season. Market research and historical records suggest approximate sales over a 100 day season of 6800 units. This produces an initial demand profile based on the canonical Bass process.
time.line <- (1:100)/10.0
m <- 6800
p <- 0.006
q <- 0.64
ngete <- exp(-(p+q) * time.line)
Bpdf <- m * ( (p+q)^2 / p ) * ngete / (1 + (q/p) * ngete)^2
plot(time.line, Bpdf, xlab = "Time", ylab = "Sales")

However, there is some concern amoung the marketing team and store managers about current trading conditions and they reckon sales could fluctuate each day by 50 garments. Furthermore, the chief merchandizer believes there is also a 15% chance that the garment will not succeed in current market conditons with its customers who are drawn towards rival designers because of some American TV show. We can factor these conditions into the simulation.
sales <- bass.model(6800,0.006,0.64,100,50.0,0.15)
plot(sales, xlab="Days", ylab="Possible Demand")

We can run these parameters 5000 times to generate a distribution model of demand and then apply the Newsvendor model to the cumulative distribution function of the model to determine optimum daily inventory.
References
[1] Marshall Fisher and Ananth Raman (2010) The New Science of Retailing: How Analytics are Transforming the Supply Chain and Improving Performance, Harvard Business School Press, 3, 61-105.
LS0tCnRpdGxlOiAiQXJ0aWN1bGF0aW5nIHRoZSBGYXNoaW9uIFByb2R1Y3QgTGlmZS1DeWNsZSAtIEV4cGxvcmF0aW9ucyB3aXRoIFIiCmF1dGhvcjogIkpvbiBTcHJhZ2cgLSBHaWdnaW5nIExvZ2lzdGljcyBBbmFseXN0IGFuZCBQcm9ncmFtbWVyIgpkYXRlOiAgICJNYXkgMjAxNyIKb3V0cHV0OiBodG1sX25vdGVib29rCgotLS0KIyBJbnRyb2R1Y3Rpb24KClRoaXMgKlIgTm90ZUJvb2sqIGV4cGxvcmVzIGEgZnJhbWV3b3JrIGZvciBtb2RlbGxpbmcgdGhlIHNlYXNvbmFsIGRlbWFuZCBmb3IgCmZhc2hpb24gZ2FybWVudHMgYmFzZWQgb24gdGhlICpCYXNzIERpZmZ1c2lvbiogbW9kZWwgb2YgZGVtYW5kIGFuZCB0aGUgKk5ld3N2ZW5kb3IqIApvcHRpbWFsIGludmVudG9yeSBtYW5hZ2VtZW50IG1vZGVsLiAgQSBzYWxlcyBhbmQgaW52ZW50b3J5IG1hbmFnZW1lbnQgc2ltdWxhdGlvbiBpcwpnZW5lcmF0ZWQgYmFzZWQgb24gdGhlc2UgbW9kZWxzIHRvIGRlbW9uc3RyYXRlIGhvdyB0aGVvcmV0aWNhbCBtb2RlbHMgY2FuIGJlIG1hZGUgb3BlcmF0aW9uYWwgdXNpbmcgb3Blbi1zb3VyY2Ugc29mdHdhcmUgZm9yIHRoZSBiZW5lZml0IG9mIHNtYWxsIHRvIG1lZGl1bSBzY2FsZSBlbnRlcnByaXNlcyB3aXRoIGxpbWl0ZWQgcmVzb3VyY2VzLiAKCiMjIFRoZSBTdG9jayBNYW5hZ2VtZW50IENoYWxsZW5nZQoKU2FsZXMgZm9yZWNhc3RpbmcgbGl0ZXJhdHVyZSBhbmQgcHJhY3RpY2UgaXMgZm9jdXNlZCBvbiB0aGUgdXNlIG9mIGhpc3RvcmljYWwgCnNhbGVzIGRhdGEgdG8gcHJlZGljdCB0aGUgZnV0dXJlIGJlaGF2aW91ciBvZiBjb25zdW1lcnMuVGltZSBTZXJpZXMgQW5hbHlzaXMgCnRlY2huaXF1ZXMsIGJhc2VkIG9uIHJlZ3Jlc3Npb259IGFuZCBjb3JyZWxhdGlvbiBhbmFseXNpcyBhdHRlbXB0IHRvIGlkZW50aWZ5IAp1bmRlcmx5aW5nIGxvbmctdGVybSBkZW1hbmQgdHJlbmRzIGFuZCBjeWNsZXMuICBUaGVzZSB0ZWNobmlxdWVzIGhvd2V2ZXIgCnJlcXVpcmUgdGVtcG9yYWwgc3RhYmlsaXR5IGFjcm9zcyBzZWFzb25hbCBtYXJrZXRzIGFuZCBhc3N1bWUgY29uc2lzdGVuY3kgaW4gCmNvbnN1bWVyIGJlaGF2aW91ciBmcm9tIG9uZSBzZWFzb24gdG8gYW5vdGhlciB0byBiZSBlZmZlY3RpdmUuIFRoaXMgaXMgY2xlYXJseSAKbm90IHRoZSBjYXNlIHdpdGggZmFzaGlvbi4gIFRoZSBmYXNoaW9uIGluZHVzdHJ5IGlzIGRyaXZlbiBieSBpbm5vdmF0aW9uIGFuZApjaGFuZ2UuIAoKVGhlIGluYWJpbGl0eSBvZiBjb252ZW50aW9uYWwgZm9yZWNhc3RpbmcgbWV0aG9kcyB0byBwcmVkaWN0IHRoZSBzZWFzb25hbCBkZW1hbmQgCmZvciBmYXNoaW9uIG1lcmNoYW5kaXNlIGhhcyBmb3JjZWQgc29tZSBvYnNlcnZlcnMgdG8gYXJndWUgdGhhdCBmb3JlY2FzdGluZyBpcyAKYW4gaW5hcHByb3ByaWF0ZSB0ZWNobmlxdWUgZm9yIHRoZSBtYW5hZ2VtZW50IG9mIHRoZSBmYXNoaW9uIHN1cHBseS1jaGFpbi4gCkluIGNvbnNlcXVlbmNlIHRoZSBmYXNoaW9uIGluZHVzdHJ5IGlzIGN1cnNlZCBieSBwb29yIGludmVudG9yeSBtYW5hZ2VtZW50LiAgClR5cGljYWxseSBhIHNlYXNvbidzIGRlbWFuZCBmb3IgZ2FybWVudHMgaXMgbm90IG1hdGNoZWQgYnkgdGhlIGludmVudG9yeSAKYW50aWNpcGF0ZWQgYnkgbWFya2V0aW5nIGFuZCBtZXJjaGFuZGlzZSBwbGFubmVycy4gVGhpcyBsZWFkcyB0byBsb3N0IHJldmVudWUgCmR1ZSB0byBlaXRoZXIgdW5kZXJzdG9ja2luZyBjYXVzaW5nIGxvc3Qgc2FsZXMgb3Igb3ZlcnN0b2NraW5nIGZvcmNpbmcgbWFya2Rvd25zIAphbmQgZGlzY291bnRzLiAKClRoZSByZXRhaWwgc2VjdG9yIGhhcyBhZG9wdGVkIHZhcmlvdXMgJ2Jlc3QgcHJhY3RpY2VzJyB0byBhZGRyZXNzIHRoaXMgcHJvYmxlbTsgCmltcG9zaW5nIGFnaWxlIGFuZCBsZWFuIG1hbmFnZW1lbnQgc3RyYXRlZ2llcyBvbiB0aGVpciBzdXBwbGllcnMuICAgV2hpbGUgCmtlZXBpbmcgc3RvY2sgbG93IHdpdGggZnJlcXVlbnQgcmVwbGVuaXNobWVudCByZS1vcmRlcnMgaGFzIHJlZHVjZWQgdGhlIApwb3NzaWJpbGl0eSBvZiBsb3N0IHJldmVudWUgZm9yIHJldGFpbGVycywgb3V0c291cmNlZCBtYW51ZmFjdHVyZXJzIHN0aWxsIG5lZWQgCnRvIGFudGljaXBhdGUgZXhwZWN0ZWQgcmUtb3JkZXJzIGJlY2F1c2Ugb2YgbG9uZyBsZWFkLXRpbWVzLgoKIyMgVGhlIEFjY2VwdGVkIE1hcmtldGluZyBNb2RlbAoKRnJvbSBhIHRoZW9yZXRpY2FsIHBlcnNwZWN0aXZlIHRoZSBkZW1hbmQgZm9yIGEgZmFzaGlvbiBnYXJtZW50IG92ZXIgYSBzZWFzb24gaXMgY2hhcmFjdGVyaXNlZCBieSBhICpwcm9kdWN0IGxpZmUtY3ljbGUqIDQgcGhhc2UgbW9kZWw6CgoKMS4gSW50cm9kdWN0aW9uCjIuIEdyb3d0aAozLiBNYXR1cml0eQo0LiBEZWNsaW5lCgoKIyMjIEludHJvZHVjdGlvbiBwaGFzZQpUaGlzIGlzIHRoZSBtb3N0IHByZWNhcmlvdXMgc3RhZ2UgaW4gYSBwcm9kdWN0J3MgbGlmZS1jeWNsZS4gIERlbWFuZCBpcyB1bmNlcnRhaW4sIAp0aGUgZ2FybWVudCBtYXksIG9yIG1heSBub3QsIHJlc29uYXRlIHdpdGggY29uc3VtZXJzIGFuZCBzZWxsIGluIHRoZSB2b2x1bWVzIApwcmVkaWN0ZWQgYnkgdGhlIG1lcmNoYW5kaXNlIHBsYW5uZXJzLiAgRGVtYW5kIGlzIGluaXRpYWxseSBsb3cgYXMgY29uc3VtZXJzIGFyZSAKanVzdCBiZWdpbm5pbmcgdG8gYXBwcmVjaWF0ZSBob3cgdGhlIGdhcm1lbnQgd2lsbCBpbXBhY3Qgb24gdGhlaXIgc3R5bGUuICAKQSBsb3QgZGVwZW5kcyBvbiB0aGUgZWZmZWN0aXZlbmVzcyBvZiB0aGUgbWFya2V0aW5nIHN0cmF0ZWd5IHJlc29uYXRpbmcgd2l0aCAKdGhlIGRlc2lyZXMgb2YgdGhlIGNvbnN1bWVyLgoKIyMjIEdyb3d0aCBwaGFzZQpJZiBjb25zdW1lcnMgYnV5IGludG8gdGhlIHByb2R1Y3QgdGhhbiBhbiBpbmNyZWFzZSBpbiBzYWxlcyBhbGxvd3MgZ3Jvd3RoIGluIApkZW1hbmQgdGhhdCBpcyBtYXRjaGVkIGJ5IGluY3JlYXNlZCByZXZlbnVlLiAgSG93IGFnZ3Jlc3NpdmUgdGhlIGdyb3d0aCBkZXBlbmRzIApvbiBzZXZlcmFsIGZhY3RvcnMsIHN1Y2ggYXMgYWR2ZXJ0aXNpbmcsIHByaWNlIHN0cmF0ZWd5LCBzdHJlbmd0aCBvZiBjb21wZXRpdGlvbiAKYW5kIHRoZSBhdmFpbGFiaWxpdHkgb2Ygc3Vic3RpdHV0ZXMuICBUaGUgZWZmZWN0aXZlbmVzcyBvZiBzdXBwbHkgY2hhaW4gCm1hbmFnZW1lbnQgc3lzdGVtcyBpcyBhbHNvIGNyaXRpY2FsIGluIGVuc3VyaW5nIHRoZSB0aW1lbHkgZmxvdyBvZiBnYXJtZW50cyB0byAKdGhlIHJldGFpbGVyLiAgICAgCgojIyMgTWF0dXJpdHkgcGhhc2UKVGhlIG1hdHVyaXR5IHN0YWdlIGlzIHRoZSBzdGFnZSB3aGVyZSBhIHByb2R1Y3QgcmVhY2hlcyBpdHMgbWF4aW11bSBzYWxlcyBhbmQgCnJldmVudWUgY3JlYXRpb24uICBIb3cgbG9uZyB0aGlzIHBoYXNlIGxhc3RzIGRlcGVuZHMgb24gaG93IHdlbGwgdGhlIGdhcm1lbnQncyAKc3R5bGUgcmVzb25hdGVzIHdpdGggdGhlIGNvbnN1bWVyIG1vb2QuICBBZ2FpbiwgdGhpcyBwZXJpb2QgY2FuIGJlIHByb2xvbmdlZCAgYnkgbWFya2V0aW5nIHN0cmF0ZWdpZXMsIGFkdmVydGlzaW5nIGFuZCBjZWxlYnJpdHkgZW5kb3JzZW1lbnQuIE90aGVyLCBtb3JlIG11bmRhbmUsICBmYWN0b3JzIGNhbiBhbHNvIHBsYXkgYSBkZWNpc2l2ZSByb2xlOiAgd2VhdGhlciwgY29uc3VtZXIgaW5jb21lLCB0aGUgc3BlZWQgYXQgCndoaWNoIGNvbXBldGl0b3JzIHByb2R1Y2UgYW5kIG1hcmtldCBhIHN1YnN0aXR1dGUgZ2FybWVudC4gIAoKIyMjIERlY2xpbmUgcGhhc2UKRXZlbnR1YWxseSwgdGhlIGNvbnN1bWVyIHdpbGwgYmVjb21lIGJvcmVkIHdpdGggdGhlIHByb2R1Y3QgYW5kIHNhbGVzIHdpbGwgZmFsbC4gIApUaGlzIGRlY2xpbmUgY2FuIGJlIGFnZ3Jlc3NpdmUsIGdpdmVuIHRoZSBlbWVyZ2VuY2Ugb2YgYW5vdGhlciBmYXNoaW9uIHN0eWxlLCBvciAKc2xvd2x5IGFzIHRoZSBzZWFzb25zIGRyYXdzIHRvIGFuIGVuZC4gICBQcmVkaWN0aW5nIHdoZW4gYSBzdHlsZSB3aWxsIGRlY2xpbmUgCmFuZCBob3cgYWdncmVzc2l2ZWx5IGlzIHRoZSBjaGFsbGVuZ2UuICBQbGFubmVycyB0ZW5kIHRvIHVzZSBwYXN0IGV4cGVyaWVuY2UgdG8gYW50aWNpcGF0ZSB0aGlzIGVuZC4gCgojIyBCYXNzIERpZmZ1c2lvbiBtb2RlbAoKV2hhdCBpcyBpbnRlcmVzdGluZyBhYm91dCB0aGUgUHJvZHVjdCBMaWZlIEN5Y2xlIE1vZGVsIHNvIGJlbG92ZWQgYnkgZmFzaGlvbgptYXJraW5nIHBlb3BsZSBpcyB0aGF0IGl0cyBwcm9maWxlIHJlc2VtYmxlcyB0aGF0IG9mIHRoZSBCYXNzIERpZmZ1c2lvbiBtb2RlbApkZXZlbG9wZWQgYnkgdGhlIGZhdGhlciBvZiBtYXJrZXRpbmcsIEZyYW5rIEJhc3MsIGluIHRoZSAxOTYwJ3MuIEJhc3MncyBtb2RlbCAKZGVzY3JpYmVzIHRoZSBwcm9jZXNzIG9mIGhvdyB0aGUgZGVtYW5kIGZvciBuZXcgcHJvZHVjdHMgcmVsYXRlcyB0byB0aGUgCmludGVyYWN0aW9uIGJldHdlZW4gdHdvIGRpZmZlcmVudCB0eXBlcyBvZiBjb25zdW1lciwgKmlubm92YXRvcnMqLCBicmFuZCAKZm9sbG93ZXJzIGluIHRoZSBjb250ZXh0IG9mIGZhc2hpb24sIGFuZCAqaW1pdGF0b3JzKi4gVGhlIGJhc2ljIGlkZWEgYmVoaW5kIAp0aGUgbW9kZWwgaXMgdGhhdCBjb25zdW1lcnMgY2FuIGJlIGRpdmlkZWQgYmV0d2VlbiAqaW5ub3ZhdG9ycyogd2hvIGRlc2lyZSAKbm92ZWx0eSBhbmQgY2hhbmdlLCBhbmQgKmltaXRhdG9ycyogd2hvIGp1c3Qgd2FudCB0byBmb2xsb3cgdHJlbmRzIHRoYXQgCippbm5vdmF0b3JzKiBoYXZlIHBpb25lZXJlZC4gVGhlIHRpbWluZyBhbmQgcmF0ZSBvZiBkZW1hbmQgZGVwZW5kcyB1cG9uIHRoZSAKc3RyZW5ndGggb2YgZGVzaXJlIGZvciBzb21ldGhpbmcgbm92ZWwgYW5kIHRoZSBkZWdyZWUgb2YgaW1pdGF0aW9uIGFtb25nIApjb25zdW1lcnMuIFRoZSBiYXNpYyBmb3JtYWwgbW9kZWwgY29uc2lzdHMgb2YgYSBzaW1wbGUgZGlmZmVyZW50aWFsIGVxdWF0aW9uIAp3aGVyZSB0aGUgbnVtYmVyIG9mIHBlb3BsZSwgJE5fe3R9JCwgd2hvIGhhdmUgYm91Z2h0IGEgcHJvZHVjdCBhdCB0aW1lICR0JCAKZGVwZW5kcyBvbiB0aHJlZSBwYXJhbWV0ZXJzOgoKCjEuICRtJDogVGhlIHRvdGFsIG51bWJlciBvZiBwZW9wbGUgd2hvIGV2ZW50dWFsbHkgYnV5IHRoZSBwcm9kdWN0LgoyLiAkcCQ6IFRoZSBjb2VmZmljaWVudCBvZiBpbm5vdmF0aW9uLgozLiAkcSQ6IFRoZSBjb2VmZmljaWVudCBvZiBpbWl0YXRpb24uCgoKRGVtYW5kIGF0ICREX3t0KzF9JCBpcyB0aGVyZWZvcmU6CgokRF97dH0gKyBwKG0gLSBEX3t0fSkgKyBxRF97dH0obSAtIERfe3R9KS9tJAoKCkFjY29yZGluZyB0byB0aGUgbW9kZWwsIHRoZSBpbmNyZWFzZSBpbiBzYWxlczogJERfe3QrMX0gLSBEX3t0fSQgaXMgZXF1YWwgdG8gCnRoZSBzdW0gb2YgYSBmaXhlZCBwcm9wb3J0aW9uICRwJCBhbmQgYSB0aW1lIHZhcnlpbmcgcHJvcG9ydGlvbiAkcShEL20pJCBvZiAKY29uc3VtZXJzIHdobyB3aWxsIGV2ZW50dWFsbHkgYnV5IHRoZSBwcm9kdWN0IGJ1dCBoYXZlIHlldCB0byBkbyBzby4gIApUaGUgdGhpbmtpbmcgYmVoaW5kIHRoZSBtb2RlbCBpcyB0aGF0IGluaXRpYWwgc2FsZXMgd2lsbCBiZSB0byBjb25zdW1lcnMgd2hvIGFyZSBpbnRlcmVzdGVkIGluIHRoZSBub3ZlbHR5IG9mIHRoZSBzdHlsZS4gVGhlIHRyZW5kIHNldHRlcnMgaW4gYSBjb21tdW5pdHkgb2YgCmNvbnN1bWVycy4gIFdoaWxlIGxhdGVyIHNhbGVzIHdpbGwgYmUgdG8gdGhvc2UgaW1pdGF0b3JzIHdobyByZWFkIHRoZSBtYWdhemluZXMgCmFuZCBmb2xsb3cgdGhlIG1lZGlhIGFuZCBhcmUgZHJhd24gdG8gdGhlIGdhcm1lbnQgYWZ0ZXIgc2VlaW5nIGlubm92YXRvcnMgd2VhciAKdGhlIGdhcm1lbnQuICAgIAoKVGhlIG1vZGVsIGlzIHVzdWFsbHkgZXhwcmVzc2VkIG5vdCBpbiB0ZXJtcyBvZiBkaXNjcmV0ZSBpbmNyZW1lbnRzIGJ1dCB1c3VhbGx5IAphcyBjb250aW51ZXMgdmFsdWVzIHdoZXJlICRmKHQpJCByZXByZXNlbnRzIHRoZSBkZW5zaXR5IGZ1bmN0aW9uIG9mIHRoZSAKZGlzdHJpYnV0aW9uIG9mIHRpbWUgdW50aWwgYSBjb25zdW1lciBwdXJjaGFzZS4KCiRTYWxlcyh0KSA9IG1mKHQpID0gXGZyYWN7bShwICsgcSleezJ9IGVeey0ocCtxKXR9fXtwWzEgKyAocS9wKWVeey0ocCtxKXR9XV57Mn19JAoKCldoaWxlIHRoZSBtb2RlbCBoYXMgc3RyaWtpbmcgc2ltaWxhcml0aWVzIHdpdGggbWFya2V0aW5nIGxpZmUtY3ljbGUgbW9kZWxzLCB0aGUgCkJhc3MgZm9ybXVsYSBoYXMgaGFkIGxpdHRsZSB0cmFjdGlvbiBhbmQgaW5mbHVlbmNlIGFtb25nIGZhc2hpb24gbWFya2V0IHBsYW5uZXJzIApvciBjb21tZW50YXRvcnMuIFRoaXMgaXMgc3RyYW5nZSBiZWNhdXNlIHRoZSBkZW1hbmQgcHJvZmlsZSBnZW5lcmF0ZWQgYnkgdGhlIApCYXNzIHByb2Nlc3MgbWlycm9ycyB0aGUgbGlmZS1jeWNsZSBtb2RlbCBvZiAqaW50cm9kdWN0aW9uKiwgKmdyb3d0aCosICptYXR1cml0eSogCmFuZCAqZGVjbGluZSogd2hlcmUgdGhlIHJhdGUgb2YgY2hhbmdlIGlzIGRldGVybWluZWQgYnkgdGhlICRwJCBhbmQgJHEkIHZhbHVlcy4gIApIb3dldmVyLCBjaG9vc2luZyBhcHByb3ByaWF0ZSB2YWx1ZXMgZm9yICRwJCwgJHEkLCBhbmQgJG0kIGNsZWFybHkgbWFrZXMgdGhlIG1vZGVsIG9wZXJhdGlvbmFsbHkgcHJvYmxlbWF0aWMuIE5vbmV0aGVsZXNzLCBpdCB3aWxsIHNlcnZlIGhhcyB0aGUgYmFzaXMgZm9yIApleHBlcmltZW50YXRpb24gdG8gdW5kZXJzdGFuZCB0aGUgY2hhbGxlbmdlIG9mIHN0b2NrIG1hbmFnZW1lbnQgc3ViamVjdCB0byAKdW5jZXJ0YWluIHNlYXNvbmFsIGRlbWFuZC4gCgpUaGUgYmFzaWMgQmFzcyBtb2RlbCBjYW4gYmUgaW1wbGVtZW50ZWQgaW4gUgoKYGBge3J9CnRpbWUubGluZSA8LSAoMToxMDApLzEwCm0gPC0gNjgwMDAKcCA8LSAwLjAwNjYKcSA8LSAwLjY0CgpuZ2V0ZSA8LSBleHAoLShwK3EpICogdGltZS5saW5lKQpCcGRmIDwtICBtICogKCAocCtxKV4yIC8gcCApICogbmdldGUgLyAoMSArIChxL3ApICogbmdldGUpXjIKcGxvdCh0aW1lLmxpbmUsIEJwZGYsICB4bGFiID0gIlRpbWUiLCB5bGFiID0gIlNhbGVzIikKYGBgCgpGcm9tIHRoZSBwbG90IGlzIGlzIGVhc3kgdG8gc2VlIHRoZSBhbiBpbnRyb2R1Y3RvcnkgcGhhc2UsIGEgZ3Jvd3RoIHBoYXNlLCBhCm1hdHVyZSBwaGFzZSwgYW5kIGEgZGVjbGluZS4gICBUaGUgY3VydmUncyBwcm9maWxlIGNhbiBiZSBjaGFuZ2VkIGJ5IGFkanVzdGluZyB0aGUgCnBhcmFtZXRlciB2YWx1ZXMuICBGb3IgZXhhbXBsZSB3ZSBjYW4gbWltaWMgYSBzbG93IHRha2UtdXAgYnkgYWRqdXN0aW5nIHRoZSAkcSQKdmFsdWU6CmBgYHtyfQp0aW1lLmxpbmUgPC0gKDE6MTUwKS8xMAptIDwtIDY4MDAwCnAgPC0gMC4wMDY2CnEgPC0gMC4yODQKCm5nZXRlIDwtIGV4cCgtKHArcSkgKiB0aW1lLmxpbmUpCkJwZGYgPC0gIG0gKiAoIChwK3EpXjIgLyBwICkgKiBuZ2V0ZSAvICgxICsgKHEvcCkgKiBuZ2V0ZSleMgpwbG90KHRpbWUubGluZSwgQnBkZiwgIHhsYWIgPSAiVGltZSIsIHlsYWIgPSAiU2FsZXMiKQpgYGAKCk9yIGFuIGFnZ3Jlc2l2ZSB0YWtlLXVwIG9mIGEgcHJvZHVjdCB3aXRoIGEgc2xvdyBkZWNsaW5lLgpgYGB7cn0KdGltZS5saW5lIDwtICgxOjE1MCkvMTAKbSA8LSA2ODAwMApwIDwtIDAuMDI0CnEgPC0gMC45NzIKCm5nZXRlIDwtIGV4cCgtKHArcSkgKiB0aW1lLmxpbmUpCkJwZGYgPC0gIG0gKiAoIChwK3EpXjIgLyBwICkgKiBuZ2V0ZSAvICgxICsgKHEvcCkgKiBuZ2V0ZSleMgpwbG90KHRpbWUubGluZSwgQnBkZiwgIHhsYWIgPSAiVGltZSIsIHlsYWIgPSAiU2FsZXMiKQpgYGAKT3Igbm8gdGFrZSB1cCBvZiBhIHByb2R1Y3Qgd2l0aCBqdXN0IHRoZSBpbm5vdmF0b3JzIGJ1eWluZyBpbnRvIHRoZSBkZXNpZ24KYGBge3J9CnRpbWUubGluZSA8LSAoMToxNTApLzEwCm0gPC0gNjgwMDAKcCA8LSAwLjAwNjYKcSA8LSAwLjAKCm5nZXRlIDwtIGV4cCgtKHArcSkgKiB0aW1lLmxpbmUpCkJwZGYgPC0gIG0gKiAoIChwK3EpXjIgLyBwICkgKiBuZ2V0ZSAvICgxICsgKHEvcCkgKiBuZ2V0ZSleMgpwbG90KHRpbWUubGluZSwgQnBkZiwgIHhsYWIgPSAiVGltZSIsIHlsYWIgPSAiU2FsZXMiKQpgYGAKCiMjIE1vZGVsIEV4cGxvcmF0aW9uCgpGaXJzdCB3ZSBjcmVhdGUgYSBtYXRyaXggZGF0YSBzdHJ1Y3R1cmUgdG8gaG9sZCA1MDAwIHJ1bnMgb2YgYSBtb2RpZmllZCBCYXNzIApwcm9jZXNzIHRoYXQgcmVwcmVzZW50cyB0aGUgcHJlZGljdGVkIHNhbGVzIG9mIGEgZmFzaGlvbiBwcm9kdWN0LiAgCgpgYGB7cn0Kc2FsZXMgPC0gIG1hdHJpeCgwLCBucm93PTE1MCwgbmNvbD01MDAwKQpgYGAKCldlIG5lZWQgdG8gZGVmaW5lIGEgZnVuY3Rpb24gdGhhdCBnZW5lcmF0ZXMgcHJlZGljdGVkIHNhbGVzIG9mIGEgZmFzaGlvbiBwcm9kdWN0CmFjY29yZGluZyB0byB0aGUgQmFzcyBmb3JtdWxhIGJ1dCB3aXRoIHBlcnR1cmJhdGlvbnMgdGhhdCBpbnRyb2R1Y2UgYQpyYW5kb20gZGlzdHVyYmFuY2UgdG8gZGVtYW5kIGF0IGVhY2ggdGltZSBwb2ludC4gIFRoaXMgd2lsbCBwcm92aWRlIHZhcmlhbmNlIGluIApkZW1hbmQgb3ZlciB0aGUgNTAwMCBzaW11bGF0aW9uIHJ1bnMgdGhhdCB3aWxsIGFsbG93IHVzIHRvIGdlbmVyYXRlIHByb2JhYmFsaXN0aWMKbW9kZWxzIG9mIGRlbWFuZC4gIFdlIGNhbiB0aGluayBvZiB0aGUgcmFuZG9tIGRpc3R1cmJhbmNlIGFzIHRoZSBpbXBhY3Qgb2Ygd2VhdGhlcgpvciBlY29ub21pYyBmYWN0b3JzIG9uIGEgZmFzaGlvbiBjb25zdW1lcidzIGJlaGF2aW91ci4KCmBgYHtyfQpiYXNzLm1vZGVsIDwtIGZ1bmN0aW9uKG0scCxxLGgsZCx1KSB7CiAgaWYocnVuaWYoMSkgPD0gdSkgeyBxIDwtIDAuMCB9CiAgVGRlbHQgPC0gICgxOmgpIC8gMTAKICBuZ2V0ZSA8LSBleHAoLSAocCtxKSAqIFRkZWx0KQogIEJwZGYgPC0gIGFicyhybm9ybShoLCBtICogKCAocCtxKV4yIC8gcCApICogbmdldGUgLyAoMSArIChxL3ApICogbmdldGUpXjIsIGQpKQogIHJldHVybihCcGRmKQp9CgpgYGAKRGVmaW5lIHRoZSBCYXNzIE1vZGVsIFBhcmFtZXRlcnMgYW5kIHRlc3QgQmFzcyBmdW5jdGlvbgoKYGBge3J9Cm0gPC0gIDY4MDAgICAgICMgVG90YWwgbnVtYmVyIG9mIGdhcm1lbnRzIGV2ZW50dWFsbHkgc29sZApwIDwtICAwLjAwNjYgICAjIENvZWZmaWNpZW50IG9mIGlubm92YXRpb24KcSA8LSAgMC42NCAgICAgIyBDb2VmZmljaWVudCBvZiBpbW1pdGF0aW9uCmggPC0gIDE1MCAgICAgICMgVGhlIG51bWJlciBvZiBkYXlzIGluIHRoZSBmYXNoaW9uIHNlYXNvbgpkIDwtICA3NSAgICAgICAjIEEgZGlzdHVyYmFuY2UgZmFjdG9yCnUgPC0gIDAuMTUgICAgICMgVGhlIHByb2JhYmlsaXR5IHRoYXQgc2FsZXMgd2lsbCBub3QgZ2FpbiB0cmFjdGlvbiBhbmQgcmVhY2gKICAgICAgICAgICAgICAgIyBhIGdyb3d0aCBwaGFzZQoKcGxvdChiYXNzLm1vZGVsKG0scCxxLGgsZCx1KSwgeGxhYiA9ICJUaW1lIExpbmUiLCB5bGFiID0gIlNhbGVzIikKYGBgCgpUaGUgbW9kaWZpZWQgQmFzcyBmdW5jdGlvbiBzZWVtcyB0byB3b3JrIHNvIHdlIHBvcHVsYXRlIHRoZSBzYWxlcyBtYXRyaXggd2l0aCAKNTAwMCBCYXNzIG1vZGVscyB1c2luZyB0aGUgcGFyYW1ldGVyIHZhbHVlcyBkZWZpbmVkIGFib3ZlLgoKYGBge3J9CmZvcihpIGluIDE6NTAwMCkgeyBzYWxlc1ssaV0gPC0gYmFzcy5tb2RlbChtLHAscSxoLGQsdSkgfQpgYGAKIyMgQW5hbHlzaXMKCkxldHMgZXhwbG9yZSB0aGUgZGVtYW5kIGZvciB0aGUgZ2FybWVudCBhY3Jvc3MgdGhlIDUwMDAgcnVucyBhdCBhIHNwZWNpZmljIHRpbWUKJHgkLgpgYGB7cn0KeCA8LSA1MApoaXN0KHNhbGVzW3gsXSwgYnJlYWtzID0gMTAwKQpgYGAKCkFuICBFbXBpcmljYWwgQ3VtdWxhdGl2ZSBEaXN0cmlidXRpb24gRnVuY3Rpb24gcHJvdmlkZXMgdGhlIHByb2JhYmlsaXR5IHRoYXQKZGVtYW5kIHdpbGwgYmUgJHgkIG9yIGxlc3MuIApgYGB7cn0KcGxvdChlY2RmKHNhbGVzW3gsXSkpCmBgYAoKCkxvb2tpbmcgYXQgdGhlIHByb2JhYmlsaXR5IHRoYXQgZGVtYW5kIHdpbGwgYmUgJHgkIGF0IGEgc3BlY2lmaWMgdGltZSAkdCQgaXMgbm90CnBhcml0aWN1bGFybHkgaW50ZXJlc3RpbmcuICBMZXRzIGNhbGN1bGF0ZSB0aGUgcHJvYmFiaWxpdHkgb2YgZGVtYW5kIGF0IGFsbAp0aW1lIHBvaW50cyAoZGF5cykuIAoKV2UgY2FsY3VsYXRlIGEgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24gYWNyb3NzIGFsbCB0aW1lICBwb2ludHMgYW5kIHN0b3JlIAppbiBhIEYoeCkgZGF0YSBmcmFtZSB3aXRoIGNvbHVtbnMgKnNhbGVzKiwgKmVjZGYqLCBhbmQgKmRheSouICBTbyBlYWNoIHJvdwpwcm92aWRlcyB0aGUgdGhlIHByb2JhYmlsaXR5IG9mIHNhbGVzIG9uIGRheS4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgp2MSA8LSAgZWNkZihzYWxlc1sxLF0pKHNhbGVzWzEsXSkKZGYgPC0gIGRhdGEuZnJhbWUoc2FsZXNbMSxdLCB2MSkKZGYkZGF5IDwtIGFzLmZhY3RvcigxKQpjb2xuYW1lcyhkZikgPC0gYygic2FsZXMiLCAiZWNkZiIsICJkYXkiKQpmb3IoaSBpbiBzZXEoMixoLCBieT0xKSkgewogIHYgPC0gZWNkZihzYWxlc1tpLF0pKHNhbGVzW2ksXSkKICBkZi52IDwtIGRhdGEuZnJhbWUoc2FsZXNbaSxdLCB2KSAKICBkZi52JGRheSA8LSBhcy5mYWN0b3IoaSkKICBjb2xuYW1lcyhkZi52KSA8LSBjKCJzYWxlcyIsICJlY2RmIiwgImRheSIpCiAgZGYgICA8LSByYmluZChkZiwgZGYudikKfQoKCgpgYGAKV2UgcGxvdCB0aG9zZSBwcm9iYWJpbGl0aWVzIGZvciBkYXkgMSwgZGF5IDI1LCBkYXkgNTAsIGRheSA3NSBhbmQgZGF5IDEwMC4KCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQoKZmlsdGVyKGRmLCBkYXk9PSBjKDEsIDI1LCA1MCwgNzUsIDEwMCkpICU+JSBnZ3Bsb3QoIGFlcyh4PXNhbGVzLHk9ZWNkZiwgY29sPWRheSkpK2dlb21fcG9pbnQoKSArIGdlb21fbGluZSgpCmBgYApGdXJ0aGVybW9yZSB3ZSBjYW4gcGxvdCB0aGUgb3B0aW11bSBhbW91bnQgb2YgaW52ZW50b3J5IHRvIGNhcnJ5IGZvciBlYWNoCmRheSBnaXZlbiBhIGVjZCAoYW4gZW1waXJpY2FsIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uKSB2YWx1ZS4KCmBgYHtyfQpmaWx0ZXIoZGYsIGVjZGYgPT0gYygwLjEwLCAwLjI1LCAwLjUwLCAwLjc1KSkgJT4lIGdncGxvdCggYWVzKHg9ZGF5LCB5PXNhbGVzLCBjb2w9YXMuZmFjdG9yKGVjZGYpKSkgKyBnZW9tX3BvaW50KCkgCmBgYAoKV2hpY2ggbGVhZHMgdXMgb250byB0aGUgKk5ld3N2ZW5kb3IgSW52ZW50b3J5KiBtb2RlbC4gCgojIyBOZXdzdmVuZG9yIEludmVudG9yeSBNb2RlbC4KClRoZSAqTmV3c3ZlbmRvciogbW9kZWwgKGFsc28gY2FsbGVkICpzaW5nbGUtcGVyaW9kKiBvciAqcGVyaXNoYWJsZSogbW9kZWwpICAgaXMgCmEgY2xhc3NpYyBhbmFseXRpY2FsIHRvb2wgZnJvbSB0aGUgb3BlcmF0aW9ucyBtYW5hZ2VtZW50IGNvbW11bml0eS4gIFRoZSBtb2RlbCAKZGV0ZXJtaW5lcyB0aGUgb3B0aW1hbCBhbW91bnQgb2YgaW52ZW50b3J5IHRoYXQgYSBidXNpbmVzcyBzaG91bGQgY2Fycnkgb3ZlciBhIApmaXhlZCBwZXJpb2QgZ2l2ZW4gYSBwZXJpc2hhYmxlIHByb2R1Y3QgdGhhdCBjYW5ub3QgYmUgZWFzaWx5IHJlcGxlbmlzaGVkIGluIApzZWFzb24uICBJbnRlcmVzdGluZ2x5LCBsaWtlIGdyb2NlcmllcyBhbmQgbmV3c3BhcGVycywgZmFzaGlvbiBnYXJtZW50cyBjYW4gYmUgCnZpZXdlZCBhcyBwZXJpc2hhYmxlIGl0ZW1zLiAgQSBmYXNoaW9uIGdhcm1lbnQgb25seSBoYXMgdmFsdWUgdG8gYSBmYXNoaW9uIGNvbnN1bWVyIAppbiBzZWFzb24uIE9uY2UgdGhhdCBzZWFzb24gaGFzIHBhc3NlZCwgdGhlIGdhcm1lbnQgaXMgb2Jzb2xldGUsIGJvdW5kIGZvciAKbGFuZGZpbGwgb3IgcmVjeWNsaW5nIG9yLCBtYXliZSwgdXBjeWNsaW5nLiAKCk9wdGltdW0gaW52ZW50b3J5LCBhY2NvcmRpbmcgdG8gdGhlIE5ld3N2ZW5kb3IgbW9kZWwsIGlzIGRldGVybWluZWQgYnkgdGhlIApyZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgY29zdCBvZiAqdW5kZXJzdG9ja2luZyosIHRoZSBjb3N0IGFzc29jaWF0ZWQgd2l0aCBub3QgCmhhdmluZyBhIGdhcm1lbnQgYXZhaWxhYmxlIHdoZW4gdGhlcmUgaXMgc3RpbGwgYSBkZW1hbmQgZm9yIHRoYXQgZ2FybWVudCwgYW5kIAp0aGUgY29zdCBvZiAqb3ZlcnN0b2NraW5nKiwgaGF2aW5nIHVuc29sZCBvciBvYnNvbGV0ZSBzdG9jayBhdCB0aGUgZW5kIG9mIHRoZSAKc2Vhc29uLgoKVGhlIGNvc3Qgb2YgKnVuZGVyc3RvY2tpbmcqLCAkQ197dX0kLCBpcyB0aGUgcmV2ZW51ZSB0aGF0IHdvdWxkIGhhdmUgYmVlbiAKb2J0YWluZWQgaWYgdGhlIGdhcm1lbnQgd2FzIHNvbGQuIFdoaWxlIHRoZSBjb3N0IG9mICpvdmVyc3RvY2tpbmcqLCAkQ197b30kLCAKaXMgdGhlIGNvc3QgdG8gdGhlIGJ1c2luZXNzIGluY3VycmVkIGJyaW5naW5nIHRoZSBnYXJtZW50IHRvIG1hcmtldC4gIAoKVGhpcyBhbGdvcml0aG1pYyBwcm9jZWR1cmUgc3VnZ2VzdHMgdGhhdCB0aGUgb3B0aW1hbCBvcmRlciBzaXplICRRXnsqfSQgaXMgCmFjaGlldmVkIHdoZW46CgokWygxLUYoUV57Kn0pKSBcdGltZXMgQ197dX1dK1tGKFFeeyp9KSBcdGltZXMgKC1DX3tvfSldID0gMCQKCgpJZiAkWygxLUYoUV57Kn0pKSBcdGltZXMgQ197dX1dK1tGKFFeeyp9KSBcdGltZXMgKC1DX3tvfSldID0gMCQgaG9sZHMgdGhlbiB0aGUgCm1lcmNoYW5kaXplciBhbmQgaW52ZW50b3J5IG1hbmFnZXIgY2Fubm90IGdhaW4gYW55IGFkdmFudGFnZSBlaXRoZXIgYnkgb3JkZXJpbmcgCm9uZSBtb3JlIGdhcm1lbnQgb3Igb25lIGxlc3MgZ2FybWVudC4gJFFeeyp9JCBpcyBvcHRpbWFsLiAgV2hhdCBpcyBjb29sLCBieSAKYWxnZWJyYWljYWxseSBtb3ZpbmcgdGhlIGV4cHJlc3Npb24gJEYoUV57Kn0pJCB0byB0aGUgbGVmdCBvZiB0aGUgZXF1YXRpb24gd2UgCmdldCB0aGUgKmNyaXRpY2FsIHJhdGlvKjoKCiRGKFFeeyp9KSA9IFxmcmFje0Nfe3V9fXsoQ197dX0gKyBDX3tvfSl9JAoKVGhlIHByb2JhYmlsaXR5IG9mIHNhdGlzZnlpbmcgYWxsIGRlbWFuZCBpcyBlcXVhbCB0byB0aGUgKmNyaXRpY2FsIHJhdGlvKi4gIFRoZSAKKmNyaXRpY2FsIHJhdGlvKiBpcyBhbHdheXMgYmV0d2VlbiAwIGFuZCAxLiBJZiB0aGUgY29zdCBvZiBvdmVyc3RvY2tpbmcgaXMgCnRoZSBzYW1lIGFzIHRoZSBjb3N0IG9mIHVuZGVyIHN0b2NraW5nIHRoZW4gdGhlICpjcml0aWNhbCByYXRpbyogaXMgMC41LiAKVGhlIG1lcmNoYW5kaXplciB3b3VsZCBjaG9vc2UgdGhlIHN0b2NrIGxldmVsIHRoYXQgZ2l2ZXMgYW4gZXF1YWwgY2hhbmNlIG9mIApoYXZpbmcgb3Igbm90IGhhdmluZyBhIHN0b2NrIG91dC4gSWYgdGhlICpjcml0aWNhbCByYXRpbyogaXMgZ3JlYXRlciAgdGhhbiAwLjUgCnRoZSBtYW5hZ2VyIHdvdWxkIG9yZGVyIG1vcmUgZ2FybWVudHMgc28gdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2YgaGF2aW5nIGVub3VnaCB0bwptZWV0IGRlbWFuZCBpcyBncmVhdGVyLiAgSWYgdGhlICpjcml0aWNhbCByYXRpbyogaXMgbGVzcyB0aGFuIDAuNSwgdGhlIG1hbmFnZXIgCndpbGwgb3JkZXIgbGVzcyBnYXJtZW50cy4gICAKCiMjIFNjZW5hcmlvCgpMZXQgdXMgcHVsbCBzb21lIG9mIHRoZXNlIGlkZWFzIHRvZ2V0aGVyIGludG8gYSBmcmFtZXdvcmsgYnkgZXhwbG9yaW5nIGEgCmNvbnRyaXZlZCBzY2VuYXJpbyB0aGF0IGlsbHVzdHJhdGVzIHRoZSBwb3NzaWJsZSByb2xlIG9mIHRoZSBtb2RlbHMgaW4gZmFzaGlvbgptZXJjaGFuZGl6aW5nLgoKSW1hZ2luZSBhIGJ1c2luZXNzIHRoYXQgc3BlbmRzIMKjNzAgcGVyIHVuaXQgZGV2ZWxvcGluZyBhIGZhc2hpb24gZ2FybWVudCBmb3IgbWFya2V0LiAgRGV2ZWxvcG1lbnQgY29zdHMgaW5jbHVkZSBtYXJrZXQgcmVzZWFyY2gsIGNvbnN1bHRhbnRzJyBmZWVzLCBtYW51ZmFjdHVyaW5nLCBhbmQgdmFyaW91cyBsb2dpc3RpYyBjb3N0cy4gIFRoZSBidXNpbmVzcyBjYWxjdWxhdGUgdGhhdCB0aGV5IG5lZWQgdG8gc2VsbCBlYWNoIGdhcm1lbnQgZm9yIMKjMTAwIHRvIGp1c3RpZnkgdGhlIGRldmVsb3BtZW50IGNvc3RzIGFuZCBndWFyYW50ZWUgYSBmYWlyIHJldHVybiBmb3IgdGhlIGJ1c2luZXNz4oCZIGludmVzdG9ycy4gICBUaGUgY2hpZWYgbWVjaGFuZGlzZXIgZm9yIHRoZSBidXNpbmVzcyBoYXMgbmVnb3RpYXRlZCBhIGRlYWwgd2l0aCBhIGdhcm1lbnQgZGlzY291bnQgY29tcGFueSB0byB0YWtlIGFueSB1bnNvbGQgZ2FybWVudHMgYXQgdGhlIGVuZCBvZiB0aGUgc2Vhc29uLiAgVGhlIGRpc2NvdW50ZXIgd2lsbCBwYXkgwqM2MS41MCBmb3IgZWFjaCB1bnNvbGQgZ2FybWVudC4gIFVuZGVyIHN1Y2ggYSBzY2VuYXJpbyAkQ197dX0kIGlzIMKjMTAwIC0gwqM3MCwgdGhlIMKjMzAgdGhhdCB3b3VsZCBoYXZlIGJlZW4gZ2VuZXJhdGVkIGJ5IGEgc2FsZSBpZiB0aGVyZSB3YXMgYSBnYXJtZW50IHRvIHNlbGwuICBUaGUgJENfe299JCBpcyDCozcwIC0gwqM2NS41MCwgdGhlIMKjOC41MCBsb3N0IGJlY2F1c2Ugb2YgcG9vciBzdG9jayBtYW5hZ2VtZW50LiAgVG8gYXZvaWQgaW5jdXJyaW5nICRDX3t1fSQgb3IgJENfe299JCB0aGUgYnVzaW5lc3MgbmVlZHMgdG8gbWFpbnRhaW4gYSBzdG9jayBsZXZlbCB3aGVyZSB0aGUgcHJvYmFiaWxpdHkgb2YgJENfe3V9JCBpcyBlcXVhbCB0byB0aGUgcHJvYmFiaWxpdHkgb2YgJENfe299JC4gICBUaGF0IGlzLCB0aGUgcHJvYmFiaWxpdHkgb2YgbWFraW5nIMKjMzAgbmVlZHMgdG8gYmUgZXF1YWwgdG8gdGhlIHByb2JhYmlsaXR5IG9mIGxvc2luZyDCozguNTAuIFNvIG1vcmUgc3RvY2sgaXMgb3JkZXJlZCB3aGlsZSB0aGUgY2hhbmNlcyBvZiBtYWtpbmcgYW4gYWRkaXRpb25hbCDCozMwIGRvbWluYXRlcy4gICBMZXNzIHN0b2NrIGlzIG9yZGVyZWQgd2hpbGUgdGhlIGNoYW5jZXMgb2YgbG9zaW5nIMKjOC41MCBkb21pbmF0ZXMuICBJbnR1aXRpdmVseSwgaW4gdGhpcyBleGFtcGxlLCBhbiBpbnZlbnRvcnkgbWFuYWdlciB3b3VsZCB0ZW5kIHRvIG92ZXJzdG9jayByYXRoZXIgdGhhbiB1bmRlcnN0b29kLiAgVGhlIHByb2JhYmlsaXR5IG9mIGxvc2luZyDCozguNTAgaXMgbW9yZSBhdHRyYWN0aXZlIHRoYW4gdGhlIHByb2JhYmlsaXR5IG9mIGxvc2luZyBhIHBvdGVudGlhbCBzYWxlIGFuZCB0aGUgwqMzMCB0aGF0IHdvdWxkIHJlc3VsdCBmcm9tIHRoYXQgc2FsZS4gQ2xlYXJseSwgdGhlcmUgaXMgYSBcdGV4dGl0e2NyaXRpY2FsIHJhdGlvfSBiZXR3ZWVuICRDX3t1fSQgYW5kICRDX3tvfSQgdGhhdCBndWFyYW50ZWVzIG5vIGxvc3Mgb2YgcmV2ZW51ZS4gIFRoZXJlZm9yZSwgdGhlIG9wdGltdW0gYW1vdW50IG9mIHN0b2NrIGEgYnVzaW5lc3MgY2FycmllcywgY2FsbCBpdCAkUV57Kn0kLCByZXF1aXJlcyBhIHByb2JhYmlsaXN0aWMgZm9yZWNhc3Qgb2YgZGVtYW5kLiAgV2hhdCBhcmUgdGhlIGNoYW5jZXMgdGhhdCBkZW1hbmQgd2lsbCBtYXRjaCAkUV97Kn0kIHNvIHRoYXQgdGhlcmUgaXMgbm8gb3ZlcnN0b2NraW5nLCBvciB1bmRlciBzdG9ja2luZz8gCgpBIHByb2JhYmlsaXN0aWMgZm9yZWNhc3QgYmFzZWQgb24gdGhlIGdlbmVyYXRpb24gb2YgYSBudW1iZXIgb2YgQmFzcyBtb2RlbHMgCnByb3ZpZGVzIGEgc2V0IG9mIHBvc3NpYmxlIGRlbWFuZCBwcm9maWxlcyBvdmVyIHRpbWUgYW5kIGFzc29jaWF0ZXMgd2l0aCBlYWNoIApwcm9maWxlIHRoZSBwcm9iYWJpbGl0eSAgaXQgd2lsbCBvY2N1ci4gIFRoZSBleHBlY3RlZCAnc2hhcGUnIG9mIGRlbWFuZDsgCmxlbmd0aCBhbmQgY3VydmUgb2YgKmdyb3d0aCosICptYXR1cml0eSosIGFuZCAqZGVjbGluZSo7IGlzIGRldGVybWluZWQgYnkgdGhlIEJhc3MgcGFyYW1ldGVycyAqcCosICpxKiBhbmQgKm0qLiAgSW5pdGlhbCB2YWx1ZXMgZm9yIHRoZXNlIHZhcmlhYmxlcyBjYW4gYmUgCmFudGljaXBhdGVkIGJ5IHRoZSBleHBlcnRpc2UgYW5kIGV4cGVyaWVuY2Ugb2YgbWVyY2hhbmRpemVycyB3aG8ga25vdyAKdGhlaXIgbWFya2V0IGFuZCBicmFuZCBjb25zdW1lcnMuICBGdXJ0aGVybW9yZSwgdGhlIHVuY2VydGFpbnkgYXNzb2NpYXRlZCB3aXRoIHRob3NlCnByb2Zlc3Npb25hbCBqdWRnZW1lbnRzIGNhbiBiZSBtb2RlbGxlZCB3aXRoIHRoZSAqZCogKHZhcmlhbmNlIGZyb20gdGhlIEJhc3MgcHJlZGljdGlvbgphdCB0aW1lICp0KikgYW5kICp1KiAocHJvYmFiaWxpdHkgdGhhdCB0aGUgbWFya2V0IHdpbGwgbm90IGFkb3B0IHRoZSBnYXJtZW50J3MgCmRlc2lnbiBhbmQgZ2VuZXJhdGUgc2FsZXMpIHBhcmFtZXRlcnMuIEZpc2hlciBhbmQgUmFtYW4gWzFdICBkaXNjcmliZSBhIHByYWdtYXRpYyBhcHByb2FjaCB0byBwcm9iYWJpbGlzdGljIGZvcmVjYXN0aW5nIGJ5IHNhbXBsaW5nIHRoZSBleHBlcnRpc2Ugb2YgbWVyY2hhbmRpc2VycyAKaW4gYSBzeXN0ZW1hdGljIHdheS4gIAoKTGV0J3MgYXNzdW1lIHRoZSBtZXJjaGFuZGl6ZXJzJyBwcm9mZXNzaW9uYWwganVkZ2VtZW50IGFudGljaXBhdGVzIHRoZSBjbGFzc2ljIApsaWZlLWN5Y2xlIGN1cnZlIGZvciBnYXJtZW50IHNhbGVzIG92ZXIgYSAxNTAgZGF5IHNlYXNvbi4gIE1hcmtldApyZXNlYXJjaCBhbmQgaGlzdG9yaWNhbCByZWNvcmRzIHN1Z2dlc3QgYXBwcm94aW1hdGUgc2FsZXMgb3ZlciBhIDEwMCBkYXkgc2Vhc29uCm9mIDY4MDAgdW5pdHMuIFRoaXMgcHJvZHVjZXMgYW4gaW5pdGlhbCBkZW1hbmQgcHJvZmlsZSBiYXNlZCBvbiB0aGUgY2Fub25pY2FsCkJhc3MgcHJvY2Vzcy4gIAoKYGBge3J9CnRpbWUubGluZSA8LSAoMToxMDApLzEwLjAKbSA8LSA2ODAwCnAgPC0gMC4wMDYKcSA8LSAwLjY0CgpuZ2V0ZSA8LSBleHAoLShwK3EpICogdGltZS5saW5lKQpCcGRmIDwtICBtICogKCAocCtxKV4yIC8gcCApICogbmdldGUgLyAoMSArIChxL3ApICogbmdldGUpXjIKcGxvdCh0aW1lLmxpbmUsIEJwZGYsICB4bGFiID0gIlRpbWUiLCB5bGFiID0gIlNhbGVzIikKYGBgCgpIb3dldmVyLCB0aGVyZSBpcyBzb21lIGNvbmNlcm4gYW1vdW5nIHRoZSBtYXJrZXRpbmcgdGVhbSBhbmQgc3RvcmUgbWFuYWdlcnMgYWJvdXQKY3VycmVudCB0cmFkaW5nIGNvbmRpdGlvbnMgYW5kIHRoZXkgcmVja29uIHNhbGVzIGNvdWxkIGZsdWN0dWF0ZSBlYWNoIGRheSBieQo1MCBnYXJtZW50cy4gIEZ1cnRoZXJtb3JlLCB0aGUgY2hpZWYgbWVyY2hhbmRpemVyIGJlbGlldmVzIHRoZXJlIGlzIGFsc28gYSAxNSUKY2hhbmNlIHRoYXQgdGhlIGdhcm1lbnQgd2lsbCBub3Qgc3VjY2VlZCAgaW4gY3VycmVudCBtYXJrZXQgY29uZGl0b25zIHdpdGggaXRzCmN1c3RvbWVycyB3aG8gYXJlIGRyYXduIHRvd2FyZHMgcml2YWwgZGVzaWduZXJzIGJlY2F1c2Ugb2Ygc29tZSBBbWVyaWNhbiBUVgpzaG93LiAgIFdlIGNhbiBmYWN0b3IgdGhlc2UgY29uZGl0aW9ucyBpbnRvIHRoZSBzaW11bGF0aW9uLgpgYGB7cn0Kc2FsZXMgIDwtICBiYXNzLm1vZGVsKDY4MDAsMC4wMDYsMC42NCwxMDAsNTAuMCwwLjE1KQpwbG90KHNhbGVzLCB4bGFiPSJEYXlzIiwgeWxhYj0iUG9zc2libGUgRGVtYW5kIikKYGBgCldlIGNhbiBydW4gdGhlc2UgcGFyYW1ldGVycyA1MDAwIHRpbWVzIHRvIGdlbmVyYXRlIGEgZGlzdHJpYnV0aW9uIG1vZGVsCm9mIGRlbWFuZCBhbmQgdGhlbiBhcHBseSB0aGUgTmV3c3ZlbmRvciBtb2RlbCB0byB0aGUgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gCmZ1bmN0aW9uIG9mIHRoZSBtb2RlbCB0byBkZXRlcm1pbmUgb3B0aW11bSBkYWlseSBpbnZlbnRvcnkuIAoKIyMgUmVmZXJlbmNlcwoKWzFdICpNYXJzaGFsbCBGaXNoZXIqIGFuZCAqQW5hbnRoIFJhbWFuKiAoMjAxMCkgKlRoZSBOZXcgU2NpZW5jZSBvZiBSZXRhaWxpbmc6IEhvdyAKQW5hbHl0aWNzIGFyZSBUcmFuc2Zvcm1pbmcgdGhlIFN1cHBseSBDaGFpbiBhbmQgSW1wcm92aW5nIFBlcmZvcm1hbmNlKiwgSGFydmFyZCAKQnVzaW5lc3MgU2Nob29sIFByZXNzLCAzLCA2MS0xMDUuCgoKCgo=