Cloud MySQL Databases

A cloud MySQL database is a MySQL database instance hosted and managed by a cloud service provider rather than running on your local machine or on-premise servers. The database engine runs on the provider’s infrastructure, securely accessible over the internet. A cloud-hosted MySQL database (or any database for that matter) affords certain benefits, while introducing several important drawbacks as well. Let’s take a look at those benefits and drawbacks in a bit more detail before diving into the mechanisms to configure and connect to a cloud MySQL instance.

Cloud vs Local Databases

The key differences when using a cloud-hosted database versus a local database server installation are the following:

  • Infrastructure Management: The cloud provider handles server provisioning, maintenance, updates, and hardware failures
  • Scalability: Resources (CPU, memory, storage) can be adjusted dynamically based on demand
  • Dynamic Pricing: There are few upfront costs and costs are incurred based on demand
  • Availability: Built-in redundancy and failover mechanisms ensure higher availability
  • Security: Industry-standard security including encryption, network isolation, and compliance certifications
  • Backup and Recovery: Automated backup schedules with point-in-time recovery capabilities

Advantages of Cloud Databases

Operational Benefits:

  • Eliminates server administration overhead (OS updates, security patches, hardware monitoring)
  • Reduces time-to-deployment from hours/days to minutes
  • Automatic scaling prevents performance bottlenecks during traffic spikes
  • Professional monitoring and alerting systems

Reliability and Security:

  • Multi-zone replication provides fault tolerance beyond single-machine setups
  • Enterprise-grade security controls including VPC isolation and SSL/TLS encryption
  • Compliance with standards like SOC 2, ISO 27001, and GDPR
  • Regular automated backups with configurable retention periods

Cost Efficiency:

  • Pay-per-use model eliminates upfront hardware costs
  • No need for dedicated database administrators for basic operations
  • Reduced electricity and cooling costs

Disadvantages of Cloud Databases

Network Dependency and Latency

Internet Connectivity Requirements:

  • Complete dependency on internet connection for database access
  • Application becomes unusable during network outages or ISP issues
  • Local MySQL continues functioning during internet disruptions

Latency Considerations:

  • Network round-trip time adds 10-100ms+ per query depending on geographic distance
  • Cumulative effect significant for applications making many small queries
  • Local MySQL typically has <1ms latency for database operations
  • High-frequency trading, real-time gaming, or micro-service architectures particularly affected

Bandwidth Limitations:

  • Large result sets consume internet bandwidth
  • Data-intensive operations (bulk imports, complex reporting) may be slow
  • Bandwidth costs for high-traffic applications
  • Local operations use internal network speeds (gigabit+)

Cost Structure

Ongoing Operational Costs:

  • Monthly/hourly fees continue indefinitely vs one-time hardware purchase
  • Costs scale with usage, storage, and performance requirements
  • Data transfer fees for high-volume applications
  • Long-term total cost often exceeds local hardware investment
  • Failure to pay disrupts the service and may even lead to loss of data
  • Vendors may suddenly raise prices leding to unanticipated costs

Unpredictable Scaling Costs:

  • Sudden traffic spikes result in immediate cost increases
  • Difficult to budget for variable workloads
  • Premium pricing for high-performance instances
  • Additional charges for backups, monitoring, and support features

Data Control and Privacy

Data Sovereignty:

  • Operational (and possibly sensitive) data physically resides on third-party infrastructure
  • Subject to cloud provider’s data handling policies and potential breaches
  • Government access requests may affect your data without your knowledge
  • Compliance challenges in regulated industries (healthcare, finance)
  • Actual location of server hosting the database may be subject to different laws and regulations and may violate customer terms of service of service-level agreements
  • Trade or actual wars may result in loss of access to data when servers are located in different countries
  • Data privacy policies can change and may result in violations of customer terms of service

Vendor Lock-in Risks:

  • Migration complexity increases over time with custom configurations
  • Proprietary backup formats or management tools
  • Price increases difficult to avoid once heavily invested
  • Dependency on vendor’s business continuity and policy changes
  • Vendor may cease business operations suddenly

Performance Limitations

Resource Sharing:

  • Multi-tenant infrastructure means shared underlying hardware
  • “Noisy neighbor” problems where other users affect your performance
  • Less predictable performance compared to dedicated hardware
  • Limited ability to optimize hardware for specific workloads

Configuration Constraints:

  • Restricted access to advanced MySQL configuration parameters
  • Cannot install custom storage engines or modify core database behavior
  • Limited control over caching strategies and memory allocation
  • Operating system-level optimizations unavailable

Security and Access Control

Extended Attack Surface:

  • Internet-accessible endpoints create additional security risks
  • Dependency on cloud provider’s security practices
  • Shared responsibility model can create security gaps
  • Multiple authentication layers increase complexity

Limited Administrative Control:

  • Cannot implement custom security monitoring or intrusion detection
  • Restricted access to system logs and performance metrics
  • Unable to implement organization-specific security policies
  • Dependency on vendor’s incident response procedures

Technical Limitations

Customization Restrictions:

  • Cannot modify MySQL source code or install custom patches
  • Limited plugin ecosystem compared to self-managed installations
  • Restricted ability to integrate with custom monitoring or backup solutions
  • Version upgrade timing controlled by vendor, not your schedule

Development and Testing Constraints:

  • Development environments require internet connectivity
  • Difficulty doing offline development
  • Replicating exact production configurations locally may be impossible
  • Additional complexity for continuous integration pipelines
  • Database seeding and testing may be slower due to network overhead

Business Continuity Risks

Vendor Dependency:

  • Service disruptions affect your application directly
  • Limited recourse during extended outages
  • Dependent on vendor’s disaster recovery capabilities
  • Business continuity tied to third-party company’s stability

Data Portability:

  • Export/import processes for migration can be complex and time-consuming
  • Potential data format incompatibilities
  • Downtime required for migration to alternative solutions
  • Risk of data loss during migration processes

Business Case for Local Databases

While cloud-hosted database-as-a-service databases may be ideal for many use cases, a local database offers distinct advantages. Applications requiring microsecond-level latency or handling thousands of queries per second may benefit from local deployment. Industries with strict data residency requirements or air-gapped network needs are best hosted locally.

Furthermore, stable applications with predictable usage patterns running for multiple years provide predictable costs. In addition, applications requiring specific database builds (e.g., a specific MySQL version), custom storage engines, or deep system integration.

From a development perspective, locally hosted databases often provides faster iteration cycles and don’t consume costly cloud resources.

The choice between a cloud or a local database ultimately depends on weighing these disadvantages against the operational benefits. For many modern applications and business needs the cloud trade-offs are generally acceptable in view of the reduced administrative overhead and improved reliability that is often hard to replicate locally without dedicated on-staff database administrators.

Aiven Platform

Aiven is a cloud database-as-a-service (DBaaS) platform specializing in open-source data technologies. Founded in 2016, Aiven provides managed services for MySQL, PostgreSQL, Apache Kafka, Redis, and other data infrastructure components across major cloud providers (AWS, Google Cloud, Azure).

Aiven’s distinguishing features include the ability to deploy across different cloud providers from a single interface while maintaining compatibility with standard MySQL without vendor lock-in. For developers it offer comprehensive APIs, Terraform support, and CLI tools. Like other cloud database platforms, Aiven’s data centers are distributed across multiple regions for latency optimization.

Configuring MySQL on Aiven

To set up a database on Aiven requires an account with the platform.

  1. Register at aiven.io using your academic email
  2. Respond to any verification emails
  3. Create a new project (logical container for your services)
  4. Select your preferred cloud provider and region based on latency requirements

Once an account has been created you can configure a MySQL instance. Navigate to “Create Service” and configure:

  • Service type: MySQL
  • Cloud provider: AWS, Google Cloud, or Azure
  • Region: Choose based on your geographic location
  • Plan: Start with the smallest (likely free) plan (typically 1 CPU, 1GB RAM, 1GB database storage) for development
  • Service name: Use descriptive naming (e.g., “class-mysql-dev”)

Next, you need to manage network Security. Start by configuring IP whitelist in the service settings and add your development machine’s public IP. For production, use VPC peering or private networking. Whenever feasible, enable SSL/TLS enforcement for encrypted connections. Download the SSL certificate and place it in an accessible but unshared folder (and ensure that the certificate cannot be accessed by an untrusted third party as revealing the certificate is a vulnerability that can expose your database and your data).

As you scale up your database needs, create application-specific databases using the Aiven console. Rather than using the administrative user for service connections, add dedicated database users with minimal required privileges, e.g. limit access to tables and views.

Finally, add monitoring by configuring alert thresholds for CPU, memory, and connection limits. Set up automated backups with appropriate retention periods. Monitor query performance through the dashboard.

The resulting setup provides a production-ready MySQL instance with enterprise-grade reliability, security, and monitoring capabilities, allowing you to focus on application development rather than database administration.

Connecting to MySQL from R

In this section, we demonstrate how to connect to an already configured and running MySQL instance hosted on Aiven. The connection parameters are unique to the database and the ones provided below are for our sample database.

Obtaining Connection Parameters

Replace the connection parameters with your own parameter values and ensure that the MySQL service is running.

Unsecured Connection

The code below shows how to connect to the MySQL service over an unsecured (unencrypted) connection. While the connection is password protected all traffic (SQL statements and returned data) is transmitted unencrypted and can be intercepted and read. This should only be used when SSL is not available or when operating on a secured internal network.

# load required library
library(RMySQL)

# define settings
db_host_aiven <- "mysql-2b10ba46-khoury-45a7.aivencloud.com"
db_port_aiven <- 11214
db_name_aiven <- "defaultdb"
db_user_aiven <- "avnadmin"
db_pwd_aiven <- "AVNS_E13X61MnR9gGy16VLEa"

# connect to remote MySQL server and database
mydb.aiven <-  dbConnect(RMySQL::MySQL(), 
                         user = db_user_aiven, 
                         password = db_pwd_aiven,
                         dbname = db_name_aiven, 
                         host = db_host_aiven, 
                         port = db_port_aiven)

Secure Connection

If SSL mode is not used, data is not encrypted and can be exposed. To use SSL mode, add the certificate to the connection, either as path to local file or by pasting into text. However, keep in mind that if the source code is published or shared, then the certificate is also shared which likely also represents a security leak and attack vector.

You need to first download the certificate file (and keep it secure).

# load required library
library(RMySQL)

# define settings
db_host_aiven <- "mysql-2b10ba46-khoury-45a7.aivencloud.com"
db_port_aiven <- 11214
db_name_aiven <- "defaultdb"
db_user_aiven <- "avnadmin"
db_pwd_aiven <- "AVNS_E13X61MnR9gGy16VLEa"

# connect securely to remote MySQL server and database
mydb.aiven <-  dbConnect(RMySQL::MySQL(), 
                         user = db_user_aiven, 
                         password = db_pwd_aiven,
                         dbname = db_name_aiven, 
                         host = db_host_aiven, 
                         port = db_port_aiven,
                         sslmode = "require",
                         sslcert = "ca-2b10ba46.pem")

Alternatively, and to avoid having to keep the certificate in a file, we can also embed the certificate as text. Of course, if you were to distribute the source code you would expose the certificate which may not be desirable.

# load required library
library(RMySQL)

# define settings
db_host_aiven <- "mysql-2b10ba46-khoury-45a7.aivencloud.com"
db_port_aiven <- 11214
db_name_aiven <- "defaultdb"
db_user_aiven <- "avnadmin"
db_pwd_aiven <- "AVNS_E13X61MnR9gGy16VLEa"

# embedded SSL certificate
db_cert <- 
"
-----BEGIN CERTIFICATE-----
MIIEQTCCAqmgAwIBAgIUZxVjk8G5pC8kOiHVBEupNZVC1sMwDQYJKoZIhvcNAQEM
BQAwOjE4MDYGA1UEAwwvNDY2YjAxNzctODFjOC00N2EwLTlmMmQtNjMxMDYxZGYx
MDY3IFByb2plY3QgQ0EwHhcNMjMwNDExMDExNTE1WhcNMzMwNDA4MDExNTE1WjA6
MTgwNgYDVQQDDC80NjZiMDE3Ny04MWM4LTQ3YTAtOWYyZC02MzEwNjFkZjEwNjcg
UHJvamVjdCBDQTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAOp2nKQj
CPbNIr7UxSwtdjgME9Z5v/RM+qb6nj2iDPBsTuxTAfakp2MQs4ylshk3kIhPq8H/
ecr0IL2Sms02cII7JnMXrR2JheiaSciEJ7ztfdqQsL9L79ZpnTO9ZWh+HNj37YYQ
2JxscHLz+bTCW2Bg2HzWfb9UPkHQfXRf5GwGABvm4EdStue9AQTNLe+/pEK2/1Fg
kn+FBme7YgVvRSsLRuWLPMDKI213GzdEV0iJ10nFeN1lcpgq+WLWMJIqUjMkF5e9
/gC6/ZEi4SVtyWtQng/V8pmHmMczDmiJGQ7XVXNKgTy4DPtO8LK9SNNBYeqrm1J8
uCxDuukUFXmHe0b7kO1jeETbzgfBj29dDSE2IxE1UusORjO/RPQpJbe6DWOhe9Xx
KI+8hjoFARvlkKQ2C+m+GuyFuz+Yr6QJBNv1i/oexIR/1lZI34J1tEEQo4pndVDf
+Exr+gwZdL8INoFDmKxjCtCiobatreMFaETPL/nMjgmgFNeEifP7FYB/DwIDAQAB
oz8wPTAdBgNVHQ4EFgQUBCoZdr/VYezftsfHCW4zpaAPHm8wDwYDVR0TBAgwBgEB
/wIBADALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEMBQADggGBADKVSW8sIyZpTQb5
XWjeQ+I7BS7+78BlJBVPFw41H7F6nSTivkxmXl8cpTkqOAr0GeITGBI2rdJQaAxC
6hu5tdm4ClxTKnoJ0w6zk7yLtSmSCnPT2T2BI/dPsmSsplU/doeS1rGS+7GU0iGU
JN2bLqFdrg2z3JCIaszW1bsikJw3vPPORlmJl0QH81TZGCqvfINEJHY66MQb6nGj
23ZUQrLFGNmkjO5kntBSG4dopcznCS7X1f1G3MUsx5yKxpayVCeC1I+rIBroaNAJ
ga2mYbgi/8GUYb/z2fu3fmNaX7NtpH2B5OCvvMttnEF5tx4e9qss8AVMrNCcUxBi
eUgmMPy29u8dfbP7zuV/aWW0/RnYOSQRBbagwFUy/DMsBfIHDFznGqRED294hQ6q
Z0aV+QkMGduDXJhiowrrSLeN3LrC4tR16f2YYUBCqs+nz4cBx4jp/rmmAUGgGBlK
AFpY0k33VfIG0vIRz0RuwdzK0sxBGC8/jGhM/wdMuHvhJIr4XQ==
-----END CERTIFICATE-----
"

# connect securely to remote MySQL server and database
mydb.aiven <-  dbConnect(RMySQL::MySQL(), 
                         user = db_user_aiven, 
                         password = db_pwd_aiven,
                         dbname = db_name_aiven, 
                         host = db_host_aiven, 
                         port = db_port_aiven,
                         sslmode = "require",
                         sslcert = db_cert)

Next, we will test the connection by creating a table with a CHECK constraint, inserting rows, and then querying the table.

drop table if exists courses
create table if not exists courses (
  cid INTEGER NOT NULL PRIMARY KEY,
  title varchar(32) NOT NULL,
  credits INTEGER NOT NULL,
  check (credits > 1)
)

Notice that the text fields (columns) are enclosed in single quotes rather than double quotes. This is required for the version of MySQL hosted by Aiven.

insert into courses (cid,title,credits) values 
  (1100,'CS and Application', 4),
  (2000,'Princ Info Sci', 4),
  (5200,'DBMS', 4),
  (5030,'Intro ML', 3)
insert into courses values (1200,'Web Systems', 4)

Let’s ensure the data is there:

select * from courses;
Table 1: 5 records
cid title credits
1100 CS and Application 4
1200 Web Systems 4
2000 Princ Info Sci 4
5030 Intro ML 3
5200 DBMS 4
select count(*) from courses;
Table 2: 1 records
count(*)
5

Looks like all is working.

Let’s execute some SQL with Aiven using R code rather than a {sql} block.

sql <- "select * from courses"
rs <- dbGetQuery(con = mydb.aiven,
                 statement = sql)

print(rs)
##    cid              title credits
## 1 1100 CS and Application       4
## 2 1200        Web Systems       4
## 3 2000     Princ Info Sci       4
## 4 5030           Intro ML       3
## 5 5200               DBMS       4

A key drawback to MySQL on Aiven is that is does not allow bulk insertion of data via dbWriteTable(), so the code below does not work.

df <- data.frame(cid = 9000:9999)

df$title <- "no title"
df$credits <- 4

status <- dbWriteTable(mydb.aiven, "courses", df, 
                       overwrite = F, append = T, 
                       row.names=FALSE)

So, any insertion must be done using SQL INSERT statements, possibly using batch insertion (i.e., multiple rows in a single INSERT statement) to reduce the performance overhead and speed up insertion. This is not an actual issue as bulk loading is quite slow and not scalable, so it should be avoided regardless of support – although it is quite convenient.

Common Problems

  • the free account has a maximum database capacity of 5MB
  • local firewall or anti-virus software that blocks port 3306; disable if there are connection issues
  • not clicking on the activation link in the email sent after account creation (and checking spam to ensure it did not end up there)
  • no support for dbWriteTable()

A common pitfall is that your local computer has a firewall configured that does not allow a client to connect to the cloud database (meaning the port is blocked). One way to “test” for that is to run your connection code on http://posit.cloud – if it works there, then it is a problem with your local setup. Alternatively, try connecting to your MySQL from the MySQL Workbench. If you can connect from the workbench then the cause is with your client code.

CAUTION: Both Aiven and db4free do not allow the use of dbWriteTable(); this approach of bulk-loading does not scale, so it should be avoided anyway. So, you must use INSERT SQL statements to write the data into Aiven and db4free. In addition, for Aiven, all text fields must be enclosed in single rather than double quotes. Inserting data row-by-row is very slow, so insert 100 or 500 rows at a time (remember that an INSERT statement can insert multiple rows at a time).

Problem Root Cause Analysis

If you have created an account on Aiven (and configured a database) but you cannot connect, then here are some suggestions for identifying the root cause:

  1. verify that the database service is running
  2. check that the connection parameters are correct
  3. check for any firewall issues – to test this, upload the connection code (a sandbox that quickly checks) to posit.cloud and run from there; if it runs on posit.cloud and not locally, it is likely a firewall or anti-virus issue

The most common reason for not being able to connect from your client to the database, is that the server hasn’t been started. Go to the Aiven console and make sure it’s running:

Also, keep in mind:

  • Aiven does not support dbWriteTable()
  • Only recent versions of MySQL support CHECK constraints

Disconnect from Database

Disconnect from the database (important as database servers have limited numbers of connection and each connection uses a resource). Use dbDisconnect() once you no longer have a need to access the database. The code below demonstrates this.

status <- dbDisconnect(mydb.aiven)

Database Administration with MySQL Workbench

We recommend that you install MySQL Workbench to help administer your MySQL database. Use the same connection information to connect to your database from MySQL Workbench.


Files & Resources

All Files for Lesson 6.941

Acknowledgements

Claude Sonnet 4 was used in the preparation of this lesson in addition to web searches.

Errata

Let us know.

LS0tCnRpdGxlOiAiQ29uZmlndXJlIEFpdmVuIENsb3VkIE15U1FMIFNlcnZpY2UgYW5kIENvbm5lY3QgZnJvbSBSIgpwYXJhbXM6CiAgY2F0ZWdvcnk6IDYKICBudW1iZXI6IDk0MQogIHRpbWU6IDI1CiAgbGV2ZWw6IGJlZ2lubmVyCiAgdGFnczogInIsTXlTUUwsYWl2ZW4sY2xvdWQiCiAgZGVzY3JpcHRpb246ICJEZW1vbnN0cmF0ZXMgaG93IHRvIGNyZWF0ZSBhIGNsb3VkIE15U1FMIGluc3RhbmNlIG9uCiAgICAgICAgICAgICAgICBBaXZlbiBhbmQgdGhlbiBjb25uZWN0IHRvIGEgZGF0YWJhc2UgZnJvbSBSLiBFeHBsYWlucwogICAgICAgICAgICAgICAgdGhlIGtleSBjb25jZXB0cyBvZiBjbG91ZC1ob3N0ZWQgZGF0YWJhc2VzIGFuZCB0aGVpcgogICAgICAgICAgICAgICAgYmVuZWZpdHMgYW5kIGRyYXdiYWNrcy4iCmRhdGU6ICI8c21hbGw+YHIgU3lzLkRhdGUoKWA8L3NtYWxsPiIKYXV0aG9yOiAiPHNtYWxsPk1hcnRpbiBTY2hlZGxiYXVlcjwvc21hbGw+IgplbWFpbDogIm0uc2NoZWRsYmF1ZXJAbmV1LmVkdSIKYWZmaWxpdGF0aW9uOiAiTm9ydGhlYXN0ZXJuIFVuaXZlcnNpdHkiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCi0tLQp0aXRsZTogIjxzbWFsbD5gciBwYXJhbXMkY2F0ZWdvcnlgLmByIHBhcmFtcyRudW1iZXJgPC9zbWFsbD48YnIvPjxzcGFuIHN0eWxlPSdjb2xvcjogIzJFNDA1MzsgZm9udC1zaXplOiAwLjllbSc+YHIgcm1hcmtkb3duOjptZXRhZGF0YSR0aXRsZWA8L3NwYW4+IgotLS0KCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19pbnNlcnQyREIuUicpKSwgaW5jbHVkZSA9IEZBTFNFfQpgYGAKCmBgYHtyIGNvbmZpZywgaW5jbHVkZT1GQUxTRX0Kb3B0aW9ucyhib29rZG93bi5yZW5kZXIuZmlsZV9zY29wZSA9IEZBTFNFKQoKIyMgRGVmYXVsdCByZXBvCmxvY2FsKHtyIDwtIGdldE9wdGlvbigicmVwb3MiKQogICAgICAgclsiQ1JBTiJdIDwtICJodHRwOi8vY3Jhbi5yLXByb2plY3Qub3JnIiAKICAgICAgIG9wdGlvbnMocmVwb3M9cikKfSkKCmxpc3Qub2YucGFja2FnZXMgPC0gYygiUk15U1FMIikKbmV3LnBhY2thZ2VzIDwtIGxpc3Qub2YucGFja2FnZXNbIShsaXN0Lm9mLnBhY2thZ2VzICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLCJQYWNrYWdlIl0pXQppZihsZW5ndGgobmV3LnBhY2thZ2VzKSkgaW5zdGFsbC5wYWNrYWdlcyhuZXcucGFja2FnZXMpCmBgYAoKIyMgQ2xvdWQgTXlTUUwgRGF0YWJhc2VzCgpBIGNsb3VkIE15U1FMIGRhdGFiYXNlIGlzIGEgW015U1FMXShodHRwczovL3d3dy5teXNxbC5jb20vKSBkYXRhYmFzZSBpbnN0YW5jZSBob3N0ZWQgYW5kIG1hbmFnZWQgYnkgYSBjbG91ZCBzZXJ2aWNlIHByb3ZpZGVyIHJhdGhlciB0aGFuIHJ1bm5pbmcgb24geW91ciBsb2NhbCBtYWNoaW5lIG9yIG9uLXByZW1pc2Ugc2VydmVycy4gVGhlIGRhdGFiYXNlIGVuZ2luZSBydW5zIG9uIHRoZSBwcm92aWRlcidzIGluZnJhc3RydWN0dXJlLCBzZWN1cmVseSBhY2Nlc3NpYmxlIG92ZXIgdGhlIGludGVybmV0LiBBIGNsb3VkLWhvc3RlZCBNeVNRTCBkYXRhYmFzZSAob3IgYW55IGRhdGFiYXNlIGZvciB0aGF0IG1hdHRlcikgYWZmb3JkcyBjZXJ0YWluIGJlbmVmaXRzLCB3aGlsZSBpbnRyb2R1Y2luZyBzZXZlcmFsIGltcG9ydGFudCBkcmF3YmFja3MgYXMgd2VsbC4gTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhvc2UgYmVuZWZpdHMgYW5kIGRyYXdiYWNrcyBpbiBhIGJpdCBtb3JlIGRldGFpbCBiZWZvcmUgZGl2aW5nIGludG8gdGhlIG1lY2hhbmlzbXMgdG8gY29uZmlndXJlIGFuZCBjb25uZWN0IHRvIGEgY2xvdWQgTXlTUUwgaW5zdGFuY2UuCgojIyMgQ2xvdWQgdnMgTG9jYWwgRGF0YWJhc2VzCgpUaGUga2V5IGRpZmZlcmVuY2VzIHdoZW4gdXNpbmcgYSBjbG91ZC1ob3N0ZWQgZGF0YWJhc2UgdmVyc3VzIGEgbG9jYWwgZGF0YWJhc2Ugc2VydmVyIGluc3RhbGxhdGlvbiBhcmUgdGhlIGZvbGxvd2luZzoKCi0gICAqKkluZnJhc3RydWN0dXJlIE1hbmFnZW1lbnQqKjogVGhlIGNsb3VkIHByb3ZpZGVyIGhhbmRsZXMgc2VydmVyIHByb3Zpc2lvbmluZywgbWFpbnRlbmFuY2UsIHVwZGF0ZXMsIGFuZCBoYXJkd2FyZSBmYWlsdXJlcwotICAgKipTY2FsYWJpbGl0eSoqOiBSZXNvdXJjZXMgKENQVSwgbWVtb3J5LCBzdG9yYWdlKSBjYW4gYmUgYWRqdXN0ZWQgZHluYW1pY2FsbHkgYmFzZWQgb24gZGVtYW5kCi0gICAqKkR5bmFtaWMgUHJpY2luZyoqOiBUaGVyZSBhcmUgZmV3IHVwZnJvbnQgY29zdHMgYW5kIGNvc3RzIGFyZSBpbmN1cnJlZCBiYXNlZCBvbiBkZW1hbmQKLSAgICoqQXZhaWxhYmlsaXR5Kio6IEJ1aWx0LWluIHJlZHVuZGFuY3kgYW5kIGZhaWxvdmVyIG1lY2hhbmlzbXMgZW5zdXJlIGhpZ2hlciBhdmFpbGFiaWxpdHkKLSAgICoqU2VjdXJpdHkqKjogSW5kdXN0cnktc3RhbmRhcmQgc2VjdXJpdHkgaW5jbHVkaW5nIGVuY3J5cHRpb24sIG5ldHdvcmsgaXNvbGF0aW9uLCBhbmQgY29tcGxpYW5jZSBjZXJ0aWZpY2F0aW9ucwotICAgKipCYWNrdXAgYW5kIFJlY292ZXJ5Kio6IEF1dG9tYXRlZCBiYWNrdXAgc2NoZWR1bGVzIHdpdGggcG9pbnQtaW4tdGltZSByZWNvdmVyeSBjYXBhYmlsaXRpZXMKCiMjIyBBZHZhbnRhZ2VzIG9mIENsb3VkIERhdGFiYXNlcwoKKipPcGVyYXRpb25hbCBCZW5lZml0czoqKgoKLSAgIEVsaW1pbmF0ZXMgc2VydmVyIGFkbWluaXN0cmF0aW9uIG92ZXJoZWFkIChPUyB1cGRhdGVzLCBzZWN1cml0eSBwYXRjaGVzLCBoYXJkd2FyZSBtb25pdG9yaW5nKQotICAgUmVkdWNlcyB0aW1lLXRvLWRlcGxveW1lbnQgZnJvbSBob3Vycy9kYXlzIHRvIG1pbnV0ZXMKLSAgIEF1dG9tYXRpYyBzY2FsaW5nIHByZXZlbnRzIHBlcmZvcm1hbmNlIGJvdHRsZW5lY2tzIGR1cmluZyB0cmFmZmljIHNwaWtlcwotICAgUHJvZmVzc2lvbmFsIG1vbml0b3JpbmcgYW5kIGFsZXJ0aW5nIHN5c3RlbXMKCioqUmVsaWFiaWxpdHkgYW5kIFNlY3VyaXR5OioqCgotICAgTXVsdGktem9uZSByZXBsaWNhdGlvbiBwcm92aWRlcyBmYXVsdCB0b2xlcmFuY2UgYmV5b25kIHNpbmdsZS1tYWNoaW5lIHNldHVwcwotICAgRW50ZXJwcmlzZS1ncmFkZSBzZWN1cml0eSBjb250cm9scyBpbmNsdWRpbmcgVlBDIGlzb2xhdGlvbiBhbmQgU1NML1RMUyBlbmNyeXB0aW9uCi0gICBDb21wbGlhbmNlIHdpdGggc3RhbmRhcmRzIGxpa2UgU09DIDIsIElTTyAyNzAwMSwgYW5kIEdEUFIKLSAgIFJlZ3VsYXIgYXV0b21hdGVkIGJhY2t1cHMgd2l0aCBjb25maWd1cmFibGUgcmV0ZW50aW9uIHBlcmlvZHMKCioqQ29zdCBFZmZpY2llbmN5OioqCgotICAgUGF5LXBlci11c2UgbW9kZWwgZWxpbWluYXRlcyB1cGZyb250IGhhcmR3YXJlIGNvc3RzCi0gICBObyBuZWVkIGZvciBkZWRpY2F0ZWQgZGF0YWJhc2UgYWRtaW5pc3RyYXRvcnMgZm9yIGJhc2ljIG9wZXJhdGlvbnMKLSAgIFJlZHVjZWQgZWxlY3RyaWNpdHkgYW5kIGNvb2xpbmcgY29zdHMKCiMjIyBEaXNhZHZhbnRhZ2VzIG9mIENsb3VkIERhdGFiYXNlcwoKIyMjIyBOZXR3b3JrIERlcGVuZGVuY3kgYW5kIExhdGVuY3kKCioqSW50ZXJuZXQgQ29ubmVjdGl2aXR5IFJlcXVpcmVtZW50czoqKgoKLSAgIENvbXBsZXRlIGRlcGVuZGVuY3kgb24gaW50ZXJuZXQgY29ubmVjdGlvbiBmb3IgZGF0YWJhc2UgYWNjZXNzCi0gICBBcHBsaWNhdGlvbiBiZWNvbWVzIHVudXNhYmxlIGR1cmluZyBuZXR3b3JrIG91dGFnZXMgb3IgSVNQIGlzc3VlcwotICAgTG9jYWwgTXlTUUwgY29udGludWVzIGZ1bmN0aW9uaW5nIGR1cmluZyBpbnRlcm5ldCBkaXNydXB0aW9ucwoKKipMYXRlbmN5IENvbnNpZGVyYXRpb25zOioqCgotICAgTmV0d29yayByb3VuZC10cmlwIHRpbWUgYWRkcyAxMC0xMDBtcysgcGVyIHF1ZXJ5IGRlcGVuZGluZyBvbiBnZW9ncmFwaGljIGRpc3RhbmNlCi0gICBDdW11bGF0aXZlIGVmZmVjdCBzaWduaWZpY2FudCBmb3IgYXBwbGljYXRpb25zIG1ha2luZyBtYW55IHNtYWxsIHF1ZXJpZXMKLSAgIExvY2FsIE15U1FMIHR5cGljYWxseSBoYXMgXDwxbXMgbGF0ZW5jeSBmb3IgZGF0YWJhc2Ugb3BlcmF0aW9ucwotICAgSGlnaC1mcmVxdWVuY3kgdHJhZGluZywgcmVhbC10aW1lIGdhbWluZywgb3IgbWljcm8tc2VydmljZSBhcmNoaXRlY3R1cmVzIHBhcnRpY3VsYXJseSBhZmZlY3RlZAoKKipCYW5kd2lkdGggTGltaXRhdGlvbnM6KioKCi0gICBMYXJnZSByZXN1bHQgc2V0cyBjb25zdW1lIGludGVybmV0IGJhbmR3aWR0aAotICAgRGF0YS1pbnRlbnNpdmUgb3BlcmF0aW9ucyAoYnVsayBpbXBvcnRzLCBjb21wbGV4IHJlcG9ydGluZykgbWF5IGJlIHNsb3cKLSAgIEJhbmR3aWR0aCBjb3N0cyBmb3IgaGlnaC10cmFmZmljIGFwcGxpY2F0aW9ucwotICAgTG9jYWwgb3BlcmF0aW9ucyB1c2UgaW50ZXJuYWwgbmV0d29yayBzcGVlZHMgKGdpZ2FiaXQrKQoKIyMjIyBDb3N0IFN0cnVjdHVyZQoKKipPbmdvaW5nIE9wZXJhdGlvbmFsIENvc3RzOioqCgotICAgTW9udGhseS9ob3VybHkgZmVlcyBjb250aW51ZSBpbmRlZmluaXRlbHkgdnMgb25lLXRpbWUgaGFyZHdhcmUgcHVyY2hhc2UKLSAgIENvc3RzIHNjYWxlIHdpdGggdXNhZ2UsIHN0b3JhZ2UsIGFuZCBwZXJmb3JtYW5jZSByZXF1aXJlbWVudHMKLSAgIERhdGEgdHJhbnNmZXIgZmVlcyBmb3IgaGlnaC12b2x1bWUgYXBwbGljYXRpb25zCi0gICBMb25nLXRlcm0gdG90YWwgY29zdCBvZnRlbiBleGNlZWRzIGxvY2FsIGhhcmR3YXJlIGludmVzdG1lbnQKLSAgIEZhaWx1cmUgdG8gcGF5IGRpc3J1cHRzIHRoZSBzZXJ2aWNlIGFuZCBtYXkgZXZlbiBsZWFkIHRvIGxvc3Mgb2YgZGF0YQotICAgVmVuZG9ycyBtYXkgc3VkZGVubHkgcmFpc2UgcHJpY2VzIGxlZGluZyB0byB1bmFudGljaXBhdGVkIGNvc3RzCgoqKlVucHJlZGljdGFibGUgU2NhbGluZyBDb3N0czoqKgoKLSAgIFN1ZGRlbiB0cmFmZmljIHNwaWtlcyByZXN1bHQgaW4gaW1tZWRpYXRlIGNvc3QgaW5jcmVhc2VzCi0gICBEaWZmaWN1bHQgdG8gYnVkZ2V0IGZvciB2YXJpYWJsZSB3b3JrbG9hZHMKLSAgIFByZW1pdW0gcHJpY2luZyBmb3IgaGlnaC1wZXJmb3JtYW5jZSBpbnN0YW5jZXMKLSAgIEFkZGl0aW9uYWwgY2hhcmdlcyBmb3IgYmFja3VwcywgbW9uaXRvcmluZywgYW5kIHN1cHBvcnQgZmVhdHVyZXMKCiMjIyMgRGF0YSBDb250cm9sIGFuZCBQcml2YWN5CgoqKkRhdGEgU292ZXJlaWdudHk6KioKCi0gICBPcGVyYXRpb25hbCAoYW5kIHBvc3NpYmx5IHNlbnNpdGl2ZSkgZGF0YSBwaHlzaWNhbGx5IHJlc2lkZXMgb24gdGhpcmQtcGFydHkgaW5mcmFzdHJ1Y3R1cmUKLSAgIFN1YmplY3QgdG8gY2xvdWQgcHJvdmlkZXIncyBkYXRhIGhhbmRsaW5nIHBvbGljaWVzIGFuZCBwb3RlbnRpYWwgYnJlYWNoZXMKLSAgIEdvdmVybm1lbnQgYWNjZXNzIHJlcXVlc3RzIG1heSBhZmZlY3QgeW91ciBkYXRhIHdpdGhvdXQgeW91ciBrbm93bGVkZ2UKLSAgIENvbXBsaWFuY2UgY2hhbGxlbmdlcyBpbiByZWd1bGF0ZWQgaW5kdXN0cmllcyAoaGVhbHRoY2FyZSwgZmluYW5jZSkKLSAgIEFjdHVhbCBsb2NhdGlvbiBvZiBzZXJ2ZXIgaG9zdGluZyB0aGUgZGF0YWJhc2UgbWF5IGJlIHN1YmplY3QgdG8gZGlmZmVyZW50IGxhd3MgYW5kIHJlZ3VsYXRpb25zIGFuZCBtYXkgdmlvbGF0ZSBjdXN0b21lciB0ZXJtcyBvZiBzZXJ2aWNlIG9mIHNlcnZpY2UtbGV2ZWwgYWdyZWVtZW50cwotICAgVHJhZGUgb3IgYWN0dWFsIHdhcnMgbWF5IHJlc3VsdCBpbiBsb3NzIG9mIGFjY2VzcyB0byBkYXRhIHdoZW4gc2VydmVycyBhcmUgbG9jYXRlZCBpbiBkaWZmZXJlbnQgY291bnRyaWVzCi0gICBEYXRhIHByaXZhY3kgcG9saWNpZXMgY2FuIGNoYW5nZSBhbmQgbWF5IHJlc3VsdCBpbiB2aW9sYXRpb25zIG9mIGN1c3RvbWVyIHRlcm1zIG9mIHNlcnZpY2UKCioqVmVuZG9yIExvY2staW4gUmlza3M6KioKCi0gICBNaWdyYXRpb24gY29tcGxleGl0eSBpbmNyZWFzZXMgb3ZlciB0aW1lIHdpdGggY3VzdG9tIGNvbmZpZ3VyYXRpb25zCi0gICBQcm9wcmlldGFyeSBiYWNrdXAgZm9ybWF0cyBvciBtYW5hZ2VtZW50IHRvb2xzCi0gICBQcmljZSBpbmNyZWFzZXMgZGlmZmljdWx0IHRvIGF2b2lkIG9uY2UgaGVhdmlseSBpbnZlc3RlZAotICAgRGVwZW5kZW5jeSBvbiB2ZW5kb3IncyBidXNpbmVzcyBjb250aW51aXR5IGFuZCBwb2xpY3kgY2hhbmdlcwotICAgVmVuZG9yIG1heSBjZWFzZSBidXNpbmVzcyBvcGVyYXRpb25zIHN1ZGRlbmx5CgojIyMgUGVyZm9ybWFuY2UgTGltaXRhdGlvbnMKCioqUmVzb3VyY2UgU2hhcmluZzoqKgoKLSAgIE11bHRpLXRlbmFudCBpbmZyYXN0cnVjdHVyZSBtZWFucyBzaGFyZWQgdW5kZXJseWluZyBoYXJkd2FyZQotICAgIk5vaXN5IG5laWdoYm9yIiBwcm9ibGVtcyB3aGVyZSBvdGhlciB1c2VycyBhZmZlY3QgeW91ciBwZXJmb3JtYW5jZQotICAgTGVzcyBwcmVkaWN0YWJsZSBwZXJmb3JtYW5jZSBjb21wYXJlZCB0byBkZWRpY2F0ZWQgaGFyZHdhcmUKLSAgIExpbWl0ZWQgYWJpbGl0eSB0byBvcHRpbWl6ZSBoYXJkd2FyZSBmb3Igc3BlY2lmaWMgd29ya2xvYWRzCgoqKkNvbmZpZ3VyYXRpb24gQ29uc3RyYWludHM6KioKCi0gICBSZXN0cmljdGVkIGFjY2VzcyB0byBhZHZhbmNlZCBNeVNRTCBjb25maWd1cmF0aW9uIHBhcmFtZXRlcnMKLSAgIENhbm5vdCBpbnN0YWxsIGN1c3RvbSBzdG9yYWdlIGVuZ2luZXMgb3IgbW9kaWZ5IGNvcmUgZGF0YWJhc2UgYmVoYXZpb3IKLSAgIExpbWl0ZWQgY29udHJvbCBvdmVyIGNhY2hpbmcgc3RyYXRlZ2llcyBhbmQgbWVtb3J5IGFsbG9jYXRpb24KLSAgIE9wZXJhdGluZyBzeXN0ZW0tbGV2ZWwgb3B0aW1pemF0aW9ucyB1bmF2YWlsYWJsZQoKIyMjIFNlY3VyaXR5IGFuZCBBY2Nlc3MgQ29udHJvbAoKKipFeHRlbmRlZCBBdHRhY2sgU3VyZmFjZToqKgoKLSAgIEludGVybmV0LWFjY2Vzc2libGUgZW5kcG9pbnRzIGNyZWF0ZSBhZGRpdGlvbmFsIHNlY3VyaXR5IHJpc2tzCi0gICBEZXBlbmRlbmN5IG9uIGNsb3VkIHByb3ZpZGVyJ3Mgc2VjdXJpdHkgcHJhY3RpY2VzCi0gICBTaGFyZWQgcmVzcG9uc2liaWxpdHkgbW9kZWwgY2FuIGNyZWF0ZSBzZWN1cml0eSBnYXBzCi0gICBNdWx0aXBsZSBhdXRoZW50aWNhdGlvbiBsYXllcnMgaW5jcmVhc2UgY29tcGxleGl0eQoKKipMaW1pdGVkIEFkbWluaXN0cmF0aXZlIENvbnRyb2w6KioKCi0gICBDYW5ub3QgaW1wbGVtZW50IGN1c3RvbSBzZWN1cml0eSBtb25pdG9yaW5nIG9yIGludHJ1c2lvbiBkZXRlY3Rpb24KLSAgIFJlc3RyaWN0ZWQgYWNjZXNzIHRvIHN5c3RlbSBsb2dzIGFuZCBwZXJmb3JtYW5jZSBtZXRyaWNzCi0gICBVbmFibGUgdG8gaW1wbGVtZW50IG9yZ2FuaXphdGlvbi1zcGVjaWZpYyBzZWN1cml0eSBwb2xpY2llcwotICAgRGVwZW5kZW5jeSBvbiB2ZW5kb3IncyBpbmNpZGVudCByZXNwb25zZSBwcm9jZWR1cmVzCgojIyMgVGVjaG5pY2FsIExpbWl0YXRpb25zCgoqKkN1c3RvbWl6YXRpb24gUmVzdHJpY3Rpb25zOioqCgotICAgQ2Fubm90IG1vZGlmeSBNeVNRTCBzb3VyY2UgY29kZSBvciBpbnN0YWxsIGN1c3RvbSBwYXRjaGVzCi0gICBMaW1pdGVkIHBsdWdpbiBlY29zeXN0ZW0gY29tcGFyZWQgdG8gc2VsZi1tYW5hZ2VkIGluc3RhbGxhdGlvbnMKLSAgIFJlc3RyaWN0ZWQgYWJpbGl0eSB0byBpbnRlZ3JhdGUgd2l0aCBjdXN0b20gbW9uaXRvcmluZyBvciBiYWNrdXAgc29sdXRpb25zCi0gICBWZXJzaW9uIHVwZ3JhZGUgdGltaW5nIGNvbnRyb2xsZWQgYnkgdmVuZG9yLCBub3QgeW91ciBzY2hlZHVsZQoKKipEZXZlbG9wbWVudCBhbmQgVGVzdGluZyBDb25zdHJhaW50czoqKgoKLSAgIERldmVsb3BtZW50IGVudmlyb25tZW50cyByZXF1aXJlIGludGVybmV0IGNvbm5lY3Rpdml0eQotICAgRGlmZmljdWx0eSBkb2luZyBvZmZsaW5lIGRldmVsb3BtZW50Ci0gICBSZXBsaWNhdGluZyBleGFjdCBwcm9kdWN0aW9uIGNvbmZpZ3VyYXRpb25zIGxvY2FsbHkgbWF5IGJlIGltcG9zc2libGUKLSAgIEFkZGl0aW9uYWwgY29tcGxleGl0eSBmb3IgY29udGludW91cyBpbnRlZ3JhdGlvbiBwaXBlbGluZXMKLSAgIERhdGFiYXNlIHNlZWRpbmcgYW5kIHRlc3RpbmcgbWF5IGJlIHNsb3dlciBkdWUgdG8gbmV0d29yayBvdmVyaGVhZAoKIyMjIEJ1c2luZXNzIENvbnRpbnVpdHkgUmlza3MKCioqVmVuZG9yIERlcGVuZGVuY3k6KioKCi0gICBTZXJ2aWNlIGRpc3J1cHRpb25zIGFmZmVjdCB5b3VyIGFwcGxpY2F0aW9uIGRpcmVjdGx5Ci0gICBMaW1pdGVkIHJlY291cnNlIGR1cmluZyBleHRlbmRlZCBvdXRhZ2VzCi0gICBEZXBlbmRlbnQgb24gdmVuZG9yJ3MgZGlzYXN0ZXIgcmVjb3ZlcnkgY2FwYWJpbGl0aWVzCi0gICBCdXNpbmVzcyBjb250aW51aXR5IHRpZWQgdG8gdGhpcmQtcGFydHkgY29tcGFueSdzIHN0YWJpbGl0eQoKKipEYXRhIFBvcnRhYmlsaXR5OioqCgotICAgRXhwb3J0L2ltcG9ydCBwcm9jZXNzZXMgZm9yIG1pZ3JhdGlvbiBjYW4gYmUgY29tcGxleCBhbmQgdGltZS1jb25zdW1pbmcKLSAgIFBvdGVudGlhbCBkYXRhIGZvcm1hdCBpbmNvbXBhdGliaWxpdGllcwotICAgRG93bnRpbWUgcmVxdWlyZWQgZm9yIG1pZ3JhdGlvbiB0byBhbHRlcm5hdGl2ZSBzb2x1dGlvbnMKLSAgIFJpc2sgb2YgZGF0YSBsb3NzIGR1cmluZyBtaWdyYXRpb24gcHJvY2Vzc2VzCgojIyMgQnVzaW5lc3MgQ2FzZSBmb3IgTG9jYWwgRGF0YWJhc2VzCgpXaGlsZSBjbG91ZC1ob3N0ZWQgZGF0YWJhc2UtYXMtYS1zZXJ2aWNlIGRhdGFiYXNlcyBtYXkgYmUgaWRlYWwgZm9yIG1hbnkgdXNlIGNhc2VzLCBhIGxvY2FsIGRhdGFiYXNlIG9mZmVycyBkaXN0aW5jdCBhZHZhbnRhZ2VzLiBBcHBsaWNhdGlvbnMgcmVxdWlyaW5nIG1pY3Jvc2Vjb25kLWxldmVsIGxhdGVuY3kgb3IgaGFuZGxpbmcgdGhvdXNhbmRzIG9mIHF1ZXJpZXMgcGVyIHNlY29uZCBtYXkgYmVuZWZpdCBmcm9tIGxvY2FsIGRlcGxveW1lbnQuIEluZHVzdHJpZXMgd2l0aCBzdHJpY3QgZGF0YSByZXNpZGVuY3kgcmVxdWlyZW1lbnRzIG9yIGFpci1nYXBwZWQgbmV0d29yayBuZWVkcyBhcmUgYmVzdCBob3N0ZWQgbG9jYWxseS4KCkZ1cnRoZXJtb3JlLCBzdGFibGUgYXBwbGljYXRpb25zIHdpdGggcHJlZGljdGFibGUgdXNhZ2UgcGF0dGVybnMgcnVubmluZyBmb3IgbXVsdGlwbGUgeWVhcnMgcHJvdmlkZSBwcmVkaWN0YWJsZSBjb3N0cy4gSW4gYWRkaXRpb24sIGFwcGxpY2F0aW9ucyByZXF1aXJpbmcgc3BlY2lmaWMgZGF0YWJhc2UgYnVpbGRzICgqZS5nLiosIGEgc3BlY2lmaWMgTXlTUUwgdmVyc2lvbiksIGN1c3RvbSBzdG9yYWdlIGVuZ2luZXMsIG9yIGRlZXAgc3lzdGVtIGludGVncmF0aW9uLgoKRnJvbSBhIGRldmVsb3BtZW50IHBlcnNwZWN0aXZlLCBsb2NhbGx5IGhvc3RlZCBkYXRhYmFzZXMgb2Z0ZW4gcHJvdmlkZXMgZmFzdGVyIGl0ZXJhdGlvbiBjeWNsZXMgYW5kIGRvbid0IGNvbnN1bWUgY29zdGx5IGNsb3VkIHJlc291cmNlcy4KClRoZSBjaG9pY2UgYmV0d2VlbiBhIGNsb3VkIG9yIGEgbG9jYWwgZGF0YWJhc2UgdWx0aW1hdGVseSBkZXBlbmRzIG9uIHdlaWdoaW5nIHRoZXNlIGRpc2FkdmFudGFnZXMgYWdhaW5zdCB0aGUgb3BlcmF0aW9uYWwgYmVuZWZpdHMuIEZvciBtYW55IG1vZGVybiBhcHBsaWNhdGlvbnMgYW5kIGJ1c2luZXNzIG5lZWRzIHRoZSBjbG91ZCB0cmFkZS1vZmZzIGFyZSBnZW5lcmFsbHkgYWNjZXB0YWJsZSBpbiB2aWV3IG9mIHRoZSByZWR1Y2VkIGFkbWluaXN0cmF0aXZlIG92ZXJoZWFkIGFuZCBpbXByb3ZlZCByZWxpYWJpbGl0eSB0aGF0IGlzIG9mdGVuIGhhcmQgdG8gcmVwbGljYXRlIGxvY2FsbHkgd2l0aG91dCBkZWRpY2F0ZWQgb24tc3RhZmYgZGF0YWJhc2UgYWRtaW5pc3RyYXRvcnMuCgojIyBBaXZlbiBQbGF0Zm9ybQoKW0FpdmVuXShodHRwOi8vYWl2ZW4uaW8pIGlzIGEgY2xvdWQgZGF0YWJhc2UtYXMtYS1zZXJ2aWNlIChEQmFhUykgcGxhdGZvcm0gc3BlY2lhbGl6aW5nIGluIG9wZW4tc291cmNlIGRhdGEgdGVjaG5vbG9naWVzLiBGb3VuZGVkIGluIDIwMTYsIEFpdmVuIHByb3ZpZGVzIG1hbmFnZWQgc2VydmljZXMgZm9yIE15U1FMLCBQb3N0Z3JlU1FMLCBBcGFjaGUgS2Fma2EsIFJlZGlzLCBhbmQgb3RoZXIgZGF0YSBpbmZyYXN0cnVjdHVyZSBjb21wb25lbnRzIGFjcm9zcyBtYWpvciBjbG91ZCBwcm92aWRlcnMgKEFXUywgR29vZ2xlIENsb3VkLCBBenVyZSkuCgpBaXZlbidzIGRpc3Rpbmd1aXNoaW5nIGZlYXR1cmVzIGluY2x1ZGUgdGhlIGFiaWxpdHkgdG8gZGVwbG95IGFjcm9zcyBkaWZmZXJlbnQgY2xvdWQgcHJvdmlkZXJzIGZyb20gYSBzaW5nbGUgaW50ZXJmYWNlIHdoaWxlIG1haW50YWluaW5nIGNvbXBhdGliaWxpdHkgd2l0aCBzdGFuZGFyZCBNeVNRTCB3aXRob3V0IHZlbmRvciBsb2NrLWluLiBGb3IgZGV2ZWxvcGVycyBpdCBvZmZlciBjb21wcmVoZW5zaXZlIEFQSXMsIFRlcnJhZm9ybSBzdXBwb3J0LCBhbmQgQ0xJIHRvb2xzLiBMaWtlIG90aGVyIGNsb3VkIGRhdGFiYXNlIHBsYXRmb3JtcywgQWl2ZW4ncyBkYXRhIGNlbnRlcnMgYXJlIGRpc3RyaWJ1dGVkIGFjcm9zcyBtdWx0aXBsZSByZWdpb25zIGZvciBsYXRlbmN5IG9wdGltaXphdGlvbi4KCiMjIyBDb25maWd1cmluZyBNeVNRTCBvbiBBaXZlbgoKVG8gc2V0IHVwIGEgZGF0YWJhc2Ugb24gQWl2ZW4gcmVxdWlyZXMgYW4gYWNjb3VudCB3aXRoIHRoZSBwbGF0Zm9ybS4KCjEuICBSZWdpc3RlciBhdCBhaXZlbi5pbyB1c2luZyB5b3VyIGFjYWRlbWljIGVtYWlsCjIuICBSZXNwb25kIHRvIGFueSB2ZXJpZmljYXRpb24gZW1haWxzCjMuICBDcmVhdGUgYSBuZXcgcHJvamVjdCAobG9naWNhbCBjb250YWluZXIgZm9yIHlvdXIgc2VydmljZXMpCjQuICBTZWxlY3QgeW91ciBwcmVmZXJyZWQgY2xvdWQgcHJvdmlkZXIgYW5kIHJlZ2lvbiBiYXNlZCBvbiBsYXRlbmN5IHJlcXVpcmVtZW50cwoKT25jZSBhbiBhY2NvdW50IGhhcyBiZWVuIGNyZWF0ZWQgeW91IGNhbiBjb25maWd1cmUgYSBNeVNRTCBpbnN0YW5jZS4gTmF2aWdhdGUgdG8gIkNyZWF0ZSBTZXJ2aWNlIiBhbmQgY29uZmlndXJlOgoKLSAgICoqU2VydmljZSB0eXBlKio6IE15U1FMCi0gICAqKkNsb3VkIHByb3ZpZGVyKio6IEFXUywgR29vZ2xlIENsb3VkLCBvciBBenVyZQotICAgKipSZWdpb24qKjogQ2hvb3NlIGJhc2VkIG9uIHlvdXIgZ2VvZ3JhcGhpYyBsb2NhdGlvbgotICAgKipQbGFuKio6IFN0YXJ0IHdpdGggdGhlIHNtYWxsZXN0IChsaWtlbHkgZnJlZSkgcGxhbiAodHlwaWNhbGx5IDEgQ1BVLCAxR0IgUkFNLCAxR0IgZGF0YWJhc2Ugc3RvcmFnZSkgZm9yIGRldmVsb3BtZW50Ci0gICAqKlNlcnZpY2UgbmFtZSoqOiBVc2UgZGVzY3JpcHRpdmUgbmFtaW5nICgqZS5nLiosICJjbGFzcy1teXNxbC1kZXYiKQoKTmV4dCwgeW91IG5lZWQgdG8gbWFuYWdlIG5ldHdvcmsgU2VjdXJpdHkuIFN0YXJ0IGJ5IGNvbmZpZ3VyaW5nIElQIHdoaXRlbGlzdCBpbiB0aGUgc2VydmljZSBzZXR0aW5ncyBhbmQgYWRkIHlvdXIgZGV2ZWxvcG1lbnQgbWFjaGluZSdzIHB1YmxpYyBJUC4gRm9yIHByb2R1Y3Rpb24sIHVzZSBWUEMgcGVlcmluZyBvciBwcml2YXRlIG5ldHdvcmtpbmcuIFdoZW5ldmVyIGZlYXNpYmxlLCBlbmFibGUgU1NML1RMUyBlbmZvcmNlbWVudCBmb3IgZW5jcnlwdGVkIGNvbm5lY3Rpb25zLiBEb3dubG9hZCB0aGUgU1NMIGNlcnRpZmljYXRlIGFuZCBwbGFjZSBpdCBpbiBhbiBhY2Nlc3NpYmxlIGJ1dCB1bnNoYXJlZCBmb2xkZXIgKGFuZCBlbnN1cmUgdGhhdCB0aGUgY2VydGlmaWNhdGUgY2Fubm90IGJlIGFjY2Vzc2VkIGJ5IGFuIHVudHJ1c3RlZCB0aGlyZCBwYXJ0eSBhcyByZXZlYWxpbmcgdGhlIGNlcnRpZmljYXRlIGlzIGEgdnVsbmVyYWJpbGl0eSB0aGF0IGNhbiBleHBvc2UgeW91ciBkYXRhYmFzZSBhbmQgeW91ciBkYXRhKS4KCkFzIHlvdSBzY2FsZSB1cCB5b3VyIGRhdGFiYXNlIG5lZWRzLCBjcmVhdGUgYXBwbGljYXRpb24tc3BlY2lmaWMgZGF0YWJhc2VzIHVzaW5nIHRoZSBBaXZlbiBjb25zb2xlLiBSYXRoZXIgdGhhbiB1c2luZyB0aGUgYWRtaW5pc3RyYXRpdmUgdXNlciBmb3Igc2VydmljZSBjb25uZWN0aW9ucywgYWRkIGRlZGljYXRlZCBkYXRhYmFzZSB1c2VycyB3aXRoIG1pbmltYWwgcmVxdWlyZWQgcHJpdmlsZWdlcywgKmUuZy4qIGxpbWl0IGFjY2VzcyB0byB0YWJsZXMgYW5kIHZpZXdzLgoKRmluYWxseSwgYWRkIG1vbml0b3JpbmcgYnkgY29uZmlndXJpbmcgYWxlcnQgdGhyZXNob2xkcyBmb3IgQ1BVLCBtZW1vcnksIGFuZCBjb25uZWN0aW9uIGxpbWl0cy4gU2V0IHVwIGF1dG9tYXRlZCBiYWNrdXBzIHdpdGggYXBwcm9wcmlhdGUgcmV0ZW50aW9uIHBlcmlvZHMuIE1vbml0b3IgcXVlcnkgcGVyZm9ybWFuY2UgdGhyb3VnaCB0aGUgZGFzaGJvYXJkLgoKVGhlIHJlc3VsdGluZyBzZXR1cCBwcm92aWRlcyBhIHByb2R1Y3Rpb24tcmVhZHkgTXlTUUwgaW5zdGFuY2Ugd2l0aCBlbnRlcnByaXNlLWdyYWRlIHJlbGlhYmlsaXR5LCBzZWN1cml0eSwgYW5kIG1vbml0b3JpbmcgY2FwYWJpbGl0aWVzLCBhbGxvd2luZyB5b3UgdG8gZm9jdXMgb24gYXBwbGljYXRpb24gZGV2ZWxvcG1lbnQgcmF0aGVyIHRoYW4gZGF0YWJhc2UgYWRtaW5pc3RyYXRpb24uCgojIyMgQ29ubmVjdGluZyB0byBNeVNRTCBmcm9tIFIKCkluIHRoaXMgc2VjdGlvbiwgd2UgZGVtb25zdHJhdGUgaG93IHRvIGNvbm5lY3QgdG8gYW4gYWxyZWFkeSBjb25maWd1cmVkIGFuZCBydW5uaW5nIE15U1FMIGluc3RhbmNlIGhvc3RlZCBvbiBBaXZlbi4gVGhlIGNvbm5lY3Rpb24gcGFyYW1ldGVycyBhcmUgdW5pcXVlIHRvIHRoZSBkYXRhYmFzZSBhbmQgdGhlIG9uZXMgcHJvdmlkZWQgYmVsb3cgYXJlIGZvciBvdXIgc2FtcGxlIGRhdGFiYXNlLgoKIyMjIyBPYnRhaW5pbmcgQ29ubmVjdGlvbiBQYXJhbWV0ZXJzCgohW10oaW1hZ2VzL2FpdmVuLWNvbm5lY3Rpb24tcGFyYW1ldGVycy10by1SLmpwZyl7d2lkdGg9Ijc1JSJ9CgpSZXBsYWNlIHRoZSBjb25uZWN0aW9uIHBhcmFtZXRlcnMgd2l0aCB5b3VyIG93biBwYXJhbWV0ZXIgdmFsdWVzIGFuZCBlbnN1cmUgdGhhdCB0aGUgTXlTUUwgc2VydmljZSBpcyBydW5uaW5nLgoKIVtdKGltYWdlcy9haXZlbi1wb3dlcm9uLXNlcnZpY2UuanBnKXt3aWR0aD0iNTAlIn0KCiMjIyMgVW5zZWN1cmVkIENvbm5lY3Rpb24KClRoZSBjb2RlIGJlbG93IHNob3dzIGhvdyB0byBjb25uZWN0IHRvIHRoZSBNeVNRTCBzZXJ2aWNlIG92ZXIgYW4gdW5zZWN1cmVkICh1bmVuY3J5cHRlZCkgY29ubmVjdGlvbi4gV2hpbGUgdGhlIGNvbm5lY3Rpb24gaXMgcGFzc3dvcmQgcHJvdGVjdGVkIGFsbCB0cmFmZmljIChTUUwgc3RhdGVtZW50cyBhbmQgcmV0dXJuZWQgZGF0YSkgaXMgdHJhbnNtaXR0ZWQgdW5lbmNyeXB0ZWQgYW5kIGNhbiBiZSBpbnRlcmNlcHRlZCBhbmQgcmVhZC4gVGhpcyBzaG91bGQgb25seSBiZSB1c2VkIHdoZW4gU1NMIGlzIG5vdCBhdmFpbGFibGUgb3Igd2hlbiBvcGVyYXRpbmcgb24gYSBzZWN1cmVkIGludGVybmFsIG5ldHdvcmsuCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZXZhbD1UfQojIGxvYWQgcmVxdWlyZWQgbGlicmFyeQpsaWJyYXJ5KFJNeVNRTCkKCiMgZGVmaW5lIHNldHRpbmdzCmRiX2hvc3RfYWl2ZW4gPC0gIm15c3FsLTJiMTBiYTQ2LWtob3VyeS00NWE3LmFpdmVuY2xvdWQuY29tIgpkYl9wb3J0X2FpdmVuIDwtIDExMjE0CmRiX25hbWVfYWl2ZW4gPC0gImRlZmF1bHRkYiIKZGJfdXNlcl9haXZlbiA8LSAiYXZuYWRtaW4iCmRiX3B3ZF9haXZlbiA8LSAiQVZOU19FMTNYNjFNblI5Z0d5MTZWTEVhIgoKIyBjb25uZWN0IHRvIHJlbW90ZSBNeVNRTCBzZXJ2ZXIgYW5kIGRhdGFiYXNlCm15ZGIuYWl2ZW4gPC0gIGRiQ29ubmVjdChSTXlTUUw6Ok15U1FMKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgdXNlciA9IGRiX3VzZXJfYWl2ZW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgcGFzc3dvcmQgPSBkYl9wd2RfYWl2ZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICBkYm5hbWUgPSBkYl9uYW1lX2FpdmVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGhvc3QgPSBkYl9ob3N0X2FpdmVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBvcnQgPSBkYl9wb3J0X2FpdmVuKQpgYGAKCiMjIyMgU2VjdXJlIENvbm5lY3Rpb24KCklmIFNTTCBtb2RlIGlzIG5vdCB1c2VkLCBkYXRhIGlzIG5vdCBlbmNyeXB0ZWQgYW5kIGNhbiBiZSBleHBvc2VkLiBUbyB1c2UgU1NMIG1vZGUsIGFkZCB0aGUgY2VydGlmaWNhdGUgdG8gdGhlIGNvbm5lY3Rpb24sIGVpdGhlciBhcyBwYXRoIHRvIGxvY2FsIGZpbGUgb3IgYnkgcGFzdGluZyBpbnRvIHRleHQuIEhvd2V2ZXIsIGtlZXAgaW4gbWluZCB0aGF0IGlmIHRoZSBzb3VyY2UgY29kZSBpcyBwdWJsaXNoZWQgb3Igc2hhcmVkLCB0aGVuIHRoZSBjZXJ0aWZpY2F0ZSBpcyBhbHNvIHNoYXJlZCB3aGljaCBsaWtlbHkgYWxzbyByZXByZXNlbnRzIGEgc2VjdXJpdHkgbGVhayBhbmQgYXR0YWNrIHZlY3Rvci4KCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBldmFsPUYsIGVjaG89Rn0Kc3RhdHVzIDwtIGRiRGlzY29ubmVjdChteWRiLmFpdmVuKQpgYGAKCllvdSBuZWVkIHRvIGZpcnN0IGRvd25sb2FkIHRoZSBjZXJ0aWZpY2F0ZSBmaWxlIChhbmQga2VlcCBpdCBzZWN1cmUpLgoKIVtdKGltYWdlcy9haXZlbi1wbS1jZXJ0LWZpbGUuanBnKXt3aWR0aD0iNTAlIn0KCmBgYHtyIHNlY3VyZVNTTENvbm5lY3Rpb24sIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBldmFsPVR9CiMgbG9hZCByZXF1aXJlZCBsaWJyYXJ5CmxpYnJhcnkoUk15U1FMKQoKIyBkZWZpbmUgc2V0dGluZ3MKZGJfaG9zdF9haXZlbiA8LSAibXlzcWwtMmIxMGJhNDYta2hvdXJ5LTQ1YTcuYWl2ZW5jbG91ZC5jb20iCmRiX3BvcnRfYWl2ZW4gPC0gMTEyMTQKZGJfbmFtZV9haXZlbiA8LSAiZGVmYXVsdGRiIgpkYl91c2VyX2FpdmVuIDwtICJhdm5hZG1pbiIKZGJfcHdkX2FpdmVuIDwtICJBVk5TX0UxM1g2MU1uUjlnR3kxNlZMRWEiCgojIGNvbm5lY3Qgc2VjdXJlbHkgdG8gcmVtb3RlIE15U1FMIHNlcnZlciBhbmQgZGF0YWJhc2UKbXlkYi5haXZlbiA8LSAgZGJDb25uZWN0KFJNeVNRTDo6TXlTUUwoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyID0gZGJfdXNlcl9haXZlbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwYXNzd29yZCA9IGRiX3B3ZF9haXZlbiwKICAgICAgICAgICAgICAgICAgICAgICAgIGRibmFtZSA9IGRiX25hbWVfYWl2ZW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgaG9zdCA9IGRiX2hvc3RfYWl2ZW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgcG9ydCA9IGRiX3BvcnRfYWl2ZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICBzc2xtb2RlID0gInJlcXVpcmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc3NsY2VydCA9ICJjYS0yYjEwYmE0Ni5wZW0iKQpgYGAKCkFsdGVybmF0aXZlbHksIGFuZCB0byBhdm9pZCBoYXZpbmcgdG8ga2VlcCB0aGUgY2VydGlmaWNhdGUgaW4gYSBmaWxlLCB3ZSBjYW4gYWxzbyBlbWJlZCB0aGUgY2VydGlmaWNhdGUgYXMgdGV4dC4gT2YgY291cnNlLCBpZiB5b3Ugd2VyZSB0byBkaXN0cmlidXRlIHRoZSBzb3VyY2UgY29kZSB5b3Ugd291bGQgZXhwb3NlIHRoZSBjZXJ0aWZpY2F0ZSB3aGljaCBtYXkgbm90IGJlIGRlc2lyYWJsZS4KCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBldmFsPVQsIGVjaG89Rn0Kc3RhdHVzIDwtIGRiRGlzY29ubmVjdChteWRiLmFpdmVuKQpgYGAKCmBgYHtyIHNlY3VyZVNTTENvbm5lY3Rpb25FbWJDZXJ0LCBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZXZhbD1UfQojIGxvYWQgcmVxdWlyZWQgbGlicmFyeQpsaWJyYXJ5KFJNeVNRTCkKCiMgZGVmaW5lIHNldHRpbmdzCmRiX2hvc3RfYWl2ZW4gPC0gIm15c3FsLTJiMTBiYTQ2LWtob3VyeS00NWE3LmFpdmVuY2xvdWQuY29tIgpkYl9wb3J0X2FpdmVuIDwtIDExMjE0CmRiX25hbWVfYWl2ZW4gPC0gImRlZmF1bHRkYiIKZGJfdXNlcl9haXZlbiA8LSAiYXZuYWRtaW4iCmRiX3B3ZF9haXZlbiA8LSAiQVZOU19FMTNYNjFNblI5Z0d5MTZWTEVhIgoKIyBlbWJlZGRlZCBTU0wgY2VydGlmaWNhdGUKZGJfY2VydCA8LSAKIgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRVFUQ0NBcW1nQXdJQkFnSVVaeFZqazhHNXBDOGtPaUhWQkV1cE5aVkMxc013RFFZSktvWklodmNOQVFFTQpCUUF3T2pFNE1EWUdBMVVFQXd3dk5EWTJZakF4TnpjdE9ERmpPQzAwTjJFd0xUbG1NbVF0TmpNeE1EWXhaR1l4Ck1EWTNJRkJ5YjJwbFkzUWdRMEV3SGhjTk1qTXdOREV4TURFeE5URTFXaGNOTXpNd05EQTRNREV4TlRFMVdqQTYKTVRnd05nWURWUVFEREM4ME5qWmlNREUzTnkwNE1XTTRMVFEzWVRBdE9XWXlaQzAyTXpFd05qRmtaakV3TmpjZwpVSEp2YW1WamRDQkRRVENDQWFJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dHUEFEQ0NBWW9DZ2dHQkFPcDJuS1FqCkNQYk5JcjdVeFN3dGRqZ01FOVo1di9STStxYjZuajJpRFBCc1R1eFRBZmFrcDJNUXM0eWxzaGsza0loUHE4SC8KZWNyMElMMlNtczAyY0lJN0puTVhyUjJKaGVpYVNjaUVKN3p0ZmRxUXNMOUw3OVpwblRPOVpXaCtITmozN1lZUQoySnhzY0hMeitiVENXMkJnMkh6V2ZiOVVQa0hRZlhSZjVHd0dBQnZtNEVkU3R1ZTlBUVROTGUrL3BFSzIvMUZnCmtuK0ZCbWU3WWdWdlJTc0xSdVdMUE1ES0kyMTNHemRFVjBpSjEwbkZlTjFsY3BncStXTFdNSklxVWpNa0Y1ZTkKL2dDNi9aRWk0U1Z0eVd0UW5nL1Y4cG1IbU1jekRtaUpHUTdYVlhOS2dUeTREUHRPOExLOVNOTkJZZXFybTFKOAp1Q3hEdXVrVUZYbUhlMGI3a08xamVFVGJ6Z2ZCajI5ZERTRTJJeEUxVXVzT1JqTy9SUFFwSmJlNkRXT2hlOVh4CktJKzhoam9GQVJ2bGtLUTJDK20rR3V5RnV6K1lyNlFKQk52MWkvb2V4SVIvMWxaSTM0SjF0RUVRbzRwbmRWRGYKK0V4citnd1pkTDhJTm9GRG1LeGpDdENpb2JhdHJlTUZhRVRQTC9uTWpnbWdGTmVFaWZQN0ZZQi9Ed0lEQVFBQgpvejh3UFRBZEJnTlZIUTRFRmdRVUJDb1pkci9WWWV6ZnRzZkhDVzR6cGFBUEhtOHdEd1lEVlIwVEJBZ3dCZ0VCCi93SUJBREFMQmdOVkhROEVCQU1DQVFZd0RRWUpLb1pJaHZjTkFRRU1CUUFEZ2dHQkFES1ZTVzhzSXlacFRRYjUKWFdqZVErSTdCUzcrNzhCbEpCVlBGdzQxSDdGNm5TVGl2a3htWGw4Y3BUa3FPQXIwR2VJVEdCSTJyZEpRYUF4Qwo2aHU1dGRtNENseFRLbm9KMHc2ems3eUx0U21TQ25QVDJUMkJJL2RQc21Tc3BsVS9kb2VTMXJHUys3R1UwaUdVCkpOMmJMcUZkcmcyejNKQ0lhc3pXMWJzaWtKdzN2UFBPUmxtSmwwUUg4MVRaR0NxdmZJTkVKSFk2Nk1RYjZuR2oKMjNaVVFyTEZHTm1rak81a250QlNHNGRvcGN6bkNTN1gxZjFHM01Vc3g1eUt4cGF5VkNlQzFJK3JJQnJvYU5BSgpnYTJtWWJnaS84R1VZYi96MmZ1M2ZtTmFYN050cEgyQjVPQ3Z2TXR0bkVGNXR4NGU5cXNzOEFWTXJOQ2NVeEJpCmVVZ21NUHkyOXU4ZGZiUDd6dVYvYVdXMC9SbllPU1FSQmJhZ3dGVXkvRE1zQmZJSERGem5HcVJFRDI5NGhRNnEKWjBhVitRa01HZHVEWEpoaW93cnJTTGVOM0xyQzR0UjE2ZjJZWVVCQ3FzK256NGNCeDRqcC9ybW1BVUdnR0JsSwpBRnBZMGszM1ZmSUcwdklSejBSdXdkekswc3hCR0M4L2pHaE0vd2RNdUh2aEpJcjRYUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KIgoKIyBjb25uZWN0IHNlY3VyZWx5IHRvIHJlbW90ZSBNeVNRTCBzZXJ2ZXIgYW5kIGRhdGFiYXNlCm15ZGIuYWl2ZW4gPC0gIGRiQ29ubmVjdChSTXlTUUw6Ok15U1FMKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgdXNlciA9IGRiX3VzZXJfYWl2ZW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgcGFzc3dvcmQgPSBkYl9wd2RfYWl2ZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICBkYm5hbWUgPSBkYl9uYW1lX2FpdmVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGhvc3QgPSBkYl9ob3N0X2FpdmVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBvcnQgPSBkYl9wb3J0X2FpdmVuLAogICAgICAgICAgICAgICAgICAgICAgICAgc3NsbW9kZSA9ICJyZXF1aXJlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNzbGNlcnQgPSBkYl9jZXJ0KQpgYGAKCk5leHQsIHdlIHdpbGwgdGVzdCB0aGUgY29ubmVjdGlvbiBieSBjcmVhdGluZyBhIHRhYmxlIHdpdGggYSBDSEVDSyBjb25zdHJhaW50LCBpbnNlcnRpbmcgcm93cywgYW5kIHRoZW4gcXVlcnlpbmcgdGhlIHRhYmxlLgoKYGBge3NxbCBjb25uZWN0aW9uPW15ZGIuYWl2ZW59CmRyb3AgdGFibGUgaWYgZXhpc3RzIGNvdXJzZXMKYGBgCgpgYGB7c3FsIGNvbm5lY3Rpb249bXlkYi5haXZlbn0KY3JlYXRlIHRhYmxlIGlmIG5vdCBleGlzdHMgY291cnNlcyAoCiAgY2lkIElOVEVHRVIgTk9UIE5VTEwgUFJJTUFSWSBLRVksCiAgdGl0bGUgdmFyY2hhcigzMikgTk9UIE5VTEwsCiAgY3JlZGl0cyBJTlRFR0VSIE5PVCBOVUxMLAogIGNoZWNrIChjcmVkaXRzID4gMSkKKQpgYGAKCk5vdGljZSB0aGF0IHRoZSB0ZXh0IGZpZWxkcyAoY29sdW1ucykgYXJlIGVuY2xvc2VkIGluIHNpbmdsZSBxdW90ZXMgcmF0aGVyIHRoYW4gZG91YmxlIHF1b3Rlcy4gVGhpcyBpcyByZXF1aXJlZCBmb3IgdGhlIHZlcnNpb24gb2YgTXlTUUwgaG9zdGVkIGJ5IEFpdmVuLgoKYGBge3NxbCBjb25uZWN0aW9uPW15ZGIuYWl2ZW59Cmluc2VydCBpbnRvIGNvdXJzZXMgKGNpZCx0aXRsZSxjcmVkaXRzKSB2YWx1ZXMgCiAgKDExMDAsJ0NTIGFuZCBBcHBsaWNhdGlvbicsIDQpLAogICgyMDAwLCdQcmluYyBJbmZvIFNjaScsIDQpLAogICg1MjAwLCdEQk1TJywgNCksCiAgKDUwMzAsJ0ludHJvIE1MJywgMykKYGBgCgpgYGB7c3FsIGNvbm5lY3Rpb249bXlkYi5haXZlbn0KaW5zZXJ0IGludG8gY291cnNlcyB2YWx1ZXMgKDEyMDAsJ1dlYiBTeXN0ZW1zJywgNCkKYGBgCgpMZXQncyBlbnN1cmUgdGhlIGRhdGEgaXMgdGhlcmU6CgpgYGB7c3FsIGNvbm5lY3Rpb249bXlkYi5haXZlbn0Kc2VsZWN0ICogZnJvbSBjb3Vyc2VzOwpgYGAKCmBgYHtzcWwgY29ubmVjdGlvbj1teWRiLmFpdmVufQpzZWxlY3QgY291bnQoKikgZnJvbSBjb3Vyc2VzOwpgYGAKCkxvb2tzIGxpa2UgYWxsIGlzIHdvcmtpbmcuCgpMZXQncyBleGVjdXRlIHNvbWUgU1FMIHdpdGggQWl2ZW4gdXNpbmcgUiBjb2RlIHJhdGhlciB0aGFuIGEge3NxbH0gYmxvY2suCgpgYGB7cn0Kc3FsIDwtICJzZWxlY3QgKiBmcm9tIGNvdXJzZXMiCnJzIDwtIGRiR2V0UXVlcnkoY29uID0gbXlkYi5haXZlbiwKICAgICAgICAgICAgICAgICBzdGF0ZW1lbnQgPSBzcWwpCgpwcmludChycykKYGBgCgpBIGtleSBkcmF3YmFjayB0byBNeVNRTCBvbiAqQWl2ZW4qIGlzIHRoYXQgaXMgZG9lcyBub3QgYWxsb3cgYnVsayBpbnNlcnRpb24gb2YgZGF0YSB2aWEgYGRiV3JpdGVUYWJsZSgpYCwgc28gdGhlIGNvZGUgYmVsb3cgZG9lcyBub3Qgd29yay4KCmBgYHtyIGV2YWw9RiwgZWNobz1UfQpkZiA8LSBkYXRhLmZyYW1lKGNpZCA9IDkwMDA6OTk5OSkKCmRmJHRpdGxlIDwtICJubyB0aXRsZSIKZGYkY3JlZGl0cyA8LSA0CgpzdGF0dXMgPC0gZGJXcml0ZVRhYmxlKG15ZGIuYWl2ZW4sICJjb3Vyc2VzIiwgZGYsIAogICAgICAgICAgICAgICAgICAgICAgIG92ZXJ3cml0ZSA9IEYsIGFwcGVuZCA9IFQsIAogICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcz1GQUxTRSkKYGBgCgohW10oaW1hZ2VzL2FpdmVuLWJ1bGstbG9hZC1lcnJvci5qcGcpe3dpZHRoPSI2MCUifQoKU28sIGFueSBpbnNlcnRpb24gbXVzdCBiZSBkb25lIHVzaW5nIFNRTCBJTlNFUlQgc3RhdGVtZW50cywgcG9zc2libHkgdXNpbmcgYmF0Y2ggaW5zZXJ0aW9uICgqaS5lLiosIG11bHRpcGxlIHJvd3MgaW4gYSBzaW5nbGUgSU5TRVJUIHN0YXRlbWVudCkgdG8gcmVkdWNlIHRoZSBwZXJmb3JtYW5jZSBvdmVyaGVhZCBhbmQgc3BlZWQgdXAgaW5zZXJ0aW9uLiBUaGlzIGlzIG5vdCBhbiBhY3R1YWwgaXNzdWUgYXMgYnVsayBsb2FkaW5nIGlzIHF1aXRlIHNsb3cgYW5kIG5vdCBzY2FsYWJsZSwgc28gaXQgc2hvdWxkIGJlIGF2b2lkZWQgcmVnYXJkbGVzcyBvZiBzdXBwb3J0IC0tIGFsdGhvdWdoIGl0IGlzIHF1aXRlIGNvbnZlbmllbnQuCgpgYGB7ciBlY2hvPUZ9CnN0YXR1cyA8LSBkYkRpc2Nvbm5lY3QobXlkYi5haXZlbikKYGBgCgojIyMjIENvbW1vbiBQcm9ibGVtcwoKLSAgIHRoZSBmcmVlIGFjY291bnQgaGFzIGEgbWF4aW11bSBkYXRhYmFzZSBjYXBhY2l0eSBvZiA1TUIKLSAgIGxvY2FsIGZpcmV3YWxsIG9yIGFudGktdmlydXMgc29mdHdhcmUgdGhhdCBibG9ja3MgcG9ydCAzMzA2OyBkaXNhYmxlIGlmIHRoZXJlIGFyZSBjb25uZWN0aW9uIGlzc3VlcwotICAgbm90IGNsaWNraW5nIG9uIHRoZSBhY3RpdmF0aW9uIGxpbmsgaW4gdGhlIGVtYWlsIHNlbnQgYWZ0ZXIgYWNjb3VudCBjcmVhdGlvbiAoYW5kIGNoZWNraW5nIHNwYW0gdG8gZW5zdXJlIGl0IGRpZCBub3QgZW5kIHVwIHRoZXJlKQotICAgbm8gc3VwcG9ydCBmb3IgYGRiV3JpdGVUYWJsZSgpYAoKQSBjb21tb24gcGl0ZmFsbCBpcyB0aGF0IHlvdXIgbG9jYWwgY29tcHV0ZXIgaGFzIGEgZmlyZXdhbGwgY29uZmlndXJlZCB0aGF0IGRvZXMgbm90IGFsbG93IGEgY2xpZW50IHRvIGNvbm5lY3QgdG8gdGhlIGNsb3VkIGRhdGFiYXNlIChtZWFuaW5nIHRoZSBwb3J0IGlzIGJsb2NrZWQpLiBPbmUgd2F5IHRvICJ0ZXN0IiBmb3IgdGhhdCBpcyB0byBydW4geW91ciBjb25uZWN0aW9uIGNvZGUgb24gPGh0dHA6Ly9wb3NpdC5jbG91ZD4gLS0gaWYgaXQgd29ya3MgdGhlcmUsIHRoZW4gaXQgaXMgYSBwcm9ibGVtIHdpdGggeW91ciBsb2NhbCBzZXR1cC4gQWx0ZXJuYXRpdmVseSwgdHJ5IGNvbm5lY3RpbmcgdG8geW91ciBNeVNRTCBmcm9tIHRoZSBNeVNRTCBXb3JrYmVuY2guIElmIHlvdSBjYW4gY29ubmVjdCBmcm9tIHRoZSB3b3JrYmVuY2ggdGhlbiB0aGUgY2F1c2UgaXMgd2l0aCB5b3VyIGNsaWVudCBjb2RlLgoKKipDQVVUSU9OKio6IEJvdGggQWl2ZW4gYW5kIGRiNGZyZWUgZG8gbm90IGFsbG93IHRoZSB1c2Ugb2YgZGJXcml0ZVRhYmxlKCk7IHRoaXMgYXBwcm9hY2ggb2YgYnVsay1sb2FkaW5nIGRvZXMgbm90IHNjYWxlLCBzbyBpdCBzaG91bGQgYmUgYXZvaWRlZCBhbnl3YXkuIFNvLCB5b3UgbXVzdCB1c2UgSU5TRVJUIFNRTCBzdGF0ZW1lbnRzIHRvIHdyaXRlIHRoZSBkYXRhIGludG8gQWl2ZW4gYW5kIGRiNGZyZWUuIEluIGFkZGl0aW9uLCBmb3IgQWl2ZW4sIGFsbCB0ZXh0IGZpZWxkcyBtdXN0IGJlIGVuY2xvc2VkIGluIHNpbmdsZSByYXRoZXIgdGhhbiBkb3VibGUgcXVvdGVzLiBJbnNlcnRpbmcgZGF0YSByb3ctYnktcm93IGlzIHZlcnkgc2xvdywgc28gaW5zZXJ0IDEwMCBvciA1MDAgcm93cyBhdCBhIHRpbWUgKHJlbWVtYmVyIHRoYXQgYW4gSU5TRVJUIHN0YXRlbWVudCBjYW4gaW5zZXJ0IG11bHRpcGxlIHJvd3MgYXQgYSB0aW1lKS4KCiMjIyMgUHJvYmxlbSBSb290IENhdXNlIEFuYWx5c2lzCgpJZiB5b3UgaGF2ZSBjcmVhdGVkIGFuIGFjY291bnQgb24gQWl2ZW4gKGFuZCBjb25maWd1cmVkIGEgZGF0YWJhc2UpIGJ1dCB5b3UgY2Fubm90IGNvbm5lY3QsIHRoZW4gaGVyZSBhcmUgc29tZSBzdWdnZXN0aW9ucyBmb3IgaWRlbnRpZnlpbmcgdGhlIHJvb3QgY2F1c2U6CgoxLiAgdmVyaWZ5IHRoYXQgdGhlIGRhdGFiYXNlIHNlcnZpY2UgaXMgcnVubmluZwoyLiAgY2hlY2sgdGhhdCB0aGUgY29ubmVjdGlvbiBwYXJhbWV0ZXJzIGFyZSBjb3JyZWN0CjMuICBjaGVjayBmb3IgYW55IGZpcmV3YWxsIGlzc3VlcyAtLSB0byB0ZXN0IHRoaXMsIHVwbG9hZCB0aGUgY29ubmVjdGlvbiBjb2RlIChhIHNhbmRib3ggdGhhdCBxdWlja2x5IGNoZWNrcykgdG8gKnBvc2l0LmNsb3VkKiBhbmQgcnVuIGZyb20gdGhlcmU7IGlmIGl0IHJ1bnMgb24gKnBvc2l0LmNsb3VkKiBhbmQgbm90IGxvY2FsbHksIGl0IGlzIGxpa2VseSBhIGZpcmV3YWxsIG9yIGFudGktdmlydXMgaXNzdWUKClRoZSBtb3N0IGNvbW1vbiByZWFzb24gZm9yIG5vdCBiZWluZyBhYmxlIHRvIGNvbm5lY3QgZnJvbSB5b3VyIGNsaWVudCB0byB0aGUgZGF0YWJhc2UsIGlzIHRoYXQgdGhlIHNlcnZlciBoYXNuJ3QgYmVlbiBzdGFydGVkLiBHbyB0byB0aGUgQWl2ZW4gY29uc29sZSBhbmQgbWFrZSBzdXJlIGl0J3MgcnVubmluZzoKCiFbXShpbWFnZXMvYWl2ZW4tY29uc29sZS1teXNxbC1zZXJ2aWNlLXJ1bm5pbmcucG5nKXt3aWR0aD0iNzUlIn0KCkFsc28sIGtlZXAgaW4gbWluZDoKCi0gICBBaXZlbiBkb2VzIG5vdCBzdXBwb3J0IGBkYldyaXRlVGFibGUoKWAKLSAgIE9ubHkgcmVjZW50IHZlcnNpb25zIG9mIE15U1FMIHN1cHBvcnQgKkNIRUNLKiBjb25zdHJhaW50cwoKIyMjIERpc2Nvbm5lY3QgZnJvbSBEYXRhYmFzZQoKRGlzY29ubmVjdCBmcm9tIHRoZSBkYXRhYmFzZSAoaW1wb3J0YW50IGFzIGRhdGFiYXNlIHNlcnZlcnMgaGF2ZSBsaW1pdGVkIG51bWJlcnMgb2YgY29ubmVjdGlvbiBhbmQgZWFjaCBjb25uZWN0aW9uIHVzZXMgYSByZXNvdXJjZSkuIFVzZSBgZGJEaXNjb25uZWN0KClgIG9uY2UgeW91IG5vIGxvbmdlciBoYXZlIGEgbmVlZCB0byBhY2Nlc3MgdGhlIGRhdGFiYXNlLiBUaGUgY29kZSBiZWxvdyBkZW1vbnN0cmF0ZXMgdGhpcy4KCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBldmFsPUYsIGVjaG89VH0Kc3RhdHVzIDwtIGRiRGlzY29ubmVjdChteWRiLmFpdmVuKQpgYGAKCiMjIERhdGFiYXNlIEFkbWluaXN0cmF0aW9uIHdpdGggTXlTUUwgV29ya2JlbmNoCgpXZSByZWNvbW1lbmQgdGhhdCB5b3UgaW5zdGFsbCBbTXlTUUwgV29ya2JlbmNoXShodHRwczovL2Rldi5teXNxbC5jb20vZG93bmxvYWRzL3dvcmtiZW5jaC8pIHRvIGhlbHAgYWRtaW5pc3RlciB5b3VyIE15U1FMIGRhdGFiYXNlLiBVc2UgdGhlIHNhbWUgY29ubmVjdGlvbiBpbmZvcm1hdGlvbiB0byBjb25uZWN0IHRvIHlvdXIgZGF0YWJhc2UgZnJvbSBNeVNRTCBXb3JrYmVuY2guCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIEZpbGVzICYgUmVzb3VyY2VzCgpgYGB7ciB6aXBGaWxlcywgZWNobz1GQUxTRX0KemlwTmFtZSA9IHNwcmludGYoIkxlc3NvbkZpbGVzLSVzLSVzLnppcCIsIAogICAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwKICAgICAgICAgICAgICAgICBwYXJhbXMkbnVtYmVyKQoKdGV4dEFMaW5rID0gcGFzdGUwKCJBbGwgRmlsZXMgZm9yIExlc3NvbiAiLCAKICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LCIuIixwYXJhbXMkbnVtYmVyKQoKIyBkb3dubG9hZEZpbGVzTGluaygpIGlzIGluY2x1ZGVkIGZyb20gX2luc2VydDJEQi5SCmtuaXRyOjpyYXdfaHRtbChkb3dubG9hZEZpbGVzTGluaygiLiIsIHppcE5hbWUsIHRleHRBTGluaykpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBBY2tub3dsZWRnZW1lbnRzCgpbQ2xhdWRlIFNvbm5ldCA0XShodHRwczovL2NsYXVkZS5haS8pIHdhcyB1c2VkIGluIHRoZSBwcmVwYXJhdGlvbiBvZiB0aGlzIGxlc3NvbiBpbiBhZGRpdGlvbiB0byB3ZWIgc2VhcmNoZXMuCgojIyBFcnJhdGEKCltMZXQgdXMga25vd10oaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLzIxMjE4NzA3Mjc4NDE1Nyl7dGFyZ2V0PSJfYmxhbmsifS4K