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