diff --git a/.docker/entry.sh b/.docker/entry.sh
deleted file mode 100644
index 0cbd972868aae22456f1593acec2fdabadd9cb4a..0000000000000000000000000000000000000000
--- a/.docker/entry.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-exec jupyter lab --no-browser
diff --git a/.docker/global-project.stack.yaml b/.docker/global-project.stack.yaml
index cbeb4f011b6680817ea6aa0ccb839c2950244cc3..f370c671428fa5fe406c7f3d51d202491e402154 100644
--- a/.docker/global-project.stack.yaml
+++ b/.docker/global-project.stack.yaml
@@ -1,32 +1,61 @@
-packages: []
+resolver: lts-21.6
+
+flags: {}
+packages:
+ - .
+ - ./ipython-kernel
+ - ./ghc-parser
+ - ./ihaskell-display/ihaskell-aeson
+ - ./ihaskell-display/ihaskell-blaze
+ - ./ihaskell-display/ihaskell-charts
+ - ./ihaskell-display/ihaskell-diagrams
+ - ./ihaskell-display/ihaskell-gnuplot
+ - ./ihaskell-display/ihaskell-graphviz
+ - ./ihaskell-display/ihaskell-hatex
+ - ./ihaskell-display/ihaskell-juicypixels
+ - ./ihaskell-display/ihaskell-magic
+ - ./ihaskell-display/ihaskell-plot
+ # - ./ihaskell-display/ihaskell-static-canvas
+ - ./ihaskell-display/ihaskell-widgets
+
extra-deps:
-# dependencies needed for ihaskell-diagrams but not in Stackage snapshot
-- diagrams-cairo-1.4.1.1
-- cairo-0.13.8.1
-- pango-0.13.8.1
-- glib-0.13.8.1
-- gtk2hs-buildtools-0.13.8.0
-# dependencies needed for ihaskell-charts but not in Stackage snapshot
- Chart-cairo-1.9.3
-# dependencies needed for ihaskell-plot but not in Stackage snapshot
+- diagrams-cairo-1.4.2.1
+- cairo-0.13.10.0
+- pango-0.13.10.0
+- glib-0.13.10.0
- plot-0.2.3.11
-# dependencies needed for ihaskell-magic but not in Stackage snapshot
-- magic-1.1
-# dependencies needed for ihaskell-static-canvas but not in Stackage snapshot
-- static-canvas-0.2.0.3
-# other resolutions
-- active-0.2.0.14
-- diagrams-1.4
-- diagrams-core-1.4.2
-- diagrams-lib-1.4.3
-- statestack-0.3
-- diagrams-contrib-1.4.4
-- diagrams-svg-1.4.3
-- dual-tree-0.2.2.1
-- monoid-extras-0.5.1
-- force-layout-0.4.0.6
-- svg-builder-0.1.1
-- ihaskell-blaze-0.3.0.1
-- repa-3.4.1.4
+- statestack-0.3.1.1
+- ihaskell-hvega
+- hvega
+
+ghc-options:
+ # Eventually we want "$locals": -Wall -Wpartial-fields -Werror
+ # ghc-parser: -Wall -Wpartial-fields -Werror
+ # ihaskell: -Wall -Wpartial-fields -Werror
+ # ihaskell-widgets: -Wall -Wpartial-fields -Werror
-resolver: lts-17.8
+nix:
+ packages:
+ - blas
+ - cairo
+ - file
+ - fribidi
+ - gcc
+ - gfortran.cc.lib
+ - libdatrie
+ - liblapack
+ - libselinux
+ - libsepol
+ - libsodium # Needed by zeromq
+ - libthai
+ - ncurses
+ - pango
+ - pkg-config
+ - pcre
+ - pcre2
+ - pkgconfig
+ - util-linux
+ - xorg.libXdmcp
+ - zeromq
+ - zlib
diff --git a/.docker/jupyter_notebook_config.json b/.docker/jupyter_notebook_config.json
deleted file mode 100644
index 4b03e56d8052cd599e78b3aaf46ddb23791d43a7..0000000000000000000000000000000000000000
--- a/.docker/jupyter_notebook_config.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "NotebookApp": {
- "allow_origin" : "*",
- "token":"",
- "password":"",
- "nbserver_extensions": {
- "jupyterlab": true
- }
- }
-}
diff --git a/.docker/jupyter_notebook_config.py b/.docker/jupyter_notebook_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1b6068eb88c1ad0bf83560fdabdb13da0db7277
--- /dev/null
+++ b/.docker/jupyter_notebook_config.py
@@ -0,0 +1,622 @@
+# Configuration file for jupyter-notebook.
+
+#------------------------------------------------------------------------------
+# Application(SingletonConfigurable) configuration
+#------------------------------------------------------------------------------
+
+## This is an application.
+
+## The date format used by logging formatters for %(asctime)s
+#c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S'
+
+## The Logging format template
+#c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s'
+
+## Set the log level by value or name.
+#c.Application.log_level = 30
+
+#------------------------------------------------------------------------------
+# JupyterApp(Application) configuration
+#------------------------------------------------------------------------------
+
+## Base class for Jupyter applications
+
+## Answer yes to any prompts.
+#c.JupyterApp.answer_yes = False
+
+## Full path of a config file.
+#c.JupyterApp.config_file = ''
+
+## Specify a config file to load.
+#c.JupyterApp.config_file_name = ''
+
+## Generate default config file.
+#c.JupyterApp.generate_config = False
+
+#------------------------------------------------------------------------------
+# NotebookApp(JupyterApp) configuration
+#------------------------------------------------------------------------------
+
+## Set the Access-Control-Allow-Credentials: true header
+#c.NotebookApp.allow_credentials = False
+
+## Set the Access-Control-Allow-Origin header
+#
+# Use '*' to allow any origin to access your server.
+#
+# Takes precedence over allow_origin_pat.
+#c.NotebookApp.allow_origin = ''
+
+## Use a regular expression for the Access-Control-Allow-Origin header
+#
+# Requests from an origin matching the expression will get replies with:
+#
+# Access-Control-Allow-Origin: origin
+#
+# where `origin` is the origin of the request.
+#
+# Ignored if allow_origin is set.
+#c.NotebookApp.allow_origin_pat = ''
+
+## Whether to allow the user to run the notebook as root.
+#c.NotebookApp.allow_root = False
+
+## DEPRECATED use base_url
+#c.NotebookApp.base_project_url = '/'
+
+## The base URL for the notebook server.
+#
+# Leading and trailing slashes can be omitted, and will automatically be added.
+#c.NotebookApp.base_url = '/'
+
+## Specify what command to use to invoke a web browser when opening the notebook.
+# If not specified, the default browser will be determined by the `webbrowser`
+# standard library module, which allows setting of the BROWSER environment
+# variable to override it.
+#c.NotebookApp.browser = ''
+
+## The full path to an SSL/TLS certificate file.
+#c.NotebookApp.certfile = ''
+
+## The full path to a certificate authority certificate for SSL/TLS client
+# authentication.
+#c.NotebookApp.client_ca = ''
+
+## The config manager class to use
+#c.NotebookApp.config_manager_class = 'notebook.services.config.manager.ConfigManager'
+
+## The notebook manager class to use.
+#c.NotebookApp.contents_manager_class = 'notebook.services.contents.largefilemanager.LargeFileManager'
+
+## Extra keyword arguments to pass to `set_secure_cookie`. See tornado's
+# set_secure_cookie docs for details.
+#c.NotebookApp.cookie_options = {}
+
+## The random bytes used to secure cookies. By default this is a new random
+# number every time you start the Notebook. Set it to a value in a config file
+# to enable logins to persist across server sessions.
+#
+# Note: Cookie secrets should be kept private, do not share config files with
+# cookie_secret stored in plaintext (you can read the value from a file).
+#c.NotebookApp.cookie_secret = b''
+
+## The file where the cookie secret is stored.
+#c.NotebookApp.cookie_secret_file = ''
+
+## The default URL to redirect to from `/`
+#c.NotebookApp.default_url = '/tree'
+
+## Disable cross-site-request-forgery protection
+#
+# Jupyter notebook 4.3.1 introduces protection from cross-site request
+# forgeries, requiring API requests to either:
+#
+# - originate from pages served by this server (validated with XSRF cookie and
+# token), or - authenticate with a token
+#
+# Some anonymous compute resources still desire the ability to run code,
+# completely without authentication. These services can disable all
+# authentication and security checks, with the full knowledge of what that
+# implies.
+#c.NotebookApp.disable_check_xsrf = False
+
+## Whether to enable MathJax for typesetting math/TeX
+#
+# MathJax is the javascript library Jupyter uses to render math/LaTeX. It is
+# very large, so you may want to disable it if you have a slow internet
+# connection, or for offline use of the notebook.
+#
+# When disabled, equations etc. will appear as their untransformed TeX source.
+#c.NotebookApp.enable_mathjax = True
+
+## extra paths to look for Javascript notebook extensions
+#c.NotebookApp.extra_nbextensions_path = []
+
+## Extra paths to search for serving static files.
+#
+# This allows adding javascript/css to be available from the notebook server
+# machine, or overriding individual files in the IPython
+#c.NotebookApp.extra_static_paths = []
+
+## Extra paths to search for serving jinja templates.
+#
+# Can be used to override templates from notebook.templates.
+#c.NotebookApp.extra_template_paths = []
+
+##
+#c.NotebookApp.file_to_run = ''
+
+## Deprecated: Use minified JS file or not, mainly use during dev to avoid JS
+# recompilation
+#c.NotebookApp.ignore_minified_js = False
+
+## (bytes/sec) Maximum rate at which messages can be sent on iopub before they
+# are limited.
+#c.NotebookApp.iopub_data_rate_limit = 1000000
+
+## (msgs/sec) Maximum rate at which messages can be sent on iopub before they are
+# limited.
+#c.NotebookApp.iopub_msg_rate_limit = 1000
+
+## The IP address the notebook server will listen on.
+#c.NotebookApp.ip = 'localhost'
+
+## Supply extra arguments that will be passed to Jinja environment.
+#c.NotebookApp.jinja_environment_options = {}
+
+## Extra variables to supply to jinja templates when rendering.
+#c.NotebookApp.jinja_template_vars = {}
+
+## The kernel manager class to use.
+#c.NotebookApp.kernel_manager_class = 'notebook.services.kernels.kernelmanager.MappingKernelManager'
+
+## The kernel spec manager class to use. Should be a subclass of
+# `jupyter_client.kernelspec.KernelSpecManager`.
+#
+# The Api of KernelSpecManager is provisional and might change without warning
+# between this version of Jupyter and the next stable one.
+#c.NotebookApp.kernel_spec_manager_class = 'jupyter_client.kernelspec.KernelSpecManager'
+
+## The full path to a private key file for usage with SSL/TLS.
+#c.NotebookApp.keyfile = ''
+
+## The login handler class to use.
+#c.NotebookApp.login_handler_class = 'notebook.auth.login.LoginHandler'
+
+## The logout handler class to use.
+#c.NotebookApp.logout_handler_class = 'notebook.auth.logout.LogoutHandler'
+
+## The MathJax.js configuration file that is to be used.
+#c.NotebookApp.mathjax_config = 'TeX-AMS-MML_HTMLorMML-full,Safe'
+
+## A custom url for MathJax.js. Should be in the form of a case-sensitive url to
+# MathJax, for example: /static/components/MathJax/MathJax.js
+#c.NotebookApp.mathjax_url = ''
+
+## Dict of Python modules to load as notebook server extensions.Entry values can
+# be used to enable and disable the loading ofthe extensions. The extensions
+# will be loaded in alphabetical order.
+#c.NotebookApp.nbserver_extensions = {}
+
+## The directory to use for notebooks and kernels.
+#c.NotebookApp.notebook_dir = ''
+
+## Whether to open in a browser after starting. The specific browser used is
+# platform dependent and determined by the python standard library `webbrowser`
+# module, unless it is overridden using the --browser (NotebookApp.browser)
+# configuration option.
+#c.NotebookApp.open_browser = True
+
+## Hashed password to use for web authentication.
+#
+# To generate, type in a python/IPython shell:
+#
+# from notebook.auth import passwd; passwd()
+#
+# The string should be of the form type:salt:hashed-password.
+#c.NotebookApp.password = ''
+
+## Forces users to use a password for the Notebook server. This is useful in a
+# multi user environment, for instance when everybody in the LAN can access each
+# other's machine though ssh.
+#
+# In such a case, server the notebook server on localhost is not secure since
+# any user can connect to the notebook server via ssh.
+#c.NotebookApp.password_required = False
+
+## The port the notebook server will listen on.
+#c.NotebookApp.port = 8888
+
+## The number of additional ports to try if the specified port is not available.
+#c.NotebookApp.port_retries = 50
+
+## DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.
+#c.NotebookApp.pylab = 'disabled'
+
+## (sec) Time window used to check the message and data rate limits.
+#c.NotebookApp.rate_limit_window = 3
+
+## Reraise exceptions encountered loading server extensions?
+#c.NotebookApp.reraise_server_extension_failures = False
+
+## DEPRECATED use the nbserver_extensions dict instead
+#c.NotebookApp.server_extensions = []
+
+## The session manager class to use.
+#c.NotebookApp.session_manager_class = 'notebook.services.sessions.sessionmanager.SessionManager'
+
+## Supply SSL options for the tornado HTTPServer. See the tornado docs for
+# details.
+#c.NotebookApp.ssl_options = {}
+
+## Supply overrides for terminado. Currently only supports "shell_command".
+#c.NotebookApp.terminado_settings = {}
+
+## Token used for authenticating first-time connections to the server.
+#
+# When no password is enabled, the default is to generate a new, random token.
+#
+# Setting to an empty string disables authentication altogether, which is NOT
+# RECOMMENDED.
+c.NotebookApp.token = ''
+
+## Supply overrides for the tornado.web.Application that the Jupyter notebook
+# uses.
+#c.NotebookApp.tornado_settings = {}
+
+## Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-
+# For headerssent by the upstream reverse proxy. Necessary if the proxy handles
+# SSL
+#c.NotebookApp.trust_xheaders = False
+
+## DEPRECATED, use tornado_settings
+#c.NotebookApp.webapp_settings = {}
+
+## The base URL for websockets, if it differs from the HTTP server (hint: it
+# almost certainly doesn't).
+#
+# Should be in the form of an HTTP origin: ws[s]://hostname[:port]
+#c.NotebookApp.websocket_url = ''
+
+#------------------------------------------------------------------------------
+# LabApp(NotebookApp) configuration
+#------------------------------------------------------------------------------
+
+## The app directory to launch JupyterLab from.
+#c.LabApp.app_dir = ''
+
+## Whether to start the app in core mode. In this mode, JupyterLab will run using
+# the JavaScript assets that are within the installed JupyterLab Python package.
+# In core mode, third party extensions are disabled. The `--dev-mode` flag is an
+# alias to this to be used when the Python package itself is installed in
+# development mode (`pip install -e .`).
+#c.LabApp.core_mode = False
+
+## The default URL to redirect to from `/`
+#c.LabApp.default_url = '/lab'
+
+#------------------------------------------------------------------------------
+# ConnectionFileMixin(LoggingConfigurable) configuration
+#------------------------------------------------------------------------------
+
+## Mixin for configurable classes that work with connection files
+
+## JSON file in which to store connection info [default: kernel-<pid>.json]
+#
+# This file will contain the IP, ports, and authentication key needed to connect
+# clients to this kernel. By default, this file will be created in the security
+# dir of the current profile, but can be specified by absolute path.
+#c.ConnectionFileMixin.connection_file = ''
+
+## set the control (ROUTER) port [default: random]
+#c.ConnectionFileMixin.control_port = 0
+
+## set the heartbeat port [default: random]
+#c.ConnectionFileMixin.hb_port = 0
+
+## set the iopub (PUB) port [default: random]
+#c.ConnectionFileMixin.iopub_port = 0
+
+## Set the kernel's IP address [default localhost]. If the IP address is
+# something other than localhost, then Consoles on other machines will be able
+# to connect to the Kernel, so be careful!
+#c.ConnectionFileMixin.ip = ''
+
+## set the shell (ROUTER) port [default: random]
+#c.ConnectionFileMixin.shell_port = 0
+
+## set the stdin (ROUTER) port [default: random]
+#c.ConnectionFileMixin.stdin_port = 0
+
+##
+#c.ConnectionFileMixin.transport = 'tcp'
+
+#------------------------------------------------------------------------------
+# KernelManager(ConnectionFileMixin) configuration
+#------------------------------------------------------------------------------
+
+## Manages a single kernel in a subprocess on this host.
+#
+# This version starts kernels with Popen.
+
+## Should we autorestart the kernel if it dies.
+#c.KernelManager.autorestart = True
+
+## DEPRECATED: Use kernel_name instead.
+#
+# The Popen Command to launch the kernel. Override this if you have a custom
+# kernel. If kernel_cmd is specified in a configuration file, Jupyter does not
+# pass any arguments to the kernel, because it cannot make any assumptions about
+# the arguments that the kernel understands. In particular, this means that the
+# kernel does not receive the option --debug if it given on the Jupyter command
+# line.
+#c.KernelManager.kernel_cmd = []
+
+## Time to wait for a kernel to terminate before killing it, in seconds.
+#c.KernelManager.shutdown_wait_time = 5.0
+
+#------------------------------------------------------------------------------
+# Session(Configurable) configuration
+#------------------------------------------------------------------------------
+
+## Object for handling serialization and sending of messages.
+#
+# The Session object handles building messages and sending them with ZMQ sockets
+# or ZMQStream objects. Objects can communicate with each other over the
+# network via Session objects, and only need to work with the dict-based IPython
+# message spec. The Session will handle serialization/deserialization, security,
+# and metadata.
+#
+# Sessions support configurable serialization via packer/unpacker traits, and
+# signing with HMAC digests via the key/keyfile traits.
+#
+# Parameters ----------
+#
+# debug : bool
+# whether to trigger extra debugging statements
+# packer/unpacker : str : 'json', 'pickle' or import_string
+# importstrings for methods to serialize message parts. If just
+# 'json' or 'pickle', predefined JSON and pickle packers will be used.
+# Otherwise, the entire importstring must be used.
+#
+# The functions must accept at least valid JSON input, and output *bytes*.
+#
+# For example, to use msgpack:
+# packer = 'msgpack.packb', unpacker='msgpack.unpackb'
+# pack/unpack : callables
+# You can also set the pack/unpack callables for serialization directly.
+# session : bytes
+# the ID of this Session object. The default is to generate a new UUID.
+# username : unicode
+# username added to message headers. The default is to ask the OS.
+# key : bytes
+# The key used to initialize an HMAC signature. If unset, messages
+# will not be signed or checked.
+# keyfile : filepath
+# The file containing a key. If this is set, `key` will be initialized
+# to the contents of the file.
+
+## Threshold (in bytes) beyond which an object's buffer should be extracted to
+# avoid pickling.
+#c.Session.buffer_threshold = 1024
+
+## Whether to check PID to protect against calls after fork.
+#
+# This check can be disabled if fork-safety is handled elsewhere.
+#c.Session.check_pid = True
+
+## Threshold (in bytes) beyond which a buffer should be sent without copying.
+#c.Session.copy_threshold = 65536
+
+## Debug output in the Session
+#c.Session.debug = False
+
+## The maximum number of digests to remember.
+#
+# The digest history will be culled when it exceeds this value.
+#c.Session.digest_history_size = 65536
+
+## The maximum number of items for a container to be introspected for custom
+# serialization. Containers larger than this are pickled outright.
+#c.Session.item_threshold = 64
+
+## execution key, for signing messages.
+#c.Session.key = b''
+
+## path to file containing execution key.
+#c.Session.keyfile = ''
+
+## Metadata dictionary, which serves as the default top-level metadata dict for
+# each message.
+#c.Session.metadata = {}
+
+## The name of the packer for serializing messages. Should be one of 'json',
+# 'pickle', or an import name for a custom callable serializer.
+#c.Session.packer = 'json'
+
+## The UUID identifying this session.
+#c.Session.session = ''
+
+## The digest scheme used to construct the message signatures. Must have the form
+# 'hmac-HASH'.
+#c.Session.signature_scheme = 'hmac-sha256'
+
+## The name of the unpacker for unserializing messages. Only used with custom
+# functions for `packer`.
+#c.Session.unpacker = 'json'
+
+## Username for the Session. Default is your system username.
+#c.Session.username = 'username'
+
+#------------------------------------------------------------------------------
+# MultiKernelManager(LoggingConfigurable) configuration
+#------------------------------------------------------------------------------
+
+## A class for managing multiple kernels.
+
+## The name of the default kernel to start
+#c.MultiKernelManager.default_kernel_name = 'python3'
+
+## The kernel manager class. This is configurable to allow subclassing of the
+# KernelManager for customized behavior.
+#c.MultiKernelManager.kernel_manager_class = 'jupyter_client.ioloop.IOLoopKernelManager'
+
+#------------------------------------------------------------------------------
+# MappingKernelManager(MultiKernelManager) configuration
+#------------------------------------------------------------------------------
+
+## A KernelManager that handles notebook mapping and HTTP error handling
+
+##
+#c.MappingKernelManager.root_dir = ''
+
+#------------------------------------------------------------------------------
+# ContentsManager(LoggingConfigurable) configuration
+#------------------------------------------------------------------------------
+
+## Base class for serving files and directories.
+#
+# This serves any text or binary file, as well as directories, with special
+# handling for JSON notebook documents.
+#
+# Most APIs take a path argument, which is always an API-style unicode path, and
+# always refers to a directory.
+#
+# - unicode, not url-escaped
+# - '/'-separated
+# - leading and trailing '/' will be stripped
+# - if unspecified, path defaults to '',
+# indicating the root path.
+
+##
+#c.ContentsManager.checkpoints = None
+
+##
+#c.ContentsManager.checkpoints_class = 'notebook.services.contents.checkpoints.Checkpoints'
+
+##
+#c.ContentsManager.checkpoints_kwargs = {}
+
+## Glob patterns to hide in file and directory listings.
+#c.ContentsManager.hide_globs = ['__pycache__', '*.pyc', '*.pyo', '.DS_Store', '*.so', '*.dylib', '*~']
+
+## Python callable or importstring thereof
+#
+# To be called on a contents model prior to save.
+#
+# This can be used to process the structure, such as removing notebook outputs
+# or other side effects that should not be saved.
+#
+# It will be called as (all arguments passed by keyword)::
+#
+# hook(path=path, model=model, contents_manager=self)
+#
+# - model: the model to be saved. Includes file contents.
+# Modifying this dict will affect the file that is stored.
+# - path: the API path of the save destination
+# - contents_manager: this ContentsManager instance
+#c.ContentsManager.pre_save_hook = None
+
+##
+#c.ContentsManager.root_dir = '/'
+
+## The base name used when creating untitled directories.
+#c.ContentsManager.untitled_directory = 'Untitled Folder'
+
+## The base name used when creating untitled files.
+#c.ContentsManager.untitled_file = 'untitled'
+
+## The base name used when creating untitled notebooks.
+#c.ContentsManager.untitled_notebook = 'Untitled'
+
+#------------------------------------------------------------------------------
+# FileManagerMixin(Configurable) configuration
+#------------------------------------------------------------------------------
+
+## Mixin for ContentsAPI classes that interact with the filesystem.
+#
+# Provides facilities for reading, writing, and copying both notebooks and
+# generic files.
+#
+# Shared by FileContentsManager and FileCheckpoints.
+#
+# Note ---- Classes using this mixin must provide the following attributes:
+#
+# root_dir : unicode
+# A directory against against which API-style paths are to be resolved.
+#
+# log : logging.Logger
+
+## By default notebooks are saved on disk on a temporary file and then if
+# succefully written, it replaces the old ones. This procedure, namely
+# 'atomic_writing', causes some bugs on file system whitout operation order
+# enforcement (like some networked fs). If set to False, the new notebook is
+# written directly on the old one which could fail (eg: full filesystem or quota
+# )
+#c.FileManagerMixin.use_atomic_writing = True
+
+#------------------------------------------------------------------------------
+# FileContentsManager(FileManagerMixin,ContentsManager) configuration
+#------------------------------------------------------------------------------
+
+## Python callable or importstring thereof
+#
+# to be called on the path of a file just saved.
+#
+# This can be used to process the file on disk, such as converting the notebook
+# to a script or HTML via nbconvert.
+#
+# It will be called as (all arguments passed by keyword)::
+#
+# hook(os_path=os_path, model=model, contents_manager=instance)
+#
+# - path: the filesystem path to the file just written - model: the model
+# representing the file - contents_manager: this ContentsManager instance
+#c.FileContentsManager.post_save_hook = None
+
+##
+#c.FileContentsManager.root_dir = ''
+
+## DEPRECATED, use post_save_hook. Will be removed in Notebook 5.0
+#c.FileContentsManager.save_script = False
+
+#------------------------------------------------------------------------------
+# NotebookNotary(LoggingConfigurable) configuration
+#------------------------------------------------------------------------------
+
+## A class for computing and verifying notebook signatures.
+
+## The hashing algorithm used to sign notebooks.
+#c.NotebookNotary.algorithm = 'sha256'
+
+## The sqlite file in which to store notebook signatures. By default, this will
+# be in your Jupyter data directory. You can set it to ':memory:' to disable
+# sqlite writing to the filesystem.
+#c.NotebookNotary.db_file = ''
+
+## The secret key with which notebooks are signed.
+#c.NotebookNotary.secret = b''
+
+## The file where the secret key is stored.
+#c.NotebookNotary.secret_file = ''
+
+## A callable returning the storage backend for notebook signatures. The default
+# uses an SQLite database.
+#c.NotebookNotary.store_factory = traitlets.Undefined
+
+#------------------------------------------------------------------------------
+# KernelSpecManager(LoggingConfigurable) configuration
+#------------------------------------------------------------------------------
+
+## If there is no Python kernelspec registered and the IPython kernel is
+# available, ensure it is added to the spec list.
+#c.KernelSpecManager.ensure_native_kernel = True
+
+## The kernel spec class. This is configurable to allow subclassing of the
+# KernelSpecManager for customized behavior.
+#c.KernelSpecManager.kernel_spec_class = 'jupyter_client.kernelspec.KernelSpec'
+
+## Whitelist of allowed kernel names.
+#
+# By default, all installed kernels are allowed.
+#c.KernelSpecManager.whitelist = set()
diff --git a/.docker/matplotlibrc b/.docker/matplotlibrc
new file mode 100644
index 0000000000000000000000000000000000000000..7f2b6be3ff8871f1fc9f5af8592baefc49692a12
--- /dev/null
+++ b/.docker/matplotlibrc
@@ -0,0 +1,628 @@
+### MATPLOTLIBRC FORMAT
+
+# This is a sample matplotlib configuration file - you can find a copy
+# of it on your system in
+# site-packages/matplotlib/mpl-data/matplotlibrc. If you edit it
+# there, please note that it will be overwritten in your next install.
+# If you want to keep a permanent local copy that will not be
+# overwritten, place it in the following location:
+# unix/linux:
+# $HOME/.config/matplotlib/matplotlibrc or
+# $XDG_CONFIG_HOME/matplotlib/matplotlibrc (if $XDG_CONFIG_HOME is set)
+# other platforms:
+# $HOME/.matplotlib/matplotlibrc
+#
+# See http://matplotlib.org/users/customizing.html#the-matplotlibrc-file for
+# more details on the paths which are checked for the configuration file.
+#
+# This file is best viewed in a editor which supports python mode
+# syntax highlighting. Blank lines, or lines starting with a comment
+# symbol, are ignored, as are trailing comments. Other lines must
+# have the format
+# key : val # optional comment
+#
+# Colors: for the color values below, you can either use - a
+# matplotlib color string, such as r, k, or b - an rgb tuple, such as
+# (1.0, 0.5, 0.0) - a hex string, such as ff00ff - a scalar
+# grayscale intensity such as 0.75 - a legal html color name, e.g., red,
+# blue, darkslategray
+
+#### CONFIGURATION BEGINS HERE
+
+# The default backend; one of GTK GTKAgg GTKCairo GTK3Agg GTK3Cairo
+# MacOSX Qt4Agg Qt5Agg TkAgg WX WXAgg Agg Cairo GDK PS PDF SVG
+# Template.
+# You can also deploy your own backend outside of matplotlib by
+# referring to the module name (which must be in the PYTHONPATH) as
+# 'module://my_backend'.
+backend : Qt5Agg
+
+# If you are using the Qt4Agg backend, you can choose here
+# to use the PyQt4 bindings or the newer PySide bindings to
+# the underlying Qt4 toolkit.
+#backend.qt4 : PyQt4 # PyQt4 | PySide
+
+# Note that this can be overridden by the environment variable
+# QT_API used by Enthought Tool Suite (ETS); valid values are
+# "pyqt" and "pyside". The "pyqt" setting has the side effect of
+# forcing the use of Version 2 API for QString and QVariant.
+
+# The port to use for the web server in the WebAgg backend.
+# webagg.port : 8888
+
+# If webagg.port is unavailable, a number of other random ports will
+# be tried until one that is available is found.
+# webagg.port_retries : 50
+
+# When True, open the webbrowser to the plot that is shown
+# webagg.open_in_browser : True
+
+# When True, the figures rendered in the nbagg backend are created with
+# a transparent background.
+# nbagg.transparent : False
+
+# if you are running pyplot inside a GUI and your backend choice
+# conflicts, we will automatically try to find a compatible one for
+# you if backend_fallback is True
+#backend_fallback: True
+
+#interactive : False
+#toolbar : toolbar2 # None | toolbar2 ("classic" is deprecated)
+#timezone : UTC # a pytz timezone string, e.g., US/Central or Europe/Paris
+
+# Where your matplotlib data lives if you installed to a non-default
+# location. This is where the matplotlib fonts, bitmaps, etc reside
+#datapath : /home/jdhunter/mpldata
+
+
+### LINES
+# See http://matplotlib.org/api/artist_api.html#module-matplotlib.lines for more
+# information on line properties.
+#lines.linewidth : 1.5 # line width in points
+#lines.linestyle : - # solid line
+#lines.color : C0 # has no affect on plot(); see axes.prop_cycle
+#lines.marker : None # the default marker
+#lines.markeredgewidth : 1.0 # the line width around the marker symbol
+#lines.markersize : 6 # markersize, in points
+#lines.dash_joinstyle : miter # miter|round|bevel
+#lines.dash_capstyle : butt # butt|round|projecting
+#lines.solid_joinstyle : miter # miter|round|bevel
+#lines.solid_capstyle : projecting # butt|round|projecting
+#lines.antialiased : True # render lines in antialiased (no jaggies)
+
+# The three standard dash patterns. These are scaled by the linewidth.
+#lines.dashed_pattern : 2.8, 1.2
+#lines.dashdot_pattern : 4.8, 1.2, 0.8, 1.2
+#lines.dotted_pattern : 1.1, 1.1
+#lines.scale_dashes : True
+
+#markers.fillstyle: full # full|left|right|bottom|top|none
+
+### PATCHES
+# Patches are graphical objects that fill 2D space, like polygons or
+# circles. See
+# http://matplotlib.org/api/artist_api.html#module-matplotlib.patches
+# information on patch properties
+#patch.linewidth : 1 # edge width in points.
+#patch.facecolor : C0
+#patch.edgecolor : black # if forced, or patch is not filled
+#patch.force_edgecolor : False # True to always use edgecolor
+#patch.antialiased : True # render patches in antialiased (no jaggies)
+
+### HATCHES
+#hatch.color : k
+#hatch.linewidth : 1.0
+
+### Boxplot
+#boxplot.notch : False
+#boxplot.vertical : True
+#boxplot.whiskers : 1.5
+#boxplot.bootstrap : None
+#boxplot.patchartist : False
+#boxplot.showmeans : False
+#boxplot.showcaps : True
+#boxplot.showbox : True
+#boxplot.showfliers : True
+#boxplot.meanline : False
+
+#boxplot.flierprops.color : 'k'
+#boxplot.flierprops.marker : 'o'
+#boxplot.flierprops.markerfacecolor : 'none'
+#boxplot.flierprops.markeredgecolor : 'k'
+#boxplot.flierprops.markersize : 6
+#boxplot.flierprops.linestyle : 'none'
+#boxplot.flierprops.linewidth : 1.0
+
+#boxplot.boxprops.color : 'k'
+#boxplot.boxprops.linewidth : 1.0
+#boxplot.boxprops.linestyle : '-'
+
+#boxplot.whiskerprops.color : 'k'
+#boxplot.whiskerprops.linewidth : 1.0
+#boxplot.whiskerprops.linestyle : '-'
+
+#boxplot.capprops.color : 'k'
+#boxplot.capprops.linewidth : 1.0
+#boxplot.capprops.linestyle : '-'
+
+#boxplot.medianprops.color : 'C1'
+#boxplot.medianprops.linewidth : 1.0
+#boxplot.medianprops.linestyle : '-'
+
+#boxplot.meanprops.color : 'C2'
+#boxplot.meanprops.marker : '^'
+#boxplot.meanprops.markerfacecolor : 'C2'
+#boxplot.meanprops.markeredgecolor : 'C2'
+#boxplot.meanprops.markersize : 6
+#boxplot.meanprops.linestyle : 'none'
+#boxplot.meanprops.linewidth : 1.0
+
+### FONT
+#
+# font properties used by text.Text. See
+# http://matplotlib.org/api/font_manager_api.html for more
+# information on font properties. The 6 font properties used for font
+# matching are given below with their default values.
+#
+# The font.family property has five values: 'serif' (e.g., Times),
+# 'sans-serif' (e.g., Helvetica), 'cursive' (e.g., Zapf-Chancery),
+# 'fantasy' (e.g., Western), and 'monospace' (e.g., Courier). Each of
+# these font families has a default list of font names in decreasing
+# order of priority associated with them. When text.usetex is False,
+# font.family may also be one or more concrete font names.
+#
+# The font.style property has three values: normal (or roman), italic
+# or oblique. The oblique style will be used for italic, if it is not
+# present.
+#
+# The font.variant property has two values: normal or small-caps. For
+# TrueType fonts, which are scalable fonts, small-caps is equivalent
+# to using a font size of 'smaller', or about 83%% of the current font
+# size.
+#
+# The font.weight property has effectively 13 values: normal, bold,
+# bolder, lighter, 100, 200, 300, ..., 900. Normal is the same as
+# 400, and bold is 700. bolder and lighter are relative values with
+# respect to the current weight.
+#
+# The font.stretch property has 11 values: ultra-condensed,
+# extra-condensed, condensed, semi-condensed, normal, semi-expanded,
+# expanded, extra-expanded, ultra-expanded, wider, and narrower. This
+# property is not currently implemented.
+#
+# The font.size property is the default font size for text, given in pts.
+# 10 pt is the standard value.
+#
+#font.family : sans-serif
+font.family : Noto Sans CJK JP
+#font.style : normal
+#font.variant : normal
+#font.weight : medium
+#font.stretch : normal
+# note that font.size controls default text sizes. To configure
+# special text sizes tick labels, axes, labels, title, etc, see the rc
+# settings for axes and ticks. Special text sizes can be defined
+# relative to font.size, using the following values: xx-small, x-small,
+# small, medium, large, x-large, xx-large, larger, or smaller
+#font.size : 10.0
+#font.serif : DejaVu Serif, Bitstream Vera Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif
+#font.sans-serif : Source Han Code JP, DejaVu Sans, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif
+#font.cursive : Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, cursive
+#font.fantasy : Comic Sans MS, Chicago, Charcoal, Impact, Western, Humor Sans, xkcd, fantasy
+#font.monospace : DejaVu Sans Mono, Bitstream Vera Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace
+
+### TEXT
+# text properties used by text.Text. See
+# http://matplotlib.org/api/artist_api.html#module-matplotlib.text for more
+# information on text properties
+
+#text.color : black
+
+### LaTeX customizations. See http://wiki.scipy.org/Cookbook/Matplotlib/UsingTex
+#text.usetex : False # use latex for all text handling. The following fonts
+ # are supported through the usual rc parameter settings:
+ # new century schoolbook, bookman, times, palatino,
+ # zapf chancery, charter, serif, sans-serif, helvetica,
+ # avant garde, courier, monospace, computer modern roman,
+ # computer modern sans serif, computer modern typewriter
+ # If another font is desired which can loaded using the
+ # LaTeX \usepackage command, please inquire at the
+ # matplotlib mailing list
+#text.latex.unicode : False # use "ucs" and "inputenc" LaTeX packages for handling
+ # unicode strings.
+#text.latex.preamble : # IMPROPER USE OF THIS FEATURE WILL LEAD TO LATEX FAILURES
+ # AND IS THEREFORE UNSUPPORTED. PLEASE DO NOT ASK FOR HELP
+ # IF THIS FEATURE DOES NOT DO WHAT YOU EXPECT IT TO.
+ # preamble is a comma separated list of LaTeX statements
+ # that are included in the LaTeX document preamble.
+ # An example:
+ # text.latex.preamble : \usepackage{bm},\usepackage{euler}
+ # The following packages are always loaded with usetex, so
+ # beware of package collisions: color, geometry, graphicx,
+ # type1cm, textcomp. Adobe Postscript (PSSNFS) font packages
+ # may also be loaded, depending on your font settings
+
+#text.dvipnghack : None # some versions of dvipng don't handle alpha
+ # channel properly. Use True to correct
+ # and flush ~/.matplotlib/tex.cache
+ # before testing and False to force
+ # correction off. None will try and
+ # guess based on your dvipng version
+
+#text.hinting : auto # May be one of the following:
+ # 'none': Perform no hinting
+ # 'auto': Use FreeType's autohinter
+ # 'native': Use the hinting information in the
+ # font file, if available, and if your
+ # FreeType library supports it
+ # 'either': Use the native hinting information,
+ # or the autohinter if none is available.
+ # For backward compatibility, this value may also be
+ # True === 'auto' or False === 'none'.
+#text.hinting_factor : 8 # Specifies the amount of softness for hinting in the
+ # horizontal direction. A value of 1 will hint to full
+ # pixels. A value of 2 will hint to half pixels etc.
+
+#text.antialiased : True # If True (default), the text will be antialiased.
+ # This only affects the Agg backend.
+
+# The following settings allow you to select the fonts in math mode.
+# They map from a TeX font name to a fontconfig font pattern.
+# These settings are only used if mathtext.fontset is 'custom'.
+# Note that this "custom" mode is unsupported and may go away in the
+# future.
+#mathtext.cal : cursive
+#mathtext.rm : serif
+#mathtext.tt : monospace
+#mathtext.it : serif:italic
+#mathtext.bf : serif:bold
+#mathtext.sf : sans
+#mathtext.fontset : dejavusans # Should be 'dejavusans' (default),
+ # 'dejavuserif', 'cm' (Computer Modern), 'stix',
+ # 'stixsans' or 'custom'
+#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern
+ # fonts when a symbol can not be found in one of
+ # the custom math fonts.
+
+#mathtext.default : it # The default font to use for math.
+ # Can be any of the LaTeX font names, including
+ # the special name "regular" for the same font
+ # used in regular text.
+
+### AXES
+# default face and edge color, default tick sizes,
+# default fontsizes for ticklabels, and so on. See
+# http://matplotlib.org/api/axes_api.html#module-matplotlib.axes
+#axes.facecolor : white # axes background color
+#axes.edgecolor : black # axes edge color
+#axes.linewidth : 0.8 # edge linewidth
+#axes.grid : False # display grid or not
+#axes.titlesize : large # fontsize of the axes title
+#axes.titlepad : 6.0 # pad between axes and title in points
+#axes.labelsize : medium # fontsize of the x any y labels
+#axes.labelpad : 4.0 # space between label and axis
+#axes.labelweight : normal # weight of the x and y labels
+#axes.labelcolor : black
+#axes.axisbelow : 'line' # draw axis gridlines and ticks below
+ # patches (True); above patches but below
+ # lines ('line'); or above all (False)
+
+#axes.formatter.limits : -7, 7 # use scientific notation if log10
+ # of the axis range is smaller than the
+ # first or larger than the second
+#axes.formatter.use_locale : False # When True, format tick labels
+ # according to the user's locale.
+ # For example, use ',' as a decimal
+ # separator in the fr_FR locale.
+#axes.formatter.use_mathtext : False # When True, use mathtext for scientific
+ # notation.
+#axes.formatter.useoffset : True # If True, the tick label formatter
+ # will default to labeling ticks relative
+ # to an offset when the data range is
+ # small compared to the minimum absolute
+ # value of the data.
+#axes.formatter.offset_threshold : 4 # When useoffset is True, the offset
+ # will be used when it can remove
+ # at least this number of significant
+ # digits from tick labels.
+
+# axes.spines.left : True # display axis spines
+# axes.spines.bottom : True
+# axes.spines.top : True
+# axes.spines.right : True
+
+
+#axes.unicode_minus : True # use unicode for the minus symbol
+ # rather than hyphen. See
+ # http://en.wikipedia.org/wiki/Plus_and_minus_signs#Character_codes
+#axes.prop_cycle : cycler('color',
+# ['1f77b4', 'ff7f0e', '2ca02c', 'd62728',
+# '9467bd', '8c564b', 'e377c2', '7f7f7f',
+# 'bcbd22', '17becf'])
+ # color cycle for plot lines
+ # as list of string colorspecs:
+ # single letter, long name, or
+ # web-style hex
+#axes.autolimit_mode : data # How to scale axes limits to the data.
+ # Use "data" to use data limits, plus some margin
+ # Use "round_number" move to the nearest "round" number
+#axes.xmargin : .05 # x margin. See `axes.Axes.margins`
+#axes.ymargin : .05 # y margin See `axes.Axes.margins`
+
+#polaraxes.grid : True # display grid on polar axes
+#axes3d.grid : True # display grid on 3d axes
+
+### DATES
+# These control the default format strings used in AutoDateFormatter.
+# Any valid format datetime format string can be used (see the python
+# `datetime` for details). For example using '%%x' will use the locale date representation
+# '%%X' will use the locale time representation and '%%c' will use the full locale datetime
+# representation.
+# These values map to the scales:
+# {'year': 365, 'month': 30, 'day': 1, 'hour': 1/24, 'minute': 1 / (24 * 60)}
+
+# date.autoformatter.year : %Y
+# date.autoformatter.month : %Y-%m
+# date.autoformatter.day : %Y-%m-%d
+# date.autoformatter.hour : %m-%d %H
+# date.autoformatter.minute : %d %H:%M
+# date.autoformatter.second : %H:%M:%S
+# date.autoformatter.microsecond : %M:%S.%f
+
+### TICKS
+# see http://matplotlib.org/api/axis_api.html#matplotlib.axis.Tick
+#xtick.top : False # draw ticks on the top side
+#xtick.bottom : True # draw ticks on the bottom side
+#xtick.major.size : 3.5 # major tick size in points
+#xtick.minor.size : 2 # minor tick size in points
+#xtick.major.width : 0.8 # major tick width in points
+#xtick.minor.width : 0.6 # minor tick width in points
+#xtick.major.pad : 3.5 # distance to major tick label in points
+#xtick.minor.pad : 3.4 # distance to the minor tick label in points
+#xtick.color : k # color of the tick labels
+#xtick.labelsize : medium # fontsize of the tick labels
+#xtick.direction : out # direction: in, out, or inout
+#xtick.minor.visible : False # visibility of minor ticks on x-axis
+#xtick.major.top : True # draw x axis top major ticks
+#xtick.major.bottom : True # draw x axis bottom major ticks
+#xtick.minor.top : True # draw x axis top minor ticks
+#xtick.minor.bottom : True # draw x axis bottom minor ticks
+
+#ytick.left : True # draw ticks on the left side
+#ytick.right : False # draw ticks on the right side
+#ytick.major.size : 3.5 # major tick size in points
+#ytick.minor.size : 2 # minor tick size in points
+#ytick.major.width : 0.8 # major tick width in points
+#ytick.minor.width : 0.6 # minor tick width in points
+#ytick.major.pad : 3.5 # distance to major tick label in points
+#ytick.minor.pad : 3.4 # distance to the minor tick label in points
+#ytick.color : k # color of the tick labels
+#ytick.labelsize : medium # fontsize of the tick labels
+#ytick.direction : out # direction: in, out, or inout
+#ytick.minor.visible : False # visibility of minor ticks on y-axis
+#ytick.major.left : True # draw y axis left major ticks
+#ytick.major.right : True # draw y axis right major ticks
+#ytick.minor.left : True # draw y axis left minor ticks
+#ytick.minor.right : True # draw y axis right minor ticks
+
+
+### GRIDS
+#grid.color : b0b0b0 # grid color
+#grid.linestyle : - # solid
+#grid.linewidth : 0.8 # in points
+#grid.alpha : 1.0 # transparency, between 0.0 and 1.0
+
+### Legend
+#legend.loc : best
+#legend.frameon : True # if True, draw the legend on a background patch
+#legend.framealpha : 0.8 # legend patch transparency
+#legend.facecolor : inherit # inherit from axes.facecolor; or color spec
+#legend.edgecolor : 0.8 # background patch boundary color
+#legend.fancybox : True # if True, use a rounded box for the
+ # legend background, else a rectangle
+#legend.shadow : False # if True, give background a shadow effect
+#legend.numpoints : 1 # the number of marker points in the legend line
+#legend.scatterpoints : 1 # number of scatter points
+#legend.markerscale : 1.0 # the relative size of legend markers vs. original
+#legend.fontsize : medium
+# Dimensions as fraction of fontsize:
+#legend.borderpad : 0.4 # border whitespace
+#legend.labelspacing : 0.5 # the vertical space between the legend entries
+#legend.handlelength : 2.0 # the length of the legend lines
+#legend.handleheight : 0.7 # the height of the legend handle
+#legend.handletextpad : 0.8 # the space between the legend line and legend text
+#legend.borderaxespad : 0.5 # the border between the axes and legend edge
+#legend.columnspacing : 2.0 # column separation
+
+### FIGURE
+# See http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure
+#figure.titlesize : large # size of the figure title (Figure.suptitle())
+#figure.titleweight : normal # weight of the figure title
+#figure.figsize : 6.4, 4.8 # figure size in inches
+#figure.dpi : 100 # figure dots per inch
+#figure.facecolor : white # figure facecolor; 0.75 is scalar gray
+#figure.edgecolor : white # figure edgecolor
+#figure.autolayout : False # When True, automatically adjust subplot
+ # parameters to make the plot fit the figure
+#figure.max_open_warning : 20 # The maximum number of figures to open through
+ # the pyplot interface before emitting a warning.
+ # If less than one this feature is disabled.
+
+# The figure subplot parameters. All dimensions are a fraction of the
+#figure.subplot.left : 0.125 # the left side of the subplots of the figure
+#figure.subplot.right : 0.9 # the right side of the subplots of the figure
+#figure.subplot.bottom : 0.11 # the bottom of the subplots of the figure
+#figure.subplot.top : 0.88 # the top of the subplots of the figure
+#figure.subplot.wspace : 0.2 # the amount of width reserved for blank space between subplots,
+ # expressed as a fraction of the average axis width
+#figure.subplot.hspace : 0.2 # the amount of height reserved for white space between subplots,
+ # expressed as a fraction of the average axis height
+
+
+### IMAGES
+#image.aspect : equal # equal | auto | a number
+#image.interpolation : nearest # see help(imshow) for options
+#image.cmap : viridis # A colormap name, gray etc...
+#image.lut : 256 # the size of the colormap lookup table
+#image.origin : upper # lower | upper
+#image.resample : True
+#image.composite_image : True # When True, all the images on a set of axes are
+ # combined into a single composite image before
+ # saving a figure as a vector graphics file,
+ # such as a PDF.
+
+### CONTOUR PLOTS
+#contour.negative_linestyle : dashed # dashed | solid
+#contour.corner_mask : True # True | False | legacy
+
+### ERRORBAR PLOTS
+#errorbar.capsize : 0 # length of end cap on error bars in pixels
+
+### HISTOGRAM PLOTS
+#hist.bins : 10 # The default number of histogram bins.
+ # If Numpy 1.11 or later is
+ # installed, may also be `auto`
+
+### SCATTER PLOTS
+#scatter.marker : o # The default marker type for scatter plots.
+
+### Agg rendering
+### Warning: experimental, 2008/10/10
+#agg.path.chunksize : 0 # 0 to disable; values in the range
+ # 10000 to 100000 can improve speed slightly
+ # and prevent an Agg rendering failure
+ # when plotting very large data sets,
+ # especially if they are very gappy.
+ # It may cause minor artifacts, though.
+ # A value of 20000 is probably a good
+ # starting point.
+### SAVING FIGURES
+#path.simplify : True # When True, simplify paths by removing "invisible"
+ # points to reduce file size and increase rendering
+ # speed
+#path.simplify_threshold : 0.1 # The threshold of similarity below which
+ # vertices will be removed in the simplification
+ # process
+#path.snap : True # When True, rectilinear axis-aligned paths will be snapped to
+ # the nearest pixel when certain criteria are met. When False,
+ # paths will never be snapped.
+#path.sketch : None # May be none, or a 3-tuple of the form (scale, length,
+ # randomness).
+ # *scale* is the amplitude of the wiggle
+ # perpendicular to the line (in pixels). *length*
+ # is the length of the wiggle along the line (in
+ # pixels). *randomness* is the factor by which
+ # the length is randomly scaled.
+
+# the default savefig params can be different from the display params
+# e.g., you may want a higher resolution, or to make the figure
+# background white
+#savefig.dpi : figure # figure dots per inch or 'figure'
+#savefig.facecolor : white # figure facecolor when saving
+#savefig.edgecolor : white # figure edgecolor when saving
+#savefig.format : png # png, ps, pdf, svg
+#savefig.bbox : standard # 'tight' or 'standard'.
+ # 'tight' is incompatible with pipe-based animation
+ # backends but will workd with temporary file based ones:
+ # e.g. setting animation.writer to ffmpeg will not work,
+ # use ffmpeg_file instead
+#savefig.pad_inches : 0.1 # Padding to be used when bbox is set to 'tight'
+#savefig.jpeg_quality: 95 # when a jpeg is saved, the default quality parameter.
+#savefig.directory : ~ # default directory in savefig dialog box,
+ # leave empty to always use current working directory
+#savefig.transparent : False # setting that controls whether figures are saved with a
+ # transparent background by default
+
+# tk backend params
+#tk.window_focus : False # Maintain shell focus for TkAgg
+
+# ps backend params
+#ps.papersize : letter # auto, letter, legal, ledger, A0-A10, B0-B10
+#ps.useafm : False # use of afm fonts, results in small files
+#ps.usedistiller : False # can be: None, ghostscript or xpdf
+ # Experimental: may produce smaller files.
+ # xpdf intended for production of publication quality files,
+ # but requires ghostscript, xpdf and ps2eps
+#ps.distiller.res : 6000 # dpi
+#ps.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType)
+
+# pdf backend params
+#pdf.compression : 6 # integer from 0 to 9
+ # 0 disables compression (good for debugging)
+#pdf.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType)
+
+# svg backend params
+#svg.image_inline : True # write raster image data directly into the svg file
+#svg.fonttype : 'path' # How to handle SVG fonts:
+# 'none': Assume fonts are installed on the machine where the SVG will be viewed.
+# 'path': Embed characters as paths -- supported by most SVG renderers
+# 'svgfont': Embed characters as SVG fonts -- supported only by Chrome,
+# Opera and Safari
+#svg.hashsalt : None # if not None, use this string as hash salt
+ # instead of uuid4
+
+# docstring params
+#docstring.hardcopy = False # set this when you want to generate hardcopy docstring
+
+# Set the verbose flags. This controls how much information
+# matplotlib gives you at runtime and where it goes. The verbosity
+# levels are: silent, helpful, debug, debug-annoying. Any level is
+# inclusive of all the levels below it. If your setting is "debug",
+# you'll get all the debug and helpful messages. When submitting
+# problems to the mailing-list, please set verbose to "helpful" or "debug"
+# and paste the output into your report.
+#
+# The "fileo" gives the destination for any calls to verbose.report.
+# These objects can a filename, or a filehandle like sys.stdout.
+#
+# You can override the rc default verbosity from the command line by
+# giving the flags --verbose-LEVEL where LEVEL is one of the legal
+# levels, e.g., --verbose-helpful.
+#
+# You can access the verbose instance in your code
+# from matplotlib import verbose.
+#verbose.level : silent # one of silent, helpful, debug, debug-annoying
+#verbose.fileo : sys.stdout # a log filename, sys.stdout or sys.stderr
+
+# Event keys to interact with figures/plots via keyboard.
+# Customize these settings according to your needs.
+# Leave the field(s) empty if you don't need a key-map. (i.e., fullscreen : '')
+
+#keymap.fullscreen : f, ctrl+f # toggling
+#keymap.home : h, r, home # home or reset mnemonic
+#keymap.back : left, c, backspace # forward / backward keys to enable
+#keymap.forward : right, v # left handed quick navigation
+#keymap.pan : p # pan mnemonic
+#keymap.zoom : o # zoom mnemonic
+#keymap.save : s # saving current figure
+#keymap.quit : ctrl+w, cmd+w # close the current figure
+#keymap.grid : g # switching on/off a grid in current axes
+#keymap.yscale : l # toggle scaling of y-axes ('log'/'linear')
+#keymap.xscale : L, k # toggle scaling of x-axes ('log'/'linear')
+#keymap.all_axes : a # enable all axes
+
+# Control location of examples data files
+#examples.directory : '' # directory to look in for custom installation
+
+###ANIMATION settings
+#animation.html : 'none' # How to display the animation as HTML in
+ # the IPython notebook. 'html5' uses
+ # HTML5 video tag.
+#animation.writer : ffmpeg # MovieWriter 'backend' to use
+#animation.codec : h264 # Codec to use for writing movie
+#animation.bitrate: -1 # Controls size/quality tradeoff for movie.
+ # -1 implies let utility auto-determine
+#animation.frame_format: 'png' # Controls frame format used by temp files
+#animation.ffmpeg_path: 'ffmpeg' # Path to ffmpeg binary. Without full path
+ # $PATH is searched
+#animation.ffmpeg_args: '' # Additional arguments to pass to ffmpeg
+#animation.avconv_path: 'avconv' # Path to avconv binary. Without full path
+ # $PATH is searched
+#animation.avconv_args: '' # Additional arguments to pass to avconv
+#animation.mencoder_path: 'mencoder'
+ # Path to mencoder binary. Without full path
+ # $PATH is searched
+#animation.mencoder_args: '' # Additional arguments to pass to mencoder
+#animation.convert_path: 'convert' # Path to ImageMagick's convert binary.
+ # On Windows use the full path since convert
+ # is also the name of a system tool.
diff --git a/Dockerfile b/Dockerfile
index ee48e8dc06760971019494bf6124462072d1bd6d..d268b7880a98623ccff213250a048aaa97cda98c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,198 +1,358 @@
-FROM jupyter/datascience-notebook:latest
+# jupyter-langs:latest
-LABEL maintainer="Jeffrey Phillips Freeman the@jeffreyfreeman.me"
+ARG GOLANG_VERSION=1.19.1
+ARG JULIA_VERSION=1.8.2
+ARG DOTNET_SDK_VERSION=6.0.401
+ARG ELIXIR_VERSION=1.12.3
+ARG JAVA_VERSION=18.0.2.1
-USER root
+# https://hub.docker.com/_/node
+ARG node_version=18.10.0
+FROM node:${node_version}-bullseye-slim as nodejs
-RUN apt-get update && \
- apt-get upgrade -y && \
- apt-get install -y \
- apt-transport-https \
- gcc \
- gnupg \
- htop \
- less \
- libfuse2 \
- libpq-dev \
- libssl1.0 \
- lsb \
- nano \
- nodejs \
- software-properties-common \
- vim \
- git \
- ##
- ## Requirements for IHaskell
- ##
- libtinfo-dev \
- libzmq3-dev \
- libcairo2-dev \
- libpango1.0-dev \
- libmagic-dev \
- libblas-dev \
- liblapack-dev \
- libffi-dev \
- libgmp-dev \
- netbase \
- # for ihaskell-graphviz
- graphviz \
- # for Stack download
- curl \
- # Stack Debian/Ubuntu manual install dependencies
- # https://docs.haskellstack.org/en/stable/install_and_upgrade/#linux-generic
- g++ \
- gcc \
- libc6-dev \
- libffi-dev \
- libgmp-dev \
- make \
- xz-utils \
- zlib1g-dev \
- # Need less for general maintenance
- less \
- ##
- ## Requirements for iRuby
- ##
- libtool \
- libffi-dev \
- ruby \
- ruby-dev \
- libzmq3-dev \
- libczmq-dev \
- ##
- ## Requirements for Rust
- ##
- cmake \
- ##
- ## Requirements for javascript
- ##
- nodejs \
- npm && \
- # Clean up apt
- rm -rf /var/lib/apt/lists/*
+# https://hub.docker.com/_/golang
+FROM golang:${GOLANG_VERSION}-bullseye as golang
+# https://hub.docker.com/_/julia
+FROM julia:${JULIA_VERSION}-bullseye as julia
+# https://hub.docker.com/_/erlang
+# https://hub.docker.com/_/elixir
+FROM elixir:${ELIXIR_VERSION}-slim as elixir
+# https://hub.docker.com/_/microsoft-dotnet-sdk
+#FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_SDK_VERSION}-bullseye-slim as dotnet-sdk
+# https://hub.docker.com/_/openjdk
+FROM openjdk:${JAVA_VERSION}-jdk-bullseye as openjdk
-##
-## Install base jupyter
-##
-
-RUN pip install ipywidgets holidays snakeviz pyinstrument py-heat-magic alpaca-trade-api qgrid &&\
- conda update -n base conda && \
- conda install -c conda-forge nodejs tqdm ipykernel line_profiler ipympl && \
- jupyter lab build && \
- jupyter labextension install @jupyterlab/hub-extension \
- @jupyter-widgets/jupyterlab-manager && \
- jupyter nbextension enable --py widgetsnbextension
-
-COPY .docker/jupyter_notebook_config.json /opt/conda/etc/jupyter/jupyter_notebook_config.json
-
-ENV PATH ${PATH}:/home/jovyan/.local/bin
-ARG NB_UID=1000
-RUN groupadd jovyan && \
- usermod -aG jovyan jovyan && \
- usermod -d /home/jovyan -u $NB_UID jovyan && \
- chown -R jovyan:jovyan /home/jovyan
+# https://hub.docker.com/r/continuumio/miniconda3
+# https://github.com/ContinuumIO/docker-images/blob/master/miniconda3/debian/Dockerfile
+FROM continuumio/miniconda3:4.12.0
+#FROM jupyter/datascience-notebook:latest
-##
-## Install IHaskell
-##
+LABEL maintainer="Jeffrey Phillips Freeman <the@jeffreyfreeman.me>"
+LABEL Description="Jupyter lab for various languages"
+LABEL Version="1.0.0"
+ENV HOME=/root
+ENV NOTEBOOK_DIR=/jupyter/notebooks
+ENV JUPYTER_DIR=/opt/jupyter
+ENV MATPLOTLIBRC=/opt/jupyter
-RUN curl -sSL https://get.haskellstack.org/ | sh && \
- mkdir -p /etc/stack && \
- mkdir -p /home/jovyan/.stack/global-project
+WORKDIR /jupyter
-COPY .docker/stack.config.yaml /etc/stack/config.yaml
-COPY .docker/global-project.stack.yaml /home/jovyan/.stack/global-project/stack.yaml
+# Install required packages
+RUN apt-get update \
+ && apt-get upgrade -y \
+ && apt-get install -y --no-install-recommends \
+ build-essential \
+ cmake \
+ gnupg \
+ locales \
+ fonts-noto-cjk \
+ # for ZeroMQ
+ libtool \
+ libffi-dev \
+ libzmq3-dev \
+ libczmq-dev \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
-ENV PATH ${PATH}:/opt/bin
+# Set Locale
+ENV LANG=ja_JP.UTF-8
+ENV LC_ALL=ja_JP.UTF-8
+RUN echo "LC_ALL=ja_JP.UTF-8" >> /etc/environment \
+ && echo "ja_JP.UTF-8 UTF-8" >> /etc/locale.gen \
+ && echo "LANG=ja_JP.UTF-8" > /etc/locale.conf \
+ && locale-gen ja_JP.UTF-8
-RUN mkdir -p /usr/local/share/jupyter/kernels && \
- mkdir -p /opt/bin && \
- chown -R root /home/jovyan && \
- stack setup && \
- rm /home/jovyan/.stack/programs/x86_64-linux/ghc*.tar.xz && \
- stack install ghc-parser && \
- stack install ipython-kernel && \
- stack install ihaskell && \
- stack install ihaskell-aeson && \
- stack install ihaskell-blaze && \
- stack install ihaskell-charts && \
- stack install ihaskell-diagrams && \
- stack install ihaskell-gnuplot && \
- stack install ihaskell-graphviz && \
- stack install ihaskell-hatex && \
- stack install ihaskell-juicypixels && \
- stack install ihaskell-magic && \
- stack install ihaskell-plot && \
- stack install hvega && \
- stack install ihaskell-hvega && \
- mkdir -p /home/jovyan/.local/share/jupyter/runtime && \
- mkdir -p /opt/ghc && \
- ln -s `stack path --compiler-bin` /opt/ghc/bin && \
- chown -R jovyan:jovyan /home/jovyan && \
- fix-permissions /home/jovyan/ && \
- fix-permissions /home/jovyan/.stack && \
- fix-permissions /home/jovyan/.stack/global-project && \
- fix-permissions /home/jovyan/.local && \
- fix-permissions /home/jovyan/.local/share && \
- fix-permissions /home/jovyan/.local/share/jupyter && \
- fix-permissions /home/jovyan/.local/share/jupyter/runtime && \
- fix-permissions /etc/stack && \
- fix-permissions /usr/local/share/jupyter && \
- fix-permissions /usr/local/share/jupyter/kernels && \
- fix-permissions /opt/bin && \
- fix-permissions /opt/ghc
-
-ENV PATH ${PATH}:/opt/ghc/bin
-
-USER jovyan
+# Upgrade conda
+RUN conda update -n base -c defaults conda
+RUN conda install -c conda-forge mamba -y
-RUN stack exec ihaskell -- install --stack --prefix=/usr/local
+# Install Jupyter
+RUN mamba update -c conda-forge --all
+RUN mamba install -y -c conda-forge \
+ python=3.10.6 \
+ notebook=6.4.12 \
+ pandas \
+ scipy \
+ bokeh \
+ matplotlib \
+ # tensorflow \
+ keras \
+ jupyterlab>=3.4 \
+ libiconv \
+ ipywidgets>=8.0 \
+ ipyleaflet \
+ # for dash
+ plotly \
+ dash \
+ lxml \
+ xlrd \
+ xlwt \
+ && conda clean -y --all
+# RUN jupyter contrib nbextension install --user
+RUN pip install tflearn jupyter_dash
-##
-## Install iRuby
-##
+RUN mkdir -p $NOTEBOOK_DIR \
+ && mkdir -p $JUPYTER_DIR \
+ && mkdir -p $MATPLOTLIBRC
+COPY .docker/matplotlibrc $MATPLOTLIBRC/matplotlibrc
+COPY .docker/jupyter_notebook_config.py $JUPYTER_DIR/jupyter_notebook_config.py
-USER root
+# Install Javascript
+ENV NODE_VERSION ${node_version}
+ENV YARN_VERSION 1.22.19
+RUN mkdir -p /opt
+COPY --from=nodejs /opt/yarn-v${YARN_VERSION} /opt/yarn
+COPY --from=nodejs /usr/local/bin/node /usr/local/bin/
+COPY --from=nodejs /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
+RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
+ && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg \
+ && ln -s /usr/local/bin/node /usr/local/bin/nodejs \
+ && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
+ && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx
+RUN yarn global add typescript tslab \
+ && tslab install \
+ && yarn add @types/node
-RUN gem install cztop && \
- gem install iruby --pre && \
- iruby register --force
+# Install jupyter labextensions
+RUN jupyter labextension install \
+ @jupyter-widgets/jupyterlab-manager \
+ jupyterlab-plotly \
+ plotlywidget \
+ jupyter-leaflet
-##
-## Install Rust support
-##
-ENV PATH ${PATH}:/home/jovyan/.cargo/bin
+# Install SPARQL
+RUN pip install sparqlkernel && \
+ jupyter sparqlkernel install
-RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \
- source /home/jovyan/.cargo/env && \
- rustup component add rust-src && \
- cargo install evcxr_jupyter && \
- evcxr_jupyter --install && \
- chown -R jovyan:jovyan /home/jovyan && \
- fix-permissions /home/jovyan/
+# Install R
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ unixodbc \
+ unixodbc-dev \
+ r-cran-rodbc
+RUN mamba install --quiet --yes -c conda-forge \
+ 'r-base>=4.1' \
+ 'r-caret' \
+ 'r-crayon' \
+ # 'r-devtools' \
+ 'r-e1071' \
+ 'r-forecast' \
+ 'r-hexbin' \
+ 'r-htmltools' \
+ 'r-htmlwidgets' \
+ 'r-irkernel' \
+ 'r-nycflights13' \
+ 'r-randomforest' \
+ 'r-rcurl' \
+ 'r-rodbc' \
+ 'r-rsqlite' \
+ 'r-shiny' \
+ 'rpy2' \
+ 'unixodbc' \
+ 'r-markdown' \
+ 'r-plotly'
-##
-## Install javascript
-##
+# Install Julia
+ENV JULIA_PATH /usr/local/julia
+ENV PATH ${JULIA_PATH}/bin:$PATH
+COPY --from=julia ${JULIA_PATH} ${JULIA_PATH}
+RUN julia --version
+RUN julia -e 'using Pkg; Pkg.add("IJulia"); Pkg.add("DataFrames"); Pkg.add("CSV"); Pkg.add("Colors"); Pkg.add("ColorSchemes"); Pkg.add("PlotlyJS");'
-ENV PATH ${PATH}:/home/jovyan/bin
+# Install golang
+ENV GOLANG_VERSION=${GOLANG_VERSION}
+# https://github.com/gopherdata/gophernotes/releases
+ENV GOPHERNOTES_VERSION=0.7.5
+ENV GOPATH=/go
+ENV PATH=$GOPATH/bin:/usr/local/go/bin:$PATH
+COPY --from=golang /usr/local/go/ /usr/local/go/
+RUN go install github.com/gopherdata/gophernotes@v${GOPHERNOTES_VERSION} \
+ && mkdir -p ~/.local/share/jupyter/kernels/gophernotes \
+ && cd ~/.local/share/jupyter/kernels/gophernotes \
+ && cp "$(go env GOPATH)"/pkg/mod/github.com/gopherdata/gophernotes@v${GOPHERNOTES_VERSION}/kernel/* "." \
+ && chmod +w ./kernel.json \
+ && sed "s|gophernotes|$(go env GOPATH)/bin/gophernotes|" < kernel.json.in > kernel.json
+
+# Install Rust https://www.rust-lang.org/
+ENV RUSTUP_HOME=/usr/local/rustup
+ENV CARGO_HOME=/usr/local/cargo
+ENV PATH=/usr/local/cargo/bin:$PATH
+ENV RUST_VERSION=1.73.0
+ENV RUSTUP_VERSION=1.25.1
+RUN set -eux; \
+ dpkgArch="$(dpkg --print-architecture)"; \
+ case "${dpkgArch##*-}" in \
+ amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='5cc9ffd1026e82e7fb2eec2121ad71f4b0f044e88bca39207b3f6b769aaa799c' ;; \
+ arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='e189948e396d47254103a49c987e7fb0e5dd8e34b200aa4481ecc4b8e41fb929' ;; \
+ *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
+ esac; \
+ url="https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/${rustArch}/rustup-init"; \
+ wget "$url"; \
+ echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
+ chmod +x rustup-init; \
+ ./rustup-init -y --no-modify-path --default-toolchain ${RUST_VERSION}; \
+ rm rustup-init; \
+ chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
+ rustup --version; \
+ cargo --version; \
+ rustc --version;
+RUN cargo install evcxr_jupyter \
+ && evcxr_jupyter --install
+
+# Install Ruby https://www.ruby-lang.org
+RUN apt-get update -y \
+ && apt-get install -y --no-install-recommends \
+ bzip2 \
+ ca-certificates \
+ libffi-dev \
+ libgmp-dev \
+ libssl-dev \
+ libyaml-dev \
+ procps \
+ zlib1g-dev \
+ autoconf \
+ bison \
+ dpkg-dev \
+ gcc \
+ libbz2-dev \
+ libgdbm-compat-dev \
+ libgdbm-dev \
+ libglib2.0-dev \
+ libncurses-dev \
+ libreadline-dev \
+ libxml2-dev \
+ libxslt-dev \
+ make \
+ ruby \
+ wget \
+ xz-utils \
+ ruby \
+ ruby-dev && \
+ gem install --no-document \
+ benchmark_driver \
+ cztop \
+ iruby \
+ && iruby register --force
+
+# Install Erlang and Elixir
+COPY --from=elixir /usr/local/lib/erlang /usr/local/lib/erlang
+COPY --from=elixir /usr/local/lib/elixir /usr/local/lib/elixir
+COPY --from=elixir /usr/local/bin/rebar3 /usr/local/bin/rebar3
+
+RUN runtimeDeps=' \
+ libodbc1 \
+ libssl1.1 \
+ libsctp1 \
+ ' \
+ && apt-get update \
+ && apt-get install -y --no-install-recommends $runtimeDeps
+
+RUN ln -s /usr/local/lib/erlang/bin/ct_run /usr/local/bin/ct_run \
+ && ln -s /usr/local/lib/erlang/bin/dialyzer /usr/local/bin/dialyzer \
+ && ln -s /usr/local/lib/erlang/bin/epmd /usr/local/bin/epmd \
+ && ln -s /usr/local/lib/erlang/bin/erl /usr/local/bin/erl \
+ && ln -s /usr/local/lib/erlang/bin/erlc /usr/local/bin/erlc \
+ && ln -s /usr/local/lib/erlang/bin/escript /usr/local/bin/escript \
+ && ln -s /usr/local/lib/erlang/bin/run_erl /usr/local/bin/run_erl \
+ && ln -s /usr/local/lib/erlang/bin/to_erl /usr/local/bin/to_erl \
+ && ln -s /usr/local/lib/erlang/bin/typer /usr/local/bin/typer \
+ && ln -s /usr/local/lib/elixir/bin/elixir /usr/local/bin/elixir \
+ && ln -s /usr/local/lib/elixir/bin/elixirc /usr/local/bin/elixirc \
+ && ln -s /usr/local/lib/elixir/bin/iex /usr/local/bin/iex \
+ && ln -s /usr/local/lib/elixir/bin/mix /usr/local/bin/mix
+RUN mix local.hex --force \
+ && mix local.rebar --force
+RUN git clone https://github.com/filmor/ierl.git ierl \
+ && cd ierl \
+ && mkdir $HOME/.ierl \
+ && mix deps.get \
+ # Build lfe explicitly for now
+ && (cd deps/lfe && ~/.mix/rebar3 compile) \
+ && (cd apps/ierl && env MIX_ENV=prod mix escript.build) \
+ && cp apps/ierl/ierl $HOME/.ierl/ierl.escript \
+ && chmod +x $HOME/.ierl/ierl.escript \
+ && $HOME/.ierl/ierl.escript install erlang --user \
+ && $HOME/.ierl/ierl.escript install elixir --user \
+ && cd .. \
+ && rm -rf ierl
+
+# Install JVM languages
+## Java
+# https://github.com/allen-ball/ganymede
+ENV JAVA_HOME /usr/local/openjdk-18
+ENV PATH $JAVA_HOME/bin:$PATH
+ENV GANYMEDE_VERSION=2.0.1.20220723
+COPY --from=openjdk ${JAVA_HOME} ${JAVA_HOME}
+RUN wget https://github.com/allen-ball/ganymede/releases/download/v${GANYMEDE_VERSION}/ganymede-${GANYMEDE_VERSION}.jar -O /tmp/ganymede.jar
+RUN ${JAVA_HOME}/bin/java \
+ -jar /tmp/ganymede.jar \
+ -i --sys-prefix --id=java --display-name=Java18 --copy-jar=true
+## Kotlin
+RUN mamba install --quiet --yes -c jetbrains 'kotlin-jupyter-kernel'
+## Scala
+RUN curl -Lo coursier https://git.io/coursier-cli \
+ && chmod +x coursier \
+ && ./coursier launch --fork almond -- --install \
+ && rm -f coursier
-RUN npm config set prefix /home/jovyan && \
- npm install -g ijavascript && \
- ijsinstall
##
-## Finalize everything
+## Install IHaskell
##
-USER jovyan
-WORKDIR /home/jovyan
+RUN curl -sSL https://get.haskellstack.org/ | sh && \
+ mkdir -p /etc/stack && \
+ mkdir -p ~/.stack/global-project
+
+COPY .docker/stack.config.yaml /etc/stack/config.yaml
+COPY .docker/global-project.stack.yaml ~/.stack/global-project/stack.yaml
+
+ENV PATH ${PATH}:/opt/bin:/opt/ghc/bin
+
+RUN mkdir -p /usr/local/share/jupyter/kernels && \
+ mkdir -p /opt/bin && \
+ stack setup && \
+ rm ~/.stack/programs/x86_64-linux/ghc*.tar.xz && \
+ stack install ghc-parser-0.2.5.0
+
+RUN apt-get install -y --no-install-recommends \
+ python3-pip \
+ git \
+ libtinfo-dev \
+ libzmq3-dev \
+ libcairo2-dev \
+ libpango1.0-dev \
+ libmagic-dev \
+ libblas-dev \
+ liblapack-dev && \
+ git clone https://github.com/gibiansky/IHaskell && \
+ cd IHaskell && \
+ pip3 install -r requirements.txt && \
+ stack install --fast && \
+ cd .. && \
+ mv /root/.local/bin/* /opt/bin/ &&\
+ ihaskell install --stack
+
+RUN mkdir -p ~/.local/share/jupyter/runtime && \
+ mkdir -p /opt/ghc && \
+ ln -s `stack path --compiler-bin` /opt/ghc/bin
+
+RUN stack exec ihaskell -- install --stack --prefix=/usr/local
-EXPOSE 8888
+# ↓ 削除系ã¯ã¯ã¾ã¨ã‚ã¦ã“ã“ã§ã‚„ã‚‹
+RUN mamba clean --all \
+ && apt-get autoremove \
+ && apt-get clean \
+ && apt-get autoclean \
+ && rm -rf /var/lib/apt/lists/* \
+ && rm -rf /tmp/*
-COPY .docker/entry.sh /bin
+ # for JupyterLab
+ EXPOSE 8888
+ # for Dash
+ EXPOSE 8050
-ENTRYPOINT ["bash", "/bin/entry.sh"]
+ CMD ["jupyter", "lab", "--no-browser", "--ip=0.0.0.0", "--allow-root", "--notebook-dir=/jupyter/notebooks", "--config=$JUPYTER_DIR/jupyter_notebook_config.py"]
diff --git a/docker-compose.yml b/docker-compose.yml
index c79c1dedcacc2e723e8953a8f7d1d9f025ac14cf..a58b6a8e0bab7f36e6c39dd83f2ef53b7541c02d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -8,7 +8,7 @@ services:
ports:
- 8888:8888
volumes:
- - '.:/home/jovyan/work'
+ - '.:/jupyter/notebooks'
mem_limit: 32G
shm_size: 4G
restart: always