What is the disadvantage of a single piece of code?
x = 25
epsilon = 0.01
numGuesses = 0
low = 0.0
high = max(1.0, x)
ans = (high + low)/2.0
while abs(ans**2 - x) >= epsilon:
print('low =', low, 'high =', high, 'ans =', ans)
numGuesses += 1
if ans**2 < x:
low = ans
else:
high = ans
ans = (high + low)/2.0
print('numGuesses =', numGuesses)
print(ans, 'is close to square root of', x)
This is a reasonable piece of code, but it lacks general utility. There are two main reasons.
- depending on inner variable value hard to reuse;
- Multiple chunks of almost identical code.
It works only for values denoted by the variables x and epsilon. This means that if we want to reuse it, we need to copy the code, possibly edit the variable names, and paste it where we want it. Because of this we cannot easily use this computation inside of some other, more complex, computation.
Furthermore, if we want to compute cube roots rather than square roots, we have to edit the code. If we want a program that computes both square and cube roots (or for that matter square roots in two different places), the program would contain multiple chunks of almost identical code. This is a very bad thing. The more code a program contains, the more chance there is for something to go wrong, and the harder the code is to maintain. Imagine, for example, that there was an error in the initial implementation of square root, and that the error came to light when testing the program. It would be all too easy to fix the implementation of square root in one place and forget that there was similar code elsewhere that was also in need of repair.
4.2 Specifications
What are the benefits of the investment in writing testing code?
- It beats typing test cases into the shell over and over again during debugging.
- It forces us think about which tests are likely to be more illuminating.
What is docstring in Python used for?
By convention, Python programmers use docstrings to provide specifications of functions. These docstrings can be accessed using the built-in function help.
What is specification of a function?
A specification of a function defines a contract between the implementer of a function and those who will be writing programs that use the function. We will refer to the users of a function as its clients. This contract can be thought of as containing two parts:
• Assumptions: These describe conditions that must be met by clients of the function. Typically, they describe constraints on the actual parameters. Almost always, they specify the acceptable set of types for each parameter, and not infrequently some constraints on the value of one or more of the parameters. For example, the first two lines of the docstring of findRoot describe the assumptions that must be satisfied by clients of findRoot.
• Guarantees: These describe conditions that must be met by the function, provided that it has been called in a way that satisfies the assumptions. The last two lines of the docstring of findRoot describe the guarantees that the implementation of the function must meet.
findRoot(x, power, epsilon)
Assumes x and epsilon int or float, power an int,
epsilon > 0 & power >= 1
Returns float y such that y**power is within epsilon of x.
If such a float does not exist, it returns None
What is the meaning of creating functions in programming?
Functions are a way of creating computational elements that we can think of as primitives.
By what means does function facilitate the convenience of have handy primitives?
Functions facilitate this by providing decomposition and abstraction.
Decomposition creates structure. It allows us to break a program into parts that are reasonably self-contained, and that may be reused in different settings.
Abstraction hides detail. It allows us to use a piece of code as if it were a black box—that is, something whose interior details we cannot see, don’t need to see, and shouldn’t even want to see.
What is the essence of abstraction?
The essence of abstraction is preserving information that is relevant in a given context, and forgetting information that is irrelevant in that context.
How to use abstraction effectively in programming?
The key to using abstraction effectively in programming is finding a notion of relevance that is appropriate for both the builder of an abstraction and the potential clients of the abstraction. That is the true art of programming.
What is abstraction all about? Give some model in daily life.
Abstraction is all about forgetting. There are lots of ways to model this, for example, the auditory apparatus of most teenagers.
Teenager says: May I borrow the car tonight?
Parent says: Yes, but be back before midnight, and make sure that the gas tank is full.
Teenager hears: Yes.
The teenager has ignored all of those pesky details that he or she considers irrelevant. Abstraction is a many-to-one process. Had the parent said Yes, but be back before 2:00 a.m., and make sure that the car is clean, it would also have been abstracted to Yes.
What is the role of specification of module in team programming?
This is the way organizations go about using teams of programmers to get things done. Given a specification of a module, a programmer can work on implementing that module without worrying unduly about what the other programmers on the team are doing. Moreover, the other programmers can use the specification to start writing code that uses that module without worrying unduly about how that module is to be implemented.
4.3 Recursion
Why it is a charming urban legend that recursion is a rather subtle programming technique?
Recursion is a very important idea, but it’s not so subtle, and it is more than a programming technique.
What kind of method is recursive?
It is a descriptive method.
What is a recursive description made of?
In general, a recursive definition is made up of two parts. There is at least one base case that directly specifies the result for a special case (case 1 in the example above), and there is at least one recursive (inductive) case (cases 2 and 3 in the example above) that defines the answer in terms of the answer to the question on some other input, typically a simpler version of the same problem.
Why we should be explicit when speaking “nature number”?
The exact definition of “natural number” is subject to debate. Some define it as the positive integers and others as the nonnegative integers. That’s why we were explicit about the possible values of n in the docstrings in
"""Assumes n an int > 0
Returns n!"""
What are the iterative and recursive implementation of factorial?
The classic inductive definition is \[
\begin{array}{c}1 !=1 \\ (n+1) !=(n+1) * n !\end{array}
\] Here is the iterative implementation of factorial.
def factI(n):
""" Assumes n an int > 0
Returns n!"""
result = 1
while n > 1:
result = result * n
n -= 1
return result
Here is the recursive implementation of factorial.
def factR(n):
""" Assumes n an int > 0
Returns n!"""
if n == 1:
return n
else:
return n * factR (n - 1)
The second is a more obvious translation of the original recursive definition.
How to describe the Fibonacci sequence of rabbits?
Suppose a newly born pair of rabbits, one male and one female, are put in a pen (or worse, released in the wild). Suppose further that the rabbits are able to mate at the age of one month (which, astonishingly, some breeds can) and have a one-month gestation period (which, astonishingly, some breeds do). Finally, suppose that these mythical rabbits never die, and that the female always produces one new pair (one male, one female) every month from its second month on. How many female rabbits will there be at the end of six months?
On the last day of the first month (call it month 0), there will be one female (ready to conceive on the first day of the next month). On the last day of the second month, there will still be only one female (since she will not give birth until the first day of the next month). On the last day of the next month, there will be two females (one pregnant and one not). On the last day of the next month, there will be three females (two pregnant and one not). And so on. Let’s look at this progression in tabular form, Figure 4.6.
0 |
1 |
1 |
1 |
2 |
2 |
3 |
3 |
4 |
5 |
5 |
8 |
6 |
13 |
Figure 4.6 Growth in population of female rabbits
Notice that for month n > 1, females(n) = females(n-1) + females(n-2). This is not an accident. Each female that was alive in month n-1 will still be alive in month n. In addition, each female that was alive in month n-2 will produce one new female in month n. The new females can be added to the females alive in month n-1 to get the number of females in month n.
The growth in population is described naturally by the recurrence.
females(0) = 1
females(1) = 1
females(n + 2) = females(n+1) + females(n)
Here is an obviously correct, but terribly inefficient implementation of the Fibonacci function.
def fib(n):
""" Assues n int >= 0
Returns Fibonacci of n """
if n == 0 or n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
def testFib(n):
for i in range(n+1):
print('fib of', i, '=', fib(i))
testFib(8)
How do you feel in the coding process of the Fibonacci function?
Writing the code is the easy part of solving this problem. Once we went from the vague statement of a problem about bunnies to a set of recursive equations, the code almost wrote itself. Finding some kind of abstract way to express a solution to the problem at hand is very often the hardest step in building a useful program.
How to construct code to implement palindrome testing with printed message to visualize the processing steps?
[Note where the printed messages are put.]
def isPalindrome(s):
""" Assumes s is a str
Returns True if s is a palindrome; False otherwise.
Punctuation marks, blanks, and capitalization are ignored."""
def toChars(s):
s = s.lower()
letters = ''
for c in s:
if c in 'abcdefghijklmnopqrstuvwxyz':
letters = letters + c
return letters
def isPal(s):
print(' isPal called with', s)
if len(s) <= 1:
print(' About to return True from base case')
return True
else:
answer = s[0] == s[-1] and isPal(s[1:-1])
print(' About to return', answer, 'for', s)
return answer
return isPal(toChars(s))
def testIsPalindrome():
print('Try dogGod')
print(isPalindrome('dogGod'))
print('Try doGood')
print(isPalindrome('doGood'))
testIsPalindrome()
What is short-circuit evaluation?
The conjunction in the else
clause is evaluated from left to right. The code first checks whether the first and last characters are the same, and if they are goes on to check whether the string minus those two characters is a palindrome. That the second conjunct is not evaluated unless the first conjunct evaluates to True
is semantically irrelevant in this example. However, later in the book we will see examples where this kind of short-circuit evaluation of Boolean expressions is semantically relevant.
What is the problem-solving principle known as divide-and-conquer?
This principle is related to but slightly different from divide-and-conquer algorithms.
The problem-solving principle is to conquer a hard problem by breaking it into a set of subproblems with the properties that
- the subproblems are easier to solve than the original problem, and
- solutions of the subproblems can be combined to solve the original problem.
Divide-and-conquer is a very old idea. Julius Caesar practiced what the Romans referred to as divide et impera (divide and rule). The British practiced it brilliantly to control the Indian subcontinent. Benjamin Franklin was well aware of the British expertise in using this technique, prompting him to say at the signing of the U.S. Declaration of Independence, “We must all hang together, or assuredly we shall all hang separately.”
4.5 Modules
What is Python module?
Python modules allow us to easily construct a program from code in multiple files. A module is a .py
file containing Python definitions and statements.
How to use names in Module?
Modules are typically stored in individual files. Each module has its own private symbol table. Executing import M
creates a binding for module M
in the scope in which the import
appears. Therefore, in the importing context we use dot notation to indicate that we are referring to a name defined in the imported module.
When is the module imported?
As we have seen, a module can contain executable statements as well as function definitions. Typically, these statements are used to initialize the module. For this reason, the statements in a module are executed only the first time a module is imported into a program. Moreover, a module is imported only once per interpreter session. If you start up a shell, import a module, and then change the contents of that module, the interpreter will still be using the original version of the module. This can lead to puzzling behavior when debugging.
4.6 Files
How does Python achieves operation-system independence?
Accessing files through something called a file handle.
Why is it important to remember to close the file when the program is finished using it?
There is a risk that some or all of the writes may not be saved.
Some of the common operations on files.
open(fn, ‘w’) fn is a string representing a file name. Creates a file for writing and returns a file handle.
open(fn, ‘r’) fn is a string representing a file name. Opens an existing file for reading and returns a file handle.
open(fn, ‘a’) fn is a string representing a file name. Opens an existing file for appending and returns a file handle.
fh.read() returns a string containing the contents of the file associated with the file handle fh.
fh.readline() returns the next line in the file associated with the file handle fh.
fh.readlines() returns a list each element of which is one line of the file asso- ciated with the file handle fh.
fh.write(s) writes the string s to the end of the file associated with the file handle fh.
fh.writeLines(S) S is a sequence of strings. Writes each element of S as a sepa- rate line to the file associated with the file handle fh.
fh.close() closes the file associated with the file handle fh.
LS0tCnRpdGxlOiAwNCBGVU5DVElPTlMsIFNDT1BJTkcsIEFORCBBQlNUUkFDVElPTgpzdWJ0aXRsZTogCmF1dGhvcjog5puy5pS/CmRhdGU6IDIwMjAtMDUtMjYKc2x1ZzogZnVuY3Rpb25zLXNjb3BpbmctYWJzdHJhY3Rpb24KdGFnczoKLSAKY2F0ZWdvcmllczoKLSBtaXQ2MDAwCi0gSUNQUCBib29rbm90ZXMKdHlwb3JhLXJvb3QtdXJsOiAuLi8uLi9zdGF0aWMKc2hvd190b2M6IHllcwpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyMgV2hhdCBpcyB0aGUgZGlzYWR2YW50YWdlIG9mIGEgc2luZ2xlIHBpZWNlIG9mIGNvZGU/CgpgYGB7cHl0aG9ufQp4ID0gMjUKZXBzaWxvbiA9IDAuMDEKbnVtR3Vlc3NlcyA9IDAKbG93ID0gMC4wCmhpZ2ggPSBtYXgoMS4wLCB4KQphbnMgPSAoaGlnaCArIGxvdykvMi4wCndoaWxlIGFicyhhbnMqKjIgLSB4KSA+PSBlcHNpbG9uOgogICAgcHJpbnQoJ2xvdyA9JywgbG93LCAnaGlnaCA9JywgaGlnaCwgJ2FucyA9JywgYW5zKSAKICAgIG51bUd1ZXNzZXMgKz0gMQogICAgaWYgYW5zKioyIDwgeDoKICAgICAgICBsb3cgPSBhbnMgCiAgICBlbHNlOgogICAgICAgIGhpZ2ggPSBhbnMKICAgIGFucyA9IChoaWdoICsgbG93KS8yLjAKcHJpbnQoJ251bUd1ZXNzZXMgPScsIG51bUd1ZXNzZXMpIApwcmludChhbnMsICdpcyBjbG9zZSB0byBzcXVhcmUgcm9vdCBvZicsIHgpCmBgYAoKVGhpcyBpcyBhIHJlYXNvbmFibGUgcGllY2Ugb2YgY29kZSwgYnV0IGl0IGxhY2tzIGdlbmVyYWwgdXRpbGl0eS4gVGhlcmUgYXJlIHR3byBtYWluIHJlYXNvbnMuCgoxLiBkZXBlbmRpbmcgb24gaW5uZXIgdmFyaWFibGUgdmFsdWUgaGFyZCB0byByZXVzZTsKMS4gTXVsdGlwbGUgY2h1bmtzIG9mIGFsbW9zdCBpZGVudGljYWwgY29kZS4KCkl0IHdvcmtzIG9ubHkgZm9yIHZhbHVlcyBkZW5vdGVkIGJ5IHRoZSB2YXJpYWJsZXMgeCBhbmQgZXBzaWxvbi4gVGhpcyBtZWFucyB0aGF0IGlmIHdlIHdhbnQgdG8gcmV1c2UgaXQsIHdlIG5lZWQgdG8gY29weSB0aGUgY29kZSwgcG9zc2libHkgZWRpdCB0aGUgdmFyaWFibGUgbmFtZXMsIGFuZCBwYXN0ZSBpdCB3aGVyZSB3ZSB3YW50IGl0LiBCZWNhdXNlIG9mIHRoaXMgd2UgY2Fubm90IGVhc2lseSB1c2UgdGhpcyBjb21wdXRhdGlvbiBpbnNpZGUgb2Ygc29tZSBvdGhlciwgbW9yZSBjb21wbGV4LCBjb21wdXRhdGlvbi4KCkZ1cnRoZXJtb3JlLCBpZiB3ZSB3YW50IHRvIGNvbXB1dGUgY3ViZSByb290cyByYXRoZXIgdGhhbiBzcXVhcmUgcm9vdHMsIHdlIGhhdmUgdG8gZWRpdCB0aGUgY29kZS4gSWYgd2Ugd2FudCBhIHByb2dyYW0gdGhhdCBjb21wdXRlcyBib3RoIHNxdWFyZSBhbmQgY3ViZSByb290cyAob3IgZm9yIHRoYXQgbWF0dGVyIHNxdWFyZSByb290cyBpbiB0d28gZGlmZmVyZW50IHBsYWNlcyksIHRoZSBwcm9ncmFtIHdvdWxkIGNvbnRhaW4gbXVsdGlwbGUgY2h1bmtzIG9mIGFsbW9zdCBpZGVudGljYWwgY29kZS4gVGhpcyBpcyBhIHZlcnkgYmFkIHRoaW5nLiBUaGUgbW9yZSBjb2RlIGEgcHJvZ3JhbSBjb250YWlucywgdGhlIG1vcmUgY2hhbmNlIHRoZXJlIGlzIGZvciBzb21ldGhpbmcgdG8gZ28gd3JvbmcsIGFuZCB0aGUgaGFyZGVyIHRoZSBjb2RlIGlzIHRvIG1haW50YWluLiBJbWFnaW5lLCBmb3IgZXhhbXBsZSwgdGhhdCB0aGVyZSB3YXMgYW4gZXJyb3IgaW4gdGhlIGluaXRpYWwgaW1wbGVtZW50YXRpb24gb2Ygc3F1YXJlIHJvb3QsIGFuZCB0aGF0IHRoZSBlcnJvciBjYW1lIHRvIGxpZ2h0IHdoZW4gdGVzdGluZyB0aGUgcHJvZ3JhbS4gSXQgd291bGQgYmUgYWxsIHRvbyBlYXN5IHRvIGZpeCB0aGUgaW1wbGVtZW50YXRpb24gb2Ygc3F1YXJlIHJvb3QgaW4gb25lIHBsYWNlIGFuZCBmb3JnZXQgdGhhdCB0aGVyZSB3YXMgc2ltaWxhciBjb2RlIGVsc2V3aGVyZSB0aGF0IHdhcyBhbHNvIGluIG5lZWQgb2YgcmVwYWlyLgoKIyMgNC4xIEZ1bmN0aW9ucyBhbmQgU2NvcGluZwoKIyMjIFdoYXQgaXMgdGhlIHByb2Zlc3Npb25hbCB0ZXJtcyBhYm91dCBhIGZ1bmN0aW9uPwoKLSBmdW5jdGlvbiBuYW1lOiBzaW1wbHkgYSBuYW1lIHRoYXQgaXMgdXNlZCB0byByZWZlciB0byB0aGUgZnVuY3Rpb24KCi0gZm9ybWFsIHBhcmFtZXRlcnM6IAotIGFjdHVhbCBwYXJhbWV0ZXJzIChvZnRlbiByZWZlcnJlZCB0byBhcyBhcmd1bWVudHMpOiAKLSBmdW5jdGlvbiBpbnZvY2F0aW9uIChhbHNvIHJlZmVycmVkIHRvIGFzIGEgZnVuY3Rpb24gY2FsbCkKICA+IFRoZSBzZXF1ZW5jZSBvZiBuYW1lcyB3aXRoaW4gdGhlIHBhcmVudGhlc2VzIGZvbGxvd2luZyB0aGUgZnVuY3Rpb24gbmFtZSAoeCwgeSBpbiB0aGlzIGV4YW1wbGUpIGFyZSB0aGUgZm9ybWFsIHBhcmFtZXRlcnMgb2YgdGhlIGZ1bmN0aW9uLiBXaGVuIHRoZSBmdW5jdGlvbiBpcyB1c2VkLCB0aGUgZm9ybWFsIHBhcmFtZXRlcnMgYXJlIGJvdW5kIChhcyBpbiBhbiBhc3NpZ25tZW50IHN0YXRlbWVudCkgdG8gdGhlIGFjdHVhbCBwYXJhbWV0ZXJzIChvZnRlbiByZWZlcnJlZCB0byBhcyBhcmd1bWVudHMpIG9mIHRoZSBmdW5jdGlvbiBpbnZvY2F0aW9uIChhbHNvIHJlZmVycmVkIHRvIGFzIGEgZnVuY3Rpb24gY2FsbCkuCgogID4gQSBmdW5jdGlvbiBjYWxsIGlzIGFuIGV4cHJlc3Npb24sIGFuZCBsaWtlIGFsbCBleHByZXNzaW9ucyBpdCBoYXMgYSB2YWx1ZS4gVGhhdCB2YWx1ZSBpcyB0aGUgdmFsdWUgcmV0dXJuZWQgYnkgdGhlIGludm9rZWQgZnVuY3Rpb24uCgotIGZ1bmN0aW9uIGJvZHk6IAoKICA+IFRoZSBmdW5jdGlvbiBib2R5IGlzIGFueSBwaWVjZSBvZiBQeXRob24gY29kZS4gIHRoaXMgbm90aW9uIG9mIGZ1bmN0aW9uIGlzIG1vcmUgZ2VuZXJhbCB0aGFuIHdoYXQgbWF0aGVtYXRpY2lhbnMgY2FsbCBhIGZ1bmN0aW9uLiBJdCB3YXMgZmlyc3QgcG9wdWxhcml6ZWQgYnkgdGhlIHByb2dyYW1taW5nIGxhbmd1YWdlIEZvcnRyYW4gMiBpbiB0aGUgbGF0ZSAxOTUwcy4KCi0gcG9pbnQgb2YgZXhlY3V0aW9uOiB0aGUgbmV4dCBpbnN0cnVjdGlvbiB0byBiZSBleGVjdXRlZAoKLSBsYW1iZGEgYWJzdHJhY3Rpb246IAoKICBQYXJhbWV0ZXJzIHByb3ZpZGUgc29tZXRoaW5nIGNhbGxlZCBsYW1iZGEgYWJzdHJhY3Rpb24sIGFsbG93aW5nIHByb2dyYW1tZXJzIHRvIHdyaXRlIGNvZGUgdGhhdCBtYW5pcHVsYXRlcyBub3Qgc3BlY2lmaWMgb2JqZWN0cywgYnV0IGluc3RlYWQgd2hhdGV2ZXIgb2JqZWN0cyB0aGUgY2FsbGVyIG9mIHRoZSBmdW5jdGlvbiBjaG9vc2VzIHRvIHVzZSBhcyBhY3R1YWwgcGFyYW1ldGVycy4g44CQ5LiN55CG6Kej6L+Z6YeM55qE5oSP5oCd77yM5LiN55CG6Kej5Li65LuA5LmI5pS+5Zyo6L+Z6YeM6K+044CC44CRCgotIG5hbWUgc3BhY2UgKGFsc28gY2FsbGVkIGEgc2NvcGUpOgoKICA+IFRoZSBmb3JtYWwgcGFyYW1ldGVyIHggYW5kIHRoZSBsb2NhbCB2YXJpYWJsZSB5IHRoYXQgYXJlIHVzZWQgaW4gZiBleGlzdCBvbmx5IHdpdGhpbiB0aGUgc2NvcGUgb2YgdGhlIGRlZmluaXRpb24gb2YgYGZgLgoKLSBzeW1ib2wgdGFibGU6IGtlZXBzIHRyYWNrIG9mIGFsbCBuYW1lcyBkZWZpbmVkIGF0IHRoYXQgbGV2ZWwgYW5kIHRoZWlyIGN1cnJlbnQgYmluZGluZ3MuCgotIGEgc3RhY2sgZnJhbWU6IGEgbmV3IHN5bWJvbCB0YWJsZSBjcmVhdGVkIHdoZW4gYSBmdW5jdGlvbiBpcyBjYWxsZWQKCiAgPiBUaGlzIHRhYmxlIGtlZXBzIHRyYWNrIG9mIGFsbCBuYW1lcyBkZWZpbmVkIHdpdGhpbiB0aGUgZnVuY3Rpb24gKGluY2x1ZGluZyB0aGUgZm9ybWFsIHBhcmFtZXRlcnMpIGFuZCB0aGVpciBjdXJyZW50IGJpbmRpbmdzLiBJZiBhIGZ1bmN0aW9uIGlzIGNhbGxlZCBmcm9tIHdpdGhpbiB0aGUgZnVuY3Rpb24gYm9keSwgeWV0IGFub3RoZXIgc3RhY2sgZnJhbWUgaXMgY3JlYXRlZC4KCi0gc3RhdGljIG9yIGxleGljYWwgc2NvcGluZzogSW4gUHl0aG9uLCBvbmUgY2FuIGFsd2F5cyBkZXRlcm1pbmUgdGhlIHNjb3BlIG9mIGEgbmFtZSBieSBsb29raW5nIGF0IHRoZSBwcm9ncmFtIHRleHQuCgojIyA0LjIgU3BlY2lmaWNhdGlvbnMKCiMjIyBXaGF0IGFyZSB0aGUgYmVuZWZpdHMgb2YgdGhlIGludmVzdG1lbnQgaW4gd3JpdGluZyB0ZXN0aW5nIGNvZGU/CgoxLiBJdCBiZWF0cyB0eXBpbmcgdGVzdCBjYXNlcyBpbnRvIHRoZSBzaGVsbCBvdmVyIGFuZCBvdmVyIGFnYWluIGR1cmluZyBkZWJ1Z2dpbmcuCjEuIEl0IGZvcmNlcyB1cyB0aGluayBhYm91dCB3aGljaCB0ZXN0cyBhcmUgbGlrZWx5IHRvIGJlIG1vcmUgaWxsdW1pbmF0aW5nLgoKIyMjIFdoYXQgaXMgZG9jc3RyaW5nIGluIFB5dGhvbiB1c2VkIGZvcj8KCkJ5IGNvbnZlbnRpb24sIFB5dGhvbiBwcm9ncmFtbWVycyB1c2UgZG9jc3RyaW5ncyB0byBwcm92aWRlIHNwZWNpZmljYXRpb25zIG9mIGZ1bmN0aW9ucy4gVGhlc2UgZG9jc3RyaW5ncyBjYW4gYmUgYWNjZXNzZWQgdXNpbmcgdGhlIGJ1aWx0LWluIGZ1bmN0aW9uICoqaGVscCoqLgoKIyMjIFdoYXQgaXMgc3BlY2lmaWNhdGlvbiBvZiBhIGZ1bmN0aW9uPwoKQSBzcGVjaWZpY2F0aW9uIG9mIGEgZnVuY3Rpb24gZGVmaW5lcyBhIGNvbnRyYWN0IGJldHdlZW4gdGhlIGltcGxlbWVudGVyIG9mIGEgZnVuY3Rpb24gYW5kIHRob3NlIHdobyB3aWxsIGJlIHdyaXRpbmcgcHJvZ3JhbXMgdGhhdCB1c2UgdGhlIGZ1bmN0aW9uLiBXZSB3aWxsIHJlZmVyIHRvIHRoZSB1c2VycyBvZiBhIGZ1bmN0aW9uIGFzIGl0cyBjbGllbnRzLiBUaGlzIGNvbnRyYWN0IGNhbiBiZSB0aG91Z2h0IG9mIGFzIGNvbnRhaW5pbmcgdHdvIHBhcnRzOgoK4oCiIEFzc3VtcHRpb25zOiBUaGVzZSBkZXNjcmliZSBjb25kaXRpb25zIHRoYXQgbXVzdCBiZSBtZXQgYnkgY2xpZW50cyBvZiB0aGUgZnVuY3Rpb24uIFR5cGljYWxseSwgdGhleSBkZXNjcmliZSBjb25zdHJhaW50cyBvbiB0aGUgYWN0dWFsIHBhcmFtZXRlcnMuIEFsbW9zdCBhbHdheXMsIHRoZXkgc3BlY2lmeSB0aGUgYWNjZXB0YWJsZSBzZXQgb2YgdHlwZXMgZm9yIGVhY2ggcGFyYW1ldGVyLCBhbmQgbm90IGluZnJlcXVlbnRseSBzb21lIGNvbnN0cmFpbnRzIG9uIHRoZSB2YWx1ZSBvZiBvbmUgb3IgbW9yZSBvZiB0aGUgcGFyYW1ldGVycy4gRm9yIGV4YW1wbGUsIHRoZSBmaXJzdCB0d28gbGluZXMgb2YgdGhlIGRvY3N0cmluZyBvZiBmaW5kUm9vdCBkZXNjcmliZSB0aGUgYXNzdW1wdGlvbnMgdGhhdCBtdXN0IGJlIHNhdGlzZmllZCBieSBjbGllbnRzIG9mIGZpbmRSb290LgoK4oCiIEd1YXJhbnRlZXM6IFRoZXNlIGRlc2NyaWJlIGNvbmRpdGlvbnMgdGhhdCBtdXN0IGJlIG1ldCBieSB0aGUgZnVuY3Rpb24sIHByb3ZpZGVkIHRoYXQgaXQgaGFzIGJlZW4gY2FsbGVkIGluIGEgd2F5IHRoYXQgc2F0aXNmaWVzIHRoZSBhc3N1bXB0aW9ucy4gVGhlIGxhc3QgdHdvIGxpbmVzIG9mIHRoZSBkb2NzdHJpbmcgb2YgZmluZFJvb3QgZGVzY3JpYmUgdGhlIGd1YXJhbnRlZXMgdGhhdCB0aGUgaW1wbGVtZW50YXRpb24gb2YgdGhlIGZ1bmN0aW9uIG11c3QgbWVldC4KCmBgYHNoZWxsCmZpbmRSb290KHgsIHBvd2VyLCBlcHNpbG9uKQoJQXNzdW1lcyB4IGFuZCBlcHNpbG9uIGludCBvciBmbG9hdCwgcG93ZXIgYW4gaW50LAoJCWVwc2lsb24gPiAwICYgcG93ZXIgPj0gMQoJUmV0dXJucyBmbG9hdCB5IHN1Y2ggdGhhdCB5Kipwb3dlciBpcyB3aXRoaW4gZXBzaWxvbiBvZiB4LgoJCUlmIHN1Y2ggYSBmbG9hdCBkb2VzIG5vdCBleGlzdCwgaXQgcmV0dXJucyBOb25lCmBgYAoKIyMjIFdoYXQgaXMgdGhlIG1lYW5pbmcgb2YgY3JlYXRpbmcgZnVuY3Rpb25zIGluIHByb2dyYW1taW5nPwoKRnVuY3Rpb25zIGFyZSBhIHdheSBvZiBjcmVhdGluZyBjb21wdXRhdGlvbmFsIGVsZW1lbnRzIHRoYXQgd2UgY2FuIHRoaW5rIG9mIGFzIHByaW1pdGl2ZXMuCgojIyMgQnkgd2hhdCBtZWFucyBkb2VzIGZ1bmN0aW9uIGZhY2lsaXRhdGUgdGhlIGNvbnZlbmllbmNlIG9mIGhhdmUgaGFuZHkgcHJpbWl0aXZlcz8KCkZ1bmN0aW9ucyBmYWNpbGl0YXRlIHRoaXMgYnkgcHJvdmlkaW5nIGRlY29tcG9zaXRpb24gYW5kIGFic3RyYWN0aW9uLgoKRGVjb21wb3NpdGlvbiBjcmVhdGVzIHN0cnVjdHVyZS4gSXQgYWxsb3dzIHVzIHRvIGJyZWFrIGEgcHJvZ3JhbSBpbnRvIHBhcnRzIHRoYXQgYXJlIHJlYXNvbmFibHkgc2VsZi1jb250YWluZWQsIGFuZCB0aGF0IG1heSBiZSByZXVzZWQgaW4gZGlmZmVyZW50IHNldHRpbmdzLgoKQWJzdHJhY3Rpb24gaGlkZXMgZGV0YWlsLiBJdCBhbGxvd3MgdXMgdG8gdXNlIGEgcGllY2Ugb2YgY29kZSBhcyBpZiBpdCB3ZXJlIGEgYmxhY2sgYm944oCUdGhhdCBpcywgc29tZXRoaW5nIHdob3NlIGludGVyaW9yIGRldGFpbHMgd2UgY2Fubm90IHNlZSwgZG9u4oCZdCBuZWVkIHRvIHNlZSwgYW5kIHNob3VsZG7igJl0IGV2ZW4gd2FudCB0byBzZWUuW15HcmF5XSAKClteR3JheV06IOKAnFdoZXJlIGlnbm9yYW5jZSBpcyBibGlzcywg4oCZdGlzIGZvbGx5IHRvIGJlIHdpc2Uu4oCd4oCUVGhvbWFzIEdyYXkg4oCc5peg55+l5piv56aP77yM5aSn5pm66Iul5oSa44CCCgojIyMgV2hhdCBpcyB0aGUgZXNzZW5jZSBvZiBhYnN0cmFjdGlvbj8KClRoZSBlc3NlbmNlIG9mIGFic3RyYWN0aW9uIGlzIHByZXNlcnZpbmcgaW5mb3JtYXRpb24gdGhhdCBpcyByZWxldmFudCBpbiBhIGdpdmVuIGNvbnRleHQsIGFuZCBmb3JnZXR0aW5nIGluZm9ybWF0aW9uIHRoYXQgaXMgaXJyZWxldmFudCBpbiB0aGF0IGNvbnRleHQuIAoKIyMjIEhvdyB0byB1c2UgYWJzdHJhY3Rpb24gZWZmZWN0aXZlbHkgaW4gcHJvZ3JhbW1pbmc/CgpUaGUga2V5IHRvIHVzaW5nIGFic3RyYWN0aW9uIGVmZmVjdGl2ZWx5IGluIHByb2dyYW1taW5nIGlzIGZpbmRpbmcgYSBub3Rpb24gb2YgcmVsZXZhbmNlIHRoYXQgaXMgYXBwcm9wcmlhdGUgZm9yIGJvdGggdGhlIGJ1aWxkZXIgb2YgYW4gYWJzdHJhY3Rpb24gYW5kIHRoZSBwb3RlbnRpYWwgY2xpZW50cyBvZiB0aGUgYWJzdHJhY3Rpb24uIFRoYXQgaXMgdGhlIHRydWUgYXJ0IG9mIHByb2dyYW1taW5nLgoKIyMjIFdoYXQgaXMgYWJzdHJhY3Rpb24gYWxsIGFib3V0PyBHaXZlIHNvbWUgbW9kZWwgaW4gZGFpbHkgbGlmZS4KCkFic3RyYWN0aW9uIGlzIGFsbCBhYm91dCBmb3JnZXR0aW5nLiBUaGVyZSBhcmUgbG90cyBvZiB3YXlzIHRvIG1vZGVsIHRoaXMsIGZvciBleGFtcGxlLCB0aGUgYXVkaXRvcnkgYXBwYXJhdHVzIG9mIG1vc3QgdGVlbmFnZXJzLgoKPiBUZWVuYWdlciBzYXlzOiBNYXkgSSBib3Jyb3cgdGhlIGNhciB0b25pZ2h0Pwo+Cj4gUGFyZW50IHNheXM6IFllcywgYnV0IGJlIGJhY2sgYmVmb3JlIG1pZG5pZ2h0LCBhbmQgbWFrZSBzdXJlIHRoYXQgdGhlIGdhcyB0YW5rIGlzIGZ1bGwuCj4KPiBUZWVuYWdlciBoZWFyczogWWVzLgoKVGhlIHRlZW5hZ2VyIGhhcyBpZ25vcmVkIGFsbCBvZiB0aG9zZSBwZXNreSBkZXRhaWxzIHRoYXQgaGUgb3Igc2hlIGNvbnNpZGVycyBpcnJlbGV2YW50LiBBYnN0cmFjdGlvbiBpcyBhIG1hbnktdG8tb25lIHByb2Nlc3MuIEhhZCB0aGUgcGFyZW50IHNhaWQgWWVzLCBidXQgYmUgYmFjayBiZWZvcmUgMjowMCBhLm0uLCBhbmQgbWFrZSBzdXJlIHRoYXQgdGhlIGNhciBpcyBjbGVhbiwgaXQgd291bGQgYWxzbyBoYXZlIGJlZW4gYWJzdHJhY3RlZCB0byBZZXMuCgojIyMgV2hhdCBpcyB0aGUgcm9sZSBvZiBzcGVjaWZpY2F0aW9uIG9mIG1vZHVsZSBpbiB0ZWFtIHByb2dyYW1taW5nPwoKVGhpcyBpcyB0aGUgd2F5IG9yZ2FuaXphdGlvbnMgZ28gYWJvdXQgdXNpbmcgdGVhbXMgb2YgcHJvZ3JhbW1lcnMgdG8gZ2V0IHRoaW5ncyBkb25lLiBHaXZlbiBhIHNwZWNpZmljYXRpb24gb2YgYSBtb2R1bGUsIGEgcHJvZ3JhbW1lciBjYW4gd29yayBvbiBpbXBsZW1lbnRpbmcgdGhhdCBtb2R1bGUgd2l0aG91dCB3b3JyeWluZyB1bmR1bHkgYWJvdXQgd2hhdCB0aGUgb3RoZXIgcHJvZ3JhbW1lcnMgb24gdGhlIHRlYW0gYXJlIGRvaW5nLiBNb3Jlb3ZlciwgdGhlIG90aGVyIHByb2dyYW1tZXJzIGNhbiB1c2UgdGhlIHNwZWNpZmljYXRpb24gdG8gc3RhcnQgd3JpdGluZyBjb2RlIHRoYXQgdXNlcyB0aGF0IG1vZHVsZSB3aXRob3V0IHdvcnJ5aW5nIHVuZHVseSBhYm91dCBob3cgdGhhdCBtb2R1bGUgaXMgdG8gYmUgaW1wbGVtZW50ZWQuCgojIyA0LjMgUmVjdXJzaW9uCgojIyMgV2h5IGl0IGlzIGEgY2hhcm1pbmcgdXJiYW4gbGVnZW5kIHRoYXQgcmVjdXJzaW9uIGlzIGEgcmF0aGVyIHN1YnRsZSBwcm9ncmFtbWluZyB0ZWNobmlxdWU/CgpSZWN1cnNpb24gaXMgYSB2ZXJ5IGltcG9ydGFudCBpZGVhLCBidXQgaXTigJlzIG5vdCBzbyBzdWJ0bGUsIGFuZCBpdCBpcyBtb3JlIHRoYW4gYSBwcm9ncmFtbWluZyB0ZWNobmlxdWUuCgojIyMgV2hhdCBraW5kIG9mIG1ldGhvZCBpcyByZWN1cnNpdmU/CgpJdCBpcyBhIGRlc2NyaXB0aXZlIG1ldGhvZC4KCiMjIyBXaGF0IGlzIGEgcmVjdXJzaXZlIGRlc2NyaXB0aW9uIG1hZGUgb2Y/CgpJbiBnZW5lcmFsLCBhIHJlY3Vyc2l2ZSBkZWZpbml0aW9uIGlzIG1hZGUgdXAgb2YgdHdvIHBhcnRzLiBUaGVyZSBpcyBhdCBsZWFzdCBvbmUgYmFzZSBjYXNlIHRoYXQgZGlyZWN0bHkgc3BlY2lmaWVzIHRoZSByZXN1bHQgZm9yIGEgc3BlY2lhbCBjYXNlIChjYXNlIDEgaW4gdGhlIGV4YW1wbGUgYWJvdmUpLCBhbmQgdGhlcmUgaXMgYXQgbGVhc3Qgb25lIHJlY3Vyc2l2ZSAoaW5kdWN0aXZlKSBjYXNlIChjYXNlcyAyIGFuZCAzIGluIHRoZSBleGFtcGxlIGFib3ZlKSB0aGF0IGRlZmluZXMgdGhlIGFuc3dlciBpbiB0ZXJtcyBvZiB0aGUgYW5zd2VyIHRvIHRoZSBxdWVzdGlvbiBvbiBzb21lIG90aGVyIGlucHV0LCB0eXBpY2FsbHkgYSBzaW1wbGVyIHZlcnNpb24gb2YgdGhlIHNhbWUgcHJvYmxlbS4KCiMjIyBXaHkgd2Ugc2hvdWxkIGJlIGV4cGxpY2l0IHdoZW4gc3BlYWtpbmcgIm5hdHVyZSBudW1iZXIiPwoKVGhlIGV4YWN0IGRlZmluaXRpb24gb2Yg4oCcbmF0dXJhbCBudW1iZXLigJ0gaXMgc3ViamVjdCB0byBkZWJhdGUuIFNvbWUgZGVmaW5lIGl0IGFzIHRoZSBwb3NpdGl2ZSBpbnRlZ2VycyBhbmQgb3RoZXJzIGFzIHRoZSBub25uZWdhdGl2ZSBpbnRlZ2Vycy4gVGhhdOKAmXMgd2h5IHdlIHdlcmUgZXhwbGljaXQgYWJvdXQgdGhlIHBvc3NpYmxlIHZhbHVlcyBvZiBuIGluIHRoZSBkb2NzdHJpbmdzIGluCgpgYGBweXRob24KIiIiQXNzdW1lcyBuIGFuIGludCA+IDAKICAgUmV0dXJucyBuISIiIgpgYGAKCiMjIyBXaGF0IGFyZSB0aGUgaXRlcmF0aXZlIGFuZCByZWN1cnNpdmUgaW1wbGVtZW50YXRpb24gb2YgZmFjdG9yaWFsPwoKVGhlIGNsYXNzaWMgaW5kdWN0aXZlIGRlZmluaXRpb24gaXMKJCQKXGJlZ2lue2FycmF5fXtjfTEgIT0xIFxcIChuKzEpICE9KG4rMSkgKiBuICFcZW5ke2FycmF5fQokJApIZXJlIGlzIHRoZSBpdGVyYXRpdmUgaW1wbGVtZW50YXRpb24gb2YgZmFjdG9yaWFsLgoKYGBge3B5dGhvbn0KZGVmIGZhY3RJKG4pOgogICAgIiIiIEFzc3VtZXMgbiBhbiBpbnQgPiAwCiAgICAgICAgUmV0dXJucyBuISIiIiAKICAgIHJlc3VsdCA9IDEKICAgIHdoaWxlIG4gPiAxOgogICAgICAgIHJlc3VsdCA9IHJlc3VsdCAqIG4gCiAgICAgICAgbiAtPSAxCiAgICByZXR1cm4gcmVzdWx0CmBgYAoKSGVyZSBpcyB0aGUgcmVjdXJzaXZlIGltcGxlbWVudGF0aW9uIG9mIGZhY3RvcmlhbC4KCmBgYHtweXRob259CmRlZiBmYWN0UihuKToKICAgICIiIiBBc3N1bWVzIG4gYW4gaW50ID4gMAogICAgICAgIFJldHVybnMgbiEiIiIgCiAgICBpZiBuID09IDE6CiAgICAgICAgcmV0dXJuIG4KICAgIGVsc2U6CiAgICAgICAgcmV0dXJuIG4gKiBmYWN0UiAobiAtIDEpCmBgYAoKVGhlIHNlY29uZCBpcyBhIG1vcmUgb2J2aW91cyB0cmFuc2xhdGlvbiBvZiB0aGUgb3JpZ2luYWwgcmVjdXJzaXZlIGRlZmluaXRpb24uCgojIyMgSG93IHRvIGRlc2NyaWJlIHRoZSBGaWJvbmFjY2kgc2VxdWVuY2Ugb2YgcmFiYml0cz8KClN1cHBvc2UgYSBuZXdseSBib3JuIHBhaXIgb2YgcmFiYml0cywgb25lIG1hbGUgYW5kIG9uZSBmZW1hbGUsIGFyZSBwdXQgaW4gYSBwZW4gKG9yIHdvcnNlLCByZWxlYXNlZCBpbiB0aGUgd2lsZCkuIFN1cHBvc2UgZnVydGhlciB0aGF0IHRoZSByYWJiaXRzIGFyZSBhYmxlIHRvIG1hdGUgYXQgdGhlIGFnZSBvZiBvbmUgbW9udGggKHdoaWNoLCBhc3RvbmlzaGluZ2x5LCBzb21lIGJyZWVkcyBjYW4pIGFuZCBoYXZlIGEgb25lLW1vbnRoIGdlc3RhdGlvbiBwZXJpb2QgKHdoaWNoLCBhc3RvbmlzaGluZ2x5LCBzb21lIGJyZWVkcyBkbykuIEZpbmFsbHksIHN1cHBvc2UgdGhhdCB0aGVzZSBteXRoaWNhbCByYWJiaXRzIG5ldmVyIGRpZSwgYW5kIHRoYXQgdGhlIGZlbWFsZSBhbHdheXMgcHJvZHVjZXMgb25lIG5ldyBwYWlyIChvbmUgbWFsZSwgb25lIGZlbWFsZSkgZXZlcnkgbW9udGggZnJvbSBpdHMgc2Vjb25kIG1vbnRoIG9uLiBIb3cgbWFueSBmZW1hbGUgcmFiYml0cyB3aWxsIHRoZXJlIGJlIGF0IHRoZSBlbmQgb2Ygc2l4IG1vbnRocz8KCk9uIHRoZSBsYXN0IGRheSBvZiB0aGUgZmlyc3QgbW9udGggKGNhbGwgaXQgbW9udGggMCksIHRoZXJlIHdpbGwgYmUgb25lIGZlbWFsZSAocmVhZHkgdG8gY29uY2VpdmUgb24gdGhlIGZpcnN0IGRheSBvZiB0aGUgbmV4dCBtb250aCkuIE9uIHRoZSBsYXN0IGRheSBvZiB0aGUgc2Vjb25kIG1vbnRoLCB0aGVyZSB3aWxsIHN0aWxsIGJlIG9ubHkgb25lIGZlbWFsZSAoc2luY2Ugc2hlIHdpbGwgbm90IGdpdmUgYmlydGggdW50aWwgdGhlIGZpcnN0IGRheSBvZiB0aGUgbmV4dCBtb250aCkuIE9uIHRoZSBsYXN0IGRheSBvZiB0aGUgbmV4dCBtb250aCwgdGhlcmUgd2lsbCBiZSB0d28gZmVtYWxlcyAob25lIHByZWduYW50IGFuZCBvbmUgbm90KS4gT24gdGhlIGxhc3QgZGF5IG9mIHRoZSBuZXh0IG1vbnRoLCB0aGVyZSB3aWxsIGJlIHRocmVlIGZlbWFsZXMgKHR3byBwcmVnbmFudCBhbmQgb25lIG5vdCkuIEFuZCBzbyBvbi4gTGV04oCZcyBsb29rIGF0IHRoaXMgcHJvZ3Jlc3Npb24gaW4gdGFidWxhciBmb3JtLCBGaWd1cmUgNC42LgoKfCBNb250aCB8IEZlbWFsZXMgfAp8IDotLS06IHwgLS0tLS0tOiB8CnwgICAwICAgfCAgICAgICAxIHwKfCAgIDEgICB8ICAgICAgIDEgfAp8ICAgMiAgIHwgICAgICAgMiB8CnwgICAzICAgfCAgICAgICAzIHwKfCAgIDQgICB8ICAgICAgIDUgfAp8ICAgNSAgIHwgICAgICAgOCB8CnwgICA2ICAgfCAgICAgIDEzIHwKCioqRmlndXJlIDQuNiBHcm93dGggaW4gcG9wdWxhdGlvbiBvZiBmZW1hbGUgcmFiYml0cyoqCgpOb3RpY2UgdGhhdCBmb3IgbW9udGggbiA+IDEsIGZlbWFsZXMobikgPSBmZW1hbGVzKG4tMSkgKyBmZW1hbGVzKG4tMikuIFRoaXMgaXMgbm90IGFuIGFjY2lkZW50LiBFYWNoIGZlbWFsZSB0aGF0IHdhcyBhbGl2ZSBpbiBtb250aCBuLTEgd2lsbCBzdGlsbCBiZSBhbGl2ZSBpbiBtb250aCBuLiBJbiBhZGRpdGlvbiwgZWFjaCBmZW1hbGUgdGhhdCB3YXMgYWxpdmUgaW4gbW9udGggbi0yIHdpbGwgcHJvZHVjZSBvbmUgbmV3IGZlbWFsZSBpbiBtb250aCBuLiBUaGUgbmV3IGZlbWFsZXMgY2FuIGJlIGFkZGVkIHRvIHRoZSBmZW1hbGVzIGFsaXZlIGluIG1vbnRoIG4tMSB0byBnZXQgdGhlIG51bWJlciBvZiBmZW1hbGVzIGluIG1vbnRoIG4uCgpUaGUgZ3Jvd3RoIGluIHBvcHVsYXRpb24gaXMgZGVzY3JpYmVkIG5hdHVyYWxseSBieSB0aGUgcmVjdXJyZW5jZS4KCmBgYHB5dGhvbgpmZW1hbGVzKDApID0gMQpmZW1hbGVzKDEpID0gMQpmZW1hbGVzKG4gKyAyKSA9IGZlbWFsZXMobisxKSArIGZlbWFsZXMobikKYGBgCgpIZXJlIGlzIGFuIG9idmlvdXNseSBjb3JyZWN0LCBidXQgdGVycmlibHkgaW5lZmZpY2llbnQgaW1wbGVtZW50YXRpb24gb2YgdGhlIEZpYm9uYWNjaSBmdW5jdGlvbi4KCmBgYHtweXRob259CmRlZiBmaWIobik6CiAgICAiIiIgQXNzdWVzIG4gaW50ID49IDAKICAgICAgICBSZXR1cm5zIEZpYm9uYWNjaSBvZiBuICIiIgogICAgaWYgbiA9PSAwIG9yIG4gPT0gMToKICAgICAgICByZXR1cm4gMQogICAgZWxzZToKICAgIAkJcmV0dXJuIGZpYihuLTEpICsgZmliKG4tMikKCmRlZiB0ZXN0RmliKG4pOgogIAlmb3IgaSBpbiByYW5nZShuKzEpOgogICAgCQlwcmludCgnZmliIG9mJywgaSwgJz0nLCBmaWIoaSkpCgp0ZXN0RmliKDgpCmBgYAoKIyMjIEhvdyBkbyB5b3UgZmVlbCBpbiB0aGUgY29kaW5nIHByb2Nlc3Mgb2YgdGhlIEZpYm9uYWNjaSBmdW5jdGlvbj8KCldyaXRpbmcgdGhlIGNvZGUgaXMgdGhlIGVhc3kgcGFydCBvZiBzb2x2aW5nIHRoaXMgcHJvYmxlbS4gT25jZSB3ZSB3ZW50IGZyb20gdGhlIHZhZ3VlIHN0YXRlbWVudCBvZiBhIHByb2JsZW0gYWJvdXQgYnVubmllcyB0byBhIHNldCBvZiByZWN1cnNpdmUgZXF1YXRpb25zLCB0aGUgY29kZSBhbG1vc3Qgd3JvdGUgaXRzZWxmLiBGaW5kaW5nIHNvbWUga2luZCBvZiBhYnN0cmFjdCB3YXkgdG8gZXhwcmVzcyBhIHNvbHV0aW9uIHRvIHRoZSBwcm9ibGVtIGF0IGhhbmQgaXMgdmVyeSBvZnRlbiB0aGUgaGFyZGVzdCBzdGVwIGluIGJ1aWxkaW5nIGEgdXNlZnVsIHByb2dyYW0uCgojIyMgSG93IHRvIGNvbnN0cnVjdCBjb2RlIHRvIGltcGxlbWVudCBwYWxpbmRyb21lIHRlc3Rpbmcgd2l0aCBwcmludGVkIG1lc3NhZ2UgdG8gdmlzdWFsaXplIHRoZSBwcm9jZXNzaW5nIHN0ZXBzPwoKW05vdGUgd2hlcmUgdGhlIHByaW50ZWQgbWVzc2FnZXMgYXJlIHB1dC5dCgpgYGB7cHl0aG9ufQpkZWYgaXNQYWxpbmRyb21lKHMpOiAKICAgICIiIiBBc3N1bWVzIHMgaXMgYSBzdHIKICAgICAgICBSZXR1cm5zIFRydWUgaWYgcyBpcyBhIHBhbGluZHJvbWU7IEZhbHNlIG90aGVyd2lzZS4gCiAgICAgICAgUHVuY3R1YXRpb24gbWFya3MsIGJsYW5rcywgYW5kIGNhcGl0YWxpemF0aW9uIGFyZSBpZ25vcmVkLiIiIgogICAgICAgIAogICAgZGVmIHRvQ2hhcnMocyk6IAogICAgICAgIHMgPSBzLmxvd2VyKCkgCiAgICAgICAgbGV0dGVycyA9ICcnIAogICAgICAgIGZvciBjIGluIHM6CiAgICAgICAgICAgIGlmIGMgaW4gJ2FiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6JzogCiAgICAgICAgICAgICAgICBsZXR0ZXJzID0gbGV0dGVycyArIGMKICAgICAgICByZXR1cm4gbGV0dGVycwogICAgICAgIAogICAgZGVmIGlzUGFsKHMpOgogICAgICAgIHByaW50KCcgaXNQYWwgY2FsbGVkIHdpdGgnLCBzKSAKICAgICAgICBpZiBsZW4ocykgPD0gMToKICAgICAgICAgICAgcHJpbnQoJyBBYm91dCB0byByZXR1cm4gVHJ1ZSBmcm9tIGJhc2UgY2FzZScpCiAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgICAgZWxzZToKICAgICAgICAgICAgYW5zd2VyID0gc1swXSA9PSBzWy0xXSBhbmQgaXNQYWwoc1sxOi0xXSkgCiAgICAgICAgICAgIHByaW50KCcgQWJvdXQgdG8gcmV0dXJuJywgYW5zd2VyLCAnZm9yJywgcykgCiAgICAgICAgICAgIHJldHVybiBhbnN3ZXIKICAgICAgICAgICAgCiAgICByZXR1cm4gaXNQYWwodG9DaGFycyhzKSkKICAgICAgCmRlZiB0ZXN0SXNQYWxpbmRyb21lKCk6IAogICAgcHJpbnQoJ1RyeSBkb2dHb2QnKSAKICAgIHByaW50KGlzUGFsaW5kcm9tZSgnZG9nR29kJykpIAogICAgcHJpbnQoJ1RyeSBkb0dvb2QnKSAKICAgIHByaW50KGlzUGFsaW5kcm9tZSgnZG9Hb29kJykpCiAgICAKdGVzdElzUGFsaW5kcm9tZSgpCmBgYAoKIyMjIFdoYXQgaXMgc2hvcnQtY2lyY3VpdCBldmFsdWF0aW9uPwoKVGhlIGNvbmp1bmN0aW9uW15jb25qdW5jdF0gaW4gdGhlIGBlbHNlYCBjbGF1c2UgaXMgZXZhbHVhdGVkIGZyb20gbGVmdCB0byByaWdodC4gVGhlIGNvZGUgZmlyc3QgY2hlY2tzIHdoZXRoZXIgdGhlIGZpcnN0IGFuZCBsYXN0IGNoYXJhY3RlcnMgYXJlIHRoZSBzYW1lLCBhbmQgaWYgdGhleSBhcmUgZ29lcyBvbiB0byBjaGVjayB3aGV0aGVyIHRoZSBzdHJpbmcgbWludXMgdGhvc2UgdHdvIGNoYXJhY3RlcnMgaXMgYSBwYWxpbmRyb21lLiBUaGF0IHRoZSBzZWNvbmQgY29uanVuY3QgaXMgbm90IGV2YWx1YXRlZCB1bmxlc3MgdGhlIGZpcnN0IGNvbmp1bmN0IGV2YWx1YXRlcyB0byBgVHJ1ZWAgaXMgc2VtYW50aWNhbGx5IGlycmVsZXZhbnQgaW4gdGhpcyBleGFtcGxlLiBIb3dldmVyLCBsYXRlciBpbiB0aGUgYm9vayB3ZSB3aWxsIHNlZSBleGFtcGxlcyB3aGVyZSB0aGlzIGtpbmQgb2YgKipzaG9ydC1jaXJjdWl0IGV2YWx1YXRpb24qKiBvZiBCb29sZWFuIGV4cHJlc3Npb25zIGlzIHNlbWFudGljYWxseSByZWxldmFudC4KClteY29uanVuY3RdOiBXaGVuIHR3byBCb29sZWFuLXZhbHVlZCBleHByZXNzaW9ucyBhcmUgY29ubmVjdGVkIGJ5IOKAnGFuZCzigJ0gZWFjaCBleHByZXNzaW9uIGlzIGNhbGxlZCBhIGNvbmp1bmN0LiBJZiB0aGV5IGFyZSBjb25uZWN0ZWQgYnkg4oCcb3Is4oCdIHRoZXkgYXJlIGNhbGxlZCBkaXNqdW5jdHMuCgojIyMgV2hhdCBpcyB0aGUgcHJvYmxlbS1zb2x2aW5nIHByaW5jaXBsZSBrbm93biBhcyBkaXZpZGUtYW5kLWNvbnF1ZXI/CgpUaGlzIHByaW5jaXBsZSBpcyByZWxhdGVkIHRvIGJ1dCBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSBkaXZpZGUtYW5kLWNvbnF1ZXIgYWxnb3JpdGhtcy4KClRoZSBwcm9ibGVtLXNvbHZpbmcgcHJpbmNpcGxlIGlzIHRvIGNvbnF1ZXIgYSBoYXJkIHByb2JsZW0gYnkgYnJlYWtpbmcgaXQgaW50byBhIHNldCBvZiBzdWJwcm9ibGVtcyB3aXRoIHRoZSBwcm9wZXJ0aWVzIHRoYXQKCi0gdGhlIHN1YnByb2JsZW1zIGFyZSBlYXNpZXIgdG8gc29sdmUgdGhhbiB0aGUgb3JpZ2luYWwgcHJvYmxlbSwgYW5kCi0gc29sdXRpb25zIG9mIHRoZSBzdWJwcm9ibGVtcyBjYW4gYmUgY29tYmluZWQgdG8gc29sdmUgdGhlIG9yaWdpbmFsIHByb2JsZW0uCgpEaXZpZGUtYW5kLWNvbnF1ZXIgaXMgYSB2ZXJ5IG9sZCBpZGVhLiBKdWxpdXMgQ2Flc2FyIHByYWN0aWNlZCB3aGF0IHRoZSBSb21hbnMgcmVmZXJyZWQgdG8gYXMgKmRpdmlkZSBldCBpbXBlcmEqIChkaXZpZGUgYW5kIHJ1bGUpLiBUaGUgQnJpdGlzaCBwcmFjdGljZWQgaXQgYnJpbGxpYW50bHkgdG8gY29udHJvbCB0aGUgSW5kaWFuIHN1YmNvbnRpbmVudC4gQmVuamFtaW4gRnJhbmtsaW4gd2FzIHdlbGwgYXdhcmUgb2YgdGhlIEJyaXRpc2ggZXhwZXJ0aXNlIGluIHVzaW5nIHRoaXMgdGVjaG5pcXVlLCBwcm9tcHRpbmcgaGltIHRvIHNheSBhdCB0aGUgc2lnbmluZyBvZiB0aGUgVS5TLiBEZWNsYXJhdGlvbiBvZiBJbmRlcGVuZGVuY2UsIOKAnFdlIG11c3QgYWxsIGhhbmcgdG9nZXRoZXIsIG9yIGFzc3VyZWRseVteYXNzdXJlZGx5XSB3ZSBzaGFsbCBhbGwgaGFuZyBzZXBhcmF0ZWx5LuKAnQoKW15hc3N1cmVkbHldOiAqW2FzIHNlbnRlbmNlIGFkdmVyYl0qIHVzZWQgdG8gZXhwcmVzcyB0aGUgc3BlYWtlcidzIGNlcnRhaW50eSB0aGF0IHNvbWV0aGluZyBpcyB0cnVlOiAqcG90dGVkIHJvc2VzIHdpbGwgbW9zdCBhc3N1cmVkbHkgbm90IHN1cnZpdmUgd2ludGVyIHdpdGhvdXQgcHJvdGVjdGlvbiouCgojIyA0LjQgR2xvYmFsIFZhcmlhYmxlcwoKIyMjIFdoeSB0aGUgc2xvcHB5IHVzZSBvZiBnbG9iYWwgdmFyaWFibGUgY2FuIGRlc3Ryb3kgcHJvZ3JhbXMgcmVhZGFiaWxpdHk/CgpJdCBpcyB3aXRoIHNvbWUgdHJlcGlkYXRpb25bXnRyZXBpZGF0aW9uXSB0aGF0IHdlIGludHJvZHVjZSB0aGUgdG9waWMgb2YgZ2xvYmFsIHZhcmlhYmxlcy4gU2luY2UgdGhlIDE5NzBzIGNhcmQtY2FycnlpbmdbXmNhcmQtY2FycnlpbmddIGNvbXB1dGVyIHNjaWVudGlzdHMgaGF2ZSBpbnZlaWdoZWRbXmludmVpZ2hdIGFnYWluc3QgdGhlbS4gVGhlIGluZGlzY3JpbWluYXRlW15pbmRpc2NyaW1pbmF0ZV0gdXNlIG9mIGdsb2JhbCB2YXJpYWJsZXMgY2FuIGxlYWQgdG8gbG90cyBvZiBwcm9ibGVtcy4gVGhlIGtleSB0byBtYWtpbmcgcHJvZ3JhbXMgcmVhZGFibGUgaXMgbG9jYWxpdHlbXmxvY2FsaXR5XS4gT25lIHJlYWRzIGEgcHJvZ3JhbSBhIHBpZWNlIGF0IGEgdGltZSwgYW5kIHRoZSBsZXNzIGNvbnRleHRbXmNvbnRleHRdIG5lZWRlZCB0byB1bmRlcnN0YW5kIGVhY2ggcGllY2UsIHRoZSBiZXR0ZXIuIFNpbmNlIGdsb2JhbCB2YXJpYWJsZXMgY2FuIGJlIG1vZGlmaWVkIG9yIHJlYWQgaW4gYSB3aWRlIHZhcmlldHkgb2YgcGxhY2VzLCB0aGUgc2xvcHB5IHVzZSBvZiB0aGVtIGNhbiBkZXN0cm95IGxvY2FsaXR5LiBOZXZlcnRoZWxlc3MsIHRoZXJlIGFyZSB0aW1lcyB3aGVuIHRoZXkgYXJlIGp1c3Qgd2hhdCBpcyBuZWVkZWQuCgpbXnRyZXBpZGF0aW9uXTogKip0cmVwaWRhdGlvbioqOiBBbiBpbnZvbHVudGFyeSB0cmVtYmxpbmcsIHNvbWV0aW1lcyBhbiBlZmZlY3Qgb2YgcGFyYWx5c2lzLCBidXQgdXN1YWxseSBjYXVzZWQgYnkgdGVycm9yIG9yIGZlYXI7IHF1YWtpbmc7IHF1aXZlcmluZy4gSGVuY2UsIGEgc3RhdGUgb2YgdGVycm9yIG9yIGFsYXJtOyBmZWFyOyBjb25mdXNpb247IGZyaWdodDsgYXMsICp0aGUgbWVuIHdlcmUgaW4gZ3JlYXQgdHJlcGlkYXRpb24qLgpbXmNhcmQtY2FycnlpbmddOiAqKmNhcmQtY2FycnlpbmcqKjogKm9mdGVuIGh1bW9yb3VzKiBjb25maXJtZWQgaW4gb3IgZGVkaWNhdGVkIHRvIGEgc3BlY2lmaWVkIHB1cnN1aXQgb3Igb3V0bG9vazogKmEgY2FyZC1jYXJyeWluZyBwZXNzaW1pc3QqLgpbXmludmVpZ2hdOiAgKippbnZlaWdoKiogVG8gZGVjbGFpbSBvciByYWlsIChhZ2FpbnN0IHNvbWUgcGVyc29uIG9yIHRoaW5nKTsgdG8gdXR0ZXIgY2Vuc29yaW91cyBhbmQgYml0dGVyIGxhbmd1YWdlOyB0byBhdHRhY2sgd2l0aCBoYXJzaCBjcml0aWNpc20gb3IgcmVwcm9hY2gsIGVpdGhlciBzcG9rZW4gb3Igd3JpdHRlbjsgdG8gdXNlIGludmVjdGl2ZXM7IOKAkyB3aXRoIGFnYWluc3Q7IGFzLCB0byAqaW52ZWlnaCogYWdhaW5zdCBjaGFyYWN0ZXIsIGNvbmR1Y3QsIG1hbm5lcnMsIGN1c3RvbXMsIG1vcmFscywgYSBsYXcsIGFuIGFidXNlLgpbXmluZGlzY3JpbWluYXRlXTogSW7LimRpcy1jcmlt4oCyaS1uYXRlLCBhLiBOb3QgZGlzY3JpbWluYXRlOyB3YW50aW5nIGRpc2NyaW1pbmF0aW9uOyB1bmRpc3Rpbmd1aXNoaW5nOyBub3QgbWFraW5nIGFueSBkaXN0aW5jdGlvbjsgY29uZnVzZWQ7IHByb21pc2N1b3VzLiDigJxCbGluZCBvciAqaW5kaXNjcmltaW5hdGUqIGZvcmdpdmVuZXNzLuKAnSAKW15sb2NhbGl0eV06ICoqbG9jYWxpdHkqKjpMaW1pdGF0aW9uIHRvIGEgY291bnR5LCBkaXN0cmljdCwgb3IgcGxhY2U7IGFzLCAqbG9jYWxpdHkqIG9mIHRyaWFsLgpbXmNvbnRleHRdOiBUaGUgcGFydCBvciBwYXJ0cyBvZiBzb21ldGhpbmcgd3JpdHRlbiBvciBwcmludGVkLCBhcyBvZiBTY3JpcHR1cmUsIHdoaWNoIHByZWNlZGUgb3IgZm9sbG93IGEgdGV4dCBvciBxdW90ZWQgc2VudGVuY2UsIG9yIGFyZSBzbyBpbnRpbWF0ZWx5IGFzc29jaWF0ZWQgd2l0aCBpdCBhcyB0byB0aHJvdyBsaWdodCB1cG9uIGl0cyBtZWFuaW5nLiAqQWNjb3JkaW5nIHRvIGFsbCB0aGUgbGlnaHQgdGhhdCB0aGUgY29udGV4dHMgYWZmb3JkLiAtIFNoYXJwKi4KCiMjIDQuNSBNb2R1bGVzCgojIyMgV2hhdCBpcyBQeXRob24gbW9kdWxlPwoKUHl0aG9uIG1vZHVsZXMgYWxsb3cgdXMgdG8gZWFzaWx5IGNvbnN0cnVjdCBhIHByb2dyYW0gZnJvbSBjb2RlIGluIG11bHRpcGxlIGZpbGVzLiBBIG1vZHVsZSBpcyBhIGAucHlgIGZpbGUgY29udGFpbmluZyBQeXRob24gZGVmaW5pdGlvbnMgYW5kIHN0YXRlbWVudHMuCgojIyMgSG93IHRvIHVzZSBuYW1lcyBpbiBNb2R1bGU/CgpNb2R1bGVzIGFyZSB0eXBpY2FsbHkgc3RvcmVkIGluIGluZGl2aWR1YWwgZmlsZXMuIEVhY2ggbW9kdWxlIGhhcyBpdHMgb3duIHByaXZhdGUgc3ltYm9sIHRhYmxlLiAgRXhlY3V0aW5nIGBpbXBvcnQgTWAgY3JlYXRlcyBhIGJpbmRpbmcgZm9yIG1vZHVsZSBgTSBgaW4gdGhlIHNjb3BlIGluIHdoaWNoIHRoZSBgaW1wb3J0YCBhcHBlYXJzLiBUaGVyZWZvcmUsIGluIHRoZSBpbXBvcnRpbmcgY29udGV4dCB3ZSB1c2UgZG90IG5vdGF0aW9uIHRvIGluZGljYXRlIHRoYXQgd2UgYXJlIHJlZmVycmluZyB0byBhIG5hbWUgZGVmaW5lZCBpbiB0aGUgaW1wb3J0ZWQgbW9kdWxlLltecmVsYXRpb25fd2l0aF9tZXRob2RfaW52b2NhdGlvbl0KCltecmVsYXRpb25fd2l0aF9tZXRob2RfaW52b2NhdGlvbl06IFN1cGVyZmljaWFsbHksIHRoaXMgbWF5IHNlZW0gdW5yZWxhdGVkIHRvIHRoZSB1c2Ugb2YgZG90IG5vdGF0aW9uIGluIG1ldGhvZCBpbnZvY2F0aW9uLiBIb3dldmVyLCBhcyB3ZSB3aWxsIHNlZSBpbiBDaGFwdGVyIDgsIHRoZXJlIGlzIGEgZGVlcCBjb25uZWN0aW9uLgoKIyMjIFdoeSBzb21lIFB5dGhvbiBwcm9ncmFtbWVycyBmcm93biB1cG9uIHVzaW5nIHRoZSBgZnJvbSBtb2RlbGUgaW1wb3J0ICpgIGZvcm0gb2YgaW1wb3J0PwoKQmVjYXVzZSBpdCBhbGxvd3MgdGhlIGltcG9ydGluZyBwcm9ncmFtIHRvIG9taXQgdGhlIG1vZHVsZSBuYW1lIHdoZW4gYWNjZXNzaW5nIG5hbWVzIGRlZmluZWQgaW5zaWRlIHRoZSBpbXBvcnRlZCBtb2R1bGUuIEV4ZWN1dGluZyB0aGUgc3RhdGVtZW50IGBmcm9tIE0gaW1wb3J0ICpgIGNyZWF0ZXMgYmluZGluZ3MgaW4gdGhlIGN1cnJlbnQgc2NvcGUgdG8gYWxsIG9iamVjdHMgZGVmaW5lZCB3aXRoaW4gYE1gLCBidXQgbm90IHRvIGBNYCBpdHNlbGYuIFRoZXkgYmVsaWV2ZSB0aGF0IGl0IG1ha2VzIGNvZGUgbW9yZSBkaWZmaWN1bHQgdG8gcmVhZC4KCiMjIyBXaGVuIGlzIHRoZSBtb2R1bGUgaW1wb3J0ZWQ/CgpBcyB3ZSBoYXZlIHNlZW4sIGEgbW9kdWxlIGNhbiBjb250YWluIGV4ZWN1dGFibGUgc3RhdGVtZW50cyBhcyB3ZWxsIGFzIGZ1bmN0aW9uIGRlZmluaXRpb25zLiBUeXBpY2FsbHksIHRoZXNlIHN0YXRlbWVudHMgYXJlIHVzZWQgdG8gaW5pdGlhbGl6ZSB0aGUgbW9kdWxlLiBGb3IgdGhpcyByZWFzb24sIHRoZSBzdGF0ZW1lbnRzIGluIGEgbW9kdWxlIGFyZSBleGVjdXRlZCBvbmx5IHRoZSBmaXJzdCB0aW1lIGEgbW9kdWxlIGlzIGltcG9ydGVkIGludG8gYSBwcm9ncmFtLiBNb3Jlb3ZlciwgYSBtb2R1bGUgaXMgaW1wb3J0ZWQgb25seSBvbmNlIHBlciBpbnRlcnByZXRlciBzZXNzaW9uLiBJZiB5b3Ugc3RhcnQgdXAgYSBzaGVsbCwgaW1wb3J0IGEgbW9kdWxlLCBhbmQgdGhlbiBjaGFuZ2UgdGhlIGNvbnRlbnRzIG9mIHRoYXQgbW9kdWxlLCB0aGUgaW50ZXJwcmV0ZXIgd2lsbCBzdGlsbCBiZSB1c2luZyB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgbW9kdWxlLiBUaGlzIGNhbiBsZWFkIHRvIHB1enpsaW5nIGJlaGF2aW9yIHdoZW4gZGVidWdnaW5nLgoKIyMgNC42IEZpbGVzCgojIyMgSG93IGRvZXMgUHl0aG9uIGFjaGlldmVzIG9wZXJhdGlvbi1zeXN0ZW0gaW5kZXBlbmRlbmNlPwoKQWNjZXNzaW5nIGZpbGVzIHRocm91Z2ggc29tZXRoaW5nIGNhbGxlZCBhIGZpbGUgaGFuZGxlLgoKIyMjIFdoeSBpcyBpdCBpbXBvcnRhbnQgdG8gcmVtZW1iZXIgdG8gY2xvc2UgdGhlIGZpbGUgd2hlbiB0aGUgcHJvZ3JhbSBpcyBmaW5pc2hlZCB1c2luZyBpdD8KClRoZXJlIGlzIGEgcmlzayB0aGF0IHNvbWUgb3IgYWxsIG9mIHRoZSB3cml0ZXMgbWF5IG5vdCBiZSBzYXZlZC4KCiMjIyBTb21lIG9mIHRoZSBjb21tb24gb3BlcmF0aW9ucyBvbiBmaWxlcy4KCiAqKm9wZW4oZm4sICd3JykqKiBmbiBpcyBhIHN0cmluZyByZXByZXNlbnRpbmcgYSBmaWxlIG5hbWUuIENyZWF0ZXMgYSBmaWxlIGZvciB3cml0aW5nIGFuZCByZXR1cm5zIGEgZmlsZSBoYW5kbGUuCgoqKm9wZW4oZm4sICdyJykqKiBmbiBpcyBhIHN0cmluZyByZXByZXNlbnRpbmcgYSBmaWxlIG5hbWUuIE9wZW5zIGFuIGV4aXN0aW5nIGZpbGUgZm9yIHJlYWRpbmcgYW5kIHJldHVybnMgYSBmaWxlIGhhbmRsZS4KCioqb3BlbihmbiwgJ2EnKSoqIGZuIGlzIGEgc3RyaW5nIHJlcHJlc2VudGluZyBhIGZpbGUgbmFtZS4gT3BlbnMgYW4gZXhpc3RpbmcgZmlsZSBmb3IgYXBwZW5kaW5nIGFuZCByZXR1cm5zIGEgZmlsZSBoYW5kbGUuCgoqKmZoLnJlYWQoKSoqIHJldHVybnMgYSBzdHJpbmcgY29udGFpbmluZyB0aGUgY29udGVudHMgb2YgdGhlIGZpbGUgYXNzb2NpYXRlZCB3aXRoIHRoZSBmaWxlIGhhbmRsZSBmaC4KCioqZmgucmVhZGxpbmUoKSoqIHJldHVybnMgdGhlIG5leHQgbGluZSBpbiB0aGUgZmlsZSBhc3NvY2lhdGVkIHdpdGggdGhlIGZpbGUgaGFuZGxlIGZoLgoKKipmaC5yZWFkbGluZXMoKSoqIHJldHVybnMgYSBsaXN0IGVhY2ggZWxlbWVudCBvZiB3aGljaCBpcyBvbmUgbGluZSBvZiB0aGUgZmlsZSBhc3NvLSBjaWF0ZWQgd2l0aCB0aGUgZmlsZSBoYW5kbGUgZmguCgoqKmZoLndyaXRlKHMpKiogd3JpdGVzIHRoZSBzdHJpbmcgcyB0byB0aGUgZW5kIG9mIHRoZSBmaWxlIGFzc29jaWF0ZWQgd2l0aCB0aGUgZmlsZSBoYW5kbGUgZmguCgoqKmZoLndyaXRlTGluZXMoUykqKiBTIGlzIGEgc2VxdWVuY2Ugb2Ygc3RyaW5ncy4gV3JpdGVzIGVhY2ggZWxlbWVudCBvZiBTIGFzIGEgc2VwYS0gcmF0ZSBsaW5lIHRvIHRoZSBmaWxlIGFzc29jaWF0ZWQgd2l0aCB0aGUgZmlsZSBoYW5kbGUgZmguCgoqKmZoLmNsb3NlKCkqKiBjbG9zZXMgdGhlIGZpbGUgYXNzb2NpYXRlZCB3aXRoIHRoZSBmaWxlIGhhbmRsZSBmaC4=