diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..1327386f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +org.geppetto.frontend.jupyter +pygeppetto +.vscode +.ipynb_checkpoints +netpyne_ui/geppetto +*.egg-info +notebook.ipynb +.git +netpyne +Dockerfile +Dockerfile_base +Dockerfile_dev +netpyne_workspace +webapp/node_modules +webapp/build +webapp/geppetto-client +k8s +src +x86_64 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 92919c3c..525912df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .ipynb_checkpoints/ netpyne-ui.log log.file +src *.pyc *.egg-info .DS_Store @@ -8,4 +9,15 @@ pygeppetto/ netpyne/ org.geppetto.frontend.jupyter/ *.ipynb -init.py \ No newline at end of file +init.py +webapp/node_modules +webapp/geppetto-client +webapp/build +netpyne_workspace +Dockerfile_mini +npm* +.vscode +app.log +utilities/x86_64 +.idea +x86_64 diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 60df24a4..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "netpyne_ui/geppetto"] - path = netpyne_ui/geppetto - url = https://github.com/openworm/org.geppetto.frontend.git diff --git a/.travis.yml b/.travis.yml index 19cd6392..3d8db331 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,76 +1,26 @@ language: python os: linux -sudo: false -dist: trusty -bundler_args: --retry 5 +python: + - "3.7" node_js: - - "7" + - "12" env: global: - secure: dn0FPQ5IG4M/3kdwnyI78ElQ308Vc3QnKAvkWfwMFb8QxDqxQdnTo7AV1qTMtbLrDNkeEWIgi4nc7jmXNtvGTwOfhAULVh6606Qs5B+ezTdwzajbbFMI8SKQx/pnTojOMu8dx7V4lMoR/YWcojR0VC1IWVC62TGbSB1k5BDGgH0= -before_install: -- sudo apt-get install -y xserver-xorg-dev libxext-dev libxi-dev -install: -- git clone --quiet https://github.com/MetaCell/geppetto-netpyne.git -- cd geppetto-netpyne -- if [ `git branch -a | egrep "remotes/origin/${TRAVIS_BRANCH}"` ]; then git checkout $TRAVIS_BRANCH ; else echo "Branch $TRAVIS_BRANCH does not exist for the dependent bundle, checking out development ..." && git checkout development; fi -- cd .. -- npm install --silent -g phantomjs -- npm install --silent -g casperjs -- npm install --silent -g slimerjs -- npm install --silent -g gl -python: - - "2.7" - - "3.5" -edge: true + - secure: dn0FPQ5IG4M/3kdwnyI78ElQ308Vc3QnKAvkWfwMFb8QxDqxQdnTo7AV1qTMtbLrDNkeEWIgi4nc7jmXNtvGTwOfhAULVh6606Qs5B+ezTdwzajbbFMI8SKQx/pnTojOMu8dx7V4lMoR/YWcojR0VC1IWVC62TGbSB1k5BDGgH0= + - DEFAULT_BRANCH: development + - LANDING_PAGE: "http://localhost:8888/geppetto" notifications: slack: metacell:5ALSeoP88DqIhORUJvxE56sq -services: - - docker -addons: - firefox: "58.0" - apt: - packages: - - mesa-utils - - xvfb - - libgl1-mesa-dri - - libglapi-mesa - - libosmesa6 - -before_script: - - "export DISPLAY=:99.0" - - "sh -e /etc/init.d/xvfb start" - - export SLIMERJSLAUNCHER=/home/travis/firefox-58.0/firefox/firefox - - export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/ - +install: + - sudo apt-get install libgnutls28-dev + - sudo apt install libcurl4-openssl-dev libssl-dev + - sudo apt-get install python3-dev script: - - travis_retry docker build -t="netpyne-ui" --build-arg netpyneuiBranch=$TRAVIS_BRANCH -f="./Dockerfile_dev" . - - travis_retry docker run -t -dit --name=netpyne-ui_container -h localhost -p 8888:8888 netpyne-ui:latest - - cd $TRAVIS_BUILD_DIR/ && ls - - cd geppetto-netpyne && ls - - cd tests - - bash utilities/netpyne-server-status.sh - - sleep 30 - - http_status=$(curl -s -I $1 http://localhost:8888/geppetto | grep HTTP/1.1 | awk {'print $2'}) + + - python utilities/install.py + - ./NetPyNE-UI & + - http_status=$(curl -s -I $1 $LANDING_PAGE | grep HTTP/1.1 | awk {'print $2'}) - echo "$http_status" - - while [ "$http_status" == "404" ]; do - echo "Restart run"; - echo "Printing logs for debugging purposes"; - docker stop $(docker ps -a -q); - docker rm $(docker ps -a -q); - docker run -t -dit --name=netpyne-ui_container -h localhost -p 8888:8888 netpyne-ui:latest - bash utilities/netpyne-server-status.sh - sleep 30; - http_status=$(curl -s -I $1 http://localhost:8888/geppetto | grep HTTP/1.1 | awk {'print $2'}) - echo "Done restarting"; - echo "$http_status"; - done; - - http_status=$(curl -s -I $1 http://localhost:28081 | grep HTTP/1.1 | awk {'print $2'}) - - echo "$http_status"; - - "curl -s -I $1 http://localhost:8888/geppetto | grep HTTP/1.1 | awk {'print $2'}" - - firefox --version - - travis_retry xvfb-run -a --server-args="-screen 0 1024x768x24" casperjs test netpyne-tests.js --host=http://localhost:8888/ --engine=slimerjs - - python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" - - docker logs -t netpyne-ui_container - - docker stop $(docker ps -a -q) - - docker rm $(docker ps -a -q) \ No newline at end of file + - cd webapp + - travis_retry npm run test -- --verbose --colors + - exit 0 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index fcc6c3c0..468bda1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,26 +1,17 @@ -FROM metacell/jupyter-neuron:latest +FROM frodriguez4600/jupyter-neuron:v7.8.0 USER $NB_USER -ARG netpyneuiBranch=development -ENV netpyneuiBranch=${netpyneuiBranch} -RUN echo "$netpyneuiBranch"; +ARG branch=development +RUN echo "$branch"; -ARG INCUBATOR_VER=unknown -RUN /bin/bash -c "INCUBATOR_VER=${INCUBATOR_VER} source activate snakes && pip install netpyne_ui" -RUN /bin/bash -c "source activate snakes && jupyter nbextension enable --py jupyter_geppetto" -RUN /bin/bash -c "source activate snakes && jupyter serverextension enable --py jupyter_geppetto" -RUN /bin/bash -c "source activate snakes && jupyter nbextension enable --py widgetsnbextension" +ENV INSTALLATION_FOLDER=/home/jovyan/work/NetPyNE-UI +WORKDIR /home/jovyan/work -WORKDIR /home/jovyan -RUN git clone --branch v0.5 https://github.com/Neurosim-lab/netpyne_workspace -WORKDIR /home/jovyan/netpyne_workspace +COPY --chown=1000:1000 . NetPyNE-UI +WORKDIR ${INSTALLATION_FOLDER}/utilities -# Uncomment to run travis using this Dockerfile -# Clone the source code and creates a symlink to the test folder -WORKDIR /home/jovyan/work -RUN wget https://github.com/MetaCell/NetPyNE-UI/archive/$netpyneuiBranch.zip -q -RUN unzip $netpyneuiBranch.zip -WORKDIR /home/jovyan/netpyne_workspace -RUN ln -sfn /home/jovyan/work/NetPyNE-UI-$netpyneuiBranch/netpyne_ui/tests tests +RUN python install.py branch $branch + +WORKDIR ${INSTALLATION_FOLDER} -CMD /bin/bash -c "source activate snakes && exec jupyter notebook --debug --NotebookApp.default_url=/geppetto --NotebookApp.token='' --library=netpyne_ui" +CMD /bin/bash -c "jupyter notebook --NotebookApp.default_url=/geppetto --NotebookApp.token='' --library=netpyne_ui --NotebookApp.disable_check_xsrf=True" \ No newline at end of file diff --git a/NetPyNE-UI b/NetPyNE-UI index b08a7285..62b0bb86 100755 --- a/NetPyNE-UI +++ b/NetPyNE-UI @@ -1,2 +1,2 @@ #!/bin/sh -exec jupyter notebook --NotebookApp.default_url=/geppetto --NotebookApp.token='' --library=netpyne_ui +exec jupyter notebook --NotebookApp.default_url=/geppetto --NotebookApp.token='' --library=netpyne_ui --NotebookApp.disable_check_xsrf=True diff --git a/README.md b/README.md index d561cd1a..63131d6a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ [![Docker Automated buil](https://img.shields.io/docker/automated/jrottenberg/ffmpeg.svg)](https://hub.docker.com/r/metacell/netpyne-ui/) - +[![Build Status](https://travis-ci.org/MetaCell/NetPyNE-UI.svg?branch=master)](https://travis-ci.org/MetaCell/NetPyNE-UI) +[![Codefresh build status]( https://g.codefresh.io/api/badges/pipeline/tarelli/NetPyNE-UI%2Ftest?branch=master&key=eyJhbGciOiJIUzI1NiJ9.NWFkNzMyNDIzNjQ1YWMwMDAxMTJkN2Rl.-gUEkJxH6NCCIRgSIgEikVDte-Q0BsGZKEs4uahgpzs&type=cf-1)]( https%3A%2F%2Fg.codefresh.io%2Fpipelines%2Ftest%2Fbuilds%3FrepoOwner%3DMetaCell%26repoName%3DNetPyNE-UI%26serviceName%3DMetaCell%252FNetPyNE-UI%26filter%3Dtrigger%3Abuild~Build%3Bbranch%3Amaster%3Bpipeline%3A5e5bbecc6c98a1209fc7bca3~test)

- +

-![Screenshot](https://github.com/metacell/netpyne-ui/raw/master/docs/netpyneui.png) +![Screenshot](https://github.com/MetaCell/NetPyNE-UI/raw/documentation/docs/netpyneui.png) This repository hosts the User Interface for [NetPyNE](http://www.neurosimlab.org/netpyne/). NetPyNE is a python package to facilitate the development, parallel simulation and analysis of biological neuronal networks using the NEURON simulator. @@ -21,15 +22,36 @@ If you are familiar with NEURON and have already NEURON installed in your machin

## Install NetPyNE User Interface from sources (for developers) + +### Python Dependencies + +We recommend the use of a new python 3 virtual environment: + +```bash +python3 -m venv npenv +source npenv/bin/activate +``` + +Or, with conda + +```bash +conda create -n netpyne python=3.7 +conda activate netpyne ``` + +### Run install script + +```bash git clone https://github.com/MetaCell/NetPyNE-UI.git cd utilities python install.py cd .. ./NetPyNE-UI ``` -### To update sources: -``` + +### To update sources + +```bash python update.py ``` diff --git a/docs/gif1.gif b/docs/gif1.gif index 3e00d494..9df141f0 100644 Binary files a/docs/gif1.gif and b/docs/gif1.gif differ diff --git a/docs/netpyneui.png b/docs/netpyneui.png index a97c1a64..240682a1 100644 Binary files a/docs/netpyneui.png and b/docs/netpyneui.png differ diff --git a/docs/wiki1-1.png b/docs/wiki1-1.png new file mode 100644 index 00000000..8f1b6cc5 Binary files /dev/null and b/docs/wiki1-1.png differ diff --git a/docs/wiki1-2.png b/docs/wiki1-2.png new file mode 100644 index 00000000..e670b883 Binary files /dev/null and b/docs/wiki1-2.png differ diff --git a/docs/wiki1.png b/docs/wiki1.png index 7924d1b8..35b058ea 100644 Binary files a/docs/wiki1.png and b/docs/wiki1.png differ diff --git a/docs/wiki10.png b/docs/wiki10.png index cf00ad07..54a7712a 100644 Binary files a/docs/wiki10.png and b/docs/wiki10.png differ diff --git a/docs/wiki11.png b/docs/wiki11.png index 762a91a8..a061e787 100644 Binary files a/docs/wiki11.png and b/docs/wiki11.png differ diff --git a/docs/wiki12.png b/docs/wiki12.png new file mode 100644 index 00000000..221cfd77 Binary files /dev/null and b/docs/wiki12.png differ diff --git a/docs/wiki13.png b/docs/wiki13.png new file mode 100644 index 00000000..7ec81f94 Binary files /dev/null and b/docs/wiki13.png differ diff --git a/docs/wiki14.png b/docs/wiki14.png new file mode 100644 index 00000000..c2e453c9 Binary files /dev/null and b/docs/wiki14.png differ diff --git a/docs/wiki15.png b/docs/wiki15.png new file mode 100644 index 00000000..3ebd3bf3 Binary files /dev/null and b/docs/wiki15.png differ diff --git a/docs/wiki16.png b/docs/wiki16.png new file mode 100644 index 00000000..79bf2fdc Binary files /dev/null and b/docs/wiki16.png differ diff --git a/docs/wiki17.png b/docs/wiki17.png new file mode 100644 index 00000000..9b5167d2 Binary files /dev/null and b/docs/wiki17.png differ diff --git a/docs/wiki2.png b/docs/wiki2.png index 6152bf2a..db2308a2 100644 Binary files a/docs/wiki2.png and b/docs/wiki2.png differ diff --git a/docs/wiki3.png b/docs/wiki3.png index 39515c8a..20f0ff20 100644 Binary files a/docs/wiki3.png and b/docs/wiki3.png differ diff --git a/docs/wiki4.png b/docs/wiki4.png index 0d7ee51f..9b6b7caa 100644 Binary files a/docs/wiki4.png and b/docs/wiki4.png differ diff --git a/docs/wiki5.png b/docs/wiki5.png index 70a79dcd..8ceee0a8 100644 Binary files a/docs/wiki5.png and b/docs/wiki5.png differ diff --git a/docs/wiki6.png b/docs/wiki6.png index e814b55b..2bf36552 100644 Binary files a/docs/wiki6.png and b/docs/wiki6.png differ diff --git a/docs/wiki7.png b/docs/wiki7.png index 0dbfb500..017cf7b9 100644 Binary files a/docs/wiki7.png and b/docs/wiki7.png differ diff --git a/docs/wiki8.png b/docs/wiki8.png index d5bb9035..194951fd 100644 Binary files a/docs/wiki8.png and b/docs/wiki8.png differ diff --git a/docs/wiki9.png b/docs/wiki9.png index 021a82b6..f92ccdce 100644 Binary files a/docs/wiki9.png and b/docs/wiki9.png differ diff --git a/jupyter_hub/Dockerfile_hub b/jupyter_hub/Dockerfile_hub new file mode 100644 index 00000000..7706e7d8 --- /dev/null +++ b/jupyter_hub/Dockerfile_hub @@ -0,0 +1,12 @@ +FROM jupyterhub/jupyterhub:latest + +# feature_jupyterhub +ARG netpyneuiBranch=feature_jupyterhub +ENV netpyneuiBranch=${netpyneuiBranch} +RUN echo "$netpyneuiBranch"; + +# Install authenticator and spawner + jupyter_client +RUN pip install jupyterhub-tmpauthenticator dockerspawner jupyter_client + +# Overwrite jupyterhub_config +RUN wget https://raw.githubusercontent.com/MetaCell/NetPyNE-UI/$netpyneuiBranch/jupyterhub/jupyterhub_config.py -q \ No newline at end of file diff --git a/Dockerfile_dev b/jupyter_hub/Dockerfile_spawner similarity index 57% rename from Dockerfile_dev rename to jupyter_hub/Dockerfile_spawner index 8f3e8e56..cfb17b6b 100644 --- a/Dockerfile_dev +++ b/jupyter_hub/Dockerfile_spawner @@ -1,10 +1,18 @@ FROM metacell/jupyter-neuron:latest + +USER root +RUN conda install -c conda-forge nodejs configurable-http-proxy + USER $NB_USER -ARG netpyneuiBranch=development +# feature_jupyterhub +ARG netpyneuiBranch=feature_jupyterhub ENV netpyneuiBranch=${netpyneuiBranch} RUN echo "$netpyneuiBranch"; +ARG INCUBATOR_VER=unknown +RUN /bin/bash -c "INCUBATOR_VER=${INCUBATOR_VER} source activate snakes && pip install jupyterhub==0.9.4" + # Clone NetPyNE-UI and install the development version RUN wget https://github.com/MetaCell/NetPyNE-UI/archive/$netpyneuiBranch.zip -q RUN unzip $netpyneuiBranch.zip @@ -15,4 +23,8 @@ WORKDIR /home/jovyan RUN git clone https://github.com/Neurosim-lab/netpyne_workspace WORKDIR /home/jovyan/netpyne_workspace RUN ln -sfn /home/jovyan/work/NetPyNE-UI-$netpyneuiBranch/netpyne_ui/tests tests -CMD /bin/bash -c "source activate snakes && exec jupyter notebook --debug --NotebookApp.default_url=/geppetto --NotebookApp.token='' --library=netpyne_ui" + +# Copy jupyterhub_config +# RUN cp /home/jovyan/work/NetPyNE-UI-$netpyneuiBranch/jupyterhub_config.py . + +CMD /bin/bash -c "source activate snakes && exec jupyterhub-singleuser --debug --NotebookApp.default_url=/geppetto --NotebookApp.token='' --library=netpyne_ui" diff --git a/jupyter_hub/jupyterhub_config.py b/jupyter_hub/jupyterhub_config.py new file mode 100644 index 00000000..a36899f1 --- /dev/null +++ b/jupyter_hub/jupyterhub_config.py @@ -0,0 +1,38 @@ +## Class for authenticating users. +# +# This should be a class with the following form: +# +# - constructor takes one kwarg: `config`, the IPython config object. +# +# with an authenticate method that: +# _class +# - is a coroutine (asyncio or tornado) +# - returns username on success, None on failure +# - takes two arguments: (handler, data), +# where `handler` is the calling web.RequestHandler, +# and `data` is the POST form data from the login page. +#c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' +# c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator' +# c.DummyAuthenticator.password = "dummypassword" +c.JupyterHub.authenticator_class = 'tmpauthenticator.TmpAuthenticator' + +## The class to use for spawning single-user servers. +# +# Should be a subclass of Spawner. +#c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' +c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner' +from jupyter_client.localinterfaces import public_ips +ip = public_ips()[0] +c.JupyterHub.hub_ip = ip +c.DockerSpawner.image = 'netpyne_ui_jupyterspawner' +c.DockerSpawner.remove_containers = True +c.DockerSpawner.remove = True +c.DockerSpawner.debug = True +c.DockerSpawner.network_name='jupyterhub_network' + +## Extra arguments to be passed to the single-user server. Only works for the LocalProcessSpawner +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables here. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# c.Spawner.args = ['--library=netpyne_ui', '--NotebookApp.default_url=/geppetto', '--NotebookApp.token='''] \ No newline at end of file diff --git a/k8s/Dockerfile b/k8s/Dockerfile new file mode 100644 index 00000000..e80a5fcc --- /dev/null +++ b/k8s/Dockerfile @@ -0,0 +1,14 @@ +FROM jupyterhub/k8s-hub:0.9.0 + +COPY --chown=1000:1000 templates/page.html /usr/local/share/jupyterhub/templates/page.html +COPY --chown=1000:1000 templates/404.html /usr/local/share/jupyterhub/templates/404.html +COPY --chown=1000:1000 templates/spawn_pending.html /usr/local/share/jupyterhub/templates/spawn_pending.html +COPY --chown=1000:1000 static/jupyter.png /usr/local/share/jupyterhub/static/images/jupyter.png +COPY --chown=1000:1000 static/jupyter.png /usr/local/share/jupyterhub/static/images/jupyterhub-80.png +COPY --chown=1000:1000 static/favicon.ico /usr/local/share/jupyterhub/static/favicon.ico +COPY --chown=1000:1000 static/favicon.ico /usr/local/share/jupyterhub/static/images/favicon.ico +COPY --chown=1000:1000 auth.py /usr/local/lib/python3.6/dist-packages/tmpauthenticator/__init__.py +COPY --chown=1000:1000 js/EventSource.js /usr/local/share/jupyterhub/static/js/EventSource.js + + +CMD ["jupyterhub", "--config", "/srv/jupyterhub_config.py"] \ No newline at end of file diff --git a/k8s/README.md b/k8s/README.md new file mode 100644 index 00000000..f60f6858 --- /dev/null +++ b/k8s/README.md @@ -0,0 +1,16 @@ +# k8s deployment + +- Deploy on minikube runnig + +```bash +kubectl create -ns netpyne +helm upgrade netpyne jupyterhub --install --reset-values --repo https://jupyterhub.github.io/helm-chart/ --version 0.9.0 --namespace netpyne --values minikube_values.yaml --force --debug +``` + +- Access the hub by running + +```bash +minikube service list +``` + +and use the url corresponding to nepyne proxy-public on port 80 \ No newline at end of file diff --git a/k8s/auth.py b/k8s/auth.py new file mode 100644 index 00000000..4c6eef90 --- /dev/null +++ b/k8s/auth.py @@ -0,0 +1,77 @@ +import uuid + +from traitlets import Bool +from tornado import gen + +from jupyterhub.auth import Authenticator +from jupyterhub.handlers import BaseHandler +from jupyterhub.utils import url_path_join + + +class TmpAuthenticateHandler(BaseHandler): + def initialize(self, force_new_server, process_user): + super().initialize() + self.force_new_server = force_new_server + self.process_user = process_user + + @gen.coroutine + def get(self): + + raw_user = yield self.get_current_user() + + if raw_user: + if self.force_new_server and raw_user.running: + status = yield raw_user.spawner.poll_and_notify() + if status is None: + yield self.stop_single_user(raw_user) + + else: + username = str(uuid.uuid4()) + raw_user = self.user_from_username(username) + self.set_login_cookie(raw_user) + + user = yield gen.maybe_future(self.process_user(raw_user, self)) + + server_name = '' + redirection = self.get_next_url(user) + user.spawners[server_name].environment["NETPYNE_URL"] = '' + + if 'hub/new-server=' in self.request.uri: + server_name = str(uuid.uuid4()).split('-').pop() + redirection = f'/hub/spawn/{user.name}/{server_name}' + user.spawners[server_name].environment["NETPYNE_URL"] = self.request.uri.split('=').pop() + + self.redirect(redirection) + + +class TmpAuthenticator(Authenticator): + auto_login = True + login_service = 'tmp' + + force_new_server = Bool( + False, + help=""" + Stop the user's server and start a new one when visiting /hub/tmplogin + When set to True, users going to /hub/tmplogin will *always* get a + new single-user server. When set to False, they'll be + redirected to their current session if one exists. + """, + config=True + ) + + def process_user(self, user, handler): + return user + + def get_handlers(self, app): + # FIXME: How to do this better? + extra_settings = { + 'force_new_server': self.force_new_server, + 'process_user': self.process_user + } + return [ + ('/tmplogin.*', TmpAuthenticateHandler, extra_settings), + ('/new-server=.*', TmpAuthenticateHandler, extra_settings) + ] + + def login_url(self, base_url): + return url_path_join(base_url, 'tmplogin') \ No newline at end of file diff --git a/k8s/cf_pipeline.yaml b/k8s/cf_pipeline.yaml new file mode 100644 index 00000000..9a9669dd --- /dev/null +++ b/k8s/cf_pipeline.yaml @@ -0,0 +1,62 @@ +version: "1.0" +stages: + - "clone" + - "build" + - "deploy" +steps: + main_clone: + type: "git-clone" + description: "Cloning main repository..." + repo: "MetaCell/NetPyNE-UI" + revision: "${{CF_BRANCH}}" + stage: "clone" + when: + branch: + only: + - "${{CF_BRANCH}}" + BuildingNetPyNE-UI: + title: Building NetPyNE-UI + type: build + stage: build + image_name: netpyne-ui + working_directory: ${{main_clone}} + tag: '${{CF_SHORT_REVISION}}' + build_arguments: + - branch=${{CF_BRANCH}} + registry: ${{REGISTRY}} + when: + branch: + only: + - "${{CF_BRANCH}}" + BuildingHub: + title: Building Hub + type: build + stage: "build" + image_name: netpyne-hub + working_directory: k8s + tag: '${{CF_SHORT_REVISION}}' + registry: ${{REGISTRY}} + when: + branch: + only: + - "${{CF_BRANCH}}" + installing_chart: + type: helm + stage: deploy + title: "Deploy chart" + working_directory: NetPyNE-UI/k8s + arguments: + action: install + chart_name: jupyterhub + release_name: ${{RELEASE_NAME}} + helm_version: 3.0.2 + chart_repo_url: 'https://jupyterhub.github.io/helm-chart/' + chart_version: '0.9.0' + kube_context: ${{CLUSTER_NAME}} + namespace: ${{NAMESPACE}} + custom_value_files: + - 'cf_values.yaml' + custom_values: + - 'hub_image_tag=${{CF_SHORT_REVISION}}' + - 'singleuser_image_tag=${{CF_SHORT_REVISION}}' + - 'proxy_secretToken=${{SECRET_TOKEN}}' \ No newline at end of file diff --git a/k8s/cf_values.yaml b/k8s/cf_values.yaml new file mode 100644 index 00000000..8cc73408 --- /dev/null +++ b/k8s/cf_values.yaml @@ -0,0 +1,53 @@ +hub: + image: + name: gcr.io/metacellllc/netpyne-hub + pullPolicy: IfNotPresent + + resources: + requests: + cpu: 100m + memory: 128Mi + + allowNamedServers: true + namedServerLimitPerUser: 2 + shutdownOnLogout: true + + extraConfig: + timing: | + c.JupyterHub.allow_named_servers = True + c.Spawner.port = 8000 + c.Spawner.http_timeout = 300 + c.Spawner.start_timeout = 300 + c.Spawner.notebook_dir = '/home/jovyan/work/NetPyNE-UI' + c.Spawner.default_url = '/geppetto' + c.Spawner.debug = True + spawner: >- + c.Spawner.args = ["--library=netpyne_ui", "--NotebookApp.disable_check_xsrf=True"] + +scheduling: + userScheduler: + replicas: 1 + +auth: + type: tmp + +singleuser: + storage: + type: none + memory: + guarantee: 0.2G + image: + name: gcr.io/metacellllc/netpyne-ui + pullPolicy: IfNotPresent + +cull: + enabled: true + users: false + removeNamedServers: true + timeout: 360 + every: 60 + concurrency: 10 + maxAge: 0 + +debug: + enabled: false \ No newline at end of file diff --git a/k8s/js/EventSource.js b/k8s/js/EventSource.js new file mode 100644 index 00000000..8a3e3d58 --- /dev/null +++ b/k8s/js/EventSource.js @@ -0,0 +1,919 @@ +require([], function() { + "use strict"; + + var setTimeout = window.setTimeout; + var clearTimeout = window.clearTimeout; + var XMLHttpRequest = window.XMLHttpRequest; + var XDomainRequest = window.XDomainRequest; + var NativeEventSource = window.EventSource; + + var document = window.document; + var Promise = window.Promise; + var fetch = window.fetch; + var Response = window.Response; + var TextDecoder = window.TextDecoder; + var TextEncoder = window.TextEncoder; + var AbortController = window.AbortController; + + if (Object.create == undefined) { + Object.create = function (C) { + function F(){} + F.prototype = C; + return new F(); + }; + } + + // ? + if (Promise != undefined && Promise.prototype["finally"] == undefined) { + Promise.prototype["finally"] = function (callback) { + return this.then(function (result) { + return Promise.resolve(callback()).then(function () { + return result; + }); + }, function (error) { + return Promise.resolve(callback()).then(function () { + throw error; + }); + }); + }; + } + + // see #118, #123, #125 + if (fetch != undefined && true) { + var originalFetch = fetch; + fetch = function (url, options) { + return Promise.resolve(originalFetch(url, options)); + }; + } + + if (AbortController == undefined) { + var originalFetch2 = fetch; + fetch = function (url, options) { + var signal = options.signal; + return originalFetch2(url, {headers: options.headers, credentials: options.credentials, cache: options.cache}).then(function (response) { + var reader = response.body.getReader(); + signal._reader = reader; + if (signal._aborted) { + signal._reader.cancel(); + } + return { + status: response.status, + statusText: response.statusText, + headers: response.headers, + body: { + getReader: function () { + return reader; + } + } + }; + }); + }; + AbortController = function () { + this.signal = { + _reader: null, + _aborted: false + }; + this.abort = function () { + if (this.signal._reader != null) { + this.signal._reader.cancel(); + } + this.signal._aborted = true; + }; + }; + } + + function TextDecoderPolyfill() { + this.bitsNeeded = 0; + this.codePoint = 0; + } + + TextDecoderPolyfill.prototype.decode = function (octets) { + function valid(codePoint, shift, octetsCount) { + if (octetsCount === 1) { + return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07FF; + } + if (octetsCount === 2) { + return codePoint >= 0x0800 >> shift && codePoint << shift <= 0xD7FF || codePoint >= 0xE000 >> shift && codePoint << shift <= 0xFFFF; + } + if (octetsCount === 3) { + return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10FFFF; + } + throw new Error(); + } + function octetsCount(bitsNeeded, codePoint) { + if (bitsNeeded === 6 * 1) { + return codePoint >> 6 > 15 ? 3 : codePoint > 31 ? 2 : 1; + } + if (bitsNeeded === 6 * 2) { + return codePoint > 15 ? 3 : 2; + } + if (bitsNeeded === 6 * 3) { + return 3; + } + throw new Error(); + } + var REPLACER = 0xFFFD; + var string = ""; + var bitsNeeded = this.bitsNeeded; + var codePoint = this.codePoint; + for (var i = 0; i < octets.length; i += 1) { + var octet = octets[i]; + if (bitsNeeded !== 0) { + if (octet < 128 || octet > 191 || !valid(codePoint << 6 | octet & 63, bitsNeeded - 6, octetsCount(bitsNeeded, codePoint))) { + bitsNeeded = 0; + codePoint = REPLACER; + string += String.fromCharCode(codePoint); + } + } + if (bitsNeeded === 0) { + if (octet >= 0 && octet <= 127) { + bitsNeeded = 0; + codePoint = octet; + } else if (octet >= 192 && octet <= 223) { + bitsNeeded = 6 * 1; + codePoint = octet & 31; + } else if (octet >= 224 && octet <= 239) { + bitsNeeded = 6 * 2; + codePoint = octet & 15; + } else if (octet >= 240 && octet <= 247) { + bitsNeeded = 6 * 3; + codePoint = octet & 7; + } else { + bitsNeeded = 0; + codePoint = REPLACER; + } + if (bitsNeeded !== 0 && !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint))) { + bitsNeeded = 0; + codePoint = REPLACER; + } + } else { + bitsNeeded -= 6; + codePoint = codePoint << 6 | octet & 63; + } + if (bitsNeeded === 0) { + if (codePoint <= 0xFFFF) { + string += String.fromCharCode(codePoint); + } else { + string += String.fromCharCode(0xD800 + (codePoint - 0xFFFF - 1 >> 10)); + string += String.fromCharCode(0xDC00 + (codePoint - 0xFFFF - 1 & 0x3FF)); + } + } + } + this.bitsNeeded = bitsNeeded; + this.codePoint = codePoint; + return string; + }; + + // Firefox < 38 throws an error with stream option + var supportsStreamOption = function () { + try { + return new TextDecoder().decode(new TextEncoder().encode("test"), {stream: true}) === "test"; + } catch (error) { + console.log(error); + } + return false; + }; + + // IE, Edge + if (TextDecoder == undefined || TextEncoder == undefined || !supportsStreamOption()) { + TextDecoder = TextDecoderPolyfill; + } + + var k = function () { + }; + + function XHRWrapper(xhr) { + this.withCredentials = false; + this.responseType = ""; + this.readyState = 0; + this.status = 0; + this.statusText = ""; + this.responseText = ""; + this.onprogress = k; + this.onreadystatechange = k; + this._contentType = ""; + this._xhr = xhr; + this._sendTimeout = 0; + this._abort = k; + } + + XHRWrapper.prototype.open = function (method, url) { + this._abort(true); + + var that = this; + var xhr = this._xhr; + var state = 1; + var timeout = 0; + + this._abort = function (silent) { + if (that._sendTimeout !== 0) { + clearTimeout(that._sendTimeout); + that._sendTimeout = 0; + } + if (state === 1 || state === 2 || state === 3) { + state = 4; + xhr.onload = k; + xhr.onerror = k; + xhr.onabort = k; + xhr.onprogress = k; + xhr.onreadystatechange = k; + // IE 8 - 9: XDomainRequest#abort() does not fire any event + // Opera < 10: XMLHttpRequest#abort() does not fire any event + xhr.abort(); + if (timeout !== 0) { + clearTimeout(timeout); + timeout = 0; + } + if (!silent) { + that.readyState = 4; + that.onreadystatechange(); + } + } + state = 0; + }; + + var onStart = function () { + if (state === 1) { + //state = 2; + var status = 0; + var statusText = ""; + var contentType = undefined; + if (!("contentType" in xhr)) { + try { + status = xhr.status; + statusText = xhr.statusText; + contentType = xhr.getResponseHeader("Content-Type"); + } catch (error) { + // IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3 + // Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2 + // https://bugs.webkit.org/show_bug.cgi?id=29121 + status = 0; + statusText = ""; + contentType = undefined; + // Firefox < 14, Chrome ?, Safari ? + // https://bugs.webkit.org/show_bug.cgi?id=29658 + // https://bugs.webkit.org/show_bug.cgi?id=77854 + } + } else { + status = 200; + statusText = "OK"; + contentType = xhr.contentType; + } + if (status !== 0) { + state = 2; + that.readyState = 2; + that.status = status; + that.statusText = statusText; + that._contentType = contentType; + that.onreadystatechange(); + } + } + }; + var onProgress = function () { + onStart(); + if (state === 2 || state === 3) { + state = 3; + var responseText = ""; + try { + responseText = xhr.responseText; + } catch (error) { + // IE 8 - 9 with XMLHttpRequest + } + that.readyState = 3; + that.responseText = responseText; + that.onprogress(); + } + }; + var onFinish = function () { + // Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3) + // IE 8 fires "onload" without "onprogress" + onProgress(); + if (state === 1 || state === 2 || state === 3) { + state = 4; + if (timeout !== 0) { + clearTimeout(timeout); + timeout = 0; + } + that.readyState = 4; + that.onreadystatechange(); + } + }; + var onReadyStateChange = function () { + if (xhr != undefined) { // Opera 12 + if (xhr.readyState === 4) { + onFinish(); + } else if (xhr.readyState === 3) { + onProgress(); + } else if (xhr.readyState === 2) { + onStart(); + } + } + }; + var onTimeout = function () { + timeout = setTimeout(function () { + onTimeout(); + }, 500); + if (xhr.readyState === 3) { + onProgress(); + } + }; + + // XDomainRequest#abort removes onprogress, onerror, onload + xhr.onload = onFinish; + xhr.onerror = onFinish; + // improper fix to match Firefox behaviour, but it is better than just ignore abort + // see https://bugzilla.mozilla.org/show_bug.cgi?id=768596 + // https://bugzilla.mozilla.org/show_bug.cgi?id=880200 + // https://code.google.com/p/chromium/issues/detail?id=153570 + // IE 8 fires "onload" without "onprogress + xhr.onabort = onFinish; + + // https://bugzilla.mozilla.org/show_bug.cgi?id=736723 + if (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype)) { + xhr.onprogress = onProgress; + } + + // IE 8 - 9 (XMLHTTPRequest) + // Opera < 12 + // Firefox < 3.5 + // Firefox 3.5 - 3.6 - ? < 9.0 + // onprogress is not fired sometimes or delayed + // see also #64 + xhr.onreadystatechange = onReadyStateChange; + + if ("contentType" in xhr) { + url += (url.indexOf("?") === -1 ? "?" : "&") + "padding=true"; + } + xhr.open(method, url, true); + + if ("readyState" in xhr) { + // workaround for Opera 12 issue with "progress" events + // #91 + timeout = setTimeout(function () { + onTimeout(); + }, 0); + } + }; + XHRWrapper.prototype.abort = function () { + this._abort(false); + }; + XHRWrapper.prototype.getResponseHeader = function (name) { + return this._contentType; + }; + XHRWrapper.prototype.setRequestHeader = function (name, value) { + var xhr = this._xhr; + if ("setRequestHeader" in xhr) { + xhr.setRequestHeader(name, value); + } + }; + XHRWrapper.prototype.getAllResponseHeaders = function () { + return this._xhr.getAllResponseHeaders != undefined ? this._xhr.getAllResponseHeaders() : ""; + }; + XHRWrapper.prototype.send = function () { + // loading indicator in Safari < ? (6), Chrome < 14, Firefox + if (!("ontimeout" in XMLHttpRequest.prototype) && + document != undefined && + document.readyState != undefined && + document.readyState !== "complete") { + var that = this; + that._sendTimeout = setTimeout(function () { + that._sendTimeout = 0; + that.send(); + }, 4); + return; + } + + var xhr = this._xhr; + // withCredentials should be set after "open" for Safari and Chrome (< 19 ?) + xhr.withCredentials = this.withCredentials; + xhr.responseType = this.responseType; + try { + // xhr.send(); throws "Not enough arguments" in Firefox 3.0 + xhr.send(undefined); + } catch (error1) { + // Safari 5.1.7, Opera 12 + throw error1; + } + }; + + function toLowerCase(name) { + return name.replace(/[A-Z]/g, function (c) { + return String.fromCharCode(c.charCodeAt(0) + 0x20); + }); + } + + function HeadersPolyfill(all) { + // Get headers: implemented according to mozilla's example code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example + var map = Object.create(null); + var array = all.split("\r\n"); + for (var i = 0; i < array.length; i += 1) { + var line = array[i]; + var parts = line.split(": "); + var name = parts.shift(); + var value = parts.join(": "); + map[toLowerCase(name)] = value; + } + this._map = map; + } + HeadersPolyfill.prototype.get = function (name) { + return this._map[toLowerCase(name)]; + }; + + function XHRTransport() { + } + + XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) { + xhr.open("GET", url); + var offset = 0; + xhr.onprogress = function () { + var responseText = xhr.responseText; + var chunk = responseText.slice(offset); + offset += chunk.length; + onProgressCallback(chunk); + }; + xhr.onreadystatechange = function () { + if (xhr.readyState === 2) { + var status = xhr.status; + var statusText = xhr.statusText; + var contentType = xhr.getResponseHeader("Content-Type"); + var headers = xhr.getAllResponseHeaders(); + onStartCallback(status, statusText, contentType, new HeadersPolyfill(headers)); + } else if (xhr.readyState === 4) { + onFinishCallback(); + } + }; + xhr.withCredentials = withCredentials; + xhr.responseType = "text"; + for (var name in headers) { + if (Object.prototype.hasOwnProperty.call(headers, name)) { + xhr.setRequestHeader(name, headers[name]); + } + } + xhr.send(); + return xhr; + }; + + function HeadersWrapper(headers) { + this._headers = headers; + } + HeadersWrapper.prototype.get = function (name) { + return this._headers.get(name); + }; + + function FetchTransport() { + } + + FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) { + var controller = new AbortController(); + var signal = controller.signal;// see #120 + var textDecoder = new TextDecoder(); + fetch(url, { + headers: headers, + credentials: withCredentials ? "include" : "same-origin", + signal: signal, + cache: "no-store" + }).then(function (response) { + var reader = response.body.getReader(); + onStartCallback(response.status, response.statusText, response.headers.get("Content-Type"), new HeadersWrapper(response.headers)); + return new Promise(function (resolve, reject) { + var readNextChunk = function () { + reader.read().then(function (result) { + if (result.done) { + //Note: bytes in textDecoder are ignored + resolve(undefined); + } else { + var chunk = textDecoder.decode(result.value, {stream: true}); + onProgressCallback(chunk); + readNextChunk(); + } + })["catch"](function (error) { + reject(error); + }); + }; + readNextChunk(); + }); + })["catch"](function (error) { + if (error.name === "AbortError") { + return undefined; // catch the exception, see #130, #133 + } else { + throw error; + } + })["finally"](function () { + onFinishCallback(); + }); + return controller; + }; + + function EventTarget() { + this._listeners = Object.create(null); + } + + function throwError(e) { + setTimeout(function () { + throw e; + }, 0); + } + + EventTarget.prototype.dispatchEvent = function (event) { + event.target = this; + var typeListeners = this._listeners[event.type]; + if (typeListeners != undefined) { + var length = typeListeners.length; + for (var i = 0; i < length; i += 1) { + var listener = typeListeners[i]; + try { + if (typeof listener.handleEvent === "function") { + listener.handleEvent(event); + } else { + listener.call(this, event); + } + } catch (e) { + throwError(e); + } + } + } + }; + EventTarget.prototype.addEventListener = function (type, listener) { + type = String(type); + var listeners = this._listeners; + var typeListeners = listeners[type]; + if (typeListeners == undefined) { + typeListeners = []; + listeners[type] = typeListeners; + } + var found = false; + for (var i = 0; i < typeListeners.length; i += 1) { + if (typeListeners[i] === listener) { + found = true; + } + } + if (!found) { + typeListeners.push(listener); + } + }; + EventTarget.prototype.removeEventListener = function (type, listener) { + type = String(type); + var listeners = this._listeners; + var typeListeners = listeners[type]; + if (typeListeners != undefined) { + var filtered = []; + for (var i = 0; i < typeListeners.length; i += 1) { + if (typeListeners[i] !== listener) { + filtered.push(typeListeners[i]); + } + } + if (filtered.length === 0) { + delete listeners[type]; + } else { + listeners[type] = filtered; + } + } + }; + + function Event(type) { + this.type = type; + this.target = undefined; + } + + function MessageEvent(type, options) { + Event.call(this, type); + this.data = options.data; + this.lastEventId = options.lastEventId; + } + + MessageEvent.prototype = Object.create(Event.prototype); + + function ConnectionEvent(type, options) { + Event.call(this, type); + this.status = options.status; + this.statusText = options.statusText; + this.headers = options.headers; + } + + ConnectionEvent.prototype = Object.create(Event.prototype); + + var WAITING = -1; + var CONNECTING = 0; + var OPEN = 1; + var CLOSED = 2; + + var AFTER_CR = -1; + var FIELD_START = 0; + var FIELD = 1; + var VALUE_START = 2; + var VALUE = 3; + + var contentTypeRegExp = /^text\/event\-stream;?(\s*charset\=utf\-8)?$/i; + + var MINIMUM_DURATION = 1000; + var MAXIMUM_DURATION = 18000000; + + var parseDuration = function (value, def) { + var n = parseInt(value, 10); + if (n !== n) { + n = def; + } + return clampDuration(n); + }; + var clampDuration = function (n) { + return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION); + }; + + var fire = function (that, f, event) { + try { + if (typeof f === "function") { + f.call(that, event); + } + } catch (e) { + throwError(e); + } + }; + + function EventSourcePolyfill(url, options) { + EventTarget.call(this); + + this.onopen = undefined; + this.onmessage = undefined; + this.onerror = undefined; + + this.url = undefined; + this.readyState = undefined; + this.withCredentials = undefined; + + this._close = undefined; + + start(this, url, options); + } + + function getBestTransport() { + return (XMLHttpRequest != undefined && ("withCredentials" in XMLHttpRequest.prototype)) || XDomainRequest == undefined + ? XMLHttpRequest + : XDomainRequest; + } + + var isFetchSupported = fetch != undefined && Response != undefined && "body" in Response.prototype; + + function start(es, url, options) { + url = String(url); + var withCredentials = options != undefined && Boolean(options.withCredentials); + + var initialRetry = clampDuration(1000); + var heartbeatTimeout = options != undefined && options.heartbeatTimeout != undefined ? parseDuration(options.heartbeatTimeout, 45000) : clampDuration(45000); + + var lastEventId = ""; + var retry = initialRetry; + var wasActivity = false; + var headers = options != undefined && options.headers != undefined ? JSON.parse(JSON.stringify(options.headers)) : undefined; + var CurrentTransport = options != undefined && options.Transport != undefined ? options.Transport : getBestTransport(); + var xhr = isFetchSupported && !(options != undefined && options.Transport != undefined) ? undefined : new XHRWrapper(new CurrentTransport()); + var transport = xhr == undefined ? new FetchTransport() : new XHRTransport(); + var abortController = undefined; + var timeout = 0; + var currentState = WAITING; + var dataBuffer = ""; + var lastEventIdBuffer = ""; + var eventTypeBuffer = ""; + + var textBuffer = ""; + var state = FIELD_START; + var fieldStart = 0; + var valueStart = 0; + + var onStart = function (status, statusText, contentType, headers) { + if (currentState === CONNECTING) { + if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) { + currentState = OPEN; + wasActivity = true; + retry = initialRetry; + es.readyState = OPEN; + var event = new ConnectionEvent("open", { + status: status, + statusText: statusText, + headers: headers + }); + es.dispatchEvent(event); + fire(es, es.onopen, event); + } else { + var message = ""; + if (status !== 200) { + if (statusText) { + statusText = statusText.replace(/\s+/g, " "); + } + message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection."; + } else { + message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection."; + } + throwError(new Error(message)); + close(); + var event = new ConnectionEvent("error", { + status: status, + statusText: statusText, + headers: headers + }); + es.dispatchEvent(event); + fire(es, es.onerror, event); + } + } + }; + + var onProgress = function (textChunk) { + if (currentState === OPEN) { + var n = -1; + for (var i = 0; i < textChunk.length; i += 1) { + var c = textChunk.charCodeAt(i); + if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) { + n = i; + } + } + var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1); + textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1); + if (chunk !== "") { + wasActivity = true; + } + for (var position = 0; position < chunk.length; position += 1) { + var c = chunk.charCodeAt(position); + if (state === AFTER_CR && c === "\n".charCodeAt(0)) { + state = FIELD_START; + } else { + if (state === AFTER_CR) { + state = FIELD_START; + } + if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) { + if (state !== FIELD_START) { + if (state === FIELD) { + valueStart = position + 1; + } + var field = chunk.slice(fieldStart, valueStart - 1); + var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position); + if (field === "data") { + dataBuffer += "\n"; + dataBuffer += value; + } else if (field === "id") { + lastEventIdBuffer = value; + } else if (field === "event") { + eventTypeBuffer = value; + } else if (field === "retry") { + initialRetry = parseDuration(value, initialRetry); + retry = initialRetry; + } else if (field === "heartbeatTimeout") { + heartbeatTimeout = parseDuration(value, heartbeatTimeout); + if (timeout !== 0) { + clearTimeout(timeout); + timeout = setTimeout(function () { + onTimeout(); + }, heartbeatTimeout); + } + } + } + if (state === FIELD_START) { + if (dataBuffer !== "") { + lastEventId = lastEventIdBuffer; + if (eventTypeBuffer === "") { + eventTypeBuffer = "message"; + } + var event = new MessageEvent(eventTypeBuffer, { + data: dataBuffer.slice(1), + lastEventId: lastEventIdBuffer + }); + es.dispatchEvent(event); + if (eventTypeBuffer === "message") { + fire(es, es.onmessage, event); + } + if (currentState === CLOSED) { + return; + } + } + dataBuffer = ""; + eventTypeBuffer = ""; + } + state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START; + } else { + if (state === FIELD_START) { + fieldStart = position; + state = FIELD; + } + if (state === FIELD) { + if (c === ":".charCodeAt(0)) { + valueStart = position + 1; + state = VALUE_START; + } + } else if (state === VALUE_START) { + state = VALUE; + } + } + } + } + } + }; + + var onFinish = function () { + if (currentState === OPEN || currentState === CONNECTING) { + currentState = WAITING; + if (timeout !== 0) { + clearTimeout(timeout); + timeout = 0; + } + timeout = setTimeout(function () { + onTimeout(); + }, retry); + retry = clampDuration(Math.min(initialRetry * 16, retry * 2)); + + es.readyState = CONNECTING; + var event = new Event("error"); + es.dispatchEvent(event); + fire(es, es.onerror, event); + } + }; + + var close = function () { + currentState = CLOSED; + if (abortController != undefined) { + abortController.abort(); + abortController = undefined; + } + if (timeout !== 0) { + clearTimeout(timeout); + timeout = 0; + } + es.readyState = CLOSED; + }; + + var onTimeout = function () { + timeout = 0; + + if (currentState !== WAITING) { + if (!wasActivity && abortController != undefined) { + throwError(new Error("No activity within " + heartbeatTimeout + " milliseconds. Reconnecting.")); + abortController.abort(); + abortController = undefined; + } else { + wasActivity = false; + timeout = setTimeout(function () { + onTimeout(); + }, heartbeatTimeout); + } + return; + } + + wasActivity = false; + timeout = setTimeout(function () { + onTimeout(); + }, heartbeatTimeout); + + currentState = CONNECTING; + dataBuffer = ""; + eventTypeBuffer = ""; + lastEventIdBuffer = lastEventId; + textBuffer = ""; + fieldStart = 0; + valueStart = 0; + state = FIELD_START; + + // https://bugzilla.mozilla.org/show_bug.cgi?id=428916 + // Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers. + var requestURL = url; + if (url.slice(0, 5) !== "data:" && url.slice(0, 5) !== "blob:") { + if (lastEventId !== "") { + requestURL += (url.indexOf("?") === -1 ? "?" : "&") + "lastEventId=" + encodeURIComponent(lastEventId); + } + } + var requestHeaders = {}; + requestHeaders["Accept"] = "text/event-stream"; + if (headers != undefined) { + for (var name in headers) { + if (Object.prototype.hasOwnProperty.call(headers, name)) { + requestHeaders[name] = headers[name]; + } + } + } + try { + abortController = transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders); + } catch (error) { + close(); + throw error; + } + }; + + es.url = url; + es.readyState = CONNECTING; + es.withCredentials = withCredentials; + es._close = close; + + onTimeout(); + } + + EventSourcePolyfill.prototype = Object.create(EventTarget.prototype); + EventSourcePolyfill.prototype.CONNECTING = CONNECTING; + EventSourcePolyfill.prototype.OPEN = OPEN; + EventSourcePolyfill.prototype.CLOSED = CLOSED; + EventSourcePolyfill.prototype.close = function () { + this._close(); + }; + + EventSourcePolyfill.CONNECTING = CONNECTING; + EventSourcePolyfill.OPEN = OPEN; + EventSourcePolyfill.CLOSED = CLOSED; + EventSourcePolyfill.prototype.withCredentials = undefined; + + window.IEEventSource = EventSourcePolyfill +}) \ No newline at end of file diff --git a/k8s/minikube_values.yaml b/k8s/minikube_values.yaml new file mode 100644 index 00000000..79d1b855 --- /dev/null +++ b/k8s/minikube_values.yaml @@ -0,0 +1,60 @@ +# Use with minikubes +hub: + image: + name: netpy-hub + tag: 'latest' + pullPolicy: IfNotPresent + + resources: + requests: + cpu: 200m + memory: 512Mi + + allowNamedServers: true + namedServerLimitPerUser: 2 + shutdownOnLogout: true + + extraConfig: + timing: | + c.JupyterHub.allow_named_servers = True + c.Spawner.port = 8000 + c.Spawner.http_timeout = 300 + c.Spawner.start_timeout = 300 + c.Spawner.notebook_dir = '/home/jovyan/work/NetPyNE-UI' + c.Spawner.default_url = '/geppetto' + c.Spawner.debug = True + c.Spawner.disable_check_xsrf=True + spawner: >- + c.Spawner.args = ["--library=netpyne_ui", "--NotebookApp.disable_check_xsrf=True"] + +scheduling: + userScheduler: + replicas: 1 + +proxy: + secretToken: 'b3fed077c7538cfc5e2a6469ddac7d43a18fc645789407b53e580b7342b968d8' + +auth: + type: tmp + +singleuser: + storage: + type: none + memory: + guarantee: 0.2G + image: + name: netpy + tag: 'latest' + pullPolicy: IfNotPresent + +cull: + enabled: true + users: false + removeNamedServers: true + timeout: 360 + every: 60 + concurrency: 10 + maxAge: 0 + +debug: + enabled: false \ No newline at end of file diff --git a/k8s/static/favicon.ico b/k8s/static/favicon.ico new file mode 100644 index 00000000..3c790fc2 Binary files /dev/null and b/k8s/static/favicon.ico differ diff --git a/k8s/static/jupyter.png b/k8s/static/jupyter.png new file mode 100644 index 00000000..8a36b9d7 Binary files /dev/null and b/k8s/static/jupyter.png differ diff --git a/k8s/templates/404.html b/k8s/templates/404.html new file mode 100644 index 00000000..3b38968c --- /dev/null +++ b/k8s/templates/404.html @@ -0,0 +1,5 @@ + +{% extends "error.html" %} + +{% block error_detail %} +{% endblock %} \ No newline at end of file diff --git a/k8s/templates/page.html b/k8s/templates/page.html new file mode 100644 index 00000000..e1449821 --- /dev/null +++ b/k8s/templates/page.html @@ -0,0 +1,123 @@ +{% macro modal(title, btn_label=None, btn_class="btn-primary") %} +{% set key = title.replace(' ', '-').lower() %} +{% set btn_label = btn_label or title %} + +{% endmacro %} + + + + + + + + + {% block title %}NetPyNE-UI{% endblock %} + + + + {% block stylesheet %} + + {% endblock %} + {% block favicon %} + + {% endblock %} + {% block scripts %} + + + + {% endblock %} + + + + + {% block meta %} + {% endblock %} + + + + + + + +{% block announcement %} +{% if announcement %} +
+ {{ announcement | safe }} +
+{% endif %} +{% endblock %} + + +{% block main %} +{% endblock %} + +{% call modal('Error', btn_label='OK') %} +
+ The error +
+{% endcall %} + +{% block script %} +{% endblock %} + + + + \ No newline at end of file diff --git a/k8s/templates/spawn_pending.html b/k8s/templates/spawn_pending.html new file mode 100644 index 00000000..7c236d7d --- /dev/null +++ b/k8s/templates/spawn_pending.html @@ -0,0 +1,101 @@ +{% extends "page.html" %} + +{% block main %} + +
+
+
+ {% block message %} + +

We are loading the NetPyNE web interface…

+ {% endblock %} +
+
+ 0% Complete +
+
+

+
+
+
+
+
+ Event log +
+
+
+
+
+ +{% endblock %} + +{% block script %} +{{ super() }} + +{% endblock %} \ No newline at end of file diff --git a/model_output.json b/model_output.json new file mode 100644 index 00000000..9619287d --- /dev/null +++ b/model_output.json @@ -0,0 +1,6437 @@ +{ + "net": { + "cells": [ + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 0, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 19.340099413101537, + "xnorm": 0.19340099413101539, + "y": 93.6351771015592, + "ynorm": 0.936351771015592, + "z": 33.7528911806287, + "znorm": 0.337528911806287 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 1, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 37.85417961472316, + "xnorm": 0.37854179614723155, + "y": 79.42265496137024, + "ynorm": 0.7942265496137024, + "z": 72.71084371658254, + "znorm": 0.7271084371658255 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 2, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 40.231326539015555, + "xnorm": 0.40231326539015555, + "y": 27.88420097718849, + "ynorm": 0.2788420097718849, + "z": 4.0990537488602445, + "znorm": 0.040990537488602444 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 3, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 53.0736020642627, + "xnorm": 0.530736020642627, + "y": 60.990046928406215, + "ynorm": 0.6099004692840622, + "z": 70.1596227078327, + "znorm": 0.7015962270783269 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 4, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 86.22650765203254, + "xnorm": 0.8622650765203254, + "y": 43.29907094517279, + "ynorm": 0.43299070945172785, + "z": 98.28196952625132, + "znorm": 0.9828196952625132 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 5, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 18.97275084187911, + "xnorm": 0.1897275084187911, + "y": 30.303045727707666, + "ynorm": 0.30303045727707667, + "z": 55.69689670677834, + "znorm": 0.5569689670677834 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 6, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 50.82208862276234, + "xnorm": 0.5082208862276234, + "y": 88.58929076497692, + "ynorm": 0.8858929076497692, + "z": 67.60160155417361, + "znorm": 0.6760160155417361 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 7, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 80.10665006467453, + "xnorm": 0.8010665006467452, + "y": 90.76698520435788, + "ynorm": 0.9076698520435789, + "z": 46.40942401103456, + "znorm": 0.4640942401103456 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 8, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 29.38965129913072, + "xnorm": 0.2938965129913072, + "y": 11.27270187454468, + "ynorm": 0.1127270187454468, + "z": 27.20613634977347, + "znorm": 0.2720613634977347 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 9, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 5.393666353683531, + "xnorm": 0.05393666353683531, + "y": 5.752420936303116, + "ynorm": 0.057524209363031154, + "z": 49.50057935214122, + "znorm": 0.4950057935214122 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 10, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 42.49757550598644, + "xnorm": 0.4249757550598644, + "y": 75.43112633856221, + "ynorm": 0.754311263385622, + "z": 7.722096050222847, + "znorm": 0.07722096050222847 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 11, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 75.29452874434773, + "xnorm": 0.7529452874434773, + "y": 99.53457692183215, + "ynorm": 0.9953457692183215, + "z": 49.431939877236275, + "znorm": 0.49431939877236275 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 12, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 33.161065091108654, + "xnorm": 0.33161065091108655, + "y": 38.89676236107555, + "ynorm": 0.38896762361075554, + "z": 99.81790846217939, + "znorm": 0.9981790846217938 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 13, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 78.17075001584116, + "xnorm": 0.7817075001584116, + "y": 44.56458628537027, + "ynorm": 0.44564586285370267, + "z": 87.67918672233839, + "znorm": 0.8767918672233839 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 14, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 81.30328301775658, + "xnorm": 0.8130328301775659, + "y": 36.80926537215494, + "ynorm": 0.3680926537215494, + "z": 97.93858318637623, + "znorm": 0.9793858318637624 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 15, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 33.32419920868143, + "xnorm": 0.33324199208681426, + "y": 77.5606433447542, + "ynorm": 0.775606433447542, + "z": 34.49650408362586, + "znorm": 0.34496504083625856 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 16, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 93.29694716881566, + "xnorm": 0.9329694716881566, + "y": 9.349959690740807, + "ynorm": 0.09349959690740807, + "z": 74.06596574604838, + "znorm": 0.7406596574604838 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 17, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 92.62211106423706, + "xnorm": 0.9262211106423706, + "y": 41.56458227858772, + "ynorm": 0.4156458227858772, + "z": 44.24904674658341, + "znorm": 0.4424904674658341 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 18, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 38.50150282063952, + "xnorm": 0.3850150282063952, + "y": 60.53124438958912, + "ynorm": 0.6053124438958912, + "z": 25.590026186408938, + "znorm": 0.2559002618640894 + } + }, + { + "conns": [ + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 19, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "S", + "x": 83.3236039189334, + "xnorm": 0.833236039189334, + "y": 85.10786947209671, + "ynorm": 0.8510786947209671, + "z": 74.50295484752792, + "znorm": 0.7450295484752791 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 0, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 3, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 20, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 14.595917841746491, + "xnorm": 0.14595917841746492, + "y": 76.6970283406095, + "ynorm": 0.7669702834060951, + "z": 58.31755270289314, + "znorm": 0.5831755270289314 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 0, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 3, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 21, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 70.59966091285467, + "xnorm": 0.7059966091285468, + "y": 16.724399426783343, + "ynorm": 0.16724399426783343, + "z": 79.44890391560064, + "znorm": 0.7944890391560064 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 22, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 34.48264870455427, + "xnorm": 0.3448264870455427, + "y": 29.190681262595884, + "ynorm": 0.29190681262595886, + "z": 30.725447546987457, + "znorm": 0.30725447546987456 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 0, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 23, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 34.78531925129115, + "xnorm": 0.34785319251291147, + "y": 57.83682485161423, + "ynorm": 0.5783682485161423, + "z": 55.326534468837416, + "znorm": 0.5532653446883742 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 3, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 24, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 23.8039814345995, + "xnorm": 0.238039814345995, + "y": 93.34508041074847, + "ynorm": 0.9334508041074847, + "z": 12.121350268805084, + "znorm": 0.12121350268805085 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 25, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 97.22312928707731, + "xnorm": 0.9722312928707731, + "y": 54.89294602188911, + "ynorm": 0.5489294602188911, + "z": 28.945946779813163, + "znorm": 0.28945946779813164 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 26, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 71.1686574222593, + "xnorm": 0.711686574222593, + "y": 12.253944619499626, + "ynorm": 0.12253944619499625, + "z": 29.878486476401218, + "znorm": 0.29878486476401217 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 0, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 3, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 27, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 56.86056263352266, + "xnorm": 0.5686056263352266, + "y": 20.58665081379315, + "ynorm": 0.20586650813793148, + "z": 1.7024822761997387, + "znorm": 0.017024822761997387 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 28, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 87.23702407739195, + "xnorm": 0.8723702407739194, + "y": 14.631315387172783, + "ynorm": 0.14631315387172783, + "z": 94.43429927471226, + "znorm": 0.9443429927471226 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 29, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 98.16098609050712, + "xnorm": 0.9816098609050713, + "y": 18.943561143487795, + "ynorm": 0.18943561143487794, + "z": 94.64099588928721, + "znorm": 0.946409958892872 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 30, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 40.0821044249269, + "xnorm": 0.40082104424926895, + "y": 97.40857943021493, + "ynorm": 0.9740857943021493, + "z": 78.57933261464831, + "znorm": 0.7857933261464831 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 3, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 31, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 29.406519623145805, + "xnorm": 0.29406519623145805, + "y": 31.47681408294551, + "ynorm": 0.3147681408294551, + "z": 76.1793544571429, + "znorm": 0.7617935445714291 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 32, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 59.36563458308446, + "xnorm": 0.5936563458308446, + "y": 19.170680986910433, + "ynorm": 0.19170680986910435, + "z": 44.00753075163636, + "znorm": 0.4400753075163636 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 33, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 13.444674943237409, + "xnorm": 0.13444674943237409, + "y": 74.95935813641191, + "ynorm": 0.749593581364119, + "z": 10.002505986485048, + "znorm": 0.10002505986485047 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 3, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 34, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 59.54330450400167, + "xnorm": 0.5954330450400167, + "y": 67.56035250901236, + "ynorm": 0.6756035250901237, + "z": 61.75314375158559, + "znorm": 0.6175314375158559 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 35, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 19.14749303386838, + "xnorm": 0.1914749303386838, + "y": 32.743411177596215, + "ynorm": 0.32743411177596216, + "z": 96.74400154111348, + "znorm": 0.9674400154111348 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 14, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 15, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 36, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 80.63356187645496, + "xnorm": 0.8063356187645496, + "y": 17.479580310760166, + "ynorm": 0.17479580310760165, + "z": 80.21769994399098, + "znorm": 0.8021769994399098 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 0, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 2, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 8, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 37, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 77.96974450397079, + "xnorm": 0.7796974450397078, + "y": 37.78503662026836, + "ynorm": 0.3778503662026836, + "z": 85.56172382422683, + "znorm": 0.8556172382422683 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 0, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 1, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 5, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 11, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 38, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 70.51938325853101, + "xnorm": 0.7051938325853101, + "y": 24.316007452012038, + "ynorm": 0.24316007452012037, + "z": 70.01965798669968, + "znorm": 0.7001965798669968 + } + }, + { + "conns": [ + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 4, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 6, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 7, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 9, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 10, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 12, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 13, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 16, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 17, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 18, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "label": "S->M", + "loc": 0.5, + "preGid": 19, + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + }, + { + "delay": 5, + "loc": 0.5, + "preGid": "NetStim", + "preLabel": "bkg", + "sec": "soma", + "synMech": "exc", + "weight": 0.01 + } + ], + "gid": 39, + "secLists": {}, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + }, + "synMechs": [ + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + }, + { + "e": 0, + "label": "exc", + "loc": 0.5, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + ], + "topol": {} + } + }, + "stims": [ + { + "noise": 0.5, + "number": 1000000000.0, + "rate": 10, + "seed": 1, + "source": "bkg", + "start": 0, + "type": "NetStim" + } + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "label": [ + "PYRrule" + ], + "pop": "M", + "x": 93.71703351062791, + "xnorm": 0.9371703351062791, + "y": 75.4602125670155, + "ynorm": 0.754602125670155, + "z": 46.68317138061785, + "znorm": 0.4668317138061785 + } + } + ], + "params": { + "cellParams": { + "PYRrule": { + "conds": { + "cellType": "PYR" + }, + "secs": { + "soma": { + "geom": { + "L": 18.8, + "Ra": 123.0, + "diam": 18.8 + }, + "mechs": { + "hh": { + "el": -70, + "gkbar": 0.036, + "gl": 0.003, + "gnabar": 0.12 + } + } + } + } + } + }, + "connParams": { + "S->M": { + "delay": 5, + "postConds": { + "pop": "M" + }, + "preConds": { + "pop": "S" + }, + "probability": 0.5, + "synMech": "exc", + "weight": 0.01 + } + }, + "correctBorder": false, + "defaultDelay": 1, + "defaultThreshold": 10, + "defaultWeight": 1, + "defineCellShapes": false, + "popParams": { + "M": { + "cellModel": "HH", + "cellType": "PYR", + "numCells": 20, + "pop": "M" + }, + "S": { + "cellModel": "HH", + "cellType": "PYR", + "numCells": 20, + "pop": "S" + } + }, + "popTagsCopiedToCells": [ + "cellModel", + "cellType" + ], + "propVelocity": 500.0, + "rotateCellsRandomly": false, + "rxdParams": {}, + "scale": 1, + "scaleConnWeight": 1, + "scaleConnWeightModels": false, + "scaleConnWeightNetStims": 1, + "shape": "cuboid", + "sizeX": 100, + "sizeY": 100, + "sizeZ": 100, + "stimSourceParams": { + "bkg": { + "noise": 0.5, + "rate": 10, + "type": "NetStim" + } + }, + "stimTargetParams": { + "bkg->PYR": { + "conds": { + "cellType": "PYR" + }, + "delay": 5, + "loc": null, + "sec": null, + "source": "bkg", + "synMech": "exc", + "weight": 0.01 + } + }, + "subConnParams": {}, + "synMechParams": { + "exc": { + "e": 0, + "mod": "Exp2Syn", + "tau1": 0.1, + "tau2": 5.0 + } + } + }, + "pops": { + "M": { + "cellGids": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39 + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "numCells": 20, + "pop": "M" + } + }, + "S": { + "cellGids": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "tags": { + "cellModel": "HH", + "cellType": "PYR", + "numCells": 20, + "pop": "S" + } + } + } + }, + "netpyne_changeset": "", + "netpyne_version": "0.9.6", + "simConfig": { + "addSynMechs": true, + "allowConnsWithWeight0": true, + "allowSelfConns": false, + "analysis": { + "plot2Dnet": true, + "plotRaster": true, + "plotTraces": { + "include": [ + 1 + ] + } + }, + "backupCfgFile": [], + "cache_efficient": false, + "checkErrors": false, + "checkErrorsVerbose": false, + "compactConnFormat": false, + "connRandomSecFromList": true, + "createNEURONObj": true, + "createPyStruct": true, + "cvode_active": false, + "cvode_atol": 0.001, + "distributeSynsUniformly": true, + "dt": 0.025, + "duration": 1000.0, + "filename": "model_output", + "gatherOnlySimData": false, + "hParams": { + "celsius": 6.3, + "clamp_resist": 0.001, + "v_init": -65.0 + }, + "includeParamsLabel": true, + "invertedYCoord": true, + "oneSynPerNetcon": true, + "printPopAvgRates": false, + "printRunTime": false, + "printSynsAfterRule": false, + "pt3dRelativeToCellLocation": true, + "rand123GlobalIndex": null, + "recordCells": [], + "recordCellsSpikes": -1, + "recordDipoles": false, + "recordLFP": [], + "recordStep": 0.1, + "recordStim": false, + "recordTime": true, + "recordTraces": { + "V_soma": { + "loc": 0.5, + "sec": "soma", + "var": "v" + } + }, + "saveCSV": false, + "saveCellConns": true, + "saveCellSecs": true, + "saveDat": false, + "saveDataInclude": [ + "netParams", + "netCells", + "netPops", + "simConfig", + "simData" + ], + "saveDpk": false, + "saveFolder": "", + "saveHDF5": false, + "saveJson": true, + "saveLFPCells": false, + "saveMat": false, + "savePickle": false, + "saveTiming": false, + "seeds": { + "conn": 1, + "loc": 1, + "stim": 1 + }, + "simLabel": "", + "timestampFilename": false, + "timing": true, + "tstop": 1000.0, + "verbose": false + }, + "simData": { + "V_soma": { + "cell_1": [] + }, + "spkid": [], + "spkt": [], + "t": [] + } +} \ No newline at end of file diff --git a/netpyne_ui/__init__.py b/netpyne_ui/__init__.py index e69de29b..cb0bf72e 100644 --- a/netpyne_ui/__init__.py +++ b/netpyne_ui/__init__.py @@ -0,0 +1,6 @@ +import logging +from jupyter_geppetto.webapi import RouteManager + +from netpyne_ui import api + +RouteManager.add_controller(api.NetPyNEController) \ No newline at end of file diff --git a/netpyne_ui/api.py b/netpyne_ui/api.py new file mode 100644 index 00000000..91cac361 --- /dev/null +++ b/netpyne_ui/api.py @@ -0,0 +1,111 @@ +import os +import logging +import uuid +import gzip +import tarfile +import shutil +from zipfile import ZipFile +from tempfile import TemporaryDirectory +from jupyter_geppetto.webapi import get, post +from notebook.base.handlers import IPythonHandler +from netpyne_ui.constants import NETPYNE_WORKDIR, UPLOAD_FOLDER_NAME, ALLOWED_EXTENSIONS, UPLOAD_FOLDER_PATH + +def allowed_file(filename, allowed_extensions=ALLOWED_EXTENSIONS): + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in allowed_extensions + + +def send_files(handler, file_path, filename): + with open(file_path, "rb") as f: + handler.set_header('Content-Type', 'application/force-download') + handler.set_header('Content-Disposition', f"attachment; filename={filename}") + + try: + while True: + _buffer = f.read(4096) + if _buffer: + handler.write(_buffer) + else: + return + except: + handler.set_status(500, f"Error sending files") + + +def get_file_paths(handler): + file_paths = False + if 'uri' in handler.request.arguments: + file_paths = [] + tmp_file_paths = [path.decode('utf-8') for path in handler.request.arguments['uri']] + for path in tmp_file_paths: + if os.path.exists(path): + file_paths.append(path) + + return file_paths + +class NetPyNEController: # pytest: no cover + + @post('/uploads') + def uploads(handler: IPythonHandler): + files = handler.request.files + files_saved = 0 + + if len(files) == 0 or 'file' not in files: + handler.set_status(400, f"Can't find 'file' or filename is empty. Files received {len(files)}") + else: + + for f in files['file']: + if not allowed_file(f.filename): + logging.warn(f"Can't store file {f.filename}. Extension not allowed") + continue + + ## Save to file + filename = f.filename + file_path = os.path.join(UPLOAD_FOLDER_PATH, filename) + + with open(file_path, 'wb') as zf: + zf.write(f['body']) + + files_saved += 1 + + if filename.endswith('.zip'): + with ZipFile(file_path) as zipObj: + zipObj.extractall(UPLOAD_FOLDER_PATH) + + elif filename.endswith('.tar.gz'): + with tarfile.open(file_path, mode='r:gz') as tar: + tar.extractall(UPLOAD_FOLDER_PATH) + + elif filename.endswith('.gz'): + with gzip.open(file_path, "rb") as gz, open(file_path.replace('.gz', ''), 'wb') as ff: + shutil.copyfileobj(gz, ff) + + handler.set_status(200, f"Number of files saved: {files_saved}. Number of files sent: {len(files['file'])}") + + handler.finish() + + @get('/downloads') + def downloads(handler: IPythonHandler): + + file_paths = get_file_paths(handler) + + if file_paths: + + if len(file_paths) == 0: + handler.set_status(400, f"Files not found.") + handler.finish() + return + + if len(file_paths) == 1: + send_files(handler, file_paths[0], file_paths[0].split('/')[-1]) + + else : + with TemporaryDirectory() as dir_path: + tar_gz_file_name = f'{str(uuid.uuid4())}.tar.gz' + tar_gz_file_path = os.path.join(dir_path, tar_gz_file_name) + with tarfile.open(tar_gz_file_path, mode='w:gz') as tar: + for file_path in file_paths: + tar.add(file_path, os.path.join('download', file_path.split('/')[-1])) + + send_files(handler, tar_gz_file_path, tar_gz_file_name) + + handler.finish() diff --git a/netpyne_ui/constants.py b/netpyne_ui/constants.py new file mode 100644 index 00000000..78eacb53 --- /dev/null +++ b/netpyne_ui/constants.py @@ -0,0 +1,15 @@ +import os + +UPLOAD_FOLDER_NAME = 'uploads' +NETPYNE_WORKDIR = 'netpyne_workspace' + +ALLOWED_EXTENSIONS = ["py", "zip", "gz", ".tar.gz", "pdf", "txt", "xls", "png", "jpeg", "hoc"] + +UPLOAD_FOLDER_PATH = os.path.join(os.getcwd(), NETPYNE_WORKDIR, UPLOAD_FOLDER_NAME) +NETPYNE_WORKDIR_PATH = os.path.join(os.getcwd(), NETPYNE_WORKDIR) + +if not os.path.exists(UPLOAD_FOLDER_PATH): + os.makedirs(UPLOAD_FOLDER_PATH) + +if not os.path.exists(NETPYNE_WORKDIR_PATH): + os.makedirs(NETPYNE_WORKDIR_PATH) \ No newline at end of file diff --git a/netpyne_ui/tests/M1detailed/M1detailed.json b/netpyne_ui/examples/M1detailed/M1detailed.json similarity index 100% rename from netpyne_ui/tests/M1detailed/M1detailed.json rename to netpyne_ui/examples/M1detailed/M1detailed.json diff --git a/netpyne_ui/tests/M1detailed/README b/netpyne_ui/examples/M1detailed/README similarity index 100% rename from netpyne_ui/tests/M1detailed/README rename to netpyne_ui/examples/M1detailed/README diff --git a/netpyne_ui/tests/M1detailed/__init__.py b/netpyne_ui/examples/M1detailed/__init__.py similarity index 100% rename from netpyne_ui/tests/M1detailed/__init__.py rename to netpyne_ui/examples/M1detailed/__init__.py diff --git a/netpyne_ui/tests/M1detailed/cells/CT6_reduced_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/CT6_reduced_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/CT6_reduced_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/CT6_reduced_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/FS3.hoc b/netpyne_ui/examples/M1detailed/cells/FS3.hoc similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/FS3.hoc rename to netpyne_ui/examples/M1detailed/cells/FS3.hoc diff --git a/netpyne_ui/tests/M1detailed/cells/IT2_reduced_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT2_reduced_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT2_reduced_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT2_reduced_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT4_reduced_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT4_reduced_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT4_reduced_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT4_reduced_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT5A_full_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT5A_full_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT5A_full_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT5A_full_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT5A_reduced_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT5A_reduced_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT5A_reduced_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT5A_reduced_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT5B_full_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT5B_full_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT5B_full_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT5B_full_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT5B_reduced_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT5B_reduced_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT5B_reduced_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT5B_reduced_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT6_reduced_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT6_reduced_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT6_reduced_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT6_reduced_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT_full_BS1578_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT_full_BS1578_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT_full_BS1578_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT_full_BS1578_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/IT_full_BS1579_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/IT_full_BS1579_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/IT_full_BS1579_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/IT_full_BS1579_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/ITcell.py b/netpyne_ui/examples/M1detailed/cells/ITcell.py similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/ITcell.py rename to netpyne_ui/examples/M1detailed/cells/ITcell.py diff --git a/netpyne_ui/tests/M1detailed/cells/LTS3.hoc b/netpyne_ui/examples/M1detailed/cells/LTS3.hoc similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/LTS3.hoc rename to netpyne_ui/examples/M1detailed/cells/LTS3.hoc diff --git a/netpyne_ui/tests/M1detailed/cells/PT5B_full_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/PT5B_full_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/PT5B_full_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/PT5B_full_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/PT5B_reduced_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/PT5B_reduced_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/PT5B_reduced_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/PT5B_reduced_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/PT_full_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/PT_full_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/PT_full_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/PT_full_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/PTcell.hoc b/netpyne_ui/examples/M1detailed/cells/PTcell.hoc similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/PTcell.hoc rename to netpyne_ui/examples/M1detailed/cells/PTcell.hoc diff --git a/netpyne_ui/tests/M1detailed/cells/PV_simple_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/PV_simple_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/PV_simple_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/PV_simple_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/SOM_simple_cellParams.pkl b/netpyne_ui/examples/M1detailed/cells/SOM_simple_cellParams.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/SOM_simple_cellParams.pkl rename to netpyne_ui/examples/M1detailed/cells/SOM_simple_cellParams.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/cellDensity.pkl b/netpyne_ui/examples/M1detailed/cells/cellDensity.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/cellDensity.pkl rename to netpyne_ui/examples/M1detailed/cells/cellDensity.pkl diff --git a/netpyne_ui/tests/M1detailed/cells/cellDensity.py b/netpyne_ui/examples/M1detailed/cells/cellDensity.py similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/cellDensity.py rename to netpyne_ui/examples/M1detailed/cells/cellDensity.py diff --git a/netpyne_ui/tests/M1detailed/cells/popColors.pkl b/netpyne_ui/examples/M1detailed/cells/popColors.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/cells/popColors.pkl rename to netpyne_ui/examples/M1detailed/cells/popColors.pkl diff --git a/netpyne_ui/tests/M1detailed/cfg.py b/netpyne_ui/examples/M1detailed/cfg.py similarity index 100% rename from netpyne_ui/tests/M1detailed/cfg.py rename to netpyne_ui/examples/M1detailed/cfg.py diff --git a/netpyne_ui/tests/M1detailed/compile b/netpyne_ui/examples/M1detailed/compile similarity index 100% rename from netpyne_ui/tests/M1detailed/compile rename to netpyne_ui/examples/M1detailed/compile diff --git a/netpyne_ui/tests/M1detailed/conn/CT6_reduced_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/CT6_reduced_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/CT6_reduced_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/CT6_reduced_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/IT2_reduced_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/IT2_reduced_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/IT2_reduced_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/IT2_reduced_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/IT4_reduced_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/IT4_reduced_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/IT4_reduced_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/IT4_reduced_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/IT5A_reduced_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/IT5A_reduced_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/IT5A_reduced_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/IT5A_reduced_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/IT5B_reduced_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/IT5B_reduced_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/IT5B_reduced_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/IT5B_reduced_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/IT6_reduced_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/IT6_reduced_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/IT6_reduced_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/IT6_reduced_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/IT_full_BS1579_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/IT_full_BS1579_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/IT_full_BS1579_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/IT_full_BS1579_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/PT5B_full_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/PT5B_full_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/PT5B_full_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/PT5B_full_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/PT5B_reduced_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/PT5B_reduced_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/PT5B_reduced_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/PT5B_reduced_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/PV_simple_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/PV_simple_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/PV_simple_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/PV_simple_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/SOM_simple_weightNorm.pkl b/netpyne_ui/examples/M1detailed/conn/SOM_simple_weightNorm.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/SOM_simple_weightNorm.pkl rename to netpyne_ui/examples/M1detailed/conn/SOM_simple_weightNorm.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/conn.pkl b/netpyne_ui/examples/M1detailed/conn/conn.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/conn.pkl rename to netpyne_ui/examples/M1detailed/conn/conn.pkl diff --git a/netpyne_ui/tests/M1detailed/conn/conn_dend_IT.json b/netpyne_ui/examples/M1detailed/conn/conn_dend_IT.json similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/conn_dend_IT.json rename to netpyne_ui/examples/M1detailed/conn/conn_dend_IT.json diff --git a/netpyne_ui/tests/M1detailed/conn/conn_dend_PT.json b/netpyne_ui/examples/M1detailed/conn/conn_dend_PT.json similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/conn_dend_PT.json rename to netpyne_ui/examples/M1detailed/conn/conn_dend_PT.json diff --git a/netpyne_ui/tests/M1detailed/conn/conn_long.pkl b/netpyne_ui/examples/M1detailed/conn/conn_long.pkl similarity index 100% rename from netpyne_ui/tests/M1detailed/conn/conn_long.pkl rename to netpyne_ui/examples/M1detailed/conn/conn_long.pkl diff --git a/netpyne_ui/tests/M1detailed/mod/HCN1.mod b/netpyne_ui/examples/M1detailed/mod/HCN1.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/HCN1.mod rename to netpyne_ui/examples/M1detailed/mod/HCN1.mod diff --git a/netpyne_ui/tests/M1detailed/mod/IC.mod b/netpyne_ui/examples/M1detailed/mod/IC.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/IC.mod rename to netpyne_ui/examples/M1detailed/mod/IC.mod diff --git a/netpyne_ui/tests/M1detailed/mod/IKsin.mod b/netpyne_ui/examples/M1detailed/mod/IKsin.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/IKsin.mod rename to netpyne_ui/examples/M1detailed/mod/IKsin.mod diff --git a/netpyne_ui/tests/M1detailed/mod/MyExp2SynBB.mod b/netpyne_ui/examples/M1detailed/mod/MyExp2SynBB.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/MyExp2SynBB.mod rename to netpyne_ui/examples/M1detailed/mod/MyExp2SynBB.mod diff --git a/netpyne_ui/tests/M1detailed/mod/MyExp2SynNMDABB.mod b/netpyne_ui/examples/M1detailed/mod/MyExp2SynNMDABB.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/MyExp2SynNMDABB.mod rename to netpyne_ui/examples/M1detailed/mod/MyExp2SynNMDABB.mod diff --git a/netpyne_ui/tests/M1detailed/mod/ar_traub.mod b/netpyne_ui/examples/M1detailed/mod/ar_traub.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/ar_traub.mod rename to netpyne_ui/examples/M1detailed/mod/ar_traub.mod diff --git a/netpyne_ui/tests/M1detailed/mod/cadad.mod b/netpyne_ui/examples/M1detailed/mod/cadad.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/cadad.mod rename to netpyne_ui/examples/M1detailed/mod/cadad.mod diff --git a/netpyne_ui/tests/M1detailed/mod/cadyn.mod b/netpyne_ui/examples/M1detailed/mod/cadyn.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/cadyn.mod rename to netpyne_ui/examples/M1detailed/mod/cadyn.mod diff --git a/netpyne_ui/tests/M1detailed/mod/cagk.mod b/netpyne_ui/examples/M1detailed/mod/cagk.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/cagk.mod rename to netpyne_ui/examples/M1detailed/mod/cagk.mod diff --git a/netpyne_ui/tests/M1detailed/mod/cal_mh.mod b/netpyne_ui/examples/M1detailed/mod/cal_mh.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/cal_mh.mod rename to netpyne_ui/examples/M1detailed/mod/cal_mh.mod diff --git a/netpyne_ui/tests/M1detailed/mod/cal_mig.mod b/netpyne_ui/examples/M1detailed/mod/cal_mig.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/cal_mig.mod rename to netpyne_ui/examples/M1detailed/mod/cal_mig.mod diff --git a/netpyne_ui/tests/M1detailed/mod/can_mig.mod b/netpyne_ui/examples/M1detailed/mod/can_mig.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/can_mig.mod rename to netpyne_ui/examples/M1detailed/mod/can_mig.mod diff --git a/netpyne_ui/tests/M1detailed/mod/canin.mod b/netpyne_ui/examples/M1detailed/mod/canin.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/canin.mod rename to netpyne_ui/examples/M1detailed/mod/canin.mod diff --git a/netpyne_ui/tests/M1detailed/mod/cat_mig.mod b/netpyne_ui/examples/M1detailed/mod/cat_mig.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/cat_mig.mod rename to netpyne_ui/examples/M1detailed/mod/cat_mig.mod diff --git a/netpyne_ui/tests/M1detailed/mod/cat_traub.mod b/netpyne_ui/examples/M1detailed/mod/cat_traub.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/cat_traub.mod rename to netpyne_ui/examples/M1detailed/mod/cat_traub.mod diff --git a/netpyne_ui/tests/M1detailed/mod/catcb.mod b/netpyne_ui/examples/M1detailed/mod/catcb.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/catcb.mod rename to netpyne_ui/examples/M1detailed/mod/catcb.mod diff --git a/netpyne_ui/tests/M1detailed/mod/gabab.mod b/netpyne_ui/examples/M1detailed/mod/gabab.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/gabab.mod rename to netpyne_ui/examples/M1detailed/mod/gabab.mod diff --git a/netpyne_ui/tests/M1detailed/mod/ghk.inc b/netpyne_ui/examples/M1detailed/mod/ghk.inc similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/ghk.inc rename to netpyne_ui/examples/M1detailed/mod/ghk.inc diff --git a/netpyne_ui/tests/M1detailed/mod/h_BS.mod b/netpyne_ui/examples/M1detailed/mod/h_BS.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/h_BS.mod rename to netpyne_ui/examples/M1detailed/mod/h_BS.mod diff --git a/netpyne_ui/tests/M1detailed/mod/h_harnett.mod b/netpyne_ui/examples/M1detailed/mod/h_harnett.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/h_harnett.mod rename to netpyne_ui/examples/M1detailed/mod/h_harnett.mod diff --git a/netpyne_ui/tests/M1detailed/mod/h_kole.mod b/netpyne_ui/examples/M1detailed/mod/h_kole.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/h_kole.mod rename to netpyne_ui/examples/M1detailed/mod/h_kole.mod diff --git a/netpyne_ui/tests/M1detailed/mod/h_migliore.mod b/netpyne_ui/examples/M1detailed/mod/h_migliore.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/h_migliore.mod rename to netpyne_ui/examples/M1detailed/mod/h_migliore.mod diff --git a/netpyne_ui/tests/M1detailed/mod/hin.mod b/netpyne_ui/examples/M1detailed/mod/hin.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/hin.mod rename to netpyne_ui/examples/M1detailed/mod/hin.mod diff --git a/netpyne_ui/tests/M1detailed/mod/ican_sidi.mod b/netpyne_ui/examples/M1detailed/mod/ican_sidi.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/ican_sidi.mod rename to netpyne_ui/examples/M1detailed/mod/ican_sidi.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kBK.mod b/netpyne_ui/examples/M1detailed/mod/kBK.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kBK.mod rename to netpyne_ui/examples/M1detailed/mod/kBK.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kap_BS.mod b/netpyne_ui/examples/M1detailed/mod/kap_BS.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kap_BS.mod rename to netpyne_ui/examples/M1detailed/mod/kap_BS.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kapcb.mod b/netpyne_ui/examples/M1detailed/mod/kapcb.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kapcb.mod rename to netpyne_ui/examples/M1detailed/mod/kapcb.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kapin.mod b/netpyne_ui/examples/M1detailed/mod/kapin.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kapin.mod rename to netpyne_ui/examples/M1detailed/mod/kapin.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kctin.mod b/netpyne_ui/examples/M1detailed/mod/kctin.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kctin.mod rename to netpyne_ui/examples/M1detailed/mod/kctin.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kdmc_BS.mod b/netpyne_ui/examples/M1detailed/mod/kdmc_BS.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kdmc_BS.mod rename to netpyne_ui/examples/M1detailed/mod/kdmc_BS.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kdr_BS.mod b/netpyne_ui/examples/M1detailed/mod/kdr_BS.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kdr_BS.mod rename to netpyne_ui/examples/M1detailed/mod/kdr_BS.mod diff --git a/netpyne_ui/tests/M1detailed/mod/kdrin.mod b/netpyne_ui/examples/M1detailed/mod/kdrin.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/kdrin.mod rename to netpyne_ui/examples/M1detailed/mod/kdrin.mod diff --git a/netpyne_ui/tests/M1detailed/mod/misc.h b/netpyne_ui/examples/M1detailed/mod/misc.h similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/misc.h rename to netpyne_ui/examples/M1detailed/mod/misc.h diff --git a/netpyne_ui/tests/M1detailed/mod/nafx.mod b/netpyne_ui/examples/M1detailed/mod/nafx.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/nafx.mod rename to netpyne_ui/examples/M1detailed/mod/nafx.mod diff --git a/netpyne_ui/tests/M1detailed/mod/nap_sidi.mod b/netpyne_ui/examples/M1detailed/mod/nap_sidi.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/nap_sidi.mod rename to netpyne_ui/examples/M1detailed/mod/nap_sidi.mod diff --git a/netpyne_ui/tests/M1detailed/mod/nax_BS.mod b/netpyne_ui/examples/M1detailed/mod/nax_BS.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/nax_BS.mod rename to netpyne_ui/examples/M1detailed/mod/nax_BS.mod diff --git a/netpyne_ui/tests/M1detailed/mod/parameters.multi b/netpyne_ui/examples/M1detailed/mod/parameters.multi similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/parameters.multi rename to netpyne_ui/examples/M1detailed/mod/parameters.multi diff --git a/netpyne_ui/tests/M1detailed/mod/savedist.mod b/netpyne_ui/examples/M1detailed/mod/savedist.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/savedist.mod rename to netpyne_ui/examples/M1detailed/mod/savedist.mod diff --git a/netpyne_ui/tests/M1detailed/mod/vecstim.mod b/netpyne_ui/examples/M1detailed/mod/vecstim.mod similarity index 100% rename from netpyne_ui/tests/M1detailed/mod/vecstim.mod rename to netpyne_ui/examples/M1detailed/mod/vecstim.mod diff --git a/netpyne_ui/tests/M1detailed/netParams.py b/netpyne_ui/examples/M1detailed/netParams.py similarity index 100% rename from netpyne_ui/tests/M1detailed/netParams.py rename to netpyne_ui/examples/M1detailed/netParams.py diff --git a/netpyne_ui/tests/M1detailed/runsim b/netpyne_ui/examples/M1detailed/runsim similarity index 100% rename from netpyne_ui/tests/M1detailed/runsim rename to netpyne_ui/examples/M1detailed/runsim diff --git a/netpyne_ui/tests/__init__.py b/netpyne_ui/examples/__init__.py similarity index 100% rename from netpyne_ui/tests/__init__.py rename to netpyne_ui/examples/__init__.py diff --git a/netpyne_ui/tests/cells/CSTR6.py b/netpyne_ui/examples/cells/CSTR6.py similarity index 100% rename from netpyne_ui/tests/cells/CSTR6.py rename to netpyne_ui/examples/cells/CSTR6.py diff --git a/netpyne_ui/tests/cells/FS3.hoc b/netpyne_ui/examples/cells/FS3.hoc similarity index 100% rename from netpyne_ui/tests/cells/FS3.hoc rename to netpyne_ui/examples/cells/FS3.hoc diff --git a/netpyne_ui/tests/cells/HHCellFile.py b/netpyne_ui/examples/cells/HHCellFile.py similarity index 100% rename from netpyne_ui/tests/cells/HHCellFile.py rename to netpyne_ui/examples/cells/HHCellFile.py diff --git a/netpyne_ui/tests/cells/ITcell.py b/netpyne_ui/examples/cells/ITcell.py similarity index 100% rename from netpyne_ui/tests/cells/ITcell.py rename to netpyne_ui/examples/cells/ITcell.py diff --git a/netpyne_ui/tests/cells/LTS3.hoc b/netpyne_ui/examples/cells/LTS3.hoc similarity index 94% rename from netpyne_ui/tests/cells/LTS3.hoc rename to netpyne_ui/examples/cells/LTS3.hoc index 998eb43d..63593af5 100644 --- a/netpyne_ui/tests/cells/LTS3.hoc +++ b/netpyne_ui/examples/cells/LTS3.hoc @@ -1,158 +1,158 @@ -//Interneuron for PFC - Calbindin/LTS interneuron -//Written 25-10-2007 by Xenia Konstantoudaki - - -begintemplate LTScell - -public soma, axon, dend - -create soma, axon, dend - -proc init () { - -create soma, axon, dend - -soma_nafcb=0.075 -soma_kdrin=0.018 -soma_hin=0.000002 -soma_kapcb=0.007*5 -soma_catcb=0.003 - -soma { - nseg=1 - L=42 - diam=42 - - insert pas - cm=1.2 //microF/cm2 - g_pas =1/40000 - e_pas = v_initcb - v_initcb= -64 - Ra=150 - - - - insert Nafx - gnafbar_Nafx= soma_nafcb - - insert kdrin - gkdrbar_kdrin= soma_kdrin - - insert hin - gbar_hin= soma_hin - - insert kapcb - gkabar_kapcb= soma_kapcb - - insert catcb - gcatbar_catcb=soma_catcb - - insert cadyn -} - -axon { - nseg=1 - L=113.22 - diam=1.1 - insert pas - cm=1.2 //microF/cm2 - g_pas =1/40000 - e_pas = v_initcb - v_initcb= -64 - Ra=150 - - insert Nafx - gnafbar_Nafx= soma_nafcb*10 - - insert kdrin - gkdrbar_kdrin= soma_kdrin*0.5 -} - -dend { - nseg=1 - L=8*22 - diam=7 - - - insert pas - cm=1.2 //microF/cm2 - g_pas =1/40000 - e_pas = v_initcb - v_initcb= -64 - Ra=150 - - insert Nafx - gnafbar_Nafx=0.018 - - insert kdrin - gkdrbar_kdrin=0.018*0.5 - - insert kapcb - gkabar_kapcb=0.00875 - - -} - - ko0_k_ion = 3.82 //mM - ki0_k_ion = 140 //mM - celsius = 23 - connect axon(0), soma(0.5) - connect dend(0), soma(0) -} - -init() - -endtemplate LTScell - -//Creating new interneurons - -// nCBcells = 1 -// objref LTScell1 - -// LTScell1 = new LTScell() - -// //Create list with segments -// objref cbsoma_list, cbcell_list - -// cbsoma_list = new SectionList() -// LTScell1.soma cbsoma_list.append() - - -// cbcell_list = new SectionList() -// LTScell1.soma cbcell_list.append() -// LTScell1.axon cbcell_list.append() -// LTScell1.dend cbcell_list.append() - - -// proc current_balancecb() { - -// finitialize($1) -// fcurrent() - -// printf("Balancing each compartment to %d mV\n", $1) - -// forsec cbcell_list{ -// for (x) { -// if (ismembrane("na_ion")) {e_pas(x)=v(x)+ina(x)/g_pas(x)} -// if (ismembrane("k_ion")) {e_pas(x)=e_pas(x)+ik(x)/g_pas(x)} - -// if (ismembrane("ca_ion")) {e_pas(x)=e_pas(x)+ica(x)/g_pas(x)} -// // if (ismembrane("Ca_ion")) {e_pas(x)=e_pas(x)+iCa(x)/g_pas(x)} -// if (ismembrane("in_ion")) {e_pas(x)=e_pas(x)+in(x)/g_pas(x)} //ican -// if (ismembrane("h")) {e_pas(x)=e_pas(x)+ihi(x)/g_pas(x)} - -// // d = distance(1,x) -// // xdist = find_vector_distance_precise(secname(),x) // calc. perpedicular distance -// // printf("x = %e, xdist = %e, d = %e, e_pas = %e mV, rm = %e mA/(mVcm2)\n", x, xdist, d, e_pas(x), 1./g_pas(x)) -// // fcurrent() -// } -// } -// } - -// current_balancecb(-64) - - - - - - +//Interneuron for PFC - Calbindin/LTS interneuron +//Written 25-10-2007 by Xenia Konstantoudaki + + +begintemplate LTScell + +public soma, axon, dend + +create soma, axon, dend + +proc init () { + +create soma, axon, dend + +soma_nafcb=0.075 +soma_kdrin=0.018 +soma_hin=0.000002 +soma_kapcb=0.007*5 +soma_catcb=0.003 + +soma { + nseg=1 + L=42 + diam=42 + + insert pas + cm=1.2 //microF/cm2 + g_pas =1/40000 + e_pas = v_initcb + v_initcb= -64 + Ra=150 + + + + insert Nafx + gnafbar_Nafx= soma_nafcb + + insert kdrin + gkdrbar_kdrin= soma_kdrin + + insert hin + gbar_hin= soma_hin + + insert kapcb + gkabar_kapcb= soma_kapcb + + insert catcb + gcatbar_catcb=soma_catcb + + insert cadyn +} + +axon { + nseg=1 + L=113.22 + diam=1.1 + insert pas + cm=1.2 //microF/cm2 + g_pas =1/40000 + e_pas = v_initcb + v_initcb= -64 + Ra=150 + + insert Nafx + gnafbar_Nafx= soma_nafcb*10 + + insert kdrin + gkdrbar_kdrin= soma_kdrin*0.5 +} + +dend { + nseg=1 + L=8*22 + diam=7 + + + insert pas + cm=1.2 //microF/cm2 + g_pas =1/40000 + e_pas = v_initcb + v_initcb= -64 + Ra=150 + + insert Nafx + gnafbar_Nafx=0.018 + + insert kdrin + gkdrbar_kdrin=0.018*0.5 + + insert kapcb + gkabar_kapcb=0.00875 + + +} + + ko0_k_ion = 3.82 //mM + ki0_k_ion = 140 //mM + celsius = 23 + connect axon(0), soma(0.5) + connect dend(0), soma(0) +} + +init() + +endtemplate LTScell + +//Creating new interneurons + +// nCBcells = 1 +// objref LTScell1 + +// LTScell1 = new LTScell() + +// //Create list with segments +// objref cbsoma_list, cbcell_list + +// cbsoma_list = new SectionList() +// LTScell1.soma cbsoma_list.append() + + +// cbcell_list = new SectionList() +// LTScell1.soma cbcell_list.append() +// LTScell1.axon cbcell_list.append() +// LTScell1.dend cbcell_list.append() + + +// proc current_balancecb() { + +// finitialize($1) +// fcurrent() + +// printf("Balancing each compartment to %d mV\n", $1) + +// forsec cbcell_list{ +// for (x) { +// if (ismembrane("na_ion")) {e_pas(x)=v(x)+ina(x)/g_pas(x)} +// if (ismembrane("k_ion")) {e_pas(x)=e_pas(x)+ik(x)/g_pas(x)} + +// if (ismembrane("ca_ion")) {e_pas(x)=e_pas(x)+ica(x)/g_pas(x)} +// // if (ismembrane("Ca_ion")) {e_pas(x)=e_pas(x)+iCa(x)/g_pas(x)} +// if (ismembrane("in_ion")) {e_pas(x)=e_pas(x)+in(x)/g_pas(x)} //ican +// if (ismembrane("h")) {e_pas(x)=e_pas(x)+ihi(x)/g_pas(x)} + +// // d = distance(1,x) +// // xdist = find_vector_distance_precise(secname(),x) // calc. perpedicular distance +// // printf("x = %e, xdist = %e, d = %e, e_pas = %e mV, rm = %e mA/(mVcm2)\n", x, xdist, d, e_pas(x), 1./g_pas(x)) +// // fcurrent() +// } +// } +// } + +// current_balancecb(-64) + + + + + + diff --git a/netpyne_ui/tests/cells/PTcell.hoc b/netpyne_ui/examples/cells/PTcell.hoc similarity index 100% rename from netpyne_ui/tests/cells/PTcell.hoc rename to netpyne_ui/examples/cells/PTcell.hoc diff --git a/netpyne_ui/tests/cells/PTcell.py b/netpyne_ui/examples/cells/PTcell.py similarity index 100% rename from netpyne_ui/tests/cells/PTcell.py rename to netpyne_ui/examples/cells/PTcell.py diff --git a/netpyne_ui/tests/cells/PTcell_simple.hoc b/netpyne_ui/examples/cells/PTcell_simple.hoc similarity index 100% rename from netpyne_ui/tests/cells/PTcell_simple.hoc rename to netpyne_ui/examples/cells/PTcell_simple.hoc diff --git a/netpyne_ui/tests/cells/SPI6.py b/netpyne_ui/examples/cells/SPI6.py similarity index 100% rename from netpyne_ui/tests/cells/SPI6.py rename to netpyne_ui/examples/cells/SPI6.py diff --git a/netpyne_ui/tests/cells/import.py b/netpyne_ui/examples/cells/import.py similarity index 100% rename from netpyne_ui/tests/cells/import.py rename to netpyne_ui/examples/cells/import.py diff --git a/netpyne_ui/tests/gui_tut1.py b/netpyne_ui/examples/gui_tut1.py similarity index 100% rename from netpyne_ui/tests/gui_tut1.py rename to netpyne_ui/examples/gui_tut1.py diff --git a/netpyne_ui/tests/mod/HCN1.mod b/netpyne_ui/examples/mod/HCN1.mod similarity index 100% rename from netpyne_ui/tests/mod/HCN1.mod rename to netpyne_ui/examples/mod/HCN1.mod diff --git a/netpyne_ui/tests/mod/IC.mod b/netpyne_ui/examples/mod/IC.mod similarity index 100% rename from netpyne_ui/tests/mod/IC.mod rename to netpyne_ui/examples/mod/IC.mod diff --git a/netpyne_ui/tests/mod/IKsin.mod b/netpyne_ui/examples/mod/IKsin.mod similarity index 100% rename from netpyne_ui/tests/mod/IKsin.mod rename to netpyne_ui/examples/mod/IKsin.mod diff --git a/netpyne_ui/tests/mod/MyExp2SynBB.mod b/netpyne_ui/examples/mod/MyExp2SynBB.mod similarity index 100% rename from netpyne_ui/tests/mod/MyExp2SynBB.mod rename to netpyne_ui/examples/mod/MyExp2SynBB.mod diff --git a/netpyne_ui/tests/mod/MyExp2SynNMDABB.mod b/netpyne_ui/examples/mod/MyExp2SynNMDABB.mod similarity index 100% rename from netpyne_ui/tests/mod/MyExp2SynNMDABB.mod rename to netpyne_ui/examples/mod/MyExp2SynNMDABB.mod diff --git a/netpyne_ui/tests/mod/ar_traub.mod b/netpyne_ui/examples/mod/ar_traub.mod similarity index 100% rename from netpyne_ui/tests/mod/ar_traub.mod rename to netpyne_ui/examples/mod/ar_traub.mod diff --git a/netpyne_ui/tests/mod/cadad.mod b/netpyne_ui/examples/mod/cadad.mod similarity index 100% rename from netpyne_ui/tests/mod/cadad.mod rename to netpyne_ui/examples/mod/cadad.mod diff --git a/netpyne_ui/tests/mod/cadyn.mod b/netpyne_ui/examples/mod/cadyn.mod similarity index 100% rename from netpyne_ui/tests/mod/cadyn.mod rename to netpyne_ui/examples/mod/cadyn.mod diff --git a/netpyne_ui/tests/mod/cagk.mod b/netpyne_ui/examples/mod/cagk.mod similarity index 100% rename from netpyne_ui/tests/mod/cagk.mod rename to netpyne_ui/examples/mod/cagk.mod diff --git a/netpyne_ui/tests/mod/cal_mh.mod b/netpyne_ui/examples/mod/cal_mh.mod similarity index 100% rename from netpyne_ui/tests/mod/cal_mh.mod rename to netpyne_ui/examples/mod/cal_mh.mod diff --git a/netpyne_ui/tests/mod/cal_mig.mod b/netpyne_ui/examples/mod/cal_mig.mod similarity index 100% rename from netpyne_ui/tests/mod/cal_mig.mod rename to netpyne_ui/examples/mod/cal_mig.mod diff --git a/netpyne_ui/tests/mod/can_mig.mod b/netpyne_ui/examples/mod/can_mig.mod similarity index 94% rename from netpyne_ui/tests/mod/can_mig.mod rename to netpyne_ui/examples/mod/can_mig.mod index aa16f008..eaa03e4b 100644 --- a/netpyne_ui/tests/mod/can_mig.mod +++ b/netpyne_ui/examples/mod/can_mig.mod @@ -1,144 +1,144 @@ -TITLE n-calcium channel -: n-type calcium channel -: MODELDB 126814 CA3 by Safiulina et al - http://senselab.med.yale.edu/modeldb/ShowModel.asp?model=126814 -: by Michele Migliore - - -UNITS { - (mA) = (milliamp) - (mV) = (millivolt) - - FARADAY = 96520 (coul) - R = 8.3134 (joule/degC) - KTOMV = .0853 (mV/degC) -} - -PARAMETER { - v (mV) - celsius (degC) - gcanbar=.0003 (mho/cm2) - ki=.001 (mM) - cai=50.e-6 (mM) - cao = 2 (mM) - q10=5 - mmin = 0.2 - hmin = 3 - a0m =0.03 - zetam = 2 - vhalfm = -14 - gmm=0.1 - USEGHK=1 - erev = 100 -} - -NEURON { - SUFFIX can - USEION ca READ cai,cao WRITE ica - RANGE gcanbar, ica, gcan - RANGE hinf,minf,taum,tauh - GLOBAL USEGHK -} - -STATE { - m h -} - -ASSIGNED { - ica (mA/cm2) - gcan (mho/cm2) - minf - hinf - taum - tauh -} - -INITIAL { - rates(v) - m = minf - h = hinf -} - -BREAKPOINT { - SOLVE states METHOD cnexp - gcan = gcanbar*m*m*h*h2(cai) - if (USEGHK == 1) { - ica = gcan*ghk(v,cai,cao) - } else { - ica = gcan*(v-erev) - } -} - -UNITSOFF -FUNCTION h2(cai(mM)) { - h2 = ki/(ki+cai) -} - - -FUNCTION ghk(v(mV), ci(mM), co(mM)) (mV) { - LOCAL nu,f - - f = KTF(celsius)/2 - nu = v/f - ghk=-f*(1. - (ci/co)*exp(nu))*efun(nu) -} - -FUNCTION KTF(celsius (degC)) (mV) { - KTF = ((25./293.15)*(celsius + 273.15)) -} - - -FUNCTION efun(z) { - if (fabs(z) < 1e-4) { - efun = 1 - z/2 - }else{ - efun = z/(exp(z) - 1) - } -} - -FUNCTION alph(v(mV)) { - alph = 1.6e-4*exp(-v/48.4) -} - -FUNCTION beth(v(mV)) { - beth = 1/(exp((-v+39.0)/10.)+1.) -} - -FUNCTION alpm(v(mV)) { - alpm = 0.1967*(-1.0*v+19.88)/(exp((-1.0*v+19.88)/10.0)-1.0) -} - -FUNCTION betm(v(mV)) { - betm = 0.046*exp(-v/20.73) -} - -FUNCTION alpmt(v(mV)) { - alpmt = exp(0.0378*zetam*(v-vhalfm)) -} - -FUNCTION betmt(v(mV)) { - betmt = exp(0.0378*zetam*gmm*(v-vhalfm)) -} - -UNITSON - -DERIVATIVE states { : exact when v held constant; integrates over dt step - rates(v) - m' = (minf - m)/taum - h' = (hinf - h)/tauh -} - -PROCEDURE rates(v (mV)) { :callable from hoc - LOCAL a, b, qt - qt=q10^((celsius-25)/10) - a = alpm(v) - b = 1/(a + betm(v)) - minf = a*b - taum = betmt(v)/(qt*a0m*(1+alpmt(v))) - if (taumost (k3,k4) - ~ost<->ist (k1,0.0) - ~ist<->cst (k2,0.0) - CONSERVE cst+ost+ist=1 -} - -:change feb8th for pfc -:PROCEDURE rates( v(mV), cani(mM)) { -PROCEDURE rates( v(mV), cai(mM)) { -: k1=alp( 0.1, v, -10.0, 1.0 ) : original - k1=alp( 0.01, v, -10.0, 1.0 ) :increases the current - k2=alp( 0.1, v, -120.0, -10.0 ) :original (0.1, -120, -10) -: k3=alpha( 0.001, 1.0, v, -20.0, 7.0 ) *1.0e8* ( cai*1.0(/mM) )^3 :original - k3=alpha( 0.001, 1.0, v, -20.0, 7.0 ) *1.0e8* (cai*1.0(/mM) )^3 - :k3 changes the attenuation - k4=alp( 0.2, v, -44.0, -5.0 ) :original -: k4=alp( 0.2, v, -44.0, -5.0 ) -} - -FUNCTION alpha( tmin(ms), tmax(ms), v(mV), vhalf(mV), k(mV) )(/ms){ - alpha = 1.0 / ( tmin + 1.0 / ( 1.0 / (tmax-tmin) + exp((v-vhalf)/k)*1.0(/ms) ) ) -} - -FUNCTION alp( tmin(ms), v(mV), vhalf(mV), k(mV) )(/ms){ - alp = 1.0 / ( tmin + exp( -(v-vhalf) / k )*1.0(ms) ) -} - - - - - - - - - + +TITLE Kct current + +COMMENT Equations from + Shao L.R., Halvorsrud R., Borg-Graham L., Storm J.F. The role of BK-type Ca2_-dependent K+ channels in spike broadening during repetitive firing in rat hippocampal pyramidal cells J.Physiology (1999),521:135-146 + + The Krasnow Institute + George Mason University + +Copyright Maciej Lazarewicz, 2001 + (mlazarew@gmu.edu) + All rights reserved. +ENDCOMMENT + +NEURON { + :SUFFIX mykca + SUFFIX kctin + USEION k READ ek WRITE ik + USEION ca READ cai + RANGE gkcbar,ik +} + +UNITS { + (molar) = (1/liter) + (mM) = (millimolar) + (S) = (siemens) + (mA) = (milliamp) + (mV) = (millivolt) +} + +PARAMETER { + gkcbar = 0 (S/cm2) + :gkbar = 1.0e-3 (S/cm2) +} + +ASSIGNED { + v (mV) + cai (mM) :26/10/04 htan se sxolio + celsius (degC) + ek (mV) + ik (mA/cm2) + k1 (/ms) + k2 (/ms) + k3 (/ms) + k4 (/ms) + q10 (1) +} + +STATE { cst ost ist } + +BREAKPOINT { + SOLVE kin METHOD sparse + ik = gkcbar * ost *( v - ek ) +} + +INITIAL { + SOLVE kin STEADYSTATE sparse +} + +KINETIC kin { +: rates(v, cani) + rates(v, cai) + ~cst<->ost (k3,k4) + ~ost<->ist (k1,0.0) + ~ist<->cst (k2,0.0) + CONSERVE cst+ost+ist=1 +} + +:change feb8th for pfc +:PROCEDURE rates( v(mV), cani(mM)) { +PROCEDURE rates( v(mV), cai(mM)) { +: k1=alp( 0.1, v, -10.0, 1.0 ) : original + k1=alp( 0.01, v, -10.0, 1.0 ) :increases the current + k2=alp( 0.1, v, -120.0, -10.0 ) :original (0.1, -120, -10) +: k3=alpha( 0.001, 1.0, v, -20.0, 7.0 ) *1.0e8* ( cai*1.0(/mM) )^3 :original + k3=alpha( 0.001, 1.0, v, -20.0, 7.0 ) *1.0e8* (cai*1.0(/mM) )^3 + :k3 changes the attenuation + k4=alp( 0.2, v, -44.0, -5.0 ) :original +: k4=alp( 0.2, v, -44.0, -5.0 ) +} + +FUNCTION alpha( tmin(ms), tmax(ms), v(mV), vhalf(mV), k(mV) )(/ms){ + alpha = 1.0 / ( tmin + 1.0 / ( 1.0 / (tmax-tmin) + exp((v-vhalf)/k)*1.0(/ms) ) ) +} + +FUNCTION alp( tmin(ms), v(mV), vhalf(mV), k(mV) )(/ms){ + alp = 1.0 / ( tmin + exp( -(v-vhalf) / k )*1.0(ms) ) +} + + + + + + + + + diff --git a/netpyne_ui/tests/mod/kdmc_BS.mod b/netpyne_ui/examples/mod/kdmc_BS.mod similarity index 96% rename from netpyne_ui/tests/mod/kdmc_BS.mod rename to netpyne_ui/examples/mod/kdmc_BS.mod index 8fa27bd9..1270e4f9 100644 --- a/netpyne_ui/tests/mod/kdmc_BS.mod +++ b/netpyne_ui/examples/mod/kdmc_BS.mod @@ -1,93 +1,93 @@ -TITLE K-D channel with activation for motor cortex -: K-D current with activation, for motor cortex pyramidal neurons, per Miller et al. (2008) -: Based on K-A current K-A current for Mitral Cells from Wang et al (1996), by M.Migliore Jan. 2002 -: 2011-02-25 Ben Suter, first version, using MM's kamt.mod as a starting template -: 2011-09-18 Ben Suter, set default parameter values to those found from MRF optimization for BS0284 model -: -: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -: Copyright 2011, Benjamin Suter -: Used in model of corticospinal neuron BS0284 and published as: -: "Intrinsic electrophysiology of mouse corticospinal neurons: a characteristic set of features embodied in a realistic computational model" -: by Benjamin Suter, Michele Migliore, and Gordon Shepherd -: Submitted September 2011 -: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - - -NEURON { - THREADSAFE - SUFFIX kdmc - USEION k READ ek WRITE ik +TITLE K-D channel with activation for motor cortex +: K-D current with activation, for motor cortex pyramidal neurons, per Miller et al. (2008) +: Based on K-A current K-A current for Mitral Cells from Wang et al (1996), by M.Migliore Jan. 2002 +: 2011-02-25 Ben Suter, first version, using MM's kamt.mod as a starting template +: 2011-09-18 Ben Suter, set default parameter values to those found from MRF optimization for BS0284 model +: +: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +: Copyright 2011, Benjamin Suter +: Used in model of corticospinal neuron BS0284 and published as: +: "Intrinsic electrophysiology of mouse corticospinal neurons: a characteristic set of features embodied in a realistic computational model" +: by Benjamin Suter, Michele Migliore, and Gordon Shepherd +: Submitted September 2011 +: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + +NEURON { + THREADSAFE + SUFFIX kdmc + USEION k READ ek WRITE ik RANGE gbar, minf, mtau, hinf, htau, ik - GLOBAL taumin -} - -PARAMETER { - gbar = 0.002 (mho/cm2) - - celsius - ek (mV) : must be explicitly def. in hoc - v (mV) - - : activation - vhalfmt = -25 : original -20 : rough estimate from Miller et al (2008) Fig. 3D I-V curve - km = 14 : manual fit to match this I-V curve - - : inactivation - : NOTE: These values are still quite arbitrary (but get about the correct htau at -40 and -30 mV - vhalfh = -5 : original -55 - zetah = 0.02 : original 0.05 - gmh = 0.2 : original 0.7 - a0h = 0.00058 : original 0.00055 - taumin = 0.1 (ms) : minimal value of time constant - - vhalfht = -100 : original -88 : measured by Storm (1988) - kh = 8 : manual fit to match inactivation curve in Storm (1988) and Johnston+Wu textbook - - q10 = 3 -} - - -UNITS { - (mA) = (milliamp) - (mV) = (millivolt) - (pS) = (picosiemens) - (um) = (micron) -} - -ASSIGNED { - ik (mA/cm2) - minf mtau (ms) - hinf htau (ms) -} - - -STATE { m h } - -BREAKPOINT { - SOLVE states METHOD cnexp - ik = gbar*m*h*(v - ek) -} - -INITIAL { - trates(v) - m = minf - h = hinf -} - -DERIVATIVE states { - trates(v) - m' = (minf-m)/mtau - h' = (hinf-h)/htau -} - -PROCEDURE trates(v) { - LOCAL qt - qt = q10^((celsius-34)/10) - - minf = 1/(1 + exp(-(v-vhalfmt)/km)) - mtau = 1 - - hinf = 1/(1 + exp((v-vhalfht)/kh)) - htau = exp(zetah*gmh*(v-vhalfh)) / (qt*a0h*(1 + exp(zetah*(v-vhalfh)))) - if(htau < taumin) { htau = taumin } : min value of time constant -} + GLOBAL taumin +} + +PARAMETER { + gbar = 0.002 (mho/cm2) + + celsius + ek (mV) : must be explicitly def. in hoc + v (mV) + + : activation + vhalfmt = -25 : original -20 : rough estimate from Miller et al (2008) Fig. 3D I-V curve + km = 14 : manual fit to match this I-V curve + + : inactivation + : NOTE: These values are still quite arbitrary (but get about the correct htau at -40 and -30 mV + vhalfh = -5 : original -55 + zetah = 0.02 : original 0.05 + gmh = 0.2 : original 0.7 + a0h = 0.00058 : original 0.00055 + taumin = 0.1 (ms) : minimal value of time constant + + vhalfht = -100 : original -88 : measured by Storm (1988) + kh = 8 : manual fit to match inactivation curve in Storm (1988) and Johnston+Wu textbook + + q10 = 3 +} + + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) + (pS) = (picosiemens) + (um) = (micron) +} + +ASSIGNED { + ik (mA/cm2) + minf mtau (ms) + hinf htau (ms) +} + + +STATE { m h } + +BREAKPOINT { + SOLVE states METHOD cnexp + ik = gbar*m*h*(v - ek) +} + +INITIAL { + trates(v) + m = minf + h = hinf +} + +DERIVATIVE states { + trates(v) + m' = (minf-m)/mtau + h' = (hinf-h)/htau +} + +PROCEDURE trates(v) { + LOCAL qt + qt = q10^((celsius-34)/10) + + minf = 1/(1 + exp(-(v-vhalfmt)/km)) + mtau = 1 + + hinf = 1/(1 + exp((v-vhalfht)/kh)) + htau = exp(zetah*gmh*(v-vhalfh)) / (qt*a0h*(1 + exp(zetah*(v-vhalfh)))) + if(htau < taumin) { htau = taumin } : min value of time constant +} diff --git a/netpyne_ui/tests/mod/kdr_BS.mod b/netpyne_ui/examples/mod/kdr_BS.mod similarity index 100% rename from netpyne_ui/tests/mod/kdr_BS.mod rename to netpyne_ui/examples/mod/kdr_BS.mod diff --git a/netpyne_ui/tests/mod/kdrin.mod b/netpyne_ui/examples/mod/kdrin.mod similarity index 100% rename from netpyne_ui/tests/mod/kdrin.mod rename to netpyne_ui/examples/mod/kdrin.mod diff --git a/netpyne_ui/tests/mod/misc.h b/netpyne_ui/examples/mod/misc.h similarity index 100% rename from netpyne_ui/tests/mod/misc.h rename to netpyne_ui/examples/mod/misc.h diff --git a/netpyne_ui/tests/mod/nafx.mod b/netpyne_ui/examples/mod/nafx.mod similarity index 100% rename from netpyne_ui/tests/mod/nafx.mod rename to netpyne_ui/examples/mod/nafx.mod diff --git a/netpyne_ui/tests/mod/nap_sidi.mod b/netpyne_ui/examples/mod/nap_sidi.mod similarity index 100% rename from netpyne_ui/tests/mod/nap_sidi.mod rename to netpyne_ui/examples/mod/nap_sidi.mod diff --git a/netpyne_ui/tests/mod/nax_BS.mod b/netpyne_ui/examples/mod/nax_BS.mod similarity index 100% rename from netpyne_ui/tests/mod/nax_BS.mod rename to netpyne_ui/examples/mod/nax_BS.mod diff --git a/netpyne_ui/tests/mod/savedist.mod b/netpyne_ui/examples/mod/savedist.mod similarity index 97% rename from netpyne_ui/tests/mod/savedist.mod rename to netpyne_ui/examples/mod/savedist.mod index d4168565..493e8dae 100644 --- a/netpyne_ui/tests/mod/savedist.mod +++ b/netpyne_ui/examples/mod/savedist.mod @@ -1,14 +1,14 @@ -TITLE Mech to store distance from origin as workaround for multisplit non-uniform densities -: 2011-09-18 Ben Suter, initial version per email from Michael Hines -: 2016-11-31 Ernie Forzano, changed suffix dist to savedist because import3d() and this mod file -: were referencing dist and causing compile error. -: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -NEURON { - SUFFIX savedist - RANGE x -} - -PARAMETER { - x = 0 (micron) -} +TITLE Mech to store distance from origin as workaround for multisplit non-uniform densities +: 2011-09-18 Ben Suter, initial version per email from Michael Hines +: 2016-11-31 Ernie Forzano, changed suffix dist to savedist because import3d() and this mod file +: were referencing dist and causing compile error. +: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +NEURON { + SUFFIX savedist + RANGE x +} + +PARAMETER { + x = 0 (micron) +} diff --git a/netpyne_ui/tests/mod/vecstim.mod b/netpyne_ui/examples/mod/vecstim.mod similarity index 100% rename from netpyne_ui/tests/mod/vecstim.mod rename to netpyne_ui/examples/mod/vecstim.mod diff --git a/netpyne_ui/tests/tut1.py b/netpyne_ui/examples/tut1.py similarity index 100% rename from netpyne_ui/tests/tut1.py rename to netpyne_ui/examples/tut1.py diff --git a/netpyne_ui/tests/tut2.py b/netpyne_ui/examples/tut2.py similarity index 100% rename from netpyne_ui/tests/tut2.py rename to netpyne_ui/examples/tut2.py diff --git a/netpyne_ui/tests/tut3.py b/netpyne_ui/examples/tut3.py similarity index 100% rename from netpyne_ui/tests/tut3.py rename to netpyne_ui/examples/tut3.py diff --git a/netpyne_ui/tests/tut4.py b/netpyne_ui/examples/tut4.py similarity index 100% rename from netpyne_ui/tests/tut4.py rename to netpyne_ui/examples/tut4.py diff --git a/netpyne_ui/tests/tut4/__init__.py b/netpyne_ui/examples/tut4/__init__.py similarity index 100% rename from netpyne_ui/tests/tut4/__init__.py rename to netpyne_ui/examples/tut4/__init__.py diff --git a/netpyne_ui/tests/tut4/izhi2007b.mod b/netpyne_ui/examples/tut4/izhi2007b.mod similarity index 100% rename from netpyne_ui/tests/tut4/izhi2007b.mod rename to netpyne_ui/examples/tut4/izhi2007b.mod diff --git a/netpyne_ui/tests/tut4/tut4.py b/netpyne_ui/examples/tut4/tut4.py similarity index 100% rename from netpyne_ui/tests/tut4/tut4.py rename to netpyne_ui/examples/tut4/tut4.py diff --git a/netpyne_ui/tests/tut5.py b/netpyne_ui/examples/tut5.py similarity index 100% rename from netpyne_ui/tests/tut5.py rename to netpyne_ui/examples/tut5.py diff --git a/netpyne_ui/tests/tut6.py b/netpyne_ui/examples/tut6.py similarity index 100% rename from netpyne_ui/tests/tut6.py rename to netpyne_ui/examples/tut6.py diff --git a/netpyne_ui/tests/tut7.py b/netpyne_ui/examples/tut7.py similarity index 100% rename from netpyne_ui/tests/tut7.py rename to netpyne_ui/examples/tut7.py diff --git a/netpyne_ui/geppetto b/netpyne_ui/geppetto deleted file mode 160000 index 0077835f..00000000 --- a/netpyne_ui/geppetto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0077835fad41f34c1cb6955af627379a7df33ba4 diff --git a/netpyne_ui/netpyne_geppetto.py b/netpyne_ui/netpyne_geppetto.py index 0a1b27b1..1c072ad4 100644 --- a/netpyne_ui/netpyne_geppetto.py +++ b/netpyne_ui/netpyne_geppetto.py @@ -30,8 +30,9 @@ from jupyter_geppetto import jupyter_geppetto, synchronization, utils import imp from contextlib import redirect_stdout, redirect_stderr +from netpyne_ui.constants import NETPYNE_WORKDIR_PATH - +os.chdir(NETPYNE_WORKDIR_PATH) class NetPyNEGeppetto(): def __init__(self): @@ -49,9 +50,22 @@ def getData(self): "netParams": self.netParams.todict(), "simConfig": self.simConfig.todict(), "isDocker": os.path.isfile('/.dockerenv'), - "currentFolder": os.getcwd() + "currentFolder": os.getcwd(), + "tuts": self.find_tutorials() } + def find_tutorials(self): + from os import listdir + from os.path import isfile, join + onlyfiles = [f for f in listdir(NETPYNE_WORKDIR_PATH) if isfile(join(NETPYNE_WORKDIR_PATH, f))] + + def _filter(_file): + return '.py' in _file and 'tut' in _file and 'gui' in _file + + return list(filter(_filter, onlyfiles)) + + + def instantiateNetPyNEModelInGeppetto(self, args): try: with redirect_stdout(sys.__stdout__): @@ -59,7 +73,7 @@ def instantiateNetPyNEModelInGeppetto(self, args): netpyne_model = self.instantiateNetPyNEModel() self.geppetto_model = self.model_interpreter.getGeppettoModel(netpyne_model) - return json.loads(GeppettoModelSerializer().serialize(self.geppetto_model)) + return json.loads(GeppettoModelSerializer.serialize(self.geppetto_model)) except: return utils.getJSONError("Error while instantiating the NetPyNE model", sys.exc_info()) @@ -98,7 +112,7 @@ def simulateNetPyNEModelInGeppetto(self, args): logging.debug('Running single thread simulation') netpyne_model = self.simulateNetPyNEModel() - return json.loads(GeppettoModelSerializer().serialize(self.geppetto_model)) + return json.loads(GeppettoModelSerializer.serialize(self.geppetto_model)) except: return utils.getJSONError("Error while simulating the NetPyNE model", sys.exc_info()) @@ -111,6 +125,7 @@ def compileModMechFiles(self, compileMod, modFolder): os.chdir(modFolder) subprocess.call(["nrnivmodl"]) + os.chdir('..') # Load mechanism if mod path is passed if modFolder: @@ -185,7 +200,7 @@ def remove(dictionary): sim.loadSimData(args['jsonModelFolder']) self.geppetto_model = self.model_interpreter.getGeppettoModel(sim) - return json.loads(GeppettoModelSerializer().serialize(self.geppetto_model)) + return json.loads(GeppettoModelSerializer.serialize(self.geppetto_model)) else: return utils.getJSONReply() except: @@ -263,6 +278,11 @@ def exportModel(self, args): sim.cfg.saveJson = True sim.saveData(include) sim.cfg.saveJson = False + + with open(f"{sim.cfg.filename}.json") as json_file: + data = json.load(json_file) + return data + return utils.getJSONReply() except: return utils.getJSONError("Error while exporting the NetPyNE model", sys.exc_info()) @@ -281,24 +301,31 @@ def importNeuroML(self, modelParams): sim.initialize() sim.importNeuroML2(modelParams['neuroMLFolder'], simConfig=specs.SimConfig(), simulate=False, analyze=False) self.geppetto_model = self.model_interpreter.getGeppettoModel(sim) - return json.loads(GeppettoModelSerializer().serialize(self.geppetto_model)) + return json.loads(GeppettoModelSerializer.serialize(self.geppetto_model)) except: return utils.getJSONError("Error while exporting the NetPyNE model", sys.exc_info()) def deleteModel(self, modelParams): + try: with redirect_stdout(sys.__stdout__): self.netParams = specs.NetParams() self.simConfig = specs.SimConfig() - self.netParams.todict() - self.netParams.todict() - if self.doIhaveInstOrSimData()['haveInstance']: sim.clearAll() + sim.initialize(specs.NetParams(), specs.SimConfig()) self.geppetto_model = None - return utils.getJSONReply() - except: return utils.getJSONError("Error while exporting the NetPyNE model", sys.exc_info()) + + try: + # This function fails is some keys don't exists + # sim.clearAll() + self.clearSim() + + except: + pass + + return utils.getJSONReply() def instantiateNetPyNEModel(self): with redirect_stdout(sys.__stdout__): @@ -352,24 +379,25 @@ def rename(self, path, oldValue,newValue): return 1 - def getPlotSettings(self, plot): - if self.simConfig.analysis and plot in self.simConfig.analysis: - return self.simConfig.analysis[plot] + def getPlotSettings(self, plot_name): + if self.simConfig.analysis and plot_name in self.simConfig.analysis: + return self.simConfig.analysis[plot_name] return {} def getDirList(self, dir=None, onlyDirs = False, filterFiles=False): # Get Current dir if dir == None or dir == '': - dir = os.getcwd() + dir = os.path.join(os.getcwd(), NETPYNE_WORKDIR_PATH) dir_list = [] + file_list = [] for f in sorted(os.listdir(str(dir)), key=str.lower): ff=os.path.join(dir,f) if os.path.isdir(ff): - dir_list.insert(0, {'title': f, 'path': ff, 'load': False, 'children': [{'title': 'Loading...'}]}) + dir_list.append({'title': f, 'path': ff, 'load': False, 'children': [{'title': 'Loading...'}]}) elif not onlyDirs: if not filterFiles or os.path.isfile(ff) and ff.endswith(filterFiles): - dir_list.append({'title': f, 'path': ff}) - return dir_list + file_list.append({'title': f, 'path': ff}) + return dir_list + file_list def getPlot(self, plotName, LFPflavour): try: @@ -377,26 +405,50 @@ def getPlot(self, plotName, LFPflavour): args = self.getPlotSettings(plotName) if LFPflavour: args['plots'] = [LFPflavour] - figData = getattr(analysis, plotName)(showFig=False, **args) - if isinstance(figData, tuple): - fig = figData[0] - if fig==-1: - return fig - elif isinstance(fig, list): - return [ui.getSVG(fig[0])] - elif isinstance(fig, dict): - svgs = [] - for key, value in fig.items(): - svgs.append(ui.getSVG(value)) - return svgs - else: - return [ui.getSVG(fig)] + args['showFig'] = False + + if plotName.startswith('iplot'): + # This arg brings dark theme. But some plots are broken by it + args['theme'] = 'gui' + html = getattr(analysis, plotName)(**args) + if not html or html == -1: + return "" + + # some plots return "fig", some return "(fig, data)" + if plotName == 'iplotRaster': + html = html[0] + elif plotName == 'iplotRxDConcentration': + html = html[0] + elif plotName == 'iplot2Dnet': + html = html[0] + return html + else: - return figData + + figData = getattr(analysis, plotName)(**args) + + if isinstance(figData, tuple): + fig = figData[0] + if fig==-1: + return fig + elif isinstance(fig, list): + return [ui.getSVG(fig[0])] + elif isinstance(fig, dict): + svgs = [] + for key, value in fig.items(): + svgs.append(ui.getSVG(value)) + return svgs + else: + return [ui.getSVG(fig)] + else: + return figData + + + except Exception as e: # TODO: Extract these two lines as a function and call it in every catch clause - err = "There was an exception in %s():"%(function.__name__) + err = "There was an exception in %s():"%(e.plotName) logging.exception(("%s \n %s \n%s"%(err,e,sys.exc_info()))) def getAvailablePops(self): @@ -413,11 +465,8 @@ def getAvailableCellModels(self): def getAvailableCellTypes(self): cellTypes = set([]) - for p in self.netParams.popParams: - if 'cellType' in self.netParams.popParams[p]: - ct = self.netParams.popParams[p]['cellType'] - if ct not in cellTypes: - cellTypes.add(ct) + for p in self.netParams.cellParams: + cellTypes.add(p) return list(cellTypes) def getAvailableSections(self): @@ -444,7 +493,7 @@ def getMechParams(self, mechanism): return [value[:-(len(mechanism) + 1)] for value in params] def getAvailablePlots(self): - plots = ["plotRaster", "plotSpikeHist", "plotSpikeStats","plotRatePSD", "plotTraces", "plotLFP", "plotShape", "plot2Dnet", "plotConn", "granger"] + plots = ["iplotRaster", "iplotSpikeHist", "plotSpikeStats","iplotRatePSD", "iplotTraces", "iplotLFP", "plotShape", "plot2Dnet", "iplotConn", "granger"] return [plot for plot in plots if plot not in list(self.simConfig.analysis.keys())] @@ -482,10 +531,17 @@ def deleteParam(self, model, label): else: pass else: - getattr(self.netParams, model).pop(label) + # remove rule + rule = getattr(self.netParams, model).pop(label) + + # side effect on other rules if "popParams" in model: self.propagate_field_rename("pop", None, label) + self.propagate_field_rename("cellModel", None, rule['cellModel']) + self.propagate_field_rename("cellType", None, rule['cellType']) + elif "stimSourceParams" in model: + self.propagate_field_rename("source", None, label) elif "synMechParams" in model: self.propagate_field_rename("synMech", None, label) @@ -494,6 +550,8 @@ def deleteParam(self, model, label): return False def validateFunction(self, functionString): + if isinstance(functionString, (float, int)): + return True return validateFunction(functionString, self.netParams.__dict__) def exportHLS(self, args): @@ -541,7 +599,8 @@ def header(title, spacer='-'): script.write(header('end script', spacer='=')) - return utils.getJSONReply() + with open(fname) as f: + return f.read() except: return utils.getJSONError("Error while importing the NetPyNE model", sys.exc_info()) @@ -596,7 +655,7 @@ def unique(label=label, old=old): for p in self.netParams.popParams: if label in self.netParams.popParams[p]: classes.append(self.netParams.popParams[p][label]) - if classes.count(old)>1: + if classes.count(old) > 0: return False else: return True @@ -608,7 +667,7 @@ def unique(label=label, old=old): self.propagate_syn_mech_rename(new, old) return True else: - if unique(): + if unique(): for (model, cond) in [['cellParams','conds'], ['connParams', 'preConds'], ['connParams', 'postConds'], ['stimTargetParams', 'conds'], ['analysis', 'include'] ]: self.propagate(model, label, cond, new, old) return True @@ -648,6 +707,61 @@ def propagate_syn_mech_rename(self, new, old): self.netParams.stimTargetParams[label]['synMech'] = new + def clearSim(self): + # clean up + sim.pc.barrier() + sim.pc.gid_clear() # clear previous gid settings + + # clean cells and simData in all nodes + sim.clearObj([cell.__dict__ if hasattr(cell, '__dict__') else cell for cell in sim.net.cells]) + if 'stims' in list(sim.simData.keys()): + sim.clearObj([stim for stim in sim.simData['stims']]) + + for key in list(sim.simData.keys()): del sim.simData[key] + + if hasattr(sim, 'net'): + for c in sim.net.cells: del c + for p in sim.net.pops: del p + if hasattr(sim.net, 'params'): + del sim.net.params + + + # clean cells and simData gathered in master node + if sim.rank == 0: + if hasattr(sim.net, 'allCells'): + sim.clearObj([cell.__dict__ if hasattr(cell, '__dict__') else cell for cell in sim.net.allCells]) + if hasattr(sim, 'allSimData'): + if 'stims' in list(sim.allSimData.keys()): + sim.clearObj([stim for stim in sim.allSimData['stims']]) + for key in list(sim.allSimData.keys()): del sim.allSimData[key] + del sim.allSimData + + + import matplotlib + matplotlib.pyplot.clf() + matplotlib.pyplot.close('all') + + if hasattr(sim, 'net'): + if hasattr(sim.net, 'allCells'): + for c in sim.net.allCells: del c + del sim.net.allCells + if hasattr(sim.net, 'allPops'): + for p in sim.net.allPops: del p + + del sim.net + + import gc; gc.collect() + + def create_celltype_from_template(self, label="CellType", conds={}, cell_template_name="Blank"): + try: + with redirect_stdout(sys.__stdout__): + self.netParams.addCellParamsTemplate(label=label, template=cell_template_name) + return True + except: + return utils.getJSONError(f"Error while creating cellType from template {cell_template_name}", + sys.exc_info()) + + logging.info("Initialising NetPyNE UI") netpyne_geppetto = NetPyNEGeppetto() logging.info("NetPyNE UI initialised") \ No newline at end of file diff --git a/netpyne_ui/netpyne_model_interpreter.py b/netpyne_ui/netpyne_model_interpreter.py index fced8523..5d1e3990 100644 --- a/netpyne_ui/netpyne_model_interpreter.py +++ b/netpyne_ui/netpyne_model_interpreter.py @@ -6,9 +6,9 @@ import pygeppetto.model as pygeppetto from pygeppetto.model.model_factory import GeppettoModelFactory from pygeppetto.model.values import Point, ArrayElement, ArrayValue +from pygeppetto.services.model_interpreter import ModelInterpreter - -class NetPyNEModelInterpreter(): +class NetPyNEModelInterpreter(ModelInterpreter): def __init__(self): self.factory = GeppettoModelFactory() @@ -18,6 +18,7 @@ def getGeppettoModel(self, netpyne_model): # We create a GeppettoModel instance and we set a name a assign a lib geppetto_model = self.factory.createGeppettoModel('NetPyNEModel') + self.factory.geppetto_common_library = geppetto_model.libraries[0] netpyne_geppetto_library = pygeppetto.GeppettoLibrary( name='netpynelib') geppetto_model.libraries.append(netpyne_geppetto_library) @@ -44,6 +45,7 @@ def extractPopulations(self, netpyne_model, netpyne_geppetto_library, geppetto_m composite_id = cell['tags']['pop'] + "_cell" cellType = pygeppetto.CompositeType(id=str(composite_id), name=str(composite_id), abstract= False) + visualType = pygeppetto.CompositeVisualType(id='cellMorphology', name='cellMorphology') cellType.visualType = visualType defaultValue = ArrayValue(elements=[]) diff --git a/netpyne_ui/tests/M1detailed/init.py b/netpyne_ui/tests/M1detailed/init.py deleted file mode 100644 index d8a6dbba..00000000 --- a/netpyne_ui/tests/M1detailed/init.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -init.py - -Starting script to run NetPyNE-based M1 model. - -Usage: - python init.py # Run simulation, optionally plot a raster - -MPI usage: - mpiexec -n 4 nrniv -python -mpi init.py - -Contributors: salvadordura@gmail.com -""" - -import matplotlib; matplotlib.use('Agg') # to avoid graphics error in servers - -from netpyne import sim -from .cfg import cfg -from .netParams import netParams - -# sim.createSimulateAnalyze(netParams, cfg) \ No newline at end of file diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 00000000..a4fbc581 --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,3 @@ +pytest==4.6.2 +pytest-cov==2.7.1 +tox==3.12.1 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..23c9fb3e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,98 @@ +airspeed==0.5.4dev-20150515 +alembic==1.4.2 +async-generator==1.10 +attrs==19.3.0 +blinker==1.4 +bokeh==2.1.1 +brotlipy==0.7.0 +cachetools==0.8.0 +certifi==2020.4.5.2 +certipy==0.1.3 +cffi==1.14.0 +chardet==3.0.4 +cryptography==2.9.2 +cycler==0.10.0 +decorator==4.4.2 +defusedxml==0.6.0 +Deprecated==1.2.10 +entrypoints==0.3 +future==0.18.2 +idna==2.9 +ipython-genutils==0.2.0 +ipywidgets==7.5.1 +jedi==0.17.0 +Jinja2==2.11.2 +jsonschema==3.2.0 +jupyter==1.0.0 +jupyter-client==6.1.3 +jupyter-console==6.1.0 +jupyter-core==4.6.3 +jupyter_geppetto==1.1.1 +jupyter-telemetry==0.0.5 +jupyterhub==1.1.0 +jupyterlab==2.1.3 +jupyterthemes==0.20.0 +kiwisolver==1.2.0 +lesscpy==0.14.0 +libNeuroML==0.2.50 +lxml==4.5.1 +Mako==1.1.0 +MarkupSafe==1.1.1 +matplotlib==2.2.4 +matplotlib-scalebar==0.6.2 +mistune==0.8.4 +multimethod==1.3 +nbconvert==5.6.1 +nbformat==5.0.6 +netpyne==0.9.6 +neuromllite==0.1.9 +NEURON==7.8.0.127 +numpy==1.18.5 +oauthlib==3.0.1 +ordered-set==4.0.2 +pamela==1.0.0 +pandas==0.23.4 +pandocfilters==1.4.2 +parso==0.7.0 +pexpect==4.8.0 +pickleshare==0.7.5 +Pillow==7.2.0 +ply==3.11 +prompt-toolkit==3.0.5 +ptyprocess==0.6.0 +pycosat==0.6.3 +pycparser==2.20 +pycurl==7.43.0.5 +pyecore==0.11.7 +pygeppetto==0.8.1 +Pygments==2.6.1 +PyJWT==1.7.1 +PyLEMS==0.4.9.3 +pyNeuroML==0.3.15 +pyOpenSSL==19.1.0 +pyparsing==2.4.7 +pyrsistent==0.16.0 +PySocks==1.7.1 +python-dateutil==2.8.1 +python-editor==1.0.4 +python-json-logger==0.1.11 +pytz==2020.1 +PyYAML==5.3.1 +pyzmq==19.0.1 +qtconsole==4.7.5 +QtPy==1.9.0 +RestrictedPython==5.0 +ruamel-yaml==0.15.80 +ruamel.yaml.clib==0.2.0 +scipy==1.4.1 +Send2Trash==1.5.0 +terminado==0.8.3 +testpath==0.4.4 +tornado==6.0.4 +traitlets==4.3.3 +typing-extensions==3.7.4.2 +urllib3==1.25.9 +webencodings==0.5.1 +widgetsnbextension==3.5.1 +wrapt==1.12.1 +zipp==3.1.0 diff --git a/run.py b/run.py new file mode 100644 index 00000000..f1dcdb3f --- /dev/null +++ b/run.py @@ -0,0 +1,22 @@ +''' +Run this to debug +''' +import sys +import os +from notebook.notebookapp import main, NotebookApp +import netpyne_ui +from jupyter_geppetto import settings + +settings.debug = True + +if __name__ == '__main__': + sys.argv.append('--NotebookApp.default_url=/geppetto') + sys.argv.append("--NotebookApp.token=''") + sys.argv.append('--library=netpyne_ui') + sys.argv.append('--NotebookApp.disable_check_xsrf=True') + + app = NotebookApp.instance() + app.initialize(sys.argv) + app.file_to_run = '' + sys.exit(app.start()) + diff --git a/setup.py b/setup.py index 086059fd..0fee0d8b 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setuptools.setup( name="netpyne_ui", - version="0.5.2", + version="0.6.0", url="https://github.com/MetaCell/NetPyNE-UI", author="MetaCell", author_email="info@metacell.us", @@ -37,7 +37,8 @@ 'Programming Language :: Python :: 3.7' ], install_requires=[ - 'jupyter_geppetto==0.4.2', - 'netpyne==0.9.1.1' + 'jupyter-geppetto>=1.0.0', + 'NEURON>=7.8.0' + 'netpyne==0.9.6' ], ) diff --git a/netpyne_ui/tests/netpyne_model_interpreter_test.py b/tests/netpyne_model_interpreter_test.py similarity index 88% rename from netpyne_ui/tests/netpyne_model_interpreter_test.py rename to tests/netpyne_model_interpreter_test.py index a25d9ae9..a9c43171 100644 --- a/netpyne_ui/tests/netpyne_model_interpreter_test.py +++ b/tests/netpyne_model_interpreter_test.py @@ -12,8 +12,9 @@ class TestNetPyNEModelInterpreter(unittest.TestCase): @classmethod def setUpClass(cls): - path, filename = os.path.split(os.path.realpath(__file__)) - cls.path = path + HERE = os.path.dirname(os.path.realpath(__file__)) + ROOT = os.path.dirname(HERE) + cls.path = os.path.join(ROOT, 'netpyne_ui/examples') def getGeppettoModel(self, netParams, simConfig): sim.create(netParams, simConfig, True) @@ -62,21 +63,21 @@ def test_tut1(self): print("------------------------------------") print("Tutorial 1 Instantiation:") print("------------------------------------") - from netpyne_ui.tests.tut1 import netParams, simConfig + from netpyne_ui.examples.tut1 import netParams, simConfig self.getGeppettoModel(netParams, simConfig) def test_tut2(self): print("------------------------------------") print("Tutorial 2 Instantiation:") print("------------------------------------") - from netpyne_ui.tests.tut2 import netParams, simConfig + from netpyne_ui.examples.tut2 import netParams, simConfig self.getGeppettoModel(netParams, simConfig) def test_tut3(self): print("------------------------------------") print("Tutorial 3 Instantiation:") print("------------------------------------") - from netpyne_ui.tests.tut3 import netParams, simConfig + from netpyne_ui.examples.tut3 import netParams, simConfig self.getGeppettoModel(netParams, simConfig) def test_tut4(self): @@ -91,21 +92,21 @@ def test_tut4(self): os.chdir(owd) neuron.load_mechanisms(modelpath) - from netpyne_ui.tests.tut4.tut4 import netParams, simConfig + from netpyne_ui.examples.tut4.tut4 import netParams, simConfig self.getGeppettoModel(netParams, simConfig) def test_tut5(self): print("------------------------------------") print("Tutorial 5 Instantiation:") print("------------------------------------") - from netpyne_ui.tests.tut5 import netParams, simConfig + from netpyne_ui.examples.tut5 import netParams, simConfig self.getGeppettoModel(netParams, simConfig) def test_tut6(self): print("------------------------------------") print("Tutorial 6 Instantiation:") print("------------------------------------") - from netpyne_ui.tests.tut6 import netParams, simConfig + from netpyne_ui.examples.tut6 import netParams, simConfig self.getGeppettoModel(netParams, simConfig) def test_M1detailed(self): @@ -121,7 +122,7 @@ def test_M1detailed(self): neuron.load_mechanisms(modpath) os.chdir(modelpath) - from netpyne_ui.tests.M1detailed.init import netParams, cfg + from netpyne_ui.examples.M1detailed.init import netParams, cfg self.getGeppettoModel(netParams, cfg) os.chdir(owd) diff --git a/utilities/custom.css b/utilities/custom.css new file mode 100644 index 00000000..b5ae0f72 --- /dev/null +++ b/utilities/custom.css @@ -0,0 +1,3258 @@ +div#notebook { + font-family: sans-serif; + font-size: 13pt; + line-height: 170%; + color: #f8f8f0; + -webkit-font-smoothing: antialiased !important; + } + body, + div.body { + font-family: sans-serif; + font-size: 13pt; + color: #f8f8f0; + background-color: #1e1e1e; + background: #1e1e1e; + -webkit-font-smoothing: antialiased !important; + } + body.notebook_app { + padding: 0; + background-color: #1e1e1e; + background: #1e1e1e; + padding-right: 0px !important; + overflow-y: hidden; + } + a { + font-family: sans-serif; + color: #f8f8f0; + -webkit-font-smoothing: antialiased !important; + } + a:hover, + a:focus { + color: #f8f8f0; + -webkit-font-smoothing: antialiased !important; + } + div#maintoolbar { + position: absolute; + width: 90%; + margin-left: -10%; + padding-right: 8%; + float: left; + background: transparent !important; + } + #maintoolbar { + margin-bottom: -3px; + margin-top: 0px; + border: 0px; + min-height: 27px; + padding-top: 2px; + padding-bottom: 0px; + } + #maintoolbar .container { + width: 75%; + margin-right: auto; + margin-left: auto; + } + .list_header, + div#notebook_list_header.row.list_header { + font-size: 14pt; + color: #f8f8f0; + background-color: transparent; + height: 35px; + } + i.fa.fa-folder { + display: inline-block; + font: normal normal normal 14px "FontAwesome"; + font-family: "FontAwesome" !important; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + font-size: 18px; + -moz-osx-font-smoothing: grayscale; + } + #running .panel-group .panel .panel-heading { + font-size: 14pt; + color: #f8f8f0; + padding: 8px 8px; + background: #2f2f2f; + background-color: #2f2f2f; + } + #running .panel-group .panel .panel-heading a { + font-size: 14pt; + color: #f8f8f0; + } + #running .panel-group .panel .panel-heading a:focus, + #running .panel-group .panel .panel-heading a:hover { + font-size: 14pt; + color: #f8f8f0; + } + #running .panel-group .panel .panel-body .list_container .list_item { + background: #232323; + background-color: #232323; + padding: 2px; + border-bottom: 2px solid rgba(93,92,82,.25); + } + #running .panel-group .panel .panel-body .list_container .list_item:hover { + background: #232323; + background-color: #232323; + } + #running .panel-group .panel .panel-body { + padding: 2px; + } + button#refresh_running_list { + border: none !important; + } + button#refresh_cluster_list { + border: none !important; + } + div.running_list_info.toolbar_info { + font-size: 15px; + padding: 4px 0 4px 0; + margin-top: 5px; + margin-bottom: 8px; + height: 24px; + line-height: 24px; + text-shadow: none; + } + .list_placeholder { + font-weight: normal; + } + #tree-selector { + padding: 0px; + border-color: transparent; + } + #project_name > ul > li > a > i.fa.fa-home { + color: #a6e22e; + font-size: 17pt; + display: inline-block; + position: static; + padding: 0px 0px; + font-weight: normal; + text-align: center; + vertical-align: text-top; + } + .fa-folder:before { + color: #ae81ff; + } + .fa-arrow-up:before { + font-size: 14px; + } + .fa-arrow-down:before { + font-size: 14px; + } + span#last-modified.btn.btn-xs.btn-default.sort-action:hover .fa, + span#sort-name.btn.btn-xs.btn-default.sort-action:hover .fa { + color: #a6e22e; + } + .folder_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f07b"; + color: #ae81ff; + } + .notebook_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f02d"; + position: relative; + color: #a6e22e !important; + top: 0px; + } + .file_icon:before { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f15b"; + position: relative; + top: 0px; + color: #888888 !important; + } + #project_name a { + display: inline-flex; + padding-left: 7px; + margin-left: -2px; + text-align: -webkit-auto; + vertical-align: baseline; + font-size: 18px; + } + div#notebook_toolbar div.dynamic-instructions { + font-family: sans-serif; + font-size: 17px; + color: #75715e; + } + span#login_widget > .button, + #logout { + font-family: "Proxima Nova", sans-serif; + color: #f8f8f0; + background: transparent; + background-color: transparent; + border: 2px solid #2f2f2f; + font-weight: normal; + box-shadow: none; + text-shadow: none; + border-radius: 3px; + margin-right: 10px; + padding: 2px 7px; + } + span#login_widget > .button:hover, + #logout:hover { + color: #a6e22e; + background-color: transparent; + background: transparent; + border: 2px solid #a6e22e; + background-image: none; + box-shadow: none !important; + border-radius: 3px; + } + span#login_widget > .button:focus, + #logout:focus, + span#login_widget > .button.focus, + #logout.focus, + span#login_widget > .button:active, + #logout:active, + span#login_widget > .button.active, + #logout.active, + .open > .dropdown-togglespan#login_widget > .button, + .open > .dropdown-toggle#logout { + color: #f8f8f2; + background-color: #f8f8f0; + background: #f8f8f0; + border-color: #f8f8f0; + background-image: none; + box-shadow: none !important; + border-radius: 2px; + } + body > #header #header-container { + padding-bottom: 0px; + padding-top: 4px; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + } + body > #header { + background: #1e1e1e; + background-color: #1e1e1e; + position: relative; + z-index: 100; + } + .list_container { + font-size: 13pt; + color: #f8f8f0; + border: none; + text-shadow: none !important; + } + .list_container > div { + border-bottom: 1px solid rgba(93,92,82,.25); + font-size: 13pt; + } + .list_header > div, + .list_item > div { + padding-top: 6px; + padding-bottom: 2px; + padding-left: 0px; + } + .list_header > div .item_link, + .list_item > div .item_link { + margin-left: -1px; + vertical-align: middle; + line-height: 22px; + font-size: 13pt; + } + .item_icon { + color: #ae81ff; + font-size: 13pt; + vertical-align: middle; + } + .list_item input:not([type="checkbox"]) { + padding-right: 0px; + height: 1.75em; + width: 25%; + margin: 0px 0 0; + margin-top: 0px; + } + .list_header > div .item_link, + .list_item > div .item_link { + margin-left: -1px; + vertical-align: middle; + line-height: 1.5em; + font-size: 12pt; + display: inline-table; + position: static; + } + #button-select-all { + height: 34px; + min-width: 55px; + z-index: 0; + border: none !important; + padding-top: 0px; + padding-bottom: 0px; + margin-bottom: 0px; + margin-top: 0px; + left: -3px; + border-radius: 0px !important; + } + #button-select-all:focus, + #button-select-all:active:focus, + #button-select-all.active:focus, + #button-select-all.focus, + #button-select-all:active.focus, + #button-select-all.active.focus { + background-color: #2f2f2f !important; + background: #2f2f2f !important; + } + button#tree-selector-btn { + height: 34px; + font-size: 12.0pt; + border: none; + left: 0px; + border-radius: 0px !important; + } + input#select-all.pull-left.tree-selector { + margin-left: 7px; + margin-right: 2px; + margin-top: 2px; + top: 4px; + } + input[type="radio"], + input[type="checkbox"] { + margin-top: 1px; + line-height: normal; + } + .delete-button { + border: none !important; + } + i.fa.fa-trash { + font-size: 13.5pt; + } + .list_container a { + font-size: 16px; + color: #f8f8f0; + border: none; + text-shadow: none !important; + font-weight: normal; + font-style: normal; + } + div.list_container a:hover { + color: #f8f8f0; + } + .list_header > div input, + .list_item > div input { + margin-right: 7px; + margin-left: 12px; + vertical-align: baseline; + line-height: 22px; + position: relative; + top: -1px; + } + div.list_item:hover { + background-color: rgba(93,92,82,.1); + } + .breadcrumb > li { + font-size: 12.0pt; + color: #f8f8f0; + border: none; + text-shadow: none !important; + } + .breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0px; + color: #f8f8f0; + font-size: 18px; + } + #project_name > .breadcrumb { + padding: 0px; + margin-bottom: 0px; + background-color: transparent; + font-weight: normal; + margin-top: -2px; + } + ul#tabs a { + font-family: sans-serif; + font-size: 13.5pt; + font-weight: normal; + font-style: normal; + text-shadow: none !important; + } + .nav-tabs { + font-family: sans-serif; + font-size: 13.5pt; + font-weight: normal; + font-style: normal; + background-color: transparent; + border-color: transparent; + text-shadow: none !important; + border: 2px solid transparent; + } + .nav-tabs > li > a:active, + .nav-tabs > li > a:focus, + .nav-tabs > li > a:hover, + .nav-tabs > li.active > a, + .nav-tabs > li.active > a:focus, + .nav-tabs > li.active > a:hover, + .nav-tabs > li.active > a, + .nav-tabs > li.active > a:hover, + .nav-tabs > li.active > a:focus { + color: #a6e22e; + background-color: transparent; + border-color: transparent; + border-bottom: 2px solid transparent; + } + .nav > li.disabled > a, + .nav > li.disabled > a:hover { + color: #75715e; + } + .nav-tabs > li > a:before { + content: ""; + position: absolute; + width: 100%; + height: 2px; + bottom: -2px; + left: 0; + background-color: #a6e22e; + visibility: hidden; + -webkit-transform: perspective(0)scaleX(0); + transform: perspective(0)scaleX(0); + -webkit-transition: ease 220ms; + transition: ease 220ms; + -webkit-font-smoothing: antialiased !important; + } + .nav-tabs > li > a:hover:before { + visibility: visible; + -webkit-transform: perspective(1)scaleX(1); + transform: perspective(1)scaleX(1); + } + .nav-tabs > li.active > a:before { + content: ""; + position: absolute; + width: 100%; + height: 2px; + bottom: -2px; + left: 0; + background-color: #a6e22e; + visibility: visible; + -webkit-transform: perspective(1)scaleX(1); + transform: perspective(1)scaleX(1); + -webkit-font-smoothing: subpixel-antialiased !important; + } + div#notebook { + font-family: sans-serif; + font-size: 13pt; + padding-top: 4px; + } + .notebook_app { + background-color: #1e1e1e; + } + #notebook-container { + padding: 13px 2px; + background-color: #1e1e1e; + min-height: 0px; + box-shadow: none; + width: 980px; + margin-right: auto; + margin-left: auto; + } + div#ipython-main-app.container { + width: 980px; + margin-right: auto; + margin-left: auto; + margin-right: auto; + margin-left: auto; + } + .container { + width: 980px; + margin-right: auto; + margin-left: auto; + } + div#menubar-container { + width: 100%; + width: 980px; + } + div#header-container { + width: 980px; + } + .notebook_app #header, + .edit_app #header { + box-shadow: none !important; + background-color: #1e1e1e; + border-bottom: 2px solid rgba(93,92,82,.25); + } + #header, + .edit_app #header { + font-family: sans-serif; + font-size: 13pt; + box-shadow: none; + background-color: #1e1e1e; + } + #header .header-bar, + .edit_app #header .header-bar { + background: #1e1e1e; + background-color: #1e1e1e; + } + body > #header .header-bar { + width: 100%; + background: #1e1e1e; + } + span.checkpoint_status, + span.autosave_status { + font-size: small; + display: none; + } + #menubar, + div#menubar { + background-color: #1e1e1e; + padding-top: 0px !important; + } + #menubar .navbar, + .navbar-default { + background-color: #1e1e1e; + margin-bottom: 0px; + margin-top: 0px; + } + .navbar { + border: none; + } + div.navbar-text, + .navbar-text, + .navbar-text.indicator_area, + p.navbar-text.indicator_area { + margin-top: 8px !important; + margin-bottom: 0px; + color: #a6e22e; + } + .navbar-default { + font-family: sans-serif; + font-size: 13pt; + background-color: #1e1e1e; + border-color: rgba(93,92,82,.25); + line-height: 1.5em; + padding-bottom: 0px; + } + .navbar-default .navbar-nav > li > a { + font-family: sans-serif; + font-size: 13pt; + color: #f8f8f0; + display: block; + line-height: 1.5em; + padding-top: 14px; + padding-bottom: 11px; + } + .navbar-default .navbar-nav > li > a:hover, + .navbar-default .navbar-nav > li > a:focus { + color: #f8f8f0 !important; + background-color: rgba(93,92,82,.25) !important; + border-color: rgba(93,92,82,.25) !important; + line-height: 1.5em; + transition: 80ms ease; + } + .navbar-default .navbar-nav > .open > a, + .navbar-default .navbar-nav > .open > a:hover, + .navbar-default .navbar-nav > .open > a:focus { + color: #f8f8f2; + background-color: #383838; + border-color: #383838; + line-height: 1.5em; + } + .navbar-nav > li > .dropdown-menu { + margin-top: 0px; + } + .navbar-nav { + margin: 0; + } + div.notification_widget.info, + .notification_widget.info, + .notification_widget:active:hover, + .notification_widget.active:hover, + .open > .dropdown-toggle.notification_widget:hover, + .notification_widget:active:focus, + .notification_widget.active:focus, + .open > .dropdown-toggle.notification_widget:focus, + .notification_widget:active.focus, + .notification_widget.active.focus, + .open > .dropdown-toggle.notification_widget.focus, + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn, + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:hover, + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:focus { + color: #f8f8f0 !important; + background-color: transparent !important; + border-color: transparent !important; + padding-bottom: 0px !important; + margin-bottom: 0px !important; + font-size: 9pt !important; + z-index: 0; + } + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn { + font-size: 9pt !important; + z-index: 0; + } + .notification_widget { + color: #ae81ff; + z-index: -500; + font-size: 9pt; + background: transparent; + background-color: transparent; + margin-right: 3px; + border: none; + } + .notification_widget, + div.notification_widget { + margin-right: 0px; + margin-left: 0px; + padding-right: 0px; + vertical-align: text-top !important; + margin-top: 6px !important; + background: transparent !important; + background-color: transparent !important; + font-size: 9pt !important; + border: none; + } + .navbar-btn.btn-xs:hover { + border: none !important; + background: transparent !important; + background-color: transparent !important; + color: #f8f8f0 !important; + } + div.notification_widget.info, + .notification_widget.info { + display: none !important; + } + .edit_mode .modal_indicator:before { + display: none; + } + .command_mode .modal_indicator:before { + display: none; + } + .item_icon { + color: #ae81ff; + } + .item_buttons .kernel-name { + font-size: 13pt; + color: #ae81ff; + } + .running_notebook_icon:before { + color: #a6e22e !important; + font: normal normal normal 15px/1 FontAwesome; + font-size: 15px; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\f10c"; + vertical-align: middle; + position: static; + display: inherit; + } + .item_buttons .running-indicator { + padding-top: 4px; + color: #a6e22e; + font-family: sans-serif; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + } + #notification_trusted { + font-family: sans-serif; + border: none; + background: transparent; + background-color: transparent; + margin-bottom: 0px !important; + vertical-align: bottom !important; + color: #75715e !important; + cursor: default !important; + } + #notification_area, + div.notification_area { + float: right !important; + position: static; + cursor: pointer; + padding-top: 6px; + padding-right: 4px; + } + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn { + font-size: 9pt !important; + z-index: 0; + margin-top: -5px !important; + } + #modal_indicator { + float: right !important; + color: #4c8be2; + background: #1e1e1e; + background-color: #1e1e1e; + margin-top: 8px !important; + margin-left: 0px; + } + #kernel_indicator { + float: right !important; + color: #a6e22e; + background: #1e1e1e; + background-color: #1e1e1e; + border-left: 2px solid #a6e22e; + padding-top: 0px; + padding-bottom: 4px; + margin-top: 10px !important; + margin-left: -2px; + padding-left: 5px !important; + } + #kernel_indicator .kernel_indicator_name { + font-size: 17px; + color: #a6e22e; + background: #1e1e1e; + background-color: #1e1e1e; + padding-left: 5px; + padding-right: 5px; + margin-top: 4px; + vertical-align: text-top; + padding-bottom: 0px; + } + .kernel_idle_icon:before { + display: inline-block; + font: normal normal normal 22px/1 FontAwesome; + font-size: 22px; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + cursor: pointer; + margin-left: 0px !important; + opacity: 0.7; + vertical-align: bottom; + margin-top: 1px; + content: "\f1db"; + } + .kernel_busy_icon:before { + display: inline-block; + font: normal normal normal 22px/1 FontAwesome; + font-size: 22px; + -webkit-animation: pulsate 2s infinite ease-out; + animation: pulsate 2s infinite ease-out; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + cursor: pointer; + margin-left: 0px !important; + vertical-align: bottom; + margin-top: 1px; + content: "\f111"; + } + @-webkit-keyframes pulsate { + 0% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } + 8% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } + 50% { + -webkit-transform: scale(0.75,0.75); + opacity: 0.3; + } + 92% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } + 100% { + -webkit-transform: scale(1.0,1.0); + opacity: 0.8; + } + } + div.notification_widget.info, + .notification_widget.info, + .notification_widget:active:hover, + .notification_widget.active:hover, + .open > .dropdown-toggle.notification_widget:hover, + .notification_widget:active:focus, + .notification_widget.active:focus, + .open > .dropdown-toggle.notification_widget:focus, + .notification_widget:active.focus, + .notification_widget.active.focus, + .open > .dropdown-toggle.notification_widget.focus, + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn, + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:hover, + div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:focus { + color: #f8f8f0; + background-color: #1e1e1e; + border-color: #1e1e1e; + } + #notification_area, + div.notification_area { + float: right !important; + position: static; + } + .notification_widget, + div.notification_widget { + margin-right: 0px; + margin-left: 0px; + padding-right: 0px; + vertical-align: text-top !important; + margin-top: 6px !important; + z-index: 1000; + } + #kernel_logo_widget, + #kernel_logo_widget .current_kernel_logo { + display: none; + } + div#ipython_notebook { + display: none; + } + i.fa.fa-icon { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: auto; + } + .fa { + display: inline-block; + font: normal normal normal 10pt/1 "FontAwesome", sans-serif; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + .dropdown-menu { + font-family: sans-serif; + font-size: 13pt; + box-shadow: none; + padding: 0px; + text-align: left; + border: none; + background-color: #383838; + background: #383838; + line-height: 1; + } + .dropdown-menu:hover { + font-family: sans-serif; + font-size: 13pt; + box-shadow: none; + padding: 0px; + text-align: left; + border: none; + background-color: #383838; + box-shadow: none; + line-height: 1; + } + .dropdown-menu > li > a { + font-family: sans-serif; + font-size: 12.0pt; + display: block; + padding: 10px 20px 9px 10px; + color: #f8f8f0; + background-color: #383838; + background: #383838; + } + .dropdown-menu > li > a:hover, + .dropdown-menu > li > a:focus { + color: #f8f8f0; + background-color: rgba(93,92,82,.25); + background: rgba(93,92,82,.25); + border-color: rgba(93,92,82,.25); + transition: 200ms ease; + } + .dropdown-menu .divider { + height: 1px; + margin: 0px 0px; + overflow: hidden; + background-color: rgba(93,92,82,.5); + } + .dropdown-submenu > .dropdown-menu { + display: none; + top: 2px !important; + left: 100%; + margin-top: -2px; + margin-left: 0px; + padding-top: 0px; + transition: 200ms ease; + } + .dropdown-menu > .disabled > a, + .dropdown-menu > .disabled > a:hover, + .dropdown-menu > .disabled > a:focus { + font-family: sans-serif; + font-size: 12.0pt; + font-weight: normal; + color: #75715e; + padding: none; + display: block; + clear: both; + white-space: nowrap; + } + .dropdown-submenu > a:after { + color: #f8f8f0; + margin-right: -16px; + margin-top: 0px; + display: inline-block; + } + .dropdown-submenu:hover > a:after, + .dropdown-submenu:active > a:after, + .dropdown-submenu:focus > a:after, + .dropdown-submenu:visited > a:after { + color: #a6e22e; + margin-right: -16px; + display: inline-block !important; + } + div.kse-dropdown > .dropdown-menu, + .kse-dropdown > .dropdown-menu { + min-width: 0; + top: 94%; + } + .btn, + .btn-default { + font-family: sans-serif; + color: #f8f8f0; + background: #2f2f2f; + background-color: #2f2f2f; + border: 2px solid #2f2f2f; + font-weight: normal; + box-shadow: none; + text-shadow: none; + border-radius: 3px; + font-size: initial; + } + .btn:hover, + .btn:active:hover, + .btn.active:hover, + .btn-default:hover, + .open > .dropdown-toggle.btn-default:hover, + .open > .dropdown-toggle.btn:hover { + color: #a6e22e; + border: 2px solid #2a2a2a; + background-color: #2a2a2a; + background: #2a2a2a; + background-image: none; + box-shadow: none !important; + border-radius: 3px; + } + .btn:active, + .btn.active, + .btn:active:focus, + .btn.active:focus, + .btn:active.focus, + .btn.active.focus, + .btn-default:focus, + .btn-default.focus, + .btn-default:active, + .btn-default.active, + .btn-default:active:hover, + .btn-default.active:hover, + .btn-default:active:focus, + .btn-default.active:focus, + .btn-default:active.focus, + .btn-default.active.focus, + .open > .dropdown-toggle.btn:focus, + .open > .dropdown-toggle.btn.focus, + .open > .dropdown-toggle.btn-default:hover, + .open > .dropdown-toggle.btn-default:focus, + .open > .dropdown-toggle.btn-default.hover, + .open > .dropdown-toggle.btn-default.focus { + color: #a6e22e; + border: 2px solid #2a2a2a; + background-color: #2a2a2a !important; + background: #2a2a2a !important; + background-image: none; + box-shadow: none !important; + border-radius: 3px; + } + .btn-default:active:hover, + .btn-default.active:hover, + .btn-default:active:focus, + .btn-default.active:focus, + .btn-default:active.focus, + .btn-default.active.focus { + color: #a6e22e !important; + background-color: #2f2f2f; + border-color: #546745 !important; + transition: 2000ms ease; + } + .btn:focus, + .btn.focus, + .btn:active:focus, + .btn.active:focus, + .btn:active, + .btn.active, + .btn:active.focus, + .btn.active.focus { + color: #a6e22e !important; + outline: none !important; + outline-width: 0px !important; + background: #546745 !important; + background-color: #546745 !important; + border-color: #546745 !important; + transition: 200ms ease !important; + } + .item_buttons > .btn, + .item_buttons > .btn-group, + .item_buttons > .input-group { + font-size: 13pt; + background: transparent; + background-color: transparent; + border: 0px solid #2f2f2f; + border-bottom: 2px solid transparent; + margin-left: 5px; + padding-top: 4px !important; + } + .item_buttons > .btn:hover, + .item_buttons > .btn-group:hover, + .item_buttons > .input-group:hover, + .item_buttons > .btn.active, + .item_buttons > .btn-group.active, + .item_buttons > .input-group.active, + .item_buttons > .btn.focus { + margin-left: 5px; + background: #2a2a2a; + padding-top: 4px !important; + background-color: transparent; + border: 0px solid transparent; + border-bottom: 2px solid #a6e22e; + border-radius: 0px; + transition: none; + } + .item_buttons { + line-height: 1.5em !important; + } + .item_buttons .btn { + min-width: 11ex; + } + .btn-group > .btn:first-child { + margin-left: 3px; + } + .btn-group > .btn-mini, + .btn-sm, + .btn-group-sm > .btn, + .btn-xs, + .btn-group-xs > .btn, + .alternate_upload .btn-upload, + .btn-group, + .btn-group-vertical { + font-size: inherit; + font-weight: normal; + height: inherit; + line-height: inherit; + } + .btn-xs, + .btn-group-xs > .btn { + font-size: initial !important; + background-image: none; + font-weight: normal; + text-shadow: none; + display: inline-table; + padding: 2px 5px; + line-height: 1.45; + } + .btn-group > .btn:first-child { + margin-left: 3px; + } + div#new-buttons > button, + #new-buttons > button, + div#refresh_notebook_list, + #refresh_notebook_list { + background: transparent; + background-color: transparent; + border: none; + } + div#new-buttons > button:hover, + #new-buttons > button:hover, + div#refresh_notebook_list, + #refresh_notebook_list, + div.alternate_upload .btn-upload, + .alternate_upload .btn-upload, + div.dynamic-buttons > button, + .dynamic-buttons > button, + .dynamic-buttons > button:focus, + .dynamic-buttons > button:active:focus, + .dynamic-buttons > button.active:focus, + .dynamic-buttons > button.focus, + .dynamic-buttons > button:active.focus, + .dynamic-buttons > button.active.focus, + #new-buttons > button:focus, + #new-buttons > button:active:focus, + #new-buttons > button.active:focus, + #new-buttons > button.focus, + #new-buttons > button:active.focus, + #new-buttons > button.active.focus, + .alternate_upload .btn-upload:focus, + .alternate_upload .btn-upload:active:focus, + .alternate_upload .btn-upload.active:focus, + .alternate_upload .btn-upload.focus, + .alternate_upload .btn-upload:active.focus, + .alternate_upload .btn-upload.active.focus { + background: transparent !important; + background-color: transparent !important; + border: none !important; + } + .alternate_upload input.fileinput { + text-align: center; + vertical-align: bottom; + margin-left: -.5ex; + display: inline-table; + border: solid 0px #2f2f2f; + margin-bottom: -1ex; + } + .alternate_upload .btn-upload { + display: inline-table; + background: transparent; + border: none; + } + .btn-group .btn + .btn, + .btn-group .btn + .btn-group, + .btn-group .btn-group + .btn, + .btn-group .btn-group + .btn-group { + margin-left: -2px; + } + .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + z-index: 2; + } + .dropdown-header { + font-family: sans-serif !important; + font-size: 13pt !important; + color: #a6e22e !important; + border-bottom: none !important; + padding: 0px !important; + margin: 6px 6px 0px !important; + } + span#last-modified.btn.btn-xs.btn-default.sort-action, + span#sort-name.btn.btn-xs.btn-default.sort-action, + span#file-size.btn.btn-xs.btn-default.sort-action { + font-family: sans-serif; + font-size: 16px; + background-color: transparent; + background: transparent; + border: none; + color: #f8f8f0; + padding-bottom: 0px; + margin-bottom: 0px; + vertical-align: sub; + } + span#last-modified.btn.btn-xs.btn-default.sort-action { + margin-left: 19px; + } + button.close { + border: 0px none; + font-family: sans-serif; + font-size: 20pt; + font-weight: normal; + } + .dynamic-buttons { + padding-top: 0px; + display: inline-block; + } + .close { + color: #f92672; + opacity: .5; + text-shadow: none; + font-weight: normal; + } + .close:hover { + color: #f92672; + opacity: 1; + font-weight: normal; + } + div.nbext-enable-btns .btn[disabled], + div.nbext-enable-btns .btn[disabled]:hover, + .btn-default.disabled, + .btn-default[disabled], + .btn-default.disabled:hover, + .btn-default[disabled]:hover, + fieldset[disabled] .btn-default:hover, + .btn-default.disabled:focus, + .btn-default[disabled]:focus, + fieldset[disabled] .btn-default:focus, + .btn-default.disabled.focus, + .btn-default[disabled].focus, + fieldset[disabled] .btn-default.focus { + color: #888888; + background: #2c2c2c; + background-color: #2c2c2c; + border-color: #2c2c2c; + transition: 200ms ease; + } + .input-group-addon { + padding: 2px 5px; + font-size: 13pt; + font-weight: normal; + height: auto; + color: #f8f8f0; + text-align: center; + background-color: transparent; + border: 2px solid transparent !important; + text-transform: capitalize; + } + a.btn.btn-default.input-group-addon:hover { + background: transparent !important; + background-color: transparent !important; + } + .btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + height: 100%; + } + .btn-group > .btn + .dropdown-toggle:hover { + background: #2a2a2a !important; + } + .input-group-btn { + position: relative; + font-size: inherit; + white-space: nowrap; + background: #2f2f2f; + background-color: #2f2f2f; + border: none; + } + .input-group-btn:hover { + background: #2a2a2a; + background-color: #2a2a2a; + border: none; + } + .input-group-btn:first-child > .btn, + .input-group-btn:first-child > .btn-group { + background: #2f2f2f; + background-color: #2f2f2f; + border: none; + margin-left: 2px; + margin-right: -1px; + font-size: inherit; + } + .input-group-btn:first-child > .btn:hover, + .input-group-btn:first-child > .btn-group:hover { + background: #2a2a2a; + background-color: #2a2a2a; + border: none; + font-size: inherit; + transition: 200ms ease; + } + div.modal .btn-group > .btn:first-child { + background: #2f2f2f; + background-color: #2f2f2f; + border: 1px solid #2c2c2c; + margin-top: 0px !important; + margin-left: 0px; + margin-bottom: 2px; + } + div.modal .btn-group > .btn:first-child:hover { + background: #2a2a2a; + background-color: #2a2a2a; + border: 1px solid #2a2a2a; + transition: 200ms ease; + } + div.modal > button, + div.modal-footer > button { + background: #2f2f2f; + background-color: #2f2f2f; + border-color: #2f2f2f; + } + div.modal > button:hover, + div.modal-footer > button:hover { + background: #2a2a2a; + background-color: #2a2a2a; + border-color: #2a2a2a; + transition: 200ms ease; + } + .modal-content { + font-family: sans-serif; + font-size: 12.0pt; + position: relative; + background: #2f2f2f; + background-color: #2f2f2f; + border: none; + border-radius: 1px; + background-clip: padding-box; + outline: none; + } + .modal-header { + font-family: sans-serif; + font-size: 13pt; + color: #f8f8f0; + background: #2f2f2f; + background-color: #2f2f2f; + border-color: rgba(93,92,82,.25); + padding: 12px; + min-height: 16.4286px; + } + .modal-content h4 { + font-family: sans-serif; + font-size: 16pt; + color: #f8f8f0; + padding: 5px; + } + .modal-body { + background-color: #232323; + position: relative; + padding: 15px; + } + .modal-footer { + padding: 8px; + text-align: right; + background-color: #232323; + border-top: none; + } + .alert-info { + background-color: #2f2f2f; + border-color: rgba(93,92,82,.25); + color: #f8f8f0; + } + .modal-header .close { + margin-top: -5px; + font-size: 25pt; + } + .modal-backdrop, + .modal-backdrop.in { + opacity: 0.85; + background-color: notebook-bg; + } + div.panel, + div.panel-default, + .panel, + .panel-default { + font-family: sans-serif; + font-size: 13pt; + background-color: #232323; + color: #f8f8f0; + margin-bottom: 14px; + border: 0; + box-shadow: none; + } + div.panel > .panel-heading, + div.panel-default > .panel-heading { + font-size: 14pt; + color: #f8f8f0; + background: #2f2f2f; + background-color: #2f2f2f; + border: 0; + } + .modal .modal-dialog { + min-width: 950px; + margin: 50px auto; + } + div.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 0px; + padding-right: 5px; + } + div.form-control, + .form-control { + font-family: sans-serif; + font-size: initial; + color: #f8f8f0; + background-color: #282828; + border: 1px solid #282828 !important; + margin-left: 2px; + box-shadow: none; + transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; + } + .form-control-static { + min-height: inherit; + height: inherit; + } + .form-group.list-group-item { + color: #f8f8f0; + background-color: #232323; + border-color: rgba(93,92,82,.25); + margin-bottom: 0px; + } + .form-group .input-group { + float: left; + } + input, + button, + select, + textarea { + background-color: #282828; + font-weight: normal; + border: 1px solid rgba(93,92,82,.25); + } + select.form-control.select-xs { + height: 33px; + font-size: 13pt; + } + .toolbar select, + .toolbar label { + width: auto; + vertical-align: middle; + margin-right: 0px; + margin-bottom: 0px; + display: inline; + font-size: 92%; + margin-left: 10px; + padding: 0px; + background: #2f2f2f !important; + background-color: #2f2f2f !important; + border: 2px solid #2f2f2f !important; + } + .form-control:focus { + border-color: #a6e22e; + outline: 2px solid #49483e; + -webkit-box-shadow: none; + } + ::-webkit-input-placeholder { + color: #75715e; + } + ::-moz-placeholder { + color: #75715e; + } + :-ms-input-placeholder { + color: #75715e; + } + :-moz-placeholder { + color: #75715e; + } + [dir="ltr"] #find-and-replace .input-group-btn + .form-control { + border: 2px solid rgba(93,92,82,.25) !important; + } + [dir="ltr"] #find-and-replace .input-group-btn + .form-control:focus { + border-color: #a6e22e; + outline: 2px solid #49483e; + -webkit-box-shadow: none; + box-shadow: none; + } + div.output.output_scroll { + box-shadow: none; + } + ::-webkit-scrollbar { + width: 11px; + max-height: 9px; + background-color: #2d2d2d; + border-radius: 3px; + border: none; + } + ::-webkit-scrollbar-track { + background: #2d2d2d; + border: none; + width: 11px; + max-height: 9px; + } + ::-webkit-scrollbar-thumb { + border-radius: 2px; + border: none; + background: #49483e; + background-clip: content-box; + width: 11px; + } + HTML, + body, + div, + dl, + dt, + dd, + ul, + ol, + li, + h1, + h2, + h3, + h4, + h5, + h6, + pre, + code, + form, + fieldset, + legend, + input, + button, + textarea, + p, + blockquote, + th, + td, + span, + a { + text-rendering: geometricPrecision; + -webkit-font-smoothing: subpixel-antialiased; + font-weight: 400; + } + div.input_area { + background-color: #6f6e6e; + background: #6f6e6e; + padding-right: 1.2em; + border: 0px; + border-radius: 5px; + margin: 2px; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + } + div.cell { + padding: 0px; + background: #434343; + background-color: #434343; + border: medium solid #434343; + border-radius: 4px; + top: 0; + } + div.cell.selected { + border: medium solid #1e1e1e; + padding: 0px; + border-radius: 5px; + } + .edit_mode div.cell.selected { + padding: 0px; + background: #434343; + background-color: #434343; + border: medium solid #434343; + border-radius: 5px; + } + div.cell.edit_mode { + padding: 0px; + background: #282828; + background-color: #282828; + } + div.CodeMirror-sizer { + margin-left: 0px; + margin-bottom: -21px; + border-right-width: 16px; + min-height: 37px; + padding-right: 0px; + padding-bottom: 0px; + margin-top: 0px; + } + div.cell.selected:before, + .edit_mode div.cell.selected:before, + div.cell.selected:before, + div.cell.selected.jupyter-soft-selected:before { + background: #282828 !important; + border: none; + border-radius: 3px; + position: absolute; + display: block; + top: 0px; + left: 0px; + width: 0px; + height: 100%; + } + div.cell.text_cell.selected::before, + .edit_mode div.cell.text_cell.selected:before, + div.cell.text_cell.selected:before, + div.cell.text_cell.selected.jupyter-soft-selected:before { + background: #282828 !important; + background-color: #282828 !important; + border-color: #57564b !important; + } + div.cell.code_cell .input { + border-left: 5px solid #434343 !important; + border-radius: 3px; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + } + div.cell.code_cell.selected .input { + border-left: 3px solid #EB517A !important; + border-radius: 3px; + padding-left: 2px; + } + .edit_mode div.cell.code_cell.selected .input { + border-left: 5px solid #33322b !important; + border-radius: 3px; + } + .edit_mode div.cell.selected:before { + height: 100%; + border-left: 5px solid #33322b !important; + border-radius: 3px; + } + div.cell.jupyter-soft-selected, + div.cell.selected.jupyter-soft-selected { + border-left-color: #33322b !important; + border-left-width: 0px !important; + padding-left: 7px !important; + border-right-color: #33322b !important; + border-right-width: 0px !important; + background: #33322b !important; + border-radius: 6px !important; + } + div.cell.selected.jupyter-soft-selected .input { + border-left: 5px solid #282828 !important; + } + div.cell.selected.jupyter-soft-selected { + border-left-color: #57564b; + border-color: #1e1e1e; + padding-left: 7px; + border-radius: 6px; + } + div.cell.code_cell.selected .input { + border-left: none; + border-radius: 3px; + } + div.cell.selected.jupyter-soft-selected .prompt, + div.cell.text_cell.selected.jupyter-soft-selected .prompt { + top: 0; + border-left: #282828 !important; + border-radius: 2px; + } + div.cell.text_cell.selected.jupyter-soft-selected .input_prompt { + border-left: none !important; + } + div.cell.text_cell.jupyter-soft-selected, + div.cell.text_cell.selected.jupyter-soft-selected { + border-left-color: #33322b !important; + border-left-width: 0px !important; + padding-left: 26px !important; + border-right-color: #33322b !important; + border-right-width: 0px !important; + background: #33322b !important; + border-radius: 5px !important; + } + div.cell.jupyter-soft-selected .input, + div.cell.selected.jupyter-soft-selected .input { + border-left-color: #33322b !important; + } + div.prompt, + .prompt { + font-family: monospace, monospace; + font-size: 9pt !important; + font-weight: normal; + color: #75715e; + line-height: 170%; + padding: 0px; + padding-top: 4px; + padding-left: 0px; + padding-right: 1px; + text-align: right !important; + min-width: 11.5ex !important; + width: 11.5ex !important; + } + div.prompt.input_prompt { + font-size: 10pt !important; + background-color: #434343; + border-top: 0px; + border-top-right-radius: 0px; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + padding-right: 8px; + margin-right: 3px; + min-width: 11.5ex; + width: 11.5ex !important; + padding-top: 10px; + height: 100%; + color: #EB517A; + } + div.cell.code_cell .input_prompt { + border-right: 0px solid #eb517a; + margin-right: 5px; + } + div.cell.selected .prompt { + top: 0; + } + .edit_mode div.cell.selected .prompt { + top: 0; + } + .edit_mode div.cell.selected .prompt { + top: 0; + } + .run_this_cell { + visibility: hidden; + color: transparent; + padding-top: 0px; + padding-bottom: 0px; + padding-left: 3px; + padding-right: 12px; + width: 1.5ex; + width: 0ex; + background: transparent; + background-color: transparent; + } + div.code_cell:hover div.input .run_this_cell { + visibility: visible; + } + div.cell.code_cell.rendered.selected .run_this_cell:hover { + background-color: #1e1e1e; + background: #1e1e1e; + color: #57564b !important; + } + div.cell.code_cell.rendered.unselected .run_this_cell:hover { + background-color: #1e1e1e; + background: #1e1e1e; + color: #57564b !important; + } + i.fa-step-forward.fa { + display: inline-block; + font: normal normal normal 9px "FontAwesome"; + } + .fa-step-forward:before { + content: "\f04b"; + } + div.cell.selected.jupyter-soft-selected .run_this_cell, + div.cell.selected.jupyter-soft-selected .run_this_cell:hover, + div.cell.unselected.jupyter-soft-selected .run_this_cell:hover, + div.cell.code_cell.rendered.selected.jupyter-soft-selected .run_this_cell:hover, + div.cell.code_cell.rendered.unselected.jupyter-soft-selected .run_this_cell:hover { + background-color: #33322b !important; + background: #33322b !important; + color: #33322b !important; + } + div.output_wrapper { + background-color: #232323; + border: 0px; + left: 0px; + margin-bottom: 0em; + margin-top: 0em; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + } + div.output_subarea.output_text.output_stream.output_stdout, + div.output_subarea.output_text { + font-family: monospace, monospace; + font-size: 8.5pt !important; + line-height: 150% !important; + background-color: #232323; + color: #cccccc; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + margin-left: 11.5px; + } + div.output_area pre { + font-family: monospace, monospace; + font-size: 9.5pt !important; + line-height: 151% !important; + color: #cccccc; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + } + div.output_area { + display: -webkit-box; + } + div.output_html { + font-family: monospace, monospace; + font-size: 8.5pt; + color: #cccccc; + background-color: #232323; + background: #232323; + } + div.output_subarea { + overflow-x: auto; + padding: 1.2em !important; + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + flex: 1; + } + div.btn.btn-default.output_collapsed { + background: #222222; + background-color: #222222; + border-color: #222222; + } + div.btn.btn-default.output_collapsed:hover { + background: #1d1d1d; + background-color: #1d1d1d; + border-color: #1d1d1d; + } + div.prompt.output_prompt { + font-family: monospace, monospace; + font-weight: bold !important; + background-color: #232323; + color: transparent; + border-bottom-left-radius: 4px; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + border-bottom-right-radius: 0px; + min-width: 11.5ex !important; + width: 11.5ex !important; + border-right: 2px solid transparent; + } + div.out_prompt_overlay.prompt { + font-family: monospace, monospace; + font-weight: bold !important; + background-color: #232323; + border-bottom-left-radius: 2px; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + border-bottom-right-radius: 0px; + min-width: 11.5ex !important; + width: 11.5ex !important; + border-right: 2px solid transparent; + color: transparent; + } + div.out_prompt_overlay.prompt:hover { + background-color: #49483e; + box-shadow: none !important; + border: none; + border-bottom-left-radius: 2px; + -webkit-border-: 2px; + -moz-border-radius: 2px; + border-top-right-radius: 0px; + border-top-left-radius: 0px; + min-width: 11.5ex !important; + width: 11.5ex !important; + border-right: 2px solid #49483e !important; + } + div.cell.code_cell .output_prompt { + border-right: 2px solid transparent; + color: transparent; + } + div.cell.selected .output_prompt, + div.cell.selected .out_prompt_overlay.prompt { + border-left: 5px solid #33322b; + border-right: 2px solid #232323; + border-radius: 0px !important; + } + .edit_mode div.cell.selected .output_prompt, + .edit_mode div.cell.selected .out_prompt_overlay.prompt { + border-left: 5px solid #33322b; + border-right: 2px solid #232323; + border-radius: 0px !important; + } + div.text_cell, + div.text_cell_render pre, + div.text_cell_render { + font-family: sans-serif; + font-size: 13pt; + line-height: 130% !important; + color: #f8f8f0; + background: #282828; + background-color: #282828; + border-radius: 0px; + } + div .text_cell_render { + padding: 0.4em 0.4em 0.4em 0.4em; + } + div.cell.text_cell .CodeMirror-lines { + padding-top: .7em !important; + padding-bottom: .4em !important; + padding-left: .5em !important; + padding-right: .5em !important; + margin-top: .4em; + margin-bottom: .3em; + } + div.cell.text_cell.unrendered div.input_area, + div.cell.text_cell.rendered div.input_area { + background-color: #282828; + background: #282828; + border: 0px; + border-radius: 2px; + } + div.cell.text_cell .CodeMirror, + div.cell.text_cell .CodeMirror pre { + line-height: 170% !important; + } + div.cell.text_cell.rendered.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #282828; + background-color: #282828; + border-radius: 0px; + } + div.cell.text_cell.unrendered.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #282828; + background-color: #282828; + border-radius: 0px; + } + div.cell.text_cell.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #282828; + background-color: #282828; + border-radius: 0px; + } + .edit_mode div.cell.text_cell.selected { + font-family: sans-serif; + line-height: 170% !important; + background: #282828; + background-color: #282828; + border-radius: 0px; + } + div.text_cell.unrendered, + div.text_cell.unrendered.selected, + div.edit_mode div.text_cell.unrendered { + font-family: sans-serif; + line-height: 170% !important; + background: #282828; + background-color: #282828; + border-radius: 0px; + } + div.cell.text_cell .prompt { + border-right: 0; + min-width: 11.5ex !important; + width: 11.5ex !important; + } + div.cell.text_cell.rendered .prompt { + font-family: monospace, monospace; + font-size: 9.5pt !important; + font-weight: normal; + color: #75715e !important; + text-align: right !important; + min-width: 14.5ex !important; + width: 14.5ex !important; + background-color: #282828; + border-right: 2px solid #49483e; + border-left: 4px solid #282828; + } + div.cell.text_cell.unrendered .prompt { + font-family: monospace, monospace; + font-size: 9.5pt !important; + font-weight: normal; + color: #75715e !important; + text-align: right !important; + min-width: 14.5ex !important; + width: 14.5ex !important; + border-right: 2px solid #49483e; + border-left: 4px solid #282828; + background-color: #282828; + } + div.cell.text_cell.rendered .prompt { + border-right: 2px solid #49483e; + } + div.cell.text_cell.rendered.selected .prompt { + top: 0; + border-left: 4px solid #57564b; + border-right: 2px solid #49483e; + } + div.text_cell.unrendered.selected .prompt, + div.text_cell.rendered.selected .prompt { + top: 0; + background: #282828; + border-left: 4px solid #33322b; + border-right: 2px solid #49483e; + } + div.rendered_html code { + font-family: monospace, monospace; + font-size: 11pt; + padding-top: 3px; + padding-left: 2px; + color: #f8f8f0; + background: #282828; + background-color: #282828; + } + pre, + code, + kbd, + samp { + white-space: pre-wrap; + } + .well code, + code { + font-family: monospace, monospace; + font-size: 11pt !important; + line-height: 170% !important; + color: #f8f8f0; + background: #282828; + background-color: #282828; + border-color: #282828; + } + kbd { + padding: 1px; + font-size: 11pt; + font-weight: 800; + color: #f8f8f0; + background-color: transparent !important; + border: 0; + box-shadow: none; + } + pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12.0pt; + line-height: 1.42857143; + color: #f8f8f0; + background-color: #282828; + border: 1px solid #282828; + border-radius: 2px; + } + div.rendered_html { + color: #f8f8f0; + } + .rendered_html * + ul { + margin-top: .4em; + margin-bottom: .3em; + } + .rendered_html * + p { + margin-top: .5em; + margin-bottom: .5em; + } + div.rendered_html pre { + font-family: monospace, monospace; + font-size: 11pt !important; + line-height: 170% !important; + color: #f8f8f0 !important; + background: #282828; + background-color: #282828; + max-width: 80%; + border-radius: 0px; + border-left: 3px solid #282828; + max-width: 80%; + border-radius: 0px; + padding-left: 5px; + margin-left: 6px; + } + div.text_cell_render pre, + div.text_cell_render code { + font-family: monospace, monospace; + font-size: 11pt !important; + line-height: 170% !important; + color: #f8f8f0; + background: #1e1e1e; + background-color: #1e1e1e; + max-width: 80%; + border-radius: 0px; + border-left: none; + } + div.text_cell_render pre { + border-left: 3px solid #49483e !important; + max-width: 80%; + border-radius: 0px; + padding-left: 5px; + margin-left: 6px; + } + div.text_cell_render h1, + div.rendered_html h1, + div.text_cell_render h2, + div.rendered_html h2, + div.text_cell_render h3, + div.rendered_html h3, + div.text_cell_render h4, + div.rendered_html h4, + div.text_cell_render h5, + div.rendered_html h5 { + font-family: sans-serif; + margin: 0.4em .2em .3em .2em !important; + } + .rendered_html h1:first-child, + .rendered_html h2:first-child, + .rendered_html h3:first-child, + .rendered_html h4:first-child, + .rendered_html h5:first-child, + .rendered_html h6:first-child { + margin-top: 0.2em !important; + margin-bottom: 0.2em !important; + } + .rendered_html h1, + .text_cell_render h1 { + color: #a6e22e !important; + font-size: 200%; + text-align: left; + font-style: normal; + font-weight: normal; + } + .rendered_html h2, + .text_cell_render h2 { + color: #a6e22e !important; + font-size: 170%; + font-style: normal; + font-weight: normal; + } + .rendered_html h3, + .text_cell_render h3 { + color: #a6e22e !important; + font-size: 140%; + font-style: normal; + font-weight: normal; + } + .rendered_html h4, + .text_cell_render h4 { + color: #a6e22e !important; + font-size: 110%; + font-style: normal; + font-weight: normal; + } + .rendered_html h5, + .text_cell_render h5 { + color: #a6e22e !important; + font-size: 100%; + font-style: normal; + font-weight: normal; + } + hr { + margin-top: 8px; + margin-bottom: 10px; + border: 0; + border-top: 1px solid #a6e22e; + } + .rendered_html hr { + color: #a6e22e; + background-color: #a6e22e; + margin-right: 2em; + } + #complete > select > option:hover { + background: rgba(93,92,82,.25); + background-color: rgba(93,92,82,.25); + } + div#_vivaldi-spatnav-focus-indicator._vivaldi-spatnav-focus-indicator { + position: absolute; + z-index: 9999999999; + top: 0px; + left: 0px; + box-shadow: none; + pointer-events: none; + border-radius: 2px; + } + .rendered_html tr, + .rendered_html th, + .rendered_html td { + text-align: left; + vertical-align: middle; + padding: 0.42em 0.47em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; + } + .rendered_html td { + font-family: sans-serif !important; + font-size: 9.3pt; + } + .rendered_html table { + font-family: sans-serif !important; + margin-left: 8px; + margin-right: auto; + border: none; + border-collapse: collapse; + border-spacing: 0; + color: #cccccc; + table-layout: fixed; + } + .rendered_html thead { + font-family: sans-serif !important; + font-size: 10.3pt !important; + background: #1e1e1e; + color: #cccccc; + border-bottom: 1px solid #1e1e1e; + vertical-align: bottom; + } + .rendered_html tbody tr:nth-child(odd) { + background: #282828; + } + .rendered_html tbody tr { + background: #202020; + } + .rendered_html tbody tr:hover:nth-child(odd) { + background: #252525; + } + .rendered_html tbody tr:hover { + background: #1e1e1e; + } + .rendered_html * + table { + margin-top: .05em; + } + div.widget-area { + background-color: #232323; + background: #232323; + color: #cccccc; + } + div.widget-area a { + font-family: sans-serif; + font-size: 12.0pt; + font-weight: normal; + font-style: normal; + color: #f8f8f0; + text-shadow: none !important; + } + div.widget-area a:hover, + div.widget-area a:focus { + font-family: sans-serif; + font-size: 12.0pt; + font-weight: normal; + font-style: normal; + color: #f8f8f0; + background: rgba(93,92,82,.25); + background-color: rgba(93,92,82,.25); + border-color: transparent; + background-image: none; + text-shadow: none !important; + } + div.widget_item.btn-group > button.btn.btn-default.widget-combo-btn, + div.widget_item.btn-group > button.btn.btn-default.widget-combo-btn:hover { + background: #2c2c2c; + background-color: #2c2c2c; + border: 2px solid #2c2c2c !important; + font-size: inherit; + z-index: 0; + } + div.jupyter-widgets.widget-hprogress.widget-hbox { + display: inline-table !important; + width: 38% !important; + margin-left: 10px; + } + div.jupyter-widgets.widget-hprogress.widget-hbox .widget-label, + div.widget-hbox .widget-label, + .widget-hbox .widget-label, + .widget-inline-hbox .widget-label, + div.widget-label { + text-align: -webkit-auto !important; + margin-left: 15px !important; + max-width: 240px !important; + min-width: 100px !important; + vertical-align: text-top !important; + color: #cccccc !important; + font-size: 14px !important; + } + .widget-hprogress .progress { + flex-grow: 1; + height: 20px; + margin-top: auto; + margin-left: 12px; + margin-bottom: auto; + width: 300px; + } + .progress { + overflow: hidden; + height: 22px; + margin-bottom: 10px; + padding-left: 10px; + background-color: #49483e !important; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; + z-index: 10; + } + .progress-bar-danger { + background-color: #e74c3c !important; + } + .progress-bar-info { + background-color: #3498db !important; + } + .progress-bar-warning { + background-color: #ff914d !important; + } + .progress-bar-success { + background-color: #83a83b !important; + } + .widget-select select { + margin-left: 12px; + } + .rendered_html :link { + font-family: sans-serif; + font-size: 100%; + color: #a6e22e; + text-decoration: underline; + } + .rendered_html :visited, + .rendered_html :visited:active, + .rendered_html :visited:focus { + color: #acdf45; + } + .rendered_html :visited:hover, + .rendered_html :link:hover { + font-family: sans-serif; + font-size: 100%; + color: #97dc0b; + } + div.cell.text_cell a.anchor-link:link { + font-size: inherit; + text-decoration: none; + padding: 0px 20px; + visibility: none; + color: rgba(0,0,0,.32); + } + div.cell.text_cell a.anchor-link:link:hover { + font-size: inherit; + color: #a6e22e; + } + .navbar-text { + margin-top: 4px; + margin-bottom: 0px; + } + #clusters > a { + color: #a6e22e; + text-decoration: underline; + cursor: auto; + } + #clusters > a:hover { + color: #ae81ff; + text-decoration: underline; + cursor: auto; + } + #nbextensions-configurator-container > div.row.container-fluid.nbext-selector > h3 { + font-size: 17px; + margin-top: 5px; + margin-bottom: 8px; + height: 24px; + padding: 4px 0 4px 0; + } + div#nbextensions-configurator-container.container, + #nbextensions-configurator-container.container { + width: 100%; + margin-right: auto; + margin-left: auto; + } + div.nbext-selector > nav > .nav > li > a { + font-family: sans-serif; + font-size: 10.5pt; + padding: 2px 5px; + } + div.nbext-selector > nav > .nav > li > a:hover { + background: transparent; + } + div.nbext-selector > nav > .nav > li:hover { + background-color: rgba(93,92,82,.25) !important; + background: rgba(93,92,82,.25) !important; + } + div.nbext-selector > nav > .nav > li.active:hover { + background: transparent !important; + background-color: transparent !important; + } + .nav-pills > li.active > a, + .nav-pills > li.active > a:active, + .nav-pills > li.active > a:hover, + .nav-pills > li.active > a:focus { + color: #f8f8f2; + background-color: rgba(93,92,82,.25) !important; + background: rgba(93,92,82,.25) !important; + -webkit-backface-visibility: hidden; + -webkit-font-smoothing: subpixel-antialiased !important; + } + div.nbext-readme > .nbext-readme-contents > .rendered_html { + font-family: sans-serif; + font-size: 11.5pt; + line-height: 145%; + padding: 1em 1em; + color: #f8f8f0; + background-color: #282828; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nbext-icon, + .nbext-desc, + .nbext-compat-div, + .nbext-enable-btns, + .nbext-params { + margin-bottom: 8px; + font-size: 11.5pt; + } + div.nbext-readme > .nbext-readme-contents { + padding: 0; + overflow-y: hidden; + } + div.nbext-readme > .nbext-readme-contents:not(:empty) { + margin-top: 0.5em; + margin-bottom: 2em; + border: none; + border-top-color: rgba(148,204,114,.2); + } + .nbext-showhide-incompat { + padding-bottom: 0.5em; + color: #888888; + font-size: 10.5pt; + } + .nbext-filter-menu.dropdown-menu > li > a:hover, + .nbext-filter-menu.dropdown-menu > li > a:focus, + .nbext-filter-menu.dropdown-menu > li > a.ui-state-focus { + color: #f8f8f0 !important; + background-color: rgba(93,92,82,.25) !important; + background: rgba(93,92,82,.25) !important; + border-color: rgba(93,92,82,.25) !important; + } + .nbext-filter-input-wrap > .nbext-filter-input-subwrap, + .nbext-filter-input-wrap > .nbext-filter-input-subwrap > input { + border: none; + outline: none; + background-color: transparent; + padding: 0; + vertical-align: middle; + margin-top: -2px; + } + span.rendered_html code { + background-color: transparent; + color: #f8f8f0; + } + #nbextensions-configurator-container > div.row.container-fluid.nbext-selector { + padding-left: 0px; + padding-right: 0px; + } + .nbext-filter-menu { + max-height: 55vh !important; + overflow-y: auto; + outline: none; + border: none; + } + .nbext-filter-menu:hover { + border: none; + } + .alert-warning { + background-color: #232323; + border-color: #232323; + color: #f8f8f0; + } + .notification_widget.danger { + color: #ffffff; + background-color: #e74c3c; + border-color: #e74c3c; + padding-right: 5px; + } + #nbextensions-configurator-container > div.nbext-buttons.tree-buttons.no-padding.pull-right > span > button { + border: none !important; + } + button#refresh_running_list { + border: none !important; + } + mark, + .mark { + background-color: #282828; + color: #f8f8f0; + padding: .15em; + } + a.text-warning, + a.text-warning:hover { + color: #75715e; + } + a.text-warning.bg-warning { + background-color: #1e1e1e; + } + span.bg-success.text-success { + background-color: transparent; + color: #a6e22e; + } + span.bg-danger.text-danger { + background-color: #1e1e1e; + color: #f92672; + } + .has-success .input-group-addon { + color: #a6e22e; + border-color: transparent; + background: inherit; + background-color: rgba(83,180,115,.10); + } + .has-success .form-control { + border-color: #a6e22e; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); + box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); + } + .has-error .input-group-addon { + color: #f92672; + border-color: transparent; + background: inherit; + background-color: rgba(192,57,67,.10); + } + .has-error .form-control { + border-color: #f92672; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); + box-shadow: inset 0 1px 1px rgba(0,0,0,0.025); + } + .kse-input-group-pretty > kbd { + font-family: monospace, monospace; + color: #f8f8f0; + font-weight: normal; + background: transparent; + } + .kse-input-group-pretty > kbd { + font-family: monospace, monospace; + color: #f8f8f0; + font-weight: normal; + background: transparent; + } + div.nbext-enable-btns .btn[disabled], + div.nbext-enable-btns .btn[disabled]:hover, + .btn-default.disabled, + .btn-default[disabled] { + background: #2c2c2c; + background-color: #2c2c2c; + color: #f3f3e6; + } + label#Keyword-Filter { + display: none; + } + .input-group .nbext-list-btn-add, + .input-group-btn:last-child > .btn-group > .btn { + background: #2f2f2f; + background-color: #2f2f2f; + border-color: #2f2f2f; + border: 2px solid #2f2f2f; + } + .input-group .nbext-list-btn-add:hover, + .input-group-btn:last-child > .btn-group > .btn:hover { + background: #2a2a2a; + background-color: #2a2a2a; + border-color: #2a2a2a; + border: 2px solid #2a2a2a; + } + #notebook-container > div.cell.code_cell.rendered.selected > div.widget-area > div.widget-subarea > div > div.widget_item.btn-group > button.btn.btn-default.dropdown-toggle.widget-combo-carrot-btn { + background: #2f2f2f; + background-color: #2f2f2f; + border-color: #2f2f2f; + } + #notebook-container > div.cell.code_cell.rendered.selected > div.widget-area > div.widget-subarea > div > div.widget_item.btn-group > button.btn.btn-default.dropdown-toggle.widget-combo-carrot-btn:hover { + background: #2a2a2a; + background-color: #2a2a2a; + border-color: #2a2a2a; + } + .ui-widget-content { + background: #2f2f2f; + background-color: #2f2f2f; + border: 2px solid #2f2f2f; + color: #f8f8f0; + } + div.collapsible_headings_toggle { + color: rgba(93,92,82,.5) !important; + } + div.collapsible_headings_toggle:hover { + color: #a6e22e !important; + } + .collapsible_headings_toggle .h1, + .collapsible_headings_toggle .h2, + .collapsible_headings_toggle .h3, + .collapsible_headings_toggle .h4, + .collapsible_headings_toggle .h5, + .collapsible_headings_toggle .h6 { + margin: 0.3em .4em 0em 0em !important; + line-height: 1.2 !important; + } + div.collapsible_headings_toggle .fa-caret-down:before, + div.collapsible_headings_toggle .fa-caret-right:before { + font-size: xx-large; + transition: transform 1000ms; + transform: none !important; + } + .collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h1:after, + .collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h2:after, + .collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h3:after, + .collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h4:after, + .collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h5:after, + .collapsible_headings_collapsed.collapsible_headings_ellipsis .rendered_html h6:after { + position: absolute; + right: 0; + bottom: 20% !important; + content: "[\002026]"; + color: rgba(93,92,82,.5) !important; + padding: 0.5em 0em 0em 0em !important; + } + .collapsible_headings_ellipsis .rendered_html h1, + .collapsible_headings_ellipsis .rendered_html h2, + .collapsible_headings_ellipsis .rendered_html h3, + .collapsible_headings_ellipsis .rendered_html h4, + .collapsible_headings_ellipsis .rendered_html h5, + .collapsible_headings_ellipsis .rendered_html h6, + .collapsible_headings_toggle .fa { + transition: transform 1000ms !important; + -webkit-transform: inherit !important; + -moz-transform: inherit !important; + -ms-transform: inherit !important; + -o-transform: inherit !important; + transform: inherit !important; + padding-right: 0px !important; + } + #toc-wrapper { + z-index: 90; + position: fixed !important; + display: flex; + flex-direction: column; + overflow: hidden; + padding: 10px; + border-style: solid; + border-width: thin; + border-right-width: medium !important; + background-color: #1e1e1e !important; + } + #toc-wrapper.ui-draggable.ui-resizable.sidebar-wrapper { + border-color: rgba(93,92,82,.25) !important; + } + #toc a, + #navigate_menu a, + .toc { + color: #f8f8f0 !important; + font-size: 11pt !important; + } + #toc li > span:hover { + background-color: rgba(93,92,82,.25) !important; + } + #toc a:hover, + #navigate_menu a:hover, + .toc { + color: #f8f8f2 !important; + font-size: 11pt !important; + } + #toc-wrapper .toc-item-num { + color: #a6e22e !important; + font-size: 11pt !important; + } + input.raw_input { + font-family: monospace, monospace; + font-size: 11pt !important; + color: #f8f8f0; + background-color: #282828; + border-color: #252525; + background: #252525; + width: auto; + vertical-align: baseline; + padding: 0em 0.25em; + margin: 0em 0.25em; + -webkit-box-shadow: none; + box-shadow: none; + } + audio, + video { + display: inline; + vertical-align: middle; + align-content: center; + margin-left: 20%; + } + .cmd-palette .modal-body { + padding: 0px; + margin: 0px; + } + .cmd-palette form { + background: #293547; + background-color: #293547; + } + .typeahead-field input:last-child, + .typeahead-hint { + background: #293547; + background-color: #293547; + z-index: 1; + } + .typeahead-field input { + font-family: sans-serif; + color: #f8f8f0; + border: none; + font-size: 28pt; + display: inline-block; + line-height: inherit; + padding: 3px 10px; + height: 70px; + } + .typeahead-select { + background-color: #293547; + } + body > div.modal.cmd-palette.typeahead-field { + display: table; + border-collapse: separate; + background-color: #2b3850; + } + .typeahead-container button { + font-family: sans-serif; + font-size: 28pt; + background-color: #2f2f2f; + border: none; + display: inline-block; + line-height: inherit; + padding: 3px 10px; + height: 70px; + } + .typeahead-search-icon { + min-width: 40px; + min-height: 55px; + display: block; + vertical-align: middle; + text-align: center; + } + .typeahead-container button:focus, + .typeahead-container button:hover { + color: #f8f8f0; + background-color: #2a2a2a; + border-color: #2a2a2a; + } + .typeahead-list > li.typeahead-group.active > a, + .typeahead-list > li.typeahead-group > a, + .typeahead-list > li.typeahead-group > a:focus, + .typeahead-list > li.typeahead-group > a:hover { + display: none; + } + .typeahead-dropdown > li > a, + .typeahead-list > li > a { + color: #f8f8f0; + text-decoration: none; + } + .typeahead-dropdown, + .typeahead-list { + font-family: sans-serif; + font-size: 13pt; + color: #f8f8f0; + background-color: #202937; + border: none; + background-clip: padding-box; + margin-top: 0px; + padding: 3px 2px 3px 0px; + line-height: 1.7; + } + .typeahead-dropdown > li.active > a, + .typeahead-dropdown > li > a:focus, + .typeahead-dropdown > li > a:hover, + .typeahead-list > li.active > a, + .typeahead-list > li > a:focus, + .typeahead-list > li > a:hover { + color: #f8f8f0; + background-color: #2b3850; + border-color: #2b3850; + } + .command-shortcut:before { + content: "(command)"; + padding-right: 3px; + color: #75715e; + } + .edit-shortcut:before { + content: "(edit)"; + padding-right: 3px; + color: #75715e; + } + ul.typeahead-list i { + margin-left: 1px; + width: 18px; + margin-right: 10px; + } + ul.typeahead-list { + max-height: 50vh; + overflow: auto; + } + .typeahead-list > li { + position: relative; + border: none; + } + div.input.typeahead-hint, + input.typeahead-hint, + body > div.modal.cmd-palette.in > div > div > div > form > div > div.typeahead-field > span.typeahead-query > input.typeahead-hint { + color: #75715e !important; + background-color: transparent; + padding: 3px 10px; + } + .typeahead-dropdown > li > a, + .typeahead-list > li > a { + display: block; + padding: 5px; + clear: both; + font-weight: 400; + line-height: 1.7; + border: 1px solid #202937; + border-bottom-color: rgba(93,92,82,.5); + } + body > div.modal.cmd-palette.in > div { + min-width: 750px; + margin: 150px auto; + } + .typeahead-container strong { + font-weight: bolder; + color: #a6e22e; + } + #find-and-replace #replace-preview .match, + #find-and-replace #replace-preview .insert { + color: #ffffff; + background-color: #57564b; + border-color: #57564b; + border-style: solid; + border-width: 1px; + border-radius: 0px; + } + #find-and-replace #replace-preview .replace .match { + background-color: #f92672; + border-color: #f92672; + border-radius: 0px; + } + #find-and-replace #replace-preview .replace .insert { + background-color: #a6e22e; + border-color: #a6e22e; + border-radius: 0px; + } + .jupyter-dashboard-menu-item.selected::before { + font-family: 'FontAwesome' !important; + content: '\f00c' !important; + position: absolute !important; + color: #a6e22e !important; + left: 0px !important; + top: 13px !important; + font-size: 12px !important; + } + .shortcut_key, + span.shortcut_key { + display: inline-block; + width: 16ex; + text-align: right; + font-family: monospace; + } + .jupyter-keybindings { + padding: 1px; + line-height: 24px; + border-bottom: 1px solid rgba(93,92,82,.25); + } + .jupyter-keybindings i { + background: #282828; + font-size: small; + padding: 5px; + margin-left: 7px; + } + div#short-key-bindings-intro.well, + .well { + background-color: #2f2f2f; + border: 1px solid #2f2f2f; + color: #f8f8f0; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; + } + #texteditor-backdrop { + background: #1e1e1e; + background-color: #1e1e1e; + } + #texteditor-backdrop #texteditor-container .CodeMirror-gutter, + #texteditor-backdrop #texteditor-container .CodeMirror-gutters { + background: #49483e; + background-color: #49483e; + color: #75715e; + } + .edit_app #menubar .navbar { + margin-bottom: 0px; + } + #texteditor-backdrop #texteditor-container { + padding: 0px; + background-color: #282828; + box-shadow: none; + } + .terminal-app { + background: #1e1e1e; + } + .terminal-app > #header { + background: #1e1e1e; + } + .terminal-app .terminal { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + color: #f8f8f0; + background: #282828; + padding: 0.4em; + border-radius: 2px; + -webkit-box-shadow: none; + box-shadow: none; + } + .terminal .xterm-viewport { + background-color: #282828; + color: #f8f8f0; + overflow-y: auto; + } + .terminal .xterm-color-0 { + color: #a6e22e; + } + .terminal .xterm-color-1 { + color: #a6e22e; + } + .terminal .xterm-color-2 { + color: #f92672; + } + .terminal .xterm-color-3 { + color: #a6e22e; + } + .terminal .xterm-color-4 { + color: #ae81ff; + } + .terminal .xterm-color-5 { + color: #e6db74; + } + .terminal .xterm-color-6 { + color: #a6e22e; + } + .terminal .xterm-color-7 { + color: #a6e22e; + } + .terminal .xterm-color-8 { + color: #a6e22e; + } + .terminal .xterm-color-9 { + color: #e6db74; + } + .terminal .xterm-color-10 { + color: #a6e22e; + } + .terminal .xterm-color-14 { + color: #a6e22e; + } + .terminal .xterm-bg-color-15 { + background-color: #282828; + } + .terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar) .terminal-cursor { + background-color: #a6e22e; + color: #282828; + } + .terminal:not(.focus) .terminal-cursor { + outline: 1px solid #a6e22e; + outline-offset: -1px; + } + .celltoolbar { + font-size: 100%; + padding-top: 3px; + border-color: transparent; + border-bottom: thin solid rgba(148,204,114,.2); + background: transparent; + } + .cell-tag, + .tags-input input, + .tags-input button { + color: #f8f8f0; + background-color: #1e1e1e; + background-image: none; + border: 1px solid #f8f8f0; + border-radius: 1px; + box-shadow: none; + width: inherit; + font-size: inherit; + height: 22px; + line-height: 22px; + } + #notebook-container > div.cell.code_cell.rendered.selected > div.input > div.inner_cell > div.ctb_hideshow.ctb_show > div > div > button, + #notebook-container > div.input > div.inner_cell > div.ctb_hideshow.ctb_show > div > div > button { + font-size: 10pt; + color: #f8f8f0; + background-color: #1e1e1e; + background-image: none; + border: 1px solid #f8f8f0; + border-radius: 1px; + box-shadow: none; + width: inherit; + font-size: inherit; + height: 22px; + line-height: 22px; + } + div#pager #pager-contents { + background: #1e1e1e !important; + background-color: #1e1e1e !important; + } + div#pager pre { + color: #f8f8f0 !important; + background: #282828 !important; + background-color: #282828 !important; + padding: 0.4em; + } + div#pager .ui-resizable-handle { + top: 0px; + height: 8px; + background: #a6e22e !important; + border-top: 1px solid #a6e22e; + border-bottom: 1px solid #a6e22e; + } + div.CodeMirror, + div.CodeMirror pre { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + color: #f8f8f0; + } + div.CodeMirror-lines { + padding-bottom: .9em; + padding-left: .5em; + padding-right: 1.5em; + padding-top: .7em; + } + span.ansiblack, + .ansi-black-fg { + color: #282828; + } + span.ansiblue, + .ansi-blue-fg, + .ansi-blue-intense-fg { + color: #66d9ef; + } + span.ansigray, + .ansi-gray-fg, + .ansi-gray-intense-fg { + color: #888888; + } + span.ansigreen, + .ansi-green-fg { + color: #a6e22e; + } + .ansi-green-intense-fg { + color: #888888; + } + span.ansipurple, + .ansi-purple-fg, + .ansi-purple-intense-fg { + color: #ae81ff; + } + span.ansicyan, + .ansi-cyan-fg, + .ansi-cyan-intense-fg { + color: #ae81ff; + } + span.ansiyellow, + .ansi-yellow-fg, + .ansi-yellow-intense-fg { + color: #e6db74; + } + span.ansired, + .ansi-red-fg, + .ansi-red-intense-fg { + color: #f92672; + } + div.output-stderr { + background-color: #f92672; + } + div.output-stderr pre { + color: #f8f8f2; + } + div.js-error { + color: #f92672; + } + .ipython_tooltip { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + border: 2px solid #141414; + background: #282828; + background-color: #282828; + border-radius: 2px; + overflow-x: visible; + overflow-y: visible; + box-shadow: none; + position: absolute; + z-index: 1000; + } + .ipython_tooltip .tooltiptext pre { + font-family: monospace, monospace; + font-size: 11pt; + line-height: 170%; + background: #282828; + background-color: #282828; + color: #f8f8f0; + overflow-x: visible; + overflow-y: visible; + max-width: 900px; + } + div#tooltip.ipython_tooltip { + overflow-x: wrap; + overflow-y: visible; + max-width: 800px; + } + div.tooltiptext.bigtooltip { + overflow-x: visible; + overflow-y: scroll; + height: 400px; + max-width: 800px; + } + .cm-s-ipython.CodeMirror { + font-family: monospace, monospace; + font-size: 11pt; + background: #6f6e6e; + color: #f8f8f0; + border-radius: 2px; + font-style: normal; + font-weight: normal; + } + .cm-s-ipython div.CodeMirror-selected { + background: #49483e; + } + .CodeMirror-gutters { + border: none; + border-right: 1px solid #49483e !important; + background-color: #49483e !important; + background: #49483e !important; + border-radius: 0px; + white-space: nowrap; + } + .cm-s-ipython .CodeMirror-gutters { + background: #49483e; + border: none; + border-radius: 0px; + width: 36px; + } + .cm-s-ipython .CodeMirror-linenumber { + color: #75715e; + } + .CodeMirror-sizer { + margin-left: 40px; + } + .CodeMirror-linenumber, + div.CodeMirror-linenumber, + .CodeMirror-gutter.CodeMirror-linenumberdiv.CodeMirror-gutter.CodeMirror-linenumber { + padding-right: 1px; + margin-left: 0px; + margin: 0px; + width: 26px !important; + padding: 0px; + text-align: right; + } + .CodeMirror-linenumber { + color: #75715e; + } + .cm-s-ipython .CodeMirror-cursor { + border-left: 2px solid #0095ff !important; + } + .cm-s-ipython span.cm-comment { + color: #75715e; + font-style: italic; + } + .cm-s-ipython span.cm-atom { + color: #ae81ff; + } + .cm-s-ipython span.cm-number { + color: #ae81ff; + } + .cm-s-ipython span.cm-property { + color: #f8f8f0; + } + .cm-s-ipython span.cm-attribute { + color: #f8f8f0; + } + .cm-s-ipython span.cm-keyword { + color: #f92672; + font-weight: normal; + } + .cm-s-ipython span.cm-string { + color: #e6db74; + } + .cm-s-ipython span.cm-meta { + color: #fd971f; + } + .cm-s-ipython span.cm-operator { + color: #a6e22e; + } + .cm-s-ipython span.cm-builtin { + color: #a6e22e; + } + .cm-s-ipython span.cm-variable { + color: #f8f8f0; + } + .cm-s-ipython span.cm-variable-2 { + color: #a6e22e; + } + .cm-s-ipython span.cm-variable-3 { + color: #fd971f; + } + .cm-s-ipython span.cm-def { + color: #a6e22e; + font-weight: normal; + } + .cm-s-ipython span.cm-error { + background: rgba(249,38,114,.4); + } + .cm-s-ipython span.cm-tag { + color: #ae81ff; + } + .cm-s-ipython span.cm-link { + color: #a6e22e; + } + .cm-s-ipython span.cm-storage { + color: #ae81ff; + } + .cm-s-ipython span.cm-entity { + color: #a6e22e; + } + .cm-s-ipython span.cm-quote { + color: #e6db74; + } + div.CodeMirror span.CodeMirror-matchingbracket { + color: #ffffff; + font-weight: bold; + background-color: #49483e; + } + div.CodeMirror span.CodeMirror-nonmatchingbracket { + color: #ffffff; + font-weight: bold; + background: rgba(249,38,114,.4) !important; + } + .cm-header-1 { + font-size: 215%; + } + .cm-header-2 { + font-size: 180%; + } + .cm-header-3 { + font-size: 150%; + } + .cm-header-4 { + font-size: 120%; + } + .cm-header-5 { + font-size: 100%; + } + .cm-s-default .cm-hr { + color: #a6e22e; + } + div.cell.text_cell .cm-s-default .cm-header { + font-family: sans-serif; + font-weight: normal; + color: #a6e22e !important; + margin-top: 0.3em !important; + margin-bottom: 0.3em !important; + } + div.cell.text_cell .cm-s-default span.cm-variable-2 { + color: #f8f8f0 !important; + } + div.cell.text_cell .cm-s-default span.cm-variable-3 { + color: #fd971f !important; + } + .cm-s-default span.cm-comment { + color: #75715e !important; + } + .cm-s-default .cm-tag { + color: #529b2f; + } + .cm-s-default .cm-builtin { + color: #a6e22e; + } + .cm-s-default .cm-string { + color: #e6db74; + } + .cm-s-default .cm-keyword { + color: #f92672; + } + .cm-s-default .cm-number { + color: #ae81ff; + } + .cm-s-default .cm-error { + color: #ae81ff; + } + .cm-s-default .cm-link { + color: #a6e22e; + } + .cm-s-default .cm-atom { + color: #ae81ff; + } + .cm-s-default .cm-def { + color: #a6e22e; + } + .CodeMirror-cursor { + border-left: 2px solid #0095ff !important; + border-right: none; + width: 0; + } + .cm-s-default div.CodeMirror-selected { + background: #49483e; + } + .cm-s-default .cm-selected { + background: #49483e; + } + .MathJax_Display, + .MathJax { + border: 0 !important; + font-size: 100% !important; + text-align: center !important; + margin: 0em !important; + line-height: 2.25 !important; + } + .MathJax:focus, + body :focus .MathJax { + display: inline-block !important; + } + .MathJax:focus, + body :focus .MathJax { + display: inline-block !important; + } + .completions { + position: absolute; + z-index: 110; + overflow: hidden; + border: medium solid #49483e; + box-shadow: none; + line-height: 1; + } + .completions select { + background: #282828; + background-color: #282828; + outline: none; + border: none; + padding: 0px; + margin: 0px; + margin-left: 2px; + overflow: auto; + font-family: monospace, monospace; + font-size: 11pt; + color: #f8f8f0; + width: auto; + } + div#maintoolbar { + display: none !important; + } + #header-container { + display: none !important; + } + + + \ No newline at end of file diff --git a/utilities/install.py b/utilities/install.py index 0e8f93f8..5f41d021 100644 --- a/utilities/install.py +++ b/utilities/install.py @@ -7,78 +7,220 @@ branch = None -#by default clones branch (which can be passed as a parameter python install.py branch test_branch) -#if branch doesnt exist clones the default_branch -def clone(repository, folder, default_branch, cwdp='', recursive = False, destination_folder = None): +HERE = os.path.dirname(os.path.abspath(__file__)) + + +# repos +JUPYTER = 'https://github.com/openworm/org.geppetto.frontend.jupyter.git' +PYGEPPETTO = 'https://github.com/openworm/pygeppetto.git' +NETPYNE = 'https://github.com/Neurosim-lab/netpyne.git' +WORKSPACE = 'https://github.com/Neurosim-lab/netpyne_workspace' + +ROOT_DIR = os.path.join(HERE, os.pardir) +DEPS_DIR = os.path.join(ROOT_DIR, 'src') + +WEBAPP_DIR = os.path.join(ROOT_DIR, 'webapp') +JUPYTER_DIR = 'jupyter-geppetto' + +def cprint(string): + print(f"\033[35;4m\U0001f560 {string} \033[0m \n") + sys.stdout.flush() + + + +def execute(cmd, cwd='.', *args, **kwargs): + exit_code = subprocess.call(cmd, cwd=cwd, *args, **kwargs) + if exit_code != 0: + raise SystemExit('Error installing NetPyNE-UI') + + + +# by default clones branch (which can be passed as a parameter python install.py branch test_branch) +# if branch doesnt exist clones the default_branch_or_tag +def clone(repository, folder=None, default_branch_or_tag=None, cwdp='', recursive=False): global branch - print("Cloning "+repository) - if recursive: - subprocess.call(['git', 'clone', '--recursive', repository], cwd='./'+cwdp) + print("Cloning " + repository) + default_branch_or_tag = default_branch_or_tag or branch or 'master' + folder = folder or os.path.basename(repository).replace('.git', '') + if folder and os.path.exists(os.path.join(cwdp, folder)): + print(f'Skipping clone of {repository}: folder exists') else: - if destination_folder: - subprocess.call(['git', 'clone', repository, destination_folder], cwd='./'+cwdp) + if recursive: + subprocess.call(['git', 'clone', '--recursive', repository], cwd='./' + cwdp) else: - subprocess.call(['git', 'clone', repository], cwd='./'+cwdp) - checkout(folder, default_branch, cwdp) + if folder: + subprocess.call(['git', 'clone', repository, folder], cwd='./' + cwdp) + else: + subprocess.call(['git', 'clone', repository], cwd='./' + cwdp) + checkout(folder, default_branch_or_tag, cwdp) -def checkout(folder, default_branch, cwdp): +def checkout(folder, default_branch_or_tag, cwdp): currentPath = os.getcwd() print(currentPath) - newPath = currentPath+"/"+cwdp+folder + newPath = os.path.join(currentPath, cwdp, folder) print(newPath) os.chdir(newPath) - python_git=subprocess.Popen("git branch -a",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - outstd,errstd=python_git.communicate() - if branch and branch in str(outstd) and branch != 'master' and branch != 'development': # don't ckeckout development for netpyne + python_git = subprocess.Popen("git branch -a", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + outstd, errstd = python_git.communicate() + if branch and branch in str(outstd): subprocess.call(['git', 'checkout', branch], cwd='./') else: - subprocess.call(['git', 'checkout', default_branch], cwd='./') + subprocess.call(['git', 'checkout', default_branch_or_tag], cwd='./') os.chdir(currentPath) -def main(argv): - global branch - if(len(argv) > 0): - if(argv[0] == 'branch'): - branch = argv[1] +def compile_mod(): + execute(['nrnivmodl', 'netpyne_workspace/mod']) + + + + +def main(branch=branch, skipNpm=False, skipTest=False, development=False): + + + + # install pytest if needed + if not skipTest: + cprint("Installing test libraries") + execute(cmd=['pip', 'install', '-r', 'requirements-test.txt'], cwd=ROOT_DIR) + + + + # clone_repo(project='openworm', + # repo_name='geppetto-client', + # folder='geppetto-client', + # default_branch='v2.4.0', + # cwdp='webapp/', + # recursive=False, + # ) + + + clone(repository=NETPYNE, default_branch_or_tag='gui_cns') + if development: + execute(cmd=['pip', 'install', '-e', '.'], cwd=ROOT_DIR) + + if not os.path.exists(DEPS_DIR): + os.mkdir(DEPS_DIR) + os.chdir(DEPS_DIR) + # install pygeppetto + cprint("Installing pygeppetto") + clone(repository=PYGEPPETTO, + folder='pygeppetto', + default_branch_or_tag='development' + ) + execute(cmd=['pip', 'install', '-e', '.'], cwd='pygeppetto') + + # install jupyter geppetto + cprint("Installing org.geppetto.frontend.jupyter") + clone(repository=JUPYTER, + folder=JUPYTER_DIR, + default_branch_or_tag='development' + ) + os.chdir(ROOT_DIR) + execute(cmd=['pip', 'install', '-e', '.'], cwd=os.path.join(DEPS_DIR, JUPYTER_DIR)) + execute(['pip3', 'install', '-e', '.'], cwd='./netpyne/') + else: + # install requirements + cprint("Installing requirements") + + execute(cmd=['pip', 'install', '-r', 'requirements.txt'], cwd=ROOT_DIR) + execute(['pip', 'install', '.'], cwd='./netpyne/') + + cprint("Installing UI python package...") + execute(cmd=['pip', 'install', '.', '--no-deps'], cwd=ROOT_DIR) + + os.chdir(ROOT_DIR) + cprint("Cloning workspace") + clone(repository=WORKSPACE, default_branch_or_tag='gui_cns') + cprint("Compiling workspace modules") + compile_mod() + + if not skipNpm and os.path.exists(os.path.join(DEPS_DIR, JUPYTER_DIR)): + cprint("Building Jupyter Geppetto extension...") + execute(cmd=['npm', 'ci'], cwd=os.path.join(DEPS_DIR,JUPYTER_DIR, 'js')) + execute(cmd=['npm', 'run', 'build-dev' if development else 'build'], cwd=os.path.join(DEPS_DIR, JUPYTER_DIR, 'js')) + + + execute(cmd=['jupyter', 'nbextension', 'install', '--py', '--symlink', '--sys-prefix', 'jupyter_geppetto']) + execute(cmd=['jupyter', 'nbextension', 'enable', '--py', '--sys-prefix', 'jupyter_geppetto']) + execute(cmd=['jupyter', 'nbextension', 'enable', '--py', '--sys-prefix', 'widgetsnbextension']) + execute(cmd=['jupyter', 'serverextension', 'enable', '--py', '--sys-prefix', 'jupyter_geppetto']) + + + + # set python console theme + execute(['jt', '-t', 'monokai']) + + print("Installing notebook theme") + from jupyter_core import paths + config_dir = paths.jupyter_config_dir() + print('Jupyter configuration dir is {}'.format(config_dir)) + css_path = os.path.join(config_dir, 'custom') + if not os.path.exists(css_path): + os.makedirs(css_path) + execute(cmd=['cp', 'custom.css', css_path], cwd=HERE) + + + # Enables Compression + json_config_path = "{}/jupyter_notebook_config.json".format(config_dir) + config = {} + if os.path.exists(json_config_path): + with open(json_config_path, 'r') as f: + try: + config = json.load(f) + except Exception as e: + print("Something went wrong reading the jupyter configuration file.\n{}" + "\nNew configuration will be created".format(str(e))) + f.close() + with open(json_config_path, 'w+') as f: + try: + _ = config['NotebookApp'] + except KeyError: + config['NotebookApp'] = {'tornado_settings': {}} + try: + _ = config['NotebookApp']['tornado_settings'] + except KeyError: + config['NotebookApp']['tornado_settings'] = {} + config['NotebookApp']['tornado_settings']['gzip'] = True + f.seek(0) + json.dump(config, f, indent=4, sort_keys=True) + f.truncate() + + # test + if skipTest: + cprint("Skipping tests") + else: + cprint("Testing NetPyNE") + # execute("python -m unittest netpyne_ui.tests.netpyne_model_interpreter_test".split()) + + + cprint("Installing client packages") + if not skipNpm: + execute(cmd=['npm', 'install' if development else 'ci'], cwd=WEBAPP_DIR) + execute(cmd=['npm', 'run', 'build-dev'], cwd=WEBAPP_DIR) + + if __name__ == "__main__": - main(sys.argv[1:]) - -os.chdir(os.getcwd()+"/../") -# Cloning Repos -clone('https://github.com/openworm/pygeppetto.git','pygeppetto','v0.4.2-alpha') -subprocess.call(['pip', 'install', '-e', '.'], cwd='./pygeppetto/') - -clone('https://github.com/Neurosim-lab/netpyne.git','netpyne','v0.9.1.3') -subprocess.call(['pip', 'install', '-e', '.'], cwd='./netpyne/') - -clone('https://github.com/openworm/org.geppetto.frontend.jupyter.git','org.geppetto.frontend.jupyter','v0.4.2-alpha') -with open('npm_frontend_jupyter_log', 'a') as stdout: - subprocess.call(['npm', 'install'], cwd='./org.geppetto.frontend.jupyter/js', stdout=stdout) -subprocess.call(['npm', 'run', 'build-dev'], cwd='./org.geppetto.frontend.jupyter/js') - -# We can't clone org.geppetto.frontend as a regular submodule because Travis doesn't have .gitmodules in the zip -# subprocess.call(['git', 'submodule', 'update', '--init'], cwd='./') -clone('https://github.com/openworm/org.geppetto.frontend.git','geppetto','v0.4.1-syncRefactor','netpyne_ui/', False, 'geppetto') -clone('https://github.com/MetaCell/geppetto-netpyne.git','geppetto-netpyne','0.5.2','netpyne_ui/geppetto/src/main/webapp/extensions/') - -print("Enabling Geppetto NetPyNE Extension ...") -geppetto_configuration = os.path.join(os.path.dirname(__file__), './utilities/GeppettoConfiguration.json') -copyfile(geppetto_configuration, './netpyne_ui/geppetto/src/main/webapp/GeppettoConfiguration.json') - -# Installing and building -print("NPM Install and build for Geppetto Frontend ...") -with open('npm_frontend_log', 'a') as stdout: - subprocess.call(['npm', 'install'], cwd='./netpyne_ui/geppetto/src/main/webapp/', stdout=stdout) -subprocess.call(['npm', 'run', 'build-dev-noTest'], cwd='./netpyne_ui/geppetto/src/main/webapp/') - -print("Installing jupyter_geppetto python package ...") -subprocess.call(['pip', 'install', '-e', '.'], cwd='./org.geppetto.frontend.jupyter') -print("Installing jupyter_geppetto Jupyter Extension ...") -subprocess.call(['jupyter', 'nbextension', 'install', '--py', '--symlink', '--user', 'jupyter_geppetto'], cwd='./org.geppetto.frontend.jupyter') -subprocess.call(['jupyter', 'nbextension', 'enable', '--py', '--user', 'jupyter_geppetto'], cwd='./org.geppetto.frontend.jupyter') -subprocess.call(['jupyter', 'nbextension', 'enable', '--py', 'widgetsnbextension'], cwd='./org.geppetto.frontend.jupyter') -subprocess.call(['jupyter', 'serverextension', 'enable', '--py', 'jupyter_geppetto'], cwd='./org.geppetto.frontend.jupyter') - -print("Installing NetPyNE UI python package ...") -subprocess.call(['pip', 'install', '-e', '.'], cwd='.') + import argparse + + parser = argparse.ArgumentParser(description='Install NetPyNE-UI and related dev libraries.') + parser.add_argument('--branch', '-b', dest='branch', type=str, action="store", nargs='?', + help='the branch to checkout for all projects. ' + 'The branch is checked out if exists, otherwise the default for the project will be used') + parser.add_argument('--npm-skip', dest='skipNpm', action='store_true', default=False, + help='Skips the long npm install and build processes') + + parser.add_argument('--no-test', dest='skipTest', action="store_true", default=False, + help='Skip python tests.') + + parser.add_argument('--dev', dest='development', action="store_true", default=False, + help='Install for development.') + + args = parser.parse_args([arg if arg != 'branch' else '-b' for arg in sys.argv[1:]]) + print(args) + branch = args.branch + + skipNpm = args.skipNpm + skipTest = args.skipTest + development = args.development + main(branch, skipNpm, skipTest, development) diff --git a/webapp/.eslintignore b/webapp/.eslintignore new file mode 100644 index 00000000..1d81b61d --- /dev/null +++ b/webapp/.eslintignore @@ -0,0 +1,9 @@ +etc/* +node/* +build/* +META-INF/* +**/tests/casperjs/**/*.js +**/tests/jest-puppeteer/**/*.js +**/*min.js +geppetto-client/** +node_modules/** \ No newline at end of file diff --git a/webapp/.eslintrc.js b/webapp/.eslintrc.js new file mode 100644 index 00000000..7e6f09b8 --- /dev/null +++ b/webapp/.eslintrc.js @@ -0,0 +1,22 @@ +module.exports = { + extends: [ + "./node_modules/@geppettoengine/geppetto-client/.eslintrc.js", + "plugin:jest/recommended" + ], + rules: { + 'multiline-comment-style': 0, + }, + plugins: ["jest"], + globals: { + page: true, + browser: true, + context: true, + jestPuppeteer: true, + acnet2: true, + c302: true, + pvdr: true, + net1: true, + CanvasContainer: true, + patchRequire: true + } +}; \ No newline at end of file diff --git a/webapp/.project b/webapp/.project new file mode 100644 index 00000000..5983ecdd --- /dev/null +++ b/webapp/.project @@ -0,0 +1,11 @@ + + + geppetto-application + + + + + + + + diff --git a/utilities/GeppettoConfiguration.json b/webapp/GeppettoConfiguration.json similarity index 87% rename from utilities/GeppettoConfiguration.json rename to webapp/GeppettoConfiguration.json index 4d6e6d2b..54e3cc20 100644 --- a/utilities/GeppettoConfiguration.json +++ b/webapp/GeppettoConfiguration.json @@ -10,10 +10,7 @@ "geppetto-default/ComponentsInitialization": false, "geppetto-netpyne/ComponentsInitialization": true }, - "themes": { - "geppetto-default/colors": false, - "geppetto-netpyne/css/colors": true - }, + "themes": "css/colors", "properties": { "title" : "NetPyNE", "description": "NetPyNE-UI is a user interface for building, visualizing and simulationg neuronal network models using NetPyNE.", diff --git a/webapp/LICENSE b/webapp/LICENSE new file mode 100644 index 00000000..80f65a0b --- /dev/null +++ b/webapp/LICENSE @@ -0,0 +1,30 @@ +The MIT License (MIT) + +Copyright © 2011, 2017 Geppetto authors +http://geppetto.org + +All rights reserved. This program and the accompanying materials +are made available under the terms of the MIT License +which accompanies this distribution, and is available at +http://opensource.org/licenses/MIT + +Contributors: + Geppetto - http://contributors.geppetto.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/webapp/Main.js b/webapp/Main.js new file mode 100644 index 00000000..5e109057 --- /dev/null +++ b/webapp/Main.js @@ -0,0 +1,40 @@ +global.jQuery = require("jquery"); +global.GEPPETTO_CONFIGURATION = require('./GeppettoConfiguration.json'); + +jQuery(function () { + require('geppetto-client-initialization'); + const ReactDOM = require('react-dom'); + const React = require('react'); + const MuiThemeProvider = require('@material-ui/core/styles').MuiThemeProvider; + const NetPyNE = require('./components').NetPyNE; + + const theme = require('./theme').default + + const Provider = require("react-redux").Provider; + const configureStore = require('./redux/store').default; + + require('./css/netpyne.less'); + require('./css/material.less'); + require('./css/traceback.less'); + require('./css/flexlayout.less'); + require('./css/tree.less'); + + const store = configureStore(); + + ReactDOM.render( +
+ + + + + + +
, + document.querySelector('#mainContainer') + ); + + GEPPETTO.G.setIdleTimeOut(-1); + GEPPETTO.Resources.COLORS.DEFAULT = "#6f54aa"; + GEPPETTO.trigger(GEPPETTO.Events.Show_spinner, "Initialising NetPyNE"); + +}); \ No newline at end of file diff --git a/webapp/PULL_REQUEST_TEMPLATE b/webapp/PULL_REQUEST_TEMPLATE new file mode 100644 index 00000000..f654a605 --- /dev/null +++ b/webapp/PULL_REQUEST_TEMPLATE @@ -0,0 +1,2 @@ +- [ ] Add coverage for whatever new functionality, to a JUnit test if it's backend, to a Casper Test if it's frontend +- [ ] Make sure both push and pr travis builds are passing before asking for a review diff --git a/webapp/README.md b/webapp/README.md new file mode 100644 index 00000000..70f819e8 --- /dev/null +++ b/webapp/README.md @@ -0,0 +1,3 @@ +# geppetto-netpyne + +Frontend Geppetto application for the [NetPyNE UI](https://github.com/MetaCell/NetPyNE-UI). diff --git a/webapp/Utils.js b/webapp/Utils.js new file mode 100644 index 00000000..0f014914 --- /dev/null +++ b/webapp/Utils.js @@ -0,0 +1,194 @@ +import { execPythonMessage, evalPythonMessage } from '@geppettoengine/geppetto-client/js/communication/geppettoJupyter/GeppettoJupyterUtils'; +import React from 'react'; + + +const Utils = { + + getAvailableKey: function (model, prefix) { + if (model == undefined) { + return prefix; + } + // Get New Available ID + var id = prefix; + if (model[id + 0] == undefined) { + return id + 0 + } + var i = 0; + id = prefix + i++ + while (model[id] != undefined) { + id = prefix + i++; + } + return id; + }, + + getMetadataField: function (key, field) { + if (key == undefined) { + return; + } + var currentObject; + var nextObject = window.metadata; + key.split('.').forEach(item => { + if (item in nextObject) { + currentObject = nextObject[item]; + if ("children" in currentObject) { + nextObject = currentObject["children"]; + } + } else { + currentObject = undefined; + return; + } + }); + return (currentObject == undefined) ? currentObject : currentObject[field]; + }, + + getHTMLType: function (key) { + var type = this.getMetadataField(key, "type") + + switch (type) { + case "int": + var htmlType = "number" + break; + default: + var htmlType = "text" + break; + } + return htmlType; + + }, + + isObject: function (item) { + return (item && typeof item === 'object' && !Array.isArray(item)); + }, + + mergeDeep: function (target, source) { + let output = Object.assign({}, target); + if (this.isObject(target) && this.isObject(source)) { + Object.keys(source).forEach(key => { + if (this.isObject(source[key])) { + if (!(key in target)) { + Object.assign(output, { [key]: source[key] }); + } else { + output[key] = this.mergeDeep(target[key], source[key]); + } + } else { + Object.assign(output, { [key]: source[key] }); + } + }); + } + return output; + }, + + getFieldsFromMetadataTree: function (tree, callback) { + function iterate (object, path) { + if (Array.isArray(object)) { + object.forEach(function (a, i) { + iterate(a, path.concat(i)); + }); + return; + } + if (object !== null && typeof object === 'object') { + Object.keys(object).forEach(function (k) { + // Don't add the leaf to path + iterate(object[k], (typeof object[k] === 'object') ? path.concat(k) : path); + + }); + return; + } + + // Push to array of field id. Remove children and create id string + modelFieldsIds.push(path.filter(path => path != 'children').join('.')); + } + + // Iterate the array extracting the fields Ids + var modelFieldsIds = []; + iterate(tree, []); + + // Generate model fields based on ids + var modelFields = []; + modelFieldsIds.filter((v, i, a) => a.indexOf(v) === i).map(id => modelFields.push(callback(id, 0))) + return modelFields; + }, + + renameKey (path, oldValue, newValue, callback) { + this.execPythonMessage('netpyne_geppetto.rename("' + path + '","' + oldValue + '","' + newValue + '")') + .then(response => { + callback(response, newValue); + }) + }, + + nameValidation (name) { + // Remove spaces + if ((/\s/.test(name))) { + name = name.replace(/\s+/g, "").replace(/^\d+/g, ""); + } else if ((/^[0-9]/.test(name))) { // Remove number at the beginning + name = name.replace(/\s+/g, "").replace(/^\d+/g, ""); + } + return name; + + }, + + // FIXME: Hack to remove scaped chars (\\ -> \ and \' -> ') manually + convertToJSON (data){ + if (typeof data === 'string' || data instanceof String){ + return JSON.parse(data.replace(/\\\\/g, '\\').replace(/\\'/g, '\'')) + } + return data + }, + + getErrorResponse (data){ + var parsedData = this.convertToJSON(data) + if (parsedData.type && parsedData['type'] == 'ERROR') { + const error = { details: parsedData['details'] } + if (Object.prototype.hasOwnProperty.call(parsedData, "message")) { + error["message"] = parsedData['message'] + } else if (Object.prototype.hasOwnProperty.call(parsedData, "websocket")) { + error["message"] = parsedData['websocket'] + } + return error + } + return null; + }, + + parsePythonException (exception){ + return

+  },
+
+  handleUpdate (updateCondition, newValue, originalValue, context, componentName) {
+    if ((updateCondition) && (newValue != originalValue)) {
+      /*
+       * if the new value has been changed by the function Utils.nameValidation means that the name convention
+       * has not been respected, so we need to open the dialog and inform the user.
+       */
+      context.setState({
+        currentName: newValue,
+        errorMessage: "Error",
+        errorDetails: "Leading digits or whitespaces are not allowed in " + componentName + " names."
+      });
+      return true;
+    } else if ((updateCondition) && (newValue == originalValue)){
+      context.setState({ currentName: newValue });
+      return true;
+    } else if (!(updateCondition) && (newValue == originalValue)) {
+      context.setState({
+        currentName: newValue,
+        errorMessage: "Error",
+        errorDetails: "Name collision detected, the name " + newValue
+                                        + " is already used in this model, please pick another name."
+      });
+      return false;
+    } else if (!(updateCondition) && (newValue != originalValue)) {
+      context.setState({
+        currentName: newValue,
+        errorMessage: "Error",
+        errorDetails: "Leading digits or whitespaces are not allowed in " + componentName + " names."
+      });
+      return false;
+    }
+  },
+
+  execPythonMessage: execPythonMessage,
+  evalPythonMessage: evalPythonMessage
+}
+
+
+export default Utils
\ No newline at end of file
diff --git a/webapp/WEB-INF/shiro.ini b/webapp/WEB-INF/shiro.ini
new file mode 100644
index 00000000..ad1c16b0
--- /dev/null
+++ b/webapp/WEB-INF/shiro.ini
@@ -0,0 +1,16 @@
+[main]
+
+shiro.loginUrl = /login
+
+cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
+securityManager.cacheManager = $cacheManager
+
+# Configure a Realm to connect to a user datastore.
+myRealm = org.geppetto.frontend.controllers.GeppettoRealm
+
+securityManager.realm = $myRealm
+
+[urls]
+#/logout = logout
+/login = authc
+/simulator = authc
\ No newline at end of file
diff --git a/webapp/WEB-INF/spring/app-config.xml b/webapp/WEB-INF/spring/app-config.xml
new file mode 100644
index 00000000..a57575c2
--- /dev/null
+++ b/webapp/WEB-INF/spring/app-config.xml
@@ -0,0 +1,105 @@
+
+
+
+	
+	
+	
+	
+	
+
+	
+
+	
+
+	
+
+	
+
+	
+		
+			/
+		
+	
+
+	
+		
+			/build/
+		
+		
+			.vm
+		
+		
+			true
+		
+	
+
+
+	
+	
+		
+		
+		
+		
+	
+
+	
+		
+	
+	
+	
+		
+	
+
+	
+	
+
+		
+		
+		
+		
+		
+
+		
+
+	
+
+
+
+
+
+
diff --git a/webapp/WEB-INF/spring/osgi-config.xml b/webapp/WEB-INF/spring/osgi-config.xml
new file mode 100644
index 00000000..48eb0e3d
--- /dev/null
+++ b/webapp/WEB-INF/spring/osgi-config.xml
@@ -0,0 +1,23 @@
+
+
+    
+    
+
+	
+
diff --git a/webapp/WEB-INF/web.ejs b/webapp/WEB-INF/web.ejs
new file mode 100644
index 00000000..7643e91d
--- /dev/null
+++ b/webapp/WEB-INF/web.ejs
@@ -0,0 +1,104 @@
+
+
+
+    org.geppetto.frontend
+
+    
+        contextClass
+        org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext
+    
+    
+        contextConfigLocation
+        /WEB-INF/spring/*.xml
+    
+
+    
+		org.springframework.web.context.request.RequestContextListener
+	
+    
+        org.springframework.web.context.ContextLoaderListener
+    
+    
+        org.apache.shiro.web.env.EnvironmentLoaderListener
+    
+
+    
+        springdispatcher
+        org.springframework.web.servlet.DispatcherServlet
+        
+            contextClass
+            org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext
+        
+        
+            contextConfigLocation
+            /WEB-INF/spring/*.xml
+        
+        1
+    
+
+    
+        springdispatcher
+        /
+    
+
+    
+   		json
+    	application/json
+	
+    
+        
+        TestServlet
+        TestServlet
+        org.geppetto.frontend.TestServlet
+    
+    
+        TestServlet
+        /TestServlet
+    
+
+    
+        ShiroFilter
+        org.apache.shiro.web.servlet.ShiroFilter
+    
+
+    
+        ShiroFilter
+        /*
+        REQUEST
+        FORWARD
+        INCLUDE
+        ERROR
+    
+
+    <% if ((htmlWebpackPlugin.options.GEPPETTO_CONFIGURATION.embedded == true) && (htmlWebpackPlugin.options.GEPPETTO_CONFIGURATION.embedderURL != "/")) { %>
+    
+	  CorsFilter
+	  org.apache.catalina.filters.CorsFilter
+	  
+		cors.allowed.origins
+		<%= htmlWebpackPlugin.options.GEPPETTO_CONFIGURATION.embedderURL %>
+	  
+	
+	
+	  CorsFilter
+	  /*
+	
+	<% } %>
+
+
+    <% if (htmlWebpackPlugin.options.GEPPETTO_CONFIGURATION.useSsl == true) { %>
+    
+        
+            securedapp
+            /*
+        
+        
+            NONE
+        
+    
+    <% } %>
+
+
diff --git a/webapp/WEB-INF/web.xml b/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..0c7a30eb
--- /dev/null
+++ b/webapp/WEB-INF/web.xml
@@ -0,0 +1,81 @@
+
+
+
+    org.geppetto.frontend
+
+    
+        contextClass
+        org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext
+    
+    
+        contextConfigLocation
+        /WEB-INF/spring/*.xml
+    
+
+    
+		org.springframework.web.context.request.RequestContextListener
+	
+    
+        org.springframework.web.context.ContextLoaderListener
+    
+    
+        org.apache.shiro.web.env.EnvironmentLoaderListener
+    
+
+    
+        springdispatcher
+        org.springframework.web.servlet.DispatcherServlet
+        
+            contextClass
+            org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext
+        
+        
+            contextConfigLocation
+            /WEB-INF/spring/*.xml
+        
+        1
+    
+
+    
+        springdispatcher
+        /
+    
+
+    
+   		json
+    	application/json
+	
+    
+        
+        TestServlet
+        TestServlet
+        org.geppetto.frontend.TestServlet
+    
+    
+        TestServlet
+        /TestServlet
+    
+
+    
+        ShiroFilter
+        org.apache.shiro.web.servlet.ShiroFilter
+    
+
+    
+        ShiroFilter
+        /*
+        REQUEST
+        FORWARD
+        INCLUDE
+        ERROR
+    
+
+    
+
+
+    
+
+
diff --git a/webapp/babel.config.js b/webapp/babel.config.js
new file mode 100644
index 00000000..026d4579
--- /dev/null
+++ b/webapp/babel.config.js
@@ -0,0 +1,11 @@
+module.exports = {
+  presets: [
+    [
+      '@babel/preset-env',
+      { targets: { node: 'current' } },
+    ],
+  ],
+  plugins: [
+    "@babel/plugin-proposal-class-properties",
+  ]
+};
\ No newline at end of file
diff --git a/webapp/build.properties b/webapp/build.properties
new file mode 100644
index 00000000..5f22cdd4
--- /dev/null
+++ b/webapp/build.properties
@@ -0,0 +1 @@
+bin.includes = META-INF/
diff --git a/webapp/components/NetPyNE.js b/webapp/components/NetPyNE.js
new file mode 100644
index 00000000..c6739cc8
--- /dev/null
+++ b/webapp/components/NetPyNE.js
@@ -0,0 +1,108 @@
+import React from "react";
+
+import { Box, Grid } from '@material-ui/core'
+import { withStyles } from '@material-ui/core/styles'
+import { ErrorDialog } from 'netpyne/components'
+
+import {
+  Topbar,
+  LayoutManager,
+  Drawer,
+  Dialog
+} from "netpyne/components";
+import Splash from './general/Splash'
+
+import Utils from '../Utils';
+const styles = ({ zIndex }) => ({
+  root: { height: '100%', overflow: 'hidden', display: 'flex', flex: 1 },
+  container: {
+    display: "flex",
+    flex: 1,
+    alignItems: "stretch",
+    flexDirection: "column"
+  },
+  topbar: { position: "relative", zIndex: zIndex.drawer + 1 },
+  content: { 
+    flexGrow:1, 
+    display: 'flex', 
+    flexDirection: 'row',
+    position: 'relative' 
+  },
+  noGrow: { flexGrow: 0 }
+});
+
+import { EDIT_WIDGETS, PYTHON_CONSOLE_WIDGET, WidgetStatus } from '../constants'
+
+
+class NetPyNE extends React.Component {
+  
+  openPythonCallDialog (event) {
+    const payload = { errorMessage: event['evalue'], errorDetails: event['traceback'].join('\n') }
+    this.props.pythonCallErrorDialogBox(payload);
+  }
+
+  addMetadataToWindow (data) {
+    console.log("Initialising NetPyNE Tabs");
+    window.metadata = data.metadata;
+    window.currentFolder = data.currentFolder;
+    window.isDocker = data.isDocker;
+    window.pythonConsoleLoaded = true
+    window.tuts = data.tuts
+  }
+
+  componentDidMount () {
+    GEPPETTO.on(GEPPETTO.Events.Error_while_exec_python_command, this.openPythonCallDialog, this);
+    this.props.setDefaultWidgets();
+    
+    GEPPETTO.on('jupyter_geppetto_extension_ready', data => {
+      let project = { id: 1, name: 'Project', experiments: [{ "id": 1, "name": 'Experiment', "status": 'DESIGN' }] }
+      GEPPETTO.Manager.loadProject(project, false);
+      GEPPETTO.Manager.loadExperiment(1, [], []);
+      Utils.execPythonMessage('from netpyne_ui.netpyne_geppetto import netpyne_geppetto');
+      Utils.evalPythonMessage('netpyne_geppetto.getData',[]).then(response => {
+        GEPPETTO.trigger(GEPPETTO.Events.Show_spinner, "Loading NetPyNE-UI");
+        const data = Utils.convertToJSON(response);
+        this.addMetadataToWindow(data);
+        this.props.setWidgets(EDIT_WIDGETS);
+        this.props.modelLoaded();
+        GEPPETTO.trigger(GEPPETTO.Events.Hide_spinner);
+      })
+      
+    });
+    
+  }
+
+  componentWillUnmount () {
+    GEPPETTO.off(GEPPETTO.Events.Error_while_exec_python_command, this.openPythonCallDialog, this)
+  }
+
+  render () {
+    const { classes } = this.props
+    if (!this.props.modelLoaded) {
+      return '';
+    }
+    const Layout = LayoutManager();
+    return (
+      
+
+
+ +
+ + + + + + + + + + +
+ + +
+ ); + } +} +export default withStyles(styles)(NetPyNE) \ No newline at end of file diff --git a/webapp/components/definition/cellRules/NetPyNECellRule.js b/webapp/components/definition/cellRules/NetPyNECellRule.js new file mode 100644 index 00000000..0b65ed74 --- /dev/null +++ b/webapp/components/definition/cellRules/NetPyNECellRule.js @@ -0,0 +1,138 @@ +import React from 'react'; +import MenuItem from '@material-ui/core/MenuItem'; +import TextField from '@material-ui/core/TextField'; + +import Button from '@material-ui/core/Button'; +import Box from '@material-ui/core/Box' +import Grid from '@material-ui/core/Grid' +import Dialog from '@material-ui/core/Dialog/Dialog'; + +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; + +import { NetPyNESelectField, NetPyNETextField, NetPyNEField, NetPyNECoordsRange } from 'netpyne/components'; +import Utils from '../../../Utils'; +import Accordion from '../../general/ExpansionPanel' +import { withStyles } from "@material-ui/core/styles" + +class NetPyNECellRule extends React.Component { + + constructor (props) { + super(props); + this.state = { + currentName: props.name, + errorMessage: undefined, + errorDetails: undefined + }; + } + + handleRenameChange = event => { + var storedValue = this.props.name; + var newValue = Utils.nameValidation(event.target.value); + var updateCondition = this.props.renameHandler(newValue); + var triggerCondition = Utils.handleUpdate(updateCondition, newValue, event.target.value, this, "CellRule"); + + if (triggerCondition) { + this.triggerUpdate(() => { + // Rename the population in Python + Utils.renameKey('netParams.cellParams', storedValue, newValue, (response, newValue) => { + this.renaming = false; + }); + this.renaming = true; + }); + } + } + + triggerUpdate (updateMethod) { + // common strategy when triggering processing of a value change, delay it, every time there is a change we reset + if (this.updateTimer != undefined) { + clearTimeout(this.updateTimer); + } + this.updateTimer = setTimeout(updateMethod, 1000); + } + + UNSAFE_componentWillReceiveProps (nextProps) { + this.setState({ currentName: nextProps.name }); + } + + postProcessMenuItems (pythonData, selected) { + return pythonData.map(name => ( + -1} + value={name} + > + {name} + + )); + } + + render () { + const { classes } = this.props + var dialogPop = (this.state.errorMessage != undefined ? ( + + {this.state.errorMessage} + + + {this.state.errorDetails} + + + + + + + ) + : undefined + ) + return ( +
+
+ + + + + + + +
+ {dialogPop} +
+ ); + } +} + + +const styles = ({ shape, spacing }) => ({ + expandable: { + borderRadius: shape.borderRadius, + backgroundColor: 'inherit', + paddingTop: spacing(2), + "&::before": { content: 'unset' } + }, + root: { + display: 'flex', + flexDirection: 'column' + } +}) + +export default withStyles(styles)(NetPyNECellRule) \ No newline at end of file diff --git a/webapp/components/definition/cellRules/NetPyNECellRules.js b/webapp/components/definition/cellRules/NetPyNECellRules.js new file mode 100644 index 00000000..0f126281 --- /dev/null +++ b/webapp/components/definition/cellRules/NetPyNECellRules.js @@ -0,0 +1,786 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import ContentAdd from '@material-ui/icons/Add'; +import NavigationMoreHoriz from '@material-ui/icons/MoreHoriz'; +import Fab from '@material-ui/core/Fab'; +import Box from '@material-ui/core/Box'; + +import { + NetPyNECellRule, + NetPyNEThumbnail, + GridLayout, + Filter, + NetPyNESection, + SelectCellTemplate +} from 'netpyne/components'; + +import NetPyNEMechanism from './sections/mechanisms/NetPyNEMechanism'; +import NetPyNENewMechanism from './sections/mechanisms/NetPyNENewMechanism'; + + +import Dialog from '@material-ui/core/Dialog/Dialog'; + +import Utils from '../../../Utils'; +import NetPyNEHome from '../../general/NetPyNEHome'; + +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; + +import RulePath from '../../general/RulePath' +import Accordion from '../../general/ExpansionPanel' +import Divider from '@material-ui/core/Divider'; +import Tooltip from '../../general/Tooltip'; + + +import { ArrowRightIcon } from '../../general/NetPyNEIcons'; + +const styles = ({ spacing }) => ({ + arrowRight : { marginLeft: spacing(1) }, + addCellRule: { marginLeft: spacing(1) }, + sections: { marginLeft: spacing(1) } +}) + +export default class NetPyNECellRules extends React.Component { + + constructor (props) { + super(props); + this.state = { + drawerOpen: false, + selectedCellRule: undefined, + selectedSection: undefined, + selectedMechanism: undefined, + deletedCellRule: undefined, + deletedSection: undefined, + errorMessage: undefined, + errorDetails: undefined, + page: "main", + filterValue: null, + anchorEl: null + }; + + this.selectPage = this.selectPage.bind(this); + + this.selectCellRule = this.selectCellRule.bind(this); + this.handleNewCellRule = this.handleNewCellRule.bind(this); + + this.selectSection = this.selectSection.bind(this); + this.handleNewSection = this.handleNewSection.bind(this); + this.deleteSection = this.deleteSection.bind(this); + + this.selectMechanism = this.selectMechanism.bind(this); + this.handleNewMechanism = this.handleNewMechanism.bind(this); + this.deleteMechanism = this.deleteMechanism.bind(this); + + this.handleRenameChildren = this.handleRenameChildren.bind(this); + this.handleRenameSections = this.handleRenameSections.bind(this); + } + + selectPage (page, state) { + this.setState({ page: page, ...state }); + } + + selectCellRule (cellRule) { + this.setState({ selectedCellRule: cellRule, selectedSection: undefined, selectedMechanism: undefined }); + } + + handleNewCellRule (defaultCellRules) { + var key = Object.keys(defaultCellRules)[0]; + var value = defaultCellRules[key]; + var model = { ...this.state.value }; + + // Get New Available ID + var cellRuleId = Utils.getAvailableKey(model, key); + var newCellRule = Object.assign({ name: cellRuleId }, value); + // Create Cell Rule Client side + Utils.execPythonMessage('netpyne_geppetto.netParams.cellParams["' + cellRuleId + '"] = ' + JSON.stringify(value)); + model[cellRuleId] = newCellRule; + // Update state + this.setState({ + value: model, + selectedCellRule: cellRuleId, + selectedSection: undefined, + selectedMechanism: undefined + }, this.props.updateCards()); + } + + selectSection (section) { + this.setState({ selectedSection: section, selectedMechanism: undefined }); + } + + handleNewSection (defaultSectionValues) { + let key = Object.keys(defaultSectionValues)[0]; + let value = defaultSectionValues[key]; + const { selectedCellRule } = this.state; + const model = {} + Object.keys(this.state.value).forEach(cellRuleName => { + const { secs, ...others } = this.state.value[cellRuleName] + model[cellRuleName] = { ...others, secs: { ...secs } } + }) + // Get New Available ID + var sectionId = Utils.getAvailableKey(model[selectedCellRule]['secs'], key); + var newSection = Object.assign({ name: sectionId }, value); + if (model[selectedCellRule]['secs'] == undefined) { + model[selectedCellRule]['secs'] = {}; + Utils.execPythonMessage('netpyne_geppetto.netParams.cellParams["' + selectedCellRule + '"]["secs"] = {}'); + } + Utils.execPythonMessage('netpyne_geppetto.netParams.cellParams["' + selectedCellRule + '"]["secs"]["' + sectionId + '"] = ' + JSON.stringify(value)); + model[selectedCellRule]["secs"][sectionId] = newSection; + // Update state + this.setState({ + value: model, + selectedSection: sectionId, + selectedMechanism: undefined + }); + + // Move to section page if not already there + if (this.state.page !== 'sections') { + this.setState({ page: 'sections' }) + } + } + + selectMechanism (mechanism) { + this.setState({ selectedMechanism: mechanism }); + } + + handleNewMechanism (mechanism) { + const { selectedCellRule, selectedSection } = this.state; + const model = {} + Object.keys(this.state.value).forEach(cellRuleName => { + const { secs, ...cellOthers } = this.state.value[cellRuleName] + const sections = {} + Object.keys(secs).forEach(sectionName => { + const { mechs, ...secOthers } = this.state.value[cellRuleName].secs[sectionName] + sections[sectionName] = { ...secOthers, mechs: { ...mechs } } + }) + model[cellRuleName] = { ...cellOthers, secs: { ...sections } } + }) + + // Create Mechanism Client side + if (model[selectedCellRule].secs[selectedSection]['mechs'] == undefined) { + model[selectedCellRule].secs[selectedSection]['mechs'] = {}; + Utils.execPythonMessage('netpyne_geppetto.netParams.cellParams["' + selectedCellRule + '"]["secs"]["' + selectedSection + '"]["mechs"] = {}'); + } + Utils + .evalPythonMessage("netpyne_geppetto.getMechParams", [mechanism]) + .then(response => { + const params = {}; + response.forEach(param => params[param] = 0); + Utils.execPythonMessage('netpyne_geppetto.netParams.cellParams["' + selectedCellRule + '"]["secs"]["' + selectedSection + '"]["mechs"]["' + mechanism + '"] = ' + JSON.stringify(params)); + }) + this.setState({ + value: model, + selectedMechanism: mechanism + }); + } + + hasSelectedCellRuleBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = currentState.value; + // deal with rename + if (currentModel != undefined && model != undefined) { + var oldP = Object.keys(currentModel); + var newP = Object.keys(model); + if (oldP.length == newP.length) { + // if it's the same lenght there could be a rename + for (var i = 0; i < oldP.length; i++) { + if (oldP[i] != newP[i]) { + if (prevState.selectedCellRule != undefined) { + if (oldP[i] == prevState.selectedCellRule) { + return newP[i]; + } + } + } + } + } + } + return undefined; + } + + hasSelectedSectionBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = this.state.value; + var currentCellRule = undefined; + var newCellRule = undefined; + + if (prevState.value != undefined && prevState.value != undefined) { + currentCellRule = prevState.value[currentState.selectedCellRule]; + newCellRule = currentState.value[currentState.selectedCellRule]; + } + + if (currentModel != undefined && model != undefined && prevState.selectedCellRule != undefined && currentCellRule != undefined && newCellRule != undefined) { + // loop sections + var oldS = Object.keys(currentCellRule.secs); + var newS = Object.keys(newCellRule.secs); + if (oldS.length == newS.length) { + for (var i = 0; i < oldS.length; i++) { + if (oldS[i] != newS[i]) { + if (prevState.selectedSection != undefined) { + if (oldS[i] == prevState.selectedSection) { + return newS[i]; + } + } + } + } + } + } + return undefined; + } + + hasSelectedMechanismBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = this.state.value; + var currentCellRule = undefined; + var newCellRule = undefined; + if (prevState.value != undefined && prevState.value != undefined) { + currentCellRule = prevState.value[currentState.selectedCellRule]; + newCellRule = currentState.value[currentState.selectedCellRule]; + } + var currentSection = undefined; + var newSection = undefined; + if (currentCellRule != undefined && newCellRule != undefined) { + currentSection = currentCellRule.secs[currentState.selectedSection]; + newSection = newCellRule.secs[currentState.selectedSection]; + } + if (currentModel != undefined && model != undefined && prevState.selectedSection != undefined && currentSection != undefined && newSection != undefined) { + // loop mechanisms + var oldM = Object.keys(currentSection.mechs); + var newM = Object.keys(newSection.mechs); + if (oldM.length == newM.length) { + for (var i = 0; i < oldM.length; i++) { + if (oldM[i] != newM[i]) { + if (prevState.selectedMechanism != undefined) { + if (oldM[i] == prevState.selectedMechanism) { + return newM[i]; + } + } + } + } + } + } + return undefined; + } + + componentDidUpdate (prevProps, prevState) { + // we need to check if any of the three entities have been renamed and if that's the case change the state for the selection variable + var newCellRuleName = this.hasSelectedCellRuleBeenRenamed(prevState, this.state); + if (newCellRuleName !== undefined) { + this.setState({ selectedCellRule: newCellRuleName, deletedCellRule: undefined }); + } else if ((prevState.value !== undefined) && (Object.keys(prevState.value).length !== Object.keys(this.state.value).length)) { + /* + * logic into this if to check if the user added a new object from the python backend and + * if the name convention pass the checks, differently rename this and open dialog to inform. + */ + var model = this.state.value; + for (var m in model) { + if ((prevState.value !== "") && (!(m in prevState.value))) { + var newValue = Utils.nameValidation(m); + if (newValue != m) { + newValue = Utils.getAvailableKey(model, newValue); + model[newValue] = model[m]; + delete model[m]; + this.setState({ + value: model, + errorMessage: "Error", + errorDetails: "Leading digits or whitespaces are not allowed in CellRule names.\n" + + m + " has been renamed " + newValue + }, + function () { + Utils.renameKey('netParams.cellParams', m, newValue, (response, newValue) => {}); + }.bind(this)); + } + } + } + } + var newSectionName = this.hasSelectedSectionBeenRenamed(prevState, this.state); + if (newSectionName !== undefined) { + this.setState({ selectedSection: newSectionName, deletedSection: undefined }); + } else if ((prevState.value !== undefined)) { + /* + * logic into this if to check if the user added a new object from the python backend and + * if the name convention pass the checks, differently rename this and open dialog to inform. + */ + var model2 = this.state.value; + var prevModel = prevState.value; + for (var n in model2) { + if ((prevModel[n] !== undefined) && (Object.keys(model2[n]['secs']).length !== Object.keys(prevModel[n]['secs']).length)) { + var cellRule = model2[n]['secs']; + for (var s in cellRule) { + if (!(s in prevState.value[n]['secs'])) { + var newValue2 = Utils.nameValidation(s); + if (newValue2 != s) { + newValue2 = Utils.getAvailableKey(model2[n]['secs'], newValue2); + model2[n]['secs'][newValue2] = model2[n]['secs'][s]; + delete model2[n]['secs'][s]; + this.setState({ + value: model2, + errorMessage: "Error", + errorDetails: "Leading digits or whitespaces are not allowed in Population names.\n" + + s + " has been renamed " + newValue2 + }, + () => Utils.renameKey('netParams.cellParams["' + n + '"]["secs"]', s, newValue2, (response, newValue) => {})); + } + } + } + } + } + } + var newMechanismName = this.hasSelectedMechanismBeenRenamed(prevState, this.state); + if (newMechanismName !== undefined) { + this.setState({ selectedMechanism: newMechanismName }); + } + + if (this.state.value && Object.keys(this.state.value).length === 0 && (prevState.value && Object.keys(prevState.value).length !== 0)) { + this.setState({ + selectedCellRule: undefined, + selectedSection: undefined, + selectedMechanism: undefined, + page: 'main' + }) + } + } + + handleHierarchyClick = (nextPage, event) => { + const { value: model, page, selectedCellRule, selectedSection, selectedMechanism } = this.state; + /* + * with this herarchy navigation, the tree buttons in the breadclumb can behave in 2 different ways + * they can move the view to a different level (cellRule -> section) (seccions --> mechanisms) + * or they can add a new cellRule ( or section or mechanims) + * here we chech if we want to jump to a different level or if we want to create a new rule in the current level + */ + if (nextPage === page) { + if (page === "main") { + event.preventDefault(); + this.setState({ anchorEl: event.currentTarget, }); + // this.handleNewCellRule({ 'CellType': { 'conds':{}, 'secs':{} } }); + } else if (page === "sections") { + this.handleNewSection({ 'Section': { 'geom': {}, 'topol': {}, 'mechs': {} } }); + } + } else { + const selection = {} + if (nextPage === 'sections' && !selectedSection) { + if (Object.keys(model[selectedCellRule]['secs']).length > 0) { + selection.selectedSection = Object.keys(model[selectedCellRule]['secs'])[0] + } + } + if (nextPage === 'mechanisms' && !selectedMechanism) { + if (Object.keys(model[selectedCellRule]['secs'][selectedSection]['mechs']).length > 0) { + selection.selectedMechanism = Object.keys(model[selectedCellRule]['secs'][selectedSection]['mechs'])[0] + } + } + this.setState({ page: nextPage, filterValue: null, ...selection }); + if (nextPage == 'sections') { // saves one click if there are no sections + if (Object.keys(model[selectedCellRule]['secs']).length == 0) { + this.handleNewSection({ 'Section': { 'geom': {}, 'topol': {}, 'mechs': {} } }); + } + } + } + } + shouldComponentUpdate (nextProps, nextState) { + var itemRenamed = this.hasSelectedCellRuleBeenRenamed(this.state, nextState) !== undefined || this.hasSelectedSectionBeenRenamed(this.state, nextState) !== undefined || this.hasSelectedMechanismBeenRenamed(this.state, nextState) !== undefined; + var newItemCreated = false; + var selectionChanged = this.state.selectedCellRule != nextState.selectedCellRule || this.state.selectedSection != nextState.selectedSection || this.state.selectedMechanism != nextState.selectedMechanism; + var pageChanged = this.state.page != nextState.page; + var newModel = this.state.value == undefined; + if (!newModel) { + newItemCreated = ((Object.keys(this.state.value).length != Object.keys(nextState.value).length)); + if (this.state.selectedCellRule != undefined && nextState.value[this.state.selectedCellRule] != undefined) { + var oldLength = this.state.value[this.state.selectedCellRule] == undefined ? 0 : Object.keys(this.state.value[this.state.selectedCellRule].secs).length; + newItemCreated = ((newItemCreated || oldLength != Object.keys(nextState.value[this.state.selectedCellRule].secs).length)); + } + if ( + this.state.selectedSection != undefined + && this.state.value[this.state.selectedCellRule] + && nextState.value[this.state.selectedCellRule] != undefined + && nextState.value[this.state.selectedCellRule].secs[this.state.selectedSection] != undefined + ) { + var oldLength = this.state.value[this.state.selectedCellRule].secs[this.state.selectedSection] == undefined + ? 0 + : Object.keys(this.state.value[this.state.selectedCellRule].secs[this.state.selectedSection].mechs).length; + newItemCreated = (newItemCreated || oldLength != Object.keys(nextState.value[this.state.selectedCellRule].secs[this.state.selectedSection].mechs).length); + } + } + var errorDialogOpen = (this.state.errorDetails !== nextState.errorDetails); + var filterChanged = nextState.filterPopValue !== this.state.filterValue + return filterChanged || newModel || newItemCreated || itemRenamed || selectionChanged || pageChanged || errorDialogOpen; + } + + deleteMechanism (name) { + if (this.state.selectedCellRule != undefined && this.state.selectedSection != undefined) { + Utils.evalPythonMessage('netpyne_geppetto.deleteParam', [[this.state.selectedCellRule, this.state.selectedSection], name]).then(response => { + var model = this.state.value; + delete model[this.state.selectedCellRule].secs[this.state.selectedSection]['mechs'][name]; + this.setState({ value: model, selectedMechanism: undefined }); + }); + } + } + + deleteSection (name) { + if (this.state.selectedCellRule != undefined) { + Utils.evalPythonMessage('netpyne_geppetto.deleteParam', [[this.state.selectedCellRule], name]).then(response => { + var model = this.state.value; + delete model[this.state.selectedCellRule]['secs'][name]; + this.setState({ value: model, selectedSection: undefined, deletedSection: name }); + }); + } + } + + handleRenameChildren (childName) { + childName = childName.replace(/\s*$/,""); + var childrenList = Object.keys(this.state.value); + for (var i = 0 ; childrenList.length > i ; i++) { + if (childName === childrenList[i]) { + return false; + } + } + return true; + } + + handleRenameSections (childName, leaf) { + childName = childName.replace(/\s*$/,""); + var childrenList = Object.keys(this.state.value[leaf]['secs']); + for (var i = 0 ; childrenList.length > i ; i++) { + if (childName === childrenList[i]) { + return false; + } + } + return true; + } + + createTooltip (rule) { + const { value: model, page, selectedCellRule, selectedSection } = this.state; + + switch (rule) { + case 'cellRule': + if (page !== 'main') { + if (selectedCellRule && selectedCellRule.length > 8 ) { + return selectedCellRule + } else { + return 'Go back to cell type' + } + } else { + return 'Create new cell type' + } + + case 'section': + if (page === 'mechanisms') { + if (!!selectedSection && selectedSection.length > 9 ) { + return selectedSection + } else { + return 'Go back to section' + } + } else { + if (page == "sections") { + return 'Create new section' + } else { + if (selectedCellRule){ + if (!!model && !!model[selectedCellRule] && Object.keys(model[selectedCellRule]['secs']).length > 0) { + return "Explore sections" + } else { + return "Create first section" + } + } else { + return "No cell type selected" + } + } + } + } + } + + createLabel (rule){ + const { value: model, page, selectedCellRule, selectedSection } = this.state; + switch (rule) { + case 'cellRule': + if (page !== 'main'){ + return 'CT' + } else { + return + } + + case 'sections': + if ( page === 'mechanisms' ) { + return 'S' + } else { + if (page == "sections" ) { + return + } else { + if (selectedCellRule) { + if (!!model && !!model[selectedCellRule] && Object.keys(model[selectedCellRule]['secs']).length > 0){ + return + } else { + return + } + } else { + return '' + } + } + } + } + } + + getFilterOptions () { + const { value: model, page, selectedCellRule, selectedSection } = this.state + if (model === undefined) { + return [] + } + if (page === 'main') { + return Object.keys(model) + } + if (model[selectedCellRule] === undefined) { + return [] + } + if (page === 'sections') { + return Object.keys(model[selectedCellRule].secs) + } + if (model[selectedCellRule].secs[selectedSection] === undefined){ + return [] + } + if (page === 'mechanisms') { + return Object.keys(model[selectedCellRule].secs[selectedSection].mechs) + } + return [] + } + + getCopyPath () { + const basePath = "netParams.cellParams" + const { value:model } = this.state + const { selectedCellRule, selectedSection, selectedMechanism } = this.state + if (!model) { + return 'undefined' + } + switch (this.state.page) { + case "main": { + if (model[selectedCellRule]) { + return `${basePath}["${selectedCellRule}"]` + } + break + } + case "sections": { + if (model[selectedCellRule].secs[selectedSection]) { + return `${basePath}["${selectedCellRule}"].secs["${selectedSection}"]` + } + break + } + case "mechanisms":{ + if (model[selectedCellRule].secs[selectedSection].mechs[selectedMechanism]) { + return `${basePath}["${selectedCellRule}"].secs["${selectedSection}"].mechs["${selectedMechanism}"]` + } + break + } + default: { + } + } + return "undefined" + } + + callbackForNewCellTypeCreated (newCellTypeName) { + this.props.updateCards() + this.setState({ anchorEl: null }) + } + + render () { + + const { value: model, page, selectedCellRule, selectedSection, selectedMechanism, errorMessage, errorDetails } = this.state; + let selection = null; + let container = null; + + const dialogPop = (errorMessage != undefined + ? + {errorMessage} + + + {errorDetails} + + + + + + + : undefined + ); + + if (page == 'main') { + if ( selectedCellRule !== undefined && model && Object.keys(model).indexOf(selectedCellRule) > -1) { + selection = ( + this.handleNewSection({ 'Section': { 'geom': {}, 'topol': {}, 'mechs': {} } })} + /> + ) + } + if (model != undefined) { + const filterName = this.state.filterValue === null ? '' : this.state.filterValue + container = Object.keys(model) + .filter(cellRuleName => cellRuleName.toLowerCase().includes(filterName.toLowerCase())) + .map(cellRuleName => ( + + )); + } + } else if (page == "sections" && Object.keys(model).length > 0 && model[selectedCellRule]) { + const sectionsModel = model[selectedCellRule].secs; + + + if ( selectedSection !== undefined && Object.keys(sectionsModel).indexOf(selectedSection) > -1 ) { + selection = ( + + ) + } + + const filterName = this.state.filterValue === null ? '' : this.state.filterValue + container = Object.keys(sectionsModel) + .filter(sectionName => sectionName.toLowerCase().includes(filterName.toLowerCase())) + .map( sectionName => + this.setState({ selectedSection: undefined })} + />) + + } else if (page == "mechanisms" && Object.keys(model).length > 0 && model[selectedCellRule] && model[selectedCellRule].secs[selectedSection]) { + const mechanismsModel = model[selectedCellRule].secs[selectedSection].mechs; + if ((selectedMechanism !== undefined) && Object.keys(mechanismsModel).indexOf(selectedMechanism) > -1) { + selection = ( + + ) + } + + const filterName = this.state.filterValue === null ? '' : this.state.filterValue + container = Object.keys(mechanismsModel) + .filter(mechName => mechName.toLowerCase().includes(filterName.toLowerCase())) + .map( mechName => + + ) + } + + return ( + + +
+ +
+
+ this.setState({ page: 'main', selectedCellRule: undefined, selectedSection: undefined, selectedMechanism: undefined })} + /> +
H
+
+ + this.setState({ anchorEl: null })} + handleButtonClick={event => this.handleHierarchyClick('main', event)} + callback={cellTypeName => this.callbackForNewCellTypeCreated(cellTypeName)} + + /> + +
+ +
S
+
+ + +
+ this.handleHierarchyClick('sections') } + > + {this.createLabel('sections')} + +
Section
+
+ +
+ + +
+ +
S
+
+ +
+ this.handleHierarchyClick('mechanisms')} + blockButton={page != 'mechanisms' && !!model && !!model[selectedCellRule] && !!model[selectedCellRule]['secs'][selectedSection] && Object.keys(model[selectedCellRule]['secs'][selectedSection]['mechs']).length > 0} + /> +
Mech
+
+ +
+ + + + + this.setState({ filterValue: newValue })} + options={this.getFilterOptions()} + /> + +
+
+ + + { container } + { selection } + { dialogPop } +
+ ); + } +} \ No newline at end of file diff --git a/webapp/components/definition/cellRules/SelectCellTemplate.js b/webapp/components/definition/cellRules/SelectCellTemplate.js new file mode 100644 index 00000000..59ce8061 --- /dev/null +++ b/webapp/components/definition/cellRules/SelectCellTemplate.js @@ -0,0 +1,105 @@ +import React, { Component } from 'react'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; + +import Fab from '@material-ui/core/Fab'; +import Tooltip from '../../general/Tooltip' +import Utils from '../../../Utils' + +export default class NetPyNENewPlot extends React.Component { + + constructor (props) { + super(props); + this.handleClick = this.handleSelection.bind(this); + this.handleButtonClick = this.handleButtonClick.bind(this); + this.state = { anchorEl: null, }; + } + + handleButtonClick = event => { + // This prevents ghost click. + event.preventDefault(); + this.setState({ anchorEl: event.currentTarget, }); + }; + + handleSelection (cellTemplateName) { + var cellRuleId = Utils.getAvailableKey(this.props.model, "CellType"); + Utils.evalPythonMessage('netpyne_geppetto.create_celltype_from_template', [cellRuleId, {}, cellTemplateName]) + .then(response => { + this.props.callback() + }) + } + + handleOpenTopbarDialog () { + var cellRuleId = Utils.getAvailableKey(this.props.model, "CellType"); + this.props.openTopbarDialog(cellRuleId) + this.props.callback() + } + + render () { + const { page, label, tooltip, handleButtonClick, anchorEl, clearAnchorEl } = this.props + + return ( +
+ +
+ handleButtonClick(event)} + > + {label} + +
Cell
+
+ +
+ + clearAnchorEl()} + > + this.handleSelection("Empty")} + > + Empty cell + + + this.handleSelection("Simple_HH")} + > + Basic HH cell + + + this.handleSelection("BallStick_HH")} + > + Ball and stick HH cell + + + + this.handleOpenTopbarDialog()} + > + Import cell template from file ... + + + +
+ ) + } +} diff --git a/webapp/components/definition/cellRules/sections/NetPyNESection.js b/webapp/components/definition/cellRules/sections/NetPyNESection.js new file mode 100644 index 00000000..0a89ca0f --- /dev/null +++ b/webapp/components/definition/cellRules/sections/NetPyNESection.js @@ -0,0 +1,178 @@ +import React from 'react'; +import MenuItem from '@material-ui/core/MenuItem'; +import TextField from '@material-ui/core/TextField'; +import FontIcon from '@material-ui/core/Icon'; +import BottomNavigation from '@material-ui/core/BottomNavigation'; +import BottomNavigationAction from '@material-ui/core/BottomNavigationAction'; +import Paper from '@material-ui/core/Paper' +import Utils from '../../../../Utils'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; + + +import { + NetPyNEField, + NetPyNETextField, + NetPyNESelectField, + ListComponent +} from 'netpyne/components'; + + +export default class NetPyNESection extends React.Component { + + constructor (props) { + super(props); + + this.state = { + currentName: props.name, + selectedIndex: 0, + sectionId: "General", + errorMessage: undefined, + errorDetails: undefined + }; + this.setPage = this.setPage.bind(this); + this.postProcessMenuItems = this.postProcessMenuItems.bind(this); + } + + setPage (page) { + this.setState({ page: page }); + } + + select = (index, sectionId) => this.setState({ selectedIndex: index, sectionId: sectionId }); + + handleRenameChange = event => { + var storedValue = this.props.name; + var newValue = Utils.nameValidation(event.target.value); + var updateCondition = this.props.renameHandler(newValue, this.props.cellRule); + var triggerCondition = Utils.handleUpdate(updateCondition, newValue, event.target.value, this, "Section"); + + if (triggerCondition) { + this.triggerUpdate(() => { + // Rename the population in Python + Utils.renameKey("netParams.cellParams['" + this.props.cellRule + "']['secs']", storedValue, newValue, (response, newValue) => { }); + }); + } + } + + triggerUpdate (updateMethod) { + // common strategy when triggering processing of a value change, delay it, every time there is a change we reset + if (this.updateTimer != undefined) { + clearTimeout(this.updateTimer); + } + this.updateTimer = setTimeout(updateMethod, 500); + } + + getBottomNavigationAction (index, sectionId, label, icon, id) { + + return )} + onClick={() => this.select(index, sectionId)} + /> + } + UNSAFE_componentWillReceiveProps (nextProps) { + this.setState({ currentName: nextProps.name }); + } + + postProcessMenuItems (pythonData, selected) { + if (pythonData[this.props.cellRule] != undefined) { + return pythonData[this.props.cellRule].map(name => ( + + {name} + + )); + } + } + + render () { + var content =
; + var that = this; + if (this.state.sectionId == "General") { + content = ( +
+ +
+ ) + } else if (this.state.sectionId == "Geometry") { + + content = (
+ + + + + + + + + + + + + + + + + + + + +
) + } else if (this.state.sectionId == "Topology") { + content = (
+ + + + + + + + + + + +
) + } + + + // Generate Menu + var index = 0; + var bottomNavigationItems = []; + bottomNavigationItems.push(this.getBottomNavigationAction(index++, 'General', 'General', 'fa-bars', 'sectionGeneralTab')); + bottomNavigationItems.push(this.getBottomNavigationAction(index++, 'Geometry', 'Geometry', 'fa-cube', 'sectionGeomTab')); + bottomNavigationItems.push(this.getBottomNavigationAction(index++, 'Topology', 'Topology', 'fa-tree', 'sectionTopoTab')); + + return ( +
+ + {bottomNavigationItems} + + {content} +
+ ); + } +} diff --git a/webapp/components/definition/cellRules/sections/mechanisms/NetPyNEMechanism.js b/webapp/components/definition/cellRules/sections/mechanisms/NetPyNEMechanism.js new file mode 100644 index 00000000..f251d64a --- /dev/null +++ b/webapp/components/definition/cellRules/sections/mechanisms/NetPyNEMechanism.js @@ -0,0 +1,75 @@ +import React from 'react'; +import TextField from '@material-ui/core/TextField'; +import Utils from '../../../../../Utils'; +import Box from '@material-ui/core/Box' +import { NetPyNETextField } from 'netpyne/components'; + +export default class NetPyNEMechanism extends React.Component { + + constructor (props) { + super(props); + this.state = { + currentName: props.name, + mechFields: '' + }; + } + + UNSAFE_componentWillReceiveProps (nextProps) { + this.setState({ currentName: nextProps.name }); + } + + renderMechFields = () => { + if (this.state.mechFields == '') { + return
+ } + + const { currentName } = this.state + const { cellRule, section, } = this.props + let tag = `netParams.cellParams['${cellRule}']['secs']['${section}']['mechs']['${currentName}']` + + return this.state.mechFields.map((name, i) => ( + + + + + )) + + }; + + render () { + var content = [] + if (this.state.currentName != undefined && this.state.currentName != '') { + Utils + .evalPythonMessage("netpyne_geppetto.getMechParams", [this.state.currentName]) + .then(response => { + if (JSON.stringify(this.state.mechFields) != JSON.stringify(response)) { + this.setState({ mechFields: response }) + } + }) + content.push(this.renderMechFields()) + } + + return ( +
+ + + + + {content} +
+ ); + } +} diff --git a/webapp/components/definition/cellRules/sections/mechanisms/NetPyNENewMechanism.js b/webapp/components/definition/cellRules/sections/mechanisms/NetPyNENewMechanism.js new file mode 100644 index 00000000..5be18744 --- /dev/null +++ b/webapp/components/definition/cellRules/sections/mechanisms/NetPyNENewMechanism.js @@ -0,0 +1,132 @@ +import React from 'react'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import NavigationMoreHoriz from '@material-ui/icons/MoreHoriz'; +import { withStyles } from '@material-ui/core/styles' +import Utils from '../../../../../Utils'; +import ContentAdd from '@material-ui/icons/Add' +import { MechIcon } from '../../../../general/NetPyNEIcons' +import Tooltip from '../../../../general/Tooltip' +const fontSize = 40 +const styles = ({ spacing, palette }) => ({ + icon : { color: palette.primary.main, cursor: 'pointer' }, + disabledIcon : { color: '#d1d1d1', cursor: 'auto' }, + iconContent: { position: 'absolute', color: 'white' }, + cogIconContent: { + width: fontSize, + height: fontSize, + position: 'absolute', + display: 'flex', + alignItems: 'center', + justifyContent: 'center' + }, + container: { + position: 'relative', + width: fontSize - 2, + height: fontSize - 2 + }, + cogIcon: { width: fontSize, height:fontSize, position: 'absolute' } + +}) + +class NetPyNENewMechanism extends React.Component { + + constructor (props) { + super(props); + this.state = { + open: false, + mechanisms: [] + }; + } + + componentDidMount () { + Utils.evalPythonMessage("netpyne_geppetto.getAvailableMechs", []) + .then(response => { + this.setState({ mechanisms: response }) + }) + } + + handleClick = event => { + this.setState({ open: false }); + this.props.handleClick(event.target.innerText); + }; + + handleButtonClick = anchor => { + const { blockButton, handleHierarchyClick } = this.props; + if (!blockButton) { + this.setState({ open: true, anchorEl: anchor }) + } + handleHierarchyClick(); + }; + + createTooltip (){ + const { disabled, blockButton } = this.props; + if (disabled) { + return "" + } else { + if (blockButton) { + return "Explore mechanisms" + } else { + return "Create new mechanism" + } + } + } + + createLabel (classes){ + const { disabled, blockButton } = this.props; + if (disabled) { + return "" + } else { + if (blockButton) { + return + } else { + return + } + } + } + render () { + const { disabled, classes, className } = this.props; + const { open, anchorEl, mechanisms } = this.state; + const tooltip = disabled ? '' : this.createTooltip() + return ( +
+ +
!disabled && this.handleButtonClick(e.currentTarget) } + > +
+
+ + + {this.createLabel(classes)} + +
+
+
+
+ + + this.setState({ open: false }) } + > + {mechanisms.map( mechLabel => + this.handleClick(event) } + > + {mechLabel} + + )} + +
+ ) + } +} + +export default withStyles(styles)(NetPyNENewMechanism) \ No newline at end of file diff --git a/webapp/components/definition/configuration/NetPyNESimConfig.js b/webapp/components/definition/configuration/NetPyNESimConfig.js new file mode 100644 index 00000000..f18b915a --- /dev/null +++ b/webapp/components/definition/configuration/NetPyNESimConfig.js @@ -0,0 +1,316 @@ +import React, { Component } from 'react'; +import FontIcon from '@material-ui/core/Icon'; +import { BottomNavigation, BottomNavigationAction } from '@material-ui/core'; +import { withStyles } from '@material-ui/core/styles' +import Paper from '@material-ui/core/Paper' +import { bgDark } from '../../../theme' +import { + NetPyNEField, + NetPyNECheckbox, + NetPyNETextField, + SelectField, + ListComponent, + GridLayout +} from 'netpyne/components'; + +class NetPyNESimConfig extends React.Component { + + constructor (props) { + super(props); + this.state = { + model: props.model, + selectedIndex: 0, + sectionId: "General" + }; + } + + UNSAFE_componentWillReceiveProps (nextProps) { + this.setState({ model: nextProps.model }); + } + + select = (index, sectionId) => this.setState({ selectedIndex: index, sectionId: sectionId }); + + render () { + var contentLeft =
; + var contentRight =
; + if (this.state.sectionId == 'General') { + contentLeft = ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ) + contentRight = ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ) + + } else if (this.state.sectionId == 'SaveConfiguration') { + contentLeft = ( +
+ + + + + { + !window.isDocker + && + + + } + + + + + + + + + + + + + +
+ ) + contentRight = ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + {/* + + + + + + + + + + + + + + */} + + + + +
+ ) + } else if (this.state.sectionId == 'Record') { + contentLeft = ( +
+ + + + + + + + + + + + + + + + +
+ ) + contentRight = ( +
+ + + + + + + +
+ ) + } else if (this.state.sectionId == 'netParams') { + var contentLeft = ( +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ ) + contentRight = ( +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ ) + } + const { classes } = this.props + return ( +
+ + } onClick={() => this.select(0, 'General')} /> + } onClick={() => this.select(1, 'Record')} /> + } onClick={() => this.select(2, 'SaveConfiguration')} /> + } onClick={() => this.select(3, 'netParams')} /> + + +
+ {contentLeft} + {contentRight} + +
+ + ); + } +} + +const styles = ({ shape, spacing }) => ({ + root: { height: `calc(100% - 56px - ${spacing(1)}px)`, flexDirection: 'column' }, + bottomNav: { margin: spacing(2) }, + layout: { height: "100%", display: 'flex' } + +}) + +export default withStyles(styles)(NetPyNESimConfig) \ No newline at end of file diff --git a/webapp/components/definition/connectivity/NetPyNEConnectivityRule.js b/webapp/components/definition/connectivity/NetPyNEConnectivityRule.js new file mode 100644 index 00000000..1b2f8b87 --- /dev/null +++ b/webapp/components/definition/connectivity/NetPyNEConnectivityRule.js @@ -0,0 +1,406 @@ +import React from "react"; +import TextField from '@material-ui/core/TextField'; +import FontIcon from "@material-ui/core/Icon"; +import { BottomNavigation, BottomNavigationAction } from "@material-ui/core"; +import Dialog from "@material-ui/core/Dialog/Dialog"; +import Button from "@material-ui/core/Button"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import DialogContentText from "@material-ui/core/DialogContentText"; +import DialogTitle from "@material-ui/core/DialogTitle"; +import MenuItem from "@material-ui/core/MenuItem"; +import Paper from '@material-ui/core/Paper' +import Box from '@material-ui/core/Box'; + +import { + NetPyNESelectField, + NetPyNEField, + NetPyNETextField, + ListComponent, + NetPyNECoordsRange +} from "netpyne/components"; +import Utils from "../../../Utils"; + +export default class NetPyNEConnectivityRule extends React.Component { + constructor (props) { + super(props); + this.state = { + currentName: props.name, + selectedIndex: 0, + sectionId: "General", + errorMessage: undefined, + errorDetails: undefined + }; + } + + handleRenameChange = event => { + var storedValue = this.props.name; + var newValue = Utils.nameValidation(event.target.value); + var updateCondition = this.props.renameHandler(newValue); + var triggerCondition = Utils.handleUpdate( + updateCondition, + newValue, + event.target.value, + this, + "ConnectionRule" + ); + + if (triggerCondition) { + this.triggerUpdate(() => { + // Rename the population in Python + Utils.renameKey( + "netParams.connParams", + storedValue, + newValue, + (response, newValue) => { + this.renaming = false; + } + ); + this.renaming = true; + }); + } + }; + + triggerUpdate (updateMethod) { + // common strategy when triggering processing of a value change, delay it, every time there is a change we reset + if (this.updateTimer != undefined) { + clearTimeout(this.updateTimer); + } + this.updateTimer = setTimeout(updateMethod, 1000); + } + + select = (index, sectionId) => + this.setState({ selectedIndex: index, sectionId: sectionId }); + + getBottomNavigationAction (index, sectionId, label, icon, id) { + return ( + } + onClick={() => this.select(index, sectionId)} + /> + ); + } + + postProcessMenuItems (pythonData, selected) { + return pythonData.map(name => ( + -1} + value={name} + > + {name} + + )); + } + + UNSAFE_componentWillReceiveProps (nextProps) { + this.setState({ currentName: nextProps.name }); + } + + render () { + const dialogPop = this.state.errorMessage != undefined ? ( + + + {this.state.errorMessage} + + + + {this.state.errorDetails} + + + + + + + ) : ( + undefined + ); + + if (this.state.sectionId == "General") { + var content = ( +
+ + + + + + + + + + + + + + + + pythonData.map(name => ( + + {name} + + )) + } + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {dialogPop} +
+ ); + } else if (this.state.sectionId == "Pre Conditions") { + var content = ( +
+ + + + + + + + + + + + + + + +
+ ); + } else if (this.state.sectionId == "Post Conditions") { + var content = ( +
+ + + + + + + + + + + + + + + +
+ ); + } + + // Generate Menu + var index = 0; + var bottomNavigationItems = []; + bottomNavigationItems.push( + this.getBottomNavigationAction( + index++, + "General", + "General", + "fa-bars", + "generalConnTab" + ) + ); + bottomNavigationItems.push( + this.getBottomNavigationAction( + index++, + "Pre Conditions", + "Pre-synaptic cells conditions", + "fa-caret-square-o-left", + "preCondsConnTab" + ) + ); + bottomNavigationItems.push( + this.getBottomNavigationAction( + index++, + "Post Conditions", + "Post-synaptic cells conditions", + "fa-caret-square-o-right", + "postCondsConnTab" + ) + ); + + return ( +
+ + {bottomNavigationItems} + + {content} +
+ ); + } + + handleChange = (event, index, values) => this.setState({ values }); +} diff --git a/webapp/components/definition/connectivity/NetPyNEConnectivityRules.js b/webapp/components/definition/connectivity/NetPyNEConnectivityRules.js new file mode 100644 index 00000000..67627911 --- /dev/null +++ b/webapp/components/definition/connectivity/NetPyNEConnectivityRules.js @@ -0,0 +1,252 @@ +import React, { Component } from 'react'; +import Dialog from '@material-ui/core/Dialog/Dialog'; + +import Button from '@material-ui/core/Button'; +import Utils from '../../../Utils'; +import NetPyNEHome from '../../general/NetPyNEHome'; +import NetPyNEAddNew from '../../general/NetPyNEAddNew'; + +import NetPyNEConnectivityRule from './NetPyNEConnectivityRule'; +import { NetPyNEThumbnail, GridLayout, Filter } from 'netpyne/components' + +import RulePath from '../../general/RulePath' +import Accordion from '../../general/ExpansionPanel' +import Divider from '@material-ui/core/Divider'; +export default class NetPyNEConnectivityRules extends Component { + + constructor (props) { + super(props); + this.state = { + drawerOpen: false, + selectedConnectivityRule: undefined, + deletedConnectivityRule: undefined, + page: "main", + errorMessage: undefined, + errorDetails: undefined, + filterValue: null + }; + + this.selectPage = this.selectPage.bind(this); + + this.selectConnectivityRule = this.selectConnectivityRule.bind(this); + this.handleNewConnectivityRule = this.handleNewConnectivityRule.bind(this); + + this.handleRenameChildren = this.handleRenameChildren.bind(this); + } + + handleToggle = () => this.setState({ drawerOpen: !this.state.drawerOpen }); + + + selectPage (page) { + this.setState({ page: page }); + } + + /* Method that handles button click */ + selectConnectivityRule (connectivityRule) { + this.setState({ selectedConnectivityRule: connectivityRule }); + } + + handleNewConnectivityRule () { + var defaultConnectivityRules = { + 'ConnectivityRule': { + 'preConds': {}, + 'postConds': {} + } + }; + // Get Key and Value + var key = Object.keys(defaultConnectivityRules)[0]; + var value = defaultConnectivityRules[key]; + const model = { ...this.state.value } + + // Get New Available ID + var connectivityRuleId = Utils.getAvailableKey(model, key); + var newConnectivityRule = Object.assign({ name: connectivityRuleId }, value); + // Create Cell Rule Client side + Utils.execPythonMessage('netpyne_geppetto.netParams.connParams["' + connectivityRuleId + '"] = ' + JSON.stringify(value)); + model[connectivityRuleId] = newConnectivityRule; + // Update state + this.setState({ + value: model, + selectedConnectivityRule: connectivityRuleId + }); + } + + + hasSelectedConnectivityRuleBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = currentState.value; + // deal with rename + if (currentModel != undefined && model != undefined) { + var oldP = Object.keys(currentModel); + var newP = Object.keys(model); + if (oldP.length == newP.length) { + // if it's the same lenght there could be a rename + for (var i = 0; i < oldP.length; i++) { + if (oldP[i] != newP[i]) { + if (prevState.selectedConnectivityRule != undefined) { + if (oldP[i] == prevState.selectedConnectivityRule) { + return newP[i]; + } + } + } + } + } + } + return undefined; + } + + + componentDidUpdate (prevProps, prevState) { + // we need to check if any of the three entities have been renamed and if that's the case change the state for the selection variable + var newConnectivityRuleName = this.hasSelectedConnectivityRuleBeenRenamed(prevState, this.state); + if (newConnectivityRuleName !== undefined) { + this.setState({ selectedConnectivityRule: newConnectivityRuleName, deletedConnectivityRule: undefined }); + } else if ((prevState.value !== undefined) && (Object.keys(prevState.value).length !== Object.keys(this.state.value).length)) { + /* + * logic into this if to check if the user added a new object from the python backend and + * if the name convention pass the checks, differently rename this and open dialog to inform. + */ + var model = this.state.value; + for (var m in model) { + if ((prevState.value !== "") && (!(m in prevState.value))) { + var newValue = Utils.nameValidation(m); + if (newValue != m) { + newValue = Utils.getAvailableKey(model, newValue); + model[newValue] = model[m]; + delete model[m]; + this.setState({ + value: model, + errorMessage: "Error", + errorDetails: "Leading digits or whitespaces are not allowed in ConnectivityRule names.\n" + + m + " has been renamed " + newValue + }, + function () { + Utils.renameKey('netParams.connParams', m, newValue, (response, newValue) => {}); + }.bind(this)); + } + } + } + } + } + + shouldComponentUpdate (nextProps, nextState) { + var itemRenamed = this.hasSelectedConnectivityRuleBeenRenamed(this.state, nextState) !== undefined; + var newItemCreated = false; + var selectionChanged = this.state.selectedConnectivityRule != nextState.selectedConnectivityRule; + var pageChanged = this.state.page != nextState.page; + var newModel = this.state.value == undefined; + if (!newModel) { + newItemCreated = ((Object.keys(this.state.value).length != Object.keys(nextState.value).length)); + } + var errorDialogOpen = (this.state.errorDetails !== nextState.errorDetails); + const filterValueChanged = nextState.filterValue !== this.state.filterValue + return filterValueChanged || newModel || newItemCreated || itemRenamed || selectionChanged || pageChanged || errorDialogOpen; + } + + handleRenameChildren (childName) { + childName = childName.replace(/\s*$/,""); + var childrenList = Object.keys(this.state.value); + for (var i = 0 ; childrenList.length > i ; i++) { + if (childName === childrenList[i]) { + return false; + } + } + return true; + } + + getCopyPath (){ + const { value: model, selectedConnectivityRule } = this.state + return model && model[selectedConnectivityRule] && `netParams.connParams["${selectedConnectivityRule}"]` + } + + render () { + var actions = [ + + + + ) + : undefined + if (this.state.sectionId == "General") { + var content = ( +
+ + + + +
+ + + +
+ + {dialogPop} +
+ ) + } else if (this.state.sectionId == "SpatialDistribution") { + var content = ( +
+ + + + + +
+ ) + } else if (this.state.sectionId == "CellList") { + var content =
Option to provide individual list of cells. Coming soon ...
+ } else { + var content =
{this.state.cellModelFields}
; + } + + return ( +
+ + {this.getModelParameters()} + + {content} +
+ ); + } +} + + +export default withStyles(styles)(NetPyNEPopulation) \ No newline at end of file diff --git a/webapp/components/definition/populations/NetPyNEPopulations.js b/webapp/components/definition/populations/NetPyNEPopulations.js new file mode 100644 index 00000000..e2df8e08 --- /dev/null +++ b/webapp/components/definition/populations/NetPyNEPopulations.js @@ -0,0 +1,257 @@ +import React from 'react'; +import Utils from '../../../Utils'; + +import { + NetPyNEHome, + NetPyNEAddNew, + NetPyNEThumbnail, + NetPyNEPopulation, + GridLayout, + Filter +} from 'netpyne/components'; + +import RulePath from '../../general/RulePath' +import Accordion from '../../general/ExpansionPanel' + +import Dialog from '@material-ui/core/Dialog/Dialog'; +import Button from '@material-ui/core/Button'; +import Divider from '@material-ui/core/Divider'; + +export default class NetPyNEPopulations extends React.Component { + + constructor (props) { + super(props); + this.state = { + drawerOpen: false, + selectedPopulation: undefined, + populationDeleted: undefined, + errorMessage: undefined, + errorDetails: undefined, + filterPopValue: null, + }; + + this.handleNewPopulation = this.handleNewPopulation.bind(this); + this.selectPopulation = this.selectPopulation.bind(this); + this.handleRenameChildren = this.handleRenameChildren.bind(this); + } + + handleToggle = () => this.setState({ drawerOpen: !this.state.drawerOpen }); + + + hasSelectedPopulationBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = currentState.value; + // deal with rename + if (currentModel != undefined && model != undefined) { + var oldP = Object.keys(currentModel); + var newP = Object.keys(model); + if (oldP.length == newP.length) { + // if it's the same lenght there could be a rename + for (var i = 0; i < oldP.length; i++) { + if (oldP[i] != newP[i]) { + if (prevState.selectedPopulation != undefined) { + if (oldP[i] == prevState.selectedPopulation) { + return newP[i]; + } + } + } + } + } + } + return undefined; + } + + componentDidUpdate (prevProps, prevState) { + // we need to check if any of the three entities have been renamed and if that's the case change the state for the selection variable + var newPopulationName = this.hasSelectedPopulationBeenRenamed(prevState, this.state); + if (newPopulationName !== undefined) { + this.setState({ + selectedPopulation: newPopulationName, + populationDeleted: undefined + }); + } else if ((prevState.value !== undefined) && (Object.keys(prevState.value).length !== Object.keys(this.state.value).length)) { + /* + * logic into this if to check if the user added a new object from the python backend and + * if the name convention pass the checks, differently rename this and open dialog to inform. + */ + var model = this.state.value; + for (var m in model) { + if ((prevState.value !== "") && (!(m in prevState.value))) { + var newValue = Utils.nameValidation(model[m].name); + if (newValue != model[m].name) { + newValue = Utils.getAvailableKey(model, newValue); + model[newValue] = model[m]; + model[newValue].name = newValue; + delete model[m]; + this.setState({ + value: model, + errorMessage: "Error", + errorDetails: "Leading digits or whitespaces are not allowed in Population names.\n" + + m + " has been renamed " + newValue + }, + () => Utils.renameKey('netParams.popParams', m, newValue, (response, newValue) => { + this.props.updateCards() + })); + } + } + } + } + } + + shouldComponentUpdate (nextProps, nextState) { + var itemRenamed = this.hasSelectedPopulationBeenRenamed(this.state, nextState) !== undefined; + var newItemCreated = false; + var selectionChanged = this.state.selectedPopulation != nextState.selectedPopulation; + var newModel = this.state.value == undefined; + if (!newModel) { + newItemCreated = ((Object.keys(this.state.value).length != Object.keys(nextState.value).length)); + } + // check if the dialog has been triggered due name convention or name collision errors. + var errorDialogOpen = (this.state.errorDetails !== nextState.errorDetails); + var filterChanged = nextState.filterPopValue !== this.state.filterPopValue + return filterChanged || newModel || newItemCreated || itemRenamed || selectionChanged || errorDialogOpen; + } + + handleNewPopulation () { + var defaultPopulationValues = { 'Population': { 'cellModel': '', 'cellType': '' } } + // Get Key and Value + var key = Object.keys(defaultPopulationValues)[0]; + var value = defaultPopulationValues[key]; + var model = { ...this.state.value }; + + // Get New Available ID + var populationId = Utils.getAvailableKey(model, key); + + // Create Population Object + var newPopulation = Object.assign({ name: populationId }, value); + + // Create Population Client side + Utils.execPythonMessage('netpyne_geppetto.netParams.popParams["' + populationId + '"] = ' + JSON.stringify(value)) + + + // Update state + model[populationId] = newPopulation; + this.setState({ + value: model, + selectedPopulation: populationId + }, () => this.props.updateCards()); + + } + + /* Method that handles button click */ + selectPopulation (populationName) { + this.setState({ selectedPopulation: populationName }); + } + + handleRenameChildren (childName) { + childName = childName.replace(/\s*$/,""); + var childrenList = Object.keys(this.state.value); + for (var i = 0 ; childrenList.length > i ; i++) { + if (childName === childrenList[i]) { + return false; + } + } + return true; + } + + getPath () { + const { value: model, selectedPopulation } = this.state + return model && model[selectedPopulation] && `netParams.popParams["${selectedPopulation}"]` + } + + render () { + var actions = [ + + + + ) + : undefined + + if (this.state.sourceType == 'IClamp') { + var variableContent = ( +
+ + + + + + + + + + + + +
+ ); + } else if (this.state.sourceType == 'VClamp') { + var variableContent = ( +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ ); + } else if (this.state.sourceType == 'AlphaSynapse') { + var variableContent = ( +
+ + + + + + + + + + + + + + + + +
+ ); + } else if (this.state.sourceType == 'NetStim') { + var variableContent = ( +
+ + + + + + + + + + + + + + + + + + + +
+ ); + } else if (this.state.sourceType == 'SEClamp') { + var variableContent = ( +
+ + + + + + + + + + + + +
+ ) + } else { + var variableContent =
+ } + + return ( +
+
+ + + + + + + + +
+ {variableContent} + {dialogPop} +
+ ); + } +} + + +export default withStyles(styles)(NetPyNEStimulationSource) \ No newline at end of file diff --git a/webapp/components/definition/stimulationSources/NetPyNEStimulationSources.js b/webapp/components/definition/stimulationSources/NetPyNEStimulationSources.js new file mode 100644 index 00000000..e8df9fd2 --- /dev/null +++ b/webapp/components/definition/stimulationSources/NetPyNEStimulationSources.js @@ -0,0 +1,229 @@ +import React, { Component } from 'react'; + + +import Utils from '../../../Utils'; +import Dialog from '@material-ui/core/Dialog/Dialog'; +import Button from '@material-ui/core/Button'; + +import { + NetPyNEHome, + NetPyNEAddNew, + NetPyNEThumbnail, + NetPyNEStimulationSource, + GridLayout, + Filter +} from 'netpyne/components'; + +import RulePath from '../../general/RulePath' +import Accordion from '../../general/ExpansionPanel' +import Divider from '@material-ui/core/Divider'; + +export default class NetPyNEStimulationSources extends Component { + + constructor (props) { + super(props); + this.state = { + selectedStimulationSource: undefined, + deletedStimulationSource: undefined, + page: "main", + errorMessage: undefined, + errorDetails: undefined, + filterValue: null + }; + this.selectStimulationSource = this.selectStimulationSource.bind(this); + this.handleNewStimulationSource = this.handleNewStimulationSource.bind(this); + + this.handleRenameChildren = this.handleRenameChildren.bind(this); + } + + /* Method that handles button click */ + selectStimulationSource (StimulationSource) { + this.setState({ selectedStimulationSource: StimulationSource }); + } + + handleNewStimulationSource () { + var defaultStimulationSources = { 'stim_source': { 'type': 'IClamp' } }; + var key = Object.keys(defaultStimulationSources)[0]; + var value = defaultStimulationSources[key]; + var model = { ...this.state.value }; + var StimulationSourceId = Utils.getAvailableKey(model, key); + var newStimulationSource = Object.assign({ name: StimulationSourceId }, value); + Utils.execPythonMessage('netpyne_geppetto.netParams.stimSourceParams["' + StimulationSourceId + '"] = ' + JSON.stringify(value)); + model[StimulationSourceId] = newStimulationSource; + this.setState({ + value: model, + selectedStimulationSource: StimulationSourceId + }, () => this.props.updateCards()); + } + + hasSelectedStimulationSourceBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = currentState.value; + // deal with rename + if (currentModel != undefined && model != undefined) { + var oldP = Object.keys(currentModel); + var newP = Object.keys(model); + if (oldP.length == newP.length) { + // if it's the same lenght there could be a rename + for (var i = 0; i < oldP.length; i++) { + if (oldP[i] != newP[i]) { + if (prevState.selectedStimulationSource != undefined) { + if (oldP[i] == prevState.selectedStimulationSource) { + return newP[i]; + } + } + } + } + } + } + return undefined; + } + + componentDidUpdate (prevProps, prevState) { + var newStimulationSourceName = this.hasSelectedStimulationSourceBeenRenamed(prevState, this.state); + if (newStimulationSourceName !== undefined) { + this.setState({ selectedStimulationSource: newStimulationSourceName, deletedStimulationSource: undefined }); + } else if ((prevState.value !== undefined) && (Object.keys(prevState.value).length !== Object.keys(this.state.value).length)) { + /* + * logic into this if to check if the user added a new object from the python backend and + * if the name convention pass the checks, differently rename this and open dialog to inform. + */ + var model = this.state.value; + for (var m in model) { + if ((prevState.value !== "") && (!(m in prevState.value))) { + var newValue = Utils.nameValidation(m); + if (newValue != m) { + newValue = Utils.getAvailableKey(model, newValue); + model[newValue] = model[m]; + delete model[m]; + this.setState({ + value: model, + errorMessage: "Error", + errorDetails: "Leading digits or whitespaces are not allowed in Population names.\n" + + m + " has been renamed " + newValue + }, + () => Utils.renameKey('netParams.stimSourceParams', m, newValue, (response, newValue) => this.props.updateCards())); + } + } + } + } + } + + shouldComponentUpdate (nextProps, nextState) { + var itemRenamed = this.hasSelectedStimulationSourceBeenRenamed(this.state, nextState) !== undefined; + var newItemCreated = false; + var selectionChanged = this.state.selectedStimulationSource != nextState.selectedStimulationSource; + var pageChanged = this.state.page != nextState.page; + var newModel = this.state.value == undefined; + if (!newModel) { + newItemCreated = ((Object.keys(this.state.value).length != Object.keys(nextState.value).length)); + } + var errorDialogOpen = (this.state.errorDetails !== nextState.errorDetails); + const filterValueChanged = nextState.filterValue !== this.state.filterValue + return filterValueChanged || newModel || newItemCreated || itemRenamed || selectionChanged || pageChanged || errorDialogOpen; + } + + handleRenameChildren (childName) { + childName = childName.replace(/\s*$/,""); + var childrenList = Object.keys(this.state.value); + for (var i = 0 ; childrenList.length > i ; i++) { + if (childName === childrenList[i]) { + return false; + } + } + return true; + } + + getPath () { + const { value: model, selectedStimulationSource } = this.state + return model && model[selectedStimulationSource] && `netParams.stimSourceParams["${selectedStimulationSource}"]` + } + + render () { + var actions = [ + + + + ) + : undefined + + if (this.state.sectionId == "General") { + var content = ( +
+ + + + + + + + + + + + + + + +
+ ); + if (this.state.isSourceTypeNetStim) { + var extraContent = ( +
+ + + + + + + + + + + + + + + +
+ ); + } else { + var extraContent =
+ } + } else if (this.state.sectionId == "Conditions") { + var content = + } + + var index = 0; + var bottomNavigationItems = []; + bottomNavigationItems.push(this.getBottomNavigationAction(index++, 'General', 'General', , 'stimTargetGeneralTab')); + bottomNavigationItems.push(this.getBottomNavigationAction(index++, 'Conditions', 'Conditions',, 'stimTargetCondsTab')); + + return ( +
+ + {bottomNavigationItems} + + {content} + {extraContent} + {dialogPop} +
+ ); + } +} diff --git a/webapp/components/definition/stimulationTargets/NetPyNEStimulationTargets.js b/webapp/components/definition/stimulationTargets/NetPyNEStimulationTargets.js new file mode 100644 index 00000000..d69c629f --- /dev/null +++ b/webapp/components/definition/stimulationTargets/NetPyNEStimulationTargets.js @@ -0,0 +1,224 @@ +import React, { Component } from 'react'; + +import Dialog from '@material-ui/core/Dialog/Dialog'; +import Button from '@material-ui/core/Button'; + +import Utils from '../../../Utils'; + +import { + NetPyNEHome, + NetPyNEAddNew, + NetPyNEThumbnail, + NetPyNEStimulationTarget, + GridLayout, + Filter +} from 'netpyne/components'; + +import RulePath from '../../general/RulePath' +import Accordion from '../../general/ExpansionPanel' +import Divider from '@material-ui/core/Divider'; +export default class NetPyNEStimulationTargets extends Component { + + constructor (props) { + super(props); + this.state = { + selectedStimulationTarget: undefined, + deletedStimulationTarget: undefined, + page: "main", + errorMessage: undefined, + errorDetails: undefined, + filterValue: null + }; + this.selectStimulationTarget = this.selectStimulationTarget.bind(this); + this.handleNewStimulationTarget = this.handleNewStimulationTarget.bind(this); + + this.handleRenameChildren = this.handleRenameChildren.bind(this); + } + + /* Method that handles button click */ + selectStimulationTarget (StimulationTarget) { + this.setState({ selectedStimulationTarget: StimulationTarget }); + } + + handleNewStimulationTarget () { + var defaultStimulationTargets = { 'stim_target': { 'source': '', 'conds': {} } }; + var key = Object.keys(defaultStimulationTargets)[0]; + var value = defaultStimulationTargets[key]; + var model = { ...this.state.value }; + var StimulationTargetId = Utils.getAvailableKey(model, key); + var newStimulationTarget = Object.assign({ name: StimulationTargetId }, value); + Utils.execPythonMessage('netpyne_geppetto.netParams.stimTargetParams["' + StimulationTargetId + '"] = ' + JSON.stringify(value)); + model[StimulationTargetId] = newStimulationTarget; + this.setState({ + value: model, + selectedStimulationTarget: StimulationTargetId + }); + } + + hasSelectedStimulationTargetBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = currentState.value; + // deal with rename + if (currentModel != undefined && model != undefined) { + var oldP = Object.keys(currentModel); + var newP = Object.keys(model); + if (oldP.length == newP.length) { + // if it's the same lenght there could be a rename + for (var i = 0; i < oldP.length; i++) { + if (oldP[i] != newP[i]) { + if (prevState.selectedStimulationTarget != undefined) { + if (oldP[i] == prevState.selectedStimulationTarget) { + return newP[i]; + } + } + } + } + } + } + return undefined; + } + + componentDidUpdate (prevProps, prevState) { + var newStimulationTargetName = this.hasSelectedStimulationTargetBeenRenamed(prevState, this.state); + if (newStimulationTargetName !== undefined) { + this.setState({ selectedStimulationTarget: newStimulationTargetName, deletedStimulationTarget: undefined }); + } else if ((prevState.value !== undefined) && (Object.keys(prevState.value).length !== Object.keys(this.state.value).length)) { + /* + * logic into this if to check if the user added a new object from the python backend and + * if the name convention pass the checks, differently rename this and open dialog to inform. + */ + var model = this.state.value; + for (var m in model) { + if ((prevState.value !== "") && (!(m in prevState.value))) { + var newValue = Utils.nameValidation(m); + if (newValue != m) { + newValue = Utils.getAvailableKey(model, newValue); + model[newValue] = model[m]; + delete model[m]; + this.setState({ + value: model, + errorMessage: "Error", + errorDetails: "Leading digits or whitespaces are not allowed in Population names.\n" + + m + " has been renamed " + newValue + }, + () => Utils.renameKey('netParams.stimTargetParams', m, newValue, (response, newValue) => {})); + } + } + } + } + } + + shouldComponentUpdate (nextProps, nextState) { + var itemRenamed = this.hasSelectedStimulationTargetBeenRenamed(this.state, nextState) !== undefined; + var newItemCreated = false; + var selectionChanged = this.state.selectedStimulationTarget != nextState.selectedStimulationTarget; + var pageChanged = this.state.page != nextState.page; + var newModel = this.state.value == undefined; + if (!newModel){ + newItemCreated = ((Object.keys(this.state.value).length != Object.keys(nextState.value).length)); + } + var errorDialogOpen = (this.state.errorDetails !== nextState.errorDetails); + const filterValueChanged = nextState.filterValue !== this.state.filterValue + return filterValueChanged || newModel || newItemCreated || itemRenamed || selectionChanged || pageChanged || errorDialogOpen; + } + + handleRenameChildren (childName) { + childName = childName.replace(/\s*$/,""); + var childrenList = Object.keys(this.state.value); + for (var i = 0 ; childrenList.length > i ; i++) { + if (childName === childrenList[i]) { + return false; + } + } + return true; + } + + getPath () { + const { value: model, selectedStimulationTarget } = this.state + return model && model[selectedStimulationTarget] && `netParams.stimTargetParams["${selectedStimulationTarget}"]` + } + + render () { + var actions = [ + + + + ) + : undefined + + if (this.state.synMechMod == '' || this.state.synMechMod == undefined) { + var content =
+ } else { + var content = ( +
+ + + + + {(this.state.synMechMod == "Exp2Syn") ?
+ + + +
: null} + + + + +
+ ) + } + + return ( +
+ + + + + + + + + {content} + {dialogPop} +
+ ); + } +} + + +export default withStyles(styles)(NetPyNESynapse); \ No newline at end of file diff --git a/webapp/components/definition/synapses/NetPyNESynapses.js b/webapp/components/definition/synapses/NetPyNESynapses.js new file mode 100644 index 00000000..17a88876 --- /dev/null +++ b/webapp/components/definition/synapses/NetPyNESynapses.js @@ -0,0 +1,227 @@ +import React,{ Component } from 'react'; + +import Utils from '../../../Utils'; +import Dialog from '@material-ui/core/Dialog/Dialog'; +import Button from '@material-ui/core/Button'; + + +import { + NetPyNEHome, + NetPyNEAddNew, + NetPyNEThumbnail, + NetPyNESynapse, + GridLayout, + Filter +} from 'netpyne/components'; + +import RulePath from '../../general/RulePath' +import Accordion from '../../general/ExpansionPanel' +import Divider from '@material-ui/core/Divider'; +export default class NetPyNESynapses extends Component { + + constructor (props) { + super(props); + this.state = { + selectedSynapse: undefined, + deletedSynapse: undefined, + page: "main", + errorMessage: undefined, + errorDetails: undefined, + filterValue: null + }; + this.selectSynapse = this.selectSynapse.bind(this); + this.handleNewSynapse = this.handleNewSynapse.bind(this); + + this.handleRenameChildren = this.handleRenameChildren.bind(this); + } + + /* Method that handles button click */ + selectSynapse (Synapse) { + this.setState({ selectedSynapse: Synapse }); + } + + handleNewSynapse () { + var defaultSynapses = { 'Synapse': { 'mod': 'Exp2Syn' } }; + var key = Object.keys(defaultSynapses)[0]; + var value = defaultSynapses[key]; + var model = { ...this.state.value }; + var SynapseId = Utils.getAvailableKey(model, key); + var newSynapse = Object.assign({ name: SynapseId }, value); + Utils.execPythonMessage('netpyne_geppetto.netParams.synMechParams["' + SynapseId + '"] = ' + JSON.stringify(value)); + model[SynapseId] = newSynapse; + this.setState({ + value: model, + selectedSynapse: SynapseId + }, () => this.props.updateCards()) + } + + hasSelectedSynapseBeenRenamed (prevState, currentState) { + var currentModel = prevState.value; + var model = currentState.value; + // deal with rename + if (currentModel != undefined && model != undefined) { + var oldP = Object.keys(currentModel); + var newP = Object.keys(model); + if (oldP.length == newP.length) { + // if it's the same lenght there could be a rename + for (var i = 0; i < oldP.length; i++) { + if (oldP[i] != newP[i]) { + if (prevState.selectedSynapse != undefined) { + if (oldP[i] == prevState.selectedSynapse) { + return newP[i]; + } + } + } + } + } + } + return undefined; + } + + componentDidUpdate (prevProps, prevState) { + var newSynapseName = this.hasSelectedSynapseBeenRenamed(prevState, this.state); + if (newSynapseName !== undefined) { + this.setState({ selectedSynapse: newSynapseName, deletedSynapse: undefined }); + } else if ((prevState.value !== undefined) && (Object.keys(prevState.value).length !== Object.keys(this.state.value).length)) { + /* + * logic into this if to check if the user added a new object from the python backend and + * if the name convention pass the checks, differently rename this and open dialog to inform. + */ + var model = this.state.value; + for (var m in model) { + if ((prevState.value !== "") && (!(m in prevState.value))) { + var newValue = Utils.nameValidation(m); + if (newValue != m) { + newValue = Utils.getAvailableKey(model, newValue); + model[newValue] = model[m]; + delete model[m]; + this.setState({ + value: model, + errorMessage: "Error", + errorDetails: "Leading digits or whitespaces are not allowed in Synapses names.\n" + + m + " has been renamed " + newValue + }, + () => Utils.renameKey('netParams.synMechParams', m, newValue, (response, newValue) => this.props.updateCards())); + } + } + } + } + } + + shouldComponentUpdate (nextProps, nextState) { + var itemRenamed = this.hasSelectedSynapseBeenRenamed(this.state, nextState) !== undefined; + var newItemCreated = false; + var selectionChanged = this.state.selectedSynapse != nextState.selectedSynapse; + var pageChanged = this.state.page != nextState.page; + var newModel = this.state.value == undefined; + if (!newModel) { + newItemCreated = ((Object.keys(this.state.value).length != Object.keys(nextState.value).length)); + } + var errorDialogOpen = (this.state.errorDetails !== nextState.errorDetails); + const filterValueChanged = nextState.filterValue !== this.state.filterValue + return filterValueChanged || newModel || newItemCreated || itemRenamed || selectionChanged || pageChanged || errorDialogOpen; + } + + handleRenameChildren (childName) { + childName = childName.replace(/\s*$/,""); + var childrenList = Object.keys(this.state.value); + for (var i = 0 ; childrenList.length > i ; i++) { + if (childName === childrenList[i]) { + return false; + } + } + return true; + } + + + getPath () { + const { value: model, selectedSynapse } = this.state + return model && model[selectedSynapse] && `netParams.synMechParams["${selectedSynapse}"]` + } + + render () { + var actions = [ + + + + + ); + } +} diff --git a/webapp/components/general/Dialog.js b/webapp/components/general/Dialog.js new file mode 100644 index 00000000..78abaac1 --- /dev/null +++ b/webapp/components/general/Dialog.js @@ -0,0 +1,96 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import MuiDialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import Typography from '@material-ui/core/Typography'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import { secondaryColor, bgDarkest } from '../../theme' +import Paper from '@material-ui/core/Paper' +import Box from '@material-ui/core/Box' +import Link from '@material-ui/core/Link' +import Icon from '@material-ui/core/Icon' + +const AboutContent = () => ( + + + + NetPyNE-UI v0.6.0 + + + + + NetPyNE is a Python package to facilitate the development, simulation, parallelization, and analysis of biological neuronal networks using the NEURON simulator. + Checkout our eLife paper. + + + + + + Want to know more? Go to our website. + + + + + + NetPyNE-UI is being developed in collaboration with: + + + + + + + + + +) + +const ContributeContent = () => ( + + + Want to contribute? + + + + GitHub repository +
.
+
+ + + + Read our contributing guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to NetPyNE-UI. + + + + + + Join our mailing list. + + + +
+ +) +export default function Dialog ({ open, title, message, handleClose }) { + + return ( +
+ + {title} + + {title === "Contribute" ? : } + + + + + +
+ ); +} diff --git a/webapp/components/general/ExpansionPanel.js b/webapp/components/general/ExpansionPanel.js new file mode 100644 index 00000000..4bb9d7b9 --- /dev/null +++ b/webapp/components/general/ExpansionPanel.js @@ -0,0 +1,46 @@ +import React, { Component } from 'react' +import Accordion from '@material-ui/core/Accordion'; +import AccordionSummary from '@material-ui/core/AccordionSummary'; +import AccordionDetails from '@material-ui/core/AccordionDetails'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import ExpandLessIcon from '@material-ui/icons/ExpandLess'; +import Tooltip from './Tooltip' + +import { withStyles } from '@material-ui/core/styles' + +const styles = ({ spacing }) => ({ button: { marginRight: 0 } }) + +class NetPyNEAccordion extends Component { + state = { expanded: false } + render () { + + const { children, classes, ...others } = this.props + const [summary, ...details] = children + + return ( + + this.setState({ expanded: !this.state.expanded }), + className: classes.button, + }} + expandIcon={ + + {this.state.expanded ? : } + + + } + > + {summary} + + + {details} + + + ) + } +} + +export default withStyles(styles)(NetPyNEAccordion) \ No newline at end of file diff --git a/webapp/components/general/FileBrowser.js b/webapp/components/general/FileBrowser.js new file mode 100644 index 00000000..59d3a9e8 --- /dev/null +++ b/webapp/components/general/FileBrowser.js @@ -0,0 +1,199 @@ +import React from 'react'; +import Tree from '@geppettoengine/geppetto-client/js/components/interface/tree/Tree' +import Utils from '../../Utils'; +import Button from '@material-ui/core/Button'; +import { changeNodeAtPath } from 'react-sortable-tree'; +import Dialog from '@material-ui/core/Dialog'; +import Box from '@material-ui/core/Box' +import Grid from '@material-ui/core/Grid' +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import { Tooltip } from 'netpyne/components' +import IconButton from '@material-ui/core/IconButton'; +import Icon from '@material-ui/core/Icon'; +import { walk } from 'react-sortable-tree'; +import { bgLight, fontColor } from '../../theme' +export default class FileBrowser extends React.Component { + + constructor (props) { + super(props); + this.handleClickVisualize = this.handleClickVisualize.bind(this); + + this.state = {}; + } + + getDirList (treeData, rowInfo) { + if (rowInfo != undefined) { + var path = rowInfo.node.path; + } else { + var path = "" + } + + Utils + .evalPythonMessage('netpyne_geppetto.getDirList', [path, this.props.exploreOnlyDirs, this.props.filterFiles]) + .then(dirList => { + if (treeData != [] && treeData.length > 0) { + rowInfo.node.children = dirList; + rowInfo.node.expanded = true; + rowInfo.node.load = true; + var newTreeData = changeNodeAtPath({ + treeData: treeData, + path: rowInfo.path, + newNode: rowInfo.node, + getNodeKey: ({ treeIndex }) => treeIndex + }); + } else { + var newTreeData = dirList; + } + if (!this.props.exploreOnlyDirs || rowInfo == undefined){ + this.setState({ selection: undefined }) + } else { + this.setState({ selection: rowInfo.node }) + } + this.refs.tree.updateTreeData(newTreeData); + }); + } + + + handleClickVisualize (event, rowInfo) { + if (rowInfo.node.load == false) { + this.getDirList(this.refs.tree.state.treeData, rowInfo); + } else if (this.props.exploreOnlyDirs || (rowInfo.node.children == undefined && rowInfo.node.load == undefined)) { + this.setState({ selection: rowInfo.node }) + } + } + + getSelectedFiles () { + const nodes = {} + if (!this.refs.tree) { + return nodes + } + walk({ + treeData: this.refs.tree.state.treeData, + getNodeKey: ({ treeIndex }) => treeIndex, + ignoreCollapsed: true, + callback: rowInfoIter => { + if (rowInfoIter.node.active) { + nodes[rowInfoIter.treeIndex] = rowInfoIter.node + } + } + }); + + return nodes + } + + componentDidUpdate (prevProps, prevState) { + if (prevProps.open == false && this.props.open) { + this.getDirList([]); + } + } + + handleMoveUp (reset = false) { + var path = this.refs.tree.state.treeData[0].path.split("/").slice(0, -2).join('/') || '/' + + if (reset) { + path = window.currentFolder + } + + this.currentFolder = path + this.getDirList([], { node: { path } }); + } + + disableSelectButton () { + if (this.props.toggleMode) { + if (Object.keys(this.getSelectedFiles()).length > 0) { + return false + } + } + if (this.state.selection) { + return !this.state.selection.active + } + return true + } + + onCancelFileBrowser () { + this.currentFolder = window.currentFolder + this.props.onRequestClose() + } + + + render () { + const actions = [ + , + + ]; + + var selectMessage = this.props.exploreOnlyDirs ? "Select a folder. " : "Select a file. "; + return ( + this.props.onRequestClose()} + style={{ zIndex: 1350 }} + > + + {`${selectMessage}Paths are relative to:`} + + + + {this.currentFolder || window.currentFolder} + + + + this.handleMoveUp()} + > + + + + + + this.handleMoveUp(true)} + > + + + + + + + + + + {actions} + + + ) + } +} + +FileBrowser.defaultProps = { + exploreOnlyDirs: false, + filterFiles: false +}; + + diff --git a/webapp/components/general/Filter.js b/webapp/components/general/Filter.js new file mode 100644 index 00000000..2a7999f8 --- /dev/null +++ b/webapp/components/general/Filter.js @@ -0,0 +1,64 @@ +import React, { Component } from 'react' +import TextField from '@material-ui/core/TextField'; +import InputAdornment from '@material-ui/core/InputAdornment'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import { withStyles } from '@material-ui/core/styles' +import Icon from '@material-ui/core/Icon' +import { bgLight } from '../../theme' +import CloseIcon from '@material-ui/icons/Close'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import Tooltip from './Tooltip' + +const styles = ({ spacing, shape }) => ({ + root: { display: 'flex', }, + adornment: { display: 'flex', alignItems: 'center' }, + filter: { flex: 1, backgroundColor: bgLight }, + underline: { + "&&&:before": { }, + "&&:after": { } + }, + listbox: { color: 'white', maxHeight: '20vh' } +}) +class Filter extends Component { + state = { open: false } + render () { + const { value, handleFilterChange, options, label, classes, ...others } = this.props + + return ( + this.setState({ open: false })} + onOpen={() => this.setState({ open: true })} + className={classes.filter} + + clearOnEscape + autoComplete + openOnFocus + autoHighlight + value={value === '' ? null : value} + options={options} + openText={''} + closeText={''} + clearText={''} + closeIcon={ + + + + } + popupIcon={ + + + + } + classes={{ inputRoot: classes.underline, listbox: classes.listbox }} + onChange={(event, newValue) => handleFilterChange(newValue)} + renderInput={props => + } + {...others} + /> + + ) + } +} + +export default withStyles(styles)(Filter) \ No newline at end of file diff --git a/webapp/components/general/GeppettoJupyterUtils.js b/webapp/components/general/GeppettoJupyterUtils.js new file mode 100644 index 00000000..14cc003c --- /dev/null +++ b/webapp/components/general/GeppettoJupyterUtils.js @@ -0,0 +1,61 @@ +const handle_output = function (data) { + // data is the object passed to the callback from the kernel execution + switch (data.msg_type) { + case 'error': + GEPPETTO.CommandController.log("ERROR while executing a Python command:"); + GEPPETTO.CommandController.log(data.content.evalue.trim()); + console.error("ERROR while executing a Python command:"); + console.error(data.content.traceback); + GEPPETTO.trigger(GEPPETTO.Events.Error_while_exec_python_command, data.content); + GEPPETTO.trigger(GEPPETTO.Events.Hide_spinner); + break; + case 'execute_result': + GEPPETTO.CommandController.log(data.content.data['text/plain'].trim(), true); + try { + var response = JSON.parse(data.content.data['text/plain'].replace(/^'(.*)'$/, '$1')); + } catch (error) { + var response = data.content.data['text/plain'].replace(/^'(.*)'$/, '$1'); + } + GEPPETTO.trigger(GEPPETTO.Events.Receive_Python_Message, { id: data.parent_header.msg_id, type: data.msg_type, response: response }); + break; + case "display_data": + // FIXME + break; + default: + GEPPETTO.CommandController.log(data.content.text.trim(), true); + } +}; + +const execPythonMessage = function (command, callback = handle_output) { + GEPPETTO.CommandController.log('Executing Python command: ' + command, true); + var kernel = IPython.notebook.kernel; + var messageID = kernel.execute(command, { iopub: { output: callback } }, { silent: false, stop_on_error: true, store_history: true }); + + return new Promise((resolve, reject) => + GEPPETTO.on(GEPPETTO.Events.Receive_Python_Message, function (data) { + if (data.id == messageID) { + resolve(data.response); + } + }) + ); +}; + +const evalPythonMessage = function (command, parameters, parse = true) { + var parametersString = ''; + if (parameters) { + if (parameters.length > 0) { + parametersString = "(" + parameters.map(parameter => "utils.convertToPython('" + JSON.stringify(parameter) + "')").join(",") + ")"; + } else { + parametersString = '()'; + } + } + + var finalCommand = command + parametersString; + if (parse) { + finalCommand = 'utils.convertToJS(' + finalCommand + ')' + } + return execPythonMessage(finalCommand, handle_output); + +}; + +export { execPythonMessage, evalPythonMessage } \ No newline at end of file diff --git a/webapp/components/general/GridLayout.js b/webapp/components/general/GridLayout.js new file mode 100644 index 00000000..34ec0ef3 --- /dev/null +++ b/webapp/components/general/GridLayout.js @@ -0,0 +1,37 @@ +import React from 'react' +import Grid from '@material-ui/core/Grid' +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; + +export default function GridLayout ({ children, className = '' }) { + // left-hand-side-top - left-hand-side-bottom - right-hand-side - others + const [lhst, lhsb, rhs, ...others] = children + return ( +
+ + + + + + {lhst} + {lhsb} + + + + + + { rhs + ? + + + {[rhs]} + + + : '' + } + + {others} +
+ + ) +} diff --git a/webapp/components/general/HTMLViewer.js b/webapp/components/general/HTMLViewer.js new file mode 100644 index 00000000..b83213c9 --- /dev/null +++ b/webapp/components/general/HTMLViewer.js @@ -0,0 +1,89 @@ +import React, { Component, createRef } from 'react' + +import HTMLViewer from '@geppettoengine/geppetto-client/js/components/interface/htmlViewer/HTMLViewer' + +import { withStyles } from '@material-ui/core/styles' + +const style = ({ palette }) => ({ + container: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'inherit' + } +}) + + +class CustomHTMLViewer extends Component { + containerRef = createRef() + + dimensions = { width: 200, height: 200 } + + componentDidMount () { + window.addEventListener('resize', this.delayedResize.bind(this)) + this.resizeIfNeeded() + } + + componentWillUnmount () { + clearTimeout(this.timer) + window.removeEventListener('resize', this.delayedResize) + } + + componentDidUpdate (){ + this.resizeIfNeeded() + } + + wasParentResized (dimensions) { + return dimensions.width !== this.dimensions.width || dimensions.height !== this.dimensions.height + } + + getParentSize () { + if (this.containerRef.current === null) { + return false + } + return this.containerRef.current.parentNode.getBoundingClientRect() + } + + getSvgComponent () { + // svg element + return this.containerRef.current.children[0].children[0].children[0] + } + + adjustSVGSize () { + const svg = this.getSvgComponent() + if (svg) { + const width = (this.dimensions.width - 20) > 0 ? `${this.dimensions.width - 20}px` : '0px' + const height = (this.dimensions.height - 20) > 0 ? `${this.dimensions.height - 20}px` : '0px' + svg.removeAttribute('width'); + svg.removeAttribute('height'); + svg.setAttribute('width', width); + svg.setAttribute('height', height); + } + + } + + resizeIfNeeded (){ + const dimensions = this.getParentSize() + + if (dimensions !== false && this.wasParentResized(dimensions)) { + this.dimensions = dimensions + this.adjustSVGSize() + } + } + + delayedResize () { + this.timer = setTimeout(() => this.resizeIfNeeded(), 100) + } + + render () { + const { classes } = this.props + return ( +
+ +
+ ) + } +} + + +export default withStyles(style)(CustomHTMLViewer) \ No newline at end of file diff --git a/webapp/components/general/List.js b/webapp/components/general/List.js new file mode 100644 index 00000000..3d2accaf --- /dev/null +++ b/webapp/components/general/List.js @@ -0,0 +1,265 @@ +import React, { Component } from 'react'; +import TextField from '@material-ui/core/TextField'; +import IconButton from '@material-ui/core/IconButton'; + +import Tooltip from './Tooltip' +import Chip from '@material-ui/core/Chip' +import Grid from '@material-ui/core/Grid' +import NetPyNEIcon from '../general/NetPyNEIcons'; +import Box from '@material-ui/core/Box' +import { withStyles } from '@material-ui/core/styles' +/** + * Generic List/Dict Component + */ +class ListComponent extends Component { + + constructor (props) { + super(props); + this.state = { + model: props.model, + children: (props.realType == 'dict' || props.realType == 'dict(dict)') ? {} : [], + newItemValue: '' + }; + this.addChild = this.addChild.bind(this); + this.handleNewItemChange = this.handleNewItemChange.bind(this); + } + + componentDidMount () { + // this.props.value is populated from pythonControlledCapability + if (this.props.default && this.isDict() && this.props.value === '') { + // this.props.onChange(null, null, this.props.default); + } + + } + + isDict () { + return this.props.realType == 'dict' || this.props.realType == 'dict(dict)' + } + + isValid (value) { + switch (this.props.realType) { + case 'list(float)': + var valid = (value.match(/^-?\d*(\.\d+)?$/)); + break; + case 'list(list(float))': + var valid = true; + value.split(',').forEach(element => { + if (!element.match(/^-?\d*(\.\d+)?$/)) { + valid = false; + } + }); + if (value.endsWith(',')) { + valid = false; + } + break; + case 'dict': + var valid = (value.match(/:/g) || []).length == 1 && !value.startsWith(':') && !value.endsWith(':'); + break; + case 'dict(dict)': + var valid = true; + var value = this.state.newItemValue.replace(/[ "']/g, ''); + + if ((value.match(/;/g) || []).length != 0) { + valid = false; + } else { + if ((value.match(/{/g) || []).length != 1 || (value.match(/}/g) || []).length != 1) { + valid = false; + } else { + if (value.indexOf('{') > value.indexOf('}') || !value.endsWith('}')) { + valid = false; + } else { + var subDict = value.match(/\{(.*?)\}/)[1]; + if ((subDict.match(/:/g) || []).length - 1 != (subDict.match(/,/g) || []).length) { + valid = false; + } else { + subDict.split(',').forEach(element => { + if ((element.match(/:/g) || []).length != 1 || element.startsWith(':') || element.endsWith(':')) { + valid = false; + } + }); + var reminder = value.replace('{' + subDict + '}', ''); + if ((reminder.match(/:/g) || []).length != 1 || !reminder.endsWith(':')) { + valid = false; + } + } + } + } + } + break; + default: + var valid = true; + break; + } + return valid; + } + + getErrorMessage () { + switch (this.props.realType) { + case 'list(float)': + var message = 'Only float numbers are allowed.'; + break; + case 'list(list(float))': + var message = 'Only comma separated float numbers are allowed.'; + break; + case 'dict': + var message = 'Key:Value pairs must be separated by colon : '; + break; + case 'dict(dict)': + var message = 'Incorrect format. Example -> v_soma : { sec: soma, loc: 0.5, var: v}'; + break + default: + var message = 'No a valid value'; + break; + } + return message; + } + + handleNewItemChange (event) { + this.setState({ newItemValue: event.target.value, newItemErrorText: '' }) + } + + addChild () { + if (this.state.newItemValue != '' && this.isValid(this.state.newItemValue)) { + var children = this.state.children; + switch (this.props.realType) { + case 'list(list(float))': + var newValue = '[' + this.state.newItemValue + ']'; + children.push(newValue); + break; + case 'dict': + var newValue = this.state.newItemValue.split(':').map(entry => entry); + if (!isNaN(newValue[1])) { + newValue[1] = parseFloat(newValue[1]) + } + children[newValue[0]] = newValue[1]; + break; + case 'dict(dict)': + var key = this.state.newItemValue.split(':')[0].replace(/[ "']/g, ''); + children[key] = {} + var newValue = this.state.newItemValue.match(/\{(.*?)\}/)[1].replace(/[ "']/g, '').split(',').map(entry => entry.split(':')); + newValue.forEach(entry => { + if (!isNaN(entry[1])) { + entry[1] = parseFloat(entry[1]) + } + children[key][entry[0]] = entry[1] + }) + break; + default: + var newValue = this.state.newItemValue; + children.push(newValue); + break; + } + // Call to conversion function + this.convertToPython(children); + } else { + this.setState({ newItemErrorText: this.getErrorMessage() }) + } + } + + removeChild (childIndex) { + var children = this.state.children; + if (this.props.realType == 'dict' || this.props.realType == 'dict(dict)') { + + delete children[childIndex]; + } else { + children.splice(childIndex, 1); + } + // Call to conversion function + this.convertToPython(children); + } + + convertToPython (children) { + // Update State + this.setState({ children: children, newItemValue: '' }); + + if (this.props.realType == 'dict' || this.props.realType == 'dict(dict)') { + var newValue = children; + } else { + var newValue = this.state.children.map((child, i) => { + switch (this.props.realType) { + case 'list(float)': + var childConverted = parseFloat(child) + break; + case 'list(list(float))': + var childConverted = JSON.parse(child); + break; + default: + var childConverted = child; + break; + } + return childConverted; + }) + } + + if (newValue != undefined && this.state.value != newValue && this.props.onChange != undefined) { + this.props.onChange(null, null, newValue); + } + } + + convertFromPython (prevProps, prevState, value) { + if (value != undefined && prevProps.value != value && value != '') { + if (this.props.realType == 'dict' || this.props.realType == 'dict(dict)') { + return (typeof value == 'string') ? JSON.parse(value) : value; + } else { + if (!Array.isArray(value)) { + value = [value]; + } + return value.map((child, i) => (typeof child == 'string') ? child : JSON.stringify(child)); + } + + } + } + + componentDidUpdate (prevProps, prevState) { + var newValue = this.convertFromPython(prevProps, prevState, this.props.value); + if (newValue != undefined) { + this.setState({ children: newValue }); + } + } + + render () { + var childrenWithExtraProp = Object.keys(this.state.children).map((key, index) => { + key = key.toString(); + if (this.props.realType == 'dict') { + var value = key + ' : ' + JSON.stringify(this.state.children[key]); + } else if (this.props.realType == 'dict(dict)') { + var value = key + ': ' + JSON.stringify(this.state.children[key]).replace(/["']/g, '').replace(/[:]/g, ': ').replace(/[,]/g, ', '); + } else { + var value = this.state.children[key]; + } + return this.removeChild(key)} color="primary" /> + }); + + const { classes } = this.props + return ( + + e.key === 'Enter' ? this.addChild() : null } + value={this.state.newItemValue} + fullWidth + helperText={this.state.newItemErrorText} + InputProps={{ + endAdornment: ( + + + + + + ) + }} + /> + {childrenWithExtraProp} + + + ) + } +} + + +const styles = () => ({ addButton: { height: 48 } }) + +export default withStyles(styles)(ListComponent) \ No newline at end of file diff --git a/webapp/components/general/NetPyNEAddNew.js b/webapp/components/general/NetPyNEAddNew.js new file mode 100644 index 00000000..2420f306 --- /dev/null +++ b/webapp/components/general/NetPyNEAddNew.js @@ -0,0 +1,43 @@ +import React, { Component } from 'react'; +import ContentAdd from '@material-ui/icons/Add'; +import Fab from '@material-ui/core/Fab'; +import { withStyles } from '@material-ui/core/styles'; +import Tooltip from './Tooltip' + +const styles = ({ spacing, palette }) => ({ plus:{ color: palette.common.white } }) + +class NetPyNEAddNew extends React.Component { + + constructor (props) { + super(props); + this.state = {}; + this.handleClick = this.handleClick.bind(this); + } + + handleClick (event) { + if (this.props.handleClick) { + event.stopPropagation() + this.props.handleClick(); + } + } + + render () { + const { classes, title } = this.props + return ( + + + + + + + ); + } +} + +export default withStyles(styles)(NetPyNEAddNew) \ No newline at end of file diff --git a/webapp/components/general/NetPyNECoordsRange.js b/webapp/components/general/NetPyNECoordsRange.js new file mode 100644 index 00000000..be692f3f --- /dev/null +++ b/webapp/components/general/NetPyNECoordsRange.js @@ -0,0 +1,133 @@ +import React, { Component } from 'react'; +import MenuItem from '@material-ui/core/MenuItem'; +import TextField from '@material-ui/core/TextField'; +import Box from '@material-ui/core/Box' +import SelectField from './Select'; +import Utils from '../../Utils'; + +import { AdapterComponent, NetPyNEField } from "netpyne/components"; + +export default class NetPyNECoordsRange extends Component { + + constructor (props) { + super(props); + this.state = { rangeType: undefined }; + + this._isMounted = false; + } + + triggerUpdate (updateMethod) { + // common strategy when triggering processing of a value change, delay it, every time there is a change we reset + if (this.updateTimer != undefined) { + clearTimeout(this.updateTimer); + } + this.updateTimer = setTimeout(updateMethod, 1000); + } + + componentDidUpdate (prevProps, prevState) { + if (this.props.name != prevProps.name) { + this.triggerUpdate(() => { + var message = 'netpyne_geppetto.' + this.props.model + "['" + this.props.name + "']" + ((this.props.conds != undefined) ? "['" + this.props.conds + "']" : ""); + Utils + .evalPythonMessage("[key in " + message + " for key in ['" + this.props.items[0].value + "', '" + this.props.items[1].value + "']]") + .then(response => { + if (response[0] && this._isMounted === true) { + this.setState({ rangeType: this.props.items[0].value }); + } else if (response[1] && this._isMounted === true){ + this.setState({ rangeType: this.props.items[1].value }); + } else if (this._isMounted === true) { + this.setState({ rangeType: undefined }); + } + }); + }); + } else if (this.props.conds != prevProps.conds) { + this.updateLayout(); + } + } + + componentDidMount () { + this._isMounted = true; + this.updateLayout(); + } + + updateLayout () { + var message = 'netpyne_geppetto.' + this.props.model + "['" + this.props.name + "']" + ((this.props.conds != undefined) ? "['" + this.props.conds + "']" : ""); + Utils + .evalPythonMessage("[key in " + message + " for key in ['" + this.props.items[0].value + "', '" + this.props.items[1].value + "']]") + .then(response => { + if (response[0] && this._isMounted === true) { + this.setState({ rangeType: this.props.items[0].value }); + } else if (response[1] && this._isMounted === true){ + this.setState({ rangeType: this.props.items[1].value }); + } else if (this._isMounted === true) { + this.setState({ rangeType: undefined }); + } + }); + } + + createMenuItems = () => this.props.items.map(obj => ( + + {obj.label} + + )); + + componentWillUnmount () { + this._isMounted = false; + } + + render () { + if (this.props.conds != undefined) { + var meta = this.props.model + "." + this.props.conds + "." + this.props.items[0].value; + var path = this.props.model + "['" + this.props.name + "']['" + this.props.conds + "']['" + this.state.rangeType + "']"; + } else { + var meta = this.props.model + '.' + this.props.items[0].value; + var path = this.props.model + "['" + this.props.name + "']['" + this.state.rangeType + "']"; + } + var min = this.props.id + "MinRange"; + var max = this.props.id + "MaxRange"; + return ( +
+ + this.setState({ rangeType: event.target.value })} + > + {this.createMenuItems()} + + + {(this.state.rangeType != undefined) + ? + { + if (!state[state.lastUpdated].toString().endsWith(".") + && ((!isNaN(parseFloat(state[min]))) && (!isNaN(parseFloat(state[max]))))) { + return [parseFloat(state[min]), parseFloat(state[max])]; + } + } + } + convertFromPython={(prevProps, prevState, value) => { + if (value != undefined && prevProps.value != value && value != '') { + var output = {} + output[min] = value[0]; + output[max] = value[1]; + return output; + } + } + } + > + + + + + : null} +
+ ); + } +} diff --git a/webapp/components/general/NetPyNEField.js b/webapp/components/general/NetPyNEField.js new file mode 100644 index 00000000..9e0046fa --- /dev/null +++ b/webapp/components/general/NetPyNEField.js @@ -0,0 +1,187 @@ +import React, { Component } from 'react'; +import Dialog from '@material-ui/core/Dialog'; +import Button from '@material-ui/core/Button'; +import MenuItem from '@material-ui/core/MenuItem'; +import Utils from '../../Utils'; + + +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import { Tooltip } from 'netpyne/components' +import Grid from '@material-ui/core/Grid' +import Box from '@material-ui/core/Box' + +export default class NetPyNEField extends Component { + constructor (props) { + super(props); + this.state = { openHelp: false }; + + } + + handleOpenHelp = help => { + this.setState({ openHelp: true, helpText: help }); + }; + + handleCloseHelp = () => { + this.setState({ openHelp: false }); + }; + + setErrorMessage (value) { + return new Promise((resolve, reject) => { + if (this.realType == 'func') { + if (value != "" && value != undefined) { + Utils.evalPythonMessage('netpyne_geppetto.validateFunction', [value]) + .then(response => { + if (!response) { + resolve({ errorMsg: 'Not a valid function' }) + } else { + resolve({ errorMsg: '' }) + } + }); + } else { + resolve({ errorMsg: '' }) + } + } else if (this.realType == 'float') { + if (isNaN(value)) { + resolve({ errorMsg: 'Only float allowed' }) + } else { + resolve({ errorMsg: '' }) + } + } + } + ); + } + + prePythonSyncProcessing (value){ + if (value == '') { + if (this.default != undefined) { + return this.default; + } else if (!this.model.split(".")[0].startsWith('simConfig') || this.model.split(".")[1].startsWith('analysis')) { + Utils.execPythonMessage('del netpyne_geppetto.' + this.model) + } + } + return value; + } + + render () { + var help = Utils.getMetadataField(this.props.id, "help"); + if (help != undefined && help != '') { + var helpComponent = ( +
+ +
+