From 14d299d3cd33ee2f1508a181cd05b5eaf3fa2ccd Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Mon, 2 Apr 2018 18:28:10 -0400 Subject: [PATCH 01/18] Kernel load conda environments, added variables to install and detect local conda environments and jupyter kernels --- images/base/Dockerfile | 53 +++++++++++++++++++++++++++++++-- images/base/src/activate_kernel | 17 +++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 images/base/src/activate_kernel diff --git a/images/base/Dockerfile b/images/base/Dockerfile index a8e81ad..22ccc4d 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -1,5 +1,5 @@ #Image: sd2e/jupyteruser-base -#Version: 0.1.1 +#Version: 0.2.0 FROM taccsciapps/jupyteruser-base:0.1.2 LABEL origin="https://bitbucket.org/gzynda/jupyter/src/40adbad7b10b34de715d5a86aec3fcf65e724b70/notebooks/base/jupyter-notebook/Dockerfile?at=CIC-425-image-redesign&fileviewer=file-view-default" @@ -42,7 +42,7 @@ ADD examples examples ############################################### # Bioconductor and BioPython -RUN conda install --yes --quiet -c bioconda bioconductor-biocinstaller && \ +RUN conda update --all && conda install -vv --yes --debug -c bioconda bioconductor-biocinstaller && \ conda install --yes --quiet biopython && \ conda install --yes --quiet -n python2 biopython && \ # Enable sd2nb sharing service @@ -78,6 +78,55 @@ RUN git clone https://github.com/SD2E/sd2e-cli.git && \ docker-clean #ENV SPARK_HOME=/usr/local/spark +############################################### +# Environment activation Kernels +############################################### + +ADD src/activate_kernel /opt/conda/bin/activate_kernel +RUN chmod 755 /opt/conda/bin/activate_kernel && \ + TMPF=/tmp/tmp.json && \ + MODK=/usr/local/share/jupyter/kernels/python2/kernel.json && \ + jq " .argv = [\"activate_kernel\", \"python2\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ + mv $TMPF ${MODK} && \ + MODK=/opt/conda/share/jupyter/kernels/python3/kernel.json && \ + jq " .argv = [\"activate_kernel\", \"root\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ + mv $TMPF ${MODK} + +############################################### +# Environment activation Kernels +############################################### + +# Fixes compilers and local package installations +ADD src/activate_kernel /opt/conda/bin/activate_kernel +RUN chmod 755 /opt/conda/bin/activate_kernel && \ + TMPF=/tmp/tmp.json && \ + MODK=/usr/local/share/jupyter/kernels/python2/kernel.json && \ + jq " .argv = [\"activate_kernel\", \"python2\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ + mv $TMPF ${MODK} && \ + MODK=/opt/conda/share/jupyter/kernels/python3/kernel.json && \ + jq " .argv = [\"activate_kernel\", \"root\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ + mv $TMPF ${MODK} + +############################################### +# Persistent local conda environments +############################################### + +# conda create -p $LOCAL_ENVS/tmnt python=2.7 ipykernel +# conda env list +# source activate tmnt +ENV LOCAL_ENVS=$HOME/tacc-work/jupyter_packages/envs +ENV CONDA_ENVS_PATH=$LOCAL_ENVS:$CONDA_ENVS_PATH + +############################################### +# Persistent local jupyter kernels +############################################### + +# $LOCAL_ENVS/tmnt/bin/python -m ipykernel install --prefix $JUPYTER_WORK --name tmnt --display-name "tmnt python" +# *Must use full path* +# refresh main jupyter to load the new kernel option +ENV JUPYTER_PATH=$HOME/tacc-work/jupyter_packages/share/jupyter:$JUPYTER_PATH +ENV JUPYTER_WORK=$HOME/tacc-work/jupyter_packages + ############################################### # Permissions ############################################### diff --git a/images/base/src/activate_kernel b/images/base/src/activate_kernel new file mode 100644 index 0000000..152988a --- /dev/null +++ b/images/base/src/activate_kernel @@ -0,0 +1,17 @@ +#!/bin/bash + +function usage { + echo -e "\n Usage: activate_kernel conda_env conn_file\n" 1>&2; +} +function ee { + # Echos to STDERR + echo -e "[ERROR] $@" 1>&2; + usage + exit 1 +} + +[ ! -n "$1" ] && ee "Please specify a conda environment" +[ ! -n "$2" ] && ee "Please specify a connection file" + +source activate $1 +python -m ipykernel_launcher -f $2 From 7d22e21cceaa15d18f4ea8ed5f0f31f6356242b3 Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Mon, 2 Apr 2018 18:43:56 -0400 Subject: [PATCH 02/18] Renamed custom to sd2e --- CONTRIBUTING.md | 4 ++-- Makefile | 12 ++++++------ TESTING.md | 2 +- build/build_jupyteruser.sh | 2 +- images/{custom => sd2e}/Dockerfile | 0 images/{custom => sd2e}/common-lisp/ql_setup.lisp | 0 images/{custom => sd2e}/common-lisp/sbclrc | 0 .../examples/common-lisp/about-cl-jupyter.ipynb | 0 .../common-lisp/profile/Jupiter's_storm.jpg | Bin .../profile/Portrait_of_Jupiter_from_Cassini.png | Bin .../examples/common-lisp/profile/commonlisp.js | 0 .../examples/common-lisp/profile/custom.js | 0 .../examples/common-lisp/profile/fish.svg | 0 .../examples/common-lisp/profile/fishbowl-small.svg | 0 .../examples/common-lisp/profile/fishbowl.svg | 0 .../common-lisp/profile/jupyter-sq-text.svg | 0 .../examples/common-lisp/profile/lambda.svg | 0 .../examples/probcomp/gapminder-exploratory.ipynb | 0 .../examples/probcomp/gapminder-missing-data.ipynb | 0 .../examples/probcomp/introduction.ipynb | 0 .../examples/probcomp/resources/country-year.csv | 0 .../probcomp/resources/frame_missing_2000.csv | 0 .../examples/probcomp/resources/gapminder.csv | 0 .../examples/probcomp/resources/satellites.csv | 0 .../examples/probcomp/satellites-predictive.ipynb | 0 25 files changed, 10 insertions(+), 10 deletions(-) rename images/{custom => sd2e}/Dockerfile (100%) rename images/{custom => sd2e}/common-lisp/ql_setup.lisp (100%) rename images/{custom => sd2e}/common-lisp/sbclrc (100%) rename images/{custom => sd2e}/examples/common-lisp/about-cl-jupyter.ipynb (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/Jupiter's_storm.jpg (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/Portrait_of_Jupiter_from_Cassini.png (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/commonlisp.js (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/custom.js (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/fish.svg (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/fishbowl-small.svg (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/fishbowl.svg (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/jupyter-sq-text.svg (100%) rename images/{custom => sd2e}/examples/common-lisp/profile/lambda.svg (100%) rename images/{custom => sd2e}/examples/probcomp/gapminder-exploratory.ipynb (100%) rename images/{custom => sd2e}/examples/probcomp/gapminder-missing-data.ipynb (100%) rename images/{custom => sd2e}/examples/probcomp/introduction.ipynb (100%) rename images/{custom => sd2e}/examples/probcomp/resources/country-year.csv (100%) rename images/{custom => sd2e}/examples/probcomp/resources/frame_missing_2000.csv (100%) rename images/{custom => sd2e}/examples/probcomp/resources/gapminder.csv (100%) rename images/{custom => sd2e}/examples/probcomp/resources/satellites.csv (100%) rename images/{custom => sd2e}/examples/probcomp/satellites-predictive.ipynb (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 51bb981..f1213be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,13 +56,13 @@ git checkout -b myFeature development Please add any external example or configuration files in a descriptive folder in ``` -images/custom/ +images/sd2e/ ``` and add a new section at the end of the main `Dockerfile` in ``` -images/custom/Dockerfile +images/sd2e/Dockerfile ``` for your code immediately **before** the permissiosn section. diff --git a/Makefile b/Makefile index fc0484a..9780031 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ help: echo " - release - push images to production environment\n" echo "Targets:" echo " - base - Recipe in images/base" - echo " - sd2e - Recipe in images/custom which is where all community software should belong" + echo " - sd2e - Recipe in images/sd2e which is where all community software should belong" echo " - singularity - Image for running on TACC HPC\n" # Make sure image targets are not used as make targets @@ -38,7 +38,7 @@ build: docker build/build_jupyteruser.sh build images/base ;; sd2e) - build/build_jupyteruser.sh build images/custom + build/build_jupyteruser.sh build images/sd2e ;; singularity) build/build_jupyteruser.sh build images/singularity @@ -55,7 +55,7 @@ test: docker build/build_jupyteruser.sh test images/base ;; sd2e) - build/build_jupyteruser.sh test images/custom + build/build_jupyteruser.sh test images/sd2e ;; singularity) build/build_jupyteruser.sh test images/singularity @@ -72,7 +72,7 @@ stage: docker build/build_jupyteruser.sh stage images/base ;; sd2e) - build/build_jupyteruser.sh stage images/custom + build/build_jupyteruser.sh stage images/sd2e ;; singularity) build/build_jupyteruser.sh stage images/singularity @@ -89,7 +89,7 @@ release: docker build/build_jupyteruser.sh release images/base ;; sd2e) - build/build_jupyteruser.sh release images/custom + build/build_jupyteruser.sh release images/sd2e ;; singularity) build/build_jupyteruser.sh release images/singularity @@ -102,5 +102,5 @@ release: docker clean: docker TARGET=$(filter-out $@,$(MAKECMDGOALS)) build/build_jupyteruser.sh clean images/singularity - build/build_jupyteruser.sh clean images/custom + build/build_jupyteruser.sh clean images/sd2e build/build_jupyteruser.sh clean images/base diff --git a/TESTING.md b/TESTING.md index b898cc0..32ca413 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,5 +1,5 @@ # Testing out your changes -After you've added software or updated configurations at `images/custom`, you can and should test in a local instance of Jupyter Notebooks. We've made this really easy for you. You can either leverage the extensive Makefile support for building and testing an updated user image, or manually drive the process. +After you've added software or updated configurations at `images/sd2e`, you can and should test in a local instance of Jupyter Notebooks. We've made this really easy for you. You can either leverage the extensive Makefile support for building and testing an updated user image, or manually drive the process. *Before you issue a PR, you must have tested locally* diff --git a/build/build_jupyteruser.sh b/build/build_jupyteruser.sh index e73d280..39cdce8 100755 --- a/build/build_jupyteruser.sh +++ b/build/build_jupyteruser.sh @@ -153,7 +153,7 @@ function pushImage { fi } -helpStr="Usage: $0 option target\n\nAutomating the build and deploy process for taccsciapps images\n\nPlease specify an option and target\n\nOptions:\n - build\n - test\n - push\n - all\n\nTargets:\n - images/base\n - images/custom" +helpStr="Usage: $0 option target\n\nAutomating the build and deploy process for taccsciapps images\n\nPlease specify an option and target\n\nOptions:\n - build\n - test\n - push\n - all\n\nTargets:\n - images/base\n - images/sd2e" # Make sure enough arguments were used if [ ! $# -eq 2 ]; then diff --git a/images/custom/Dockerfile b/images/sd2e/Dockerfile similarity index 100% rename from images/custom/Dockerfile rename to images/sd2e/Dockerfile diff --git a/images/custom/common-lisp/ql_setup.lisp b/images/sd2e/common-lisp/ql_setup.lisp similarity index 100% rename from images/custom/common-lisp/ql_setup.lisp rename to images/sd2e/common-lisp/ql_setup.lisp diff --git a/images/custom/common-lisp/sbclrc b/images/sd2e/common-lisp/sbclrc similarity index 100% rename from images/custom/common-lisp/sbclrc rename to images/sd2e/common-lisp/sbclrc diff --git a/images/custom/examples/common-lisp/about-cl-jupyter.ipynb b/images/sd2e/examples/common-lisp/about-cl-jupyter.ipynb similarity index 100% rename from images/custom/examples/common-lisp/about-cl-jupyter.ipynb rename to images/sd2e/examples/common-lisp/about-cl-jupyter.ipynb diff --git a/images/custom/examples/common-lisp/profile/Jupiter's_storm.jpg b/images/sd2e/examples/common-lisp/profile/Jupiter's_storm.jpg similarity index 100% rename from images/custom/examples/common-lisp/profile/Jupiter's_storm.jpg rename to images/sd2e/examples/common-lisp/profile/Jupiter's_storm.jpg diff --git a/images/custom/examples/common-lisp/profile/Portrait_of_Jupiter_from_Cassini.png b/images/sd2e/examples/common-lisp/profile/Portrait_of_Jupiter_from_Cassini.png similarity index 100% rename from images/custom/examples/common-lisp/profile/Portrait_of_Jupiter_from_Cassini.png rename to images/sd2e/examples/common-lisp/profile/Portrait_of_Jupiter_from_Cassini.png diff --git a/images/custom/examples/common-lisp/profile/commonlisp.js b/images/sd2e/examples/common-lisp/profile/commonlisp.js similarity index 100% rename from images/custom/examples/common-lisp/profile/commonlisp.js rename to images/sd2e/examples/common-lisp/profile/commonlisp.js diff --git a/images/custom/examples/common-lisp/profile/custom.js b/images/sd2e/examples/common-lisp/profile/custom.js similarity index 100% rename from images/custom/examples/common-lisp/profile/custom.js rename to images/sd2e/examples/common-lisp/profile/custom.js diff --git a/images/custom/examples/common-lisp/profile/fish.svg b/images/sd2e/examples/common-lisp/profile/fish.svg similarity index 100% rename from images/custom/examples/common-lisp/profile/fish.svg rename to images/sd2e/examples/common-lisp/profile/fish.svg diff --git a/images/custom/examples/common-lisp/profile/fishbowl-small.svg b/images/sd2e/examples/common-lisp/profile/fishbowl-small.svg similarity index 100% rename from images/custom/examples/common-lisp/profile/fishbowl-small.svg rename to images/sd2e/examples/common-lisp/profile/fishbowl-small.svg diff --git a/images/custom/examples/common-lisp/profile/fishbowl.svg b/images/sd2e/examples/common-lisp/profile/fishbowl.svg similarity index 100% rename from images/custom/examples/common-lisp/profile/fishbowl.svg rename to images/sd2e/examples/common-lisp/profile/fishbowl.svg diff --git a/images/custom/examples/common-lisp/profile/jupyter-sq-text.svg b/images/sd2e/examples/common-lisp/profile/jupyter-sq-text.svg similarity index 100% rename from images/custom/examples/common-lisp/profile/jupyter-sq-text.svg rename to images/sd2e/examples/common-lisp/profile/jupyter-sq-text.svg diff --git a/images/custom/examples/common-lisp/profile/lambda.svg b/images/sd2e/examples/common-lisp/profile/lambda.svg similarity index 100% rename from images/custom/examples/common-lisp/profile/lambda.svg rename to images/sd2e/examples/common-lisp/profile/lambda.svg diff --git a/images/custom/examples/probcomp/gapminder-exploratory.ipynb b/images/sd2e/examples/probcomp/gapminder-exploratory.ipynb similarity index 100% rename from images/custom/examples/probcomp/gapminder-exploratory.ipynb rename to images/sd2e/examples/probcomp/gapminder-exploratory.ipynb diff --git a/images/custom/examples/probcomp/gapminder-missing-data.ipynb b/images/sd2e/examples/probcomp/gapminder-missing-data.ipynb similarity index 100% rename from images/custom/examples/probcomp/gapminder-missing-data.ipynb rename to images/sd2e/examples/probcomp/gapminder-missing-data.ipynb diff --git a/images/custom/examples/probcomp/introduction.ipynb b/images/sd2e/examples/probcomp/introduction.ipynb similarity index 100% rename from images/custom/examples/probcomp/introduction.ipynb rename to images/sd2e/examples/probcomp/introduction.ipynb diff --git a/images/custom/examples/probcomp/resources/country-year.csv b/images/sd2e/examples/probcomp/resources/country-year.csv similarity index 100% rename from images/custom/examples/probcomp/resources/country-year.csv rename to images/sd2e/examples/probcomp/resources/country-year.csv diff --git a/images/custom/examples/probcomp/resources/frame_missing_2000.csv b/images/sd2e/examples/probcomp/resources/frame_missing_2000.csv similarity index 100% rename from images/custom/examples/probcomp/resources/frame_missing_2000.csv rename to images/sd2e/examples/probcomp/resources/frame_missing_2000.csv diff --git a/images/custom/examples/probcomp/resources/gapminder.csv b/images/sd2e/examples/probcomp/resources/gapminder.csv similarity index 100% rename from images/custom/examples/probcomp/resources/gapminder.csv rename to images/sd2e/examples/probcomp/resources/gapminder.csv diff --git a/images/custom/examples/probcomp/resources/satellites.csv b/images/sd2e/examples/probcomp/resources/satellites.csv similarity index 100% rename from images/custom/examples/probcomp/resources/satellites.csv rename to images/sd2e/examples/probcomp/resources/satellites.csv diff --git a/images/custom/examples/probcomp/satellites-predictive.ipynb b/images/sd2e/examples/probcomp/satellites-predictive.ipynb similarity index 100% rename from images/custom/examples/probcomp/satellites-predictive.ipynb rename to images/sd2e/examples/probcomp/satellites-predictive.ipynb From 2b3efc2a09410b12f6312c65b0290e2b2bb78c77 Mon Sep 17 00:00:00 2001 From: Matt Vaughn Date: Thu, 5 Apr 2018 13:25:32 -0500 Subject: [PATCH 03/18] Need to move off OS X --- .bash_history | 40 + .docker/.buildNodeID | 1 + Makefile | 2 +- images/base/Dockerfile | 34 +- images/base/src/add-sd2e-groups.sh | 10 + images/sd2e/Dockerfile | 8 +- test/dotjupyter/custom/current_theme.txt | 1 + test/dotjupyter/custom/custom.css | 3187 ++++++++++++++++++++++ 8 files changed, 3269 insertions(+), 14 deletions(-) create mode 100644 .bash_history create mode 100644 .docker/.buildNodeID create mode 100644 images/base/src/add-sd2e-groups.sh create mode 100644 test/dotjupyter/custom/current_theme.txt create mode 100644 test/dotjupyter/custom/custom.css diff --git a/.bash_history b/.bash_history new file mode 100644 index 0000000..2812e90 --- /dev/null +++ b/.bash_history @@ -0,0 +1,40 @@ +ls +make help +make build base +docker pull taccsciapps/jupyteruser-base:0.1.2 +make build base +docker run -it sd2e/jupyteruser-base:0.2.0 bash +pwd +uname -a +exit +make help +make build base +docker run -it sd2e/jupyteruser-base:0.2.0 bash +docker run -it taccsciapps/jupyteruser-base:0.1.2 bash +docker run -it taccsciapps/jupyteruser-base:0.1.2 bash +docker run -it sd2e/jupyteruser-base:0.2.0 bash +pwd +exit +ls +make +make build base +docker run -it sd2e/jupyteruser-base:0.2.0 bash +make help +make test sd2e +make stage base +make stage sd2e +make build sd2e +make build sd2e +docker images +docker images sd2e/* | head +make build sd2e +make build sd2e +make build sd2e +make build sd2e +make stage sd2e +make stage sd2e +make build sd2e +make build base +make build base +make build sd2e +exit diff --git a/.docker/.buildNodeID b/.docker/.buildNodeID new file mode 100644 index 0000000..b209565 --- /dev/null +++ b/.docker/.buildNodeID @@ -0,0 +1 @@ +84b7e47442e586221cf746dcda767428ca76293f4cc69c2776025184242bbce3 \ No newline at end of file diff --git a/Makefile b/Makefile index 9780031..9913343 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ help: echo " - release - push images to production environment\n" echo "Targets:" echo " - base - Recipe in images/base" - echo " - sd2e - Recipe in images/sd2e which is where all community software should belong" + echo " - sd2e - Recipe in images/custom which is where all community software should belong" echo " - singularity - Image for running on TACC HPC\n" # Make sure image targets are not used as make targets diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 22ccc4d..cd27bdb 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -1,5 +1,5 @@ #Image: sd2e/jupyteruser-base -#Version: 0.2.0 +#Version: 0.2.1 FROM taccsciapps/jupyteruser-base:0.1.2 LABEL origin="https://bitbucket.org/gzynda/jupyter/src/40adbad7b10b34de715d5a86aec3fcf65e724b70/notebooks/base/jupyter-notebook/Dockerfile?at=CIC-425-image-redesign&fileviewer=file-view-default" @@ -11,13 +11,20 @@ USER root # Image release ARG image_version=development -ENV NB_GID=G-819382 +# Parameterize GID +# 65536 is a dummy value since we now override user UID/GID at launch +# using Docker nsmap. This should means it's only important for GIDs not +# collide and that g+r(x) permissions are set where needed +ARG TACC_GID=65536 +ENV NB_GROUP=G-${TACC_GID} +ENV NB_GID=${TACC_GID} + RUN echo "${image_version}" > /etc/sd2e_jupyteruser-base-release && \ chmod a+r /etc/sd2e_jupyteruser-base-release && \ # Make sure Jupyter group == SD2E-Community == 819382 -groupadd --gid 819382 $NB_GID && \ -usermod -a -G $NB_GID jupyter && \ -usermod -g $NB_GID jupyter && \ +groupadd --gid ${NB_GID} ${NB_GROUP} && \ +usermod -a -G ${NB_GROUP} jupyter && \ +usermod -g ${NB_GROUP} jupyter && \ # Jupyterhub correctly sets JUPYTERHUB_USER echo 'PS1="$JUPYTERHUB_USER@\h:\w\$ "' >> /home/jupyter/.bashrc && \ # allow users to add kernels @@ -26,6 +33,8 @@ chmod 777 /opt/conda/share/jupyter/kernels && \ echo "export JPY_USER=\$JUPYTERHUB_USER\n\ export WORK=/home/jupyter/tacc-work\n\ export SD2_DATA=/home/jupyter/sd2e-community\n\ +export PROJECTS_DATA=/home/jupyter/sd2e-projects\n\ +export PARTNERS_DATA=/home/jupyter/sd2e-partners\n\ export PYTHONUSERBASE=/home/jupyter/tacc-work/jupyter_packages\n" >> /home/jupyter/.bashrc # Add activation sripts ADD src/activate-python.sh /opt/conda/etc/conda/activate.d/activate-python.sh @@ -46,12 +55,12 @@ RUN conda update --all && conda install -vv --yes --debug -c bioconda bioconduct conda install --yes --quiet biopython && \ conda install --yes --quiet -n python2 biopython && \ # Enable sd2nb sharing service -cd /root && \ +cd /root && \ git clone https://github.com/SD2E/sd2nb-app.git && \ ( cd sd2nb-app && make && make install ) && \ rm -rf sd2nb-app && \ -# Enable sd2e-jupyter -cd /root && \ +# Enable sd2e-jupyter +cd /root && \ git clone https://github.com/SD2E/sd2e-jupyter-ascending.git && \ ( cd sd2e-jupyter-ascending && make && make install ) && \ rm -rf sd2e-jupyter-ascending && \ @@ -127,13 +136,20 @@ ENV CONDA_ENVS_PATH=$LOCAL_ENVS:$CONDA_ENVS_PATH ENV JUPYTER_PATH=$HOME/tacc-work/jupyter_packages/share/jupyter:$JUPYTER_PATH ENV JUPYTER_WORK=$HOME/tacc-work/jupyter_packages +############################################### +# Affiliated projects +############################################### + +ADD src/add-sd2e-groups.sh /tmp/add-sd2e-groups.sh +RUN bash /tmp/add-sd2e-groups.sh + ############################################### # Permissions ############################################### # The notebook is run by the TACC userid, not jupyter, # so permissions need to be open -RUN chown -R jupyter:G-819382 /home/jupyter && \ +RUN chown -R jupyter:${NB_GROUP} /home/jupyter && \ chmod 777 /home/jupyter && \ find /home/jupyter -type f -exec chmod 666 {} \; && \ find /home/jupyter -type d -exec chmod 777 {} \; diff --git a/images/base/src/add-sd2e-groups.sh b/images/base/src/add-sd2e-groups.sh new file mode 100644 index 0000000..85f492b --- /dev/null +++ b/images/base/src/add-sd2e-groups.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +while read -r nb_gid nb_group ; do + echo "Adding ${nb_gid}:${nb_group}" + groupadd --force --gid ${nb_gid} "G-${nb_gid}" +done < ul > li > a > i.fa.fa-home { + color: #ff7823; + font-size: 17pt; + display: inline-block; + position: static; + padding: 0px 0px; + font-weight: normal; + text-align: center; + vertical-align: text-top; +} +.fa-folder:before { + color: #126dce; +} +.fa-arrow-up:before { + font-size: 14px; +} +.fa-arrow-down:before { + font-size: 14px; +} +span#last-modified.btn.btn-xs.btn-default.sort-action:hover .fa, +span#sort-name.btn.btn-xs.btn-default.sort-action:hover .fa { + color: #ef5c00; +} +.folder_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f07b"; + color: #126dce; +} +.notebook_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f02d"; + position: relative; + color: #009e07 !important; + top: 0px; +} +.file_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f15b"; + position: relative; + top: 0px; + color: #6a737d !important; +} +#project_name a { + display: inline-flex; + padding-left: 7px; + margin-left: -2px; + text-align: -webkit-auto; + vertical-align: baseline; + font-size: 18px; +} +div#notebook_toolbar div.dynamic-instructions { + font-family: sans-serif; + font-size: 17px; + color: #828892; +} +span#login_widget > .button, +#logout { + font-family: "Proxima Nova", sans-serif; + color: #303030; + background: transparent; + background-color: transparent; + border: 2px solid #e5e5e5; + font-weight: normal; + box-shadow: none; + text-shadow: none; + border-radius: 3px; + margin-right: 10px; + padding: 2px 7px; +} +span#login_widget > .button:hover, +#logout:hover { + color: #ef5c00; + background-color: transparent; + background: transparent; + border: 2px solid #ef5c00; + background-image: none; + box-shadow: none !important; + border-radius: 3px; +} +span#login_widget > .button:focus, +#logout:focus, +span#login_widget > .button.focus, +#logout.focus, +span#login_widget > .button:active, +#logout:active, +span#login_widget > .button.active, +#logout.active, +.open > .dropdown-togglespan#login_widget > .button, +.open > .dropdown-toggle#logout { + color: #1c1c1c; + background-color: #303030; + background: #303030; + border-color: #303030; + background-image: none; + box-shadow: none !important; + border-radius: 2px; +} +body > #header #header-container { + padding-bottom: 0px; + padding-top: 4px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} +body > #header { + background: #ffffff; + background-color: #ffffff; + position: relative; + z-index: 100; +} +.list_container { + font-size: 13pt; + color: #303030; + border: none; + text-shadow: none !important; +} +.list_container > div { + border-bottom: 1px solid rgba(180,180,180,.14); + font-size: 13pt; +} +.list_header > div, +.list_item > div { + padding-top: 6px; + padding-bottom: 2px; + padding-left: 0px; +} +.list_header > div .item_link, +.list_item > div .item_link { + margin-left: -1px; + vertical-align: middle; + line-height: 22px; + font-size: 13pt; +} +.item_icon { + color: #126dce; + font-size: 13pt; + vertical-align: middle; +} +.list_item input:not([type="checkbox"]) { + padding-right: 0px; + height: 1.75em; + width: 25%; + margin: 0px 0 0; + margin-top: 0px; +} +.list_header > div .item_link, +.list_item > div .item_link { + margin-left: -1px; + vertical-align: middle; + line-height: 1.5em; + font-size: 12pt; + display: inline-table; + position: static; +} +#button-select-all { + height: 34px; + min-width: 55px; + z-index: 0; + border: none !important; + padding-top: 0px; + padding-bottom: 0px; + margin-bottom: 0px; + margin-top: 0px; + left: -3px; + border-radius: 0px !important; +} +#button-select-all:focus, +#button-select-all:active:focus, +#button-select-all.active:focus, +#button-select-all.focus, +#button-select-all:active.focus, +#button-select-all.active.focus { + background-color: #e5e5e5 !important; + background: #e5e5e5 !important; +} +button#tree-selector-btn { + height: 34px; + font-size: 12.0pt; + border: none; + left: 0px; + border-radius: 0px !important; +} +input#select-all.pull-left.tree-selector { + margin-left: 7px; + margin-right: 2px; + margin-top: 2px; + top: 4px; +} +input[type="radio"], +input[type="checkbox"] { + margin-top: 1px; + line-height: normal; +} +.delete-button { + border: none !important; +} +i.fa.fa-trash { + font-size: 13.5pt; +} +.list_container a { + font-size: 16px; + color: #303030; + border: none; + text-shadow: none !important; + font-weight: normal; + font-style: normal; +} +div.list_container a:hover { + color: #2f2f2f; +} +.list_header > div input, +.list_item > div input { + margin-right: 7px; + margin-left: 12px; + vertical-align: baseline; + line-height: 22px; + position: relative; + top: -1px; +} +div.list_item:hover { + background-color: #fafafa; +} +.breadcrumb > li { + font-size: 12.0pt; + color: #303030; + border: none; + text-shadow: none !important; +} +.breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0px; + color: #303030; + font-size: 18px; +} +#project_name > .breadcrumb { + padding: 0px; + margin-bottom: 0px; + background-color: transparent; + font-weight: normal; + margin-top: -2px; +} +ul#tabs a { + font-family: sans-serif; + font-size: 13.5pt; + font-weight: normal; + font-style: normal; + text-shadow: none !important; +} +.nav-tabs { + font-family: sans-serif; + font-size: 13.5pt; + font-weight: normal; + font-style: normal; + background-color: transparent; + border-color: transparent; + text-shadow: none !important; + border: 2px solid transparent; +} +.nav-tabs > li > a:active, +.nav-tabs > li > a:focus, +.nav-tabs > li > a:hover, +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:focus, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #ef5c00; + background-color: transparent; + border-color: transparent; + border-bottom: 2px solid transparent; +} +.nav > li.disabled > a, +.nav > li.disabled > a:hover { + color: #828892; +} +.nav-tabs > li > a:before { + content: ""; + position: absolute; + width: 100%; + height: 2px; + bottom: -2px; + left: 0; + background-color: #ef5c00; + visibility: hidden; + -webkit-transform: perspective(0)scaleX(0); + transform: perspective(0)scaleX(0); + -webkit-transition: ease 220ms; + transition: ease 220ms; + -webkit-font-smoothing: antialiased !important; +} +.nav-tabs > li > a:hover:before { + visibility: visible; + -webkit-transform: perspective(1)scaleX(1); + transform: perspective(1)scaleX(1); +} +.nav-tabs > li.active > a:before { + content: ""; + position: absolute; + width: 100%; + height: 2px; + bottom: -2px; + left: 0; + background-color: #ef5c00; + visibility: visible; + -webkit-transform: perspective(1)scaleX(1); + transform: perspective(1)scaleX(1); + -webkit-font-smoothing: subpixel-antialiased !important; +} +div#notebook { + font-family: sans-serif; + font-size: 13pt; + padding-top: 4px; +} +.notebook_app { + background-color: #ffffff; +} +#notebook-container { + padding: 13px 2px; + background-color: #ffffff; + min-height: 0px; + box-shadow: none; + width: 980px; + margin-right: auto; + margin-left: auto; +} +div#ipython-main-app.container { + width: 980px; + margin-right: auto; + margin-left: auto; + margin-right: auto; + margin-left: auto; +} +.container { + width: 980px; + margin-right: auto; + margin-left: auto; +} +div#menubar-container { + width: 100%; + width: 980px; +} +div#header-container { + width: 980px; +} +.notebook_app #header, +.edit_app #header { + box-shadow: none !important; + background-color: #ffffff; + border-bottom: 2px solid rgba(180,180,180,.14); +} +#header, +.edit_app #header { + font-family: sans-serif; + font-size: 13pt; + box-shadow: none; + background-color: #ffffff; +} +#header .header-bar, +.edit_app #header .header-bar { + background: #ffffff; + background-color: #ffffff; +} +body > #header .header-bar { + width: 100%; + background: #ffffff; +} +span.checkpoint_status, +span.autosave_status { + font-size: small; + display: none; +} +#menubar, +div#menubar { + background-color: #ffffff; + padding-top: 0px !important; +} +#menubar .navbar, +.navbar-default { + background-color: #ffffff; + margin-bottom: 0px; + margin-top: 0px; +} +.navbar { + border: none; +} +div.navbar-text, +.navbar-text, +.navbar-text.indicator_area, +p.navbar-text.indicator_area { + margin-top: 8px !important; + margin-bottom: 0px; + color: #ff7823; +} +.navbar-default { + font-family: sans-serif; + font-size: 13pt; + background-color: #ffffff; + border-color: #d4d4d4; + line-height: 1.5em; + padding-bottom: 0px; +} +.navbar-default .navbar-nav > li > a { + font-family: sans-serif; + font-size: 13pt; + color: #303030; + display: block; + line-height: 1.5em; + padding-top: 14px; + padding-bottom: 11px; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #2f2f2f; + background-color: rgba(180,180,180,.14); + border-color: #d4d4d4; + line-height: 1.5em; + transition: 200ms ease; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #1c1c1c; + background-color: #dedede; + border-color: #dedede; + line-height: 1.5em; + transition: 200ms ease; +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0px; +} +.navbar-nav { + margin: 0; +} +div.notification_widget.info, +.notification_widget.info, +.notification_widget:active:hover, +.notification_widget.active:hover, +.open > .dropdown-toggle.notification_widget:hover, +.notification_widget:active:focus, +.notification_widget.active:focus, +.open > .dropdown-toggle.notification_widget:focus, +.notification_widget:active.focus, +.notification_widget.active.focus, +.open > .dropdown-toggle.notification_widget.focus, +div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn, +div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:hover, +div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:focus { + color: #303030 !important; + background-color: transparent !important; + border-color: transparent !important; + padding-bottom: 0px !important; + margin-bottom: 0px !important; + font-size: 9pt !important; + z-index: 0; +} +div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn { + font-size: 9pt !important; + z-index: 0; +} +.notification_widget { + color: #126dce; + z-index: -500; + font-size: 9pt; + background: transparent; + background-color: transparent; + margin-right: 3px; + border: none; +} +.notification_widget, +div.notification_widget { + margin-right: 0px; + margin-left: 0px; + padding-right: 0px; + vertical-align: text-top !important; + margin-top: 6px !important; + background: transparent !important; + background-color: transparent !important; + font-size: 9pt !important; + border: none; +} +.navbar-btn.btn-xs:hover { + border: none !important; + background: transparent !important; + background-color: transparent !important; + color: #303030 !important; +} +div.notification_widget.info, +.notification_widget.info { + display: none !important; +} +.edit_mode .modal_indicator:before { + font-size: 18px; + color: #ff7823; + opacity: 1.0; + padding-bottom: 0px; + vertical-align: -webkit-baseline-middle; + margin-left: 1px; + margin-bottom: 0px; +} +.command_mode .modal_indicator:before { + font-family: sans-serif; + font-size: 18px; + color: #ff7823; + padding-bottom: 0px; + vertical-align: -webkit-baseline-middle; + margin-left: 1px; + margin-bottom: 0px; +} +.item_icon { + color: #126dce; +} +.item_buttons .kernel-name { + font-size: 13pt; + color: #126dce; +} +.running_notebook_icon:before { + color: #009e07 !important; + font: normal normal normal 15px/1 FontAwesome; + font-size: 15px; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f10c"; + vertical-align: middle; + position: static; + display: inherit; +} +.item_buttons .running-indicator { + padding-top: 4px; + color: #009e07; + font-family: sans-serif; + text-rendering: auto; + -webkit-font-smoothing: antialiased; +} +#notification_trusted { + font-family: sans-serif; + font-size: 17px !important; + color: #126dce; + border: none; + background: transparent; + background-color: transparent; + margin-bottom: 0px !important; + margin-top: 11px !important; + vertical-align: middle !important; +} +#modal_indicator { + float: right !important; + color: #4c8be2; + background: #ffffff; + background-color: #ffffff; + margin-top: 8px !important; + margin-left: 0px; +} +#kernel_indicator { + float: right !important; + color: #ff7823; + background: #ffffff; + background-color: #ffffff; + border-left: 2px solid #ff7823; + padding-top: 0px; + padding-bottom: 4px; + margin-top: 8px !important; + margin-left: -2px; +} +#kernel_indicator .kernel_indicator_name { + font-size: 17px; + color: #ff7823; + background: #ffffff; + background-color: #ffffff; + padding-left: 5px; + padding-right: 5px; + margin-top: 4px; + vertical-align: -webkit-baseline-middle; + padding-bottom: 0px; +} +.kernel_idle_icon:before { + display: inline-block; + font: normal normal normal 22px/1 FontAwesome; + font-size: 22px; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + cursor: pointer; + margin-left: 0px !important; + opacity: 0.7; + vertical-align: middle; + margin-top: 1px; + content: "\f1db"; +} +.kernel_busy_icon:before { + display: inline-block; + font: normal normal normal 22px/1 FontAwesome; + font-size: 22px; + -webkit-animation: pulsate 2s infinite ease-out; + animation: pulsate 2s infinite ease-out; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + cursor: pointer; + margin-left: 0px !important; + vertical-align: middle; + margin-top: 1px; + content: "\f111"; +} +@-webkit-keyframes pulsate { + 0% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } + 8% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } + 50% { + -webkit-transform: scale(0.75,0.75); + opacity: 0.3; + } + 92% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } + 100% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } +} +i#kernel_indicator_icon { + vertical-align: sub; +} +div.notification_widget.info, +.notification_widget.info, +.notification_widget:active:hover, +.notification_widget.active:hover, +.open > .dropdown-toggle.notification_widget:hover, +.notification_widget:active:focus, +.notification_widget.active:focus, +.open > .dropdown-toggle.notification_widget:focus, +.notification_widget:active.focus, +.notification_widget.active.focus, +.open > .dropdown-toggle.notification_widget.focus, +div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn, +div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:hover, +div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:focus { + color: #303030; + background-color: #ffffff; + border-color: #ffffff; +} +#notification_area, +div.notification_area { + float: right !important; + position: static; +} +.notification_widget, +div.notification_widget { + margin-right: 0px; + margin-left: 0px; + padding-right: 0px; + vertical-align: text-top !important; + margin-top: 6px !important; + z-index: 1000; +} +#kernel_logo_widget, +#kernel_logo_widget .current_kernel_logo { + display: none; +} +div#ipython_notebook { + display: none; +} +i.fa.fa-icon { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: auto; +} +.fa { + display: inline-block; + font: normal normal normal 10pt/1 "FontAwesome", sans-serif; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.dropdown-menu { + font-family: sans-serif; + font-size: 13pt; + box-shadow: none; + padding: 0px; + text-align: left; + border: 2px solid #dedede; + background-color: #dedede; + background: #dedede; + line-height: 1; +} +.dropdown-menu:hover { + font-family: sans-serif; + font-size: 13pt; + box-shadow: none; + padding: 0px; + text-align: left; + border: 2px solid #dedede; + background-color: #dedede; + box-shadow: none; + line-height: 1; +} +.dropdown-menu > li > a { + font-family: sans-serif; + font-size: 12.0pt; + line-height: 1.1; + display: block; + padding: 10px 20px 9px 10px; + color: #303030; + background-color: #dedede; + background: #dedede; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #2f2f2f; + background-color: #d4d4d4; + background: #d4d4d4; + border-color: #d4d4d4; + transition: 200ms ease; +} +.dropdown-menu .divider { + height: 1px; + margin: 0px 0px; + overflow: hidden; + background-color: rgba(180,180,180,.30); +} +.dropdown-submenu > .dropdown-menu { + top: 0px; + left: 100%; + margin-top: -2px; + margin-left: 0px; + padding-top: 0px; + transition: 200ms ease; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + font-family: sans-serif; + font-size: 12.0pt; + font-weight: normal; + color: #828892; + padding: none; + display: block; + clear: both; + line-height: 1.1; + white-space: nowrap; +} +.dropdown-submenu > a:after { + color: #303030; + margin-right: -16px; + margin-top: 0px; +} +.dropdown-submenu:hover > a:after, +.dropdown-submenu:active > a:after, +.dropdown-submenu:focus > a:after, +.dropdown-submenu:visited > a:after { + color: #ff7823; + margin-right: -16px; +} +div.kse-dropdown > .dropdown-menu, +.kse-dropdown > .dropdown-menu { + min-width: 0; + top: 94%; +} +.btn, +.btn-default { + font-family: sans-serif; + color: #303030; + background: #e5e5e5; + background-color: #e5e5e5; + border: 2px solid #e5e5e5; + font-weight: normal; + box-shadow: none; + text-shadow: none; + border-radius: 3px; + font-size: initial; +} +.btn:hover, +.btn:active:hover, +.btn.active:hover, +.btn-default:hover, +.open > .dropdown-toggle.btn-default:hover, +.open > .dropdown-toggle.btn:hover { + color: #ef5c00; + border: 2px solid #e0e0e0; + background-color: #e0e0e0; + background: #e0e0e0; + background-image: none; + box-shadow: none !important; + border-radius: 3px; +} +.btn:active, +.btn.active, +.btn:active:focus, +.btn.active:focus, +.btn:active.focus, +.btn.active.focus, +.btn-default:focus, +.btn-default.focus, +.btn-default:active, +.btn-default.active, +.btn-default:active:hover, +.btn-default.active:hover, +.btn-default:active:focus, +.btn-default.active:focus, +.btn-default:active.focus, +.btn-default.active.focus, +.open > .dropdown-toggle.btn:focus, +.open > .dropdown-toggle.btn.focus, +.open > .dropdown-toggle.btn-default:hover, +.open > .dropdown-toggle.btn-default:focus, +.open > .dropdown-toggle.btn-default.hover, +.open > .dropdown-toggle.btn-default.focus { + color: #ef5c00; + border: 2px solid #e0e0e0; + background-color: #e0e0e0 !important; + background: #e0e0e0 !important; + background-image: none; + box-shadow: none !important; + border-radius: 3px; +} +.btn-default:active:hover, +.btn-default.active:hover, +.btn-default:active:focus, +.btn-default.active:focus, +.btn-default:active.focus, +.btn-default.active.focus { + color: #ef5c00 !important; + background-color: #e5e5e5; + border-color: #ffccac !important; + transition: 2000ms ease; +} +.btn:focus, +.btn.focus, +.btn:active:focus, +.btn.active:focus, +.btn:active, +.btn.active, +.btn:active.focus, +.btn.active.focus { + color: #ef5c00 !important; + outline: none !important; + outline-width: 0px !important; + background: #ffccac !important; + background-color: #ffccac !important; + border-color: #ffccac !important; + transition: 200ms ease !important; +} +.item_buttons > .btn, +.item_buttons > .btn-group, +.item_buttons > .input-group { + font-size: 13pt; + background: transparent; + background-color: transparent; + border: 0px solid #e4e4e4; + border-bottom: 2px solid transparent; + margin-left: 5px; + padding-top: 4px !important; +} +.item_buttons > .btn:hover, +.item_buttons > .btn-group:hover, +.item_buttons > .input-group:hover, +.item_buttons > .btn.active, +.item_buttons > .btn-group.active, +.item_buttons > .input-group.active, +.item_buttons > .btn.focus { + margin-left: 5px; + background: #dfdfdf; + padding-top: 4px !important; + background-color: transparent; + border: 0px solid transparent; + border-bottom: 2px solid #ff7823; + border-radius: 0px; + transition: none; +} +.item_buttons { + line-height: 1.5em !important; +} +.item_buttons .btn { + min-width: 11ex; +} +.btn-group > .btn:first-child { + margin-left: 3px; +} +.btn-group > .btn-mini, +.btn-sm, +.btn-group-sm > .btn, +.btn-xs, +.btn-group-xs > .btn, +.alternate_upload .btn-upload, +.btn-group, +.btn-group-vertical { + font-size: inherit; + font-weight: normal; + height: inherit; + line-height: inherit; +} +.btn-xs, +.btn-group-xs > .btn { + font-size: initial !important; + background-image: none; + font-weight: normal; + text-shadow: none; + display: inline-table; + padding: 2px 5px; + line-height: 1.45; +} +.btn-group > .btn:first-child { + margin-left: 3px; +} +div#new-buttons > button, +#new-buttons > button, +div#refresh_notebook_list, +#refresh_notebook_list { + background: transparent; + background-color: transparent; + border: none; +} +div#new-buttons > button:hover, +#new-buttons > button:hover, +div#refresh_notebook_list, +#refresh_notebook_list, +div.alternate_upload .btn-upload, +.alternate_upload .btn-upload, +div.dynamic-buttons > button, +.dynamic-buttons > button, +.dynamic-buttons > button:focus, +.dynamic-buttons > button:active:focus, +.dynamic-buttons > button.active:focus, +.dynamic-buttons > button.focus, +.dynamic-buttons > button:active.focus, +.dynamic-buttons > button.active.focus, +#new-buttons > button:focus, +#new-buttons > button:active:focus, +#new-buttons > button.active:focus, +#new-buttons > button.focus, +#new-buttons > button:active.focus, +#new-buttons > button.active.focus, +.alternate_upload .btn-upload:focus, +.alternate_upload .btn-upload:active:focus, +.alternate_upload .btn-upload.active:focus, +.alternate_upload .btn-upload.focus, +.alternate_upload .btn-upload:active.focus, +.alternate_upload .btn-upload.active.focus { + background: transparent !important; + background-color: transparent !important; + border: none !important; +} +.alternate_upload input.fileinput { + text-align: center; + vertical-align: bottom; + margin-left: -.5ex; + display: inline-table; + border: solid 0px #e5e5e5; + margin-bottom: -1ex; +} +.alternate_upload .btn-upload { + display: inline-table; + background: transparent; + border: none; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -2px; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + z-index: 2; +} +.dropdown-header { + font-family: sans-serif !important; + font-size: 13pt !important; + color: #ff7823 !important; + border-bottom: none !important; + padding: 0px !important; + margin: 6px 6px 0px !important; +} +span#last-modified.btn.btn-xs.btn-default.sort-action, +span#sort-name.btn.btn-xs.btn-default.sort-action { + font-family: sans-serif; + font-size: 16px; + background-color: transparent; + background: transparent; + border: none; + color: #303030; + padding-bottom: 0px; + margin-bottom: 0px; + vertical-align: sub; +} +span#last-modified.btn.btn-xs.btn-default.sort-action { + margin-left: 19px; +} +button.close { + border: 0px none; + font-family: sans-serif; + font-size: 20pt; + font-weight: normal; +} +.dynamic-buttons { + padding-top: 0px; + display: inline-block; +} +.close { + color: #de143d; + opacity: .5; + text-shadow: none; + font-weight: normal; +} +.close:hover { + color: #de143d; + opacity: 1; + font-weight: normal; +} +div.nbext-enable-btns .btn[disabled], +div.nbext-enable-btns .btn[disabled]:hover, +.btn-default.disabled, +.btn-default[disabled], +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus { + color: #4a4a4a; + background: #e2e2e2; + background-color: #e2e2e2; + border-color: #e2e2e2; + transition: 200ms ease; +} +.input-group-addon { + padding: 2px 5px; + font-size: 13pt; + font-weight: normal; + height: auto; + color: #303030; + text-align: center; + background-color: transparent; + border: 2px solid transparent !important; + text-transform: capitalize; +} +a.btn.btn-default.input-group-addon:hover { + background: transparent !important; + background-color: transparent !important; +} +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + height: 100%; +} +.btn-group > .btn + .dropdown-toggle:hover { + background: #e0e0e0 !important; +} +.input-group-btn { + position: relative; + font-size: inherit; + white-space: nowrap; + background: #e4e4e4; + background-color: #e4e4e4; + border: none; +} +.input-group-btn:hover { + background: #dfdfdf; + background-color: #dfdfdf; + border: none; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + background: #e4e4e4; + background-color: #e4e4e4; + border: none; + margin-left: 2px; + margin-right: -1px; + font-size: inherit; +} +.input-group-btn:first-child > .btn:hover, +.input-group-btn:first-child > .btn-group:hover { + background: #e0e0e0; + background-color: #e0e0e0; + border: none; + font-size: inherit; + transition: 200ms ease; +} +div.modal .btn-group > .btn:first-child { + background: #e4e4e4; + background-color: #e4e4e4; + border: 1px solid #e1e1e1; + margin-top: 0px !important; + margin-left: 0px; + margin-bottom: 2px; +} +div.modal .btn-group > .btn:first-child:hover { + background: #dfdfdf; + background-color: #dfdfdf; + border: 1px solid #dfdfdf; + transition: 200ms ease; +} +div.modal > button, +div.modal-footer > button { + background: #e4e4e4; + background-color: #e4e4e4; + border-color: #e4e4e4; +} +div.modal > button:hover, +div.modal-footer > button:hover { + background: #dfdfdf; + background-color: #dfdfdf; + border-color: #dfdfdf; + transition: 200ms ease; +} +.modal-content { + font-family: sans-serif; + font-size: 12.0pt; + position: relative; + background: #e4e4e4; + background-color: #e4e4e4; + border: none; + border-radius: 1px; + background-clip: padding-box; + outline: none; +} +.modal-header { + font-family: sans-serif; + font-size: 13pt; + color: #303030; + background: #e4e4e4; + background-color: #e4e4e4; + border-color: #dedede; + padding: 12px; + min-height: 16.4286px; +} +.modal-content h4 { + font-family: sans-serif; + font-size: 16pt; + color: #303030; + padding: 5px; +} +.modal-body { + background-color: #ffffff; + position: relative; + padding: 15px; +} +.modal-footer { + padding: 8px; + text-align: right; + background-color: #ffffff; + border-top: none; +} +.alert-info { + background-color: #fdfdfd; + border-color: #dedede; + color: #303030; +} +.modal-header .close { + margin-top: -5px; + font-size: 25pt; +} +.modal-backdrop, +.modal-backdrop.in { + opacity: 0.85; + background-color: notebook-bg; +} +div.panel, +div.panel-default, +.panel, +.panel-default { + font-family: sans-serif; + font-size: 13pt; + background-color: #f4f4f4; + color: #303030; + margin-bottom: 14px; + border: 0; + box-shadow: none; +} +div.panel > .panel-heading, +div.panel-default > .panel-heading { + font-size: 14pt; + color: #303030; + background: #e4e4e4; + background-color: #e4e4e4; + border: 0; +} +.modal .modal-dialog { + min-width: 950px; + margin: 50px auto; +} +div.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 0px; + padding-right: 5px; +} +div.form-control, +.form-control { + font-family: sans-serif; + font-size: initial; + color: #303030; + background-color: #ffffff; + border: 1px solid #d0d0d0 !important; + margin-left: 2px; + box-shadow: none; + transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; +} +.form-control-static { + min-height: inherit; + height: inherit; +} +.form-group.list-group-item { + color: #303030; + background-color: #f4f4f4; + border-color: #dedede; + margin-bottom: 0px; +} +input, +button, +select, +textarea { + background-color: #ffffff; + font-weight: normal; + border: 1px solid #dedede; +} +select.form-control.select-xs { + height: 33px; + font-size: 13pt; +} +.toolbar select, +.toolbar label { + width: auto; + vertical-align: middle; + margin-right: 0px; + margin-bottom: 0px; + display: inline; + font-size: 92%; + margin-left: 10px; + padding: 0px; + background: #e5e5e5 !important; + background-color: #e5e5e5 !important; + border: 2px solid #e5e5e5 !important; +} +.form-control:focus { + border-color: #ff7823; + outline: 2px solid rgba(240,147,43,.50); + -webkit-box-shadow: none; +} +::-webkit-input-placeholder { + color: #828892; +} +::-moz-placeholder { + color: #828892; +} +:-ms-input-placeholder { + color: #828892; +} +:-moz-placeholder { + color: #828892; +} +[dir="ltr"] #find-and-replace .input-group-btn + .form-control { + border: 2px solid #dedede !important; +} +[dir="ltr"] #find-and-replace .input-group-btn + .form-control:focus { + border-color: #ff7823; + outline: 2px solid rgba(240,147,43,.50); + -webkit-box-shadow: none; + box-shadow: none; +} +div.output.output_scroll { + box-shadow: none; +} +::-webkit-scrollbar { + width: 11px; + max-height: 9px; + background-color: #ebebeb; + border-radius: 3px; + border: none; +} +::-webkit-scrollbar-track { + background: #ebebeb; + border: none; + width: 11px; + max-height: 9px; +} +::-webkit-scrollbar-thumb { + border-radius: 2px; + border: none; + background: #909090; + background-clip: content-box; + width: 11px; +} +HTML, +body, +div, +dl, +dt, +dd, +ul, +ol, +li, +h1, +h2, +h3, +h4, +h5, +h6, +pre, +code, +form, +fieldset, +legend, +input, +button, +textarea, +p, +blockquote, +th, +td, +span, +a { + text-rendering: auto; + -webkit-font-smoothing: antialiased; +} +div.input_area { + background-color: #ededed; + background: #ededed; + padding-right: 1.2em; + border: 0px; + border-radius: 0px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} +div.cell { + padding: 0px; + background: #ffffff; + background-color: #ffffff; + border: medium solid #ffffff; + border-radius: 0px; + top: 0; +} +div.cell.selected { + background: #ffffff; + background-color: #ffffff; + border: medium solid #ffffff; + padding: 0px; + border-radius: 3px; +} +.edit_mode div.cell.selected { + padding: 0px; + background: #ffffff; + background-color: #ffffff; + border: medium solid #ffffff; + border-radius: 3px; +} +div.cell.edit_mode { + padding: 0px; + background: #ffffff; + background-color: #ffffff; +} +div.CodeMirror-sizer { + margin-left: 0px; + margin-bottom: -21px; + border-right-width: 16px; + min-height: 37px; + padding-right: 0px; + padding-bottom: 0px; + margin-top: 0px; +} +div.cell.selected:before { + background: #ededed; + border: none; + border-radius: 3px; + position: absolute; + display: block; + top: 0px; + left: 0px; + width: 0px; + height: 100%; +} +.edit_mode div.cell.selected:before { + background: #ffffff; + border: none; + border-radius: 3px; + position: absolute; + display: block; + top: 0px; + left: 0px; + width: 0px; + height: 100%; +} +div.cell.code_cell .input { + border-left: 5px solid #ededed !important; + border-radius: 3px; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +div.cell.code_cell.selected .input { + border-left: 5px solid #ff7823 !important; + border-radius: 3px; +} +.edit_mode div.cell.code_cell.selected .input { + border-left: 5px solid #ffd5bb !important; + border-radius: 3px; +} +div.cell.selected:before, +div.cell.selected.jupyter-soft-selected:before { + position: absolute; + display: block; + top: -1px; + left: -1px; + width: 5px; + height: calc(102%); + content: ''; + background: transparent !important; +} +div.cell.jupyter-soft-selected, +div.cell.selected.jupyter-soft-selected { + border-left-color: #ffd5bb !important; + border-left-width: 0px !important; + padding-left: 7px !important; + border-right-color: #ffd5bb !important; + border-right-width: 0px !important; + background: #ffd5bb !important; + border-radius: 6px !important; +} +div.cell.selected.jupyter-soft-selected .input { + border-left: 5px solid #ededed !important; +} +div.cell.selected.jupyter-soft-selected:before, +.edit_mode div.cell.selected:before .input { + background: #ffd5bb !important; + border: 2px solid #ffd5bb !important; + border-radius: 6px !important; + position: absolute !important; + display: block !important; + top: 0px !important; + left: 0px !important; + width: 6px !important; + height: 100% !important; +} +div.cell.selected.jupyter-soft-selected { + border-left-color: #ff7823; + border-color: #ffffff; + padding-left: 7px; + border-radius: 6px; +} +div.cell.code_cell.selected .input { + border-left: none; + border-radius: 3px; +} +div.cell.selected.jupyter-soft-selected .prompt, +div.cell.text_cell.selected.jupyter-soft-selected .prompt { + top: 0; + border-left: #ededed !important; + border-radius: 2px; +} +div.cell.text_cell.selected.jupyter-soft-selected .input_prompt { + border-left: none !important; +} +div.cell.text_cell.selected.jupyter-soft-selected:before { + background: #f2f2f2 !important; + border: 2px solid #f2f2f2 !important; + border-radius: 6px !important; + position: absolute !important; + display: block !important; + top: 0px !important; + left: 0px !important; + width: 6px !important; + height: 100% !important; +} +div.cell.text_cell.jupyter-soft-selected, +div.cell.text_cell.selected.jupyter-soft-selected { + border-left-color: #f2f2f2 !important; + border-left-width: 0px !important; + padding-left: 7px !important; + border-right-color: #f2f2f2 !important; + border-right-width: 0px !important; + background: #f2f2f2 !important; + border-radius: 6px !important; +} +div.prompt, +.prompt { + font-family: monospace, monospace; + font-size: 9pt !important; + font-weight: normal; + color: #828892; + line-height: 170%; + padding: 0px; + padding-top: 4px; + padding-left: 0px; + padding-right: 1px; + text-align: right !important; + min-width: 12.5ex !important; + width: 12.5ex !important; +} +div.prompt.input_prompt { + font-size: 9pt !important; + background-color: #ededed; + border-top: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + padding-right: 3px; + min-width: 12.5ex; + width: 12.5ex !important; +} +div.cell.code_cell .input_prompt { + border-right: 2px solid rgba(240,147,43,.50); +} +div.cell.selected .prompt { + top: 0; +} +.edit_mode div.cell.selected .prompt { + top: 0; +} +.edit_mode div.cell.selected .prompt { + top: 0; +} +div.output_wrapper { + background-color: #ffffff; + border: 0px; + left: 0px; + margin-bottom: 0em; + margin-top: 0em; + border-top-right-radius: 0px; + border-top-left-radius: 0px; +} +div.output_subarea.output_text.output_stream.output_stdout, +div.output_subarea.output_text { + font-family: monospace, monospace; + font-size: 8.5pt !important; + line-height: 150% !important; + background-color: #ffffff; + color: #303030; + border-top-right-radius: 0px; + border-top-left-radius: 0px; +} +div.output_area pre { + font-family: monospace, monospace; + font-size: 8.5pt !important; + line-height: 151% !important; + color: #303030; + border-top-right-radius: 0px; + border-top-left-radius: 0px; +} +div.output_area { + display: -webkit-box; +} +div.output_html { + font-family: monospace, monospace; + font-size: 8.5pt; + color: #353535; + background-color: #ffffff; + background: #ffffff; +} +div.output_subarea { + overflow-x: auto; + padding: 0.8em !important; + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + flex: 1; +} +div.btn.btn-default.output_collapsed { + background: #d7d7d7; + background-color: #d7d7d7; + border-color: #d7d7d7; +} +div.btn.btn-default.output_collapsed:hover { + background: #d2d2d2; + background-color: #d2d2d2; + border-color: #d2d2d2; +} +div.prompt.output_prompt { + font-family: monospace, monospace; + font-size: 9.5pt !important; + font-weight: bold !important; + background-color: #ffffff; + color: transparent; + border-bottom-left-radius: 4px; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + border-bottom-right-radius: 0px; + min-width: 12.5ex !important; + width: 12.5ex !important; + border-right: 2px solid transparent; +} +div.out_prompt_overlay.prompt { + font-family: monospace, monospace; + font-size: 9.5pt !important; + font-weight: bold !important; + background-color: #ffffff; + border-bottom-left-radius: 2px; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + border-bottom-right-radius: 0px; + min-width: 12.5ex !important; + width: 12.5ex !important; + border-right: 2px solid transparent; + color: transparent; +} +div.out_prompt_overlay.prompt:hover { + background-color: #f7f7f7; + box-shadow: none !important; + border: none; + border-bottom-left-radius: 2px; + -webkit-border-: 2px; + -moz-border-radius: 2px; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + min-width: 12.5ex !important; + width: 12.5ex !important; + border-right: 2px solid #f7f7f7 !important; +} +div.cell.code_cell .output_prompt { + border-right: 2px solid transparent; + color: transparent; +} +div.cell.selected .output_prompt, +div.cell.selected .out_prompt_overlay.prompt { + border-left: 5px solid #f2f2f2; + border-right: 2px solid #ffffff; + border-radius: 0px !important; +} +.edit_mode div.cell.selected .output_prompt, +.edit_mode div.cell.selected .out_prompt_overlay.prompt { + border-left: 5px solid #f2f2f2; + border-right: 2px solid #ffffff; + border-radius: 0px !important; +} +div.text_cell, +div.text_cell_render pre, +div.text_cell_render { + font-family: sans-serif; + font-size: 13pt; + line-height: 130% !important; + color: #353535; + background: #ffffff; + background-color: #ffffff; + border-radius: 0px; +} +div .text_cell_render { + padding: 0.4em 0.4em 0.4em 0.4em; +} +div.cell.text_cell .CodeMirror-lines { + padding-top: .7em !important; + padding-bottom: .4em !important; + padding-left: .5em !important; + padding-right: .5em !important; + margin-top: .4em; + margin-bottom: .3em; +} +div.cell.text_cell.unrendered div.input_area, +div.cell.text_cell.rendered div.input_area { + background-color: #ffffff; + background: #ffffff; + border: 0px; + border-radius: 2px; +} +div.cell.text_cell .CodeMirror, +div.cell.text_cell .CodeMirror pre { + line-height: 170% !important; +} +div.cell.text_cell.rendered.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #ffffff; + background-color: #ffffff; + border-radius: 0px; +} +div.cell.text_cell.unrendered.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #ffffff; + background-color: #ffffff; + border-radius: 0px; +} +div.cell.text_cell.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #ffffff; + background-color: #ffffff; + border-radius: 0px; +} +.edit_mode div.cell.text_cell.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #ffffff; + background-color: #ffffff; + border-radius: 0px; +} +div.text_cell.unrendered, +div.text_cell.unrendered.selected, +div.edit_mode div.text_cell.unrendered { + font-family: sans-serif; + line-height: 170% !important; + background: #ffffff; + background-color: #ffffff; + border-radius: 0px; +} +div.cell.text_cell.selected:before { + background: #f2f2f2; + border: 2px solid #f2f2f2; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; + position: absolute; + display: block; + top: 0px; + left: 0px; + width: 5px; + height: 100%; +} +.edit_mode div.cell.text_cell.selected:before { + background: #f2f2f2; + border: 2px solid #f2f2f2; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; + position: absolute; + display: block; + top: 0px; + left: 0px; + width: 5px; + height: 100%; +} +div.cell.text_cell .prompt { + border-right: 0; +} +div.cell.text_cell.rendered .prompt { + font-family: monospace, monospace; + font-size: 9.5pt; + font-weight: normal; + color: #828892 !important; + text-align: right !important; + min-width: 12.5ex !important; + width: 12.5ex !important; + background-color: #ffffff; + border-right: 2px solid transparent; + border-left: 5px solid #ffffff; +} +div.cell.text_cell.unrendered .prompt { + font-family: monospace, monospace; + font-size: 9.5pt; + font-weight: normal; + color: #828892 !important; + text-align: right !important; + min-width: 12.5ex !important; + width: 12.5ex !important; + border-right: 2px solid transparent; + border-left: 5px solid #ffffff; +} +div.cell.text_cell.rendered .prompt { + border-right: 2px solid transparent; +} +div.cell.text_cell.rendered.selected .prompt { + top: 0; + border-left: 5px solid #f2f2f2; + border-right: 2px solid transparent; +} +div.text_cell.unrendered.selected .prompt { + top: 0; + background: #ffffff; + border-left: 5px solid #f2f2f2; + border-right: 2px solid transparent; +} +div.rendered_html code { + font-family: monospace, monospace; + font-size: 11pt; + padding-top: 3px; + padding-left: 2px; + color: #303030; + background: #efefef; + background-color: #efefef; +} +pre, +code, +kbd, +samp { + white-space: pre-wrap; +} +.well code, +code { + font-family: monospace, monospace; + font-size: 11pt !important; + line-height: 170% !important; + color: #353535; + background: #efefef; + background-color: #efefef; + border-color: #efefef; +} +kbd { + padding: 1px; + font-size: 11pt; + font-weight: 800; + color: #303030; + background-color: transparent !important; + border: 0; + box-shadow: none; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12.0pt; + line-height: 1.42857143; + color: #303030; + background-color: #efefef; + border: 1px solid #e7e7e7; + border-radius: 2px; +} +div.rendered_html { + color: #353535; +} +.rendered_html * + ul { + margin-top: .4em; + margin-bottom: .3em; +} +.rendered_html * + p { + margin-top: .5em; + margin-bottom: .5em; +} +div.rendered_html pre { + font-family: monospace, monospace; + font-size: 11pt !important; + line-height: 170% !important; + color: #353535; + background: #efefef; + background-color: #efefef; + max-width: 80%; + border-radius: 0px; + border-left: 3px solid #efefef; + max-width: 80%; + border-radius: 0px; + padding-left: 5px; + margin-left: 6px; +} +div.text_cell_render pre, +div.text_cell_render code { + font-family: monospace, monospace; + font-size: 11pt !important; + line-height: 170% !important; + color: #353535; + background: #ffffff; + background-color: #ffffff; + max-width: 80%; + border-radius: 0px; + border-left: none; +} +div.text_cell_render pre { + border-left: 3px solid rgba(240,147,43,.50) !important; + max-width: 80%; + border-radius: 0px; + padding-left: 5px; + margin-left: 6px; +} +div.text_cell_render h1, +div.rendered_html h1, +div.text_cell_render h2, +div.rendered_html h2, +div.text_cell_render h3, +div.rendered_html h3, +div.text_cell_render h4, +div.rendered_html h4, +div.text_cell_render h5, +div.rendered_html h5 { + font-family: sans-serif; + margin: 0.4em .2em .3em .2em !important; +} +.rendered_html h1:first-child, +.rendered_html h2:first-child, +.rendered_html h3:first-child, +.rendered_html h4:first-child, +.rendered_html h5:first-child, +.rendered_html h6:first-child { + margin-top: 0.2em !important; + margin-bottom: 0.2em !important; +} +.rendered_html h1, +.text_cell_render h1 { + color: #126dce; + font-size: 200%; + text-align: center; + font-style: normal; + font-weight: lighter; +} +.rendered_html h2, +.text_cell_render h2 { + text-align: left; + font-size: 170%; + color: #3f3d46; + font-style: normal; + font-weight: lighter; +} +.rendered_html h3, +.text_cell_render h3 { + font-size: 140%; + color: #3f3d46; + font-style: normal; + font-weight: lighter; +} +.rendered_html h4, +.text_cell_render h4 { + font-size: 110%; + color: #3f3d46; + font-style: normal; + font-weight: lighter; +} +.rendered_html h5, +.text_cell_render h5 { + font-size: 100%; + color: #2f2f2f; + font-style: normal; + font-weight: lighter; +} +hr { + margin-top: 8px; + margin-bottom: 10px; + border: 0; + border-top: 1px solid #126dce; +} +.rendered_html hr { + color: #126dce; + background-color: #126dce; + margin-right: 2em; +} +#complete > select > option:hover { + background: #d4d4d4; + background-color: #d4d4d4; +} +div#_vivaldi-spatnav-focus-indicator._vivaldi-spatnav-focus-indicator { + position: absolute; + z-index: 9999999999; + top: 0px; + left: 0px; + box-shadow: none; + pointer-events: none; + border-radius: 2px; +} +.rendered_html tr, +.rendered_html th, +.rendered_html td { + text-align: left; + vertical-align: middle; + padding: 0.42em 0.47em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +.rendered_html td { + font-family: sans-serif !important; + font-size: 9.3pt; +} +.rendered_html table { + font-family: sans-serif !important; + margin-left: 8px; + margin-right: auto; + border: none; + border-collapse: collapse; + border-spacing: 0; + color: #353535; + table-layout: fixed; +} +.rendered_html thead { + font-family: sans-serif !important; + font-size: 10.3pt !important; + background: #ebebeb; + color: #353535; + border-bottom: 1px solid #ebebeb; + vertical-align: bottom; +} +.rendered_html tbody tr:nth-child(odd) { + background: #fafafa; +} +.rendered_html tbody tr { + background: #f2f2f2; +} +.rendered_html tbody tr:hover:nth-child(odd) { + background: #f7f7f7; +} +.rendered_html tbody tr:hover { + background: #f0f0f0; +} +.rendered_html * + table { + margin-top: .05em; +} +div.widget-area { + background-color: #ffffff; + background: #ffffff; + color: #303030; +} +div.widget-area a { + font-family: sans-serif; + font-size: 12.0pt; + font-weight: normal; + font-style: normal; + color: #303030; + text-shadow: none !important; +} +div.widget-area a:hover, +div.widget-area a:focus { + font-family: sans-serif; + font-size: 12.0pt; + font-weight: normal; + font-style: normal; + color: #2f2f2f; + background: rgba(180,180,180,.14); + background-color: rgba(180,180,180,.14); + border-color: transparent; + background-image: none; + text-shadow: none !important; +} +div.widget_item.btn-group > button.btn.btn-default.widget-combo-btn, +div.widget_item.btn-group > button.btn.btn-default.widget-combo-btn:hover { + background: #e1e1e1; + background-color: #e1e1e1; + border: 2px solid #e1e1e1 !important; + font-size: inherit; + z-index: 0; +} +div.jupyter-widgets.widget-hprogress.widget-hbox { + display: inline-table !important; + width: 38% !important; + margin-left: 10px; +} +div.jupyter-widgets.widget-hprogress.widget-hbox .widget-label, +div.widget-hbox .widget-label, +.widget-hbox .widget-label, +.widget-inline-hbox .widget-label, +div.widget-label { + text-align: -webkit-auto !important; + margin-left: 15px !important; + max-width: 240px !important; + min-width: 100px !important; + vertical-align: text-top !important; + color: #303030 !important; + font-size: 14px !important; +} +.widget-hprogress .progress { + flex-grow: 1; + height: 20px; + margin-top: auto; + margin-left: 12px; + margin-bottom: auto; + width: 300px; +} +.progress { + overflow: hidden; + height: 22px; + margin-bottom: 10px; + padding-left: 10px; + background-color: #d6d6d6 !important; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; + z-index: 10; +} +.progress-bar-danger { + background-color: #e5344a !important; +} +.progress-bar-info { + background-color: #2980b9 !important; +} +.progress-bar-warning { + background-color: #f39c12 !important; +} +.progress-bar-success { + background-color: #5cb85c !important; +} +.widget-select select { + margin-left: 12px; +} +.rendered_html :link { + font-family: sans-serif; + font-size: 100%; + color: #ff7823; + text-decoration: underline; +} +.rendered_html :visited, +.rendered_html :visited:active, +.rendered_html :visited:focus { + color: #fa853d; +} +.rendered_html :visited:hover, +.rendered_html :link:hover { + font-family: sans-serif; + font-size: 100%; + color: #f96000; +} +div.cell.text_cell a.anchor-link:link { + font-size: inherit; + text-decoration: none; + padding: 0px 20px; + visibility: none; + color: rgba(0,0,0,.32); +} +div.cell.text_cell a.anchor-link:link:hover { + font-size: inherit; + color: #828892; +} +.navbar-text { + margin-top: 4px; + margin-bottom: 0px; +} +#clusters > a { + color: #ef5c00; + text-decoration: underline; + cursor: auto; +} +#clusters > a:hover { + color: #126dce; + text-decoration: underline; + cursor: auto; +} +#nbextensions-configurator-container > div.row.container-fluid.nbext-selector > h3 { + font-size: 17px; + margin-top: 5px; + margin-bottom: 8px; + height: 24px; + padding: 4px 0 4px 0; +} +div#nbextensions-configurator-container.container, +#nbextensions-configurator-container.container { + width: 100%; + margin-right: auto; + margin-left: auto; +} +div.nbext-selector > nav > .nav > li > a { + font-family: sans-serif; + font-size: 10.5pt; + padding: 2px 5px; +} +div.nbext-selector > nav > .nav > li > a:hover { + background: transparent; +} +div.nbext-selector > nav > .nav > li:hover { + background-color: rgba(180,180,180,.14) !important; + background: rgba(180,180,180,.14) !important; +} +div.nbext-selector > nav > .nav > li.active:hover { + background: transparent !important; + background-color: transparent !important; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:active, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #1c1c1c; + background-color: rgba(180,180,180,.14) !important; + background: rgba(180,180,180,.14) !important; + -webkit-backface-visibility: hidden; + -webkit-font-smoothing: subpixel-antialiased !important; +} +div.nbext-readme > .nbext-readme-contents > .rendered_html { + font-family: sans-serif; + font-size: 11.5pt; + line-height: 145%; + padding: 1em 1em; + color: #353535; + background-color: #ffffff; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.nbext-icon, +.nbext-desc, +.nbext-compat-div, +.nbext-enable-btns, +.nbext-params { + margin-bottom: 8px; + font-size: 11.5pt; +} +div.nbext-readme > .nbext-readme-contents { + padding: 0; + overflow-y: hidden; +} +div.nbext-readme > .nbext-readme-contents:not(:empty) { + margin-top: 0.5em; + margin-bottom: 2em; + border: none; + border-top-color: #828892; +} +.nbext-showhide-incompat { + padding-bottom: 0.5em; + color: #4a4a4a; + font-size: 10.5pt; +} +.nbext-filter-menu.dropdown-menu > li > a:hover, +.nbext-filter-menu.dropdown-menu > li > a:focus, +.nbext-filter-menu.dropdown-menu > li > a.ui-state-focus { + color: #2f2f2f !important; + background-color: #d4d4d4 !important; + background: #d4d4d4 !important; + border-color: #d4d4d4 !important; +} +.nbext-filter-input-wrap > .nbext-filter-input-subwrap, +.nbext-filter-input-wrap > .nbext-filter-input-subwrap > input { + border: none; + outline: none; + background-color: transparent; + padding: 0; + vertical-align: middle; + margin-top: -2px; +} +span.rendered_html code { + background-color: transparent; + color: #303030; +} +#nbextensions-configurator-container > div.row.container-fluid.nbext-selector { + padding-left: 0px; + padding-right: 0px; +} +.nbext-filter-menu { + max-height: 50vh; + overflow-y: auto; + outline: none; + border: 2px solid #dedede; +} +.nbext-filter-menu:hover { + border: 2px solid #dedede; +} +.alert-warning { + background-color: #f4f4f4; + border-color: #f4f4f4; + color: #303030; +} +.notification_widget.danger { + color: #ffffff; + background-color: #e5344a; + border-color: #e5344a; + padding-right: 5px; +} +#nbextensions-configurator-container > div.nbext-buttons.tree-buttons.no-padding.pull-right > span > button { + border: none !important; +} +button#refresh_running_list { + border: none !important; +} +mark, +.mark { + background-color: #ffffff; + color: #353535; + padding: .15em; +} +a.text-warning, +a.text-warning:hover { + color: #828892; +} +a.text-warning.bg-warning { + background-color: #ffffff; +} +span.bg-success.text-success { + background-color: transparent; + color: #009e07; +} +span.bg-danger.text-danger { + background-color: #ffffff; + color: #de143d; +} +.has-success .input-group-addon { + color: #009e07; + border-color: transparent; + background: inherit; + background-color: rgba(83,180,115,.10); +} +.has-success .form-control { + border-color: #009e07; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); + box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); +} +.has-error .input-group-addon { + color: #de143d; + border-color: transparent; + background: inherit; + background-color: rgba(192,57,67,.10); +} +.has-error .form-control { + border-color: #de143d; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); + box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); +} +.kse-input-group-pretty > kbd { + font-family: monospace, monospace; + color: #303030; + font-weight: normal; + background: transparent; +} +.kse-input-group-pretty > kbd { + font-family: monospace, monospace; + color: #303030; + font-weight: normal; + background: transparent; +} +div.nbext-enable-btns .btn[disabled], +div.nbext-enable-btns .btn[disabled]:hover, +.btn-default.disabled, +.btn-default[disabled] { + background: #e2e2e2; + background-color: #e2e2e2; + color: #282828; +} +label#Keyword-Filter { + display: none; +} +.input-group .nbext-list-btn-add, +.input-group-btn:last-child > .btn-group > .btn { + background: #e4e4e4; + background-color: #e4e4e4; + border-color: #e4e4e4; + border: 2px solid #e4e4e4; +} +.input-group .nbext-list-btn-add:hover, +.input-group-btn:last-child > .btn-group > .btn:hover { + background: #dfdfdf; + background-color: #dfdfdf; + border-color: #dfdfdf; + border: 2px solid #dfdfdf; +} +#notebook-container > div.cell.code_cell.rendered.selected > div.widget-area > div.widget-subarea > div > div.widget_item.btn-group > button.btn.btn-default.dropdown-toggle.widget-combo-carrot-btn { + background: #e4e4e4; + background-color: #e4e4e4; + border-color: #e4e4e4; +} +#notebook-container > div.cell.code_cell.rendered.selected > div.widget-area > div.widget-subarea > div > div.widget_item.btn-group > button.btn.btn-default.dropdown-toggle.widget-combo-carrot-btn:hover { + background: #dfdfdf; + background-color: #dfdfdf; + border-color: #dfdfdf; +} +.ui-widget-content { + background: #e5e5e5; + background-color: #e5e5e5; + border: 2px solid #e5e5e5; + color: #303030; +} +div.collapsible_headings_toggle { + color: rgba(180,180,180,.30) !important; +} +div.collapsible_headings_toggle:hover { + color: #ff7823 !important; +} +.collapsible_headings_toggle .h1, +.collapsible_headings_toggle .h2, +.collapsible_headings_toggle .h3, +.collapsible_headings_toggle .h4, +.collapsible_headings_toggle .h5, +.collapsible_headings_toggle .h6 { + margin: 0.3em .4em 0em 0em !important; + line-height: 1.2 !important; +} +div.collapsible_headings_toggle .fa-caret-down:before, +div.collapsible_headings_toggle .fa-caret-right:before { + font-size: xx-large; + transition: transform 1000ms; + transform: none !important; +} +.collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h1:after, +.collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h2:after, +.collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h3:after, +.collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h4:after, +.collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h5:after, +.collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h6:after { + position: absolute; + right: 0; + bottom: 20% !important; + content: "[\002026]"; + color: rgba(180,180,180,.30) !important; + padding: 0.5em 0em 0em 0em !important; +} +.collapsible_headings_ellipsis .rendered_html h1, +.collapsible_headings_ellipsis .rendered_html h2, +.collapsible_headings_ellipsis .rendered_html h3, +.collapsible_headings_ellipsis .rendered_html h4, +.collapsible_headings_ellipsis .rendered_html h5, +.collapsible_headings_ellipsis .rendered_html h6, +.collapsible_headings_toggle .fa { + transition: transform 1000ms !important; + -webkit-transform: inherit !important; + -moz-transform: inherit !important; + -ms-transform: inherit !important; + -o-transform: inherit !important; + transform: inherit !important; + padding-right: 0px !important; +} +input.raw_input { + font-family: monospace, monospace; + font-size: 11pt !important; + color: #303030; + background-color: #efefef; + border-color: #ececec; + background: #ececec; + width: auto; + vertical-align: baseline; + padding: 0em 0.25em; + margin: 0em 0.25em; + -webkit-box-shadow: none; + box-shadow: none; +} +audio, +video { + display: inline; + vertical-align: middle; + align-content: center; + margin-left: 20%; +} +.cmd-palette .modal-body { + padding: 0px; + margin: 0px; +} +.cmd-palette form { + background: #e5e5e5; + background-color: #e5e5e5; +} +.typeahead-field input:last-child, +.typeahead-hint { + background: #e5e5e5; + background-color: #e5e5e5; + z-index: 1; +} +.typeahead-field input { + font-family: sans-serif; + color: #303030; + border: none; + font-size: 28pt; + display: inline-block; + line-height: inherit; + padding: 3px 10px; + height: 70px; +} +.typeahead-select { + background-color: #e5e5e5; +} +body > div.modal.cmd-palette.typeahead-field { + display: table; + border-collapse: separate; + background-color: #f4f4f4; +} +.typeahead-container button { + font-family: sans-serif; + font-size: 28pt; + background-color: #e4e4e4; + border: none; + display: inline-block; + line-height: inherit; + padding: 3px 10px; + height: 70px; +} +.typeahead-search-icon { + min-width: 40px; + min-height: 55px; + display: block; + vertical-align: middle; + text-align: center; +} +.typeahead-container button:focus, +.typeahead-container button:hover { + color: #2f2f2f; + background-color: #dfdfdf; + border-color: #e0e0e0; +} +.typeahead-list > li.typeahead-group.active > a, +.typeahead-list > li.typeahead-group > a, +.typeahead-list > li.typeahead-group > a:focus, +.typeahead-list > li.typeahead-group > a:hover { + display: none; +} +.typeahead-dropdown > li > a, +.typeahead-list > li > a { + color: #303030; + text-decoration: none; +} +.typeahead-dropdown, +.typeahead-list { + font-family: sans-serif; + font-size: 13pt; + color: #303030; + background-color: #ffffff; + border: none; + background-clip: padding-box; + margin-top: 0px; + padding: 3px 2px 3px 0px; + line-height: 1.7; +} +.typeahead-dropdown > li.active > a, +.typeahead-dropdown > li > a:focus, +.typeahead-dropdown > li > a:hover, +.typeahead-list > li.active > a, +.typeahead-list > li > a:focus, +.typeahead-list > li > a:hover { + color: #2f2f2f; + background-color: #f4f4f4; + border-color: #f4f4f4; +} +.command-shortcut:before { + content: "(command)"; + padding-right: 3px; + color: #828892; +} +.edit-shortcut:before { + content: "(edit)"; + padding-right: 3px; + color: #828892; +} +ul.typeahead-list i { + margin-left: 1px; + width: 18px; + margin-right: 10px; +} +ul.typeahead-list { + max-height: 50vh; + overflow: auto; +} +.typeahead-list > li { + position: relative; + border: none; +} +div.input.typeahead-hint, +input.typeahead-hint, +body > div.modal.cmd-palette.in > div > div > div > form > div > div.typeahead-field > span.typeahead-query > input.typeahead-hint { + color: #828892 !important; + background-color: transparent; + padding: 3px 10px; +} +.typeahead-dropdown > li > a, +.typeahead-list > li > a { + display: block; + padding: 5px; + clear: both; + font-weight: 400; + line-height: 1.7; + border: 1px solid #ffffff; + border-bottom-color: rgba(180,180,180,.30); +} +body > div.modal.cmd-palette.in > div { + min-width: 750px; + margin: 150px auto; +} +.typeahead-container strong { + font-weight: bolder; + color: #ff7823; +} +#find-and-replace #replace-preview .match, +#find-and-replace #replace-preview .insert { + color: #ffffff; + background-color: #ff7823; + border-color: #ff7823; + border-style: solid; + border-width: 1px; + border-radius: 0px; +} +#find-and-replace #replace-preview .replace .match { + background-color: #de143d; + border-color: #de143d; + border-radius: 0px; +} +#find-and-replace #replace-preview .replace .insert { + background-color: #009e07; + border-color: #009e07; + border-radius: 0px; +} +.shortcut_key, +span.shortcut_key { + display: inline-block; + width: 16ex; + text-align: right; + font-family: monospace; +} +.jupyter-keybindings { + padding: 1px; + line-height: 24px; + border-bottom: 1px solid rgba(180,180,180,.14); +} +.jupyter-keybindings i { + background: #efefef; + font-size: small; + padding: 5px; + margin-left: 7px; +} +div#short-key-bindings-intro.well, +.well { + background-color: #e4e4e4; + border: 1px solid #e4e4e4; + color: #303030; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; +} +#texteditor-backdrop { + background: #ffffff; + background-color: #ffffff; +} +#texteditor-backdrop #texteditor-container .CodeMirror-gutter, +#texteditor-backdrop #texteditor-container .CodeMirror-gutters { + background: #e0e1e3; + background-color: #e0e1e3; + color: #828892; +} +.edit_app #menubar .navbar { + margin-bottom: 0px; +} +#texteditor-backdrop #texteditor-container { + padding: 0px; + background-color: #ededed; + box-shadow: none; +} +.terminal-app { + background: #ffffff; +} +.terminal-app .terminal { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + color: #303030; + background: #ededed; + padding: 0.4em; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; +} +.terminal .xterm-viewport { + background-color: #ededed; + color: #303030; + overflow-y: auto; +} +.terminal .xterm-color-0 { + color: #ff7823; +} +.terminal .xterm-color-1 { + color: #de143d; +} +.terminal .xterm-color-2 { + color: #713bc5; +} +.terminal .xterm-color-3 { + color: #e22978; +} +.terminal .xterm-color-4 { + color: #ff8132; +} +.terminal .xterm-color-5 { + color: #009e07; +} +.terminal .xterm-color-6 { + color: #e22978; +} +.terminal .xterm-color-7 { + color: #e22978; +} +.terminal .xterm-color-8 { + color: #ef5c00; +} +.terminal .xterm-color-9 { + color: #009e07; +} +.terminal .xterm-color-10 { + color: #e22978; +} +.terminal .xterm-color-14 { + color: #e22978; +} +.terminal .xterm-bg-color-15 { + background-color: #ededed; +} +.terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar) .terminal-cursor { + background-color: #ff7823; + color: #ededed; +} +.terminal:not(.focus) .terminal-cursor { + outline: 1px solid #ff7823; + outline-offset: -1px; +} +.celltoolbar { + font-size: 100%; + padding-top: 3px; + border-color: transparent; + border-bottom: thin solid #828892; + background: transparent; +} +.cell-tag, +.tags-input input, +.tags-input button { + color: #303030; + background-color: #ffffff; + background-image: none; + border: 1px solid #303030; + border-radius: 1px; + box-shadow: none; + width: inherit; + font-size: inherit; + height: 22px; + line-height: 22px; +} +#notebook-container > div.cell.code_cell.rendered.selected > div.input > div.inner_cell > div.ctb_hideshow.ctb_show > div > div > button, +#notebook-container > div.input > div.inner_cell > div.ctb_hideshow.ctb_show > div > div > button { + font-size: 10pt; + color: #303030; + background-color: #ffffff; + background-image: none; + border: 1px solid #303030; + border-radius: 1px; + box-shadow: none; + width: inherit; + font-size: inherit; + height: 22px; + line-height: 22px; +} +div#pager #pager-contents { + background: #ffffff !important; + background-color: #ffffff !important; +} +div#pager pre { + color: #303030 !important; + background: #ededed !important; + background-color: #ededed !important; + padding: 0.4em; +} +div#pager .ui-resizable-handle { + top: 0px; + height: 8px; + background: #ff7823 !important; + border-top: 1px solid #ff7823; + border-bottom: 1px solid #ff7823; +} +div.CodeMirror, +div.CodeMirror pre { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + color: #303030; +} +div.CodeMirror-lines { + padding-bottom: .9em; + padding-left: .5em; + padding-right: 1.5em; + padding-top: .7em; +} +span.ansiblack, +.ansi-black-fg { + color: #e22978; +} +span.ansiblue, +.ansi-blue-fg, +.ansi-blue-intense-fg { + color: #009e07; +} +span.ansigray, +.ansi-gray-fg, +.ansi-gray-intense-fg { + color: #ff8132; +} +span.ansigreen, +.ansi-green-fg { + color: #333333; +} +.ansi-green-intense-fg { + color: #ff8132; +} +span.ansipurple, +.ansi-purple-fg, +.ansi-purple-intense-fg { + color: #653bc5; +} +span.ansicyan, +.ansi-cyan-fg, +.ansi-cyan-intense-fg { + color: #653bc5; +} +span.ansiyellow, +.ansi-yellow-fg, +.ansi-yellow-intense-fg { + color: #ff8132; +} +span.ansired, +.ansi-red-fg, +.ansi-red-intense-fg { + color: #de143d; +} +div.output-stderr { + background-color: #ebb5b7; +} +div.output-stderr pre { + color: #000000; +} +div.js-error { + color: #de143d; +} +.ipython_tooltip { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + border: 2px solid #dadada; + background: #eeeeee; + background-color: #eeeeee; + border-radius: 2px; + overflow-x: visible; + overflow-y: visible; + box-shadow: none; + position: absolute; + z-index: 1000; +} +.ipython_tooltip .tooltiptext pre { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + background: #eeeeee; + background-color: #eeeeee; + color: #303030; + overflow-x: visible; + overflow-y: visible; + max-width: 900px; +} +div#tooltip.ipython_tooltip { + overflow-x: wrap; + overflow-y: visible; + max-width: 800px; +} +div.tooltiptext.bigtooltip { + overflow-x: visible; + overflow-y: scroll; + height: 400px; + max-width: 800px; +} +.cm-s-ipython.CodeMirror { + font-family: monospace, monospace; + font-size: 11pt; + background: #ededed; + color: #303030; + border-radius: 2px; + font-style: normal; + font-weight: normal; +} +.cm-s-ipython div.CodeMirror-selected { + background: #e0e1e3; +} +.CodeMirror-gutters { + border: none; + border-right: 1px solid #e0e1e3 !important; + background-color: #e0e1e3 !important; + background: #e0e1e3 !important; + border-radius: 0px; + white-space: nowrap; +} +.cm-s-ipython .CodeMirror-gutters { + background: #e0e1e3; + border: none; + border-radius: 0px; + width: 36px; +} +.cm-s-ipython .CodeMirror-linenumber { + color: #828892; +} +.CodeMirror-sizer { + margin-left: 40px; +} +.CodeMirror-linenumber, +div.CodeMirror-linenumber, +.CodeMirror-gutter.CodeMirror-linenumberdiv.CodeMirror-gutter.CodeMirror-linenumber { + padding-right: 1px; + margin-left: 0px; + margin: 0px; + width: 26px !important; + padding: 0px; + text-align: right; +} +.CodeMirror-linenumber { + color: #828892; +} +.cm-s-ipython .CodeMirror-cursor { + border-left: 2px solid #ff711a !important; +} +.cm-s-ipython span.cm-comment { + color: #8d8d8d; + font-style: italic; +} +.cm-s-ipython span.cm-atom { + color: #055be0; +} +.cm-s-ipython span.cm-number { + color: #ff8132; +} +.cm-s-ipython span.cm-property { + color: #303030; +} +.cm-s-ipython span.cm-attribute { + color: #303030; +} +.cm-s-ipython span.cm-keyword { + color: #713bc5; + font-weight: normal; +} +.cm-s-ipython span.cm-string { + color: #009e07; +} +.cm-s-ipython span.cm-meta { + color: #aa22ff; +} +.cm-s-ipython span.cm-operator { + color: #055be0; +} +.cm-s-ipython span.cm-builtin { + color: #e22978; +} +.cm-s-ipython span.cm-variable { + color: #303030; +} +.cm-s-ipython span.cm-variable-2 { + color: #de143d; +} +.cm-s-ipython span.cm-variable-3 { + color: #aa22ff; +} +.cm-s-ipython span.cm-def { + color: #e22978; + font-weight: normal; +} +.cm-s-ipython span.cm-error { + background: rgba(191,97,106,.40); +} +.cm-s-ipython span.cm-tag { + color: #e22978; +} +.cm-s-ipython span.cm-link { + color: #ef5c00; +} +.cm-s-ipython span.cm-storage { + color: #055be0; +} +.cm-s-ipython span.cm-entity { + color: #e22978; +} +.cm-s-ipython span.cm-quote { + color: #009e07; +} +div.CodeMirror span.CodeMirror-matchingbracket { + color: #1c1c1c; + background-color: rgba(30,112,199,.30); +} +div.CodeMirror span.CodeMirror-nonmatchingbracket { + color: #1c1c1c; + background: rgba(191,97,106,.40) !important; +} +.cm-header-1 { + font-size: 215%; +} +.cm-header-2 { + font-size: 180%; +} +.cm-header-3 { + font-size: 150%; +} +.cm-header-4 { + font-size: 120%; +} +.cm-header-5 { + font-size: 100%; +} +.cm-s-default .cm-hr { + color: #055be0; +} +div.cell.text_cell .cm-s-default .cm-header { + font-family: sans-serif; + font-weight: normal; + color: #126dce; + margin-top: 0.3em !important; + margin-bottom: 0.3em !important; +} +div.cell.text_cell .cm-s-default span.cm-variable-2 { + color: #353535; +} +div.cell.text_cell .cm-s-default span.cm-variable-3 { + color: #aa22ff; +} +.cm-s-default span.cm-comment { + color: #8d8d8d; +} +.cm-s-default .cm-tag { + color: #009fb7; +} +.cm-s-default .cm-builtin { + color: #e22978; +} +.cm-s-default .cm-string { + color: #009e07; +} +.cm-s-default .cm-keyword { + color: #713bc5; +} +.cm-s-default .cm-number { + color: #ff8132; +} +.cm-s-default .cm-error { + color: #055be0; +} +.cm-s-default .cm-link { + color: #ef5c00; +} +.cm-s-default .cm-atom { + color: #ff8132; +} +.cm-s-default .cm-def { + color: #e22978; +} +.CodeMirror-cursor { + border-left: 2px solid #ff711a !important; + border-right: none; + width: 0; +} +.cm-s-default div.CodeMirror-selected { + background: #e0e1e3; +} +.cm-s-default .cm-selected { + background: #e0e1e3; +} +.MathJax_Display, +.MathJax { + border: 0 !important; + font-size: 100% !important; + text-align: center !important; + margin: 0em !important; + line-height: 2.25 !important; +} +.MathJax:focus, +body :focus .MathJax { + display: inline-block !important; +} +.MathJax:focus, +body :focus .MathJax { + display: inline-block !important; +} +.completions { + position: absolute; + z-index: 110; + overflow: hidden; + border: medium solid rgba(240,147,43,.50); + box-shadow: none; + line-height: 1; +} +.completions select { + background: #ededed; + background-color: #ededed; + outline: none; + border: none; + padding: 0px; + margin: 0px; + margin-left: 2px; + overflow: auto; + font-family: monospace, monospace; + font-size: 11pt; + color: #303030; + width: auto; +} +div#maintoolbar { + display: none !important; +} +#header-container { + display: none !important; +} + + + \ No newline at end of file From 8e5431de2ea748b9725ecd008395d4f386859b60 Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Thu, 5 Apr 2018 15:45:16 -0400 Subject: [PATCH 04/18] Added TF, Keras, and upgraded iventure --- images/sd2e/Dockerfile | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/images/sd2e/Dockerfile b/images/sd2e/Dockerfile index 63e0ce7..fba08fd 100644 --- a/images/sd2e/Dockerfile +++ b/images/sd2e/Dockerfile @@ -1,7 +1,7 @@ #Image: sd2e/jupyteruser-sd2e -#Version: 0.3.1 +#Version: 0.3.2 -FROM sd2e/jupyteruser-base:0.1.1 +FROM sd2e/jupyteruser-base:0.2.0 # Image release USER root @@ -40,7 +40,7 @@ bash -c "export MPLBACKEND=Agg && source activate python2 && pip2 install git+ht pip2 install git+https://github.com/probcomp/cgpm.git@v0.1.2 && \ pip2 install git+https://github.com/probcomp/crosscat.git@v0.1.56.1 && \ pip2 install git+https://github.com/probcomp/bayeslite.git@v0.3.2 && \ - pip2 install git+https://github.com/probcomp/iventure.git@v0.2.2" && \ + pip2 install git+https://github.com/probcomp/iventure.git@v0.2.3" && \ # Clean cache docker-clean @@ -112,6 +112,22 @@ RUN apt-get install -y cmake graphviz && \ conda install --quiet --yes -n python2 python-graphviz && \ docker-clean +########################################## +# Support Tensorflow and Keras +########################################## +USER root +LABEL "comment"="Support Tensorflow and Keras" "issue"="SD2E/jupyteruser-sd2e/issues/13" +RUN bash -c "source activate python2 && \ +pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.6.0-cp27-none-linux_x86_64.whl && \ +pip install keras" && \ +bash -c "source activate root && \ +pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.6.0-cp36-cp36m-linux_x86_64.whl && \ +pip install keras" && \ + docker-clean +RUN cd examples && \ + git clone https://github.com/leriomaggio/deep-learning-keras-tensorflow.git && \ + cd deep-learning-keras-tensorflow && rm -rf .git + ############################################### # Permissions ############################################### From df4c41ab3660f80050b69929cf470d77e0cb25ca Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Thu, 5 Apr 2018 21:35:35 -0500 Subject: [PATCH 05/18] Fixed Makefile for osx, add advanced jupyter example, fixed warning from comments in dockerfiles --- Makefile | 145 ++++---- images/base/Dockerfile | 35 +- images/base/examples/Advanced Jupyter.ipynb | 376 ++++++++++++++++++++ images/sd2e/Dockerfile | 18 +- 4 files changed, 479 insertions(+), 95 deletions(-) create mode 100644 images/base/examples/Advanced Jupyter.ipynb diff --git a/Makefile b/Makefile index 9780031..e441af1 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ -.ONESHELL: .PHONY: build test docker help stage release clean ifndef VERBOSE .SILENT: build test docker help stage release clean @@ -9,15 +8,15 @@ all: help .PHONY: help help: - echo "\nUsage: make [action] [target]\n" - echo "Actions:" - echo " - build - build docker images locally" - echo " - test - test images locally" - echo " - stage - push images to staging environment" - echo " - release - push images to production environment\n" - echo "Targets:" - echo " - base - Recipe in images/base" - echo " - sd2e - Recipe in images/sd2e which is where all community software should belong" + echo "\nUsage: make [action] [target]\n" && \ + echo "Actions:" && \ + echo " - build - build docker images locally" && \ + echo " - test - test images locally" && \ + echo " - stage - push images to staging environment" && \ + echo " - release - push images to production environment\n" && \ + echo "Targets:" && \ + echo " - base - Recipe in images/base" && \ + echo " - sd2e - Recipe in images/sd2e which is where all community software should belong" && \ echo " - singularity - Image for running on TACC HPC\n" # Make sure image targets are not used as make targets @@ -25,82 +24,82 @@ help: @: docker: - docker info > /dev/null 2> /dev/null - if [ ! $$? -eq 0 ]; then - echo "\n[ERROR] Could not communicate with docker daemon. You may need to run with sudo.\n" - exit 1 + docker info &> /dev/null && \ + if [ ! $$? -eq 0 ]; then \ + echo "\n[ERROR] Could not communicate with docker daemon. You may need to run with sudo.\n"; \ + exit 1; \ fi build: docker - TARGET=$(filter-out $@,$(MAKECMDGOALS)) - case $${TARGET} in - base) - build/build_jupyteruser.sh build images/base - ;; - sd2e) - build/build_jupyteruser.sh build images/sd2e - ;; - singularity) - build/build_jupyteruser.sh build images/singularity - ;; - *) - $(MAKE) help - ;; + TARGET=$(filter-out $@,$(MAKECMDGOALS)) && \ + case $${TARGET} in \ + base) \ + build/build_jupyteruser.sh build images/base; \ + ;; \ + sd2e) \ + build/build_jupyteruser.sh build images/sd2e; \ + ;; \ + singularity) \ + build/build_jupyteruser.sh build images/singularity; \ + ;; \ + *) \ + $(MAKE) help; \ + ;; \ esac test: docker - TARGET=$(filter-out $@,$(MAKECMDGOALS)) - case $$TARGET in - base) - build/build_jupyteruser.sh test images/base - ;; - sd2e) - build/build_jupyteruser.sh test images/sd2e - ;; - singularity) - build/build_jupyteruser.sh test images/singularity - ;; - *) - $(MAKE) help - ;; + TARGET=$(filter-out $@,$(MAKECMDGOALS)) && \ + case $$TARGET in \ + base) \ + build/build_jupyteruser.sh test images/base; \ + ;; \ + sd2e) \ + build/build_jupyteruser.sh test images/sd2e; \ + ;; \ + singularity) \ + build/build_jupyteruser.sh test images/singularity; \ + ;; \ + *) \ + $(MAKE) help; \ + ;; \ esac stage: docker - TARGET=$(filter-out $@,$(MAKECMDGOALS)) - case $$TARGET in - base) - build/build_jupyteruser.sh stage images/base - ;; - sd2e) - build/build_jupyteruser.sh stage images/sd2e - ;; - singularity) - build/build_jupyteruser.sh stage images/singularity - ;; - *) - $(MAKE) help - ;; + TARGET=$(filter-out $@,$(MAKECMDGOALS)) && \ + case $$TARGET in \ + base) \ + build/build_jupyteruser.sh stage images/base; \ + ;; \ + sd2e) \ + build/build_jupyteruser.sh stage images/sd2e; \ + ;; \ + singularity) \ + build/build_jupyteruser.sh stage images/singularity; \ + ;; \ + *) \ + $(MAKE) help; \ + ;; \ esac release: docker - TARGET=$(filter-out $@,$(MAKECMDGOALS)) - case $$TARGET in - base) - build/build_jupyteruser.sh release images/base - ;; - sd2e) - build/build_jupyteruser.sh release images/sd2e - ;; - singularity) - build/build_jupyteruser.sh release images/singularity - ;; - *) - $(MAKE) help - ;; + TARGET=$(filter-out $@,$(MAKECMDGOALS)) && \ + case $$TARGET in \ + base) \ + build/build_jupyteruser.sh release images/base; \ + ;; \ + sd2e) \ + build/build_jupyteruser.sh release images/sd2e; \ + ;; \ + singularity) \ + build/build_jupyteruser.sh release images/singularity; \ + ;; \ + *) \ + $(MAKE) help; \ + ;; \ esac clean: docker - TARGET=$(filter-out $@,$(MAKECMDGOALS)) - build/build_jupyteruser.sh clean images/singularity - build/build_jupyteruser.sh clean images/sd2e + TARGET=$(filter-out $@,$(MAKECMDGOALS)) && \ + build/build_jupyteruser.sh clean images/singularity && \ + build/build_jupyteruser.sh clean images/sd2e && \ build/build_jupyteruser.sh clean images/base diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 22ccc4d..0882552 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -13,20 +13,21 @@ USER root ARG image_version=development ENV NB_GID=G-819382 RUN echo "${image_version}" > /etc/sd2e_jupyteruser-base-release && \ -chmod a+r /etc/sd2e_jupyteruser-base-release && \ + chmod a+r /etc/sd2e_jupyteruser-base-release # Make sure Jupyter group == SD2E-Community == 819382 -groupadd --gid 819382 $NB_GID && \ -usermod -a -G $NB_GID jupyter && \ -usermod -g $NB_GID jupyter && \ +RUN groupadd --gid 819382 $NB_GID && \ + usermod -a -G $NB_GID jupyter && \ + usermod -g $NB_GID jupyter # Jupyterhub correctly sets JUPYTERHUB_USER -echo 'PS1="$JUPYTERHUB_USER@\h:\w\$ "' >> /home/jupyter/.bashrc && \ +RUN echo 'PS1="$JUPYTERHUB_USER@\h:\w\$ "' >> /home/jupyter/.bashrc # allow users to add kernels -chmod 777 /opt/conda/share/jupyter/kernels && \ +RUN chmod 777 /opt/conda/share/jupyter/kernels # Environment variables -echo "export JPY_USER=\$JUPYTERHUB_USER\n\ +RUN echo "export JPY_USER=\$JUPYTERHUB_USER\n\ export WORK=/home/jupyter/tacc-work\n\ export SD2_DATA=/home/jupyter/sd2e-community\n\ export PYTHONUSERBASE=/home/jupyter/tacc-work/jupyter_packages\n" >> /home/jupyter/.bashrc + # Add activation sripts ADD src/activate-python.sh /opt/conda/etc/conda/activate.d/activate-python.sh ADD src/activate-python.sh /opt/conda/envs/python2/etc/conda/activate.d/activate-python.sh @@ -42,24 +43,28 @@ ADD examples examples ############################################### # Bioconductor and BioPython -RUN conda update --all && conda install -vv --yes --debug -c bioconda bioconductor-biocinstaller && \ +RUN conda update --all && conda install --yes -c bioconda bioconductor-biocinstaller && \ conda install --yes --quiet biopython && \ conda install --yes --quiet -n python2 biopython && \ + docker-clean # Enable sd2nb sharing service -cd /root && \ +RUN cd /root && \ git clone https://github.com/SD2E/sd2nb-app.git && \ ( cd sd2nb-app && make && make install ) && \ rm -rf sd2nb-app && \ -# Enable sd2e-jupyter -cd /root && \ + docker-clean +# Enable sd2e-jupyter +RUN cd /root && \ git clone https://github.com/SD2E/sd2e-jupyter-ascending.git && \ ( cd sd2e-jupyter-ascending && make && make install ) && \ rm -rf sd2e-jupyter-ascending && \ + docker-clean # Ubuntu Packages -apt-get update && \ - # jq and bsdmainutils->column is required for abaco CLI +# - jq - required for abaco CLI +# - bsdmainutils->column - required for abaco CLI \ +#apt-get install -y tree less openjdk-8-jre ca-certificates-java && \ +RUN apt-get update && \ apt-get install -y tree less jq rsync bsdmainutils && \ - #apt-get install -y tree less openjdk-8-jre ca-certificates-java && \ docker-clean # Replace stock Agave CLI with SD2E-customized tooling ADD src/configuration.rc configuration.rc @@ -69,13 +74,13 @@ RUN git clone https://github.com/SD2E/sd2e-cli.git && \ make install && rm -rf /opt/cli && rm -rf $HOME/sd2e-cli && \ mv /home/jupyter/sd2e-cloud-cli /opt/cli && \ chmod -R a+rX /opt/cli && chmod -R a+x /opt/cli/bin && \ + docker-clean # Spark 2.2.1 and pyspark #cd /usr/local && \ # curl http://apache.claz.org/spark/spark-2.2.1/spark-2.2.1-bin-hadoop2.7.tgz | tar -xzf - && \ # mv spark-2.2.1-bin-hadoop2.7 spark && \ # conda install --yes pyspark && \ # conda install -n python2 --yes pyspark && \ -docker-clean #ENV SPARK_HOME=/usr/local/spark ############################################### diff --git a/images/base/examples/Advanced Jupyter.ipynb b/images/base/examples/Advanced Jupyter.ipynb new file mode 100644 index 0000000..7760e22 --- /dev/null +++ b/images/base/examples/Advanced Jupyter.ipynb @@ -0,0 +1,376 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Advanced Jupyter\n", + "\n", + "If you have ever felt constrained by our choices of kernels and environments included in the SD2E Jupyter server, this notebook will demonstrate how to:\n", + "\n", + "- Create your own conda environment\n", + "- Create your own Jupyter Kernel\n", + "- Use your new Jupyter Kernel\n", + "- Clean your local environment\n", + "\n", + "We have taken the time to remove most of the hurdles to this process, but please submit an issue to\n", + "\n", + "https://github.com/SD2E/jupyteruser-sd2e/issues\n", + "\n", + "if you run into any walls.\n", + "\n", + "## Creating a new conda envrionment\n", + "\n", + "We are utilizing the [Anaconda python distribution](https://www.anaconda.com/what-is-anaconda/) for SD2E since it \n", + "\n", + "- ships with the Intel MKL\n", + "- manages python and system packages\n", + "- allows and manages encapsulated environments\n", + "\n", + "So we can support as many development environments as possible. If you would like a brand new environment, but do not want it to be incorporated into the base image (what you are running right now), you can create a local environment that conda will manage and persist between server restarts.\n", + "\n", + "First, lets see what `conda` environments are currently available:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# conda environments:\n", + "#\n", + "base * /opt/conda\n", + "python2 /opt/conda/envs/python2\n", + "\n" + ] + } + ], + "source": [ + "conda env list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you have not modified your environment, you should see two environments:\n", + "\n", + "- **base** - (python3) activated with `source activate root`\n", + "- **python2** - activated with `source activate python2`\n", + "\n", + "I am developing a new analysis that is dependant on scipy 0.16.0, which is older than (and conflicts with) the version of scipy in the main python2 environment. Creating a brand new environment will be the easiest path forward for my development, so lets create one called \"tabsAreGreat\" with [`conda create`](https://conda.io/docs/commands/conda-create.html).\n", + "\n", + "To make your life a little easier, we created a `LOCAL_ENVS` variable for you to prefix your environment with, and added it to the path that conda crawls when search for environments." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Solving environment: done\n", + "\n", + "## Package Plan ##\n", + "\n", + " environment location: /home/jupyter/tacc-work/jupyter_packages/envs/tabsAreGreat\n", + "\n", + " added / updated specs: \n", + " - ipykernel\n", + " - python=2.7\n", + " - scipy==0.16.0\n", + "\n", + "\n", + "The following packages will be downloaded:\n", + "\n", + " package | build\n", + " ---------------------------|-----------------\n", + " scipy-0.16.0 | np110py27_1 23.9 MB anaconda\n", + " scandir-1.7 | py27h14c3975_0 27 KB anaconda\n", + " libgfortran-3.0.0 | 1 281 KB anaconda\n", + " wheel-0.31.0 | py27_0 61 KB anaconda\n", + " openblas-0.2.14 | 4 3.6 MB anaconda\n", + " pyzmq-17.0.0 | py27h14c3975_0 440 KB anaconda\n", + " python-2.7.14 | h1571d57_31 11.8 MB anaconda\n", + " tornado-5.0.1 | py27_1 617 KB anaconda\n", + " python-dateutil-2.7.2 | py27_0 254 KB anaconda\n", + " pip-9.0.3 | py27_0 2.4 MB anaconda\n", + " pexpect-4.4.0 | py27_0 70 KB anaconda\n", + " readline-7.0 | ha6073c6_4 1.1 MB anaconda\n", + " ipykernel-4.8.2 | py27_0 143 KB anaconda\n", + " setuptools-39.0.1 | py27_0 582 KB anaconda\n", + " numpy-1.10.2 | py27_0 5.9 MB anaconda\n", + " ipython-5.6.0 | py27_0 1020 KB anaconda\n", + " jupyter_client-5.2.3 | py27_0 122 KB anaconda\n", + " ------------------------------------------------------------\n", + " Total: 52.2 MB\n", + "\n", + "The following NEW packages will be INSTALLED:\n", + "\n", + " backports: 1.0-py27h63c9359_1 anaconda\n", + " backports.shutil_get_terminal_size: 1.0.0-py27h5bc021e_2 anaconda\n", + " backports_abc: 0.5-py27h7b3c97b_0 anaconda\n", + " ca-certificates: 2018.03.07-0 anaconda\n", + " certifi: 2018.1.18-py27_0 anaconda\n", + " decorator: 4.2.1-py27_0 anaconda\n", + " enum34: 1.1.6-py27h99a27e9_1 anaconda\n", + " futures: 3.2.0-py27h7b459c0_0 anaconda\n", + " ipykernel: 4.8.2-py27_0 anaconda\n", + " ipython: 5.6.0-py27_0 anaconda\n", + " ipython_genutils: 0.2.0-py27h89fb69b_0 anaconda\n", + " jupyter_client: 5.2.3-py27_0 anaconda\n", + " jupyter_core: 4.4.0-py27h345911c_0 anaconda\n", + " libedit: 3.1-heed3624_0 anaconda\n", + " libffi: 3.2.1-hd88cf55_4 anaconda\n", + " libgcc-ng: 7.2.0-hdf63c60_3 anaconda\n", + " libgfortran: 3.0.0-1 anaconda\n", + " libsodium: 1.0.16-h1bed415_0 anaconda\n", + " libstdcxx-ng: 7.2.0-hdf63c60_3 anaconda\n", + " ncurses: 6.0-h9df7e31_2 anaconda\n", + " numpy: 1.10.2-py27_0 anaconda\n", + " openblas: 0.2.14-4 anaconda\n", + " openssl: 1.0.2o-h20670df_0 anaconda\n", + " pathlib2: 2.3.0-py27h6e9d198_0 anaconda\n", + " pexpect: 4.4.0-py27_0 anaconda\n", + " pickleshare: 0.7.4-py27h09770e1_0 anaconda\n", + " pip: 9.0.3-py27_0 anaconda\n", + " prompt_toolkit: 1.0.15-py27h1b593e1_0 anaconda\n", + " ptyprocess: 0.5.2-py27h4ccb14c_0 anaconda\n", + " pygments: 2.2.0-py27h4a8b6f5_0 anaconda\n", + " python: 2.7.14-h1571d57_31 anaconda\n", + " python-dateutil: 2.7.2-py27_0 anaconda\n", + " pyzmq: 17.0.0-py27h14c3975_0 anaconda\n", + " readline: 7.0-ha6073c6_4 anaconda\n", + " scandir: 1.7-py27h14c3975_0 anaconda\n", + " scipy: 0.16.0-np110py27_1 anaconda\n", + " setuptools: 39.0.1-py27_0 anaconda\n", + " simplegeneric: 0.8.1-py27_2 anaconda\n", + " singledispatch: 3.4.0.3-py27h9bcb476_0 anaconda\n", + " six: 1.11.0-py27h5f960f1_1 anaconda\n", + " sqlite: 3.22.0-h1bed415_0 anaconda\n", + " tk: 8.6.7-hc745277_3 anaconda\n", + " tornado: 5.0.1-py27_1 anaconda\n", + " traitlets: 4.3.2-py27hd6ce930_0 anaconda\n", + " wcwidth: 0.1.7-py27h9e3e1ab_0 anaconda\n", + " wheel: 0.31.0-py27_0 anaconda\n", + " zeromq: 4.2.3-h439df22_3 anaconda\n", + " zlib: 1.2.11-ha838bed_2 anaconda\n", + "\n", + "\n", + "Downloading and Extracting Packages\n", + "scipy 0.16.0: ########################################################## | 100% \n", + "scandir 1.7: ########################################################### | 100% \n", + "libgfortran 3.0.0: ##################################################### | 100% \n", + "wheel 0.31.0: ########################################################## | 100% \n", + "openblas 0.2.14: ####################################################### | 100% \n", + "pyzmq 17.0.0: ########################################################## | 100% \n", + "python 2.7.14: ######################################################### | 100% \n", + "tornado 5.0.1: ######################################################### | 100% \n", + "python-dateutil 2.7.2: ################################################# | 100% \n", + "pip 9.0.3: ############################################################# | 100% \n", + "pexpect 4.4.0: ######################################################### | 100% \n", + "readline 7.0: ########################################################## | 100% \n", + "ipykernel 4.8.2: ####################################################### | 100% \n", + "setuptools 39.0.1: ##################################################### | 100% \n", + "numpy 1.10.2: ########################################################## | 100% \n", + "ipython 5.6.0: ######################################################### | 100% \n", + "jupyter_client 5.2.3: ################################################## | 100% \n", + "Preparing transaction: done\n", + "Verifying transaction: done\n", + "Executing transaction: done\n", + "#\n", + "# To activate this environment, use:\n", + "# > source activate /home/jupyter/tacc-work/jupyter_packages/envs/tabsAreGreat\n", + "#\n", + "# To deactivate an active environment, use:\n", + "# > source deactivate\n", + "#\n", + "\n" + ] + } + ], + "source": [ + "conda create -y -p $LOCAL_ENVS/tabsAreGreat python=2.7 ipykernel 'scipy==0.16.0'\n", + "\n", + "# -y - respond yes to all questions\n", + "# -p PATH - prefix/name\n", + "# python=2.7 - python2 environment\n", + "# ipykernel - required to make a kernel file later\n", + "# 'scipy==0.16.0' - scipy requirement" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You should now be able to list this new environment" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# conda environments:\n", + "#\n", + "tabsAreGreat /home/jupyter/tacc-work/jupyter_packages/envs/tabsAreGreat\n", + "base * /opt/conda\n", + "python2 /opt/conda/envs/python2\n", + "\n" + ] + } + ], + "source": [ + "conda env list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can now see that this new \"tabsAreGreat\" environment was created in your `tacc-work` directory, so it will persist between reboots, and you will be able to utilize it with\n", + "```\n", + "source activate tabsAreGreat\n", + "```\n", + "until your delete it.\n", + "\n", + "## Creating new Jupyter kernels\n", + "\n", + "While you now have a brand new conda environment, you can only interact with it over the command line.\n", + "\n", + "\"original\n", + "\n", + "You need to first create a new kernel spec to use it in a notebook. Once again, we created a convenience variable called `JUPYTER_WORK` which the Jupyter server automatically polls. To create it, invoke the python in your new environment\n", + "```\n", + "$LOCAL_ENVS/tabsAreGreat\n", + "```\n", + "with the following arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installed kernelspec tabsAreGreat in /home/jupyter/tacc-work/jupyter_packages/share/jupyter/kernels/tabsaregreat\n" + ] + } + ], + "source": [ + "$LOCAL_ENVS/tabsAreGreat/bin/python -m ipykernel install \\\n", + " --prefix $JUPYTER_WORK \\\n", + " --name tabsAreGreat \\\n", + " --display-name \"tabs are great\"\n", + "\n", + "# -m ipykernel install - install a jupyter kernel\n", + "# --prefix $JUPYTER_WORK - kernel installation path\n", + "# --name tabsAreGreat - name of the kernel (no spaces)\n", + "# --display-name \"tabs are great\" - the name that will display in the drop-down list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can see that once again, this was installed to your `tacc-work` directory, so it will persist until you delete it.\n", + "\n", + "## Use your new kernel\n", + "\n", + "To use it (as in right now) just refresh the main Jupyter tab and click the \"New\" drop-down tab\n", + "\n", + "\"new\n", + "\n", + "and you should see a new option called \"tabs are great\".\n", + "\n", + "## Clean your environment\n", + "\n", + "When you want to de-clutter your development environment and remove both this kernel and environment, you just have to delete two directories:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Conda environment\n", + "rm -rf $LOCAL_ENVS/tabsAreGreat\n", + "# Jupyter kernel\n", + "rm -rf $JUPYTER_WORK/share/jupyter/kernels/tabsaregreat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All traces of this environment should now be gone." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# conda environments:\n", + "#\n", + "base * /opt/conda\n", + "python2 /opt/conda/envs/python2\n", + "\n" + ] + } + ], + "source": [ + "conda env list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extra functionality\n", + "\n", + "If you think we should handle additional functionality in the SD2E Jupyter environment, please submit a feature request to\n", + "\n", + "https://github.com/SD2E/jupyteruser-sd2e/issues\n", + "\n", + "Thanks and happy hacking!\n", + "\n", + "-- TACC" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Bash", + "language": "bash", + "name": "bash" + }, + "language_info": { + "codemirror_mode": "shell", + "file_extension": ".sh", + "mimetype": "text/x-sh", + "name": "bash" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/images/sd2e/Dockerfile b/images/sd2e/Dockerfile index fba08fd..c0e2914 100644 --- a/images/sd2e/Dockerfile +++ b/images/sd2e/Dockerfile @@ -26,24 +26,27 @@ USER root LABEL "comment"="Support for Open Probabilistic Programming Stack" "issue"="SD2E/jupyteruser-sd2e/issues/2" # Libraries RUN apt-get update && \ - apt-get install -y libboost-all-dev libgsl0-dev ccache && \ - apt-get clean && \ + apt-get install -y libboost-all-dev libgsl0-dev ccache && \ + apt-get clean && \ + docker-clean # Install dependencies and remove anaconda toolchain -conda install -n python2 --quiet --yes flask jsonschema patsy requests six && \ +RUN conda install -n python2 --quiet --yes flask jsonschema patsy requests six && \ conda install -n python2 -c conda-forge apsw && \ conda uninstall -n python2 --yes \ binutils_impl_linux-64 binutils_linux-64 \ gcc_impl_linux-64 gcc_linux-64 \ gxx_impl_linux-64 gxx_linux-64 && \ + docker-clean # Install probcomp software stack -bash -c "export MPLBACKEND=Agg && source activate python2 && pip2 install git+https://github.com/probcomp/Venturecxx@v0.5.1.1 && \ +RUN bash -c "export MPLBACKEND=Agg && source activate python2 && \ + pip2 install git+https://github.com/probcomp/Venturecxx@v0.5.1.1 && \ pip2 install git+https://github.com/probcomp/cgpm.git@v0.1.2 && \ pip2 install git+https://github.com/probcomp/crosscat.git@v0.1.56.1 && \ pip2 install git+https://github.com/probcomp/bayeslite.git@v0.3.2 && \ pip2 install git+https://github.com/probcomp/iventure.git@v0.2.3" && \ -# Clean cache -docker-clean - + rm -rf .ccache && \ + docker-clean +# Grab latest example notebooks RUN mkdir -p /home/jupyter/examples/probcomp && \ cd /home/jupyter/examples/probcomp && \ curl http://probcomp-workshop-materials.s3.amazonaws.com/latest.tgz | tar -xzf - @@ -63,6 +66,7 @@ RUN mkdir /opt/common-lisp && \ git clone git://git.code.sf.net/p/sbcl/sbcl && \ cd sbcl && \ git checkout tags/sbcl-1.4.3 && \ + export SBCL_MAKE_JOBS="-j $(nproc --all)" && \ sh make.sh && rm -rf .git && \ cd /opt/common-lisp/sbcl && \ sh install.sh && \ From 6acc9c1b5542f17f8550cd8f9092716a25dabc21 Mon Sep 17 00:00:00 2001 From: Matt Vaughn Date: Thu, 5 Apr 2018 21:46:18 -0500 Subject: [PATCH 06/18] WIP --- images/sd2e/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/sd2e/Dockerfile b/images/sd2e/Dockerfile index e722fca..78a2230 100644 --- a/images/sd2e/Dockerfile +++ b/images/sd2e/Dockerfile @@ -1,7 +1,7 @@ #Image: sd2e/jupyteruser-sd2e #Version: 0.3.2 -FROM sd2e/jupyteruser-base:0.2.0 +FROM sd2e/jupyteruser-base:0.2.1 # Image release USER root From 6bafbcc796b5a491ae2c1b2e58bdc029ec1db9cb Mon Sep 17 00:00:00 2001 From: Matt Vaughn Date: Thu, 5 Apr 2018 23:51:16 -0500 Subject: [PATCH 07/18] Merged in Greg's fixes to Makefile and updates --- Makefile | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 111782f..e789ece 100644 --- a/Makefile +++ b/Makefile @@ -8,17 +8,7 @@ all: help .PHONY: help help: -<<<<<<< HEAD - echo "\nUsage: make [action] [target]\n" - echo "Actions:" - echo " - build - build docker images locally" - echo " - test - test images locally" - echo " - stage - push images to staging environment" - echo " - release - push images to production environment\n" - echo "Targets:" - echo " - base - Recipe in images/base" - echo " - sd2e - Recipe in images/custom which is where all community software should belong" -======= + echo "\nUsage: make [action] [target]\n" && \ echo "Actions:" && \ echo " - build - build docker images locally" && \ @@ -28,7 +18,6 @@ help: echo "Targets:" && \ echo " - base - Recipe in images/base" && \ echo " - sd2e - Recipe in images/sd2e which is where all community software should belong" && \ ->>>>>>> development echo " - singularity - Image for running on TACC HPC\n" # Make sure image targets are not used as make targets From faa3eb2f00f701b96e2f590133e16168cb31d967 Mon Sep 17 00:00:00 2001 From: Matt Vaughn Date: Fri, 6 Apr 2018 06:47:56 -0500 Subject: [PATCH 08/18] Merged --- images/base/Dockerfile | 2 +- images/base/src/add-sd2e-groups.sh | 2 +- images/sd2e/Dockerfile | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 43dfa59..1fedb8d 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -23,7 +23,7 @@ RUN echo "${image_version}" > /etc/sd2e_jupyteruser-base-release && \ chmod a+r /etc/sd2e_jupyteruser-base-release RUN groupadd --gid ${NB_GID} ${NB_GROUP} && \ usermod -a -G ${NB_GROUP} jupyter && \ - usermod -g ${NB_GROUP} jupyter && + usermod -g ${NB_GROUP} jupyter # Jupyterhub correctly sets JUPYTERHUB_USER RUN echo 'PS1="$JUPYTERHUB_USER@\h:\w\$ "' >> /home/jupyter/.bashrc diff --git a/images/base/src/add-sd2e-groups.sh b/images/base/src/add-sd2e-groups.sh index 85f492b..96a9278 100644 --- a/images/base/src/add-sd2e-groups.sh +++ b/images/base/src/add-sd2e-groups.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash while read -r nb_gid nb_group ; do echo "Adding ${nb_gid}:${nb_group}" diff --git a/images/sd2e/Dockerfile b/images/sd2e/Dockerfile index 16360a2..c08e73c 100644 --- a/images/sd2e/Dockerfile +++ b/images/sd2e/Dockerfile @@ -38,12 +38,9 @@ RUN conda install -n python2 --quiet --yes flask jsonschema patsy requests six & gxx_impl_linux-64 gxx_linux-64 && \ docker-clean # Install probcomp software stack -<<<<<<< HEAD -bash -c "export MPLBACKEND=Agg && source activate python2 && pip2 install git+https://github.com/probcomp/Venturecxx@v0.5.1.1 && \ -======= + RUN bash -c "export MPLBACKEND=Agg && source activate python2 && \ pip2 install git+https://github.com/probcomp/Venturecxx@v0.5.1.1 && \ ->>>>>>> development pip2 install git+https://github.com/probcomp/cgpm.git@v0.1.2 && \ pip2 install git+https://github.com/probcomp/crosscat.git@v0.1.56.1 && \ pip2 install git+https://github.com/probcomp/bayeslite.git@v0.3.2 && \ From 2fda38ab2de75ed34f85bc05a0fce377ae7f9f15 Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Wed, 11 Apr 2018 12:52:13 -0400 Subject: [PATCH 09/18] First version started from ubuntu --- .bash_history | 40 ------ .docker/.buildNodeID | 1 - Makefile | 2 +- images/base/Dockerfile | 279 +++++++++++++++++++++++++++++------------ 4 files changed, 201 insertions(+), 121 deletions(-) delete mode 100644 .bash_history delete mode 100644 .docker/.buildNodeID diff --git a/.bash_history b/.bash_history deleted file mode 100644 index 2812e90..0000000 --- a/.bash_history +++ /dev/null @@ -1,40 +0,0 @@ -ls -make help -make build base -docker pull taccsciapps/jupyteruser-base:0.1.2 -make build base -docker run -it sd2e/jupyteruser-base:0.2.0 bash -pwd -uname -a -exit -make help -make build base -docker run -it sd2e/jupyteruser-base:0.2.0 bash -docker run -it taccsciapps/jupyteruser-base:0.1.2 bash -docker run -it taccsciapps/jupyteruser-base:0.1.2 bash -docker run -it sd2e/jupyteruser-base:0.2.0 bash -pwd -exit -ls -make -make build base -docker run -it sd2e/jupyteruser-base:0.2.0 bash -make help -make test sd2e -make stage base -make stage sd2e -make build sd2e -make build sd2e -docker images -docker images sd2e/* | head -make build sd2e -make build sd2e -make build sd2e -make build sd2e -make stage sd2e -make stage sd2e -make build sd2e -make build base -make build base -make build sd2e -exit diff --git a/.docker/.buildNodeID b/.docker/.buildNodeID deleted file mode 100644 index b209565..0000000 --- a/.docker/.buildNodeID +++ /dev/null @@ -1 +0,0 @@ -84b7e47442e586221cf746dcda767428ca76293f4cc69c2776025184242bbce3 \ No newline at end of file diff --git a/Makefile b/Makefile index e789ece..b6f3237 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ help: @: docker: - docker info &> /dev/null && \ + docker info 1> /dev/null 2> /dev/null && \ if [ ! $$? -eq 0 ]; then \ echo "\n[ERROR] Could not communicate with docker daemon. You may need to run with sudo.\n"; \ exit 1; \ diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 1fedb8d..74a11df 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -1,34 +1,85 @@ #Image: sd2e/jupyteruser-base -#Version: 0.2.1 +#Version: 0.2.2 -FROM taccsciapps/jupyteruser-base:0.1.2 -LABEL origin="https://bitbucket.org/gzynda/jupyter/src/40adbad7b10b34de715d5a86aec3fcf65e724b70/notebooks/base/jupyter-notebook/Dockerfile?at=CIC-425-image-redesign&fileviewer=file-view-default" - -############################################### +FROM ubuntu:xenial +LABEL maintainer="Greg Zynda " +################################################################### # Environment -############################################### +################################################################### +ENV DEBIAN_FRONTEND=noninteractive USER root - -# Image release +WORKDIR /root +# Image release in /etc ARG image_version=development +RUN echo "${image_version}" > /etc/sd2e_jupyteruser-base-release && \ + chmod a+r /etc/sd2e_jupyteruser-base-release +# Use IU ubuntu mirror +RUN sed -i "s~archive.ubuntu.com~ftp.ussg.iu.edu/linux~" /etc/apt/sources.list +# Add clean script +RUN echo "apt-get clean\n\ +[ -x \"$(command -v conda)\" ] && conda clean -tipsy\n\ +for dir in /tmp/* /var/tmp/* /home/jupyter/.ccache /home/jupyter/.cache/pip /root/* /root/\.* /var/lib/apt/lists/*; do\n\ + [ -e $dir ] && rm -rf $dir\n\ +done" > /usr/bin/docker-clean && chmod a+rx /usr/bin/docker-clean && \ +# Create Singularity Mounts +mkdir /scratch /work /home1 /gpfs /corral-repl /corral-tacc /data +# Expose notebook port +EXPOSE 8888 +################################################################### +# Dependencies +################################################################### +USER root +# Install dependencies +# - jq - required for abaco CLI +# - bsdmainutils->column - required for abaco CLI \ +RUN apt-get update && \ + apt-get install -yq --no-install-recommends \ + bzip2 unzip ca-certificates build-essential \ + emacs vim git wget ssh curl \ + tree less jq rsync bsdmainutils && \ + docker-clean +################################################################### +# Create jupyter user +################################################################### +# the default $NB_USER is jovyan, but we want the default user to be jupyter +# - create jupyter early +# - run all user installation commands as jupyter +# - add jupyter user to special uid + +# Jupyter GIDs +ARG TACC_GID=65536 +ARG AGAVE_GID=G-816877 # Parameterize GID # 65536 is a dummy value since we now override user UID/GID at launch # using Docker nsmap. This should means it's only important for GIDs not # collide and that g+r(x) permissions are set where needed -ARG TACC_GID=65536 -ENV NB_GROUP=G-${TACC_GID} -ENV NB_GID=${TACC_GID} +ENV NB_USER=jupyter \ + NB_GID=${TACC_GID} \ + NB_GROUP=${TACC_GID} \ + SHELL=/bin/bashh +RUN groupadd --gid 816877 ${AGAVE_GID} && \ + useradd --uid 458981 --gid ${AGAVE_GID} -m --home /home/jupyter --shell /bin/bash $NB_USER && \ + groupadd --gid ${NB_GID} ${NB_GROUP} && \ + usermod -a -G ${NB_GROUP} jupyter +# Make primary group TACC_GID +RUN usermod -g ${NB_GROUP} jupyter -RUN echo "${image_version}" > /etc/sd2e_jupyteruser-base-release && \ - chmod a+r /etc/sd2e_jupyteruser-base-release -RUN groupadd --gid ${NB_GID} ${NB_GROUP} && \ - usermod -a -G ${NB_GROUP} jupyter && \ - usermod -g ${NB_GROUP} jupyter +################################################################### +# Modify jupyter user environment +################################################################### + +# Add jupyter helper scripts +ARG BURL=https://raw.githubusercontent.com/jupyter/docker-stacks/master/base-notebook +RUN bash -c "cd /usr/local/bin && for target in fix-permissions start{\"\",-notebook,-singleuser}.sh; do wget -q ${BURL}/\$target && chmod a+rx \$target; done" && \ +mkdir /etc/jupyter && cd /etc/jupyter && wget -q ${BURL}/jupyter_notebook_config.py && \ +fix-permissions /etc/jupyter /usr/local/bin +# login as jupyter +USER jupyter +# Change docker CWD to /home/jupyter +WORKDIR /home/jupyter/ # Jupyterhub correctly sets JUPYTERHUB_USER -RUN echo 'PS1="$JUPYTERHUB_USER@\h:\w\$ "' >> /home/jupyter/.bashrc -# allow users to add kernels -RUN chmod 777 /opt/conda/share/jupyter/kernels +RUN echo 'PS1="${JUPYTERHUB_USER:-jupyter}@\h:\w\$ "' >> /home/jupyter/.bashrc # Environment variables RUN echo "export JPY_USER=\$JUPYTERHUB_USER\n\ export WORK=/home/jupyter/tacc-work\n\ @@ -37,75 +88,91 @@ export PROJECTS_DATA=/home/jupyter/sd2e-projects\n\ export PARTNERS_DATA=/home/jupyter/sd2e-partners\n\ export PYTHONUSERBASE=/home/jupyter/tacc-work/jupyter_packages\n" >> /home/jupyter/.bashrc -# Add activation sripts -ADD src/activate-python.sh /opt/conda/etc/conda/activate.d/activate-python.sh -ADD src/activate-python.sh /opt/conda/envs/python2/etc/conda/activate.d/activate-python.sh -RUN find /opt/conda -type d -name activate.d -exec chmod -R a+rx {} \; - # Add readme ADD docs/SD2E_README.md /home/jupyter/SD2E_README.md # Add examples ADD examples examples -############################################### -# Packages -############################################### +################################################################### +# Install python +################################################################### +USER root +# Add conda env variables +ENV MINICONDA_VERSION=4.4.10 \ + CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:$PATH +# Download and install miniconda +RUN mkdir $CONDA_DIR && chmod -R a+rX $CONDA_DIR && \ + wget --quiet https://repo.continuum.io/miniconda/Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh && \ + bash Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh -f -b -p $CONDA_DIR && \ + rm Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh && \ + conda config --system --set auto_update_conda false && \ + conda config --system --set show_channel_urls true && \ + conda update -n base conda && \ + conda update --all --quiet --yes && \ + docker-clean +################################################################### +# Create python3 environment +################################################################### -# Bioconductor and BioPython -RUN conda update --all && conda install --yes -c bioconda bioconductor-biocinstaller && \ - conda install --yes --quiet biopython && \ - conda install --yes --quiet -n python2 biopython && \ - docker-clean -# Enable sd2nb sharing service +# Add packages to python3 environment +RUN conda install --yes \ + 'jupyter=1.0*' \ + 'numpy=1.14*' \ + 'pandas=0.22*' \ + 'matplotlib=2.2*' \ + 'scipy=1.0*' \ + 'seaborn=0.8*' \ + 'scikit-learn=0.19*' \ + 'scikit-image=0.13*' \ + 'cython=0.27*' \ + 'biopython' \ + 'h5py=2.7*' && docker-clean +RUN conda create --yes -n python2 \ + 'python=2.7' \ + 'ipykernel' \ + 'numpy=1.14*' \ + 'pandas=0.22*' \ + 'matplotlib=2.2*' \ + 'scipy=1.0*' \ + 'seaborn=0.8*' \ + 'scikit-learn=0.19*' \ + 'scikit-image=0.13*' \ + 'cython=0.27*' \ + 'biopython' \ + 'h5py=2.7*' && docker-clean -RUN cd /root && \ - git clone https://github.com/SD2E/sd2nb-app.git && \ - ( cd sd2nb-app && make && make install ) && \ - rm -rf sd2nb-app && \ - docker-clean -# Enable sd2e-jupyter -RUN cd /root && \ - git clone https://github.com/SD2E/sd2e-jupyter-ascending.git && \ - ( cd sd2e-jupyter-ascending && make && make install ) && \ - rm -rf sd2e-jupyter-ascending && \ - docker-clean -# Ubuntu Packages -# - jq - required for abaco CLI -# - bsdmainutils->column - required for abaco CLI \ -#apt-get install -y tree less openjdk-8-jre ca-certificates-java && \ -RUN apt-get update && \ - apt-get install -y tree less jq rsync bsdmainutils && \ - docker-clean -# Replace stock Agave CLI with SD2E-customized tooling -ADD src/configuration.rc configuration.rc -RUN git clone https://github.com/SD2E/sd2e-cli.git && \ - mv configuration.rc sd2e-cli/ && cd sd2e-cli && \ - git submodule update --init --recursive && make && \ - make install && rm -rf /opt/cli && rm -rf $HOME/sd2e-cli && \ - mv /home/jupyter/sd2e-cloud-cli /opt/cli && \ - chmod -R a+rX /opt/cli && chmod -R a+x /opt/cli/bin && \ - docker-clean -# Spark 2.2.1 and pyspark -#cd /usr/local && \ -# curl http://apache.claz.org/spark/spark-2.2.1/spark-2.2.1-bin-hadoop2.7.tgz | tar -xzf - && \ -# mv spark-2.2.1-bin-hadoop2.7 spark && \ -# conda install --yes pyspark && \ -# conda install -n python2 --yes pyspark && \ -#ENV SPARK_HOME=/usr/local/spark +# Create pip2 and pip3 shortcuts +RUN ln -s $CONDA_DIR/envs/python2/bin/pip $CONDA_DIR/bin/pip2 && \ + ln -s $CONDA_DIR/bin/pip $CONDA_DIR/bin/pip3 && \ + chmod a+rX $CONDA_DIR -############################################### -# Environment activation Kernels -############################################### +# Add activation sripts +ENV PYTHONUSERBASE=/home/jupyter/tacc-work/jupyter_packages +#ADD src/activate-python.sh /opt/conda/etc/conda/activate.d/activate-python.sh +#ADD src/activate-python.sh /opt/conda/envs/python2/etc/conda/activate.d/activate-python.sh +#RUN find ${CONDA_DIR} -type d -name activate.d -exec chmod -R a+rx {} \; -ADD src/activate_kernel /opt/conda/bin/activate_kernel -RUN chmod 755 /opt/conda/bin/activate_kernel && \ - TMPF=/tmp/tmp.json && \ - MODK=/usr/local/share/jupyter/kernels/python2/kernel.json && \ - jq " .argv = [\"activate_kernel\", \"python2\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ - mv $TMPF ${MODK} && \ - MODK=/opt/conda/share/jupyter/kernels/python3/kernel.json && \ - jq " .argv = [\"activate_kernel\", \"root\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ - mv $TMPF ${MODK} +################################################################### +# Additional kernels +################################################################### +# Install Python 2 kernel spec globally to avoid permission problems when NB_UID +# switching at runtime and to allow the notebook server running out of the root +# environment to find it. Also, activate the python2 environment upon kernel + +# Create python2 kernel +RUN bash -c "source activate python2 && ipython kernel install" +# Create bash kernel +RUN pip install bash_kernel && \ + python -m bash_kernel.install && \ + docker-clean +# Create R kernel +RUN conda create --quiet --yes -n R \ + 'r-essentials' \ + 'r-base' && \ + docker-clean +# Install bioconductor +RUN bash -c "source activate R && Rscript -e 'source(\"https://bioconductor.org/biocLite.R\"); biocLite();'" ############################################### # Environment activation Kernels @@ -122,6 +189,51 @@ RUN chmod 755 /opt/conda/bin/activate_kernel && \ jq " .argv = [\"activate_kernel\", \"root\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ mv $TMPF ${MODK} +################################################################### +# Agave tools +################################################################### + +# install SD2E Agave CLI +ADD src/configuration.rc configuration.rc +RUN git clone https://github.com/SD2E/sd2e-cli.git && \ + mv configuration.rc sd2e-cli/ && cd sd2e-cli && \ + git submodule update --init --recursive && \ + make && make install && \ + cd ../ && rm -rf sd2e-cli && \ + mv /root/sd2e-cloud-cli /opt/cli && \ + ls -a /root && rm -rf /root/* /root/.[^\.]* && \ + chmod -R a+rX /opt/cli && chmod -R a+x /opt/cli/bin && \ + docker-clean +# add cli to PATH +ENV PATH=$PATH:/opt/cli/bin + +# install agavepy +RUN pip2 install git+https://github.com/TACC/agavepy.git && \ + pip install git+https://github.com/TACC/agavepy.git && \ + docker-clean +# Enable sd2nb sharing service +RUN cd /root && \ + git clone https://github.com/SD2E/sd2nb-app.git && \ + ( cd sd2nb-app && make && make install ) && \ + rm -rf sd2nb-app && \ + docker-clean +# Enable sd2e-jupyter +RUN cd /root && \ + git clone https://github.com/SD2E/sd2e-jupyter-ascending.git && \ + ( cd sd2e-jupyter-ascending && make && make install ) && \ + rm -rf sd2e-jupyter-ascending && \ + docker-clean + +################################################################### +# Add entrypoint +################################################################### +# Add Tini +ARG TINI_VERSION=v0.17.0 +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/local/bin/tini +RUN chmod a+rx /usr/local/bin/tini +ENTRYPOINT ["tini", "--"] +CMD ["start-notebook.sh"] + ############################################### # Persistent local conda environments ############################################### @@ -160,4 +272,13 @@ RUN chown -R jupyter:${NB_GROUP} /home/jupyter && \ find /home/jupyter -type f -exec chmod 666 {} \; && \ find /home/jupyter -type d -exec chmod 777 {} \; +################################################################### +# Cache matplotlib for jupyter user +################################################################### USER jupyter +# build matplotlib python2 font cache +RUN MPLBACKEND=Agg $CONDA_DIR/envs/python2/bin/python -c "import matplotlib.pyplot" && \ + docker-clean +# build matplotlib python3 font cache +RUN MPLBACKEND=Agg python -c "import matplotlib.pyplot" && \ + docker-clean From 06125c09824549002d681a8aac29c24c59900d4e Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Wed, 11 Apr 2018 13:14:45 -0400 Subject: [PATCH 10/18] typo in SHELL --- images/base/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 74a11df..7151a37 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -56,7 +56,7 @@ ARG AGAVE_GID=G-816877 ENV NB_USER=jupyter \ NB_GID=${TACC_GID} \ NB_GROUP=${TACC_GID} \ - SHELL=/bin/bashh + SHELL=/bin/bash RUN groupadd --gid 816877 ${AGAVE_GID} && \ useradd --uid 458981 --gid ${AGAVE_GID} -m --home /home/jupyter --shell /bin/bash $NB_USER && \ groupadd --gid ${NB_GID} ${NB_GROUP} && \ From 6c1f7a6a73a0b21e759bc7af3840c7318b010853 Mon Sep 17 00:00:00 2001 From: Matthew Vaughn Date: Wed, 11 Apr 2018 12:43:14 -0500 Subject: [PATCH 11/18] Smarter git user configuration --- images/base/Dockerfile | 5 +++++ images/base/src/setup-git-user.sh | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 images/base/src/setup-git-user.sh diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 74a11df..2c0bd5f 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -282,3 +282,8 @@ RUN MPLBACKEND=Agg $CONDA_DIR/envs/python2/bin/python -c "import matplotlib.pypl # build matplotlib python3 font cache RUN MPLBACKEND=Agg python -c "import matplotlib.pyplot" && \ docker-clean + + +# Fix git +COPY src/setup-git-user.sh $HOME/.setup-git-user.sh +RUN echo "if [ -z \"\$GIT_USER_CONFIGURED\" ]; then source \$HOME/.setup-git-user.sh; fi" >> $HOME/.bashrc diff --git a/images/base/src/setup-git-user.sh b/images/base/src/setup-git-user.sh new file mode 100644 index 0000000..7117c49 --- /dev/null +++ b/images/base/src/setup-git-user.sh @@ -0,0 +1,6 @@ +auth-tokens-refresh -S 1>2 2>/dev/null || true +export GIT_AUTHOR_NAME=$(profiles-list -v me | jq -r '"\(.first_name) \(.last_name)"' 2>/dev/null || echo \"Jupyter User\") +export GIT_AUTHOR_EMAIL=$(profiles-list -v me | jq -r .email 2>/dev/null || echo ${JUPYTERHUB_USER}@tacc.cloud) +export GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME +export GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL +export GIT_USER_CONFIGURED=1 From 40b178c6ddda90367c7e98ba5c1d73171377c710 Mon Sep 17 00:00:00 2001 From: Matthew Vaughn Date: Wed, 11 Apr 2018 14:02:03 -0500 Subject: [PATCH 12/18] Install Hub, the GitHub CLI --- images/base/Dockerfile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 8f49112..1084332 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -223,6 +223,13 @@ RUN cd /root && \ ( cd sd2e-jupyter-ascending && make && make install ) && \ rm -rf sd2e-jupyter-ascending && \ docker-clean +# Add hub +RUN cd /root && \ + curl -skL -O "https://github.com/github/hub/releases/download/v2.3.0-pre10/hub-linux-amd64-2.3.0-pre10.tgz" && \ + tar zxf hub-linux-amd64-2.3.0-pre10.tgz && \ + cd hub-linux-amd64-2.3.0-pre10 && \ + ./install && \ + cd /root && rm -rf hub-linux-amd64-2.3.0-pre10* ################################################################### # Add entrypoint @@ -285,5 +292,5 @@ RUN MPLBACKEND=Agg python -c "import matplotlib.pyplot" && \ # Fix git -COPY src/setup-git-user.sh $HOME/.setup-git-user.sh -RUN echo "if [ -z \"\$GIT_USER_CONFIGURED\" ]; then source \$HOME/.setup-git-user.sh; fi" >> $HOME/.bashrc +ADD src/setup-git-user.sh /home/jupyter/.config/setup-git-user.sh +RUN echo "if [ -z \"\$GIT_USER_CONFIGURED\" ]; then source \$HOME/.config/setup-git-user.sh; fi" >> $HOME/.bashrc From 9203c791badf1ffb3b739d0c7b4612352a5962fe Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Mon, 16 Apr 2018 22:16:48 -0400 Subject: [PATCH 13/18] Refactored all images --- build/build_jupyteruser.sh | 3 +- images/base/Dockerfile | 97 +++++++++------- images/base/examples/Advanced Jupyter.ipynb | 2 +- images/base/src/setup-git-user.sh | 18 ++- images/sd2e/Dockerfile | 117 ++++++++++---------- images/sd2e/common-lisp/ql_setup.lisp | 2 + 6 files changed, 129 insertions(+), 110 deletions(-) diff --git a/build/build_jupyteruser.sh b/build/build_jupyteruser.sh index 39cdce8..91c86bd 100755 --- a/build/build_jupyteruser.sh +++ b/build/build_jupyteruser.sh @@ -94,7 +94,8 @@ function testImage { EIP=$(dig +short myip.opendns.com @resolver1.opendns.com) ed "Local Address: http://localhost:8888" ed "External Address: http://${EIP}:8888" - ed "docker run --rm -p 8888:8888 ${IMG}:${VERSION} start-notebook.sh" + # Added -u flag to test as non-existent user + ed "docker run -u 1337 --rm -p 8888:8888 ${IMG}:${VERSION} start-notebook.sh" docker run --rm -p 8888:8888 ${IMG}:${VERSION} start-notebook.sh if [ ! $? -eq 0 ]; then ee "Notebook could not launch" diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 1084332..7d5a4eb 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -16,13 +16,14 @@ RUN echo "${image_version}" > /etc/sd2e_jupyteruser-base-release && \ # Use IU ubuntu mirror RUN sed -i "s~archive.ubuntu.com~ftp.ussg.iu.edu/linux~" /etc/apt/sources.list # Add clean script -RUN echo "apt-get clean\n\ -[ -x \"$(command -v conda)\" ] && conda clean -tipsy\n\ -for dir in /tmp/* /var/tmp/* /home/jupyter/.ccache /home/jupyter/.cache/pip /root/* /root/\.* /var/lib/apt/lists/*; do\n\ - [ -e $dir ] && rm -rf $dir\n\ -done" > /usr/bin/docker-clean && chmod a+rx /usr/bin/docker-clean && \ +RUN echo "#!/bin/bash\n\ +apt-get clean\n\ +[ -x \"\$(command -v conda)\" ] && conda clean -tipsy\n\ +for dir in /tmp/* /var/tmp/* /home/jupyter/{.ccache,.cache/pip,conda-bld,.conda} /root/* /root/\.[^\.]* /var/lib/apt/lists/* /var/log/*; do\n\ + [ -e \$dir ] && rm -rf \$dir || true\n\ +done" > /usr/bin/docker-clean && chmod a+rx /usr/bin/docker-clean && docker-clean # Create Singularity Mounts -mkdir /scratch /work /home1 /gpfs /corral-repl /corral-tacc /data +RUN mkdir /scratch /work /home1 /gpfs /corral-repl /corral-tacc /data # Expose notebook port EXPOSE 8888 ################################################################### @@ -32,10 +33,11 @@ USER root # Install dependencies # - jq - required for abaco CLI # - bsdmainutils->column - required for abaco CLI \ +# - Install *-nox (non-GUI) versions of tools when available RUN apt-get update && \ apt-get install -yq --no-install-recommends \ bzip2 unzip ca-certificates build-essential \ - emacs vim git wget ssh curl \ + emacs-nox vim-nox git wget openssh-client curl \ tree less jq rsync bsdmainutils && \ docker-clean ################################################################### @@ -61,6 +63,9 @@ RUN groupadd --gid 816877 ${AGAVE_GID} && \ useradd --uid 458981 --gid ${AGAVE_GID} -m --home /home/jupyter --shell /bin/bash $NB_USER && \ groupadd --gid ${NB_GID} ${NB_GROUP} && \ usermod -a -G ${NB_GROUP} jupyter +# While not ideal, this is required since the users that are injected +# into the container do not exist. +ENV HOME=/home/jupyter # Make primary group TACC_GID RUN usermod -g ${NB_GROUP} jupyter @@ -73,14 +78,20 @@ ARG BURL=https://raw.githubusercontent.com/jupyter/docker-stacks/master/base-not RUN bash -c "cd /usr/local/bin && for target in fix-permissions start{\"\",-notebook,-singleuser}.sh; do wget -q ${BURL}/\$target && chmod a+rx \$target; done" && \ mkdir /etc/jupyter && cd /etc/jupyter && wget -q ${BURL}/jupyter_notebook_config.py && \ fix-permissions /etc/jupyter /usr/local/bin + +# Fix git for all users +ADD src/setup-git-user.sh /etc/profile.d/setup-git-user.sh +RUN chmod a+rx /etc/profile.d/setup-git-user.sh + # login as jupyter USER jupyter # Change docker CWD to /home/jupyter WORKDIR /home/jupyter/ -# Jupyterhub correctly sets JUPYTERHUB_USER +# Changes to local bashrc - these will require different variables in Singularity +## Jupyterhub correctly sets JUPYTERHUB_USER RUN echo 'PS1="${JUPYTERHUB_USER:-jupyter}@\h:\w\$ "' >> /home/jupyter/.bashrc -# Environment variables +## Environment variables RUN echo "export JPY_USER=\$JUPYTERHUB_USER\n\ export WORK=/home/jupyter/tacc-work\n\ export SD2_DATA=/home/jupyter/sd2e-community\n\ @@ -92,6 +103,8 @@ export PYTHONUSERBASE=/home/jupyter/tacc-work/jupyter_packages\n" >> /home/jupyt ADD docs/SD2E_README.md /home/jupyter/SD2E_README.md # Add examples ADD examples examples +# Add R kernel +ADD https://raw.githubusercontent.com/IRkernel/IRkernel/master/example-notebooks/Demo.ipynb examples/R-Demo.ipynb ################################################################### # Install python @@ -100,13 +113,14 @@ USER root # Add conda env variables ENV MINICONDA_VERSION=4.4.10 \ CONDA_DIR=/opt/conda +# Conda path needs to go first so system python is not used ENV PATH=${CONDA_DIR}/bin:$PATH # Download and install miniconda RUN mkdir $CONDA_DIR && chmod -R a+rX $CONDA_DIR && \ wget --quiet https://repo.continuum.io/miniconda/Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh && \ bash Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh -f -b -p $CONDA_DIR && \ - rm Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh && \ - conda config --system --set auto_update_conda false && \ + rm Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh +RUN docker-clean && conda config --system --set auto_update_conda false && \ conda config --system --set show_channel_urls true && \ conda update -n base conda && \ conda update --all --quiet --yes && \ @@ -116,31 +130,33 @@ RUN mkdir $CONDA_DIR && chmod -R a+rX $CONDA_DIR && \ ################################################################### # Add packages to python3 environment +## installing r-essentials without r-base breaks gcc RUN conda install --yes \ - 'jupyter=1.0*' \ + notebook jupyter_console nbconvert ipykernel ipywidgets \ 'numpy=1.14*' \ - 'pandas=0.22*' \ - 'matplotlib=2.2*' \ 'scipy=1.0*' \ - 'seaborn=0.8*' \ + 'cython=0.27*' \ + 'pandas=0.22*' \ + matplotlib seaborn \ + 'h5py=2.7*' \ + 'r-essentials' 'r-base' \ 'scikit-learn=0.19*' \ 'scikit-image=0.13*' \ - 'cython=0.27*' \ - 'biopython' \ - 'h5py=2.7*' && docker-clean -RUN conda create --yes -n python2 \ + 'biopython' && \ +conda install -c defaults -c conda-forge --no-update-deps jupyterhub && \ +conda create --yes -n python2 \ 'python=2.7' \ 'ipykernel' \ 'numpy=1.14*' \ - 'pandas=0.22*' \ - 'matplotlib=2.2*' \ 'scipy=1.0*' \ - 'seaborn=0.8*' \ + 'cython=0.27*' \ + 'pandas=0.22*' \ + 'h5py=2.7*' \ + matplotlib seaborn \ 'scikit-learn=0.19*' \ 'scikit-image=0.13*' \ - 'cython=0.27*' \ 'biopython' \ - 'h5py=2.7*' && docker-clean + && docker-clean && rm -rf ${CONDA_DIR}/pkgs/* # Create pip2 and pip3 shortcuts RUN ln -s $CONDA_DIR/envs/python2/bin/pip $CONDA_DIR/bin/pip2 && \ @@ -167,12 +183,13 @@ RUN pip install bash_kernel && \ python -m bash_kernel.install && \ docker-clean # Create R kernel -RUN conda create --quiet --yes -n R \ - 'r-essentials' \ - 'r-base' && \ - docker-clean +# 'r-base' && \ +#RUN conda install --quiet --yes -n base r-essentials && docker-clean +#RUN conda create --quiet --yes -n R \ +# 'r-essentials' && \ +# docker-clean # Install bioconductor -RUN bash -c "source activate R && Rscript -e 'source(\"https://bioconductor.org/biocLite.R\"); biocLite();'" +RUN bash -c "source activate base && Rscript -e 'source(\"https://bioconductor.org/biocLite.R\"); biocLite();'" ############################################### # Environment activation Kernels @@ -186,7 +203,7 @@ RUN chmod 755 /opt/conda/bin/activate_kernel && \ jq " .argv = [\"activate_kernel\", \"python2\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ mv $TMPF ${MODK} && \ MODK=/opt/conda/share/jupyter/kernels/python3/kernel.json && \ - jq " .argv = [\"activate_kernel\", \"root\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ + jq " .argv = [\"activate_kernel\", \"base\", \"{connection_file}\"] " ${MODK} | tee $TMPF && \ mv $TMPF ${MODK} ################################################################### @@ -208,9 +225,9 @@ RUN git clone https://github.com/SD2E/sd2e-cli.git && \ ENV PATH=$PATH:/opt/cli/bin # install agavepy -RUN pip2 install git+https://github.com/TACC/agavepy.git && \ - pip install git+https://github.com/TACC/agavepy.git && \ - docker-clean +RUN bash -c "source activate base && pip install git+https://github.com/TACC/agavepy.git" && \ + bash -c "source activate python2 && pip install git+https://github.com/TACC/agavepy.git" && \ + docker-clean && find /root # Enable sd2nb sharing service RUN cd /root && \ git clone https://github.com/SD2E/sd2nb-app.git && \ @@ -239,6 +256,7 @@ ARG TINI_VERSION=v0.17.0 ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/local/bin/tini RUN chmod a+rx /usr/local/bin/tini ENTRYPOINT ["tini", "--"] +#ENTRYPOINT ["bash"] CMD ["start-notebook.sh"] ############################################### @@ -248,7 +266,7 @@ CMD ["start-notebook.sh"] # conda create -p $LOCAL_ENVS/tmnt python=2.7 ipykernel # conda env list # source activate tmnt -ENV LOCAL_ENVS=$HOME/tacc-work/jupyter_packages/envs +ENV LOCAL_ENVS=/home/jupyter/tacc-work/jupyter_packages/envs ENV CONDA_ENVS_PATH=$LOCAL_ENVS:$CONDA_ENVS_PATH ############################################### @@ -258,15 +276,15 @@ ENV CONDA_ENVS_PATH=$LOCAL_ENVS:$CONDA_ENVS_PATH # $LOCAL_ENVS/tmnt/bin/python -m ipykernel install --prefix $JUPYTER_WORK --name tmnt --display-name "tmnt python" # *Must use full path* # refresh main jupyter to load the new kernel option -ENV JUPYTER_PATH=$HOME/tacc-work/jupyter_packages/share/jupyter:$JUPYTER_PATH -ENV JUPYTER_WORK=$HOME/tacc-work/jupyter_packages +ENV JUPYTER_PATH=/home/jupyter/tacc-work/jupyter_packages/share/jupyter:$JUPYTER_PATH +ENV JUPYTER_WORK=/home/jupyter/tacc-work/jupyter_packages ############################################### # Affiliated projects ############################################### ADD src/add-sd2e-groups.sh /tmp/add-sd2e-groups.sh -RUN bash /tmp/add-sd2e-groups.sh +RUN bash /tmp/add-sd2e-groups.sh && docker-clean ############################################### # Permissions @@ -289,8 +307,3 @@ RUN MPLBACKEND=Agg $CONDA_DIR/envs/python2/bin/python -c "import matplotlib.pypl # build matplotlib python3 font cache RUN MPLBACKEND=Agg python -c "import matplotlib.pyplot" && \ docker-clean - - -# Fix git -ADD src/setup-git-user.sh /home/jupyter/.config/setup-git-user.sh -RUN echo "if [ -z \"\$GIT_USER_CONFIGURED\" ]; then source \$HOME/.config/setup-git-user.sh; fi" >> $HOME/.bashrc diff --git a/images/base/examples/Advanced Jupyter.ipynb b/images/base/examples/Advanced Jupyter.ipynb index 7760e22..277338b 100644 --- a/images/base/examples/Advanced Jupyter.ipynb +++ b/images/base/examples/Advanced Jupyter.ipynb @@ -59,7 +59,7 @@ "source": [ "If you have not modified your environment, you should see two environments:\n", "\n", - "- **base** - (python3) activated with `source activate root`\n", + "- **base** - (python3) activated with `source activate base`\n", "- **python2** - activated with `source activate python2`\n", "\n", "I am developing a new analysis that is dependant on scipy 0.16.0, which is older than (and conflicts with) the version of scipy in the main python2 environment. Creating a brand new environment will be the easiest path forward for my development, so lets create one called \"tabsAreGreat\" with [`conda create`](https://conda.io/docs/commands/conda-create.html).\n", diff --git a/images/base/src/setup-git-user.sh b/images/base/src/setup-git-user.sh index 7117c49..838969e 100644 --- a/images/base/src/setup-git-user.sh +++ b/images/base/src/setup-git-user.sh @@ -1,6 +1,12 @@ -auth-tokens-refresh -S 1>2 2>/dev/null || true -export GIT_AUTHOR_NAME=$(profiles-list -v me | jq -r '"\(.first_name) \(.last_name)"' 2>/dev/null || echo \"Jupyter User\") -export GIT_AUTHOR_EMAIL=$(profiles-list -v me | jq -r .email 2>/dev/null || echo ${JUPYTERHUB_USER}@tacc.cloud) -export GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME -export GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL -export GIT_USER_CONFIGURED=1 +if [ -z "$GIT_COMMITTER_EMAIL"]; then + # Refresh agave token + if [ -e $HOME/.agave/current ]; then + auth-tokens-refresh -S &>/dev/null || true + # Get user info and populate git vars + export GIT_COMMITTER_NAME=$(profiles-list -v me | jq -r '"\(.first_name) \(.last_name)"' 2>/dev/null || echo "Jupyter User") + export GIT_COMMITTER_EMAIL=$(profiles-list -v me | jq -r .email 2>/dev/null || echo ${JUPYTERHUB_USER-jupyter}@tacc.cloud) + else + export GIT_COMMITTER_NAME="Jupyter User" + export GIT_COMMITTER_EMAIL="jupyter@tacc.cloud" + fi +fi diff --git a/images/sd2e/Dockerfile b/images/sd2e/Dockerfile index c08e73c..0d983cd 100644 --- a/images/sd2e/Dockerfile +++ b/images/sd2e/Dockerfile @@ -1,7 +1,10 @@ #Image: sd2e/jupyteruser-sd2e -#Version: 0.3.2 +#Version: 0.3.3 -FROM sd2e/jupyteruser-base:0.2.1 +FROM sd2e/jupyteruser-base:0.2.2 + +# Convenience variable +ARG CONDA_ARGS="--quiet --no-update-deps --yes" # Image release USER root @@ -14,8 +17,10 @@ RUN echo "${image_version}" > /etc/sd2e_jupyteruser-sd2e-release && \ ########################################## USER root LABEL "comment"="Support for plotly igraph and networkx" "issue"="SD2E/jupyteruser-sd2e/issues/3" -RUN conda install --quiet --yes python-igraph plotly networkx && \ - conda install --quiet --yes -n python2 python-igraph plotly networkx && \ +RUN conda install ${CONDA_ARGS} plotly networkx && \ + bash -c "source activate base && pip install python-igraph" && \ + conda install ${CONDA_ARGS} -n python2 plotly networkx && \ + bash -c "source activate python2 && pip install python-igraph" && \ docker-clean ########################################## @@ -24,28 +29,24 @@ RUN conda install --quiet --yes python-igraph plotly networkx && \ USER root LABEL "comment"="Support for Open Probabilistic Programming Stack" "issue"="SD2E/jupyteruser-sd2e/issues/2" -# Libraries -RUN apt-get update && \ - apt-get install -y libboost-all-dev libgsl0-dev ccache && \ - apt-get clean && \ - docker-clean -# Install dependencies and remove anaconda toolchain -RUN conda install -n python2 --quiet --yes flask jsonschema patsy requests six && \ - conda install -n python2 -c conda-forge apsw && \ - conda uninstall -n python2 --yes \ - binutils_impl_linux-64 binutils_linux-64 \ - gcc_impl_linux-64 gcc_linux-64 \ - gxx_impl_linux-64 gxx_linux-64 && \ + +# Install run dependencies +RUN apt-get update && apt-get install -yq --no-install-recommends libgsl0-dev && \ + conda install -n python2 ${CONDA_ARGS} flask jsonschema patsy requests six && \ + conda install -n python2 ${CONDA_ARGS} -c conda-forge apsw && \ docker-clean # Install probcomp software stack - +### Make sure to remove build deps +RUN apt-get update && apt-get install -y --no-install-recommends libboost-all-dev ccache RUN bash -c "export MPLBACKEND=Agg && source activate python2 && \ - pip2 install git+https://github.com/probcomp/Venturecxx@v0.5.1.1 && \ - pip2 install git+https://github.com/probcomp/cgpm.git@v0.1.2 && \ - pip2 install git+https://github.com/probcomp/crosscat.git@v0.1.56.1 && \ - pip2 install git+https://github.com/probcomp/bayeslite.git@v0.3.2 && \ - pip2 install git+https://github.com/probcomp/iventure.git@v0.2.3" && \ + pip install git+https://github.com/probcomp/Venturecxx@v0.5.1.1 && \ + pip install git+https://github.com/probcomp/cgpm.git@v0.1.2 && \ + pip install git+https://github.com/probcomp/crosscat.git@v0.1.56.1 && \ + pip install git+https://github.com/probcomp/bayeslite.git@v0.3.2 && \ + pip install git+https://github.com/probcomp/iventure.git@v0.2.3" && \ rm -rf .ccache && \ + apt-get --purge remove -y libboost-all-dev ccache && \ + apt-get --purge -y autoremove && \ docker-clean # Grab latest example notebooks RUN mkdir -p /home/jupyter/examples/probcomp && \ @@ -56,32 +57,27 @@ RUN mkdir -p /home/jupyter/examples/probcomp && \ #### Common Lisp Kernel Setup Begin #### ########################################## -# Get sbcl from the package manage and use it to build -# the sbcl 1.4.0 from source. The version from the package -# manager is not the current version. -RUN mkdir /opt/common-lisp && \ - apt-get update && \ - apt-get install -y sbcl libzmq3-dev && \ - apt-get clean && \ - cd /opt/common-lisp && \ - git clone git://git.code.sf.net/p/sbcl/sbcl && \ - cd sbcl && \ - git checkout tags/sbcl-1.4.3 && \ - export SBCL_MAKE_JOBS="-j $(nproc --all)" && \ - sh make.sh && rm -rf .git && \ - cd /opt/common-lisp/sbcl && \ - sh install.sh && \ - apt-get purge -y sbcl # Uninstall the version from apt-get - -COPY common-lisp/ql_setup.lisp /opt/common-lisp/ql_setup.lisp +ENV CL_PREFIX=/opt/common-lisp +ARG CLV=1.4.6-x86-64-linux +# Install dependency +RUN apt-get update && apt-get install -yq --no-install-recommends libzmq3-dev && \ + docker-clean +# Install SBCL +RUN curl -L prdownloads.sourceforge.net/sbcl/sbcl-${CLV}-binary.tar.bz2 | tar -xjf - && \ + ( cd sbcl-${CLV} && INSTALL_ROOT=${CL_PREFIX} bash install.sh ) && \ + rm -rf sbcl-${CLV} && \ + docker-clean +# Set env variable for sbcl http://www.sbcl.org/getting.html +ENV SBCL_HOME=${CL_PREFIX}/lib/sbcl +ENV PATH=${CL_PREFIX}/bin:${PATH} + +COPY common-lisp/ql_setup.lisp ${CL_PREFIX}/ql_setup.lisp # Install the common lisp jupyter kernel -RUN cd /opt/common-lisp/ && \ +RUN cd ${CL_PREFIX} && \ git clone https://github.com/fredokun/cl-jupyter.git && \ - cd cl-jupyter && rm -rf .git && \ - python ./install-cl-jupyter.py && \ - cd /opt/common-lisp && \ - curl -O https://beta.quicklisp.org/quicklisp.lisp && \ + ( cd cl-jupyter && rm -rf .git && ${CONDA_DIR}/bin/python ./install-cl-jupyter.py ) && \ + curl -LO https://beta.quicklisp.org/quicklisp.lisp && \ sbcl --load ql_setup.lisp && \ rm quicklisp.lisp ql_setup.lisp @@ -91,20 +87,23 @@ RUN cd /opt/common-lisp/ && \ COPY common-lisp/sbclrc /home/jupyter/.sbclrc # Move the kernel json file to the correct location -RUN mkdir /opt/conda/share/jupyter/kernels/lisp && \ - mv $HOME/.ipython/kernels/lisp/kernel.json /opt/conda/share/jupyter/kernels/lisp && \ - chmod -R a+rwX /opt/conda/share/jupyter/kernels/lisp && \ - rm -rf ${HOME}/.ipython && docker-clean +RUN cp -r $HOME/.ipython/kernels/lisp ${CONDA_DIR}/share/jupyter/kernels/ && \ + rm -rf $HOME/.ipython && \ + chmod -R a+rX ${CONDA_DIR}/share/jupyter/kernels/lisp && \ + docker-clean COPY examples/common-lisp /home/jupyter/examples/common-lisp +USER jupyter +RUN sbcl --load ${CL_PREFIX}/cl-jupyter/cl-jupyter.lisp + ########################################## # pyemd support ########################################## USER root LABEL "comment"="support for pyemd" "issue"="SD2E/jupyteruser-sd2e/issues/8" -RUN conda install --quiet --yes pyemd && \ - conda install --quiet --yes -n python2 pyemd && \ +RUN conda install ${CONDA_ARGS} pyemd && \ + conda install ${CONDA_ARGS} -n python2 pyemd && \ docker-clean ########################################## @@ -112,9 +111,9 @@ RUN conda install --quiet --yes pyemd && \ ########################################## USER root LABEL "comment"="Support DSGRN code" "issue"="SD2E/jupyteruser-sd2e/issues/9" -RUN apt-get install -y cmake graphviz && \ - conda install --quiet --yes python-graphviz && \ - conda install --quiet --yes -n python2 python-graphviz && \ +RUN apt-get update && apt-get install -yq --no-install-recommends cmake graphviz && \ + conda install ${CONDA_ARGS} python-graphviz && \ + conda install ${CONDA_ARGS} -n python2 python-graphviz && \ docker-clean ########################################## @@ -122,16 +121,14 @@ RUN apt-get install -y cmake graphviz && \ ########################################## USER root LABEL "comment"="Support Tensorflow and Keras" "issue"="SD2E/jupyteruser-sd2e/issues/13" -RUN bash -c "source activate python2 && \ -pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.6.0-cp27-none-linux_x86_64.whl && \ -pip install keras" && \ -bash -c "source activate root && \ -pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.6.0-cp36-cp36m-linux_x86_64.whl && \ -pip install keras" && \ +RUN conda install ${CONDA_ARGS} 'tensorflow=1.6*' keras theano && \ + conda install ${CONDA_ARGS} -n python2 'tensorflow=1.6*' keras theano && \ docker-clean RUN cd examples && \ git clone https://github.com/leriomaggio/deep-learning-keras-tensorflow.git && \ cd deep-learning-keras-tensorflow && rm -rf .git +# Necessary for theano +ENV MKL_THREADING_LAYER=GNU ############################################### # Permissions diff --git a/images/sd2e/common-lisp/ql_setup.lisp b/images/sd2e/common-lisp/ql_setup.lisp index f3db2df..af97014 100644 --- a/images/sd2e/common-lisp/ql_setup.lisp +++ b/images/sd2e/common-lisp/ql_setup.lisp @@ -9,8 +9,10 @@ (ql:quickload "alexandria") (ql:quickload "trivial-features") (ql:quickload "babel") +(ql:quickload "ironclad") ;; Run the kernel script once to get all of the required packages installed ;; so that that pacakges aren't installed when running starting the notebook. (load "cl-jupyter/cl-jupyter.lisp") +(ql:quickload "cl-jupyter") (quit) From 72515aec13b85a23b11cf62e28bc07bde3672a9f Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Mon, 16 Apr 2018 22:49:54 -0400 Subject: [PATCH 14/18] Fixed cli path --- images/base/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 7d5a4eb..f6379df 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -217,8 +217,7 @@ RUN git clone https://github.com/SD2E/sd2e-cli.git && \ git submodule update --init --recursive && \ make && make install && \ cd ../ && rm -rf sd2e-cli && \ - mv /root/sd2e-cloud-cli /opt/cli && \ - ls -a /root && rm -rf /root/* /root/.[^\.]* && \ + mv ${HOME}/sd2e-cloud-cli /opt/cli && \ chmod -R a+rX /opt/cli && chmod -R a+x /opt/cli/bin && \ docker-clean # add cli to PATH @@ -227,7 +226,7 @@ ENV PATH=$PATH:/opt/cli/bin # install agavepy RUN bash -c "source activate base && pip install git+https://github.com/TACC/agavepy.git" && \ bash -c "source activate python2 && pip install git+https://github.com/TACC/agavepy.git" && \ - docker-clean && find /root + docker-clean # Enable sd2nb sharing service RUN cd /root && \ git clone https://github.com/SD2E/sd2nb-app.git && \ From 86614028f4e14dffeeb85508b3d78867282c2cbb Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Wed, 18 Apr 2018 15:28:26 -0400 Subject: [PATCH 15/18] Fixed username --- images/base/Dockerfile | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index f6379df..092ab18 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -65,7 +65,8 @@ RUN groupadd --gid 816877 ${AGAVE_GID} && \ usermod -a -G ${NB_GROUP} jupyter # While not ideal, this is required since the users that are injected # into the container do not exist. -ENV HOME=/home/jupyter +ENV HOME=/home/jupyter \ + USER=jupyter # Make primary group TACC_GID RUN usermod -g ${NB_GROUP} jupyter @@ -80,6 +81,8 @@ mkdir /etc/jupyter && cd /etc/jupyter && wget -q ${BURL}/jupyter_notebook_config fix-permissions /etc/jupyter /usr/local/bin # Fix git for all users +# profile is only loaded in an interactive login shell +# - https://askubuntu.com/questions/438150/scripts-in-etc-profile-d-being-ignored/438170#438170 ADD src/setup-git-user.sh /etc/profile.d/setup-git-user.sh RUN chmod a+rx /etc/profile.d/setup-git-user.sh @@ -97,7 +100,8 @@ export WORK=/home/jupyter/tacc-work\n\ export SD2_DATA=/home/jupyter/sd2e-community\n\ export PROJECTS_DATA=/home/jupyter/sd2e-projects\n\ export PARTNERS_DATA=/home/jupyter/sd2e-partners\n\ -export PYTHONUSERBASE=/home/jupyter/tacc-work/jupyter_packages\n" >> /home/jupyter/.bashrc +export PYTHONUSERBASE=/home/jupyter/tacc-work/jupyter_packages\n\n\ +[ -e /etc/profile.d/setup-git-user.sh ] && . /etc/profile.d/setup-git-user.sh" >> /home/jupyter/.bashrc # Add readme ADD docs/SD2E_README.md /home/jupyter/SD2E_README.md @@ -119,11 +123,12 @@ ENV PATH=${CONDA_DIR}/bin:$PATH RUN mkdir $CONDA_DIR && chmod -R a+rX $CONDA_DIR && \ wget --quiet https://repo.continuum.io/miniconda/Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh && \ bash Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh -f -b -p $CONDA_DIR && \ - rm Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh -RUN docker-clean && conda config --system --set auto_update_conda false && \ + rm Miniconda3-${MINICONDA_VERSION}-Linux-x86_64.sh && \ + conda config --system --set auto_update_conda false && \ conda config --system --set show_channel_urls true && \ conda update -n base conda && \ conda update --all --quiet --yes && \ + rm -rf ${CONDA_DIR}/pkgs/* && \ docker-clean ################################################################### # Create python3 environment @@ -131,8 +136,8 @@ RUN docker-clean && conda config --system --set auto_update_conda false && \ # Add packages to python3 environment ## installing r-essentials without r-base breaks gcc -RUN conda install --yes \ - notebook jupyter_console nbconvert ipykernel ipywidgets \ +RUN conda install --yes --no-update-deps -c defaults -c conda-forge \ + jupyter \ 'numpy=1.14*' \ 'scipy=1.0*' \ 'cython=0.27*' \ @@ -142,8 +147,8 @@ RUN conda install --yes \ 'r-essentials' 'r-base' \ 'scikit-learn=0.19*' \ 'scikit-image=0.13*' \ + jupyterhub \ 'biopython' && \ -conda install -c defaults -c conda-forge --no-update-deps jupyterhub && \ conda create --yes -n python2 \ 'python=2.7' \ 'ipykernel' \ From 7df5427c12e7c6431f13a833a9358de707dbb508 Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Wed, 18 Apr 2018 20:54:01 -0500 Subject: [PATCH 16/18] Fixed typo and vim --- images/base/Dockerfile | 3 ++- images/base/src/setup-git-user.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 092ab18..cbd7a38 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -38,7 +38,8 @@ RUN apt-get update && \ apt-get install -yq --no-install-recommends \ bzip2 unzip ca-certificates build-essential \ emacs-nox vim-nox git wget openssh-client curl \ - tree less jq rsync bsdmainutils && \ + tree less jq rsync bsdmainutils locales && \ + locale-gen en_US.UTF-8 && \ docker-clean ################################################################### # Create jupyter user diff --git a/images/base/src/setup-git-user.sh b/images/base/src/setup-git-user.sh index 838969e..a1b86b2 100644 --- a/images/base/src/setup-git-user.sh +++ b/images/base/src/setup-git-user.sh @@ -1,4 +1,4 @@ -if [ -z "$GIT_COMMITTER_EMAIL"]; then +if [ -z "$GIT_COMMITTER_EMAIL" ]; then # Refresh agave token if [ -e $HOME/.agave/current ]; then auth-tokens-refresh -S &>/dev/null || true From d898a5a6c7198366881c7ff48a7264c389a92ccc Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Thu, 19 Apr 2018 01:04:31 -0400 Subject: [PATCH 17/18] Trying to fix locales --- images/base/Dockerfile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index cbd7a38..7c34db2 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -39,7 +39,10 @@ RUN apt-get update && \ bzip2 unzip ca-certificates build-essential \ emacs-nox vim-nox git wget openssh-client curl \ tree less jq rsync bsdmainutils locales && \ - locale-gen en_US.UTF-8 && \ + echo "LANG=\"en_US.UTF-8\"\n\ +LANGUAGE=\"en_US.UTF-8\"\n\ +LC_ALL=\"en_US.UTF-8\"" >> /etc/default/locale && \ + echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen && \ docker-clean ################################################################### # Create jupyter user @@ -67,7 +70,10 @@ RUN groupadd --gid 816877 ${AGAVE_GID} && \ # While not ideal, this is required since the users that are injected # into the container do not exist. ENV HOME=/home/jupyter \ - USER=jupyter + USER=jupyter \ + LC_ALL=en_US.UTF-8 \ + LANG=en_US.UTF-8 \ + LANGUAGE=en_US.UTF-8 # Make primary group TACC_GID RUN usermod -g ${NB_GROUP} jupyter From aa0deab702be433ae2340de693f8cf254d90ad43 Mon Sep 17 00:00:00 2001 From: Greg Zynda Date: Fri, 20 Apr 2018 23:38:25 -0400 Subject: [PATCH 18/18] Updated version, changelog, and readme --- CHANGELOG.md | 16 ++++++++++++++++ README.md | 2 ++ VERSION | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43a10bc..377501e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project are to be documented in this file. +## Version 0.3.3 + + - Added hub https://github.com/github/hub + - Create persistent environments + - `conda create -y -p $LOCAL_ENVS/tabsAreGreat python=2.7 ipykernel 'scipy==0.16.0'` + - Discover persistent environments + - `conda env list` + - Create a new kernel + - `$LOCAL_ENVS/tabsAreGreat/bin/python -m ipykernel install --prefix $JUPYTER_WORK --name tabsAreGreat --display-name "tabs are great"` + - Refresh main page + - Added ML modules + - Tensorflow 1.6 + - Theano + - Keras + - Optimized image size by starting from ubuntu base + ## Version 0.3.1 - Added `PYTHONUSERBASE` variable, which points at `tacc-work/jupyter_packages`, and allows for persistent local pip installs diff --git a/README.md b/README.md index 0884fd0..e57523d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ * Jupyter Notebook \(v5.2.0\)server * Conda Python 3.4.x and Python 2.7.x environments + * Custom environments and kernels now supported through `Advanced Jupyter.ipynb` notebook * Pre-installed python packages (highlights) * pandas * matplotlib 2.1.2 @@ -16,6 +17,7 @@ * Plotly, igraph, networkx, graphviz for graphs and plots * MIT's [Open Probabilistic Programming Stack](http://probcomp.org/) * [Common Lisp kernel and stack](http://www.sbcl.org/) + * v1.4.6 Now installed as binary * Bioconda and Bioconductor * BioPython * Git diff --git a/VERSION b/VERSION index 9e11b32..1c09c74 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.1 +0.3.3