1. Introduction to Programming in Python

save Python files with the .py extension to indicate they’re Python scripts.

Example: Creating Python Script

Save a file named hello.py:

print("hello, world")

Prints “hello, world” to the screen. The function print() is used to display text or other output in Python.

Run using to use the command line or terminal or bash. (run python code dirrectly in python console by typing python to get to python prompt then crtrl z to exit out and back to term)

python hello.py

Should output:

hello, world

2. Variables and User Input

A variable is a container to store data, such as numbers or text. Ask users for input to make your program more interactive.

Example: User Greeting

# Ask the user for their name
name = input("What's your name? ")

# Print a personalized greeting
print(f"Hello, {name}")

Here, input() is used to take user input. The user’s input is stored in a variable called name, and then it’s used to greet them using an f-string, which allows inserting variables directly into strings.

Improved Greeting with Input Sanitization

You can also improve your greeting by cleaning up any extra whitespace or capitalization issues:

# Ask the user for their name and remove extra spaces
name = input("What's your name? ").strip().title()

# Print a cleaned-up personalized greeting
print(f"Hello, {name}")

In this code:

  • strip() removes any leading or trailing whitespace from the user’s input.
  • title() capitalizes the first letter of each word.

3. Basic Math Operations

Python can be used as a simple calculator to add, subtract, multiply, or divide numbers. You can also ask users to input numbers to perform calculations.

Example: Simple Calculator

# Ask the user for two numbers
x = int(input("Enter the first number: "))
y = int(input("Enter the second number: "))

# Calculate and print the sum
sum = x + y
print(f"The sum of {x} and {y} is {sum}")

Here, the int() function is used to convert the user’s input into an integer so that mathematical operations can be performed. By default, input() gives a string, and converting it is necessary to treat it as a number.

Example: Multiple Operations

You can add more operations to the calculator:

# Ask the user for two numbers
x = int(input("Enter the first number: "))
y = int(input("Enter the second number: "))

# Perform different operations
print(f"The sum is: {x + y}")
print(f"The difference is: {x - y}")
print(f"The product is: {x * y}")
print(f"The quotient is: {x / y}")

Perform addition, subtraction, multiplication, and division ( / ) operator. ## 4. Combining Strings and Numbers

Display a result that combines both text and numbers. Use formatted strings.

Example: Outputting Numbers in a Sentence

x = int(input("Enter a number: "))
y = int(input("Enter another number: "))

# Calculate the product
product = x * y

# Print the result in a full sentence
print(f"The product of {x} and {y} is {product}.")

This code asks the user for two numbers, calculates their product, and prints the result.

5. Error Handling: Handling Invalid Input

Sometimes users enter invalid data. Improve our calculator to handle such cases.

Example: Using try-except to Handle Input Errors

try:
    x = int(input("Enter the first number: "))
    y = int(input("Enter the second number: "))
    print(f"The sum is: {x + y}")
except ValueError:
    print("Please enter a valid number.")

Use a try-except block to catch errors when the user enters something that isn’t a number. If they enter an invalid value, the program prints an error message.

  • Create variables to store user input using input().
  • The print() function is used to display information.
  • Functions like strip(), title(), and int() help clean up user input and convert data types.
  • Use basic math operators (+, -, *, /) to perform calculations.
  • Handle user errors gracefully using try-except.

Create a new file in the terminal, use the command touch. The touch command is commonly used to create an empty file or update the timestamp of an existing file.

Creating a File Using touch

In the terminal, type:

touch my_module.py

Creates an empty file named my_module.py in the current directory. (like nano/ ~.bashrc)

Python Basic Module Example

Next: Craete a simple Python module. A module is essentially a Python file containing reusable code, such as functions or classes, which can be imported into other scripts.

Make mod. called math_utils.py to add afew more functions to our calc.

It should 1. Define a Python module with multiple functions. 2. Make the functions more reusable and include slightly advanced concepts. 3. Import and use this module from another script.

Step 1: Create the Module (math_utils.py)

Run this in terminal:

touch math_utils.py

Step 2: Add Functions to the Module

Open math_utils.py and add functions to it. Use code editor, such as VS Code, sublime if available is IMO the best code editor. Save as .py - they run in gitbash - easier on system than VScode or VS when colmputing with simple python scripts.

Code to add:

# math_utils.py

def add(x, y):
    return x + y

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    if y == 0:
        return "Error: Division by zero is undefined."
    return x / y

def power(base, exponent):
    """Returns the base raised to the power of exponent."""
    return base ** exponent

def factorial(n):
    """Returns the factorial of a given number n."""
    if n < 0:
        return "Error: Factorial is not defined for negative numbers."
    elif n == 0 or n == 1:
        return 1
    else:
        result = 1
        for i in range(2, n + 1):
            result *= i
        return result

def gcd(a, b):
    """Returns the greatest common divisor of a and b."""
    while b:
        a, b = b, a % b
    return a

Explanation:

  • Basic Arithmetic Functions (add, subtract, multiply, divide): These functions perform basic operations.
  • Power Function (power): Raises a number to the power of another.
  • Factorial Function (factorial): Calculates the factorial of a non-negative integer.
  • GCD Function (gcd): Finds the greatest common divisor of two integers using the Euclidean algorithm.

Step 3: Use the Module in Another Script

Create a script named main.py that’ll use math_utils module. First, create the file:

touch main.py

Add to code:

# main.py

import math_utils

# Take user inputs for arithmetic operations
x = int(input("Enter the first number: "))
y = int(input("Enter the second number: "))

print(f"Sum: {math_utils.add(x, y)}")
print(f"Difference: {math_utils.subtract(x, y)}")
print(f"Product: {math_utils.multiply(x, y)}")
print(f"Quotient: {math_utils.divide(x, y)}")

# Take user inputs for more advanced functions
base = int(input("Enter the base number: "))
exponent = int(input("Enter the exponent: "))
print(f"{base} raised to the power of {exponent}: {math_utils.power(base, exponent)}")

n = int(input("Enter a number to find its factorial: "))
print(f"Factorial of {n}: {math_utils.factorial(n)}")

a = int(input("Enter the first number to find GCD: "))
b = int(input("Enter the second number to find GCD: "))
print(f"GCD of {a} and {b}: {math_utils.gcd(a, b)}")

Step 4: Run the Script

To run the script, use:

python main.py

Example Run

Typical interaction with main.py

Enter the first number: 5
Enter the second number: 10
Sum: 15
Difference: -5
Product: 50
Quotient: 0.5
Enter the base number: 2
Enter the exponent: 3
2 raised to the power of 3: 8
Enter a number to find its factorial: 5
Factorial of 5: 120
Enter the first number to find GCD: 54
Enter the second number to find GCD: 24
GCD of 54 and 24: 6

review

  1. Create Files: Use touch to create empty files such as math_utils.py and main.py.
  2. Define a Module: Add functions to math_utils.py to handle different mathematical tasks.
  3. Use the Module: Import math_utils in main.py to use the functions you defined.

Play with math_utils adding more functions like square root, prime checking, etc, play around with code, use python references. Practice using in different tools. Practice calling from different platforms. Memorize basics and keyboard shortcuts. The heavy lifting isn’t as heavy if you know the basics. They’re the safety net. Be safe. Then advance.

As with in the cutthroat kitchen - KNOW THE LAYOUT OF THE LAND. LEARN THE TOOLS. USE THE TOOLS. Coding skills irrelevant if you can’t efficiently get to a notebook, window, linux line etc. WSL, UBUNTU, CMD, GIT, Windows (and/or Mac). Learn commands, Memorize commands. Be able to quickly and efficiently navigate around a computer and the programs within it.


'''
The parentheses with nothing inside means that this function at the moment
is not going to take any inputs, no arguments there too.
The colon means, stay tuned for some indentation.
Everything that's indented beneath this line of code
is going to be part of this function.
'''

def hello(): 
    print("hello")


name = input("What's your name? ")
hello(name)
# "Hello.py"


# Ask for name
name = input ("What's your name? ")

# Remove whitespace from str
name = name.strip()

# Capitalize user's name
name = name.capitalize()


# Address user - fstring
print (f"Hello, {name}")


# pseudo code 
# or print ("hello,")  n/ print(name)

"""
outline code  
buildingblocks
what do i want to do
what do i want to accomplish
this is all part of pseudocode
input prompts string - text 
next return values and define values
"""

"""
run in terminal using : python hello.py
anything between triple double quotes is a comment 
you can also use single quote to comment
"""


# Say hello
print("hello, " + name)

# pass in more arguments
print("hello,", name)


# str = string
# override move to next line in print statement
# docs/python.org/3/library/functions.html#print 
print(name) 



"""
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
parameters vs arguments - what problem can take vs what youre tryiong to apply
= means assignment
== means equals as value
"""

# So
print("hello, ", end="")
print(name)

# look at difference
print("hello,", name, sep="???")

# using actual quotes - escaping out
print("hello, \"friend\"")


# Again for practice and muscle memory
you = input("What should I call you? ")

# Remove whitespace from str
you = you.strip()

# Capitalize user's name
you = you.capitalize()

# Title Based Cazpitalization
you = you.title()

# or
# name = name.title()


# Say hello to user
print(f"hello, {you}")

# Again
nickname = input("What is your nickname? ")
nickname = nickname.strip()
nickname = nickname.capitalize()
# Title Based Cazpitalization
nickname = nickname.title()

print(f"hello, {nickname}")




print("hello, \"friend\"")

#Condensed
#Ask for name
username = input("What is your username? ").strip().title()

# Say Whats up to user
print(f"What's shakin', {username}?")

# method is a funtiopn that's built in to type of value like these functions (f string etc)

# Adding name split
splitname = input ("What's your name? ").strip().title()
# Split users name into first, middle and last
first, middle, last,  = splitname.split(" ")
# Say what's up
print(f'Sup, {splitname}')

# now only address by first anme
print(f"/Sup, {first}")


# integer is int
'''
number without decimal
+ - * / % 
interactive mode
'''


'''
running within python interpreter
immediate translation/interactive code
print("....")
1+1
8/2
etc for interactive mode
'''






# create calculator.py

"Calculator.py"

# basic arithmetic
a=4
b = 5 
c = 12
print(a + b + c)


# Using input
x = input("What is x? ")
y = input("What is y? ")
z = int(x) + int(y)
print(z)

# Do we actually need z? using it right away and won't call it again - so why waste variable and take time defining?
# Let's nest it here instead of i - I'll nest and immediately call for it
g = int(input("What is g? "))
h = int(input("What is h? "))

print(g + h)


# Overnesting is a real thing - when we start having longer lines of code it gets to be a clusterf 
# making it harder to decipher whatr we want to do and more cumbersome when it comes to modifying code and tweaking. 
# Consider visceral reation to code, likelihood if mistakes and value it brings.  More erros and propensity tp mess up isn't worth it
print(int(input("What's x? ")) + int(input("What's y? "))) # this is valid but it's prone to typos and of the code is longer - easier to f up

# decimals FLOATS
j = float(input("What's j? "))
k = float(input("What's k? "))
print(j + k)

# ROUND FUNCTION:  round(number[, ndigits])
# [ ]  these specify optional values

l = round (j + k)
# or
print(l)

# Concatenate w f string - change system settings period/commas etc for separators
print(f"{l}") # or print("l") - that will literally print l

#Include rounding and separators # Include commas
print(f"{l:,}")

# Division
m = float(input("What is m? "))
n = float(input("What is n? "))

o = m/n 
print(o)

o = round(m / n, 2) # round to 2 digits
# or   
# o = round(m / n) - this is without rounding
print(o)


# ** OR **
# fstring to round to 2 digits
print(f"{o:.2f}")

'''
The parentheses with nothing inside means that this function at the moment
is not going to take any inputs, no arguments there too.
The colon means, stay tuned for some indentation.
Everything that's indented beneath this line of code
is going to be part of this function.
'''

def hello(): 
    print("hello")


hello
name = input("What's your name? ")


# extending beyond:
def hello(to="world"):
    print("hello," to)


hello()
name = input("What's your name? ")
hello(name)



## good habits:

def main():
    name = input("What's your name? ")
    hello(name)


def hello(to="world"):
    print("hello,", to)


# NOW MAKE SURE YOU CALL THE DAMN FUNCTION 
main()

'''
# wrong:
## good habits:

def main():
    name = input("What's your name? ")
    hello()


def hello():
    print("hello,", name)

main()  
# this is a scope issue..  it's only existing in the context in which I defined it.  this is wrong.  
'''


# Side-effect only proints to screen.  
# RETURN use return to actully return a value. 
def main():
    x = int(input("What's x? "))
    print("x squared is", square(x))


main()

# need to define square to call it for a return value to another funtion

# so:

def main():
    x = int(input("What's x? "))
    print("x squared is", square(x))

def square(n):
    return n*n 
    # or     return n ** 2    # raise n to the power of 2 ( two astericks means it raises the thing on the left to the power of the thing on the right)
    # or     return pow(n, 2)   

    '''
    POW for raising something to the power that
    takes two arguments, the first of which is the number, the second of which
    is the exponent.  
    ''''





 
    '''
    We've defined a function called Main and I've implemented two lines.
    The first of these lines prompts the user for a value
    x and converts it to an INT and stores it in a variable called x.
    So I've implemented my very own function that returns the square of a value
    and because I'm using the return keyword, that
    ensures that I can pass the return value of this, just
    like the return value of input or INT or float, to another function,
    '''
main()

reference / cite

SMU MSDS Bootcamp December 2022 Professor: Scott Saenz , TA: Stephen Tahan Dir: Sean Fleming

LS0tDQp0aXRsZTogIkludHJvIFB5dGhvbiAtQkFTSUNTIg0KYXV0aG9yOiAiSmVzc2ljYSBNY1BoYXVsIg0KZGF0ZTogIkRlY2VtYmVyIDEsIDIwMjIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyAxLiAqKkludHJvZHVjdGlvbiB0byBQcm9ncmFtbWluZyBpbiBQeXRob24qKg0KDQpzYXZlIFB5dGhvbiBmaWxlcyB3aXRoIHRoZSBgLnB5YCBleHRlbnNpb24gdG8gaW5kaWNhdGUgdGhleSdyZSBQeXRob24gc2NyaXB0cy4NCg0KIyMjIEV4YW1wbGU6IENyZWF0aW5nIFB5dGhvbiBTY3JpcHQNCg0KU2F2ZSBhIGZpbGUgbmFtZWQgYGhlbGxvLnB5YDoNCg0KYGBgIHB5dGhvbg0KcHJpbnQoImhlbGxvLCB3b3JsZCIpDQpgYGANCg0KUHJpbnRzICJoZWxsbywgd29ybGQiIHRvIHRoZSBzY3JlZW4uIFRoZSBmdW5jdGlvbiBgcHJpbnQoKWAgaXMgdXNlZCB0byBkaXNwbGF5IHRleHQgb3Igb3RoZXIgb3V0cHV0IGluIFB5dGhvbi4NCg0KUnVuIHVzaW5nIHRvIHVzZSB0aGUgY29tbWFuZCBsaW5lIG9yIHRlcm1pbmFsIG9yIGJhc2guIChydW4gcHl0aG9uIGNvZGUgZGlycmVjdGx5IGluIHB5dGhvbiBjb25zb2xlIGJ5IHR5cGluZyBweXRob24gdG8gZ2V0IHRvIHB5dGhvbiBwcm9tcHQgIHRoZW4gY3J0cmwgeiB0byBleGl0IG91dCBhbmQgYmFjayB0byB0ZXJtKQ0KDQpgYGAgc2gNCnB5dGhvbiBoZWxsby5weQ0KYGBgDQpTaG91bGQgb3V0cHV0Og0KDQpgYGAgICAgICAgICANCmhlbGxvLCB3b3JsZA0KYGBgDQoNCiMjIDIuICoqVmFyaWFibGVzIGFuZCBVc2VyIElucHV0KioNCg0KQSB2YXJpYWJsZSBpcyBhIGNvbnRhaW5lciB0byBzdG9yZSBkYXRhLCBzdWNoIGFzIG51bWJlcnMgb3IgdGV4dC4gQXNrIHVzZXJzIGZvciBpbnB1dCB0byBtYWtlIHlvdXIgcHJvZ3JhbSBtb3JlIGludGVyYWN0aXZlLg0KDQojIyMgRXhhbXBsZTogVXNlciBHcmVldGluZw0KDQpgYGAgcHl0aG9uDQojIEFzayB0aGUgdXNlciBmb3IgdGhlaXIgbmFtZQ0KbmFtZSA9IGlucHV0KCJXaGF0J3MgeW91ciBuYW1lPyAiKQ0KDQojIFByaW50IGEgcGVyc29uYWxpemVkIGdyZWV0aW5nDQpwcmludChmIkhlbGxvLCB7bmFtZX0iKQ0KYGBgDQoNCkhlcmUsIGBpbnB1dCgpYCBpcyB1c2VkIHRvIHRha2UgdXNlciBpbnB1dC4gVGhlIHVzZXIncyBpbnB1dCBpcyBzdG9yZWQgaW4gYSB2YXJpYWJsZSBjYWxsZWQgYG5hbWVgLCBhbmQgdGhlbiBpdCdzIHVzZWQgdG8gZ3JlZXQgdGhlbSB1c2luZyBhbiBgZi1zdHJpbmdgLCB3aGljaCBhbGxvd3MgaW5zZXJ0aW5nIHZhcmlhYmxlcyBkaXJlY3RseSBpbnRvIHN0cmluZ3MuDQoNCiMjIyBJbXByb3ZlZCBHcmVldGluZyB3aXRoIElucHV0IFNhbml0aXphdGlvbg0KDQpZb3UgY2FuIGFsc28gaW1wcm92ZSB5b3VyIGdyZWV0aW5nIGJ5IGNsZWFuaW5nIHVwIGFueSBleHRyYSB3aGl0ZXNwYWNlIG9yIGNhcGl0YWxpemF0aW9uIGlzc3VlczoNCg0KYGBgIHB5dGhvbg0KIyBBc2sgdGhlIHVzZXIgZm9yIHRoZWlyIG5hbWUgYW5kIHJlbW92ZSBleHRyYSBzcGFjZXMNCm5hbWUgPSBpbnB1dCgiV2hhdCdzIHlvdXIgbmFtZT8gIikuc3RyaXAoKS50aXRsZSgpDQoNCiMgUHJpbnQgYSBjbGVhbmVkLXVwIHBlcnNvbmFsaXplZCBncmVldGluZw0KcHJpbnQoZiJIZWxsbywge25hbWV9IikNCmBgYA0KDQpJbiB0aGlzIGNvZGU6DQoNCi0gICBgc3RyaXAoKWAgcmVtb3ZlcyBhbnkgbGVhZGluZyBvciB0cmFpbGluZyB3aGl0ZXNwYWNlIGZyb20gdGhlIHVzZXIncyBpbnB1dC4NCi0gICBgdGl0bGUoKWAgY2FwaXRhbGl6ZXMgdGhlIGZpcnN0IGxldHRlciBvZiBlYWNoIHdvcmQuDQoNCiMjIDMuICoqQmFzaWMgTWF0aCBPcGVyYXRpb25zKioNCg0KUHl0aG9uIGNhbiBiZSB1c2VkIGFzIGEgc2ltcGxlIGNhbGN1bGF0b3IgdG8gYWRkLCBzdWJ0cmFjdCwgbXVsdGlwbHksIG9yIGRpdmlkZSBudW1iZXJzLiBZb3UgY2FuIGFsc28gYXNrIHVzZXJzIHRvIGlucHV0IG51bWJlcnMgdG8gcGVyZm9ybSBjYWxjdWxhdGlvbnMuDQoNCiMjIyBFeGFtcGxlOiBTaW1wbGUgQ2FsY3VsYXRvcg0KDQpgYGAgcHl0aG9uDQojIEFzayB0aGUgdXNlciBmb3IgdHdvIG51bWJlcnMNCnggPSBpbnQoaW5wdXQoIkVudGVyIHRoZSBmaXJzdCBudW1iZXI6ICIpKQ0KeSA9IGludChpbnB1dCgiRW50ZXIgdGhlIHNlY29uZCBudW1iZXI6ICIpKQ0KDQojIENhbGN1bGF0ZSBhbmQgcHJpbnQgdGhlIHN1bQ0Kc3VtID0geCArIHkNCnByaW50KGYiVGhlIHN1bSBvZiB7eH0gYW5kIHt5fSBpcyB7c3VtfSIpDQpgYGANCg0KSGVyZSwgdGhlIGBpbnQoKWAgZnVuY3Rpb24gaXMgdXNlZCB0byBjb252ZXJ0IHRoZSB1c2VyJ3MgaW5wdXQgaW50byBhbiBpbnRlZ2VyIHNvIHRoYXQgbWF0aGVtYXRpY2FsIG9wZXJhdGlvbnMgY2FuIGJlIHBlcmZvcm1lZC4gQnkgZGVmYXVsdCwgYGlucHV0KClgIGdpdmVzIGEgc3RyaW5nLCBhbmQgY29udmVydGluZyBpdCBpcyBuZWNlc3NhcnkgdG8gdHJlYXQgaXQgYXMgYSBudW1iZXIuDQoNCiMjIyBFeGFtcGxlOiBNdWx0aXBsZSBPcGVyYXRpb25zDQoNCllvdSBjYW4gYWRkIG1vcmUgb3BlcmF0aW9ucyB0byB0aGUgY2FsY3VsYXRvcjoNCg0KYGBgIHB5dGhvbg0KIyBBc2sgdGhlIHVzZXIgZm9yIHR3byBudW1iZXJzDQp4ID0gaW50KGlucHV0KCJFbnRlciB0aGUgZmlyc3QgbnVtYmVyOiAiKSkNCnkgPSBpbnQoaW5wdXQoIkVudGVyIHRoZSBzZWNvbmQgbnVtYmVyOiAiKSkNCg0KIyBQZXJmb3JtIGRpZmZlcmVudCBvcGVyYXRpb25zDQpwcmludChmIlRoZSBzdW0gaXM6IHt4ICsgeX0iKQ0KcHJpbnQoZiJUaGUgZGlmZmVyZW5jZSBpczoge3ggLSB5fSIpDQpwcmludChmIlRoZSBwcm9kdWN0IGlzOiB7eCAqIHl9IikNCnByaW50KGYiVGhlIHF1b3RpZW50IGlzOiB7eCAvIHl9IikNCmBgYA0KDQpQZXJmb3JtIGFkZGl0aW9uLCBzdWJ0cmFjdGlvbiwgbXVsdGlwbGljYXRpb24sIGFuZCBkaXZpc2lvbiAoIGAvYCApIG9wZXJhdG9yLg0KIyMgNC4gKipDb21iaW5pbmcgU3RyaW5ncyBhbmQgTnVtYmVycyoqDQoNCkRpc3BsYXkgYSByZXN1bHQgdGhhdCBjb21iaW5lcyBib3RoIHRleHQgYW5kIG51bWJlcnMuICBVc2UgZm9ybWF0dGVkIHN0cmluZ3MuDQoNCiMjIyBFeGFtcGxlOiBPdXRwdXR0aW5nIE51bWJlcnMgaW4gYSBTZW50ZW5jZQ0KDQpgYGAgcHl0aG9uDQp4ID0gaW50KGlucHV0KCJFbnRlciBhIG51bWJlcjogIikpDQp5ID0gaW50KGlucHV0KCJFbnRlciBhbm90aGVyIG51bWJlcjogIikpDQoNCiMgQ2FsY3VsYXRlIHRoZSBwcm9kdWN0DQpwcm9kdWN0ID0geCAqIHkNCg0KIyBQcmludCB0aGUgcmVzdWx0IGluIGEgZnVsbCBzZW50ZW5jZQ0KcHJpbnQoZiJUaGUgcHJvZHVjdCBvZiB7eH0gYW5kIHt5fSBpcyB7cHJvZHVjdH0uIikNCmBgYA0KDQpUaGlzIGNvZGUgYXNrcyB0aGUgdXNlciBmb3IgdHdvIG51bWJlcnMsIGNhbGN1bGF0ZXMgdGhlaXIgcHJvZHVjdCwgYW5kIHByaW50cyB0aGUgcmVzdWx0Lg0KDQojIyA1LiAqKkVycm9yIEhhbmRsaW5nOiBIYW5kbGluZyBJbnZhbGlkIElucHV0KioNCg0KU29tZXRpbWVzIHVzZXJzIGVudGVyIGludmFsaWQgZGF0YS4gSW1wcm92ZSBvdXIgY2FsY3VsYXRvciB0byBoYW5kbGUgc3VjaCBjYXNlcy4NCg0KIyMjIEV4YW1wbGU6IFVzaW5nIGB0cnktZXhjZXB0YCB0byBIYW5kbGUgSW5wdXQgRXJyb3JzDQoNCmBgYCBweXRob24NCnRyeToNCiAgICB4ID0gaW50KGlucHV0KCJFbnRlciB0aGUgZmlyc3QgbnVtYmVyOiAiKSkNCiAgICB5ID0gaW50KGlucHV0KCJFbnRlciB0aGUgc2Vjb25kIG51bWJlcjogIikpDQogICAgcHJpbnQoZiJUaGUgc3VtIGlzOiB7eCArIHl9IikNCmV4Y2VwdCBWYWx1ZUVycm9yOg0KICAgIHByaW50KCJQbGVhc2UgZW50ZXIgYSB2YWxpZCBudW1iZXIuIikNCmBgYA0KVXNlIGEgYHRyeS1leGNlcHRgIGJsb2NrIHRvIGNhdGNoIGVycm9ycyB3aGVuIHRoZSB1c2VyIGVudGVycyBzb21ldGhpbmcgdGhhdCBpc24ndCBhIG51bWJlci4gSWYgdGhleSBlbnRlciBhbiBpbnZhbGlkIHZhbHVlLCB0aGUgcHJvZ3JhbSBwcmludHMgYW4gZXJyb3IgbWVzc2FnZS4NCg0KLSAgIENyZWF0ZSB2YXJpYWJsZXMgdG8gc3RvcmUgdXNlciBpbnB1dCB1c2luZyBgaW5wdXQoKWAuDQotICAgVGhlIGBwcmludCgpYCBmdW5jdGlvbiBpcyB1c2VkIHRvIGRpc3BsYXkgaW5mb3JtYXRpb24uDQotICAgRnVuY3Rpb25zIGxpa2UgYHN0cmlwKClgLCBgdGl0bGUoKWAsIGFuZCBgaW50KClgIGhlbHAgY2xlYW4gdXAgdXNlciBpbnB1dCBhbmQgY29udmVydCBkYXRhIHR5cGVzLg0KLSAgIFVzZSBiYXNpYyBtYXRoIG9wZXJhdG9ycyAoYCtgLCBgLWAsIGAqYCwgYC9gKSB0byBwZXJmb3JtIGNhbGN1bGF0aW9ucy4NCi0gICBIYW5kbGUgdXNlciBlcnJvcnMgZ3JhY2VmdWxseSB1c2luZyBgdHJ5LWV4Y2VwdGAuDQoNCkNyZWF0ZSBhIG5ldyBmaWxlIGluIHRoZSB0ZXJtaW5hbCwgdXNlIHRoZSBjb21tYW5kIGB0b3VjaGAuIFRoZSBgdG91Y2hgIGNvbW1hbmQgaXMgY29tbW9ubHkgdXNlZCB0byBjcmVhdGUgYW4gZW1wdHkgZmlsZSBvciB1cGRhdGUgdGhlIHRpbWVzdGFtcCBvZiBhbiBleGlzdGluZyBmaWxlLiANCg0KIyMjIENyZWF0aW5nIGEgRmlsZSBVc2luZyBgdG91Y2hgDQoNCkluIHRoZSB0ZXJtaW5hbCwgdHlwZToNCg0KYGBgIHNoDQp0b3VjaCBteV9tb2R1bGUucHkNCmBgYA0KDQpDcmVhdGVzIGFuIGVtcHR5IGZpbGUgbmFtZWQgYG15X21vZHVsZS5weWAgaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5LiAobGlrZSBuYW5vLyB+LmJhc2hyYykNCg0KIyMgUHl0aG9uIEJhc2ljIE1vZHVsZSBFeGFtcGxlDQoNCk5leHQ6IENyYWV0ZSBhIHNpbXBsZSBQeXRob24gbW9kdWxlLiBBIG1vZHVsZSBpcyBlc3NlbnRpYWxseSBhIFB5dGhvbiBmaWxlIGNvbnRhaW5pbmcgcmV1c2FibGUgY29kZSwgc3VjaCBhcyBmdW5jdGlvbnMgb3IgY2xhc3Nlcywgd2hpY2ggY2FuIGJlIGltcG9ydGVkIGludG8gb3RoZXIgc2NyaXB0cy4NCg0KTWFrZSBtb2QuIGNhbGxlZCBgbWF0aF91dGlscy5weWAgdG8gYWRkICBhZmV3IG1vcmUgZnVuY3Rpb25zIHRvIG91ciBjYWxjLg0KDQpJdCBzaG91bGQgMS4gRGVmaW5lIGEgUHl0aG9uIG1vZHVsZSB3aXRoIG11bHRpcGxlIGZ1bmN0aW9ucy4gMi4gTWFrZSB0aGUgZnVuY3Rpb25zIG1vcmUgcmV1c2FibGUgYW5kIGluY2x1ZGUgc2xpZ2h0bHkgYWR2YW5jZWQgY29uY2VwdHMuIDMuIEltcG9ydCBhbmQgdXNlIHRoaXMgbW9kdWxlIGZyb20gYW5vdGhlciBzY3JpcHQuDQoNCiMjIyBTdGVwIDE6IENyZWF0ZSB0aGUgTW9kdWxlIChgbWF0aF91dGlscy5weWApDQoNClJ1biB0aGlzIGluIHRlcm1pbmFsOg0KDQpgYGAgc2gNCnRvdWNoIG1hdGhfdXRpbHMucHkNCmBgYA0KDQojIyMgU3RlcCAyOiBBZGQgRnVuY3Rpb25zIHRvIHRoZSBNb2R1bGUNCg0KT3BlbiBgbWF0aF91dGlscy5weWAgYW5kIGFkZCBmdW5jdGlvbnMgdG8gaXQuIFVzZSBjb2RlIGVkaXRvciwgc3VjaCBhcyBWUyBDb2RlLCBzdWJsaW1lIGlmIGF2YWlsYWJsZSBpcyBJTU8gdGhlIGJlc3QgY29kZSBlZGl0b3IuIFNhdmUgYXMgLnB5IC0gdGhleSBydW4gaW4gZ2l0YmFzaCAtIGVhc2llciBvbiBzeXN0ZW0gdGhhbiBWU2NvZGUgb3IgVlMgd2hlbiBjb2xtcHV0aW5nIHdpdGggc2ltcGxlIHB5dGhvbiBzY3JpcHRzLg0KDQpDb2RlIHRvIGFkZDoNCg0KYGBgIHB5dGhvbg0KIyBtYXRoX3V0aWxzLnB5DQoNCmRlZiBhZGQoeCwgeSk6DQogICAgcmV0dXJuIHggKyB5DQoNCmRlZiBzdWJ0cmFjdCh4LCB5KToNCiAgICByZXR1cm4geCAtIHkNCg0KZGVmIG11bHRpcGx5KHgsIHkpOg0KICAgIHJldHVybiB4ICogeQ0KDQpkZWYgZGl2aWRlKHgsIHkpOg0KICAgIGlmIHkgPT0gMDoNCiAgICAgICAgcmV0dXJuICJFcnJvcjogRGl2aXNpb24gYnkgemVybyBpcyB1bmRlZmluZWQuIg0KICAgIHJldHVybiB4IC8geQ0KDQpkZWYgcG93ZXIoYmFzZSwgZXhwb25lbnQpOg0KICAgICIiIlJldHVybnMgdGhlIGJhc2UgcmFpc2VkIHRvIHRoZSBwb3dlciBvZiBleHBvbmVudC4iIiINCiAgICByZXR1cm4gYmFzZSAqKiBleHBvbmVudA0KDQpkZWYgZmFjdG9yaWFsKG4pOg0KICAgICIiIlJldHVybnMgdGhlIGZhY3RvcmlhbCBvZiBhIGdpdmVuIG51bWJlciBuLiIiIg0KICAgIGlmIG4gPCAwOg0KICAgICAgICByZXR1cm4gIkVycm9yOiBGYWN0b3JpYWwgaXMgbm90IGRlZmluZWQgZm9yIG5lZ2F0aXZlIG51bWJlcnMuIg0KICAgIGVsaWYgbiA9PSAwIG9yIG4gPT0gMToNCiAgICAgICAgcmV0dXJuIDENCiAgICBlbHNlOg0KICAgICAgICByZXN1bHQgPSAxDQogICAgICAgIGZvciBpIGluIHJhbmdlKDIsIG4gKyAxKToNCiAgICAgICAgICAgIHJlc3VsdCAqPSBpDQogICAgICAgIHJldHVybiByZXN1bHQNCg0KZGVmIGdjZChhLCBiKToNCiAgICAiIiJSZXR1cm5zIHRoZSBncmVhdGVzdCBjb21tb24gZGl2aXNvciBvZiBhIGFuZCBiLiIiIg0KICAgIHdoaWxlIGI6DQogICAgICAgIGEsIGIgPSBiLCBhICUgYg0KICAgIHJldHVybiBhDQpgYGANCg0KIyMjIyBFeHBsYW5hdGlvbjoNCg0KLSAgICoqQmFzaWMgQXJpdGhtZXRpYyBGdW5jdGlvbnMqKiAoYGFkZGAsIGBzdWJ0cmFjdGAsIGBtdWx0aXBseWAsIGBkaXZpZGVgKTogVGhlc2UgZnVuY3Rpb25zIHBlcmZvcm0gYmFzaWMgb3BlcmF0aW9ucy4NCi0gICAqKlBvd2VyIEZ1bmN0aW9uKiogKGBwb3dlcmApOiBSYWlzZXMgYSBudW1iZXIgdG8gdGhlIHBvd2VyIG9mIGFub3RoZXIuDQotICAgKipGYWN0b3JpYWwgRnVuY3Rpb24qKiAoYGZhY3RvcmlhbGApOiBDYWxjdWxhdGVzIHRoZSBmYWN0b3JpYWwgb2YgYSBub24tbmVnYXRpdmUgaW50ZWdlci4NCi0gICAqKkdDRCBGdW5jdGlvbioqIChgZ2NkYCk6IEZpbmRzIHRoZSBncmVhdGVzdCBjb21tb24gZGl2aXNvciBvZiB0d28gaW50ZWdlcnMgdXNpbmcgdGhlIEV1Y2xpZGVhbiBhbGdvcml0aG0uDQoNCiMjIyBTdGVwIDM6IFVzZSB0aGUgTW9kdWxlIGluIEFub3RoZXIgU2NyaXB0DQoNCkNyZWF0ZSBhIHNjcmlwdCBuYW1lZCBgbWFpbi5weWAgdGhhdCdsbCB1c2UgYG1hdGhfdXRpbHNgIG1vZHVsZS4gRmlyc3QsIGNyZWF0ZSB0aGUgZmlsZToNCg0KYGBgIHNoDQp0b3VjaCBtYWluLnB5DQpgYGANCg0KQWRkIHRvIGNvZGU6DQoNCmBgYCBweXRob24NCiMgbWFpbi5weQ0KDQppbXBvcnQgbWF0aF91dGlscw0KDQojIFRha2UgdXNlciBpbnB1dHMgZm9yIGFyaXRobWV0aWMgb3BlcmF0aW9ucw0KeCA9IGludChpbnB1dCgiRW50ZXIgdGhlIGZpcnN0IG51bWJlcjogIikpDQp5ID0gaW50KGlucHV0KCJFbnRlciB0aGUgc2Vjb25kIG51bWJlcjogIikpDQoNCnByaW50KGYiU3VtOiB7bWF0aF91dGlscy5hZGQoeCwgeSl9IikNCnByaW50KGYiRGlmZmVyZW5jZToge21hdGhfdXRpbHMuc3VidHJhY3QoeCwgeSl9IikNCnByaW50KGYiUHJvZHVjdDoge21hdGhfdXRpbHMubXVsdGlwbHkoeCwgeSl9IikNCnByaW50KGYiUXVvdGllbnQ6IHttYXRoX3V0aWxzLmRpdmlkZSh4LCB5KX0iKQ0KDQojIFRha2UgdXNlciBpbnB1dHMgZm9yIG1vcmUgYWR2YW5jZWQgZnVuY3Rpb25zDQpiYXNlID0gaW50KGlucHV0KCJFbnRlciB0aGUgYmFzZSBudW1iZXI6ICIpKQ0KZXhwb25lbnQgPSBpbnQoaW5wdXQoIkVudGVyIHRoZSBleHBvbmVudDogIikpDQpwcmludChmIntiYXNlfSByYWlzZWQgdG8gdGhlIHBvd2VyIG9mIHtleHBvbmVudH06IHttYXRoX3V0aWxzLnBvd2VyKGJhc2UsIGV4cG9uZW50KX0iKQ0KDQpuID0gaW50KGlucHV0KCJFbnRlciBhIG51bWJlciB0byBmaW5kIGl0cyBmYWN0b3JpYWw6ICIpKQ0KcHJpbnQoZiJGYWN0b3JpYWwgb2Yge259OiB7bWF0aF91dGlscy5mYWN0b3JpYWwobil9IikNCg0KYSA9IGludChpbnB1dCgiRW50ZXIgdGhlIGZpcnN0IG51bWJlciB0byBmaW5kIEdDRDogIikpDQpiID0gaW50KGlucHV0KCJFbnRlciB0aGUgc2Vjb25kIG51bWJlciB0byBmaW5kIEdDRDogIikpDQpwcmludChmIkdDRCBvZiB7YX0gYW5kIHtifToge21hdGhfdXRpbHMuZ2NkKGEsIGIpfSIpDQpgYGANCg0KIyMjIFN0ZXAgNDogUnVuIHRoZSBTY3JpcHQNCg0KVG8gcnVuIHRoZSBzY3JpcHQsIHVzZToNCg0KYGBgIHNoDQpweXRob24gbWFpbi5weQ0KYGBgDQoNCiMjIyBFeGFtcGxlIFJ1bg0KDQpUeXBpY2FsIGludGVyYWN0aW9uIHdpdGggYG1haW4ucHlgDQoNCmBgYCAgICAgICAgIA0KRW50ZXIgdGhlIGZpcnN0IG51bWJlcjogNQ0KRW50ZXIgdGhlIHNlY29uZCBudW1iZXI6IDEwDQpTdW06IDE1DQpEaWZmZXJlbmNlOiAtNQ0KUHJvZHVjdDogNTANClF1b3RpZW50OiAwLjUNCkVudGVyIHRoZSBiYXNlIG51bWJlcjogMg0KRW50ZXIgdGhlIGV4cG9uZW50OiAzDQoyIHJhaXNlZCB0byB0aGUgcG93ZXIgb2YgMzogOA0KRW50ZXIgYSBudW1iZXIgdG8gZmluZCBpdHMgZmFjdG9yaWFsOiA1DQpGYWN0b3JpYWwgb2YgNTogMTIwDQpFbnRlciB0aGUgZmlyc3QgbnVtYmVyIHRvIGZpbmQgR0NEOiA1NA0KRW50ZXIgdGhlIHNlY29uZCBudW1iZXIgdG8gZmluZCBHQ0Q6IDI0DQpHQ0Qgb2YgNTQgYW5kIDI0OiA2DQpgYGANCg0KIyMjIHJldmlldw0KDQoxLiAgKipDcmVhdGUgRmlsZXMqKjogVXNlIGB0b3VjaGAgdG8gY3JlYXRlIGVtcHR5IGZpbGVzIHN1Y2ggYXMgYG1hdGhfdXRpbHMucHlgIGFuZCBgbWFpbi5weWAuDQoyLiAgKipEZWZpbmUgYSBNb2R1bGUqKjogQWRkIGZ1bmN0aW9ucyB0byBgbWF0aF91dGlscy5weWAgdG8gaGFuZGxlIGRpZmZlcmVudCBtYXRoZW1hdGljYWwgdGFza3MuDQozLiAgKipVc2UgdGhlIE1vZHVsZSoqOiBJbXBvcnQgYG1hdGhfdXRpbHNgIGluIGBtYWluLnB5YCB0byB1c2UgdGhlIGZ1bmN0aW9ucyB5b3UgZGVmaW5lZC4NCg0KUGxheSB3aXRoIGBtYXRoX3V0aWxzYCBhZGRpbmcgbW9yZSBmdW5jdGlvbnMgbGlrZSBzcXVhcmUgcm9vdCwgcHJpbWUgY2hlY2tpbmcsIGV0YywgcGxheSBhcm91bmQgd2l0aCBjb2RlLCB1c2UgcHl0aG9uIHJlZmVyZW5jZXMuIFByYWN0aWNlIHVzaW5nIGluIGRpZmZlcmVudCB0b29scy4gUHJhY3RpY2UgY2FsbGluZyBmcm9tIGRpZmZlcmVudCBwbGF0Zm9ybXMuIE1lbW9yaXplIGJhc2ljcyBhbmQga2V5Ym9hcmQgc2hvcnRjdXRzLiBUaGUgaGVhdnkgbGlmdGluZyBpc24ndCBhcyBoZWF2eSBpZiB5b3Uga25vdyB0aGUgYmFzaWNzLiBUaGV5J3JlIHRoZSBzYWZldHkgbmV0LiBCZSBzYWZlLiBUaGVuIGFkdmFuY2UuDQoNCkFzIHdpdGggaW4gdGhlIGN1dHRocm9hdCBraXRjaGVuIC0gS05PVyBUSEUgTEFZT1VUIE9GIFRIRSBMQU5ELiBMRUFSTiBUSEUgVE9PTFMuIFVTRSBUSEUgVE9PTFMuIENvZGluZyBza2lsbHMgaXJyZWxldmFudCBpZiB5b3UgY2FuJ3QgZWZmaWNpZW50bHkgZ2V0IHRvIGEgbm90ZWJvb2ssIHdpbmRvdywgbGludXggbGluZSBldGMuIFdTTCwgVUJVTlRVLCBDTUQsIEdJVCwgV2luZG93cyAoYW5kL29yIE1hYykuIExlYXJuIGNvbW1hbmRzLCBNZW1vcml6ZSBjb21tYW5kcy4gQmUgYWJsZSB0byBxdWlja2x5IGFuZCBlZmZpY2llbnRseSBuYXZpZ2F0ZSBhcm91bmQgYSBjb21wdXRlciBhbmQgdGhlIHByb2dyYW1zIHdpdGhpbiBpdC4NCg0KYGBgIHB5dGhvbg0KDQonJycNClRoZSBwYXJlbnRoZXNlcyB3aXRoIG5vdGhpbmcgaW5zaWRlIG1lYW5zIHRoYXQgdGhpcyBmdW5jdGlvbiBhdCB0aGUgbW9tZW50DQppcyBub3QgZ29pbmcgdG8gdGFrZSBhbnkgaW5wdXRzLCBubyBhcmd1bWVudHMgdGhlcmUgdG9vLg0KVGhlIGNvbG9uIG1lYW5zLCBzdGF5IHR1bmVkIGZvciBzb21lIGluZGVudGF0aW9uLg0KRXZlcnl0aGluZyB0aGF0J3MgaW5kZW50ZWQgYmVuZWF0aCB0aGlzIGxpbmUgb2YgY29kZQ0KaXMgZ29pbmcgdG8gYmUgcGFydCBvZiB0aGlzIGZ1bmN0aW9uLg0KJycnDQoNCmRlZiBoZWxsbygpOiANCiAgICBwcmludCgiaGVsbG8iKQ0KDQoNCm5hbWUgPSBpbnB1dCgiV2hhdCdzIHlvdXIgbmFtZT8gIikNCmhlbGxvKG5hbWUpDQpgYGANCg0KYGBgIHB5dGhvbg0KIyAiSGVsbG8ucHkiDQoNCg0KIyBBc2sgZm9yIG5hbWUNCm5hbWUgPSBpbnB1dCAoIldoYXQncyB5b3VyIG5hbWU/ICIpDQoNCiMgUmVtb3ZlIHdoaXRlc3BhY2UgZnJvbSBzdHINCm5hbWUgPSBuYW1lLnN0cmlwKCkNCg0KIyBDYXBpdGFsaXplIHVzZXIncyBuYW1lDQpuYW1lID0gbmFtZS5jYXBpdGFsaXplKCkNCg0KDQojIEFkZHJlc3MgdXNlciAtIGZzdHJpbmcNCnByaW50IChmIkhlbGxvLCB7bmFtZX0iKQ0KDQoNCiMgcHNldWRvIGNvZGUgDQojIG9yIHByaW50ICgiaGVsbG8sIikgIG4vIHByaW50KG5hbWUpDQoNCiIiIg0Kb3V0bGluZSBjb2RlICANCmJ1aWxkaW5nYmxvY2tzDQp3aGF0IGRvIGkgd2FudCB0byBkbw0Kd2hhdCBkbyBpIHdhbnQgdG8gYWNjb21wbGlzaA0KdGhpcyBpcyBhbGwgcGFydCBvZiBwc2V1ZG9jb2RlDQppbnB1dCBwcm9tcHRzIHN0cmluZyAtIHRleHQgDQpuZXh0IHJldHVybiB2YWx1ZXMgYW5kIGRlZmluZSB2YWx1ZXMNCiIiIg0KDQoiIiINCnJ1biBpbiB0ZXJtaW5hbCB1c2luZyA6IHB5dGhvbiBoZWxsby5weQ0KYW55dGhpbmcgYmV0d2VlbiB0cmlwbGUgZG91YmxlIHF1b3RlcyBpcyBhIGNvbW1lbnQgDQp5b3UgY2FuIGFsc28gdXNlIHNpbmdsZSBxdW90ZSB0byBjb21tZW50DQoiIiINCg0KDQojIFNheSBoZWxsbw0KcHJpbnQoImhlbGxvLCAiICsgbmFtZSkNCg0KIyBwYXNzIGluIG1vcmUgYXJndW1lbnRzDQpwcmludCgiaGVsbG8sIiwgbmFtZSkNCg0KDQojIHN0ciA9IHN0cmluZw0KIyBvdmVycmlkZSBtb3ZlIHRvIG5leHQgbGluZSBpbiBwcmludCBzdGF0ZW1lbnQNCiMgZG9jcy9weXRob24ub3JnLzMvbGlicmFyeS9mdW5jdGlvbnMuaHRtbCNwcmludCANCnByaW50KG5hbWUpIA0KDQoNCg0KIiIiDQpwcmludCgqb2JqZWN0cywgc2VwPScgJywgZW5kPSdcbicsIGZpbGU9c3lzLnN0ZG91dCwgZmx1c2g9RmFsc2UpDQpwYXJhbWV0ZXJzIHZzIGFyZ3VtZW50cyAtIHdoYXQgcHJvYmxlbSBjYW4gdGFrZSB2cyB3aGF0IHlvdXJlIHRyeWlvbmcgdG8gYXBwbHkNCj0gbWVhbnMgYXNzaWdubWVudA0KPT0gbWVhbnMgZXF1YWxzIGFzIHZhbHVlDQoiIiINCg0KIyBTbw0KcHJpbnQoImhlbGxvLCAiLCBlbmQ9IiIpDQpwcmludChuYW1lKQ0KDQojIGxvb2sgYXQgZGlmZmVyZW5jZQ0KcHJpbnQoImhlbGxvLCIsIG5hbWUsIHNlcD0iPz8/IikNCg0KIyB1c2luZyBhY3R1YWwgcXVvdGVzIC0gZXNjYXBpbmcgb3V0DQpwcmludCgiaGVsbG8sIFwiZnJpZW5kXCIiKQ0KDQoNCiMgQWdhaW4gZm9yIHByYWN0aWNlIGFuZCBtdXNjbGUgbWVtb3J5DQp5b3UgPSBpbnB1dCgiV2hhdCBzaG91bGQgSSBjYWxsIHlvdT8gIikNCg0KIyBSZW1vdmUgd2hpdGVzcGFjZSBmcm9tIHN0cg0KeW91ID0geW91LnN0cmlwKCkNCg0KIyBDYXBpdGFsaXplIHVzZXIncyBuYW1lDQp5b3UgPSB5b3UuY2FwaXRhbGl6ZSgpDQoNCiMgVGl0bGUgQmFzZWQgQ2F6cGl0YWxpemF0aW9uDQp5b3UgPSB5b3UudGl0bGUoKQ0KDQojIG9yDQojIG5hbWUgPSBuYW1lLnRpdGxlKCkNCg0KDQojIFNheSBoZWxsbyB0byB1c2VyDQpwcmludChmImhlbGxvLCB7eW91fSIpDQoNCiMgQWdhaW4NCm5pY2tuYW1lID0gaW5wdXQoIldoYXQgaXMgeW91ciBuaWNrbmFtZT8gIikNCm5pY2tuYW1lID0gbmlja25hbWUuc3RyaXAoKQ0Kbmlja25hbWUgPSBuaWNrbmFtZS5jYXBpdGFsaXplKCkNCiMgVGl0bGUgQmFzZWQgQ2F6cGl0YWxpemF0aW9uDQpuaWNrbmFtZSA9IG5pY2tuYW1lLnRpdGxlKCkNCg0KcHJpbnQoZiJoZWxsbywge25pY2tuYW1lfSIpDQoNCg0KDQoNCnByaW50KCJoZWxsbywgXCJmcmllbmRcIiIpDQoNCiNDb25kZW5zZWQNCiNBc2sgZm9yIG5hbWUNCnVzZXJuYW1lID0gaW5wdXQoIldoYXQgaXMgeW91ciB1c2VybmFtZT8gIikuc3RyaXAoKS50aXRsZSgpDQoNCiMgU2F5IFdoYXRzIHVwIHRvIHVzZXINCnByaW50KGYiV2hhdCdzIHNoYWtpbicsIHt1c2VybmFtZX0/IikNCg0KIyBtZXRob2QgaXMgYSBmdW50aW9wbiB0aGF0J3MgYnVpbHQgaW4gdG8gdHlwZSBvZiB2YWx1ZSBsaWtlIHRoZXNlIGZ1bmN0aW9ucyAoZiBzdHJpbmcgZXRjKQ0KDQojIEFkZGluZyBuYW1lIHNwbGl0DQpzcGxpdG5hbWUgPSBpbnB1dCAoIldoYXQncyB5b3VyIG5hbWU/ICIpLnN0cmlwKCkudGl0bGUoKQ0KIyBTcGxpdCB1c2VycyBuYW1lIGludG8gZmlyc3QsIG1pZGRsZSBhbmQgbGFzdA0KZmlyc3QsIG1pZGRsZSwgbGFzdCwgID0gc3BsaXRuYW1lLnNwbGl0KCIgIikNCiMgU2F5IHdoYXQncyB1cA0KcHJpbnQoZidTdXAsIHtzcGxpdG5hbWV9JykNCg0KIyBub3cgb25seSBhZGRyZXNzIGJ5IGZpcnN0IGFubWUNCnByaW50KGYiL1N1cCwge2ZpcnN0fSIpDQoNCg0KIyBpbnRlZ2VyIGlzIGludA0KJycnDQpudW1iZXIgd2l0aG91dCBkZWNpbWFsDQorIC0gKiAvICUgDQppbnRlcmFjdGl2ZSBtb2RlDQonJycNCg0KDQonJycNCnJ1bm5pbmcgd2l0aGluIHB5dGhvbiBpbnRlcnByZXRlcg0KaW1tZWRpYXRlIHRyYW5zbGF0aW9uL2ludGVyYWN0aXZlIGNvZGUNCnByaW50KCIuLi4uIikNCjErMQ0KOC8yDQpldGMgZm9yIGludGVyYWN0aXZlIG1vZGUNCicnJw0KDQoNCg0KDQoNCg0KIyBjcmVhdGUgY2FsY3VsYXRvci5weQ0KDQoiQ2FsY3VsYXRvci5weSINCg0KIyBiYXNpYyBhcml0aG1ldGljDQphPTQNCmIgPSA1IA0KYyA9IDEyDQpwcmludChhICsgYiArIGMpDQoNCg0KIyBVc2luZyBpbnB1dA0KeCA9IGlucHV0KCJXaGF0IGlzIHg/ICIpDQp5ID0gaW5wdXQoIldoYXQgaXMgeT8gIikNCnogPSBpbnQoeCkgKyBpbnQoeSkNCnByaW50KHopDQoNCiMgRG8gd2UgYWN0dWFsbHkgbmVlZCB6PyB1c2luZyBpdCByaWdodCBhd2F5IGFuZCB3b24ndCBjYWxsIGl0IGFnYWluIC0gc28gd2h5IHdhc3RlIHZhcmlhYmxlIGFuZCB0YWtlIHRpbWUgZGVmaW5pbmc/DQojIExldCdzIG5lc3QgaXQgaGVyZSBpbnN0ZWFkIG9mIGkgLSBJJ2xsIG5lc3QgYW5kIGltbWVkaWF0ZWx5IGNhbGwgZm9yIGl0DQpnID0gaW50KGlucHV0KCJXaGF0IGlzIGc/ICIpKQ0KaCA9IGludChpbnB1dCgiV2hhdCBpcyBoPyAiKSkNCg0KcHJpbnQoZyArIGgpDQoNCg0KIyBPdmVybmVzdGluZyBpcyBhIHJlYWwgdGhpbmcgLSB3aGVuIHdlIHN0YXJ0IGhhdmluZyBsb25nZXIgbGluZXMgb2YgY29kZSBpdCBnZXRzIHRvIGJlIGEgY2x1c3RlcmYgDQojIG1ha2luZyBpdCBoYXJkZXIgdG8gZGVjaXBoZXIgd2hhdHIgd2Ugd2FudCB0byBkbyBhbmQgbW9yZSBjdW1iZXJzb21lIHdoZW4gaXQgY29tZXMgdG8gbW9kaWZ5aW5nIGNvZGUgYW5kIHR3ZWFraW5nLiANCiMgQ29uc2lkZXIgdmlzY2VyYWwgcmVhdGlvbiB0byBjb2RlLCBsaWtlbGlob29kIGlmIG1pc3Rha2VzIGFuZCB2YWx1ZSBpdCBicmluZ3MuICBNb3JlIGVycm9zIGFuZCBwcm9wZW5zaXR5IHRwIG1lc3MgdXAgaXNuJ3Qgd29ydGggaXQNCnByaW50KGludChpbnB1dCgiV2hhdCdzIHg/ICIpKSArIGludChpbnB1dCgiV2hhdCdzIHk/ICIpKSkgIyB0aGlzIGlzIHZhbGlkIGJ1dCBpdCdzIHByb25lIHRvIHR5cG9zIGFuZCBvZiB0aGUgY29kZSBpcyBsb25nZXIgLSBlYXNpZXIgdG8gZiB1cA0KDQojIGRlY2ltYWxzIEZMT0FUUw0KaiA9IGZsb2F0KGlucHV0KCJXaGF0J3Mgaj8gIikpDQprID0gZmxvYXQoaW5wdXQoIldoYXQncyBrPyAiKSkNCnByaW50KGogKyBrKQ0KDQojIFJPVU5EIEZVTkNUSU9OOiAgcm91bmQobnVtYmVyWywgbmRpZ2l0c10pDQojIFsgXSAgdGhlc2Ugc3BlY2lmeSBvcHRpb25hbCB2YWx1ZXMNCg0KbCA9IHJvdW5kIChqICsgaykNCiMgb3INCnByaW50KGwpDQoNCiMgQ29uY2F0ZW5hdGUgdyBmIHN0cmluZyAtIGNoYW5nZSBzeXN0ZW0gc2V0dGluZ3MgcGVyaW9kL2NvbW1hcyBldGMgZm9yIHNlcGFyYXRvcnMNCnByaW50KGYie2x9IikgIyBvciBwcmludCgibCIpIC0gdGhhdCB3aWxsIGxpdGVyYWxseSBwcmludCBsDQoNCiNJbmNsdWRlIHJvdW5kaW5nIGFuZCBzZXBhcmF0b3JzICMgSW5jbHVkZSBjb21tYXMNCnByaW50KGYie2w6LH0iKQ0KDQojIERpdmlzaW9uDQptID0gZmxvYXQoaW5wdXQoIldoYXQgaXMgbT8gIikpDQpuID0gZmxvYXQoaW5wdXQoIldoYXQgaXMgbj8gIikpDQoNCm8gPSBtL24gDQpwcmludChvKQ0KDQpvID0gcm91bmQobSAvIG4sIDIpICMgcm91bmQgdG8gMiBkaWdpdHMNCiMgb3IgICANCiMgbyA9IHJvdW5kKG0gLyBuKSAtIHRoaXMgaXMgd2l0aG91dCByb3VuZGluZw0KcHJpbnQobykNCg0KDQojICoqIE9SICoqDQojIGZzdHJpbmcgdG8gcm91bmQgdG8gMiBkaWdpdHMNCnByaW50KGYie286LjJmfSIpDQoNCicnJw0KVGhlIHBhcmVudGhlc2VzIHdpdGggbm90aGluZyBpbnNpZGUgbWVhbnMgdGhhdCB0aGlzIGZ1bmN0aW9uIGF0IHRoZSBtb21lbnQNCmlzIG5vdCBnb2luZyB0byB0YWtlIGFueSBpbnB1dHMsIG5vIGFyZ3VtZW50cyB0aGVyZSB0b28uDQpUaGUgY29sb24gbWVhbnMsIHN0YXkgdHVuZWQgZm9yIHNvbWUgaW5kZW50YXRpb24uDQpFdmVyeXRoaW5nIHRoYXQncyBpbmRlbnRlZCBiZW5lYXRoIHRoaXMgbGluZSBvZiBjb2RlDQppcyBnb2luZyB0byBiZSBwYXJ0IG9mIHRoaXMgZnVuY3Rpb24uDQonJycNCg0KZGVmIGhlbGxvKCk6IA0KICAgIHByaW50KCJoZWxsbyIpDQoNCg0KaGVsbG8NCm5hbWUgPSBpbnB1dCgiV2hhdCdzIHlvdXIgbmFtZT8gIikNCg0KDQojIGV4dGVuZGluZyBiZXlvbmQ6DQpkZWYgaGVsbG8odG89IndvcmxkIik6DQogICAgcHJpbnQoImhlbGxvLCIgdG8pDQoNCg0KaGVsbG8oKQ0KbmFtZSA9IGlucHV0KCJXaGF0J3MgeW91ciBuYW1lPyAiKQ0KaGVsbG8obmFtZSkNCg0KDQoNCiMjIGdvb2QgaGFiaXRzOg0KDQpkZWYgbWFpbigpOg0KICAgIG5hbWUgPSBpbnB1dCgiV2hhdCdzIHlvdXIgbmFtZT8gIikNCiAgICBoZWxsbyhuYW1lKQ0KDQoNCmRlZiBoZWxsbyh0bz0id29ybGQiKToNCiAgICBwcmludCgiaGVsbG8sIiwgdG8pDQoNCg0KIyBOT1cgTUFLRSBTVVJFIFlPVSBDQUxMIFRIRSBEQU1OIEZVTkNUSU9OIA0KbWFpbigpDQoNCicnJw0KIyB3cm9uZzoNCiMjIGdvb2QgaGFiaXRzOg0KDQpkZWYgbWFpbigpOg0KICAgIG5hbWUgPSBpbnB1dCgiV2hhdCdzIHlvdXIgbmFtZT8gIikNCiAgICBoZWxsbygpDQoNCg0KZGVmIGhlbGxvKCk6DQogICAgcHJpbnQoImhlbGxvLCIsIG5hbWUpDQoNCm1haW4oKSAgDQojIHRoaXMgaXMgYSBzY29wZSBpc3N1ZS4uICBpdCdzIG9ubHkgZXhpc3RpbmcgaW4gdGhlIGNvbnRleHQgaW4gd2hpY2ggSSBkZWZpbmVkIGl0LiAgdGhpcyBpcyB3cm9uZy4gIA0KJycnDQoNCg0KIyBTaWRlLWVmZmVjdCBvbmx5IHByb2ludHMgdG8gc2NyZWVuLiAgDQojIFJFVFVSTiB1c2UgcmV0dXJuIHRvIGFjdHVsbHkgcmV0dXJuIGEgdmFsdWUuIA0KZGVmIG1haW4oKToNCiAgICB4ID0gaW50KGlucHV0KCJXaGF0J3MgeD8gIikpDQogICAgcHJpbnQoInggc3F1YXJlZCBpcyIsIHNxdWFyZSh4KSkNCg0KDQptYWluKCkNCg0KIyBuZWVkIHRvIGRlZmluZSBzcXVhcmUgdG8gY2FsbCBpdCBmb3IgYSByZXR1cm4gdmFsdWUgdG8gYW5vdGhlciBmdW50aW9uDQoNCiMgc286DQoNCmRlZiBtYWluKCk6DQogICAgeCA9IGludChpbnB1dCgiV2hhdCdzIHg/ICIpKQ0KICAgIHByaW50KCJ4IHNxdWFyZWQgaXMiLCBzcXVhcmUoeCkpDQoNCmRlZiBzcXVhcmUobik6DQogICAgcmV0dXJuIG4qbiANCiAgICAjIG9yICAgICByZXR1cm4gbiAqKiAyICAgICMgcmFpc2UgbiB0byB0aGUgcG93ZXIgb2YgMiAoIHR3byBhc3Rlcmlja3MgbWVhbnMgaXQgcmFpc2VzIHRoZSB0aGluZyBvbiB0aGUgbGVmdCB0byB0aGUgcG93ZXIgb2YgdGhlIHRoaW5nIG9uIHRoZSByaWdodCkNCiAgICAjIG9yICAgICByZXR1cm4gcG93KG4sIDIpICAgDQoNCiAgICAnJycNCiAgICBQT1cgZm9yIHJhaXNpbmcgc29tZXRoaW5nIHRvIHRoZSBwb3dlciB0aGF0DQogICAgdGFrZXMgdHdvIGFyZ3VtZW50cywgdGhlIGZpcnN0IG9mIHdoaWNoIGlzIHRoZSBudW1iZXIsIHRoZSBzZWNvbmQgb2Ygd2hpY2gNCiAgICBpcyB0aGUgZXhwb25lbnQuICANCiAgICAnJycnDQoNCg0KDQoNCg0KIA0KICAgICcnJw0KICAgIFdlJ3ZlIGRlZmluZWQgYSBmdW5jdGlvbiBjYWxsZWQgTWFpbiBhbmQgSSd2ZSBpbXBsZW1lbnRlZCB0d28gbGluZXMuDQogICAgVGhlIGZpcnN0IG9mIHRoZXNlIGxpbmVzIHByb21wdHMgdGhlIHVzZXIgZm9yIGEgdmFsdWUNCiAgICB4IGFuZCBjb252ZXJ0cyBpdCB0byBhbiBJTlQgYW5kIHN0b3JlcyBpdCBpbiBhIHZhcmlhYmxlIGNhbGxlZCB4Lg0KICAgIFNvIEkndmUgaW1wbGVtZW50ZWQgbXkgdmVyeSBvd24gZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBzcXVhcmUgb2YgYSB2YWx1ZQ0KICAgIGFuZCBiZWNhdXNlIEknbSB1c2luZyB0aGUgcmV0dXJuIGtleXdvcmQsIHRoYXQNCiAgICBlbnN1cmVzIHRoYXQgSSBjYW4gcGFzcyB0aGUgcmV0dXJuIHZhbHVlIG9mIHRoaXMsIGp1c3QNCiAgICBsaWtlIHRoZSByZXR1cm4gdmFsdWUgb2YgaW5wdXQgb3IgSU5UIG9yIGZsb2F0LCB0byBhbm90aGVyIGZ1bmN0aW9uLA0KICAgICcnJw0KbWFpbigpDQpgYGANCg0KW3JlZmVyZW5jZSAvIGNpdGVdKGNzNTAuaGFydmFyZC5lZHUpDQoNClNNVSBNU0RTIEJvb3RjYW1wIERlY2VtYmVyIDIwMjIgUHJvZmVzc29yOiBTY290dCBTYWVueiAsIFRBOiBTdGVwaGVuIFRhaGFuIERpcjogU2VhbiBGbGVtaW5nDQo=