Title: Python Step 2: Intermediate Basics for New Python Programmers

Author: Jessica McPhaul
Date: December 3, 2022
Output: HTML Notebook


Lesson Overview

This lesson will build on the fundamental concepts you learned in Step 1. It aims to introduce you to essential tools and practices for effective Python programming, including:

  1. Setting Up Visual Studio Code (VS Code)
  2. Basic Python Constructs: Variables, input/output, and operations.
  3. Working with Functions: Defining and calling reusable pieces of code.
  4. Using the Command Line: Navigating your system through VS Code.
  5. Advanced Concepts: Variable scope, side effects, and improving your understanding of code organization.

Python Step 2 Concepts and Code

1. Setting Up VS Code

VS Code is an Integrated Development Environment (IDE) that allows you to code, debug, and run your programs all in one place.

What is an IDE?
An IDE helps programmers write code by providing useful features such as: - Syntax Highlighting: Makes reading code easier. - Error Checking: Points out potential issues while typing. - Integrated Terminal: Allows running code directly.

Steps to Set Up VS Code: - Install VS Code: Go to https://code.visualstudio.com/ and download. - Install Python Extension: Search for “Python” in the Extensions Marketplace (icon on the left sidebar). - Create a Python File: Open VS Code, click “New File”, and save it with the .py extension (e.g., hello.py).

Example Code:

# hello.py
print("Hello, world!")  # This line prints text to the console

# To run this script, open the Terminal in VS Code and type:
# python hello.py

2. Basic Python Constructs

Now that you have VS Code set up, let’s revisit some basic constructs.

Variables, Input, and Output
  • Variables: Containers for storing values.
    • Example: age = 25 assigns the value 25 to age.
  • Input and Output:
    • input(): Gathers input from the user.
    • print(): Displays information to the screen.

Example Code:

# Getting the user's name and age
name = input("What's your name? ")  # Input is always a string
age = input("How old are you? ")  # Collecting age as a string

# Output using formatted strings (f-strings)
print(f"Hello, {name}! You are {age} years old.")
Data Types

Python has different types of data: - Strings (str): Textual data (e.g., "Hello") - Integers (int): Whole numbers (e.g., 25) - Floats (float): Decimal numbers (e.g., 3.14)

You can convert data types:

# Convert age to an integer to perform math operations
age = int(age)  # Now age is an integer
print(f"Next year, you'll be {age + 1} years old.")

3. Working with Functions

Functions help us organize code into reusable blocks.

Function Basics: - Use the def keyword to create a function. - Functions can accept parameters and return values.

Example Code:

# Defining a function that greets a user
def greet_user(name):
    """
    Greet the user with their name.
    :param name: str - The user's name
    :return: str - A personalized greeting
    """
    return f"Hello, {name}!"

# Call the function
user_name = input("Enter your name: ")
print(greet_user(user_name))

Why Use Functions? - Reusability: Write code once, use it multiple times. - Readability: Break down complex tasks into smaller, easier parts.

4. Using the Command Line in VS Code

The command line is a powerful way to interact with your computer. In VS Code, you can use the Terminal to execute commands.

Basic Commands to Know: - ls: Lists all files and folders in the current directory. - cd <directory>: Changes the current working directory. - mkdir <folder_name>: Creates a new folder. - rm <file_name>: Deletes a file. - clear: Clears the terminal output for a cleaner workspace.

Example Walkthrough: - Open VS Code’s terminal (usually accessible with Ctrl + `` or from the menu). - Typemkdir my_new_projectto create a new folder. - Usecd my_new_projectto navigate into your new folder. - Typetouch my_script.py(in Linux/macOS) orNew-Item -Path my_script.py -ItemType File` (in Windows) to create a Python file.

5. Advanced Concepts: Scope and Side Effects

Scope in Python

Scope refers to where a variable can be accessed or modified.

  • Local Scope: Variables defined inside a function only exist within that function.
  • Global Scope: Variables defined outside all functions can be accessed by any code in the file.

Example Code:

greeting = "Hello"  # This is a global variable

def greet():
    local_greeting = "Hi"  # This variable is local to the function
    print(local_greeting)

greet()  # Output: Hi
print(greeting)  # Output: Hello
# print(local_greeting)  # Error: local_greeting is not defined here
Side Effects in Functions

Side Effects occur when a function modifies something outside its scope.

Example Code with Side Effects:

# Global variable
mood = ":("

def change_mood(new_mood):
    global mood  # Declare that you are using the global variable
    mood = new_mood

change_mood(":D")  # Now the global `mood` variable is ":D"
print(f"The current mood is {mood}")  # Output: The current mood is :D

Using global variables should be done with caution as it can make code harder to debug.

Additional Practice: Create a Python Script

Now that you’ve learned these concepts, create a Python script that: - Takes the user’s name and favorite number. - Defines a function to calculate the square of that number. - Prints a personalized message using the user’s inputs.

Example Solution:

# Function to calculate the square of a number
def square_number(num):
    return num * num

# Collecting user information
name = input("What's your name? ")
fav_num = int(input("What's your favorite number? "))

# Outputting a personalized message
print(f"Hello, {name}! The square of your favorite number is {square_number(fav_num)}.")

Summary

In Python Step 2, you learned: 1. Setting Up VS Code: How to install and use it for Python development. 2. Basic Constructs: Variables, input/output, and basic operations. 3. Functions: Defining, calling, and understanding parameters and return values. 4. Command Line Basics: Navigating with commands like ls, cd, and mkdir. 5. Advanced Concepts: Local and global scope, and understanding side effects in functions.

Additional Resources


I’d like to make a lesson that feels like a tutor is talkiing directly to me. However my syntax will flip flop and not be consistent in narration audience. If you are reading this and you aren’t me. SOrry. (shrug) I want this to be super practical, hands-on, and easy to follow.


1. Basic Python Constructs: Variables, Input/Output, and Operations

1.1 Variables

Alright, so let’s start with the basics: variables. Imagine them as storage boxes. When I want to store something—like a name, a number, or even a list of things—I just put them in these “boxes” and give each box a name. That way, I know what’s inside.

Example:

name = "Jessica"    # String (text)
age = 25            # Integer (whole number)
height = 5.6        # Float (decimal number)

print(name)         # Outputs: Jessica
print(age)          # Outputs: 25
print(height)       # Outputs: 5.6

So, I just put "Jessica" in the box called name, and I can pull it out whenever I want by calling print(name).

1.2 Input and Output

Next up, input and output. This is just getting data from the user (input) and displaying it (output).

  • print() is like me shouting out what’s inside the box.
  • input() is me asking you for something, and what you give back goes right into a box.

Example:

# Getting input from the user
user_name = input("Enter your name: ")
print(f"Hello, {user_name}!")  # Uses an f-string to combine text and variables

With input(), I’m asking for your name. Whatever you type gets put in the box called user_name. Then, with print(), I use an f-string (which is just a fancy way to add variables to text) to say hello.

1.3 Basic Operations

You can also do math with variables. It’s like turning Python into a calculator.

Basic Math Operators are: - + for addition - - for subtraction - * for multiplication - / for division

Example:

# Simple calculator
x = 10
y = 5

print(x + y)  # Outputs: 15
print(x - y)  # Outputs: 5
print(x * y)  # Outputs: 50
print(x / y)  # Outputs: 2.0

I can use input() to get numbers and do calculations with them too:

num1 = int(input("Enter the first number: "))  # Convert input to an integer
num2 = int(input("Enter the second number: "))

result = num1 + num2
print(f"The sum of {num1} and {num2} is {result}")

Here, I used int() to convert the input from a string (text) to an integer (a whole number). That way, I can do math with it.

2. Working with Functions: Defining and Calling Reusable Code

Let’s talk about functions. Functions are one of my favorite things because they make my life easier. They’re like a recipe card: and I love cooking. I write the instructions once, and then every time I need that dish, I can just follow the same steps.

2.1 Defining Functions

To make a function, I use def, then give it a name, add parentheses, and a colon. Everything I want the function to do is indented below it.

Example:

def greet():
    print("Hello, world!")

# Calling the function
greet()  # Outputs: Hello, world!

So, here, greet() is my recipe card. Anytime I want to say “Hello, world!”, I just call greet().

2.2 Functions with Parameters

But what if I want to greet someone specific? That’s where parameters come in.

Example:

def greet_user(name):
    print(f"Hello, {name}!")

# Calling the function with an argument
greet_user("Jessica")  # Outputs: Hello, Jessica!

I’m passing in "Jessica" to the function, and it uses that to personalize the greeting.

2.3 Return Values

Sometimes, I need a function to give me back a result. For that, I use return.

Example:

def add_numbers(a, b):
    return a + b

# Calling the function and storing the result
sum_result = add_numbers(5, 10)
print(f"The sum is {sum_result}")  # Outputs: The sum is 15

The function add_numbers() adds two numbers and gives me the result with return. I then store that result in sum_result and print it.

3. Using the Command Line: Navigating in VS Code

Now let’s jump into using the command line. It’s basically a way to talk to your computer without clicking around. In VS Code, it’s super handy for running Python files, managing folders, etc.

3.1 Common Command Line Commands

  • ls: This lists everything in the current folder.
  • cd <directory>: This changes where you are in the computer’s file system.
  • mkdir <folder_name>: This creates a new folder.
  • rm <file_name>: This deletes a file.
  • clear: This clears out all the text in the terminal.

Example of Using the Terminal in VS Code: 1. Open Terminal: Use `Ctrl + `` (that’s the backtick under Esc). 2. Commands to Try: sh mkdir my_python_project # Create a new folder cd my_python_project # Move into that folder touch hello.py # Create a new Python file called 'hello.py' 3. To run my Python script: sh python hello.py And that’s how I run the code I’ve written in a terminal.

4. Advanced Concepts: Variable Scope, Side Effects, and Code Organization

4.1 Variable Scope

Scope is where my variables live and where they can be used.

  • Local Scope: Variables that I create inside a function. They can only be used within that function.
  • Global Scope: Variables I create outside of functions that can be used anywhere in the program.

Example:

greeting = "Hello"  # Global variable

def greet():
    local_greeting = "Hi"  # Local variable
    print(local_greeting)

greet()             # Outputs: Hi
print(greeting)     # Outputs: Hello
# print(local_greeting)  # This would cause an error because local_greeting only lives inside greet()

So, local_greeting only exists inside greet(). Outside of greet(), it’s gone.

4.2 Side Effects

Side Effects happen when I use a function that changes something outside its own scope. It’s like when I mess around with a global variable inside a function.

Example of a Side Effect:

mood = ":("  # Global variable representing a mood

def change_mood(new_mood):
    global mood  # I use 'global' to tell Python I’m changing the global variable
    mood = new_mood

change_mood(":D")  # I call the function to change the mood
print(f"The current mood is {mood}")  # Outputs: The current mood is :D

I have to be careful when doing this because changing global variables can lead to bugs that are hard to find.

4.3 Organizing Code with Functions

Functions really shine when I’m trying to keep my code organized. Instead of a huge mess of commands, I break things down into little steps (functions), making it easier to manage.

Example:

# Function to collect user details
def get_user_details():
    name = input("Enter your name: ")
    age = int(input("Enter your age: "))
    return name, age

# Function to display greeting
def display_greeting(name, age):
    print(f"Hello, {name}! You are {age} years old.")

# Main function to run the program
def main():
    user_name, user_age = get_user_details()
    display_greeting(user_name, user_age)

# Call the main function to start the program
main()

Breaking things down this way helps me keep my brain from getting overwhelmed, and I can focus on solving one part of the problem at a time.

Summary

In this lesson, I covered: 1. Basic Constructs: How to use variables, get input, display output, and do math. 2. Functions: How to write reusable blocks of code, use parameters, and get return values. 3. Command Line in VS Code: How to move around your files and run Python scripts. 4. Advanced Concepts: The idea of scope (local vs global), side effects, and keeping code organized with functions.

Practice Challenge

The goal is to be able to write python code without even thinking about it.

review and review and practice this lesson, implementing other tactics and comparing results. Finger muscle memory and habits need to be built. Keep at it. JESSICA YOU MUST FUCKING PRACTICE. JESSICA. KEEP AT IT. YOU WILL NEVER RELY ON ANYONE TO TAKE CARE OF YOU. IN ORDER TO BE SUCCESSFUL YOU MUST BE DRIVEN PRACTCE IS THE KEY TO MASTERING THIS SHIT! YOU CAN DO IT. THIS IS NOT JUST FOR YOU - ITS ALSO FOR YOUR KIDS. YOU NEED THIS. WE DON’T BREAK. WE ACCELARATE AND MOVE FORWARD ON A BETTER PATH THAN BEFORE. NOW TAKE 5 THEN DO THIS ALL AGAIN.

LS0tDQp0aXRsZTogIkludHJvIHRvIFB5dGhvbiAtIFN0ZXAgMiBSZXZpZXciDQphdXRob3I6ICJKZXNzaWNhIE1jUGhhdWwiDQpkYXRlOiAiNCBEZWNlbWJlciAyMDIyIg0KYm9vdGNhbXA6ICJTTVVEU0JDIC0gUHJvZmVzc29yOiBTY290dCBTYWVueiwgVEE6IFN0ZXBoZW4gVGFoYW4sIERpcjogU2VhbiBGbGVtaW5nIiANCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KDQojIyMgVGl0bGU6IFB5dGhvbiBTdGVwIDI6IEludGVybWVkaWF0ZSBCYXNpY3MgZm9yIE5ldyBQeXRob24gUHJvZ3JhbW1lcnMNCioqQXV0aG9yKio6IEplc3NpY2EgTWNQaGF1bCAgDQoqKkRhdGUqKjogRGVjZW1iZXIgMywgMjAyMiAgDQoqKk91dHB1dCoqOiBIVE1MIE5vdGVib29rICANCg0KLS0tDQoNCg0KDQojIyMjIExlc3NvbiBPdmVydmlldw0KVGhpcyBsZXNzb24gd2lsbCBidWlsZCBvbiB0aGUgZnVuZGFtZW50YWwgY29uY2VwdHMgeW91IGxlYXJuZWQgaW4gU3RlcCAxLiBJdCBhaW1zIHRvIGludHJvZHVjZSB5b3UgdG8gZXNzZW50aWFsIHRvb2xzIGFuZCBwcmFjdGljZXMgZm9yIGVmZmVjdGl2ZSBQeXRob24gcHJvZ3JhbW1pbmcsIGluY2x1ZGluZzoNCg0KMS4gKipTZXR0aW5nIFVwIFZpc3VhbCBTdHVkaW8gQ29kZSAoVlMgQ29kZSkqKg0KMi4gKipCYXNpYyBQeXRob24gQ29uc3RydWN0cyoqOiBWYXJpYWJsZXMsIGlucHV0L291dHB1dCwgYW5kIG9wZXJhdGlvbnMuDQozLiAqKldvcmtpbmcgd2l0aCBGdW5jdGlvbnMqKjogRGVmaW5pbmcgYW5kIGNhbGxpbmcgcmV1c2FibGUgcGllY2VzIG9mIGNvZGUuDQo0LiAqKlVzaW5nIHRoZSBDb21tYW5kIExpbmUqKjogTmF2aWdhdGluZyB5b3VyIHN5c3RlbSB0aHJvdWdoIFZTIENvZGUuDQo1LiAqKkFkdmFuY2VkIENvbmNlcHRzKio6IFZhcmlhYmxlIHNjb3BlLCBzaWRlIGVmZmVjdHMsIGFuZCBpbXByb3ZpbmcgeW91ciB1bmRlcnN0YW5kaW5nIG9mIGNvZGUgb3JnYW5pemF0aW9uLg0KDQotLS0NCg0KIyMjIFB5dGhvbiBTdGVwIDIgQ29uY2VwdHMgYW5kIENvZGUNCg0KIyMjIyAxLiAqKlNldHRpbmcgVXAgVlMgQ29kZSoqDQpWUyBDb2RlIGlzIGFuIEludGVncmF0ZWQgRGV2ZWxvcG1lbnQgRW52aXJvbm1lbnQgKElERSkgdGhhdCBhbGxvd3MgeW91IHRvIGNvZGUsIGRlYnVnLCBhbmQgcnVuIHlvdXIgcHJvZ3JhbXMgYWxsIGluIG9uZSBwbGFjZS4NCg0KKipXaGF0IGlzIGFuIElERT8qKiAgDQpBbiBJREUgaGVscHMgcHJvZ3JhbW1lcnMgd3JpdGUgY29kZSBieSBwcm92aWRpbmcgdXNlZnVsIGZlYXR1cmVzIHN1Y2ggYXM6DQotICoqU3ludGF4IEhpZ2hsaWdodGluZyoqOiBNYWtlcyByZWFkaW5nIGNvZGUgZWFzaWVyLg0KLSAqKkVycm9yIENoZWNraW5nKio6IFBvaW50cyBvdXQgcG90ZW50aWFsIGlzc3VlcyB3aGlsZSB0eXBpbmcuDQotICoqSW50ZWdyYXRlZCBUZXJtaW5hbCoqOiBBbGxvd3MgcnVubmluZyBjb2RlIGRpcmVjdGx5Lg0KDQoqKlN0ZXBzIHRvIFNldCBVcCBWUyBDb2RlOioqDQotICoqSW5zdGFsbCBWUyBDb2RlKio6IEdvIHRvIGh0dHBzOi8vY29kZS52aXN1YWxzdHVkaW8uY29tLyBhbmQgZG93bmxvYWQuDQotICoqSW5zdGFsbCBQeXRob24gRXh0ZW5zaW9uKio6IFNlYXJjaCBmb3IgIlB5dGhvbiIgaW4gdGhlIEV4dGVuc2lvbnMgTWFya2V0cGxhY2UgKGljb24gb24gdGhlIGxlZnQgc2lkZWJhcikuDQotICoqQ3JlYXRlIGEgUHl0aG9uIEZpbGUqKjogT3BlbiBWUyBDb2RlLCBjbGljayAiTmV3IEZpbGUiLCBhbmQgc2F2ZSBpdCB3aXRoIHRoZSBgLnB5YCBleHRlbnNpb24gKGUuZy4sIGBoZWxsby5weWApLg0KDQoqKkV4YW1wbGUgQ29kZToqKg0KYGBgcHl0aG9uDQojIGhlbGxvLnB5DQpwcmludCgiSGVsbG8sIHdvcmxkISIpICAjIFRoaXMgbGluZSBwcmludHMgdGV4dCB0byB0aGUgY29uc29sZQ0KDQojIFRvIHJ1biB0aGlzIHNjcmlwdCwgb3BlbiB0aGUgVGVybWluYWwgaW4gVlMgQ29kZSBhbmQgdHlwZToNCiMgcHl0aG9uIGhlbGxvLnB5DQpgYGANCg0KIyMjIyAyLiAqKkJhc2ljIFB5dGhvbiBDb25zdHJ1Y3RzKioNCk5vdyB0aGF0IHlvdSBoYXZlIFZTIENvZGUgc2V0IHVwLCBsZXQncyByZXZpc2l0IHNvbWUgYmFzaWMgY29uc3RydWN0cy4NCg0KIyMjIyMgVmFyaWFibGVzLCBJbnB1dCwgYW5kIE91dHB1dA0KLSAqKlZhcmlhYmxlcyoqOiBDb250YWluZXJzIGZvciBzdG9yaW5nIHZhbHVlcy4NCiAgLSBFeGFtcGxlOiBgYWdlID0gMjVgIGFzc2lnbnMgdGhlIHZhbHVlIGAyNWAgdG8gYGFnZWAuDQotICoqSW5wdXQgYW5kIE91dHB1dCoqOg0KICAtICoqYGlucHV0KClgKio6IEdhdGhlcnMgaW5wdXQgZnJvbSB0aGUgdXNlci4NCiAgLSAqKmBwcmludCgpYCoqOiBEaXNwbGF5cyBpbmZvcm1hdGlvbiB0byB0aGUgc2NyZWVuLg0KDQoqKkV4YW1wbGUgQ29kZToqKg0KYGBgcHl0aG9uDQojIEdldHRpbmcgdGhlIHVzZXIncyBuYW1lIGFuZCBhZ2UNCm5hbWUgPSBpbnB1dCgiV2hhdCdzIHlvdXIgbmFtZT8gIikgICMgSW5wdXQgaXMgYWx3YXlzIGEgc3RyaW5nDQphZ2UgPSBpbnB1dCgiSG93IG9sZCBhcmUgeW91PyAiKSAgIyBDb2xsZWN0aW5nIGFnZSBhcyBhIHN0cmluZw0KDQojIE91dHB1dCB1c2luZyBmb3JtYXR0ZWQgc3RyaW5ncyAoZi1zdHJpbmdzKQ0KcHJpbnQoZiJIZWxsbywge25hbWV9ISBZb3UgYXJlIHthZ2V9IHllYXJzIG9sZC4iKQ0KYGBgDQoNCiMjIyMjIERhdGEgVHlwZXMNClB5dGhvbiBoYXMgZGlmZmVyZW50IHR5cGVzIG9mIGRhdGE6DQotICoqU3RyaW5ncyoqIChgc3RyYCk6IFRleHR1YWwgZGF0YSAoZS5nLiwgYCJIZWxsbyJgKQ0KLSAqKkludGVnZXJzKiogKGBpbnRgKTogV2hvbGUgbnVtYmVycyAoZS5nLiwgYDI1YCkNCi0gKipGbG9hdHMqKiAoYGZsb2F0YCk6IERlY2ltYWwgbnVtYmVycyAoZS5nLiwgYDMuMTRgKQ0KDQpZb3UgY2FuIGNvbnZlcnQgZGF0YSB0eXBlczoNCmBgYHB5dGhvbg0KIyBDb252ZXJ0IGFnZSB0byBhbiBpbnRlZ2VyIHRvIHBlcmZvcm0gbWF0aCBvcGVyYXRpb25zDQphZ2UgPSBpbnQoYWdlKSAgIyBOb3cgYWdlIGlzIGFuIGludGVnZXINCnByaW50KGYiTmV4dCB5ZWFyLCB5b3UnbGwgYmUge2FnZSArIDF9IHllYXJzIG9sZC4iKQ0KYGBgDQoNCiMjIyMgMy4gKipXb3JraW5nIHdpdGggRnVuY3Rpb25zKioNCkZ1bmN0aW9ucyBoZWxwIHVzIG9yZ2FuaXplIGNvZGUgaW50byByZXVzYWJsZSBibG9ja3MuDQoNCioqRnVuY3Rpb24gQmFzaWNzOioqDQotIFVzZSB0aGUgYGRlZmAga2V5d29yZCB0byBjcmVhdGUgYSBmdW5jdGlvbi4NCi0gRnVuY3Rpb25zIGNhbiBhY2NlcHQgKipwYXJhbWV0ZXJzKiogYW5kIHJldHVybiAqKnZhbHVlcyoqLg0KDQoqKkV4YW1wbGUgQ29kZToqKg0KYGBgcHl0aG9uDQojIERlZmluaW5nIGEgZnVuY3Rpb24gdGhhdCBncmVldHMgYSB1c2VyDQpkZWYgZ3JlZXRfdXNlcihuYW1lKToNCiAgICAiIiINCiAgICBHcmVldCB0aGUgdXNlciB3aXRoIHRoZWlyIG5hbWUuDQogICAgOnBhcmFtIG5hbWU6IHN0ciAtIFRoZSB1c2VyJ3MgbmFtZQ0KICAgIDpyZXR1cm46IHN0ciAtIEEgcGVyc29uYWxpemVkIGdyZWV0aW5nDQogICAgIiIiDQogICAgcmV0dXJuIGYiSGVsbG8sIHtuYW1lfSEiDQoNCiMgQ2FsbCB0aGUgZnVuY3Rpb24NCnVzZXJfbmFtZSA9IGlucHV0KCJFbnRlciB5b3VyIG5hbWU6ICIpDQpwcmludChncmVldF91c2VyKHVzZXJfbmFtZSkpDQpgYGANCg0KKipXaHkgVXNlIEZ1bmN0aW9ucz8qKg0KLSAqKlJldXNhYmlsaXR5Kio6IFdyaXRlIGNvZGUgb25jZSwgdXNlIGl0IG11bHRpcGxlIHRpbWVzLg0KLSAqKlJlYWRhYmlsaXR5Kio6IEJyZWFrIGRvd24gY29tcGxleCB0YXNrcyBpbnRvIHNtYWxsZXIsIGVhc2llciBwYXJ0cy4NCg0KIyMjIyA0LiAqKlVzaW5nIHRoZSBDb21tYW5kIExpbmUgaW4gVlMgQ29kZSoqDQpUaGUgKipjb21tYW5kIGxpbmUqKiBpcyBhIHBvd2VyZnVsIHdheSB0byBpbnRlcmFjdCB3aXRoIHlvdXIgY29tcHV0ZXIuIEluIFZTIENvZGUsIHlvdSBjYW4gdXNlIHRoZSAqKlRlcm1pbmFsKiogdG8gZXhlY3V0ZSBjb21tYW5kcy4NCg0KKipCYXNpYyBDb21tYW5kcyB0byBLbm93OioqDQotICoqYGxzYCoqOiBMaXN0cyBhbGwgZmlsZXMgYW5kIGZvbGRlcnMgaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5Lg0KLSAqKmBjZCA8ZGlyZWN0b3J5PmAqKjogQ2hhbmdlcyB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4NCi0gKipgbWtkaXIgPGZvbGRlcl9uYW1lPmAqKjogQ3JlYXRlcyBhIG5ldyBmb2xkZXIuDQotICoqYHJtIDxmaWxlX25hbWU+YCoqOiBEZWxldGVzIGEgZmlsZS4NCi0gKipgY2xlYXJgKio6IENsZWFycyB0aGUgdGVybWluYWwgb3V0cHV0IGZvciBhIGNsZWFuZXIgd29ya3NwYWNlLg0KDQoqKkV4YW1wbGUgV2Fsa3Rocm91Z2g6KioNCi0gT3BlbiBWUyBDb2RlJ3MgdGVybWluYWwgKHVzdWFsbHkgYWNjZXNzaWJsZSB3aXRoIGBDdHJsICsgYGAgb3IgZnJvbSB0aGUgbWVudSkuDQotIFR5cGUgYG1rZGlyIG15X25ld19wcm9qZWN0YCB0byBjcmVhdGUgYSBuZXcgZm9sZGVyLg0KLSBVc2UgYGNkIG15X25ld19wcm9qZWN0YCB0byBuYXZpZ2F0ZSBpbnRvIHlvdXIgbmV3IGZvbGRlci4NCi0gVHlwZSBgdG91Y2ggbXlfc2NyaXB0LnB5YCAoaW4gTGludXgvbWFjT1MpIG9yIGBOZXctSXRlbSAtUGF0aCBteV9zY3JpcHQucHkgLUl0ZW1UeXBlIEZpbGVgIChpbiBXaW5kb3dzKSB0byBjcmVhdGUgYSBQeXRob24gZmlsZS4NCg0KIyMjIyA1LiAqKkFkdmFuY2VkIENvbmNlcHRzOiBTY29wZSBhbmQgU2lkZSBFZmZlY3RzKioNCg0KIyMjIyMgU2NvcGUgaW4gUHl0aG9uDQoqKlNjb3BlKiogcmVmZXJzIHRvIHdoZXJlIGEgdmFyaWFibGUgY2FuIGJlIGFjY2Vzc2VkIG9yIG1vZGlmaWVkLg0KDQotICoqTG9jYWwgU2NvcGUqKjogVmFyaWFibGVzIGRlZmluZWQgaW5zaWRlIGEgZnVuY3Rpb24gb25seSBleGlzdCB3aXRoaW4gdGhhdCBmdW5jdGlvbi4NCi0gKipHbG9iYWwgU2NvcGUqKjogVmFyaWFibGVzIGRlZmluZWQgb3V0c2lkZSBhbGwgZnVuY3Rpb25zIGNhbiBiZSBhY2Nlc3NlZCBieSBhbnkgY29kZSBpbiB0aGUgZmlsZS4NCg0KKipFeGFtcGxlIENvZGU6KioNCmBgYHB5dGhvbg0KZ3JlZXRpbmcgPSAiSGVsbG8iICAjIFRoaXMgaXMgYSBnbG9iYWwgdmFyaWFibGUNCg0KZGVmIGdyZWV0KCk6DQogICAgbG9jYWxfZ3JlZXRpbmcgPSAiSGkiICAjIFRoaXMgdmFyaWFibGUgaXMgbG9jYWwgdG8gdGhlIGZ1bmN0aW9uDQogICAgcHJpbnQobG9jYWxfZ3JlZXRpbmcpDQoNCmdyZWV0KCkgICMgT3V0cHV0OiBIaQ0KcHJpbnQoZ3JlZXRpbmcpICAjIE91dHB1dDogSGVsbG8NCiMgcHJpbnQobG9jYWxfZ3JlZXRpbmcpICAjIEVycm9yOiBsb2NhbF9ncmVldGluZyBpcyBub3QgZGVmaW5lZCBoZXJlDQpgYGANCg0KIyMjIyMgU2lkZSBFZmZlY3RzIGluIEZ1bmN0aW9ucw0KKipTaWRlIEVmZmVjdHMqKiBvY2N1ciB3aGVuIGEgZnVuY3Rpb24gbW9kaWZpZXMgc29tZXRoaW5nIG91dHNpZGUgaXRzIHNjb3BlLg0KDQoqKkV4YW1wbGUgQ29kZSB3aXRoIFNpZGUgRWZmZWN0czoqKg0KYGBgcHl0aG9uDQojIEdsb2JhbCB2YXJpYWJsZQ0KbW9vZCA9ICI6KCINCg0KZGVmIGNoYW5nZV9tb29kKG5ld19tb29kKToNCiAgICBnbG9iYWwgbW9vZCAgIyBEZWNsYXJlIHRoYXQgeW91IGFyZSB1c2luZyB0aGUgZ2xvYmFsIHZhcmlhYmxlDQogICAgbW9vZCA9IG5ld19tb29kDQoNCmNoYW5nZV9tb29kKCI6RCIpICAjIE5vdyB0aGUgZ2xvYmFsIGBtb29kYCB2YXJpYWJsZSBpcyAiOkQiDQpwcmludChmIlRoZSBjdXJyZW50IG1vb2QgaXMge21vb2R9IikgICMgT3V0cHV0OiBUaGUgY3VycmVudCBtb29kIGlzIDpEDQpgYGANCg0KVXNpbmcgKipnbG9iYWwqKiB2YXJpYWJsZXMgc2hvdWxkIGJlIGRvbmUgd2l0aCBjYXV0aW9uIGFzIGl0IGNhbiBtYWtlIGNvZGUgaGFyZGVyIHRvIGRlYnVnLg0KDQojIyMjIEFkZGl0aW9uYWwgUHJhY3RpY2U6IENyZWF0ZSBhIFB5dGhvbiBTY3JpcHQNCk5vdyB0aGF0IHlvdeKAmXZlIGxlYXJuZWQgdGhlc2UgY29uY2VwdHMsIGNyZWF0ZSBhIFB5dGhvbiBzY3JpcHQgdGhhdDoNCi0gVGFrZXMgdGhlIHVzZXIncyBuYW1lIGFuZCBmYXZvcml0ZSBudW1iZXIuDQotIERlZmluZXMgYSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlICoqc3F1YXJlKiogb2YgdGhhdCBudW1iZXIuDQotIFByaW50cyBhIHBlcnNvbmFsaXplZCBtZXNzYWdlIHVzaW5nIHRoZSB1c2VyJ3MgaW5wdXRzLg0KDQoqKkV4YW1wbGUgU29sdXRpb246KioNCmBgYHB5dGhvbg0KIyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIHNxdWFyZSBvZiBhIG51bWJlcg0KZGVmIHNxdWFyZV9udW1iZXIobnVtKToNCiAgICByZXR1cm4gbnVtICogbnVtDQoNCiMgQ29sbGVjdGluZyB1c2VyIGluZm9ybWF0aW9uDQpuYW1lID0gaW5wdXQoIldoYXQncyB5b3VyIG5hbWU/ICIpDQpmYXZfbnVtID0gaW50KGlucHV0KCJXaGF0J3MgeW91ciBmYXZvcml0ZSBudW1iZXI/ICIpKQ0KDQojIE91dHB1dHRpbmcgYSBwZXJzb25hbGl6ZWQgbWVzc2FnZQ0KcHJpbnQoZiJIZWxsbywge25hbWV9ISBUaGUgc3F1YXJlIG9mIHlvdXIgZmF2b3JpdGUgbnVtYmVyIGlzIHtzcXVhcmVfbnVtYmVyKGZhdl9udW0pfS4iKQ0KYGBgDQoNCiMjIyMgU3VtbWFyeQ0KSW4gKipQeXRob24gU3RlcCAyKiosIHlvdSBsZWFybmVkOg0KMS4gKipTZXR0aW5nIFVwIFZTIENvZGUqKjogSG93IHRvIGluc3RhbGwgYW5kIHVzZSBpdCBmb3IgUHl0aG9uIGRldmVsb3BtZW50Lg0KMi4gKipCYXNpYyBDb25zdHJ1Y3RzKio6IFZhcmlhYmxlcywgaW5wdXQvb3V0cHV0LCBhbmQgYmFzaWMgb3BlcmF0aW9ucy4NCjMuICoqRnVuY3Rpb25zKio6IERlZmluaW5nLCBjYWxsaW5nLCBhbmQgdW5kZXJzdGFuZGluZyBwYXJhbWV0ZXJzIGFuZCByZXR1cm4gdmFsdWVzLg0KNC4gKipDb21tYW5kIExpbmUgQmFzaWNzKio6IE5hdmlnYXRpbmcgd2l0aCBjb21tYW5kcyBsaWtlIGBsc2AsIGBjZGAsIGFuZCBgbWtkaXJgLg0KNS4gKipBZHZhbmNlZCBDb25jZXB0cyoqOiBMb2NhbCBhbmQgZ2xvYmFsIHNjb3BlLCBhbmQgdW5kZXJzdGFuZGluZyBzaWRlIGVmZmVjdHMgaW4gZnVuY3Rpb25zLg0KDQojIyMjIEFkZGl0aW9uYWwgUmVzb3VyY2VzDQotICoqUHl0aG9uIERvY3VtZW50YXRpb24qKjogaHR0cHM6Ly9kb2NzLnB5dGhvbi5vcmcvMy8NCi0gKipWUyBDb2RlIERvY3VtZW50YXRpb24qKjogaHR0cHM6Ly9jb2RlLnZpc3VhbHN0dWRpby5jb20vZG9jcw0KLSAqKkNTNTAgUHl0aG9uIENvdXJzZSoqOiBodHRwczovL2NzNTAuaGFydmFyZC5lZHUvcHl0aG9uLw0KDQotLS0NCg0KIEknZCBsaWtlIHRvIG1ha2UgYSBsZXNzb24gdGhhdCBmZWVscyBsaWtlIGEgdHV0b3IgaXMgdGFsa2lpbmcgZGlyZWN0bHkgdG8gbWUuICBIb3dldmVyIG15IHN5bnRheCB3aWxsIGZsaXAgZmxvcCBhbmQgbm90IGJlIGNvbnNpc3RlbnQgaW4gbmFycmF0aW9uIGF1ZGllbmNlLiAgSWYgeW91IGFyZSByZWFkaW5nIHRoaXMgYW5kIHlvdSBhcmVuJ3QgbWUuICBTT3JyeS4gIChzaHJ1ZykgICBJIHdhbnQgdGhpcyB0byBiZSBzdXBlciBwcmFjdGljYWwsIGhhbmRzLW9uLCBhbmQgZWFzeSB0byBmb2xsb3cuDQoNCi0tLQ0KDQojIyMgMS4gQmFzaWMgUHl0aG9uIENvbnN0cnVjdHM6IFZhcmlhYmxlcywgSW5wdXQvT3V0cHV0LCBhbmQgT3BlcmF0aW9ucw0KDQojIyMjICoqMS4xIFZhcmlhYmxlcyoqDQpBbHJpZ2h0LCBzbyBsZXTigJlzIHN0YXJ0IHdpdGggdGhlIGJhc2ljczogdmFyaWFibGVzLiBJbWFnaW5lIHRoZW0gYXMgc3RvcmFnZSBib3hlcy4gV2hlbiBJIHdhbnQgdG8gc3RvcmUgc29tZXRoaW5n4oCUbGlrZSBhIG5hbWUsIGEgbnVtYmVyLCBvciBldmVuIGEgbGlzdCBvZiB0aGluZ3PigJRJIGp1c3QgcHV0IHRoZW0gaW4gdGhlc2UgImJveGVzIiBhbmQgZ2l2ZSBlYWNoIGJveCBhIG5hbWUuIFRoYXQgd2F5LCBJIGtub3cgd2hhdCdzIGluc2lkZS4NCg0KKipFeGFtcGxlOioqDQpgYGBweXRob24NCm5hbWUgPSAiSmVzc2ljYSIgICAgIyBTdHJpbmcgKHRleHQpDQphZ2UgPSAyNSAgICAgICAgICAgICMgSW50ZWdlciAod2hvbGUgbnVtYmVyKQ0KaGVpZ2h0ID0gNS42ICAgICAgICAjIEZsb2F0IChkZWNpbWFsIG51bWJlcikNCg0KcHJpbnQobmFtZSkgICAgICAgICAjIE91dHB1dHM6IEplc3NpY2ENCnByaW50KGFnZSkgICAgICAgICAgIyBPdXRwdXRzOiAyNQ0KcHJpbnQoaGVpZ2h0KSAgICAgICAjIE91dHB1dHM6IDUuNg0KYGBgDQpTbywgSSBqdXN0IHB1dCBgIkplc3NpY2EiYCBpbiB0aGUgYm94IGNhbGxlZCBgbmFtZWAsIGFuZCBJIGNhbiBwdWxsIGl0IG91dCB3aGVuZXZlciBJIHdhbnQgYnkgY2FsbGluZyBgcHJpbnQobmFtZSlgLg0KDQojIyMjICoqMS4yIElucHV0IGFuZCBPdXRwdXQqKg0KTmV4dCB1cCwgaW5wdXQgYW5kIG91dHB1dC4gVGhpcyBpcyBqdXN0IGdldHRpbmcgZGF0YSBmcm9tIHRoZSB1c2VyIChpbnB1dCkgYW5kIGRpc3BsYXlpbmcgaXQgKG91dHB1dCkuDQoNCi0gKipgcHJpbnQoKWAqKiBpcyBsaWtlIG1lIHNob3V0aW5nIG91dCB3aGF04oCZcyBpbnNpZGUgdGhlIGJveC4NCi0gKipgaW5wdXQoKWAqKiBpcyBtZSBhc2tpbmcgeW91IGZvciBzb21ldGhpbmcsIGFuZCB3aGF0IHlvdSBnaXZlIGJhY2sgZ29lcyByaWdodCBpbnRvIGEgYm94Lg0KDQoqKkV4YW1wbGU6KioNCmBgYHB5dGhvbg0KIyBHZXR0aW5nIGlucHV0IGZyb20gdGhlIHVzZXINCnVzZXJfbmFtZSA9IGlucHV0KCJFbnRlciB5b3VyIG5hbWU6ICIpDQpwcmludChmIkhlbGxvLCB7dXNlcl9uYW1lfSEiKSAgIyBVc2VzIGFuIGYtc3RyaW5nIHRvIGNvbWJpbmUgdGV4dCBhbmQgdmFyaWFibGVzDQpgYGANCldpdGggYGlucHV0KClgLCBJ4oCZbSBhc2tpbmcgZm9yIHlvdXIgbmFtZS4gV2hhdGV2ZXIgeW91IHR5cGUgZ2V0cyBwdXQgaW4gdGhlIGJveCBjYWxsZWQgYHVzZXJfbmFtZWAuIFRoZW4sIHdpdGggYHByaW50KClgLCBJIHVzZSBhbiAqKmYtc3RyaW5nKiogKHdoaWNoIGlzIGp1c3QgYSBmYW5jeSB3YXkgdG8gYWRkIHZhcmlhYmxlcyB0byB0ZXh0KSB0byBzYXkgaGVsbG8uDQoNCiMjIyMgKioxLjMgQmFzaWMgT3BlcmF0aW9ucyoqDQpZb3UgY2FuIGFsc28gZG8gbWF0aCB3aXRoIHZhcmlhYmxlcy4gSXTigJlzIGxpa2UgdHVybmluZyBQeXRob24gaW50byBhIGNhbGN1bGF0b3IuDQoNCioqQmFzaWMgTWF0aCBPcGVyYXRvcnMqKiBhcmU6DQotICoqYCtgKiogZm9yIGFkZGl0aW9uDQotICoqYC1gKiogZm9yIHN1YnRyYWN0aW9uDQotICoqYCpgKiogZm9yIG11bHRpcGxpY2F0aW9uDQotICoqYC9gKiogZm9yIGRpdmlzaW9uDQoNCioqRXhhbXBsZToqKg0KYGBgcHl0aG9uDQojIFNpbXBsZSBjYWxjdWxhdG9yDQp4ID0gMTANCnkgPSA1DQoNCnByaW50KHggKyB5KSAgIyBPdXRwdXRzOiAxNQ0KcHJpbnQoeCAtIHkpICAjIE91dHB1dHM6IDUNCnByaW50KHggKiB5KSAgIyBPdXRwdXRzOiA1MA0KcHJpbnQoeCAvIHkpICAjIE91dHB1dHM6IDIuMA0KYGBgDQpJIGNhbiB1c2UgYGlucHV0KClgIHRvIGdldCBudW1iZXJzIGFuZCBkbyBjYWxjdWxhdGlvbnMgd2l0aCB0aGVtIHRvbzoNCg0KYGBgcHl0aG9uDQpudW0xID0gaW50KGlucHV0KCJFbnRlciB0aGUgZmlyc3QgbnVtYmVyOiAiKSkgICMgQ29udmVydCBpbnB1dCB0byBhbiBpbnRlZ2VyDQpudW0yID0gaW50KGlucHV0KCJFbnRlciB0aGUgc2Vjb25kIG51bWJlcjogIikpDQoNCnJlc3VsdCA9IG51bTEgKyBudW0yDQpwcmludChmIlRoZSBzdW0gb2Yge251bTF9IGFuZCB7bnVtMn0gaXMge3Jlc3VsdH0iKQ0KYGBgDQpIZXJlLCBJIHVzZWQgYGludCgpYCB0byBjb252ZXJ0IHRoZSBpbnB1dCBmcm9tIGEgc3RyaW5nICh0ZXh0KSB0byBhbiBpbnRlZ2VyIChhIHdob2xlIG51bWJlcikuIFRoYXQgd2F5LCBJIGNhbiBkbyBtYXRoIHdpdGggaXQuDQoNCiMjIyAyLiBXb3JraW5nIHdpdGggRnVuY3Rpb25zOiBEZWZpbmluZyBhbmQgQ2FsbGluZyBSZXVzYWJsZSBDb2RlDQoNCkxldOKAmXMgdGFsayBhYm91dCAqKmZ1bmN0aW9ucyoqLiBGdW5jdGlvbnMgYXJlIG9uZSBvZiBteSBmYXZvcml0ZSB0aGluZ3MgYmVjYXVzZSB0aGV5IG1ha2UgbXkgbGlmZSBlYXNpZXIuIFRoZXnigJlyZSBsaWtlIGEgcmVjaXBlIGNhcmQ6IGFuZCBJIGxvdmUgY29va2luZy4gSSAgd3JpdGUgdGhlIGluc3RydWN0aW9ucyBvbmNlLCBhbmQgdGhlbiBldmVyeSB0aW1lIEkgbmVlZCB0aGF0IGRpc2gsIEkgY2FuIGp1c3QgZm9sbG93IHRoZSBzYW1lIHN0ZXBzLg0KDQojIyMjICoqMi4xIERlZmluaW5nIEZ1bmN0aW9ucyoqDQpUbyBtYWtlIGEgZnVuY3Rpb24sIEkgdXNlIGBkZWZgLCB0aGVuIGdpdmUgaXQgYSBuYW1lLCBhZGQgcGFyZW50aGVzZXMsIGFuZCBhIGNvbG9uLiBFdmVyeXRoaW5nIEkgd2FudCB0aGUgZnVuY3Rpb24gdG8gZG8gaXMgaW5kZW50ZWQgYmVsb3cgaXQuDQoNCioqRXhhbXBsZToqKg0KYGBgcHl0aG9uDQpkZWYgZ3JlZXQoKToNCiAgICBwcmludCgiSGVsbG8sIHdvcmxkISIpDQoNCiMgQ2FsbGluZyB0aGUgZnVuY3Rpb24NCmdyZWV0KCkgICMgT3V0cHV0czogSGVsbG8sIHdvcmxkIQ0KYGBgDQpTbywgaGVyZSwgYGdyZWV0KClgIGlzIG15IHJlY2lwZSBjYXJkLiBBbnl0aW1lIEkgd2FudCB0byBzYXkgIkhlbGxvLCB3b3JsZCEiLCBJIGp1c3QgY2FsbCBgZ3JlZXQoKWAuDQoNCiMjIyMgKioyLjIgRnVuY3Rpb25zIHdpdGggUGFyYW1ldGVycyoqDQpCdXQgd2hhdCBpZiBJIHdhbnQgdG8gZ3JlZXQgc29tZW9uZSBzcGVjaWZpYz8gVGhhdOKAmXMgd2hlcmUgKipwYXJhbWV0ZXJzKiogY29tZSBpbi4NCg0KKipFeGFtcGxlOioqDQpgYGBweXRob24NCmRlZiBncmVldF91c2VyKG5hbWUpOg0KICAgIHByaW50KGYiSGVsbG8sIHtuYW1lfSEiKQ0KDQojIENhbGxpbmcgdGhlIGZ1bmN0aW9uIHdpdGggYW4gYXJndW1lbnQNCmdyZWV0X3VzZXIoIkplc3NpY2EiKSAgIyBPdXRwdXRzOiBIZWxsbywgSmVzc2ljYSENCmBgYA0KSeKAmW0gcGFzc2luZyBpbiBgIkplc3NpY2EiYCB0byB0aGUgZnVuY3Rpb24sIGFuZCBpdCB1c2VzIHRoYXQgdG8gcGVyc29uYWxpemUgdGhlIGdyZWV0aW5nLg0KDQojIyMjICoqMi4zIFJldHVybiBWYWx1ZXMqKg0KU29tZXRpbWVzLCBJIG5lZWQgYSBmdW5jdGlvbiB0byBnaXZlIG1lIGJhY2sgYSByZXN1bHQuIEZvciB0aGF0LCBJIHVzZSAqKnJldHVybioqLg0KDQoqKkV4YW1wbGU6KioNCmBgYHB5dGhvbg0KZGVmIGFkZF9udW1iZXJzKGEsIGIpOg0KICAgIHJldHVybiBhICsgYg0KDQojIENhbGxpbmcgdGhlIGZ1bmN0aW9uIGFuZCBzdG9yaW5nIHRoZSByZXN1bHQNCnN1bV9yZXN1bHQgPSBhZGRfbnVtYmVycyg1LCAxMCkNCnByaW50KGYiVGhlIHN1bSBpcyB7c3VtX3Jlc3VsdH0iKSAgIyBPdXRwdXRzOiBUaGUgc3VtIGlzIDE1DQpgYGANClRoZSBmdW5jdGlvbiBgYWRkX251bWJlcnMoKWAgYWRkcyB0d28gbnVtYmVycyBhbmQgZ2l2ZXMgbWUgdGhlIHJlc3VsdCB3aXRoIGByZXR1cm5gLiBJIHRoZW4gc3RvcmUgdGhhdCByZXN1bHQgaW4gYHN1bV9yZXN1bHRgIGFuZCBwcmludCBpdC4NCg0KIyMjIDMuIFVzaW5nIHRoZSBDb21tYW5kIExpbmU6IE5hdmlnYXRpbmcgaW4gVlMgQ29kZQ0KDQpOb3cgbGV04oCZcyBqdW1wIGludG8gdXNpbmcgdGhlICoqY29tbWFuZCBsaW5lKiouIEl04oCZcyBiYXNpY2FsbHkgYSB3YXkgdG8gdGFsayB0byB5b3VyIGNvbXB1dGVyIHdpdGhvdXQgY2xpY2tpbmcgYXJvdW5kLiBJbiAqKlZTIENvZGUqKiwgaXTigJlzIHN1cGVyIGhhbmR5IGZvciBydW5uaW5nIFB5dGhvbiBmaWxlcywgbWFuYWdpbmcgZm9sZGVycywgZXRjLg0KDQojIyMjICoqMy4xIENvbW1vbiBDb21tYW5kIExpbmUgQ29tbWFuZHMqKg0KLSAqKmBsc2AqKjogVGhpcyBsaXN0cyBldmVyeXRoaW5nIGluIHRoZSBjdXJyZW50IGZvbGRlci4NCi0gKipgY2QgPGRpcmVjdG9yeT5gKio6IFRoaXMgY2hhbmdlcyB3aGVyZSB5b3UgYXJlIGluIHRoZSBjb21wdXRlcuKAmXMgZmlsZSBzeXN0ZW0uDQotICoqYG1rZGlyIDxmb2xkZXJfbmFtZT5gKio6IFRoaXMgY3JlYXRlcyBhIG5ldyBmb2xkZXIuDQotICoqYHJtIDxmaWxlX25hbWU+YCoqOiBUaGlzIGRlbGV0ZXMgYSBmaWxlLg0KLSAqKmBjbGVhcmAqKjogVGhpcyBjbGVhcnMgb3V0IGFsbCB0aGUgdGV4dCBpbiB0aGUgdGVybWluYWwuDQoNCioqRXhhbXBsZSBvZiBVc2luZyB0aGUgVGVybWluYWwgaW4gVlMgQ29kZSoqOg0KMS4gKipPcGVuIFRlcm1pbmFsKio6IFVzZSBgQ3RybCArIGBgICh0aGF04oCZcyB0aGUgYmFja3RpY2sgdW5kZXIgRXNjKS4NCjIuICoqQ29tbWFuZHMgdG8gVHJ5Kio6DQogICBgYGBzaA0KICAgbWtkaXIgbXlfcHl0aG9uX3Byb2plY3QgICAjIENyZWF0ZSBhIG5ldyBmb2xkZXINCiAgIGNkIG15X3B5dGhvbl9wcm9qZWN0ICAgICAgIyBNb3ZlIGludG8gdGhhdCBmb2xkZXINCiAgIHRvdWNoIGhlbGxvLnB5ICAgICAgICAgICAgIyBDcmVhdGUgYSBuZXcgUHl0aG9uIGZpbGUgY2FsbGVkICdoZWxsby5weScNCiAgIGBgYA0KMy4gVG8gcnVuIG15IFB5dGhvbiBzY3JpcHQ6DQogICBgYGBzaA0KICAgcHl0aG9uIGhlbGxvLnB5DQogICBgYGANCiAgIEFuZCB0aGF04oCZcyBob3cgSSBydW4gdGhlIGNvZGUgSeKAmXZlIHdyaXR0ZW4gaW4gYSB0ZXJtaW5hbC4NCg0KIyMjIDQuIEFkdmFuY2VkIENvbmNlcHRzOiBWYXJpYWJsZSBTY29wZSwgU2lkZSBFZmZlY3RzLCBhbmQgQ29kZSBPcmdhbml6YXRpb24NCg0KIyMjIyAqKjQuMSBWYXJpYWJsZSBTY29wZSoqDQoqKlNjb3BlKiogaXMgd2hlcmUgbXkgdmFyaWFibGVzIGxpdmUgYW5kIHdoZXJlIHRoZXkgY2FuIGJlIHVzZWQuDQoNCi0gKipMb2NhbCBTY29wZSoqOiBWYXJpYWJsZXMgdGhhdCBJIGNyZWF0ZSBpbnNpZGUgYSBmdW5jdGlvbi4gVGhleSBjYW4gb25seSBiZSB1c2VkIHdpdGhpbiB0aGF0IGZ1bmN0aW9uLg0KLSAqKkdsb2JhbCBTY29wZSoqOiBWYXJpYWJsZXMgSSBjcmVhdGUgb3V0c2lkZSBvZiBmdW5jdGlvbnMgdGhhdCBjYW4gYmUgdXNlZCBhbnl3aGVyZSBpbiB0aGUgcHJvZ3JhbS4NCg0KKipFeGFtcGxlKio6DQpgYGBweXRob24NCmdyZWV0aW5nID0gIkhlbGxvIiAgIyBHbG9iYWwgdmFyaWFibGUNCg0KZGVmIGdyZWV0KCk6DQogICAgbG9jYWxfZ3JlZXRpbmcgPSAiSGkiICAjIExvY2FsIHZhcmlhYmxlDQogICAgcHJpbnQobG9jYWxfZ3JlZXRpbmcpDQoNCmdyZWV0KCkgICAgICAgICAgICAgIyBPdXRwdXRzOiBIaQ0KcHJpbnQoZ3JlZXRpbmcpICAgICAjIE91dHB1dHM6IEhlbGxvDQojIHByaW50KGxvY2FsX2dyZWV0aW5nKSAgIyBUaGlzIHdvdWxkIGNhdXNlIGFuIGVycm9yIGJlY2F1c2UgbG9jYWxfZ3JlZXRpbmcgb25seSBsaXZlcyBpbnNpZGUgZ3JlZXQoKQ0KYGBgDQpTbywgYGxvY2FsX2dyZWV0aW5nYCBvbmx5IGV4aXN0cyBpbnNpZGUgYGdyZWV0KClgLiBPdXRzaWRlIG9mIGBncmVldCgpYCwgaXTigJlzIGdvbmUuDQoNCiMjIyMgKio0LjIgU2lkZSBFZmZlY3RzKioNCioqU2lkZSBFZmZlY3RzKiogaGFwcGVuIHdoZW4gSSB1c2UgYSBmdW5jdGlvbiB0aGF0IGNoYW5nZXMgc29tZXRoaW5nIG91dHNpZGUgaXRzIG93biBzY29wZS4gSXTigJlzIGxpa2Ugd2hlbiBJIG1lc3MgYXJvdW5kIHdpdGggYSBnbG9iYWwgdmFyaWFibGUgaW5zaWRlIGEgZnVuY3Rpb24uDQoNCioqRXhhbXBsZSBvZiBhIFNpZGUgRWZmZWN0Kio6DQpgYGBweXRob24NCm1vb2QgPSAiOigiICAjIEdsb2JhbCB2YXJpYWJsZSByZXByZXNlbnRpbmcgYSBtb29kDQoNCmRlZiBjaGFuZ2VfbW9vZChuZXdfbW9vZCk6DQogICAgZ2xvYmFsIG1vb2QgICMgSSB1c2UgJ2dsb2JhbCcgdG8gdGVsbCBQeXRob24gSeKAmW0gY2hhbmdpbmcgdGhlIGdsb2JhbCB2YXJpYWJsZQ0KICAgIG1vb2QgPSBuZXdfbW9vZA0KDQpjaGFuZ2VfbW9vZCgiOkQiKSAgIyBJIGNhbGwgdGhlIGZ1bmN0aW9uIHRvIGNoYW5nZSB0aGUgbW9vZA0KcHJpbnQoZiJUaGUgY3VycmVudCBtb29kIGlzIHttb29kfSIpICAjIE91dHB1dHM6IFRoZSBjdXJyZW50IG1vb2QgaXMgOkQNCmBgYA0KSSBoYXZlIHRvIGJlIGNhcmVmdWwgd2hlbiBkb2luZyB0aGlzIGJlY2F1c2UgY2hhbmdpbmcgZ2xvYmFsIHZhcmlhYmxlcyBjYW4gbGVhZCB0byBidWdzIHRoYXQgYXJlIGhhcmQgdG8gZmluZC4NCg0KIyMjIyAqKjQuMyBPcmdhbml6aW5nIENvZGUgd2l0aCBGdW5jdGlvbnMqKg0KRnVuY3Rpb25zIHJlYWxseSBzaGluZSB3aGVuIEnigJltIHRyeWluZyB0byBrZWVwIG15IGNvZGUgb3JnYW5pemVkLiBJbnN0ZWFkIG9mIGEgaHVnZSBtZXNzIG9mIGNvbW1hbmRzLCBJIGJyZWFrIHRoaW5ncyBkb3duIGludG8gbGl0dGxlIHN0ZXBzIChmdW5jdGlvbnMpLCBtYWtpbmcgaXQgZWFzaWVyIHRvIG1hbmFnZS4NCg0KKipFeGFtcGxlKio6DQpgYGBweXRob24NCiMgRnVuY3Rpb24gdG8gY29sbGVjdCB1c2VyIGRldGFpbHMNCmRlZiBnZXRfdXNlcl9kZXRhaWxzKCk6DQogICAgbmFtZSA9IGlucHV0KCJFbnRlciB5b3VyIG5hbWU6ICIpDQogICAgYWdlID0gaW50KGlucHV0KCJFbnRlciB5b3VyIGFnZTogIikpDQogICAgcmV0dXJuIG5hbWUsIGFnZQ0KDQojIEZ1bmN0aW9uIHRvIGRpc3BsYXkgZ3JlZXRpbmcNCmRlZiBkaXNwbGF5X2dyZWV0aW5nKG5hbWUsIGFnZSk6DQogICAgcHJpbnQoZiJIZWxsbywge25hbWV9ISBZb3UgYXJlIHthZ2V9IHllYXJzIG9sZC4iKQ0KDQojIE1haW4gZnVuY3Rpb24gdG8gcnVuIHRoZSBwcm9ncmFtDQpkZWYgbWFpbigpOg0KICAgIHVzZXJfbmFtZSwgdXNlcl9hZ2UgPSBnZXRfdXNlcl9kZXRhaWxzKCkNCiAgICBkaXNwbGF5X2dyZWV0aW5nKHVzZXJfbmFtZSwgdXNlcl9hZ2UpDQoNCiMgQ2FsbCB0aGUgbWFpbiBmdW5jdGlvbiB0byBzdGFydCB0aGUgcHJvZ3JhbQ0KbWFpbigpDQpgYGANCkJyZWFraW5nIHRoaW5ncyBkb3duIHRoaXMgd2F5IGhlbHBzIG1lIGtlZXAgbXkgYnJhaW4gZnJvbSBnZXR0aW5nIG92ZXJ3aGVsbWVkLCBhbmQgSSBjYW4gZm9jdXMgb24gc29sdmluZyBvbmUgcGFydCBvZiB0aGUgcHJvYmxlbSBhdCBhIHRpbWUuDQoNCiMjIyBTdW1tYXJ5DQpJbiB0aGlzIGxlc3NvbiwgSSBjb3ZlcmVkOg0KMS4gKipCYXNpYyBDb25zdHJ1Y3RzKio6IEhvdyB0byB1c2UgdmFyaWFibGVzLCBnZXQgaW5wdXQsIGRpc3BsYXkgb3V0cHV0LCBhbmQgZG8gbWF0aC4NCjIuICoqRnVuY3Rpb25zKio6IEhvdyB0byB3cml0ZSByZXVzYWJsZSBibG9ja3Mgb2YgY29kZSwgdXNlIHBhcmFtZXRlcnMsIGFuZCBnZXQgcmV0dXJuIHZhbHVlcy4NCjMuICoqQ29tbWFuZCBMaW5lIGluIFZTIENvZGUqKjogSG93IHRvIG1vdmUgYXJvdW5kIHlvdXIgZmlsZXMgYW5kIHJ1biBQeXRob24gc2NyaXB0cy4NCjQuICoqQWR2YW5jZWQgQ29uY2VwdHMqKjogVGhlIGlkZWEgb2Ygc2NvcGUgKGxvY2FsIHZzIGdsb2JhbCksIHNpZGUgZWZmZWN0cywgYW5kIGtlZXBpbmcgY29kZSBvcmdhbml6ZWQgd2l0aCBmdW5jdGlvbnMuDQoNCiMjIyBQcmFjdGljZSBDaGFsbGVuZ2UNCi0gQ3JlYXRlIGEgUHl0aG9uIHNjcmlwdCB3aGVyZSB5b3U6DQogIDEuIEFzayBmb3IgYSB1c2VyJ3MgbmFtZSBhbmQgdGhlaXIgZmF2b3JpdGUgbnVtYmVyLg0KICAyLiBXcml0ZSBhIGZ1bmN0aW9uIHRoYXQgKipkb3VibGVzKiogdGhlIG51bWJlci4NCiAgMy4gVXNlIGEgKipnbG9iYWwqKiB2YXJpYWJsZSB0byBjb3VudCBob3cgbWFueSB0aW1lcyB0aGUgcHJvZ3JhbSBoYXMgYmVlbiBydW4uDQogIDQuIFByaW50IG91dCB0aGUgZG91YmxlZCBudW1iZXIgYW5kIGhvdyBtYW55IHRpbWVzIHRoZSBzY3JpcHQgaGFzIGJlZW4gZXhlY3V0ZWQuDQoNClRoZSBnb2FsIGlzIHRvIGJlIGFibGUgdG8gd3JpdGUgcHl0aG9uIGNvZGUgd2l0aG91dCBldmVuIHRoaW5raW5nIGFib3V0IGl0Lg0KDQpyZXZpZXcgYW5kIHJldmlldyBhbmQgcHJhY3RpY2UgdGhpcyBsZXNzb24sIGltcGxlbWVudGluZyBvdGhlciB0YWN0aWNzIGFuZCBjb21wYXJpbmcgcmVzdWx0cy4gIEZpbmdlciBtdXNjbGUgbWVtb3J5IGFuZCBoYWJpdHMgbmVlZCB0byBiZSBidWlsdC4gIEtlZXAgYXQgaXQuICBKRVNTSUNBIFlPVSBNVVNUIEZVQ0tJTkcgUFJBQ1RJQ0UuIEpFU1NJQ0EuIEtFRVAgQVQgSVQuICBZT1UgV0lMTCBORVZFUiBSRUxZIE9OIEFOWU9ORSBUTyBUQUtFIENBUkUgT0YgWU9VLiBJTiBPUkRFUiBUTyBCRSBTVUNDRVNTRlVMIFlPVSBNVVNUIEJFIERSSVZFTiAgUFJBQ1RDRSBJUyBUSEUgS0VZIFRPIE1BU1RFUklORyBUSElTIFNISVQhIFlPVSBDQU4gRE8gSVQuICAgVEhJUyBJUyBOT1QgSlVTVCBGT1IgWU9VIC0gSVRTIEFMU08gRk9SIFlPVVIgS0lEUy4gIFlPVSBORUVEIFRISVMuICBXRSBET04nVCBCUkVBSy4gIFdFIEFDQ0VMQVJBVEUgQU5EIE1PVkUgRk9SV0FSRCBPTiBBIEJFVFRFUiBQQVRIIFRIQU4gQkVGT1JFLiAgTk9XIFRBS0UgNSBUSEVOIERPIFRISVMgQUxMIEFHQUlOLiAgIA==