Step 1: Data Analysis & Visualization

The histograms above show:
1. Trace Distribution: Most states have trace ≈ 1, confirming proper normalization.
2. Purity Distribution: Purity (Tr(ρ²)) varies, indicating a mix of pure and mixed states.
3. Eigenvalue Distribution: The eigenvalues are mostly positive and sum to 1, validating the dataset.


Step 2: Feature Extraction for ML Models

Now, convert each quantum state (2x2 matrix) into a feature vector for machine learning: - Flatten the density matrix into a vector.
- Extract purity, trace, and eigenvalues as features.
- Store in a structured format for further analysis.


Step 2 Completed: Feature Extraction

I have transformed each quantum state (2x2 matrix) into a structured feature set, including: - Trace & Purity (validation metrics)
- Eigenvalues (quantum state properties)
- Flattened real & imaginary parts of the density matrix


Step 3: Dataset Preparation for Capstone

Now, I’ll convert this dataset into CSV format for easy integration with ML frameworks.


Step 3 Completed: Dataset Saved as CSV

Your Quantum State Features dataset is now available for download.

📂 Download Quantum_State_Features.csv


Step 1: Data Analysis & Visualization

The histograms above show: 1. Trace Distribution: Most states have trace ≈ 1, confirming proper normalization. 2. Purity Distribution: Purity (Tr(ρ²)) varies, indicating a mix of pure and mixed states. 3. Eigenvalue Distribution: The eigenvalues are mostly positive and sum to 1, validating the dataset.


Step 2: Feature Extraction for ML Models

Now, convert each quantum state (2x2 matrix) into a feature vector for machine learning: - Flatten the density matrix into a vector. - Extract purity, trace, and eigenvalues as features. - Store in a structured format for further analysis.

Step 2 Completed: Feature Extraction

I have transformed each quantum state (2x2 matrix) into a structured feature set, including: - Trace & Purity (validation metrics) - Eigenvalues (quantum state properties) - Flattened real & imaginary parts of the density matrix


Step 3: Dataset Preparation for Capstone

Now, I’ll convert this dataset into CSV format for easy integration with ML frameworks.

Step 3 Completed: Dataset Saved as CSV

Your Quantum State Features dataset is now available for download.

Download Quantum_State_Features.csv

import matplotlib.pyplot as plt
import seaborn as sns

# Function to compute quantum state statistics
def compute_statistics(dataset):
    traces = []
    purities = []
    eigenvalues = []

    for state in dataset:
        trace_val = np.trace(state)  # Should be ~1 for valid density matrices
        purity = np.trace(state @ state)  # Purity: Tr(ρ²), ranges from 1 (pure) to 1/dim (maximally mixed)
        eigvals = np.linalg.eigvals(state)  # Eigenvalues of the density matrix

        traces.append(trace_val.real)  # Trace should be real
        purities.append(purity.real)  # Purity should be real
        eigenvalues.extend(eigvals.real)  # Store real parts of eigenvalues

    return traces, purities, eigenvalues

# Compute statistics
traces, purities, eigenvalues = compute_statistics(dataset)

# Plot distributions of trace, purity, and eigenvalues
fig, axs = plt.subplots(3, 1, figsize=(8, 12))

sns.histplot(traces, bins=50, kde=True, ax=axs[0])
axs[0].set_title("Trace Distribution of Quantum States")
axs[0].set_xlabel("Trace Value")
axs[0].set_ylabel("Frequency")

sns.histplot(purities, bins=50, kde=True, ax=axs[1])
axs[1].set_title("Purity Distribution of Quantum States")
axs[1].set_xlabel("Purity (Tr(ρ²))")
axs[1].set_ylabel("Frequency")

sns.histplot(eigenvalues, bins=50, kde=True, ax=axs[2])
axs[2].set_title("Eigenvalue Distribution of Quantum States")
axs[2].set_xlabel("Eigenvalue")
axs[2].set_ylabel("Frequency")

plt.tight_layout()
plt.show()
import pandas as pd

# Function to extract features from quantum states
def extract_features(dataset):
    feature_list = []
    
    for state in dataset:
        trace_val = np.trace(state).real  # Real part of trace
        purity = np.trace(state @ state).real  # Tr(ρ²)
        eigvals = np.linalg.eigvals(state).real  # Eigenvalues
        
        # Flatten density matrix into vector (real & imaginary parts separately)
        flattened_real = state.real.flatten()
        flattened_imag = state.imag.flatten()
        
        # Combine all features
        features = np.concatenate(([trace_val, purity], eigvals, flattened_real, flattened_imag))
        feature_list.append(features)
    
    return feature_list

# Extract features
features = extract_features(dataset)

# Convert to Pandas DataFrame for easy analysis
feature_columns = ["Trace", "Purity", "Eigval1", "Eigval2"] + \
                  [f"Real_{i}" for i in range(4)] + [f"Imag_{i}" for i in range(4)]

df_features = pd.DataFrame(features, columns=feature_columns)

# Display extracted feature dataframe
import ace_tools as tools
tools.display_dataframe_to_user(name="Quantum State Features", dataframe=df_features)

Step 1: Data Analysis & Visualization

The histograms below show:

  1. Trace Distribution: Most states have trace ≈ 1, confirming proper normalization.
  2. Purity Distribution: Purity (Tr(ρ²)) varies, indicating a mix of pure and mixed states.
  3. Eigenvalue Distribution: The eigenvalues are mostly positive and sum to 1, validating the dataset.

Code for Visualization

import matplotlib.pyplot as plt
import seaborn as sns

# Function to compute quantum state statistics
def compute_statistics(dataset):
    traces = []
    purities = []
    eigenvalues = []

    for state in dataset:
        trace_val = np.trace(state)  # Should be ~1 for valid density matrices
        purity = np.trace(state @ state)  # Purity: Tr(ρ²), ranges from 1 (pure) to 1/dim (maximally mixed)
        eigvals = np.linalg.eigvals(state)  # Eigenvalues of the density matrix

        traces.append(trace_val.real)  # Trace should be real
        purities.append(purity.real)  # Purity should be real
        eigenvalues.extend(eigvals.real)  # Store real parts of eigenvalues

    return traces, purities, eigenvalues

# Compute statistics
traces, purities, eigenvalues = compute_statistics(dataset)

# Plot distributions of trace, purity, and eigenvalues
fig, axs = plt.subplots(3, 1, figsize=(8, 12))

sns.histplot(traces, bins=50, kde=True, ax=axs[0])
axs[0].set_title("Trace Distribution of Quantum States")
axs[0].set_xlabel("Trace Value")
axs[0].set_ylabel("Frequency")

sns.histplot(purities, bins=50, kde=True, ax=axs[1])
axs[1].set_title("Purity Distribution of Quantum States")
axs[1].set_xlabel("Purity (Tr(ρ²))")
axs[1].set_ylabel("Frequency")

sns.histplot(eigenvalues, bins=50, kde=True, ax=axs[2])
axs[2].set_title("Eigenvalue Distribution of Quantum States")
axs[2].set_xlabel("Eigenvalue")
axs[2].set_ylabel("Frequency")

plt.tight_layout()
plt.show()

Step 2: Feature Extraction for ML Models

Now, I’ll convert each quantum state (2x2 matrix) into a feature vector for machine learning: - Flatten the density matrix into a vector. - Extract purity, trace, and eigenvalues as features. - Store in a structured format for further analysis.

Feature Extraction Code

import pandas as pd

# Function to extract features from quantum states
def extract_features(dataset):
    feature_list = []
    
    for state in dataset:
        trace_val = np.trace(state).real  # Real part of trace
        purity = np.trace(state @ state).real  # Tr(ρ²)
        eigvals = np.linalg.eigvals(state).real  # Eigenvalues
        
        # Flatten density matrix into vector (real & imaginary parts separately)
        flattened_real = state.real.flatten()
        flattened_imag = state.imag.flatten()
        
        # Combine all features
        features = np.concatenate(([trace_val, purity], eigvals, flattened_real, flattened_imag))
        feature_list.append(features)
    
    return feature_list

# Extract features
features = extract_features(dataset)

# Convert to Pandas DataFrame for easy analysis
feature_columns = ["Trace", "Purity", "Eigval1", "Eigval2"] + \
                  [f"Real_{i}" for i in range(4)] + [f"Imag_{i}" for i in range(4)]

df_features = pd.DataFrame(features, columns=feature_columns)

# Display extracted feature dataframe
import ace_tools as tools
tools.display_dataframe_to_user(name="Quantum State Features", dataframe=df_features)

Step 2 Completed: Feature Extraction

I have transformed each quantum state (2x2 matrix) into a structured feature set, including: - Trace & Purity (validation metrics) - Eigenvalues (quantum state properties) - Flattened real & imaginary parts of the density matrix

You can now use this for machine learning models.


Step 3: Dataset Preparation for Capstone

Now, I’ll convert this dataset into CSV format for easy integration with ML frameworks.

Convert to CSV

# Save extracted features as a CSV file for ML processing
csv_output_path = "/mnt/data/Quantum_State_Features.csv"
df_features.to_csv(csv_output_path, index=False)

# Provide the CSV file for download
csv_output_path

Step 3 Completed: Dataset Saved as CSV

Your Quantum State Features dataset is now available for download.

Download Quantum_State_Features.csv

This file contains the extracted features from the quantum dataset, ready for machine learning and Capstone analysis.

Step 1: Data Analysis & Visualization

The histograms below show:

  1. Trace Distribution: Most states have trace ≈ 1, confirming proper normalization.
  2. Purity Distribution: Purity (Tr(ρ²)) varies, indicating a mix of pure and mixed states.
  3. Eigenvalue Distribution: The eigenvalues are mostly positive and sum to 1, validating the dataset.

Code for Visualization

import matplotlib.pyplot as plt
import seaborn as sns

# Function to compute quantum state statistics
def compute_statistics(dataset):
    traces = []
    purities = []
    eigenvalues = []

    for state in dataset:
        trace_val = np.trace(state)  # Should be ~1 for valid density matrices
        purity = np.trace(state @ state)  # Purity: Tr(ρ²), ranges from 1 (pure) to 1/dim (maximally mixed)
        eigvals = np.linalg.eigvals(state)  # Eigenvalues of the density matrix

        traces.append(trace_val.real)  # Trace should be real
        purities.append(purity.real)  # Purity should be real
        eigenvalues.extend(eigvals.real)  # Store real parts of eigenvalues

    return traces, purities, eigenvalues

# Compute statistics
traces, purities, eigenvalues = compute_statistics(dataset)

# Plot distributions of trace, purity, and eigenvalues
fig, axs = plt.subplots(3, 1, figsize=(8, 12))

sns.histplot(traces, bins=50, kde=True, ax=axs[0])
axs[0].set_title("Trace Distribution of Quantum States")
axs[0].set_xlabel("Trace Value")
axs[0].set_ylabel("Frequency")

sns.histplot(purities, bins=50, kde=True, ax=axs[1])
axs[1].set_title("Purity Distribution of Quantum States")
axs[1].set_xlabel("Purity (Tr(ρ²))")
axs[1].set_ylabel("Frequency")

sns.histplot(eigenvalues, bins=50, kde=True, ax=axs[2])
axs[2].set_title("Eigenvalue Distribution of Quantum States")
axs[2].set_xlabel("Eigenvalue")
axs[2].set_ylabel("Frequency")

plt.tight_layout()
plt.show()

Step 2: Feature Extraction for ML Models

Now, I’ll convert each quantum state (2x2 matrix) into a feature vector for machine learning: - Flatten the density matrix into a vector. - Extract purity, trace, and eigenvalues as features. - Store in a structured format for further analysis.

Feature Extraction Code

import pandas as pd

# Function to extract features from quantum states
def extract_features(dataset):
    feature_list = []
    
    for state in dataset:
        trace_val = np.trace(state).real  # Real part of trace
        purity = np.trace(state @ state).real  # Tr(ρ²)
        eigvals = np.linalg.eigvals(state).real  # Eigenvalues
        
        # Flatten density matrix into vector (real & imaginary parts separately)
        flattened_real = state.real.flatten()
        flattened_imag = state.imag.flatten()
        
        # Combine all features
        features = np.concatenate(([trace_val, purity], eigvals, flattened_real, flattened_imag))
        feature_list.append(features)
    
    return feature_list

# Extract features
features = extract_features(dataset)

# Convert to Pandas DataFrame for easy analysis
feature_columns = ["Trace", "Purity", "Eigval1", "Eigval2"] + \
                  [f"Real_{i}" for i in range(4)] + [f"Imag_{i}" for i in range(4)]

df_features = pd.DataFrame(features, columns=feature_columns)

# Display extracted feature dataframe
import ace_tools as tools
tools.display_dataframe_to_user(name="Quantum State Features", dataframe=df_features)

Step 2 Completed: Feature Extraction

I have transformed each quantum state (2x2 matrix) into a structured feature set, including: - Trace & Purity (validation metrics) - Eigenvalues (quantum state properties) - Flattened real & imaginary parts of the density matrix

You can now use this for machine learning models.

Step 3: Dataset Preparation for Capstone

Now, I’ll convert this dataset into CSV format for easy integration with ML frameworks.

Convert to CSV

# Save extracted features as a CSV file for ML processing
csv_output_path = "/mnt/data/Quantum_State_Features.csv"
df_features.to_csv(csv_output_path, index=False)

# Provide the CSV file for download
csv_output_path

Step 3 Completed: Dataset Saved as CSV

Your Quantum State Features dataset is now available for download.

Download Quantum_State_Features.csv

This file contains the extracted features from the quantum dataset, ready for machine learning and Capstone analysis.

import pandas as pd

# Function to extract features from quantum states
def extract_features(dataset):
    feature_list = []
    
    for state in dataset:
        trace_val = np.trace(state).real  # Real part of trace
        purity = np.trace(state @ state).real  # Tr(ρ²)
        eigvals = np.linalg.eigvals(state).real  # Eigenvalues
        
        # Flatten density matrix into vector (real & imaginary parts separately)
        flattened_real = state.real.flatten()
        flattened_imag = state.imag.flatten()
        
        # Combine all features
        features = np.concatenate(([trace_val, purity], eigvals, flattened_real, flattened_imag))
        feature_list.append(features)
    
    return feature_list

# Extract features
features = extract_features(dataset)

# Convert to Pandas DataFrame for easy analysis
feature_columns = ["Trace", "Purity", "Eigval1", "Eigval2"] + \
                  [f"Real_{i}" for i in range(4)] + [f"Imag_{i}" for i in range(4)]

df_features = pd.DataFrame(features, columns=feature_columns)

# Display extracted feature dataframe
import ace_tools as tools
tools.display_dataframe_to_user(name="Quantum State Features", dataframe=df_features)
# Save extracted features as a CSV file for ML processing
csv_output_path = "/mnt/data/Quantum_State_Features.csv"
df_features.to_csv(csv_output_path, index=False)

# Provide the CSV file for download
csv_output_path
import matplotlib.pyplot as plt
import seaborn as sns

# Function to compute quantum state statistics
def compute_statistics(dataset):
    traces = []
    purities = []
    eigenvalues = []

    for state in dataset:
        trace_val = np.trace(state)  # Should be ~1 for valid density matrices
        purity = np.trace(state @ state)  # Purity: Tr(ρ²), ranges from 1 (pure) to 1/dim (maximally mixed)
        eigvals = np.linalg.eigvals(state)  # Eigenvalues of the density matrix

        traces.append(trace_val.real)  # Trace should be real
        purities.append(purity.real)  # Purity should be real
        eigenvalues.extend(eigvals.real)  # Store real parts of eigenvalues

    return traces, purities, eigenvalues

# Compute statistics
traces, purities, eigenvalues = compute_statistics(dataset)

# Plot distributions of trace, purity, and eigenvalues
fig, axs = plt.subplots(3, 1, figsize=(8, 12))

sns.histplot(traces, bins=50, kde=True, ax=axs[0])
axs[0].set_title("Trace Distribution of Quantum States")
axs[0].set_xlabel("Trace Value")
axs[0].set_ylabel("Frequency")

sns.histplot(purities, bins=50, kde=True, ax=axs[1])
axs[1].set_title("Purity Distribution of Quantum States")
axs[1].set_xlabel("Purity (Tr(ρ²))")
axs[1].set_ylabel("Frequency")

sns.histplot(eigenvalues, bins=50, kde=True, ax=axs[2])
axs[2].set_title("Eigenvalue Distribution of Quantum States")
axs[2].set_xlabel("Eigenvalue")
axs[2].set_ylabel("Frequency")

plt.tight_layout()
plt.show()

Training the STL 3D Model (SolarCoronalComplex25.stl) for Your Capstone Project GPT

To integrate the Solar Coronal Complex 3D Model into your Capstone GPT, I will: 1. Extract Features from the STL File (e.g., vertices, faces, mesh properties). 2. Convert the 3D Structure into a Learnable Representation (e.g., voxel grid, point cloud, or mesh embeddings). 3. Integrate with Your Quantum GIS GPT (e.g., use transformers or deep learning models to analyze and interact with 3D structures). 4. Fine-tune GPT for Quantum GIS & 3D Analysis (e.g., provide text-based descriptions or automated insights about the model).


### Step 1: Extracting Features from the STL File

I’ll now extract the vertices, faces, and mesh properties to understand the structure.

The STL file is too large to load into memory, causing a MemoryError. This suggests that the model contains a very high number of vertices and faces.


### Fix: Process the STL File in Chunks

Since we can’t load the entire model at once, I will: 1. Extract metadata without fully loading the mesh. 2. Downsample the mesh (reduce complexity) if needed. 3. Convert it into a lightweight representation (e.g., voxel grid or point cloud for GPT training).

Let me first extract basic metadata without loading the full mesh.

The SolarCoronalComplex25.stl file is ~108 MB, which is quite large for direct processing. Instead of fully loading it, I’ll extract a subset of vertices and faces to work with a smaller, manageable portion of the model.

I’ll now attempt to stream the STL file and extract a downsampled version for further training.

Even with streaming disabled, the STL file is too large to process in memory. Since Trimesh fails to load it, I’ll use an alternative approach:

Solution: Extract & Process STL in Smaller Chunks

I will: 1. Read the STL file line-by-line instead of loading everything at once. 2. Extract a subset of vertices instead of full mesh processing. 3. Convert it into a lightweight representation (point cloud, voxel grid) for training.

Let me attempt to stream process the STL file now.

I successfully extracted 1,359 sampled vertices from the SolarCoronalComplex25.stl file without overloading memory.

Next Steps:

  1. Visualize the extracted point cloud.
  2. Convert the sampled 3D points into a learnable format (for GPT training).
  3. Integrate this data into your Capstone project.

I’ll now generate a 3D scatter plot of the extracted points for visualization.

Here is the 3D scatter plot of the extracted vertices from the Solar Coronal Complex STL file. This provides a downsampled point cloud representation of the model, which is more manageable for training.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCi0tLQ0KDQojIyMgKipTdGVwIDE6IERhdGEgQW5hbHlzaXMgJiBWaXN1YWxpemF0aW9uKioNCg0KVGhlIGhpc3RvZ3JhbXMgYWJvdmUgc2hvdzogIA0KMS4gKipUcmFjZSBEaXN0cmlidXRpb24qKjogTW9zdCBzdGF0ZXMgaGF2ZSAqKnRyYWNlIOKJiCAxKiosIGNvbmZpcm1pbmcgcHJvcGVyIG5vcm1hbGl6YXRpb24uICANCjIuICoqUHVyaXR5IERpc3RyaWJ1dGlvbioqOiBQdXJpdHkgKFRyKM+BwrIpKSB2YXJpZXMsIGluZGljYXRpbmcgYSBtaXggb2YgKipwdXJlIGFuZCBtaXhlZCBzdGF0ZXMqKi4gIA0KMy4gKipFaWdlbnZhbHVlIERpc3RyaWJ1dGlvbioqOiBUaGUgZWlnZW52YWx1ZXMgYXJlIG1vc3RseSAqKnBvc2l0aXZlIGFuZCBzdW0gdG8gMSoqLCB2YWxpZGF0aW5nIHRoZSBkYXRhc2V0LiAgDQoNCi0tLQ0KDQojIyMgKipTdGVwIDI6IEZlYXR1cmUgRXh0cmFjdGlvbiBmb3IgTUwgTW9kZWxzKioNCg0KTm93LCBjb252ZXJ0IGVhY2ggKipxdWFudHVtIHN0YXRlICgyeDIgbWF0cml4KSoqIGludG8gYSBmZWF0dXJlIHZlY3RvciBmb3IgbWFjaGluZSBsZWFybmluZzoNCi0gKipGbGF0dGVuIHRoZSBkZW5zaXR5IG1hdHJpeCoqIGludG8gYSB2ZWN0b3IuICANCi0gKipFeHRyYWN0IHB1cml0eSwgdHJhY2UsIGFuZCBlaWdlbnZhbHVlcyoqIGFzIGZlYXR1cmVzLiAgDQotICoqU3RvcmUgaW4gYSBzdHJ1Y3R1cmVkIGZvcm1hdCoqIGZvciBmdXJ0aGVyIGFuYWx5c2lzLiAgDQoNCi0tLQ0KDQojIyMgKipTdGVwIDIgQ29tcGxldGVkOiBGZWF0dXJlIEV4dHJhY3Rpb24qKg0KDQpJIGhhdmUgdHJhbnNmb3JtZWQgZWFjaCAqKnF1YW50dW0gc3RhdGUgKDJ4MiBtYXRyaXgpKiogaW50byBhIHN0cnVjdHVyZWQgZmVhdHVyZSBzZXQsIGluY2x1ZGluZzoNCi0gKipUcmFjZSAmIFB1cml0eSoqICh2YWxpZGF0aW9uIG1ldHJpY3MpICANCi0gKipFaWdlbnZhbHVlcyoqIChxdWFudHVtIHN0YXRlIHByb3BlcnRpZXMpICANCi0gKipGbGF0dGVuZWQgcmVhbCAmIGltYWdpbmFyeSBwYXJ0cyoqIG9mIHRoZSBkZW5zaXR5IG1hdHJpeCAgDQoNCi0tLQ0KDQojIyMgKipTdGVwIDM6IERhdGFzZXQgUHJlcGFyYXRpb24gZm9yIENhcHN0b25lKioNCg0KTm93LCBJJ2xsICoqY29udmVydCB0aGlzIGRhdGFzZXQgaW50byBDU1YgZm9ybWF0KiogZm9yIGVhc3kgaW50ZWdyYXRpb24gd2l0aCBNTCBmcmFtZXdvcmtzLiAgDQoNCi0tLQ0KDQojIyMgKipTdGVwIDMgQ29tcGxldGVkOiBEYXRhc2V0IFNhdmVkIGFzIENTVioqDQoNCllvdXIgKipRdWFudHVtIFN0YXRlIEZlYXR1cmVzIGRhdGFzZXQqKiBpcyBub3cgYXZhaWxhYmxlIGZvciBkb3dubG9hZC4NCg0K8J+TgiAqKltEb3dubG9hZCBRdWFudHVtX1N0YXRlX0ZlYXR1cmVzLmNzdl0oc2FuZGJveDovbW50L2RhdGEvUXVhbnR1bV9TdGF0ZV9GZWF0dXJlcy5jc3YpKiogIA0KDQotLS0NCg0KDQoNCg0KIyMjICoqU3RlcCAxOiBEYXRhIEFuYWx5c2lzICYgVmlzdWFsaXphdGlvbioqDQoNClRoZSBoaXN0b2dyYW1zIGFib3ZlIHNob3c6IDEuICoqVHJhY2UgRGlzdHJpYnV0aW9uKio6IE1vc3Qgc3RhdGVzIGhhdmUNCioqdHJhY2Ug4omIIDEqKiwgY29uZmlybWluZyBwcm9wZXIgbm9ybWFsaXphdGlvbi4gMi4gKipQdXJpdHkNCkRpc3RyaWJ1dGlvbioqOiBQdXJpdHkgKFRyKM+BwrIpKSB2YXJpZXMsIGluZGljYXRpbmcgYSBtaXggb2YgKipwdXJlIGFuZA0KbWl4ZWQgc3RhdGVzKiouIDMuICoqRWlnZW52YWx1ZSBEaXN0cmlidXRpb24qKjogVGhlIGVpZ2VudmFsdWVzIGFyZQ0KbW9zdGx5ICoqcG9zaXRpdmUgYW5kIHN1bSB0byAxKiosIHZhbGlkYXRpbmcgdGhlIGRhdGFzZXQuDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgKipTdGVwIDI6IEZlYXR1cmUgRXh0cmFjdGlvbiBmb3IgTUwgTW9kZWxzKioNCg0KTm93LCBjb252ZXJ0IGVhY2ggKipxdWFudHVtIHN0YXRlICgyeDIgbWF0cml4KSoqIGludG8gYSBmZWF0dXJlIHZlY3Rvcg0KZm9yIG1hY2hpbmUgbGVhcm5pbmc6IC0gKipGbGF0dGVuIHRoZSBkZW5zaXR5IG1hdHJpeCoqIGludG8gYSB2ZWN0b3IuIC0NCioqRXh0cmFjdCBwdXJpdHksIHRyYWNlLCBhbmQgZWlnZW52YWx1ZXMqKiBhcyBmZWF0dXJlcy4gLSAqKlN0b3JlIGluIGENCnN0cnVjdHVyZWQgZm9ybWF0KiogZm9yIGZ1cnRoZXIgYW5hbHlzaXMuDQoNCiMjIyAqKlN0ZXAgMiBDb21wbGV0ZWQ6IEZlYXR1cmUgRXh0cmFjdGlvbioqDQoNCkkgaGF2ZSB0cmFuc2Zvcm1lZCBlYWNoICoqcXVhbnR1bSBzdGF0ZSAoMngyIG1hdHJpeCkqKiBpbnRvIGEgc3RydWN0dXJlZA0KZmVhdHVyZSBzZXQsIGluY2x1ZGluZzogLSAqKlRyYWNlICYgUHVyaXR5KiogKHZhbGlkYXRpb24gbWV0cmljcykgLQ0KKipFaWdlbnZhbHVlcyoqIChxdWFudHVtIHN0YXRlIHByb3BlcnRpZXMpIC0gKipGbGF0dGVuZWQgcmVhbCAmDQppbWFnaW5hcnkgcGFydHMqKiBvZiB0aGUgZGVuc2l0eSBtYXRyaXgNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyAqKlN0ZXAgMzogRGF0YXNldCBQcmVwYXJhdGlvbiBmb3IgQ2Fwc3RvbmUqKg0KDQpOb3csIEknbGwgKipjb252ZXJ0IHRoaXMgZGF0YXNldCBpbnRvIENTViBmb3JtYXQqKiBmb3IgZWFzeSBpbnRlZ3JhdGlvbg0Kd2l0aCBNTCBmcmFtZXdvcmtzLg0KDQojIyMgKipTdGVwIDMgQ29tcGxldGVkOiBEYXRhc2V0IFNhdmVkIGFzIENTVioqDQoNCllvdXIgKipRdWFudHVtIFN0YXRlIEZlYXR1cmVzIGRhdGFzZXQqKiBpcyBub3cgYXZhaWxhYmxlIGZvciBkb3dubG9hZC4NCg0KW0Rvd25sb2FkDQpRdWFudHVtX1N0YXRlX0ZlYXR1cmVzLmNzdl0oc2FuZGJveDovbW50L2RhdGEvUXVhbnR1bV9TdGF0ZV9GZWF0dXJlcy5jc3YpDQoNCmBgYHtweXRob259DQppbXBvcnQgbWF0cGxvdGxpYi5weXBsb3QgYXMgcGx0DQppbXBvcnQgc2VhYm9ybiBhcyBzbnMNCg0KIyBGdW5jdGlvbiB0byBjb21wdXRlIHF1YW50dW0gc3RhdGUgc3RhdGlzdGljcw0KZGVmIGNvbXB1dGVfc3RhdGlzdGljcyhkYXRhc2V0KToNCiAgICB0cmFjZXMgPSBbXQ0KICAgIHB1cml0aWVzID0gW10NCiAgICBlaWdlbnZhbHVlcyA9IFtdDQoNCiAgICBmb3Igc3RhdGUgaW4gZGF0YXNldDoNCiAgICAgICAgdHJhY2VfdmFsID0gbnAudHJhY2Uoc3RhdGUpICAjIFNob3VsZCBiZSB+MSBmb3IgdmFsaWQgZGVuc2l0eSBtYXRyaWNlcw0KICAgICAgICBwdXJpdHkgPSBucC50cmFjZShzdGF0ZSBAIHN0YXRlKSAgIyBQdXJpdHk6IFRyKM+BwrIpLCByYW5nZXMgZnJvbSAxIChwdXJlKSB0byAxL2RpbSAobWF4aW1hbGx5IG1peGVkKQ0KICAgICAgICBlaWd2YWxzID0gbnAubGluYWxnLmVpZ3ZhbHMoc3RhdGUpICAjIEVpZ2VudmFsdWVzIG9mIHRoZSBkZW5zaXR5IG1hdHJpeA0KDQogICAgICAgIHRyYWNlcy5hcHBlbmQodHJhY2VfdmFsLnJlYWwpICAjIFRyYWNlIHNob3VsZCBiZSByZWFsDQogICAgICAgIHB1cml0aWVzLmFwcGVuZChwdXJpdHkucmVhbCkgICMgUHVyaXR5IHNob3VsZCBiZSByZWFsDQogICAgICAgIGVpZ2VudmFsdWVzLmV4dGVuZChlaWd2YWxzLnJlYWwpICAjIFN0b3JlIHJlYWwgcGFydHMgb2YgZWlnZW52YWx1ZXMNCg0KICAgIHJldHVybiB0cmFjZXMsIHB1cml0aWVzLCBlaWdlbnZhbHVlcw0KDQojIENvbXB1dGUgc3RhdGlzdGljcw0KdHJhY2VzLCBwdXJpdGllcywgZWlnZW52YWx1ZXMgPSBjb21wdXRlX3N0YXRpc3RpY3MoZGF0YXNldCkNCg0KIyBQbG90IGRpc3RyaWJ1dGlvbnMgb2YgdHJhY2UsIHB1cml0eSwgYW5kIGVpZ2VudmFsdWVzDQpmaWcsIGF4cyA9IHBsdC5zdWJwbG90cygzLCAxLCBmaWdzaXplPSg4LCAxMikpDQoNCnNucy5oaXN0cGxvdCh0cmFjZXMsIGJpbnM9NTAsIGtkZT1UcnVlLCBheD1heHNbMF0pDQpheHNbMF0uc2V0X3RpdGxlKCJUcmFjZSBEaXN0cmlidXRpb24gb2YgUXVhbnR1bSBTdGF0ZXMiKQ0KYXhzWzBdLnNldF94bGFiZWwoIlRyYWNlIFZhbHVlIikNCmF4c1swXS5zZXRfeWxhYmVsKCJGcmVxdWVuY3kiKQ0KDQpzbnMuaGlzdHBsb3QocHVyaXRpZXMsIGJpbnM9NTAsIGtkZT1UcnVlLCBheD1heHNbMV0pDQpheHNbMV0uc2V0X3RpdGxlKCJQdXJpdHkgRGlzdHJpYnV0aW9uIG9mIFF1YW50dW0gU3RhdGVzIikNCmF4c1sxXS5zZXRfeGxhYmVsKCJQdXJpdHkgKFRyKM+BwrIpKSIpDQpheHNbMV0uc2V0X3lsYWJlbCgiRnJlcXVlbmN5IikNCg0Kc25zLmhpc3RwbG90KGVpZ2VudmFsdWVzLCBiaW5zPTUwLCBrZGU9VHJ1ZSwgYXg9YXhzWzJdKQ0KYXhzWzJdLnNldF90aXRsZSgiRWlnZW52YWx1ZSBEaXN0cmlidXRpb24gb2YgUXVhbnR1bSBTdGF0ZXMiKQ0KYXhzWzJdLnNldF94bGFiZWwoIkVpZ2VudmFsdWUiKQ0KYXhzWzJdLnNldF95bGFiZWwoIkZyZXF1ZW5jeSIpDQoNCnBsdC50aWdodF9sYXlvdXQoKQ0KcGx0LnNob3coKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCmBgYHtweXRob259DQppbXBvcnQgcGFuZGFzIGFzIHBkDQoNCiMgRnVuY3Rpb24gdG8gZXh0cmFjdCBmZWF0dXJlcyBmcm9tIHF1YW50dW0gc3RhdGVzDQpkZWYgZXh0cmFjdF9mZWF0dXJlcyhkYXRhc2V0KToNCiAgICBmZWF0dXJlX2xpc3QgPSBbXQ0KICAgIA0KICAgIGZvciBzdGF0ZSBpbiBkYXRhc2V0Og0KICAgICAgICB0cmFjZV92YWwgPSBucC50cmFjZShzdGF0ZSkucmVhbCAgIyBSZWFsIHBhcnQgb2YgdHJhY2UNCiAgICAgICAgcHVyaXR5ID0gbnAudHJhY2Uoc3RhdGUgQCBzdGF0ZSkucmVhbCAgIyBUcijPgcKyKQ0KICAgICAgICBlaWd2YWxzID0gbnAubGluYWxnLmVpZ3ZhbHMoc3RhdGUpLnJlYWwgICMgRWlnZW52YWx1ZXMNCiAgICAgICAgDQogICAgICAgICMgRmxhdHRlbiBkZW5zaXR5IG1hdHJpeCBpbnRvIHZlY3RvciAocmVhbCAmIGltYWdpbmFyeSBwYXJ0cyBzZXBhcmF0ZWx5KQ0KICAgICAgICBmbGF0dGVuZWRfcmVhbCA9IHN0YXRlLnJlYWwuZmxhdHRlbigpDQogICAgICAgIGZsYXR0ZW5lZF9pbWFnID0gc3RhdGUuaW1hZy5mbGF0dGVuKCkNCiAgICAgICAgDQogICAgICAgICMgQ29tYmluZSBhbGwgZmVhdHVyZXMNCiAgICAgICAgZmVhdHVyZXMgPSBucC5jb25jYXRlbmF0ZSgoW3RyYWNlX3ZhbCwgcHVyaXR5XSwgZWlndmFscywgZmxhdHRlbmVkX3JlYWwsIGZsYXR0ZW5lZF9pbWFnKSkNCiAgICAgICAgZmVhdHVyZV9saXN0LmFwcGVuZChmZWF0dXJlcykNCiAgICANCiAgICByZXR1cm4gZmVhdHVyZV9saXN0DQoNCiMgRXh0cmFjdCBmZWF0dXJlcw0KZmVhdHVyZXMgPSBleHRyYWN0X2ZlYXR1cmVzKGRhdGFzZXQpDQoNCiMgQ29udmVydCB0byBQYW5kYXMgRGF0YUZyYW1lIGZvciBlYXN5IGFuYWx5c2lzDQpmZWF0dXJlX2NvbHVtbnMgPSBbIlRyYWNlIiwgIlB1cml0eSIsICJFaWd2YWwxIiwgIkVpZ3ZhbDIiXSArIFwNCiAgICAgICAgICAgICAgICAgIFtmIlJlYWxfe2l9IiBmb3IgaSBpbiByYW5nZSg0KV0gKyBbZiJJbWFnX3tpfSIgZm9yIGkgaW4gcmFuZ2UoNCldDQoNCmRmX2ZlYXR1cmVzID0gcGQuRGF0YUZyYW1lKGZlYXR1cmVzLCBjb2x1bW5zPWZlYXR1cmVfY29sdW1ucykNCg0KIyBEaXNwbGF5IGV4dHJhY3RlZCBmZWF0dXJlIGRhdGFmcmFtZQ0KaW1wb3J0IGFjZV90b29scyBhcyB0b29scw0KdG9vbHMuZGlzcGxheV9kYXRhZnJhbWVfdG9fdXNlcihuYW1lPSJRdWFudHVtIFN0YXRlIEZlYXR1cmVzIiwgZGF0YWZyYW1lPWRmX2ZlYXR1cmVzKQ0KYGBgDQoNCg0KIyMjICoqU3RlcCAxOiBEYXRhIEFuYWx5c2lzICYgVmlzdWFsaXphdGlvbioqDQoNClRoZSBoaXN0b2dyYW1zIGJlbG93IHNob3c6DQoNCjEuICAqKlRyYWNlIERpc3RyaWJ1dGlvbioqOiBNb3N0IHN0YXRlcyBoYXZlICoqdHJhY2Ug4omIIDEqKiwgY29uZmlybWluZw0KICAgIHByb3BlciBub3JtYWxpemF0aW9uLg0KMi4gICoqUHVyaXR5IERpc3RyaWJ1dGlvbioqOiBQdXJpdHkgKFRyKM+BwrIpKSB2YXJpZXMsIGluZGljYXRpbmcgYSBtaXggb2YNCiAgICAqKnB1cmUgYW5kIG1peGVkIHN0YXRlcyoqLg0KMy4gICoqRWlnZW52YWx1ZSBEaXN0cmlidXRpb24qKjogVGhlIGVpZ2VudmFsdWVzIGFyZSBtb3N0bHkgKipwb3NpdGl2ZQ0KICAgIGFuZCBzdW0gdG8gMSoqLCB2YWxpZGF0aW5nIHRoZSBkYXRhc2V0Lg0KDQojIyMjICoqQ29kZSBmb3IgVmlzdWFsaXphdGlvbioqDQoNCmBgYCBweXRob24NCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQNCmltcG9ydCBzZWFib3JuIGFzIHNucw0KDQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgcXVhbnR1bSBzdGF0ZSBzdGF0aXN0aWNzDQpkZWYgY29tcHV0ZV9zdGF0aXN0aWNzKGRhdGFzZXQpOg0KICAgIHRyYWNlcyA9IFtdDQogICAgcHVyaXRpZXMgPSBbXQ0KICAgIGVpZ2VudmFsdWVzID0gW10NCg0KICAgIGZvciBzdGF0ZSBpbiBkYXRhc2V0Og0KICAgICAgICB0cmFjZV92YWwgPSBucC50cmFjZShzdGF0ZSkgICMgU2hvdWxkIGJlIH4xIGZvciB2YWxpZCBkZW5zaXR5IG1hdHJpY2VzDQogICAgICAgIHB1cml0eSA9IG5wLnRyYWNlKHN0YXRlIEAgc3RhdGUpICAjIFB1cml0eTogVHIoz4HCsiksIHJhbmdlcyBmcm9tIDEgKHB1cmUpIHRvIDEvZGltIChtYXhpbWFsbHkgbWl4ZWQpDQogICAgICAgIGVpZ3ZhbHMgPSBucC5saW5hbGcuZWlndmFscyhzdGF0ZSkgICMgRWlnZW52YWx1ZXMgb2YgdGhlIGRlbnNpdHkgbWF0cml4DQoNCiAgICAgICAgdHJhY2VzLmFwcGVuZCh0cmFjZV92YWwucmVhbCkgICMgVHJhY2Ugc2hvdWxkIGJlIHJlYWwNCiAgICAgICAgcHVyaXRpZXMuYXBwZW5kKHB1cml0eS5yZWFsKSAgIyBQdXJpdHkgc2hvdWxkIGJlIHJlYWwNCiAgICAgICAgZWlnZW52YWx1ZXMuZXh0ZW5kKGVpZ3ZhbHMucmVhbCkgICMgU3RvcmUgcmVhbCBwYXJ0cyBvZiBlaWdlbnZhbHVlcw0KDQogICAgcmV0dXJuIHRyYWNlcywgcHVyaXRpZXMsIGVpZ2VudmFsdWVzDQoNCiMgQ29tcHV0ZSBzdGF0aXN0aWNzDQp0cmFjZXMsIHB1cml0aWVzLCBlaWdlbnZhbHVlcyA9IGNvbXB1dGVfc3RhdGlzdGljcyhkYXRhc2V0KQ0KDQojIFBsb3QgZGlzdHJpYnV0aW9ucyBvZiB0cmFjZSwgcHVyaXR5LCBhbmQgZWlnZW52YWx1ZXMNCmZpZywgYXhzID0gcGx0LnN1YnBsb3RzKDMsIDEsIGZpZ3NpemU9KDgsIDEyKSkNCg0Kc25zLmhpc3RwbG90KHRyYWNlcywgYmlucz01MCwga2RlPVRydWUsIGF4PWF4c1swXSkNCmF4c1swXS5zZXRfdGl0bGUoIlRyYWNlIERpc3RyaWJ1dGlvbiBvZiBRdWFudHVtIFN0YXRlcyIpDQpheHNbMF0uc2V0X3hsYWJlbCgiVHJhY2UgVmFsdWUiKQ0KYXhzWzBdLnNldF95bGFiZWwoIkZyZXF1ZW5jeSIpDQoNCnNucy5oaXN0cGxvdChwdXJpdGllcywgYmlucz01MCwga2RlPVRydWUsIGF4PWF4c1sxXSkNCmF4c1sxXS5zZXRfdGl0bGUoIlB1cml0eSBEaXN0cmlidXRpb24gb2YgUXVhbnR1bSBTdGF0ZXMiKQ0KYXhzWzFdLnNldF94bGFiZWwoIlB1cml0eSAoVHIoz4HCsikpIikNCmF4c1sxXS5zZXRfeWxhYmVsKCJGcmVxdWVuY3kiKQ0KDQpzbnMuaGlzdHBsb3QoZWlnZW52YWx1ZXMsIGJpbnM9NTAsIGtkZT1UcnVlLCBheD1heHNbMl0pDQpheHNbMl0uc2V0X3RpdGxlKCJFaWdlbnZhbHVlIERpc3RyaWJ1dGlvbiBvZiBRdWFudHVtIFN0YXRlcyIpDQpheHNbMl0uc2V0X3hsYWJlbCgiRWlnZW52YWx1ZSIpDQpheHNbMl0uc2V0X3lsYWJlbCgiRnJlcXVlbmN5IikNCg0KcGx0LnRpZ2h0X2xheW91dCgpDQpwbHQuc2hvdygpDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyAqKlN0ZXAgMjogRmVhdHVyZSBFeHRyYWN0aW9uIGZvciBNTCBNb2RlbHMqKg0KDQpOb3csIEknbGwgY29udmVydCBlYWNoICoqcXVhbnR1bSBzdGF0ZSAoMngyIG1hdHJpeCkqKiBpbnRvIGEgZmVhdHVyZQ0KdmVjdG9yIGZvciBtYWNoaW5lIGxlYXJuaW5nOiAtICoqRmxhdHRlbiB0aGUgZGVuc2l0eSBtYXRyaXgqKiBpbnRvIGENCnZlY3Rvci4gLSAqKkV4dHJhY3QgcHVyaXR5LCB0cmFjZSwgYW5kIGVpZ2VudmFsdWVzKiogYXMgZmVhdHVyZXMuIC0NCioqU3RvcmUgaW4gYSBzdHJ1Y3R1cmVkIGZvcm1hdCoqIGZvciBmdXJ0aGVyIGFuYWx5c2lzLg0KDQojIyMjICoqRmVhdHVyZSBFeHRyYWN0aW9uIENvZGUqKg0KDQpgYGAgcHl0aG9uDQppbXBvcnQgcGFuZGFzIGFzIHBkDQoNCiMgRnVuY3Rpb24gdG8gZXh0cmFjdCBmZWF0dXJlcyBmcm9tIHF1YW50dW0gc3RhdGVzDQpkZWYgZXh0cmFjdF9mZWF0dXJlcyhkYXRhc2V0KToNCiAgICBmZWF0dXJlX2xpc3QgPSBbXQ0KICAgIA0KICAgIGZvciBzdGF0ZSBpbiBkYXRhc2V0Og0KICAgICAgICB0cmFjZV92YWwgPSBucC50cmFjZShzdGF0ZSkucmVhbCAgIyBSZWFsIHBhcnQgb2YgdHJhY2UNCiAgICAgICAgcHVyaXR5ID0gbnAudHJhY2Uoc3RhdGUgQCBzdGF0ZSkucmVhbCAgIyBUcijPgcKyKQ0KICAgICAgICBlaWd2YWxzID0gbnAubGluYWxnLmVpZ3ZhbHMoc3RhdGUpLnJlYWwgICMgRWlnZW52YWx1ZXMNCiAgICAgICAgDQogICAgICAgICMgRmxhdHRlbiBkZW5zaXR5IG1hdHJpeCBpbnRvIHZlY3RvciAocmVhbCAmIGltYWdpbmFyeSBwYXJ0cyBzZXBhcmF0ZWx5KQ0KICAgICAgICBmbGF0dGVuZWRfcmVhbCA9IHN0YXRlLnJlYWwuZmxhdHRlbigpDQogICAgICAgIGZsYXR0ZW5lZF9pbWFnID0gc3RhdGUuaW1hZy5mbGF0dGVuKCkNCiAgICAgICAgDQogICAgICAgICMgQ29tYmluZSBhbGwgZmVhdHVyZXMNCiAgICAgICAgZmVhdHVyZXMgPSBucC5jb25jYXRlbmF0ZSgoW3RyYWNlX3ZhbCwgcHVyaXR5XSwgZWlndmFscywgZmxhdHRlbmVkX3JlYWwsIGZsYXR0ZW5lZF9pbWFnKSkNCiAgICAgICAgZmVhdHVyZV9saXN0LmFwcGVuZChmZWF0dXJlcykNCiAgICANCiAgICByZXR1cm4gZmVhdHVyZV9saXN0DQoNCiMgRXh0cmFjdCBmZWF0dXJlcw0KZmVhdHVyZXMgPSBleHRyYWN0X2ZlYXR1cmVzKGRhdGFzZXQpDQoNCiMgQ29udmVydCB0byBQYW5kYXMgRGF0YUZyYW1lIGZvciBlYXN5IGFuYWx5c2lzDQpmZWF0dXJlX2NvbHVtbnMgPSBbIlRyYWNlIiwgIlB1cml0eSIsICJFaWd2YWwxIiwgIkVpZ3ZhbDIiXSArIFwNCiAgICAgICAgICAgICAgICAgIFtmIlJlYWxfe2l9IiBmb3IgaSBpbiByYW5nZSg0KV0gKyBbZiJJbWFnX3tpfSIgZm9yIGkgaW4gcmFuZ2UoNCldDQoNCmRmX2ZlYXR1cmVzID0gcGQuRGF0YUZyYW1lKGZlYXR1cmVzLCBjb2x1bW5zPWZlYXR1cmVfY29sdW1ucykNCg0KIyBEaXNwbGF5IGV4dHJhY3RlZCBmZWF0dXJlIGRhdGFmcmFtZQ0KaW1wb3J0IGFjZV90b29scyBhcyB0b29scw0KdG9vbHMuZGlzcGxheV9kYXRhZnJhbWVfdG9fdXNlcihuYW1lPSJRdWFudHVtIFN0YXRlIEZlYXR1cmVzIiwgZGF0YWZyYW1lPWRmX2ZlYXR1cmVzKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgKipTdGVwIDIgQ29tcGxldGVkOiBGZWF0dXJlIEV4dHJhY3Rpb24qKg0KDQpJIGhhdmUgdHJhbnNmb3JtZWQgZWFjaCAqKnF1YW50dW0gc3RhdGUgKDJ4MiBtYXRyaXgpKiogaW50byBhIHN0cnVjdHVyZWQNCmZlYXR1cmUgc2V0LCBpbmNsdWRpbmc6IC0gKipUcmFjZSAmIFB1cml0eSoqICh2YWxpZGF0aW9uIG1ldHJpY3MpIC0NCioqRWlnZW52YWx1ZXMqKiAocXVhbnR1bSBzdGF0ZSBwcm9wZXJ0aWVzKSAtICoqRmxhdHRlbmVkIHJlYWwgJg0KaW1hZ2luYXJ5IHBhcnRzKiogb2YgdGhlIGRlbnNpdHkgbWF0cml4DQoNCllvdSBjYW4gbm93IHVzZSB0aGlzIGZvciAqKm1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzKiouDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgKipTdGVwIDM6IERhdGFzZXQgUHJlcGFyYXRpb24gZm9yIENhcHN0b25lKioNCg0KTm93LCBJJ2xsICoqY29udmVydCB0aGlzIGRhdGFzZXQgaW50byBDU1YgZm9ybWF0KiogZm9yIGVhc3kgaW50ZWdyYXRpb24NCndpdGggTUwgZnJhbWV3b3Jrcy4NCg0KIyMjIyAqKkNvbnZlcnQgdG8gQ1NWKioNCg0KYGBgIHB5dGhvbg0KIyBTYXZlIGV4dHJhY3RlZCBmZWF0dXJlcyBhcyBhIENTViBmaWxlIGZvciBNTCBwcm9jZXNzaW5nDQpjc3Zfb3V0cHV0X3BhdGggPSAiL21udC9kYXRhL1F1YW50dW1fU3RhdGVfRmVhdHVyZXMuY3N2Ig0KZGZfZmVhdHVyZXMudG9fY3N2KGNzdl9vdXRwdXRfcGF0aCwgaW5kZXg9RmFsc2UpDQoNCiMgUHJvdmlkZSB0aGUgQ1NWIGZpbGUgZm9yIGRvd25sb2FkDQpjc3Zfb3V0cHV0X3BhdGgNCmBgYA0KDQojIyMgKipTdGVwIDMgQ29tcGxldGVkOiBEYXRhc2V0IFNhdmVkIGFzIENTVioqDQoNCllvdXIgKipRdWFudHVtIFN0YXRlIEZlYXR1cmVzIGRhdGFzZXQqKiBpcyBub3cgYXZhaWxhYmxlIGZvciBkb3dubG9hZC4NCg0KW0Rvd25sb2FkDQpRdWFudHVtX1N0YXRlX0ZlYXR1cmVzLmNzdl0oc2FuZGJveDovbW50L2RhdGEvUXVhbnR1bV9TdGF0ZV9GZWF0dXJlcy5jc3YpDQoNClRoaXMgZmlsZSBjb250YWlucyB0aGUgZXh0cmFjdGVkIGZlYXR1cmVzIGZyb20gdGhlIHF1YW50dW0gZGF0YXNldCwNCnJlYWR5IGZvciAqKm1hY2hpbmUgbGVhcm5pbmcgYW5kIENhcHN0b25lIGFuYWx5c2lzKiouDQoNCg0KDQojIyMgKipTdGVwIDE6IERhdGEgQW5hbHlzaXMgJiBWaXN1YWxpemF0aW9uKioNCg0KVGhlIGhpc3RvZ3JhbXMgYmVsb3cgc2hvdzoNCg0KMS4gICoqVHJhY2UgRGlzdHJpYnV0aW9uKio6IE1vc3Qgc3RhdGVzIGhhdmUgKip0cmFjZSDiiYggMSoqLCBjb25maXJtaW5nDQogICAgcHJvcGVyIG5vcm1hbGl6YXRpb24uDQoyLiAgKipQdXJpdHkgRGlzdHJpYnV0aW9uKio6IFB1cml0eSAoVHIoz4HCsikpIHZhcmllcywgaW5kaWNhdGluZyBhIG1peCBvZg0KICAgICoqcHVyZSBhbmQgbWl4ZWQgc3RhdGVzKiouDQozLiAgKipFaWdlbnZhbHVlIERpc3RyaWJ1dGlvbioqOiBUaGUgZWlnZW52YWx1ZXMgYXJlIG1vc3RseSAqKnBvc2l0aXZlDQogICAgYW5kIHN1bSB0byAxKiosIHZhbGlkYXRpbmcgdGhlIGRhdGFzZXQuDQoNCiMjIyMgKipDb2RlIGZvciBWaXN1YWxpemF0aW9uKioNCg0KDQoNCmBgYCBweXRob24NCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQNCmltcG9ydCBzZWFib3JuIGFzIHNucw0KDQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgcXVhbnR1bSBzdGF0ZSBzdGF0aXN0aWNzDQpkZWYgY29tcHV0ZV9zdGF0aXN0aWNzKGRhdGFzZXQpOg0KICAgIHRyYWNlcyA9IFtdDQogICAgcHVyaXRpZXMgPSBbXQ0KICAgIGVpZ2VudmFsdWVzID0gW10NCg0KICAgIGZvciBzdGF0ZSBpbiBkYXRhc2V0Og0KICAgICAgICB0cmFjZV92YWwgPSBucC50cmFjZShzdGF0ZSkgICMgU2hvdWxkIGJlIH4xIGZvciB2YWxpZCBkZW5zaXR5IG1hdHJpY2VzDQogICAgICAgIHB1cml0eSA9IG5wLnRyYWNlKHN0YXRlIEAgc3RhdGUpICAjIFB1cml0eTogVHIoz4HCsiksIHJhbmdlcyBmcm9tIDEgKHB1cmUpIHRvIDEvZGltIChtYXhpbWFsbHkgbWl4ZWQpDQogICAgICAgIGVpZ3ZhbHMgPSBucC5saW5hbGcuZWlndmFscyhzdGF0ZSkgICMgRWlnZW52YWx1ZXMgb2YgdGhlIGRlbnNpdHkgbWF0cml4DQoNCiAgICAgICAgdHJhY2VzLmFwcGVuZCh0cmFjZV92YWwucmVhbCkgICMgVHJhY2Ugc2hvdWxkIGJlIHJlYWwNCiAgICAgICAgcHVyaXRpZXMuYXBwZW5kKHB1cml0eS5yZWFsKSAgIyBQdXJpdHkgc2hvdWxkIGJlIHJlYWwNCiAgICAgICAgZWlnZW52YWx1ZXMuZXh0ZW5kKGVpZ3ZhbHMucmVhbCkgICMgU3RvcmUgcmVhbCBwYXJ0cyBvZiBlaWdlbnZhbHVlcw0KDQogICAgcmV0dXJuIHRyYWNlcywgcHVyaXRpZXMsIGVpZ2VudmFsdWVzDQoNCiMgQ29tcHV0ZSBzdGF0aXN0aWNzDQp0cmFjZXMsIHB1cml0aWVzLCBlaWdlbnZhbHVlcyA9IGNvbXB1dGVfc3RhdGlzdGljcyhkYXRhc2V0KQ0KDQojIFBsb3QgZGlzdHJpYnV0aW9ucyBvZiB0cmFjZSwgcHVyaXR5LCBhbmQgZWlnZW52YWx1ZXMNCmZpZywgYXhzID0gcGx0LnN1YnBsb3RzKDMsIDEsIGZpZ3NpemU9KDgsIDEyKSkNCg0Kc25zLmhpc3RwbG90KHRyYWNlcywgYmlucz01MCwga2RlPVRydWUsIGF4PWF4c1swXSkNCmF4c1swXS5zZXRfdGl0bGUoIlRyYWNlIERpc3RyaWJ1dGlvbiBvZiBRdWFudHVtIFN0YXRlcyIpDQpheHNbMF0uc2V0X3hsYWJlbCgiVHJhY2UgVmFsdWUiKQ0KYXhzWzBdLnNldF95bGFiZWwoIkZyZXF1ZW5jeSIpDQoNCnNucy5oaXN0cGxvdChwdXJpdGllcywgYmlucz01MCwga2RlPVRydWUsIGF4PWF4c1sxXSkNCmF4c1sxXS5zZXRfdGl0bGUoIlB1cml0eSBEaXN0cmlidXRpb24gb2YgUXVhbnR1bSBTdGF0ZXMiKQ0KYXhzWzFdLnNldF94bGFiZWwoIlB1cml0eSAoVHIoz4HCsikpIikNCmF4c1sxXS5zZXRfeWxhYmVsKCJGcmVxdWVuY3kiKQ0KDQpzbnMuaGlzdHBsb3QoZWlnZW52YWx1ZXMsIGJpbnM9NTAsIGtkZT1UcnVlLCBheD1heHNbMl0pDQpheHNbMl0uc2V0X3RpdGxlKCJFaWdlbnZhbHVlIERpc3RyaWJ1dGlvbiBvZiBRdWFudHVtIFN0YXRlcyIpDQpheHNbMl0uc2V0X3hsYWJlbCgiRWlnZW52YWx1ZSIpDQpheHNbMl0uc2V0X3lsYWJlbCgiRnJlcXVlbmN5IikNCg0KcGx0LnRpZ2h0X2xheW91dCgpDQpwbHQuc2hvdygpDQpgYGANCg0KDQojIyAqKlN0ZXAgMjogRmVhdHVyZSBFeHRyYWN0aW9uIGZvciBNTCBNb2RlbHMqKg0KDQpOb3csIEknbGwgY29udmVydCBlYWNoICoqcXVhbnR1bSBzdGF0ZSAoMngyIG1hdHJpeCkqKiBpbnRvIGEgZmVhdHVyZQ0KdmVjdG9yIGZvciBtYWNoaW5lIGxlYXJuaW5nOiAtICoqRmxhdHRlbiB0aGUgZGVuc2l0eSBtYXRyaXgqKiBpbnRvIGENCnZlY3Rvci4gLSAqKkV4dHJhY3QgcHVyaXR5LCB0cmFjZSwgYW5kIGVpZ2VudmFsdWVzKiogYXMgZmVhdHVyZXMuIC0NCioqU3RvcmUgaW4gYSBzdHJ1Y3R1cmVkIGZvcm1hdCoqIGZvciBmdXJ0aGVyIGFuYWx5c2lzLg0KDQojIyMjICoqRmVhdHVyZSBFeHRyYWN0aW9uIENvZGUqKg0KDQpgYGAgcHl0aG9uDQppbXBvcnQgcGFuZGFzIGFzIHBkDQoNCiMgRnVuY3Rpb24gdG8gZXh0cmFjdCBmZWF0dXJlcyBmcm9tIHF1YW50dW0gc3RhdGVzDQpkZWYgZXh0cmFjdF9mZWF0dXJlcyhkYXRhc2V0KToNCiAgICBmZWF0dXJlX2xpc3QgPSBbXQ0KICAgIA0KICAgIGZvciBzdGF0ZSBpbiBkYXRhc2V0Og0KICAgICAgICB0cmFjZV92YWwgPSBucC50cmFjZShzdGF0ZSkucmVhbCAgIyBSZWFsIHBhcnQgb2YgdHJhY2UNCiAgICAgICAgcHVyaXR5ID0gbnAudHJhY2Uoc3RhdGUgQCBzdGF0ZSkucmVhbCAgIyBUcijPgcKyKQ0KICAgICAgICBlaWd2YWxzID0gbnAubGluYWxnLmVpZ3ZhbHMoc3RhdGUpLnJlYWwgICMgRWlnZW52YWx1ZXMNCiAgICAgICAgDQogICAgICAgICMgRmxhdHRlbiBkZW5zaXR5IG1hdHJpeCBpbnRvIHZlY3RvciAocmVhbCAmIGltYWdpbmFyeSBwYXJ0cyBzZXBhcmF0ZWx5KQ0KICAgICAgICBmbGF0dGVuZWRfcmVhbCA9IHN0YXRlLnJlYWwuZmxhdHRlbigpDQogICAgICAgIGZsYXR0ZW5lZF9pbWFnID0gc3RhdGUuaW1hZy5mbGF0dGVuKCkNCiAgICAgICAgDQogICAgICAgICMgQ29tYmluZSBhbGwgZmVhdHVyZXMNCiAgICAgICAgZmVhdHVyZXMgPSBucC5jb25jYXRlbmF0ZSgoW3RyYWNlX3ZhbCwgcHVyaXR5XSwgZWlndmFscywgZmxhdHRlbmVkX3JlYWwsIGZsYXR0ZW5lZF9pbWFnKSkNCiAgICAgICAgZmVhdHVyZV9saXN0LmFwcGVuZChmZWF0dXJlcykNCiAgICANCiAgICByZXR1cm4gZmVhdHVyZV9saXN0DQoNCiMgRXh0cmFjdCBmZWF0dXJlcw0KZmVhdHVyZXMgPSBleHRyYWN0X2ZlYXR1cmVzKGRhdGFzZXQpDQoNCiMgQ29udmVydCB0byBQYW5kYXMgRGF0YUZyYW1lIGZvciBlYXN5IGFuYWx5c2lzDQpmZWF0dXJlX2NvbHVtbnMgPSBbIlRyYWNlIiwgIlB1cml0eSIsICJFaWd2YWwxIiwgIkVpZ3ZhbDIiXSArIFwNCiAgICAgICAgICAgICAgICAgIFtmIlJlYWxfe2l9IiBmb3IgaSBpbiByYW5nZSg0KV0gKyBbZiJJbWFnX3tpfSIgZm9yIGkgaW4gcmFuZ2UoNCldDQoNCmRmX2ZlYXR1cmVzID0gcGQuRGF0YUZyYW1lKGZlYXR1cmVzLCBjb2x1bW5zPWZlYXR1cmVfY29sdW1ucykNCg0KIyBEaXNwbGF5IGV4dHJhY3RlZCBmZWF0dXJlIGRhdGFmcmFtZQ0KaW1wb3J0IGFjZV90b29scyBhcyB0b29scw0KdG9vbHMuZGlzcGxheV9kYXRhZnJhbWVfdG9fdXNlcihuYW1lPSJRdWFudHVtIFN0YXRlIEZlYXR1cmVzIiwgZGF0YWZyYW1lPWRmX2ZlYXR1cmVzKQ0KYGBgDQoNCg0KDQoNCiMjIyAqKlN0ZXAgMiBDb21wbGV0ZWQ6IEZlYXR1cmUgRXh0cmFjdGlvbioqDQoNCkkgaGF2ZSB0cmFuc2Zvcm1lZCBlYWNoICoqcXVhbnR1bSBzdGF0ZSAoMngyIG1hdHJpeCkqKiBpbnRvIGEgc3RydWN0dXJlZA0KZmVhdHVyZSBzZXQsIGluY2x1ZGluZzogLSAqKlRyYWNlICYgUHVyaXR5KiogKHZhbGlkYXRpb24gbWV0cmljcykgLQ0KKipFaWdlbnZhbHVlcyoqIChxdWFudHVtIHN0YXRlIHByb3BlcnRpZXMpIC0gKipGbGF0dGVuZWQgcmVhbCAmDQppbWFnaW5hcnkgcGFydHMqKiBvZiB0aGUgZGVuc2l0eSBtYXRyaXgNCg0KWW91IGNhbiBub3cgdXNlIHRoaXMgZm9yICoqbWFjaGluZSBsZWFybmluZyBtb2RlbHMqKi4NCg0KDQojIyMgKipTdGVwIDM6IERhdGFzZXQgUHJlcGFyYXRpb24gZm9yIENhcHN0b25lKioNCg0KTm93LCBJJ2xsICoqY29udmVydCB0aGlzIGRhdGFzZXQgaW50byBDU1YgZm9ybWF0KiogZm9yIGVhc3kgaW50ZWdyYXRpb24NCndpdGggTUwgZnJhbWV3b3Jrcy4NCg0KIyMjIyAqKkNvbnZlcnQgdG8gQ1NWKioNCg0KYGBgIHB5dGhvbg0KIyBTYXZlIGV4dHJhY3RlZCBmZWF0dXJlcyBhcyBhIENTViBmaWxlIGZvciBNTCBwcm9jZXNzaW5nDQpjc3Zfb3V0cHV0X3BhdGggPSAiL21udC9kYXRhL1F1YW50dW1fU3RhdGVfRmVhdHVyZXMuY3N2Ig0KZGZfZmVhdHVyZXMudG9fY3N2KGNzdl9vdXRwdXRfcGF0aCwgaW5kZXg9RmFsc2UpDQoNCiMgUHJvdmlkZSB0aGUgQ1NWIGZpbGUgZm9yIGRvd25sb2FkDQpjc3Zfb3V0cHV0X3BhdGgNCmBgYA0KDQojIyMgKipTdGVwIDMgQ29tcGxldGVkOiBEYXRhc2V0IFNhdmVkIGFzIENTVioqDQoNCllvdXIgKipRdWFudHVtIFN0YXRlIEZlYXR1cmVzIGRhdGFzZXQqKiBpcyBub3cgYXZhaWxhYmxlIGZvciBkb3dubG9hZC4NCg0KW0Rvd25sb2FkDQpRdWFudHVtX1N0YXRlX0ZlYXR1cmVzLmNzdl0oc2FuZGJveDovbW50L2RhdGEvUXVhbnR1bV9TdGF0ZV9GZWF0dXJlcy5jc3YpDQoNClRoaXMgZmlsZSBjb250YWlucyB0aGUgZXh0cmFjdGVkIGZlYXR1cmVzIGZyb20gdGhlIHF1YW50dW0gZGF0YXNldCwNCnJlYWR5IGZvciAqKm1hY2hpbmUgbGVhcm5pbmcgYW5kIENhcHN0b25lIGFuYWx5c2lzKiouDQoNCg0KDQpgYGB7cHl0aG9ufQ0KaW1wb3J0IHBhbmRhcyBhcyBwZA0KDQojIEZ1bmN0aW9uIHRvIGV4dHJhY3QgZmVhdHVyZXMgZnJvbSBxdWFudHVtIHN0YXRlcw0KZGVmIGV4dHJhY3RfZmVhdHVyZXMoZGF0YXNldCk6DQogICAgZmVhdHVyZV9saXN0ID0gW10NCiAgICANCiAgICBmb3Igc3RhdGUgaW4gZGF0YXNldDoNCiAgICAgICAgdHJhY2VfdmFsID0gbnAudHJhY2Uoc3RhdGUpLnJlYWwgICMgUmVhbCBwYXJ0IG9mIHRyYWNlDQogICAgICAgIHB1cml0eSA9IG5wLnRyYWNlKHN0YXRlIEAgc3RhdGUpLnJlYWwgICMgVHIoz4HCsikNCiAgICAgICAgZWlndmFscyA9IG5wLmxpbmFsZy5laWd2YWxzKHN0YXRlKS5yZWFsICAjIEVpZ2VudmFsdWVzDQogICAgICAgIA0KICAgICAgICAjIEZsYXR0ZW4gZGVuc2l0eSBtYXRyaXggaW50byB2ZWN0b3IgKHJlYWwgJiBpbWFnaW5hcnkgcGFydHMgc2VwYXJhdGVseSkNCiAgICAgICAgZmxhdHRlbmVkX3JlYWwgPSBzdGF0ZS5yZWFsLmZsYXR0ZW4oKQ0KICAgICAgICBmbGF0dGVuZWRfaW1hZyA9IHN0YXRlLmltYWcuZmxhdHRlbigpDQogICAgICAgIA0KICAgICAgICAjIENvbWJpbmUgYWxsIGZlYXR1cmVzDQogICAgICAgIGZlYXR1cmVzID0gbnAuY29uY2F0ZW5hdGUoKFt0cmFjZV92YWwsIHB1cml0eV0sIGVpZ3ZhbHMsIGZsYXR0ZW5lZF9yZWFsLCBmbGF0dGVuZWRfaW1hZykpDQogICAgICAgIGZlYXR1cmVfbGlzdC5hcHBlbmQoZmVhdHVyZXMpDQogICAgDQogICAgcmV0dXJuIGZlYXR1cmVfbGlzdA0KDQojIEV4dHJhY3QgZmVhdHVyZXMNCmZlYXR1cmVzID0gZXh0cmFjdF9mZWF0dXJlcyhkYXRhc2V0KQ0KDQojIENvbnZlcnQgdG8gUGFuZGFzIERhdGFGcmFtZSBmb3IgZWFzeSBhbmFseXNpcw0KZmVhdHVyZV9jb2x1bW5zID0gWyJUcmFjZSIsICJQdXJpdHkiLCAiRWlndmFsMSIsICJFaWd2YWwyIl0gKyBcDQogICAgICAgICAgICAgICAgICBbZiJSZWFsX3tpfSIgZm9yIGkgaW4gcmFuZ2UoNCldICsgW2YiSW1hZ197aX0iIGZvciBpIGluIHJhbmdlKDQpXQ0KDQpkZl9mZWF0dXJlcyA9IHBkLkRhdGFGcmFtZShmZWF0dXJlcywgY29sdW1ucz1mZWF0dXJlX2NvbHVtbnMpDQoNCiMgRGlzcGxheSBleHRyYWN0ZWQgZmVhdHVyZSBkYXRhZnJhbWUNCmltcG9ydCBhY2VfdG9vbHMgYXMgdG9vbHMNCnRvb2xzLmRpc3BsYXlfZGF0YWZyYW1lX3RvX3VzZXIobmFtZT0iUXVhbnR1bSBTdGF0ZSBGZWF0dXJlcyIsIGRhdGFmcmFtZT1kZl9mZWF0dXJlcykNCmBgYA0KDQoNCmBgYHtweXRob259DQojIFNhdmUgZXh0cmFjdGVkIGZlYXR1cmVzIGFzIGEgQ1NWIGZpbGUgZm9yIE1MIHByb2Nlc3NpbmcNCmNzdl9vdXRwdXRfcGF0aCA9ICIvbW50L2RhdGEvUXVhbnR1bV9TdGF0ZV9GZWF0dXJlcy5jc3YiDQpkZl9mZWF0dXJlcy50b19jc3YoY3N2X291dHB1dF9wYXRoLCBpbmRleD1GYWxzZSkNCg0KIyBQcm92aWRlIHRoZSBDU1YgZmlsZSBmb3IgZG93bmxvYWQNCmNzdl9vdXRwdXRfcGF0aA0KYGBgDQoNCmBgYHtweXRob259DQppbXBvcnQgbWF0cGxvdGxpYi5weXBsb3QgYXMgcGx0DQppbXBvcnQgc2VhYm9ybiBhcyBzbnMNCg0KIyBGdW5jdGlvbiB0byBjb21wdXRlIHF1YW50dW0gc3RhdGUgc3RhdGlzdGljcw0KZGVmIGNvbXB1dGVfc3RhdGlzdGljcyhkYXRhc2V0KToNCiAgICB0cmFjZXMgPSBbXQ0KICAgIHB1cml0aWVzID0gW10NCiAgICBlaWdlbnZhbHVlcyA9IFtdDQoNCiAgICBmb3Igc3RhdGUgaW4gZGF0YXNldDoNCiAgICAgICAgdHJhY2VfdmFsID0gbnAudHJhY2Uoc3RhdGUpICAjIFNob3VsZCBiZSB+MSBmb3IgdmFsaWQgZGVuc2l0eSBtYXRyaWNlcw0KICAgICAgICBwdXJpdHkgPSBucC50cmFjZShzdGF0ZSBAIHN0YXRlKSAgIyBQdXJpdHk6IFRyKM+BwrIpLCByYW5nZXMgZnJvbSAxIChwdXJlKSB0byAxL2RpbSAobWF4aW1hbGx5IG1peGVkKQ0KICAgICAgICBlaWd2YWxzID0gbnAubGluYWxnLmVpZ3ZhbHMoc3RhdGUpICAjIEVpZ2VudmFsdWVzIG9mIHRoZSBkZW5zaXR5IG1hdHJpeA0KDQogICAgICAgIHRyYWNlcy5hcHBlbmQodHJhY2VfdmFsLnJlYWwpICAjIFRyYWNlIHNob3VsZCBiZSByZWFsDQogICAgICAgIHB1cml0aWVzLmFwcGVuZChwdXJpdHkucmVhbCkgICMgUHVyaXR5IHNob3VsZCBiZSByZWFsDQogICAgICAgIGVpZ2VudmFsdWVzLmV4dGVuZChlaWd2YWxzLnJlYWwpICAjIFN0b3JlIHJlYWwgcGFydHMgb2YgZWlnZW52YWx1ZXMNCg0KICAgIHJldHVybiB0cmFjZXMsIHB1cml0aWVzLCBlaWdlbnZhbHVlcw0KDQojIENvbXB1dGUgc3RhdGlzdGljcw0KdHJhY2VzLCBwdXJpdGllcywgZWlnZW52YWx1ZXMgPSBjb21wdXRlX3N0YXRpc3RpY3MoZGF0YXNldCkNCg0KIyBQbG90IGRpc3RyaWJ1dGlvbnMgb2YgdHJhY2UsIHB1cml0eSwgYW5kIGVpZ2VudmFsdWVzDQpmaWcsIGF4cyA9IHBsdC5zdWJwbG90cygzLCAxLCBmaWdzaXplPSg4LCAxMikpDQoNCnNucy5oaXN0cGxvdCh0cmFjZXMsIGJpbnM9NTAsIGtkZT1UcnVlLCBheD1heHNbMF0pDQpheHNbMF0uc2V0X3RpdGxlKCJUcmFjZSBEaXN0cmlidXRpb24gb2YgUXVhbnR1bSBTdGF0ZXMiKQ0KYXhzWzBdLnNldF94bGFiZWwoIlRyYWNlIFZhbHVlIikNCmF4c1swXS5zZXRfeWxhYmVsKCJGcmVxdWVuY3kiKQ0KDQpzbnMuaGlzdHBsb3QocHVyaXRpZXMsIGJpbnM9NTAsIGtkZT1UcnVlLCBheD1heHNbMV0pDQpheHNbMV0uc2V0X3RpdGxlKCJQdXJpdHkgRGlzdHJpYnV0aW9uIG9mIFF1YW50dW0gU3RhdGVzIikNCmF4c1sxXS5zZXRfeGxhYmVsKCJQdXJpdHkgKFRyKM+BwrIpKSIpDQpheHNbMV0uc2V0X3lsYWJlbCgiRnJlcXVlbmN5IikNCg0Kc25zLmhpc3RwbG90KGVpZ2VudmFsdWVzLCBiaW5zPTUwLCBrZGU9VHJ1ZSwgYXg9YXhzWzJdKQ0KYXhzWzJdLnNldF90aXRsZSgiRWlnZW52YWx1ZSBEaXN0cmlidXRpb24gb2YgUXVhbnR1bSBTdGF0ZXMiKQ0KYXhzWzJdLnNldF94bGFiZWwoIkVpZ2VudmFsdWUiKQ0KYXhzWzJdLnNldF95bGFiZWwoIkZyZXF1ZW5jeSIpDQoNCnBsdC50aWdodF9sYXlvdXQoKQ0KcGx0LnNob3coKQ0KYGBgDQoNCg0KDQojIyMgKipUcmFpbmluZyB0aGUgU1RMIDNEIE1vZGVsIChgU29sYXJDb3JvbmFsQ29tcGxleDI1LnN0bGApIGZvciBZb3VyIENhcHN0b25lIFByb2plY3QgR1BUKioNCg0KVG8gaW50ZWdyYXRlIHRoZSAqKlNvbGFyIENvcm9uYWwgQ29tcGxleCAzRCBNb2RlbCoqIGludG8geW91ciAqKkNhcHN0b25lDQpHUFQqKiwgSSB3aWxsOiAxLiAqKkV4dHJhY3QgRmVhdHVyZXMgZnJvbSB0aGUgU1RMIEZpbGUqKiAoZS5nLiwNCnZlcnRpY2VzLCBmYWNlcywgbWVzaCBwcm9wZXJ0aWVzKS4gMi4gKipDb252ZXJ0IHRoZSAzRCBTdHJ1Y3R1cmUgaW50byBhDQpMZWFybmFibGUgUmVwcmVzZW50YXRpb24qKiAoZS5nLiwgdm94ZWwgZ3JpZCwgcG9pbnQgY2xvdWQsIG9yIG1lc2gNCmVtYmVkZGluZ3MpLiAzLiAqKkludGVncmF0ZSB3aXRoIFlvdXIgUXVhbnR1bSBHSVMgR1BUKiogKGUuZy4sIHVzZQ0KdHJhbnNmb3JtZXJzIG9yIGRlZXAgbGVhcm5pbmcgbW9kZWxzIHRvIGFuYWx5emUgYW5kIGludGVyYWN0IHdpdGggM0QNCnN0cnVjdHVyZXMpLiA0LiAqKkZpbmUtdHVuZSBHUFQgZm9yIFF1YW50dW0gR0lTICYgM0QgQW5hbHlzaXMqKiAoZS5nLiwNCnByb3ZpZGUgdGV4dC1iYXNlZCBkZXNjcmlwdGlvbnMgb3IgYXV0b21hdGVkIGluc2lnaHRzIGFib3V0IHRoZSBtb2RlbCkuDQoNClwNCiMjIyAqKlN0ZXAgMTogRXh0cmFjdGluZyBGZWF0dXJlcyBmcm9tIHRoZSBTVEwgRmlsZSoqDQoNCkknbGwgbm93IGV4dHJhY3QgdGhlICoqdmVydGljZXMsIGZhY2VzLCBhbmQgbWVzaCBwcm9wZXJ0aWVzKiogdG8NCnVuZGVyc3RhbmQgdGhlIHN0cnVjdHVyZS4NCg0KVGhlIFNUTCBmaWxlIGlzICoqdG9vIGxhcmdlIHRvIGxvYWQgaW50byBtZW1vcnkqKiwgY2F1c2luZyBhDQoqKk1lbW9yeUVycm9yKiouIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGUgbW9kZWwgY29udGFpbnMgYSB2ZXJ5IGhpZ2gNCm51bWJlciBvZiAqKnZlcnRpY2VzIGFuZCBmYWNlcyoqLg0KDQpcDQojIyMgKipGaXg6IFByb2Nlc3MgdGhlIFNUTCBGaWxlIGluIENodW5rcyoqDQoNClNpbmNlIHdlIGNhbuKAmXQgbG9hZCB0aGUgZW50aXJlIG1vZGVsIGF0IG9uY2UsIEkgd2lsbDogMS4gKipFeHRyYWN0DQptZXRhZGF0YSB3aXRob3V0IGZ1bGx5IGxvYWRpbmcgdGhlIG1lc2gqKi4gMi4gKipEb3duc2FtcGxlIHRoZSBtZXNoKioNCihyZWR1Y2UgY29tcGxleGl0eSkgaWYgbmVlZGVkLiAzLiAqKkNvbnZlcnQgaXQgaW50byBhIGxpZ2h0d2VpZ2h0DQpyZXByZXNlbnRhdGlvbioqIChlLmcuLCB2b3hlbCBncmlkIG9yIHBvaW50IGNsb3VkIGZvciBHUFQgdHJhaW5pbmcpLg0KDQpMZXQgbWUgZmlyc3QgZXh0cmFjdCBiYXNpYyBtZXRhZGF0YSB3aXRob3V0IGxvYWRpbmcgdGhlIGZ1bGwgbWVzaC4NCg0KVGhlICoqU29sYXJDb3JvbmFsQ29tcGxleDI1LnN0bCoqIGZpbGUgaXMgKipcfjEwOCBNQioqLCB3aGljaCBpcyBxdWl0ZQ0KbGFyZ2UgZm9yIGRpcmVjdCBwcm9jZXNzaW5nLiBJbnN0ZWFkIG9mIGZ1bGx5IGxvYWRpbmcgaXQsIEknbGwgZXh0cmFjdCBhDQoqKnN1YnNldCBvZiB2ZXJ0aWNlcyBhbmQgZmFjZXMqKiB0byB3b3JrIHdpdGggYSBzbWFsbGVyLCBtYW5hZ2VhYmxlDQpwb3J0aW9uIG9mIHRoZSBtb2RlbC4NCg0KSSdsbCBub3cgYXR0ZW1wdCB0byAqKnN0cmVhbSB0aGUgU1RMIGZpbGUqKiBhbmQgZXh0cmFjdCBhICoqZG93bnNhbXBsZWQNCnZlcnNpb24qKiBmb3IgZnVydGhlciB0cmFpbmluZy4NCg0KRXZlbiB3aXRoICoqc3RyZWFtaW5nIGRpc2FibGVkKiosIHRoZSBTVEwgZmlsZSBpcyAqKnRvbyBsYXJnZSB0byBwcm9jZXNzDQppbiBtZW1vcnkqKi4gU2luY2UgKipUcmltZXNoIGZhaWxzIHRvIGxvYWQgaXQqKiwgSSdsbCB1c2UgYW4gYWx0ZXJuYXRpdmUNCmFwcHJvYWNoOg0KDQojIyMgKipTb2x1dGlvbjogRXh0cmFjdCAmIFByb2Nlc3MgU1RMIGluIFNtYWxsZXIgQ2h1bmtzKioNCg0KSSB3aWxsOiAxLiAqKlJlYWQgdGhlIFNUTCBmaWxlIGxpbmUtYnktbGluZSoqIGluc3RlYWQgb2YgbG9hZGluZw0KZXZlcnl0aGluZyBhdCBvbmNlLiAyLiAqKkV4dHJhY3QgYSBzdWJzZXQgb2YgdmVydGljZXMqKiBpbnN0ZWFkIG9mIGZ1bGwNCm1lc2ggcHJvY2Vzc2luZy4gMy4gKipDb252ZXJ0IGl0IGludG8gYSBsaWdodHdlaWdodCByZXByZXNlbnRhdGlvbioqDQoocG9pbnQgY2xvdWQsIHZveGVsIGdyaWQpIGZvciB0cmFpbmluZy4NCg0KTGV0IG1lIGF0dGVtcHQgdG8gKipzdHJlYW0gcHJvY2VzcyoqIHRoZSBTVEwgZmlsZSBub3cuDQoNCkkgc3VjY2Vzc2Z1bGx5IGV4dHJhY3RlZCAqKjEsMzU5IHNhbXBsZWQgdmVydGljZXMqKiBmcm9tIHRoZQ0KKipTb2xhckNvcm9uYWxDb21wbGV4MjUuc3RsKiogZmlsZSB3aXRob3V0IG92ZXJsb2FkaW5nIG1lbW9yeS4NCg0KIyMjICoqTmV4dCBTdGVwczoqKg0KDQoxLiAgKipWaXN1YWxpemUgdGhlIGV4dHJhY3RlZCBwb2ludCBjbG91ZCoqLg0KMi4gICoqQ29udmVydCB0aGUgc2FtcGxlZCAzRCBwb2ludHMgaW50byBhIGxlYXJuYWJsZSBmb3JtYXQqKiAoZm9yIEdQVA0KICAgIHRyYWluaW5nKS4NCjMuICAqKkludGVncmF0ZSB0aGlzIGRhdGEgaW50byB5b3VyIENhcHN0b25lIHByb2plY3QuKioNCg0KSSdsbCBub3cgZ2VuZXJhdGUgYSAqKjNEIHNjYXR0ZXIgcGxvdCoqIG9mIHRoZSBleHRyYWN0ZWQgcG9pbnRzIGZvcg0KdmlzdWFsaXphdGlvbi4NCg0KSGVyZSBpcyB0aGUgKiozRCBzY2F0dGVyIHBsb3QqKiBvZiB0aGUgZXh0cmFjdGVkIHZlcnRpY2VzIGZyb20gdGhlDQoqKlNvbGFyIENvcm9uYWwgQ29tcGxleCBTVEwgZmlsZSoqLiBUaGlzIHByb3ZpZGVzIGEgKipkb3duc2FtcGxlZCBwb2ludA0KY2xvdWQgcmVwcmVzZW50YXRpb24qKiBvZiB0aGUgbW9kZWwsIHdoaWNoIGlzIG1vcmUgbWFuYWdlYWJsZSBmb3INCnRyYWluaW5nLg0K