Introduction
The logical process for solving statistics problems follows the basic
steps
include_graphics("img/StatsProcess.png")
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")
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.
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.
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")
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")
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")
Types of Data
Infrastructure
The types of Data Infrastructure can be broadly categorized in the
following ways:
include_graphics("img/DataInfrastructureTypes.png")
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.
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.
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")
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")
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 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")
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")
In the next sections, we describe ETL and ETL tools briefly.
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.
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.
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.
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")
LS0tDQp0aXRsZTogIkRhdGEgQWNxdWlzaXRpb24gYW5kIEludGVncmF0aW9uIg0KZGF0ZTogIkNoZW5nIFBlbmciDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiA0DQogICAgZmlnX2hlaWdodDogMw0KZWRpdG9yX29wdGlvbnM6DQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCi0tLQ0KDQoNCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogVGFibGUgb2YgY29udGVudCAtIG5hdmlnYXRpb24gKi8NCmRpdiNUT0MgbGkgew0KICAgIGxpc3Qtc3R5bGU6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0Z3JheTsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogICAgY29sb3I6ICM3ODBjMGM7DQp9DQoNCg0KLyogVGl0bGUgZm9udHMgKi8NCmgxLnRpdGxlIHsNCiAgZm9udC1zaXplOiAyNHB4Ow0KICBjb2xvcjogZGFya2JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IA0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IGRhcmtibHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCi8qIFNlY3Rpb24gaGVhZGVycyAqLw0KaDEgew0KICAgIGZvbnQtc2l6ZTogMjJweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMiB7DQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsNCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogRGVjb3JhdGlvbiBvZiBoeXBlcmxpbmtzICAqLw0KDQovKiB1bnZpc2l0ZWQgbGluayAqLw0KYTpsaW5rIHsNCiAgY29sb3I6IGdyZWVuOw0KfQ0KDQovKiB2aXNpdGVkIGxpbmsgKi8NCmE6dmlzaXRlZCB7DQogIGNvbG9yOiBwdXJwbGU7DQp9DQoNCi8qIG1vdXNlIG92ZXIgbGluayAqLw0KYTpob3ZlciB7DQogIGNvbG9yOiByZWQ7DQp9DQoNCi8qIHNlbGVjdGVkIGxpbmsgKi8NCmE6YWN0aXZlIHsNCiAgY29sb3I6IHllbGxvdzsNCn0NCjwvc3R5bGU+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpvcHRpb25zKHJlcG9zID0gbGlzdChDUkFOPSJodHRwOi8vY3Jhbi5yc3R1ZGlvLmNvbS8iKSkNCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KDQpcDQoNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhlIGxvZ2ljYWwgcHJvY2VzcyBmb3Igc29sdmluZyBzdGF0aXN0aWNzIHByb2JsZW1zIGZvbGxvd3MgdGhlIGJhc2ljIHN0ZXBzIA0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iMzUlIiwgb3V0LndpZHRoPSI3MCUiLCBmaWcuY2FwPSJTdGF0aXN0aWNhbCBwcm9ibGVtIHNvbHZpbmcgcHJvY2VzcyJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvU3RhdHNQcm9jZXNzLnBuZyIpDQpgYGANCg0KSW4gdGVhY2hpbmcgc3RhdGlzdGljcyBjb3Vyc2VzLCB0aGUgcmVhc29uaW5nIHByb2Nlc3MgdXNlZCBpbiBjb3Vyc2UgcHJvamVjdHMgaXMNCg0KKiBMZWFybiBhIG5ldyBtZXRob2QvbW9kZWwNCg0KKiBGaW5kICoqcHJlLXByb2Nlc3NlZCBkYXRhIHNldHMqKiBvciBjb2xsZWN0ICoqZGF0YSBiYXNlZCBvbiB0aGUgZGVzaWduIG9mIGV4cGVyaW1lbnQqKi4NCg0KKiBmb3JtdWxhdGUgcXVlc3Rpb25zIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGUgZGF0YSBzZXRzIHRoYXQgY2FuIGJlIGFkZHJlc3NlZCBieSB0aGUgbmV3IG1ldGhvZHMvbW9kZWxzIGFuZCBwcmV2aW91c2x5IGxlYXJuZWQgbWV0aG9kcy9tb2RlbHMuICoqVGhlc2UgbWV0aG9kcyAvIG1vZGVscyBhcmUgYmFzZWQgb24gaS5pLmQuIGRhdGEgYW5kIGNlcnRhaW4gZGlzdHJpYnV0aW9uYWwgYXNzdW1wdGlvbnMqKiBzdWNoIGFzIG5vcm1hbCwgYmlub21pYWwsIHNuZCBQb2lzc29uIGRpc3RyaWJ1dGlvbnMuDQoNCiogUGVyZm9ybSB0aGUgYW5hbHlzaXMNCg0KKiBSZXBvcnQgdGhlIHJlc3VsdHMgYW5kIG1ha2UgcmVjb21tZW5kYXRpb25zLg0KDQoNCg0KSW4gdGhlIHJlYWwgd29ybGQgZGF0YSBzY2llbmNlIHByb2Nlc3Mgd2hpY2ggdXN1YWxseSBkZWFscyB3aXRoIGNvbXBsZXggZGF0YSB0aGF0IGNvdWxkIGJlIGxhcmdlIGluIHNpemUsIGNvbXBsZXggaW4gdGVybXMgb2YgZGF0YSB0eXBlcywgYW5kIGRhdGEgZ2VuZXJhdGlvbiBwcm9jZXNzLCBwcm9qZWN0cyBzdGFydCB3aXRoIGEgdmFndWUgYnVzaW5lc3MgcXVlc3Rpb24gc3VjaCBhcyAqV2h5IG91ciBzYWxlcyBhcmUgZGVjbGluaW5nIGluIHRoZSBOb3J0aGVhc3QgcmVnaW9uKiwgKmhvdyB0byByZWR1Y2UgZnJhdWQgbG9zcyosIGV0Yy4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI2MCUiLCBvdXQud2lkdGg9IjgwJSIsIGZpZy5jYXA9ICJEYXRhIHNjaWVuY2UgcHJvYmxlbSBzb2x2aW5nIHByb2Nlc3MifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL0RTLXByb2Nlc3MucG5nIikNCmBgYA0KDQpUaGF0IGlzIHJlYWwtd29ybGQgcHJvamVjdHMgc3RhcnQgd2l0aCBhIHZhZ3VlIGJ1c2luZXNzIHF1ZXN0aW9uIHF1ZXN0aW9uIHdpdGggbm8gZGF0YSEgV2UgbmVlZCB0byBnYWluIGEgY2xlYXIgYnVzaW5lc3MgdW5kZXJzdGFuZGluZyBvZiB0aGUgcHJvYmxlbSB0byBmb3JtdWxhdGUgY2xlYXIgYnVzaW5lc3MgcHJvYmxlbXMgYW5kIHRoZW4gY29udmVydCB0aGUgKipjbGVhciBidXNpbmVzcyBwcm9ibGVtKiogdG8gKiphbiBhbmFseXRpYyBwcm9ibGVtKiouIFdpdGggdGhlIGNsZWFyIGFuYWx5dGljIHByb2JsZW0gYW5kIGFuYWx5dGljIGJhY2tncm91bmQgb2YgdGhlIG1lbWJlcnMgb2YgdGhlIHByb2plY3QgdGVhbSwgZGF0YSBzY2llbnRpc3RzIGFuZCBkYXRhIHNjaWVudGlzdHMgd2lsbCBnYXRoZXIgcmVsZXZhbnQgaW5mb3JtYXRpb24gdG8gcGVyZm9ybSBhbmFseXNpcy4gDQoNClRoZSBuYXR1cmUgb2YgaW5kdXN0cnkgZGF0YSB1c2VkIGluIGRhdGEgc2NpZW5jZSBwcm9qZWN0cyBpcyBkaWZmZXJlbnQgZnJvbSB0aGF0IHVzZWQgaW4gY2xhc3NpY2FsIHByb2plY3RzOiBsYXJnZSBzaXplLCBtb3N0IGxpa2VseSBub24taS5pLmQsIG1hY2hpbmUtZ2VuZXJhdGVkLCBub24tZXhwZXJpbWVudGFsIGRlc2lnbiBnZW5lcmF0ZWQsIGV0Yy4gVGhlc2UgdHlwZXMgb2YgZGF0YSBhcmUgbm90IGFwcHJvcHJpYXRlIGZvciBjbGFzc2ljYWwgbW9kZWxpbmcuIE1vcmVvdmVyLCB0aGUgZGF0YSBpcyBnZW5lcmF0ZWQgZnJvbSBkaWZmZXJlbnQgc291cmNlcyBpbiBkaWZmZXJlbnQgZm9ybWF0cyBhbmQgc3RvcmVkIGluIHBsYWNlcyAob24tcHJlbWlzZSwgY2xvdWQsIG9yIGh5YnJpZCkuIFRoaXMgcmVxdWlyZXMgYmFzaWMga25vd2xlZGdlIG9mIG9yZ2FuaXphdGlvbmFsIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgYW5kIGFyY2hpdGVjdHVyZS4gVGhpcyBub3RlIG91dGxpbmVzIHRoZSBpZGVhIG9mIG9yZ2FuaXphdGlvbmFsIGRhdGEgYWNxdWlzaXRpb24gYW5kIGludGVncmF0aW9uLg0KDQoNCiMgRGF0YSBBcmNoaXRlY3R1cmUgYW5kIERhdGEgSW5mcmFzdHJ1Y3R1cmUNCg0KRGF0YSBJbmZyYXN0cnVjdHVyZSBpcyB0aGUgZGlnaXRhbCBpbmZyYXN0cnVjdHVyZSBidWlsdCB0byBtYW5hZ2UsIHN0b3JlLCBhbmQgcHJvY2VzcyBkYXRhLiBUaGlzIGluY2x1ZGVzIGRhdGFiYXNlcywgZGF0YSB3YXJlaG91c2VzLCBzZXJ2ZXJzLCBoYXJkd2FyZSBhbmQgc29mdHdhcmUsIG5ldHdvcmsgZXF1aXBtZW50LCBhbmQgZGF0YSBjZW50ZXJzLiBJdCdzIHRoZSBmb3VuZGF0aW9uIHVwb24gd2hpY2ggZGF0YSBtYW5hZ2VtZW50IHN0cmF0ZWd5IGlzIGJ1aWx0LiANCg0KIyMgRGF0YSBBcmNoaXRlY3R1cmUNCg0KQSBkYXRhIGFyY2hpdGVjdHVyZSBkZXNjcmliZXMgaG93IGRhdGEgaXMgbWFuYWdlZC1mcm9tIGNvbGxlY3Rpb24gdGhyb3VnaCB0cmFuc2Zvcm1hdGlvbiwgZGlzdHJpYnV0aW9uLCBhbmQgY29uc3VtcHRpb24uIEl0IHNldHMgdGhlIGJsdWVwcmludCBmb3IgZGF0YSBhbmQgdGhlIHdheSBpdCBmbG93cyB0aHJvdWdoIGRhdGEgc3RvcmFnZSBzeXN0ZW1zLiAgRGF0YSBMYWtlIC0+IERhdGEgV2FyZWhvdXNlIC0+IERhdGEgTWFydA0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC5oZWlnaHQ9IjYwJSIsIG91dC53aWR0aD0iODAlIiwgZmlnLmNhcD0gIkEgZGVtb25zdHJhdGlvbiBvZiBhIHNpbXBsZSBkYXRhIGFyY2hpdGVjdHVyZSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRGF0YUFyY2hpdGVjdHVyZS5wbmciKQ0KYGBgDQoNClRocmVlIGNvbXBvbmVudHMgb2YgZGF0YSBhcmNoaXRlY3R1cmUgYXJlIGRhdGEgbGFrZSwgZGF0YSB3YXJlaG91c2UsIGRhdGEgbWFydDoNCg0KKipEYXRhIExha2UqKjogaG9sZHMgYW4gb3JpZ2luYWwgY29weSBvZiBkYXRhIHByb2R1Y2VkIGluIHRoZSBidXNpbmVzcy4gRGF0YSBwcm9jZXNzaW5nIGZyb20gdGhlIG9yaWdpbmFsIHNob3VsZCBiZSBtaW5pbWFsIGlmIGFueTsgb3RoZXJ3aXNlLCBpbiBjYXNlIHNvbWUgZGF0YSBwcm9jZXNzaW5nIHR1cm5zIG91dCB0byBiZSB3cm9uZyBpbiB0aGUgZW5kLCBpdCB3aWxsIG5vdCBiZSBwb3NzaWJsZSB0byBmaXggdGhlIGVycm9yIHJldHJvc3BlY3RpdmVseS4NCg0KKipEYXRhIFdhcmVob3VzZSoqOiBob2xkcyBkYXRhIHByb2Nlc3NlZCBhbmQgc3RydWN0dXJlZCBieSBhIG1hbmFnZWQgZGF0YSBtb2RlbCwgcmVmbGVjdGluZyB0aGUgZ2xvYmFsIChub3Qgc3BlY2lmaWMpIGRpcmVjdGlvbiBvZiB0aGUgZmluYWwgdXNlIG9mIHRoZSBkYXRhLiBJbiBtYW55IGNhc2VzLCB0aGUgZGF0YSBpcyBpbiB0YWJ1bGFyIGZvcm1hdC4NCg0KKipEYXRhIE1hcnQqKjogaG9sZHMgYSBwYXJ0IGFuZC9vciBhZ2dyZWdhdGVkIGRhdGEgc2V0IGZvciB0aGUgdXNlIG9mIGEgcGFydGljdWxhciBidXNpbmVzcyBmdW5jdGlvbiwgZS5nLiBzcGVjaWZpYyBidXNpbmVzcyB1bml0IG9yIHNwZWNpZmljIGdlb2dyYXBoaWNhbCBhcmVhLiBBIHR5cGljYWwgZXhhbXBsZSBpcyB3aGVuIHdlIHByZXBhcmUgdGhlIHN1bW1hcnkgb2YgS1BJcyBmb3IgYSBzcGVjaWZpYyBidXNpbmVzcyBsaW5lIGZvbGxvd2VkIGJ5IHZpc3VhbGl6YXRpb24gaW4gYSBCSSB0b29sLiBFc3BlY2lhbGx5LCBwcmVwYXJpbmcgdGhpcyBraW5kIG9mIHNlcGFyYXRlIGFuZCBpbmRlcGVuZGVudCBjb21wb25lbnQgYWZ0ZXIgdGhlIHdhcmVob3VzZSBpcyB3b3J0aHdoaWxlIHdoZW4gdGhlIHVzZXIgd2FudHMgdGhlIGRhdGEgbWFydCAqKnJlZ3VsYXJseSBhbmQgZnJlcXVlbnRseSB1cGRhdGVkKiouIE9uIHRoZSBjb250cmFyeSwgdGhpcyBwb3J0aW9uIGNhbiBiZSBza2lwcGVkIGluIGNhc2VzIHdoZXJlIHRoZSB1c2VyIG9ubHkgd2FudHMgc29tZSBzZXQgb2YgZGF0YSBmb3IgYWQgaG9jIGFuYWx5c2lzIGRvbmUgb25seSBvbmNlLg0KDQoNClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3Mgd2hvIGNyZWF0ZXMvbWFpbnRhaW5zIGFuZCB1c2VzIHRoZXNlIGNvbXBvbmVudHMgaW4gdGhlIGFyY2hpdGVjdHVyZS4NCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC5oZWlnaHQ9IjgwJSIsIG91dC53aWR0aD0iMTAwJSIsIGZpZy5jYXA9ICJTdW1tYXJ5IG9mIGRhdGEgYXJjaGl0ZWN0dXJlIGNvbXBvbmVudHMifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL1VzZW9mRGF0YUluZnJhc3RydWN0dXJlLnBuZyIpDQpgYGANCg0KDQojIyBQdXJwb3NlIG9mIERhdGEgSW5mcmFzdHJ1Y3R1cmUNCg0KRGlmZmVyZW50IGNvbXBhbmllcyB3aXRoIGRpZmZlcmVudCB1c2VzIGFuZCBnb2FscyBuZWVkIGRpZmZlcmVudCB0ZWNobm9sb2dpY2FsIGFwcHJvYWNoZXMgYW5kIHRvb2xzLiBDb21wYW5pZXMgaW52ZXN0IGluIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgaW4gc2V2ZXJhbCBhcmVhcy4NCg0KKipEYXRhIGNvbGxlY3Rpb24qKjogY29tcGFuaWVzIGNhbiBzZXQgdXAgbWFueSBkYXRhIGNvbGxlY3Rpb24gc3lzdGVtcyB0aGVtc2VsdmVzIG9yIGNvbGxhYm9yYXRlIHdpdGggYSBkYXRhIGNvbXBhbnkuDQoNCioqRGF0YSBzdG9yYWdlKio6IHdpdGggdGhlIGV4cGxvc2lvbiBvZiB0aGUgdm9sdW1lIG9mIGRhdGEgZ2VuZXJhdGVkIGFuZCBzdG9yZWQsIGNvbXBhbmllcyBuZWVkIHNvcGhpc3RpY2F0ZWQgYnV0IGFjY2Vzc2libGUgc3lzdGVtcyBhbmQgdG9vbHMuIFRoZXkgaW5jbHVkZSBhIGRhdGEgd2FyZWhvdXNlLCBkYXRhIGxha2UsIGRpc3RyaWJ1dGVkL2Nsb3VkLWJhc2VkIHN0b3JhZ2Ugc3lzdGVtLCBjb21wYW55IHNlcnZlciwgYW5kIGNvbXB1dGVyIGhhcmQgZGlzay4NCg0KKipEYXRhIEFuYWx5dGljcyoqOiBDb21wYW5pZXMgdXNlIHByb2dyYW1taW5nIGxhbmd1YWdlcyBhbmQgcGxhdGZvcm1zIHRvIHR1cm4gZGF0YSBpbnRvIGluc2lnaHRzLiBEYXRhIGFuYWx5c2lzIGludm9sdmVzIHRocmVlIG1haW4gYmFzaWMgc3RlcHM6IDEpIGRhdGEgcHJlcGFyYXRpb24gKGRhdGEgaW50ZWdyYXRpb24pLCAyKSBtb2RlbCBidWlsZGluZyBhbmQgaW5zaWdodHMgZXh0cmFjdGlvbiwgYW5kIDMpIGltcGxlbWVudGF0aW9uIGFuZCBpbXBsZW1lbnRhdGlvbi4NCg0KDQoqKkRhdGEgQ29tbXVuaWNhdGlvbnMqKjogVG9vbHMgZm9yIG1vcmUgZWZmZWN0aXZlIGNvbW11bmljYXRpb25zLg0KDQoNClRoZSBmb2xsb3dpbmcgZmlndXJlIHN1bW1hcml6ZXMgdGhlc2Uga2V5IGVsZW1lbnRzLg0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iODAlIiwgb3V0LndpZHRoPSIxMDAlIiwgZmlnLmNhcD0gIkVsZW1lbnRzIG9mIGRhdGEgYXJjaGl0ZWN0dXJlIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9FbGVtZW50c09mRGF0YUluZnJhc3RydWN0dXJlLnBuZyIpDQpgYGANCg0KDQoNCg0KIyMgVHlwZXMgb2YgRGF0YSBJbmZyYXN0cnVjdHVyZQ0KDQpUaGUgdHlwZXMgb2YgRGF0YSBJbmZyYXN0cnVjdHVyZSBjYW4gYmUgYnJvYWRseSBjYXRlZ29yaXplZCBpbiB0aGUgZm9sbG93aW5nIHdheXM6DQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iNDAlIiwgb3V0LndpZHRoPSI4MCUiLCBmaWcuY2FwPSAiVHlwZXMgb2YgZGF0YSBpbmZyYXN0cnVjdHVyZSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRGF0YUluZnJhc3RydWN0dXJlVHlwZXMucG5nIikNCmBgYA0KDQoNCioqVHJhZGl0aW9uYWwgSW5mcmFzdHJ1Y3R1cmUqKjogVGhpcyByZWZlcnMgdG8gYSBzdGFuZGFyZCBJVCBpbmZyYXN0cnVjdHVyZSB0aGF0IHVzZXMgaW4taG91c2Ugc2VydmVycywgc3RvcmFnZSBzeXN0ZW1zLCBhbmQgbmV0d29yayBkZXZpY2VzIHRvIGNvbGxlY3QsIHN0b3JlLCBwcm9jZXNzLCBhbmQgbWFuYWdlIGRhdGEuIFRoaXMga2luZCBvZiBpbmZyYXN0cnVjdHVyZSByZXF1aXJlcyBzaWduaWZpY2FudCByZXNvdXJjZXMgYW5kIHRlY2huaWNhbCBleHBlcnRpc2UgdG8gbWFuYWdlLg0KDQoqKkNsb3VkIEluZnJhc3RydWN0dXJlKio6IENsb3VkLWJhc2VkIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgdXNlcyBjbG91ZCBzdG9yYWdlIGFuZCBjb21wdXRpbmcgcmVzb3VyY2VzIHByb3ZpZGVkIGJ5IHRoaXJkLXBhcnR5IGNsb3VkIHNlcnZpY2UgcHJvdmlkZXJzLiBJdCBvZmZlcnMgc2NhbGFiaWxpdHksIGNvc3QtZWZmZWN0aXZlbmVzcywgYW5kIGNvbnZlbmllbmNlLCBlbGltaW5hdGluZyB0aGUgbmVlZCB0byBtYWludGFpbiBvbnNpdGUgc2VydmVyIHJvb21zIGFuZCBJVCBzdGFmZi4gRXhhbXBsZXMgaW5jbHVkZSBBbWF6b24gV2ViIFNlcnZpY2VzLCBNaWNyb3NvZnQgQXp1cmUsIGFuZCBHb29nbGUgQ2xvdWQgUGxhdGZvcm0uIA0KIA0KKipIeWJyaWQgSW5mcmFzdHJ1Y3R1cmUqKjogSHlicmlkIGRhdGEgaW5mcmFzdHJ1Y3R1cmUgY29tYmluZXMgdGhlIGVsZW1lbnRzIG9mIGJvdGggdHJhZGl0aW9uYWwgYW5kIGNsb3VkIGluZnJhc3RydWN0dXJlcy4gU29tZSBkYXRhIG1heSBiZSBzdG9yZWQgb24tcHJlbWlzZXMgZm9yIHNwZWVkIGFuZCBzZWN1cml0eSBjb25zaWRlcmF0aW9ucywgd2hpbGUgb3RoZXJzIG1heSBiZSBzdG9yZWQgaW4gdGhlIGNsb3VkIGZvciBjb3N0LWVmZmVjdGl2ZW5lc3MgYW5kIHNjYWxhYmlsaXR5Lg0KQ29udmVyZ2VkIEluZnJhc3RydWN0dXJlOiBDb252ZXJnZWQgZGF0YSBpbmZyYXN0cnVjdHVyZSBwcmUtcGFja2FnZXMgbXVsdGlwbGUgSVQgY29tcG9uZW50cyBpbnRvIGEgc2luZ2xlLCBvcHRpbWl6ZWQgc29sdXRpb24uIFRoaXMgdHlwZSBpbmNsdWRlcyBzdG9yYWdlLCBzZXJ2ZXJzLCBuZXR3b3JraW5nLCBhbmQgc29mdHdhcmUgcHJvdmlzaW9uZWQgYW5kIG1hbmFnZWQgYXMgYSBzaW5nbGUgZW50aXR5Lg0KDQoqKkh5cGVyLUNvbnZlcmdlZCBJbmZyYXN0cnVjdHVyZSoqIFRoaXMgaXMgYW4gZXZvbHV0aW9uIG9mIGNvbnZlcmdlZCBpbmZyYXN0cnVjdHVyZSB3aGVyZWluIGFsbCBjb21wb25lbnRzIGFyZSBzb2Z0d2FyZS1kZWZpbmVkLCB3aXRoIHRpZ2h0IGludGVncmF0aW9uIGJldHdlZW4gdGVjaG5vbG9naWVzLCBvZmZlcmluZyBldmVuIGdyZWF0ZXIgc2ltcGxpZmljYXRpb24gYW5kIGNvc3Qgc2F2aW5ncy4NCg0KKipFZGdlIEluZnJhc3RydWN0dXJlKio6IEVkZ2UgZGF0YSBpbmZyYXN0cnVjdHVyZSBwcm9jZXNzZXMgZGF0YSBjbG9zZXIgdG8gaXRzIHNvdXJjZSwgcmVkdWNpbmcgbGF0ZW5jeSBhbmQgdHJhbnNtaXNzaW9uIGNvc3RzLiBXaXRoIHRoZSByaXNlIG9mIEludGVybmV0IG9mIFRoaW5ncyAoSW9UKSBkZXZpY2VzLCBlZGdlIGNvbXB1dGluZyBoYXMgYmVjb21lIGluY3JlYXNpbmdseSBpbXBvcnRhbnQuIA0KDQoNCg0KDQojIyBBc3BlY3RzIG9mIERhdGEgSW5mcmFzdHJ1Y3R1cmUNCg0KRGF0YSBpbmZyYXN0cnVjdHVyZSBoYXMgc2V2ZXJhbCBmdW5kYW1lbnRhbCBhc3BlY3RzIHN1cHBvcnRpbmcgZGF0YSBjb2xsZWN0aW9uLCBzdG9yYWdlLCBwcm9jZXNzaW5nLCBkaXN0cmlidXRpb24sIGFuZCB1c2FnZS4gVGhlIG1haW4gYXNwZWN0cyBvZiBkYXRhIGluZnJhc3RydWN0dXJlIGluY2x1ZGU6DQoNCg0KKipQaHlzaWNhbCBJbmZyYXN0cnVjdHVyZSoqOiBUaGlzIGNvbXByaXNlcyBoYXJkd2FyZSBjb21wb25lbnRzIGxpa2Ugc2VydmVycywgY29tcHV0ZXJzLCByb3V0ZXJzLCBhbmQgcGh5c2ljYWwgc3RvcmFnZSBkZXZpY2VzLiBJdCBjYW4gYWxzbyBpbmNsdWRlIGRhdGEgY2VudGVycyBhbmQgdGhlIHBoeXNpY2FsIGZhY2lsaXRpZXMgdGhhdCBob3VzZSB0aGUgaGFyZHdhcmUuDQoNCg0KKipTb2Z0d2FyZSBJbmZyYXN0cnVjdHVyZSoqOiBUaGlzIGluY2x1ZGVzIGRhdGFiYXNlcywgZGF0YSB3YXJlaG91c2VzLCBleHRyYWN0aW9uLCB0cmFuc2Zvcm1hdGlvbiwgYW5kIGxvYWRpbmcgKEVUTCkgdG9vbHMsIGRhdGEgYW5hbHl0aWNzIHNvZnR3YXJlLCBhbmQgb3RoZXIgYXBwbGljYXRpb25zIGFuZCBwbGF0Zm9ybXMgdGhhdCBmYWNpbGl0YXRlIGRhdGEgbWFuYWdlbWVudCwgcHJvY2Vzc2luZywgYW5kIGFuYWx5c2lzLg0KTmV0d29yayBJbmZyYXN0cnVjdHVyZTogVGhpcyBpbnZvbHZlcyB0aGUgdGVsZWNvbW11bmljYXRpb24gbmV0d29ya3MgKExBTiwgV0FOLCBJbnRlcm5ldCkgdGhhdCBlbmFibGUgZGF0YSB0cmFuc2ZlciB3aXRoaW4gYW5kIGJldHdlZW4gc3lzdGVtcywgc2VydmVycywgYW5kIHN0b3JhZ2UgZGV2aWNlcy4NCg0KDQoqKkNsb3VkIFN0b3JhZ2UqKjogV2l0aCB0ZWNobm9sb2dpY2FsIGFkdmFuY2VtZW50cywgbW9yZSBjb21wYW5pZXMgYXJlIG1vdmluZyB0aGVpciBkYXRhIGluZnJhc3RydWN0dXJlIHRvIHRoZSBjbG91ZC4gQ2xvdWQgc3RvcmFnZSBwcm92aWRlcyBhIGZsZXhpYmxlIGFuZCBzY2FsYWJsZSBzb2x1dGlvbiB0aGF0IGNhbiBiZSBleHBhbmRlZCBvciBjb250cmFjdGVkIGJhc2VkIG9uIHN0b3JhZ2UgbmVlZHMuIA0KRGF0YSBQcm9jZXNzaW5nIEZyYW1ld29ya3M6IFRoZXNlIGFyZSBzb2Z0d2FyZSBsaWJyYXJpZXMgb3IgZW5naW5lcyB0aGF0IGVuYWJsZSBsYXJnZS1zY2FsZSBkYXRhIHByb2Nlc3NpbmcuIEV4YW1wbGVzIGluY2x1ZGUgSGFkb29wLCBBcGFjaGUgU3BhcmssIGV0Yy4NCg0KDQoqKlNlY3VyaXR5IEluZnJhc3RydWN0dXJlKio6IFNlY3VyaXR5IG1lYXN1cmVzIGFyZSBlc3NlbnRpYWwgdG8gcHJvdGVjdCBkYXRhIGZyb20gdW5hdXRob3JpemVkIGFjY2VzcywgYnJlYWNoZXMsIG9yIGN5YmVyLWF0dGFja3MuIFRoZXNlIG1lYXN1cmVzIGNhbiBpbmNsdWRlIGZpcmV3YWxscywgZW5jcnlwdGlvbiBzb2Z0d2FyZSwgYW5kIHVzZXItYWNjZXNzIGNvbnRyb2xzLg0KDQoNCioqRGF0YSBHb3Zlcm5hbmNlKio6IFRoaXMgaW52b2x2ZXMgdGhlIHBvbGljaWVzLCBwcm9jZXNzZXMsIGFuZCBwcmFjdGljZXMgdG8gY29udHJvbCwgbWFuYWdlLCBhbmQgZW5zdXJlIHRoZSBxdWFsaXR5IGFuZCBwcml2YWN5IG9mIGRhdGEgYW5kIGNvbXBsaWFuY2Ugd2l0aCByZWd1bGF0aW9ucyBzdWNoIGFzIEdEUFIuDQoNCg0KKipEYXRhIEFyY2hpdGVjdHVyZSoqOiBUaGlzIGlzIHRoZSBkZXNpZ24gb3IgYmx1ZXByaW50IG9mIHRoZSBkYXRhIGluZnJhc3RydWN0dXJlLiBJdCBkZXNjcmliZXMgaG93IGFuIG9yZ2FuaXphdGlvbiBjb2xsZWN0cywgc3RvcmVzLCB0cmFuc2Zvcm1zLCBwcm9jZXNzZXMsIGFuZCBjb25zdW1lcyBkYXRhLiANCg0KDQojIERhdGEgSW50ZWdyYXRpb24NCg0KRGF0YSBpbnRlZ3JhdGlvbiByZWZlcnMgdG8gdGhlIHByb2Nlc3Mgb2YgYnJpbmdpbmcgdG9nZXRoZXIgZGF0YSBmcm9tIG11bHRpcGxlIHNvdXJjZXMgYWNyb3NzIGFuIG9yZ2FuaXphdGlvbiB0byBwcm92aWRlIGEgY29tcGxldGUsIGFjY3VyYXRlLCBhbmQgdXAtdG8tZGF0ZSBkYXRhc2V0IGZvciBkYXRhIGFuYWx5c2lzIGFuZCBvdGhlciBhcHBsaWNhdGlvbnMgYW5kIGJ1c2luZXNzIHByb2Nlc3Nlcy4gSXQgaW5jbHVkZXMgZGF0YSByZXBsaWNhdGlvbiwgaW5nZXN0aW9uLCBhbmQgdHJhbnNmb3JtYXRpb24gdG8gY29tYmluZSBkaWZmZXJlbnQgdHlwZXMgb2YgZGF0YSBpbnRvIHN0YW5kYXJkaXplZCBmb3JtYXRzIHRvIGJlIHN0b3JlZCBpbiBhIHRhcmdldCByZXBvc2l0b3J5IHN1Y2ggYXMgYSBkYXRhIHdhcmVob3VzZSwgZGF0YSBsYWtlLCBvciBkYXRhIG1hcnQuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI0MCUiLCBvdXQud2lkdGg9IjgwJSIsIGZpZy5jYXA9ICJEYXRhIGludGVncmF0aW9uIGFwcHJvYWNoZXMifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL0RhdGFJbnRlZ3JhdGlvbkFwcHJvYWNoZXMucG5nIikNCmBgYA0KDQoNCiMjIE1ham9yIERhdGEgSW50ZWdyYXRpb24gVGVjaG5pcXVlcw0KDQoNCioqRVRMKioNCg0KQW4gRVRMIHBpcGVsaW5lIGlzIGEgdHJhZGl0aW9uYWwgdHlwZSBvZiBkYXRhIHBpcGVsaW5lIHRoYXQgY29udmVydHMgcmF3IGRhdGEgdG8gbWF0Y2ggdGhlIHRhcmdldCBzeXN0ZW0gdmlhIHRocmVlIHN0ZXBzOiBleHRyYWN0LCB0cmFuc2Zvcm0sIGFuZCBsb2FkLiBEYXRhIGlzIHRyYW5zZm9ybWVkIGluIGEgc3RhZ2luZyBhcmVhIGJlZm9yZSBpdCBpcyBsb2FkZWQgaW50byB0aGUgdGFyZ2V0IHJlcG9zaXRvcnkgKHR5cGljYWxseSBhIGRhdGEgd2FyZWhvdXNlKS4gVGhpcyBhbGxvd3MgZm9yIGZhc3QgYW5kIGFjY3VyYXRlIGRhdGEgYW5hbHlzaXMgaW4gdGhlIHRhcmdldCBzeXN0ZW0gYW5kIGlzIG1vc3QgYXBwcm9wcmlhdGUgZm9yIHNtYWxsIGRhdGEgc2V0cyB0aGF0IHJlcXVpcmUgY29tcGxleCB0cmFuc2Zvcm1hdGlvbnMuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iNDAlIiwgb3V0LndpZHRoPSI2MCUiLCBmaWcuY2FwPSAiRGF0YSBpbnRlZ3JhdGlvbiBhcHByb2FjaGU6IEVUTCJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRVRMLnBuZyIpDQpgYGANCg0KKipFTFQqKg0KDQpJbiB0aGUgbW9yZSBtb2Rlcm4gRUxUIHBpcGVsaW5lLCB0aGUgZGF0YSBpcyBpbW1lZGlhdGVseSBsb2FkZWQgYW5kIHRoZW4gdHJhbnNmb3JtZWQgd2l0aGluIHRoZSB0YXJnZXQgc3lzdGVtLCB0eXBpY2FsbHkgYSBjbG91ZC1iYXNlZCBkYXRhIGxha2UsIGRhdGEgd2FyZWhvdXNlLCBvciBkYXRhIGxha2UuIFRoaXMgYXBwcm9hY2ggaXMgbW9yZSBhcHByb3ByaWF0ZSB3aGVuIGRhdGEgc2V0cyBhcmUgbGFyZ2UgYW5kIHRpbWVsaW5lc3MgaXMgaW1wb3J0YW50IHNpbmNlIGxvYWRpbmcgaXMgb2Z0ZW4gcXVpY2tlci4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI0MCUiLCBvdXQud2lkdGg9IjYwJSIsIGZpZy5jYXA9ICJEYXRhIGludGVncmF0aW9uIGFwcHJvYWNoZTogRUxUIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9FTFQucG5nIikNCmBgYA0KDQoNCioqRGF0YSBTdHJlYW1pbmcqKg0KDQpJbnN0ZWFkIG9mIGxvYWRpbmcgZGF0YSBpbnRvIGEgbmV3IHJlcG9zaXRvcnkgaW4gYmF0Y2hlcywgc3RyZWFtaW5nIGRhdGEgaW50ZWdyYXRpb24gbW92ZXMgZGF0YSBjb250aW51b3VzbHkgaW4gcmVhbCB0aW1lIGZyb20gc291cmNlIHRvIHRhcmdldC4gTW9kZXJuIGRhdGEgaW50ZWdyYXRpb24gKERJKSBwbGF0Zm9ybXMgY2FuIGRlbGl2ZXIgYW5hbHl0aWNzLXJlYWR5IGRhdGEgaW50byBzdHJlYW1pbmcgYW5kIGNsb3VkIHBsYXRmb3JtcywgZGF0YSB3YXJlaG91c2VzLCBhbmQgZGF0YSBsYWtlcy4NCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC5oZWlnaHQ9IjYwJSIsIG91dC53aWR0aD0iODAlIiwgZmlnLmNhcD0gIkRhdGEgaW50ZWdyYXRpb24gYXBwcm9hY2hlOiBTdHJlYW1pbmcifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL1N0cmVhbWluZy5wbmciKQ0KYGBgDQoNCioqQXBwbGljYXRpb24gSW50ZWdyYXRpb24qKg0KDQpBcHBsaWNhdGlvbiBpbnRlZ3JhdGlvbiAoQVBJKSBhbGxvd3Mgc2VwYXJhdGUgYXBwbGljYXRpb25zIHRvIHdvcmsgdG9nZXRoZXIgYnkgbW92aW5nIGFuZCBzeW5jaW5nIGRhdGEgYmV0d2VlbiB0aGVtLiBUaGUgbW9zdCB0eXBpY2FsIHVzZSBjYXNlIGlzIHRvIHN1cHBvcnQgb3BlcmF0aW9uYWwgbmVlZHMgc3VjaCBhcyBlbnN1cmluZyB0aGF0IHlvdXIgSFIgc3lzdGVtIGhhcyB0aGUgc2FtZSBkYXRhIGFzIHlvdXIgZmluYW5jZSBzeXN0ZW0uIFRoZXJlZm9yZSwgdGhlIGFwcGxpY2F0aW9uIGludGVncmF0aW9uIG11c3QgcHJvdmlkZSBjb25zaXN0ZW5jeSBiZXR3ZWVuIHRoZSBkYXRhIHNldHMuIEFsc28sIHRoZXNlIHZhcmlvdXMgYXBwbGljYXRpb25zIHVzdWFsbHkgaGF2ZSB1bmlxdWUgQVBJcyBmb3IgZ2l2aW5nIGFuZCB0YWtpbmcgZGF0YSBzbyBTYWFTIGFwcGxpY2F0aW9uIGF1dG9tYXRpb24gdG9vbHMgY2FuIGhlbHAgeW91IGNyZWF0ZSBhbmQgbWFpbnRhaW4gbmF0aXZlIEFQSSBpbnRlZ3JhdGlvbiBlZmZpY2llbnRseSBhbmQgYXQgc2NhbGUuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmhlaWdodD0iNjAlIiwgb3V0LndpZHRoPSI4MCUiLCBmaWcuY2FwPSAiRGF0YSBpbnRlZ3JhdGlvbiBhcHByb2FjaGU6IEFQSSJ9DQppbmNsdWRlX2dyYXBoaWNzKCJpbWcvQVBJLnBuZyIpDQpgYGANCg0KDQpJbiB0aGUgbmV4dCBzZWN0aW9ucywgd2UgZGVzY3JpYmUgRVRMIGFuZCBFVEwgdG9vbHMgYnJpZWZseS4NCg0KDQojIyBFVEwNCg0KKipFVEwqKiBzdGFuZHMgZm9yIEV4dHJhY3QsIFRyYW5zZm9ybSwgTG9hZC4gSXQgaXMgYSBwcm9jZXNzIHVzZWQgaW4gZGF0YSBpbnRlZ3JhdGlvbiB0byBleHRyYWN0IGRhdGEgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIHRyYW5zZm9ybSB0aGUgZGF0YSB0byBtZWV0IHNwZWNpZmljIGJ1c2luZXNzIHJlcXVpcmVtZW50cyBhbmQgbG9hZCB0aGUgdHJhbnNmb3JtZWQgZGF0YSBpbnRvIGEgdGFyZ2V0IHN5c3RlbSwgc3VjaCBhcyBhIGRhdGEgd2FyZWhvdXNlIG9yIGEgZGF0YWJhc2UuIERhdGEgaW4gdGhlc2Ugc3lzdGVtcyBjYW4gYmUgdXNlZCB0byBwZXJmb3JtIGJ1c2luZXNzIGFuYWx5c2lzIGFuZCBnZW5lcmF0ZSBidXNpbmVzcyBJbnRlbGxpZ2VuY2UgKEJJKSByZXBvcnRzLg0KDQpUaGUgZXh0cmFjdGlvbiBwaGFzZSBpbnZvbHZlcyByZXRyaWV2aW5nIGRhdGEgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIHN1Y2ggYXMgZGF0YWJhc2VzLCBmbGF0IGZpbGVzLCB3ZWIgc2VydmljZXMsIG9yIGNsb3VkLWJhc2VkIGFwcGxpY2F0aW9ucy4gVGhlIHRyYW5zZm9ybWF0aW9uIHBoYXNlIGludm9sdmVzIGNsZWFuaW5nLCBlbnJpY2hpbmcsIGFnZ3JlZ2F0aW5nLCBvciBvdGhlcndpc2UgbW9kaWZ5aW5nIHRoZSBkYXRhIHRvIG1lZXQgdGhlIG5lZWRzIG9mIHRoZSB0YXJnZXQgc3lzdGVtLiBGaW5hbGx5LCB0aGUgbG9hZCBwaGFzZSBpbnZvbHZlcyB3cml0aW5nIHRoZSB0cmFuc2Zvcm1lZCBkYXRhIHRvIHRoZSB0YXJnZXQgc3lzdGVtLg0KDQpXaXRoIHRoZSBpbmNyZWFzaW5nIGFkb3B0aW9uIG9mIGJpZyBkYXRhIHRlY2hub2xvZ2llcywgc3VjaCBhcyBIYWRvb3AgYW5kIFNwYXJrLCBFVEwgcHJvY2Vzc2VzIGhhdmUgYmVjb21lIG1vcmUgY29tcGxleCBhbmQgcmVxdWlyZSBtb3JlIGFkdmFuY2VkIHRvb2xzIGFuZCB0ZWNobm9sb2dpZXMuIEVUTCB3b3JrZmxvd3MgaW4gYmlnIGRhdGEgb2Z0ZW4gaW52b2x2ZSBwcm9jZXNzaW5nIGRhdGEgaW4gcGFyYWxsZWwgYWNyb3NzIG11bHRpcGxlIG5vZGVzIGluIGEgZGlzdHJpYnV0ZWQgZW52aXJvbm1lbnQsIHdoaWNoIHJlcXVpcmVzIHNwZWNpYWxpemVkIHRvb2xzIHRoYXQgY2FuIGhhbmRsZSBkYXRhIHBhcnRpdGlvbmluZywgZGF0YSBzaHVmZmxpbmcsIGFuZCBmYXVsdCB0b2xlcmFuY2UuDQoNClRoZXJlIGFyZSBtYW55IEVUTCBwaXBlbGluZXMgYW5kIHRhc2sgYXV0b21hdGlvbiB0b29scyBhdmFpbGFibGUsIHJhbmdpbmcgZnJvbSBvcGVuLXNvdXJjZSBzb2x1dGlvbnMgdG8gY29tbWVyY2lhbCBwcm9kdWN0cy4gU29tZSBvZiB0aGUgbW9zdCBjb21tb24gRVRMIHRvb2xzIGluY2x1ZGUNCg0KKipBcGFjaGUgQWlyZmxvdyoqOiBpcyBhbiBvcGVuLXNvdXJjZSBwbGF0Zm9ybSBmb3IgcHJvZ3JhbW1hdGljYWxseSBhdXRob3JpbmcsIHNjaGVkdWxpbmcsIGFuZCBtb25pdG9yaW5nIHdvcmtmbG93cy4gSXQgcHJvdmlkZXMgYSB3YXkgdG8gY3JlYXRlLCBleGVjdXRlLCBhbmQgbWFuYWdlIGNvbXBsZXggZGF0YSBwaXBlbGluZXMgdGhhdCBpbnRlZ3JhdGUgZGF0YSBmcm9tIG11bHRpcGxlIHNvdXJjZXMgYW5kIHN5c3RlbXMuIEFpcmZsb3cgdXNlcyBQeXRob24gc2NyaXB0cyB0byBkZWZpbmUgdGFza3MgYW5kIGRlcGVuZGVuY2llcyBpbiBhIHdvcmtmbG93LCB3aGljaCBhcmUgb3JnYW5pemVkIGludG8gYSBkaXJlY3RlZCBhY3ljbGljIGdyYXBoIChEQUcpIHdoZXJlIGVhY2ggc3RlcCB3b3VsZCByZXByZXNlbnQgYSBzcGVjaWZpYyBkYXRhIGVuZ2luZWVyaW5nIHRhc2suDQoNCg0KKipNaWNyb3NvZnQgU1FMIFNlcnZlciBJbnRlZ3JhdGlvbiBTZXJ2aWNlcyAoU1NJUykqKjogU1NJUyBpcyBhIGRhdGEgaW50ZWdyYXRpb24gYW5kIEVUTCBwbGF0Zm9ybSBpbnRyb2R1Y2VkIHdpdGggU1FMIFNlcnZlciAyMDA1IGFuZCBpcyB1c2VkIGZvciBvbi1wcmVtaXNlcyBTUUwgU2VydmVyIGRlcGxveW1lbnRzLiBJbiAyMDE1LCBBenVyZSBEYXRhIEZhY3RvcnkgKEFERikgd2FzIGludHJvZHVjZWQgYXMgYSBjbG91ZC1iYXNlZCBuby1jb2RlIGRhdGEgaW50ZWdyYXRpb24gc2VydmljZSB0byBtZWV0IHRoZSBpbmNyZWFzaW5nIGRlbWFuZCBmb3IgY2xvdWQtYmFzZWQgZGF0YSBwcm9jZXNzaW5nLg0KDQoNCioqR29vZ2xlIENsb3VkIERhdGFmbG93Kio6IEdvb2dsZSBDbG91ZCBEYXRhZmxvdyBpcyBhIGZ1bGx5IG1hbmFnZWQsIGNsb3VkLWJhc2VkIGRhdGEgcHJvY2Vzc2luZyBzZXJ2aWNlIGZvciBiYXRjaCBhbmQgc3RyZWFtaW5nIGRhdGEuIEl0IGlzIGJ1aWx0IG9uIEFwYWNoZSBCZWFtLCBhbiBvcGVuLXNvdXJjZSB1bmlmaWVkIHByb2dyYW1taW5nIG1vZGVsIGZvciBkZWZpbmluZyBhbmQgZXhlY3V0aW5nIGRhdGEgcHJvY2Vzc2luZyBwaXBlbGluZXMuIFdpdGggQ2xvdWQgRGF0YWZsb3csIHVzZXJzIGNhbiBkZXZlbG9wIGFuZCBleGVjdXRlIGRhdGEgcHJvY2Vzc2luZyBwaXBlbGluZXMgaW4gYSBmdWxseSBtYW5hZ2VkIGFuZCBvcHRpbWl6ZWQgZW52aXJvbm1lbnQsIHdpdGhvdXQgdGhlIG5lZWQgZm9yIGluZnJhc3RydWN0dXJlIG1hbmFnZW1lbnQuDQoNCg0KKipBV1MgR2x1ZSoqOiBBV1MgR2x1ZSBpcyBhIGZ1bGx5IG1hbmFnZWQsIHNlcnZlcmxlc3MgRVRMIChFeHRyYWN0LCBUcmFuc2Zvcm0sIExvYWQpIHNlcnZpY2UgcHJvdmlkZWQgYnkgQW1hem9uIFdlYiBTZXJ2aWNlcyAoQVdTKS4gSXQgaXMgZGVzaWduZWQgdG8gbWFrZSBpdCBlYXN5IGZvciB1c2VycyB0byBleHRyYWN0IGRhdGEgZnJvbSBhIHZhcmlldHkgb2Ygc291cmNlcywgdHJhbnNmb3JtIGl0LCBhbmQgdGhlbiBsb2FkIGRhdGEgaW50byBkYXRhIHN0b3JlcyBmb3IgYW5hbHlzaXMuIEFXUyBHbHVlIGF1dG9tYXRlcyB0aGUgcHJvY2VzcyBvZiBidWlsZGluZyBFVEwgd29ya2Zsb3dzLCBpbmNsdWRpbmcgZGF0YSBzY2hlbWEgZGlzY292ZXJ5LCBkYXRhIHRyYW5zZm9ybWF0aW9uLCBhbmQgam9iIHNjaGVkdWxpbmcuDQoNCg0KDQojIFNRTCBhbmQgUmVsYXRpb25hbCBEYXRhYmFzZQ0KDQpTUUwgKFN0cnVjdHVyZWQgUXVlcnkgTGFuZ3VhZ2UpIGlzIGEgZG9tYWluLXNwZWNpZmljIGxhbmd1YWdlIHRoYXQgaXMgdXNlZCB0byBtYW5hZ2UgYW5kIG1hbmlwdWxhdGUgZGF0YSB3aXRoaW4gcmVsYXRpb25hbCBkYXRhYmFzZSBtYW5hZ2VtZW50IHN5c3RlbXMgKFJEQk1TKS4gSXQgaXMgZGVzaWduZWQgdG8gYmUgZGVjbGFyYXRpdmUsIG1lYW5pbmcgdGhhdCB1c2VycyBzcGVjaWZ5IHdoYXQgdGhleSB3YW50IHRoZSBkYXRhYmFzZSB0byBkbywgcmF0aGVyIHRoYW4gaG93IHRvIGRvIGl0Lg0KDQpTUUwgcGxheXMgYSBjcnVjaWFsIHJvbGUgaW4gRVRMIHByb2Nlc3Nlcy4gSXQgZW5hYmxlcyBkYXRhIGFuYWx5c3RzIGFuZCBkZXZlbG9wZXJzIHRvIGV4dHJhY3QgZGF0YSBmcm9tIHZhcmlvdXMgc291cmNlcywgdHJhbnNmb3JtIGFuZCBtYW5pcHVsYXRlIGl0IHRvIGZpdCB0aGUgdGFyZ2V0IHN5c3RlbSdzIHNjaGVtYSwgYW5kIHRoZW4gbG9hZCBpdCBpbnRvIHRoZSBkZXN0aW5hdGlvbiBkYXRhYmFzZSBvciBkYXRhIHdhcmVob3VzZSwgZ2l2aW5nIHdheSBmb3IgdmFyaW91cyBhZHZhbmNlZCB1c2UgY2FzZXMgc3VjaCBhcyBNYWNoaW5lIGxlYXJuaW5nIGFuZCBBSSBhcHBsaWNhdGlvbnMuDQoNClNRTCdzIGFiaWxpdHkgdG8gaGFuZGxlIGNvbXBsZXggZGF0YSB0cmFuc2Zvcm1hdGlvbnMgYW5kIHF1ZXJpZXMgbWFrZXMgaXQgYW4gZXNzZW50aWFsIHRvb2wgZm9yIEVUTCBvcGVyYXRpb25zLg0KDQoNCiMjIFNRTCBTeW50YXgNCg0KU2V2ZXJhbCBzdGFuZGFyZCBTUUwgY29tbWFuZHMgY2FuIGJlIHVzZWQgdG8gaW50ZXJhY3Qgd2l0aCBhIGRhdGFiYXNlLiBIZXJlIGFyZSBzb21lIG9mIHRoZSBtb3N0IGNvbW1vbiBvbmVzOg0KDQoqKlNFTEVDVCoqOiByZXRyaWV2ZSBkYXRhIGZyb20gYSB0YWJsZSBvciB2aWV3DQoNCioqSU5TRVJUKio6IGluc2VydCBkYXRhIGludG8gYSB0YWJsZQ0KDQoqKlVQREFURSoqOiB1cGRhdGUgZXhpc3RpbmcgZGF0YSBpbiBhIHRhYmxlDQoNCioqREVMRVRFKio6IGRlbGV0ZSBkYXRhIGZyb20gYSB0YWJsZQ0KDQoqKkNSRUFURSoqOiBjcmVhdGUgYSBuZXcgdGFibGUsIHZpZXcsIG9yIG90aGVyIGRhdGFiYXNlIG9iamVjdA0KDQoqKkFMVEVSKio6IG1vZGlmeSBhbiBleGlzdGluZyB0YWJsZSwgdmlldywgb3Igb3RoZXIgZGF0YWJhc2Ugb2JqZWN0DQoNCioqRFJPUCoqOiBkZWxldGUgYW4gZXhpc3RpbmcgdGFibGUsIHZpZXcsIG9yIG90aGVyIGRhdGFiYXNlIG9iamVjdA0KDQoqKlRSVU5DQVRFKio6IGRlbGV0ZSBhbGwgZGF0YSBmcm9tIGEgdGFibGUsIGJ1dCBrZWVwIHRoZSBzdHJ1Y3R1cmUgaW50YWN0DQoNClRoZXNlIGNvbW1hbmRzIGFyZSBvZnRlbiBjb21iaW5lZCBpbiB2YXJpb3VzIHdheXMgdG8gY3JlYXRlIG1vcmUgY29tcGxleCBTUUwgc3RhdGVtZW50cywgc3VjaCBhcyBKT0lOcywgc3VicXVlcmllcywgYW5kIGFnZ3JlZ2F0ZSBmdW5jdGlvbnMuDQoNCg0KIyMgQmFzaWNzIG9mIFJlbGF0aW9uYWwgRGF0YWJhc2UNCg0KQSByZWxhdGlvbmFsIGRhdGFiYXNlIChSREIpIGlzIGEgd2F5IG9mIHN0cnVjdHVyaW5nIGluZm9ybWF0aW9uIGluIHRhYmxlcywgcm93cywgYW5kIGNvbHVtbnMuIEFuIFJEQiBjYW4gZXN0YWJsaXNoIGxpbmtz4oCUb3IgcmVsYXRpb25zaGlwc+KAk2JldHdlZW4gaW5mb3JtYXRpb24gYnkgam9pbmluZyB0YWJsZXMsIHdoaWNoIG1ha2VzIGl0IGVhc3kgdG8gdW5kZXJzdGFuZCBhbmQgZ2FpbiBpbnNpZ2h0cyBpbnRvIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpb3VzIGRhdGEgcG9pbnRzLiANCg0KVGhpbmsgb2YgdGhlIHJlbGF0aW9uYWwgZGF0YWJhc2UgYXMgYSBjb2xsZWN0aW9uIG9mIHNwcmVhZHNoZWV0IGZpbGVzIHRoYXQgaGVscCBidXNpbmVzc2VzIG9yZ2FuaXplLCBtYW5hZ2UsIGFuZCByZWxhdGUgZGF0YS4gSW4gdGhlIHJlbGF0aW9uYWwgZGF0YWJhc2UgbW9kZWwsIGVhY2gg4oCcc3ByZWFkc2hlZXTigJ0gaXMgYSB0YWJsZSB0aGF0IHN0b3JlcyBpbmZvcm1hdGlvbiwgcmVwcmVzZW50ZWQgYXMgY29sdW1ucyAoYXR0cmlidXRlcykgYW5kIHJvd3MgKHJlY29yZHMgb3IgdHVwbGVzKS4gDQoNCioqQXR0cmlidXRlcyAoY29sdW1ucykqKiBzcGVjaWZ5IGEgZGF0YSB0eXBlDQoNCioqUmVjb3JkIChvciByb3cpKiogY29udGFpbnMgdGhlIHZhbHVlIG9mIHRoYXQgc3BlY2lmaWMgZGF0YSB0eXBlDQoNCioqUHJpbWFyeSBrZXkqKiAgQWxsIHRhYmxlcyBpbiBhIHJlbGF0aW9uYWwgZGF0YWJhc2UgaGF2ZSBhbiBhdHRyaWJ1dGUga25vd24gYXMgdGhlICpwcmltYXJ5IGtleSogaXMgYSAqKnVuaXF1ZSBpZGVudGlmaWVyIG9mIGEgcm93KiouDQoNCioqZm9yZWlnbiBrZXkqKiBFYWNoIHJvdyBjYW4gYmUgdXNlZCB0byBjcmVhdGUgYSByZWxhdGlvbnNoaXAgKipiZXR3ZWVuIGRpZmZlcmVudCB0YWJsZXMqKiB1c2luZyBhICpmb3JlaWduIGtleSog4oCUIGEgcmVmZXJlbmNlIHRvIGEgcHJpbWFyeSBrZXkgb2YgYW5vdGhlciBleGlzdGluZyB0YWJsZS4NCg0KDQpUaGUgZm9sbG93aW5nIGZpZ3VyZSBzaG93cyB0aGUgYmFzaWMgc3RydWN0dXJlIG9mIGEgcmVsYXRpb25hbCBkYXRhYmFzZS4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuaGVpZ2h0PSI3MCUiLCBvdXQud2lkdGg9IjcwJSIsIGZpZy5jYXA9ICJEYXRhIGludGVncmF0aW9uIGFwcHJvYWNoZTogQVBJIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9SZWxhdGlvbmFsRGF0YWJhc2VTdHJ1Y3R1cmUucG5nIikNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0K