Introduction
The purpose of this document is to outline inventory management techniques from the standpoint of operations research. This document will cover the basics of inventory management and include specific examples covered in the Georgia Tech MGMT-6203 course. The contents included here are NOT part of a homework assignment, or exam, but rather just a “re-working” of the examples used in the course content. Georgia Tech is very much concerned about academic integrity and honesty. My goal is not to cheat, but rather the help others understand the lectures.
The original work was done by Bob Myers, Lecturer, Georgia Institute of Technology, MGMT-6203 Data Analytics for Business, Summer 2020.
Inventory Basics
Inventory is:
- Raw materials
- Component parts
- Work in process (Through at least 1 step.)
- Finished goods
- MRO - Items that are required but not used to make something.
“Stock of anything for future use.”
Inventory management matches supply to demand.
Why would a company want more inventory?
- Hedge for demand
- Protects agains supply disruption
- Discounts for ordering more
Why would a company want inventory?
- Inventory can become obsolete
- Perhishable can spoil
- Shrinkage (theft)
- Holding Costs (Insurance, security, warehouse, etc)
- Opportunity Costs - More money tied up in inventory
Inventory management comes down to determining when to reorder, and how much to order?
Economic Order Quantity (EOQ)
Total Cost = Ordering Cost + Inventory Cost
- Ordering Cost = (Number of orders) x (cost per order)
- Inventory (holding) Cost = (average inventory) x (holding cost per year)
Ordering costs encourage more inventory. Inventory costs encourages less inventory.
Assumptions:
- Demand D is known and constant
- We have a known ordering cost, S, and immediate replenishment
- No limit on order on quantity
- Annual holding costs of average inventory is H per unit
- Assume Ordering and Inventory (Holding) costs are the only relevant costs
Note in the above, that the average inventory is S/2
Based on the above, we can create a graph that shows total cost, holding costs and ordering costs. What we will want to do with the below equation is to minimize the EOQ equation based on a given D,S and H.
As a result, the Total cost is a minimum when Ordering cost = Holding cost or:
\[\frac{D}{Q}S=\frac{Q}{2}H\] Solving for Q we get the formula to economic quantity:
\[Q^*=\sqrt{\frac{2SD}{H}}\] We use the notation \(Q^*\) to denote that holding cost equals ordering cost.
The above is the formula to EOQ
Going further we can compute the number of orders (N) we expect to make in a year.
\[N=\frac{D}{Q^*}\]
And we can calculate the number of days between orders (T) as follows:
Given: \(wdy=\)Working days per year
\[T=\frac{wdy}{N}\] The following R code will compute Q*, N and T given S, Q and H. In this function:
- s=Ordering Cost
- d=Constant Demand
- h=Holding Cost
calculate_eoq <- function(s=order_cost,d=demand,h=holding_cost,wdy=working_days_per_year){
Qstar <- sqrt((2*s*d)/h)
n <- d/Qstar
t <- wdy/n
return(data.frame(EOQ=Qstar,N=n,'T'=t))
}
calculate_eoq(10,1000,.50,200)
Q9
Economic ordering with discount:
In order to compute the Expanded Total Cost (ETC), we use the following steps:
##1
\[ETC=\frac{D}{Q}*S+\frac{Q}{2}*H+P*D\] Where:
- D = Annual Demand
- Q = Quantity Ordered
- S = Setup/Order Cost
- H = Holding Cost per unit per year
- P = Price per unit
##2
Consider the following inventory order setup:
Demand=1400 Price per unit=400 Inventory Cost (percentage)=20% Order Cost=25
If we order 300 or more, we get a 5% discount. In that case we would have:
- Demand=1400
- Price per unit=400*95%
- Inventory Cost (percentage)=20%
- Order Cost=25
To see if it makes economic sense to take the discount for 300 units, we calculate the ETC at the different levels:
discount_etc <- calculate_etc(1400,300,25,.2*25,400*.95)$ETC
cat(paste("\nCalculate total cost with discount= ",discount_etc))
Calculate total cost with discount= 532866.666666667
nodisc_etc <- calculate_etc(1400,300,25*.2,0,400)$ETC
cat(paste("\nCalculate total cost without discount=", nodisc_etc))
Calculate total cost without discount= 560023.333333333
Since the discount price is lower, it makes sense to take the 5% discount for ordering 300.
Reorder point ROP
When should we place an order. When, as in when the inventory drops below a certain point.
L: Lead Time (Known and constant) \(\bar{d}\): Average daily demand (Known and constant)
Generally, we have this formula…
\[ROP=\bar{d}*L\]
In the above ROP is a QUANTITY. When inventory drops below that point, we will reorder.
Now, if demand can vary, we have the following:
Safety Stock creates a buffer.
As a result, the probability of having sufficient a stock out plus the probability of a stock out is 100%.
So, that leads us to the following equation for Safety Stock (SS) given the standard deviation in lead time demand.
\[SS=(z)(\sigma_{LT})\]
Where \(z\) is a score from a standard normal talbe for service level \(G_{(z)}\)
So, we are going to make an approximation using this formula:
\[\sigma_{LT}=\sqrt{(L)(\sigma_D)^2}=\sigma_D\sqrt{LT}\ne(\sigma_D)(LT)\] In other words, standard deviation over multiple periods is the square root of the sum of the variances, not the sum of the standard deviations.
This provides us the folloiwng expanded of ROP:
\[ROP = E[d]+Z\sigma_D\sqrt{LT}\] Where: - E[d] = Expected demand during lead time - Z= Number of standard deviations (from Z table) - \(\sigma_d\)=Standard deviation of demand - LT=Lead time
Remember that the impacts of safety stock are: - How strong the desire to NOT stock out - Demand uncertainty - Lead time
A complete example
You work at Best Buy in an Inventory Management role. Your boss wants no more than 10% of stock out probability and has asked you to recommend a reorder point for Apple iPads. You review the sales data and determine that the daily average demand for iPads is 15 with a standard deviation of 5 units. The lead time from Apple for more iPads is 2 days. What reorder point do you recommend and what portion of that is safety stock?
- Lead time = 2
- \(\sigma_D\)=5
- E[d] = Average Demand * LT = 30
To find the Z value, you need to look in the Z table, and find the value IN THE TABLE that is close to the service level. In this case, since our stock out probability is 10%, our service level is 100%-10%=90%. The corresponding value from this table (the Z column) is 1.2.
So, the last value is Z=1.28.
Using the equation above, we have the following:
\[ROP = E[d]+Z\sigma_D\sqrt{LT} = 30+(1.2)(5)\sqrt{2}\approx39\] The following code provides a function to calculate ROP based on the variables above:
calculate_rop <- function(ED, Z, sigma, LT){
return(data.frame(ROP=ED+(Z*sigma*sqrt(LT)), ss=Z*sigma*sqrt(LT)))
}
calculate_rop(30,1.28,5,2)
Safety stock can be calculated as:
\[SS=\sigma_D\sqrt{LT}=1.28*5*sqrt(2)\approx9\]
Sample Inventory Policy
So, when do you order and how much do you reorder.
To answer part 1, we want to us the EOQ equation. Since now quantity discount was mentioned, we use the basic EOQ equation.
- D=8000
- S=50
- H=IP=$10.05=.5
\[EOQ=\sqrt{\frac{2*D*S}{H}}=\sqrt{\frac{2*8000*50}{.5}}\approx1265\] Using the previously defined function in R, we have:
The number to reorder, EOQ, is 1265 units.
To answer part 2, we have the following:
ED = Expected Demand during Lead Time = Demand Per Year / 365 = 21.97802
So, calculating per week, we have the following:
- E[d]=8000/52=153.8462
- \(\sigma_D\)=400
- z=1.75
- LT=7
Note that the Z score was found by looking in a table, and finding the Z score for .96.
Using the function defined above, we have:
As a result, we should reorder 1265 units when inventory drops below 2006.
This completes this write up.
LS0tCnRpdGxlOiAiSW52ZW50b3J5IE1hbmFnZW1lbnQiCm91dHB1dDogaHRtbF9ub3RlYm9vawphdXRob3I6IE1pbGVzIFBvcnRlcgpEYXRlOiBKdWx5IDE3LCAyMDIwCi0tLQoKIyBJbnRyb2R1Y3Rpb24KClRoZSBwdXJwb3NlIG9mIHRoaXMgZG9jdW1lbnQgaXMgdG8gb3V0bGluZSBpbnZlbnRvcnkgbWFuYWdlbWVudCB0ZWNobmlxdWVzIGZyb20gdGhlIHN0YW5kcG9pbnQgb2Ygb3BlcmF0aW9ucyByZXNlYXJjaC4gIFRoaXMgZG9jdW1lbnQgd2lsbCBjb3ZlciB0aGUgYmFzaWNzIG9mIGludmVudG9yeSBtYW5hZ2VtZW50IGFuZCBpbmNsdWRlIHNwZWNpZmljIGV4YW1wbGVzIGNvdmVyZWQgaW4gdGhlIEdlb3JnaWEgVGVjaCBNR01ULTYyMDMgY291cnNlLiAgVGhlIGNvbnRlbnRzIGluY2x1ZGVkIGhlcmUgYXJlIE5PVCBwYXJ0IG9mIGEgaG9tZXdvcmsgYXNzaWdubWVudCwgb3IgZXhhbSwgYnV0IHJhdGhlciBqdXN0IGEgInJlLXdvcmtpbmciIG9mIHRoZSBleGFtcGxlcyB1c2VkIGluIHRoZSBjb3Vyc2UgY29udGVudC4gIEdlb3JnaWEgVGVjaCBpcyB2ZXJ5IG11Y2ggY29uY2VybmVkIGFib3V0IGFjYWRlbWljIGludGVncml0eSBhbmQgaG9uZXN0eS4gIE15IGdvYWwgaXMgbm90IHRvIGNoZWF0LCBidXQgcmF0aGVyIHRoZSBoZWxwIG90aGVycyB1bmRlcnN0YW5kIHRoZSBsZWN0dXJlcy4KClRoZSBvcmlnaW5hbCB3b3JrIHdhcyBkb25lIGJ5IEJvYiBNeWVycywgTGVjdHVyZXIsIEdlb3JnaWEgSW5zdGl0dXRlIG9mIFRlY2hub2xvZ3ksIE1HTVQtNjIwMyBEYXRhIEFuYWx5dGljcyBmb3IgQnVzaW5lc3MsIFN1bW1lciAyMDIwLiAKCiMgSW52ZW50b3J5IEJhc2ljcwoKSW52ZW50b3J5IGlzOgoKIC0gUmF3IG1hdGVyaWFscwogLSBDb21wb25lbnQgcGFydHMKIC0gV29yayBpbiBwcm9jZXNzIChUaHJvdWdoIGF0IGxlYXN0IDEgc3RlcC4pCiAtIEZpbmlzaGVkIGdvb2RzCiAtIE1STyAtIEl0ZW1zIHRoYXQgYXJlIHJlcXVpcmVkIGJ1dCBub3QgdXNlZCB0byBtYWtlIHNvbWV0aGluZy4KIAogIlN0b2NrIG9mIGFueXRoaW5nIGZvciBmdXR1cmUgdXNlLiIKIApJbnZlbnRvcnkgbWFuYWdlbWVudCBtYXRjaGVzIHN1cHBseSB0byBkZW1hbmQuCiAKV2h5IHdvdWxkIGEgY29tcGFueSB3YW50IG1vcmUgaW52ZW50b3J5PwoKLSBIZWRnZSBmb3IgZGVtYW5kCi0gUHJvdGVjdHMgYWdhaW5zIHN1cHBseSBkaXNydXB0aW9uCi0gRGlzY291bnRzIGZvciBvcmRlcmluZyBtb3JlCgpXaHkgd291bGQgYSBjb21wYW55IHdhbnQgaW52ZW50b3J5PwoKLSBJbnZlbnRvcnkgY2FuIGJlY29tZSBvYnNvbGV0ZQotIFBlcmhpc2hhYmxlIGNhbiBzcG9pbAotIFNocmlua2FnZSAodGhlZnQpCi0gSG9sZGluZyBDb3N0cyAoSW5zdXJhbmNlLCBzZWN1cml0eSwgd2FyZWhvdXNlLCBldGMpCi0gT3Bwb3J0dW5pdHkgQ29zdHMgLSBNb3JlIG1vbmV5IHRpZWQgdXAgaW4gaW52ZW50b3J5CgpJbnZlbnRvcnkgbWFuYWdlbWVudCBjb21lcyBkb3duIHRvIGRldGVybWluaW5nIHdoZW4gdG8gcmVvcmRlciwgYW5kIGhvdyBtdWNoIHRvIG9yZGVyPwoKIyBFY29ub21pYyBPcmRlciBRdWFudGl0eSAoRU9RKQoKVG90YWwgQ29zdCA9IE9yZGVyaW5nIENvc3QgKyBJbnZlbnRvcnkgQ29zdAoKLSBPcmRlcmluZyBDb3N0ID0gIChOdW1iZXIgb2Ygb3JkZXJzKSB4IChjb3N0IHBlciBvcmRlcikKLSBJbnZlbnRvcnkgKGhvbGRpbmcpIENvc3QgPSAoYXZlcmFnZSBpbnZlbnRvcnkpIHggKGhvbGRpbmcgY29zdCBwZXIgeWVhcikKCk9yZGVyaW5nIGNvc3RzIGVuY291cmFnZSBtb3JlIGludmVudG9yeS4KSW52ZW50b3J5IGNvc3RzIGVuY291cmFnZXMgbGVzcyBpbnZlbnRvcnkuCgpBc3N1bXB0aW9uczoKCi0gRGVtYW5kICpEKiBpcyBrbm93biBhbmQgY29uc3RhbnQKLSBXZSBoYXZlIGEga25vd24gb3JkZXJpbmcgY29zdCwgKlMqLCBhbmQgaW1tZWRpYXRlIHJlcGxlbmlzaG1lbnQKLSBObyBsaW1pdCBvbiBvcmRlciBvbiBxdWFudGl0eQotIEFubnVhbCBob2xkaW5nIGNvc3RzIG9mIGF2ZXJhZ2UgaW52ZW50b3J5IGlzICpIKiBwZXIgdW5pdAotIEFzc3VtZSBPcmRlcmluZyBhbmQgSW52ZW50b3J5IChIb2xkaW5nKSBjb3N0cyBhcmUgdGhlIG9ubHkgcmVsZXZhbnQgY29zdHMKCiFbT3JkZXIgQmF0Y2hlc10ob3JkZXJfYmF0Y2hlcy5wbmcpCgpOb3RlIGluIHRoZSBhYm92ZSwgdGhhdCB0aGUgYXZlcmFnZSBpbnZlbnRvcnkgaXMgUy8yCgpCYXNlZCBvbiB0aGUgYWJvdmUsIHdlIGNhbiBjcmVhdGUgYSBncmFwaCB0aGF0IHNob3dzIHRvdGFsIGNvc3QsIGhvbGRpbmcgY29zdHMgYW5kIG9yZGVyaW5nIGNvc3RzLiAgV2hhdCB3ZSB3aWxsIHdhbnQgdG8gZG8gd2l0aCB0aGUgYmVsb3cgZXF1YXRpb24gaXMgdG8gbWluaW1pemUgdGhlIEVPUSBlcXVhdGlvbiBiYXNlZCBvbiBhIGdpdmVuIEQsUyBhbmQgSC4KCiFbRU9RIEdyYXBoaWNdKEVPUV9HcmFwaGljLnBuZykKCkFzIGEgcmVzdWx0LCB0aGUgVG90YWwgY29zdCBpcyBhIG1pbmltdW0gd2hlbiBPcmRlcmluZyBjb3N0ID0gSG9sZGluZyBjb3N0IG9yOgoKJCRcZnJhY3tEfXtRfVM9XGZyYWN7UX17Mn1IJCQKU29sdmluZyBmb3IgUSB3ZSBnZXQgdGhlIGZvcm11bGEgdG8gZWNvbm9taWMgcXVhbnRpdHk6CgokJFFeKj1cc3FydHtcZnJhY3syU0R9e0h9fSQkCldlIHVzZSB0aGUgbm90YXRpb24gJFFeKiQgdG8gZGVub3RlIHRoYXQgaG9sZGluZyBjb3N0IGVxdWFscyBvcmRlcmluZyBjb3N0LgoKVGhlIGFib3ZlIGlzIHRoZSBmb3JtdWxhIHRvIEVPUQoKR29pbmcgZnVydGhlciB3ZSBjYW4gY29tcHV0ZSB0aGUgbnVtYmVyIG9mIG9yZGVycyAoTikgd2UgZXhwZWN0IHRvIG1ha2UgaW4gYSB5ZWFyLgoKJCROPVxmcmFje0R9e1FeKn0kJAoKQW5kIHdlIGNhbiBjYWxjdWxhdGUgdGhlIG51bWJlciBvZiBkYXlzIGJldHdlZW4gb3JkZXJzIChUKSBhcyBmb2xsb3dzOgoKR2l2ZW46ICR3ZHk9JFdvcmtpbmcgZGF5cyBwZXIgeWVhcgoKJCRUPVxmcmFje3dkeX17Tn0kJApUaGUgZm9sbG93aW5nIFIgY29kZSB3aWxsIGNvbXB1dGUgUSosIE4gYW5kIFQgZ2l2ZW4gUywgUSBhbmQgSC4gIEluIHRoaXMgZnVuY3Rpb246CgotIHM9T3JkZXJpbmcgQ29zdAotIGQ9Q29uc3RhbnQgRGVtYW5kCi0gaD1Ib2xkaW5nIENvc3QKCmBgYHtyfQpjYWxjdWxhdGVfZW9xIDwtIGZ1bmN0aW9uKHM9b3JkZXJfY29zdCxkPWRlbWFuZCxoPWhvbGRpbmdfY29zdCx3ZHk9d29ya2luZ19kYXlzX3Blcl95ZWFyKXsKICBRc3RhciA8LSBzcXJ0KCgyKnMqZCkvaCkKICBuIDwtIGQvUXN0YXIKICB0IDwtIHdkeS9uCiAgcmV0dXJuKGRhdGEuZnJhbWUoRU9RPVFzdGFyLE49biwnVCc9dCkpCn0KCmNhbGN1bGF0ZV9lb3EoMTAsMTAwMCwuNTAsMjAwKQpgYGAKCiMgUTkKCmBgYHtyfQpjYWxjdWxhdGVfZW9xKDMwLCA2MDAwLCAxMCwgMzAwKQpgYGAKRWNvbm9taWMgb3JkZXJpbmcgd2l0aCBkaXNjb3VudDoKCkluIG9yZGVyIHRvIGNvbXB1dGUgdGhlIEV4cGFuZGVkIFRvdGFsIENvc3QgKEVUQyksIHdlIHVzZSB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKIyMxCgokJEVUQz1cZnJhY3tEfXtRfSpTK1xmcmFje1F9ezJ9KkgrUCpEJCQKV2hlcmU6CgotIEQgPSBBbm51YWwgRGVtYW5kCi0gUSA9IFF1YW50aXR5IE9yZGVyZWQKLSBTID0gU2V0dXAvT3JkZXIgQ29zdAotIEggPSBIb2xkaW5nIENvc3QgcGVyIHVuaXQgcGVyIHllYXIKLSBQID0gUHJpY2UgcGVyIHVuaXQKCiMjMiAgCgpDb25zaWRlciB0aGUgZm9sbG93aW5nIGludmVudG9yeSBvcmRlciBzZXR1cDoKCkRlbWFuZD0xNDAwClByaWNlIHBlciB1bml0PTQwMApJbnZlbnRvcnkgQ29zdCAocGVyY2VudGFnZSk9MjAlCk9yZGVyIENvc3Q9MjUKCklmIHdlIG9yZGVyIDMwMCBvciBtb3JlLCB3ZSBnZXQgYSA1JSBkaXNjb3VudC4gIEluIHRoYXQgY2FzZSB3ZSB3b3VsZCBoYXZlOgoKLSBEZW1hbmQ9MTQwMAotIFByaWNlIHBlciB1bml0PTQwMCo5NSUKLSBJbnZlbnRvcnkgQ29zdCAocGVyY2VudGFnZSk9MjAlCi0gT3JkZXIgQ29zdD0yNQoKVG8gc2VlIGlmIGl0IG1ha2VzIGVjb25vbWljIHNlbnNlIHRvIHRha2UgdGhlIGRpc2NvdW50IGZvciAzMDAgdW5pdHMsIHdlIGNhbGN1bGF0ZSB0aGUgRVRDIGF0IHRoZSBkaWZmZXJlbnQgbGV2ZWxzOgoKYGBge3J9CmRpc2NvdW50X2V0YyA8LSBjYWxjdWxhdGVfZXRjKDE0MDAsMzAwLDI1LC4yKjI1LDQwMCouOTUpJEVUQwpjYXQocGFzdGUoIlxuQ2FsY3VsYXRlIHRvdGFsIGNvc3Qgd2l0aCBkaXNjb3VudD0gICAiLGRpc2NvdW50X2V0YykpCgpub2Rpc2NfZXRjIDwtIGNhbGN1bGF0ZV9ldGMoMTQwMCwzMDAsMjUqLjIsMCw0MDApJEVUQwpjYXQocGFzdGUoIlxuQ2FsY3VsYXRlIHRvdGFsIGNvc3Qgd2l0aG91dCBkaXNjb3VudD0iLCBub2Rpc2NfZXRjKSkKCmBgYApTaW5jZSB0aGUgZGlzY291bnQgcHJpY2UgaXMgbG93ZXIsIGl0IG1ha2VzIHNlbnNlIHRvIHRha2UgdGhlIDUlIGRpc2NvdW50IGZvciBvcmRlcmluZyAzMDAuCgojIFJlb3JkZXIgcG9pbnQgUk9QCgpXaGVuIHNob3VsZCB3ZSBwbGFjZSBhbiBvcmRlci4gIFdoZW4sIGFzIGluIHdoZW4gdGhlIGludmVudG9yeSBkcm9wcyBiZWxvdyBhIGNlcnRhaW4gcG9pbnQuCgpMOiBMZWFkIFRpbWUgKEtub3duIGFuZCBjb25zdGFudCkKJFxiYXJ7ZH0kOiBBdmVyYWdlIGRhaWx5IGRlbWFuZCAoS25vd24gYW5kIGNvbnN0YW50KQoKR2VuZXJhbGx5LCB3ZSBoYXZlIHRoaXMgZm9ybXVsYS4uLgoKJCRST1A9XGJhcntkfSpMJCQKCkluIHRoZSBhYm92ZSBST1AgaXMgYSBRVUFOVElUWS4gIFdoZW4gaW52ZW50b3J5IGRyb3BzIGJlbG93IHRoYXQgcG9pbnQsIHdlIHdpbGwgcmVvcmRlci4KCk5vdywgaWYgZGVtYW5kIGNhbiB2YXJ5LCB3ZSBoYXZlIHRoZSBmb2xsb3dpbmc6CgohW1VuY2VydGFpbiBEZW1hbmRdKHVuY2VydGFpbl9kZW1hbmQucG5nKQoKU2FmZXR5IFN0b2NrIGNyZWF0ZXMgYSBidWZmZXIuCgohW1NhZmV0eSBTdG9ja10oc2FmZXR5X3N0b2NrLnBuZykKIVtTZXJ2aWNlIExldmVsXShzZXJ2aWNlX2xldmVsLnBuZykKQXMgYSByZXN1bHQsIHRoZSBwcm9iYWJpbGl0eSBvZiBoYXZpbmcgc3VmZmljaWVudCBhIHN0b2NrIG91dCBwbHVzIHRoZSBwcm9iYWJpbGl0eSBvZiBhIHN0b2NrIG91dCBpcyAxMDAlLgoKU28sIHRoYXQgbGVhZHMgdXMgdG8gdGhlIGZvbGxvd2luZyBlcXVhdGlvbiBmb3IgU2FmZXR5IFN0b2NrIChTUykgZ2l2ZW4gdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBpbiBsZWFkIHRpbWUgZGVtYW5kLgoKJCRTUz0oeikoXHNpZ21hX3tMVH0pJCQKCldoZXJlICR6JCBpcyBhIHNjb3JlIGZyb20gYSBzdGFuZGFyZCBub3JtYWwgdGFsYmUgZm9yIHNlcnZpY2UgbGV2ZWwgJEdfeyh6KX0kCgpTbywgd2UgYXJlIGdvaW5nIHRvIG1ha2UgYW4gYXBwcm94aW1hdGlvbiB1c2luZyB0aGlzIGZvcm11bGE6CgokJFxzaWdtYV97TFR9PVxzcXJ0eyhMKShcc2lnbWFfRCleMn09XHNpZ21hX0Rcc3FydHtMVH1cbmUoXHNpZ21hX0QpKExUKSQkCkluIG90aGVyIHdvcmRzLCBzdGFuZGFyZCBkZXZpYXRpb24gb3ZlciBtdWx0aXBsZSBwZXJpb2RzIGlzIHRoZSBzcXVhcmUgcm9vdCBvZiB0aGUgc3VtIG9mIHRoZSB2YXJpYW5jZXMsIG5vdCB0aGUgc3VtIG9mIHRoZSBzdGFuZGFyZCBkZXZpYXRpb25zLgoKVGhpcyBwcm92aWRlcyB1cyB0aGUgZm9sbG9pd25nIGV4cGFuZGVkIG9mIFJPUDoKCiQkUk9QID0gRVtkXStaXHNpZ21hX0Rcc3FydHtMVH0kJApXaGVyZToKLSBFW2RdID0gRXhwZWN0ZWQgZGVtYW5kIGR1cmluZyBsZWFkIHRpbWUKLSBaPSBOdW1iZXIgb2Ygc3RhbmRhcmQgZGV2aWF0aW9ucyAoZnJvbSBaIHRhYmxlKQotICRcc2lnbWFfZCQ9U3RhbmRhcmQgZGV2aWF0aW9uIG9mIGRlbWFuZAotIExUPUxlYWQgdGltZQoKUmVtZW1iZXIgdGhhdCB0aGUgaW1wYWN0cyBvZiBzYWZldHkgc3RvY2sgYXJlOgotIEhvdyBzdHJvbmcgdGhlIGRlc2lyZSB0byBOT1Qgc3RvY2sgb3V0Ci0gRGVtYW5kIHVuY2VydGFpbnR5Ci0gTGVhZCB0aW1lCgojIEEgY29tcGxldGUgZXhhbXBsZQoKWW91IHdvcmsgYXQgQmVzdCBCdXkgaW4gYW4gSW52ZW50b3J5IE1hbmFnZW1lbnQgcm9sZS4gIFlvdXIgYm9zcyB3YW50cyBubyBtb3JlIHRoYW4gMTAlIG9mIHN0b2NrIG91dCBwcm9iYWJpbGl0eSBhbmQgaGFzIGFza2VkIHlvdSB0byByZWNvbW1lbmQgYSByZW9yZGVyIHBvaW50IGZvciBBcHBsZSBpUGFkcy4gIFlvdSByZXZpZXcgdGhlIHNhbGVzIGRhdGEgYW5kIGRldGVybWluZSB0aGF0IHRoZSBkYWlseSBhdmVyYWdlIGRlbWFuZCBmb3IgaVBhZHMgaXMgMTUgd2l0aCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiA1IHVuaXRzLiAgVGhlIGxlYWQgdGltZSBmcm9tIEFwcGxlIGZvciBtb3JlIGlQYWRzIGlzIDIgZGF5cy4gIFdoYXQgcmVvcmRlciBwb2ludCBkbyB5b3UgcmVjb21tZW5kIGFuZCB3aGF0IHBvcnRpb24gb2YgdGhhdCBpcyBzYWZldHkgc3RvY2s/CgotIExlYWQgdGltZSA9IDIKLSAkXHNpZ21hX0QkPTUKLSBFW2RdID0gQXZlcmFnZSBEZW1hbmQgKiBMVCA9IDMwCgpUbyBmaW5kIHRoZSBaIHZhbHVlLCB5b3UgbmVlZCB0byBsb29rIGluIHRoZSBaIHRhYmxlLCBhbmQgZmluZCB0aGUgdmFsdWUgSU4gVEhFIFRBQkxFIHRoYXQgaXMgY2xvc2UgdG8gdGhlIHNlcnZpY2UgbGV2ZWwuICBJbiB0aGlzIGNhc2UsIHNpbmNlIG91ciBzdG9jayBvdXQgcHJvYmFiaWxpdHkgaXMgMTAlLCBvdXIgc2VydmljZSBsZXZlbCBpcyAxMDAlLTEwJT05MCUuICBUaGUgY29ycmVzcG9uZGluZyB2YWx1ZSBmcm9tIHRoaXMgdGFibGUgKHRoZSBaIGNvbHVtbikgaXMgMS4yLgoKIVtaIHRhYmxlXSh6X3RhYmxlLnBuZykKU28sIHRoZSBsYXN0IHZhbHVlIGlzIFo9MS4yOC4KClVzaW5nIHRoZSBlcXVhdGlvbiBhYm92ZSwgd2UgaGF2ZSB0aGUgZm9sbG93aW5nOgoKJCRST1AgPSBFW2RdK1pcc2lnbWFfRFxzcXJ0e0xUfSA9IDMwKygxLjIpKDUpXHNxcnR7Mn1cYXBwcm94MzkkJApUaGUgZm9sbG93aW5nIGNvZGUgcHJvdmlkZXMgYSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgUk9QIGJhc2VkIG9uIHRoZSB2YXJpYWJsZXMgYWJvdmU6CgpgYGB7cn0KY2FsY3VsYXRlX3JvcCA8LSBmdW5jdGlvbihFRCwgWiwgc2lnbWEsIExUKXsKICByZXR1cm4oZGF0YS5mcmFtZShST1A9RUQrKFoqc2lnbWEqc3FydChMVCkpLCBzcz1aKnNpZ21hKnNxcnQoTFQpKSkKfQpjYWxjdWxhdGVfcm9wKDMwLDEuMjgsNSwyKQpgYGAKCgpTYWZldHkgc3RvY2sgY2FuIGJlIGNhbGN1bGF0ZWQgYXM6CgokJFNTPVxzaWdtYV9EXHNxcnR7TFR9PTEuMjgqNSpzcXJ0KDIpXGFwcHJveDkkJAoKIyBTYW1wbGUgSW52ZW50b3J5IFBvbGljeQoKIVtHVFJJIEVYQU1QTEVdKGd0cmlfZXhhbXBsZS5wbmcpCgpTbywgd2hlbiBkbyB5b3Ugb3JkZXIgYW5kIGhvdyBtdWNoIGRvIHlvdSByZW9yZGVyLgoKVG8gYW5zd2VyIHBhcnQgMSwgd2Ugd2FudCB0byB1cyB0aGUgRU9RIGVxdWF0aW9uLiAgU2luY2Ugbm93IHF1YW50aXR5IGRpc2NvdW50IHdhcyBtZW50aW9uZWQsIHdlIHVzZSB0aGUgYmFzaWMgRU9RIGVxdWF0aW9uLgoKLSBEPTgwMDAKLSBTPTUwCi0gSD1JKlA9JDEwKi4wNT0uNQoKJCRFT1E9XHNxcnR7XGZyYWN7MipEKlN9e0h9fT1cc3FydHtcZnJhY3syKjgwMDAqNTB9ey41fX1cYXBwcm94MTI2NSQkClVzaW5nIHRoZSBwcmV2aW91c2x5IGRlZmluZWQgZnVuY3Rpb24gaW4gUiwgd2UgaGF2ZToKCmBgYHtyfQpjYWxjdWxhdGVfZW9xKDUwLDgwMDAsLjUsMzY1KQpgYGAKClRoZSBudW1iZXIgdG8gcmVvcmRlciwgRU9RLCBpcyAxMjY1IHVuaXRzLgoKVG8gYW5zd2VyIHBhcnQgMiwgd2UgaGF2ZSB0aGUgZm9sbG93aW5nOgoKRUQgPSBFeHBlY3RlZCBEZW1hbmQgZHVyaW5nIExlYWQgVGltZSA9IERlbWFuZCBQZXIgWWVhciAvIDM2NSA9IDIxLjk3ODAyCgpTbywgY2FsY3VsYXRpbmcgcGVyIHdlZWssIHdlIGhhdmUgdGhlIGZvbGxvd2luZzoKCi0gRVtkXT04MDAwLzUyPTE1My44NDYyCi0gJFxzaWdtYV9EJD00MDAKLSB6PTEuNzUKLSBMVD03CgpOb3RlIHRoYXQgdGhlIFogc2NvcmUgd2FzIGZvdW5kIGJ5IGxvb2tpbmcgaW4gYSB0YWJsZSwgYW5kIGZpbmRpbmcgdGhlIFogc2NvcmUgZm9yIC45Ni4KCiFbWiBUYWJsZSAyXSh6X3RhYmxlMi5wbmcpCgpVc2luZyB0aGUgZnVuY3Rpb24gZGVmaW5lZCBhYm92ZSwgd2UgaGF2ZToKCmBgYHtyfQpjYWxjdWxhdGVfcm9wKDE1My44NDYyLDEuNzUsNDAwLDcpCmBgYAoKQXMgYSByZXN1bHQsIHdlIHNob3VsZCByZW9yZGVyIDEyNjUgdW5pdHMgd2hlbiBpbnZlbnRvcnkgZHJvcHMgYmVsb3cgMjAwNi4KClRoaXMgY29tcGxldGVzIHRoaXMgd3JpdGUgdXAuCgoKCgoKCgoKCgoKIAo=