Stream Name: Texaschikkita
Stream URL: https://rpubs.com/Texaschikkita
Stream ID: 9962324179
Measurement Id: G-CV2648GQMK


NVIDIA GPU Libraries and Tools: A Comprehensive Guide with Usage Examples

This guide provides an overview and practical code snippets for NVIDIA’s GPU-accelerated libraries, focusing on their unique capabilities and usage scenarios. The libraries are grouped by functionality: Quantum Computing, Post-Quantum Cryptography, Data Processing, Image/Video Processing, Communication, Deep Learning, and Partner Libraries.


Quantum Computing

1. cuQuantum

Description: NVIDIA’s SDK for high-performance quantum computing simulations.

Key Features:

  • GPU-accelerated quantum circuit simulation.
  • Integration with Qiskit and Cirq.
  • State vector and tensor network simulations.
  • Optimized for quantum-classical hybrid computing.

Example: Simulating a Quantum Circuit

from cuquantum import contract, circuit

# Define a simple quantum circuit
circuit = circuit.CircuitBuilder(2)
circuit.h(0).cx(0, 1)  # Apply Hadamard and CNOT gates

# Simulate the state vector
state = circuit.final_state_vector()
print("State vector:", state)

Integration with Qiskit:

from qiskit import QuantumCircuit
from qiskit.providers.aer import AerSimulator
from cuquantum import QiskitBackend

# Create a Qiskit quantum circuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)

# Use cuQuantum simulator
simulator = AerSimulator(backend=QiskitBackend())
result = simulator.run(qc).result()
print("Result:", result.get_statevector())

2. cuPQC (CUDA Post-Quantum Cryptography)

Description: A library for implementing quantum-resistant cryptographic algorithms.

Key Features:

  • Lattice-based cryptography and hash-based signatures.
  • GPU-accelerated operations for post-quantum cryptography.

Example: Lattice-Based Encryption

#include <cupqc/lattice_crypto.h>

int main() {
    // Initialize keys
    LatticeKeyPair keys = generate_lattice_keys();
    std::string message = "Quantum-safe encryption!";
    
    // Encrypt and decrypt
    auto ciphertext = encrypt_lattice(keys.public_key, message);
    auto decrypted_message = decrypt_lattice(keys.private_key, ciphertext);

    std::cout << "Decrypted message: " << decrypted_message << std::endl;
    return 0;
}

Data Processing Libraries

3. RAPIDS cuDF

Description: GPU-accelerated DataFrame library with a Pandas-like API.

Example: DataFrame Manipulations

import cudf

df = cudf.DataFrame({
    'a': [1, 2, 3],
    'b': [4, 5, 6]
})
df['c'] = df['a'] + df['b']
print(df)

4. NVTabular

Description: Preprocessing library for tabular data, ideal for recommender systems.

Example: Feature Engineering

import nvtabular as nvt

workflow = nvt.Workflow([
    nvt.ops.FillMissing() >> nvt.ops.Categorify()
])
dataset = nvt.Dataset("data.csv")
processed_data = workflow.fit_transform(dataset)

5. RAPIDS cuGraph

Description: GPU-accelerated graph analytics.

Example: PageRank Calculation

import cugraph
import cudf

# Create a graph
edges = cudf.DataFrame({'src': [0, 1, 2], 'dst': [1, 2, 0]})
graph = cugraph.Graph()
graph.from_cudf_edgelist(edges, source='src', destination='dst')

# Compute PageRank
pagerank_scores = cugraph.pagerank(graph)
print(pagerank_scores)

Image and Video Processing

6. NVIDIA DALI

Description: Accelerated data loading and augmentation for deep learning.

Example: Image Augmentation

import nvidia.dali.pipeline as pipeline
from nvidia.dali.plugin.pytorch import DALIGenericIterator

@pipeline.Pipeline
def data_pipeline():
    images = dali.fn.readers.file(file_root="/path/to/images")
    augmented = dali.fn.crop_mirror_normalize(images, crop=(224, 224))
    return augmented

7. cvCUDA

Description: Real-time image and video processing.

Example: Image Resizing

#include <cv-cuda/cv_cuda.h>

cv::Mat img = cv::imread("input.jpg");
cv::Mat resized;
cv::cuda::resize(img, resized, cv::Size(224, 224));
cv::imwrite("output.jpg", resized);

Communication Libraries

8. NCCL (NVIDIA Collective Communications Library)

Description: Efficient multi-GPU communication primitives.

Example: Distributed Training in PyTorch

import torch
import torch.distributed as dist

dist.init_process_group(backend='nccl')
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[torch.cuda.current_device()])

Deep Learning

9. cuDNN (CUDA Deep Neural Network library)

Description: Optimized routines for training deep neural networks.

Example: Convolution Operation

#include <cudnn.h>

// Initialize cuDNN and convolution descriptors
cudnnHandle_t handle;
cudnnCreate(&handle);
// Define and execute convolution using cuDNN API

10. NVIDIA TensorRT

Description: High-performance inference for deep learning models.

Example: Optimize Model

import tensorrt as trt

logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)
network = builder.create_network()
# Load and optimize model for inference

Partner Libraries

11. OpenCV with CUDA

Description: GPU-accelerated computer vision functions.

Example: Face Detection

import cv2

cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
img = cv2.imread('image.jpg')
faces = cascade.detectMultiScale(img)
for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imwrite('output.jpg', img)

LS0tDQp0aXRsZTogIk5WSURJQSBMaWJyYXJpZXMgT3ZlcnZpZXciDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KPCEtLSBHb29nbGUgdGFnIChndGFnLmpzKSAtLT4gIA0KPHNjcmlwdCBhc3luYyBzcmM9Imh0dHBzOi8vd3d3Lmdvb2dsZXRhZ21hbmFnZXIuY29tL2d0YWcvanM/aWQ9Ry1DVjI2NDhHUU1LIj48L3NjcmlwdD4gIA0KPHNjcmlwdD4gIA0KICB3aW5kb3cuZGF0YUxheWVyID0gd2luZG93LmRhdGFMYXllciB8fCBbXTsgIA0KICBmdW5jdGlvbiBndGFnKCl7ZGF0YUxheWVyLnB1c2goYXJndW1lbnRzKTt9ICANCiAgZ3RhZygnanMnLCBuZXcgRGF0ZSgpKTsgIA0KDQogIGd0YWcoJ2NvbmZpZycsICdHLUNWMjY0OEdRTUsnKTsgIA0KPC9zY3JpcHQ+ICANCg0KU3RyZWFtIE5hbWU6IFRleGFzY2hpa2tpdGEgIA0KU3RyZWFtIFVSTDogaHR0cHM6Ly9ycHVicy5jb20vVGV4YXNjaGlra2l0YSAgDQpTdHJlYW0gSUQ6IDk5NjIzMjQxNzkgIA0KTWVhc3VyZW1lbnQgSWQ6IEctQ1YyNjQ4R1FNSyAgDQoNCi0tLQ0KDQojIyMgTlZJRElBIEdQVSBMaWJyYXJpZXMgYW5kIFRvb2xzOiBBIENvbXByZWhlbnNpdmUgR3VpZGUgd2l0aCBVc2FnZSBFeGFtcGxlcw0KDQpUaGlzIGd1aWRlIHByb3ZpZGVzIGFuIG92ZXJ2aWV3IGFuZCBwcmFjdGljYWwgY29kZSBzbmlwcGV0cyBmb3IgTlZJRElBJ3MgR1BVLWFjY2VsZXJhdGVkIGxpYnJhcmllcywgZm9jdXNpbmcgb24gdGhlaXIgdW5pcXVlIGNhcGFiaWxpdGllcyBhbmQgdXNhZ2Ugc2NlbmFyaW9zLiBUaGUgbGlicmFyaWVzIGFyZSBncm91cGVkIGJ5IGZ1bmN0aW9uYWxpdHk6IFF1YW50dW0gQ29tcHV0aW5nLCBQb3N0LVF1YW50dW0gQ3J5cHRvZ3JhcGh5LCBEYXRhIFByb2Nlc3NpbmcsIEltYWdlL1ZpZGVvIFByb2Nlc3NpbmcsIENvbW11bmljYXRpb24sIERlZXAgTGVhcm5pbmcsIGFuZCBQYXJ0bmVyIExpYnJhcmllcy4NCg0KLS0tDQoNCiMjICoqUXVhbnR1bSBDb21wdXRpbmcqKg0KDQojIyMgMS4gKipjdVF1YW50dW0qKg0KKipEZXNjcmlwdGlvbioqOiBOVklESUEncyBTREsgZm9yIGhpZ2gtcGVyZm9ybWFuY2UgcXVhbnR1bSBjb21wdXRpbmcgc2ltdWxhdGlvbnMuDQoNCiMjIyMgS2V5IEZlYXR1cmVzOg0KLSBHUFUtYWNjZWxlcmF0ZWQgcXVhbnR1bSBjaXJjdWl0IHNpbXVsYXRpb24uDQotIEludGVncmF0aW9uIHdpdGggUWlza2l0IGFuZCBDaXJxLg0KLSBTdGF0ZSB2ZWN0b3IgYW5kIHRlbnNvciBuZXR3b3JrIHNpbXVsYXRpb25zLg0KLSBPcHRpbWl6ZWQgZm9yIHF1YW50dW0tY2xhc3NpY2FsIGh5YnJpZCBjb21wdXRpbmcuDQoNCiMjIyMgRXhhbXBsZTogU2ltdWxhdGluZyBhIFF1YW50dW0gQ2lyY3VpdA0KYGBgcHl0aG9uDQpmcm9tIGN1cXVhbnR1bSBpbXBvcnQgY29udHJhY3QsIGNpcmN1aXQNCg0KIyBEZWZpbmUgYSBzaW1wbGUgcXVhbnR1bSBjaXJjdWl0DQpjaXJjdWl0ID0gY2lyY3VpdC5DaXJjdWl0QnVpbGRlcigyKQ0KY2lyY3VpdC5oKDApLmN4KDAsIDEpICAjIEFwcGx5IEhhZGFtYXJkIGFuZCBDTk9UIGdhdGVzDQoNCiMgU2ltdWxhdGUgdGhlIHN0YXRlIHZlY3Rvcg0Kc3RhdGUgPSBjaXJjdWl0LmZpbmFsX3N0YXRlX3ZlY3RvcigpDQpwcmludCgiU3RhdGUgdmVjdG9yOiIsIHN0YXRlKQ0KYGBgDQoNCiMjIyMgSW50ZWdyYXRpb24gd2l0aCBRaXNraXQ6DQpgYGBweXRob24NCmZyb20gcWlza2l0IGltcG9ydCBRdWFudHVtQ2lyY3VpdA0KZnJvbSBxaXNraXQucHJvdmlkZXJzLmFlciBpbXBvcnQgQWVyU2ltdWxhdG9yDQpmcm9tIGN1cXVhbnR1bSBpbXBvcnQgUWlza2l0QmFja2VuZA0KDQojIENyZWF0ZSBhIFFpc2tpdCBxdWFudHVtIGNpcmN1aXQNCnFjID0gUXVhbnR1bUNpcmN1aXQoMikNCnFjLmgoMCkNCnFjLmN4KDAsIDEpDQoNCiMgVXNlIGN1UXVhbnR1bSBzaW11bGF0b3INCnNpbXVsYXRvciA9IEFlclNpbXVsYXRvcihiYWNrZW5kPVFpc2tpdEJhY2tlbmQoKSkNCnJlc3VsdCA9IHNpbXVsYXRvci5ydW4ocWMpLnJlc3VsdCgpDQpwcmludCgiUmVzdWx0OiIsIHJlc3VsdC5nZXRfc3RhdGV2ZWN0b3IoKSkNCmBgYA0KDQotLS0NCg0KIyMjIDIuICoqY3VQUUMgKENVREEgUG9zdC1RdWFudHVtIENyeXB0b2dyYXBoeSkqKg0KKipEZXNjcmlwdGlvbioqOiBBIGxpYnJhcnkgZm9yIGltcGxlbWVudGluZyBxdWFudHVtLXJlc2lzdGFudCBjcnlwdG9ncmFwaGljIGFsZ29yaXRobXMuDQoNCiMjIyMgS2V5IEZlYXR1cmVzOg0KLSBMYXR0aWNlLWJhc2VkIGNyeXB0b2dyYXBoeSBhbmQgaGFzaC1iYXNlZCBzaWduYXR1cmVzLg0KLSBHUFUtYWNjZWxlcmF0ZWQgb3BlcmF0aW9ucyBmb3IgcG9zdC1xdWFudHVtIGNyeXB0b2dyYXBoeS4NCg0KIyMjIyBFeGFtcGxlOiBMYXR0aWNlLUJhc2VkIEVuY3J5cHRpb24NCmBgYGNwcA0KI2luY2x1ZGUgPGN1cHFjL2xhdHRpY2VfY3J5cHRvLmg+DQoNCmludCBtYWluKCkgew0KICAgIC8vIEluaXRpYWxpemUga2V5cw0KICAgIExhdHRpY2VLZXlQYWlyIGtleXMgPSBnZW5lcmF0ZV9sYXR0aWNlX2tleXMoKTsNCiAgICBzdGQ6OnN0cmluZyBtZXNzYWdlID0gIlF1YW50dW0tc2FmZSBlbmNyeXB0aW9uISI7DQogICAgDQogICAgLy8gRW5jcnlwdCBhbmQgZGVjcnlwdA0KICAgIGF1dG8gY2lwaGVydGV4dCA9IGVuY3J5cHRfbGF0dGljZShrZXlzLnB1YmxpY19rZXksIG1lc3NhZ2UpOw0KICAgIGF1dG8gZGVjcnlwdGVkX21lc3NhZ2UgPSBkZWNyeXB0X2xhdHRpY2Uoa2V5cy5wcml2YXRlX2tleSwgY2lwaGVydGV4dCk7DQoNCiAgICBzdGQ6OmNvdXQgPDwgIkRlY3J5cHRlZCBtZXNzYWdlOiAiIDw8IGRlY3J5cHRlZF9tZXNzYWdlIDw8IHN0ZDo6ZW5kbDsNCiAgICByZXR1cm4gMDsNCn0NCmBgYA0KDQotLS0NCg0KIyMgKipEYXRhIFByb2Nlc3NpbmcgTGlicmFyaWVzKioNCg0KIyMjIDMuICoqUkFQSURTIGN1REYqKg0KKipEZXNjcmlwdGlvbioqOiBHUFUtYWNjZWxlcmF0ZWQgRGF0YUZyYW1lIGxpYnJhcnkgd2l0aCBhIFBhbmRhcy1saWtlIEFQSS4NCg0KIyMjIyBFeGFtcGxlOiBEYXRhRnJhbWUgTWFuaXB1bGF0aW9ucw0KYGBgcHl0aG9uDQppbXBvcnQgY3VkZg0KDQpkZiA9IGN1ZGYuRGF0YUZyYW1lKHsNCiAgICAnYSc6IFsxLCAyLCAzXSwNCiAgICAnYic6IFs0LCA1LCA2XQ0KfSkNCmRmWydjJ10gPSBkZlsnYSddICsgZGZbJ2InXQ0KcHJpbnQoZGYpDQpgYGANCg0KLS0tDQoNCiMjIyA0LiAqKk5WVGFidWxhcioqDQoqKkRlc2NyaXB0aW9uKio6IFByZXByb2Nlc3NpbmcgbGlicmFyeSBmb3IgdGFidWxhciBkYXRhLCBpZGVhbCBmb3IgcmVjb21tZW5kZXIgc3lzdGVtcy4NCg0KIyMjIyBFeGFtcGxlOiBGZWF0dXJlIEVuZ2luZWVyaW5nDQpgYGBweXRob24NCmltcG9ydCBudnRhYnVsYXIgYXMgbnZ0DQoNCndvcmtmbG93ID0gbnZ0LldvcmtmbG93KFsNCiAgICBudnQub3BzLkZpbGxNaXNzaW5nKCkgPj4gbnZ0Lm9wcy5DYXRlZ29yaWZ5KCkNCl0pDQpkYXRhc2V0ID0gbnZ0LkRhdGFzZXQoImRhdGEuY3N2IikNCnByb2Nlc3NlZF9kYXRhID0gd29ya2Zsb3cuZml0X3RyYW5zZm9ybShkYXRhc2V0KQ0KYGBgDQoNCi0tLQ0KDQojIyMgNS4gKipSQVBJRFMgY3VHcmFwaCoqDQoqKkRlc2NyaXB0aW9uKio6IEdQVS1hY2NlbGVyYXRlZCBncmFwaCBhbmFseXRpY3MuDQoNCiMjIyMgRXhhbXBsZTogUGFnZVJhbmsgQ2FsY3VsYXRpb24NCmBgYHB5dGhvbg0KaW1wb3J0IGN1Z3JhcGgNCmltcG9ydCBjdWRmDQoNCiMgQ3JlYXRlIGEgZ3JhcGgNCmVkZ2VzID0gY3VkZi5EYXRhRnJhbWUoeydzcmMnOiBbMCwgMSwgMl0sICdkc3QnOiBbMSwgMiwgMF19KQ0KZ3JhcGggPSBjdWdyYXBoLkdyYXBoKCkNCmdyYXBoLmZyb21fY3VkZl9lZGdlbGlzdChlZGdlcywgc291cmNlPSdzcmMnLCBkZXN0aW5hdGlvbj0nZHN0JykNCg0KIyBDb21wdXRlIFBhZ2VSYW5rDQpwYWdlcmFua19zY29yZXMgPSBjdWdyYXBoLnBhZ2VyYW5rKGdyYXBoKQ0KcHJpbnQocGFnZXJhbmtfc2NvcmVzKQ0KYGBgDQoNCi0tLQ0KDQojIyAqKkltYWdlIGFuZCBWaWRlbyBQcm9jZXNzaW5nKioNCg0KIyMjIDYuICoqTlZJRElBIERBTEkqKg0KKipEZXNjcmlwdGlvbioqOiBBY2NlbGVyYXRlZCBkYXRhIGxvYWRpbmcgYW5kIGF1Z21lbnRhdGlvbiBmb3IgZGVlcCBsZWFybmluZy4NCg0KIyMjIyBFeGFtcGxlOiBJbWFnZSBBdWdtZW50YXRpb24NCmBgYHB5dGhvbg0KaW1wb3J0IG52aWRpYS5kYWxpLnBpcGVsaW5lIGFzIHBpcGVsaW5lDQpmcm9tIG52aWRpYS5kYWxpLnBsdWdpbi5weXRvcmNoIGltcG9ydCBEQUxJR2VuZXJpY0l0ZXJhdG9yDQoNCkBwaXBlbGluZS5QaXBlbGluZQ0KZGVmIGRhdGFfcGlwZWxpbmUoKToNCiAgICBpbWFnZXMgPSBkYWxpLmZuLnJlYWRlcnMuZmlsZShmaWxlX3Jvb3Q9Ii9wYXRoL3RvL2ltYWdlcyIpDQogICAgYXVnbWVudGVkID0gZGFsaS5mbi5jcm9wX21pcnJvcl9ub3JtYWxpemUoaW1hZ2VzLCBjcm9wPSgyMjQsIDIyNCkpDQogICAgcmV0dXJuIGF1Z21lbnRlZA0KYGBgDQoNCi0tLQ0KDQojIyMgNy4gKipjdkNVREEqKg0KKipEZXNjcmlwdGlvbioqOiBSZWFsLXRpbWUgaW1hZ2UgYW5kIHZpZGVvIHByb2Nlc3NpbmcuDQoNCiMjIyMgRXhhbXBsZTogSW1hZ2UgUmVzaXppbmcNCmBgYGNwcA0KI2luY2x1ZGUgPGN2LWN1ZGEvY3ZfY3VkYS5oPg0KDQpjdjo6TWF0IGltZyA9IGN2OjppbXJlYWQoImlucHV0LmpwZyIpOw0KY3Y6Ok1hdCByZXNpemVkOw0KY3Y6OmN1ZGE6OnJlc2l6ZShpbWcsIHJlc2l6ZWQsIGN2OjpTaXplKDIyNCwgMjI0KSk7DQpjdjo6aW13cml0ZSgib3V0cHV0LmpwZyIsIHJlc2l6ZWQpOw0KYGBgDQoNCi0tLQ0KDQojIyAqKkNvbW11bmljYXRpb24gTGlicmFyaWVzKioNCg0KIyMjIDguICoqTkNDTCAoTlZJRElBIENvbGxlY3RpdmUgQ29tbXVuaWNhdGlvbnMgTGlicmFyeSkqKg0KKipEZXNjcmlwdGlvbioqOiBFZmZpY2llbnQgbXVsdGktR1BVIGNvbW11bmljYXRpb24gcHJpbWl0aXZlcy4NCg0KIyMjIyBFeGFtcGxlOiBEaXN0cmlidXRlZCBUcmFpbmluZyBpbiBQeVRvcmNoDQpgYGBweXRob24NCmltcG9ydCB0b3JjaA0KaW1wb3J0IHRvcmNoLmRpc3RyaWJ1dGVkIGFzIGRpc3QNCg0KZGlzdC5pbml0X3Byb2Nlc3NfZ3JvdXAoYmFja2VuZD0nbmNjbCcpDQptb2RlbCA9IHRvcmNoLm5uLnBhcmFsbGVsLkRpc3RyaWJ1dGVkRGF0YVBhcmFsbGVsKG1vZGVsLCBkZXZpY2VfaWRzPVt0b3JjaC5jdWRhLmN1cnJlbnRfZGV2aWNlKCldKQ0KYGBgDQoNCi0tLQ0KDQojIyAqKkRlZXAgTGVhcm5pbmcqKg0KDQojIyMgOS4gKipjdUROTiAoQ1VEQSBEZWVwIE5ldXJhbCBOZXR3b3JrIGxpYnJhcnkpKioNCioqRGVzY3JpcHRpb24qKjogT3B0aW1pemVkIHJvdXRpbmVzIGZvciB0cmFpbmluZyBkZWVwIG5ldXJhbCBuZXR3b3Jrcy4NCg0KIyMjIyBFeGFtcGxlOiBDb252b2x1dGlvbiBPcGVyYXRpb24NCmBgYGNwcA0KI2luY2x1ZGUgPGN1ZG5uLmg+DQoNCi8vIEluaXRpYWxpemUgY3VETk4gYW5kIGNvbnZvbHV0aW9uIGRlc2NyaXB0b3JzDQpjdWRubkhhbmRsZV90IGhhbmRsZTsNCmN1ZG5uQ3JlYXRlKCZoYW5kbGUpOw0KLy8gRGVmaW5lIGFuZCBleGVjdXRlIGNvbnZvbHV0aW9uIHVzaW5nIGN1RE5OIEFQSQ0KYGBgDQoNCi0tLQ0KDQojIyMgMTAuICoqTlZJRElBIFRlbnNvclJUKioNCioqRGVzY3JpcHRpb24qKjogSGlnaC1wZXJmb3JtYW5jZSBpbmZlcmVuY2UgZm9yIGRlZXAgbGVhcm5pbmcgbW9kZWxzLg0KDQojIyMjIEV4YW1wbGU6IE9wdGltaXplIE1vZGVsDQpgYGBweXRob24NCmltcG9ydCB0ZW5zb3JydCBhcyB0cnQNCg0KbG9nZ2VyID0gdHJ0LkxvZ2dlcih0cnQuTG9nZ2VyLldBUk5JTkcpDQpidWlsZGVyID0gdHJ0LkJ1aWxkZXIobG9nZ2VyKQ0KbmV0d29yayA9IGJ1aWxkZXIuY3JlYXRlX25ldHdvcmsoKQ0KIyBMb2FkIGFuZCBvcHRpbWl6ZSBtb2RlbCBmb3IgaW5mZXJlbmNlDQpgYGANCg0KLS0tDQoNCiMjICoqUGFydG5lciBMaWJyYXJpZXMqKg0KDQojIyMgMTEuICoqT3BlbkNWIHdpdGggQ1VEQSoqDQoqKkRlc2NyaXB0aW9uKio6IEdQVS1hY2NlbGVyYXRlZCBjb21wdXRlciB2aXNpb24gZnVuY3Rpb25zLg0KDQojIyMjIEV4YW1wbGU6IEZhY2UgRGV0ZWN0aW9uDQpgYGBweXRob24NCmltcG9ydCBjdjINCg0KY2FzY2FkZSA9IGN2Mi5DYXNjYWRlQ2xhc3NpZmllcignaGFhcmNhc2NhZGVfZnJvbnRhbGZhY2VfZGVmYXVsdC54bWwnKQ0KaW1nID0gY3YyLmltcmVhZCgnaW1hZ2UuanBnJykNCmZhY2VzID0gY2FzY2FkZS5kZXRlY3RNdWx0aVNjYWxlKGltZykNCmZvciAoeCwgeSwgdywgaCkgaW4gZmFjZXM6DQogICAgY3YyLnJlY3RhbmdsZShpbWcsICh4LCB5KSwgKHgrdywgeStoKSwgKDI1NSwgMCwgMCksIDIpDQpjdjIuaW13cml0ZSgnb3V0cHV0LmpwZycsIGltZykNCmBgYA0KDQotLS0NCg==