Create Environment
In Bash (Use mamba or conda depending on your system setup)
mamba create -n ml7331 python=3.9 r-base=4.4.1
mamba activate ml7331
mamba install ipykernel
python -m ipykernel install --user --name ml7331 --display-name "Python (ml7331)"
# (restart VSCode or source ~/.bashrc)
mamba activate ml7331
mamba install tzlocal
mamba install plotly
pip install rpy2
pip install seaborn
pip install jupyter
pip install matplotlib
pip install scipy
pip install scikit-learn
pip install pillow
pip install tensorflow
pip install notebook
pip install folium
pip install geopandas
pip install PyGithub
pip install github3.py
pip install python-gitlab
pip check
In R
.libPaths(c("C:/Users/jessi/mambaforge/envs/ml7331/Lib/R/library", .libPaths()))
install.packages("reticulate")
install.packages('arules')
install.packages('arulesViz')
install.packages('mlbench')
install.packages("tidyverse")
install.packages("caret")
install.packages("mlr")
install.packages("xgboost")
Verify Installs:
library(arules)
library(arulesViz)
library(mlbench)
library(reticulate)
Save the Environment:
mamba env export -n ml7331 > ml7331_environment.yml
# If updated:
mamba env export -n ml7331 > ml7331_environment_updated.yml
conda clean --all
In R Studio:
library(reticulate)
use_condaenv("ml7331", required = TRUE)
Run a Simple Python Command:
py_run_string("x = 10")
py_run_string("y = x + 5")
py$x # Access the Python variable in R
py$y # Access another Python variable in R
Install an R Package Using Mamba:
system("mamba install -c conda-forge r-ggplot2")
Install numpy Using Mamba:
system("mamba install -c conda-forge numpy")
Alternatively Use PIP:
# Install numpy using pip
py_install("numpy", method = "pip")
Verify Installs:
Check TensorFlow:
tensorflow <- import("tensorflow")
print(tensorflow$__version__)
Check Keras (if needed):
keras <- import("keras")
print(keras$__version__)
Check Installed Packages:
system("mamba list")
system("pip list")
In R Markdown, Notebook, or Quarto:
x = 10
y = x + 5
print(y)
Notes:
rpy2
is used to run R within Python (install with
pip).
reticulate
is used to run Python within R (install
within R).
Additional Setup Notes for August 20, 2024
Set Python Path in R Studio:
library(reticulate)
use_python("C:/Users/jessi/mambaforge/envs/ml7331/python.exe", required = TRUE)
Check Versions and Paths:
Get R Path:
R.home()
Get Python Version:
python --version
Example Python Code to Set R_HOME in Python:
import os
# Set R_HOME to the full directory path
os.environ['R_HOME'] = r'C:\Program Files\R\R-4.4.1'
import rpy2.robjects as ro
# Test R integration
print(ro.r('R.version.string'))
Install Specific Package Versions:
mamba install \
numpy=1.23.5 \
pandas=2.2.2 \
scikit-learn=1.5.1 \
matplotlib=3.9.1 \
seaborn=0.13.2 \
tensorflow=2.10.0 \
jupyterlab=4.2.4
mamba install \
scipy=1.13.1 \
pytorch=2.3.1 \
torch-geometric=2.5.3 \
transformers=4.37.2
GitHub Integration Example Code:
```python
#from github import Github
#g = Github("your_personal_access_token")
#user = g.get_user("username")
#for repo in user.get_repos():
#print(repo.name)
```
```python
#import gitlab
#gl = gitlab.Gitlab('https://gitlab.com', private_token='your_private_access_token')
#projects = gl.projects.list()
#for project in projects:
#print(project.name)
```
GraphLab Environment Setup:
Create and Activate GraphLab Environment:
mamba create -n graphlab-env python=2.7 r-base=3.6.1
mamba activate graphlab-env
mamba install anaconda rpy2 tzlocal plotly pillow
pip install tornado==4.5.3
In R:
.libPaths(c("C:/Users/jessi/mambaforge/envs/graphlab-env/Lib/R/library", .libPaths()))
install.packages("reticulate")
install.packages("ggplot2")
Save the Environment:
mamba env export -n graphlab-env > graphlab-env.yml
Reopen the Environment in R Studio:
library(reticulate)
use_condaenv("graphlab-env", required = TRUE)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KLS0tDQp0aXRsZTogIk1MNzMzMSBFbnZpcm9ubWVudHMiDQphdXRob3I6ICJKZXNzaVRNY1AiDQojZm9ybWF0OiBiZWFtZXIgKGJlYW1lciBvbGQpDQpmb3JtYXQ6IGh0bWwNCmVkaXRvcjogdmlzdWFsDQotLS0NCg0KIyMgQ3JlYXRlIEVudmlyb25tZW50DQoNCiMjIyBJbiBCYXNoIChVc2UgbWFtYmEgb3IgY29uZGEgZGVwZW5kaW5nIG9uIHlvdXIgc3lzdGVtIHNldHVwKQ0KDQpgYGAgYmFzaA0KbWFtYmEgY3JlYXRlIC1uIG1sNzMzMSBweXRob249My45IHItYmFzZT00LjQuMQ0KbWFtYmEgYWN0aXZhdGUgbWw3MzMxDQptYW1iYSBpbnN0YWxsIGlweWtlcm5lbA0KcHl0aG9uIC1tIGlweWtlcm5lbCBpbnN0YWxsIC0tdXNlciAtLW5hbWUgbWw3MzMxIC0tZGlzcGxheS1uYW1lICJQeXRob24gKG1sNzMzMSkiDQojIChyZXN0YXJ0IFZTQ29kZSBvciBzb3VyY2Ugfi8uYmFzaHJjKQ0KbWFtYmEgYWN0aXZhdGUgbWw3MzMxDQptYW1iYSBpbnN0YWxsIHR6bG9jYWwNCm1hbWJhIGluc3RhbGwgcGxvdGx5IA0KcGlwIGluc3RhbGwgcnB5Mg0KcGlwIGluc3RhbGwgc2VhYm9ybg0KcGlwIGluc3RhbGwganVweXRlcg0KcGlwIGluc3RhbGwgbWF0cGxvdGxpYg0KcGlwIGluc3RhbGwgc2NpcHkNCnBpcCBpbnN0YWxsIHNjaWtpdC1sZWFybg0KcGlwIGluc3RhbGwgcGlsbG93DQpwaXAgaW5zdGFsbCB0ZW5zb3JmbG93DQpwaXAgaW5zdGFsbCBub3RlYm9vaw0KcGlwIGluc3RhbGwgZm9saXVtDQpwaXAgaW5zdGFsbCBnZW9wYW5kYXMNCnBpcCBpbnN0YWxsIFB5R2l0aHViDQpwaXAgaW5zdGFsbCBnaXRodWIzLnB5DQpwaXAgaW5zdGFsbCBweXRob24tZ2l0bGFiDQpwaXAgY2hlY2sNCmBgYA0KDQojIyMgSW4gUg0KDQpgYGAgcg0KLmxpYlBhdGhzKGMoIkM6L1VzZXJzL2plc3NpL21hbWJhZm9yZ2UvZW52cy9tbDczMzEvTGliL1IvbGlicmFyeSIsIC5saWJQYXRocygpKSkgDQppbnN0YWxsLnBhY2thZ2VzKCJyZXRpY3VsYXRlIikNCmluc3RhbGwucGFja2FnZXMoJ2FydWxlcycpDQppbnN0YWxsLnBhY2thZ2VzKCdhcnVsZXNWaXonKQ0KaW5zdGFsbC5wYWNrYWdlcygnbWxiZW5jaCcpDQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KaW5zdGFsbC5wYWNrYWdlcygibWxyIikNCmluc3RhbGwucGFja2FnZXMoInhnYm9vc3QiKQ0KYGBgDQoNCiMjIyBWZXJpZnkgSW5zdGFsbHM6DQoNCmBgYCByDQpsaWJyYXJ5KGFydWxlcykNCmxpYnJhcnkoYXJ1bGVzVml6KQ0KbGlicmFyeShtbGJlbmNoKQ0KbGlicmFyeShyZXRpY3VsYXRlKQ0KYGBgDQoNCiMjIyBTYXZlIHRoZSBFbnZpcm9ubWVudDoNCg0KYGBgIGJhc2gNCm1hbWJhIGVudiBleHBvcnQgLW4gbWw3MzMxID4gbWw3MzMxX2Vudmlyb25tZW50LnltbA0KIyBJZiB1cGRhdGVkOg0KbWFtYmEgZW52IGV4cG9ydCAtbiBtbDczMzEgPiBtbDczMzFfZW52aXJvbm1lbnRfdXBkYXRlZC55bWwNCmNvbmRhIGNsZWFuIC0tYWxsDQpgYGANCg0KIyMgSW4gUiBTdHVkaW86DQoNCmBgYCByDQpsaWJyYXJ5KHJldGljdWxhdGUpDQp1c2VfY29uZGFlbnYoIm1sNzMzMSIsIHJlcXVpcmVkID0gVFJVRSkNCmBgYA0KDQojIyMgUnVuIGEgU2ltcGxlIFB5dGhvbiBDb21tYW5kOg0KDQpgYGAgcg0KcHlfcnVuX3N0cmluZygieCA9IDEwIikNCnB5X3J1bl9zdHJpbmcoInkgPSB4ICsgNSIpDQpweSR4ICAjIEFjY2VzcyB0aGUgUHl0aG9uIHZhcmlhYmxlIGluIFINCnB5JHkgICMgQWNjZXNzIGFub3RoZXIgUHl0aG9uIHZhcmlhYmxlIGluIFINCmBgYA0KDQojIyMgSW5zdGFsbCBhbiBSIFBhY2thZ2UgVXNpbmcgTWFtYmE6DQoNCmBgYCByDQpzeXN0ZW0oIm1hbWJhIGluc3RhbGwgLWMgY29uZGEtZm9yZ2Ugci1nZ3Bsb3QyIikNCmBgYA0KDQojIyMgSW5zdGFsbCBudW1weSBVc2luZyBNYW1iYToNCg0KYGBgIHINCnN5c3RlbSgibWFtYmEgaW5zdGFsbCAtYyBjb25kYS1mb3JnZSBudW1weSIpDQpgYGANCg0KIyMjIEFsdGVybmF0aXZlbHkgVXNlIFBJUDoNCg0KYGBgIHINCiMgSW5zdGFsbCBudW1weSB1c2luZyBwaXANCnB5X2luc3RhbGwoIm51bXB5IiwgbWV0aG9kID0gInBpcCIpDQpgYGANCg0KIyMjIFZlcmlmeSBJbnN0YWxsczoNCg0KIyMjIyBDaGVjayBUZW5zb3JGbG93Og0KDQpgYGAgcg0KdGVuc29yZmxvdyA8LSBpbXBvcnQoInRlbnNvcmZsb3ciKQ0KcHJpbnQodGVuc29yZmxvdyRfX3ZlcnNpb25fXykNCmBgYA0KDQojIyMjIENoZWNrIEtlcmFzIChpZiBuZWVkZWQpOg0KDQpgYGAgcg0Ka2VyYXMgPC0gaW1wb3J0KCJrZXJhcyIpDQpwcmludChrZXJhcyRfX3ZlcnNpb25fXykNCmBgYA0KDQojIyMgQ2hlY2sgSW5zdGFsbGVkIFBhY2thZ2VzOg0KDQpgYGAgcg0Kc3lzdGVtKCJtYW1iYSBsaXN0IikNCnN5c3RlbSgicGlwIGxpc3QiKQ0KYGBgDQoNCiMjIEluIFIgTWFya2Rvd24sIE5vdGVib29rLCBvciBRdWFydG86DQoNCmBgYHtweXRob259DQp4ID0gMTANCnkgPSB4ICsgNQ0KcHJpbnQoeSkNCmBgYA0KDQojIyMgTm90ZXM6DQoNCi0gICBgcnB5MmAgaXMgdXNlZCB0byBydW4gUiB3aXRoaW4gUHl0aG9uIChpbnN0YWxsIHdpdGggcGlwKS4NCi0gICBgcmV0aWN1bGF0ZWAgaXMgdXNlZCB0byBydW4gUHl0aG9uIHdpdGhpbiBSIChpbnN0YWxsIHdpdGhpbiBSKS4NCg0KIyMgQWRkaXRpb25hbCBTZXR1cCBOb3RlcyBmb3IgQXVndXN0IDIwLCAyMDI0DQoNCiMjIyBTZXQgUHl0aG9uIFBhdGggaW4gUiBTdHVkaW86DQoNCmBgYCByDQpsaWJyYXJ5KHJldGljdWxhdGUpDQp1c2VfcHl0aG9uKCJDOi9Vc2Vycy9qZXNzaS9tYW1iYWZvcmdlL2VudnMvbWw3MzMxL3B5dGhvbi5leGUiLCByZXF1aXJlZCA9IFRSVUUpDQpgYGANCg0KIyMjIENvbmZpZ3VyZSBRdWFydG8gdG8gVXNlIHRoZSBDb3JyZWN0IFB5dGhvbiBFbnZpcm9ubWVudDoNCg0KLSAgICoqQmFzaDoqKg0KDQogICAgYGBgIGJhc2gNCiAgICBleHBvcnQgUVVBUlRPX1BZVEhPTj0iQzovVXNlcnMvamVzc2kvbWFtYmFmb3JnZS9lbnZzL21sNzMzMS9weXRob24uZXhlIg0KICAgIGBgYA0KDQotICAgKipDb21tYW5kIFByb21wdDoqKg0KDQogICAgYGBgIGNtZA0KICAgIHNldCBRVUFSVE9fUFlUSE9OPSJDOi9Vc2Vycy9qZXNzaS9tYW1iYWZvcmdlL2VudnMvbWw3MzMxL3B5dGhvbi5leGUiDQogICAgYGBgDQoNCi0gICAqKlI6KioNCg0KICAgIGBgYCByDQogICAgZmlsZS5lZGl0KCJ+Ly5SZW52aXJvbiIpDQogICAgYGBgDQoNCi0gICAqKlRpbnlUZVggSW5zdGFsbGF0aW9uOioqDQoNCiAgICBgYGAgcg0KICAgIHRpbnl0ZXg6Omluc3RhbGxfdGlueXRleChidW5kbGUgPSAnVGlueVRlWC0yJykNCiAgICBgYGANCg0KIyMjIENoZWNrIFZlcnNpb25zIGFuZCBQYXRoczoNCg0KLSAgICoqR2V0IFIgUGF0aDoqKg0KDQogICAgYGBgIHINCiAgICBSLmhvbWUoKQ0KICAgIGBgYA0KDQotICAgKipHZXQgUHl0aG9uIFZlcnNpb246KioNCg0KICAgIGBgYCBiYXNoDQogICAgcHl0aG9uIC0tdmVyc2lvbg0KICAgIGBgYA0KDQojIyMgRXhhbXBsZSBQeXRob24gQ29kZSB0byBTZXQgUl9IT01FIGluIFB5dGhvbjoNCg0KYGBge3B5dGhvbn0NCmltcG9ydCBvcyAgDQoNCiMgU2V0IFJfSE9NRSB0byB0aGUgZnVsbCBkaXJlY3RvcnkgcGF0aCAgDQpvcy5lbnZpcm9uWydSX0hPTUUnXSA9IHInQzpcUHJvZ3JhbSBGaWxlc1xSXFItNC40LjEnICANCg0KaW1wb3J0IHJweTIucm9iamVjdHMgYXMgcm8gIA0KIyBUZXN0IFIgaW50ZWdyYXRpb24gIA0KcHJpbnQocm8ucignUi52ZXJzaW9uLnN0cmluZycpKQ0KYGBgDQoNCiMjIyBJbnN0YWxsIFNwZWNpZmljIFBhY2thZ2UgVmVyc2lvbnM6DQoNCmBgYCBiYXNoDQptYW1iYSBpbnN0YWxsIFwNCiAgICBudW1weT0xLjIzLjUgXA0KICAgIHBhbmRhcz0yLjIuMiBcDQogICAgc2Npa2l0LWxlYXJuPTEuNS4xIFwNCiAgICBtYXRwbG90bGliPTMuOS4xIFwNCiAgICBzZWFib3JuPTAuMTMuMiBcDQogICAgdGVuc29yZmxvdz0yLjEwLjAgXA0KICAgIGp1cHl0ZXJsYWI9NC4yLjQNCm1hbWJhIGluc3RhbGwgXA0KICAgIHNjaXB5PTEuMTMuMSBcDQogICAgcHl0b3JjaD0yLjMuMSBcDQogICAgdG9yY2gtZ2VvbWV0cmljPTIuNS4zIFwNCiAgICB0cmFuc2Zvcm1lcnM9NC4zNy4yDQpgYGANCg0KIyMjIEdpdEh1YiBJbnRlZ3JhdGlvbiBFeGFtcGxlIENvZGU6DQoNCi0gICAqKlVzaW5nIFB5R2l0aHViOioqDQoNCiAgICBgYGB7cHl0aG9ufQ0KICAgICNmcm9tIGdpdGh1YiBpbXBvcnQgR2l0aHViICANCg0KICAgICNnID0gR2l0aHViKCJ5b3VyX3BlcnNvbmFsX2FjY2Vzc190b2tlbiIpICANCg0KICAgICN1c2VyID0gZy5nZXRfdXNlcigidXNlcm5hbWUiKSAgDQoNCiAgICAjZm9yIHJlcG8gaW4gdXNlci5nZXRfcmVwb3MoKTogIA0KICAgICAgICAjcHJpbnQocmVwby5uYW1lKQ0KICAgIGBgYA0KDQotICAgKipVc2luZyBHaXRMYWI6KioNCg0KICAgIGBgYHtweXRob259DQogICAgI2ltcG9ydCBnaXRsYWIgIA0KDQogICAgI2dsID0gZ2l0bGFiLkdpdGxhYignaHR0cHM6Ly9naXRsYWIuY29tJywgcHJpdmF0ZV90b2tlbj0neW91cl9wcml2YXRlX2FjY2Vzc190b2tlbicpICANCg0KICAgICNwcm9qZWN0cyA9IGdsLnByb2plY3RzLmxpc3QoKSAgDQogICAgI2ZvciBwcm9qZWN0IGluIHByb2plY3RzOiAgDQogICAgICAgICNwcmludChwcm9qZWN0Lm5hbWUpDQogICAgYGBgDQoNCiMjIEdyYXBoTGFiIEVudmlyb25tZW50IFNldHVwOg0KDQojIyMgQ3JlYXRlIGFuZCBBY3RpdmF0ZSBHcmFwaExhYiBFbnZpcm9ubWVudDoNCg0KYGBgIGJhc2gNCm1hbWJhIGNyZWF0ZSAtbiBncmFwaGxhYi1lbnYgcHl0aG9uPTIuNyByLWJhc2U9My42LjENCm1hbWJhIGFjdGl2YXRlIGdyYXBobGFiLWVudg0KbWFtYmEgaW5zdGFsbCBhbmFjb25kYSBycHkyIHR6bG9jYWwgcGxvdGx5IHBpbGxvdw0KcGlwIGluc3RhbGwgdG9ybmFkbz09NC41LjMNCmBgYA0KDQojIyMgSW4gUjoNCg0KYGBgIHINCi5saWJQYXRocyhjKCJDOi9Vc2Vycy9qZXNzaS9tYW1iYWZvcmdlL2VudnMvZ3JhcGhsYWItZW52L0xpYi9SL2xpYnJhcnkiLCAubGliUGF0aHMoKSkpDQppbnN0YWxsLnBhY2thZ2VzKCJyZXRpY3VsYXRlIikNCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KYGBgDQoNCiMjIyBTYXZlIHRoZSBFbnZpcm9ubWVudDoNCg0KYGBgIGJhc2gNCm1hbWJhIGVudiBleHBvcnQgLW4gZ3JhcGhsYWItZW52ID4gZ3JhcGhsYWItZW52LnltbA0KYGBgDQoNCiMjIyBSZW9wZW4gdGhlIEVudmlyb25tZW50IGluIFIgU3R1ZGlvOg0KDQpgYGAgcg0KbGlicmFyeShyZXRpY3VsYXRlKQ0KdXNlX2NvbmRhZW52KCJncmFwaGxhYi1lbnYiLCByZXF1aXJlZCA9IFRSVUUpDQpgYGANCg0KIyMgVXNlZnVsIE1hbWJhIENvbW1hbmRzOg0KDQotICAgKipMaXN0IEVudmlyb25tZW50czoqKg0KDQogICAgYGBgIGJhc2gNCiAgICBtYW1iYSBlbnYgbGlzdA0KICAgIGBgYA0KDQotICAgKipSZW1vdmUgRW52aXJvbm1lbnQ6KioNCg0KICAgIGBgYCBiYXNoDQogICAgbWFtYmEgcmVtb3ZlIC1uIGVudmlyb25tZW50X25hbWUgLS1hbGwNCiAgICBgYGANCg0KPCEtLSAtLT4NCg0KLSAgIA0KDQotICAgW1F1YXJ0byBQdWJsaXNoaW5nXShodHRwczovL3F1YXJ0by5vcmcvZG9jcy9wdWJsaXNoaW5nL3F1YXJ0by1wdWIuaHRtbCkNCg0KLSAgIFtOZXRsaWZ5XShodHRwczovL2FwcC5uZXRsaWZ5LmNvbS90ZWFtcy8ndXNlcm5hbWUnL3NpdGVzKQ0KDQotICAgW0x1Y2lkXShodHRwczovL2x1Y2lkLmFwcC9kb2N1bWVudHMjL2RvY3VtZW50cz9mb2xkZXJfaWQ9cmVjZW50KQ0KDQotICAgW0VpZ2VuRmFjdG9yXShodHRwOi8vd3d3LmVpZ2VuZmFjdG9yLm9yZy9wcm9qZWN0cy9qb3VybmFsUmFuay9qb3VybmFsc2VhcmNoLnBocCkNCg0KLSAgIFtBaXJmbG93XShodHRwczovL2FpcmZsb3cuYXBhY2hlLm9yZy9kb2NzL2FwYWNoZS1haXJmbG93L3N0YWJsZS9zdGFydC5odG1sKQ0KDQotICAgW1BhbmRvY10oaHR0cHM6Ly9wYW5kb2Mub3JnKQ0KDQotICAgW3Bvc2l0IENsb3VkXShodHRwczovL3Bvc2l0LmNsb3VkKQ0KDQotICAgW1Bvc2l0IENoZWF0c2hlZXRzXShodHRwczovL3Bvc2l0LmNvL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8/X2dsPTEqMmQ4MHRqKl9nYSpNVEl3T0RZM016VXdMakUzTWpReU1ESTBPRFkuKl9nYV8yQzBXWjFKSEcwKk1UY3lOREl3TWpRNE5pNHhMakV1TVRjeU5ESXdNemMzTkM0d0xqQXVNQS4uKQ0KDQotICAgW0plbmtpbnNdKGh0dHBzOi8vYWNjb3VudHMuamVua2lucy5pbykNCg0KLSAgIFtKZW5raW5zIERlZmF1bHQgUG9ydCBSdW5dKGh0dHBzOi8vbG9jYWxob3N0OjgwODApDQoNCi0gICBbUXVhcnRvXShodHRwczovL3F1YXJ0b3B1Yi5jb20pDQoNCi0gICBbUG9zaXQgQ29ubmVjdCBDbG91ZF0oaHR0cHM6Ly9jb25uZWN0LnBvc2l0LmNsb3VkKQ0KDQotICAgW1RpbnlUZVhdKGh0dHBzOi8veWlodWkub3JnL3Rpbnl0ZXgvKQ0KDQotICAgW0h1Z2VUZVhdKGh0dHBzOi8veWlodWkub3JnL2VuLzIwMjIvMDUvdGlueXRleC1mdWxsLykNCg0KLSAgIFtNaUtUZVhdKGh0dHBzOi8vbWlrdGV4Lm9yZy8pDQoNCi0gICBbdHVnL3RsbWdyXShodHRwczovL3d3dy50dWcub3JnL3RleGxpdmUvdGxtZ3IuaHRtbCkNCg0KLSAgIFtDUkFOIFBhY2thZ2VzXShodHRwczovL2NyYW4ucnN0dWRpby5jb20vc3JjL2NvbnRyaWIvUEFDS0FHRVMpDQoNCi0gICBbUXVhcnRvIFJlZmVyZW5jZV0oaHR0cHM6Ly9jcmFuLnJzdHVkaW8uY29tL3NyYy9jb250cmliL1BBQ0tBR0VTKQ0KDQotICAgW1JTdHVkaW8gR2l0aHViIGlvXShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL2NoZWF0c2hlZXRzL2h0bWwvcXVhcnRvLmh0bWw/X2dsPTEqc2U3bHk0Kl9nYSpNVEl3T0RZM016VXdMakUzTWpReU1ESTBPRFkuKl9nYV8yQzBXWjFKSEcwKk1UY3lOREl3TWpRNE5pNHhMakV1TVRjeU5ESXdNemM0TWk0d0xqQXVNQS4uKQ0KDQotICAgW1F1YXJ0byBFZGl0aW5nIFNob3J0Y3V0c10oaHR0cHM6Ly9xdWFydG8ub3JnL2RvY3MvdmlzdWFsLWVkaXRvci9vcHRpb25zLmh0bWwjc2hvcnRjdXRzKQ0KDQotICAgYHF1YXJ0bzo6cXVhcnRvX3B1Ymxpc2hfZG9jKClgwqANCg0KLSAgIA0KDQogICAgYGBgICAgICAgICAgDQogICAgcXVhcnRvIHBhbmRvYyAtbyB0ZW1wbGF0ZS5wcHR4IC0tcHJpbnQtZGVmYXVsdC1kYXRhLWZpbGUgcmVmZXJlbmNlLnBwdHggDQogICAgcXVhcnRvOjpxdWFydG9fcHVibGlzaF9kb2MoKcKgDQoNCiAgICAjIFRlcm1pbmFsDQogICAgcXVhcnRvIHB1Ymxpc2ggcXVhcnRvLXB1YiBkb2N1bWVudC5xbWQNCiAgICBxdWFydG8gcHVibGlzaCBnaC1wYWdlcyBkb2N1bWVudC5xbWQNCiAgICBxdWFydG8gcHVibGlzaCBuZXRsaWZ5IGRvY3VtZW50LnFtZA0KICAgIHF1YXJ0byBwdWJsaXNoIGNvbm5lY3QgZG9jdW1lbnQucW1kDQogICAgYGBgDQo=