1 Introduction

The logical process for solving statistics problems follows the basic steps

include_graphics("img/StatsProcess.png")
Statistical problem solving process

Statistical problem solving process

In teaching statistics courses, the reasoning process used in course projects is

  • Learn a new method/model

  • Find pre-processed data sets or collect data based on the design of experiment.

  • formulate questions based on the information in the data sets that can be addressed by the new methods/models and previously learned methods/models. These methods / models are based on i.i.d. data and certain distributional assumptions such as normal, binomial, snd Poisson distributions.

  • Perform the analysis

  • Report the results and make recommendations.

In the real world data science process which usually deals with complex data that could be large in size, complex in terms of data types, and data generation process, projects start with a vague business question such as Why our sales are declining in the Northeast region, how to reduce fraud loss, etc.

include_graphics("img/DS-process.png")
Data science problem solving process

Data science problem solving process

That is real-world projects start with a vague business question question with no data! We need to gain a clear business understanding of the problem to formulate clear business problems and then convert the clear business problem to an analytic problem. With the clear analytic problem and analytic background of the members of the project team, data scientists and data scientists will gather relevant information to perform analysis.

The nature of industry data used in data science projects is different from that used in classical projects: large size, most likely non-i.i.d, machine-generated, non-experimental design generated, etc. These types of data are not appropriate for classical modeling. Moreover, the data is generated from different sources in different formats and stored in places (on-premise, cloud, or hybrid). This requires basic knowledge of organizational data infrastructure and architecture. This note outlines the idea of organizational data acquisition and integration.

2 Data Architecture and Data Infrastructure

Data Infrastructure is the digital infrastructure built to manage, store, and process data. This includes databases, data warehouses, servers, hardware and software, network equipment, and data centers. It’s the foundation upon which data management strategy is built.

2.1 Data Architecture

A data architecture describes how data is managed-from collection through transformation, distribution, and consumption. It sets the blueprint for data and the way it flows through data storage systems. Data Lake -> Data Warehouse -> Data Mart

include_graphics("img/DataArchitecture.png")
A demonstration of a simple data architecture

A demonstration of a simple data architecture

Three components of data architecture are data lake, data warehouse, data mart:

Data Lake: holds an original copy of data produced in the business. Data processing from the original should be minimal if any; otherwise, in case some data processing turns out to be wrong in the end, it will not be possible to fix the error retrospectively.

Data Warehouse: holds data processed and structured by a managed data model, reflecting the global (not specific) direction of the final use of the data. In many cases, the data is in tabular format.

Data Mart: holds a part and/or aggregated data set for the use of a particular business function, e.g. specific business unit or specific geographical area. A typical example is when we prepare the summary of KPIs for a specific business line followed by visualization in a BI tool. Especially, preparing this kind of separate and independent component after the warehouse is worthwhile when the user wants the data mart regularly and frequently updated. On the contrary, this portion can be skipped in cases where the user only wants some set of data for ad hoc analysis done only once.

The following table shows who creates/maintains and uses these components in the architecture.

include_graphics("img/UseofDataInfrastructure.png")
Summary of data architecture components

Summary of data architecture components

2.2 Purpose of Data Infrastructure

Different companies with different uses and goals need different technological approaches and tools. Companies invest in data infrastructure in several areas.

Data collection: companies can set up many data collection systems themselves or collaborate with a data company.

Data storage: with the explosion of the volume of data generated and stored, companies need sophisticated but accessible systems and tools. They include a data warehouse, data lake, distributed/cloud-based storage system, company server, and computer hard disk.

Data Analytics: Companies use programming languages and platforms to turn data into insights. Data analysis involves three main basic steps: 1) data preparation (data integration), 2) model building and insights extraction, and 3) implementation and implementation.

Data Communications: Tools for more effective communications.

The following figure summarizes these key elements.

include_graphics("img/ElementsOfDataInfrastructure.png")
Elements of data architecture

Elements of data architecture

2.3 Types of Data Infrastructure

The types of Data Infrastructure can be broadly categorized in the following ways:

include_graphics("img/DataInfrastructureTypes.png")
Types of data infrastructure

Types of data infrastructure

Traditional Infrastructure: This refers to a standard IT infrastructure that uses in-house servers, storage systems, and network devices to collect, store, process, and manage data. This kind of infrastructure requires significant resources and technical expertise to manage.

Cloud Infrastructure: Cloud-based data infrastructure uses cloud storage and computing resources provided by third-party cloud service providers. It offers scalability, cost-effectiveness, and convenience, eliminating the need to maintain onsite server rooms and IT staff. Examples include Amazon Web Services, Microsoft Azure, and Google Cloud Platform.

Hybrid Infrastructure: Hybrid data infrastructure combines the elements of both traditional and cloud infrastructures. Some data may be stored on-premises for speed and security considerations, while others may be stored in the cloud for cost-effectiveness and scalability. Converged Infrastructure: Converged data infrastructure pre-packages multiple IT components into a single, optimized solution. This type includes storage, servers, networking, and software provisioned and managed as a single entity.

Hyper-Converged Infrastructure This is an evolution of converged infrastructure wherein all components are software-defined, with tight integration between technologies, offering even greater simplification and cost savings.

Edge Infrastructure: Edge data infrastructure processes data closer to its source, reducing latency and transmission costs. With the rise of Internet of Things (IoT) devices, edge computing has become increasingly important.

2.4 Aspects of Data Infrastructure

Data infrastructure has several fundamental aspects supporting data collection, storage, processing, distribution, and usage. The main aspects of data infrastructure include:

Physical Infrastructure: This comprises hardware components like servers, computers, routers, and physical storage devices. It can also include data centers and the physical facilities that house the hardware.

Software Infrastructure: This includes databases, data warehouses, extraction, transformation, and loading (ETL) tools, data analytics software, and other applications and platforms that facilitate data management, processing, and analysis. Network Infrastructure: This involves the telecommunication networks (LAN, WAN, Internet) that enable data transfer within and between systems, servers, and storage devices.

Cloud Storage: With technological advancements, more companies are moving their data infrastructure to the cloud. Cloud storage provides a flexible and scalable solution that can be expanded or contracted based on storage needs. Data Processing Frameworks: These are software libraries or engines that enable large-scale data processing. Examples include Hadoop, Apache Spark, etc.

Security Infrastructure: Security measures are essential to protect data from unauthorized access, breaches, or cyber-attacks. These measures can include firewalls, encryption software, and user-access controls.

Data Governance: This involves the policies, processes, and practices to control, manage, and ensure the quality and privacy of data and compliance with regulations such as GDPR.

Data Architecture: This is the design or blueprint of the data infrastructure. It describes how an organization collects, stores, transforms, processes, and consumes data.

3 Data Integration

Data integration refers to the process of bringing together data from multiple sources across an organization to provide a complete, accurate, and up-to-date dataset for data analysis and other applications and business processes. It includes data replication, ingestion, and transformation to combine different types of data into standardized formats to be stored in a target repository such as a data warehouse, data lake, or data mart.

include_graphics("img/DataIntegrationApproaches.png")
Data integration approaches

Data integration approaches

3.1 Major Data Integration Techniques

ETL

An ETL pipeline is a traditional type of data pipeline that converts raw data to match the target system via three steps: extract, transform, and load. Data is transformed in a staging area before it is loaded into the target repository (typically a data warehouse). This allows for fast and accurate data analysis in the target system and is most appropriate for small data sets that require complex transformations.

include_graphics("img/ETL.png")
Data integration approache: ETL

Data integration approache: ETL

ELT

In the more modern ELT pipeline, the data is immediately loaded and then transformed within the target system, typically a cloud-based data lake, data warehouse, or data lake. This approach is more appropriate when data sets are large and timeliness is important since loading is often quicker.

include_graphics("img/ELT.png")
Data integration approache: ELT

Data integration approache: ELT

Data Streaming

Instead of loading data into a new repository in batches, streaming data integration moves data continuously in real time from source to target. Modern data integration (DI) platforms can deliver analytics-ready data into streaming and cloud platforms, data warehouses, and data lakes.

include_graphics("img/Streaming.png")
Data integration approache: Streaming

Data integration approache: Streaming

Application Integration

Application integration (API) allows separate applications to work together by moving and syncing data between them. The most typical use case is to support operational needs such as ensuring that your HR system has the same data as your finance system. Therefore, the application integration must provide consistency between the data sets. Also, these various applications usually have unique APIs for giving and taking data so SaaS application automation tools can help you create and maintain native API integration efficiently and at scale.

include_graphics("img/API.png")
Data integration approache: API

Data integration approache: API

In the next sections, we describe ETL and ETL tools briefly.

3.2 ETL

ETL stands for Extract, Transform, Load. It is a process used in data integration to extract data from various sources, transform the data to meet specific business requirements and load the transformed data into a target system, such as a data warehouse or a database. Data in these systems can be used to perform business analysis and generate business Intelligence (BI) reports.

The extraction phase involves retrieving data from various sources, such as databases, flat files, web services, or cloud-based applications. The transformation phase involves cleaning, enriching, aggregating, or otherwise modifying the data to meet the needs of the target system. Finally, the load phase involves writing the transformed data to the target system.

With the increasing adoption of big data technologies, such as Hadoop and Spark, ETL processes have become more complex and require more advanced tools and technologies. ETL workflows in big data often involve processing data in parallel across multiple nodes in a distributed environment, which requires specialized tools that can handle data partitioning, data shuffling, and fault tolerance.

There are many ETL pipelines and task automation tools available, ranging from open-source solutions to commercial products. Some of the most common ETL tools include

Apache Airflow: is an open-source platform for programmatically authoring, scheduling, and monitoring workflows. It provides a way to create, execute, and manage complex data pipelines that integrate data from multiple sources and systems. Airflow uses Python scripts to define tasks and dependencies in a workflow, which are organized into a directed acyclic graph (DAG) where each step would represent a specific data engineering task.

Microsoft SQL Server Integration Services (SSIS): SSIS is a data integration and ETL platform introduced with SQL Server 2005 and is used for on-premises SQL Server deployments. In 2015, Azure Data Factory (ADF) was introduced as a cloud-based no-code data integration service to meet the increasing demand for cloud-based data processing.

Google Cloud Dataflow: Google Cloud Dataflow is a fully managed, cloud-based data processing service for batch and streaming data. It is built on Apache Beam, an open-source unified programming model for defining and executing data processing pipelines. With Cloud Dataflow, users can develop and execute data processing pipelines in a fully managed and optimized environment, without the need for infrastructure management.

AWS Glue: AWS Glue is a fully managed, serverless ETL (Extract, Transform, Load) service provided by Amazon Web Services (AWS). It is designed to make it easy for users to extract data from a variety of sources, transform it, and then load data into data stores for analysis. AWS Glue automates the process of building ETL workflows, including data schema discovery, data transformation, and job scheduling.

4 SQL and Relational Database

SQL (Structured Query Language) is a domain-specific language that is used to manage and manipulate data within relational database management systems (RDBMS). It is designed to be declarative, meaning that users specify what they want the database to do, rather than how to do it.

SQL plays a crucial role in ETL processes. It enables data analysts and developers to extract data from various sources, transform and manipulate it to fit the target system’s schema, and then load it into the destination database or data warehouse, giving way for various advanced use cases such as Machine learning and AI applications.

SQL’s ability to handle complex data transformations and queries makes it an essential tool for ETL operations.

4.1 SQL Syntax

Several standard SQL commands can be used to interact with a database. Here are some of the most common ones:

SELECT: retrieve data from a table or view

INSERT: insert data into a table

UPDATE: update existing data in a table

DELETE: delete data from a table

CREATE: create a new table, view, or other database object

ALTER: modify an existing table, view, or other database object

DROP: delete an existing table, view, or other database object

TRUNCATE: delete all data from a table, but keep the structure intact

These commands are often combined in various ways to create more complex SQL statements, such as JOINs, subqueries, and aggregate functions.

4.2 Basics of Relational Database

A relational database (RDB) is a way of structuring information in tables, rows, and columns. An RDB can establish links—or relationships–between information by joining tables, which makes it easy to understand and gain insights into the relationship between various data points.

Think of the relational database as a collection of spreadsheet files that help businesses organize, manage, and relate data. In the relational database model, each “spreadsheet” is a table that stores information, represented as columns (attributes) and rows (records or tuples).

Attributes (columns) specify a data type

Record (or row) contains the value of that specific data type

Primary key All tables in a relational database have an attribute known as the primary key is a unique identifier of a row.

foreign key Each row can be used to create a relationship between different tables using a foreign key — a reference to a primary key of another existing table.

The following figure shows the basic structure of a relational database.

include_graphics("img/RelationalDatabaseStructure.png")
Data integration approache: API

Data integration approache: API

LS0tDQp0aXRsZTogIkRhdGEgQWNxdWlzaXRpb24gYW5kIEludGVncmF0aW9uIg0KZGF0ZTogIkNoZW5nIFBlbmciDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiA0DQogICAgZmlnX2hlaWdodDogMw0KZWRpdG9yX29wdGlvbnM6DQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCi0tLQ0KDQoNCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogVGFibGUgb2YgY29udGVudCAtIG5hdmlnYXRpb24gKi8NCmRpdiNUT0MgbGkgew0KICAgIGxpc3Qtc3R5bGU6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0Z3JheTsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogICAgY29sb3I6ICM3ODBjMGM7DQp9DQoNCg0KLyogVGl0bGUgZm9udHMgKi8NCmgxLnRpdGxlIHsNCiAgZm9udC1zaXplOiAyNHB4Ow0KICBjb2xvcjogZGFya2JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IA0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IGRhcmtibHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCi8qIFNlY3Rpb24gaGVhZGVycyAqLw0KaDEgew0KICAgIGZvbnQtc2l6ZTogMjJweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMiB7DQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsNCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogRGVjb3JhdGlvbiBvZiBoeXBlcmxpbmtzICAqLw0KDQovKiB1bnZpc2l0ZWQgbGluayAqLw0KYTpsaW5rIHsNCiAgY29sb3I6IGdyZWVuOw0KfQ0KDQovKiB2aXNpdGVkIGxpbmsgKi8NCmE6dmlzaXRlZCB7DQogIGNvbG9yOiBwdXJwbGU7DQp9DQoNCi8qIG1vdXNlIG92ZXIgbGluayAqLw0KYTpob3ZlciB7DQogIGNvbG9yOiByZWQ7DQp9DQoNCi8qIHNlbGVjdGVkIGxpbmsgKi8NCmE6YWN0aXZlIHsNCiAgY29sb3I6IHllbGxvdzsNCn0NCjwvc3R5bGU+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpvcHRpb25zKHJlcG9zID0gbGlzdChDUkFOPSJodHRwOi8vY3Jhbi5yc3R1ZGlvLmNvbS8iKSkNCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KDQpcDQoNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhlIGxvZ2ljYWwgcHJvY2VzcyBmb3Igc29sdmluZyBzdGF0aXN0aWNzIHByb2JsZW1zIGZvbGxvd3MgdGhlIGJhc2ljIHN0ZXBzIA0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iMzUlIiwgb3V0LndpZHRoPSI3MCUiLCBmaWcuY2FwPSJTdGF0aXN0aWNhbCBwcm9ibGVtIHNvbHZpbmcgcHJvY2VzcyJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvU3RhdHNQcm9jZXNzLnBuZyIpDQpgYGANCg0KSW4gdGVhY2hpbmcgc3RhdGlzdGljcyBjb3Vyc2VzLCB0aGUgcmVhc29uaW5nIHByb2Nlc3MgdXNlZCBpbiBjb3Vyc2UgcHJvamVjdHMgaXMNCg0KKiBMZWFybiBhIG5ldyBtZXRob2QvbW9kZWwNCg0KKiBGaW5kICoqcHJlLXByb2Nlc3NlZCBkYXRhIHNldHMqKiBvciBjb2xsZWN0ICoqZGF0YSBiYXNlZCBvbiB0aGUgZGVzaWduIG9mIGV4cGVyaW1lbnQqKi4NCg0KKiBmb3JtdWxhdGUgcXVlc3Rpb25zIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGUgZGF0YSBzZXRzIHRoYXQgY2FuIGJlIGFkZHJlc3NlZCBieSB0aGUgbmV3IG1ldGhvZHMvbW9kZWxzIGFuZCBwcmV2aW91c2x5IGxlYXJuZWQgbWV0aG9kcy9tb2RlbHMuICoqVGhlc2UgbWV0aG9kcyAvIG1vZGVscyBhcmUgYmFzZWQgb24gaS5pLmQuIGRhdGEgYW5kIGNlcnRhaW4gZGlzdHJpYnV0aW9uYWwgYXNzdW1wdGlvbnMqKiBzdWNoIGFzIG5vcm1hbCwgYmlub21pYWwsIHNuZCBQb2lzc29uIGRpc3RyaWJ1dGlvbnMuDQoNCiogUGVyZm9ybSB0aGUgYW5hbHlzaXMNCg0KKiBSZXBvcnQgdGhlIHJlc3VsdHMgYW5kIG1ha2UgcmVjb21tZW5kYXRpb25zLg0KDQoNCg0KSW4gdGhlIHJlYWwgd29ybGQgZGF0YSBzY2llbmNlIHByb2Nlc3Mgd2hpY2ggdXN1YWxseSBkZWFscyB3aXRoIGNvbXBsZXggZGF0YSB0aGF0IGNvdWxkIGJlIGxhcmdlIGluIHNpemUsIGNvbXBsZXggaW4gdGVybXMgb2YgZGF0YSB0eXBlcywgYW5kIGRhdGEgZ2VuZXJhdGlvbiBwcm9jZXNzLCBwcm9qZWN0cyBzdGFydCB3aXRoIGEgdmFndWUgYnVzaW5lc3MgcXVlc3Rpb24gc3VjaCBhcyAqV2h5IG91ciBzYWxlcyBhcmUgZGVjbGluaW5nIGluIHRoZSBOb3J0aGVhc3QgcmVnaW9uKiwgKmhvdyB0byByZWR1Y2UgZnJhdWQgbG9zcyosIGV0Yy4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI2MCUiLCBvdXQud2lkdGg9IjgwJSIsIGZpZy5jYXA9ICJEYXRhIHNjaWVuY2UgcHJvYmxlbSBzb2x2aW5nIHByb2Nlc3MifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL0RTLXByb2Nlc3MucG5nIikNCmBgYA0KDQpUaGF0IGlzIHJlYWwtd29ybGQgcHJvamVjdHMgc3RhcnQgd2l0aCBhIHZhZ3VlIGJ1c2luZXNzIHF1ZXN0aW9uIHF1ZXN0aW9uIHdpdGggbm8gZGF0YSEgV2UgbmVlZCB0byBnYWluIGEgY2xlYXIgYnVzaW5lc3MgdW5kZXJzdGFuZGluZyBvZiB0aGUgcHJvYmxlbSB0byBmb3JtdWxhdGUgY2xlYXIgYnVzaW5lc3MgcHJvYmxlbXMgYW5kIHRoZW4gY29udmVydCB0aGUgKipjbGVhciBidXNpbmVzcyBwcm9ibGVtKiogdG8gKiphbiBhbmFseXRpYyBwcm9ibGVtKiouIFdpdGggdGhlIGNsZWFyIGFuYWx5dGljIHByb2JsZW0gYW5kIGFuYWx5dGljIGJhY2tncm91bmQgb2YgdGhlIG1lbWJlcnMgb2YgdGhlIHByb2plY3QgdGVhbSwgZGF0YSBzY2llbnRpc3RzIGFuZCBkYXRhIHNjaWVudGlzdHMgd2lsbCBnYXRoZXIgcmVsZXZhbnQgaW5mb3JtYXRpb24gdG8gcGVyZm9ybSBhbmFseXNpcy4gDQoNClRoZSBuYXR1cmUgb2YgaW5kdXN0cnkgZGF0YSB1c2VkIGluIGRhdGEgc2NpZW5jZSBwcm9qZWN0cyBpcyBkaWZmZXJlbnQgZnJvbSB0aGF0IHVzZWQgaW4gY2xhc3NpY2FsIHByb2plY3RzOiBsYXJnZSBzaXplLCBtb3N0IGxpa2VseSBub24taS5pLmQsIG1hY2hpbmUtZ2VuZXJhdGVkLCBub24tZXhwZXJpbWVudGFsIGRlc2lnbiBnZW5lcmF0ZWQsIGV0Yy4gVGhlc2UgdHlwZXMgb2YgZGF0YSBhcmUgbm90IGFwcHJvcHJpYXRlIGZvciBjbGFzc2ljYWwgbW9kZWxpbmcuIE1vcmVvdmVyLCB0aGUgZGF0YSBpcyBnZW5lcmF0ZWQgZnJvbSBkaWZmZXJlbnQgc291cmNlcyBpbiBkaWZmZXJlbnQgZm9ybWF0cyBhbmQgc3RvcmVkIGluIHBsYWNlcyAob24tcHJlbWlzZSwgY2xvdWQsIG9yIGh5YnJpZCkuIFRoaXMgcmVxdWlyZXMgYmFzaWMga25vd2xlZGdlIG9mIG9yZ2FuaXphdGlvbmFsIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgYW5kIGFyY2hpdGVjdHVyZS4gVGhpcyBub3RlIG91dGxpbmVzIHRoZSBpZGVhIG9mIG9yZ2FuaXphdGlvbmFsIGRhdGEgYWNxdWlzaXRpb24gYW5kIGludGVncmF0aW9uLg0KDQoNCiMgRGF0YSBBcmNoaXRlY3R1cmUgYW5kIERhdGEgSW5mcmFzdHJ1Y3R1cmUNCg0KRGF0YSBJbmZyYXN0cnVjdHVyZSBpcyB0aGUgZGlnaXRhbCBpbmZyYXN0cnVjdHVyZSBidWlsdCB0byBtYW5hZ2UsIHN0b3JlLCBhbmQgcHJvY2VzcyBkYXRhLiBUaGlzIGluY2x1ZGVzIGRhdGFiYXNlcywgZGF0YSB3YXJlaG91c2VzLCBzZXJ2ZXJzLCBoYXJkd2FyZSBhbmQgc29mdHdhcmUsIG5ldHdvcmsgZXF1aXBtZW50LCBhbmQgZGF0YSBjZW50ZXJzLiBJdCdzIHRoZSBmb3VuZGF0aW9uIHVwb24gd2hpY2ggZGF0YSBtYW5hZ2VtZW50IHN0cmF0ZWd5IGlzIGJ1aWx0LiANCg0KIyMgRGF0YSBBcmNoaXRlY3R1cmUNCg0KQSBkYXRhIGFyY2hpdGVjdHVyZSBkZXNjcmliZXMgaG93IGRhdGEgaXMgbWFuYWdlZC1mcm9tIGNvbGxlY3Rpb24gdGhyb3VnaCB0cmFuc2Zvcm1hdGlvbiwgZGlzdHJpYnV0aW9uLCBhbmQgY29uc3VtcHRpb24uIEl0IHNldHMgdGhlIGJsdWVwcmludCBmb3IgZGF0YSBhbmQgdGhlIHdheSBpdCBmbG93cyB0aHJvdWdoIGRhdGEgc3RvcmFnZSBzeXN0ZW1zLiAgRGF0YSBMYWtlIC0+IERhdGEgV2FyZWhvdXNlIC0+IERhdGEgTWFydA0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC5oZWlnaHQ9IjYwJSIsIG91dC53aWR0aD0iODAlIiwgZmlnLmNhcD0gIkEgZGVtb25zdHJhdGlvbiBvZiBhIHNpbXBsZSBkYXRhIGFyY2hpdGVjdHVyZSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRGF0YUFyY2hpdGVjdHVyZS5wbmciKQ0KYGBgDQoNClRocmVlIGNvbXBvbmVudHMgb2YgZGF0YSBhcmNoaXRlY3R1cmUgYXJlIGRhdGEgbGFrZSwgZGF0YSB3YXJlaG91c2UsIGRhdGEgbWFydDoNCg0KKipEYXRhIExha2UqKjogaG9sZHMgYW4gb3JpZ2luYWwgY29weSBvZiBkYXRhIHByb2R1Y2VkIGluIHRoZSBidXNpbmVzcy4gRGF0YSBwcm9jZXNzaW5nIGZyb20gdGhlIG9yaWdpbmFsIHNob3VsZCBiZSBtaW5pbWFsIGlmIGFueTsgb3RoZXJ3aXNlLCBpbiBjYXNlIHNvbWUgZGF0YSBwcm9jZXNzaW5nIHR1cm5zIG91dCB0byBiZSB3cm9uZyBpbiB0aGUgZW5kLCBpdCB3aWxsIG5vdCBiZSBwb3NzaWJsZSB0byBmaXggdGhlIGVycm9yIHJldHJvc3BlY3RpdmVseS4NCg0KKipEYXRhIFdhcmVob3VzZSoqOiBob2xkcyBkYXRhIHByb2Nlc3NlZCBhbmQgc3RydWN0dXJlZCBieSBhIG1hbmFnZWQgZGF0YSBtb2RlbCwgcmVmbGVjdGluZyB0aGUgZ2xvYmFsIChub3Qgc3BlY2lmaWMpIGRpcmVjdGlvbiBvZiB0aGUgZmluYWwgdXNlIG9mIHRoZSBkYXRhLiBJbiBtYW55IGNhc2VzLCB0aGUgZGF0YSBpcyBpbiB0YWJ1bGFyIGZvcm1hdC4NCg0KKipEYXRhIE1hcnQqKjogaG9sZHMgYSBwYXJ0IGFuZC9vciBhZ2dyZWdhdGVkIGRhdGEgc2V0IGZvciB0aGUgdXNlIG9mIGEgcGFydGljdWxhciBidXNpbmVzcyBmdW5jdGlvbiwgZS5nLiBzcGVjaWZpYyBidXNpbmVzcyB1bml0IG9yIHNwZWNpZmljIGdlb2dyYXBoaWNhbCBhcmVhLiBBIHR5cGljYWwgZXhhbXBsZSBpcyB3aGVuIHdlIHByZXBhcmUgdGhlIHN1bW1hcnkgb2YgS1BJcyBmb3IgYSBzcGVjaWZpYyBidXNpbmVzcyBsaW5lIGZvbGxvd2VkIGJ5IHZpc3VhbGl6YXRpb24gaW4gYSBCSSB0b29sLiBFc3BlY2lhbGx5LCBwcmVwYXJpbmcgdGhpcyBraW5kIG9mIHNlcGFyYXRlIGFuZCBpbmRlcGVuZGVudCBjb21wb25lbnQgYWZ0ZXIgdGhlIHdhcmVob3VzZSBpcyB3b3J0aHdoaWxlIHdoZW4gdGhlIHVzZXIgd2FudHMgdGhlIGRhdGEgbWFydCAqKnJlZ3VsYXJseSBhbmQgZnJlcXVlbnRseSB1cGRhdGVkKiouIE9uIHRoZSBjb250cmFyeSwgdGhpcyBwb3J0aW9uIGNhbiBiZSBza2lwcGVkIGluIGNhc2VzIHdoZXJlIHRoZSB1c2VyIG9ubHkgd2FudHMgc29tZSBzZXQgb2YgZGF0YSBmb3IgYWQgaG9jIGFuYWx5c2lzIGRvbmUgb25seSBvbmNlLg0KDQoNClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3Mgd2hvIGNyZWF0ZXMvbWFpbnRhaW5zIGFuZCB1c2VzIHRoZXNlIGNvbXBvbmVudHMgaW4gdGhlIGFyY2hpdGVjdHVyZS4NCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC5oZWlnaHQ9IjgwJSIsIG91dC53aWR0aD0iMTAwJSIsIGZpZy5jYXA9ICJTdW1tYXJ5IG9mIGRhdGEgYXJjaGl0ZWN0dXJlIGNvbXBvbmVudHMifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL1VzZW9mRGF0YUluZnJhc3RydWN0dXJlLnBuZyIpDQpgYGANCg0KDQojIyBQdXJwb3NlIG9mIERhdGEgSW5mcmFzdHJ1Y3R1cmUNCg0KRGlmZmVyZW50IGNvbXBhbmllcyB3aXRoIGRpZmZlcmVudCB1c2VzIGFuZCBnb2FscyBuZWVkIGRpZmZlcmVudCB0ZWNobm9sb2dpY2FsIGFwcHJvYWNoZXMgYW5kIHRvb2xzLiBDb21wYW5pZXMgaW52ZXN0IGluIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgaW4gc2V2ZXJhbCBhcmVhcy4NCg0KKipEYXRhIGNvbGxlY3Rpb24qKjogY29tcGFuaWVzIGNhbiBzZXQgdXAgbWFueSBkYXRhIGNvbGxlY3Rpb24gc3lzdGVtcyB0aGVtc2VsdmVzIG9yIGNvbGxhYm9yYXRlIHdpdGggYSBkYXRhIGNvbXBhbnkuDQoNCioqRGF0YSBzdG9yYWdlKio6IHdpdGggdGhlIGV4cGxvc2lvbiBvZiB0aGUgdm9sdW1lIG9mIGRhdGEgZ2VuZXJhdGVkIGFuZCBzdG9yZWQsIGNvbXBhbmllcyBuZWVkIHNvcGhpc3RpY2F0ZWQgYnV0IGFjY2Vzc2libGUgc3lzdGVtcyBhbmQgdG9vbHMuIFRoZXkgaW5jbHVkZSBhIGRhdGEgd2FyZWhvdXNlLCBkYXRhIGxha2UsIGRpc3RyaWJ1dGVkL2Nsb3VkLWJhc2VkIHN0b3JhZ2Ugc3lzdGVtLCBjb21wYW55IHNlcnZlciwgYW5kIGNvbXB1dGVyIGhhcmQgZGlzay4NCg0KKipEYXRhIEFuYWx5dGljcyoqOiBDb21wYW5pZXMgdXNlIHByb2dyYW1taW5nIGxhbmd1YWdlcyBhbmQgcGxhdGZvcm1zIHRvIHR1cm4gZGF0YSBpbnRvIGluc2lnaHRzLiBEYXRhIGFuYWx5c2lzIGludm9sdmVzIHRocmVlIG1haW4gYmFzaWMgc3RlcHM6IDEpIGRhdGEgcHJlcGFyYXRpb24gKGRhdGEgaW50ZWdyYXRpb24pLCAyKSBtb2RlbCBidWlsZGluZyBhbmQgaW5zaWdodHMgZXh0cmFjdGlvbiwgYW5kIDMpIGltcGxlbWVudGF0aW9uIGFuZCBpbXBsZW1lbnRhdGlvbi4NCg0KDQoqKkRhdGEgQ29tbXVuaWNhdGlvbnMqKjogVG9vbHMgZm9yIG1vcmUgZWZmZWN0aXZlIGNvbW11bmljYXRpb25zLg0KDQoNClRoZSBmb2xsb3dpbmcgZmlndXJlIHN1bW1hcml6ZXMgdGhlc2Uga2V5IGVsZW1lbnRzLg0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iODAlIiwgb3V0LndpZHRoPSIxMDAlIiwgZmlnLmNhcD0gIkVsZW1lbnRzIG9mIGRhdGEgYXJjaGl0ZWN0dXJlIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9FbGVtZW50c09mRGF0YUluZnJhc3RydWN0dXJlLnBuZyIpDQpgYGANCg0KDQoNCg0KIyMgVHlwZXMgb2YgRGF0YSBJbmZyYXN0cnVjdHVyZQ0KDQpUaGUgdHlwZXMgb2YgRGF0YSBJbmZyYXN0cnVjdHVyZSBjYW4gYmUgYnJvYWRseSBjYXRlZ29yaXplZCBpbiB0aGUgZm9sbG93aW5nIHdheXM6DQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iNDAlIiwgb3V0LndpZHRoPSI4MCUiLCBmaWcuY2FwPSAiVHlwZXMgb2YgZGF0YSBpbmZyYXN0cnVjdHVyZSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRGF0YUluZnJhc3RydWN0dXJlVHlwZXMucG5nIikNCmBgYA0KDQoNCioqVHJhZGl0aW9uYWwgSW5mcmFzdHJ1Y3R1cmUqKjogVGhpcyByZWZlcnMgdG8gYSBzdGFuZGFyZCBJVCBpbmZyYXN0cnVjdHVyZSB0aGF0IHVzZXMgaW4taG91c2Ugc2VydmVycywgc3RvcmFnZSBzeXN0ZW1zLCBhbmQgbmV0d29yayBkZXZpY2VzIHRvIGNvbGxlY3QsIHN0b3JlLCBwcm9jZXNzLCBhbmQgbWFuYWdlIGRhdGEuIFRoaXMga2luZCBvZiBpbmZyYXN0cnVjdHVyZSByZXF1aXJlcyBzaWduaWZpY2FudCByZXNvdXJjZXMgYW5kIHRlY2huaWNhbCBleHBlcnRpc2UgdG8gbWFuYWdlLg0KDQoqKkNsb3VkIEluZnJhc3RydWN0dXJlKio6IENsb3VkLWJhc2VkIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgdXNlcyBjbG91ZCBzdG9yYWdlIGFuZCBjb21wdXRpbmcgcmVzb3VyY2VzIHByb3ZpZGVkIGJ5IHRoaXJkLXBhcnR5IGNsb3VkIHNlcnZpY2UgcHJvdmlkZXJzLiBJdCBvZmZlcnMgc2NhbGFiaWxpdHksIGNvc3QtZWZmZWN0aXZlbmVzcywgYW5kIGNvbnZlbmllbmNlLCBlbGltaW5hdGluZyB0aGUgbmVlZCB0byBtYWludGFpbiBvbnNpdGUgc2VydmVyIHJvb21zIGFuZCBJVCBzdGFmZi4gRXhhbXBsZXMgaW5jbHVkZSBBbWF6b24gV2ViIFNlcnZpY2VzLCBNaWNyb3NvZnQgQXp1cmUsIGFuZCBHb29nbGUgQ2xvdWQgUGxhdGZvcm0uIA0KIA0KKipIeWJyaWQgSW5mcmFzdHJ1Y3R1cmUqKjogSHlicmlkIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgY29tYmluZXMgdGhlIGVsZW1lbnRzIG9mIGJvdGggdHJhZGl0aW9uYWwgYW5kIGNsb3VkIGluZnJhc3RydWN0dXJlcy4gU29tZSBkYXRhIG1heSBiZSBzdG9yZWQgb24tcHJlbWlzZXMgZm9yIHNwZWVkIGFuZCBzZWN1cml0eSBjb25zaWRlcmF0aW9ucywgd2hpbGUgb3RoZXJzIG1heSBiZSBzdG9yZWQgaW4gdGhlIGNsb3VkIGZvciBjb3N0LWVmZmVjdGl2ZW5lc3MgYW5kIHNjYWxhYmlsaXR5Lg0KQ29udmVyZ2VkIEluZnJhc3RydWN0dXJlOiBDb252ZXJnZWQgZGF0YSBpbmZyYXN0cnVjdHVyZSBwcmUtcGFja2FnZXMgbXVsdGlwbGUgSVQgY29tcG9uZW50cyBpbnRvIGEgc2luZ2xlLCBvcHRpbWl6ZWQgc29sdXRpb24uIFRoaXMgdHlwZSBpbmNsdWRlcyBzdG9yYWdlLCBzZXJ2ZXJzLCBuZXR3b3JraW5nLCBhbmQgc29mdHdhcmUgcHJvdmlzaW9uZWQgYW5kIG1hbmFnZWQgYXMgYSBzaW5nbGUgZW50aXR5Lg0KDQoqKkh5cGVyLUNvbnZlcmdlZCBJbmZyYXN0cnVjdHVyZSoqIFRoaXMgaXMgYW4gZXZvbHV0aW9uIG9mIGNvbnZlcmdlZCBpbmZyYXN0cnVjdHVyZSB3aGVyZWluIGFsbCBjb21wb25lbnRzIGFyZSBzb2Z0d2FyZS1kZWZpbmVkLCB3aXRoIHRpZ2h0IGludGVncmF0aW9uIGJldHdlZW4gdGVjaG5vbG9naWVzLCBvZmZlcmluZyBldmVuIGdyZWF0ZXIgc2ltcGxpZmljYXRpb24gYW5kIGNvc3Qgc2F2aW5ncy4NCg0KKipFZGdlIEluZnJhc3RydWN0dXJlKio6IEVkZ2UgZGF0YSBpbmZyYXN0cnVjdHVyZSBwcm9jZXNzZXMgZGF0YSBjbG9zZXIgdG8gaXRzIHNvdXJjZSwgcmVkdWNpbmcgbGF0ZW5jeSBhbmQgdHJhbnNtaXNzaW9uIGNvc3RzLiBXaXRoIHRoZSByaXNlIG9mIEludGVybmV0IG9mIFRoaW5ncyAoSW9UKSBkZXZpY2VzLCBlZGdlIGNvbXB1dGluZyBoYXMgYmVjb21lIGluY3JlYXNpbmdseSBpbXBvcnRhbnQuIA0KDQoNCg0KDQojIyBBc3BlY3RzIG9mIERhdGEgSW5mcmFzdHJ1Y3R1cmUNCg0KRGF0YSBpbmZyYXN0cnVjdHVyZSBoYXMgc2V2ZXJhbCBmdW5kYW1lbnRhbCBhc3BlY3RzIHN1cHBvcnRpbmcgZGF0YSBjb2xsZWN0aW9uLCBzdG9yYWdlLCBwcm9jZXNzaW5nLCBkaXN0cmlidXRpb24sIGFuZCB1c2FnZS4gVGhlIG1haW4gYXNwZWN0cyBvZiBkYXRhIGluZnJhc3RydWN0dXJlIGluY2x1ZGU6DQoNCg0KKipQaHlzaWNhbCBJbmZyYXN0cnVjdHVyZSoqOiBUaGlzIGNvbXByaXNlcyBoYXJkd2FyZSBjb21wb25lbnRzIGxpa2Ugc2VydmVycywgY29tcHV0ZXJzLCByb3V0ZXJzLCBhbmQgcGh5c2ljYWwgc3RvcmFnZSBkZXZpY2VzLiBJdCBjYW4gYWxzbyBpbmNsdWRlIGRhdGEgY2VudGVycyBhbmQgdGhlIHBoeXNpY2FsIGZhY2lsaXRpZXMgdGhhdCBob3VzZSB0aGUgaGFyZHdhcmUuDQoNCg0KKipTb2Z0d2FyZSBJbmZyYXN0cnVjdHVyZSoqOiBUaGlzIGluY2x1ZGVzIGRhdGFiYXNlcywgZGF0YSB3YXJlaG91c2VzLCBleHRyYWN0aW9uLCB0cmFuc2Zvcm1hdGlvbiwgYW5kIGxvYWRpbmcgKEVUTCkgdG9vbHMsIGRhdGEgYW5hbHl0aWNzIHNvZnR3YXJlLCBhbmQgb3RoZXIgYXBwbGljYXRpb25zIGFuZCBwbGF0Zm9ybXMgdGhhdCBmYWNpbGl0YXRlIGRhdGEgbWFuYWdlbWVudCwgcHJvY2Vzc2luZywgYW5kIGFuYWx5c2lzLg0KTmV0d29yayBJbmZyYXN0cnVjdHVyZTogVGhpcyBpbnZvbHZlcyB0aGUgdGVsZWNvbW11bmljYXRpb24gbmV0d29ya3MgKExBTiwgV0FOLCBJbnRlcm5ldCkgdGhhdCBlbmFibGUgZGF0YSB0cmFuc2ZlciB3aXRoaW4gYW5kIGJldHdlZW4gc3lzdGVtcywgc2VydmVycywgYW5kIHN0b3JhZ2UgZGV2aWNlcy4NCg0KDQoqKkNsb3VkIFN0b3JhZ2UqKjogV2l0aCB0ZWNobm9sb2dpY2FsIGFkdmFuY2VtZW50cywgbW9yZSBjb21wYW5pZXMgYXJlIG1vdmluZyB0aGVpciBkYXRhIGluZnJhc3RydWN0dXJlIHRvIHRoZSBjbG91ZC4gQ2xvdWQgc3RvcmFnZSBwcm92aWRlcyBhIGZsZXhpYmxlIGFuZCBzY2FsYWJsZSBzb2x1dGlvbiB0aGF0IGNhbiBiZSBleHBhbmRlZCBvciBjb250cmFjdGVkIGJhc2VkIG9uIHN0b3JhZ2UgbmVlZHMuIA0KRGF0YSBQcm9jZXNzaW5nIEZyYW1ld29ya3M6IFRoZXNlIGFyZSBzb2Z0d2FyZSBsaWJyYXJpZXMgb3IgZW5naW5lcyB0aGF0IGVuYWJsZSBsYXJnZS1zY2FsZSBkYXRhIHByb2Nlc3NpbmcuIEV4YW1wbGVzIGluY2x1ZGUgSGFkb29wLCBBcGFjaGUgU3BhcmssIGV0Yy4NCg0KDQoqKlNlY3VyaXR5IEluZnJhc3RydWN0dXJlKio6IFNlY3VyaXR5IG1lYXN1cmVzIGFyZSBlc3NlbnRpYWwgdG8gcHJvdGVjdCBkYXRhIGZyb20gdW5hdXRob3JpemVkIGFjY2VzcywgYnJlYWNoZXMsIG9yIGN5YmVyLWF0dGFja3MuIFRoZXNlIG1lYXN1cmVzIGNhbiBpbmNsdWRlIGZpcmV3YWxscywgZW5jcnlwdGlvbiBzb2Z0d2FyZSwgYW5kIHVzZXItYWNjZXNzIGNvbnRyb2xzLg0KDQoNCioqRGF0YSBHb3Zlcm5hbmNlKio6IFRoaXMgaW52b2x2ZXMgdGhlIHBvbGljaWVzLCBwcm9jZXNzZXMsIGFuZCBwcmFjdGljZXMgdG8gY29udHJvbCwgbWFuYWdlLCBhbmQgZW5zdXJlIHRoZSBxdWFsaXR5IGFuZCBwcml2YWN5IG9mIGRhdGEgYW5kIGNvbXBsaWFuY2Ugd2l0aCByZWd1bGF0aW9ucyBzdWNoIGFzIEdEUFIuDQoNCg0KKipEYXRhIEFyY2hpdGVjdHVyZSoqOiBUaGlzIGlzIHRoZSBkZXNpZ24gb3IgYmx1ZXByaW50IG9mIHRoZSBkYXRhIGluZnJhc3RydWN0dXJlLiBJdCBkZXNjcmliZXMgaG93IGFuIG9yZ2FuaXphdGlvbiBjb2xsZWN0cywgc3RvcmVzLCB0cmFuc2Zvcm1zLCBwcm9jZXNzZXMsIGFuZCBjb25zdW1lcyBkYXRhLiANCg0KDQojIERhdGEgSW50ZWdyYXRpb24NCg0KRGF0YSBpbnRlZ3JhdGlvbiByZWZlcnMgdG8gdGhlIHByb2Nlc3Mgb2YgYnJpbmdpbmcgdG9nZXRoZXIgZGF0YSBmcm9tIG11bHRpcGxlIHNvdXJjZXMgYWNyb3NzIGFuIG9yZ2FuaXphdGlvbiB0byBwcm92aWRlIGEgY29tcGxldGUsIGFjY3VyYXRlLCBhbmQgdXAtdG8tZGF0ZSBkYXRhc2V0IGZvciBkYXRhIGFuYWx5c2lzIGFuZCBvdGhlciBhcHBsaWNhdGlvbnMgYW5kIGJ1c2luZXNzIHByb2Nlc3Nlcy4gSXQgaW5jbHVkZXMgZGF0YSByZXBsaWNhdGlvbiwgaW5nZXN0aW9uLCBhbmQgdHJhbnNmb3JtYXRpb24gdG8gY29tYmluZSBkaWZmZXJlbnQgdHlwZXMgb2YgZGF0YSBpbnRvIHN0YW5kYXJkaXplZCBmb3JtYXRzIHRvIGJlIHN0b3JlZCBpbiBhIHRhcmdldCByZXBvc2l0b3J5IHN1Y2ggYXMgYSBkYXRhIHdhcmVob3VzZSwgZGF0YSBsYWtlLCBvciBkYXRhIG1hcnQuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI0MCUiLCBvdXQud2lkdGg9IjgwJSIsIGZpZy5jYXA9ICJEYXRhIGludGVncmF0aW9uIGFwcHJvYWNoZXMifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL0RhdGFJbnRlZ3JhdGlvbkFwcHJvYWNoZXMucG5nIikNCmBgYA0KDQoNCiMjIE1ham9yIERhdGEgSW50ZWdyYXRpb24gVGVjaG5pcXVlcw0KDQoNCioqRVRMKioNCg0KQW4gRVRMIHBpcGVsaW5lIGlzIGEgdHJhZGl0aW9uYWwgdHlwZSBvZiBkYXRhIHBpcGVsaW5lIHRoYXQgY29udmVydHMgcmF3IGRhdGEgdG8gbWF0Y2ggdGhlIHRhcmdldCBzeXN0ZW0gdmlhIHRocmVlIHN0ZXBzOiBleHRyYWN0LCB0cmFuc2Zvcm0sIGFuZCBsb2FkLiBEYXRhIGlzIHRyYW5zZm9ybWVkIGluIGEgc3RhZ2luZyBhcmVhIGJlZm9yZSBpdCBpcyBsb2FkZWQgaW50byB0aGUgdGFyZ2V0IHJlcG9zaXRvcnkgKHR5cGljYWxseSBhIGRhdGEgd2FyZWhvdXNlKS4gVGhpcyBhbGxvd3MgZm9yIGZhc3QgYW5kIGFjY3VyYXRlIGRhdGEgYW5hbHlzaXMgaW4gdGhlIHRhcmdldCBzeXN0ZW0gYW5kIGlzIG1vc3QgYXBwcm9wcmlhdGUgZm9yIHNtYWxsIGRhdGEgc2V0cyB0aGF0IHJlcXVpcmUgY29tcGxleCB0cmFuc2Zvcm1hdGlvbnMuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iNDAlIiwgb3V0LndpZHRoPSI2MCUiLCBmaWcuY2FwPSAiRGF0YSBpbnRlZ3JhdGlvbiBhcHByb2FjaGU6IEVUTCJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRVRMLnBuZyIpDQpgYGANCg0KKipFTFQqKg0KDQpJbiB0aGUgbW9yZSBtb2Rlcm4gRUxUIHBpcGVsaW5lLCB0aGUgZGF0YSBpcyBpbW1lZGlhdGVseSBsb2FkZWQgYW5kIHRoZW4gdHJhbnNmb3JtZWQgd2l0aGluIHRoZSB0YXJnZXQgc3lzdGVtLCB0eXBpY2FsbHkgYSBjbG91ZC1iYXNlZCBkYXRhIGxha2UsIGRhdGEgd2FyZWhvdXNlLCBvciBkYXRhIGxha2UuIFRoaXMgYXBwcm9hY2ggaXMgbW9yZSBhcHByb3ByaWF0ZSB3aGVuIGRhdGEgc2V0cyBhcmUgbGFyZ2UgYW5kIHRpbWVsaW5lc3MgaXMgaW1wb3J0YW50IHNpbmNlIGxvYWRpbmcgaXMgb2Z0ZW4gcXVpY2tlci4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI0MCUiLCBvdXQud2lkdGg9IjYwJSIsIGZpZy5jYXA9ICJEYXRhIGludGVncmF0aW9uIGFwcHJvYWNoZTogRUxUIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9FTFQucG5nIikNCmBgYA0KDQoNCioqRGF0YSBTdHJlYW1pbmcqKg0KDQpJbnN0ZWFkIG9mIGxvYWRpbmcgZGF0YSBpbnRvIGEgbmV3IHJlcG9zaXRvcnkgaW4gYmF0Y2hlcywgc3RyZWFtaW5nIGRhdGEgaW50ZWdyYXRpb24gbW92ZXMgZGF0YSBjb250aW51b3VzbHkgaW4gcmVhbCB0aW1lIGZyb20gc291cmNlIHRvIHRhcmdldC4gTW9kZXJuIGRhdGEgaW50ZWdyYXRpb24gKERJKSBwbGF0Zm9ybXMgY2FuIGRlbGl2ZXIgYW5hbHl0aWNzLXJlYWR5IGRhdGEgaW50byBzdHJlYW1pbmcgYW5kIGNsb3VkIHBsYXRmb3JtcywgZGF0YSB3YXJlaG91c2VzLCBhbmQgZGF0YSBsYWtlcy4NCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC5oZWlnaHQ9IjYwJSIsIG91dC53aWR0aD0iODAlIiwgZmlnLmNhcD0gIkRhdGEgaW50ZWdyYXRpb24gYXBwcm9hY2hlOiBTdHJlYW1pbmcifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL1N0cmVhbWluZy5wbmciKQ0KYGBgDQoNCioqQXBwbGljYXRpb24gSW50ZWdyYXRpb24qKg0KDQpBcHBsaWNhdGlvbiBpbnRlZ3JhdGlvbiAoQVBJKSBhbGxvd3Mgc2VwYXJhdGUgYXBwbGljYXRpb25zIHRvIHdvcmsgdG9nZXRoZXIgYnkgbW92aW5nIGFuZCBzeW5jaW5nIGRhdGEgYmV0d2VlbiB0aGVtLiBUaGUgbW9zdCB0eXBpY2FsIHVzZSBjYXNlIGlzIHRvIHN1cHBvcnQgb3BlcmF0aW9uYWwgbmVlZHMgc3VjaCBhcyBlbnN1cmluZyB0aGF0IHlvdXIgSFIgc3lzdGVtIGhhcyB0aGUgc2FtZSBkYXRhIGFzIHlvdXIgZmluYW5jZSBzeXN0ZW0uIFRoZXJlZm9yZSwgdGhlIGFwcGxpY2F0aW9uIGludGVncmF0aW9uIG11c3QgcHJvdmlkZSBjb25zaXN0ZW5jeSBiZXR3ZWVuIHRoZSBkYXRhIHNldHMuIEFsc28sIHRoZXNlIHZhcmlvdXMgYXBwbGljYXRpb25zIHVzdWFsbHkgaGF2ZSB1bmlxdWUgQVBJcyBmb3IgZ2l2aW5nIGFuZCB0YWtpbmcgZGF0YSBzbyBTYWFTIGFwcGxpY2F0aW9uIGF1dG9tYXRpb24gdG9vbHMgY2FuIGhlbHAgeW91IGNyZWF0ZSBhbmQgbWFpbnRhaW4gbmF0aXZlIEFQSSBpbnRlZ3JhdGlvbiBlZmZpY2llbnRseSBhbmQgYXQgc2NhbGUuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iNjAlIiwgb3V0LndpZHRoPSI4MCUiLCBmaWcuY2FwPSAiRGF0YSBpbnRlZ3JhdGlvbiBhcHByb2FjaGU6IEFQSSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvQVBJLnBuZyIpDQpgYGANCg0KDQpJbiB0aGUgbmV4dCBzZWN0aW9ucywgd2UgZGVzY3JpYmUgRVRMIGFuZCBFVEwgdG9vbHMgYnJpZWZseS4NCg0KDQojIyBFVEwNCg0KKipFVEwqKiBzdGFuZHMgZm9yIEV4dHJhY3QsIFRyYW5zZm9ybSwgTG9hZC4gSXQgaXMgYSBwcm9jZXNzIHVzZWQgaW4gZGF0YSBpbnRlZ3JhdGlvbiB0byBleHRyYWN0IGRhdGEgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIHRyYW5zZm9ybSB0aGUgZGF0YSB0byBtZWV0IHNwZWNpZmljIGJ1c2luZXNzIHJlcXVpcmVtZW50cyBhbmQgbG9hZCB0aGUgdHJhbnNmb3JtZWQgZGF0YSBpbnRvIGEgdGFyZ2V0IHN5c3RlbSwgc3VjaCBhcyBhIGRhdGEgd2FyZWhvdXNlIG9yIGEgZGF0YWJhc2UuIERhdGEgaW4gdGhlc2Ugc3lzdGVtcyBjYW4gYmUgdXNlZCB0byBwZXJmb3JtIGJ1c2luZXNzIGFuYWx5c2lzIGFuZCBnZW5lcmF0ZSBidXNpbmVzcyBJbnRlbGxpZ2VuY2UgKEJJKSByZXBvcnRzLg0KDQpUaGUgZXh0cmFjdGlvbiBwaGFzZSBpbnZvbHZlcyByZXRyaWV2aW5nIGRhdGEgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIHN1Y2ggYXMgZGF0YWJhc2VzLCBmbGF0IGZpbGVzLCB3ZWIgc2VydmljZXMsIG9yIGNsb3VkLWJhc2VkIGFwcGxpY2F0aW9ucy4gVGhlIHRyYW5zZm9ybWF0aW9uIHBoYXNlIGludm9sdmVzIGNsZWFuaW5nLCBlbnJpY2hpbmcsIGFnZ3JlZ2F0aW5nLCBvciBvdGhlcndpc2UgbW9kaWZ5aW5nIHRoZSBkYXRhIHRvIG1lZXQgdGhlIG5lZWRzIG9mIHRoZSB0YXJnZXQgc3lzdGVtLiBGaW5hbGx5LCB0aGUgbG9hZCBwaGFzZSBpbnZvbHZlcyB3cml0aW5nIHRoZSB0cmFuc2Zvcm1lZCBkYXRhIHRvIHRoZSB0YXJnZXQgc3lzdGVtLg0KDQpXaXRoIHRoZSBpbmNyZWFzaW5nIGFkb3B0aW9uIG9mIGJpZyBkYXRhIHRlY2hub2xvZ2llcywgc3VjaCBhcyBIYWRvb3AgYW5kIFNwYXJrLCBFVEwgcHJvY2Vzc2VzIGhhdmUgYmVjb21lIG1vcmUgY29tcGxleCBhbmQgcmVxdWlyZSBtb3JlIGFkdmFuY2VkIHRvb2xzIGFuZCB0ZWNobm9sb2dpZXMuIEVUTCB3b3JrZmxvd3MgaW4gYmlnIGRhdGEgb2Z0ZW4gaW52b2x2ZSBwcm9jZXNzaW5nIGRhdGEgaW4gcGFyYWxsZWwgYWNyb3NzIG11bHRpcGxlIG5vZGVzIGluIGEgZGlzdHJpYnV0ZWQgZW52aXJvbm1lbnQsIHdoaWNoIHJlcXVpcmVzIHNwZWNpYWxpemVkIHRvb2xzIHRoYXQgY2FuIGhhbmRsZSBkYXRhIHBhcnRpdGlvbmluZywgZGF0YSBzaHVmZmxpbmcsIGFuZCBmYXVsdCB0b2xlcmFuY2UuDQoNClRoZXJlIGFyZSBtYW55IEVUTCBwaXBlbGluZXMgYW5kIHRhc2sgYXV0b21hdGlvbiB0b29scyBhdmFpbGFibGUsIHJhbmdpbmcgZnJvbSBvcGVuLXNvdXJjZSBzb2x1dGlvbnMgdG8gY29tbWVyY2lhbCBwcm9kdWN0cy4gU29tZSBvZiB0aGUgbW9zdCBjb21tb24gRVRMIHRvb2xzIGluY2x1ZGUNCg0KKipBcGFjaGUgQWlyZmxvdyoqOiBpcyBhbiBvcGVuLXNvdXJjZSBwbGF0Zm9ybSBmb3IgcHJvZ3JhbW1hdGljYWxseSBhdXRob3JpbmcsIHNjaGVkdWxpbmcsIGFuZCBtb25pdG9yaW5nIHdvcmtmbG93cy4gSXQgcHJvdmlkZXMgYSB3YXkgdG8gY3JlYXRlLCBleGVjdXRlLCBhbmQgbWFuYWdlIGNvbXBsZXggZGF0YSBwaXBlbGluZXMgdGhhdCBpbnRlZ3JhdGUgZGF0YSBmcm9tIG11bHRpcGxlIHNvdXJjZXMgYW5kIHN5c3RlbXMuIEFpcmZsb3cgdXNlcyBQeXRob24gc2NyaXB0cyB0byBkZWZpbmUgdGFza3MgYW5kIGRlcGVuZGVuY2llcyBpbiBhIHdvcmtmbG93LCB3aGljaCBhcmUgb3JnYW5pemVkIGludG8gYSBkaXJlY3RlZCBhY3ljbGljIGdyYXBoIChEQUcpIHdoZXJlIGVhY2ggc3RlcCB3b3VsZCByZXByZXNlbnQgYSBzcGVjaWZpYyBkYXRhIGVuZ2luZWVyaW5nIHRhc2suDQoNCg0KKipNaWNyb3NvZnQgU1FMIFNlcnZlciBJbnRlZ3JhdGlvbiBTZXJ2aWNlcyAoU1NJUykqKjogU1NJUyBpcyBhIGRhdGEgaW50ZWdyYXRpb24gYW5kIEVUTCBwbGF0Zm9ybSBpbnRyb2R1Y2VkIHdpdGggU1FMIFNlcnZlciAyMDA1IGFuZCBpcyB1c2VkIGZvciBvbi1wcmVtaXNlcyBTUUwgU2VydmVyIGRlcGxveW1lbnRzLiBJbiAyMDE1LCBBenVyZSBEYXRhIEZhY3RvcnkgKEFERikgd2FzIGludHJvZHVjZWQgYXMgYSBjbG91ZC1iYXNlZCBuby1jb2RlIGRhdGEgaW50ZWdyYXRpb24gc2VydmljZSB0byBtZWV0IHRoZSBpbmNyZWFzaW5nIGRlbWFuZCBmb3IgY2xvdWQtYmFzZWQgZGF0YSBwcm9jZXNzaW5nLg0KDQoNCioqR29vZ2xlIENsb3VkIERhdGFmbG93Kio6IEdvb2dsZSBDbG91ZCBEYXRhZmxvdyBpcyBhIGZ1bGx5IG1hbmFnZWQsIGNsb3VkLWJhc2VkIGRhdGEgcHJvY2Vzc2luZyBzZXJ2aWNlIGZvciBiYXRjaCBhbmQgc3RyZWFtaW5nIGRhdGEuIEl0IGlzIGJ1aWx0IG9uIEFwYWNoZSBCZWFtLCBhbiBvcGVuLXNvdXJjZSB1bmlmaWVkIHByb2dyYW1taW5nIG1vZGVsIGZvciBkZWZpbmluZyBhbmQgZXhlY3V0aW5nIGRhdGEgcHJvY2Vzc2luZyBwaXBlbGluZXMuIFdpdGggQ2xvdWQgRGF0YWZsb3csIHVzZXJzIGNhbiBkZXZlbG9wIGFuZCBleGVjdXRlIGRhdGEgcHJvY2Vzc2luZyBwaXBlbGluZXMgaW4gYSBmdWxseSBtYW5hZ2VkIGFuZCBvcHRpbWl6ZWQgZW52aXJvbm1lbnQsIHdpdGhvdXQgdGhlIG5lZWQgZm9yIGluZnJhc3RydWN0dXJlIG1hbmFnZW1lbnQuDQoNCg0KKipBV1MgR2x1ZSoqOiBBV1MgR2x1ZSBpcyBhIGZ1bGx5IG1hbmFnZWQsIHNlcnZlcmxlc3MgRVRMIChFeHRyYWN0LCBUcmFuc2Zvcm0sIExvYWQpIHNlcnZpY2UgcHJvdmlkZWQgYnkgQW1hem9uIFdlYiBTZXJ2aWNlcyAoQVdTKS4gSXQgaXMgZGVzaWduZWQgdG8gbWFrZSBpdCBlYXN5IGZvciB1c2VycyB0byBleHRyYWN0IGRhdGEgZnJvbSBhIHZhcmlldHkgb2Ygc291cmNlcywgdHJhbnNmb3JtIGl0LCBhbmQgdGhlbiBsb2FkIGRhdGEgaW50byBkYXRhIHN0b3JlcyBmb3IgYW5hbHlzaXMuIEFXUyBHbHVlIGF1dG9tYXRlcyB0aGUgcHJvY2VzcyBvZiBidWlsZGluZyBFVEwgd29ya2Zsb3dzLCBpbmNsdWRpbmcgZGF0YSBzY2hlbWEgZGlzY292ZXJ5LCBkYXRhIHRyYW5zZm9ybWF0aW9uLCBhbmQgam9iIHNjaGVkdWxpbmcuDQoNCg0KDQojIFNRTCBhbmQgUmVsYXRpb25hbCBEYXRhYmFzZQ0KDQpTUUwgKFN0cnVjdHVyZWQgUXVlcnkgTGFuZ3VhZ2UpIGlzIGEgZG9tYWluLXNwZWNpZmljIGxhbmd1YWdlIHRoYXQgaXMgdXNlZCB0byBtYW5hZ2UgYW5kIG1hbmlwdWxhdGUgZGF0YSB3aXRoaW4gcmVsYXRpb25hbCBkYXRhYmFzZSBtYW5hZ2VtZW50IHN5c3RlbXMgKFJEQk1TKS4gSXQgaXMgZGVzaWduZWQgdG8gYmUgZGVjbGFyYXRpdmUsIG1lYW5pbmcgdGhhdCB1c2VycyBzcGVjaWZ5IHdoYXQgdGhleSB3YW50IHRoZSBkYXRhYmFzZSB0byBkbywgcmF0aGVyIHRoYW4gaG93IHRvIGRvIGl0Lg0KDQpTUUwgcGxheXMgYSBjcnVjaWFsIHJvbGUgaW4gRVRMIHByb2Nlc3Nlcy4gSXQgZW5hYmxlcyBkYXRhIGFuYWx5c3RzIGFuZCBkZXZlbG9wZXJzIHRvIGV4dHJhY3QgZGF0YSBmcm9tIHZhcmlvdXMgc291cmNlcywgdHJhbnNmb3JtIGFuZCBtYW5pcHVsYXRlIGl0IHRvIGZpdCB0aGUgdGFyZ2V0IHN5c3RlbSdzIHNjaGVtYSwgYW5kIHRoZW4gbG9hZCBpdCBpbnRvIHRoZSBkZXN0aW5hdGlvbiBkYXRhYmFzZSBvciBkYXRhIHdhcmVob3VzZSwgZ2l2aW5nIHdheSBmb3IgdmFyaW91cyBhZHZhbmNlZCB1c2UgY2FzZXMgc3VjaCBhcyBNYWNoaW5lIGxlYXJuaW5nIGFuZCBBSSBhcHBsaWNhdGlvbnMuDQoNClNRTCdzIGFiaWxpdHkgdG8gaGFuZGxlIGNvbXBsZXggZGF0YSB0cmFuc2Zvcm1hdGlvbnMgYW5kIHF1ZXJpZXMgbWFrZXMgaXQgYW4gZXNzZW50aWFsIHRvb2wgZm9yIEVUTCBvcGVyYXRpb25zLg0KDQoNCiMjIFNRTCBTeW50YXgNCg0KU2V2ZXJhbCBzdGFuZGFyZCBTUUwgY29tbWFuZHMgY2FuIGJlIHVzZWQgdG8gaW50ZXJhY3Qgd2l0aCBhIGRhdGFiYXNlLiBIZXJlIGFyZSBzb21lIG9mIHRoZSBtb3N0IGNvbW1vbiBvbmVzOg0KDQoqKlNFTEVDVCoqOiByZXRyaWV2ZSBkYXRhIGZyb20gYSB0YWJsZSBvciB2aWV3DQoNCioqSU5TRVJUKio6IGluc2VydCBkYXRhIGludG8gYSB0YWJsZQ0KDQoqKlVQREFURSoqOiB1cGRhdGUgZXhpc3RpbmcgZGF0YSBpbiBhIHRhYmxlDQoNCioqREVMRVRFKio6IGRlbGV0ZSBkYXRhIGZyb20gYSB0YWJsZQ0KDQoqKkNSRUFURSoqOiBjcmVhdGUgYSBuZXcgdGFibGUsIHZpZXcsIG9yIG90aGVyIGRhdGFiYXNlIG9iamVjdA0KDQoqKkFMVEVSKio6IG1vZGlmeSBhbiBleGlzdGluZyB0YWJsZSwgdmlldywgb3Igb3RoZXIgZGF0YWJhc2Ugb2JqZWN0DQoNCioqRFJPUCoqOiBkZWxldGUgYW4gZXhpc3RpbmcgdGFibGUsIHZpZXcsIG9yIG90aGVyIGRhdGFiYXNlIG9iamVjdA0KDQoqKlRSVU5DQVRFKio6IGRlbGV0ZSBhbGwgZGF0YSBmcm9tIGEgdGFibGUsIGJ1dCBrZWVwIHRoZSBzdHJ1Y3R1cmUgaW50YWN0DQoNClRoZXNlIGNvbW1hbmRzIGFyZSBvZnRlbiBjb21iaW5lZCBpbiB2YXJpb3VzIHdheXMgdG8gY3JlYXRlIG1vcmUgY29tcGxleCBTUUwgc3RhdGVtZW50cywgc3VjaCBhcyBKT0lOcywgc3VicXVlcmllcywgYW5kIGFnZ3JlZ2F0ZSBmdW5jdGlvbnMuDQoNCg0KIyMgQmFzaWNzIG9mIFJlbGF0aW9uYWwgRGF0YWJhc2UNCg0KQSByZWxhdGlvbmFsIGRhdGFiYXNlIChSREIpIGlzIGEgd2F5IG9mIHN0cnVjdHVyaW5nIGluZm9ybWF0aW9uIGluIHRhYmxlcywgcm93cywgYW5kIGNvbHVtbnMuIEFuIFJEQiBjYW4gZXN0YWJsaXNoIGxpbmtz4oCUb3IgcmVsYXRpb25zaGlwc+KAk2JldHdlZW4gaW5mb3JtYXRpb24gYnkgam9pbmluZyB0YWJsZXMsIHdoaWNoIG1ha2VzIGl0IGVhc3kgdG8gdW5kZXJzdGFuZCBhbmQgZ2FpbiBpbnNpZ2h0cyBpbnRvIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpb3VzIGRhdGEgcG9pbnRzLiANCg0KVGhpbmsgb2YgdGhlIHJlbGF0aW9uYWwgZGF0YWJhc2UgYXMgYSBjb2xsZWN0aW9uIG9mIHNwcmVhZHNoZWV0IGZpbGVzIHRoYXQgaGVscCBidXNpbmVzc2VzIG9yZ2FuaXplLCBtYW5hZ2UsIGFuZCByZWxhdGUgZGF0YS4gSW4gdGhlIHJlbGF0aW9uYWwgZGF0YWJhc2UgbW9kZWwsIGVhY2gg4oCcc3ByZWFkc2hlZXTigJ0gaXMgYSB0YWJsZSB0aGF0IHN0b3JlcyBpbmZvcm1hdGlvbiwgcmVwcmVzZW50ZWQgYXMgY29sdW1ucyAoYXR0cmlidXRlcykgYW5kIHJvd3MgKHJlY29yZHMgb3IgdHVwbGVzKS4gDQoNCioqQXR0cmlidXRlcyAoY29sdW1ucykqKiBzcGVjaWZ5IGEgZGF0YSB0eXBlDQoNCioqUmVjb3JkIChvciByb3cpKiogY29udGFpbnMgdGhlIHZhbHVlIG9mIHRoYXQgc3BlY2lmaWMgZGF0YSB0eXBlDQoNCioqUHJpbWFyeSBrZXkqKiAgQWxsIHRhYmxlcyBpbiBhIHJlbGF0aW9uYWwgZGF0YWJhc2UgaGF2ZSBhbiBhdHRyaWJ1dGUga25vd24gYXMgdGhlICpwcmltYXJ5IGtleSogaXMgYSAqKnVuaXF1ZSBpZGVudGlmaWVyIG9mIGEgcm93KiouDQoNCioqZm9yZWlnbiBrZXkqKiBFYWNoIHJvdyBjYW4gYmUgdXNlZCB0byBjcmVhdGUgYSByZWxhdGlvbnNoaXAgKipiZXR3ZWVuIGRpZmZlcmVudCB0YWJsZXMqKiB1c2luZyBhICpmb3JlaWduIGtleSog4oCUIGEgcmVmZXJlbmNlIHRvIGEgcHJpbWFyeSBrZXkgb2YgYW5vdGhlciBleGlzdGluZyB0YWJsZS4NCg0KDQpUaGUgZm9sbG93aW5nIGZpZ3VyZSBzaG93cyB0aGUgYmFzaWMgc3RydWN0dXJlIG9mIGEgcmVsYXRpb25hbCBkYXRhYmFzZS4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI3MCUiLCBvdXQud2lkdGg9IjcwJSIsIGZpZy5jYXA9ICJEYXRhIGludGVncmF0aW9uIGFwcHJvYWNoZTogQVBJIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9SZWxhdGlvbmFsRGF0YWJhc2VTdHJ1Y3R1cmUucG5nIikNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0K