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.
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). - Type
mkdir
my_new_projectto create a new folder. - Use
cd
my_new_projectto navigate into your new folder. - Type
touch
my_script.py(in Linux/macOS) or
New-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.
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
- Create a Python script where you:
- Ask for a user’s name and their favorite number.
- Write a function that doubles the number.
- Use a global variable to count how many times the
program has been run.
- Print out the doubled number and how many times the script has been
executed.
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==