diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 20f2e33a69494993892966bfd96437165682569f..0000000000000000000000000000000000000000
--- a/.coveragerc
+++ /dev/null
@@ -1,2 +0,0 @@
-[run]
-omit = dicom_upload/tests/*
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 90af452272779e1152b5b86d52f2e30ccc0e3cfd..0000000000000000000000000000000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,74 +0,0 @@
-language: python
-python:
-  - 3.7
-  - 3.6
-  - 3.5
-sudo: false
-dist: xenial
-services:
-  - xvfb
-addons:
-  apt_packages:
-    - pandoc
-env:
-  matrix:
-    - GROUP=python
-matrix:
-  include:
-    - python: 3.5
-      env: GROUP=js
-  include:
-    - python: 3.6
-      env: GROUP=docs
-cache:
-  pip: true
-  directories:
-    - node_modules # NPM packages
-    - $HOME/.npm
-before_install:
-  - pip install -U pip setuptools
-  - nvm install 8
-  - |
-    if [[ $GROUP == python ]]; then
-      pip install codecov
-    elif [[ $GROUP == js ]]; then
-      npm install -g codecov
-    fi
-install:
-  - |
-    if [[ $GROUP == python ]]; then
-      pip install --upgrade ".[test]" -v
-    elif [[ $GROUP == js ]]; then
-      pip install --upgrade -e ".[test]" -v
-    elif [[ $GROUP == docs ]]; then
-      pip install --upgrade ".[test, examples, docs]" -v
-    fi
-before_script:
-  # Set up a virtual screen for Firefox browser testing:
-  - |
-    if [[ $GROUP == js ]]; then
-      export CHROME_BIN=chromium-browser
-    fi
-    git config --global user.email travis@fake.com
-    git config --global user.name "Travis CI"
-script:
-  - |
-    if [[ $GROUP == python ]]; then
-      EXIT_STATUS=0
-      pushd $(mktemp -d)
-      py.test -l --cov-report xml:$TRAVIS_BUILD_DIR/coverage.xml --cov=dicom_upload --pyargs dicom_upload || EXIT_STATUS=$?
-      popd
-      (exit $EXIT_STATUS)
-    elif [[ $GROUP == js ]]; then
-      npm test
-    elif [[ $GROUP == docs ]]; then
-      EXIT_STATUS=0
-      cd docs
-      make html || EXIT_STATUS=$?
-      make linkcheck || EXIT_STATUS=$?
-      cd ..
-      python -m pytest_check_links --links-ext=.md -o testpaths=. -o addopts= || EXIT_STATUS=$?
-      (exit $EXIT_STATUS)
-    fi
-after_success:
-  - codecov
diff --git a/LICENSE.txt b/LICENSE.txt
index 99c418a74ea06fb099956389090d2afcb157869b..98c33569079213fc77af8a3ca3290f9e817c5f23 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,6 +1,8 @@
-Copyright (c) 2019 Alice Grosch
+Copyright (c) 2019 Juelich Supercomputing Centre (JSC)
 All rights reserved.
 
+    Alice Grosch <a.grosch@fz-juelich.de>
+
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
diff --git a/README.md b/README.md
index f1bc1b9800beffbbec19a8b1bc800dcf59f57df9..39ab7a09082aa2426792526e42742234e9ed07a7 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,11 @@
 [![codecov](https://codecov.io/gh/jsc/dicom-upload/branch/master/graph/badge.svg)](https://codecov.io/gh/jsc/dicom-upload)
 
 
-Upload DICOM files with removed headers.
+FileUpload Widget using the Jupyter Notebook Server RestAPI.
+Uploads DICOM files with anonymized headers, i.d. the 0004 and 
+0010 tags are removed on JS side before the upload.
+
+Can handle large files by uploading files in chunks.
 
 ## Installation
 
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 98100000e33a5604cf665e90470dec6a40781d8b..0000000000000000000000000000000000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-# Do not build feature branch with open Pull Requests
-skip_branch_with_pr: true
-
-# environment variables
-environment:
-  nodejs_version: "8"
-  matrix:
-    - PYTHON: "C:\\Miniconda3-x64"
-      PYTHON_VERSION: "3.7"
-      PYTHON_MAJOR: 3
-      PYTHON_ARCH: "64"
-    - PYTHON: "C:\\Miniconda3"
-      PYTHON_VERSION: "3.4"
-      PYTHON_MAJOR: 3
-      PYTHON_ARCH: "32"
-
-# build cache to preserve files/folders between builds
-cache:
-  - '%AppData%/npm-cache'
-  - '%PYTHON%/pkgs'
-  - '%LOCALAPPDATA%\pip\Cache'
-
-# scripts that run after cloning repository
-install:
-  # Install node:
-  - ps: Install-Product node $env:nodejs_version
-  # Ensure python scripts are from right version:
-  - 'SET "PATH=%PYTHON%\Scripts;%PYTHON%;%PATH%"'
-  # Setup conda:
-  - 'conda list'
-  - 'conda update conda -y'
-  # If 32 bit, force conda to use it:
-  - 'IF %PYTHON_ARCH% EQU 32 SET CONDA_FORCE_32BIT=1'
-  - 'conda create -n test_env python=%PYTHON_VERSION% -y'
-  - 'activate test_env'
-  # Update install tools:
-  - 'conda install setuptools pip -y'
-  - 'python -m pip install --upgrade pip'
-  - 'python -m easy_install --upgrade setuptools'
-  # Install coverage utilities:
-  - 'pip install codecov'
-  # Install our package:
-  - 'pip install --upgrade ".[test]" -v'
-
-build: off
-
-# scripts to run before tests
-before_test:
-  - git config --global user.email appveyor@fake.com
-  - git config --global user.name "AppVeyor CI"
-  - set "tmptestdir=%tmp%\dicom_upload-%RANDOM%"
-  - mkdir "%tmptestdir%"
-  - cd "%tmptestdir%"
-
-
-# to run your custom scripts instead of automatic tests
-test_script:
-  - 'py.test -l --cov-report xml:"%APPVEYOR_BUILD_FOLDER%\coverage.xml" --cov=dicom_upload --pyargs dicom_upload'
-
-on_success:
-  - cd "%APPVEYOR_BUILD_FOLDER%"
-  - codecov -X gcov --file "%APPVEYOR_BUILD_FOLDER%\coverage.xml"
diff --git a/codecov.yml b/codecov.yml
deleted file mode 100644
index 8d3dfa92737547b02732fd5684dae158c4cf76ba..0000000000000000000000000000000000000000
--- a/codecov.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-comment: off
-# show coverage in CI status, but never consider it a failure
-coverage:
-  status:
-    project:
-      default:
-        target: 0%
-    patch:
-      default:
-        target: 0%
-ignore:
-  - "dicom_upload/tests"
diff --git a/css/widget.css b/css/widget.css
deleted file mode 100644
index 98542cecf9ab63028d2c09ede16d2c69d9878f0e..0000000000000000000000000000000000000000
--- a/css/widget.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.custom-widget {
-  background-color: blue;
-}
diff --git a/dicom_upload/widget_upload.py b/dicom_upload/widget_upload.py
index 91abdf9ed93f47293fa2b59f4e598eddf7344006..56647598b1ff98997526da1750c85af6c5a0e50f 100644
--- a/dicom_upload/widget_upload.py
+++ b/dicom_upload/widget_upload.py
@@ -1,11 +1,17 @@
 #!/usr/bin/env python
 # coding: utf-8
 
-# Copyright (c) Alice Grosch.
+# Copyright (c) Juelich Supercomputing Centre (JSC).
 # Distributed under the terms of the Modified BSD License.
 
 """
-TODO: Add module docstring
+DICOM Upload Widget using the Jupyter Notebook Server RestAPI.
+Uploads DICOM files with anonymized headers, i.e. the 0008 and 
+0010 tags are removed on the JS side before the upload.
+
+Files that aren't in DICOM format are ignored.
+
+Can handle large files by uploading files in chunks.
 """
 from ipywidgets import ValueWidget
 from ipywidgets import register, widget_serialization
@@ -20,7 +26,17 @@ from ._frontend import module_name, module_version
 
 
 class Uploader(DescriptionWidget, ValueWidget):
-    """TODO: Add docstring here
+    """Upload Widget. 
+
+    Uploads DICOM files only via the Jupyter Notebook Server RestAPI,
+    all other files will be ignored.
+    DICOM files are anonymized by removing header tags starting with 
+    0008 and 0010 on the JS side before uploading.
+
+    The widget is able to upload large files by uploading them in chunks.
+    The file contents will however not be directly available over the widget,
+    but will have to be read into the notebook separately.
+
     """
     _model_name = Unicode('UploaderModel').tag(sync=True)
     _model_module = Unicode(module_name).tag(sync=True)
@@ -46,13 +62,17 @@ class Uploader(DescriptionWidget, ValueWidget):
 
     # Variables set on the JavaScript side.
     files = List().tag(sync=True)
-    responses = List([]).tag(sync=True)
+    responses = List().tag(sync=True)
     finished = Bool(False).tag(sync=True)
     hash = Unicode().tag(sync=True)
     _upload = Bool(False).tag(sync=True)
 
     
     def __init__(self, upload_url='http://localhost:8888/api/contents/', token='', *args, **kwargs):
+        """Args:
+            upload_url (str): Jupyter notebook URL appended by api/contents/<path>/. Directories on <path> must already exist.
+            token (str): Jupyter notebook authentication token.
+        """
         super(Uploader, self).__init__(*args, **kwargs)
         self.upload_url = upload_url
         self.token = token
@@ -61,6 +81,6 @@ class Uploader(DescriptionWidget, ValueWidget):
     def _default_description(self):
         return 'Upload'
 
-    # Calls javascript function to upload.
     def upload(self):
+        """Uploads file(s) via the JS fetch API."""
         self._upload = True
\ No newline at end of file
diff --git a/src/widget.ts b/src/widget.ts
index 79a47fdb2452c2e9e2ad59f8d6b2f12f6e627efe..27866a1b00260514c6077c95ad01a44b1e3152be 100644
--- a/src/widget.ts
+++ b/src/widget.ts
@@ -1,4 +1,4 @@
-// Copyright (c) Alice Grosch
+// Copyright (c) Juelich Supercomputing Centre (JSC)
 // Distributed under the terms of the Modified BSD License.
 
 import {