Overview
This lesson explores multi-threading in Java and the mechanisms Java offers for thread synchronization. It will explain Java’s multi-threading capabilities and thread synchronization mechanisms starting from the basics of creating and managing threads to advanced synchronization techniques and real-world application scenarios. Focused will be placed on the knowledge and skills necessary to write efficient and thread-safe Java applications for JVM code running on modern multi-core CPUs.
Multi-Threading and Multi-Processing
Multi-threading and multi-processing are two methods for running multiple, concurrent paths of execution. Both are essential for building operating systems and modern software systems. While they are similar in that they run code concurrently, there are significant differences between them and developers must carefully choose an appropriate mechanism depending on requirements, operating and programming language support, and the desired isolation of the different paths of execution. Both approaches are used in the construction of client/server application architectures and are sometimes combined in a hybrid architecture.
Multi-Threading is the concurrent execution of multiple threads within a single process, allowing tasks to run independently but share the same memory space and resources. It is ideal for scenarios where tasks need to be coordinated within a single program, often on a multi-core CPU.
Multi-Processing is the concurrent execution of multiple independent processes, each with its own separate memory space and resources. Processes run independently and can take advantage of multiple CPU cores or even run on separate machines. It’s suitable for scenarios that require isolation, fault tolerance, and true parallelism.
Multi-Threading
Multi-threading is a fundamental concept in computer science and software development that involves the simultaneous execution of multiple threads within a single process or program. Each thread represents a sequence of instructions that can execute independently but shares the same memory space and resources with other threads in the same process. Multi-threading enables a program to perform multiple tasks concurrently, improving its responsiveness, performance, and resource utilization.
Here are some key aspects and explanations of multi-threading:
Thread: A thread can be thought of as a lightweight, independent unit of execution within a program. Threads share the same code segment and data space (memory) with other threads in the same process. They have their own program counter, stack, and register set, which allows them to execute independently.
Concurrency: Multi-threading is a way to achieve concurrency in a program. Concurrency refers to the ability of a program to execute multiple tasks or operations simultaneously, without necessarily running them in parallel.
Parallelism: While multi-threading allows for concurrency, it’s important to distinguish it from parallelism. Parallelism refers to the simultaneous execution of multiple threads or processes on multiple CPU cores or processors. Not all concurrent programs are parallel; some may run on a single core and switch between threads to achieve concurrency.
Benefits of Multi-Threading:
- Responsiveness: Multi-threading is crucial for applications with user interfaces (e.g., GUIs or web servers) to remain responsive while handling background tasks.
- Performance: Multi-threading can improve performance by utilizing multiple CPU cores efficiently. Tasks can be divided among threads, making use of available processing power.
- Resource Utilization: Multi-threading helps in efficient resource utilization, as threads can run concurrently on different CPU cores, maximizing system resource usage.
- Scalability: In modern computing environments with multi-core CPUs, multi-threading is essential for building scalable applications.
Thread States and Lifecycle: Threads go through various states during their lifecycle, including new, runnable, blocked, waiting, timed waiting, and terminated. The Java programming language, for example, provides a well-defined thread lifecycle and APIs for managing threads.
Thread Synchronization: When multiple threads access shared data or resources, there is a risk of data corruption or race conditions. Thread synchronization mechanisms, such as locks, semaphores, and monitors, are used to coordinate and control access to shared resources to ensure data consistency.
Examples of Multi-Threading:
- A web server handling multiple client requests concurrently.
- A word processor with a spell-checker running in the background while the user continues typing.
- A video player decoding and rendering video frames while simultaneously handling user input.
In summary, multi-threading is a powerful technique that enables concurrent execution of tasks within a single program, enhancing responsiveness, performance, and resource utilization. However, it also introduces challenges related to thread synchronization and coordination, which must be carefully managed to ensure data consistency and avoid issues like race conditions.
Multi-Processing
Multi-processing is a concept in computer science and software development that involves the execution of multiple independent processes concurrently, each with its own memory space, resources, and state. Unlike multi-threading, where multiple threads share the same memory space within a single process, multi-processing allows different processes to run simultaneously, often on separate CPU cores or even on different physical machines. Each process operates independently, and they can communicate with each other through inter-process communication (IPC) mechanisms. Let’s explore the key aspects and explanations of multi-processing:
Process: A process is an independent program that runs in its own memory space. Each process has its own memory allocation, program counter, stack, and resources. Processes are isolated from each other, which means that a failure or crash in one process typically does not affect other processes.
Concurrency: Multi-processing allows for true concurrency, as different processes can run simultaneously on multiple CPU cores or processors. This enables the execution of multiple tasks or programs concurrently.
Parallelism: Multi-processing can lead to parallelism when processes are executed simultaneously on separate CPU cores or processors. Parallelism allows for maximum utilization of available hardware resources and can significantly improve performance for compute-intensive tasks.
Benefits of Multi-Processing:
- Isolation: Processes are isolated from each other, providing a high degree of fault tolerance. If one process crashes, it doesn’t necessarily affect other processes.
- Resource Allocation: Each process has its own memory space and resources, making it easier to manage resource allocation and isolation.
- Parallel Execution: Multi-processing can take full advantage of multi-core CPUs and distributed computing environments to execute tasks in parallel.
- Enhanced Security: Process isolation can enhance security by preventing unauthorized access to memory and resources of other processes.
Process Synchronization: In multi-processing, processes can run independently, but there may be cases where they need to synchronize their actions or share data. IPC mechanisms such as pipes, message queues, shared memory, and sockets are used for inter-process communication and synchronization.
Examples of Multi-Processing:
- A web server handling multiple client requests by creating separate processes for each connection.
- A modern operating system, where various system services and applications run as separate processes.
- Distributed computing applications that execute tasks on different machines or nodes.
In summary, multi-processing allows for concurrent execution of multiple independent processes, each with its own memory space and resources. This approach is well-suited for scenarios where isolation, fault tolerance, and true parallelism are essential. While multi-processing offers benefits in terms of resource isolation and fault tolerance, it also introduces challenges related to process communication and synchronization, which must be carefully managed for successful multi-processing applications.
Hybrid Architecture
A hybrid multi-processing with multi-threading architecture combines elements of both multi-processing and multi-threading to take advantage of the benefits of each approach. In this architecture, you have multiple independent processes running concurrently, and each of these processes contains multiple threads that can execute independently within that process. This combination allows for a flexible and powerful approach to concurrent programming.
Here are the key characteristics of a hybrid multi-processing with multi-threading architecture:
Multiple Processes: The system consists of multiple separate processes, each with its own memory space and resources. These processes can run independently and may even be executed on different CPU cores or physical machines.
Multi-Threading Within Each Process: Within each individual process, multi-threading is employed. This means that each process contains multiple threads that share the same memory space and resources specific to that process. These threads can execute concurrently and take advantage of multi-core CPUs within the scope of their parent process.
Isolation: Processes are isolated from each other, providing a high degree of fault tolerance and security. If one process encounters an issue or crashes, it is less likely to impact other processes.
Parallelism: Both inter-process parallelism (between processes) and intra-process parallelism (within a process) can be achieved. This allows for efficient utilization of hardware resources on both the process and thread levels.
Flexibility: The combination of processes and threads provides flexibility in designing and implementing concurrent applications. It allows developers to choose the appropriate level of concurrency for different parts of the application, optimizing resource usage.
Inter-Process Communication: Since processes are isolated, they may communicate with each other using inter-process communication (IPC) mechanisms, such as message passing, sockets, or shared memory. This enables coordination and data sharing between different processes.
A common use case for a hybrid multi-processing with multi-threading architecture is in complex software systems where different components or modules have varying requirements for isolation and parallelism. For example, a web server might use this architecture, with each client request being processed in a separate process, and within each process, multi-threading is used to handle multiple incoming connections concurrently.
This hybrid approach allows developers to design systems that balance the advantages of isolation and true parallelism (multi-processing) with the efficiency and resource sharing benefits of multi-threading. However, it also adds complexity to the system due to the need to manage both inter-process and intra-process synchronization and coordination.
Introduction to Multi-Threading in Java
In modern software development, the need for efficient and responsive applications is critical and essential. One of the ways to achieve this is through multi-threading, a fundamental concept in concurrent programming. Java, a popular and widely-used programming language, provides robust support for multi-threading, making it an excellent choice for building scalable and high-performance applications. This chapter serves as the foundation for our journey into the realm of multi-threading in Java.
Objectives
- Understanding the Basics of Threads
- Why Multi-Threading Matters
- Java’s Multi-Threading Support
Understanding the Basics of Threads
A thread, in the context of computer programming, can be thought of as a lightweight process or a unit of execution within a program. Threads allow a program to perform multiple tasks concurrently, sharing the same memory space and resources. They enable developers to write code that can execute in parallel, harnessing the full potential of multi-core processors.
In Java, threads are implemented using the java.lang.Thread
class, and they can be created and managed easily. Threads have their own stack and program counter, which enables them to execute independently while sharing data and resources with other threads.
Java’s Multi-Threading Support
Java provides a rich set of features and APIs for multi-threading, making it relatively easy to work with threads and manage their interactions. Some key aspects of Java’s multi-threading support include:
Thread Creation: You can create threads in Java by extending the Thread
class or implementing the Runnable
interface. This flexibility allows you to define the code that each thread will execute.
Thread Synchronization: Java provides mechanisms for synchronizing threads and managing access to shared resources. This prevents issues like data corruption and race conditions.
High-Level Concurrency Utilities: The java.util.concurrent
package offers high-level constructs such as thread pools, concurrent collections, and synchronization primitives, simplifying the development of multi-threaded applications.
Memory Model: Java defines a memory model that governs how threads interact with memory and guarantees visibility and consistency of shared data.
Thread States and Lifecycle: Threads in Java have well-defined states, and their lifecycle is managed by the Java Virtual Machine (JVM).
In the subsequent sections, we will dive deeper into these concepts, exploring thread creation, synchronization mechanisms, best practices, and real-world examples. By the end of this journey, you’ll have a thorough understanding of how to harness the power of multi-threading in Java to build robust and high-performance applications.
Creating and Managing Threads
In this section, we delve into the practical aspects of working with threads in Java. Understanding how to create, manage, and control threads is fundamental to harnessing the power of multi-threading. This section explores the intricacies of thread creation, their lifecycle, and how to manage them effectively.
Objectives
- Creating Threads in Java
- Running Threads
- Thread States and Lifecycle
- Daemon Threads
Creating Threads in Java
Java provides two primary ways to create threads:
Extending the Thread
Class: You can create a new thread by extending the java.lang.Thread
class. By overriding the run()
method within your subclass, you define the code that the thread will execute when started.
class MyThread extends Thread {
public void run() {
// Thread's code here
}
}
// Creating and starting a thread
MyThread myThread = new MyThread();
myThread.start();
Implementing the Runnable
Interface: An alternative approach is to implement the java.lang.Runnable
interface. This interface defines a run()
method that you need to implement, and then you can create a Thread
object, passing your Runnable
instance to its constructor.
class MyRunnable implements Runnable {
public void run() {
// Thread's code here
}
}
// Creating and starting a thread using Runnable
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
Running Threads
Once threads are created, they can be started using the start()
method. The JVM manages the execution of threads, and when a thread is started, it transitions from the NEW
state to the RUNNABLE
state, indicating it’s ready for execution.
Thread States and Lifecycle
Threads go through various states during their lifecycle. The common thread states in Java include:
- NEW: The initial state when a thread is created but not yet started.
- RUNNABLE: The thread is ready to execute and waiting for CPU time.
- BLOCKED: The thread is blocked, often waiting for a lock or resource.
- WAITING: The thread is in a waiting state and can be awakened by another thread.
- TIMED_WAITING: Similar to waiting but with a timeout.
- TERMINATED: The thread has completed its execution.
Understanding the thread lifecycle is essential for managing and debugging multi-threaded applications effectively.
Daemon Threads
In Java, you can create daemon threads by calling the setDaemon(true)
method on a Thread
object. Daemon threads are threads that run in the background and do not prevent the JVM from exiting when all non-daemon threads have completed. They are often used for tasks like garbage collection or monitoring.
Thread daemonThread = new Thread(() -> {
// Thread's code here
});
daemonThread.setDaemon(true);
daemonThread.start();
In this section we set the stage for our exploration of multi-threading in Java by covering the fundamental concepts of creating and managing threads. In the next section, we will delve into thread synchronization.
Synchronization in Java
Thread synchronization is a fundamental concept in concurrent programming that involves coordinating the execution of multiple threads to ensure they access shared resources or sections of code in a controlled and orderly manner. The goal of thread synchronization is to prevent race conditions, data corruption, and other concurrency-related issues that can arise when multiple threads access shared data simultaneously.
Objectives
- The Need for Thread Synchronization
- Synchronized Methods and Blocks
- Intrinsic Locks (Monitor Locks)
- Volatile Keyword
Need for Synchronization
Thread synchronization is important because in multi-threaded applications, multiple threads may run concurrently and access shared resources or variables. Without proper synchronization, the following problems can occur:
Race Conditions: Race conditions occur when the behavior of a program depends on the relative timing of events between threads. For example, two threads may simultaneously access and modify a shared variable, leading to unpredictable results.
Data Corruption: Simultaneous writes to shared data without proper synchronization can result in data corruption or inconsistency. One thread may overwrite changes made by another, leading to incorrect program behavior.
Deadlocks: Deadlocks happen when two or more threads are blocked, waiting for each other to release resources they need. This can result in a situation where no progress is possible, effectively bringing the application to a standstill.
To address these issues, thread synchronization mechanisms are used to control access to shared resources and enforce rules that ensure safe concurrent execution. Common synchronization mechanisms in Java include:
Synchronized Methods and Blocks: Java allows you to declare methods as synchronized
or use synchronized blocks to protect critical sections of code. When a thread enters a synchronized method or block, it acquires a lock that prevents other threads from executing synchronized code on the same object until the lock is released.
Locks (ReentrantLock): Java provides the ReentrantLock
class, which offers more fine-grained control over locking and unlocking. It allows for features such as fairness, timeouts, and advanced lock management.
Semaphores, CountDownLatch, and CyclicBarrier: These synchronization constructs are provided by the java.util.concurrent
package and allow threads to coordinate their activities, wait for signals, or synchronize at specific points in the execution.
Atomic Variables: Classes like AtomicInteger
and AtomicReference
offer atomic operations, ensuring that certain operations on shared variables are indivisible and thread-safe.
Volatile Keyword: The volatile
keyword ensures the visibility of changes made to a variable across threads. It guarantees that the most up-to-date value of the variable is always read.
Thread synchronization is a crucial skill for developers working with multi-threaded applications, as it helps prevent concurrency-related bugs and ensures the correctness and reliability of the software. However, improper or excessive synchronization can lead to performance bottlenecks, so it’s essential to strike a balance between synchronization and performance optimization.
Synchronized Methods and Blocks
Java provides two primary mechanisms for thread synchronization:
Synchronized Methods: You can declare a method as synchronized
by using the synchronized
keyword. When a thread invokes a synchronized method, it acquires a lock associated with the object on which the method is called. Other threads attempting to call synchronized methods on the same object will block until the lock is released.
public synchronized void synchronizedMethod() {
// Synchronized code here
}
Synchronized Blocks: You can also create synchronized blocks within methods to protect critical sections of code. A synchronized block is enclosed within the synchronized
keyword and specifies the object that provides the lock.
synchronized (lockObject) {
// Synchronized code here
}
Intrinsic Locks (Monitor Locks)
In Java, each object has an intrinsic lock, also known as a monitor lock. When a synchronized method or block is entered, the thread acquires the intrinsic lock associated with the object on which the method or block is invoked. This lock ensures that only one thread can execute the synchronized code at a time.
The volatile
Keyword
While synchronized
methods and blocks are used for protecting critical sections of code, the volatile
keyword is used to ensure the visibility of changes made to a variable across threads. When a variable is declared as volatile
, any write to that variable is immediately visible to other threads. This ensures that the most up-to-date value of the variable is always read.
private volatile boolean flag = false;
This section presented a foundation for understanding thread synchronization in Java. In the next section, we will explore more advanced synchronization techniques and some best practices.
Thread Safety and Race Conditions
Addressing multi-threading in Java. This chapter delves into the concept of thread safety, the challenges posed by race conditions, and the techniques used to ensure that concurrent access to shared resources does not lead to data corruption or unpredictable behavior.
Objectives
- Understanding Thread Safety
- Identifying and Handling Race Conditions
- Atomic Variables and Operations
- Immutable Objects
Understanding Thread Safety
Thread safety is a fundamental concept in concurrent programming. It refers to the property of a program or system where multiple threads can access shared resources concurrently without causing data corruption, inconsistent state, or unexpected behavior. In thread-safe programs, the results are predictable and adhere to the intended logic, regardless of the order in which threads execute.
Ensuring thread safety is vital because in multi-threaded applications, various threads may access shared data or resources simultaneously. Without proper thread safety measures, the following problems can occur:
Race Conditions: Race conditions occur when multiple threads access shared data concurrently, and the final state of the data depends on the unpredictable timing of thread execution.
Data Corruption: Unprotected writes to shared data can lead to data corruption. One thread may overwrite changes made by another, leading to incorrect or inconsistent results.
Inconsistent State: Lack of thread safety can result in objects being left in an inconsistent state if interrupted or accessed simultaneously by multiple threads.
Identifying and Handling Race Conditions
To address race conditions and ensure thread safety, developers must:
Identify Critical Sections: Identify the sections of code where shared data is accessed or modified. These sections are known as “critical sections” and need protection.
Apply Synchronization: Use synchronization mechanisms such as synchronized
methods, blocks, or locks to protect critical sections. This ensures that only one thread can access the critical section at a time.
Atomic Operations: Use atomic operations provided by classes like AtomicInteger
or AtomicReference
to perform compound actions on shared variables atomically. These operations are inherently thread-safe.
Immutable Objects: Consider using immutable objects. Immutable objects are those whose state cannot be modified after creation, making them inherently thread-safe. Any operation on an immutable object creates a new instance rather than modifying the existing one.
Best Practices for Thread Safety
Maintaining thread safety in Java applications involves following best practices, including:
Minimize Shared Mutable State: Reduce the use of shared mutable state whenever possible. Isolate shared data and minimize the number of threads that can access it.
Use Thread-Local Variables: In some cases, thread-local variables can eliminate the need for synchronization by ensuring that each thread has its own copy of the data.
Testing and Debugging: Thoroughly test multi-threaded code, including edge cases and stress tests. Debugging tools and techniques specific to multi-threading, such as thread dumps and profilers, can help identify issues.
Concurrency Libraries: Leverage Java’s concurrency libraries, such as the java.util.concurrent
package, which provides thread-safe data structures and synchronization primitives.
Documentation: Document thread-safety guarantees for classes and methods, making it clear to developers which parts of the code need to be synchronized and which are safe for concurrent use.
In summary, Chapter 4 explores the importance of thread safety in multi-threaded Java applications, highlighting the challenges posed by race conditions and offering strategies to identify, prevent, and handle them. Understanding and applying thread safety principles are crucial for building robust and reliable multi-threaded software.
Using Java’s Concurrency Utilities
This section is a pivotal part of our exploration into multi-threading in Java where we dive into the rich set of concurrency utility classes and methods provided by the java.util.concurrent
package. These mechanisms simplify the development of multi-threaded applications by offering high-level constructs, thread pools, concurrent collections, and synchronization primitives.
Objectives
- java.util.concurrent Package Overview
- Executors and Thread Pools
- Concurrent Collections
- Callable and Future
java.util.concurrent
Package Overview
The java.util.concurrent
package, introduced in Java 5, is a treasure trove of classes and interfaces designed to make multi-threaded programming more accessible and efficient. It encompasses a wide range of features and tools that can significantly simplify the task of managing concurrent tasks and data.
Some of the core components of this package include:
Executors: The Executor
framework abstracts the management of threads, allowing you to focus on tasks rather than managing thread creation and lifecycle. It provides a way to submit tasks for execution and control the thread pool.
Thread Pools: ExecutorService
interfaces, along with implementations like ThreadPoolExecutor
and ScheduledThreadPoolExecutor
, simplify the creation and management of thread pools. Thread pools are crucial for managing thread lifecycle and resource consumption.
Concurrent Collections: Java’s concurrent collections, such as ConcurrentHashMap
and ConcurrentLinkedQueue
, are designed for safe and efficient access by multiple threads. They eliminate the need for manual synchronization and provide excellent performance in multi-threaded scenarios.
Synchronization Primitives: The package offers various synchronization primitives like Semaphore
, CountDownLatch
, and CyclicBarrier
that enable threads to coordinate their activities and synchronize at specific points during execution.
Atomic Variables: Classes like AtomicInteger
, AtomicLong
, and AtomicReference
provide atomic operations on variables, ensuring that complex operations on shared data are executed atomically without the need for explicit synchronization.
Executors and Thread Pools
Thread pools are a fundamental concept in concurrent programming, and the java.util.concurrent
package makes working with them straightforward. You can create and manage thread pools to efficiently reuse threads, control resource consumption, and simplify task submission. The package offers different types of thread pools, including fixed-size, cached, and scheduled thread pools.
Here’s an example of creating a fixed-size thread pool using Executors
:
ExecutorService executor = Executors.newFixedThreadPool(4); // Creates a pool with 4 threads
Concurrent Collections
Java’s concurrent collections are designed for safe, efficient, and thread-friendly data storage and retrieval. For example, ConcurrentHashMap
allows multiple threads to read and write to the map concurrently without explicit synchronization.
ConcurrentMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("key", 42);
int value = concurrentMap.get("key");
Callable and Future
The Callable
and Future
interfaces allow you to perform tasks that return results and can be executed asynchronously. A Callable
is similar to a Runnable
but can return a result or throw an exception. A Future
represents the result of an asynchronous computation and provides methods to retrieve the result or handle exceptions when the task completes.
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
// Compute a result
return 42;
});
// Retrieve the result when it's available
int result = future.get();
In short, the java.util.concurrent
package offers a plethora of constructs, classes, and utility methods to simplify multi-threaded programming in Java. By leveraging thread pools, concurrent collections, synchronization primitives, and other features, developers can build efficient, scalable, and thread-safe applications more easily and effectively. Understanding these utilities is essential for building application with safe multi-threading.
Advanced Synchronization Techniques
This section takes our journey into multi-threading in Java to a deeper level by exploring advanced thread synchronization techniques and patterns. Specifically, we move beyond basic synchronization and delve into more complex scenarios and strategies for managing concurrency.
Objectives
- ReentrantLock and Condition
- Read-Write Locks
- Semaphores and CountDownLatch
- CyclicBarrier and Phaser
Lock Objects and Lock Interfaces
While synchronized
blocks and methods provide a straightforward way to manage synchronization, Java also offers more advanced synchronization through explicit lock objects and interfaces in the java.util.concurrent.locks
package. These mechanisms provide greater control over thread synchronization and can be particularly useful in complex scenarios.
ReentrantLock
: The ReentrantLock
class is a versatile alternative to synchronized blocks. It allows fine-grained control over locking and unlocking and supports features such as fairness, which ensures that threads acquire the lock in the order they request it.
ReentrantLock lock = new ReentrantLock();
lock.lock(); // Acquire the lock
try {
// Synchronized code here
} finally {
lock.unlock(); // Release the lock in a finally block
}
ReadWriteLock
: The ReadWriteLock
interface provides a way to manage concurrent access to shared data where multiple threads may read data concurrently, but write operations should be exclusive. It offers two types of locks: a read lock and a write lock.
ReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.readLock().lock(); // Acquire the read lock
try {
// Read data
} finally {
rwLock.readLock().unlock(); // Release the read lock
}
StampedLock
: Introduced in Java 8, StampedLock
is a more advanced read-write lock with an optimistic locking mode. It provides better performance for read-heavy workloads while maintaining thread safety for writes.
Condition Variables
Condition variables, represented by the java.util.concurrent.locks.Condition
interface, are used to coordinate the execution of threads in more complex synchronization scenarios. They allow threads to wait until a specific condition is met before proceeding. Condition variables are often used in conjunction with explicit locks.
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// Thread 1
lock.lock();
try {
while (!conditionMet) {
condition.await(); // Wait until the condition is met
}
// Continue execution
} finally {
lock.unlock();
}
// Thread 2
lock.lock();
try {
// Change some state
conditionMet = true;
condition.signal(); // Signal waiting threads that the condition is met
} finally {
lock.unlock();
}
Thread Safety Patterns
Chapter 6 also introduces thread safety patterns, which are design approaches and strategies for ensuring thread safety in multi-threaded applications. These patterns include:
Immutable Objects: Designing objects that cannot be modified after creation, eliminating the need for synchronization.
Guarded Blocks: Using while
loops to wait for specific conditions to be met before proceeding.
Balking: A pattern where a thread detects a condition and decides not to proceed with an action, avoiding unnecessary work.
Producer-Consumer: Coordinating between threads that produce data and threads that consume data using shared data structures.
Read-Write Locks: Using read-write locks to allow multiple threads to read data concurrently but ensuring exclusive access for write operations.
Best Practices for Advanced Synchronization
We explored best practices for advanced synchronization, emphasizing the importance of clear documentation, proper exception handling, and thorough testing when dealing with complex synchronization scenarios. However, developers must use synchronization constructs cautiously and consider alternatives when appropriate, as excessive synchronization can lead to performance bottlenecks and turn multi-threaded code into single-threaded execution.
Chapter 7: Thread Communication
In this section, we delve into some essential aspects of thread communication, including the wait
and notify
mechanisms, and the use of blocking queues in Java. These concepts are essential for building efficient and synchronized multi-threaded applications.
Objectives
- Inter-Thread Communication
- Producer-Consumer Problem
- Wait and Notify
- Blocking Queues
Thread Communication
Thread communication is the practice of enabling threads to interact, synchronize, and exchange information with each other in a controlled manner. It’s vital in multi-threaded applications where threads may need to coordinate their actions, signal events, or share data. Two fundamental mechanisms for thread communication in Java are wait
and notify
.
wait()
and notify()
Methods: These methods are part of the Object
class and allow threads to synchronize and communicate. Here’s how they work:
wait()
: A thread calls wait()
to release the lock on an object and enter a waiting state. It waits until another thread invokes notify()
or notifyAll()
on the same object.
notify()
: A thread calls notify()
to wake up one of the waiting threads that called wait()
on the same object. It’s used to signal that a condition has changed and that waiting threads can proceed.
// Producer-Consumer example using wait and notify
class SharedResource {
private int data;
private boolean newDataAvailable = false;
public synchronized void produce(int value) {
while (newDataAvailable) {
try {
wait(); // Wait until the data is consumed
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
data = value;
newDataAvailable = true;
notify(); // Signal that new data is available
}
public synchronized int consume() {
while (!newDataAvailable) {
try {
wait(); // Wait until new data is produced
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
newDataAvailable = false;
notify(); // Signal that the data has been consumed
return data;
}
}
Blocking Queues
Blocking queues are thread-safe data structures that simplify thread communication and synchronization by providing built-in methods for handling waiting and notification. Java’s java.util.concurrent
package includes several types of blocking queues, such as LinkedBlockingQueue
, ArrayBlockingQueue
, and PriorityBlockingQueue
. These queues offer a convenient way to implement producer-consumer patterns and other multi-threaded scenarios.
Key features of blocking queues:
- Blocking Operations: Blocking queues offer blocking operations for enqueueing (
put
) and dequeueing (take
) elements. These operations block until space is available (for put
) or until an element is available (for take
).
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
// Producer
queue.put(42);
// Consumer
int value = queue.take();
- Time-Bound Operations: Blocking queues allow you to specify a timeout when waiting for an operation to complete. For example, you can use
offer
with a timeout to enqueue an element if space is available within a certain time.
boolean success = queue.offer(42, 1, TimeUnit.SECONDS);
Thread-Safety: Blocking queues are designed for thread-safe concurrent access. They handle all synchronization internally, making it safe for multiple threads to enqueue and dequeue elements concurrently.
Blocking Semantics: When a thread tries to dequeue an element from an empty queue (take
operation) or enqueue an element into a full queue (put
operation), it will block until the condition is satisfied.
Blocking queues are commonly used in scenarios like thread pool task scheduling, event handling, and load balancing, where multiple threads need to cooperate efficiently and safely.
Best Practices for Thread Communication and Blocking Queues
When using wait
and notify
, and when working with blocking queues, consider the following best practices:
Always Use wait()
and notify()
with Synchronization: It’s crucial to enclose calls to wait()
and notify()
within synchronized blocks to ensure proper synchronization and avoid race conditions.
Timeouts: When using blocking operations or time-bound operations with blocking queues, consider specifying reasonable timeouts to prevent indefinite blocking.
Avoid Busy Waiting: Don’t use busy waiting loops (polling) when waiting for conditions. Instead, prefer mechanisms like wait
and notify
or blocking queues, which are more efficient and resource-friendly.
Choose the Right Blocking Queue: Select the appropriate type of blocking queue (e.g., LinkedBlockingQueue
, ArrayBlockingQueue
, or PriorityBlockingQueue
) based on your specific requirements and usage patterns.
In summary, wait
and notify
and the use of blocking queues in Java are key mechanisms for building efficient and synchronized multi-threaded applications, ensuring that threads can cooperate and exchange information effectively while maintaining thread safety.
Multi-Threading in Real-World Applications
In this section, we explore various domains and industries where multi-threading plays a crucial role:
Web Servers: Multi-threading is essential for handling concurrent client requests efficiently. Web servers often use thread pools to process incoming connections concurrently.
Database Systems: Database management systems often employ multi-threading to handle multiple database connections and execute queries concurrently. Connection pooling and query parallelism are common techniques.
Game Development: Video games rely on multi-threading to manage graphics rendering, physics simulations, and AI computations. Game engines use multi-threaded architectures to ensure smooth gameplay.
Financial Systems: In the financial industry, multi-threading is used to process large volumes of real-time market data, perform complex calculations, and execute high-frequency trading strategies.
Scientific Computing: Scientific simulations and data analysis benefit from multi-threading to distribute computational workloads across multiple threads, speeding up calculations.
Machine Learning: Training complex machine learning models often involves parallelism, allowing multiple threads or processes to process different data points or model updates simultaneously.
Thread Pools
Thread pools are a fundamental concept in concurrent programming, particularly in Java, where they are extensively used to manage and optimize the execution of tasks by a pool of worker threads. Thread pools help improve the efficiency of multi-threaded applications by reusing threads, reducing thread creation and destruction overhead, and controlling the number of concurrent threads. In this detailed explanation, we’ll explore thread pools in depth.
Key Components of a Thread Pool:
Thread Pool Size: This is the number of worker threads available in the pool. It determines how many tasks can be executed concurrently. The thread pool size should be chosen carefully based on factors like the available CPU cores and the nature of tasks.
Task Queue: The task queue (also known as a work queue) is a data structure where tasks are stored before they are executed. When a task is submitted to the thread pool, it’s added to the task queue. Worker threads retrieve tasks from the queue and execute them.
Task Submission: Tasks are submitted to the thread pool for execution. These tasks can be represented as instances of Runnable
or Callable
interfaces in Java.
Worker Threads: Worker threads are pre-created threads that continuously retrieve tasks from the task queue and execute them. They remain active until the thread pool is shut down.
Thread Pool Management: The thread pool is responsible for creating and managing worker threads, handling task submission, and ensuring the proper lifecycle management of threads.
Advantages of Using Thread Pools:
Thread Reuse: Thread pools reuse existing threads rather than creating and destroying them for each task. This reduces the overhead associated with thread creation, which can be costly.
Thread Lifecycle Management: Thread pools manage the lifecycle of worker threads, ensuring that threads remain active and available to process tasks until the thread pool is shut down.
Concurrency Control: Thread pools allow you to control the maximum number of concurrent threads, preventing resource exhaustion and thread thrashing.
Queueing Mechanism: Thread pools provide a queueing mechanism for tasks. If all threads are busy, new tasks are placed in the queue, ensuring that tasks are processed in the order they were submitted.
Resource Management: By controlling the number of threads, thread pools help manage system resources more effectively, preventing overloading and improving application stability.
Common Thread Pool Types:
FixedThreadPool: This type of thread pool maintains a constant number of threads in the pool. Once created, the number of threads remains fixed, and if a task is submitted when all threads are busy, it waits in the queue until a thread becomes available.
CachedThreadPool: In this type of thread pool, the number of threads can grow or shrink dynamically based on the workload. If a thread is idle for a certain period, it may be terminated, and new threads may be created as needed.
ScheduledThreadPool: This thread pool is designed for scheduling tasks to run at specific intervals or after a delay. It’s commonly used for tasks like periodic maintenance or timed execution of tasks.
SingleThreadExecutor: This thread pool contains only one thread, ensuring that tasks are executed sequentially in the order they were submitted. It’s suitable for tasks that require strict order of execution.
Thread Pool Best Practices:
Proper Sizing: Choose an appropriate thread pool size based on the available resources, such as CPU cores, and the nature of the tasks. Oversizing or undersizing the thread pool can impact performance.
Task Dependency: Consider task dependencies and potential bottlenecks when designing multi-threaded applications with thread pools. Ensure that tasks are divided and scheduled efficiently.
Graceful Shutdown: Always shut down the thread pool gracefully when it’s no longer needed. This allows existing tasks to complete while preventing new tasks from being submitted.
Error Handling: Implement error handling and exception management for tasks within the thread pool. Unhandled exceptions in worker threads can lead to unexpected application behavior.
Monitoring and Tuning: Monitor the performance of your thread pool and adjust its configuration as needed to optimize resource usage and throughput.
Thread pools are a powerful tool in multi-threaded programming, allowing for efficient management of concurrent tasks, improved resource utilization, and better control over the execution of parallel workloads. Understanding the characteristics and types of thread pools is essential for designing robust and efficient multi-threaded applications.
Example: Simple Multi-Threaded Web Server
Creating a multi-threaded web server in Java that uses synchronization involves handling multiple client connections concurrently while ensuring that access to shared resources, such as server sockets and request processing, is synchronized to prevent data races and conflicts. Below is a detailed example of a multi-threaded web server using Java’s ServerSocket
, Thread
, and synchronization to handle incoming HTTP requests:
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class MultiThreadedWebServer {
private static final int PORT = 8080;
private static final int THREAD_POOL_SIZE = 10;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
System.out.println("MultiThreaded Web Server started on port " + PORT);
while (true) {
Socket clientSocket = serverSocket.accept(); // Accept incoming client connections
Runnable requestHandler = new RequestHandler(clientSocket);
executorService.submit(requestHandler); // Delegate request handling to a thread
}
}
}
class RequestHandler implements Runnable {
private Socket clientSocket;
public RequestHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
try {
handleRequest(clientSocket);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void handleRequest(Socket clientSocket) throws IOException {
// Read and process the HTTP request from the client
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String request;
while ((request = in.readLine()) != null) {
if (request.isEmpty()) {
break; // End of request headers
}
}
// Generate an HTTP response
String response = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"\r\n" +
"<html><body>Hello, World!</body></html>";
// Send the response to the client
out.println(response);
// Close the streams and the socket
in.close();
out.close();
}
}
In this example:
We create a MultiThreadedWebServer
class that listens for incoming client connections on port 8080 using a ServerSocket
.
We use an ExecutorService
to manage a fixed pool of worker threads (THREAD_POOL_SIZE
) responsible for handling incoming client requests.
Each incoming client connection is delegated to a RequestHandler
thread. This allows multiple clients to be served concurrently.
The RequestHandler
class implements the Runnable
interface, which defines the run()
method for handling each client request. It reads the HTTP request, processes it, generates an HTTP response, and sends it back to the client.
Synchronization is not explicitly shown in this basic example, but it would be necessary when dealing with shared resources or data structures in a more complex server implementation. For instance, if you were managing a shared data store, you would use synchronization mechanisms like synchronized
blocks or classes, or higher-level concurrent data structures from the java.util.concurrent
package to ensure thread safety.
This example demonstrates the fundamental structure of a multi-threaded web server in Java. To make it production-ready, you would need to handle various HTTP methods, error responses, content negotiation, and potentially use a more advanced framework or library to simplify the handling of HTTP requests and responses.
Conclusion
References & Resources
These resources below can provide additional information deepen your understanding of multi-threading in Java, best practices for concurrent programming, and performance optimization techniques.
Books:
“Java Concurrency in Practice” by Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea - This book is considered the definitive guide to Java concurrency and offers practical insights into writing thread-safe and scalable Java applications.
“Java Threads” by Scott Oaks and Henry Wong - A comprehensive guide to understanding Java threads, their lifecycle, and how to use them effectively.
“Java Performance: The Definitive Guide” by Scott Oaks - While not exclusively about multi-threading, this book covers performance optimization in Java, including topics related to multi-threading and concurrency.
Appendix A: Java’s Memory Model
Objectives
- Understanding Java’s Memory Model
- Happens-Before Relationship
- Memory Barriers and Visibility
Appendix A: Java’s Memory Model
Java’s Memory Model defines the rules and guarantees about how memory is accessed and manipulated by threads in a multi-threaded Java program. It ensures that multi-threaded programs behave predictably and consistently across different hardware and platforms. This appendix provides an in-depth explanation of Java’s Memory Model, illustrated with examples and sample code.
1. Shared Memory and Threads
In multi-threaded Java applications, multiple threads may access shared data simultaneously. It’s essential to understand how these threads interact with memory to prevent issues like data races, visibility problems, and unexpected behavior.
Example 1: Shared Variable
public class SharedVariableExample {
private static int sharedVariable = 0;
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
sharedVariable = 42;
});
Thread thread2 = new Thread(() -> {
int localValue = sharedVariable;
System.out.println("Thread 2: Shared Variable = " + localValue);
});
thread1.start();
thread2.start();
}
}
In this example, sharedVariable
is accessed by two threads concurrently. Without proper synchronization, the value of sharedVariable
may not be consistent between threads.
2. Happens-Before Relationship
Java’s Memory Model introduces the concept of the “happens-before” relationship. It defines the order in which actions performed by one thread are visible to other threads. Actions that happen-before other actions must be seen in the correct order by other threads.
Example 2: Happens-Before
public class HappensBeforeExample {
private static int sharedVariable = 0;
private static boolean flag = false;
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
sharedVariable = 42;
flag = true;
});
Thread thread2 = new Thread(() -> {
if (flag) {
System.out.println("Thread 2: Shared Variable = " + sharedVariable);
}
});
thread1.start();
thread2.start();
}
}
In this example, the flag
variable acts as a synchronization point. The happens-before relationship ensures that if flag
is true
in Thread 2, it must see the update to sharedVariable
made by Thread 1.
3. Synchronization
Synchronization in Java is achieved through the use of synchronized
blocks and methods, volatile
variables, and explicit locks like ReentrantLock
. These mechanisms enforce the happens-before relationship and ensure that threads access shared data safely.
Example 3: Synchronized Method
public class SynchronizedMethodExample {
private static int sharedVariable = 0;
public synchronized static void increment() {
sharedVariable++;
}
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
increment();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Shared Variable: " + sharedVariable);
}
}
In this example, the increment
method is synchronized, ensuring that only one thread can execute it at a time. This guarantees that the shared variable is modified safely.
4. Volatile Variables
The volatile
keyword is used to declare variables that are accessed by multiple threads. It ensures that reads and writes to the variable are atomic and that changes made by one thread are immediately visible to other threads.
Example 4: Volatile Variable
public class VolatileVariableExample {
private static volatile boolean flag = false;
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
flag = true;
});
Thread thread2 = new Thread(() -> {
while (!flag) {
// Spin-wait until flag becomes true
}
System.out.println("Thread 2: Flag is true.");
});
thread1.start();
thread2.start();
}
}
In this example, the flag
variable is declared as volatile
, ensuring that changes made by Thread 1 to flag
are immediately visible to Thread 2.
Java’s Memory Model is a critical part of Java’s multi-threading support, providing rules and guarantees that allow developers to write safe and correct multi-threaded programs. Understanding the principles of shared memory, the happens-before relationship, synchronization, and volatile variables is essential for writing reliable multi-threaded code in Java. Always consider these concepts when working with multi-threaded applications to avoid subtle concurrency issues and ensure the correctness of your code.
Appendix B: Java Thread API Reference
At-a-Glance
- java.lang.Thread
- java.util.concurrent Package
- java.util.concurrent.locks Package
Appendix B: Java Thread API Reference
This appendix provides a summary and high-level (and incomplete) overview of the Java Thread API, which is part of the java.lang
package.
Threads in Java are a fundamental component of multi-threaded programming, and the Thread class provides essential methods and functionality for creating and managing threads. In this reference, we’ll cover key methods and concepts related to the Java Thread API.
java.lang.Thread
Class
The Thread
class represents a thread of execution in a Java program. Threads are used for concurrent execution of code and can be created and managed using this class.
Constructors
Thread()
: Creates a new thread with no target Runnable.
Thread(Runnable target)
: Creates a new thread with the specified target Runnable.
Thread(ThreadGroup group, Runnable target)
: Creates a new thread with the specified target Runnable and places it in the specified thread group.
Thread(String name)
: Creates a new thread with the specified name.
Methods
start()
: Starts the execution of the thread. The run()
method of the Runnable associated with this thread is invoked.
run()
: This method contains the code that constitutes the new thread’s task. You can override this method by subclassing Thread.
join()
: Waits for this thread to die. It blocks until the thread on which it is called terminates.
setName(String name)
: Sets the name of the thread.
getName()
: Returns the name of the thread.
getId()
: Returns the unique identifier assigned to this thread.
isAlive()
: Tests if this thread is alive. A thread is considered alive if it has been started and has not yet died.
interrupt()
: Interrupts this thread, causing it to stop executing if it’s in a blocked state or throw an InterruptedException if it’s waiting.
isInterrupted()
: Tests whether the thread has been interrupted.
currentThread()
: Static method that returns the currently executing thread.
sleep(long millis)
: Causes the thread to sleep for the specified number of milliseconds.
yield()
: A hint to the scheduler that the current thread is willing to yield its current use of the processor.
setPriority(int priority)
: Sets the priority of this thread.
getPriority()
: Returns the priority of this thread.
setDaemon(boolean on)
: Marks this thread as either a daemon thread or a user thread.
isDaemon()
: Tests if this thread is a daemon thread.
getState()
: Returns the current state of this thread (e.g., NEW, RUNNABLE, BLOCKED, WAITING).
getThreadGroup()
: Returns the thread group to which this thread belongs.
setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
: Sets the default uncaught exception handler for this thread.
getUncaughtExceptionHandler()
: Returns the current default uncaught exception handler for this thread.
java.lang.Runnable
Interface
The Runnable
interface represents a task that can be executed concurrently by a thread. It defines a single abstract method run()
that should be implemented by classes that want to provide a concurrent task.
Methods
run()
: The abstract method that should contain the code to be executed by the thread.
Examples
Creating and Starting a Thread
Thread myThread = new Thread(() -> {
// Runnable code goes here
System.out.println("Thread is running.");
});
myThread.start(); // Starts the thread
Overriding the run()
Method
class MyThread extends Thread {
@Override
public void run() {
// Custom thread code
System.out.println("MyThread is running.");
}
}
MyThread myThread = new MyThread();
myThread.start();
Using Runnable
class MyRunnable implements Runnable {
@Override
public void run() {
// Custom runnable code
System.out.println("MyRunnable is running.");
}
}
Thread myThread = new Thread(new MyRunnable());
myThread.start();
This short reference section provided an overview of key classes and methods in the Java Thread API, which is essential for managing threads and concurrent execution in Java applications. Understanding these classes and their usage is crucial for developing multi-threaded Java programs effectively.
Appendix C: Glossary of Key Terms
Multi-Threading: The concurrent execution of multiple threads (smaller units of a process) in a single program to achieve parallelism and improve performance.
Multi-Processing: Concurrency achieved by running multiple processes simultaneously, each with its own memory space and resources, often on multiple CPU cores.
Hybrid Multi-Processing: Combines multi-threading within multiple processes, allowing for parallelism at both the process and thread levels.
Concurrency: The concept of multiple tasks appearing to be executed in overlapping time periods, often used interchangeably with multi-threading.
Thread: A lightweight, independent unit of execution within a process, capable of running concurrently with other threads.
Process: A separate, self-contained program with its own memory space, resources, and execution environment.
Synchronization: The coordination of multiple threads to ensure they access shared resources in a controlled and orderly manner, preventing data races and conflicts.
Deadlock: A situation in which two or more threads are unable to proceed because each is waiting for the other to release a resource.
Thread Pool: A collection of pre-created threads that can be reused to execute tasks, reducing the overhead of thread creation and destruction.
Task Queue: A data structure that holds tasks (units of work) to be executed by threads in a thread pool.
Happens-Before Relationship: A relationship defined by the Java Memory Model that ensures a specific order of execution or visibility between actions in different threads.
Volatile Variable: A variable in Java declared as volatile
that ensures atomic reads and writes and guarantees visibility of changes to other threads.
Synchronized: A Java keyword that can be used with methods and blocks to ensure exclusive access to critical sections of code, preventing concurrent access issues.
API: Abbreviation for “Application Programming Interface,” which defines the methods, classes, and protocols for building software and interacting with libraries.
Thread Safety: A property of code or data structures that guarantees correct behavior in a multi-threaded environment without data races or other concurrency issues.
Blocking Queue: A thread-safe data structure that allows elements to be enqueued and dequeued, blocking when necessary to maintain thread safety and synchronization.
Callable: An interface in Java that represents a task that can be executed and return a result, often used in conjunction with thread pools.
Future: An object in Java that represents the result of an asynchronous computation, providing a way to retrieve the result or handle exceptions when the task completes.
Concurrent Programming: The design and implementation of software that can effectively and safely run multiple threads or processes concurrently.
Java Memory Model: A set of rules and guarantees that define how memory is accessed and manipulated by threads in a multi-threaded Java program.
Atomic Operation: An operation that is performed as a single, indivisible unit, ensuring that it is not interrupted or interleaved by other threads.
Race Condition: A situation in which the behavior of a program depends on the relative timing of events, often leading to unintended and unpredictable results.
Daemon Thread: A thread in Java that runs in the background and does not prevent the JVM from exiting when all non-daemon threads have finished executing.
Thread Group: A mechanism in Java to group multiple threads together, providing organizational and management capabilities.
Uncaught Exception Handler: A mechanism in Java for handling exceptions that occur in threads but are not caught within the thread’s code.
CPU Core: A physical processing unit on a CPU chip capable of executing instructions independently, often used to run threads in parallel.
Thread Priority: A numeric value assigned to a thread that hints at its relative importance to the scheduler, affecting its scheduling order.
Concurrency Bug: A type of software bug that arises in multi-threaded or concurrent programs due to unexpected interactions between threads.
Thread State: The current condition or status of a thread, such as NEW, RUNNABLE, BLOCKED, WAITING, etc., indicating what the thread is currently doing.
Thread Interruption: A mechanism to request that a thread voluntarily terminate or perform some other action, typically used for thread management and cleanup.
Thread Sleep: A method that pauses the execution of a thread for a specified duration, allowing other threads to run.
Busy Waiting: A synchronization technique in which a thread repeatedly checks a condition within a loop, potentially consuming CPU resources.
Blocking: A state in which a thread is paused, often due to waiting for an event or resource to become available.
These terms cover a wide range of concepts related to multi-threading, concurrency, and the Java Thread API, providing a comprehensive glossary for the conversation.
LS0tCnRpdGxlOiAiTXVsdGktVGhyZWFkaW5nIGFuZCBUaHJlYWQgU3luY2hyb25pemF0aW9uIGluIEphdmEiCnBhcmFtczoKICBjYXRlZ29yeTogOQogIG51bWJlcjogNTAxCiAgdGltZTogIjYwIG1pbiIKICBsZXZlbDogaW50ZXJtZWRpYXRlCiAgdGFnczogIkphdmEsc3luY2hyb25pemF0aW9uLG11bHRpLXRocmVhZGluZyxyYWNlIGNvbmRpdGlvbnMiCiAgZGVzY3JpcHRpb246ICJFeGxwbGFpbnMgaG93IG11bHRpLXRocmVhZGluZyBpcyBzdXBwb3J0ZWQgYnkgSmF2YQogICAgICAgICAgICAgICAgYW5kIGhvdyB0aHJlYWRzIGFyZSBjb21tb25seSBzeW5jaHJvbml6ZWQgdG8gYXZvaWQKICAgICAgICAgICAgICAgIHJhY2UgY29uZGl0aW9ucy4iCmRhdGU6ICI8c21hbGw+YHIgU3lzLkRhdGUoKWA8L3NtYWxsPiIKYXV0aG9yOiAiPHNtYWxsPk1hcnRpbiBTY2hlZGxiYXVlcjwvc21hbGw+IgplbWFpbDogIm0uc2NoZWRsYmF1ZXJAbmV1LmVkdSIKYWZmaWxpdGF0aW9uOiAiTm9ydGhlYXN0ZXJuIFVuaXZlcnNpdHkiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCi0tLQp0aXRsZTogIjxzbWFsbD5gciBwYXJhbXMkY2F0ZWdvcnlgLmByIHBhcmFtcyRudW1iZXJgPC9zbWFsbD48YnIvPjxzcGFuIHN0eWxlPSdjb2xvcjogIzJFNDA1MzsgZm9udC1zaXplOiAwLjllbSc+YHIgcm1hcmtkb3duOjptZXRhZGF0YSR0aXRsZWA8L3NwYW4+IgotLS0KCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19pbnNlcnQyREIuUicpKSwgaW5jbHVkZSA9IEZBTFNFfQpgYGAKCiMjIE92ZXJ2aWV3CgpUaGlzIGxlc3NvbiBleHBsb3JlcyBtdWx0aS10aHJlYWRpbmcgaW4gSmF2YSBhbmQgdGhlIG1lY2hhbmlzbXMgSmF2YSBvZmZlcnMgZm9yIHRocmVhZCBzeW5jaHJvbml6YXRpb24uIEl0IHdpbGwgZXhwbGFpbiBKYXZhJ3MgbXVsdGktdGhyZWFkaW5nIGNhcGFiaWxpdGllcyBhbmQgdGhyZWFkIHN5bmNocm9uaXphdGlvbiBtZWNoYW5pc21zIHN0YXJ0aW5nIGZyb20gdGhlIGJhc2ljcyBvZiBjcmVhdGluZyBhbmQgbWFuYWdpbmcgdGhyZWFkcyB0byBhZHZhbmNlZCBzeW5jaHJvbml6YXRpb24gdGVjaG5pcXVlcyBhbmQgcmVhbC13b3JsZCBhcHBsaWNhdGlvbiBzY2VuYXJpb3MuIEZvY3VzZWQgd2lsbCBiZSBwbGFjZWQgb24gdGhlIGtub3dsZWRnZSBhbmQgc2tpbGxzIG5lY2Vzc2FyeSB0byB3cml0ZSBlZmZpY2llbnQgYW5kIHRocmVhZC1zYWZlIEphdmEgYXBwbGljYXRpb25zIGZvciBKVk0gY29kZSBydW5uaW5nIG9uIG1vZGVybiBtdWx0aS1jb3JlIENQVXMuCgojIyBNdWx0aS1UaHJlYWRpbmcgYW5kIE11bHRpLVByb2Nlc3NpbmcKCk11bHRpLXRocmVhZGluZyBhbmQgbXVsdGktcHJvY2Vzc2luZyBhcmUgdHdvIG1ldGhvZHMgZm9yIHJ1bm5pbmcgbXVsdGlwbGUsIGNvbmN1cnJlbnQgcGF0aHMgb2YgZXhlY3V0aW9uLiBCb3RoIGFyZSBlc3NlbnRpYWwgZm9yIGJ1aWxkaW5nIG9wZXJhdGluZyBzeXN0ZW1zIGFuZCBtb2Rlcm4gc29mdHdhcmUgc3lzdGVtcy4gV2hpbGUgdGhleSBhcmUgc2ltaWxhciBpbiB0aGF0IHRoZXkgcnVuIGNvZGUgY29uY3VycmVudGx5LCB0aGVyZSBhcmUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGVtIGFuZCBkZXZlbG9wZXJzIG11c3QgY2FyZWZ1bGx5IGNob29zZSBhbiBhcHByb3ByaWF0ZSBtZWNoYW5pc20gZGVwZW5kaW5nIG9uIHJlcXVpcmVtZW50cywgb3BlcmF0aW5nIGFuZCBwcm9ncmFtbWluZyBsYW5ndWFnZSBzdXBwb3J0LCBhbmQgdGhlIGRlc2lyZWQgaXNvbGF0aW9uIG9mIHRoZSBkaWZmZXJlbnQgcGF0aHMgb2YgZXhlY3V0aW9uLiBCb3RoIGFwcHJvYWNoZXMgYXJlIHVzZWQgaW4gdGhlIGNvbnN0cnVjdGlvbiBvZiBjbGllbnQvc2VydmVyIGFwcGxpY2F0aW9uIGFyY2hpdGVjdHVyZXMgYW5kIGFyZSBzb21ldGltZXMgY29tYmluZWQgaW4gYSBoeWJyaWQgYXJjaGl0ZWN0dXJlLgoKKipNdWx0aS1UaHJlYWRpbmcqKiBpcyB0aGUgY29uY3VycmVudCBleGVjdXRpb24gb2YgbXVsdGlwbGUgdGhyZWFkcyAqd2l0aGluIGEgc2luZ2xlIHByb2Nlc3MqLCBhbGxvd2luZyB0YXNrcyB0byBydW4gaW5kZXBlbmRlbnRseSBidXQgKnNoYXJlIHRoZSBzYW1lIG1lbW9yeSogc3BhY2UgYW5kIHJlc291cmNlcy4gSXQgaXMgaWRlYWwgZm9yIHNjZW5hcmlvcyB3aGVyZSB0YXNrcyBuZWVkIHRvIGJlIGNvb3JkaW5hdGVkIHdpdGhpbiBhIHNpbmdsZSBwcm9ncmFtLCBvZnRlbiBvbiBhIG11bHRpLWNvcmUgQ1BVLgoKKipNdWx0aS1Qcm9jZXNzaW5nKiogaXMgdGhlIGNvbmN1cnJlbnQgZXhlY3V0aW9uIG9mIG11bHRpcGxlICppbmRlcGVuZGVudCBwcm9jZXNzZXMqLCBlYWNoIHdpdGggaXRzIG93biAqc2VwYXJhdGUgbWVtb3J5KiBzcGFjZSBhbmQgcmVzb3VyY2VzLiBQcm9jZXNzZXMgcnVuIGluZGVwZW5kZW50bHkgYW5kIGNhbiB0YWtlIGFkdmFudGFnZSBvZiBtdWx0aXBsZSBDUFUgY29yZXMgb3IgZXZlbiBydW4gb24gc2VwYXJhdGUgbWFjaGluZXMuIEl0J3Mgc3VpdGFibGUgZm9yIHNjZW5hcmlvcyB0aGF0IHJlcXVpcmUgaXNvbGF0aW9uLCBmYXVsdCB0b2xlcmFuY2UsIGFuZCB0cnVlIHBhcmFsbGVsaXNtLgoKIyMjIE11bHRpLVRocmVhZGluZwoKTXVsdGktdGhyZWFkaW5nIGlzIGEgZnVuZGFtZW50YWwgY29uY2VwdCBpbiBjb21wdXRlciBzY2llbmNlIGFuZCBzb2Z0d2FyZSBkZXZlbG9wbWVudCB0aGF0IGludm9sdmVzIHRoZSBzaW11bHRhbmVvdXMgZXhlY3V0aW9uIG9mIG11bHRpcGxlIHRocmVhZHMgd2l0aGluIGEgc2luZ2xlIHByb2Nlc3Mgb3IgcHJvZ3JhbS4gRWFjaCB0aHJlYWQgcmVwcmVzZW50cyBhIHNlcXVlbmNlIG9mIGluc3RydWN0aW9ucyB0aGF0IGNhbiBleGVjdXRlIGluZGVwZW5kZW50bHkgYnV0IHNoYXJlcyB0aGUgc2FtZSBtZW1vcnkgc3BhY2UgYW5kIHJlc291cmNlcyB3aXRoIG90aGVyIHRocmVhZHMgaW4gdGhlIHNhbWUgcHJvY2Vzcy4gTXVsdGktdGhyZWFkaW5nIGVuYWJsZXMgYSBwcm9ncmFtIHRvIHBlcmZvcm0gbXVsdGlwbGUgdGFza3MgY29uY3VycmVudGx5LCBpbXByb3ZpbmcgaXRzIHJlc3BvbnNpdmVuZXNzLCBwZXJmb3JtYW5jZSwgYW5kIHJlc291cmNlIHV0aWxpemF0aW9uLgoKSGVyZSBhcmUgc29tZSBrZXkgYXNwZWN0cyBhbmQgZXhwbGFuYXRpb25zIG9mIG11bHRpLXRocmVhZGluZzoKCjEuICAqKlRocmVhZCoqOiBBIHRocmVhZCBjYW4gYmUgdGhvdWdodCBvZiBhcyBhIGxpZ2h0d2VpZ2h0LCBpbmRlcGVuZGVudCB1bml0IG9mIGV4ZWN1dGlvbiB3aXRoaW4gYSBwcm9ncmFtLiBUaHJlYWRzIHNoYXJlIHRoZSBzYW1lIGNvZGUgc2VnbWVudCBhbmQgZGF0YSBzcGFjZSAobWVtb3J5KSB3aXRoIG90aGVyIHRocmVhZHMgaW4gdGhlIHNhbWUgcHJvY2Vzcy4gVGhleSBoYXZlIHRoZWlyIG93biBwcm9ncmFtIGNvdW50ZXIsIHN0YWNrLCBhbmQgcmVnaXN0ZXIgc2V0LCB3aGljaCBhbGxvd3MgdGhlbSB0byBleGVjdXRlIGluZGVwZW5kZW50bHkuCgoyLiAgKipDb25jdXJyZW5jeSoqOiBNdWx0aS10aHJlYWRpbmcgaXMgYSB3YXkgdG8gYWNoaWV2ZSBjb25jdXJyZW5jeSBpbiBhIHByb2dyYW0uIENvbmN1cnJlbmN5IHJlZmVycyB0byB0aGUgYWJpbGl0eSBvZiBhIHByb2dyYW0gdG8gZXhlY3V0ZSBtdWx0aXBsZSB0YXNrcyBvciBvcGVyYXRpb25zIHNpbXVsdGFuZW91c2x5LCB3aXRob3V0IG5lY2Vzc2FyaWx5IHJ1bm5pbmcgdGhlbSBpbiBwYXJhbGxlbC4KCjMuICAqKlBhcmFsbGVsaXNtKio6IFdoaWxlIG11bHRpLXRocmVhZGluZyBhbGxvd3MgZm9yIGNvbmN1cnJlbmN5LCBpdCdzIGltcG9ydGFudCB0byBkaXN0aW5ndWlzaCBpdCBmcm9tIHBhcmFsbGVsaXNtLiBQYXJhbGxlbGlzbSByZWZlcnMgdG8gdGhlIHNpbXVsdGFuZW91cyBleGVjdXRpb24gb2YgbXVsdGlwbGUgdGhyZWFkcyBvciBwcm9jZXNzZXMgb24gbXVsdGlwbGUgQ1BVIGNvcmVzIG9yIHByb2Nlc3NvcnMuIE5vdCBhbGwgY29uY3VycmVudCBwcm9ncmFtcyBhcmUgcGFyYWxsZWw7IHNvbWUgbWF5IHJ1biBvbiBhIHNpbmdsZSBjb3JlIGFuZCBzd2l0Y2ggYmV0d2VlbiB0aHJlYWRzIHRvIGFjaGlldmUgY29uY3VycmVuY3kuCgo0LiAgKipCZW5lZml0cyBvZiBNdWx0aS1UaHJlYWRpbmcqKjoKCiAgICAtICAgKipSZXNwb25zaXZlbmVzcyoqOiBNdWx0aS10aHJlYWRpbmcgaXMgY3J1Y2lhbCBmb3IgYXBwbGljYXRpb25zIHdpdGggdXNlciBpbnRlcmZhY2VzIChlLmcuLCBHVUlzIG9yIHdlYiBzZXJ2ZXJzKSB0byByZW1haW4gcmVzcG9uc2l2ZSB3aGlsZSBoYW5kbGluZyBiYWNrZ3JvdW5kIHRhc2tzLgogICAgLSAgICoqUGVyZm9ybWFuY2UqKjogTXVsdGktdGhyZWFkaW5nIGNhbiBpbXByb3ZlIHBlcmZvcm1hbmNlIGJ5IHV0aWxpemluZyBtdWx0aXBsZSBDUFUgY29yZXMgZWZmaWNpZW50bHkuIFRhc2tzIGNhbiBiZSBkaXZpZGVkIGFtb25nIHRocmVhZHMsIG1ha2luZyB1c2Ugb2YgYXZhaWxhYmxlIHByb2Nlc3NpbmcgcG93ZXIuCiAgICAtICAgKipSZXNvdXJjZSBVdGlsaXphdGlvbioqOiBNdWx0aS10aHJlYWRpbmcgaGVscHMgaW4gZWZmaWNpZW50IHJlc291cmNlIHV0aWxpemF0aW9uLCBhcyB0aHJlYWRzIGNhbiBydW4gY29uY3VycmVudGx5IG9uIGRpZmZlcmVudCBDUFUgY29yZXMsIG1heGltaXppbmcgc3lzdGVtIHJlc291cmNlIHVzYWdlLgogICAgLSAgICoqU2NhbGFiaWxpdHkqKjogSW4gbW9kZXJuIGNvbXB1dGluZyBlbnZpcm9ubWVudHMgd2l0aCBtdWx0aS1jb3JlIENQVXMsIG11bHRpLXRocmVhZGluZyBpcyBlc3NlbnRpYWwgZm9yIGJ1aWxkaW5nIHNjYWxhYmxlIGFwcGxpY2F0aW9ucy4KCjUuICAqKlRocmVhZCBTdGF0ZXMgYW5kIExpZmVjeWNsZSoqOiBUaHJlYWRzIGdvIHRocm91Z2ggdmFyaW91cyBzdGF0ZXMgZHVyaW5nIHRoZWlyIGxpZmVjeWNsZSwgaW5jbHVkaW5nIG5ldywgcnVubmFibGUsIGJsb2NrZWQsIHdhaXRpbmcsIHRpbWVkIHdhaXRpbmcsIGFuZCB0ZXJtaW5hdGVkLiBUaGUgSmF2YSBwcm9ncmFtbWluZyBsYW5ndWFnZSwgZm9yIGV4YW1wbGUsIHByb3ZpZGVzIGEgd2VsbC1kZWZpbmVkIHRocmVhZCBsaWZlY3ljbGUgYW5kIEFQSXMgZm9yIG1hbmFnaW5nIHRocmVhZHMuCgo2LiAgKipUaHJlYWQgU3luY2hyb25pemF0aW9uKio6IFdoZW4gbXVsdGlwbGUgdGhyZWFkcyBhY2Nlc3Mgc2hhcmVkIGRhdGEgb3IgcmVzb3VyY2VzLCB0aGVyZSBpcyBhIHJpc2sgb2YgZGF0YSBjb3JydXB0aW9uIG9yIHJhY2UgY29uZGl0aW9ucy4gVGhyZWFkIHN5bmNocm9uaXphdGlvbiBtZWNoYW5pc21zLCBzdWNoIGFzIGxvY2tzLCBzZW1hcGhvcmVzLCBhbmQgbW9uaXRvcnMsIGFyZSB1c2VkIHRvIGNvb3JkaW5hdGUgYW5kIGNvbnRyb2wgYWNjZXNzIHRvIHNoYXJlZCByZXNvdXJjZXMgdG8gZW5zdXJlIGRhdGEgY29uc2lzdGVuY3kuCgo3LiAgKipFeGFtcGxlcyBvZiBNdWx0aS1UaHJlYWRpbmcqKjoKCiAgICAtICAgQSB3ZWIgc2VydmVyIGhhbmRsaW5nIG11bHRpcGxlIGNsaWVudCByZXF1ZXN0cyBjb25jdXJyZW50bHkuCiAgICAtICAgQSB3b3JkIHByb2Nlc3NvciB3aXRoIGEgc3BlbGwtY2hlY2tlciBydW5uaW5nIGluIHRoZSBiYWNrZ3JvdW5kIHdoaWxlIHRoZSB1c2VyIGNvbnRpbnVlcyB0eXBpbmcuCiAgICAtICAgQSB2aWRlbyBwbGF5ZXIgZGVjb2RpbmcgYW5kIHJlbmRlcmluZyB2aWRlbyBmcmFtZXMgd2hpbGUgc2ltdWx0YW5lb3VzbHkgaGFuZGxpbmcgdXNlciBpbnB1dC4KCkluIHN1bW1hcnksIG11bHRpLXRocmVhZGluZyBpcyBhIHBvd2VyZnVsIHRlY2huaXF1ZSB0aGF0IGVuYWJsZXMgY29uY3VycmVudCBleGVjdXRpb24gb2YgdGFza3Mgd2l0aGluIGEgc2luZ2xlIHByb2dyYW0sIGVuaGFuY2luZyByZXNwb25zaXZlbmVzcywgcGVyZm9ybWFuY2UsIGFuZCByZXNvdXJjZSB1dGlsaXphdGlvbi4gSG93ZXZlciwgaXQgYWxzbyBpbnRyb2R1Y2VzIGNoYWxsZW5nZXMgcmVsYXRlZCB0byB0aHJlYWQgc3luY2hyb25pemF0aW9uIGFuZCBjb29yZGluYXRpb24sIHdoaWNoIG11c3QgYmUgY2FyZWZ1bGx5IG1hbmFnZWQgdG8gZW5zdXJlIGRhdGEgY29uc2lzdGVuY3kgYW5kIGF2b2lkIGlzc3VlcyBsaWtlIHJhY2UgY29uZGl0aW9ucy4KCiMjIyBNdWx0aS1Qcm9jZXNzaW5nCgpNdWx0aS1wcm9jZXNzaW5nIGlzIGEgY29uY2VwdCBpbiBjb21wdXRlciBzY2llbmNlIGFuZCBzb2Z0d2FyZSBkZXZlbG9wbWVudCB0aGF0IGludm9sdmVzIHRoZSBleGVjdXRpb24gb2YgbXVsdGlwbGUgaW5kZXBlbmRlbnQgcHJvY2Vzc2VzIGNvbmN1cnJlbnRseSwgZWFjaCB3aXRoIGl0cyBvd24gbWVtb3J5IHNwYWNlLCByZXNvdXJjZXMsIGFuZCBzdGF0ZS4gVW5saWtlIG11bHRpLXRocmVhZGluZywgd2hlcmUgbXVsdGlwbGUgdGhyZWFkcyBzaGFyZSB0aGUgc2FtZSBtZW1vcnkgc3BhY2Ugd2l0aGluIGEgc2luZ2xlIHByb2Nlc3MsIG11bHRpLXByb2Nlc3NpbmcgYWxsb3dzIGRpZmZlcmVudCBwcm9jZXNzZXMgdG8gcnVuIHNpbXVsdGFuZW91c2x5LCBvZnRlbiBvbiBzZXBhcmF0ZSBDUFUgY29yZXMgb3IgZXZlbiBvbiBkaWZmZXJlbnQgcGh5c2ljYWwgbWFjaGluZXMuIEVhY2ggcHJvY2VzcyBvcGVyYXRlcyBpbmRlcGVuZGVudGx5LCBhbmQgdGhleSBjYW4gY29tbXVuaWNhdGUgd2l0aCBlYWNoIG90aGVyIHRocm91Z2ggaW50ZXItcHJvY2VzcyBjb21tdW5pY2F0aW9uIChJUEMpIG1lY2hhbmlzbXMuIExldCdzIGV4cGxvcmUgdGhlIGtleSBhc3BlY3RzIGFuZCBleHBsYW5hdGlvbnMgb2YgbXVsdGktcHJvY2Vzc2luZzoKCjEuICAqKlByb2Nlc3MqKjogQSBwcm9jZXNzIGlzIGFuIGluZGVwZW5kZW50IHByb2dyYW0gdGhhdCBydW5zIGluIGl0cyBvd24gbWVtb3J5IHNwYWNlLiBFYWNoIHByb2Nlc3MgaGFzIGl0cyBvd24gbWVtb3J5IGFsbG9jYXRpb24sIHByb2dyYW0gY291bnRlciwgc3RhY2ssIGFuZCByZXNvdXJjZXMuIFByb2Nlc3NlcyBhcmUgaXNvbGF0ZWQgZnJvbSBlYWNoIG90aGVyLCB3aGljaCBtZWFucyB0aGF0IGEgZmFpbHVyZSBvciBjcmFzaCBpbiBvbmUgcHJvY2VzcyB0eXBpY2FsbHkgZG9lcyBub3QgYWZmZWN0IG90aGVyIHByb2Nlc3Nlcy4KCjIuICAqKkNvbmN1cnJlbmN5Kio6IE11bHRpLXByb2Nlc3NpbmcgYWxsb3dzIGZvciB0cnVlIGNvbmN1cnJlbmN5LCBhcyBkaWZmZXJlbnQgcHJvY2Vzc2VzIGNhbiBydW4gc2ltdWx0YW5lb3VzbHkgb24gbXVsdGlwbGUgQ1BVIGNvcmVzIG9yIHByb2Nlc3NvcnMuIFRoaXMgZW5hYmxlcyB0aGUgZXhlY3V0aW9uIG9mIG11bHRpcGxlIHRhc2tzIG9yIHByb2dyYW1zIGNvbmN1cnJlbnRseS4KCjMuICAqKlBhcmFsbGVsaXNtKio6IE11bHRpLXByb2Nlc3NpbmcgY2FuIGxlYWQgdG8gcGFyYWxsZWxpc20gd2hlbiBwcm9jZXNzZXMgYXJlIGV4ZWN1dGVkIHNpbXVsdGFuZW91c2x5IG9uIHNlcGFyYXRlIENQVSBjb3JlcyBvciBwcm9jZXNzb3JzLiBQYXJhbGxlbGlzbSBhbGxvd3MgZm9yIG1heGltdW0gdXRpbGl6YXRpb24gb2YgYXZhaWxhYmxlIGhhcmR3YXJlIHJlc291cmNlcyBhbmQgY2FuIHNpZ25pZmljYW50bHkgaW1wcm92ZSBwZXJmb3JtYW5jZSBmb3IgY29tcHV0ZS1pbnRlbnNpdmUgdGFza3MuCgo0LiAgKipCZW5lZml0cyBvZiBNdWx0aS1Qcm9jZXNzaW5nKio6CgogICAgLSAgICoqSXNvbGF0aW9uKio6IFByb2Nlc3NlcyBhcmUgaXNvbGF0ZWQgZnJvbSBlYWNoIG90aGVyLCBwcm92aWRpbmcgYSBoaWdoIGRlZ3JlZSBvZiBmYXVsdCB0b2xlcmFuY2UuIElmIG9uZSBwcm9jZXNzIGNyYXNoZXMsIGl0IGRvZXNuJ3QgbmVjZXNzYXJpbHkgYWZmZWN0IG90aGVyIHByb2Nlc3Nlcy4KICAgIC0gICAqKlJlc291cmNlIEFsbG9jYXRpb24qKjogRWFjaCBwcm9jZXNzIGhhcyBpdHMgb3duIG1lbW9yeSBzcGFjZSBhbmQgcmVzb3VyY2VzLCBtYWtpbmcgaXQgZWFzaWVyIHRvIG1hbmFnZSByZXNvdXJjZSBhbGxvY2F0aW9uIGFuZCBpc29sYXRpb24uCiAgICAtICAgKipQYXJhbGxlbCBFeGVjdXRpb24qKjogTXVsdGktcHJvY2Vzc2luZyBjYW4gdGFrZSBmdWxsIGFkdmFudGFnZSBvZiBtdWx0aS1jb3JlIENQVXMgYW5kIGRpc3RyaWJ1dGVkIGNvbXB1dGluZyBlbnZpcm9ubWVudHMgdG8gZXhlY3V0ZSB0YXNrcyBpbiBwYXJhbGxlbC4KICAgIC0gICAqKkVuaGFuY2VkIFNlY3VyaXR5Kio6IFByb2Nlc3MgaXNvbGF0aW9uIGNhbiBlbmhhbmNlIHNlY3VyaXR5IGJ5IHByZXZlbnRpbmcgdW5hdXRob3JpemVkIGFjY2VzcyB0byBtZW1vcnkgYW5kIHJlc291cmNlcyBvZiBvdGhlciBwcm9jZXNzZXMuCgo1LiAgKipQcm9jZXNzIFN5bmNocm9uaXphdGlvbioqOiBJbiBtdWx0aS1wcm9jZXNzaW5nLCBwcm9jZXNzZXMgY2FuIHJ1biBpbmRlcGVuZGVudGx5LCBidXQgdGhlcmUgbWF5IGJlIGNhc2VzIHdoZXJlIHRoZXkgbmVlZCB0byBzeW5jaHJvbml6ZSB0aGVpciBhY3Rpb25zIG9yIHNoYXJlIGRhdGEuIElQQyBtZWNoYW5pc21zIHN1Y2ggYXMgcGlwZXMsIG1lc3NhZ2UgcXVldWVzLCBzaGFyZWQgbWVtb3J5LCBhbmQgc29ja2V0cyBhcmUgdXNlZCBmb3IgaW50ZXItcHJvY2VzcyBjb21tdW5pY2F0aW9uIGFuZCBzeW5jaHJvbml6YXRpb24uCgo2LiAgKipFeGFtcGxlcyBvZiBNdWx0aS1Qcm9jZXNzaW5nKio6CgogICAgLSAgIEEgd2ViIHNlcnZlciBoYW5kbGluZyBtdWx0aXBsZSBjbGllbnQgcmVxdWVzdHMgYnkgY3JlYXRpbmcgc2VwYXJhdGUgcHJvY2Vzc2VzIGZvciBlYWNoIGNvbm5lY3Rpb24uCiAgICAtICAgQSBtb2Rlcm4gb3BlcmF0aW5nIHN5c3RlbSwgd2hlcmUgdmFyaW91cyBzeXN0ZW0gc2VydmljZXMgYW5kIGFwcGxpY2F0aW9ucyBydW4gYXMgc2VwYXJhdGUgcHJvY2Vzc2VzLgogICAgLSAgIERpc3RyaWJ1dGVkIGNvbXB1dGluZyBhcHBsaWNhdGlvbnMgdGhhdCBleGVjdXRlIHRhc2tzIG9uIGRpZmZlcmVudCBtYWNoaW5lcyBvciBub2Rlcy4KCkluIHN1bW1hcnksIG11bHRpLXByb2Nlc3NpbmcgYWxsb3dzIGZvciBjb25jdXJyZW50IGV4ZWN1dGlvbiBvZiBtdWx0aXBsZSBpbmRlcGVuZGVudCBwcm9jZXNzZXMsIGVhY2ggd2l0aCBpdHMgb3duIG1lbW9yeSBzcGFjZSBhbmQgcmVzb3VyY2VzLiBUaGlzIGFwcHJvYWNoIGlzIHdlbGwtc3VpdGVkIGZvciBzY2VuYXJpb3Mgd2hlcmUgaXNvbGF0aW9uLCBmYXVsdCB0b2xlcmFuY2UsIGFuZCB0cnVlIHBhcmFsbGVsaXNtIGFyZSBlc3NlbnRpYWwuIFdoaWxlIG11bHRpLXByb2Nlc3Npbmcgb2ZmZXJzIGJlbmVmaXRzIGluIHRlcm1zIG9mIHJlc291cmNlIGlzb2xhdGlvbiBhbmQgZmF1bHQgdG9sZXJhbmNlLCBpdCBhbHNvIGludHJvZHVjZXMgY2hhbGxlbmdlcyByZWxhdGVkIHRvIHByb2Nlc3MgY29tbXVuaWNhdGlvbiBhbmQgc3luY2hyb25pemF0aW9uLCB3aGljaCBtdXN0IGJlIGNhcmVmdWxseSBtYW5hZ2VkIGZvciBzdWNjZXNzZnVsIG11bHRpLXByb2Nlc3NpbmcgYXBwbGljYXRpb25zLgoKIyMjIEh5YnJpZCBBcmNoaXRlY3R1cmUKCkEgaHlicmlkIG11bHRpLXByb2Nlc3Npbmcgd2l0aCBtdWx0aS10aHJlYWRpbmcgYXJjaGl0ZWN0dXJlIGNvbWJpbmVzIGVsZW1lbnRzIG9mIGJvdGggbXVsdGktcHJvY2Vzc2luZyBhbmQgbXVsdGktdGhyZWFkaW5nIHRvIHRha2UgYWR2YW50YWdlIG9mIHRoZSBiZW5lZml0cyBvZiBlYWNoIGFwcHJvYWNoLiBJbiB0aGlzIGFyY2hpdGVjdHVyZSwgeW91IGhhdmUgbXVsdGlwbGUgaW5kZXBlbmRlbnQgcHJvY2Vzc2VzIHJ1bm5pbmcgY29uY3VycmVudGx5LCBhbmQgZWFjaCBvZiB0aGVzZSBwcm9jZXNzZXMgY29udGFpbnMgbXVsdGlwbGUgdGhyZWFkcyB0aGF0IGNhbiBleGVjdXRlIGluZGVwZW5kZW50bHkgd2l0aGluIHRoYXQgcHJvY2Vzcy4gVGhpcyBjb21iaW5hdGlvbiBhbGxvd3MgZm9yIGEgZmxleGlibGUgYW5kIHBvd2VyZnVsIGFwcHJvYWNoIHRvIGNvbmN1cnJlbnQgcHJvZ3JhbW1pbmcuCgpIZXJlIGFyZSB0aGUga2V5IGNoYXJhY3RlcmlzdGljcyBvZiBhIGh5YnJpZCBtdWx0aS1wcm9jZXNzaW5nIHdpdGggbXVsdGktdGhyZWFkaW5nIGFyY2hpdGVjdHVyZToKCjEuICAqKk11bHRpcGxlIFByb2Nlc3NlcyoqOiBUaGUgc3lzdGVtIGNvbnNpc3RzIG9mIG11bHRpcGxlIHNlcGFyYXRlIHByb2Nlc3NlcywgZWFjaCB3aXRoIGl0cyBvd24gbWVtb3J5IHNwYWNlIGFuZCByZXNvdXJjZXMuIFRoZXNlIHByb2Nlc3NlcyBjYW4gcnVuIGluZGVwZW5kZW50bHkgYW5kIG1heSBldmVuIGJlIGV4ZWN1dGVkIG9uIGRpZmZlcmVudCBDUFUgY29yZXMgb3IgcGh5c2ljYWwgbWFjaGluZXMuCgoyLiAgKipNdWx0aS1UaHJlYWRpbmcgV2l0aGluIEVhY2ggUHJvY2VzcyoqOiBXaXRoaW4gZWFjaCBpbmRpdmlkdWFsIHByb2Nlc3MsIG11bHRpLXRocmVhZGluZyBpcyBlbXBsb3llZC4gVGhpcyBtZWFucyB0aGF0IGVhY2ggcHJvY2VzcyBjb250YWlucyBtdWx0aXBsZSB0aHJlYWRzIHRoYXQgc2hhcmUgdGhlIHNhbWUgbWVtb3J5IHNwYWNlIGFuZCByZXNvdXJjZXMgc3BlY2lmaWMgdG8gdGhhdCBwcm9jZXNzLiBUaGVzZSB0aHJlYWRzIGNhbiBleGVjdXRlIGNvbmN1cnJlbnRseSBhbmQgdGFrZSBhZHZhbnRhZ2Ugb2YgbXVsdGktY29yZSBDUFVzIHdpdGhpbiB0aGUgc2NvcGUgb2YgdGhlaXIgcGFyZW50IHByb2Nlc3MuCgozLiAgKipJc29sYXRpb24qKjogUHJvY2Vzc2VzIGFyZSBpc29sYXRlZCBmcm9tIGVhY2ggb3RoZXIsIHByb3ZpZGluZyBhIGhpZ2ggZGVncmVlIG9mIGZhdWx0IHRvbGVyYW5jZSBhbmQgc2VjdXJpdHkuIElmIG9uZSBwcm9jZXNzIGVuY291bnRlcnMgYW4gaXNzdWUgb3IgY3Jhc2hlcywgaXQgaXMgbGVzcyBsaWtlbHkgdG8gaW1wYWN0IG90aGVyIHByb2Nlc3Nlcy4KCjQuICAqKlBhcmFsbGVsaXNtKio6IEJvdGggaW50ZXItcHJvY2VzcyBwYXJhbGxlbGlzbSAoYmV0d2VlbiBwcm9jZXNzZXMpIGFuZCBpbnRyYS1wcm9jZXNzIHBhcmFsbGVsaXNtICh3aXRoaW4gYSBwcm9jZXNzKSBjYW4gYmUgYWNoaWV2ZWQuIFRoaXMgYWxsb3dzIGZvciBlZmZpY2llbnQgdXRpbGl6YXRpb24gb2YgaGFyZHdhcmUgcmVzb3VyY2VzIG9uIGJvdGggdGhlIHByb2Nlc3MgYW5kIHRocmVhZCBsZXZlbHMuCgo1LiAgKipGbGV4aWJpbGl0eSoqOiBUaGUgY29tYmluYXRpb24gb2YgcHJvY2Vzc2VzIGFuZCB0aHJlYWRzIHByb3ZpZGVzIGZsZXhpYmlsaXR5IGluIGRlc2lnbmluZyBhbmQgaW1wbGVtZW50aW5nIGNvbmN1cnJlbnQgYXBwbGljYXRpb25zLiBJdCBhbGxvd3MgZGV2ZWxvcGVycyB0byBjaG9vc2UgdGhlIGFwcHJvcHJpYXRlIGxldmVsIG9mIGNvbmN1cnJlbmN5IGZvciBkaWZmZXJlbnQgcGFydHMgb2YgdGhlIGFwcGxpY2F0aW9uLCBvcHRpbWl6aW5nIHJlc291cmNlIHVzYWdlLgoKNi4gICoqSW50ZXItUHJvY2VzcyBDb21tdW5pY2F0aW9uKio6IFNpbmNlIHByb2Nlc3NlcyBhcmUgaXNvbGF0ZWQsIHRoZXkgbWF5IGNvbW11bmljYXRlIHdpdGggZWFjaCBvdGhlciB1c2luZyBpbnRlci1wcm9jZXNzIGNvbW11bmljYXRpb24gKElQQykgbWVjaGFuaXNtcywgc3VjaCBhcyBtZXNzYWdlIHBhc3NpbmcsIHNvY2tldHMsIG9yIHNoYXJlZCBtZW1vcnkuIFRoaXMgZW5hYmxlcyBjb29yZGluYXRpb24gYW5kIGRhdGEgc2hhcmluZyBiZXR3ZWVuIGRpZmZlcmVudCBwcm9jZXNzZXMuCgpBIGNvbW1vbiB1c2UgY2FzZSBmb3IgYSBoeWJyaWQgbXVsdGktcHJvY2Vzc2luZyB3aXRoIG11bHRpLXRocmVhZGluZyBhcmNoaXRlY3R1cmUgaXMgaW4gY29tcGxleCBzb2Z0d2FyZSBzeXN0ZW1zIHdoZXJlIGRpZmZlcmVudCBjb21wb25lbnRzIG9yIG1vZHVsZXMgaGF2ZSB2YXJ5aW5nIHJlcXVpcmVtZW50cyBmb3IgaXNvbGF0aW9uIGFuZCBwYXJhbGxlbGlzbS4gRm9yIGV4YW1wbGUsIGEgd2ViIHNlcnZlciBtaWdodCB1c2UgdGhpcyBhcmNoaXRlY3R1cmUsIHdpdGggZWFjaCBjbGllbnQgcmVxdWVzdCBiZWluZyBwcm9jZXNzZWQgaW4gYSBzZXBhcmF0ZSBwcm9jZXNzLCBhbmQgd2l0aGluIGVhY2ggcHJvY2VzcywgbXVsdGktdGhyZWFkaW5nIGlzIHVzZWQgdG8gaGFuZGxlIG11bHRpcGxlIGluY29taW5nIGNvbm5lY3Rpb25zIGNvbmN1cnJlbnRseS4KClRoaXMgaHlicmlkIGFwcHJvYWNoIGFsbG93cyBkZXZlbG9wZXJzIHRvIGRlc2lnbiBzeXN0ZW1zIHRoYXQgYmFsYW5jZSB0aGUgYWR2YW50YWdlcyBvZiBpc29sYXRpb24gYW5kIHRydWUgcGFyYWxsZWxpc20gKG11bHRpLXByb2Nlc3NpbmcpIHdpdGggdGhlIGVmZmljaWVuY3kgYW5kIHJlc291cmNlIHNoYXJpbmcgYmVuZWZpdHMgb2YgbXVsdGktdGhyZWFkaW5nLiBIb3dldmVyLCBpdCBhbHNvIGFkZHMgY29tcGxleGl0eSB0byB0aGUgc3lzdGVtIGR1ZSB0byB0aGUgbmVlZCB0byBtYW5hZ2UgYm90aCBpbnRlci1wcm9jZXNzIGFuZCBpbnRyYS1wcm9jZXNzIHN5bmNocm9uaXphdGlvbiBhbmQgY29vcmRpbmF0aW9uLgoKIyMgSW50cm9kdWN0aW9uIHRvIE11bHRpLVRocmVhZGluZyBpbiBKYXZhCgpJbiBtb2Rlcm4gc29mdHdhcmUgZGV2ZWxvcG1lbnQsIHRoZSBuZWVkIGZvciBlZmZpY2llbnQgYW5kIHJlc3BvbnNpdmUgYXBwbGljYXRpb25zIGlzIGNyaXRpY2FsIGFuZCBlc3NlbnRpYWwuIE9uZSBvZiB0aGUgd2F5cyB0byBhY2hpZXZlIHRoaXMgaXMgdGhyb3VnaCBtdWx0aS10aHJlYWRpbmcsIGEgZnVuZGFtZW50YWwgY29uY2VwdCBpbiBjb25jdXJyZW50IHByb2dyYW1taW5nLiBKYXZhLCBhIHBvcHVsYXIgYW5kIHdpZGVseS11c2VkIHByb2dyYW1taW5nIGxhbmd1YWdlLCBwcm92aWRlcyByb2J1c3Qgc3VwcG9ydCBmb3IgbXVsdGktdGhyZWFkaW5nLCBtYWtpbmcgaXQgYW4gZXhjZWxsZW50IGNob2ljZSBmb3IgYnVpbGRpbmcgc2NhbGFibGUgYW5kIGhpZ2gtcGVyZm9ybWFuY2UgYXBwbGljYXRpb25zLiBUaGlzIGNoYXB0ZXIgc2VydmVzIGFzIHRoZSBmb3VuZGF0aW9uIGZvciBvdXIgam91cm5leSBpbnRvIHRoZSByZWFsbSBvZiBtdWx0aS10aHJlYWRpbmcgaW4gSmF2YS4KCiMjIyBPYmplY3RpdmVzCgotICAgVW5kZXJzdGFuZGluZyB0aGUgQmFzaWNzIG9mIFRocmVhZHMKLSAgIFdoeSBNdWx0aS1UaHJlYWRpbmcgTWF0dGVycwotICAgSmF2YSdzIE11bHRpLVRocmVhZGluZyBTdXBwb3J0CgojIyMgVW5kZXJzdGFuZGluZyB0aGUgQmFzaWNzIG9mIFRocmVhZHMKCkEgdGhyZWFkLCBpbiB0aGUgY29udGV4dCBvZiBjb21wdXRlciBwcm9ncmFtbWluZywgY2FuIGJlIHRob3VnaHQgb2YgYXMgYSBsaWdodHdlaWdodCBwcm9jZXNzIG9yIGEgdW5pdCBvZiBleGVjdXRpb24gd2l0aGluIGEgcHJvZ3JhbS4gVGhyZWFkcyBhbGxvdyBhIHByb2dyYW0gdG8gcGVyZm9ybSBtdWx0aXBsZSB0YXNrcyBjb25jdXJyZW50bHksIHNoYXJpbmcgdGhlIHNhbWUgbWVtb3J5IHNwYWNlIGFuZCByZXNvdXJjZXMuIFRoZXkgZW5hYmxlIGRldmVsb3BlcnMgdG8gd3JpdGUgY29kZSB0aGF0IGNhbiBleGVjdXRlIGluIHBhcmFsbGVsLCBoYXJuZXNzaW5nIHRoZSBmdWxsIHBvdGVudGlhbCBvZiBtdWx0aS1jb3JlIHByb2Nlc3NvcnMuCgpJbiBKYXZhLCB0aHJlYWRzIGFyZSBpbXBsZW1lbnRlZCB1c2luZyB0aGUgYGphdmEubGFuZy5UaHJlYWRgIGNsYXNzLCBhbmQgdGhleSBjYW4gYmUgY3JlYXRlZCBhbmQgbWFuYWdlZCBlYXNpbHkuIFRocmVhZHMgaGF2ZSB0aGVpciBvd24gc3RhY2sgYW5kIHByb2dyYW0gY291bnRlciwgd2hpY2ggZW5hYmxlcyB0aGVtIHRvIGV4ZWN1dGUgaW5kZXBlbmRlbnRseSB3aGlsZSBzaGFyaW5nIGRhdGEgYW5kIHJlc291cmNlcyB3aXRoIG90aGVyIHRocmVhZHMuCgojIyMgSmF2YSdzIE11bHRpLVRocmVhZGluZyBTdXBwb3J0CgpKYXZhIHByb3ZpZGVzIGEgcmljaCBzZXQgb2YgZmVhdHVyZXMgYW5kIEFQSXMgZm9yIG11bHRpLXRocmVhZGluZywgbWFraW5nIGl0IHJlbGF0aXZlbHkgZWFzeSB0byB3b3JrIHdpdGggdGhyZWFkcyBhbmQgbWFuYWdlIHRoZWlyIGludGVyYWN0aW9ucy4gU29tZSBrZXkgYXNwZWN0cyBvZiBKYXZhJ3MgbXVsdGktdGhyZWFkaW5nIHN1cHBvcnQgaW5jbHVkZToKCi0gICAqKlRocmVhZCBDcmVhdGlvbioqOiBZb3UgY2FuIGNyZWF0ZSB0aHJlYWRzIGluIEphdmEgYnkgZXh0ZW5kaW5nIHRoZSBgVGhyZWFkYCBjbGFzcyBvciBpbXBsZW1lbnRpbmcgdGhlIGBSdW5uYWJsZWAgaW50ZXJmYWNlLiBUaGlzIGZsZXhpYmlsaXR5IGFsbG93cyB5b3UgdG8gZGVmaW5lIHRoZSBjb2RlIHRoYXQgZWFjaCB0aHJlYWQgd2lsbCBleGVjdXRlLgoKLSAgICoqVGhyZWFkIFN5bmNocm9uaXphdGlvbioqOiBKYXZhIHByb3ZpZGVzIG1lY2hhbmlzbXMgZm9yIHN5bmNocm9uaXppbmcgdGhyZWFkcyBhbmQgbWFuYWdpbmcgYWNjZXNzIHRvIHNoYXJlZCByZXNvdXJjZXMuIFRoaXMgcHJldmVudHMgaXNzdWVzIGxpa2UgZGF0YSBjb3JydXB0aW9uIGFuZCByYWNlIGNvbmRpdGlvbnMuCgotICAgKipIaWdoLUxldmVsIENvbmN1cnJlbmN5IFV0aWxpdGllcyoqOiBUaGUgYGphdmEudXRpbC5jb25jdXJyZW50YCBwYWNrYWdlIG9mZmVycyBoaWdoLWxldmVsIGNvbnN0cnVjdHMgc3VjaCBhcyB0aHJlYWQgcG9vbHMsIGNvbmN1cnJlbnQgY29sbGVjdGlvbnMsIGFuZCBzeW5jaHJvbml6YXRpb24gcHJpbWl0aXZlcywgc2ltcGxpZnlpbmcgdGhlIGRldmVsb3BtZW50IG9mIG11bHRpLXRocmVhZGVkIGFwcGxpY2F0aW9ucy4KCi0gICAqKk1lbW9yeSBNb2RlbCoqOiBKYXZhIGRlZmluZXMgYSBtZW1vcnkgbW9kZWwgdGhhdCBnb3Zlcm5zIGhvdyB0aHJlYWRzIGludGVyYWN0IHdpdGggbWVtb3J5IGFuZCBndWFyYW50ZWVzIHZpc2liaWxpdHkgYW5kIGNvbnNpc3RlbmN5IG9mIHNoYXJlZCBkYXRhLgoKLSAgICoqVGhyZWFkIFN0YXRlcyBhbmQgTGlmZWN5Y2xlKio6IFRocmVhZHMgaW4gSmF2YSBoYXZlIHdlbGwtZGVmaW5lZCBzdGF0ZXMsIGFuZCB0aGVpciBsaWZlY3ljbGUgaXMgbWFuYWdlZCBieSB0aGUgSmF2YSBWaXJ0dWFsIE1hY2hpbmUgKEpWTSkuCgpJbiB0aGUgc3Vic2VxdWVudCBzZWN0aW9ucywgd2Ugd2lsbCBkaXZlIGRlZXBlciBpbnRvIHRoZXNlIGNvbmNlcHRzLCBleHBsb3JpbmcgdGhyZWFkIGNyZWF0aW9uLCBzeW5jaHJvbml6YXRpb24gbWVjaGFuaXNtcywgYmVzdCBwcmFjdGljZXMsIGFuZCByZWFsLXdvcmxkIGV4YW1wbGVzLiBCeSB0aGUgZW5kIG9mIHRoaXMgam91cm5leSwgeW91J2xsIGhhdmUgYSB0aG9yb3VnaCB1bmRlcnN0YW5kaW5nIG9mIGhvdyB0byBoYXJuZXNzIHRoZSBwb3dlciBvZiBtdWx0aS10aHJlYWRpbmcgaW4gSmF2YSB0byBidWlsZCByb2J1c3QgYW5kIGhpZ2gtcGVyZm9ybWFuY2UgYXBwbGljYXRpb25zLgoKIyMgQ3JlYXRpbmcgYW5kIE1hbmFnaW5nIFRocmVhZHMKCkluIHRoaXMgc2VjdGlvbiwgd2UgZGVsdmUgaW50byB0aGUgcHJhY3RpY2FsIGFzcGVjdHMgb2Ygd29ya2luZyB3aXRoIHRocmVhZHMgaW4gSmF2YS4gVW5kZXJzdGFuZGluZyBob3cgdG8gY3JlYXRlLCBtYW5hZ2UsIGFuZCBjb250cm9sIHRocmVhZHMgaXMgZnVuZGFtZW50YWwgdG8gaGFybmVzc2luZyB0aGUgcG93ZXIgb2YgbXVsdGktdGhyZWFkaW5nLiBUaGlzIHNlY3Rpb24gZXhwbG9yZXMgdGhlIGludHJpY2FjaWVzIG9mIHRocmVhZCBjcmVhdGlvbiwgdGhlaXIgbGlmZWN5Y2xlLCBhbmQgaG93IHRvIG1hbmFnZSB0aGVtIGVmZmVjdGl2ZWx5LgoKIyMjIE9iamVjdGl2ZXMKCi0gICBDcmVhdGluZyBUaHJlYWRzIGluIEphdmEKLSAgIFJ1bm5pbmcgVGhyZWFkcwotICAgVGhyZWFkIFN0YXRlcyBhbmQgTGlmZWN5Y2xlCi0gICBEYWVtb24gVGhyZWFkcwoKIyMjIENyZWF0aW5nIFRocmVhZHMgaW4gSmF2YQoKSmF2YSBwcm92aWRlcyB0d28gcHJpbWFyeSB3YXlzIHRvIGNyZWF0ZSB0aHJlYWRzOgoKMS4gICoqRXh0ZW5kaW5nIHRoZSBgVGhyZWFkYCBDbGFzcyoqOiBZb3UgY2FuIGNyZWF0ZSBhIG5ldyB0aHJlYWQgYnkgZXh0ZW5kaW5nIHRoZSBgamF2YS5sYW5nLlRocmVhZGAgY2xhc3MuIEJ5IG92ZXJyaWRpbmcgdGhlIGBydW4oKWAgbWV0aG9kIHdpdGhpbiB5b3VyIHN1YmNsYXNzLCB5b3UgZGVmaW5lIHRoZSBjb2RlIHRoYXQgdGhlIHRocmVhZCB3aWxsIGV4ZWN1dGUgd2hlbiBzdGFydGVkLgoKICAgIGBgYCBqYXZhCiAgICBjbGFzcyBNeVRocmVhZCBleHRlbmRzIFRocmVhZCB7CiAgICAgICAgcHVibGljIHZvaWQgcnVuKCkgewogICAgICAgICAgICAvLyBUaHJlYWQncyBjb2RlIGhlcmUKICAgICAgICB9CiAgICB9CgogICAgLy8gQ3JlYXRpbmcgYW5kIHN0YXJ0aW5nIGEgdGhyZWFkCiAgICBNeVRocmVhZCBteVRocmVhZCA9IG5ldyBNeVRocmVhZCgpOwogICAgbXlUaHJlYWQuc3RhcnQoKTsKICAgIGBgYAoKMi4gICoqSW1wbGVtZW50aW5nIHRoZSBgUnVubmFibGVgIEludGVyZmFjZSoqOiBBbiBhbHRlcm5hdGl2ZSBhcHByb2FjaCBpcyB0byBpbXBsZW1lbnQgdGhlIGBqYXZhLmxhbmcuUnVubmFibGVgIGludGVyZmFjZS4gVGhpcyBpbnRlcmZhY2UgZGVmaW5lcyBhIGBydW4oKWAgbWV0aG9kIHRoYXQgeW91IG5lZWQgdG8gaW1wbGVtZW50LCBhbmQgdGhlbiB5b3UgY2FuIGNyZWF0ZSBhIGBUaHJlYWRgIG9iamVjdCwgcGFzc2luZyB5b3VyIGBSdW5uYWJsZWAgaW5zdGFuY2UgdG8gaXRzIGNvbnN0cnVjdG9yLgoKICAgIGBgYCBqYXZhCiAgICBjbGFzcyBNeVJ1bm5hYmxlIGltcGxlbWVudHMgUnVubmFibGUgewogICAgICAgIHB1YmxpYyB2b2lkIHJ1bigpIHsKICAgICAgICAgICAgLy8gVGhyZWFkJ3MgY29kZSBoZXJlCiAgICAgICAgfQogICAgfQoKICAgIC8vIENyZWF0aW5nIGFuZCBzdGFydGluZyBhIHRocmVhZCB1c2luZyBSdW5uYWJsZQogICAgTXlSdW5uYWJsZSBteVJ1bm5hYmxlID0gbmV3IE15UnVubmFibGUoKTsKICAgIFRocmVhZCB0aHJlYWQgPSBuZXcgVGhyZWFkKG15UnVubmFibGUpOwogICAgdGhyZWFkLnN0YXJ0KCk7CiAgICBgYGAKCiMjIyBSdW5uaW5nIFRocmVhZHMKCk9uY2UgdGhyZWFkcyBhcmUgY3JlYXRlZCwgdGhleSBjYW4gYmUgc3RhcnRlZCB1c2luZyB0aGUgYHN0YXJ0KClgIG1ldGhvZC4gVGhlIEpWTSBtYW5hZ2VzIHRoZSBleGVjdXRpb24gb2YgdGhyZWFkcywgYW5kIHdoZW4gYSB0aHJlYWQgaXMgc3RhcnRlZCwgaXQgdHJhbnNpdGlvbnMgZnJvbSB0aGUgYE5FV2Agc3RhdGUgdG8gdGhlIGBSVU5OQUJMRWAgc3RhdGUsIGluZGljYXRpbmcgaXQncyByZWFkeSBmb3IgZXhlY3V0aW9uLgoKIyMjIFRocmVhZCBTdGF0ZXMgYW5kIExpZmVjeWNsZQoKVGhyZWFkcyBnbyB0aHJvdWdoIHZhcmlvdXMgc3RhdGVzIGR1cmluZyB0aGVpciBsaWZlY3ljbGUuIFRoZSBjb21tb24gdGhyZWFkIHN0YXRlcyBpbiBKYXZhIGluY2x1ZGU6CgotICAgKipORVcqKjogVGhlIGluaXRpYWwgc3RhdGUgd2hlbiBhIHRocmVhZCBpcyBjcmVhdGVkIGJ1dCBub3QgeWV0IHN0YXJ0ZWQuCi0gICAqKlJVTk5BQkxFKio6IFRoZSB0aHJlYWQgaXMgcmVhZHkgdG8gZXhlY3V0ZSBhbmQgd2FpdGluZyBmb3IgQ1BVIHRpbWUuCi0gICAqKkJMT0NLRUQqKjogVGhlIHRocmVhZCBpcyBibG9ja2VkLCBvZnRlbiB3YWl0aW5nIGZvciBhIGxvY2sgb3IgcmVzb3VyY2UuCi0gICAqKldBSVRJTkcqKjogVGhlIHRocmVhZCBpcyBpbiBhIHdhaXRpbmcgc3RhdGUgYW5kIGNhbiBiZSBhd2FrZW5lZCBieSBhbm90aGVyIHRocmVhZC4KLSAgICoqVElNRURfV0FJVElORyoqOiBTaW1pbGFyIHRvIHdhaXRpbmcgYnV0IHdpdGggYSB0aW1lb3V0LgotICAgKipURVJNSU5BVEVEKio6IFRoZSB0aHJlYWQgaGFzIGNvbXBsZXRlZCBpdHMgZXhlY3V0aW9uLgoKVW5kZXJzdGFuZGluZyB0aGUgdGhyZWFkIGxpZmVjeWNsZSBpcyBlc3NlbnRpYWwgZm9yIG1hbmFnaW5nIGFuZCBkZWJ1Z2dpbmcgbXVsdGktdGhyZWFkZWQgYXBwbGljYXRpb25zIGVmZmVjdGl2ZWx5LgoKIyMjIERhZW1vbiBUaHJlYWRzCgpJbiBKYXZhLCB5b3UgY2FuIGNyZWF0ZSBkYWVtb24gdGhyZWFkcyBieSBjYWxsaW5nIHRoZSBgc2V0RGFlbW9uKHRydWUpYCBtZXRob2Qgb24gYSBgVGhyZWFkYCBvYmplY3QuIERhZW1vbiB0aHJlYWRzIGFyZSB0aHJlYWRzIHRoYXQgcnVuIGluIHRoZSBiYWNrZ3JvdW5kIGFuZCBkbyBub3QgcHJldmVudCB0aGUgSlZNIGZyb20gZXhpdGluZyB3aGVuIGFsbCBub24tZGFlbW9uIHRocmVhZHMgaGF2ZSBjb21wbGV0ZWQuIFRoZXkgYXJlIG9mdGVuIHVzZWQgZm9yIHRhc2tzIGxpa2UgZ2FyYmFnZSBjb2xsZWN0aW9uIG9yIG1vbml0b3JpbmcuCgpgYGAgamF2YQpUaHJlYWQgZGFlbW9uVGhyZWFkID0gbmV3IFRocmVhZCgoKSAtPiB7CiAgICAvLyBUaHJlYWQncyBjb2RlIGhlcmUKfSk7CmRhZW1vblRocmVhZC5zZXREYWVtb24odHJ1ZSk7CmRhZW1vblRocmVhZC5zdGFydCgpOwpgYGAKCkluIHRoaXMgc2VjdGlvbiB3ZSBzZXQgdGhlIHN0YWdlIGZvciBvdXIgZXhwbG9yYXRpb24gb2YgbXVsdGktdGhyZWFkaW5nIGluIEphdmEgYnkgY292ZXJpbmcgdGhlIGZ1bmRhbWVudGFsIGNvbmNlcHRzIG9mIGNyZWF0aW5nIGFuZCBtYW5hZ2luZyB0aHJlYWRzLiBJbiB0aGUgbmV4dCBzZWN0aW9uLCB3ZSB3aWxsIGRlbHZlIGludG8gdGhyZWFkIHN5bmNocm9uaXphdGlvbi4KCiMjIFN5bmNocm9uaXphdGlvbiBpbiBKYXZhCgpUaHJlYWQgc3luY2hyb25pemF0aW9uIGlzIGEgZnVuZGFtZW50YWwgY29uY2VwdCBpbiBjb25jdXJyZW50IHByb2dyYW1taW5nIHRoYXQgaW52b2x2ZXMgY29vcmRpbmF0aW5nIHRoZSBleGVjdXRpb24gb2YgbXVsdGlwbGUgdGhyZWFkcyB0byBlbnN1cmUgdGhleSBhY2Nlc3Mgc2hhcmVkIHJlc291cmNlcyBvciBzZWN0aW9ucyBvZiBjb2RlIGluIGEgY29udHJvbGxlZCBhbmQgb3JkZXJseSBtYW5uZXIuIFRoZSBnb2FsIG9mIHRocmVhZCBzeW5jaHJvbml6YXRpb24gaXMgdG8gcHJldmVudCByYWNlIGNvbmRpdGlvbnMsIGRhdGEgY29ycnVwdGlvbiwgYW5kIG90aGVyIGNvbmN1cnJlbmN5LXJlbGF0ZWQgaXNzdWVzIHRoYXQgY2FuIGFyaXNlIHdoZW4gbXVsdGlwbGUgdGhyZWFkcyBhY2Nlc3Mgc2hhcmVkIGRhdGEgc2ltdWx0YW5lb3VzbHkuCgojIyMgT2JqZWN0aXZlcwoKLSAgIFRoZSBOZWVkIGZvciBUaHJlYWQgU3luY2hyb25pemF0aW9uCi0gICBTeW5jaHJvbml6ZWQgTWV0aG9kcyBhbmQgQmxvY2tzCi0gICBJbnRyaW5zaWMgTG9ja3MgKE1vbml0b3IgTG9ja3MpCi0gICBWb2xhdGlsZSBLZXl3b3JkCgojIyMgTmVlZCBmb3IgU3luY2hyb25pemF0aW9uCgpUaHJlYWQgc3luY2hyb25pemF0aW9uIGlzIGltcG9ydGFudCBiZWNhdXNlIGluIG11bHRpLXRocmVhZGVkIGFwcGxpY2F0aW9ucywgbXVsdGlwbGUgdGhyZWFkcyBtYXkgcnVuIGNvbmN1cnJlbnRseSBhbmQgYWNjZXNzIHNoYXJlZCByZXNvdXJjZXMgb3IgdmFyaWFibGVzLiBXaXRob3V0IHByb3BlciBzeW5jaHJvbml6YXRpb24sIHRoZSBmb2xsb3dpbmcgcHJvYmxlbXMgY2FuIG9jY3VyOgoKMS4gICoqUmFjZSBDb25kaXRpb25zKio6IFJhY2UgY29uZGl0aW9ucyBvY2N1ciB3aGVuIHRoZSBiZWhhdmlvciBvZiBhIHByb2dyYW0gZGVwZW5kcyBvbiB0aGUgcmVsYXRpdmUgdGltaW5nIG9mIGV2ZW50cyBiZXR3ZWVuIHRocmVhZHMuIEZvciBleGFtcGxlLCB0d28gdGhyZWFkcyBtYXkgc2ltdWx0YW5lb3VzbHkgYWNjZXNzIGFuZCBtb2RpZnkgYSBzaGFyZWQgdmFyaWFibGUsIGxlYWRpbmcgdG8gdW5wcmVkaWN0YWJsZSByZXN1bHRzLgoKMi4gICoqRGF0YSBDb3JydXB0aW9uKio6IFNpbXVsdGFuZW91cyB3cml0ZXMgdG8gc2hhcmVkIGRhdGEgd2l0aG91dCBwcm9wZXIgc3luY2hyb25pemF0aW9uIGNhbiByZXN1bHQgaW4gZGF0YSBjb3JydXB0aW9uIG9yIGluY29uc2lzdGVuY3kuIE9uZSB0aHJlYWQgbWF5IG92ZXJ3cml0ZSBjaGFuZ2VzIG1hZGUgYnkgYW5vdGhlciwgbGVhZGluZyB0byBpbmNvcnJlY3QgcHJvZ3JhbSBiZWhhdmlvci4KCjMuICAqKkRlYWRsb2NrcyoqOiBEZWFkbG9ja3MgaGFwcGVuIHdoZW4gdHdvIG9yIG1vcmUgdGhyZWFkcyBhcmUgYmxvY2tlZCwgd2FpdGluZyBmb3IgZWFjaCBvdGhlciB0byByZWxlYXNlIHJlc291cmNlcyB0aGV5IG5lZWQuIFRoaXMgY2FuIHJlc3VsdCBpbiBhIHNpdHVhdGlvbiB3aGVyZSBubyBwcm9ncmVzcyBpcyBwb3NzaWJsZSwgZWZmZWN0aXZlbHkgYnJpbmdpbmcgdGhlIGFwcGxpY2F0aW9uIHRvIGEgc3RhbmRzdGlsbC4KClRvIGFkZHJlc3MgdGhlc2UgaXNzdWVzLCB0aHJlYWQgc3luY2hyb25pemF0aW9uIG1lY2hhbmlzbXMgYXJlIHVzZWQgdG8gY29udHJvbCBhY2Nlc3MgdG8gc2hhcmVkIHJlc291cmNlcyBhbmQgZW5mb3JjZSBydWxlcyB0aGF0IGVuc3VyZSBzYWZlIGNvbmN1cnJlbnQgZXhlY3V0aW9uLiBDb21tb24gc3luY2hyb25pemF0aW9uIG1lY2hhbmlzbXMgaW4gSmF2YSBpbmNsdWRlOgoKLSAgICoqU3luY2hyb25pemVkIE1ldGhvZHMgYW5kIEJsb2NrcyoqOiBKYXZhIGFsbG93cyB5b3UgdG8gZGVjbGFyZSBtZXRob2RzIGFzIGBzeW5jaHJvbml6ZWRgIG9yIHVzZSBzeW5jaHJvbml6ZWQgYmxvY2tzIHRvIHByb3RlY3QgY3JpdGljYWwgc2VjdGlvbnMgb2YgY29kZS4gV2hlbiBhIHRocmVhZCBlbnRlcnMgYSBzeW5jaHJvbml6ZWQgbWV0aG9kIG9yIGJsb2NrLCBpdCBhY3F1aXJlcyBhIGxvY2sgdGhhdCBwcmV2ZW50cyBvdGhlciB0aHJlYWRzIGZyb20gZXhlY3V0aW5nIHN5bmNocm9uaXplZCBjb2RlIG9uIHRoZSBzYW1lIG9iamVjdCB1bnRpbCB0aGUgbG9jayBpcyByZWxlYXNlZC4KCi0gICAqKkxvY2tzIChSZWVudHJhbnRMb2NrKSoqOiBKYXZhIHByb3ZpZGVzIHRoZSBgUmVlbnRyYW50TG9ja2AgY2xhc3MsIHdoaWNoIG9mZmVycyBtb3JlIGZpbmUtZ3JhaW5lZCBjb250cm9sIG92ZXIgbG9ja2luZyBhbmQgdW5sb2NraW5nLiBJdCBhbGxvd3MgZm9yIGZlYXR1cmVzIHN1Y2ggYXMgZmFpcm5lc3MsIHRpbWVvdXRzLCBhbmQgYWR2YW5jZWQgbG9jayBtYW5hZ2VtZW50LgoKLSAgICoqU2VtYXBob3JlcywgQ291bnREb3duTGF0Y2gsIGFuZCBDeWNsaWNCYXJyaWVyKio6IFRoZXNlIHN5bmNocm9uaXphdGlvbiBjb25zdHJ1Y3RzIGFyZSBwcm92aWRlZCBieSB0aGUgYGphdmEudXRpbC5jb25jdXJyZW50YCBwYWNrYWdlIGFuZCBhbGxvdyB0aHJlYWRzIHRvIGNvb3JkaW5hdGUgdGhlaXIgYWN0aXZpdGllcywgd2FpdCBmb3Igc2lnbmFscywgb3Igc3luY2hyb25pemUgYXQgc3BlY2lmaWMgcG9pbnRzIGluIHRoZSBleGVjdXRpb24uCgotICAgKipBdG9taWMgVmFyaWFibGVzKio6IENsYXNzZXMgbGlrZSBgQXRvbWljSW50ZWdlcmAgYW5kIGBBdG9taWNSZWZlcmVuY2VgIG9mZmVyIGF0b21pYyBvcGVyYXRpb25zLCBlbnN1cmluZyB0aGF0IGNlcnRhaW4gb3BlcmF0aW9ucyBvbiBzaGFyZWQgdmFyaWFibGVzIGFyZSBpbmRpdmlzaWJsZSBhbmQgdGhyZWFkLXNhZmUuCgotICAgKipWb2xhdGlsZSBLZXl3b3JkKio6IFRoZSBgdm9sYXRpbGVgIGtleXdvcmQgZW5zdXJlcyB0aGUgdmlzaWJpbGl0eSBvZiBjaGFuZ2VzIG1hZGUgdG8gYSB2YXJpYWJsZSBhY3Jvc3MgdGhyZWFkcy4gSXQgZ3VhcmFudGVlcyB0aGF0IHRoZSBtb3N0IHVwLXRvLWRhdGUgdmFsdWUgb2YgdGhlIHZhcmlhYmxlIGlzIGFsd2F5cyByZWFkLgoKVGhyZWFkIHN5bmNocm9uaXphdGlvbiBpcyBhIGNydWNpYWwgc2tpbGwgZm9yIGRldmVsb3BlcnMgd29ya2luZyB3aXRoIG11bHRpLXRocmVhZGVkIGFwcGxpY2F0aW9ucywgYXMgaXQgaGVscHMgcHJldmVudCBjb25jdXJyZW5jeS1yZWxhdGVkIGJ1Z3MgYW5kIGVuc3VyZXMgdGhlIGNvcnJlY3RuZXNzIGFuZCByZWxpYWJpbGl0eSBvZiB0aGUgc29mdHdhcmUuIEhvd2V2ZXIsIGltcHJvcGVyIG9yIGV4Y2Vzc2l2ZSBzeW5jaHJvbml6YXRpb24gY2FuIGxlYWQgdG8gcGVyZm9ybWFuY2UgYm90dGxlbmVja3MsIHNvIGl0J3MgZXNzZW50aWFsIHRvIHN0cmlrZSBhIGJhbGFuY2UgYmV0d2VlbiBzeW5jaHJvbml6YXRpb24gYW5kIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbi4KCiMjIyBTeW5jaHJvbml6ZWQgTWV0aG9kcyBhbmQgQmxvY2tzCgpKYXZhIHByb3ZpZGVzIHR3byBwcmltYXJ5IG1lY2hhbmlzbXMgZm9yIHRocmVhZCBzeW5jaHJvbml6YXRpb246CgoxLiAgKipTeW5jaHJvbml6ZWQgTWV0aG9kcyoqOiBZb3UgY2FuIGRlY2xhcmUgYSBtZXRob2QgYXMgYHN5bmNocm9uaXplZGAgYnkgdXNpbmcgdGhlIGBzeW5jaHJvbml6ZWRgIGtleXdvcmQuIFdoZW4gYSB0aHJlYWQgaW52b2tlcyBhIHN5bmNocm9uaXplZCBtZXRob2QsIGl0IGFjcXVpcmVzIGEgbG9jayBhc3NvY2lhdGVkIHdpdGggdGhlIG9iamVjdCBvbiB3aGljaCB0aGUgbWV0aG9kIGlzIGNhbGxlZC4gT3RoZXIgdGhyZWFkcyBhdHRlbXB0aW5nIHRvIGNhbGwgc3luY2hyb25pemVkIG1ldGhvZHMgb24gdGhlIHNhbWUgb2JqZWN0IHdpbGwgYmxvY2sgdW50aWwgdGhlIGxvY2sgaXMgcmVsZWFzZWQuCgogICAgYGBgIGphdmEKICAgIHB1YmxpYyBzeW5jaHJvbml6ZWQgdm9pZCBzeW5jaHJvbml6ZWRNZXRob2QoKSB7CiAgICAgICAgLy8gU3luY2hyb25pemVkIGNvZGUgaGVyZQogICAgfQogICAgYGBgCgoyLiAgKipTeW5jaHJvbml6ZWQgQmxvY2tzKio6IFlvdSBjYW4gYWxzbyBjcmVhdGUgc3luY2hyb25pemVkIGJsb2NrcyB3aXRoaW4gbWV0aG9kcyB0byBwcm90ZWN0IGNyaXRpY2FsIHNlY3Rpb25zIG9mIGNvZGUuIEEgc3luY2hyb25pemVkIGJsb2NrIGlzIGVuY2xvc2VkIHdpdGhpbiB0aGUgYHN5bmNocm9uaXplZGAga2V5d29yZCBhbmQgc3BlY2lmaWVzIHRoZSBvYmplY3QgdGhhdCBwcm92aWRlcyB0aGUgbG9jay4KCiAgICBgYGAgamF2YQogICAgc3luY2hyb25pemVkIChsb2NrT2JqZWN0KSB7CiAgICAgICAgLy8gU3luY2hyb25pemVkIGNvZGUgaGVyZQogICAgfQogICAgYGBgCgojIyMgSW50cmluc2ljIExvY2tzIChNb25pdG9yIExvY2tzKQoKSW4gSmF2YSwgZWFjaCBvYmplY3QgaGFzIGFuIGludHJpbnNpYyBsb2NrLCBhbHNvIGtub3duIGFzIGEgbW9uaXRvciBsb2NrLiBXaGVuIGEgc3luY2hyb25pemVkIG1ldGhvZCBvciBibG9jayBpcyBlbnRlcmVkLCB0aGUgdGhyZWFkIGFjcXVpcmVzIHRoZSBpbnRyaW5zaWMgbG9jayBhc3NvY2lhdGVkIHdpdGggdGhlIG9iamVjdCBvbiB3aGljaCB0aGUgbWV0aG9kIG9yIGJsb2NrIGlzIGludm9rZWQuIFRoaXMgbG9jayBlbnN1cmVzIHRoYXQgb25seSBvbmUgdGhyZWFkIGNhbiBleGVjdXRlIHRoZSBzeW5jaHJvbml6ZWQgY29kZSBhdCBhIHRpbWUuCgojIyMgVGhlIGB2b2xhdGlsZWAgS2V5d29yZAoKV2hpbGUgYHN5bmNocm9uaXplZGAgbWV0aG9kcyBhbmQgYmxvY2tzIGFyZSB1c2VkIGZvciBwcm90ZWN0aW5nIGNyaXRpY2FsIHNlY3Rpb25zIG9mIGNvZGUsIHRoZSBgdm9sYXRpbGVgIGtleXdvcmQgaXMgdXNlZCB0byBlbnN1cmUgdGhlIHZpc2liaWxpdHkgb2YgY2hhbmdlcyBtYWRlIHRvIGEgdmFyaWFibGUgYWNyb3NzIHRocmVhZHMuIFdoZW4gYSB2YXJpYWJsZSBpcyBkZWNsYXJlZCBhcyBgdm9sYXRpbGVgLCBhbnkgd3JpdGUgdG8gdGhhdCB2YXJpYWJsZSBpcyBpbW1lZGlhdGVseSB2aXNpYmxlIHRvIG90aGVyIHRocmVhZHMuIFRoaXMgZW5zdXJlcyB0aGF0IHRoZSBtb3N0IHVwLXRvLWRhdGUgdmFsdWUgb2YgdGhlIHZhcmlhYmxlIGlzIGFsd2F5cyByZWFkLgoKYGBgIGphdmEKcHJpdmF0ZSB2b2xhdGlsZSBib29sZWFuIGZsYWcgPSBmYWxzZTsKYGBgCgpUaGlzIHNlY3Rpb24gcHJlc2VudGVkIGEgZm91bmRhdGlvbiBmb3IgdW5kZXJzdGFuZGluZyB0aHJlYWQgc3luY2hyb25pemF0aW9uIGluIEphdmEuIEluIHRoZSBuZXh0IHNlY3Rpb24sIHdlIHdpbGwgZXhwbG9yZSBtb3JlIGFkdmFuY2VkIHN5bmNocm9uaXphdGlvbiB0ZWNobmlxdWVzIGFuZCBzb21lIGJlc3QgcHJhY3RpY2VzLgoKIyMgVGhyZWFkIFNhZmV0eSBhbmQgUmFjZSBDb25kaXRpb25zCgpBZGRyZXNzaW5nIG11bHRpLXRocmVhZGluZyBpbiBKYXZhLiBUaGlzIGNoYXB0ZXIgZGVsdmVzIGludG8gdGhlIGNvbmNlcHQgb2YgdGhyZWFkIHNhZmV0eSwgdGhlIGNoYWxsZW5nZXMgcG9zZWQgYnkgcmFjZSBjb25kaXRpb25zLCBhbmQgdGhlIHRlY2huaXF1ZXMgdXNlZCB0byBlbnN1cmUgdGhhdCBjb25jdXJyZW50IGFjY2VzcyB0byBzaGFyZWQgcmVzb3VyY2VzIGRvZXMgbm90IGxlYWQgdG8gZGF0YSBjb3JydXB0aW9uIG9yIHVucHJlZGljdGFibGUgYmVoYXZpb3IuCgojIyMgT2JqZWN0aXZlcwoKLSAgIFVuZGVyc3RhbmRpbmcgVGhyZWFkIFNhZmV0eQotICAgSWRlbnRpZnlpbmcgYW5kIEhhbmRsaW5nIFJhY2UgQ29uZGl0aW9ucwotICAgQXRvbWljIFZhcmlhYmxlcyBhbmQgT3BlcmF0aW9ucwotICAgSW1tdXRhYmxlIE9iamVjdHMKCiMjIyBVbmRlcnN0YW5kaW5nIFRocmVhZCBTYWZldHkKClRocmVhZCBzYWZldHkgaXMgYSBmdW5kYW1lbnRhbCBjb25jZXB0IGluIGNvbmN1cnJlbnQgcHJvZ3JhbW1pbmcuIEl0IHJlZmVycyB0byB0aGUgcHJvcGVydHkgb2YgYSBwcm9ncmFtIG9yIHN5c3RlbSB3aGVyZSBtdWx0aXBsZSB0aHJlYWRzIGNhbiBhY2Nlc3Mgc2hhcmVkIHJlc291cmNlcyBjb25jdXJyZW50bHkgd2l0aG91dCBjYXVzaW5nIGRhdGEgY29ycnVwdGlvbiwgaW5jb25zaXN0ZW50IHN0YXRlLCBvciB1bmV4cGVjdGVkIGJlaGF2aW9yLiBJbiB0aHJlYWQtc2FmZSBwcm9ncmFtcywgdGhlIHJlc3VsdHMgYXJlIHByZWRpY3RhYmxlIGFuZCBhZGhlcmUgdG8gdGhlIGludGVuZGVkIGxvZ2ljLCByZWdhcmRsZXNzIG9mIHRoZSBvcmRlciBpbiB3aGljaCB0aHJlYWRzIGV4ZWN1dGUuCgpFbnN1cmluZyB0aHJlYWQgc2FmZXR5IGlzIHZpdGFsIGJlY2F1c2UgaW4gbXVsdGktdGhyZWFkZWQgYXBwbGljYXRpb25zLCB2YXJpb3VzIHRocmVhZHMgbWF5IGFjY2VzcyBzaGFyZWQgZGF0YSBvciByZXNvdXJjZXMgc2ltdWx0YW5lb3VzbHkuIFdpdGhvdXQgcHJvcGVyIHRocmVhZCBzYWZldHkgbWVhc3VyZXMsIHRoZSBmb2xsb3dpbmcgcHJvYmxlbXMgY2FuIG9jY3VyOgoKMS4gICoqUmFjZSBDb25kaXRpb25zKio6IFJhY2UgY29uZGl0aW9ucyBvY2N1ciB3aGVuIG11bHRpcGxlIHRocmVhZHMgYWNjZXNzIHNoYXJlZCBkYXRhIGNvbmN1cnJlbnRseSwgYW5kIHRoZSBmaW5hbCBzdGF0ZSBvZiB0aGUgZGF0YSBkZXBlbmRzIG9uIHRoZSB1bnByZWRpY3RhYmxlIHRpbWluZyBvZiB0aHJlYWQgZXhlY3V0aW9uLgoKMi4gICoqRGF0YSBDb3JydXB0aW9uKio6IFVucHJvdGVjdGVkIHdyaXRlcyB0byBzaGFyZWQgZGF0YSBjYW4gbGVhZCB0byBkYXRhIGNvcnJ1cHRpb24uIE9uZSB0aHJlYWQgbWF5IG92ZXJ3cml0ZSBjaGFuZ2VzIG1hZGUgYnkgYW5vdGhlciwgbGVhZGluZyB0byBpbmNvcnJlY3Qgb3IgaW5jb25zaXN0ZW50IHJlc3VsdHMuCgozLiAgKipJbmNvbnNpc3RlbnQgU3RhdGUqKjogTGFjayBvZiB0aHJlYWQgc2FmZXR5IGNhbiByZXN1bHQgaW4gb2JqZWN0cyBiZWluZyBsZWZ0IGluIGFuIGluY29uc2lzdGVudCBzdGF0ZSBpZiBpbnRlcnJ1cHRlZCBvciBhY2Nlc3NlZCBzaW11bHRhbmVvdXNseSBieSBtdWx0aXBsZSB0aHJlYWRzLgoKIyMjIElkZW50aWZ5aW5nIGFuZCBIYW5kbGluZyBSYWNlIENvbmRpdGlvbnMKClRvIGFkZHJlc3MgcmFjZSBjb25kaXRpb25zIGFuZCBlbnN1cmUgdGhyZWFkIHNhZmV0eSwgZGV2ZWxvcGVycyBtdXN0OgoKMS4gICoqSWRlbnRpZnkgQ3JpdGljYWwgU2VjdGlvbnMqKjogSWRlbnRpZnkgdGhlIHNlY3Rpb25zIG9mIGNvZGUgd2hlcmUgc2hhcmVkIGRhdGEgaXMgYWNjZXNzZWQgb3IgbW9kaWZpZWQuIFRoZXNlIHNlY3Rpb25zIGFyZSBrbm93biBhcyAiY3JpdGljYWwgc2VjdGlvbnMiIGFuZCBuZWVkIHByb3RlY3Rpb24uCgoyLiAgKipBcHBseSBTeW5jaHJvbml6YXRpb24qKjogVXNlIHN5bmNocm9uaXphdGlvbiBtZWNoYW5pc21zIHN1Y2ggYXMgYHN5bmNocm9uaXplZGAgbWV0aG9kcywgYmxvY2tzLCBvciBsb2NrcyB0byBwcm90ZWN0IGNyaXRpY2FsIHNlY3Rpb25zLiBUaGlzIGVuc3VyZXMgdGhhdCBvbmx5IG9uZSB0aHJlYWQgY2FuIGFjY2VzcyB0aGUgY3JpdGljYWwgc2VjdGlvbiBhdCBhIHRpbWUuCgozLiAgKipBdG9taWMgT3BlcmF0aW9ucyoqOiBVc2UgYXRvbWljIG9wZXJhdGlvbnMgcHJvdmlkZWQgYnkgY2xhc3NlcyBsaWtlIGBBdG9taWNJbnRlZ2VyYCBvciBgQXRvbWljUmVmZXJlbmNlYCB0byBwZXJmb3JtIGNvbXBvdW5kIGFjdGlvbnMgb24gc2hhcmVkIHZhcmlhYmxlcyBhdG9taWNhbGx5LiBUaGVzZSBvcGVyYXRpb25zIGFyZSBpbmhlcmVudGx5IHRocmVhZC1zYWZlLgoKNC4gICoqSW1tdXRhYmxlIE9iamVjdHMqKjogQ29uc2lkZXIgdXNpbmcgaW1tdXRhYmxlIG9iamVjdHMuIEltbXV0YWJsZSBvYmplY3RzIGFyZSB0aG9zZSB3aG9zZSBzdGF0ZSBjYW5ub3QgYmUgbW9kaWZpZWQgYWZ0ZXIgY3JlYXRpb24sIG1ha2luZyB0aGVtIGluaGVyZW50bHkgdGhyZWFkLXNhZmUuIEFueSBvcGVyYXRpb24gb24gYW4gaW1tdXRhYmxlIG9iamVjdCBjcmVhdGVzIGEgbmV3IGluc3RhbmNlIHJhdGhlciB0aGFuIG1vZGlmeWluZyB0aGUgZXhpc3Rpbmcgb25lLgoKIyMjIEJlc3QgUHJhY3RpY2VzIGZvciBUaHJlYWQgU2FmZXR5CgpNYWludGFpbmluZyB0aHJlYWQgc2FmZXR5IGluIEphdmEgYXBwbGljYXRpb25zIGludm9sdmVzIGZvbGxvd2luZyBiZXN0IHByYWN0aWNlcywgaW5jbHVkaW5nOgoKMS4gICoqTWluaW1pemUgU2hhcmVkIE11dGFibGUgU3RhdGUqKjogUmVkdWNlIHRoZSB1c2Ugb2Ygc2hhcmVkIG11dGFibGUgc3RhdGUgd2hlbmV2ZXIgcG9zc2libGUuIElzb2xhdGUgc2hhcmVkIGRhdGEgYW5kIG1pbmltaXplIHRoZSBudW1iZXIgb2YgdGhyZWFkcyB0aGF0IGNhbiBhY2Nlc3MgaXQuCgoyLiAgKipVc2UgVGhyZWFkLUxvY2FsIFZhcmlhYmxlcyoqOiBJbiBzb21lIGNhc2VzLCB0aHJlYWQtbG9jYWwgdmFyaWFibGVzIGNhbiBlbGltaW5hdGUgdGhlIG5lZWQgZm9yIHN5bmNocm9uaXphdGlvbiBieSBlbnN1cmluZyB0aGF0IGVhY2ggdGhyZWFkIGhhcyBpdHMgb3duIGNvcHkgb2YgdGhlIGRhdGEuCgozLiAgKipUZXN0aW5nIGFuZCBEZWJ1Z2dpbmcqKjogVGhvcm91Z2hseSB0ZXN0IG11bHRpLXRocmVhZGVkIGNvZGUsIGluY2x1ZGluZyBlZGdlIGNhc2VzIGFuZCBzdHJlc3MgdGVzdHMuIERlYnVnZ2luZyB0b29scyBhbmQgdGVjaG5pcXVlcyBzcGVjaWZpYyB0byBtdWx0aS10aHJlYWRpbmcsIHN1Y2ggYXMgdGhyZWFkIGR1bXBzIGFuZCBwcm9maWxlcnMsIGNhbiBoZWxwIGlkZW50aWZ5IGlzc3Vlcy4KCjQuICAqKkNvbmN1cnJlbmN5IExpYnJhcmllcyoqOiBMZXZlcmFnZSBKYXZhJ3MgY29uY3VycmVuY3kgbGlicmFyaWVzLCBzdWNoIGFzIHRoZSBgamF2YS51dGlsLmNvbmN1cnJlbnRgIHBhY2thZ2UsIHdoaWNoIHByb3ZpZGVzIHRocmVhZC1zYWZlIGRhdGEgc3RydWN0dXJlcyBhbmQgc3luY2hyb25pemF0aW9uIHByaW1pdGl2ZXMuCgo1LiAgKipEb2N1bWVudGF0aW9uKio6IERvY3VtZW50IHRocmVhZC1zYWZldHkgZ3VhcmFudGVlcyBmb3IgY2xhc3NlcyBhbmQgbWV0aG9kcywgbWFraW5nIGl0IGNsZWFyIHRvIGRldmVsb3BlcnMgd2hpY2ggcGFydHMgb2YgdGhlIGNvZGUgbmVlZCB0byBiZSBzeW5jaHJvbml6ZWQgYW5kIHdoaWNoIGFyZSBzYWZlIGZvciBjb25jdXJyZW50IHVzZS4KCkluIHN1bW1hcnksIENoYXB0ZXIgNCBleHBsb3JlcyB0aGUgaW1wb3J0YW5jZSBvZiB0aHJlYWQgc2FmZXR5IGluIG11bHRpLXRocmVhZGVkIEphdmEgYXBwbGljYXRpb25zLCBoaWdobGlnaHRpbmcgdGhlIGNoYWxsZW5nZXMgcG9zZWQgYnkgcmFjZSBjb25kaXRpb25zIGFuZCBvZmZlcmluZyBzdHJhdGVnaWVzIHRvIGlkZW50aWZ5LCBwcmV2ZW50LCBhbmQgaGFuZGxlIHRoZW0uIFVuZGVyc3RhbmRpbmcgYW5kIGFwcGx5aW5nIHRocmVhZCBzYWZldHkgcHJpbmNpcGxlcyBhcmUgY3J1Y2lhbCBmb3IgYnVpbGRpbmcgcm9idXN0IGFuZCByZWxpYWJsZSBtdWx0aS10aHJlYWRlZCBzb2Z0d2FyZS4KCiMjIFVzaW5nIEphdmEncyBDb25jdXJyZW5jeSBVdGlsaXRpZXMKClRoaXMgc2VjdGlvbiBpcyBhIHBpdm90YWwgcGFydCBvZiBvdXIgZXhwbG9yYXRpb24gaW50byBtdWx0aS10aHJlYWRpbmcgaW4gSmF2YSB3aGVyZSB3ZSBkaXZlIGludG8gdGhlIHJpY2ggc2V0IG9mIGNvbmN1cnJlbmN5IHV0aWxpdHkgY2xhc3NlcyBhbmQgbWV0aG9kcyBwcm92aWRlZCBieSB0aGUgYGphdmEudXRpbC5jb25jdXJyZW50YCBwYWNrYWdlLiBUaGVzZSBtZWNoYW5pc21zIHNpbXBsaWZ5IHRoZSBkZXZlbG9wbWVudCBvZiBtdWx0aS10aHJlYWRlZCBhcHBsaWNhdGlvbnMgYnkgb2ZmZXJpbmcgaGlnaC1sZXZlbCBjb25zdHJ1Y3RzLCB0aHJlYWQgcG9vbHMsIGNvbmN1cnJlbnQgY29sbGVjdGlvbnMsIGFuZCBzeW5jaHJvbml6YXRpb24gcHJpbWl0aXZlcy4KCiMjIyBPYmplY3RpdmVzCgotICAgamF2YS51dGlsLmNvbmN1cnJlbnQgUGFja2FnZSBPdmVydmlldwotICAgRXhlY3V0b3JzIGFuZCBUaHJlYWQgUG9vbHMKLSAgIENvbmN1cnJlbnQgQ29sbGVjdGlvbnMKLSAgIENhbGxhYmxlIGFuZCBGdXR1cmUKCiMjIyBgamF2YS51dGlsLmNvbmN1cnJlbnRgIFBhY2thZ2UgT3ZlcnZpZXcKClRoZSBgamF2YS51dGlsLmNvbmN1cnJlbnRgIHBhY2thZ2UsIGludHJvZHVjZWQgaW4gSmF2YSA1LCBpcyBhIHRyZWFzdXJlIHRyb3ZlIG9mIGNsYXNzZXMgYW5kIGludGVyZmFjZXMgZGVzaWduZWQgdG8gbWFrZSBtdWx0aS10aHJlYWRlZCBwcm9ncmFtbWluZyBtb3JlIGFjY2Vzc2libGUgYW5kIGVmZmljaWVudC4gSXQgZW5jb21wYXNzZXMgYSB3aWRlIHJhbmdlIG9mIGZlYXR1cmVzIGFuZCB0b29scyB0aGF0IGNhbiBzaWduaWZpY2FudGx5IHNpbXBsaWZ5IHRoZSB0YXNrIG9mIG1hbmFnaW5nIGNvbmN1cnJlbnQgdGFza3MgYW5kIGRhdGEuCgpTb21lIG9mIHRoZSBjb3JlIGNvbXBvbmVudHMgb2YgdGhpcyBwYWNrYWdlIGluY2x1ZGU6CgoxLiAgKipFeGVjdXRvcnMqKjogVGhlIGBFeGVjdXRvcmAgZnJhbWV3b3JrIGFic3RyYWN0cyB0aGUgbWFuYWdlbWVudCBvZiB0aHJlYWRzLCBhbGxvd2luZyB5b3UgdG8gZm9jdXMgb24gdGFza3MgcmF0aGVyIHRoYW4gbWFuYWdpbmcgdGhyZWFkIGNyZWF0aW9uIGFuZCBsaWZlY3ljbGUuIEl0IHByb3ZpZGVzIGEgd2F5IHRvIHN1Ym1pdCB0YXNrcyBmb3IgZXhlY3V0aW9uIGFuZCBjb250cm9sIHRoZSB0aHJlYWQgcG9vbC4KCjIuICAqKlRocmVhZCBQb29scyoqOiBgRXhlY3V0b3JTZXJ2aWNlYCBpbnRlcmZhY2VzLCBhbG9uZyB3aXRoIGltcGxlbWVudGF0aW9ucyBsaWtlIGBUaHJlYWRQb29sRXhlY3V0b3JgIGFuZCBgU2NoZWR1bGVkVGhyZWFkUG9vbEV4ZWN1dG9yYCwgc2ltcGxpZnkgdGhlIGNyZWF0aW9uIGFuZCBtYW5hZ2VtZW50IG9mIHRocmVhZCBwb29scy4gVGhyZWFkIHBvb2xzIGFyZSBjcnVjaWFsIGZvciBtYW5hZ2luZyB0aHJlYWQgbGlmZWN5Y2xlIGFuZCByZXNvdXJjZSBjb25zdW1wdGlvbi4KCjMuICAqKkNvbmN1cnJlbnQgQ29sbGVjdGlvbnMqKjogSmF2YSdzIGNvbmN1cnJlbnQgY29sbGVjdGlvbnMsIHN1Y2ggYXMgYENvbmN1cnJlbnRIYXNoTWFwYCBhbmQgYENvbmN1cnJlbnRMaW5rZWRRdWV1ZWAsIGFyZSBkZXNpZ25lZCBmb3Igc2FmZSBhbmQgZWZmaWNpZW50IGFjY2VzcyBieSBtdWx0aXBsZSB0aHJlYWRzLiBUaGV5IGVsaW1pbmF0ZSB0aGUgbmVlZCBmb3IgbWFudWFsIHN5bmNocm9uaXphdGlvbiBhbmQgcHJvdmlkZSBleGNlbGxlbnQgcGVyZm9ybWFuY2UgaW4gbXVsdGktdGhyZWFkZWQgc2NlbmFyaW9zLgoKNC4gICoqU3luY2hyb25pemF0aW9uIFByaW1pdGl2ZXMqKjogVGhlIHBhY2thZ2Ugb2ZmZXJzIHZhcmlvdXMgc3luY2hyb25pemF0aW9uIHByaW1pdGl2ZXMgbGlrZSBgU2VtYXBob3JlYCwgYENvdW50RG93bkxhdGNoYCwgYW5kIGBDeWNsaWNCYXJyaWVyYCB0aGF0IGVuYWJsZSB0aHJlYWRzIHRvIGNvb3JkaW5hdGUgdGhlaXIgYWN0aXZpdGllcyBhbmQgc3luY2hyb25pemUgYXQgc3BlY2lmaWMgcG9pbnRzIGR1cmluZyBleGVjdXRpb24uCgo1LiAgKipBdG9taWMgVmFyaWFibGVzKio6IENsYXNzZXMgbGlrZSBgQXRvbWljSW50ZWdlcmAsIGBBdG9taWNMb25nYCwgYW5kIGBBdG9taWNSZWZlcmVuY2VgIHByb3ZpZGUgYXRvbWljIG9wZXJhdGlvbnMgb24gdmFyaWFibGVzLCBlbnN1cmluZyB0aGF0IGNvbXBsZXggb3BlcmF0aW9ucyBvbiBzaGFyZWQgZGF0YSBhcmUgZXhlY3V0ZWQgYXRvbWljYWxseSB3aXRob3V0IHRoZSBuZWVkIGZvciBleHBsaWNpdCBzeW5jaHJvbml6YXRpb24uCgojIyMgRXhlY3V0b3JzIGFuZCBUaHJlYWQgUG9vbHMKClRocmVhZCBwb29scyBhcmUgYSBmdW5kYW1lbnRhbCBjb25jZXB0IGluIGNvbmN1cnJlbnQgcHJvZ3JhbW1pbmcsIGFuZCB0aGUgYGphdmEudXRpbC5jb25jdXJyZW50YCBwYWNrYWdlIG1ha2VzIHdvcmtpbmcgd2l0aCB0aGVtIHN0cmFpZ2h0Zm9yd2FyZC4gWW91IGNhbiBjcmVhdGUgYW5kIG1hbmFnZSB0aHJlYWQgcG9vbHMgdG8gZWZmaWNpZW50bHkgcmV1c2UgdGhyZWFkcywgY29udHJvbCByZXNvdXJjZSBjb25zdW1wdGlvbiwgYW5kIHNpbXBsaWZ5IHRhc2sgc3VibWlzc2lvbi4gVGhlIHBhY2thZ2Ugb2ZmZXJzIGRpZmZlcmVudCB0eXBlcyBvZiB0aHJlYWQgcG9vbHMsIGluY2x1ZGluZyBmaXhlZC1zaXplLCBjYWNoZWQsIGFuZCBzY2hlZHVsZWQgdGhyZWFkIHBvb2xzLgoKSGVyZSdzIGFuIGV4YW1wbGUgb2YgY3JlYXRpbmcgYSBmaXhlZC1zaXplIHRocmVhZCBwb29sIHVzaW5nIGBFeGVjdXRvcnNgOgoKYGBgIGphdmEKRXhlY3V0b3JTZXJ2aWNlIGV4ZWN1dG9yID0gRXhlY3V0b3JzLm5ld0ZpeGVkVGhyZWFkUG9vbCg0KTsgLy8gQ3JlYXRlcyBhIHBvb2wgd2l0aCA0IHRocmVhZHMKYGBgCgojIyMgQ29uY3VycmVudCBDb2xsZWN0aW9ucwoKSmF2YSdzIGNvbmN1cnJlbnQgY29sbGVjdGlvbnMgYXJlIGRlc2lnbmVkIGZvciBzYWZlLCBlZmZpY2llbnQsIGFuZCB0aHJlYWQtZnJpZW5kbHkgZGF0YSBzdG9yYWdlIGFuZCByZXRyaWV2YWwuIEZvciBleGFtcGxlLCBgQ29uY3VycmVudEhhc2hNYXBgIGFsbG93cyBtdWx0aXBsZSB0aHJlYWRzIHRvIHJlYWQgYW5kIHdyaXRlIHRvIHRoZSBtYXAgY29uY3VycmVudGx5IHdpdGhvdXQgZXhwbGljaXQgc3luY2hyb25pemF0aW9uLgoKYGBgIGphdmEKQ29uY3VycmVudE1hcDxTdHJpbmcsIEludGVnZXI+IGNvbmN1cnJlbnRNYXAgPSBuZXcgQ29uY3VycmVudEhhc2hNYXA8PigpOwpjb25jdXJyZW50TWFwLnB1dCgia2V5IiwgNDIpOwppbnQgdmFsdWUgPSBjb25jdXJyZW50TWFwLmdldCgia2V5Iik7CmBgYAoKIyMjIENhbGxhYmxlIGFuZCBGdXR1cmUKClRoZSBgQ2FsbGFibGVgIGFuZCBgRnV0dXJlYCBpbnRlcmZhY2VzIGFsbG93IHlvdSB0byBwZXJmb3JtIHRhc2tzIHRoYXQgcmV0dXJuIHJlc3VsdHMgYW5kIGNhbiBiZSBleGVjdXRlZCBhc3luY2hyb25vdXNseS4gQSBgQ2FsbGFibGVgIGlzIHNpbWlsYXIgdG8gYSBgUnVubmFibGVgIGJ1dCBjYW4gcmV0dXJuIGEgcmVzdWx0IG9yIHRocm93IGFuIGV4Y2VwdGlvbi4gQSBgRnV0dXJlYCByZXByZXNlbnRzIHRoZSByZXN1bHQgb2YgYW4gYXN5bmNocm9ub3VzIGNvbXB1dGF0aW9uIGFuZCBwcm92aWRlcyBtZXRob2RzIHRvIHJldHJpZXZlIHRoZSByZXN1bHQgb3IgaGFuZGxlIGV4Y2VwdGlvbnMgd2hlbiB0aGUgdGFzayBjb21wbGV0ZXMuCgpgYGAgamF2YQpFeGVjdXRvclNlcnZpY2UgZXhlY3V0b3IgPSBFeGVjdXRvcnMubmV3U2luZ2xlVGhyZWFkRXhlY3V0b3IoKTsKRnV0dXJlPEludGVnZXI+IGZ1dHVyZSA9IGV4ZWN1dG9yLnN1Ym1pdCgoKSAtPiB7CiAgICAvLyBDb21wdXRlIGEgcmVzdWx0CiAgICByZXR1cm4gNDI7Cn0pOwoKLy8gUmV0cmlldmUgdGhlIHJlc3VsdCB3aGVuIGl0J3MgYXZhaWxhYmxlCmludCByZXN1bHQgPSBmdXR1cmUuZ2V0KCk7CmBgYAoKSW4gc2hvcnQsIHRoZSBgamF2YS51dGlsLmNvbmN1cnJlbnRgIHBhY2thZ2Ugb2ZmZXJzIGEgcGxldGhvcmEgb2YgY29uc3RydWN0cywgY2xhc3NlcywgYW5kIHV0aWxpdHkgbWV0aG9kcyB0byBzaW1wbGlmeSBtdWx0aS10aHJlYWRlZCBwcm9ncmFtbWluZyBpbiBKYXZhLiBCeSBsZXZlcmFnaW5nIHRocmVhZCBwb29scywgY29uY3VycmVudCBjb2xsZWN0aW9ucywgc3luY2hyb25pemF0aW9uIHByaW1pdGl2ZXMsIGFuZCBvdGhlciBmZWF0dXJlcywgZGV2ZWxvcGVycyBjYW4gYnVpbGQgZWZmaWNpZW50LCBzY2FsYWJsZSwgYW5kIHRocmVhZC1zYWZlIGFwcGxpY2F0aW9ucyBtb3JlIGVhc2lseSBhbmQgZWZmZWN0aXZlbHkuIFVuZGVyc3RhbmRpbmcgdGhlc2UgdXRpbGl0aWVzIGlzIGVzc2VudGlhbCBmb3IgYnVpbGRpbmcgYXBwbGljYXRpb24gd2l0aCBzYWZlIG11bHRpLXRocmVhZGluZy4KCiMjIEFkdmFuY2VkIFN5bmNocm9uaXphdGlvbiBUZWNobmlxdWVzCgpUaGlzIHNlY3Rpb24gdGFrZXMgb3VyIGpvdXJuZXkgaW50byBtdWx0aS10aHJlYWRpbmcgaW4gSmF2YSB0byBhIGRlZXBlciBsZXZlbCBieSBleHBsb3JpbmcgYWR2YW5jZWQgdGhyZWFkIHN5bmNocm9uaXphdGlvbiB0ZWNobmlxdWVzIGFuZCBwYXR0ZXJucy4gU3BlY2lmaWNhbGx5LCB3ZSBtb3ZlIGJleW9uZCBiYXNpYyBzeW5jaHJvbml6YXRpb24gYW5kIGRlbHZlIGludG8gbW9yZSBjb21wbGV4IHNjZW5hcmlvcyBhbmQgc3RyYXRlZ2llcyBmb3IgbWFuYWdpbmcgY29uY3VycmVuY3kuCgojIyMgT2JqZWN0aXZlcwoKLSAgIFJlZW50cmFudExvY2sgYW5kIENvbmRpdGlvbgotICAgUmVhZC1Xcml0ZSBMb2NrcwotICAgU2VtYXBob3JlcyBhbmQgQ291bnREb3duTGF0Y2gKLSAgIEN5Y2xpY0JhcnJpZXIgYW5kIFBoYXNlcgoKIyMjIExvY2sgT2JqZWN0cyBhbmQgTG9jayBJbnRlcmZhY2VzCgpXaGlsZSBgc3luY2hyb25pemVkYCBibG9ja3MgYW5kIG1ldGhvZHMgcHJvdmlkZSBhIHN0cmFpZ2h0Zm9yd2FyZCB3YXkgdG8gbWFuYWdlIHN5bmNocm9uaXphdGlvbiwgSmF2YSBhbHNvIG9mZmVycyBtb3JlIGFkdmFuY2VkIHN5bmNocm9uaXphdGlvbiB0aHJvdWdoIGV4cGxpY2l0IGxvY2sgb2JqZWN0cyBhbmQgaW50ZXJmYWNlcyBpbiB0aGUgYGphdmEudXRpbC5jb25jdXJyZW50LmxvY2tzYCBwYWNrYWdlLiBUaGVzZSBtZWNoYW5pc21zIHByb3ZpZGUgZ3JlYXRlciBjb250cm9sIG92ZXIgdGhyZWFkIHN5bmNocm9uaXphdGlvbiBhbmQgY2FuIGJlIHBhcnRpY3VsYXJseSB1c2VmdWwgaW4gY29tcGxleCBzY2VuYXJpb3MuCgoxLiAgKipgUmVlbnRyYW50TG9ja2AqKjogVGhlIGBSZWVudHJhbnRMb2NrYCBjbGFzcyBpcyBhIHZlcnNhdGlsZSBhbHRlcm5hdGl2ZSB0byBzeW5jaHJvbml6ZWQgYmxvY2tzLiBJdCBhbGxvd3MgZmluZS1ncmFpbmVkIGNvbnRyb2wgb3ZlciBsb2NraW5nIGFuZCB1bmxvY2tpbmcgYW5kIHN1cHBvcnRzIGZlYXR1cmVzIHN1Y2ggYXMgZmFpcm5lc3MsIHdoaWNoIGVuc3VyZXMgdGhhdCB0aHJlYWRzIGFjcXVpcmUgdGhlIGxvY2sgaW4gdGhlIG9yZGVyIHRoZXkgcmVxdWVzdCBpdC4KCiAgICBgYGAgamF2YQogICAgUmVlbnRyYW50TG9jayBsb2NrID0gbmV3IFJlZW50cmFudExvY2soKTsKICAgIGxvY2subG9jaygpOyAvLyBBY3F1aXJlIHRoZSBsb2NrCiAgICB0cnkgewogICAgICAgIC8vIFN5bmNocm9uaXplZCBjb2RlIGhlcmUKICAgIH0gZmluYWxseSB7CiAgICAgICAgbG9jay51bmxvY2soKTsgLy8gUmVsZWFzZSB0aGUgbG9jayBpbiBhIGZpbmFsbHkgYmxvY2sKICAgIH0KICAgIGBgYAoKMi4gICoqYFJlYWRXcml0ZUxvY2tgKio6IFRoZSBgUmVhZFdyaXRlTG9ja2AgaW50ZXJmYWNlIHByb3ZpZGVzIGEgd2F5IHRvIG1hbmFnZSBjb25jdXJyZW50IGFjY2VzcyB0byBzaGFyZWQgZGF0YSB3aGVyZSBtdWx0aXBsZSB0aHJlYWRzIG1heSByZWFkIGRhdGEgY29uY3VycmVudGx5LCBidXQgd3JpdGUgb3BlcmF0aW9ucyBzaG91bGQgYmUgZXhjbHVzaXZlLiBJdCBvZmZlcnMgdHdvIHR5cGVzIG9mIGxvY2tzOiBhIHJlYWQgbG9jayBhbmQgYSB3cml0ZSBsb2NrLgoKICAgIGBgYCBqYXZhCiAgICBSZWFkV3JpdGVMb2NrIHJ3TG9jayA9IG5ldyBSZWVudHJhbnRSZWFkV3JpdGVMb2NrKCk7CiAgICByd0xvY2sucmVhZExvY2soKS5sb2NrKCk7IC8vIEFjcXVpcmUgdGhlIHJlYWQgbG9jawogICAgdHJ5IHsKICAgICAgICAvLyBSZWFkIGRhdGEKICAgIH0gZmluYWxseSB7CiAgICAgICAgcndMb2NrLnJlYWRMb2NrKCkudW5sb2NrKCk7IC8vIFJlbGVhc2UgdGhlIHJlYWQgbG9jawogICAgfQogICAgYGBgCgozLiAgKipgU3RhbXBlZExvY2tgKio6IEludHJvZHVjZWQgaW4gSmF2YSA4LCBgU3RhbXBlZExvY2tgIGlzIGEgbW9yZSBhZHZhbmNlZCByZWFkLXdyaXRlIGxvY2sgd2l0aCBhbiBvcHRpbWlzdGljIGxvY2tpbmcgbW9kZS4gSXQgcHJvdmlkZXMgYmV0dGVyIHBlcmZvcm1hbmNlIGZvciByZWFkLWhlYXZ5IHdvcmtsb2FkcyB3aGlsZSBtYWludGFpbmluZyB0aHJlYWQgc2FmZXR5IGZvciB3cml0ZXMuCgojIyMgQ29uZGl0aW9uIFZhcmlhYmxlcwoKQ29uZGl0aW9uIHZhcmlhYmxlcywgcmVwcmVzZW50ZWQgYnkgdGhlIGBqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcy5Db25kaXRpb25gIGludGVyZmFjZSwgYXJlIHVzZWQgdG8gY29vcmRpbmF0ZSB0aGUgZXhlY3V0aW9uIG9mIHRocmVhZHMgaW4gbW9yZSBjb21wbGV4IHN5bmNocm9uaXphdGlvbiBzY2VuYXJpb3MuIFRoZXkgYWxsb3cgdGhyZWFkcyB0byB3YWl0IHVudGlsIGEgc3BlY2lmaWMgY29uZGl0aW9uIGlzIG1ldCBiZWZvcmUgcHJvY2VlZGluZy4gQ29uZGl0aW9uIHZhcmlhYmxlcyBhcmUgb2Z0ZW4gdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIGV4cGxpY2l0IGxvY2tzLgoKYGBgIGphdmEKUmVlbnRyYW50TG9jayBsb2NrID0gbmV3IFJlZW50cmFudExvY2soKTsKQ29uZGl0aW9uIGNvbmRpdGlvbiA9IGxvY2submV3Q29uZGl0aW9uKCk7CgovLyBUaHJlYWQgMQpsb2NrLmxvY2soKTsKdHJ5IHsKICAgIHdoaWxlICghY29uZGl0aW9uTWV0KSB7CiAgICAgICAgY29uZGl0aW9uLmF3YWl0KCk7IC8vIFdhaXQgdW50aWwgdGhlIGNvbmRpdGlvbiBpcyBtZXQKICAgIH0KICAgIC8vIENvbnRpbnVlIGV4ZWN1dGlvbgp9IGZpbmFsbHkgewogICAgbG9jay51bmxvY2soKTsKfQoKLy8gVGhyZWFkIDIKbG9jay5sb2NrKCk7CnRyeSB7CiAgICAvLyBDaGFuZ2Ugc29tZSBzdGF0ZQogICAgY29uZGl0aW9uTWV0ID0gdHJ1ZTsKICAgIGNvbmRpdGlvbi5zaWduYWwoKTsgLy8gU2lnbmFsIHdhaXRpbmcgdGhyZWFkcyB0aGF0IHRoZSBjb25kaXRpb24gaXMgbWV0Cn0gZmluYWxseSB7CiAgICBsb2NrLnVubG9jaygpOwp9CmBgYAoKIyMjIFRocmVhZCBTYWZldHkgUGF0dGVybnMKCkNoYXB0ZXIgNiBhbHNvIGludHJvZHVjZXMgdGhyZWFkIHNhZmV0eSBwYXR0ZXJucywgd2hpY2ggYXJlIGRlc2lnbiBhcHByb2FjaGVzIGFuZCBzdHJhdGVnaWVzIGZvciBlbnN1cmluZyB0aHJlYWQgc2FmZXR5IGluIG11bHRpLXRocmVhZGVkIGFwcGxpY2F0aW9ucy4gVGhlc2UgcGF0dGVybnMgaW5jbHVkZToKCjEuICAqKkltbXV0YWJsZSBPYmplY3RzKio6IERlc2lnbmluZyBvYmplY3RzIHRoYXQgY2Fubm90IGJlIG1vZGlmaWVkIGFmdGVyIGNyZWF0aW9uLCBlbGltaW5hdGluZyB0aGUgbmVlZCBmb3Igc3luY2hyb25pemF0aW9uLgoKMi4gICoqR3VhcmRlZCBCbG9ja3MqKjogVXNpbmcgYHdoaWxlYCBsb29wcyB0byB3YWl0IGZvciBzcGVjaWZpYyBjb25kaXRpb25zIHRvIGJlIG1ldCBiZWZvcmUgcHJvY2VlZGluZy4KCjMuICAqKkJhbGtpbmcqKjogQSBwYXR0ZXJuIHdoZXJlIGEgdGhyZWFkIGRldGVjdHMgYSBjb25kaXRpb24gYW5kIGRlY2lkZXMgbm90IHRvIHByb2NlZWQgd2l0aCBhbiBhY3Rpb24sIGF2b2lkaW5nIHVubmVjZXNzYXJ5IHdvcmsuCgo0LiAgKipQcm9kdWNlci1Db25zdW1lcioqOiBDb29yZGluYXRpbmcgYmV0d2VlbiB0aHJlYWRzIHRoYXQgcHJvZHVjZSBkYXRhIGFuZCB0aHJlYWRzIHRoYXQgY29uc3VtZSBkYXRhIHVzaW5nIHNoYXJlZCBkYXRhIHN0cnVjdHVyZXMuCgo1LiAgKipSZWFkLVdyaXRlIExvY2tzKio6IFVzaW5nIHJlYWQtd3JpdGUgbG9ja3MgdG8gYWxsb3cgbXVsdGlwbGUgdGhyZWFkcyB0byByZWFkIGRhdGEgY29uY3VycmVudGx5IGJ1dCBlbnN1cmluZyBleGNsdXNpdmUgYWNjZXNzIGZvciB3cml0ZSBvcGVyYXRpb25zLgoKIyMjIEJlc3QgUHJhY3RpY2VzIGZvciBBZHZhbmNlZCBTeW5jaHJvbml6YXRpb24KCldlIGV4cGxvcmVkIGJlc3QgcHJhY3RpY2VzIGZvciBhZHZhbmNlZCBzeW5jaHJvbml6YXRpb24sIGVtcGhhc2l6aW5nIHRoZSBpbXBvcnRhbmNlIG9mIGNsZWFyIGRvY3VtZW50YXRpb24sIHByb3BlciBleGNlcHRpb24gaGFuZGxpbmcsIGFuZCB0aG9yb3VnaCB0ZXN0aW5nIHdoZW4gZGVhbGluZyB3aXRoIGNvbXBsZXggc3luY2hyb25pemF0aW9uIHNjZW5hcmlvcy4gSG93ZXZlciwgZGV2ZWxvcGVycyBtdXN0IHVzZSBzeW5jaHJvbml6YXRpb24gY29uc3RydWN0cyBjYXV0aW91c2x5IGFuZCBjb25zaWRlciBhbHRlcm5hdGl2ZXMgd2hlbiBhcHByb3ByaWF0ZSwgYXMgZXhjZXNzaXZlIHN5bmNocm9uaXphdGlvbiBjYW4gbGVhZCB0byBwZXJmb3JtYW5jZSBib3R0bGVuZWNrcyBhbmQgdHVybiBtdWx0aS10aHJlYWRlZCBjb2RlIGludG8gc2luZ2xlLXRocmVhZGVkIGV4ZWN1dGlvbi4KCiMjIENoYXB0ZXIgNzogVGhyZWFkIENvbW11bmljYXRpb24KCkluIHRoaXMgc2VjdGlvbiwgd2UgZGVsdmUgaW50byBzb21lIGVzc2VudGlhbCBhc3BlY3RzIG9mIHRocmVhZCBjb21tdW5pY2F0aW9uLCBpbmNsdWRpbmcgdGhlIGB3YWl0YCBhbmQgYG5vdGlmeWAgbWVjaGFuaXNtcywgYW5kIHRoZSB1c2Ugb2YgYmxvY2tpbmcgcXVldWVzIGluIEphdmEuIFRoZXNlIGNvbmNlcHRzIGFyZSBlc3NlbnRpYWwgZm9yIGJ1aWxkaW5nIGVmZmljaWVudCBhbmQgc3luY2hyb25pemVkIG11bHRpLXRocmVhZGVkIGFwcGxpY2F0aW9ucy4KCiMjIyBPYmplY3RpdmVzCgotICAgSW50ZXItVGhyZWFkIENvbW11bmljYXRpb24KLSAgIFByb2R1Y2VyLUNvbnN1bWVyIFByb2JsZW0KLSAgIFdhaXQgYW5kIE5vdGlmeQotICAgQmxvY2tpbmcgUXVldWVzCgojIyMgVGhyZWFkIENvbW11bmljYXRpb24KClRocmVhZCBjb21tdW5pY2F0aW9uIGlzIHRoZSBwcmFjdGljZSBvZiBlbmFibGluZyB0aHJlYWRzIHRvIGludGVyYWN0LCBzeW5jaHJvbml6ZSwgYW5kIGV4Y2hhbmdlIGluZm9ybWF0aW9uIHdpdGggZWFjaCBvdGhlciBpbiBhIGNvbnRyb2xsZWQgbWFubmVyLiBJdCdzIHZpdGFsIGluIG11bHRpLXRocmVhZGVkIGFwcGxpY2F0aW9ucyB3aGVyZSB0aHJlYWRzIG1heSBuZWVkIHRvIGNvb3JkaW5hdGUgdGhlaXIgYWN0aW9ucywgc2lnbmFsIGV2ZW50cywgb3Igc2hhcmUgZGF0YS4gVHdvIGZ1bmRhbWVudGFsIG1lY2hhbmlzbXMgZm9yIHRocmVhZCBjb21tdW5pY2F0aW9uIGluIEphdmEgYXJlIGB3YWl0YCBhbmQgYG5vdGlmeWAuCgoxLiAgKipgd2FpdCgpYCBhbmQgYG5vdGlmeSgpYCBNZXRob2RzKio6IFRoZXNlIG1ldGhvZHMgYXJlIHBhcnQgb2YgdGhlIGBPYmplY3RgIGNsYXNzIGFuZCBhbGxvdyB0aHJlYWRzIHRvIHN5bmNocm9uaXplIGFuZCBjb21tdW5pY2F0ZS4gSGVyZSdzIGhvdyB0aGV5IHdvcms6CiAgICAtICAgYHdhaXQoKWA6IEEgdGhyZWFkIGNhbGxzIGB3YWl0KClgIHRvIHJlbGVhc2UgdGhlIGxvY2sgb24gYW4gb2JqZWN0IGFuZCBlbnRlciBhIHdhaXRpbmcgc3RhdGUuIEl0IHdhaXRzIHVudGlsIGFub3RoZXIgdGhyZWFkIGludm9rZXMgYG5vdGlmeSgpYCBvciBgbm90aWZ5QWxsKClgIG9uIHRoZSBzYW1lIG9iamVjdC4KICAgIC0gICBgbm90aWZ5KClgOiBBIHRocmVhZCBjYWxscyBgbm90aWZ5KClgIHRvIHdha2UgdXAgb25lIG9mIHRoZSB3YWl0aW5nIHRocmVhZHMgdGhhdCBjYWxsZWQgYHdhaXQoKWAgb24gdGhlIHNhbWUgb2JqZWN0LiBJdCdzIHVzZWQgdG8gc2lnbmFsIHRoYXQgYSBjb25kaXRpb24gaGFzIGNoYW5nZWQgYW5kIHRoYXQgd2FpdGluZyB0aHJlYWRzIGNhbiBwcm9jZWVkLgoKYGBgIGphdmEKLy8gUHJvZHVjZXItQ29uc3VtZXIgZXhhbXBsZSB1c2luZyB3YWl0IGFuZCBub3RpZnkKY2xhc3MgU2hhcmVkUmVzb3VyY2UgewogICAgcHJpdmF0ZSBpbnQgZGF0YTsKICAgIHByaXZhdGUgYm9vbGVhbiBuZXdEYXRhQXZhaWxhYmxlID0gZmFsc2U7CgogICAgcHVibGljIHN5bmNocm9uaXplZCB2b2lkIHByb2R1Y2UoaW50IHZhbHVlKSB7CiAgICAgICAgd2hpbGUgKG5ld0RhdGFBdmFpbGFibGUpIHsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHdhaXQoKTsgLy8gV2FpdCB1bnRpbCB0aGUgZGF0YSBpcyBjb25zdW1lZAogICAgICAgICAgICB9IGNhdGNoIChJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBlKSB7CiAgICAgICAgICAgICAgICBUaHJlYWQuY3VycmVudFRocmVhZCgpLmludGVycnVwdCgpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGRhdGEgPSB2YWx1ZTsKICAgICAgICBuZXdEYXRhQXZhaWxhYmxlID0gdHJ1ZTsKICAgICAgICBub3RpZnkoKTsgLy8gU2lnbmFsIHRoYXQgbmV3IGRhdGEgaXMgYXZhaWxhYmxlCiAgICB9CgogICAgcHVibGljIHN5bmNocm9uaXplZCBpbnQgY29uc3VtZSgpIHsKICAgICAgICB3aGlsZSAoIW5ld0RhdGFBdmFpbGFibGUpIHsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHdhaXQoKTsgLy8gV2FpdCB1bnRpbCBuZXcgZGF0YSBpcyBwcm9kdWNlZAogICAgICAgICAgICB9IGNhdGNoIChJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBlKSB7CiAgICAgICAgICAgICAgICBUaHJlYWQuY3VycmVudFRocmVhZCgpLmludGVycnVwdCgpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIG5ld0RhdGFBdmFpbGFibGUgPSBmYWxzZTsKICAgICAgICBub3RpZnkoKTsgLy8gU2lnbmFsIHRoYXQgdGhlIGRhdGEgaGFzIGJlZW4gY29uc3VtZWQKICAgICAgICByZXR1cm4gZGF0YTsKICAgIH0KfQpgYGAKCiMjIyBCbG9ja2luZyBRdWV1ZXMKCkJsb2NraW5nIHF1ZXVlcyBhcmUgdGhyZWFkLXNhZmUgZGF0YSBzdHJ1Y3R1cmVzIHRoYXQgc2ltcGxpZnkgdGhyZWFkIGNvbW11bmljYXRpb24gYW5kIHN5bmNocm9uaXphdGlvbiBieSBwcm92aWRpbmcgYnVpbHQtaW4gbWV0aG9kcyBmb3IgaGFuZGxpbmcgd2FpdGluZyBhbmQgbm90aWZpY2F0aW9uLiBKYXZhJ3MgYGphdmEudXRpbC5jb25jdXJyZW50YCBwYWNrYWdlIGluY2x1ZGVzIHNldmVyYWwgdHlwZXMgb2YgYmxvY2tpbmcgcXVldWVzLCBzdWNoIGFzIGBMaW5rZWRCbG9ja2luZ1F1ZXVlYCwgYEFycmF5QmxvY2tpbmdRdWV1ZWAsIGFuZCBgUHJpb3JpdHlCbG9ja2luZ1F1ZXVlYC4gVGhlc2UgcXVldWVzIG9mZmVyIGEgY29udmVuaWVudCB3YXkgdG8gaW1wbGVtZW50IHByb2R1Y2VyLWNvbnN1bWVyIHBhdHRlcm5zIGFuZCBvdGhlciBtdWx0aS10aHJlYWRlZCBzY2VuYXJpb3MuCgpLZXkgZmVhdHVyZXMgb2YgYmxvY2tpbmcgcXVldWVzOgoKLSAgICoqQmxvY2tpbmcgT3BlcmF0aW9ucyoqOiBCbG9ja2luZyBxdWV1ZXMgb2ZmZXIgYmxvY2tpbmcgb3BlcmF0aW9ucyBmb3IgZW5xdWV1ZWluZyAoYHB1dGApIGFuZCBkZXF1ZXVlaW5nIChgdGFrZWApIGVsZW1lbnRzLiBUaGVzZSBvcGVyYXRpb25zIGJsb2NrIHVudGlsIHNwYWNlIGlzIGF2YWlsYWJsZSAoZm9yIGBwdXRgKSBvciB1bnRpbCBhbiBlbGVtZW50IGlzIGF2YWlsYWJsZSAoZm9yIGB0YWtlYCkuCgpgYGAgamF2YQpCbG9ja2luZ1F1ZXVlPEludGVnZXI+IHF1ZXVlID0gbmV3IExpbmtlZEJsb2NraW5nUXVldWU8PigxMCk7CgovLyBQcm9kdWNlcgpxdWV1ZS5wdXQoNDIpOwoKLy8gQ29uc3VtZXIKaW50IHZhbHVlID0gcXVldWUudGFrZSgpOwpgYGAKCi0gICAqKlRpbWUtQm91bmQgT3BlcmF0aW9ucyoqOiBCbG9ja2luZyBxdWV1ZXMgYWxsb3cgeW91IHRvIHNwZWNpZnkgYSB0aW1lb3V0IHdoZW4gd2FpdGluZyBmb3IgYW4gb3BlcmF0aW9uIHRvIGNvbXBsZXRlLiBGb3IgZXhhbXBsZSwgeW91IGNhbiB1c2UgYG9mZmVyYCB3aXRoIGEgdGltZW91dCB0byBlbnF1ZXVlIGFuIGVsZW1lbnQgaWYgc3BhY2UgaXMgYXZhaWxhYmxlIHdpdGhpbiBhIGNlcnRhaW4gdGltZS4KCmBgYCBqYXZhCmJvb2xlYW4gc3VjY2VzcyA9IHF1ZXVlLm9mZmVyKDQyLCAxLCBUaW1lVW5pdC5TRUNPTkRTKTsKYGBgCgotICAgKipUaHJlYWQtU2FmZXR5Kio6IEJsb2NraW5nIHF1ZXVlcyBhcmUgZGVzaWduZWQgZm9yIHRocmVhZC1zYWZlIGNvbmN1cnJlbnQgYWNjZXNzLiBUaGV5IGhhbmRsZSBhbGwgc3luY2hyb25pemF0aW9uIGludGVybmFsbHksIG1ha2luZyBpdCBzYWZlIGZvciBtdWx0aXBsZSB0aHJlYWRzIHRvIGVucXVldWUgYW5kIGRlcXVldWUgZWxlbWVudHMgY29uY3VycmVudGx5LgoKLSAgICoqQmxvY2tpbmcgU2VtYW50aWNzKio6IFdoZW4gYSB0aHJlYWQgdHJpZXMgdG8gZGVxdWV1ZSBhbiBlbGVtZW50IGZyb20gYW4gZW1wdHkgcXVldWUgKGB0YWtlYCBvcGVyYXRpb24pIG9yIGVucXVldWUgYW4gZWxlbWVudCBpbnRvIGEgZnVsbCBxdWV1ZSAoYHB1dGAgb3BlcmF0aW9uKSwgaXQgd2lsbCBibG9jayB1bnRpbCB0aGUgY29uZGl0aW9uIGlzIHNhdGlzZmllZC4KCkJsb2NraW5nIHF1ZXVlcyBhcmUgY29tbW9ubHkgdXNlZCBpbiBzY2VuYXJpb3MgbGlrZSB0aHJlYWQgcG9vbCB0YXNrIHNjaGVkdWxpbmcsIGV2ZW50IGhhbmRsaW5nLCBhbmQgbG9hZCBiYWxhbmNpbmcsIHdoZXJlIG11bHRpcGxlIHRocmVhZHMgbmVlZCB0byBjb29wZXJhdGUgZWZmaWNpZW50bHkgYW5kIHNhZmVseS4KCiMjIyBCZXN0IFByYWN0aWNlcyBmb3IgVGhyZWFkIENvbW11bmljYXRpb24gYW5kIEJsb2NraW5nIFF1ZXVlcwoKV2hlbiB1c2luZyBgd2FpdGAgYW5kIGBub3RpZnlgLCBhbmQgd2hlbiB3b3JraW5nIHdpdGggYmxvY2tpbmcgcXVldWVzLCBjb25zaWRlciB0aGUgZm9sbG93aW5nIGJlc3QgcHJhY3RpY2VzOgoKMS4gICoqQWx3YXlzIFVzZSBgd2FpdCgpYCBhbmQgYG5vdGlmeSgpYCB3aXRoIFN5bmNocm9uaXphdGlvbioqOiBJdCdzIGNydWNpYWwgdG8gZW5jbG9zZSBjYWxscyB0byBgd2FpdCgpYCBhbmQgYG5vdGlmeSgpYCB3aXRoaW4gc3luY2hyb25pemVkIGJsb2NrcyB0byBlbnN1cmUgcHJvcGVyIHN5bmNocm9uaXphdGlvbiBhbmQgYXZvaWQgcmFjZSBjb25kaXRpb25zLgoKMi4gICoqVGltZW91dHMqKjogV2hlbiB1c2luZyBibG9ja2luZyBvcGVyYXRpb25zIG9yIHRpbWUtYm91bmQgb3BlcmF0aW9ucyB3aXRoIGJsb2NraW5nIHF1ZXVlcywgY29uc2lkZXIgc3BlY2lmeWluZyByZWFzb25hYmxlIHRpbWVvdXRzIHRvIHByZXZlbnQgaW5kZWZpbml0ZSBibG9ja2luZy4KCjMuICAqKkF2b2lkIEJ1c3kgV2FpdGluZyoqOiBEb24ndCB1c2UgYnVzeSB3YWl0aW5nIGxvb3BzIChwb2xsaW5nKSB3aGVuIHdhaXRpbmcgZm9yIGNvbmRpdGlvbnMuIEluc3RlYWQsIHByZWZlciBtZWNoYW5pc21zIGxpa2UgYHdhaXRgIGFuZCBgbm90aWZ5YCBvciBibG9ja2luZyBxdWV1ZXMsIHdoaWNoIGFyZSBtb3JlIGVmZmljaWVudCBhbmQgcmVzb3VyY2UtZnJpZW5kbHkuCgo0LiAgKipDaG9vc2UgdGhlIFJpZ2h0IEJsb2NraW5nIFF1ZXVlKio6IFNlbGVjdCB0aGUgYXBwcm9wcmlhdGUgdHlwZSBvZiBibG9ja2luZyBxdWV1ZSAoZS5nLiwgYExpbmtlZEJsb2NraW5nUXVldWVgLCBgQXJyYXlCbG9ja2luZ1F1ZXVlYCwgb3IgYFByaW9yaXR5QmxvY2tpbmdRdWV1ZWApIGJhc2VkIG9uIHlvdXIgc3BlY2lmaWMgcmVxdWlyZW1lbnRzIGFuZCB1c2FnZSBwYXR0ZXJucy4KCkluIHN1bW1hcnksIGB3YWl0YCBhbmQgYG5vdGlmeWAgYW5kIHRoZSB1c2Ugb2YgYmxvY2tpbmcgcXVldWVzIGluIEphdmEgYXJlIGtleSBtZWNoYW5pc21zIGZvciBidWlsZGluZyBlZmZpY2llbnQgYW5kIHN5bmNocm9uaXplZCBtdWx0aS10aHJlYWRlZCBhcHBsaWNhdGlvbnMsIGVuc3VyaW5nIHRoYXQgdGhyZWFkcyBjYW4gY29vcGVyYXRlIGFuZCBleGNoYW5nZSBpbmZvcm1hdGlvbiBlZmZlY3RpdmVseSB3aGlsZSBtYWludGFpbmluZyB0aHJlYWQgc2FmZXR5LgoKIyMgTXVsdGktVGhyZWFkaW5nIGluIFJlYWwtV29ybGQgQXBwbGljYXRpb25zCgpJbiB0aGlzIHNlY3Rpb24sIHdlIGV4cGxvcmUgdmFyaW91cyBkb21haW5zIGFuZCBpbmR1c3RyaWVzIHdoZXJlIG11bHRpLXRocmVhZGluZyBwbGF5cyBhIGNydWNpYWwgcm9sZToKCjEuICAqKldlYiBTZXJ2ZXJzKio6IE11bHRpLXRocmVhZGluZyBpcyBlc3NlbnRpYWwgZm9yIGhhbmRsaW5nIGNvbmN1cnJlbnQgY2xpZW50IHJlcXVlc3RzIGVmZmljaWVudGx5LiBXZWIgc2VydmVycyBvZnRlbiB1c2UgdGhyZWFkIHBvb2xzIHRvIHByb2Nlc3MgaW5jb21pbmcgY29ubmVjdGlvbnMgY29uY3VycmVudGx5LgoKMi4gICoqRGF0YWJhc2UgU3lzdGVtcyoqOiBEYXRhYmFzZSBtYW5hZ2VtZW50IHN5c3RlbXMgb2Z0ZW4gZW1wbG95IG11bHRpLXRocmVhZGluZyB0byBoYW5kbGUgbXVsdGlwbGUgZGF0YWJhc2UgY29ubmVjdGlvbnMgYW5kIGV4ZWN1dGUgcXVlcmllcyBjb25jdXJyZW50bHkuIENvbm5lY3Rpb24gcG9vbGluZyBhbmQgcXVlcnkgcGFyYWxsZWxpc20gYXJlIGNvbW1vbiB0ZWNobmlxdWVzLgoKMy4gICoqR2FtZSBEZXZlbG9wbWVudCoqOiBWaWRlbyBnYW1lcyByZWx5IG9uIG11bHRpLXRocmVhZGluZyB0byBtYW5hZ2UgZ3JhcGhpY3MgcmVuZGVyaW5nLCBwaHlzaWNzIHNpbXVsYXRpb25zLCBhbmQgQUkgY29tcHV0YXRpb25zLiBHYW1lIGVuZ2luZXMgdXNlIG11bHRpLXRocmVhZGVkIGFyY2hpdGVjdHVyZXMgdG8gZW5zdXJlIHNtb290aCBnYW1lcGxheS4KCjQuICAqKkZpbmFuY2lhbCBTeXN0ZW1zKio6IEluIHRoZSBmaW5hbmNpYWwgaW5kdXN0cnksIG11bHRpLXRocmVhZGluZyBpcyB1c2VkIHRvIHByb2Nlc3MgbGFyZ2Ugdm9sdW1lcyBvZiByZWFsLXRpbWUgbWFya2V0IGRhdGEsIHBlcmZvcm0gY29tcGxleCBjYWxjdWxhdGlvbnMsIGFuZCBleGVjdXRlIGhpZ2gtZnJlcXVlbmN5IHRyYWRpbmcgc3RyYXRlZ2llcy4KCjUuICAqKlNjaWVudGlmaWMgQ29tcHV0aW5nKio6IFNjaWVudGlmaWMgc2ltdWxhdGlvbnMgYW5kIGRhdGEgYW5hbHlzaXMgYmVuZWZpdCBmcm9tIG11bHRpLXRocmVhZGluZyB0byBkaXN0cmlidXRlIGNvbXB1dGF0aW9uYWwgd29ya2xvYWRzIGFjcm9zcyBtdWx0aXBsZSB0aHJlYWRzLCBzcGVlZGluZyB1cCBjYWxjdWxhdGlvbnMuCgo2LiAgKipNYWNoaW5lIExlYXJuaW5nKio6IFRyYWluaW5nIGNvbXBsZXggbWFjaGluZSBsZWFybmluZyBtb2RlbHMgb2Z0ZW4gaW52b2x2ZXMgcGFyYWxsZWxpc20sIGFsbG93aW5nIG11bHRpcGxlIHRocmVhZHMgb3IgcHJvY2Vzc2VzIHRvIHByb2Nlc3MgZGlmZmVyZW50IGRhdGEgcG9pbnRzIG9yIG1vZGVsIHVwZGF0ZXMgc2ltdWx0YW5lb3VzbHkuCgojIyMgVGhyZWFkIFBvb2xzCgpUaHJlYWQgcG9vbHMgYXJlIGEgZnVuZGFtZW50YWwgY29uY2VwdCBpbiBjb25jdXJyZW50IHByb2dyYW1taW5nLCBwYXJ0aWN1bGFybHkgaW4gSmF2YSwgd2hlcmUgdGhleSBhcmUgZXh0ZW5zaXZlbHkgdXNlZCB0byBtYW5hZ2UgYW5kIG9wdGltaXplIHRoZSBleGVjdXRpb24gb2YgdGFza3MgYnkgYSBwb29sIG9mIHdvcmtlciB0aHJlYWRzLiBUaHJlYWQgcG9vbHMgaGVscCBpbXByb3ZlIHRoZSBlZmZpY2llbmN5IG9mIG11bHRpLXRocmVhZGVkIGFwcGxpY2F0aW9ucyBieSByZXVzaW5nIHRocmVhZHMsIHJlZHVjaW5nIHRocmVhZCBjcmVhdGlvbiBhbmQgZGVzdHJ1Y3Rpb24gb3ZlcmhlYWQsIGFuZCBjb250cm9sbGluZyB0aGUgbnVtYmVyIG9mIGNvbmN1cnJlbnQgdGhyZWFkcy4gSW4gdGhpcyBkZXRhaWxlZCBleHBsYW5hdGlvbiwgd2UnbGwgZXhwbG9yZSB0aHJlYWQgcG9vbHMgaW4gZGVwdGguCgojIyMjIEtleSBDb21wb25lbnRzIG9mIGEgVGhyZWFkIFBvb2w6CgoxLiAgKipUaHJlYWQgUG9vbCBTaXplKio6IFRoaXMgaXMgdGhlIG51bWJlciBvZiB3b3JrZXIgdGhyZWFkcyBhdmFpbGFibGUgaW4gdGhlIHBvb2wuIEl0IGRldGVybWluZXMgaG93IG1hbnkgdGFza3MgY2FuIGJlIGV4ZWN1dGVkIGNvbmN1cnJlbnRseS4gVGhlIHRocmVhZCBwb29sIHNpemUgc2hvdWxkIGJlIGNob3NlbiBjYXJlZnVsbHkgYmFzZWQgb24gZmFjdG9ycyBsaWtlIHRoZSBhdmFpbGFibGUgQ1BVIGNvcmVzIGFuZCB0aGUgbmF0dXJlIG9mIHRhc2tzLgoKMi4gICoqVGFzayBRdWV1ZSoqOiBUaGUgdGFzayBxdWV1ZSAoYWxzbyBrbm93biBhcyBhIHdvcmsgcXVldWUpIGlzIGEgZGF0YSBzdHJ1Y3R1cmUgd2hlcmUgdGFza3MgYXJlIHN0b3JlZCBiZWZvcmUgdGhleSBhcmUgZXhlY3V0ZWQuIFdoZW4gYSB0YXNrIGlzIHN1Ym1pdHRlZCB0byB0aGUgdGhyZWFkIHBvb2wsIGl0J3MgYWRkZWQgdG8gdGhlIHRhc2sgcXVldWUuIFdvcmtlciB0aHJlYWRzIHJldHJpZXZlIHRhc2tzIGZyb20gdGhlIHF1ZXVlIGFuZCBleGVjdXRlIHRoZW0uCgozLiAgKipUYXNrIFN1Ym1pc3Npb24qKjogVGFza3MgYXJlIHN1Ym1pdHRlZCB0byB0aGUgdGhyZWFkIHBvb2wgZm9yIGV4ZWN1dGlvbi4gVGhlc2UgdGFza3MgY2FuIGJlIHJlcHJlc2VudGVkIGFzIGluc3RhbmNlcyBvZiBgUnVubmFibGVgIG9yIGBDYWxsYWJsZWAgaW50ZXJmYWNlcyBpbiBKYXZhLgoKNC4gICoqV29ya2VyIFRocmVhZHMqKjogV29ya2VyIHRocmVhZHMgYXJlIHByZS1jcmVhdGVkIHRocmVhZHMgdGhhdCBjb250aW51b3VzbHkgcmV0cmlldmUgdGFza3MgZnJvbSB0aGUgdGFzayBxdWV1ZSBhbmQgZXhlY3V0ZSB0aGVtLiBUaGV5IHJlbWFpbiBhY3RpdmUgdW50aWwgdGhlIHRocmVhZCBwb29sIGlzIHNodXQgZG93bi4KCjUuICAqKlRocmVhZCBQb29sIE1hbmFnZW1lbnQqKjogVGhlIHRocmVhZCBwb29sIGlzIHJlc3BvbnNpYmxlIGZvciBjcmVhdGluZyBhbmQgbWFuYWdpbmcgd29ya2VyIHRocmVhZHMsIGhhbmRsaW5nIHRhc2sgc3VibWlzc2lvbiwgYW5kIGVuc3VyaW5nIHRoZSBwcm9wZXIgbGlmZWN5Y2xlIG1hbmFnZW1lbnQgb2YgdGhyZWFkcy4KCiMjIyMgQWR2YW50YWdlcyBvZiBVc2luZyBUaHJlYWQgUG9vbHM6CgoxLiAgKipUaHJlYWQgUmV1c2UqKjogVGhyZWFkIHBvb2xzIHJldXNlIGV4aXN0aW5nIHRocmVhZHMgcmF0aGVyIHRoYW4gY3JlYXRpbmcgYW5kIGRlc3Ryb3lpbmcgdGhlbSBmb3IgZWFjaCB0YXNrLiBUaGlzIHJlZHVjZXMgdGhlIG92ZXJoZWFkIGFzc29jaWF0ZWQgd2l0aCB0aHJlYWQgY3JlYXRpb24sIHdoaWNoIGNhbiBiZSBjb3N0bHkuCgoyLiAgKipUaHJlYWQgTGlmZWN5Y2xlIE1hbmFnZW1lbnQqKjogVGhyZWFkIHBvb2xzIG1hbmFnZSB0aGUgbGlmZWN5Y2xlIG9mIHdvcmtlciB0aHJlYWRzLCBlbnN1cmluZyB0aGF0IHRocmVhZHMgcmVtYWluIGFjdGl2ZSBhbmQgYXZhaWxhYmxlIHRvIHByb2Nlc3MgdGFza3MgdW50aWwgdGhlIHRocmVhZCBwb29sIGlzIHNodXQgZG93bi4KCjMuICAqKkNvbmN1cnJlbmN5IENvbnRyb2wqKjogVGhyZWFkIHBvb2xzIGFsbG93IHlvdSB0byBjb250cm9sIHRoZSBtYXhpbXVtIG51bWJlciBvZiBjb25jdXJyZW50IHRocmVhZHMsIHByZXZlbnRpbmcgcmVzb3VyY2UgZXhoYXVzdGlvbiBhbmQgdGhyZWFkIHRocmFzaGluZy4KCjQuICAqKlF1ZXVlaW5nIE1lY2hhbmlzbSoqOiBUaHJlYWQgcG9vbHMgcHJvdmlkZSBhIHF1ZXVlaW5nIG1lY2hhbmlzbSBmb3IgdGFza3MuIElmIGFsbCB0aHJlYWRzIGFyZSBidXN5LCBuZXcgdGFza3MgYXJlIHBsYWNlZCBpbiB0aGUgcXVldWUsIGVuc3VyaW5nIHRoYXQgdGFza3MgYXJlIHByb2Nlc3NlZCBpbiB0aGUgb3JkZXIgdGhleSB3ZXJlIHN1Ym1pdHRlZC4KCjUuICAqKlJlc291cmNlIE1hbmFnZW1lbnQqKjogQnkgY29udHJvbGxpbmcgdGhlIG51bWJlciBvZiB0aHJlYWRzLCB0aHJlYWQgcG9vbHMgaGVscCBtYW5hZ2Ugc3lzdGVtIHJlc291cmNlcyBtb3JlIGVmZmVjdGl2ZWx5LCBwcmV2ZW50aW5nIG92ZXJsb2FkaW5nIGFuZCBpbXByb3ZpbmcgYXBwbGljYXRpb24gc3RhYmlsaXR5LgoKIyMjIyBDb21tb24gVGhyZWFkIFBvb2wgVHlwZXM6CgoxLiAgKipGaXhlZFRocmVhZFBvb2wqKjogVGhpcyB0eXBlIG9mIHRocmVhZCBwb29sIG1haW50YWlucyBhIGNvbnN0YW50IG51bWJlciBvZiB0aHJlYWRzIGluIHRoZSBwb29sLiBPbmNlIGNyZWF0ZWQsIHRoZSBudW1iZXIgb2YgdGhyZWFkcyByZW1haW5zIGZpeGVkLCBhbmQgaWYgYSB0YXNrIGlzIHN1Ym1pdHRlZCB3aGVuIGFsbCB0aHJlYWRzIGFyZSBidXN5LCBpdCB3YWl0cyBpbiB0aGUgcXVldWUgdW50aWwgYSB0aHJlYWQgYmVjb21lcyBhdmFpbGFibGUuCgoyLiAgKipDYWNoZWRUaHJlYWRQb29sKio6IEluIHRoaXMgdHlwZSBvZiB0aHJlYWQgcG9vbCwgdGhlIG51bWJlciBvZiB0aHJlYWRzIGNhbiBncm93IG9yIHNocmluayBkeW5hbWljYWxseSBiYXNlZCBvbiB0aGUgd29ya2xvYWQuIElmIGEgdGhyZWFkIGlzIGlkbGUgZm9yIGEgY2VydGFpbiBwZXJpb2QsIGl0IG1heSBiZSB0ZXJtaW5hdGVkLCBhbmQgbmV3IHRocmVhZHMgbWF5IGJlIGNyZWF0ZWQgYXMgbmVlZGVkLgoKMy4gICoqU2NoZWR1bGVkVGhyZWFkUG9vbCoqOiBUaGlzIHRocmVhZCBwb29sIGlzIGRlc2lnbmVkIGZvciBzY2hlZHVsaW5nIHRhc2tzIHRvIHJ1biBhdCBzcGVjaWZpYyBpbnRlcnZhbHMgb3IgYWZ0ZXIgYSBkZWxheS4gSXQncyBjb21tb25seSB1c2VkIGZvciB0YXNrcyBsaWtlIHBlcmlvZGljIG1haW50ZW5hbmNlIG9yIHRpbWVkIGV4ZWN1dGlvbiBvZiB0YXNrcy4KCjQuICAqKlNpbmdsZVRocmVhZEV4ZWN1dG9yKio6IFRoaXMgdGhyZWFkIHBvb2wgY29udGFpbnMgb25seSBvbmUgdGhyZWFkLCBlbnN1cmluZyB0aGF0IHRhc2tzIGFyZSBleGVjdXRlZCBzZXF1ZW50aWFsbHkgaW4gdGhlIG9yZGVyIHRoZXkgd2VyZSBzdWJtaXR0ZWQuIEl0J3Mgc3VpdGFibGUgZm9yIHRhc2tzIHRoYXQgcmVxdWlyZSBzdHJpY3Qgb3JkZXIgb2YgZXhlY3V0aW9uLgoKIyMjIyBUaHJlYWQgUG9vbCBCZXN0IFByYWN0aWNlczoKCjEuICAqKlByb3BlciBTaXppbmcqKjogQ2hvb3NlIGFuIGFwcHJvcHJpYXRlIHRocmVhZCBwb29sIHNpemUgYmFzZWQgb24gdGhlIGF2YWlsYWJsZSByZXNvdXJjZXMsIHN1Y2ggYXMgQ1BVIGNvcmVzLCBhbmQgdGhlIG5hdHVyZSBvZiB0aGUgdGFza3MuIE92ZXJzaXppbmcgb3IgdW5kZXJzaXppbmcgdGhlIHRocmVhZCBwb29sIGNhbiBpbXBhY3QgcGVyZm9ybWFuY2UuCgoyLiAgKipUYXNrIERlcGVuZGVuY3kqKjogQ29uc2lkZXIgdGFzayBkZXBlbmRlbmNpZXMgYW5kIHBvdGVudGlhbCBib3R0bGVuZWNrcyB3aGVuIGRlc2lnbmluZyBtdWx0aS10aHJlYWRlZCBhcHBsaWNhdGlvbnMgd2l0aCB0aHJlYWQgcG9vbHMuIEVuc3VyZSB0aGF0IHRhc2tzIGFyZSBkaXZpZGVkIGFuZCBzY2hlZHVsZWQgZWZmaWNpZW50bHkuCgozLiAgKipHcmFjZWZ1bCBTaHV0ZG93bioqOiBBbHdheXMgc2h1dCBkb3duIHRoZSB0aHJlYWQgcG9vbCBncmFjZWZ1bGx5IHdoZW4gaXQncyBubyBsb25nZXIgbmVlZGVkLiBUaGlzIGFsbG93cyBleGlzdGluZyB0YXNrcyB0byBjb21wbGV0ZSB3aGlsZSBwcmV2ZW50aW5nIG5ldyB0YXNrcyBmcm9tIGJlaW5nIHN1Ym1pdHRlZC4KCjQuICAqKkVycm9yIEhhbmRsaW5nKio6IEltcGxlbWVudCBlcnJvciBoYW5kbGluZyBhbmQgZXhjZXB0aW9uIG1hbmFnZW1lbnQgZm9yIHRhc2tzIHdpdGhpbiB0aGUgdGhyZWFkIHBvb2wuIFVuaGFuZGxlZCBleGNlcHRpb25zIGluIHdvcmtlciB0aHJlYWRzIGNhbiBsZWFkIHRvIHVuZXhwZWN0ZWQgYXBwbGljYXRpb24gYmVoYXZpb3IuCgo1LiAgKipNb25pdG9yaW5nIGFuZCBUdW5pbmcqKjogTW9uaXRvciB0aGUgcGVyZm9ybWFuY2Ugb2YgeW91ciB0aHJlYWQgcG9vbCBhbmQgYWRqdXN0IGl0cyBjb25maWd1cmF0aW9uIGFzIG5lZWRlZCB0byBvcHRpbWl6ZSByZXNvdXJjZSB1c2FnZSBhbmQgdGhyb3VnaHB1dC4KClRocmVhZCBwb29scyBhcmUgYSBwb3dlcmZ1bCB0b29sIGluIG11bHRpLXRocmVhZGVkIHByb2dyYW1taW5nLCBhbGxvd2luZyBmb3IgZWZmaWNpZW50IG1hbmFnZW1lbnQgb2YgY29uY3VycmVudCB0YXNrcywgaW1wcm92ZWQgcmVzb3VyY2UgdXRpbGl6YXRpb24sIGFuZCBiZXR0ZXIgY29udHJvbCBvdmVyIHRoZSBleGVjdXRpb24gb2YgcGFyYWxsZWwgd29ya2xvYWRzLiBVbmRlcnN0YW5kaW5nIHRoZSBjaGFyYWN0ZXJpc3RpY3MgYW5kIHR5cGVzIG9mIHRocmVhZCBwb29scyBpcyBlc3NlbnRpYWwgZm9yIGRlc2lnbmluZyByb2J1c3QgYW5kIGVmZmljaWVudCBtdWx0aS10aHJlYWRlZCBhcHBsaWNhdGlvbnMuCgojIyBFeGFtcGxlOiBTaW1wbGUgTXVsdGktVGhyZWFkZWQgV2ViIFNlcnZlcgoKQ3JlYXRpbmcgYSBtdWx0aS10aHJlYWRlZCB3ZWIgc2VydmVyIGluIEphdmEgdGhhdCB1c2VzIHN5bmNocm9uaXphdGlvbiBpbnZvbHZlcyBoYW5kbGluZyBtdWx0aXBsZSBjbGllbnQgY29ubmVjdGlvbnMgY29uY3VycmVudGx5IHdoaWxlIGVuc3VyaW5nIHRoYXQgYWNjZXNzIHRvIHNoYXJlZCByZXNvdXJjZXMsIHN1Y2ggYXMgc2VydmVyIHNvY2tldHMgYW5kIHJlcXVlc3QgcHJvY2Vzc2luZywgaXMgc3luY2hyb25pemVkIHRvIHByZXZlbnQgZGF0YSByYWNlcyBhbmQgY29uZmxpY3RzLiBCZWxvdyBpcyBhIGRldGFpbGVkIGV4YW1wbGUgb2YgYSBtdWx0aS10aHJlYWRlZCB3ZWIgc2VydmVyIHVzaW5nIEphdmEncyBgU2VydmVyU29ja2V0YCwgYFRocmVhZGAsIGFuZCBzeW5jaHJvbml6YXRpb24gdG8gaGFuZGxlIGluY29taW5nIEhUVFAgcmVxdWVzdHM6CgpgYGAgamF2YQppbXBvcnQgamF2YS5pby4qOwppbXBvcnQgamF2YS5uZXQuKjsKaW1wb3J0IGphdmEudXRpbC5jb25jdXJyZW50Lio7CgpwdWJsaWMgY2xhc3MgTXVsdGlUaHJlYWRlZFdlYlNlcnZlciB7CiAgICBwcml2YXRlIHN0YXRpYyBmaW5hbCBpbnQgUE9SVCA9IDgwODA7CiAgICBwcml2YXRlIHN0YXRpYyBmaW5hbCBpbnQgVEhSRUFEX1BPT0xfU0laRSA9IDEwOwoKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHRocm93cyBJT0V4Y2VwdGlvbiB7CiAgICAgICAgU2VydmVyU29ja2V0IHNlcnZlclNvY2tldCA9IG5ldyBTZXJ2ZXJTb2NrZXQoUE9SVCk7CiAgICAgICAgRXhlY3V0b3JTZXJ2aWNlIGV4ZWN1dG9yU2VydmljZSA9IEV4ZWN1dG9ycy5uZXdGaXhlZFRocmVhZFBvb2woVEhSRUFEX1BPT0xfU0laRSk7CgogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiTXVsdGlUaHJlYWRlZCBXZWIgU2VydmVyIHN0YXJ0ZWQgb24gcG9ydCAiICsgUE9SVCk7CgogICAgICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgICAgIFNvY2tldCBjbGllbnRTb2NrZXQgPSBzZXJ2ZXJTb2NrZXQuYWNjZXB0KCk7IC8vIEFjY2VwdCBpbmNvbWluZyBjbGllbnQgY29ubmVjdGlvbnMKICAgICAgICAgICAgUnVubmFibGUgcmVxdWVzdEhhbmRsZXIgPSBuZXcgUmVxdWVzdEhhbmRsZXIoY2xpZW50U29ja2V0KTsKICAgICAgICAgICAgZXhlY3V0b3JTZXJ2aWNlLnN1Ym1pdChyZXF1ZXN0SGFuZGxlcik7IC8vIERlbGVnYXRlIHJlcXVlc3QgaGFuZGxpbmcgdG8gYSB0aHJlYWQKICAgICAgICB9CiAgICB9Cn0KCmNsYXNzIFJlcXVlc3RIYW5kbGVyIGltcGxlbWVudHMgUnVubmFibGUgewogICAgcHJpdmF0ZSBTb2NrZXQgY2xpZW50U29ja2V0OwoKICAgIHB1YmxpYyBSZXF1ZXN0SGFuZGxlcihTb2NrZXQgY2xpZW50U29ja2V0KSB7CiAgICAgICAgdGhpcy5jbGllbnRTb2NrZXQgPSBjbGllbnRTb2NrZXQ7CiAgICB9CgogICAgQE92ZXJyaWRlCiAgICBwdWJsaWMgdm9pZCBydW4oKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgaGFuZGxlUmVxdWVzdChjbGllbnRTb2NrZXQpOwogICAgICAgIH0gY2F0Y2ggKElPRXhjZXB0aW9uIGUpIHsKICAgICAgICAgICAgZS5wcmludFN0YWNrVHJhY2UoKTsKICAgICAgICB9IGZpbmFsbHkgewogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgY2xpZW50U29ja2V0LmNsb3NlKCk7CiAgICAgICAgICAgIH0gY2F0Y2ggKElPRXhjZXB0aW9uIGUpIHsKICAgICAgICAgICAgICAgIGUucHJpbnRTdGFja1RyYWNlKCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgcHJpdmF0ZSB2b2lkIGhhbmRsZVJlcXVlc3QoU29ja2V0IGNsaWVudFNvY2tldCkgdGhyb3dzIElPRXhjZXB0aW9uIHsKICAgICAgICAvLyBSZWFkIGFuZCBwcm9jZXNzIHRoZSBIVFRQIHJlcXVlc3QgZnJvbSB0aGUgY2xpZW50CiAgICAgICAgQnVmZmVyZWRSZWFkZXIgaW4gPSBuZXcgQnVmZmVyZWRSZWFkZXIobmV3IElucHV0U3RyZWFtUmVhZGVyKGNsaWVudFNvY2tldC5nZXRJbnB1dFN0cmVhbSgpKSk7CiAgICAgICAgUHJpbnRXcml0ZXIgb3V0ID0gbmV3IFByaW50V3JpdGVyKGNsaWVudFNvY2tldC5nZXRPdXRwdXRTdHJlYW0oKSwgdHJ1ZSk7CgogICAgICAgIFN0cmluZyByZXF1ZXN0OwogICAgICAgIHdoaWxlICgocmVxdWVzdCA9IGluLnJlYWRMaW5lKCkpICE9IG51bGwpIHsKICAgICAgICAgICAgaWYgKHJlcXVlc3QuaXNFbXB0eSgpKSB7CiAgICAgICAgICAgICAgICBicmVhazsgLy8gRW5kIG9mIHJlcXVlc3QgaGVhZGVycwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvLyBHZW5lcmF0ZSBhbiBIVFRQIHJlc3BvbnNlCiAgICAgICAgU3RyaW5nIHJlc3BvbnNlID0gIkhUVFAvMS4xIDIwMCBPS1xyXG4iICsKICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29udGVudC1UeXBlOiB0ZXh0L2h0bWxcclxuIiArCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlxyXG4iICsKICAgICAgICAgICAgICAgICAgICAgICAgICAiPGh0bWw+PGJvZHk+SGVsbG8sIFdvcmxkITwvYm9keT48L2h0bWw+IjsKCiAgICAgICAgLy8gU2VuZCB0aGUgcmVzcG9uc2UgdG8gdGhlIGNsaWVudAogICAgICAgIG91dC5wcmludGxuKHJlc3BvbnNlKTsKCiAgICAgICAgLy8gQ2xvc2UgdGhlIHN0cmVhbXMgYW5kIHRoZSBzb2NrZXQKICAgICAgICBpbi5jbG9zZSgpOwogICAgICAgIG91dC5jbG9zZSgpOwogICAgfQp9CmBgYAoKSW4gdGhpcyBleGFtcGxlOgoKMS4gIFdlIGNyZWF0ZSBhIGBNdWx0aVRocmVhZGVkV2ViU2VydmVyYCBjbGFzcyB0aGF0IGxpc3RlbnMgZm9yIGluY29taW5nIGNsaWVudCBjb25uZWN0aW9ucyBvbiBwb3J0IDgwODAgdXNpbmcgYSBgU2VydmVyU29ja2V0YC4KCjIuICBXZSB1c2UgYW4gYEV4ZWN1dG9yU2VydmljZWAgdG8gbWFuYWdlIGEgZml4ZWQgcG9vbCBvZiB3b3JrZXIgdGhyZWFkcyAoYFRIUkVBRF9QT09MX1NJWkVgKSByZXNwb25zaWJsZSBmb3IgaGFuZGxpbmcgaW5jb21pbmcgY2xpZW50IHJlcXVlc3RzLgoKMy4gIEVhY2ggaW5jb21pbmcgY2xpZW50IGNvbm5lY3Rpb24gaXMgZGVsZWdhdGVkIHRvIGEgYFJlcXVlc3RIYW5kbGVyYCB0aHJlYWQuIFRoaXMgYWxsb3dzIG11bHRpcGxlIGNsaWVudHMgdG8gYmUgc2VydmVkIGNvbmN1cnJlbnRseS4KCjQuICBUaGUgYFJlcXVlc3RIYW5kbGVyYCBjbGFzcyBpbXBsZW1lbnRzIHRoZSBgUnVubmFibGVgIGludGVyZmFjZSwgd2hpY2ggZGVmaW5lcyB0aGUgYHJ1bigpYCBtZXRob2QgZm9yIGhhbmRsaW5nIGVhY2ggY2xpZW50IHJlcXVlc3QuIEl0IHJlYWRzIHRoZSBIVFRQIHJlcXVlc3QsIHByb2Nlc3NlcyBpdCwgZ2VuZXJhdGVzIGFuIEhUVFAgcmVzcG9uc2UsIGFuZCBzZW5kcyBpdCBiYWNrIHRvIHRoZSBjbGllbnQuCgo1LiAgU3luY2hyb25pemF0aW9uIGlzIG5vdCBleHBsaWNpdGx5IHNob3duIGluIHRoaXMgYmFzaWMgZXhhbXBsZSwgYnV0IGl0IHdvdWxkIGJlIG5lY2Vzc2FyeSB3aGVuIGRlYWxpbmcgd2l0aCBzaGFyZWQgcmVzb3VyY2VzIG9yIGRhdGEgc3RydWN0dXJlcyBpbiBhIG1vcmUgY29tcGxleCBzZXJ2ZXIgaW1wbGVtZW50YXRpb24uIEZvciBpbnN0YW5jZSwgaWYgeW91IHdlcmUgbWFuYWdpbmcgYSBzaGFyZWQgZGF0YSBzdG9yZSwgeW91IHdvdWxkIHVzZSBzeW5jaHJvbml6YXRpb24gbWVjaGFuaXNtcyBsaWtlIGBzeW5jaHJvbml6ZWRgIGJsb2NrcyBvciBjbGFzc2VzLCBvciBoaWdoZXItbGV2ZWwgY29uY3VycmVudCBkYXRhIHN0cnVjdHVyZXMgZnJvbSB0aGUgYGphdmEudXRpbC5jb25jdXJyZW50YCBwYWNrYWdlIHRvIGVuc3VyZSB0aHJlYWQgc2FmZXR5LgoKVGhpcyBleGFtcGxlIGRlbW9uc3RyYXRlcyB0aGUgZnVuZGFtZW50YWwgc3RydWN0dXJlIG9mIGEgbXVsdGktdGhyZWFkZWQgd2ViIHNlcnZlciBpbiBKYXZhLiBUbyBtYWtlIGl0IHByb2R1Y3Rpb24tcmVhZHksIHlvdSB3b3VsZCBuZWVkIHRvIGhhbmRsZSB2YXJpb3VzIEhUVFAgbWV0aG9kcywgZXJyb3IgcmVzcG9uc2VzLCBjb250ZW50IG5lZ290aWF0aW9uLCBhbmQgcG90ZW50aWFsbHkgdXNlIGEgbW9yZSBhZHZhbmNlZCBmcmFtZXdvcmsgb3IgbGlicmFyeSB0byBzaW1wbGlmeSB0aGUgaGFuZGxpbmcgb2YgSFRUUCByZXF1ZXN0cyBhbmQgcmVzcG9uc2VzLgoKIyMgQ29uY2x1c2lvbgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBGaWxlcyAmIFJlc291cmNlcwoKYGBge3IgemlwRmlsZXMsIGVjaG89RkFMU0V9CnppcE5hbWUgPSBzcHJpbnRmKCJMZXNzb25GaWxlcy0lcy0lcy56aXAiLCAKICAgICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksCiAgICAgICAgICAgICAgICAgcGFyYW1zJG51bWJlcikKCnRleHRBTGluayA9IHBhc3RlMCgiQWxsIEZpbGVzIGZvciBMZXNzb24gIiwgCiAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwiLiIscGFyYW1zJG51bWJlcikKCiMgZG93bmxvYWRGaWxlc0xpbmsoKSBpcyBpbmNsdWRlZCBmcm9tIF9pbnNlcnQyREIuUgprbml0cjo6cmF3X2h0bWwoZG93bmxvYWRGaWxlc0xpbmsoIi4iLCB6aXBOYW1lLCB0ZXh0QUxpbmspKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgUmVmZXJlbmNlcyAmIFJlc291cmNlcwoKVGhlc2UgcmVzb3VyY2VzIGJlbG93IGNhbiBwcm92aWRlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gZGVlcGVuIHlvdXIgdW5kZXJzdGFuZGluZyBvZiBtdWx0aS10aHJlYWRpbmcgaW4gSmF2YSwgYmVzdCBwcmFjdGljZXMgZm9yIGNvbmN1cnJlbnQgcHJvZ3JhbW1pbmcsIGFuZCBwZXJmb3JtYW5jZSBvcHRpbWl6YXRpb24gdGVjaG5pcXVlcy4KCiMjIyBCb29rczoKCjEuICAiSmF2YSBDb25jdXJyZW5jeSBpbiBQcmFjdGljZSIgYnkgQnJpYW4gR29ldHosIFRpbSBQZWllcmxzLCBKb3NodWEgQmxvY2gsIEpvc2VwaCBCb3diZWVyLCBEYXZpZCBIb2xtZXMsIGFuZCBEb3VnIExlYSAtIFRoaXMgYm9vayBpcyBjb25zaWRlcmVkIHRoZSBkZWZpbml0aXZlIGd1aWRlIHRvIEphdmEgY29uY3VycmVuY3kgYW5kIG9mZmVycyBwcmFjdGljYWwgaW5zaWdodHMgaW50byB3cml0aW5nIHRocmVhZC1zYWZlIGFuZCBzY2FsYWJsZSBKYXZhIGFwcGxpY2F0aW9ucy4KCjIuICAiSmF2YSBUaHJlYWRzIiBieSBTY290dCBPYWtzIGFuZCBIZW5yeSBXb25nIC0gQSBjb21wcmVoZW5zaXZlIGd1aWRlIHRvIHVuZGVyc3RhbmRpbmcgSmF2YSB0aHJlYWRzLCB0aGVpciBsaWZlY3ljbGUsIGFuZCBob3cgdG8gdXNlIHRoZW0gZWZmZWN0aXZlbHkuCgozLiAgIkphdmEgUGVyZm9ybWFuY2U6IFRoZSBEZWZpbml0aXZlIEd1aWRlIiBieSBTY290dCBPYWtzIC0gV2hpbGUgbm90IGV4Y2x1c2l2ZWx5IGFib3V0IG11bHRpLXRocmVhZGluZywgdGhpcyBib29rIGNvdmVycyBwZXJmb3JtYW5jZSBvcHRpbWl6YXRpb24gaW4gSmF2YSwgaW5jbHVkaW5nIHRvcGljcyByZWxhdGVkIHRvIG11bHRpLXRocmVhZGluZyBhbmQgY29uY3VycmVuY3kuCgojIyMgV2Vic2l0ZXM6CgotICAgW09yYWNsZSdzIEphdmEgQ29uY3VycmVuY3kgRG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9kb2NzLm9yYWNsZS5jb20vamF2YXNlL3R1dG9yaWFsL2Vzc2VudGlhbC9jb25jdXJyZW5jeS8pIC0gT3JhY2xlJ3Mgb2ZmaWNpYWwgZG9jdW1lbnRhdGlvbiBvbiBKYXZhIGNvbmN1cnJlbmN5IHByb3ZpZGVzIHR1dG9yaWFscyBhbmQgZ3VpZGVzIG9uIG11bHRpLXRocmVhZGluZyBpbiBKYXZhLgoKLSAgIFtCYWVsZHVuZydzIEphdmEgQ29uY3VycmVuY3kgYW5kIE11bHRpdGhyZWFkaW5nXShodHRwczovL3d3dy5iYWVsZHVuZy5jb20vamF2YS1jb25jdXJyZW5jeS1tdWx0aXRocmVhZGluZy10dXRvcmlhbCkgLSBCYWVsZHVuZyBvZmZlcnMgYSBjb2xsZWN0aW9uIG9mIGluLWRlcHRoIGFydGljbGVzIGFuZCB0dXRvcmlhbHMgb24gSmF2YSBjb25jdXJyZW5jeSB0b3BpY3MuCgojIyMgT25saW5lIENvbW11bml0aWVzOgoKLSAgIFtTdGFjayBPdmVyZmxvdyAtIEphdmEgQ29uY3VycmVuY3ldKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zL3RhZ2dlZC9qYXZhK2NvbmN1cnJlbmN5KSAtIFN0YWNrIE92ZXJmbG93IGlzIGEgdmFsdWFibGUgcmVzb3VyY2UgZm9yIGFza2luZyBhbmQgYW5zd2VyaW5nIHF1ZXN0aW9ucyByZWxhdGVkIHRvIEphdmEgY29uY3VycmVuY3kuCgotICAgW0phdmEgQ29uY3VycmVuY3kgTWFpbGluZyBMaXN0XShodHRwOi8vY3Mub3N3ZWdvLmVkdS9tYWlsbWFuL2xpc3RpbmZvL2NvbmN1cnJlbmN5LWludGVyZXN0KSAtIFRoZSBjb25jdXJyZW5jeS1pbnRlcmVzdCBtYWlsaW5nIGxpc3QgaXMgYSBwbGF0Zm9ybSBmb3IgZGlzY3Vzc2luZyBjb25jdXJyZW5jeS1yZWxhdGVkIHRvcGljcyBhbmQgaXNzdWVzIHdpdGggZXhwZXJ0cyBhbmQgZW50aHVzaWFzdHMuCgojIyMgVG9vbHMgYW5kIExpYnJhcmllczoKCi0gICBbSk1IIChKYXZhIE1pY3JvYmVuY2htYXJraW5nIEhhcm5lc3MpXShodHRwczovL29wZW5qZGsuamF2YS5uZXQvcHJvamVjdHMvY29kZS10b29scy9qbWgvKSAtIEpNSCBpcyBhIEphdmEgbGlicmFyeSBmb3IgYmVuY2htYXJraW5nIGFuZCBwcm9maWxpbmcgbXVsdGktdGhyZWFkZWQgY29kZSwgaGVscGluZyB5b3Ugb3B0aW1pemUgdGhlIHBlcmZvcm1hbmNlIG9mIHlvdXIgSmF2YSBhcHBsaWNhdGlvbnMuCgotICAgW0FwYWNoZSBNYXZlbl0oaHR0cHM6Ly9tYXZlbi5hcGFjaGUub3JnLykgLSBNYXZlbiBpcyBhIGJ1aWxkIGF1dG9tYXRpb24gYW5kIHByb2plY3QgbWFuYWdlbWVudCB0b29sIHdpZGVseSB1c2VkIGZvciBKYXZhIHByb2plY3RzLCBpbmNsdWRpbmcgbXVsdGktdGhyZWFkZWQgYXBwbGljYXRpb25zLiBJdCBjYW4gc2ltcGxpZnkgdGhlIG1hbmFnZW1lbnQgb2YgZGVwZW5kZW5jaWVzIGFuZCBidWlsZCBwcm9jZXNzZXMuCgojIyBBcHBlbmRpeCBBOiBKYXZhJ3MgTWVtb3J5IE1vZGVsCgojIyMgT2JqZWN0aXZlcwoKLSAgIFVuZGVyc3RhbmRpbmcgSmF2YSdzIE1lbW9yeSBNb2RlbAotICAgSGFwcGVucy1CZWZvcmUgUmVsYXRpb25zaGlwCi0gICBNZW1vcnkgQmFycmllcnMgYW5kIFZpc2liaWxpdHkKCkFwcGVuZGl4IEE6IEphdmEncyBNZW1vcnkgTW9kZWwKCkphdmEncyBNZW1vcnkgTW9kZWwgZGVmaW5lcyB0aGUgcnVsZXMgYW5kIGd1YXJhbnRlZXMgYWJvdXQgaG93IG1lbW9yeSBpcyBhY2Nlc3NlZCBhbmQgbWFuaXB1bGF0ZWQgYnkgdGhyZWFkcyBpbiBhIG11bHRpLXRocmVhZGVkIEphdmEgcHJvZ3JhbS4gSXQgZW5zdXJlcyB0aGF0IG11bHRpLXRocmVhZGVkIHByb2dyYW1zIGJlaGF2ZSBwcmVkaWN0YWJseSBhbmQgY29uc2lzdGVudGx5IGFjcm9zcyBkaWZmZXJlbnQgaGFyZHdhcmUgYW5kIHBsYXRmb3Jtcy4gVGhpcyBhcHBlbmRpeCBwcm92aWRlcyBhbiBpbi1kZXB0aCBleHBsYW5hdGlvbiBvZiBKYXZhJ3MgTWVtb3J5IE1vZGVsLCBpbGx1c3RyYXRlZCB3aXRoIGV4YW1wbGVzIGFuZCBzYW1wbGUgY29kZS4KCiMjIyAxLiBTaGFyZWQgTWVtb3J5IGFuZCBUaHJlYWRzCgpJbiBtdWx0aS10aHJlYWRlZCBKYXZhIGFwcGxpY2F0aW9ucywgbXVsdGlwbGUgdGhyZWFkcyBtYXkgYWNjZXNzIHNoYXJlZCBkYXRhIHNpbXVsdGFuZW91c2x5LiBJdCdzIGVzc2VudGlhbCB0byB1bmRlcnN0YW5kIGhvdyB0aGVzZSB0aHJlYWRzIGludGVyYWN0IHdpdGggbWVtb3J5IHRvIHByZXZlbnQgaXNzdWVzIGxpa2UgZGF0YSByYWNlcywgdmlzaWJpbGl0eSBwcm9ibGVtcywgYW5kIHVuZXhwZWN0ZWQgYmVoYXZpb3IuCgojIyMjIEV4YW1wbGUgMTogU2hhcmVkIFZhcmlhYmxlCgpgYGAgamF2YQpwdWJsaWMgY2xhc3MgU2hhcmVkVmFyaWFibGVFeGFtcGxlIHsKICAgIHByaXZhdGUgc3RhdGljIGludCBzaGFyZWRWYXJpYWJsZSA9IDA7CgogICAgcHVibGljIHN0YXRpYyB2b2lkIG1haW4oU3RyaW5nW10gYXJncykgewogICAgICAgIFRocmVhZCB0aHJlYWQxID0gbmV3IFRocmVhZCgoKSAtPiB7CiAgICAgICAgICAgIHNoYXJlZFZhcmlhYmxlID0gNDI7CiAgICAgICAgfSk7CgogICAgICAgIFRocmVhZCB0aHJlYWQyID0gbmV3IFRocmVhZCgoKSAtPiB7CiAgICAgICAgICAgIGludCBsb2NhbFZhbHVlID0gc2hhcmVkVmFyaWFibGU7CiAgICAgICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiVGhyZWFkIDI6IFNoYXJlZCBWYXJpYWJsZSA9ICIgKyBsb2NhbFZhbHVlKTsKICAgICAgICB9KTsKCiAgICAgICAgdGhyZWFkMS5zdGFydCgpOwogICAgICAgIHRocmVhZDIuc3RhcnQoKTsKICAgIH0KfQpgYGAKCkluIHRoaXMgZXhhbXBsZSwgYHNoYXJlZFZhcmlhYmxlYCBpcyBhY2Nlc3NlZCBieSB0d28gdGhyZWFkcyBjb25jdXJyZW50bHkuIFdpdGhvdXQgcHJvcGVyIHN5bmNocm9uaXphdGlvbiwgdGhlIHZhbHVlIG9mIGBzaGFyZWRWYXJpYWJsZWAgbWF5IG5vdCBiZSBjb25zaXN0ZW50IGJldHdlZW4gdGhyZWFkcy4KCiMjIyAyLiBIYXBwZW5zLUJlZm9yZSBSZWxhdGlvbnNoaXAKCkphdmEncyBNZW1vcnkgTW9kZWwgaW50cm9kdWNlcyB0aGUgY29uY2VwdCBvZiB0aGUgImhhcHBlbnMtYmVmb3JlIiByZWxhdGlvbnNoaXAuIEl0IGRlZmluZXMgdGhlIG9yZGVyIGluIHdoaWNoIGFjdGlvbnMgcGVyZm9ybWVkIGJ5IG9uZSB0aHJlYWQgYXJlIHZpc2libGUgdG8gb3RoZXIgdGhyZWFkcy4gQWN0aW9ucyB0aGF0IGhhcHBlbi1iZWZvcmUgb3RoZXIgYWN0aW9ucyBtdXN0IGJlIHNlZW4gaW4gdGhlIGNvcnJlY3Qgb3JkZXIgYnkgb3RoZXIgdGhyZWFkcy4KCiMjIyMgRXhhbXBsZSAyOiBIYXBwZW5zLUJlZm9yZQoKYGBgIGphdmEKcHVibGljIGNsYXNzIEhhcHBlbnNCZWZvcmVFeGFtcGxlIHsKICAgIHByaXZhdGUgc3RhdGljIGludCBzaGFyZWRWYXJpYWJsZSA9IDA7CiAgICBwcml2YXRlIHN0YXRpYyBib29sZWFuIGZsYWcgPSBmYWxzZTsKCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgVGhyZWFkIHRocmVhZDEgPSBuZXcgVGhyZWFkKCgpIC0+IHsKICAgICAgICAgICAgc2hhcmVkVmFyaWFibGUgPSA0MjsKICAgICAgICAgICAgZmxhZyA9IHRydWU7CiAgICAgICAgfSk7CgogICAgICAgIFRocmVhZCB0aHJlYWQyID0gbmV3IFRocmVhZCgoKSAtPiB7CiAgICAgICAgICAgIGlmIChmbGFnKSB7CiAgICAgICAgICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oIlRocmVhZCAyOiBTaGFyZWQgVmFyaWFibGUgPSAiICsgc2hhcmVkVmFyaWFibGUpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CgogICAgICAgIHRocmVhZDEuc3RhcnQoKTsKICAgICAgICB0aHJlYWQyLnN0YXJ0KCk7CiAgICB9Cn0KYGBgCgpJbiB0aGlzIGV4YW1wbGUsIHRoZSBgZmxhZ2AgdmFyaWFibGUgYWN0cyBhcyBhIHN5bmNocm9uaXphdGlvbiBwb2ludC4gVGhlIGhhcHBlbnMtYmVmb3JlIHJlbGF0aW9uc2hpcCBlbnN1cmVzIHRoYXQgaWYgYGZsYWdgIGlzIGB0cnVlYCBpbiBUaHJlYWQgMiwgaXQgbXVzdCBzZWUgdGhlIHVwZGF0ZSB0byBgc2hhcmVkVmFyaWFibGVgIG1hZGUgYnkgVGhyZWFkIDEuCgojIyMgMy4gU3luY2hyb25pemF0aW9uCgpTeW5jaHJvbml6YXRpb24gaW4gSmF2YSBpcyBhY2hpZXZlZCB0aHJvdWdoIHRoZSB1c2Ugb2YgYHN5bmNocm9uaXplZGAgYmxvY2tzIGFuZCBtZXRob2RzLCBgdm9sYXRpbGVgIHZhcmlhYmxlcywgYW5kIGV4cGxpY2l0IGxvY2tzIGxpa2UgYFJlZW50cmFudExvY2tgLiBUaGVzZSBtZWNoYW5pc21zIGVuZm9yY2UgdGhlIGhhcHBlbnMtYmVmb3JlIHJlbGF0aW9uc2hpcCBhbmQgZW5zdXJlIHRoYXQgdGhyZWFkcyBhY2Nlc3Mgc2hhcmVkIGRhdGEgc2FmZWx5LgoKIyMjIyBFeGFtcGxlIDM6IFN5bmNocm9uaXplZCBNZXRob2QKCmBgYCBqYXZhCnB1YmxpYyBjbGFzcyBTeW5jaHJvbml6ZWRNZXRob2RFeGFtcGxlIHsKICAgIHByaXZhdGUgc3RhdGljIGludCBzaGFyZWRWYXJpYWJsZSA9IDA7CgogICAgcHVibGljIHN5bmNocm9uaXplZCBzdGF0aWMgdm9pZCBpbmNyZW1lbnQoKSB7CiAgICAgICAgc2hhcmVkVmFyaWFibGUrKzsKICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgVGhyZWFkIHRocmVhZDEgPSBuZXcgVGhyZWFkKCgpIC0+IHsKICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCAxMDAwMDAwOyBpKyspIHsKICAgICAgICAgICAgICAgIGluY3JlbWVudCgpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CgogICAgICAgIFRocmVhZCB0aHJlYWQyID0gbmV3IFRocmVhZCgoKSAtPiB7CiAgICAgICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgMTAwMDAwMDsgaSsrKSB7CiAgICAgICAgICAgICAgICBpbmNyZW1lbnQoKTsKICAgICAgICAgICAgfQogICAgICAgIH0pOwoKICAgICAgICB0aHJlYWQxLnN0YXJ0KCk7CiAgICAgICAgdGhyZWFkMi5zdGFydCgpOwoKICAgICAgICB0cnkgewogICAgICAgICAgICB0aHJlYWQxLmpvaW4oKTsKICAgICAgICAgICAgdGhyZWFkMi5qb2luKCk7CiAgICAgICAgfSBjYXRjaCAoSW50ZXJydXB0ZWRFeGNlcHRpb24gZSkgewogICAgICAgICAgICBUaHJlYWQuY3VycmVudFRocmVhZCgpLmludGVycnVwdCgpOwogICAgICAgIH0KCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJTaGFyZWQgVmFyaWFibGU6ICIgKyBzaGFyZWRWYXJpYWJsZSk7CiAgICB9Cn0KYGBgCgpJbiB0aGlzIGV4YW1wbGUsIHRoZSBgaW5jcmVtZW50YCBtZXRob2QgaXMgc3luY2hyb25pemVkLCBlbnN1cmluZyB0aGF0IG9ubHkgb25lIHRocmVhZCBjYW4gZXhlY3V0ZSBpdCBhdCBhIHRpbWUuIFRoaXMgZ3VhcmFudGVlcyB0aGF0IHRoZSBzaGFyZWQgdmFyaWFibGUgaXMgbW9kaWZpZWQgc2FmZWx5LgoKIyMjIDQuIFZvbGF0aWxlIFZhcmlhYmxlcwoKVGhlIGB2b2xhdGlsZWAga2V5d29yZCBpcyB1c2VkIHRvIGRlY2xhcmUgdmFyaWFibGVzIHRoYXQgYXJlIGFjY2Vzc2VkIGJ5IG11bHRpcGxlIHRocmVhZHMuIEl0IGVuc3VyZXMgdGhhdCByZWFkcyBhbmQgd3JpdGVzIHRvIHRoZSB2YXJpYWJsZSBhcmUgYXRvbWljIGFuZCB0aGF0IGNoYW5nZXMgbWFkZSBieSBvbmUgdGhyZWFkIGFyZSBpbW1lZGlhdGVseSB2aXNpYmxlIHRvIG90aGVyIHRocmVhZHMuCgojIyMjIEV4YW1wbGUgNDogVm9sYXRpbGUgVmFyaWFibGUKCmBgYCBqYXZhCnB1YmxpYyBjbGFzcyBWb2xhdGlsZVZhcmlhYmxlRXhhbXBsZSB7CiAgICBwcml2YXRlIHN0YXRpYyB2b2xhdGlsZSBib29sZWFuIGZsYWcgPSBmYWxzZTsKCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgVGhyZWFkIHRocmVhZDEgPSBuZXcgVGhyZWFkKCgpIC0+IHsKICAgICAgICAgICAgZmxhZyA9IHRydWU7CiAgICAgICAgfSk7CgogICAgICAgIFRocmVhZCB0aHJlYWQyID0gbmV3IFRocmVhZCgoKSAtPiB7CiAgICAgICAgICAgIHdoaWxlICghZmxhZykgewogICAgICAgICAgICAgICAgLy8gU3Bpbi13YWl0IHVudGlsIGZsYWcgYmVjb21lcyB0cnVlCiAgICAgICAgICAgIH0KICAgICAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJUaHJlYWQgMjogRmxhZyBpcyB0cnVlLiIpOwogICAgICAgIH0pOwoKICAgICAgICB0aHJlYWQxLnN0YXJ0KCk7CiAgICAgICAgdGhyZWFkMi5zdGFydCgpOwogICAgfQp9CmBgYAoKSW4gdGhpcyBleGFtcGxlLCB0aGUgYGZsYWdgIHZhcmlhYmxlIGlzIGRlY2xhcmVkIGFzIGB2b2xhdGlsZWAsIGVuc3VyaW5nIHRoYXQgY2hhbmdlcyBtYWRlIGJ5IFRocmVhZCAxIHRvIGBmbGFnYCBhcmUgaW1tZWRpYXRlbHkgdmlzaWJsZSB0byBUaHJlYWQgMi4KCkphdmEncyBNZW1vcnkgTW9kZWwgaXMgYSBjcml0aWNhbCBwYXJ0IG9mIEphdmEncyBtdWx0aS10aHJlYWRpbmcgc3VwcG9ydCwgcHJvdmlkaW5nIHJ1bGVzIGFuZCBndWFyYW50ZWVzIHRoYXQgYWxsb3cgZGV2ZWxvcGVycyB0byB3cml0ZSBzYWZlIGFuZCBjb3JyZWN0IG11bHRpLXRocmVhZGVkIHByb2dyYW1zLiBVbmRlcnN0YW5kaW5nIHRoZSBwcmluY2lwbGVzIG9mIHNoYXJlZCBtZW1vcnksIHRoZSBoYXBwZW5zLWJlZm9yZSByZWxhdGlvbnNoaXAsIHN5bmNocm9uaXphdGlvbiwgYW5kIHZvbGF0aWxlIHZhcmlhYmxlcyBpcyBlc3NlbnRpYWwgZm9yIHdyaXRpbmcgcmVsaWFibGUgbXVsdGktdGhyZWFkZWQgY29kZSBpbiBKYXZhLiBBbHdheXMgY29uc2lkZXIgdGhlc2UgY29uY2VwdHMgd2hlbiB3b3JraW5nIHdpdGggbXVsdGktdGhyZWFkZWQgYXBwbGljYXRpb25zIHRvIGF2b2lkIHN1YnRsZSBjb25jdXJyZW5jeSBpc3N1ZXMgYW5kIGVuc3VyZSB0aGUgY29ycmVjdG5lc3Mgb2YgeW91ciBjb2RlLgoKIyMgQXBwZW5kaXggQjogSmF2YSBUaHJlYWQgQVBJIFJlZmVyZW5jZQoKIyMjIEF0LWEtR2xhbmNlCgotICAgamF2YS5sYW5nLlRocmVhZAotICAgamF2YS51dGlsLmNvbmN1cnJlbnQgUGFja2FnZQotICAgamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MgUGFja2FnZQoKKipBcHBlbmRpeCBCOiBKYXZhIFRocmVhZCBBUEkgUmVmZXJlbmNlKioKClRoaXMgYXBwZW5kaXggcHJvdmlkZXMgYSBzdW1tYXJ5IGFuZCBoaWdoLWxldmVsIChhbmQgaW5jb21wbGV0ZSkgb3ZlcnZpZXcgb2YgdGhlIEphdmEgVGhyZWFkIEFQSSwgd2hpY2ggaXMgcGFydCBvZiB0aGUgYGphdmEubGFuZ2AgcGFja2FnZS4KClRocmVhZHMgaW4gSmF2YSBhcmUgYSBmdW5kYW1lbnRhbCBjb21wb25lbnQgb2YgbXVsdGktdGhyZWFkZWQgcHJvZ3JhbW1pbmcsIGFuZCB0aGUgVGhyZWFkIGNsYXNzIHByb3ZpZGVzIGVzc2VudGlhbCBtZXRob2RzIGFuZCBmdW5jdGlvbmFsaXR5IGZvciBjcmVhdGluZyBhbmQgbWFuYWdpbmcgdGhyZWFkcy4gSW4gdGhpcyByZWZlcmVuY2UsIHdlJ2xsIGNvdmVyIGtleSBtZXRob2RzIGFuZCBjb25jZXB0cyByZWxhdGVkIHRvIHRoZSBKYXZhIFRocmVhZCBBUEkuCgojIyMgYGphdmEubGFuZy5UaHJlYWRgIENsYXNzCgpUaGUgYFRocmVhZGAgY2xhc3MgcmVwcmVzZW50cyBhIHRocmVhZCBvZiBleGVjdXRpb24gaW4gYSBKYXZhIHByb2dyYW0uIFRocmVhZHMgYXJlIHVzZWQgZm9yIGNvbmN1cnJlbnQgZXhlY3V0aW9uIG9mIGNvZGUgYW5kIGNhbiBiZSBjcmVhdGVkIGFuZCBtYW5hZ2VkIHVzaW5nIHRoaXMgY2xhc3MuCgojIyMjIENvbnN0cnVjdG9ycwoKMS4gICoqYFRocmVhZCgpYCoqOiBDcmVhdGVzIGEgbmV3IHRocmVhZCB3aXRoIG5vIHRhcmdldCBSdW5uYWJsZS4KCjIuICAqKmBUaHJlYWQoUnVubmFibGUgdGFyZ2V0KWAqKjogQ3JlYXRlcyBhIG5ldyB0aHJlYWQgd2l0aCB0aGUgc3BlY2lmaWVkIHRhcmdldCBSdW5uYWJsZS4KCjMuICAqKmBUaHJlYWQoVGhyZWFkR3JvdXAgZ3JvdXAsIFJ1bm5hYmxlIHRhcmdldClgKio6IENyZWF0ZXMgYSBuZXcgdGhyZWFkIHdpdGggdGhlIHNwZWNpZmllZCB0YXJnZXQgUnVubmFibGUgYW5kIHBsYWNlcyBpdCBpbiB0aGUgc3BlY2lmaWVkIHRocmVhZCBncm91cC4KCjQuICAqKmBUaHJlYWQoU3RyaW5nIG5hbWUpYCoqOiBDcmVhdGVzIGEgbmV3IHRocmVhZCB3aXRoIHRoZSBzcGVjaWZpZWQgbmFtZS4KCiMjIyMgTWV0aG9kcwoKMS4gICoqYHN0YXJ0KClgKio6IFN0YXJ0cyB0aGUgZXhlY3V0aW9uIG9mIHRoZSB0aHJlYWQuIFRoZSBgcnVuKClgIG1ldGhvZCBvZiB0aGUgUnVubmFibGUgYXNzb2NpYXRlZCB3aXRoIHRoaXMgdGhyZWFkIGlzIGludm9rZWQuCgoyLiAgKipgcnVuKClgKio6IFRoaXMgbWV0aG9kIGNvbnRhaW5zIHRoZSBjb2RlIHRoYXQgY29uc3RpdHV0ZXMgdGhlIG5ldyB0aHJlYWQncyB0YXNrLiBZb3UgY2FuIG92ZXJyaWRlIHRoaXMgbWV0aG9kIGJ5IHN1YmNsYXNzaW5nIFRocmVhZC4KCjMuICAqKmBqb2luKClgKio6IFdhaXRzIGZvciB0aGlzIHRocmVhZCB0byBkaWUuIEl0IGJsb2NrcyB1bnRpbCB0aGUgdGhyZWFkIG9uIHdoaWNoIGl0IGlzIGNhbGxlZCB0ZXJtaW5hdGVzLgoKNC4gICoqYHNldE5hbWUoU3RyaW5nIG5hbWUpYCoqOiBTZXRzIHRoZSBuYW1lIG9mIHRoZSB0aHJlYWQuCgo1LiAgKipgZ2V0TmFtZSgpYCoqOiBSZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSB0aHJlYWQuCgo2LiAgKipgZ2V0SWQoKWAqKjogUmV0dXJucyB0aGUgdW5pcXVlIGlkZW50aWZpZXIgYXNzaWduZWQgdG8gdGhpcyB0aHJlYWQuCgo3LiAgKipgaXNBbGl2ZSgpYCoqOiBUZXN0cyBpZiB0aGlzIHRocmVhZCBpcyBhbGl2ZS4gQSB0aHJlYWQgaXMgY29uc2lkZXJlZCBhbGl2ZSBpZiBpdCBoYXMgYmVlbiBzdGFydGVkIGFuZCBoYXMgbm90IHlldCBkaWVkLgoKOC4gICoqYGludGVycnVwdCgpYCoqOiBJbnRlcnJ1cHRzIHRoaXMgdGhyZWFkLCBjYXVzaW5nIGl0IHRvIHN0b3AgZXhlY3V0aW5nIGlmIGl0J3MgaW4gYSBibG9ja2VkIHN0YXRlIG9yIHRocm93IGFuIEludGVycnVwdGVkRXhjZXB0aW9uIGlmIGl0J3Mgd2FpdGluZy4KCjkuICAqKmBpc0ludGVycnVwdGVkKClgKio6IFRlc3RzIHdoZXRoZXIgdGhlIHRocmVhZCBoYXMgYmVlbiBpbnRlcnJ1cHRlZC4KCjEwLiAqKmBjdXJyZW50VGhyZWFkKClgKio6IFN0YXRpYyBtZXRob2QgdGhhdCByZXR1cm5zIHRoZSBjdXJyZW50bHkgZXhlY3V0aW5nIHRocmVhZC4KCjExLiAqKmBzbGVlcChsb25nIG1pbGxpcylgKio6IENhdXNlcyB0aGUgdGhyZWFkIHRvIHNsZWVwIGZvciB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiBtaWxsaXNlY29uZHMuCgoxMi4gKipgeWllbGQoKWAqKjogQSBoaW50IHRvIHRoZSBzY2hlZHVsZXIgdGhhdCB0aGUgY3VycmVudCB0aHJlYWQgaXMgd2lsbGluZyB0byB5aWVsZCBpdHMgY3VycmVudCB1c2Ugb2YgdGhlIHByb2Nlc3Nvci4KCjEzLiAqKmBzZXRQcmlvcml0eShpbnQgcHJpb3JpdHkpYCoqOiBTZXRzIHRoZSBwcmlvcml0eSBvZiB0aGlzIHRocmVhZC4KCjE0LiAqKmBnZXRQcmlvcml0eSgpYCoqOiBSZXR1cm5zIHRoZSBwcmlvcml0eSBvZiB0aGlzIHRocmVhZC4KCjE1LiAqKmBzZXREYWVtb24oYm9vbGVhbiBvbilgKio6IE1hcmtzIHRoaXMgdGhyZWFkIGFzIGVpdGhlciBhIGRhZW1vbiB0aHJlYWQgb3IgYSB1c2VyIHRocmVhZC4KCjE2LiAqKmBpc0RhZW1vbigpYCoqOiBUZXN0cyBpZiB0aGlzIHRocmVhZCBpcyBhIGRhZW1vbiB0aHJlYWQuCgoxNy4gKipgZ2V0U3RhdGUoKWAqKjogUmV0dXJucyB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGlzIHRocmVhZCAoZS5nLiwgTkVXLCBSVU5OQUJMRSwgQkxPQ0tFRCwgV0FJVElORykuCgoxOC4gKipgZ2V0VGhyZWFkR3JvdXAoKWAqKjogUmV0dXJucyB0aGUgdGhyZWFkIGdyb3VwIHRvIHdoaWNoIHRoaXMgdGhyZWFkIGJlbG9uZ3MuCgoxOS4gKipgc2V0VW5jYXVnaHRFeGNlcHRpb25IYW5kbGVyKFVuY2F1Z2h0RXhjZXB0aW9uSGFuZGxlciBlaClgKio6IFNldHMgdGhlIGRlZmF1bHQgdW5jYXVnaHQgZXhjZXB0aW9uIGhhbmRsZXIgZm9yIHRoaXMgdGhyZWFkLgoKMjAuICoqYGdldFVuY2F1Z2h0RXhjZXB0aW9uSGFuZGxlcigpYCoqOiBSZXR1cm5zIHRoZSBjdXJyZW50IGRlZmF1bHQgdW5jYXVnaHQgZXhjZXB0aW9uIGhhbmRsZXIgZm9yIHRoaXMgdGhyZWFkLgoKIyMjIGBqYXZhLmxhbmcuUnVubmFibGVgIEludGVyZmFjZQoKVGhlIGBSdW5uYWJsZWAgaW50ZXJmYWNlIHJlcHJlc2VudHMgYSB0YXNrIHRoYXQgY2FuIGJlIGV4ZWN1dGVkIGNvbmN1cnJlbnRseSBieSBhIHRocmVhZC4gSXQgZGVmaW5lcyBhIHNpbmdsZSBhYnN0cmFjdCBtZXRob2QgYHJ1bigpYCB0aGF0IHNob3VsZCBiZSBpbXBsZW1lbnRlZCBieSBjbGFzc2VzIHRoYXQgd2FudCB0byBwcm92aWRlIGEgY29uY3VycmVudCB0YXNrLgoKIyMjIyBNZXRob2RzCgoxLiAgKipgcnVuKClgKio6IFRoZSBhYnN0cmFjdCBtZXRob2QgdGhhdCBzaG91bGQgY29udGFpbiB0aGUgY29kZSB0byBiZSBleGVjdXRlZCBieSB0aGUgdGhyZWFkLgoKIyMjIEV4YW1wbGVzCgojIyMjIENyZWF0aW5nIGFuZCBTdGFydGluZyBhIFRocmVhZAoKYGBgIGphdmEKVGhyZWFkIG15VGhyZWFkID0gbmV3IFRocmVhZCgoKSAtPiB7CiAgICAvLyBSdW5uYWJsZSBjb2RlIGdvZXMgaGVyZQogICAgU3lzdGVtLm91dC5wcmludGxuKCJUaHJlYWQgaXMgcnVubmluZy4iKTsKfSk7CgpteVRocmVhZC5zdGFydCgpOyAvLyBTdGFydHMgdGhlIHRocmVhZApgYGAKCiMjIyMgT3ZlcnJpZGluZyB0aGUgYHJ1bigpYCBNZXRob2QKCmBgYCBqYXZhCmNsYXNzIE15VGhyZWFkIGV4dGVuZHMgVGhyZWFkIHsKICAgIEBPdmVycmlkZQogICAgcHVibGljIHZvaWQgcnVuKCkgewogICAgICAgIC8vIEN1c3RvbSB0aHJlYWQgY29kZQogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiTXlUaHJlYWQgaXMgcnVubmluZy4iKTsKICAgIH0KfQoKTXlUaHJlYWQgbXlUaHJlYWQgPSBuZXcgTXlUaHJlYWQoKTsKbXlUaHJlYWQuc3RhcnQoKTsKYGBgCgojIyMjIFVzaW5nIFJ1bm5hYmxlCgpgYGAgamF2YQpjbGFzcyBNeVJ1bm5hYmxlIGltcGxlbWVudHMgUnVubmFibGUgewogICAgQE92ZXJyaWRlCiAgICBwdWJsaWMgdm9pZCBydW4oKSB7CiAgICAgICAgLy8gQ3VzdG9tIHJ1bm5hYmxlIGNvZGUKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oIk15UnVubmFibGUgaXMgcnVubmluZy4iKTsKICAgIH0KfQoKVGhyZWFkIG15VGhyZWFkID0gbmV3IFRocmVhZChuZXcgTXlSdW5uYWJsZSgpKTsKbXlUaHJlYWQuc3RhcnQoKTsKYGBgCgpUaGlzIHNob3J0IHJlZmVyZW5jZSBzZWN0aW9uIHByb3ZpZGVkIGFuIG92ZXJ2aWV3IG9mIGtleSBjbGFzc2VzIGFuZCBtZXRob2RzIGluIHRoZSBKYXZhIFRocmVhZCBBUEksIHdoaWNoIGlzIGVzc2VudGlhbCBmb3IgbWFuYWdpbmcgdGhyZWFkcyBhbmQgY29uY3VycmVudCBleGVjdXRpb24gaW4gSmF2YSBhcHBsaWNhdGlvbnMuIFVuZGVyc3RhbmRpbmcgdGhlc2UgY2xhc3NlcyBhbmQgdGhlaXIgdXNhZ2UgaXMgY3J1Y2lhbCBmb3IgZGV2ZWxvcGluZyBtdWx0aS10aHJlYWRlZCBKYXZhIHByb2dyYW1zIGVmZmVjdGl2ZWx5LgoKIyMgQXBwZW5kaXggQzogR2xvc3Nhcnkgb2YgS2V5IFRlcm1zCgoxLiAgKipNdWx0aS1UaHJlYWRpbmcqKjogVGhlIGNvbmN1cnJlbnQgZXhlY3V0aW9uIG9mIG11bHRpcGxlIHRocmVhZHMgKHNtYWxsZXIgdW5pdHMgb2YgYSBwcm9jZXNzKSBpbiBhIHNpbmdsZSBwcm9ncmFtIHRvIGFjaGlldmUgcGFyYWxsZWxpc20gYW5kIGltcHJvdmUgcGVyZm9ybWFuY2UuCgoyLiAgKipNdWx0aS1Qcm9jZXNzaW5nKio6IENvbmN1cnJlbmN5IGFjaGlldmVkIGJ5IHJ1bm5pbmcgbXVsdGlwbGUgcHJvY2Vzc2VzIHNpbXVsdGFuZW91c2x5LCBlYWNoIHdpdGggaXRzIG93biBtZW1vcnkgc3BhY2UgYW5kIHJlc291cmNlcywgb2Z0ZW4gb24gbXVsdGlwbGUgQ1BVIGNvcmVzLgoKMy4gICoqSHlicmlkIE11bHRpLVByb2Nlc3NpbmcqKjogQ29tYmluZXMgbXVsdGktdGhyZWFkaW5nIHdpdGhpbiBtdWx0aXBsZSBwcm9jZXNzZXMsIGFsbG93aW5nIGZvciBwYXJhbGxlbGlzbSBhdCBib3RoIHRoZSBwcm9jZXNzIGFuZCB0aHJlYWQgbGV2ZWxzLgoKNC4gICoqQ29uY3VycmVuY3kqKjogVGhlIGNvbmNlcHQgb2YgbXVsdGlwbGUgdGFza3MgYXBwZWFyaW5nIHRvIGJlIGV4ZWN1dGVkIGluIG92ZXJsYXBwaW5nIHRpbWUgcGVyaW9kcywgb2Z0ZW4gdXNlZCBpbnRlcmNoYW5nZWFibHkgd2l0aCBtdWx0aS10aHJlYWRpbmcuCgo1LiAgKipUaHJlYWQqKjogQSBsaWdodHdlaWdodCwgaW5kZXBlbmRlbnQgdW5pdCBvZiBleGVjdXRpb24gd2l0aGluIGEgcHJvY2VzcywgY2FwYWJsZSBvZiBydW5uaW5nIGNvbmN1cnJlbnRseSB3aXRoIG90aGVyIHRocmVhZHMuCgo2LiAgKipQcm9jZXNzKio6IEEgc2VwYXJhdGUsIHNlbGYtY29udGFpbmVkIHByb2dyYW0gd2l0aCBpdHMgb3duIG1lbW9yeSBzcGFjZSwgcmVzb3VyY2VzLCBhbmQgZXhlY3V0aW9uIGVudmlyb25tZW50LgoKNy4gICoqU3luY2hyb25pemF0aW9uKio6IFRoZSBjb29yZGluYXRpb24gb2YgbXVsdGlwbGUgdGhyZWFkcyB0byBlbnN1cmUgdGhleSBhY2Nlc3Mgc2hhcmVkIHJlc291cmNlcyBpbiBhIGNvbnRyb2xsZWQgYW5kIG9yZGVybHkgbWFubmVyLCBwcmV2ZW50aW5nIGRhdGEgcmFjZXMgYW5kIGNvbmZsaWN0cy4KCjguICAqKkRlYWRsb2NrKio6IEEgc2l0dWF0aW9uIGluIHdoaWNoIHR3byBvciBtb3JlIHRocmVhZHMgYXJlIHVuYWJsZSB0byBwcm9jZWVkIGJlY2F1c2UgZWFjaCBpcyB3YWl0aW5nIGZvciB0aGUgb3RoZXIgdG8gcmVsZWFzZSBhIHJlc291cmNlLgoKOS4gICoqVGhyZWFkIFBvb2wqKjogQSBjb2xsZWN0aW9uIG9mIHByZS1jcmVhdGVkIHRocmVhZHMgdGhhdCBjYW4gYmUgcmV1c2VkIHRvIGV4ZWN1dGUgdGFza3MsIHJlZHVjaW5nIHRoZSBvdmVyaGVhZCBvZiB0aHJlYWQgY3JlYXRpb24gYW5kIGRlc3RydWN0aW9uLgoKMTAuICoqVGFzayBRdWV1ZSoqOiBBIGRhdGEgc3RydWN0dXJlIHRoYXQgaG9sZHMgdGFza3MgKHVuaXRzIG9mIHdvcmspIHRvIGJlIGV4ZWN1dGVkIGJ5IHRocmVhZHMgaW4gYSB0aHJlYWQgcG9vbC4KCjExLiAqKkhhcHBlbnMtQmVmb3JlIFJlbGF0aW9uc2hpcCoqOiBBIHJlbGF0aW9uc2hpcCBkZWZpbmVkIGJ5IHRoZSBKYXZhIE1lbW9yeSBNb2RlbCB0aGF0IGVuc3VyZXMgYSBzcGVjaWZpYyBvcmRlciBvZiBleGVjdXRpb24gb3IgdmlzaWJpbGl0eSBiZXR3ZWVuIGFjdGlvbnMgaW4gZGlmZmVyZW50IHRocmVhZHMuCgoxMi4gKipWb2xhdGlsZSBWYXJpYWJsZSoqOiBBIHZhcmlhYmxlIGluIEphdmEgZGVjbGFyZWQgYXMgYHZvbGF0aWxlYCB0aGF0IGVuc3VyZXMgYXRvbWljIHJlYWRzIGFuZCB3cml0ZXMgYW5kIGd1YXJhbnRlZXMgdmlzaWJpbGl0eSBvZiBjaGFuZ2VzIHRvIG90aGVyIHRocmVhZHMuCgoxMy4gKipTeW5jaHJvbml6ZWQqKjogQSBKYXZhIGtleXdvcmQgdGhhdCBjYW4gYmUgdXNlZCB3aXRoIG1ldGhvZHMgYW5kIGJsb2NrcyB0byBlbnN1cmUgZXhjbHVzaXZlIGFjY2VzcyB0byBjcml0aWNhbCBzZWN0aW9ucyBvZiBjb2RlLCBwcmV2ZW50aW5nIGNvbmN1cnJlbnQgYWNjZXNzIGlzc3Vlcy4KCjE0LiAqKkFQSSoqOiBBYmJyZXZpYXRpb24gZm9yICJBcHBsaWNhdGlvbiBQcm9ncmFtbWluZyBJbnRlcmZhY2UsIiB3aGljaCBkZWZpbmVzIHRoZSBtZXRob2RzLCBjbGFzc2VzLCBhbmQgcHJvdG9jb2xzIGZvciBidWlsZGluZyBzb2Z0d2FyZSBhbmQgaW50ZXJhY3Rpbmcgd2l0aCBsaWJyYXJpZXMuCgoxNS4gKipUaHJlYWQgU2FmZXR5Kio6IEEgcHJvcGVydHkgb2YgY29kZSBvciBkYXRhIHN0cnVjdHVyZXMgdGhhdCBndWFyYW50ZWVzIGNvcnJlY3QgYmVoYXZpb3IgaW4gYSBtdWx0aS10aHJlYWRlZCBlbnZpcm9ubWVudCB3aXRob3V0IGRhdGEgcmFjZXMgb3Igb3RoZXIgY29uY3VycmVuY3kgaXNzdWVzLgoKMTYuICoqQmxvY2tpbmcgUXVldWUqKjogQSB0aHJlYWQtc2FmZSBkYXRhIHN0cnVjdHVyZSB0aGF0IGFsbG93cyBlbGVtZW50cyB0byBiZSBlbnF1ZXVlZCBhbmQgZGVxdWV1ZWQsIGJsb2NraW5nIHdoZW4gbmVjZXNzYXJ5IHRvIG1haW50YWluIHRocmVhZCBzYWZldHkgYW5kIHN5bmNocm9uaXphdGlvbi4KCjE3LiAqKkNhbGxhYmxlKio6IEFuIGludGVyZmFjZSBpbiBKYXZhIHRoYXQgcmVwcmVzZW50cyBhIHRhc2sgdGhhdCBjYW4gYmUgZXhlY3V0ZWQgYW5kIHJldHVybiBhIHJlc3VsdCwgb2Z0ZW4gdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRocmVhZCBwb29scy4KCjE4LiAqKkZ1dHVyZSoqOiBBbiBvYmplY3QgaW4gSmF2YSB0aGF0IHJlcHJlc2VudHMgdGhlIHJlc3VsdCBvZiBhbiBhc3luY2hyb25vdXMgY29tcHV0YXRpb24sIHByb3ZpZGluZyBhIHdheSB0byByZXRyaWV2ZSB0aGUgcmVzdWx0IG9yIGhhbmRsZSBleGNlcHRpb25zIHdoZW4gdGhlIHRhc2sgY29tcGxldGVzLgoKMTkuICoqQ29uY3VycmVudCBQcm9ncmFtbWluZyoqOiBUaGUgZGVzaWduIGFuZCBpbXBsZW1lbnRhdGlvbiBvZiBzb2Z0d2FyZSB0aGF0IGNhbiBlZmZlY3RpdmVseSBhbmQgc2FmZWx5IHJ1biBtdWx0aXBsZSB0aHJlYWRzIG9yIHByb2Nlc3NlcyBjb25jdXJyZW50bHkuCgoyMC4gKipKYXZhIE1lbW9yeSBNb2RlbCoqOiBBIHNldCBvZiBydWxlcyBhbmQgZ3VhcmFudGVlcyB0aGF0IGRlZmluZSBob3cgbWVtb3J5IGlzIGFjY2Vzc2VkIGFuZCBtYW5pcHVsYXRlZCBieSB0aHJlYWRzIGluIGEgbXVsdGktdGhyZWFkZWQgSmF2YSBwcm9ncmFtLgoKMjEuICoqQXRvbWljIE9wZXJhdGlvbioqOiBBbiBvcGVyYXRpb24gdGhhdCBpcyBwZXJmb3JtZWQgYXMgYSBzaW5nbGUsIGluZGl2aXNpYmxlIHVuaXQsIGVuc3VyaW5nIHRoYXQgaXQgaXMgbm90IGludGVycnVwdGVkIG9yIGludGVybGVhdmVkIGJ5IG90aGVyIHRocmVhZHMuCgoyMi4gKipSYWNlIENvbmRpdGlvbioqOiBBIHNpdHVhdGlvbiBpbiB3aGljaCB0aGUgYmVoYXZpb3Igb2YgYSBwcm9ncmFtIGRlcGVuZHMgb24gdGhlIHJlbGF0aXZlIHRpbWluZyBvZiBldmVudHMsIG9mdGVuIGxlYWRpbmcgdG8gdW5pbnRlbmRlZCBhbmQgdW5wcmVkaWN0YWJsZSByZXN1bHRzLgoKMjMuICoqRGFlbW9uIFRocmVhZCoqOiBBIHRocmVhZCBpbiBKYXZhIHRoYXQgcnVucyBpbiB0aGUgYmFja2dyb3VuZCBhbmQgZG9lcyBub3QgcHJldmVudCB0aGUgSlZNIGZyb20gZXhpdGluZyB3aGVuIGFsbCBub24tZGFlbW9uIHRocmVhZHMgaGF2ZSBmaW5pc2hlZCBleGVjdXRpbmcuCgoyNC4gKipUaHJlYWQgR3JvdXAqKjogQSBtZWNoYW5pc20gaW4gSmF2YSB0byBncm91cCBtdWx0aXBsZSB0aHJlYWRzIHRvZ2V0aGVyLCBwcm92aWRpbmcgb3JnYW5pemF0aW9uYWwgYW5kIG1hbmFnZW1lbnQgY2FwYWJpbGl0aWVzLgoKMjUuICoqVW5jYXVnaHQgRXhjZXB0aW9uIEhhbmRsZXIqKjogQSBtZWNoYW5pc20gaW4gSmF2YSBmb3IgaGFuZGxpbmcgZXhjZXB0aW9ucyB0aGF0IG9jY3VyIGluIHRocmVhZHMgYnV0IGFyZSBub3QgY2F1Z2h0IHdpdGhpbiB0aGUgdGhyZWFkJ3MgY29kZS4KCjI2LiAqKkNQVSBDb3JlKio6IEEgcGh5c2ljYWwgcHJvY2Vzc2luZyB1bml0IG9uIGEgQ1BVIGNoaXAgY2FwYWJsZSBvZiBleGVjdXRpbmcgaW5zdHJ1Y3Rpb25zIGluZGVwZW5kZW50bHksIG9mdGVuIHVzZWQgdG8gcnVuIHRocmVhZHMgaW4gcGFyYWxsZWwuCgoyNy4gKipUaHJlYWQgUHJpb3JpdHkqKjogQSBudW1lcmljIHZhbHVlIGFzc2lnbmVkIHRvIGEgdGhyZWFkIHRoYXQgaGludHMgYXQgaXRzIHJlbGF0aXZlIGltcG9ydGFuY2UgdG8gdGhlIHNjaGVkdWxlciwgYWZmZWN0aW5nIGl0cyBzY2hlZHVsaW5nIG9yZGVyLgoKMjguICoqQ29uY3VycmVuY3kgQnVnKio6IEEgdHlwZSBvZiBzb2Z0d2FyZSBidWcgdGhhdCBhcmlzZXMgaW4gbXVsdGktdGhyZWFkZWQgb3IgY29uY3VycmVudCBwcm9ncmFtcyBkdWUgdG8gdW5leHBlY3RlZCBpbnRlcmFjdGlvbnMgYmV0d2VlbiB0aHJlYWRzLgoKMjkuICoqVGhyZWFkIFN0YXRlKio6IFRoZSBjdXJyZW50IGNvbmRpdGlvbiBvciBzdGF0dXMgb2YgYSB0aHJlYWQsIHN1Y2ggYXMgTkVXLCBSVU5OQUJMRSwgQkxPQ0tFRCwgV0FJVElORywgZXRjLiwgaW5kaWNhdGluZyB3aGF0IHRoZSB0aHJlYWQgaXMgY3VycmVudGx5IGRvaW5nLgoKMzAuICoqVGhyZWFkIEludGVycnVwdGlvbioqOiBBIG1lY2hhbmlzbSB0byByZXF1ZXN0IHRoYXQgYSB0aHJlYWQgdm9sdW50YXJpbHkgdGVybWluYXRlIG9yIHBlcmZvcm0gc29tZSBvdGhlciBhY3Rpb24sIHR5cGljYWxseSB1c2VkIGZvciB0aHJlYWQgbWFuYWdlbWVudCBhbmQgY2xlYW51cC4KCjMxLiAqKlRocmVhZCBTbGVlcCoqOiBBIG1ldGhvZCB0aGF0IHBhdXNlcyB0aGUgZXhlY3V0aW9uIG9mIGEgdGhyZWFkIGZvciBhIHNwZWNpZmllZCBkdXJhdGlvbiwgYWxsb3dpbmcgb3RoZXIgdGhyZWFkcyB0byBydW4uCgozMi4gKipCdXN5IFdhaXRpbmcqKjogQSBzeW5jaHJvbml6YXRpb24gdGVjaG5pcXVlIGluIHdoaWNoIGEgdGhyZWFkIHJlcGVhdGVkbHkgY2hlY2tzIGEgY29uZGl0aW9uIHdpdGhpbiBhIGxvb3AsIHBvdGVudGlhbGx5IGNvbnN1bWluZyBDUFUgcmVzb3VyY2VzLgoKMzMuICoqQmxvY2tpbmcqKjogQSBzdGF0ZSBpbiB3aGljaCBhIHRocmVhZCBpcyBwYXVzZWQsIG9mdGVuIGR1ZSB0byB3YWl0aW5nIGZvciBhbiBldmVudCBvciByZXNvdXJjZSB0byBiZWNvbWUgYXZhaWxhYmxlLgoKVGhlc2UgdGVybXMgY292ZXIgYSB3aWRlIHJhbmdlIG9mIGNvbmNlcHRzIHJlbGF0ZWQgdG8gbXVsdGktdGhyZWFkaW5nLCBjb25jdXJyZW5jeSwgYW5kIHRoZSBKYXZhIFRocmVhZCBBUEksIHByb3ZpZGluZyBhIGNvbXByZWhlbnNpdmUgZ2xvc3NhcnkgZm9yIHRoZSBjb252ZXJzYXRpb24uCgojIyBFcnJhdGEKCltMZXQgdXMga25vd10oaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLzIxMjE4NzA3Mjc4NDE1Nyl7dGFyZ2V0PSJfYmxhbmsifS4K