diff --git a/.gitignore b/.gitignore index a78571ac301a..71abb8278ea5 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,11 @@ target/ # Generated data *.csv *.data -*.hdf5 \ No newline at end of file +*.dat +*.hdf5 + +# Temporary files +*.md~ +tmp/ + +docs/examples/data/* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e095e535f825..9a96c5bb5202 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,17 +22,28 @@ Figured out a new way to use qcodes? Found a package that makes your life better ### Setup -- Clone and register the package for development as described in [README.md#installation] +- Clone and register the package for development as described in the [README](README.md#installation) ### Running Tests -The core test runner is in `qcodes/test.py: +The core test runner is in `qcodes/test.py`: ``` python qcodes/test.py -# optional extra verbosity -python qcodes/test.py -v +# optional extra verbosity and fail fast +python qcodes/test.py -v -f ``` -You should see output that looks something like this: + +You can also run single tests with: +``` +# python -m unittest module +# python -m unittest module.class +# python -m unittest module.class.function +python -m unittest qcodes.tests.test_metadata +# or +python -m unittest qcodes.tests.test_metadata.TestMetadatable.test_snapshot +``` + +If you run the core test runner, you should see output that looks something like this: ``` .........***** found one MockMock, testing ***** ............................................Timing resolution: @@ -122,7 +133,7 @@ Coverage testing is generally meaningless for instrument drivers, as calls to `a - Write your new feature or fix. Be sure it doesn't break any existing tests, and please write tests that cover your feature as well, or if you are fixing a bug, write a test that would have failed before your fix. Our goal is 100% test coverage, and although we are not there, we should always strive to increase our coverage with each new feature. Please be aware also that 100% test coverage does NOT necessarily mean 100% logic coverage. If (as is often the case in Python) a single line of code can behave differently for different inputs, coverage in itself will not ensure that this is tested. -- The standard test commands are listed above under [Running Tests](#running_tests). More notes on different test runners can be found in [TESTING.md]. +- The standard test commands are listed above under [Running Tests](#running_tests). More notes on different test runners can be found in [TESTING](TESTING.md). - Core tests live in [qcodes/tests](https://github.com/qdev-dk/Qcodes/tree/master/qcodes/tests) and instrument tests live in the same directories as the instrument drivers. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000000..e38678b0de3a --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,26 @@ +Copyright (c) 2015, 2016 by Microsoft Corporation and Københavns Universitet. + +QCoDeS is currently available only within the Microsoft Station Q collaboration and by specific private arrangement with a beta test group. Please do not share it with anyone who is not part of the beta test program. If you have a coworker who would like access, please contact Alex Johnson (alex.johnson@nbi.ku.dk) to see if they can be added to the program. + +Please report all bugs, limitations, or missing functionality as issues on the Qcodes GitHub. + +We encourage you to contribute any bug fixes or new functionality you develop, especially device drivers, by creating a GitHub branch and submitting a pull request. Note that any code you contribute may be included in the public open source release of QCoDeS. + +We intend to release it as open source software once it is robust and reasonably stable, under the following license terms: + +> QCoDeS is available under the [MIT open-source license](https://opensource.org/licenses/MIT): +> +> 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. + +> 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/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index ad51df55917f..000000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,8 +0,0 @@ -Copyright (c) 2015-16 Alex Johnson - -Qcodes is currently a private development of Microsoft's Station Q -collaboration, and IS NOT licensed for distribution outside the collaboration. -We intend to release it as open source software once it is robust and reasonably -stable under the [MIT license](https://en.wikipedia.org/wiki/MIT_License) or similar, -so that Qcodes may be used freely and incorporated into other packages, even if they -are closed source. diff --git a/README.md b/README.md index 69bdcf1594d6..889fffe45e9f 100644 --- a/README.md +++ b/README.md @@ -45,13 +45,7 @@ If you registered Qcodes with Python via `setup.py develop`, all you need to do See the [docs](docs) directory, particularly the notebooks in [docs/examples](docs/examples) -Until we have this prepared as an installable package, you need to make sure Python can find qcodes by adding the repository root directory to `sys.path`: -``` -import sys -qcpath = 'your/Qcodes/repository/path' -if qcpath not in sys.path: - sys.path.append(qcpath) -``` +For frequently asked questions see the [Qcodes FAQ](docs/FAQ.md). ## Contributing @@ -61,4 +55,4 @@ See the [Roadmap](ROADMAP.md) an overview of where the project intends to go. ## License -Qcodes is currently a private development of Microsoft's Station Q collaboration, and IS NOT licensed for distribution outside the collaboration. We intend to release it as open source software once it is robust and reasonably stable, under the MIT license or similar. See [License](LICENSE.txt) +Qcodes is currently a private development of Microsoft's Station Q collaboration, and IS NOT licensed for distribution outside the collaboration except by arrangement. We intend to release it as open source software once it is robust and reasonably stable, under the MIT license. See [License](LICENSE.md). diff --git a/TESTING.md b/TESTING.md index ef722a208118..83ad966ba7e9 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,6 +1,6 @@ # Notes on test runners compatible with Qcodes -There is now a test script [test.py] in the root directory that uses the standard `unittest` machinery to run all the core tests (does not include instrument drivers). It has been tested on Mac (terminal), and Windows (cmd, git bash, and PowerShell). It includes coverage testing, but will only print a coverage report if tests pass. +There is now a test script [test.py](qcodes/test.py) in the qcodes directory that uses the standard `unittest` machinery to run all the core tests (does not include instrument drivers). It has been tested on Mac (terminal), and Windows (cmd, git bash, and PowerShell). It includes coverage testing, but will only print a coverage report if tests pass. The biggest difficulty with testing Qcodes is windows multiprocessing. The spawn method restricts execution in ways that are annoying for regular users (no class/function definitions in the notebook, no closures) but seem to be completely incompatible with some test runners (and/or coverage tracking) diff --git a/docs/FAQ.md b/docs/FAQ.md new file mode 100644 index 000000000000..62090016b6b0 --- /dev/null +++ b/docs/FAQ.md @@ -0,0 +1,33 @@ +# QCodes FAQ + +This FAQ is intended for users for Qcodes. For development, see Github. + +## Installation + +### How to install Qcodes? + +... +## Usage + +### What are the different ways to run Loops, and when would you use them? + +`Loop.run()` (or `ActiveLoop.run()`) has a two arguments that control where the loop runs and how the data is handled: `background` (`True` (default) or `False`) and `data_manager` (`None` (gets the default `DataManager`) or `False`). + +- Default usage: `Loop.run()`: + Involves two extra processes, one `` process that sequences the loop actions and a `` process that the `` feeds data to, then stores it to disk and provides it to other processes that want it. This is the normal way to run loops, because it minimizes the work done in the measurement process, so it runs as fast as possible, and also keeps the main process free for other tasks like live plotting and analysis. + +- Foreground with a DataManager: `Loop.run(background=False)`: + The measurement loop runs in the process that started it, rather than making a new process, so the starting process blocks until the loop is finished. You might do this to make debugging easier. + +- Background with no DataManager: `Loop.run(data_manager=False)`: + The measurement loop runs in the background, but does not start (or connect to, if one is started already) a `` process; instead, it holds and stores the data itself. If the main process wants to sync this data during acquisition, it will need to read it from disk. Not sure why you would use this mode, but it's possible. + +- Foreground with no DataManager: `Loop.run(background=False, data_manager=False)`: + No extra processes are involved; the measurement loop runs in the process that started it, and holds and saves the data itself. If you want to start another measurement loop while one is already running (for example if you have a complex parameter that runs its own measurement loop to determine some derived value), you need to use this mode. That's because only one background measurement is allowed at a time, and only one `DataSet` may be on the `` at a time. But this mode will still save the `DataSet` it makes; in most such complex parameter cases you want an even more stripped-down loop: `Loop.run_temp()` which just calls: `Loop.run(background=False, quiet=True, data_manager=False, location=False)` so it does not save anything, nor does it print the normal messages that `run` prints describing the `DataSet` it makes. + +### How to abort a running measurement? + +Use `qc.halt_bg()`. To list the active measurements use `qc.active_children()` + + + diff --git a/docs/examples/Load-and-plot-old-data.ipynb b/docs/examples/Load-and-plot-old-data.ipynb index f125d5e0cce4..4c8218d0efd2 100644 --- a/docs/examples/Load-and-plot-old-data.ipynb +++ b/docs/examples/Load-and-plot-old-data.ipynb @@ -1,5 +1,30 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Loading data for analysis: the `load_data` function.\n", + "\n", + "`DataSet` objects are not intended to be instantiated directly, but\n", + "rather through the helper functions:\n", + "- `load_data` for existing data sets, including the data currently\n", + " being acquired.\n", + "- `new_data` to make an empty data set to be populated with new\n", + " measurements or simulation data. `new_data` is called internally by\n", + " `Loop.run()` so is also generally not needed directly.\n", + "\n", + "If you omit `location`, or if `location` matches the data set currently\n", + "being acquired, `load_data` and subsequent calls to `data_set.sync()`\n", + "will pull from the `DataServer` (`DataMode.PULL_FROM_SERVER`).\n", + "Otherwise `load_data` and `data_set.sync()` will read from disk\n", + "(`DataMode.LOCAL`).\n", + "\n", + "Note that a `DataServer` is, at least for now, local to one parent\n", + "process / notebook, so if you open a separate notebook for analysis, even\n", + "your live data will be pulled from disk." + ] + }, { "cell_type": "code", "execution_count": 1, @@ -234,7 +259,7 @@ " min-height: 50px;\n", " max-height: 400px;\n", " min-width: 400px;\n", - " max-width: 700px;\n", + " max-width: 1000px;\n", "}" ], "text/plain": [ @@ -248,8 +273,8 @@ "data": { "text/plain": [ "DataSet: DataMode.LOCAL, location='testsweep'\n", - " amplitude: None\n", - " chan0: None" + " chan0: None\n", + " amplitude: None" ] }, "execution_count": 1, @@ -260,7 +285,7 @@ "source": [ "%matplotlib nbagg\n", "import qcodes as qc\n", - "data = qc.DataSet('testsweep')\n", + "data = qc.load_data('testsweep')\n", "data" ] }, @@ -1050,7 +1075,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -1062,6 +1087,32 @@ "qc.MatPlot(data.amplitude)" ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "RuntimeError", + "evalue": "DataManager has no live data", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mlive_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mload_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# this will be an error because there is no live data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mlive_data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/Users/alex/qdev/Qcodes/qcodes/data/data_set.py\u001b[0m in \u001b[0;36mload_data\u001b[0;34m(location, data_manager, formatter, io)\u001b[0m\n\u001b[1;32m 85\u001b[0m 'not exist or was requested not to be used')\n\u001b[1;32m 86\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 87\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0m_get_live_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata_manager\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 88\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 89\u001b[0m elif (data_manager and\n", + "\u001b[0;32m/Users/alex/qdev/Qcodes/qcodes/data/data_set.py\u001b[0m in \u001b[0;36m_get_live_data\u001b[0;34m(data_manager)\u001b[0m\n\u001b[1;32m 99\u001b[0m \u001b[0mlive_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata_manager\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mask\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'get_data'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 100\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlive_data\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlive_data\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mNoData\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 101\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'DataManager has no live data'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 102\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 103\u001b[0m \u001b[0mlive_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mDataMode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mPULL_FROM_SERVER\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mRuntimeError\u001b[0m: DataManager has no live data" + ] + } + ], + "source": [ + "live_data = qc.load_data() # this will be an error because there is no live data\n", + "live_data" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/docs/examples/Qcodes example parameter call.ipynb b/docs/examples/Qcodes example parameter call.ipynb new file mode 100644 index 000000000000..74ae997c59e2 --- /dev/null +++ b/docs/examples/Qcodes example parameter call.ipynb @@ -0,0 +1,681 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "/*\n", + " * Qcodes Jupyter/IPython widgets\n", + " */\n", + "require([\n", + " 'nbextensions/widgets/widgets/js/widget',\n", + " 'nbextensions/widgets/widgets/js/manager'\n", + "], function (widget, manager) {\n", + "\n", + " var UpdateView = widget.DOMWidgetView.extend({\n", + " render: function() {\n", + " window.MYWIDGET = this;\n", + " this._interval = 0;\n", + " this.update();\n", + " },\n", + " update: function() {\n", + " this.display(this.model.get('_message'));\n", + " this.setInterval();\n", + " },\n", + " display: function(message) {\n", + " /*\n", + " * display method: override this for custom display logic\n", + " */\n", + " this.el.innerHTML = message;\n", + " },\n", + " remove: function() {\n", + " clearInterval(this._updater);\n", + " },\n", + " setInterval: function(newInterval) {\n", + " var me = this;\n", + " if(newInterval===undefined) newInterval = me.model.get('interval');\n", + " if(newInterval===me._interval) return;\n", + "\n", + " me._interval = newInterval;\n", + "\n", + " if(me._updater) clearInterval(me._updater);\n", + "\n", + " if(me._interval) {\n", + " me._updater = setInterval(function() {\n", + " me.send({myupdate: true});\n", + " if(!me.model.comm_live) {\n", + " console.log('missing comm, canceling widget updates', me);\n", + " clearInterval(me._updater);\n", + " }\n", + " }, me._interval * 1000);\n", + " }\n", + " }\n", + " });\n", + " manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\n", + "\n", + " var HiddenUpdateView = UpdateView.extend({\n", + " display: function(message) {\n", + " this.$el.hide();\n", + " }\n", + " });\n", + " manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\n", + "\n", + " var SubprocessView = UpdateView.extend({\n", + " render: function() {\n", + " var me = window.SPVIEW = this;\n", + " me._interval = 0;\n", + " me._minimize = '';\n", + " me._restore = '';\n", + "\n", + " // in case there is already an outputView present,\n", + " // like from before restarting the kernel\n", + " $('.qcodes-output-view').not(me.$el).remove();\n", + "\n", + " me.$el\n", + " .addClass('qcodes-output-view')\n", + " .attr('qcodes-state', 'docked')\n", + " .html(\n", + " '
' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '
' +\n", + " '
'\n",
+       "                );\n",
+       "\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\n",
+       "            me.outputArea = me.$el.find('pre');\n",
+       "            me.subprocessList = me.$el.find('span');\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\n",
+       "\n",
+       "            me.clearButton.click(function() {\n",
+       "                me.outputArea.html('');\n",
+       "                me.clearButton.addClass('disabled');\n",
+       "            });\n",
+       "\n",
+       "            me.abortButton.click(function() {\n",
+       "                me.send({abort: true});\n",
+       "            });\n",
+       "\n",
+       "            me.$el.find('.js-state').click(function() {\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\n",
+       "                        .split('-')[1].split(' ')[0];\n",
+       "\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\n",
+       "                // some other bit of code resets the parent after render if I do it there.\n",
+       "                // To be safe, just do it on every state click.\n",
+       "                me.$el.appendTo('body');\n",
+       "\n",
+       "                if(oldState === 'floated') {\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\n",
+       "                }\n",
+       "\n",
+       "                me.$el.attr('qcodes-state', state);\n",
+       "\n",
+       "                if(state === 'floated') {\n",
+       "                    me.$el.draggable().css({\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\n",
+       "                    });\n",
+       "                }\n",
+       "            });\n",
+       "\n",
+       "            $(window).resize(function() {\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\n",
+       "                    var position = me.$el.position(),\n",
+       "                        minVis = 20,\n",
+       "                        maxLeft = window.innerWidth - minVis,\n",
+       "                        maxTop = window.innerHeight - minVis;\n",
+       "\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\n",
+       "                }\n",
+       "            });\n",
+       "\n",
+       "            me.update();\n",
+       "        },\n",
+       "\n",
+       "        display: function(message) {\n",
+       "            if(message) {\n",
+       "                var initialScroll = this.outputArea.scrollTop();\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\n",
+       "\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\n",
+       "                    this.$el.find('.qcodes-docked').click();\n",
+       "                    // always scroll to the bottom if we're restoring\n",
+       "                    // because of a new message\n",
+       "                    initialScroll = scrollBottom;\n",
+       "                }\n",
+       "\n",
+       "                this.outputArea.append(message);\n",
+       "                this.clearButton.removeClass('disabled');\n",
+       "\n",
+       "                // if we were scrolled to the bottom initially, make sure\n",
+       "                // we stay that way.\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\n",
+       "            }\n",
+       "\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\n",
+       "            this.subprocessList.text(processes);\n",
+       "        }\n",
+       "    });\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\n",
+       "});\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# spawn doesn't like function or class definitions in the interpreter\n",
+    "# session - had to move them to a file.\n",
+    "from toymodel import AModel, MockGates, MockSource, MockMeter, AverageGetter, AverageAndRaw\n",
+    "\n",
+    "# now create this \"experiment\"\n",
+    "model = AModel()\n",
+    "gates = MockGates('gates', model=model)\n",
+    "source = MockSource('source', model=model)\n",
+    "meter = MockMeter('meter', model=model)\n",
+    "\n",
+    "station = qc.Station(gates, source, meter)\n",
+    "\n",
+    "# could measure any number of things by adding arguments to this\n",
+    "# function call, but here we're just measuring one, the meter amplitude\n",
+    "station.set_measurement(meter.amplitude)\n",
+    "\n",
+    "# it's nice to have the key parameters be part of the global namespace\n",
+    "# that way they're objects that we can easily set, get, and slice\n",
+    "# this could be simplified to a station method that gathers all parameters\n",
+    "# and adds them all as (disambiguated) globals, printing what it did\n",
+    "# something like:\n",
+    "#   station.gather_parameters(globals())\n",
+    "c0, c1, c2, vsd = gates.chan0, gates.chan1, gates.chan2, source.amplitude\n",
+    "\n",
+    "# once we have implemented a monitor, defining a station will start a\n",
+    "# DataServer process, and you would see it in the subprocess widget,\n",
+    "# or via active_children() as here:\n",
+    "# qc.active_children()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.117"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "meter.amplitude()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.5"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "vsd(0.5)\n",
+    "vsd()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0.627]"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# we can get the measured quantities right now\n",
+    "station.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# start a Loop\n",
+    "# the sweep values are defined by slicing the parameter object\n",
+    "# but more complicated sweeps (eg nonlinear, or adaptive) can\n",
+    "# easily be used instead\n",
+    "\n",
+    "# run_temp makes this a foreground (blocking) loop with no saving location.\n",
+    "\n",
+    "data = qc.Loop(c0[-20:20:0.1], 0.03).run_temp()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'amplitude': DataArray[400]: amplitude\n",
+       " array([ 0.627,  0.661,  0.69 ,  0.711,  0.723,  0.723,  0.711,  0.687,\n",
+       "         0.653,  0.613,  0.569,  0.524,  0.479,  0.437,  0.398,  0.362,\n",
+       "         0.329,  0.3  ,  0.273,  0.25 ,  0.229,  0.21 ,  0.194,  0.179,\n",
+       "         0.166,  0.154,  0.143,  0.134,  0.125,  0.117,  0.11 ,  0.103,\n",
+       "         0.098,  0.092,  0.087,  0.083,  0.078,  0.075,  0.071,  0.068,\n",
+       "         0.065,  0.062,  0.059,  0.057,  0.054,  0.052,  0.05 ,  0.048,\n",
+       "         0.046,  0.045,  0.043,  0.045,  0.046,  0.048,  0.05 ,  0.052,\n",
+       "         0.054,  0.057,  0.059,  0.062,  0.065,  0.068,  0.071,  0.075,\n",
+       "         0.078,  0.083,  0.087,  0.092,  0.098,  0.103,  0.11 ,  0.117,\n",
+       "         0.125,  0.134,  0.143,  0.154,  0.166,  0.179,  0.194,  0.21 ,\n",
+       "         0.229,  0.25 ,  0.273,  0.3  ,  0.329,  0.362,  0.398,  0.437,\n",
+       "         0.479,  0.524,  0.569,  0.613,  0.653,  0.687,  0.711,  0.723,\n",
+       "         0.723,  0.711,  0.69 ,  0.661,  0.627,  0.661,  0.69 ,  0.711,\n",
+       "         0.723,  0.723,  0.711,  0.687,  0.653,  0.613,  0.569,  0.524,\n",
+       "         0.479,  0.437,  0.398,  0.362,  0.329,  0.3  ,  0.273,  0.25 ,\n",
+       "         0.229,  0.21 ,  0.194,  0.179,  0.166,  0.154,  0.143,  0.134,\n",
+       "         0.125,  0.117,  0.11 ,  0.103,  0.098,  0.092,  0.087,  0.083,\n",
+       "         0.078,  0.075,  0.071,  0.068,  0.065,  0.062,  0.059,  0.057,\n",
+       "         0.054,  0.052,  0.05 ,  0.048,  0.046,  0.045,  0.043,  0.045,\n",
+       "         0.046,  0.048,  0.05 ,  0.052,  0.054,  0.057,  0.059,  0.062,\n",
+       "         0.065,  0.068,  0.071,  0.075,  0.078,  0.083,  0.087,  0.092,\n",
+       "         0.098,  0.103,  0.11 ,  0.117,  0.125,  0.134,  0.143,  0.154,\n",
+       "         0.166,  0.179,  0.194,  0.21 ,  0.229,  0.25 ,  0.273,  0.3  ,\n",
+       "         0.329,  0.362,  0.398,  0.437,  0.479,  0.524,  0.569,  0.613,\n",
+       "         0.653,  0.687,  0.711,  0.723,  0.723,  0.711,  0.69 ,  0.661,\n",
+       "         0.627,  0.661,  0.69 ,  0.711,  0.723,  0.723,  0.711,  0.687,\n",
+       "         0.653,  0.613,  0.569,  0.524,  0.479,  0.437,  0.398,  0.362,\n",
+       "         0.329,  0.3  ,  0.273,  0.25 ,  0.229,  0.21 ,  0.194,  0.179,\n",
+       "         0.166,  0.154,  0.143,  0.134,  0.125,  0.117,  0.11 ,  0.103,\n",
+       "         0.098,  0.092,  0.087,  0.083,  0.078,  0.075,  0.071,  0.068,\n",
+       "         0.065,  0.062,  0.059,  0.057,  0.054,  0.052,  0.05 ,  0.048,\n",
+       "         0.046,  0.045,  0.043,  0.045,  0.046,  0.048,  0.05 ,  0.052,\n",
+       "         0.054,  0.057,  0.059,  0.062,  0.065,  0.068,  0.071,  0.075,\n",
+       "         0.078,  0.083,  0.087,  0.092,  0.098,  0.103,  0.11 ,  0.117,\n",
+       "         0.125,  0.134,  0.143,  0.154,  0.166,  0.179,  0.194,  0.21 ,\n",
+       "         0.229,  0.25 ,  0.273,  0.3  ,  0.329,  0.362,  0.398,  0.437,\n",
+       "         0.479,  0.524,  0.569,  0.613,  0.653,  0.687,  0.711,  0.723,\n",
+       "         0.723,  0.711,  0.69 ,  0.661,  0.627,  0.661,  0.69 ,  0.711,\n",
+       "         0.723,  0.723,  0.711,  0.687,  0.653,  0.613,  0.569,  0.524,\n",
+       "         0.479,  0.437,  0.398,  0.362,  0.329,  0.3  ,  0.273,  0.25 ,\n",
+       "         0.229,  0.21 ,  0.194,  0.179,  0.166,  0.154,  0.143,  0.134,\n",
+       "         0.125,  0.117,  0.11 ,  0.103,  0.098,  0.092,  0.087,  0.083,\n",
+       "         0.078,  0.075,  0.071,  0.068,  0.065,  0.062,  0.059,  0.057,\n",
+       "         0.054,  0.052,  0.05 ,  0.048,  0.046,  0.045,  0.043,  0.045,\n",
+       "         0.046,  0.048,  0.05 ,  0.052,  0.054,  0.057,  0.059,  0.062,\n",
+       "         0.065,  0.068,  0.071,  0.075,  0.078,  0.083,  0.087,  0.092,\n",
+       "         0.098,  0.103,  0.11 ,  0.117,  0.125,  0.134,  0.143,  0.154,\n",
+       "         0.166,  0.179,  0.194,  0.21 ,  0.229,  0.25 ,  0.273,  0.3  ,\n",
+       "         0.329,  0.362,  0.398,  0.437,  0.479,  0.524,  0.569,  0.613,\n",
+       "         0.653,  0.687,  0.711,  0.723,  0.723,  0.711,  0.69 ,  0.661]),\n",
+       " 'chan0': DataArray[400]: chan0\n",
+       " array([-20. , -19.9, -19.8, -19.7, -19.6, -19.5, -19.4, -19.3, -19.2,\n",
+       "        -19.1, -19. , -18.9, -18.8, -18.7, -18.6, -18.5, -18.4, -18.3,\n",
+       "        -18.2, -18.1, -18. , -17.9, -17.8, -17.7, -17.6, -17.5, -17.4,\n",
+       "        -17.3, -17.2, -17.1, -17. , -16.9, -16.8, -16.7, -16.6, -16.5,\n",
+       "        -16.4, -16.3, -16.2, -16.1, -16. , -15.9, -15.8, -15.7, -15.6,\n",
+       "        -15.5, -15.4, -15.3, -15.2, -15.1, -15. , -14.9, -14.8, -14.7,\n",
+       "        -14.6, -14.5, -14.4, -14.3, -14.2, -14.1, -14. , -13.9, -13.8,\n",
+       "        -13.7, -13.6, -13.5, -13.4, -13.3, -13.2, -13.1, -13. , -12.9,\n",
+       "        -12.8, -12.7, -12.6, -12.5, -12.4, -12.3, -12.2, -12.1, -12. ,\n",
+       "        -11.9, -11.8, -11.7, -11.6, -11.5, -11.4, -11.3, -11.2, -11.1,\n",
+       "        -11. , -10.9, -10.8, -10.7, -10.6, -10.5, -10.4, -10.3, -10.2,\n",
+       "        -10.1, -10. ,  -9.9,  -9.8,  -9.7,  -9.6,  -9.5,  -9.4,  -9.3,\n",
+       "         -9.2,  -9.1,  -9. ,  -8.9,  -8.8,  -8.7,  -8.6,  -8.5,  -8.4,\n",
+       "         -8.3,  -8.2,  -8.1,  -8. ,  -7.9,  -7.8,  -7.7,  -7.6,  -7.5,\n",
+       "         -7.4,  -7.3,  -7.2,  -7.1,  -7. ,  -6.9,  -6.8,  -6.7,  -6.6,\n",
+       "         -6.5,  -6.4,  -6.3,  -6.2,  -6.1,  -6. ,  -5.9,  -5.8,  -5.7,\n",
+       "         -5.6,  -5.5,  -5.4,  -5.3,  -5.2,  -5.1,  -5. ,  -4.9,  -4.8,\n",
+       "         -4.7,  -4.6,  -4.5,  -4.4,  -4.3,  -4.2,  -4.1,  -4. ,  -3.9,\n",
+       "         -3.8,  -3.7,  -3.6,  -3.5,  -3.4,  -3.3,  -3.2,  -3.1,  -3. ,\n",
+       "         -2.9,  -2.8,  -2.7,  -2.6,  -2.5,  -2.4,  -2.3,  -2.2,  -2.1,\n",
+       "         -2. ,  -1.9,  -1.8,  -1.7,  -1.6,  -1.5,  -1.4,  -1.3,  -1.2,\n",
+       "         -1.1,  -1. ,  -0.9,  -0.8,  -0.7,  -0.6,  -0.5,  -0.4,  -0.3,\n",
+       "         -0.2,  -0.1,   0. ,   0.1,   0.2,   0.3,   0.4,   0.5,   0.6,\n",
+       "          0.7,   0.8,   0.9,   1. ,   1.1,   1.2,   1.3,   1.4,   1.5,\n",
+       "          1.6,   1.7,   1.8,   1.9,   2. ,   2.1,   2.2,   2.3,   2.4,\n",
+       "          2.5,   2.6,   2.7,   2.8,   2.9,   3. ,   3.1,   3.2,   3.3,\n",
+       "          3.4,   3.5,   3.6,   3.7,   3.8,   3.9,   4. ,   4.1,   4.2,\n",
+       "          4.3,   4.4,   4.5,   4.6,   4.7,   4.8,   4.9,   5. ,   5.1,\n",
+       "          5.2,   5.3,   5.4,   5.5,   5.6,   5.7,   5.8,   5.9,   6. ,\n",
+       "          6.1,   6.2,   6.3,   6.4,   6.5,   6.6,   6.7,   6.8,   6.9,\n",
+       "          7. ,   7.1,   7.2,   7.3,   7.4,   7.5,   7.6,   7.7,   7.8,\n",
+       "          7.9,   8. ,   8.1,   8.2,   8.3,   8.4,   8.5,   8.6,   8.7,\n",
+       "          8.8,   8.9,   9. ,   9.1,   9.2,   9.3,   9.4,   9.5,   9.6,\n",
+       "          9.7,   9.8,   9.9,  10. ,  10.1,  10.2,  10.3,  10.4,  10.5,\n",
+       "         10.6,  10.7,  10.8,  10.9,  11. ,  11.1,  11.2,  11.3,  11.4,\n",
+       "         11.5,  11.6,  11.7,  11.8,  11.9,  12. ,  12.1,  12.2,  12.3,\n",
+       "         12.4,  12.5,  12.6,  12.7,  12.8,  12.9,  13. ,  13.1,  13.2,\n",
+       "         13.3,  13.4,  13.5,  13.6,  13.7,  13.8,  13.9,  14. ,  14.1,\n",
+       "         14.2,  14.3,  14.4,  14.5,  14.6,  14.7,  14.8,  14.9,  15. ,\n",
+       "         15.1,  15.2,  15.3,  15.4,  15.5,  15.6,  15.7,  15.8,  15.9,\n",
+       "         16. ,  16.1,  16.2,  16.3,  16.4,  16.5,  16.6,  16.7,  16.8,\n",
+       "         16.9,  17. ,  17.1,  17.2,  17.3,  17.4,  17.5,  17.6,  17.7,\n",
+       "         17.8,  17.9,  18. ,  18.1,  18.2,  18.3,  18.4,  18.5,  18.6,\n",
+       "         18.7,  18.8,  18.9,  19. ,  19.1,  19.2,  19.3,  19.4,  19.5,\n",
+       "         19.6,  19.7,  19.8,  19.9])}"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# manually bring the data into the main process and display it as numbers\n",
+    "data.sync()\n",
+    "data.arrays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "# live-updating plot, that syncs the data and stops updating when it's finished\n",
+    "# plot = qc.MatPlot(data.amplitude)\n",
+    "plotQ = qc.QtPlot(data.amplitude)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
+      "   chan0: chan0\n",
+      "   amplitude_3: amplitude\n",
+      "   chan1: chan1\n",
+      "   amplitude_0: amplitude\n",
+      "started at 2016-04-20 12:16:14\n"
+     ]
+    }
+   ],
+   "source": [
+    "data2 = qc.Loop(c1[-15:15:1], 0.1).loop(c0[-15:12:.5], 0.01).each(\n",
+    "    meter.amplitude, # first measurement, at c2=0 -> amplitude_0 bcs it's action 0\n",
+    "    qc.Task(c2.set, 1), # action 1 -> c2.set(1)\n",
+    "    qc.Wait(0.001),\n",
+    "    meter.amplitude, # second measurement, at c2=1 -> amplitude_4 bcs it's action 4\n",
+    "    qc.Task(c2.set, 0)\n",
+    "    ).run(location='test2d', overwrite=True)\n",
+    "\n",
+    "# use the subplot and add features of qc.MatPlot\n",
+    "# plot2 = qc.MatPlot(data2.amplitude_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1, 2))\n",
+    "# plot2.add(data2.amplitude_3, cmap=plt.cm.hot, subplot=2)\n",
+    "\n",
+    "# the equivalent in QtPlot\n",
+    "plot2Q = qc.QtPlot(data2.amplitude_0, figsize=(1200, 500))\n",
+    "plot2Q.add(data2.amplitude_3, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
+      "   amplitude_3_0: amplitude\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan1: chan1\n",
+      "   amplitude_5_0: amplitude\n",
+      "   chan0: chan0\n",
+      "   amplitude_2: amplitude\n",
+      "started at 2016-04-18 16:23:45\n"
+     ]
+    }
+   ],
+   "source": [
+    "data3 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
+    "    qc.Task(c0.set, -10),\n",
+    "    qc.Task(c2.set, 0),\n",
+    "    # a 1D measurement\n",
+    "    meter.amplitude,\n",
+    "    # a 2D sweep, .each is actually unnecessary bcs this is the default measurement\n",
+    "    qc.Loop(c0[-15:15:1], 0.001).each(meter.amplitude),\n",
+    "    qc.Task(c0.set, -10),\n",
+    "    # a 2D sweep with the same outer but different inner loop\n",
+    "    qc.Loop(c2[-10:10:0.2], 0.001),\n",
+    "    AverageGetter(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
+    ").run(location='test_multi_d', overwrite=True)\n",
+    "\n",
+    "# several plots updating simultaneously\n",
+    "# plot3 = qc.MatPlot(data3.amplitude_3_0, cmap=plt.cm.hot)\n",
+    "# plot3b = qc.MatPlot(data3.amplitude_5_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\n",
+    "# plot3b.add(data3.avg_amplitude, subplot=2)\n",
+    "plot3Q = qc.QtPlot(data3.amplitude_3_0)\n",
+    "plot3bQ = qc.QtPlot(data3.amplitude_5_0, figsize=(1200, 500))\n",
+    "plot3bQ.add(data3.avg_amplitude, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan1: chan1\n",
+      "   amplitude: amplitude\n",
+      "started at 2016-04-18 16:24:13\n"
+     ]
+    }
+   ],
+   "source": [
+    "# An example of a parameter that returns several values of different dimension\n",
+    "# This produces the last two arrays from data3, but only takes the data once.\n",
+    "data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
+    "    AverageAndRaw(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
+    ").run(location='test_complex_param', overwrite=True)\n",
+    "\n",
+    "# plot4 = qc.MatPlot(data4.amplitude, cmap=plt.cm.hot, subplots=(1,2), figsize=(12, 4.5))\n",
+    "# plot4.add(data4.avg_amplitude, subplot=2)\n",
+    "plot4Q = qc.QtPlot(data4.amplitude, figsize=(1200, 500))\n",
+    "plot4Q.add(data4.avg_amplitude, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.0"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Agilent 34400A.ipynb b/docs/examples/Qcodes example with Agilent 34400A.ipynb
new file mode 100644
index 000000000000..b4c778442893
--- /dev/null
+++ b/docs/examples/Qcodes example with Agilent 34400A.ipynb	
@@ -0,0 +1,455 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "from qcodes.utils.validators import Enum, Strings\n",
+    "import qcodes.instrument_drivers.tektronix.Keithley_2600 as keith\n",
+    "import qcodes.instrument_drivers.agilent.Agilent_34400A as agi\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "class Timer(object):\n",
+    "    def __init__(self, name=None):\n",
+    "        self.name = name\n",
+    "\n",
+    "    def __enter__(self):\n",
+    "        self.tstart = time.time()\n",
+    "\n",
+    "    def __exit__(self, type, value, traceback):\n",
+    "        if self.name:\n",
+    "            print('[%s]' % self.name,)\n",
+    "        print('Elapsed: %s' % (time.time() - self.tstart))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# create Instruments\n",
+    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a')\n",
+    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b')\n",
+    "\n",
+    "a1 = agi.Agilent_34400A('Agilent1', 'GPIB0::11::INSTR')\n",
+    "a2 = agi.Agilent_34400A('Agilent2', 'GPIB0::6::INSTR')\n",
+    "\n",
+    "# set integration time (number of line cycles)\n",
+    "a1.NPLC.set(10)\n",
+    "a2.NPLC.set(10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "station1 = qc.Station(a1,a2)\n",
+    "station1.set_measurement(a1.volt)\n",
+    "station2 = qc.Station(a1,a2)\n",
+    "station2.set_measurement(a1.volt, a2.volt)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Time s1]\n",
+      "Elapsed: 2.0011143684387207\n"
+     ]
+    },
+    {
+     "ename": "Empty",
+     "evalue": "",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mEmpty\u001b[0m                                     Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# Time single readings\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mTimer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Time s1'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m     \u001b[0mstation1\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmeasure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      4\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mTimer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Time s2'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mstation2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmeasure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\station.py\u001b[0m in \u001b[0;36mmeasure\u001b[1;34m(self, *actions)\u001b[0m\n\u001b[0;32m    105\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0maction\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mactions\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    106\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'get'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 107\u001b[1;33m                 \u001b[0mout\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    108\u001b[0m             \u001b[1;32melif\u001b[0m \u001b[0mcallable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    109\u001b[0m                 \u001b[0maction\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\instrument\\remote.py\u001b[0m in \u001b[0;36mget\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    121\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    122\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 123\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_instrument\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mconnection\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'get'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    124\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    125\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\instrument\\server.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, func_name, *args, **kwargs)\u001b[0m\n\u001b[0;32m    134\u001b[0m         \u001b[0mQuery\u001b[0m \u001b[0mthe\u001b[0m \u001b[0mserver\u001b[0m \u001b[0mcopy\u001b[0m \u001b[0mof\u001b[0m \u001b[0mthis\u001b[0m \u001b[0minstrument\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mexpecting\u001b[0m \u001b[0ma\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    135\u001b[0m         '''\n\u001b[1;32m--> 136\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmanager\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'ask'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mid\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfunc_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    137\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    138\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfunc_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, timeout, *query)\u001b[0m\n\u001b[0;32m    332\u001b[0m                 \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_error_queue\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mempty\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    333\u001b[0m                     \u001b[1;31m# only raise if we're not about to find a deeper error\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 334\u001b[1;33m                     \u001b[1;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    335\u001b[0m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_for_errors\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_expect_error\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    336\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, timeout, *query)\u001b[0m\n\u001b[0;32m    324\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    325\u001b[0m             \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 326\u001b[1;33m                 \u001b[0mres\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_response\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    327\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    328\u001b[0m                 \u001b[1;32mwhile\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_response_queue\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mempty\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36m_check_response\u001b[1;34m(self, timeout)\u001b[0m\n\u001b[0;32m    301\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    302\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_check_response\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 303\u001b[1;33m         \u001b[0mres\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_response_queue\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    304\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mres\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mSERVER_ERR\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    305\u001b[0m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_expect_error\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mc:\\users\\qdev\\anaconda3\\lib\\multiprocessing\\queues.py\u001b[0m in \u001b[0;36mget\u001b[1;34m(self, block, timeout)\u001b[0m\n\u001b[0;32m    103\u001b[0m                     \u001b[0mtimeout\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdeadline\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mtime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    104\u001b[0m                     \u001b[1;32mif\u001b[0m \u001b[0mtimeout\u001b[0m \u001b[1;33m<\u001b[0m \u001b[1;36m0\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 105\u001b[1;33m                         \u001b[1;32mraise\u001b[0m \u001b[0mEmpty\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    106\u001b[0m                 \u001b[1;32melif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    107\u001b[0m                     \u001b[1;32mraise\u001b[0m \u001b[0mEmpty\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mEmpty\u001b[0m: "
+     ]
+    }
+   ],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time s1'):\n",
+    "    station1.measure()\n",
+    "with Timer('Time s2'):\n",
+    "    station2.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time a1'):\n",
+    "    a1.volt.get()\n",
+    "with Timer('Time a2'):\n",
+    "    a2.volt.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True,background=False)\n",
+    "\n",
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True,background=False)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Ithaco.ipynb b/docs/examples/Qcodes example with Ithaco.ipynb
new file mode 100644
index 000000000000..59c370425723
--- /dev/null
+++ b/docs/examples/Qcodes example with Ithaco.ipynb	
@@ -0,0 +1,666 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# %matplotlib nbagg\n",
+    "%gui qt \n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "from qcodes.utils.validators import Enum, Strings\n",
+    "import qcodes.instrument_drivers.tektronix.Keithley_2600 as keith\n",
+    "import qcodes.instrument_drivers.agilent.Agilent_34400A as agi\n",
+    "import qcodes.instrument_drivers.ithaco.Ithaco_1211 as ithaco\n",
+    "\n",
+    "from qcodes.instrument.parameter import Parameter, StandardParameter\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "class Timer(object):\n",
+    "    def __init__(self, name=None):\n",
+    "        self.name = name\n",
+    "\n",
+    "    def __enter__(self):\n",
+    "        self.tstart = time.time()\n",
+    "\n",
+    "    def __exit__(self, type, value, traceback):\n",
+    "        if self.name:\n",
+    "            print('[%s]' % self.name,)\n",
+    "        print('Elapsed: %s' % (time.time() - self.tstart))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# create Instruments\n",
+    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a')\n",
+    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b')\n",
+    "\n",
+    "a1 = agi.Agilent_34400A('Agilent1', 'GPIB0::11::INSTR')\n",
+    "a2 = agi.Agilent_34400A('Agilent2', 'GPIB0::6::INSTR')\n",
+    "\n",
+    "camp = ithaco.Ithaco_1211('camp1')\n",
+    "camp.sens.set(1e-4)\n",
+    "\n",
+    "curr = ithaco.CurrentParameter(a2.volt, camp)\n",
+    "\n",
+    "# set integration time (number of line cycles)\n",
+    "a1.NPLC.set(1)\n",
+    "a2.NPLC.set(1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'functions': {},\n",
+       " 'metadata': {'info': {'model': '1211',\n",
+       "   'serial_number': None,\n",
+       "   'software_revision': None,\n",
+       "   'vendor': 'Ithaco (DL Instruments)'}},\n",
+       " 'parameters': {'invert': {'ts': '2016-04-21 15:56:06', 'value': True},\n",
+       "  'risetime': {'ts': '2016-04-21 15:56:06', 'value': 0.3},\n",
+       "  'sens': {'ts': '2016-04-21 15:56:06', 'value': 0.0001},\n",
+       "  'sens_x': {'ts': '2016-04-21 15:56:06', 'value': 1},\n",
+       "  'suppression': {'ts': '2016-04-21 15:56:06', 'value': 1e-07}}}"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "camp.snapshot()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'V'"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a2.volt.units"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('V', 'A')"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "curr.units"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   current: current\n",
+      "   volt: volt\n",
+      "   volt_set: volt\n",
+      "started at 2016-04-21 15:56:10\n"
+     ]
+    }
+   ],
+   "source": [
+    "data = qc.Loop(k1.volt[-5:5:1], 0).each(curr).run(location='testsweep', overwrite=True)\n",
+    "plotQ = qc.QtPlot(data.current,windowTitle='YEAH')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ""
+      ]
+     },
+     "execution_count": 16,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "plotQ"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'current': DataArray[10]: current\n",
+       " array([ -4.98941000e-04,  -3.99618000e-04,  -3.00370000e-04,\n",
+       "         -2.01084000e-04,  -1.01763000e-04,  -2.42637000e-06,\n",
+       "          9.69014000e-05,   1.96216000e-04,   2.95535000e-04,\n",
+       "          3.94851000e-04]), 'volt': DataArray[10]: volt\n",
+       " array([ 4.98941  ,  3.99618  ,  3.0037   ,  2.01084  ,  1.01763  ,\n",
+       "         0.0242637, -0.969014 , -1.96216  , -2.95535  , -3.94851  ]), 'volt_set': DataArray[10]: volt_set\n",
+       " array([-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.])}"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "data.sync()\n",
+    "data.arrays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "station1 = qc.Station(a1,a2)\n",
+    "station1.set_measurement(a1.volt)\n",
+    "station2 = qc.Station(a1,a2)\n",
+    "station2.set_measurement(a1.volt, a2.volt)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Time s1]\n",
+      "Elapsed: 0.05600309371948242\n",
+      "[Time s2]\n",
+      "Elapsed: 0.10500597953796387\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time s1'):\n",
+    "    station1.measure()\n",
+    "with Timer('Time s2'):\n",
+    "    station2.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Time a1]\n",
+      "Elapsed: 0.05600309371948242\n",
+      "[Time a2]\n",
+      "Elapsed: 0.049002885818481445\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time a1'):\n",
+    "    a1.volt.get()\n",
+    "with Timer('Time a2'):\n",
+    "    a2.volt.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt: volt\n",
+      "started at 2016-04-21 15:51:15\n",
+      "[Time Loop 1]\n",
+      "Elapsed: 0.5770328044891357\n",
+      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt_0: volt\n",
+      "   volt_1: volt\n",
+      "started at 2016-04-21 15:51:16\n",
+      "[Time Loop 2]\n",
+      "Elapsed: 1.0900623798370361\n"
+     ]
+    }
+   ],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True,background=False)\n",
+    "\n",
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True,background=False)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt: volt\n",
+      "started at 2016-04-21 15:51:16\n",
+      "[Time Loop 1]\n",
+      "Elapsed: 1.075061559677124\n"
+     ]
+    }
+   ],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt_0: volt\n",
+      "   volt_1: volt\n",
+      "started at 2016-04-21 15:51:17\n",
+      "[Time Loop 2]\n",
+      "Elapsed: 1.569089651107788\n"
+     ]
+    }
+   ],
+   "source": [
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Keithley 2600.ipynb b/docs/examples/Qcodes example with Keithley 2600.ipynb
new file mode 100644
index 000000000000..2df8a5e6e2d4
--- /dev/null
+++ b/docs/examples/Qcodes example with Keithley 2600.ipynb	
@@ -0,0 +1,730 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "No loop running\n"
+     ]
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.halt_bg()\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import qcodes.instrument_drivers.tektronix.Keithley_2600 as keith"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# spawn doesn't like function or class definitions in the interpreter\n",
+    "# session - had to move them to a file.\n",
+    "\n",
+    "# now create this \"experiment\"\n",
+    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a')#,server_name=None)\n",
+    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b')#,server_name=None)\n",
+    "\n",
+    "station = qc.Station(k1,k2)\n",
+    "\n",
+    "# could measure any number of things by adding arguments to this\n",
+    "# function call, but here we're just measuring one, the meter amplitude\n",
+    "station.set_measurement(k1.curr,k2.curr)\n",
+    "\n",
+    "# it's nice to have the key parameters be part of the global namespace\n",
+    "# that way they're objects that we can easily set, get, and slice\n",
+    "# this could be simplified to a station method that gathers all parameters\n",
+    "# and adds them all as (disambiguated) globals, printing what it did\n",
+    "# something like:\n",
+    "#   station.gather_parameters(globals())\n",
+    "\n",
+    "vsd1, vsd2, curr1, curr2 = k1.volt, k2.volt, k1.curr, k2.curr\n",
+    "\n",
+    "# once we have implemented a monitor, defining a station will start a\n",
+    "# DataServer process, and you would see it in the subprocess widget,\n",
+    "# or via active_children() as here:\n",
+    "# qc.active_children()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'instruments': {'Keithley1': {'functions': {},\n",
+       "   'metadata': {'info': {'model': '2614B',\n",
+       "     'serial_number': '4083825',\n",
+       "     'software_revision': '3.2.1',\n",
+       "     'vendor': 'Keithley Instruments Inc.'}},\n",
+       "   'parameters': {'curr': {'ts': None, 'value': None},\n",
+       "    'limiti': {'ts': None, 'value': None},\n",
+       "    'limitv': {'ts': None, 'value': None},\n",
+       "    'mode': {'ts': None, 'value': None},\n",
+       "    'output': {'ts': None, 'value': None},\n",
+       "    'rangei': {'ts': None, 'value': None},\n",
+       "    'rangev': {'ts': None, 'value': None},\n",
+       "    'volt': {'ts': None, 'value': None}}},\n",
+       "  'Keithley2': {'functions': {},\n",
+       "   'metadata': {'info': {'model': '2614B',\n",
+       "     'serial_number': '4083825',\n",
+       "     'software_revision': '3.2.1',\n",
+       "     'vendor': 'Keithley Instruments Inc.'}},\n",
+       "   'parameters': {'curr': {'ts': None, 'value': None},\n",
+       "    'limiti': {'ts': None, 'value': None},\n",
+       "    'limitv': {'ts': None, 'value': None},\n",
+       "    'mode': {'ts': None, 'value': None},\n",
+       "    'output': {'ts': None, 'value': None},\n",
+       "    'rangei': {'ts': None, 'value': None},\n",
+       "    'rangev': {'ts': None, 'value': None},\n",
+       "    'volt': {'ts': None, 'value': None}}}}}"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "station.snapshot()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[2.98023e-13, -9.41753e-13]"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# we can get the measured quantities right now\n",
+    "station.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   curr_0: curr\n",
+      "   curr_1: curr\n",
+      "   volt: volt\n",
+      "started at 2016-04-20 15:37:23\n"
+     ]
+    }
+   ],
+   "source": [
+    "# start a Loop (which by default runs in a seprarate process)\n",
+    "# the sweep values are defined by slicing the parameter object\n",
+    "# but more complicated sweeps (eg nonlinear, or adaptive) can\n",
+    "# easily be used instead\n",
+    "\n",
+    "# Notice that I'm using an explicit location and `overwrite=True` here so that\n",
+    "# running this notebook over and over won't result in extra files.\n",
+    "# But if you leave these out, you get a new timestamped DataSet each time.\n",
+    "data = qc.Loop(vsd1[-5:5:0.5], 0.03).run(location='testsweep', overwrite=True)\n",
+    "\n",
+    "# now there should be two extra processes running, DataServer and a sweep\n",
+    "# I'll omit the active_children call now because you can see them in the\n",
+    "# subprocess widget"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'curr_0': DataArray[20]: curr_0\n",
+       " array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,\n",
+       "         nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan]),\n",
+       " 'curr_1': DataArray[20]: curr_1\n",
+       " array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,\n",
+       "         nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan]),\n",
+       " 'volt': DataArray[20]: volt\n",
+       " array([ -5.,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,\n",
+       "         nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan])}"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# manually bring the data into the main process and display it as numbers\n",
+    "data.sync()\n",
+    "data.arrays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "# live-updating plot, that syncs the data and stops updating when it's finished\n",
+    "# plot = qc.MatPlot(data.amplitude)\n",
+    "plotQ1 = qc.QtPlot(data.volt, data.curr_0)\n",
+    "plotQ2 = qc.QtPlot(data.volt, data.curr_1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
+      "   curr_1: curr\n",
+      "   volt: volt\n",
+      "   curr_0: curr\n",
+      "   volt_0: volt\n",
+      "started at 2016-04-20 15:22:46\n"
+     ]
+    }
+   ],
+   "source": [
+    "data2 = qc.Loop(vsd1[-5:5:0.1],0).each(\n",
+    "                qc.Loop(vsd2[-2:2:.2], 0)\n",
+    ").run(location='test2d', overwrite=True)\n",
+    "\n",
+    "# use the subplot and add features of qc.MatPlot\n",
+    "# plot2 = qc.MatPlot(data2.amplitude_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1, 2))\n",
+    "# plot2.add(data2.amplitude_3, cmap=plt.cm.hot, subplot=2)\n",
+    "\n",
+    "# the equivalent in QtPlot\n",
+    "plot2Q = qc.QtPlot(data2.curr_1, figsize=(1200, 500))\n",
+    "# plot2Q.add(data2.curr_1, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'model': '2614B',\n",
+       " 'serial_number': '4083825',\n",
+       " 'software_revision': '3.2.1',\n",
+       " 'vendor': 'Keithley Instruments Inc.'}"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "k1.setattr(('metadata','test'), 11)\n",
+    "k1.getattr('info')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'Keithley Instruments Inc., Model 2614B, 4083825, 3.2.1'"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "k1.ask_direct('*IDN?')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'instruments': {'Keithley1': {'functions': {},\n",
+       "   'metadata': {'test': 11},\n",
+       "   'parameters': {'curr': {'ts': '2016-04-20 15:31:51', 'value': -2.14577e-13},\n",
+       "    'limiti': {'ts': '2016-04-20 15:31:51', 'value': 0.1},\n",
+       "    'limitv': {'ts': '2016-04-20 15:31:51', 'value': 20.0},\n",
+       "    'mode': {'ts': '2016-04-20 15:31:51', 'value': 'voltage'},\n",
+       "    'output': {'ts': '2016-04-20 15:31:51', 'value': 'ON'},\n",
+       "    'rangei': {'ts': '2016-04-20 15:31:51', 'value': 1e-07},\n",
+       "    'rangev': {'ts': '2016-04-20 15:31:51', 'value': 20.0},\n",
+       "    'volt': {'ts': '2016-04-20 15:31:51', 'value': 4.90016}}},\n",
+       "  'Keithley2': {'functions': {},\n",
+       "   'parameters': {'curr': {'ts': '2016-04-20 15:31:51', 'value': -1.07288e-12},\n",
+       "    'limiti': {'ts': '2016-04-20 15:31:51', 'value': 0.1},\n",
+       "    'limitv': {'ts': '2016-04-20 15:31:51', 'value': 20.0},\n",
+       "    'mode': {'ts': '2016-04-20 15:31:51', 'value': 'voltage'},\n",
+       "    'output': {'ts': '2016-04-20 15:31:51', 'value': 'ON'},\n",
+       "    'rangei': {'ts': '2016-04-20 15:31:51', 'value': 1e-07},\n",
+       "    'rangev': {'ts': '2016-04-20 15:31:51', 'value': 2.0},\n",
+       "    'volt': {'ts': '2016-04-20 15:31:51', 'value': 1.80006}}}}}"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "station.snapshot(update=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "plot2Q.add(data2.curr_0, subplot=2)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
+      "   curr_0_1: curr\n",
+      "   volt_0: volt\n",
+      "   curr_0_0: curr\n",
+      "   volt_1: volt\n",
+      "   curr_1_0: curr\n",
+      "   curr_1_1: curr\n",
+      "   volt: volt\n",
+      "started at 2016-04-20 14:09:16\n"
+     ]
+    },
+    {
+     "ename": "AttributeError",
+     "evalue": "'DataSet' object and its delegates have no attribute 'curr_1'",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[1;31m# plot3b = qc.MatPlot(data3.curr_1_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# plot3b.add(data3.curr_0_1, subplot=2)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mplot3Q\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     11\u001b[0m \u001b[0mplot3bQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfigsize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1200\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m500\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[0mplot3bQ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msubplot\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\helpers.py\u001b[0m in \u001b[0;36m__getattr__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m    187\u001b[0m         raise AttributeError(\n\u001b[0;32m    188\u001b[0m             \"'{}' object and its delegates have no attribute '{}'\".format(\n\u001b[1;32m--> 189\u001b[1;33m                 self.__class__.__name__, key))\n\u001b[0m\u001b[0;32m    190\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    191\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m__dir__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mAttributeError\u001b[0m: 'DataSet' object and its delegates have no attribute 'curr_1'"
+     ]
+    }
+   ],
+   "source": [
+    "data3 = qc.Loop(vsd1[-15:15:1], 0).each(\n",
+    "                qc.Loop(vsd2[-5:5:1], 0),\n",
+    "                qc.Loop(vsd2[5:-5:1], 0),\n",
+    ").run(location='test_multi_d', overwrite=True)\n",
+    "\n",
+    "# several plots updating simultaneously\n",
+    "# plot3 = qc.MatPlot(data3.curr_1_1, cmap=plt.cm.hot)\n",
+    "# plot3b = qc.MatPlot(data3.curr_1_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\n",
+    "# plot3b.add(data3.curr_0_1, subplot=2)\n",
+    "plot3Q = qc.QtPlot(data3.curr_1)\n",
+    "plot3bQ = qc.QtPlot(data3.curr_1, figsize=(1200, 500))\n",
+    "plot3bQ.add(data3.curr_0, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan1: chan1\n",
+      "   amplitude: amplitude\n",
+      "started at 2016-02-02 12:18:09\n"
+     ]
+    }
+   ],
+   "source": [
+    "# An example of a parameter that returns several values of different dimension\n",
+    "# This produces the last two arrays from data3, but only takes the data once.\n",
+    "data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
+    "    AverageAndRaw(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
+    ").run(location='test_complex_param', overwrite=True)\n",
+    "\n",
+    "# plot4 = qc.MatPlot(data4.amplitude, cmap=plt.cm.hot, subplots=(1,2), figsize=(12, 4.5))\n",
+    "# plot4.add(data4.avg_amplitude, subplot=2)\n",
+    "plot4Q = qc.QtPlot(data4.amplitude, figsize=(1200, 500))\n",
+    "plot4Q.add(data4.avg_amplitude, subplot=2)"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Mercury IPS (Magnet).ipynb b/docs/examples/Qcodes example with Mercury IPS (Magnet).ipynb
new file mode 100644
index 000000000000..58bd186f0453
--- /dev/null
+++ b/docs/examples/Qcodes example with Mercury IPS (Magnet).ipynb	
@@ -0,0 +1,432 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "import re\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "from qcodes.instrument_drivers.oxford.mercuryiPS import MercuryiPS"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "magnet = MercuryiPS(name = 'Magnet', address='ASRL10::INSTR')# , server_name=None"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0.0\n",
+      "3.352161306002045e-06\n"
+     ]
+    }
+   ],
+   "source": [
+    "# this does not work with the remote server thing\n",
+    "# print(magnet.axes)\n",
+    "# print(magnet.info)\n",
+    "print(magnet.x_fld.get())\n",
+    "print(magnet.x_fldC.get())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'HOLD'"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# magnet.hold()\n",
+    "magnet.x_ACTN.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.05"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "magnet.x_rate.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.0"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "magnet.x_setpoint.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "RTOZ\n",
+      "HOLD\n"
+     ]
+    }
+   ],
+   "source": [
+    "magnet.x_ACTN.set('RTOZ')\n",
+    "print(magnet.x_ACTN.get())\n",
+    "time.sleep(1)\n",
+    "print(magnet.x_ACTN.get())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Triton.ipynb b/docs/examples/Qcodes example with Triton.ipynb
new file mode 100644
index 000000000000..dd3d40e41485
--- /dev/null
+++ b/docs/examples/Qcodes example with Triton.ipynb	
@@ -0,0 +1,364 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "13:21:17\n",
+      "23.3481\n",
+      "23.3481\n",
+      "Idle\n",
+      "OK\n"
+     ]
+    }
+   ],
+   "source": [
+    "import qcodes.instrument_drivers.oxford.triton as triton\n",
+    "\n",
+    "\n",
+    "triton = triton.Triton(name = 'Triton 1', address='127.0.0.1', port=33576, tmpfile='Triton1_thermometry.reg')\n",
+    "# triton._get_temp_channels('thermometry.reg')\n",
+    "# print(triton.chan_alias)\n",
+    "\n",
+    "print(triton.time.get())\n",
+    "print(triton.T5.get())\n",
+    "print(triton.MC.get())\n",
+    "# for name,param in triton.parameters.items():\n",
+    "#     print(name,param.get())\n",
+    "print(triton.action.get())\n",
+    "print(triton.status.get())\n",
+    "# triton.close()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "t = triton.ask('*IDN?')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['OXFORD INSTRUMENTS', 'Triton', 'N/A', '2.445']"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "t.split(':')[1:]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example.ipynb b/docs/examples/Qcodes example.ipynb
index 72e32516e913..0eb4a6bf1347 100644
--- a/docs/examples/Qcodes example.ipynb	
+++ b/docs/examples/Qcodes example.ipynb	
@@ -10,171 +10,171 @@
     {
      "data": {
       "application/javascript": [
-       "/*\n",
-       " * Qcodes Jupyter/IPython widgets\n",
-       " */\n",
-       "require([\n",
-       "    'nbextensions/widgets/widgets/js/widget',\n",
-       "    'nbextensions/widgets/widgets/js/manager'\n",
-       "], function (widget, manager) {\n",
-       "\n",
-       "    var UpdateView = widget.DOMWidgetView.extend({\n",
-       "        render: function() {\n",
-       "            window.MYWIDGET = this;\n",
-       "            this._interval = 0;\n",
-       "            this.update();\n",
-       "        },\n",
-       "        update: function() {\n",
-       "            this.display(this.model.get('_message'));\n",
-       "            this.setInterval();\n",
-       "        },\n",
-       "        display: function(message) {\n",
-       "            /*\n",
-       "             * display method: override this for custom display logic\n",
-       "             */\n",
-       "            this.el.innerHTML = message;\n",
-       "        },\n",
-       "        remove: function() {\n",
-       "            clearInterval(this._updater);\n",
-       "        },\n",
-       "        setInterval: function(newInterval) {\n",
-       "            var me = this;\n",
-       "            if(newInterval===undefined) newInterval = me.model.get('interval');\n",
-       "            if(newInterval===me._interval) return;\n",
-       "\n",
-       "            me._interval = newInterval;\n",
-       "\n",
-       "            if(me._updater) clearInterval(me._updater);\n",
-       "\n",
-       "            if(me._interval) {\n",
-       "                me._updater = setInterval(function() {\n",
-       "                    me.send({myupdate: true});\n",
-       "                    if(!me.model.comm_live) {\n",
-       "                        console.log('missing comm, canceling widget updates', me);\n",
-       "                        clearInterval(me._updater);\n",
-       "                    }\n",
-       "                }, me._interval * 1000);\n",
-       "            }\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\n",
-       "\n",
-       "    var HiddenUpdateView = UpdateView.extend({\n",
-       "        display: function(message) {\n",
-       "            this.$el.hide();\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\n",
-       "\n",
-       "    var SubprocessView = UpdateView.extend({\n",
-       "        render: function() {\n",
-       "            var me = window.SPVIEW = this;\n",
-       "            me._interval = 0;\n",
-       "            me._minimize = '';\n",
-       "            me._restore = '';\n",
-       "\n",
-       "            // in case there is already an outputView present,\n",
-       "            // like from before restarting the kernel\n",
-       "            $('.qcodes-output-view').not(me.$el).remove();\n",
-       "\n",
-       "            me.$el\n",
-       "                .addClass('qcodes-output-view')\n",
-       "                .attr('qcodes-state', 'docked')\n",
-       "                .html(\n",
-       "                    '
' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '
' +\n", - " '
'\n",
-       "                );\n",
-       "\n",
-       "            me.clearButton = me.$el.find('.qcodes-clear-output');\n",
-       "            me.minButton = me.$el.find('.qcodes-minimize');\n",
-       "            me.outputArea = me.$el.find('pre');\n",
-       "            me.subprocessList = me.$el.find('span');\n",
-       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\n",
-       "\n",
-       "            me.clearButton.click(function() {\n",
-       "                me.outputArea.html('');\n",
-       "                me.clearButton.addClass('disabled');\n",
-       "            });\n",
-       "\n",
-       "            me.abortButton.click(function() {\n",
-       "                me.send({abort: true});\n",
-       "            });\n",
-       "\n",
-       "            me.$el.find('.js-state').click(function() {\n",
-       "                var oldState = me.$el.attr('qcodes-state'),\n",
-       "                    state = this.className.substr(this.className.indexOf('qcodes'))\n",
-       "                        .split('-')[1].split(' ')[0];\n",
-       "\n",
-       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\n",
-       "                // some other bit of code resets the parent after render if I do it there.\n",
-       "                // To be safe, just do it on every state click.\n",
-       "                me.$el.appendTo('body');\n",
-       "\n",
-       "                if(oldState === 'floated') {\n",
-       "                    me.$el.draggable('destroy').css({left:'', top: ''});\n",
-       "                }\n",
-       "\n",
-       "                me.$el.attr('qcodes-state', state);\n",
-       "\n",
-       "                if(state === 'floated') {\n",
-       "                    me.$el.draggable().css({\n",
-       "                        left: window.innerWidth - me.$el.width() - 15,\n",
-       "                        top: window.innerHeight - me.$el.height() - 10\n",
-       "                    });\n",
-       "                }\n",
-       "            });\n",
-       "\n",
-       "            $(window).resize(function() {\n",
-       "                if(me.$el.attr('qcodes-state') === 'floated') {\n",
-       "                    var position = me.$el.position(),\n",
-       "                        minVis = 20,\n",
-       "                        maxLeft = window.innerWidth - minVis,\n",
-       "                        maxTop = window.innerHeight - minVis;\n",
-       "\n",
-       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\n",
-       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\n",
-       "                }\n",
-       "            });\n",
-       "\n",
-       "            me.update();\n",
-       "        },\n",
-       "\n",
-       "        display: function(message) {\n",
-       "            if(message) {\n",
-       "                var initialScroll = this.outputArea.scrollTop();\n",
-       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\n",
-       "                var scrollBottom = this.outputArea.scrollTop();\n",
-       "\n",
-       "                if(this.$el.attr('qcodes-state') === 'minimized') {\n",
-       "                    this.$el.find('.qcodes-docked').click();\n",
-       "                    // always scroll to the bottom if we're restoring\n",
-       "                    // because of a new message\n",
-       "                    initialScroll = scrollBottom;\n",
-       "                }\n",
-       "\n",
-       "                this.outputArea.append(message);\n",
-       "                this.clearButton.removeClass('disabled');\n",
-       "\n",
-       "                // if we were scrolled to the bottom initially, make sure\n",
-       "                // we stay that way.\n",
-       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\n",
-       "                    this.outputArea.prop('scrollHeight') : initialScroll);\n",
-       "            }\n",
-       "\n",
-       "            var processes = this.model.get('_processes') || 'No subprocesses';\n",
-       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\n",
-       "            this.subprocessList.text(processes);\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\n",
-       "});\n"
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
       ],
       "text/plain": [
        ""
@@ -186,55 +186,55 @@
     {
      "data": {
       "text/html": [
-       ""
       ],
       "text/plain": [
@@ -308,7 +308,14 @@
     {
      "data": {
       "text/plain": [
-       "[0.117]"
+       "{'instruments': {'gates': {'functions': {'reset': {}},\n",
+       "   'parameters': {'chan0': {'ts': None, 'value': None},\n",
+       "    'chan1': {'ts': None, 'value': None},\n",
+       "    'chan2': {'ts': None, 'value': None}}},\n",
+       "  'meter': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': None, 'value': None}}},\n",
+       "  'source': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': None, 'value': None}}}}}"
       ]
      },
      "execution_count": 3,
@@ -316,6 +323,57 @@
      "output_type": "execute_result"
     }
    ],
+   "source": [
+    "station.snapshot()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'instruments': {'gates': {'functions': {'reset': {}},\n",
+       "   'parameters': {'chan0': {'ts': '2016-04-20 17:31:50', 'value': 0.0},\n",
+       "    'chan1': {'ts': '2016-04-20 17:31:50', 'value': 0.0},\n",
+       "    'chan2': {'ts': '2016-04-20 17:31:50', 'value': 0.0}}},\n",
+       "  'meter': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': '2016-04-20 17:31:50', 'value': 0.117}}},\n",
+       "  'source': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': '2016-04-20 17:31:50', 'value': 0.1}}}}}"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "station.snapshot(update=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0.117]"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "# we can get the measured quantities right now\n",
     "station.measure()"
@@ -323,7 +381,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 7,
    "metadata": {
     "collapsed": false
    },
@@ -332,10 +390,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
-      "   amplitude: amplitude\n",
+      "DataSet: DataMode.PULL_FROM_SERVER, location='data/testsweep'\n",
       "   chan0: chan0\n",
-      "started at 2016-04-13 15:23:05\n"
+      "   amplitude: amplitude\n",
+      "started at 2016-04-20 17:32:19\n"
      ]
     }
    ],
@@ -348,7 +406,7 @@
     "# Notice that I'm using an explicit location and `overwrite=True` here so that\n",
     "# running this notebook over and over won't result in extra files.\n",
     "# But if you leave these out, you get a new timestamped DataSet each time.\n",
-    "data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True)\n",
+    "data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='data/testsweep', overwrite=True)\n",
     "\n",
     "# now there should be two extra processes running, DataServer and a sweep\n",
     "# I'll omit the active_children call now because you can see them in the\n",
@@ -357,7 +415,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 8,
    "metadata": {
     "collapsed": false,
     "scrolled": true
@@ -377,46 +435,46 @@
        "         0.007,  0.008,  0.008,  0.008,  0.009,  0.009,  0.01 ,  0.01 ,\n",
        "         0.01 ,  0.011,  0.011,  0.012,  0.013,  0.013,  0.014,  0.015,\n",
        "         0.016,  0.017,  0.018,  0.019,  0.02 ,  0.022,  0.023,  0.025,\n",
-       "         0.027,  0.029,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan]),\n",
+       "         0.027,  0.029,  0.031,  0.034,  0.037,  0.04 ,  0.044,  0.048,\n",
+       "         0.053,  0.058,  0.064,  0.071,  0.077,  0.085,  0.092,  0.099,\n",
+       "         0.106,  0.111,  0.115,  0.117,  0.117,  0.117,  0.115,  0.111,\n",
+       "         0.106,  0.099,  0.092,  0.085,  0.077,  0.071,  0.064,  0.058,\n",
+       "         0.053,  0.048,  0.044,  0.04 ,  0.037,  0.034,  0.031,  0.029,\n",
+       "         0.027,  0.025,  0.023,  0.022,  0.02 ,  0.019,  0.018,  0.017,\n",
+       "         0.016,  0.015,  0.014,  0.013,  0.013,  0.012,  0.011,  0.011,\n",
+       "         0.01 ,  0.01 ,  0.01 ,  0.009,  0.009,  0.008,  0.008,  0.008,\n",
+       "         0.007,  0.007,  0.007,  0.007,  0.006,  0.006,  0.006,  0.006,\n",
+       "         0.006,  0.007,  0.007,  0.007,  0.007,  0.008,  0.008,  0.008,\n",
+       "         0.009,  0.009,  0.01 ,  0.01 ,  0.01 ,  0.011,  0.011,  0.012,\n",
+       "         0.013,  0.013,  0.014,  0.015,  0.016,  0.017,  0.018,  0.019,\n",
+       "         0.02 ,  0.022,  0.023,  0.025,  0.027,  0.029,  0.031,  0.034,\n",
+       "         0.037,  0.04 ,  0.044,  0.048,  0.053,  0.058,  0.064,  0.071,\n",
+       "         0.077,  0.085,  0.092,  0.099,  0.106,  0.111,  0.115,  0.117,\n",
+       "         0.117,  0.117,  0.115,  0.111,  0.106,  0.099,  0.092,  0.085,\n",
+       "         0.077,  0.071,  0.064,  0.058,  0.053,  0.048,  0.044,  0.04 ,\n",
+       "         0.037,  0.034,  0.031,  0.029,  0.027,  0.025,  0.023,  0.022,\n",
+       "         0.02 ,  0.019,  0.018,  0.017,  0.016,  0.015,  0.014,  0.013,\n",
+       "         0.013,  0.012,  0.011,  0.011,  0.01 ,  0.01 ,  0.01 ,  0.009,\n",
+       "         0.009,  0.008,  0.008,  0.008,  0.007,  0.007,  0.007,  0.007,\n",
+       "         0.006,  0.006,  0.006,  0.006,  0.006,  0.007,  0.007,  0.007,\n",
+       "         0.007,  0.008,  0.008,  0.008,  0.009,  0.009,  0.01 ,  0.01 ,\n",
+       "         0.01 ,  0.011,  0.011,  0.012,  0.013,  0.013,  0.014,  0.015,\n",
+       "         0.016,  0.017,  0.018,  0.019,  0.02 ,  0.022,  0.023,  0.025,\n",
+       "         0.027,  0.029,  0.031,  0.034,  0.037,  0.04 ,  0.044,  0.048,\n",
+       "         0.053,  0.058,  0.064,  0.071,  0.077,  0.085,  0.092,  0.099,\n",
+       "         0.106,  0.111,  0.115,  0.117,  0.117,  0.117,  0.115,  0.111,\n",
+       "         0.106,  0.099,  0.092,  0.085,  0.077,  0.071,  0.064,  0.058,\n",
+       "         0.053,  0.048,  0.044,  0.04 ,  0.037,  0.034,  0.031,  0.029,\n",
+       "         0.027,  0.025,  0.023,  0.022,  0.02 ,  0.019,  0.018,  0.017,\n",
+       "         0.016,  0.015,  0.014,  0.013,  0.013,  0.012,  0.011,  0.011,\n",
+       "         0.01 ,  0.01 ,  0.01 ,  0.009,  0.009,  0.008,  0.008,  0.008,\n",
+       "         0.007,  0.007,  0.007,  0.007,  0.006,  0.006,  0.006,  0.006,\n",
+       "         0.006,  0.007,  0.007,  0.007,  0.007,  0.008,  0.008,  0.008,\n",
+       "         0.009,  0.009,  0.01 ,  0.01 ,  0.01 ,  0.011,  0.011,  0.012,\n",
+       "         0.013,  0.013,  0.014,  0.015,  0.016,  0.017,  0.018,  0.019,\n",
+       "         0.02 ,  0.022,  0.023,  0.025,  0.027,  0.029,  0.031,  0.034,\n",
+       "         0.037,  0.04 ,  0.044,  0.048,  0.053,  0.058,  0.064,  0.071,\n",
+       "         0.077,  0.085,  0.092,  0.099,  0.106,  0.111,  0.115,  0.117]),\n",
        " 'chan0': DataArray[400]: chan0\n",
        " array([-20. , -19.9, -19.8, -19.7, -19.6, -19.5, -19.4, -19.3, -19.2,\n",
        "        -19.1, -19. , -18.9, -18.8, -18.7, -18.6, -18.5, -18.4, -18.3,\n",
@@ -427,45 +485,45 @@
        "        -14.6, -14.5, -14.4, -14.3, -14.2, -14.1, -14. , -13.9, -13.8,\n",
        "        -13.7, -13.6, -13.5, -13.4, -13.3, -13.2, -13.1, -13. , -12.9,\n",
        "        -12.8, -12.7, -12.6, -12.5, -12.4, -12.3, -12.2, -12.1, -12. ,\n",
-       "        -11.9, -11.8,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan])}"
+       "        -11.9, -11.8, -11.7, -11.6, -11.5, -11.4, -11.3, -11.2, -11.1,\n",
+       "        -11. , -10.9, -10.8, -10.7, -10.6, -10.5, -10.4, -10.3, -10.2,\n",
+       "        -10.1, -10. ,  -9.9,  -9.8,  -9.7,  -9.6,  -9.5,  -9.4,  -9.3,\n",
+       "         -9.2,  -9.1,  -9. ,  -8.9,  -8.8,  -8.7,  -8.6,  -8.5,  -8.4,\n",
+       "         -8.3,  -8.2,  -8.1,  -8. ,  -7.9,  -7.8,  -7.7,  -7.6,  -7.5,\n",
+       "         -7.4,  -7.3,  -7.2,  -7.1,  -7. ,  -6.9,  -6.8,  -6.7,  -6.6,\n",
+       "         -6.5,  -6.4,  -6.3,  -6.2,  -6.1,  -6. ,  -5.9,  -5.8,  -5.7,\n",
+       "         -5.6,  -5.5,  -5.4,  -5.3,  -5.2,  -5.1,  -5. ,  -4.9,  -4.8,\n",
+       "         -4.7,  -4.6,  -4.5,  -4.4,  -4.3,  -4.2,  -4.1,  -4. ,  -3.9,\n",
+       "         -3.8,  -3.7,  -3.6,  -3.5,  -3.4,  -3.3,  -3.2,  -3.1,  -3. ,\n",
+       "         -2.9,  -2.8,  -2.7,  -2.6,  -2.5,  -2.4,  -2.3,  -2.2,  -2.1,\n",
+       "         -2. ,  -1.9,  -1.8,  -1.7,  -1.6,  -1.5,  -1.4,  -1.3,  -1.2,\n",
+       "         -1.1,  -1. ,  -0.9,  -0.8,  -0.7,  -0.6,  -0.5,  -0.4,  -0.3,\n",
+       "         -0.2,  -0.1,   0. ,   0.1,   0.2,   0.3,   0.4,   0.5,   0.6,\n",
+       "          0.7,   0.8,   0.9,   1. ,   1.1,   1.2,   1.3,   1.4,   1.5,\n",
+       "          1.6,   1.7,   1.8,   1.9,   2. ,   2.1,   2.2,   2.3,   2.4,\n",
+       "          2.5,   2.6,   2.7,   2.8,   2.9,   3. ,   3.1,   3.2,   3.3,\n",
+       "          3.4,   3.5,   3.6,   3.7,   3.8,   3.9,   4. ,   4.1,   4.2,\n",
+       "          4.3,   4.4,   4.5,   4.6,   4.7,   4.8,   4.9,   5. ,   5.1,\n",
+       "          5.2,   5.3,   5.4,   5.5,   5.6,   5.7,   5.8,   5.9,   6. ,\n",
+       "          6.1,   6.2,   6.3,   6.4,   6.5,   6.6,   6.7,   6.8,   6.9,\n",
+       "          7. ,   7.1,   7.2,   7.3,   7.4,   7.5,   7.6,   7.7,   7.8,\n",
+       "          7.9,   8. ,   8.1,   8.2,   8.3,   8.4,   8.5,   8.6,   8.7,\n",
+       "          8.8,   8.9,   9. ,   9.1,   9.2,   9.3,   9.4,   9.5,   9.6,\n",
+       "          9.7,   9.8,   9.9,  10. ,  10.1,  10.2,  10.3,  10.4,  10.5,\n",
+       "         10.6,  10.7,  10.8,  10.9,  11. ,  11.1,  11.2,  11.3,  11.4,\n",
+       "         11.5,  11.6,  11.7,  11.8,  11.9,  12. ,  12.1,  12.2,  12.3,\n",
+       "         12.4,  12.5,  12.6,  12.7,  12.8,  12.9,  13. ,  13.1,  13.2,\n",
+       "         13.3,  13.4,  13.5,  13.6,  13.7,  13.8,  13.9,  14. ,  14.1,\n",
+       "         14.2,  14.3,  14.4,  14.5,  14.6,  14.7,  14.8,  14.9,  15. ,\n",
+       "         15.1,  15.2,  15.3,  15.4,  15.5,  15.6,  15.7,  15.8,  15.9,\n",
+       "         16. ,  16.1,  16.2,  16.3,  16.4,  16.5,  16.6,  16.7,  16.8,\n",
+       "         16.9,  17. ,  17.1,  17.2,  17.3,  17.4,  17.5,  17.6,  17.7,\n",
+       "         17.8,  17.9,  18. ,  18.1,  18.2,  18.3,  18.4,  18.5,  18.6,\n",
+       "         18.7,  18.8,  18.9,  19. ,  19.1,  19.2,  19.3,  19.4,  19.5,\n",
+       "         19.6,  19.7,  19.8,  19.9])}"
       ]
      },
-     "execution_count": 5,
+     "execution_count": 8,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -478,7 +536,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 9,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -492,7 +550,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 10,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -504,10 +562,10 @@
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
       "   chan1: chan1\n",
-      "   amplitude_3: amplitude\n",
       "   chan0: chan0\n",
+      "   amplitude_3: amplitude\n",
       "   amplitude_0: amplitude\n",
-      "started at 2016-04-13 15:23:28\n"
+      "started at 2016-04-20 17:35:13\n"
      ]
     }
    ],
@@ -531,7 +589,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 11,
    "metadata": {
     "collapsed": false
    },
@@ -540,15 +598,15 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
+      "DataSet: DataMode.PULL_FROM_SERVER, location='data/test_multi_d'\n",
+      "   amplitude_5_0: amplitude\n",
+      "   amplitude_3_0: amplitude\n",
       "   avg_amplitude: avg_amplitude\n",
-      "   chan2: chan2\n",
+      "   chan1: chan1\n",
       "   chan0: chan0\n",
+      "   chan2: chan2\n",
       "   amplitude_2: amplitude\n",
-      "   chan1: chan1\n",
-      "   amplitude_3_0: amplitude\n",
-      "   amplitude_5_0: amplitude\n",
-      "started at 2016-04-13 15:24:20\n"
+      "started at 2016-04-20 17:35:21\n"
      ]
     }
    ],
@@ -564,7 +622,7 @@
     "    # a 2D sweep with the same outer but different inner loop\n",
     "    qc.Loop(c2[-10:10:0.2], 0.001),\n",
     "    AverageGetter(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
-    ").run(location='test_multi_d', overwrite=True)\n",
+    ").run(location='data/test_multi_d', overwrite=True)\n",
     "\n",
     "# several plots updating simultaneously\n",
     "# plot3 = qc.MatPlot(data3.amplitude_3_0, cmap=plt.cm.hot)\n",
@@ -577,7 +635,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 12,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -587,12 +645,12 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
+      "DataSet: DataMode.PULL_FROM_SERVER, location='data/test_complex_param'\n",
       "   avg_amplitude: avg_amplitude\n",
-      "   chan2: chan2\n",
       "   chan1: chan1\n",
+      "   chan2: chan2\n",
       "   amplitude: amplitude\n",
-      "started at 2016-02-02 12:18:09\n"
+      "started at 2016-04-20 17:35:49\n"
      ]
     }
    ],
@@ -601,13 +659,22 @@
     "# This produces the last two arrays from data3, but only takes the data once.\n",
     "data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
     "    AverageAndRaw(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
-    ").run(location='test_complex_param', overwrite=True)\n",
+    ").run(location='data/test_complex_param', overwrite=True)\n",
     "\n",
     "# plot4 = qc.MatPlot(data4.amplitude, cmap=plt.cm.hot, subplots=(1,2), figsize=(12, 4.5))\n",
     "# plot4.add(data4.avg_amplitude, subplot=2)\n",
     "plot4Q = qc.QtPlot(data4.amplitude, figsize=(1200, 500))\n",
     "plot4Q.add(data4.avg_amplitude, subplot=2)"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
@@ -626,7 +693,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.5.0"
+   "version": "3.5.1"
   }
  },
  "nbformat": 4,
diff --git a/docs/examples/Triton1_thermometry.reg b/docs/examples/Triton1_thermometry.reg
new file mode 100644
index 000000000000..8230c8925020
--- /dev/null
+++ b/docs/examples/Triton1_thermometry.reg
@@ -0,0 +1,295 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry]
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[-1]]
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Magnet top/X55352.cof"
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[0]]
+"m_lpszName"="PT2 Head"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/4K head/X53075.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="2000"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="897.18"
+"m_dblResistance"="944.51"
+"m_dblOldTemperature"="21.8619581878346"
+"m_dblTemperature"="20.7073938117749"
+"m_dblOldTime"="1460555546"
+"m_dblTime"="1460555661"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[10]]
+"m_lpszName"="Still shield tail"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/CP/M_RuO2_Ext_4.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:0000000b
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="200"
+"m_dblExcitation"="0.000199999893084169"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="67.869"
+"m_dblResistance"="67.855"
+"m_dblOldTemperature"="287.095485095483"
+"m_dblTemperature"="287.167409962017"
+"m_dblOldTime"="1387444773"
+"m_dblTime"="1387444887"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[11]]
+"m_lpszName"="chan[11]"
+"m_lpszCalibFileName"="C:\\VeriCold\\Thermometry\\none.dll"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000011
+"m_dwExcitation"=dword:00000007
+"m_dblRange"="200000"
+"m_dblExcitation"="0.002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="149"
+"m_dblResistance"="192"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="1455629381"
+"m_dblTime"="1455629514"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:000003ea
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[12]]
+"m_lpszName"="Lead 1"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Lead 1/X53306.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="632000"
+"m_dblExcitation"="0.000199999776668847"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="7840"
+"m_dblResistance"="17319"
+"m_dblOldTemperature"="1.62496396307643"
+"m_dblTemperature"="1.41588562351072"
+"m_dblOldTime"="1386671337"
+"m_dblTime"="1386671488"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000001
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[13]]
+"m_lpszName"="Lead 2"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Lead 2/X55193.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000000
+"m_dblRange"="1000"
+"m_dblExcitation"="2.47032822920623e-323"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="0"
+"m_dblResistance"="0"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="0"
+"m_dblTime"="0"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[14]]
+"m_lpszName"="Sample rod"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/CP/M_RuO2_Ext_4.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000000
+"m_dblRange"="1000"
+"m_dblExcitation"="9.99998883344234e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="0"
+"m_dblResistance"="0"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="0"
+"m_dblTime"="0"
+"m_bAutorange"="false"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[15]]
+"m_lpszName"="Lower 4K shield"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/4K shield bottom/X55350.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000000
+"m_dblRange"="1000"
+"m_dblExcitation"="9.99998883344234e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="0"
+"m_dblResistance"="0"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="0"
+"m_dblTime"="0"
+"m_bAutorange"="false"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[1]]
+"m_lpszName"="PT2 Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/4K plate/X52922.340"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="2000"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="1162.17"
+"m_dblResistance"="1231.5"
+"m_dblOldTemperature"="21.2899987351121"
+"m_dblTemperature"="20.0278849440418"
+"m_dblOldTime"="1460555555"
+"m_dblTime"="1460555670"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[2]]
+"m_lpszName"="Still Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/still/Cgbh9.vcc"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000e
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="6320"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="4518.41"
+"m_dblResistance"="4520.25"
+"m_dblOldTemperature"="62.7156089361273"
+"m_dblTemperature"="62.3436033599238"
+"m_dblOldTime"="1460555569"
+"m_dblTime"="1460555684"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000001
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[3]]
+"m_lpszName"="MC Cernox"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/MC/X52921.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="2000"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="675.35"
+"m_dblResistance"="676.68"
+"m_dblOldTemperature"="34.8821016614691"
+"m_dblTemperature"="34.8088886990759"
+"m_dblOldTime"="1460555582"
+"m_dblTime"="1460555698"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[4]]
+"m_lpszName"="MC RuO2"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/MC/DDah8_DAH8.vcc"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000004
+"m_dblRange"="2000"
+"m_dblExcitation"="6.32e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="531.8"
+"m_dblResistance"="531.79"
+"m_dblOldTemperature"="17.4380571653974"
+"m_dblTemperature"="17.4414440709406"
+"m_dblOldTime"="1460555476"
+"m_dblTime"="1460555591"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000001
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[5]]
+"m_lpszName"="100mK Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/CP/M_RuO2_Ext_4.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000e
+"m_dwExcitation"=dword:00000004
+"m_dblRange"="6320"
+"m_dblExcitation"="6.32e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="2252.99"
+"m_dblResistance"="2255.98"
+"m_dblOldTemperature"="51.8305567689997"
+"m_dblTemperature"="49.9064763085877"
+"m_dblOldTime"="1460555489"
+"m_dblTime"="1460555604"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[6]]
+"m_lpszName"="Magnet  Bottom"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Magnet top/X55352.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000c
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="632"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="431.724"
+"m_dblResistance"="432.145"
+"m_dblOldTemperature"="21.8656699671321"
+"m_dblTemperature"="21.8374371966018"
+"m_dblOldTime"="1460555502"
+"m_dblTime"="1460555617"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[7]]
+"m_lpszName"="Magnet Almost Bottom"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Magnet Bottom/X55342.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000b
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="200"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="250.825"
+"m_dblResistance"="251.859"
+"m_dblOldTemperature"="58.0663607489416"
+"m_dblTemperature"="57.7839958105985"
+"m_dblOldTime"="1459019529"
+"m_dblTime"="1459019646"
+"m_bAutorange"="false"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[8]]
+"m_lpszName"="PT1 Head"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/pt100std.dll"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:00000009
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="20"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="11.6661"
+"m_dblResistance"="11.571"
+"m_dblOldTemperature"="57.3984906949643"
+"m_dblTemperature"="57.1817076128138"
+"m_dblOldTime"="1460555522"
+"m_dblTime"="1460555638"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[9]]
+"m_lpszName"="PT1 Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/pt100std.dll"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:00000009
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="20"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="18.382"
+"m_dblResistance"="18.3744"
+"m_dblOldTemperature"="72.8123204216882"
+"m_dblTemperature"="72.7947627066479"
+"m_dblOldTime"="1460555531"
+"m_dblTime"="1460555647"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
diff --git a/docs/examples/test2d.dat b/docs/examples/test2d.dat
deleted file mode 100644
index feafadab27d1..000000000000
--- a/docs/examples/test2d.dat
+++ /dev/null
@@ -1,1652 +0,0 @@
-# chan1	chan0	amplitude_0	amplitude_3
-# "Gate Channel 1 (mV)"	"Gate Channel 0 (mV)"	"Current (nA)"	"Current (nA)"
-# 30	54
--15	-15	0.003	0.009
--15	-14.5	0.004	0.009
--15	-14	0.004	0.01
--15	-13.5	0.004	0.011
--15	-13	0.005	0.012
--15	-12.5	0.005	0.013
--15	-12	0.005	0.014
--15	-11.5	0.006	0.015
--15	-11	0.006	0.016
--15	-10.5	0.006	0.017
--15	-10	0.006	0.017
--15	-9.5	0.006	0.017
--15	-9	0.006	0.016
--15	-8.5	0.006	0.015
--15	-8	0.005	0.014
--15	-7.5	0.005	0.013
--15	-7	0.005	0.012
--15	-6.5	0.004	0.011
--15	-6	0.004	0.01
--15	-5.5	0.004	0.009
--15	-5	0.003	0.009
--15	-4.5	0.004	0.009
--15	-4	0.004	0.01
--15	-3.5	0.004	0.011
--15	-3	0.005	0.012
--15	-2.5	0.005	0.013
--15	-2	0.005	0.014
--15	-1.5	0.006	0.015
--15	-1	0.006	0.016
--15	-0.5	0.006	0.017
--15	0	0.006	0.017
--15	0.5	0.006	0.017
--15	1	0.006	0.016
--15	1.5	0.006	0.015
--15	2	0.005	0.014
--15	2.5	0.005	0.013
--15	3	0.005	0.012
--15	3.5	0.004	0.011
--15	4	0.004	0.01
--15	4.5	0.004	0.009
--15	5	0.003	0.009
--15	5.5	0.004	0.009
--15	6	0.004	0.01
--15	6.5	0.004	0.011
--15	7	0.005	0.012
--15	7.5	0.005	0.013
--15	8	0.005	0.014
--15	8.5	0.006	0.015
--15	9	0.006	0.016
--15	9.5	0.006	0.017
--15	10	0.006	0.017
--15	10.5	0.006	0.017
--15	11	0.006	0.016
--15	11.5	0.006	0.015
-
--14	-15	0.004	0.01
--14	-14.5	0.004	0.012
--14	-14	0.005	0.013
--14	-13.5	0.005	0.015
--14	-13	0.006	0.017
--14	-12.5	0.007	0.019
--14	-12	0.007	0.021
--14	-11.5	0.008	0.023
--14	-11	0.008	0.025
--14	-10.5	0.009	0.026
--14	-10	0.009	0.027
--14	-9.5	0.009	0.026
--14	-9	0.008	0.025
--14	-8.5	0.008	0.023
--14	-8	0.007	0.021
--14	-7.5	0.007	0.019
--14	-7	0.006	0.017
--14	-6.5	0.005	0.015
--14	-6	0.005	0.013
--14	-5.5	0.004	0.012
--14	-5	0.004	0.01
--14	-4.5	0.004	0.012
--14	-4	0.005	0.013
--14	-3.5	0.005	0.015
--14	-3	0.006	0.017
--14	-2.5	0.007	0.019
--14	-2	0.007	0.021
--14	-1.5	0.008	0.023
--14	-1	0.008	0.025
--14	-0.5	0.009	0.026
--14	0	0.009	0.027
--14	0.5	0.009	0.026
--14	1	0.008	0.025
--14	1.5	0.008	0.023
--14	2	0.007	0.021
--14	2.5	0.007	0.019
--14	3	0.006	0.017
--14	3.5	0.005	0.015
--14	4	0.005	0.013
--14	4.5	0.004	0.012
--14	5	0.004	0.01
--14	5.5	0.004	0.012
--14	6	0.005	0.013
--14	6.5	0.005	0.015
--14	7	0.006	0.017
--14	7.5	0.007	0.019
--14	8	0.007	0.021
--14	8.5	0.008	0.023
--14	9	0.008	0.025
--14	9.5	0.009	0.026
--14	10	0.009	0.027
--14	10.5	0.009	0.026
--14	11	0.008	0.025
--14	11.5	0.008	0.023
-
--13	-15	0.005	0.012
--13	-14.5	0.005	0.014
--13	-14	0.006	0.017
--13	-13.5	0.007	0.02
--13	-13	0.008	0.024
--13	-12.5	0.009	0.028
--13	-12	0.01	0.033
--13	-11.5	0.012	0.039
--13	-11	0.013	0.044
--13	-10.5	0.014	0.048
--13	-10	0.014	0.05
--13	-9.5	0.014	0.048
--13	-9	0.013	0.044
--13	-8.5	0.012	0.039
--13	-8	0.01	0.033
--13	-7.5	0.009	0.028
--13	-7	0.008	0.024
--13	-6.5	0.007	0.02
--13	-6	0.006	0.017
--13	-5.5	0.005	0.014
--13	-5	0.005	0.012
--13	-4.5	0.005	0.014
--13	-4	0.006	0.017
--13	-3.5	0.007	0.02
--13	-3	0.008	0.024
--13	-2.5	0.009	0.028
--13	-2	0.01	0.033
--13	-1.5	0.012	0.039
--13	-1	0.013	0.044
--13	-0.5	0.014	0.048
--13	0	0.014	0.05
--13	0.5	0.014	0.048
--13	1	0.013	0.044
--13	1.5	0.012	0.039
--13	2	0.01	0.033
--13	2.5	0.009	0.028
--13	3	0.008	0.024
--13	3.5	0.007	0.02
--13	4	0.006	0.017
--13	4.5	0.005	0.014
--13	5	0.005	0.012
--13	5.5	0.005	0.014
--13	6	0.006	0.017
--13	6.5	0.007	0.02
--13	7	0.008	0.024
--13	7.5	0.009	0.028
--13	8	0.01	0.033
--13	8.5	0.012	0.039
--13	9	0.013	0.044
--13	9.5	0.014	0.048
--13	10	0.014	0.05
--13	10.5	0.014	0.048
--13	11	0.013	0.044
--13	11.5	0.012	0.039
-
--12	-15	0.005	0.014
--12	-14.5	0.006	0.017
--12	-14	0.007	0.021
--12	-13.5	0.009	0.026
--12	-13	0.01	0.033
--12	-12.5	0.013	0.043
--12	-12	0.016	0.057
--12	-11.5	0.019	0.074
--12	-11	0.023	0.094
--12	-10.5	0.026	0.11
--12	-10	0.027	0.117
--12	-9.5	0.026	0.11
--12	-9	0.023	0.094
--12	-8.5	0.019	0.074
--12	-8	0.016	0.057
--12	-7.5	0.013	0.043
--12	-7	0.01	0.033
--12	-6.5	0.009	0.026
--12	-6	0.007	0.021
--12	-5.5	0.006	0.017
--12	-5	0.005	0.014
--12	-4.5	0.006	0.017
--12	-4	0.007	0.021
--12	-3.5	0.009	0.026
--12	-3	0.01	0.033
--12	-2.5	0.013	0.043
--12	-2	0.016	0.057
--12	-1.5	0.019	0.074
--12	-1	0.023	0.094
--12	-0.5	0.026	0.11
--12	0	0.027	0.117
--12	0.5	0.026	0.11
--12	1	0.023	0.094
--12	1.5	0.019	0.074
--12	2	0.016	0.057
--12	2.5	0.013	0.043
--12	3	0.01	0.033
--12	3.5	0.009	0.026
--12	4	0.007	0.021
--12	4.5	0.006	0.017
--12	5	0.005	0.014
--12	5.5	0.006	0.017
--12	6	0.007	0.021
--12	6.5	0.009	0.026
--12	7	0.01	0.033
--12	7.5	0.013	0.043
--12	8	0.016	0.057
--12	8.5	0.019	0.074
--12	9	0.023	0.094
--12	9.5	0.026	0.11
--12	10	0.027	0.117
--12	10.5	0.026	0.11
--12	11	0.023	0.094
--12	11.5	0.019	0.074
-
--11	-15	0.006	0.016
--11	-14.5	0.007	0.02
--11	-14	0.008	0.025
--11	-13.5	0.01	0.033
--11	-13	0.013	0.044
--11	-12.5	0.017	0.063
--11	-12	0.023	0.094
--11	-11.5	0.031	0.141
--11	-11	0.044	0.196
--11	-10.5	0.057	0.228
--11	-10	0.064	0.233
--11	-9.5	0.057	0.228
--11	-9	0.044	0.196
--11	-8.5	0.031	0.141
--11	-8	0.023	0.094
--11	-7.5	0.017	0.063
--11	-7	0.013	0.044
--11	-6.5	0.01	0.033
--11	-6	0.008	0.025
--11	-5.5	0.007	0.02
--11	-5	0.006	0.016
--11	-4.5	0.007	0.02
--11	-4	0.008	0.025
--11	-3.5	0.01	0.033
--11	-3	0.013	0.044
--11	-2.5	0.017	0.063
--11	-2	0.023	0.094
--11	-1.5	0.031	0.141
--11	-1	0.044	0.196
--11	-0.5	0.057	0.228
--11	0	0.064	0.233
--11	0.5	0.057	0.228
--11	1	0.044	0.196
--11	1.5	0.031	0.141
--11	2	0.023	0.094
--11	2.5	0.017	0.063
--11	3	0.013	0.044
--11	3.5	0.01	0.033
--11	4	0.008	0.025
--11	4.5	0.007	0.02
--11	5	0.006	0.016
--11	5.5	0.007	0.02
--11	6	0.008	0.025
--11	6.5	0.01	0.033
--11	7	0.013	0.044
--11	7.5	0.017	0.063
--11	8	0.023	0.094
--11	8.5	0.031	0.141
--11	9	0.044	0.196
--11	9.5	0.057	0.228
--11	10	0.064	0.233
--11	10.5	0.057	0.228
--11	11	0.044	0.196
--11	11.5	0.031	0.141
-
--10	-15	0.006	0.017
--10	-14.5	0.007	0.021
--10	-14	0.009	0.027
--10	-13.5	0.011	0.035
--10	-13	0.014	0.05
--10	-12.5	0.019	0.074
--10	-12	0.027	0.117
--10	-11.5	0.04	0.184
--10	-11	0.064	0.233
--10	-10.5	0.099	0.201
--10	-10	0.117	0.147
--10	-9.5	0.099	0.201
--10	-9	0.064	0.233
--10	-8.5	0.04	0.184
--10	-8	0.027	0.117
--10	-7.5	0.019	0.074
--10	-7	0.014	0.05
--10	-6.5	0.011	0.035
--10	-6	0.009	0.027
--10	-5.5	0.007	0.021
--10	-5	0.006	0.017
--10	-4.5	0.007	0.021
--10	-4	0.009	0.027
--10	-3.5	0.011	0.035
--10	-3	0.014	0.05
--10	-2.5	0.019	0.074
--10	-2	0.027	0.117
--10	-1.5	0.04	0.184
--10	-1	0.064	0.233
--10	-0.5	0.099	0.201
--10	0	0.117	0.147
--10	0.5	0.099	0.201
--10	1	0.064	0.233
--10	1.5	0.04	0.184
--10	2	0.027	0.117
--10	2.5	0.019	0.074
--10	3	0.014	0.05
--10	3.5	0.011	0.035
--10	4	0.009	0.027
--10	4.5	0.007	0.021
--10	5	0.006	0.017
--10	5.5	0.007	0.021
--10	6	0.009	0.027
--10	6.5	0.011	0.035
--10	7	0.014	0.05
--10	7.5	0.019	0.074
--10	8	0.027	0.117
--10	8.5	0.04	0.184
--10	9	0.064	0.233
--10	9.5	0.099	0.201
--10	10	0.117	0.147
--10	10.5	0.099	0.201
--10	11	0.064	0.233
--10	11.5	0.04	0.184
-
--9	-15	0.006	0.016
--9	-14.5	0.007	0.02
--9	-14	0.008	0.025
--9	-13.5	0.01	0.033
--9	-13	0.013	0.044
--9	-12.5	0.017	0.063
--9	-12	0.023	0.094
--9	-11.5	0.031	0.141
--9	-11	0.044	0.196
--9	-10.5	0.057	0.228
--9	-10	0.064	0.233
--9	-9.5	0.057	0.228
--9	-9	0.044	0.196
--9	-8.5	0.031	0.141
--9	-8	0.023	0.094
--9	-7.5	0.017	0.063
--9	-7	0.013	0.044
--9	-6.5	0.01	0.033
--9	-6	0.008	0.025
--9	-5.5	0.007	0.02
--9	-5	0.006	0.016
--9	-4.5	0.007	0.02
--9	-4	0.008	0.025
--9	-3.5	0.01	0.033
--9	-3	0.013	0.044
--9	-2.5	0.017	0.063
--9	-2	0.023	0.094
--9	-1.5	0.031	0.141
--9	-1	0.044	0.196
--9	-0.5	0.057	0.228
--9	0	0.064	0.233
--9	0.5	0.057	0.228
--9	1	0.044	0.196
--9	1.5	0.031	0.141
--9	2	0.023	0.094
--9	2.5	0.017	0.063
--9	3	0.013	0.044
--9	3.5	0.01	0.033
--9	4	0.008	0.025
--9	4.5	0.007	0.02
--9	5	0.006	0.016
--9	5.5	0.007	0.02
--9	6	0.008	0.025
--9	6.5	0.01	0.033
--9	7	0.013	0.044
--9	7.5	0.017	0.063
--9	8	0.023	0.094
--9	8.5	0.031	0.141
--9	9	0.044	0.196
--9	9.5	0.057	0.228
--9	10	0.064	0.233
--9	10.5	0.057	0.228
--9	11	0.044	0.196
--9	11.5	0.031	0.141
-
--8	-15	0.005	0.014
--8	-14.5	0.006	0.017
--8	-14	0.007	0.021
--8	-13.5	0.009	0.026
--8	-13	0.01	0.033
--8	-12.5	0.013	0.043
--8	-12	0.016	0.057
--8	-11.5	0.019	0.074
--8	-11	0.023	0.094
--8	-10.5	0.026	0.11
--8	-10	0.027	0.117
--8	-9.5	0.026	0.11
--8	-9	0.023	0.094
--8	-8.5	0.019	0.074
--8	-8	0.016	0.057
--8	-7.5	0.013	0.043
--8	-7	0.01	0.033
--8	-6.5	0.009	0.026
--8	-6	0.007	0.021
--8	-5.5	0.006	0.017
--8	-5	0.005	0.014
--8	-4.5	0.006	0.017
--8	-4	0.007	0.021
--8	-3.5	0.009	0.026
--8	-3	0.01	0.033
--8	-2.5	0.013	0.043
--8	-2	0.016	0.057
--8	-1.5	0.019	0.074
--8	-1	0.023	0.094
--8	-0.5	0.026	0.11
--8	0	0.027	0.117
--8	0.5	0.026	0.11
--8	1	0.023	0.094
--8	1.5	0.019	0.074
--8	2	0.016	0.057
--8	2.5	0.013	0.043
--8	3	0.01	0.033
--8	3.5	0.009	0.026
--8	4	0.007	0.021
--8	4.5	0.006	0.017
--8	5	0.005	0.014
--8	5.5	0.006	0.017
--8	6	0.007	0.021
--8	6.5	0.009	0.026
--8	7	0.01	0.033
--8	7.5	0.013	0.043
--8	8	0.016	0.057
--8	8.5	0.019	0.074
--8	9	0.023	0.094
--8	9.5	0.026	0.11
--8	10	0.027	0.117
--8	10.5	0.026	0.11
--8	11	0.023	0.094
--8	11.5	0.019	0.074
-
--7	-15	0.005	0.012
--7	-14.5	0.005	0.014
--7	-14	0.006	0.017
--7	-13.5	0.007	0.02
--7	-13	0.008	0.024
--7	-12.5	0.009	0.028
--7	-12	0.01	0.033
--7	-11.5	0.012	0.039
--7	-11	0.013	0.044
--7	-10.5	0.014	0.048
--7	-10	0.014	0.05
--7	-9.5	0.014	0.048
--7	-9	0.013	0.044
--7	-8.5	0.012	0.039
--7	-8	0.01	0.033
--7	-7.5	0.009	0.028
--7	-7	0.008	0.024
--7	-6.5	0.007	0.02
--7	-6	0.006	0.017
--7	-5.5	0.005	0.014
--7	-5	0.005	0.012
--7	-4.5	0.005	0.014
--7	-4	0.006	0.017
--7	-3.5	0.007	0.02
--7	-3	0.008	0.024
--7	-2.5	0.009	0.028
--7	-2	0.01	0.033
--7	-1.5	0.012	0.039
--7	-1	0.013	0.044
--7	-0.5	0.014	0.048
--7	0	0.014	0.05
--7	0.5	0.014	0.048
--7	1	0.013	0.044
--7	1.5	0.012	0.039
--7	2	0.01	0.033
--7	2.5	0.009	0.028
--7	3	0.008	0.024
--7	3.5	0.007	0.02
--7	4	0.006	0.017
--7	4.5	0.005	0.014
--7	5	0.005	0.012
--7	5.5	0.005	0.014
--7	6	0.006	0.017
--7	6.5	0.007	0.02
--7	7	0.008	0.024
--7	7.5	0.009	0.028
--7	8	0.01	0.033
--7	8.5	0.012	0.039
--7	9	0.013	0.044
--7	9.5	0.014	0.048
--7	10	0.014	0.05
--7	10.5	0.014	0.048
--7	11	0.013	0.044
--7	11.5	0.012	0.039
-
--6	-15	0.004	0.01
--6	-14.5	0.004	0.012
--6	-14	0.005	0.013
--6	-13.5	0.005	0.015
--6	-13	0.006	0.017
--6	-12.5	0.007	0.019
--6	-12	0.007	0.021
--6	-11.5	0.008	0.023
--6	-11	0.008	0.025
--6	-10.5	0.009	0.026
--6	-10	0.009	0.027
--6	-9.5	0.009	0.026
--6	-9	0.008	0.025
--6	-8.5	0.008	0.023
--6	-8	0.007	0.021
--6	-7.5	0.007	0.019
--6	-7	0.006	0.017
--6	-6.5	0.005	0.015
--6	-6	0.005	0.013
--6	-5.5	0.004	0.012
--6	-5	0.004	0.01
--6	-4.5	0.004	0.012
--6	-4	0.005	0.013
--6	-3.5	0.005	0.015
--6	-3	0.006	0.017
--6	-2.5	0.007	0.019
--6	-2	0.007	0.021
--6	-1.5	0.008	0.023
--6	-1	0.008	0.025
--6	-0.5	0.009	0.026
--6	0	0.009	0.027
--6	0.5	0.009	0.026
--6	1	0.008	0.025
--6	1.5	0.008	0.023
--6	2	0.007	0.021
--6	2.5	0.007	0.019
--6	3	0.006	0.017
--6	3.5	0.005	0.015
--6	4	0.005	0.013
--6	4.5	0.004	0.012
--6	5	0.004	0.01
--6	5.5	0.004	0.012
--6	6	0.005	0.013
--6	6.5	0.005	0.015
--6	7	0.006	0.017
--6	7.5	0.007	0.019
--6	8	0.007	0.021
--6	8.5	0.008	0.023
--6	9	0.008	0.025
--6	9.5	0.009	0.026
--6	10	0.009	0.027
--6	10.5	0.009	0.026
--6	11	0.008	0.025
--6	11.5	0.008	0.023
-
--5	-15	0.003	0.009
--5	-14.5	0.004	0.009
--5	-14	0.004	0.01
--5	-13.5	0.004	0.011
--5	-13	0.005	0.012
--5	-12.5	0.005	0.013
--5	-12	0.005	0.014
--5	-11.5	0.006	0.015
--5	-11	0.006	0.016
--5	-10.5	0.006	0.017
--5	-10	0.006	0.017
--5	-9.5	0.006	0.017
--5	-9	0.006	0.016
--5	-8.5	0.006	0.015
--5	-8	0.005	0.014
--5	-7.5	0.005	0.013
--5	-7	0.005	0.012
--5	-6.5	0.004	0.011
--5	-6	0.004	0.01
--5	-5.5	0.004	0.009
--5	-5	0.003	0.009
--5	-4.5	0.004	0.009
--5	-4	0.004	0.01
--5	-3.5	0.004	0.011
--5	-3	0.005	0.012
--5	-2.5	0.005	0.013
--5	-2	0.005	0.014
--5	-1.5	0.006	0.015
--5	-1	0.006	0.016
--5	-0.5	0.006	0.017
--5	0	0.006	0.017
--5	0.5	0.006	0.017
--5	1	0.006	0.016
--5	1.5	0.006	0.015
--5	2	0.005	0.014
--5	2.5	0.005	0.013
--5	3	0.005	0.012
--5	3.5	0.004	0.011
--5	4	0.004	0.01
--5	4.5	0.004	0.009
--5	5	0.003	0.009
--5	5.5	0.004	0.009
--5	6	0.004	0.01
--5	6.5	0.004	0.011
--5	7	0.005	0.012
--5	7.5	0.005	0.013
--5	8	0.005	0.014
--5	8.5	0.006	0.015
--5	9	0.006	0.016
--5	9.5	0.006	0.017
--5	10	0.006	0.017
--5	10.5	0.006	0.017
--5	11	0.006	0.016
--5	11.5	0.006	0.015
-
--4	-15	0.004	0.01
--4	-14.5	0.004	0.012
--4	-14	0.005	0.013
--4	-13.5	0.005	0.015
--4	-13	0.006	0.017
--4	-12.5	0.007	0.019
--4	-12	0.007	0.021
--4	-11.5	0.008	0.023
--4	-11	0.008	0.025
--4	-10.5	0.009	0.026
--4	-10	0.009	0.027
--4	-9.5	0.009	0.026
--4	-9	0.008	0.025
--4	-8.5	0.008	0.023
--4	-8	0.007	0.021
--4	-7.5	0.007	0.019
--4	-7	0.006	0.017
--4	-6.5	0.005	0.015
--4	-6	0.005	0.013
--4	-5.5	0.004	0.012
--4	-5	0.004	0.01
--4	-4.5	0.004	0.012
--4	-4	0.005	0.013
--4	-3.5	0.005	0.015
--4	-3	0.006	0.017
--4	-2.5	0.007	0.019
--4	-2	0.007	0.021
--4	-1.5	0.008	0.023
--4	-1	0.008	0.025
--4	-0.5	0.009	0.026
--4	0	0.009	0.027
--4	0.5	0.009	0.026
--4	1	0.008	0.025
--4	1.5	0.008	0.023
--4	2	0.007	0.021
--4	2.5	0.007	0.019
--4	3	0.006	0.017
--4	3.5	0.005	0.015
--4	4	0.005	0.013
--4	4.5	0.004	0.012
--4	5	0.004	0.01
--4	5.5	0.004	0.012
--4	6	0.005	0.013
--4	6.5	0.005	0.015
--4	7	0.006	0.017
--4	7.5	0.007	0.019
--4	8	0.007	0.021
--4	8.5	0.008	0.023
--4	9	0.008	0.025
--4	9.5	0.009	0.026
--4	10	0.009	0.027
--4	10.5	0.009	0.026
--4	11	0.008	0.025
--4	11.5	0.008	0.023
-
--3	-15	0.005	0.012
--3	-14.5	0.005	0.014
--3	-14	0.006	0.017
--3	-13.5	0.007	0.02
--3	-13	0.008	0.024
--3	-12.5	0.009	0.028
--3	-12	0.01	0.033
--3	-11.5	0.012	0.039
--3	-11	0.013	0.044
--3	-10.5	0.014	0.048
--3	-10	0.014	0.05
--3	-9.5	0.014	0.048
--3	-9	0.013	0.044
--3	-8.5	0.012	0.039
--3	-8	0.01	0.033
--3	-7.5	0.009	0.028
--3	-7	0.008	0.024
--3	-6.5	0.007	0.02
--3	-6	0.006	0.017
--3	-5.5	0.005	0.014
--3	-5	0.005	0.012
--3	-4.5	0.005	0.014
--3	-4	0.006	0.017
--3	-3.5	0.007	0.02
--3	-3	0.008	0.024
--3	-2.5	0.009	0.028
--3	-2	0.01	0.033
--3	-1.5	0.012	0.039
--3	-1	0.013	0.044
--3	-0.5	0.014	0.048
--3	0	0.014	0.05
--3	0.5	0.014	0.048
--3	1	0.013	0.044
--3	1.5	0.012	0.039
--3	2	0.01	0.033
--3	2.5	0.009	0.028
--3	3	0.008	0.024
--3	3.5	0.007	0.02
--3	4	0.006	0.017
--3	4.5	0.005	0.014
--3	5	0.005	0.012
--3	5.5	0.005	0.014
--3	6	0.006	0.017
--3	6.5	0.007	0.02
--3	7	0.008	0.024
--3	7.5	0.009	0.028
--3	8	0.01	0.033
--3	8.5	0.012	0.039
--3	9	0.013	0.044
--3	9.5	0.014	0.048
--3	10	0.014	0.05
--3	10.5	0.014	0.048
--3	11	0.013	0.044
--3	11.5	0.012	0.039
-
--2	-15	0.005	0.014
--2	-14.5	0.006	0.017
--2	-14	0.007	0.021
--2	-13.5	0.009	0.026
--2	-13	0.01	0.033
--2	-12.5	0.013	0.043
--2	-12	0.016	0.057
--2	-11.5	0.019	0.074
--2	-11	0.023	0.094
--2	-10.5	0.026	0.11
--2	-10	0.027	0.117
--2	-9.5	0.026	0.11
--2	-9	0.023	0.094
--2	-8.5	0.019	0.074
--2	-8	0.016	0.057
--2	-7.5	0.013	0.043
--2	-7	0.01	0.033
--2	-6.5	0.009	0.026
--2	-6	0.007	0.021
--2	-5.5	0.006	0.017
--2	-5	0.005	0.014
--2	-4.5	0.006	0.017
--2	-4	0.007	0.021
--2	-3.5	0.009	0.026
--2	-3	0.01	0.033
--2	-2.5	0.013	0.043
--2	-2	0.016	0.057
--2	-1.5	0.019	0.074
--2	-1	0.023	0.094
--2	-0.5	0.026	0.11
--2	0	0.027	0.117
--2	0.5	0.026	0.11
--2	1	0.023	0.094
--2	1.5	0.019	0.074
--2	2	0.016	0.057
--2	2.5	0.013	0.043
--2	3	0.01	0.033
--2	3.5	0.009	0.026
--2	4	0.007	0.021
--2	4.5	0.006	0.017
--2	5	0.005	0.014
--2	5.5	0.006	0.017
--2	6	0.007	0.021
--2	6.5	0.009	0.026
--2	7	0.01	0.033
--2	7.5	0.013	0.043
--2	8	0.016	0.057
--2	8.5	0.019	0.074
--2	9	0.023	0.094
--2	9.5	0.026	0.11
--2	10	0.027	0.117
--2	10.5	0.026	0.11
--2	11	0.023	0.094
--2	11.5	0.019	0.074
-
--1	-15	0.006	0.016
--1	-14.5	0.007	0.02
--1	-14	0.008	0.025
--1	-13.5	0.01	0.033
--1	-13	0.013	0.044
--1	-12.5	0.017	0.063
--1	-12	0.023	0.094
--1	-11.5	0.031	0.141
--1	-11	0.044	0.196
--1	-10.5	0.057	0.228
--1	-10	0.064	0.233
--1	-9.5	0.057	0.228
--1	-9	0.044	0.196
--1	-8.5	0.031	0.141
--1	-8	0.023	0.094
--1	-7.5	0.017	0.063
--1	-7	0.013	0.044
--1	-6.5	0.01	0.033
--1	-6	0.008	0.025
--1	-5.5	0.007	0.02
--1	-5	0.006	0.016
--1	-4.5	0.007	0.02
--1	-4	0.008	0.025
--1	-3.5	0.01	0.033
--1	-3	0.013	0.044
--1	-2.5	0.017	0.063
--1	-2	0.023	0.094
--1	-1.5	0.031	0.141
--1	-1	0.044	0.196
--1	-0.5	0.057	0.228
--1	0	0.064	0.233
--1	0.5	0.057	0.228
--1	1	0.044	0.196
--1	1.5	0.031	0.141
--1	2	0.023	0.094
--1	2.5	0.017	0.063
--1	3	0.013	0.044
--1	3.5	0.01	0.033
--1	4	0.008	0.025
--1	4.5	0.007	0.02
--1	5	0.006	0.016
--1	5.5	0.007	0.02
--1	6	0.008	0.025
--1	6.5	0.01	0.033
--1	7	0.013	0.044
--1	7.5	0.017	0.063
--1	8	0.023	0.094
--1	8.5	0.031	0.141
--1	9	0.044	0.196
--1	9.5	0.057	0.228
--1	10	0.064	0.233
--1	10.5	0.057	0.228
--1	11	0.044	0.196
--1	11.5	0.031	0.141
-
-0	-15	0.006	0.017
-0	-14.5	0.007	0.021
-0	-14	0.009	0.027
-0	-13.5	0.011	0.035
-0	-13	0.014	0.05
-0	-12.5	0.019	0.074
-0	-12	0.027	0.117
-0	-11.5	0.04	0.184
-0	-11	0.064	0.233
-0	-10.5	0.099	0.201
-0	-10	0.117	0.147
-0	-9.5	0.099	0.201
-0	-9	0.064	0.233
-0	-8.5	0.04	0.184
-0	-8	0.027	0.117
-0	-7.5	0.019	0.074
-0	-7	0.014	0.05
-0	-6.5	0.011	0.035
-0	-6	0.009	0.027
-0	-5.5	0.007	0.021
-0	-5	0.006	0.017
-0	-4.5	0.007	0.021
-0	-4	0.009	0.027
-0	-3.5	0.011	0.035
-0	-3	0.014	0.05
-0	-2.5	0.019	0.074
-0	-2	0.027	0.117
-0	-1.5	0.04	0.184
-0	-1	0.064	0.233
-0	-0.5	0.099	0.201
-0	0	0.117	0.147
-0	0.5	0.099	0.201
-0	1	0.064	0.233
-0	1.5	0.04	0.184
-0	2	0.027	0.117
-0	2.5	0.019	0.074
-0	3	0.014	0.05
-0	3.5	0.011	0.035
-0	4	0.009	0.027
-0	4.5	0.007	0.021
-0	5	0.006	0.017
-0	5.5	0.007	0.021
-0	6	0.009	0.027
-0	6.5	0.011	0.035
-0	7	0.014	0.05
-0	7.5	0.019	0.074
-0	8	0.027	0.117
-0	8.5	0.04	0.184
-0	9	0.064	0.233
-0	9.5	0.099	0.201
-0	10	0.117	0.147
-0	10.5	0.099	0.201
-0	11	0.064	0.233
-0	11.5	0.04	0.184
-
-1	-15	0.006	0.016
-1	-14.5	0.007	0.02
-1	-14	0.008	0.025
-1	-13.5	0.01	0.033
-1	-13	0.013	0.044
-1	-12.5	0.017	0.063
-1	-12	0.023	0.094
-1	-11.5	0.031	0.141
-1	-11	0.044	0.196
-1	-10.5	0.057	0.228
-1	-10	0.064	0.233
-1	-9.5	0.057	0.228
-1	-9	0.044	0.196
-1	-8.5	0.031	0.141
-1	-8	0.023	0.094
-1	-7.5	0.017	0.063
-1	-7	0.013	0.044
-1	-6.5	0.01	0.033
-1	-6	0.008	0.025
-1	-5.5	0.007	0.02
-1	-5	0.006	0.016
-1	-4.5	0.007	0.02
-1	-4	0.008	0.025
-1	-3.5	0.01	0.033
-1	-3	0.013	0.044
-1	-2.5	0.017	0.063
-1	-2	0.023	0.094
-1	-1.5	0.031	0.141
-1	-1	0.044	0.196
-1	-0.5	0.057	0.228
-1	0	0.064	0.233
-1	0.5	0.057	0.228
-1	1	0.044	0.196
-1	1.5	0.031	0.141
-1	2	0.023	0.094
-1	2.5	0.017	0.063
-1	3	0.013	0.044
-1	3.5	0.01	0.033
-1	4	0.008	0.025
-1	4.5	0.007	0.02
-1	5	0.006	0.016
-1	5.5	0.007	0.02
-1	6	0.008	0.025
-1	6.5	0.01	0.033
-1	7	0.013	0.044
-1	7.5	0.017	0.063
-1	8	0.023	0.094
-1	8.5	0.031	0.141
-1	9	0.044	0.196
-1	9.5	0.057	0.228
-1	10	0.064	0.233
-1	10.5	0.057	0.228
-1	11	0.044	0.196
-1	11.5	0.031	0.141
-
-2	-15	0.005	0.014
-2	-14.5	0.006	0.017
-2	-14	0.007	0.021
-2	-13.5	0.009	0.026
-2	-13	0.01	0.033
-2	-12.5	0.013	0.043
-2	-12	0.016	0.057
-2	-11.5	0.019	0.074
-2	-11	0.023	0.094
-2	-10.5	0.026	0.11
-2	-10	0.027	0.117
-2	-9.5	0.026	0.11
-2	-9	0.023	0.094
-2	-8.5	0.019	0.074
-2	-8	0.016	0.057
-2	-7.5	0.013	0.043
-2	-7	0.01	0.033
-2	-6.5	0.009	0.026
-2	-6	0.007	0.021
-2	-5.5	0.006	0.017
-2	-5	0.005	0.014
-2	-4.5	0.006	0.017
-2	-4	0.007	0.021
-2	-3.5	0.009	0.026
-2	-3	0.01	0.033
-2	-2.5	0.013	0.043
-2	-2	0.016	0.057
-2	-1.5	0.019	0.074
-2	-1	0.023	0.094
-2	-0.5	0.026	0.11
-2	0	0.027	0.117
-2	0.5	0.026	0.11
-2	1	0.023	0.094
-2	1.5	0.019	0.074
-2	2	0.016	0.057
-2	2.5	0.013	0.043
-2	3	0.01	0.033
-2	3.5	0.009	0.026
-2	4	0.007	0.021
-2	4.5	0.006	0.017
-2	5	0.005	0.014
-2	5.5	0.006	0.017
-2	6	0.007	0.021
-2	6.5	0.009	0.026
-2	7	0.01	0.033
-2	7.5	0.013	0.043
-2	8	0.016	0.057
-2	8.5	0.019	0.074
-2	9	0.023	0.094
-2	9.5	0.026	0.11
-2	10	0.027	0.117
-2	10.5	0.026	0.11
-2	11	0.023	0.094
-2	11.5	0.019	0.074
-
-3	-15	0.005	0.012
-3	-14.5	0.005	0.014
-3	-14	0.006	0.017
-3	-13.5	0.007	0.02
-3	-13	0.008	0.024
-3	-12.5	0.009	0.028
-3	-12	0.01	0.033
-3	-11.5	0.012	0.039
-3	-11	0.013	0.044
-3	-10.5	0.014	0.048
-3	-10	0.014	0.05
-3	-9.5	0.014	0.048
-3	-9	0.013	0.044
-3	-8.5	0.012	0.039
-3	-8	0.01	0.033
-3	-7.5	0.009	0.028
-3	-7	0.008	0.024
-3	-6.5	0.007	0.02
-3	-6	0.006	0.017
-3	-5.5	0.005	0.014
-3	-5	0.005	0.012
-3	-4.5	0.005	0.014
-3	-4	0.006	0.017
-3	-3.5	0.007	0.02
-3	-3	0.008	0.024
-3	-2.5	0.009	0.028
-3	-2	0.01	0.033
-3	-1.5	0.012	0.039
-3	-1	0.013	0.044
-3	-0.5	0.014	0.048
-3	0	0.014	0.05
-3	0.5	0.014	0.048
-3	1	0.013	0.044
-3	1.5	0.012	0.039
-3	2	0.01	0.033
-3	2.5	0.009	0.028
-3	3	0.008	0.024
-3	3.5	0.007	0.02
-3	4	0.006	0.017
-3	4.5	0.005	0.014
-3	5	0.005	0.012
-3	5.5	0.005	0.014
-3	6	0.006	0.017
-3	6.5	0.007	0.02
-3	7	0.008	0.024
-3	7.5	0.009	0.028
-3	8	0.01	0.033
-3	8.5	0.012	0.039
-3	9	0.013	0.044
-3	9.5	0.014	0.048
-3	10	0.014	0.05
-3	10.5	0.014	0.048
-3	11	0.013	0.044
-3	11.5	0.012	0.039
-
-4	-15	0.004	0.01
-4	-14.5	0.004	0.012
-4	-14	0.005	0.013
-4	-13.5	0.005	0.015
-4	-13	0.006	0.017
-4	-12.5	0.007	0.019
-4	-12	0.007	0.021
-4	-11.5	0.008	0.023
-4	-11	0.008	0.025
-4	-10.5	0.009	0.026
-4	-10	0.009	0.027
-4	-9.5	0.009	0.026
-4	-9	0.008	0.025
-4	-8.5	0.008	0.023
-4	-8	0.007	0.021
-4	-7.5	0.007	0.019
-4	-7	0.006	0.017
-4	-6.5	0.005	0.015
-4	-6	0.005	0.013
-4	-5.5	0.004	0.012
-4	-5	0.004	0.01
-4	-4.5	0.004	0.012
-4	-4	0.005	0.013
-4	-3.5	0.005	0.015
-4	-3	0.006	0.017
-4	-2.5	0.007	0.019
-4	-2	0.007	0.021
-4	-1.5	0.008	0.023
-4	-1	0.008	0.025
-4	-0.5	0.009	0.026
-4	0	0.009	0.027
-4	0.5	0.009	0.026
-4	1	0.008	0.025
-4	1.5	0.008	0.023
-4	2	0.007	0.021
-4	2.5	0.007	0.019
-4	3	0.006	0.017
-4	3.5	0.005	0.015
-4	4	0.005	0.013
-4	4.5	0.004	0.012
-4	5	0.004	0.01
-4	5.5	0.004	0.012
-4	6	0.005	0.013
-4	6.5	0.005	0.015
-4	7	0.006	0.017
-4	7.5	0.007	0.019
-4	8	0.007	0.021
-4	8.5	0.008	0.023
-4	9	0.008	0.025
-4	9.5	0.009	0.026
-4	10	0.009	0.027
-4	10.5	0.009	0.026
-4	11	0.008	0.025
-4	11.5	0.008	0.023
-
-5	-15	0.003	0.009
-5	-14.5	0.004	0.009
-5	-14	0.004	0.01
-5	-13.5	0.004	0.011
-5	-13	0.005	0.012
-5	-12.5	0.005	0.013
-5	-12	0.005	0.014
-5	-11.5	0.006	0.015
-5	-11	0.006	0.016
-5	-10.5	0.006	0.017
-5	-10	0.006	0.017
-5	-9.5	0.006	0.017
-5	-9	0.006	0.016
-5	-8.5	0.006	0.015
-5	-8	0.005	0.014
-5	-7.5	0.005	0.013
-5	-7	0.005	0.012
-5	-6.5	0.004	0.011
-5	-6	0.004	0.01
-5	-5.5	0.004	0.009
-5	-5	0.003	0.009
-5	-4.5	0.004	0.009
-5	-4	0.004	0.01
-5	-3.5	0.004	0.011
-5	-3	0.005	0.012
-5	-2.5	0.005	0.013
-5	-2	0.005	0.014
-5	-1.5	0.006	0.015
-5	-1	0.006	0.016
-5	-0.5	0.006	0.017
-5	0	0.006	0.017
-5	0.5	0.006	0.017
-5	1	0.006	0.016
-5	1.5	0.006	0.015
-5	2	0.005	0.014
-5	2.5	0.005	0.013
-5	3	0.005	0.012
-5	3.5	0.004	0.011
-5	4	0.004	0.01
-5	4.5	0.004	0.009
-5	5	0.003	0.009
-5	5.5	0.004	0.009
-5	6	0.004	0.01
-5	6.5	0.004	0.011
-5	7	0.005	0.012
-5	7.5	0.005	0.013
-5	8	0.005	0.014
-5	8.5	0.006	0.015
-5	9	0.006	0.016
-5	9.5	0.006	0.017
-5	10	0.006	0.017
-5	10.5	0.006	0.017
-5	11	0.006	0.016
-5	11.5	0.006	0.015
-
-6	-15	0.004	0.01
-6	-14.5	0.004	0.012
-6	-14	0.005	0.013
-6	-13.5	0.005	0.015
-6	-13	0.006	0.017
-6	-12.5	0.007	0.019
-6	-12	0.007	0.021
-6	-11.5	0.008	0.023
-6	-11	0.008	0.025
-6	-10.5	0.009	0.026
-6	-10	0.009	0.027
-6	-9.5	0.009	0.026
-6	-9	0.008	0.025
-6	-8.5	0.008	0.023
-6	-8	0.007	0.021
-6	-7.5	0.007	0.019
-6	-7	0.006	0.017
-6	-6.5	0.005	0.015
-6	-6	0.005	0.013
-6	-5.5	0.004	0.012
-6	-5	0.004	0.01
-6	-4.5	0.004	0.012
-6	-4	0.005	0.013
-6	-3.5	0.005	0.015
-6	-3	0.006	0.017
-6	-2.5	0.007	0.019
-6	-2	0.007	0.021
-6	-1.5	0.008	0.023
-6	-1	0.008	0.025
-6	-0.5	0.009	0.026
-6	0	0.009	0.027
-6	0.5	0.009	0.026
-6	1	0.008	0.025
-6	1.5	0.008	0.023
-6	2	0.007	0.021
-6	2.5	0.007	0.019
-6	3	0.006	0.017
-6	3.5	0.005	0.015
-6	4	0.005	0.013
-6	4.5	0.004	0.012
-6	5	0.004	0.01
-6	5.5	0.004	0.012
-6	6	0.005	0.013
-6	6.5	0.005	0.015
-6	7	0.006	0.017
-6	7.5	0.007	0.019
-6	8	0.007	0.021
-6	8.5	0.008	0.023
-6	9	0.008	0.025
-6	9.5	0.009	0.026
-6	10	0.009	0.027
-6	10.5	0.009	0.026
-6	11	0.008	0.025
-6	11.5	0.008	0.023
-
-7	-15	0.005	0.012
-7	-14.5	0.005	0.014
-7	-14	0.006	0.017
-7	-13.5	0.007	0.02
-7	-13	0.008	0.024
-7	-12.5	0.009	0.028
-7	-12	0.01	0.033
-7	-11.5	0.012	0.039
-7	-11	0.013	0.044
-7	-10.5	0.014	0.048
-7	-10	0.014	0.05
-7	-9.5	0.014	0.048
-7	-9	0.013	0.044
-7	-8.5	0.012	0.039
-7	-8	0.01	0.033
-7	-7.5	0.009	0.028
-7	-7	0.008	0.024
-7	-6.5	0.007	0.02
-7	-6	0.006	0.017
-7	-5.5	0.005	0.014
-7	-5	0.005	0.012
-7	-4.5	0.005	0.014
-7	-4	0.006	0.017
-7	-3.5	0.007	0.02
-7	-3	0.008	0.024
-7	-2.5	0.009	0.028
-7	-2	0.01	0.033
-7	-1.5	0.012	0.039
-7	-1	0.013	0.044
-7	-0.5	0.014	0.048
-7	0	0.014	0.05
-7	0.5	0.014	0.048
-7	1	0.013	0.044
-7	1.5	0.012	0.039
-7	2	0.01	0.033
-7	2.5	0.009	0.028
-7	3	0.008	0.024
-7	3.5	0.007	0.02
-7	4	0.006	0.017
-7	4.5	0.005	0.014
-7	5	0.005	0.012
-7	5.5	0.005	0.014
-7	6	0.006	0.017
-7	6.5	0.007	0.02
-7	7	0.008	0.024
-7	7.5	0.009	0.028
-7	8	0.01	0.033
-7	8.5	0.012	0.039
-7	9	0.013	0.044
-7	9.5	0.014	0.048
-7	10	0.014	0.05
-7	10.5	0.014	0.048
-7	11	0.013	0.044
-7	11.5	0.012	0.039
-
-8	-15	0.005	0.014
-8	-14.5	0.006	0.017
-8	-14	0.007	0.021
-8	-13.5	0.009	0.026
-8	-13	0.01	0.033
-8	-12.5	0.013	0.043
-8	-12	0.016	0.057
-8	-11.5	0.019	0.074
-8	-11	0.023	0.094
-8	-10.5	0.026	0.11
-8	-10	0.027	0.117
-8	-9.5	0.026	0.11
-8	-9	0.023	0.094
-8	-8.5	0.019	0.074
-8	-8	0.016	0.057
-8	-7.5	0.013	0.043
-8	-7	0.01	0.033
-8	-6.5	0.009	0.026
-8	-6	0.007	0.021
-8	-5.5	0.006	0.017
-8	-5	0.005	0.014
-8	-4.5	0.006	0.017
-8	-4	0.007	0.021
-8	-3.5	0.009	0.026
-8	-3	0.01	0.033
-8	-2.5	0.013	0.043
-8	-2	0.016	0.057
-8	-1.5	0.019	0.074
-8	-1	0.023	0.094
-8	-0.5	0.026	0.11
-8	0	0.027	0.117
-8	0.5	0.026	0.11
-8	1	0.023	0.094
-8	1.5	0.019	0.074
-8	2	0.016	0.057
-8	2.5	0.013	0.043
-8	3	0.01	0.033
-8	3.5	0.009	0.026
-8	4	0.007	0.021
-8	4.5	0.006	0.017
-8	5	0.005	0.014
-8	5.5	0.006	0.017
-8	6	0.007	0.021
-8	6.5	0.009	0.026
-8	7	0.01	0.033
-8	7.5	0.013	0.043
-8	8	0.016	0.057
-8	8.5	0.019	0.074
-8	9	0.023	0.094
-8	9.5	0.026	0.11
-8	10	0.027	0.117
-8	10.5	0.026	0.11
-8	11	0.023	0.094
-8	11.5	0.019	0.074
-
-9	-15	0.006	0.016
-9	-14.5	0.007	0.02
-9	-14	0.008	0.025
-9	-13.5	0.01	0.033
-9	-13	0.013	0.044
-9	-12.5	0.017	0.063
-9	-12	0.023	0.094
-9	-11.5	0.031	0.141
-9	-11	0.044	0.196
-9	-10.5	0.057	0.228
-9	-10	0.064	0.233
-9	-9.5	0.057	0.228
-9	-9	0.044	0.196
-9	-8.5	0.031	0.141
-9	-8	0.023	0.094
-9	-7.5	0.017	0.063
-9	-7	0.013	0.044
-9	-6.5	0.01	0.033
-9	-6	0.008	0.025
-9	-5.5	0.007	0.02
-9	-5	0.006	0.016
-9	-4.5	0.007	0.02
-9	-4	0.008	0.025
-9	-3.5	0.01	0.033
-9	-3	0.013	0.044
-9	-2.5	0.017	0.063
-9	-2	0.023	0.094
-9	-1.5	0.031	0.141
-9	-1	0.044	0.196
-9	-0.5	0.057	0.228
-9	0	0.064	0.233
-9	0.5	0.057	0.228
-9	1	0.044	0.196
-9	1.5	0.031	0.141
-9	2	0.023	0.094
-9	2.5	0.017	0.063
-9	3	0.013	0.044
-9	3.5	0.01	0.033
-9	4	0.008	0.025
-9	4.5	0.007	0.02
-9	5	0.006	0.016
-9	5.5	0.007	0.02
-9	6	0.008	0.025
-9	6.5	0.01	0.033
-9	7	0.013	0.044
-9	7.5	0.017	0.063
-9	8	0.023	0.094
-9	8.5	0.031	0.141
-9	9	0.044	0.196
-9	9.5	0.057	0.228
-9	10	0.064	0.233
-9	10.5	0.057	0.228
-9	11	0.044	0.196
-9	11.5	0.031	0.141
-
-10	-15	0.006	0.017
-10	-14.5	0.007	0.021
-10	-14	0.009	0.027
-10	-13.5	0.011	0.035
-10	-13	0.014	0.05
-10	-12.5	0.019	0.074
-10	-12	0.027	0.117
-10	-11.5	0.04	0.184
-10	-11	0.064	0.233
-10	-10.5	0.099	0.201
-10	-10	0.117	0.147
-10	-9.5	0.099	0.201
-10	-9	0.064	0.233
-10	-8.5	0.04	0.184
-10	-8	0.027	0.117
-10	-7.5	0.019	0.074
-10	-7	0.014	0.05
-10	-6.5	0.011	0.035
-10	-6	0.009	0.027
-10	-5.5	0.007	0.021
-10	-5	0.006	0.017
-10	-4.5	0.007	0.021
-10	-4	0.009	0.027
-10	-3.5	0.011	0.035
-10	-3	0.014	0.05
-10	-2.5	0.019	0.074
-10	-2	0.027	0.117
-10	-1.5	0.04	0.184
-10	-1	0.064	0.233
-10	-0.5	0.099	0.201
-10	0	0.117	0.147
-10	0.5	0.099	0.201
-10	1	0.064	0.233
-10	1.5	0.04	0.184
-10	2	0.027	0.117
-10	2.5	0.019	0.074
-10	3	0.014	0.05
-10	3.5	0.011	0.035
-10	4	0.009	0.027
-10	4.5	0.007	0.021
-10	5	0.006	0.017
-10	5.5	0.007	0.021
-10	6	0.009	0.027
-10	6.5	0.011	0.035
-10	7	0.014	0.05
-10	7.5	0.019	0.074
-10	8	0.027	0.117
-10	8.5	0.04	0.184
-10	9	0.064	0.233
-10	9.5	0.099	0.201
-10	10	0.117	0.147
-10	10.5	0.099	0.201
-10	11	0.064	0.233
-10	11.5	0.04	0.184
-
-11	-15	0.006	0.016
-11	-14.5	0.007	0.02
-11	-14	0.008	0.025
-11	-13.5	0.01	0.033
-11	-13	0.013	0.044
-11	-12.5	0.017	0.063
-11	-12	0.023	0.094
-11	-11.5	0.031	0.141
-11	-11	0.044	0.196
-11	-10.5	0.057	0.228
-11	-10	0.064	0.233
-11	-9.5	0.057	0.228
-11	-9	0.044	0.196
-11	-8.5	0.031	0.141
-11	-8	0.023	0.094
-11	-7.5	0.017	0.063
-11	-7	0.013	0.044
-11	-6.5	0.01	0.033
-11	-6	0.008	0.025
-11	-5.5	0.007	0.02
-11	-5	0.006	0.016
-11	-4.5	0.007	0.02
-11	-4	0.008	0.025
-11	-3.5	0.01	0.033
-11	-3	0.013	0.044
-11	-2.5	0.017	0.063
-11	-2	0.023	0.094
-11	-1.5	0.031	0.141
-11	-1	0.044	0.196
-11	-0.5	0.057	0.228
-11	0	0.064	0.233
-11	0.5	0.057	0.228
-11	1	0.044	0.196
-11	1.5	0.031	0.141
-11	2	0.023	0.094
-11	2.5	0.017	0.063
-11	3	0.013	0.044
-11	3.5	0.01	0.033
-11	4	0.008	0.025
-11	4.5	0.007	0.02
-11	5	0.006	0.016
-11	5.5	0.007	0.02
-11	6	0.008	0.025
-11	6.5	0.01	0.033
-11	7	0.013	0.044
-11	7.5	0.017	0.063
-11	8	0.023	0.094
-11	8.5	0.031	0.141
-11	9	0.044	0.196
-11	9.5	0.057	0.228
-11	10	0.064	0.233
-11	10.5	0.057	0.228
-11	11	0.044	0.196
-11	11.5	0.031	0.141
-
-12	-15	0.005	0.014
-12	-14.5	0.006	0.017
-12	-14	0.007	0.021
-12	-13.5	0.009	0.026
-12	-13	0.01	0.033
-12	-12.5	0.013	0.043
-12	-12	0.016	0.057
-12	-11.5	0.019	0.074
-12	-11	0.023	0.094
-12	-10.5	0.026	0.11
-12	-10	0.027	0.117
-12	-9.5	0.026	0.11
-12	-9	0.023	0.094
-12	-8.5	0.019	0.074
-12	-8	0.016	0.057
-12	-7.5	0.013	0.043
-12	-7	0.01	0.033
-12	-6.5	0.009	0.026
-12	-6	0.007	0.021
-12	-5.5	0.006	0.017
-12	-5	0.005	0.014
-12	-4.5	0.006	0.017
-12	-4	0.007	0.021
-12	-3.5	0.009	0.026
-12	-3	0.01	0.033
-12	-2.5	0.013	0.043
-12	-2	0.016	0.057
-12	-1.5	0.019	0.074
-12	-1	0.023	0.094
-12	-0.5	0.026	0.11
-12	0	0.027	0.117
-12	0.5	0.026	0.11
-12	1	0.023	0.094
-12	1.5	0.019	0.074
-12	2	0.016	0.057
-12	2.5	0.013	0.043
-12	3	0.01	0.033
-12	3.5	0.009	0.026
-12	4	0.007	0.021
-12	4.5	0.006	0.017
-12	5	0.005	0.014
-12	5.5	0.006	0.017
-12	6	0.007	0.021
-12	6.5	0.009	0.026
-12	7	0.01	0.033
-12	7.5	0.013	0.043
-12	8	0.016	0.057
-12	8.5	0.019	0.074
-12	9	0.023	0.094
-12	9.5	0.026	0.11
-12	10	0.027	0.117
-12	10.5	0.026	0.11
-12	11	0.023	0.094
-12	11.5	0.019	0.074
-
-13	-15	0.005	0.012
-13	-14.5	0.005	0.014
-13	-14	0.006	0.017
-13	-13.5	0.007	0.02
-13	-13	0.008	0.024
-13	-12.5	0.009	0.028
-13	-12	0.01	0.033
-13	-11.5	0.012	0.039
-13	-11	0.013	0.044
-13	-10.5	0.014	0.048
-13	-10	0.014	0.05
-13	-9.5	0.014	0.048
-13	-9	0.013	0.044
-13	-8.5	0.012	0.039
-13	-8	0.01	0.033
-13	-7.5	0.009	0.028
-13	-7	0.008	0.024
-13	-6.5	0.007	0.02
-13	-6	0.006	0.017
-13	-5.5	0.005	0.014
-13	-5	0.005	0.012
-13	-4.5	0.005	0.014
-13	-4	0.006	0.017
-13	-3.5	0.007	0.02
-13	-3	0.008	0.024
-13	-2.5	0.009	0.028
-13	-2	0.01	0.033
-13	-1.5	0.012	0.039
-13	-1	0.013	0.044
-13	-0.5	0.014	0.048
-13	0	0.014	0.05
-13	0.5	0.014	0.048
-13	1	0.013	0.044
-13	1.5	0.012	0.039
-13	2	0.01	0.033
-13	2.5	0.009	0.028
-13	3	0.008	0.024
-13	3.5	0.007	0.02
-13	4	0.006	0.017
-13	4.5	0.005	0.014
-13	5	0.005	0.012
-13	5.5	0.005	0.014
-13	6	0.006	0.017
-13	6.5	0.007	0.02
-13	7	0.008	0.024
-13	7.5	0.009	0.028
-13	8	0.01	0.033
-13	8.5	0.012	0.039
-13	9	0.013	0.044
-13	9.5	0.014	0.048
-13	10	0.014	0.05
-13	10.5	0.014	0.048
-13	11	0.013	0.044
-13	11.5	0.012	0.039
-
-14	-15	0.004	0.01
-14	-14.5	0.004	0.012
-14	-14	0.005	0.013
-14	-13.5	0.005	0.015
-14	-13	0.006	0.017
-14	-12.5	0.007	0.019
-14	-12	0.007	0.021
-14	-11.5	0.008	0.023
-14	-11	0.008	0.025
-14	-10.5	0.009	0.026
-14	-10	0.009	0.027
-14	-9.5	0.009	0.026
-14	-9	0.008	0.025
-14	-8.5	0.008	0.023
-14	-8	0.007	0.021
-14	-7.5	0.007	0.019
-14	-7	0.006	0.017
-14	-6.5	0.005	0.015
-14	-6	0.005	0.013
-14	-5.5	0.004	0.012
-14	-5	0.004	0.01
-14	-4.5	0.004	0.012
-14	-4	0.005	0.013
-14	-3.5	0.005	0.015
-14	-3	0.006	0.017
-14	-2.5	0.007	0.019
-14	-2	0.007	0.021
-14	-1.5	0.008	0.023
-14	-1	0.008	0.025
-14	-0.5	0.009	0.026
-14	0	0.009	0.027
-14	0.5	0.009	0.026
-14	1	0.008	0.025
-14	1.5	0.008	0.023
-14	2	0.007	0.021
-14	2.5	0.007	0.019
-14	3	0.006	0.017
-14	3.5	0.005	0.015
-14	4	0.005	0.013
-14	4.5	0.004	0.012
-14	5	0.004	0.01
-14	5.5	0.004	0.012
-14	6	0.005	0.013
-14	6.5	0.005	0.015
-14	7	0.006	0.017
-14	7.5	0.007	0.019
-14	8	0.007	0.021
-14	8.5	0.008	0.023
-14	9	0.008	0.025
-14	9.5	0.009	0.026
-14	10	0.009	0.027
-14	10.5	0.009	0.026
-14	11	0.008	0.025
-14	11.5	0.008	0.023
diff --git a/docs/examples/test_complex_param/chan1.dat b/docs/examples/test_complex_param/chan1.dat
deleted file mode 100644
index 7d416d204ea6..000000000000
--- a/docs/examples/test_complex_param/chan1.dat
+++ /dev/null
@@ -1,33 +0,0 @@
-# chan1	avg_amplitude
-# "Gate Channel 1 (mV)"	"Average: Current (nA)"
-# 30
--15	1.63366
--14	1.48254
--13	1.3513
--12	1.24736
--11	1.17375
--10	1.12666
--9	1.17375
--8	1.24736
--7	1.3513
--6	1.48254
--5	1.63366
--4	1.48254
--3	1.3513
--2	1.24736
--1	1.17375
-0	1.12666
-1	1.17375
-2	1.24736
-3	1.3513
-4	1.48254
-5	1.63366
-6	1.48254
-7	1.3513
-8	1.24736
-9	1.17375
-10	1.12666
-11	1.17375
-12	1.24736
-13	1.3513
-14	1.48254
diff --git a/docs/examples/test_complex_param/chan1_chan2.dat b/docs/examples/test_complex_param/chan1_chan2.dat
deleted file mode 100644
index 27a88c0745ae..000000000000
--- a/docs/examples/test_complex_param/chan1_chan2.dat
+++ /dev/null
@@ -1,3032 +0,0 @@
-# chan1	chan2	amplitude
-# "Gate Channel 1 (mV)"	"Gate Channel 2 (mV)"	"Current (nA)"
-# 30	100
--15	-10	3.362
--15	-9.8	3.253
--15	-9.6	3.148
--15	-9.4	3.047
--15	-9.2	2.95
--15	-9	2.858
--15	-8.8	2.771
--15	-8.6	2.689
--15	-8.4	2.613
--15	-8.2	2.544
--15	-8	2.483
--15	-7.8	2.43
--15	-7.6	2.388
--15	-7.4	2.357
--15	-7.2	2.339
--15	-7	2.339
--15	-6.8	2.359
--15	-6.6	2.402
--15	-6.4	2.475
--15	-6.2	2.581
--15	-6	2.721
--15	-5.8	2.889
--15	-5.6	3.062
--15	-5.4	3.188
--15	-5.2	3.192
--15	-5	3.01
--15	-4.8	2.644
--15	-4.6	2.177
--15	-4.4	1.709
--15	-4.2	1.306
--15	-4	0.985
--15	-3.8	0.741
--15	-3.6	0.559
--15	-3.4	0.424
--15	-3.2	0.323
--15	-3	0.247
--15	-2.8	0.19
--15	-2.6	0.146
--15	-2.4	0.112
--15	-2.2	0.086
--15	-2	0.066
--15	-1.8	0.051
--15	-1.6	0.039
--15	-1.4	0.029
--15	-1.2	0.022
--15	-1	0.017
--15	-0.8	0.013
--15	-0.6	0.01
--15	-0.4	0.008
--15	-0.2	0.007
--15	0	0.006
--15	0.2	0.007
--15	0.4	0.008
--15	0.6	0.01
--15	0.8	0.013
--15	1	0.017
--15	1.2	0.022
--15	1.4	0.029
--15	1.6	0.039
--15	1.8	0.051
--15	2	0.066
--15	2.2	0.086
--15	2.4	0.112
--15	2.6	0.146
--15	2.8	0.19
--15	3	0.247
--15	3.2	0.323
--15	3.4	0.424
--15	3.6	0.559
--15	3.8	0.741
--15	4	0.985
--15	4.2	1.306
--15	4.4	1.709
--15	4.6	2.177
--15	4.8	2.644
--15	5	3.01
--15	5.2	3.192
--15	5.4	3.188
--15	5.6	3.062
--15	5.8	2.889
--15	6	2.721
--15	6.2	2.581
--15	6.4	2.475
--15	6.6	2.402
--15	6.8	2.359
--15	7	2.339
--15	7.2	2.339
--15	7.4	2.357
--15	7.6	2.388
--15	7.8	2.43
--15	8	2.483
--15	8.2	2.544
--15	8.4	2.613
--15	8.6	2.689
--15	8.8	2.771
--15	9	2.858
--15	9.2	2.95
--15	9.4	3.047
--15	9.6	3.148
--15	9.8	3.253
-
--14	-10	3.279
--14	-9.8	3.163
--14	-9.6	3.05
--14	-9.4	2.94
--14	-9.2	2.833
--14	-9	2.73
--14	-8.8	2.63
--14	-8.6	2.533
--14	-8.4	2.44
--14	-8.2	2.351
--14	-8	2.265
--14	-7.8	2.184
--14	-7.6	2.108
--14	-7.4	2.036
--14	-7.2	1.97
--14	-7	1.91
--14	-6.8	1.857
--14	-6.6	1.811
--14	-6.4	1.773
--14	-6.2	1.746
--14	-6	1.731
--14	-5.8	1.73
--14	-5.6	1.745
--14	-5.4	1.779
--14	-5.2	1.835
--14	-5	1.912
--14	-4.8	2.005
--14	-4.6	2.097
--14	-4.4	2.152
--14	-4.2	2.122
--14	-4	1.968
--14	-3.8	1.699
--14	-3.6	1.372
--14	-3.4	1.055
--14	-3.2	0.788
--14	-3	0.58
--14	-2.8	0.425
--14	-2.6	0.311
--14	-2.4	0.228
--14	-2.2	0.168
--14	-2	0.124
--14	-1.8	0.091
--14	-1.6	0.067
--14	-1.4	0.049
--14	-1.2	0.036
--14	-1	0.027
--14	-0.8	0.02
--14	-0.6	0.015
--14	-0.4	0.012
--14	-0.2	0.01
--14	0	0.009
--14	0.2	0.01
--14	0.4	0.012
--14	0.6	0.015
--14	0.8	0.02
--14	1	0.027
--14	1.2	0.036
--14	1.4	0.049
--14	1.6	0.067
--14	1.8	0.091
--14	2	0.124
--14	2.2	0.168
--14	2.4	0.228
--14	2.6	0.311
--14	2.8	0.425
--14	3	0.58
--14	3.2	0.788
--14	3.4	1.055
--14	3.6	1.372
--14	3.8	1.699
--14	4	1.968
--14	4.2	2.122
--14	4.4	2.152
--14	4.6	2.097
--14	4.8	2.005
--14	5	1.912
--14	5.2	1.835
--14	5.4	1.779
--14	5.6	1.745
--14	5.8	1.73
--14	6	1.731
--14	6.2	1.746
--14	6.4	1.773
--14	6.6	1.811
--14	6.8	1.857
--14	7	1.91
--14	7.2	1.97
--14	7.4	2.036
--14	7.6	2.108
--14	7.8	2.184
--14	8	2.265
--14	8.2	2.351
--14	8.4	2.44
--14	8.6	2.533
--14	8.8	2.63
--14	9	2.73
--14	9.2	2.833
--14	9.4	2.94
--14	9.6	3.05
--14	9.8	3.163
-
--13	-10	3.232
--13	-9.8	3.113
--13	-9.6	2.996
--13	-9.4	2.882
--13	-9.2	2.771
--13	-9	2.663
--13	-8.8	2.557
--13	-8.6	2.454
--13	-8.4	2.355
--13	-8.2	2.258
--13	-8	2.164
--13	-7.8	2.073
--13	-7.6	1.986
--13	-7.4	1.901
--13	-7.2	1.82
--13	-7	1.743
--13	-6.8	1.669
--13	-6.6	1.599
--13	-6.4	1.533
--13	-6.2	1.471
--13	-6	1.414
--13	-5.8	1.361
--13	-5.6	1.315
--13	-5.4	1.275
--13	-5.2	1.242
--13	-5	1.216
--13	-4.8	1.2
--13	-4.6	1.195
--13	-4.4	1.201
--13	-4.2	1.22
--13	-4	1.25
--13	-3.8	1.288
--13	-3.6	1.321
--13	-3.4	1.328
--13	-3.2	1.28
--13	-3	1.158
--13	-2.8	0.973
--13	-2.6	0.763
--13	-2.4	0.569
--13	-2.2	0.41
--13	-2	0.291
--13	-1.8	0.204
--13	-1.6	0.143
--13	-1.4	0.1
--13	-1.2	0.07
--13	-1	0.05
--13	-0.8	0.035
--13	-0.6	0.026
--13	-0.4	0.02
--13	-0.2	0.016
--13	0	0.014
--13	0.2	0.016
--13	0.4	0.02
--13	0.6	0.026
--13	0.8	0.035
--13	1	0.05
--13	1.2	0.07
--13	1.4	0.1
--13	1.6	0.143
--13	1.8	0.204
--13	2	0.291
--13	2.2	0.41
--13	2.4	0.569
--13	2.6	0.763
--13	2.8	0.973
--13	3	1.158
--13	3.2	1.28
--13	3.4	1.328
--13	3.6	1.321
--13	3.8	1.288
--13	4	1.25
--13	4.2	1.22
--13	4.4	1.201
--13	4.6	1.195
--13	4.8	1.2
--13	5	1.216
--13	5.2	1.242
--13	5.4	1.275
--13	5.6	1.315
--13	5.8	1.361
--13	6	1.414
--13	6.2	1.471
--13	6.4	1.533
--13	6.6	1.599
--13	6.8	1.669
--13	7	1.743
--13	7.2	1.82
--13	7.4	1.901
--13	7.6	1.986
--13	7.8	2.073
--13	8	2.164
--13	8.2	2.258
--13	8.4	2.355
--13	8.6	2.454
--13	8.8	2.557
--13	9	2.663
--13	9.2	2.771
--13	9.4	2.882
--13	9.6	2.996
--13	9.8	3.113
-
--12	-10	3.203
--12	-9.8	3.082
--12	-9.6	2.964
--12	-9.4	2.848
--12	-9.2	2.735
--12	-9	2.624
--12	-8.8	2.516
--12	-8.6	2.411
--12	-8.4	2.308
--12	-8.2	2.208
--12	-8	2.111
--12	-7.8	2.016
--12	-7.6	1.924
--12	-7.4	1.835
--12	-7.2	1.748
--12	-7	1.665
--12	-6.8	1.584
--12	-6.6	1.506
--12	-6.4	1.431
--12	-6.2	1.359
--12	-6	1.29
--12	-5.8	1.224
--12	-5.6	1.161
--12	-5.4	1.102
--12	-5.2	1.046
--12	-5	0.993
--12	-4.8	0.945
--12	-4.6	0.901
--12	-4.4	0.861
--12	-4.2	0.825
--12	-4	0.795
--12	-3.8	0.771
--12	-3.6	0.753
--12	-3.4	0.741
--12	-3.2	0.736
--12	-3	0.736
--12	-2.8	0.738
--12	-2.6	0.735
--12	-2.4	0.715
--12	-2.2	0.666
--12	-2	0.58
--12	-1.8	0.468
--12	-1.6	0.351
--12	-1.4	0.25
--12	-1.2	0.172
--12	-1	0.117
--12	-0.8	0.08
--12	-0.6	0.055
--12	-0.4	0.04
--12	-0.2	0.031
--12	0	0.027
--12	0.2	0.031
--12	0.4	0.04
--12	0.6	0.055
--12	0.8	0.08
--12	1	0.117
--12	1.2	0.172
--12	1.4	0.25
--12	1.6	0.351
--12	1.8	0.468
--12	2	0.58
--12	2.2	0.666
--12	2.4	0.715
--12	2.6	0.735
--12	2.8	0.738
--12	3	0.736
--12	3.2	0.736
--12	3.4	0.741
--12	3.6	0.753
--12	3.8	0.771
--12	4	0.795
--12	4.2	0.825
--12	4.4	0.861
--12	4.6	0.901
--12	4.8	0.945
--12	5	0.993
--12	5.2	1.046
--12	5.4	1.102
--12	5.6	1.161
--12	5.8	1.224
--12	6	1.29
--12	6.2	1.359
--12	6.4	1.431
--12	6.6	1.506
--12	6.8	1.584
--12	7	1.665
--12	7.2	1.748
--12	7.4	1.835
--12	7.6	1.924
--12	7.8	2.016
--12	8	2.111
--12	8.2	2.208
--12	8.4	2.308
--12	8.6	2.411
--12	8.8	2.516
--12	9	2.624
--12	9.2	2.735
--12	9.4	2.848
--12	9.6	2.964
--12	9.8	3.082
-
--11	-10	3.185
--11	-9.8	3.063
--11	-9.6	2.943
--11	-9.4	2.827
--11	-9.2	2.712
--11	-9	2.601
--11	-8.8	2.491
--11	-8.6	2.385
--11	-8.4	2.281
--11	-8.2	2.179
--11	-8	2.08
--11	-7.8	1.984
--11	-7.6	1.89
--11	-7.4	1.799
--11	-7.2	1.71
--11	-7	1.624
--11	-6.8	1.54
--11	-6.6	1.459
--11	-6.4	1.381
--11	-6.2	1.305
--11	-6	1.232
--11	-5.8	1.161
--11	-5.6	1.094
--11	-5.4	1.029
--11	-5.2	0.966
--11	-5	0.906
--11	-4.8	0.849
--11	-4.6	0.795
--11	-4.4	0.744
--11	-4.2	0.695
--11	-4	0.65
--11	-3.8	0.607
--11	-3.6	0.567
--11	-3.4	0.531
--11	-3.2	0.498
--11	-3	0.468
--11	-2.8	0.442
--11	-2.6	0.419
--11	-2.4	0.399
--11	-2.2	0.382
--11	-2	0.368
--11	-1.8	0.354
--11	-1.6	0.337
--11	-1.4	0.313
--11	-1.2	0.279
--11	-1	0.233
--11	-0.8	0.182
--11	-0.6	0.135
--11	-0.4	0.099
--11	-0.2	0.075
--11	0	0.064
--11	0.2	0.075
--11	0.4	0.099
--11	0.6	0.135
--11	0.8	0.182
--11	1	0.233
--11	1.2	0.279
--11	1.4	0.313
--11	1.6	0.337
--11	1.8	0.354
--11	2	0.368
--11	2.2	0.382
--11	2.4	0.399
--11	2.6	0.419
--11	2.8	0.442
--11	3	0.468
--11	3.2	0.498
--11	3.4	0.531
--11	3.6	0.567
--11	3.8	0.607
--11	4	0.65
--11	4.2	0.695
--11	4.4	0.744
--11	4.6	0.795
--11	4.8	0.849
--11	5	0.906
--11	5.2	0.966
--11	5.4	1.029
--11	5.6	1.094
--11	5.8	1.161
--11	6	1.232
--11	6.2	1.305
--11	6.4	1.381
--11	6.6	1.459
--11	6.8	1.54
--11	7	1.624
--11	7.2	1.71
--11	7.4	1.799
--11	7.6	1.89
--11	7.8	1.984
--11	8	2.08
--11	8.2	2.179
--11	8.4	2.281
--11	8.6	2.385
--11	8.8	2.491
--11	9	2.601
--11	9.2	2.712
--11	9.4	2.827
--11	9.6	2.943
--11	9.8	3.063
-
--10	-10	3.173
--10	-9.8	3.05
--10	-9.6	2.93
--10	-9.4	2.813
--10	-9.2	2.698
--10	-9	2.586
--10	-8.8	2.476
--10	-8.6	2.368
--10	-8.4	2.264
--10	-8.2	2.161
--10	-8	2.062
--10	-7.8	1.964
--10	-7.6	1.869
--10	-7.4	1.777
--10	-7.2	1.687
--10	-7	1.6
--10	-6.8	1.515
--10	-6.6	1.433
--10	-6.4	1.353
--10	-6.2	1.276
--10	-6	1.202
--10	-5.8	1.129
--10	-5.6	1.06
--10	-5.4	0.993
--10	-5.2	0.928
--10	-5	0.866
--10	-4.8	0.806
--10	-4.6	0.749
--10	-4.4	0.694
--10	-4.2	0.642
--10	-4	0.593
--10	-3.8	0.546
--10	-3.6	0.501
--10	-3.4	0.459
--10	-3.2	0.419
--10	-3	0.382
--10	-2.8	0.348
--10	-2.6	0.316
--10	-2.4	0.286
--10	-2.2	0.259
--10	-2	0.234
--10	-1.8	0.212
--10	-1.6	0.192
--10	-1.4	0.175
--10	-1.2	0.16
--10	-1	0.147
--10	-0.8	0.137
--10	-0.6	0.129
--10	-0.4	0.123
--10	-0.2	0.119
--10	0	0.117
--10	0.2	0.119
--10	0.4	0.123
--10	0.6	0.129
--10	0.8	0.137
--10	1	0.147
--10	1.2	0.16
--10	1.4	0.175
--10	1.6	0.192
--10	1.8	0.212
--10	2	0.234
--10	2.2	0.259
--10	2.4	0.286
--10	2.6	0.316
--10	2.8	0.348
--10	3	0.382
--10	3.2	0.419
--10	3.4	0.459
--10	3.6	0.501
--10	3.8	0.546
--10	4	0.593
--10	4.2	0.642
--10	4.4	0.694
--10	4.6	0.749
--10	4.8	0.806
--10	5	0.866
--10	5.2	0.928
--10	5.4	0.993
--10	5.6	1.06
--10	5.8	1.129
--10	6	1.202
--10	6.2	1.276
--10	6.4	1.353
--10	6.6	1.433
--10	6.8	1.515
--10	7	1.6
--10	7.2	1.687
--10	7.4	1.777
--10	7.6	1.869
--10	7.8	1.964
--10	8	2.062
--10	8.2	2.161
--10	8.4	2.264
--10	8.6	2.368
--10	8.8	2.476
--10	9	2.586
--10	9.2	2.698
--10	9.4	2.813
--10	9.6	2.93
--10	9.8	3.05
-
--9	-10	3.185
--9	-9.8	3.063
--9	-9.6	2.943
--9	-9.4	2.827
--9	-9.2	2.712
--9	-9	2.601
--9	-8.8	2.491
--9	-8.6	2.385
--9	-8.4	2.281
--9	-8.2	2.179
--9	-8	2.08
--9	-7.8	1.984
--9	-7.6	1.89
--9	-7.4	1.799
--9	-7.2	1.71
--9	-7	1.624
--9	-6.8	1.54
--9	-6.6	1.459
--9	-6.4	1.381
--9	-6.2	1.305
--9	-6	1.232
--9	-5.8	1.161
--9	-5.6	1.094
--9	-5.4	1.029
--9	-5.2	0.966
--9	-5	0.906
--9	-4.8	0.849
--9	-4.6	0.795
--9	-4.4	0.744
--9	-4.2	0.695
--9	-4	0.65
--9	-3.8	0.607
--9	-3.6	0.567
--9	-3.4	0.531
--9	-3.2	0.498
--9	-3	0.468
--9	-2.8	0.442
--9	-2.6	0.419
--9	-2.4	0.399
--9	-2.2	0.382
--9	-2	0.368
--9	-1.8	0.354
--9	-1.6	0.337
--9	-1.4	0.313
--9	-1.2	0.279
--9	-1	0.233
--9	-0.8	0.182
--9	-0.6	0.135
--9	-0.4	0.099
--9	-0.2	0.075
--9	0	0.064
--9	0.2	0.075
--9	0.4	0.099
--9	0.6	0.135
--9	0.8	0.182
--9	1	0.233
--9	1.2	0.279
--9	1.4	0.313
--9	1.6	0.337
--9	1.8	0.354
--9	2	0.368
--9	2.2	0.382
--9	2.4	0.399
--9	2.6	0.419
--9	2.8	0.442
--9	3	0.468
--9	3.2	0.498
--9	3.4	0.531
--9	3.6	0.567
--9	3.8	0.607
--9	4	0.65
--9	4.2	0.695
--9	4.4	0.744
--9	4.6	0.795
--9	4.8	0.849
--9	5	0.906
--9	5.2	0.966
--9	5.4	1.029
--9	5.6	1.094
--9	5.8	1.161
--9	6	1.232
--9	6.2	1.305
--9	6.4	1.381
--9	6.6	1.459
--9	6.8	1.54
--9	7	1.624
--9	7.2	1.71
--9	7.4	1.799
--9	7.6	1.89
--9	7.8	1.984
--9	8	2.08
--9	8.2	2.179
--9	8.4	2.281
--9	8.6	2.385
--9	8.8	2.491
--9	9	2.601
--9	9.2	2.712
--9	9.4	2.827
--9	9.6	2.943
--9	9.8	3.063
-
--8	-10	3.203
--8	-9.8	3.082
--8	-9.6	2.964
--8	-9.4	2.848
--8	-9.2	2.735
--8	-9	2.624
--8	-8.8	2.516
--8	-8.6	2.411
--8	-8.4	2.308
--8	-8.2	2.208
--8	-8	2.111
--8	-7.8	2.016
--8	-7.6	1.924
--8	-7.4	1.835
--8	-7.2	1.748
--8	-7	1.665
--8	-6.8	1.584
--8	-6.6	1.506
--8	-6.4	1.431
--8	-6.2	1.359
--8	-6	1.29
--8	-5.8	1.224
--8	-5.6	1.161
--8	-5.4	1.102
--8	-5.2	1.046
--8	-5	0.993
--8	-4.8	0.945
--8	-4.6	0.901
--8	-4.4	0.861
--8	-4.2	0.825
--8	-4	0.795
--8	-3.8	0.771
--8	-3.6	0.753
--8	-3.4	0.741
--8	-3.2	0.736
--8	-3	0.736
--8	-2.8	0.738
--8	-2.6	0.735
--8	-2.4	0.715
--8	-2.2	0.666
--8	-2	0.58
--8	-1.8	0.468
--8	-1.6	0.351
--8	-1.4	0.25
--8	-1.2	0.172
--8	-1	0.117
--8	-0.8	0.08
--8	-0.6	0.055
--8	-0.4	0.04
--8	-0.2	0.031
--8	0	0.027
--8	0.2	0.031
--8	0.4	0.04
--8	0.6	0.055
--8	0.8	0.08
--8	1	0.117
--8	1.2	0.172
--8	1.4	0.25
--8	1.6	0.351
--8	1.8	0.468
--8	2	0.58
--8	2.2	0.666
--8	2.4	0.715
--8	2.6	0.735
--8	2.8	0.738
--8	3	0.736
--8	3.2	0.736
--8	3.4	0.741
--8	3.6	0.753
--8	3.8	0.771
--8	4	0.795
--8	4.2	0.825
--8	4.4	0.861
--8	4.6	0.901
--8	4.8	0.945
--8	5	0.993
--8	5.2	1.046
--8	5.4	1.102
--8	5.6	1.161
--8	5.8	1.224
--8	6	1.29
--8	6.2	1.359
--8	6.4	1.431
--8	6.6	1.506
--8	6.8	1.584
--8	7	1.665
--8	7.2	1.748
--8	7.4	1.835
--8	7.6	1.924
--8	7.8	2.016
--8	8	2.111
--8	8.2	2.208
--8	8.4	2.308
--8	8.6	2.411
--8	8.8	2.516
--8	9	2.624
--8	9.2	2.735
--8	9.4	2.848
--8	9.6	2.964
--8	9.8	3.082
-
--7	-10	3.232
--7	-9.8	3.113
--7	-9.6	2.996
--7	-9.4	2.882
--7	-9.2	2.771
--7	-9	2.663
--7	-8.8	2.557
--7	-8.6	2.454
--7	-8.4	2.355
--7	-8.2	2.258
--7	-8	2.164
--7	-7.8	2.073
--7	-7.6	1.986
--7	-7.4	1.901
--7	-7.2	1.82
--7	-7	1.743
--7	-6.8	1.669
--7	-6.6	1.599
--7	-6.4	1.533
--7	-6.2	1.471
--7	-6	1.414
--7	-5.8	1.361
--7	-5.6	1.315
--7	-5.4	1.275
--7	-5.2	1.242
--7	-5	1.216
--7	-4.8	1.2
--7	-4.6	1.195
--7	-4.4	1.201
--7	-4.2	1.22
--7	-4	1.25
--7	-3.8	1.288
--7	-3.6	1.321
--7	-3.4	1.328
--7	-3.2	1.28
--7	-3	1.158
--7	-2.8	0.973
--7	-2.6	0.763
--7	-2.4	0.569
--7	-2.2	0.41
--7	-2	0.291
--7	-1.8	0.204
--7	-1.6	0.143
--7	-1.4	0.1
--7	-1.2	0.07
--7	-1	0.05
--7	-0.8	0.035
--7	-0.6	0.026
--7	-0.4	0.02
--7	-0.2	0.016
--7	0	0.014
--7	0.2	0.016
--7	0.4	0.02
--7	0.6	0.026
--7	0.8	0.035
--7	1	0.05
--7	1.2	0.07
--7	1.4	0.1
--7	1.6	0.143
--7	1.8	0.204
--7	2	0.291
--7	2.2	0.41
--7	2.4	0.569
--7	2.6	0.763
--7	2.8	0.973
--7	3	1.158
--7	3.2	1.28
--7	3.4	1.328
--7	3.6	1.321
--7	3.8	1.288
--7	4	1.25
--7	4.2	1.22
--7	4.4	1.201
--7	4.6	1.195
--7	4.8	1.2
--7	5	1.216
--7	5.2	1.242
--7	5.4	1.275
--7	5.6	1.315
--7	5.8	1.361
--7	6	1.414
--7	6.2	1.471
--7	6.4	1.533
--7	6.6	1.599
--7	6.8	1.669
--7	7	1.743
--7	7.2	1.82
--7	7.4	1.901
--7	7.6	1.986
--7	7.8	2.073
--7	8	2.164
--7	8.2	2.258
--7	8.4	2.355
--7	8.6	2.454
--7	8.8	2.557
--7	9	2.663
--7	9.2	2.771
--7	9.4	2.882
--7	9.6	2.996
--7	9.8	3.113
-
--6	-10	3.279
--6	-9.8	3.163
--6	-9.6	3.05
--6	-9.4	2.94
--6	-9.2	2.833
--6	-9	2.73
--6	-8.8	2.63
--6	-8.6	2.533
--6	-8.4	2.44
--6	-8.2	2.351
--6	-8	2.265
--6	-7.8	2.184
--6	-7.6	2.108
--6	-7.4	2.036
--6	-7.2	1.97
--6	-7	1.91
--6	-6.8	1.857
--6	-6.6	1.811
--6	-6.4	1.773
--6	-6.2	1.746
--6	-6	1.731
--6	-5.8	1.73
--6	-5.6	1.745
--6	-5.4	1.779
--6	-5.2	1.835
--6	-5	1.912
--6	-4.8	2.005
--6	-4.6	2.097
--6	-4.4	2.152
--6	-4.2	2.122
--6	-4	1.968
--6	-3.8	1.699
--6	-3.6	1.372
--6	-3.4	1.055
--6	-3.2	0.788
--6	-3	0.58
--6	-2.8	0.425
--6	-2.6	0.311
--6	-2.4	0.228
--6	-2.2	0.168
--6	-2	0.124
--6	-1.8	0.091
--6	-1.6	0.067
--6	-1.4	0.049
--6	-1.2	0.036
--6	-1	0.027
--6	-0.8	0.02
--6	-0.6	0.015
--6	-0.4	0.012
--6	-0.2	0.01
--6	0	0.009
--6	0.2	0.01
--6	0.4	0.012
--6	0.6	0.015
--6	0.8	0.02
--6	1	0.027
--6	1.2	0.036
--6	1.4	0.049
--6	1.6	0.067
--6	1.8	0.091
--6	2	0.124
--6	2.2	0.168
--6	2.4	0.228
--6	2.6	0.311
--6	2.8	0.425
--6	3	0.58
--6	3.2	0.788
--6	3.4	1.055
--6	3.6	1.372
--6	3.8	1.699
--6	4	1.968
--6	4.2	2.122
--6	4.4	2.152
--6	4.6	2.097
--6	4.8	2.005
--6	5	1.912
--6	5.2	1.835
--6	5.4	1.779
--6	5.6	1.745
--6	5.8	1.73
--6	6	1.731
--6	6.2	1.746
--6	6.4	1.773
--6	6.6	1.811
--6	6.8	1.857
--6	7	1.91
--6	7.2	1.97
--6	7.4	2.036
--6	7.6	2.108
--6	7.8	2.184
--6	8	2.265
--6	8.2	2.351
--6	8.4	2.44
--6	8.6	2.533
--6	8.8	2.63
--6	9	2.73
--6	9.2	2.833
--6	9.4	2.94
--6	9.6	3.05
--6	9.8	3.163
-
--5	-10	3.362
--5	-9.8	3.253
--5	-9.6	3.148
--5	-9.4	3.047
--5	-9.2	2.95
--5	-9	2.858
--5	-8.8	2.771
--5	-8.6	2.689
--5	-8.4	2.613
--5	-8.2	2.544
--5	-8	2.483
--5	-7.8	2.43
--5	-7.6	2.388
--5	-7.4	2.357
--5	-7.2	2.339
--5	-7	2.339
--5	-6.8	2.359
--5	-6.6	2.402
--5	-6.4	2.475
--5	-6.2	2.581
--5	-6	2.721
--5	-5.8	2.889
--5	-5.6	3.062
--5	-5.4	3.188
--5	-5.2	3.192
--5	-5	3.01
--5	-4.8	2.644
--5	-4.6	2.177
--5	-4.4	1.709
--5	-4.2	1.306
--5	-4	0.985
--5	-3.8	0.741
--5	-3.6	0.559
--5	-3.4	0.424
--5	-3.2	0.323
--5	-3	0.247
--5	-2.8	0.19
--5	-2.6	0.146
--5	-2.4	0.112
--5	-2.2	0.086
--5	-2	0.066
--5	-1.8	0.051
--5	-1.6	0.039
--5	-1.4	0.029
--5	-1.2	0.022
--5	-1	0.017
--5	-0.8	0.013
--5	-0.6	0.01
--5	-0.4	0.008
--5	-0.2	0.007
--5	0	0.006
--5	0.2	0.007
--5	0.4	0.008
--5	0.6	0.01
--5	0.8	0.013
--5	1	0.017
--5	1.2	0.022
--5	1.4	0.029
--5	1.6	0.039
--5	1.8	0.051
--5	2	0.066
--5	2.2	0.086
--5	2.4	0.112
--5	2.6	0.146
--5	2.8	0.19
--5	3	0.247
--5	3.2	0.323
--5	3.4	0.424
--5	3.6	0.559
--5	3.8	0.741
--5	4	0.985
--5	4.2	1.306
--5	4.4	1.709
--5	4.6	2.177
--5	4.8	2.644
--5	5	3.01
--5	5.2	3.192
--5	5.4	3.188
--5	5.6	3.062
--5	5.8	2.889
--5	6	2.721
--5	6.2	2.581
--5	6.4	2.475
--5	6.6	2.402
--5	6.8	2.359
--5	7	2.339
--5	7.2	2.339
--5	7.4	2.357
--5	7.6	2.388
--5	7.8	2.43
--5	8	2.483
--5	8.2	2.544
--5	8.4	2.613
--5	8.6	2.689
--5	8.8	2.771
--5	9	2.858
--5	9.2	2.95
--5	9.4	3.047
--5	9.6	3.148
--5	9.8	3.253
-
--4	-10	3.279
--4	-9.8	3.163
--4	-9.6	3.05
--4	-9.4	2.94
--4	-9.2	2.833
--4	-9	2.73
--4	-8.8	2.63
--4	-8.6	2.533
--4	-8.4	2.44
--4	-8.2	2.351
--4	-8	2.265
--4	-7.8	2.184
--4	-7.6	2.108
--4	-7.4	2.036
--4	-7.2	1.97
--4	-7	1.91
--4	-6.8	1.857
--4	-6.6	1.811
--4	-6.4	1.773
--4	-6.2	1.746
--4	-6	1.731
--4	-5.8	1.73
--4	-5.6	1.745
--4	-5.4	1.779
--4	-5.2	1.835
--4	-5	1.912
--4	-4.8	2.005
--4	-4.6	2.097
--4	-4.4	2.152
--4	-4.2	2.122
--4	-4	1.968
--4	-3.8	1.699
--4	-3.6	1.372
--4	-3.4	1.055
--4	-3.2	0.788
--4	-3	0.58
--4	-2.8	0.425
--4	-2.6	0.311
--4	-2.4	0.228
--4	-2.2	0.168
--4	-2	0.124
--4	-1.8	0.091
--4	-1.6	0.067
--4	-1.4	0.049
--4	-1.2	0.036
--4	-1	0.027
--4	-0.8	0.02
--4	-0.6	0.015
--4	-0.4	0.012
--4	-0.2	0.01
--4	0	0.009
--4	0.2	0.01
--4	0.4	0.012
--4	0.6	0.015
--4	0.8	0.02
--4	1	0.027
--4	1.2	0.036
--4	1.4	0.049
--4	1.6	0.067
--4	1.8	0.091
--4	2	0.124
--4	2.2	0.168
--4	2.4	0.228
--4	2.6	0.311
--4	2.8	0.425
--4	3	0.58
--4	3.2	0.788
--4	3.4	1.055
--4	3.6	1.372
--4	3.8	1.699
--4	4	1.968
--4	4.2	2.122
--4	4.4	2.152
--4	4.6	2.097
--4	4.8	2.005
--4	5	1.912
--4	5.2	1.835
--4	5.4	1.779
--4	5.6	1.745
--4	5.8	1.73
--4	6	1.731
--4	6.2	1.746
--4	6.4	1.773
--4	6.6	1.811
--4	6.8	1.857
--4	7	1.91
--4	7.2	1.97
--4	7.4	2.036
--4	7.6	2.108
--4	7.8	2.184
--4	8	2.265
--4	8.2	2.351
--4	8.4	2.44
--4	8.6	2.533
--4	8.8	2.63
--4	9	2.73
--4	9.2	2.833
--4	9.4	2.94
--4	9.6	3.05
--4	9.8	3.163
-
--3	-10	3.232
--3	-9.8	3.113
--3	-9.6	2.996
--3	-9.4	2.882
--3	-9.2	2.771
--3	-9	2.663
--3	-8.8	2.557
--3	-8.6	2.454
--3	-8.4	2.355
--3	-8.2	2.258
--3	-8	2.164
--3	-7.8	2.073
--3	-7.6	1.986
--3	-7.4	1.901
--3	-7.2	1.82
--3	-7	1.743
--3	-6.8	1.669
--3	-6.6	1.599
--3	-6.4	1.533
--3	-6.2	1.471
--3	-6	1.414
--3	-5.8	1.361
--3	-5.6	1.315
--3	-5.4	1.275
--3	-5.2	1.242
--3	-5	1.216
--3	-4.8	1.2
--3	-4.6	1.195
--3	-4.4	1.201
--3	-4.2	1.22
--3	-4	1.25
--3	-3.8	1.288
--3	-3.6	1.321
--3	-3.4	1.328
--3	-3.2	1.28
--3	-3	1.158
--3	-2.8	0.973
--3	-2.6	0.763
--3	-2.4	0.569
--3	-2.2	0.41
--3	-2	0.291
--3	-1.8	0.204
--3	-1.6	0.143
--3	-1.4	0.1
--3	-1.2	0.07
--3	-1	0.05
--3	-0.8	0.035
--3	-0.6	0.026
--3	-0.4	0.02
--3	-0.2	0.016
--3	0	0.014
--3	0.2	0.016
--3	0.4	0.02
--3	0.6	0.026
--3	0.8	0.035
--3	1	0.05
--3	1.2	0.07
--3	1.4	0.1
--3	1.6	0.143
--3	1.8	0.204
--3	2	0.291
--3	2.2	0.41
--3	2.4	0.569
--3	2.6	0.763
--3	2.8	0.973
--3	3	1.158
--3	3.2	1.28
--3	3.4	1.328
--3	3.6	1.321
--3	3.8	1.288
--3	4	1.25
--3	4.2	1.22
--3	4.4	1.201
--3	4.6	1.195
--3	4.8	1.2
--3	5	1.216
--3	5.2	1.242
--3	5.4	1.275
--3	5.6	1.315
--3	5.8	1.361
--3	6	1.414
--3	6.2	1.471
--3	6.4	1.533
--3	6.6	1.599
--3	6.8	1.669
--3	7	1.743
--3	7.2	1.82
--3	7.4	1.901
--3	7.6	1.986
--3	7.8	2.073
--3	8	2.164
--3	8.2	2.258
--3	8.4	2.355
--3	8.6	2.454
--3	8.8	2.557
--3	9	2.663
--3	9.2	2.771
--3	9.4	2.882
--3	9.6	2.996
--3	9.8	3.113
-
--2	-10	3.203
--2	-9.8	3.082
--2	-9.6	2.964
--2	-9.4	2.848
--2	-9.2	2.735
--2	-9	2.624
--2	-8.8	2.516
--2	-8.6	2.411
--2	-8.4	2.308
--2	-8.2	2.208
--2	-8	2.111
--2	-7.8	2.016
--2	-7.6	1.924
--2	-7.4	1.835
--2	-7.2	1.748
--2	-7	1.665
--2	-6.8	1.584
--2	-6.6	1.506
--2	-6.4	1.431
--2	-6.2	1.359
--2	-6	1.29
--2	-5.8	1.224
--2	-5.6	1.161
--2	-5.4	1.102
--2	-5.2	1.046
--2	-5	0.993
--2	-4.8	0.945
--2	-4.6	0.901
--2	-4.4	0.861
--2	-4.2	0.825
--2	-4	0.795
--2	-3.8	0.771
--2	-3.6	0.753
--2	-3.4	0.741
--2	-3.2	0.736
--2	-3	0.736
--2	-2.8	0.738
--2	-2.6	0.735
--2	-2.4	0.715
--2	-2.2	0.666
--2	-2	0.58
--2	-1.8	0.468
--2	-1.6	0.351
--2	-1.4	0.25
--2	-1.2	0.172
--2	-1	0.117
--2	-0.8	0.08
--2	-0.6	0.055
--2	-0.4	0.04
--2	-0.2	0.031
--2	0	0.027
--2	0.2	0.031
--2	0.4	0.04
--2	0.6	0.055
--2	0.8	0.08
--2	1	0.117
--2	1.2	0.172
--2	1.4	0.25
--2	1.6	0.351
--2	1.8	0.468
--2	2	0.58
--2	2.2	0.666
--2	2.4	0.715
--2	2.6	0.735
--2	2.8	0.738
--2	3	0.736
--2	3.2	0.736
--2	3.4	0.741
--2	3.6	0.753
--2	3.8	0.771
--2	4	0.795
--2	4.2	0.825
--2	4.4	0.861
--2	4.6	0.901
--2	4.8	0.945
--2	5	0.993
--2	5.2	1.046
--2	5.4	1.102
--2	5.6	1.161
--2	5.8	1.224
--2	6	1.29
--2	6.2	1.359
--2	6.4	1.431
--2	6.6	1.506
--2	6.8	1.584
--2	7	1.665
--2	7.2	1.748
--2	7.4	1.835
--2	7.6	1.924
--2	7.8	2.016
--2	8	2.111
--2	8.2	2.208
--2	8.4	2.308
--2	8.6	2.411
--2	8.8	2.516
--2	9	2.624
--2	9.2	2.735
--2	9.4	2.848
--2	9.6	2.964
--2	9.8	3.082
-
--1	-10	3.185
--1	-9.8	3.063
--1	-9.6	2.943
--1	-9.4	2.827
--1	-9.2	2.712
--1	-9	2.601
--1	-8.8	2.491
--1	-8.6	2.385
--1	-8.4	2.281
--1	-8.2	2.179
--1	-8	2.08
--1	-7.8	1.984
--1	-7.6	1.89
--1	-7.4	1.799
--1	-7.2	1.71
--1	-7	1.624
--1	-6.8	1.54
--1	-6.6	1.459
--1	-6.4	1.381
--1	-6.2	1.305
--1	-6	1.232
--1	-5.8	1.161
--1	-5.6	1.094
--1	-5.4	1.029
--1	-5.2	0.966
--1	-5	0.906
--1	-4.8	0.849
--1	-4.6	0.795
--1	-4.4	0.744
--1	-4.2	0.695
--1	-4	0.65
--1	-3.8	0.607
--1	-3.6	0.567
--1	-3.4	0.531
--1	-3.2	0.498
--1	-3	0.468
--1	-2.8	0.442
--1	-2.6	0.419
--1	-2.4	0.399
--1	-2.2	0.382
--1	-2	0.368
--1	-1.8	0.354
--1	-1.6	0.337
--1	-1.4	0.313
--1	-1.2	0.279
--1	-1	0.233
--1	-0.8	0.182
--1	-0.6	0.135
--1	-0.4	0.099
--1	-0.2	0.075
--1	0	0.064
--1	0.2	0.075
--1	0.4	0.099
--1	0.6	0.135
--1	0.8	0.182
--1	1	0.233
--1	1.2	0.279
--1	1.4	0.313
--1	1.6	0.337
--1	1.8	0.354
--1	2	0.368
--1	2.2	0.382
--1	2.4	0.399
--1	2.6	0.419
--1	2.8	0.442
--1	3	0.468
--1	3.2	0.498
--1	3.4	0.531
--1	3.6	0.567
--1	3.8	0.607
--1	4	0.65
--1	4.2	0.695
--1	4.4	0.744
--1	4.6	0.795
--1	4.8	0.849
--1	5	0.906
--1	5.2	0.966
--1	5.4	1.029
--1	5.6	1.094
--1	5.8	1.161
--1	6	1.232
--1	6.2	1.305
--1	6.4	1.381
--1	6.6	1.459
--1	6.8	1.54
--1	7	1.624
--1	7.2	1.71
--1	7.4	1.799
--1	7.6	1.89
--1	7.8	1.984
--1	8	2.08
--1	8.2	2.179
--1	8.4	2.281
--1	8.6	2.385
--1	8.8	2.491
--1	9	2.601
--1	9.2	2.712
--1	9.4	2.827
--1	9.6	2.943
--1	9.8	3.063
-
-0	-10	3.173
-0	-9.8	3.05
-0	-9.6	2.93
-0	-9.4	2.813
-0	-9.2	2.698
-0	-9	2.586
-0	-8.8	2.476
-0	-8.6	2.368
-0	-8.4	2.264
-0	-8.2	2.161
-0	-8	2.062
-0	-7.8	1.964
-0	-7.6	1.869
-0	-7.4	1.777
-0	-7.2	1.687
-0	-7	1.6
-0	-6.8	1.515
-0	-6.6	1.433
-0	-6.4	1.353
-0	-6.2	1.276
-0	-6	1.202
-0	-5.8	1.129
-0	-5.6	1.06
-0	-5.4	0.993
-0	-5.2	0.928
-0	-5	0.866
-0	-4.8	0.806
-0	-4.6	0.749
-0	-4.4	0.694
-0	-4.2	0.642
-0	-4	0.593
-0	-3.8	0.546
-0	-3.6	0.501
-0	-3.4	0.459
-0	-3.2	0.419
-0	-3	0.382
-0	-2.8	0.348
-0	-2.6	0.316
-0	-2.4	0.286
-0	-2.2	0.259
-0	-2	0.234
-0	-1.8	0.212
-0	-1.6	0.192
-0	-1.4	0.175
-0	-1.2	0.16
-0	-1	0.147
-0	-0.8	0.137
-0	-0.6	0.129
-0	-0.4	0.123
-0	-0.2	0.119
-0	0	0.117
-0	0.2	0.119
-0	0.4	0.123
-0	0.6	0.129
-0	0.8	0.137
-0	1	0.147
-0	1.2	0.16
-0	1.4	0.175
-0	1.6	0.192
-0	1.8	0.212
-0	2	0.234
-0	2.2	0.259
-0	2.4	0.286
-0	2.6	0.316
-0	2.8	0.348
-0	3	0.382
-0	3.2	0.419
-0	3.4	0.459
-0	3.6	0.501
-0	3.8	0.546
-0	4	0.593
-0	4.2	0.642
-0	4.4	0.694
-0	4.6	0.749
-0	4.8	0.806
-0	5	0.866
-0	5.2	0.928
-0	5.4	0.993
-0	5.6	1.06
-0	5.8	1.129
-0	6	1.202
-0	6.2	1.276
-0	6.4	1.353
-0	6.6	1.433
-0	6.8	1.515
-0	7	1.6
-0	7.2	1.687
-0	7.4	1.777
-0	7.6	1.869
-0	7.8	1.964
-0	8	2.062
-0	8.2	2.161
-0	8.4	2.264
-0	8.6	2.368
-0	8.8	2.476
-0	9	2.586
-0	9.2	2.698
-0	9.4	2.813
-0	9.6	2.93
-0	9.8	3.05
-
-1	-10	3.185
-1	-9.8	3.063
-1	-9.6	2.943
-1	-9.4	2.827
-1	-9.2	2.712
-1	-9	2.601
-1	-8.8	2.491
-1	-8.6	2.385
-1	-8.4	2.281
-1	-8.2	2.179
-1	-8	2.08
-1	-7.8	1.984
-1	-7.6	1.89
-1	-7.4	1.799
-1	-7.2	1.71
-1	-7	1.624
-1	-6.8	1.54
-1	-6.6	1.459
-1	-6.4	1.381
-1	-6.2	1.305
-1	-6	1.232
-1	-5.8	1.161
-1	-5.6	1.094
-1	-5.4	1.029
-1	-5.2	0.966
-1	-5	0.906
-1	-4.8	0.849
-1	-4.6	0.795
-1	-4.4	0.744
-1	-4.2	0.695
-1	-4	0.65
-1	-3.8	0.607
-1	-3.6	0.567
-1	-3.4	0.531
-1	-3.2	0.498
-1	-3	0.468
-1	-2.8	0.442
-1	-2.6	0.419
-1	-2.4	0.399
-1	-2.2	0.382
-1	-2	0.368
-1	-1.8	0.354
-1	-1.6	0.337
-1	-1.4	0.313
-1	-1.2	0.279
-1	-1	0.233
-1	-0.8	0.182
-1	-0.6	0.135
-1	-0.4	0.099
-1	-0.2	0.075
-1	0	0.064
-1	0.2	0.075
-1	0.4	0.099
-1	0.6	0.135
-1	0.8	0.182
-1	1	0.233
-1	1.2	0.279
-1	1.4	0.313
-1	1.6	0.337
-1	1.8	0.354
-1	2	0.368
-1	2.2	0.382
-1	2.4	0.399
-1	2.6	0.419
-1	2.8	0.442
-1	3	0.468
-1	3.2	0.498
-1	3.4	0.531
-1	3.6	0.567
-1	3.8	0.607
-1	4	0.65
-1	4.2	0.695
-1	4.4	0.744
-1	4.6	0.795
-1	4.8	0.849
-1	5	0.906
-1	5.2	0.966
-1	5.4	1.029
-1	5.6	1.094
-1	5.8	1.161
-1	6	1.232
-1	6.2	1.305
-1	6.4	1.381
-1	6.6	1.459
-1	6.8	1.54
-1	7	1.624
-1	7.2	1.71
-1	7.4	1.799
-1	7.6	1.89
-1	7.8	1.984
-1	8	2.08
-1	8.2	2.179
-1	8.4	2.281
-1	8.6	2.385
-1	8.8	2.491
-1	9	2.601
-1	9.2	2.712
-1	9.4	2.827
-1	9.6	2.943
-1	9.8	3.063
-
-2	-10	3.203
-2	-9.8	3.082
-2	-9.6	2.964
-2	-9.4	2.848
-2	-9.2	2.735
-2	-9	2.624
-2	-8.8	2.516
-2	-8.6	2.411
-2	-8.4	2.308
-2	-8.2	2.208
-2	-8	2.111
-2	-7.8	2.016
-2	-7.6	1.924
-2	-7.4	1.835
-2	-7.2	1.748
-2	-7	1.665
-2	-6.8	1.584
-2	-6.6	1.506
-2	-6.4	1.431
-2	-6.2	1.359
-2	-6	1.29
-2	-5.8	1.224
-2	-5.6	1.161
-2	-5.4	1.102
-2	-5.2	1.046
-2	-5	0.993
-2	-4.8	0.945
-2	-4.6	0.901
-2	-4.4	0.861
-2	-4.2	0.825
-2	-4	0.795
-2	-3.8	0.771
-2	-3.6	0.753
-2	-3.4	0.741
-2	-3.2	0.736
-2	-3	0.736
-2	-2.8	0.738
-2	-2.6	0.735
-2	-2.4	0.715
-2	-2.2	0.666
-2	-2	0.58
-2	-1.8	0.468
-2	-1.6	0.351
-2	-1.4	0.25
-2	-1.2	0.172
-2	-1	0.117
-2	-0.8	0.08
-2	-0.6	0.055
-2	-0.4	0.04
-2	-0.2	0.031
-2	0	0.027
-2	0.2	0.031
-2	0.4	0.04
-2	0.6	0.055
-2	0.8	0.08
-2	1	0.117
-2	1.2	0.172
-2	1.4	0.25
-2	1.6	0.351
-2	1.8	0.468
-2	2	0.58
-2	2.2	0.666
-2	2.4	0.715
-2	2.6	0.735
-2	2.8	0.738
-2	3	0.736
-2	3.2	0.736
-2	3.4	0.741
-2	3.6	0.753
-2	3.8	0.771
-2	4	0.795
-2	4.2	0.825
-2	4.4	0.861
-2	4.6	0.901
-2	4.8	0.945
-2	5	0.993
-2	5.2	1.046
-2	5.4	1.102
-2	5.6	1.161
-2	5.8	1.224
-2	6	1.29
-2	6.2	1.359
-2	6.4	1.431
-2	6.6	1.506
-2	6.8	1.584
-2	7	1.665
-2	7.2	1.748
-2	7.4	1.835
-2	7.6	1.924
-2	7.8	2.016
-2	8	2.111
-2	8.2	2.208
-2	8.4	2.308
-2	8.6	2.411
-2	8.8	2.516
-2	9	2.624
-2	9.2	2.735
-2	9.4	2.848
-2	9.6	2.964
-2	9.8	3.082
-
-3	-10	3.232
-3	-9.8	3.113
-3	-9.6	2.996
-3	-9.4	2.882
-3	-9.2	2.771
-3	-9	2.663
-3	-8.8	2.557
-3	-8.6	2.454
-3	-8.4	2.355
-3	-8.2	2.258
-3	-8	2.164
-3	-7.8	2.073
-3	-7.6	1.986
-3	-7.4	1.901
-3	-7.2	1.82
-3	-7	1.743
-3	-6.8	1.669
-3	-6.6	1.599
-3	-6.4	1.533
-3	-6.2	1.471
-3	-6	1.414
-3	-5.8	1.361
-3	-5.6	1.315
-3	-5.4	1.275
-3	-5.2	1.242
-3	-5	1.216
-3	-4.8	1.2
-3	-4.6	1.195
-3	-4.4	1.201
-3	-4.2	1.22
-3	-4	1.25
-3	-3.8	1.288
-3	-3.6	1.321
-3	-3.4	1.328
-3	-3.2	1.28
-3	-3	1.158
-3	-2.8	0.973
-3	-2.6	0.763
-3	-2.4	0.569
-3	-2.2	0.41
-3	-2	0.291
-3	-1.8	0.204
-3	-1.6	0.143
-3	-1.4	0.1
-3	-1.2	0.07
-3	-1	0.05
-3	-0.8	0.035
-3	-0.6	0.026
-3	-0.4	0.02
-3	-0.2	0.016
-3	0	0.014
-3	0.2	0.016
-3	0.4	0.02
-3	0.6	0.026
-3	0.8	0.035
-3	1	0.05
-3	1.2	0.07
-3	1.4	0.1
-3	1.6	0.143
-3	1.8	0.204
-3	2	0.291
-3	2.2	0.41
-3	2.4	0.569
-3	2.6	0.763
-3	2.8	0.973
-3	3	1.158
-3	3.2	1.28
-3	3.4	1.328
-3	3.6	1.321
-3	3.8	1.288
-3	4	1.25
-3	4.2	1.22
-3	4.4	1.201
-3	4.6	1.195
-3	4.8	1.2
-3	5	1.216
-3	5.2	1.242
-3	5.4	1.275
-3	5.6	1.315
-3	5.8	1.361
-3	6	1.414
-3	6.2	1.471
-3	6.4	1.533
-3	6.6	1.599
-3	6.8	1.669
-3	7	1.743
-3	7.2	1.82
-3	7.4	1.901
-3	7.6	1.986
-3	7.8	2.073
-3	8	2.164
-3	8.2	2.258
-3	8.4	2.355
-3	8.6	2.454
-3	8.8	2.557
-3	9	2.663
-3	9.2	2.771
-3	9.4	2.882
-3	9.6	2.996
-3	9.8	3.113
-
-4	-10	3.279
-4	-9.8	3.163
-4	-9.6	3.05
-4	-9.4	2.94
-4	-9.2	2.833
-4	-9	2.73
-4	-8.8	2.63
-4	-8.6	2.533
-4	-8.4	2.44
-4	-8.2	2.351
-4	-8	2.265
-4	-7.8	2.184
-4	-7.6	2.108
-4	-7.4	2.036
-4	-7.2	1.97
-4	-7	1.91
-4	-6.8	1.857
-4	-6.6	1.811
-4	-6.4	1.773
-4	-6.2	1.746
-4	-6	1.731
-4	-5.8	1.73
-4	-5.6	1.745
-4	-5.4	1.779
-4	-5.2	1.835
-4	-5	1.912
-4	-4.8	2.005
-4	-4.6	2.097
-4	-4.4	2.152
-4	-4.2	2.122
-4	-4	1.968
-4	-3.8	1.699
-4	-3.6	1.372
-4	-3.4	1.055
-4	-3.2	0.788
-4	-3	0.58
-4	-2.8	0.425
-4	-2.6	0.311
-4	-2.4	0.228
-4	-2.2	0.168
-4	-2	0.124
-4	-1.8	0.091
-4	-1.6	0.067
-4	-1.4	0.049
-4	-1.2	0.036
-4	-1	0.027
-4	-0.8	0.02
-4	-0.6	0.015
-4	-0.4	0.012
-4	-0.2	0.01
-4	0	0.009
-4	0.2	0.01
-4	0.4	0.012
-4	0.6	0.015
-4	0.8	0.02
-4	1	0.027
-4	1.2	0.036
-4	1.4	0.049
-4	1.6	0.067
-4	1.8	0.091
-4	2	0.124
-4	2.2	0.168
-4	2.4	0.228
-4	2.6	0.311
-4	2.8	0.425
-4	3	0.58
-4	3.2	0.788
-4	3.4	1.055
-4	3.6	1.372
-4	3.8	1.699
-4	4	1.968
-4	4.2	2.122
-4	4.4	2.152
-4	4.6	2.097
-4	4.8	2.005
-4	5	1.912
-4	5.2	1.835
-4	5.4	1.779
-4	5.6	1.745
-4	5.8	1.73
-4	6	1.731
-4	6.2	1.746
-4	6.4	1.773
-4	6.6	1.811
-4	6.8	1.857
-4	7	1.91
-4	7.2	1.97
-4	7.4	2.036
-4	7.6	2.108
-4	7.8	2.184
-4	8	2.265
-4	8.2	2.351
-4	8.4	2.44
-4	8.6	2.533
-4	8.8	2.63
-4	9	2.73
-4	9.2	2.833
-4	9.4	2.94
-4	9.6	3.05
-4	9.8	3.163
-
-5	-10	3.362
-5	-9.8	3.253
-5	-9.6	3.148
-5	-9.4	3.047
-5	-9.2	2.95
-5	-9	2.858
-5	-8.8	2.771
-5	-8.6	2.689
-5	-8.4	2.613
-5	-8.2	2.544
-5	-8	2.483
-5	-7.8	2.43
-5	-7.6	2.388
-5	-7.4	2.357
-5	-7.2	2.339
-5	-7	2.339
-5	-6.8	2.359
-5	-6.6	2.402
-5	-6.4	2.475
-5	-6.2	2.581
-5	-6	2.721
-5	-5.8	2.889
-5	-5.6	3.062
-5	-5.4	3.188
-5	-5.2	3.192
-5	-5	3.01
-5	-4.8	2.644
-5	-4.6	2.177
-5	-4.4	1.709
-5	-4.2	1.306
-5	-4	0.985
-5	-3.8	0.741
-5	-3.6	0.559
-5	-3.4	0.424
-5	-3.2	0.323
-5	-3	0.247
-5	-2.8	0.19
-5	-2.6	0.146
-5	-2.4	0.112
-5	-2.2	0.086
-5	-2	0.066
-5	-1.8	0.051
-5	-1.6	0.039
-5	-1.4	0.029
-5	-1.2	0.022
-5	-1	0.017
-5	-0.8	0.013
-5	-0.6	0.01
-5	-0.4	0.008
-5	-0.2	0.007
-5	0	0.006
-5	0.2	0.007
-5	0.4	0.008
-5	0.6	0.01
-5	0.8	0.013
-5	1	0.017
-5	1.2	0.022
-5	1.4	0.029
-5	1.6	0.039
-5	1.8	0.051
-5	2	0.066
-5	2.2	0.086
-5	2.4	0.112
-5	2.6	0.146
-5	2.8	0.19
-5	3	0.247
-5	3.2	0.323
-5	3.4	0.424
-5	3.6	0.559
-5	3.8	0.741
-5	4	0.985
-5	4.2	1.306
-5	4.4	1.709
-5	4.6	2.177
-5	4.8	2.644
-5	5	3.01
-5	5.2	3.192
-5	5.4	3.188
-5	5.6	3.062
-5	5.8	2.889
-5	6	2.721
-5	6.2	2.581
-5	6.4	2.475
-5	6.6	2.402
-5	6.8	2.359
-5	7	2.339
-5	7.2	2.339
-5	7.4	2.357
-5	7.6	2.388
-5	7.8	2.43
-5	8	2.483
-5	8.2	2.544
-5	8.4	2.613
-5	8.6	2.689
-5	8.8	2.771
-5	9	2.858
-5	9.2	2.95
-5	9.4	3.047
-5	9.6	3.148
-5	9.8	3.253
-
-6	-10	3.279
-6	-9.8	3.163
-6	-9.6	3.05
-6	-9.4	2.94
-6	-9.2	2.833
-6	-9	2.73
-6	-8.8	2.63
-6	-8.6	2.533
-6	-8.4	2.44
-6	-8.2	2.351
-6	-8	2.265
-6	-7.8	2.184
-6	-7.6	2.108
-6	-7.4	2.036
-6	-7.2	1.97
-6	-7	1.91
-6	-6.8	1.857
-6	-6.6	1.811
-6	-6.4	1.773
-6	-6.2	1.746
-6	-6	1.731
-6	-5.8	1.73
-6	-5.6	1.745
-6	-5.4	1.779
-6	-5.2	1.835
-6	-5	1.912
-6	-4.8	2.005
-6	-4.6	2.097
-6	-4.4	2.152
-6	-4.2	2.122
-6	-4	1.968
-6	-3.8	1.699
-6	-3.6	1.372
-6	-3.4	1.055
-6	-3.2	0.788
-6	-3	0.58
-6	-2.8	0.425
-6	-2.6	0.311
-6	-2.4	0.228
-6	-2.2	0.168
-6	-2	0.124
-6	-1.8	0.091
-6	-1.6	0.067
-6	-1.4	0.049
-6	-1.2	0.036
-6	-1	0.027
-6	-0.8	0.02
-6	-0.6	0.015
-6	-0.4	0.012
-6	-0.2	0.01
-6	0	0.009
-6	0.2	0.01
-6	0.4	0.012
-6	0.6	0.015
-6	0.8	0.02
-6	1	0.027
-6	1.2	0.036
-6	1.4	0.049
-6	1.6	0.067
-6	1.8	0.091
-6	2	0.124
-6	2.2	0.168
-6	2.4	0.228
-6	2.6	0.311
-6	2.8	0.425
-6	3	0.58
-6	3.2	0.788
-6	3.4	1.055
-6	3.6	1.372
-6	3.8	1.699
-6	4	1.968
-6	4.2	2.122
-6	4.4	2.152
-6	4.6	2.097
-6	4.8	2.005
-6	5	1.912
-6	5.2	1.835
-6	5.4	1.779
-6	5.6	1.745
-6	5.8	1.73
-6	6	1.731
-6	6.2	1.746
-6	6.4	1.773
-6	6.6	1.811
-6	6.8	1.857
-6	7	1.91
-6	7.2	1.97
-6	7.4	2.036
-6	7.6	2.108
-6	7.8	2.184
-6	8	2.265
-6	8.2	2.351
-6	8.4	2.44
-6	8.6	2.533
-6	8.8	2.63
-6	9	2.73
-6	9.2	2.833
-6	9.4	2.94
-6	9.6	3.05
-6	9.8	3.163
-
-7	-10	3.232
-7	-9.8	3.113
-7	-9.6	2.996
-7	-9.4	2.882
-7	-9.2	2.771
-7	-9	2.663
-7	-8.8	2.557
-7	-8.6	2.454
-7	-8.4	2.355
-7	-8.2	2.258
-7	-8	2.164
-7	-7.8	2.073
-7	-7.6	1.986
-7	-7.4	1.901
-7	-7.2	1.82
-7	-7	1.743
-7	-6.8	1.669
-7	-6.6	1.599
-7	-6.4	1.533
-7	-6.2	1.471
-7	-6	1.414
-7	-5.8	1.361
-7	-5.6	1.315
-7	-5.4	1.275
-7	-5.2	1.242
-7	-5	1.216
-7	-4.8	1.2
-7	-4.6	1.195
-7	-4.4	1.201
-7	-4.2	1.22
-7	-4	1.25
-7	-3.8	1.288
-7	-3.6	1.321
-7	-3.4	1.328
-7	-3.2	1.28
-7	-3	1.158
-7	-2.8	0.973
-7	-2.6	0.763
-7	-2.4	0.569
-7	-2.2	0.41
-7	-2	0.291
-7	-1.8	0.204
-7	-1.6	0.143
-7	-1.4	0.1
-7	-1.2	0.07
-7	-1	0.05
-7	-0.8	0.035
-7	-0.6	0.026
-7	-0.4	0.02
-7	-0.2	0.016
-7	0	0.014
-7	0.2	0.016
-7	0.4	0.02
-7	0.6	0.026
-7	0.8	0.035
-7	1	0.05
-7	1.2	0.07
-7	1.4	0.1
-7	1.6	0.143
-7	1.8	0.204
-7	2	0.291
-7	2.2	0.41
-7	2.4	0.569
-7	2.6	0.763
-7	2.8	0.973
-7	3	1.158
-7	3.2	1.28
-7	3.4	1.328
-7	3.6	1.321
-7	3.8	1.288
-7	4	1.25
-7	4.2	1.22
-7	4.4	1.201
-7	4.6	1.195
-7	4.8	1.2
-7	5	1.216
-7	5.2	1.242
-7	5.4	1.275
-7	5.6	1.315
-7	5.8	1.361
-7	6	1.414
-7	6.2	1.471
-7	6.4	1.533
-7	6.6	1.599
-7	6.8	1.669
-7	7	1.743
-7	7.2	1.82
-7	7.4	1.901
-7	7.6	1.986
-7	7.8	2.073
-7	8	2.164
-7	8.2	2.258
-7	8.4	2.355
-7	8.6	2.454
-7	8.8	2.557
-7	9	2.663
-7	9.2	2.771
-7	9.4	2.882
-7	9.6	2.996
-7	9.8	3.113
-
-8	-10	3.203
-8	-9.8	3.082
-8	-9.6	2.964
-8	-9.4	2.848
-8	-9.2	2.735
-8	-9	2.624
-8	-8.8	2.516
-8	-8.6	2.411
-8	-8.4	2.308
-8	-8.2	2.208
-8	-8	2.111
-8	-7.8	2.016
-8	-7.6	1.924
-8	-7.4	1.835
-8	-7.2	1.748
-8	-7	1.665
-8	-6.8	1.584
-8	-6.6	1.506
-8	-6.4	1.431
-8	-6.2	1.359
-8	-6	1.29
-8	-5.8	1.224
-8	-5.6	1.161
-8	-5.4	1.102
-8	-5.2	1.046
-8	-5	0.993
-8	-4.8	0.945
-8	-4.6	0.901
-8	-4.4	0.861
-8	-4.2	0.825
-8	-4	0.795
-8	-3.8	0.771
-8	-3.6	0.753
-8	-3.4	0.741
-8	-3.2	0.736
-8	-3	0.736
-8	-2.8	0.738
-8	-2.6	0.735
-8	-2.4	0.715
-8	-2.2	0.666
-8	-2	0.58
-8	-1.8	0.468
-8	-1.6	0.351
-8	-1.4	0.25
-8	-1.2	0.172
-8	-1	0.117
-8	-0.8	0.08
-8	-0.6	0.055
-8	-0.4	0.04
-8	-0.2	0.031
-8	0	0.027
-8	0.2	0.031
-8	0.4	0.04
-8	0.6	0.055
-8	0.8	0.08
-8	1	0.117
-8	1.2	0.172
-8	1.4	0.25
-8	1.6	0.351
-8	1.8	0.468
-8	2	0.58
-8	2.2	0.666
-8	2.4	0.715
-8	2.6	0.735
-8	2.8	0.738
-8	3	0.736
-8	3.2	0.736
-8	3.4	0.741
-8	3.6	0.753
-8	3.8	0.771
-8	4	0.795
-8	4.2	0.825
-8	4.4	0.861
-8	4.6	0.901
-8	4.8	0.945
-8	5	0.993
-8	5.2	1.046
-8	5.4	1.102
-8	5.6	1.161
-8	5.8	1.224
-8	6	1.29
-8	6.2	1.359
-8	6.4	1.431
-8	6.6	1.506
-8	6.8	1.584
-8	7	1.665
-8	7.2	1.748
-8	7.4	1.835
-8	7.6	1.924
-8	7.8	2.016
-8	8	2.111
-8	8.2	2.208
-8	8.4	2.308
-8	8.6	2.411
-8	8.8	2.516
-8	9	2.624
-8	9.2	2.735
-8	9.4	2.848
-8	9.6	2.964
-8	9.8	3.082
-
-9	-10	3.185
-9	-9.8	3.063
-9	-9.6	2.943
-9	-9.4	2.827
-9	-9.2	2.712
-9	-9	2.601
-9	-8.8	2.491
-9	-8.6	2.385
-9	-8.4	2.281
-9	-8.2	2.179
-9	-8	2.08
-9	-7.8	1.984
-9	-7.6	1.89
-9	-7.4	1.799
-9	-7.2	1.71
-9	-7	1.624
-9	-6.8	1.54
-9	-6.6	1.459
-9	-6.4	1.381
-9	-6.2	1.305
-9	-6	1.232
-9	-5.8	1.161
-9	-5.6	1.094
-9	-5.4	1.029
-9	-5.2	0.966
-9	-5	0.906
-9	-4.8	0.849
-9	-4.6	0.795
-9	-4.4	0.744
-9	-4.2	0.695
-9	-4	0.65
-9	-3.8	0.607
-9	-3.6	0.567
-9	-3.4	0.531
-9	-3.2	0.498
-9	-3	0.468
-9	-2.8	0.442
-9	-2.6	0.419
-9	-2.4	0.399
-9	-2.2	0.382
-9	-2	0.368
-9	-1.8	0.354
-9	-1.6	0.337
-9	-1.4	0.313
-9	-1.2	0.279
-9	-1	0.233
-9	-0.8	0.182
-9	-0.6	0.135
-9	-0.4	0.099
-9	-0.2	0.075
-9	0	0.064
-9	0.2	0.075
-9	0.4	0.099
-9	0.6	0.135
-9	0.8	0.182
-9	1	0.233
-9	1.2	0.279
-9	1.4	0.313
-9	1.6	0.337
-9	1.8	0.354
-9	2	0.368
-9	2.2	0.382
-9	2.4	0.399
-9	2.6	0.419
-9	2.8	0.442
-9	3	0.468
-9	3.2	0.498
-9	3.4	0.531
-9	3.6	0.567
-9	3.8	0.607
-9	4	0.65
-9	4.2	0.695
-9	4.4	0.744
-9	4.6	0.795
-9	4.8	0.849
-9	5	0.906
-9	5.2	0.966
-9	5.4	1.029
-9	5.6	1.094
-9	5.8	1.161
-9	6	1.232
-9	6.2	1.305
-9	6.4	1.381
-9	6.6	1.459
-9	6.8	1.54
-9	7	1.624
-9	7.2	1.71
-9	7.4	1.799
-9	7.6	1.89
-9	7.8	1.984
-9	8	2.08
-9	8.2	2.179
-9	8.4	2.281
-9	8.6	2.385
-9	8.8	2.491
-9	9	2.601
-9	9.2	2.712
-9	9.4	2.827
-9	9.6	2.943
-9	9.8	3.063
-
-10	-10	3.173
-10	-9.8	3.05
-10	-9.6	2.93
-10	-9.4	2.813
-10	-9.2	2.698
-10	-9	2.586
-10	-8.8	2.476
-10	-8.6	2.368
-10	-8.4	2.264
-10	-8.2	2.161
-10	-8	2.062
-10	-7.8	1.964
-10	-7.6	1.869
-10	-7.4	1.777
-10	-7.2	1.687
-10	-7	1.6
-10	-6.8	1.515
-10	-6.6	1.433
-10	-6.4	1.353
-10	-6.2	1.276
-10	-6	1.202
-10	-5.8	1.129
-10	-5.6	1.06
-10	-5.4	0.993
-10	-5.2	0.928
-10	-5	0.866
-10	-4.8	0.806
-10	-4.6	0.749
-10	-4.4	0.694
-10	-4.2	0.642
-10	-4	0.593
-10	-3.8	0.546
-10	-3.6	0.501
-10	-3.4	0.459
-10	-3.2	0.419
-10	-3	0.382
-10	-2.8	0.348
-10	-2.6	0.316
-10	-2.4	0.286
-10	-2.2	0.259
-10	-2	0.234
-10	-1.8	0.212
-10	-1.6	0.192
-10	-1.4	0.175
-10	-1.2	0.16
-10	-1	0.147
-10	-0.8	0.137
-10	-0.6	0.129
-10	-0.4	0.123
-10	-0.2	0.119
-10	0	0.117
-10	0.2	0.119
-10	0.4	0.123
-10	0.6	0.129
-10	0.8	0.137
-10	1	0.147
-10	1.2	0.16
-10	1.4	0.175
-10	1.6	0.192
-10	1.8	0.212
-10	2	0.234
-10	2.2	0.259
-10	2.4	0.286
-10	2.6	0.316
-10	2.8	0.348
-10	3	0.382
-10	3.2	0.419
-10	3.4	0.459
-10	3.6	0.501
-10	3.8	0.546
-10	4	0.593
-10	4.2	0.642
-10	4.4	0.694
-10	4.6	0.749
-10	4.8	0.806
-10	5	0.866
-10	5.2	0.928
-10	5.4	0.993
-10	5.6	1.06
-10	5.8	1.129
-10	6	1.202
-10	6.2	1.276
-10	6.4	1.353
-10	6.6	1.433
-10	6.8	1.515
-10	7	1.6
-10	7.2	1.687
-10	7.4	1.777
-10	7.6	1.869
-10	7.8	1.964
-10	8	2.062
-10	8.2	2.161
-10	8.4	2.264
-10	8.6	2.368
-10	8.8	2.476
-10	9	2.586
-10	9.2	2.698
-10	9.4	2.813
-10	9.6	2.93
-10	9.8	3.05
-
-11	-10	3.185
-11	-9.8	3.063
-11	-9.6	2.943
-11	-9.4	2.827
-11	-9.2	2.712
-11	-9	2.601
-11	-8.8	2.491
-11	-8.6	2.385
-11	-8.4	2.281
-11	-8.2	2.179
-11	-8	2.08
-11	-7.8	1.984
-11	-7.6	1.89
-11	-7.4	1.799
-11	-7.2	1.71
-11	-7	1.624
-11	-6.8	1.54
-11	-6.6	1.459
-11	-6.4	1.381
-11	-6.2	1.305
-11	-6	1.232
-11	-5.8	1.161
-11	-5.6	1.094
-11	-5.4	1.029
-11	-5.2	0.966
-11	-5	0.906
-11	-4.8	0.849
-11	-4.6	0.795
-11	-4.4	0.744
-11	-4.2	0.695
-11	-4	0.65
-11	-3.8	0.607
-11	-3.6	0.567
-11	-3.4	0.531
-11	-3.2	0.498
-11	-3	0.468
-11	-2.8	0.442
-11	-2.6	0.419
-11	-2.4	0.399
-11	-2.2	0.382
-11	-2	0.368
-11	-1.8	0.354
-11	-1.6	0.337
-11	-1.4	0.313
-11	-1.2	0.279
-11	-1	0.233
-11	-0.8	0.182
-11	-0.6	0.135
-11	-0.4	0.099
-11	-0.2	0.075
-11	0	0.064
-11	0.2	0.075
-11	0.4	0.099
-11	0.6	0.135
-11	0.8	0.182
-11	1	0.233
-11	1.2	0.279
-11	1.4	0.313
-11	1.6	0.337
-11	1.8	0.354
-11	2	0.368
-11	2.2	0.382
-11	2.4	0.399
-11	2.6	0.419
-11	2.8	0.442
-11	3	0.468
-11	3.2	0.498
-11	3.4	0.531
-11	3.6	0.567
-11	3.8	0.607
-11	4	0.65
-11	4.2	0.695
-11	4.4	0.744
-11	4.6	0.795
-11	4.8	0.849
-11	5	0.906
-11	5.2	0.966
-11	5.4	1.029
-11	5.6	1.094
-11	5.8	1.161
-11	6	1.232
-11	6.2	1.305
-11	6.4	1.381
-11	6.6	1.459
-11	6.8	1.54
-11	7	1.624
-11	7.2	1.71
-11	7.4	1.799
-11	7.6	1.89
-11	7.8	1.984
-11	8	2.08
-11	8.2	2.179
-11	8.4	2.281
-11	8.6	2.385
-11	8.8	2.491
-11	9	2.601
-11	9.2	2.712
-11	9.4	2.827
-11	9.6	2.943
-11	9.8	3.063
-
-12	-10	3.203
-12	-9.8	3.082
-12	-9.6	2.964
-12	-9.4	2.848
-12	-9.2	2.735
-12	-9	2.624
-12	-8.8	2.516
-12	-8.6	2.411
-12	-8.4	2.308
-12	-8.2	2.208
-12	-8	2.111
-12	-7.8	2.016
-12	-7.6	1.924
-12	-7.4	1.835
-12	-7.2	1.748
-12	-7	1.665
-12	-6.8	1.584
-12	-6.6	1.506
-12	-6.4	1.431
-12	-6.2	1.359
-12	-6	1.29
-12	-5.8	1.224
-12	-5.6	1.161
-12	-5.4	1.102
-12	-5.2	1.046
-12	-5	0.993
-12	-4.8	0.945
-12	-4.6	0.901
-12	-4.4	0.861
-12	-4.2	0.825
-12	-4	0.795
-12	-3.8	0.771
-12	-3.6	0.753
-12	-3.4	0.741
-12	-3.2	0.736
-12	-3	0.736
-12	-2.8	0.738
-12	-2.6	0.735
-12	-2.4	0.715
-12	-2.2	0.666
-12	-2	0.58
-12	-1.8	0.468
-12	-1.6	0.351
-12	-1.4	0.25
-12	-1.2	0.172
-12	-1	0.117
-12	-0.8	0.08
-12	-0.6	0.055
-12	-0.4	0.04
-12	-0.2	0.031
-12	0	0.027
-12	0.2	0.031
-12	0.4	0.04
-12	0.6	0.055
-12	0.8	0.08
-12	1	0.117
-12	1.2	0.172
-12	1.4	0.25
-12	1.6	0.351
-12	1.8	0.468
-12	2	0.58
-12	2.2	0.666
-12	2.4	0.715
-12	2.6	0.735
-12	2.8	0.738
-12	3	0.736
-12	3.2	0.736
-12	3.4	0.741
-12	3.6	0.753
-12	3.8	0.771
-12	4	0.795
-12	4.2	0.825
-12	4.4	0.861
-12	4.6	0.901
-12	4.8	0.945
-12	5	0.993
-12	5.2	1.046
-12	5.4	1.102
-12	5.6	1.161
-12	5.8	1.224
-12	6	1.29
-12	6.2	1.359
-12	6.4	1.431
-12	6.6	1.506
-12	6.8	1.584
-12	7	1.665
-12	7.2	1.748
-12	7.4	1.835
-12	7.6	1.924
-12	7.8	2.016
-12	8	2.111
-12	8.2	2.208
-12	8.4	2.308
-12	8.6	2.411
-12	8.8	2.516
-12	9	2.624
-12	9.2	2.735
-12	9.4	2.848
-12	9.6	2.964
-12	9.8	3.082
-
-13	-10	3.232
-13	-9.8	3.113
-13	-9.6	2.996
-13	-9.4	2.882
-13	-9.2	2.771
-13	-9	2.663
-13	-8.8	2.557
-13	-8.6	2.454
-13	-8.4	2.355
-13	-8.2	2.258
-13	-8	2.164
-13	-7.8	2.073
-13	-7.6	1.986
-13	-7.4	1.901
-13	-7.2	1.82
-13	-7	1.743
-13	-6.8	1.669
-13	-6.6	1.599
-13	-6.4	1.533
-13	-6.2	1.471
-13	-6	1.414
-13	-5.8	1.361
-13	-5.6	1.315
-13	-5.4	1.275
-13	-5.2	1.242
-13	-5	1.216
-13	-4.8	1.2
-13	-4.6	1.195
-13	-4.4	1.201
-13	-4.2	1.22
-13	-4	1.25
-13	-3.8	1.288
-13	-3.6	1.321
-13	-3.4	1.328
-13	-3.2	1.28
-13	-3	1.158
-13	-2.8	0.973
-13	-2.6	0.763
-13	-2.4	0.569
-13	-2.2	0.41
-13	-2	0.291
-13	-1.8	0.204
-13	-1.6	0.143
-13	-1.4	0.1
-13	-1.2	0.07
-13	-1	0.05
-13	-0.8	0.035
-13	-0.6	0.026
-13	-0.4	0.02
-13	-0.2	0.016
-13	0	0.014
-13	0.2	0.016
-13	0.4	0.02
-13	0.6	0.026
-13	0.8	0.035
-13	1	0.05
-13	1.2	0.07
-13	1.4	0.1
-13	1.6	0.143
-13	1.8	0.204
-13	2	0.291
-13	2.2	0.41
-13	2.4	0.569
-13	2.6	0.763
-13	2.8	0.973
-13	3	1.158
-13	3.2	1.28
-13	3.4	1.328
-13	3.6	1.321
-13	3.8	1.288
-13	4	1.25
-13	4.2	1.22
-13	4.4	1.201
-13	4.6	1.195
-13	4.8	1.2
-13	5	1.216
-13	5.2	1.242
-13	5.4	1.275
-13	5.6	1.315
-13	5.8	1.361
-13	6	1.414
-13	6.2	1.471
-13	6.4	1.533
-13	6.6	1.599
-13	6.8	1.669
-13	7	1.743
-13	7.2	1.82
-13	7.4	1.901
-13	7.6	1.986
-13	7.8	2.073
-13	8	2.164
-13	8.2	2.258
-13	8.4	2.355
-13	8.6	2.454
-13	8.8	2.557
-13	9	2.663
-13	9.2	2.771
-13	9.4	2.882
-13	9.6	2.996
-13	9.8	3.113
-
-14	-10	3.279
-14	-9.8	3.163
-14	-9.6	3.05
-14	-9.4	2.94
-14	-9.2	2.833
-14	-9	2.73
-14	-8.8	2.63
-14	-8.6	2.533
-14	-8.4	2.44
-14	-8.2	2.351
-14	-8	2.265
-14	-7.8	2.184
-14	-7.6	2.108
-14	-7.4	2.036
-14	-7.2	1.97
-14	-7	1.91
-14	-6.8	1.857
-14	-6.6	1.811
-14	-6.4	1.773
-14	-6.2	1.746
-14	-6	1.731
-14	-5.8	1.73
-14	-5.6	1.745
-14	-5.4	1.779
-14	-5.2	1.835
-14	-5	1.912
-14	-4.8	2.005
-14	-4.6	2.097
-14	-4.4	2.152
-14	-4.2	2.122
-14	-4	1.968
-14	-3.8	1.699
-14	-3.6	1.372
-14	-3.4	1.055
-14	-3.2	0.788
-14	-3	0.58
-14	-2.8	0.425
-14	-2.6	0.311
-14	-2.4	0.228
-14	-2.2	0.168
-14	-2	0.124
-14	-1.8	0.091
-14	-1.6	0.067
-14	-1.4	0.049
-14	-1.2	0.036
-14	-1	0.027
-14	-0.8	0.02
-14	-0.6	0.015
-14	-0.4	0.012
-14	-0.2	0.01
-14	0	0.009
-14	0.2	0.01
-14	0.4	0.012
-14	0.6	0.015
-14	0.8	0.02
-14	1	0.027
-14	1.2	0.036
-14	1.4	0.049
-14	1.6	0.067
-14	1.8	0.091
-14	2	0.124
-14	2.2	0.168
-14	2.4	0.228
-14	2.6	0.311
-14	2.8	0.425
-14	3	0.58
-14	3.2	0.788
-14	3.4	1.055
-14	3.6	1.372
-14	3.8	1.699
-14	4	1.968
-14	4.2	2.122
-14	4.4	2.152
-14	4.6	2.097
-14	4.8	2.005
-14	5	1.912
-14	5.2	1.835
-14	5.4	1.779
-14	5.6	1.745
-14	5.8	1.73
-14	6	1.731
-14	6.2	1.746
-14	6.4	1.773
-14	6.6	1.811
-14	6.8	1.857
-14	7	1.91
-14	7.2	1.97
-14	7.4	2.036
-14	7.6	2.108
-14	7.8	2.184
-14	8	2.265
-14	8.2	2.351
-14	8.4	2.44
-14	8.6	2.533
-14	8.8	2.63
-14	9	2.73
-14	9.2	2.833
-14	9.4	2.94
-14	9.6	3.05
-14	9.8	3.163
diff --git a/docs/examples/test_multi_d/chan1.dat b/docs/examples/test_multi_d/chan1.dat
deleted file mode 100644
index 91ead1d6f75d..000000000000
--- a/docs/examples/test_multi_d/chan1.dat
+++ /dev/null
@@ -1,33 +0,0 @@
-# chan1	avg_amplitude	amplitude_2
-# "Gate Channel 1 (mV)"	"Average: Current (nA)"	"Current (nA)"
-# 30
--15	1.63366	0.006
--14	1.48254	0.009
--13	1.3513	0.014
--12	1.24736	0.027
--11	1.17375	0.064
--10	1.12666	0.117
--9	1.17375	0.064
--8	1.24736	0.027
--7	1.3513	0.014
--6	1.48254	0.009
--5	1.63366	0.006
--4	1.48254	0.009
--3	1.3513	0.014
--2	1.24736	0.027
--1	1.17375	0.064
-0	1.12666	0.117
-1	1.17375	0.064
-2	1.24736	0.027
-3	1.3513	0.014
-4	1.48254	0.009
-5	1.63366	0.006
-6	1.48254	0.009
-7	1.3513	0.014
-8	1.24736	0.027
-9	1.17375	0.064
-10	1.12666	0.117
-11	1.17375	0.064
-12	1.24736	0.027
-13	1.3513	0.014
-14	1.48254	0.009
diff --git a/docs/examples/test_multi_d/chan1_chan0.dat b/docs/examples/test_multi_d/chan1_chan0.dat
deleted file mode 100644
index 25d0d053de83..000000000000
--- a/docs/examples/test_multi_d/chan1_chan0.dat
+++ /dev/null
@@ -1,932 +0,0 @@
-# chan1	chan0	amplitude_3_0
-# "Gate Channel 1 (mV)"	"Gate Channel 0 (mV)"	"Current (nA)"
-# 30	30
--15	-15	0.003
--15	-14	0.004
--15	-13	0.005
--15	-12	0.005
--15	-11	0.006
--15	-10	0.006
--15	-9	0.006
--15	-8	0.005
--15	-7	0.005
--15	-6	0.004
--15	-5	0.003
--15	-4	0.004
--15	-3	0.005
--15	-2	0.005
--15	-1	0.006
--15	0	0.006
--15	1	0.006
--15	2	0.005
--15	3	0.005
--15	4	0.004
--15	5	0.003
--15	6	0.004
--15	7	0.005
--15	8	0.005
--15	9	0.006
--15	10	0.006
--15	11	0.006
--15	12	0.005
--15	13	0.005
--15	14	0.004
-
--14	-15	0.004
--14	-14	0.005
--14	-13	0.006
--14	-12	0.007
--14	-11	0.008
--14	-10	0.009
--14	-9	0.008
--14	-8	0.007
--14	-7	0.006
--14	-6	0.005
--14	-5	0.004
--14	-4	0.005
--14	-3	0.006
--14	-2	0.007
--14	-1	0.008
--14	0	0.009
--14	1	0.008
--14	2	0.007
--14	3	0.006
--14	4	0.005
--14	5	0.004
--14	6	0.005
--14	7	0.006
--14	8	0.007
--14	9	0.008
--14	10	0.009
--14	11	0.008
--14	12	0.007
--14	13	0.006
--14	14	0.005
-
--13	-15	0.005
--13	-14	0.006
--13	-13	0.008
--13	-12	0.01
--13	-11	0.013
--13	-10	0.014
--13	-9	0.013
--13	-8	0.01
--13	-7	0.008
--13	-6	0.006
--13	-5	0.005
--13	-4	0.006
--13	-3	0.008
--13	-2	0.01
--13	-1	0.013
--13	0	0.014
--13	1	0.013
--13	2	0.01
--13	3	0.008
--13	4	0.006
--13	5	0.005
--13	6	0.006
--13	7	0.008
--13	8	0.01
--13	9	0.013
--13	10	0.014
--13	11	0.013
--13	12	0.01
--13	13	0.008
--13	14	0.006
-
--12	-15	0.005
--12	-14	0.007
--12	-13	0.01
--12	-12	0.016
--12	-11	0.023
--12	-10	0.027
--12	-9	0.023
--12	-8	0.016
--12	-7	0.01
--12	-6	0.007
--12	-5	0.005
--12	-4	0.007
--12	-3	0.01
--12	-2	0.016
--12	-1	0.023
--12	0	0.027
--12	1	0.023
--12	2	0.016
--12	3	0.01
--12	4	0.007
--12	5	0.005
--12	6	0.007
--12	7	0.01
--12	8	0.016
--12	9	0.023
--12	10	0.027
--12	11	0.023
--12	12	0.016
--12	13	0.01
--12	14	0.007
-
--11	-15	0.006
--11	-14	0.008
--11	-13	0.013
--11	-12	0.023
--11	-11	0.044
--11	-10	0.064
--11	-9	0.044
--11	-8	0.023
--11	-7	0.013
--11	-6	0.008
--11	-5	0.006
--11	-4	0.008
--11	-3	0.013
--11	-2	0.023
--11	-1	0.044
--11	0	0.064
--11	1	0.044
--11	2	0.023
--11	3	0.013
--11	4	0.008
--11	5	0.006
--11	6	0.008
--11	7	0.013
--11	8	0.023
--11	9	0.044
--11	10	0.064
--11	11	0.044
--11	12	0.023
--11	13	0.013
--11	14	0.008
-
--10	-15	0.006
--10	-14	0.009
--10	-13	0.014
--10	-12	0.027
--10	-11	0.064
--10	-10	0.117
--10	-9	0.064
--10	-8	0.027
--10	-7	0.014
--10	-6	0.009
--10	-5	0.006
--10	-4	0.009
--10	-3	0.014
--10	-2	0.027
--10	-1	0.064
--10	0	0.117
--10	1	0.064
--10	2	0.027
--10	3	0.014
--10	4	0.009
--10	5	0.006
--10	6	0.009
--10	7	0.014
--10	8	0.027
--10	9	0.064
--10	10	0.117
--10	11	0.064
--10	12	0.027
--10	13	0.014
--10	14	0.009
-
--9	-15	0.006
--9	-14	0.008
--9	-13	0.013
--9	-12	0.023
--9	-11	0.044
--9	-10	0.064
--9	-9	0.044
--9	-8	0.023
--9	-7	0.013
--9	-6	0.008
--9	-5	0.006
--9	-4	0.008
--9	-3	0.013
--9	-2	0.023
--9	-1	0.044
--9	0	0.064
--9	1	0.044
--9	2	0.023
--9	3	0.013
--9	4	0.008
--9	5	0.006
--9	6	0.008
--9	7	0.013
--9	8	0.023
--9	9	0.044
--9	10	0.064
--9	11	0.044
--9	12	0.023
--9	13	0.013
--9	14	0.008
-
--8	-15	0.005
--8	-14	0.007
--8	-13	0.01
--8	-12	0.016
--8	-11	0.023
--8	-10	0.027
--8	-9	0.023
--8	-8	0.016
--8	-7	0.01
--8	-6	0.007
--8	-5	0.005
--8	-4	0.007
--8	-3	0.01
--8	-2	0.016
--8	-1	0.023
--8	0	0.027
--8	1	0.023
--8	2	0.016
--8	3	0.01
--8	4	0.007
--8	5	0.005
--8	6	0.007
--8	7	0.01
--8	8	0.016
--8	9	0.023
--8	10	0.027
--8	11	0.023
--8	12	0.016
--8	13	0.01
--8	14	0.007
-
--7	-15	0.005
--7	-14	0.006
--7	-13	0.008
--7	-12	0.01
--7	-11	0.013
--7	-10	0.014
--7	-9	0.013
--7	-8	0.01
--7	-7	0.008
--7	-6	0.006
--7	-5	0.005
--7	-4	0.006
--7	-3	0.008
--7	-2	0.01
--7	-1	0.013
--7	0	0.014
--7	1	0.013
--7	2	0.01
--7	3	0.008
--7	4	0.006
--7	5	0.005
--7	6	0.006
--7	7	0.008
--7	8	0.01
--7	9	0.013
--7	10	0.014
--7	11	0.013
--7	12	0.01
--7	13	0.008
--7	14	0.006
-
--6	-15	0.004
--6	-14	0.005
--6	-13	0.006
--6	-12	0.007
--6	-11	0.008
--6	-10	0.009
--6	-9	0.008
--6	-8	0.007
--6	-7	0.006
--6	-6	0.005
--6	-5	0.004
--6	-4	0.005
--6	-3	0.006
--6	-2	0.007
--6	-1	0.008
--6	0	0.009
--6	1	0.008
--6	2	0.007
--6	3	0.006
--6	4	0.005
--6	5	0.004
--6	6	0.005
--6	7	0.006
--6	8	0.007
--6	9	0.008
--6	10	0.009
--6	11	0.008
--6	12	0.007
--6	13	0.006
--6	14	0.005
-
--5	-15	0.003
--5	-14	0.004
--5	-13	0.005
--5	-12	0.005
--5	-11	0.006
--5	-10	0.006
--5	-9	0.006
--5	-8	0.005
--5	-7	0.005
--5	-6	0.004
--5	-5	0.003
--5	-4	0.004
--5	-3	0.005
--5	-2	0.005
--5	-1	0.006
--5	0	0.006
--5	1	0.006
--5	2	0.005
--5	3	0.005
--5	4	0.004
--5	5	0.003
--5	6	0.004
--5	7	0.005
--5	8	0.005
--5	9	0.006
--5	10	0.006
--5	11	0.006
--5	12	0.005
--5	13	0.005
--5	14	0.004
-
--4	-15	0.004
--4	-14	0.005
--4	-13	0.006
--4	-12	0.007
--4	-11	0.008
--4	-10	0.009
--4	-9	0.008
--4	-8	0.007
--4	-7	0.006
--4	-6	0.005
--4	-5	0.004
--4	-4	0.005
--4	-3	0.006
--4	-2	0.007
--4	-1	0.008
--4	0	0.009
--4	1	0.008
--4	2	0.007
--4	3	0.006
--4	4	0.005
--4	5	0.004
--4	6	0.005
--4	7	0.006
--4	8	0.007
--4	9	0.008
--4	10	0.009
--4	11	0.008
--4	12	0.007
--4	13	0.006
--4	14	0.005
-
--3	-15	0.005
--3	-14	0.006
--3	-13	0.008
--3	-12	0.01
--3	-11	0.013
--3	-10	0.014
--3	-9	0.013
--3	-8	0.01
--3	-7	0.008
--3	-6	0.006
--3	-5	0.005
--3	-4	0.006
--3	-3	0.008
--3	-2	0.01
--3	-1	0.013
--3	0	0.014
--3	1	0.013
--3	2	0.01
--3	3	0.008
--3	4	0.006
--3	5	0.005
--3	6	0.006
--3	7	0.008
--3	8	0.01
--3	9	0.013
--3	10	0.014
--3	11	0.013
--3	12	0.01
--3	13	0.008
--3	14	0.006
-
--2	-15	0.005
--2	-14	0.007
--2	-13	0.01
--2	-12	0.016
--2	-11	0.023
--2	-10	0.027
--2	-9	0.023
--2	-8	0.016
--2	-7	0.01
--2	-6	0.007
--2	-5	0.005
--2	-4	0.007
--2	-3	0.01
--2	-2	0.016
--2	-1	0.023
--2	0	0.027
--2	1	0.023
--2	2	0.016
--2	3	0.01
--2	4	0.007
--2	5	0.005
--2	6	0.007
--2	7	0.01
--2	8	0.016
--2	9	0.023
--2	10	0.027
--2	11	0.023
--2	12	0.016
--2	13	0.01
--2	14	0.007
-
--1	-15	0.006
--1	-14	0.008
--1	-13	0.013
--1	-12	0.023
--1	-11	0.044
--1	-10	0.064
--1	-9	0.044
--1	-8	0.023
--1	-7	0.013
--1	-6	0.008
--1	-5	0.006
--1	-4	0.008
--1	-3	0.013
--1	-2	0.023
--1	-1	0.044
--1	0	0.064
--1	1	0.044
--1	2	0.023
--1	3	0.013
--1	4	0.008
--1	5	0.006
--1	6	0.008
--1	7	0.013
--1	8	0.023
--1	9	0.044
--1	10	0.064
--1	11	0.044
--1	12	0.023
--1	13	0.013
--1	14	0.008
-
-0	-15	0.006
-0	-14	0.009
-0	-13	0.014
-0	-12	0.027
-0	-11	0.064
-0	-10	0.117
-0	-9	0.064
-0	-8	0.027
-0	-7	0.014
-0	-6	0.009
-0	-5	0.006
-0	-4	0.009
-0	-3	0.014
-0	-2	0.027
-0	-1	0.064
-0	0	0.117
-0	1	0.064
-0	2	0.027
-0	3	0.014
-0	4	0.009
-0	5	0.006
-0	6	0.009
-0	7	0.014
-0	8	0.027
-0	9	0.064
-0	10	0.117
-0	11	0.064
-0	12	0.027
-0	13	0.014
-0	14	0.009
-
-1	-15	0.006
-1	-14	0.008
-1	-13	0.013
-1	-12	0.023
-1	-11	0.044
-1	-10	0.064
-1	-9	0.044
-1	-8	0.023
-1	-7	0.013
-1	-6	0.008
-1	-5	0.006
-1	-4	0.008
-1	-3	0.013
-1	-2	0.023
-1	-1	0.044
-1	0	0.064
-1	1	0.044
-1	2	0.023
-1	3	0.013
-1	4	0.008
-1	5	0.006
-1	6	0.008
-1	7	0.013
-1	8	0.023
-1	9	0.044
-1	10	0.064
-1	11	0.044
-1	12	0.023
-1	13	0.013
-1	14	0.008
-
-2	-15	0.005
-2	-14	0.007
-2	-13	0.01
-2	-12	0.016
-2	-11	0.023
-2	-10	0.027
-2	-9	0.023
-2	-8	0.016
-2	-7	0.01
-2	-6	0.007
-2	-5	0.005
-2	-4	0.007
-2	-3	0.01
-2	-2	0.016
-2	-1	0.023
-2	0	0.027
-2	1	0.023
-2	2	0.016
-2	3	0.01
-2	4	0.007
-2	5	0.005
-2	6	0.007
-2	7	0.01
-2	8	0.016
-2	9	0.023
-2	10	0.027
-2	11	0.023
-2	12	0.016
-2	13	0.01
-2	14	0.007
-
-3	-15	0.005
-3	-14	0.006
-3	-13	0.008
-3	-12	0.01
-3	-11	0.013
-3	-10	0.014
-3	-9	0.013
-3	-8	0.01
-3	-7	0.008
-3	-6	0.006
-3	-5	0.005
-3	-4	0.006
-3	-3	0.008
-3	-2	0.01
-3	-1	0.013
-3	0	0.014
-3	1	0.013
-3	2	0.01
-3	3	0.008
-3	4	0.006
-3	5	0.005
-3	6	0.006
-3	7	0.008
-3	8	0.01
-3	9	0.013
-3	10	0.014
-3	11	0.013
-3	12	0.01
-3	13	0.008
-3	14	0.006
-
-4	-15	0.004
-4	-14	0.005
-4	-13	0.006
-4	-12	0.007
-4	-11	0.008
-4	-10	0.009
-4	-9	0.008
-4	-8	0.007
-4	-7	0.006
-4	-6	0.005
-4	-5	0.004
-4	-4	0.005
-4	-3	0.006
-4	-2	0.007
-4	-1	0.008
-4	0	0.009
-4	1	0.008
-4	2	0.007
-4	3	0.006
-4	4	0.005
-4	5	0.004
-4	6	0.005
-4	7	0.006
-4	8	0.007
-4	9	0.008
-4	10	0.009
-4	11	0.008
-4	12	0.007
-4	13	0.006
-4	14	0.005
-
-5	-15	0.003
-5	-14	0.004
-5	-13	0.005
-5	-12	0.005
-5	-11	0.006
-5	-10	0.006
-5	-9	0.006
-5	-8	0.005
-5	-7	0.005
-5	-6	0.004
-5	-5	0.003
-5	-4	0.004
-5	-3	0.005
-5	-2	0.005
-5	-1	0.006
-5	0	0.006
-5	1	0.006
-5	2	0.005
-5	3	0.005
-5	4	0.004
-5	5	0.003
-5	6	0.004
-5	7	0.005
-5	8	0.005
-5	9	0.006
-5	10	0.006
-5	11	0.006
-5	12	0.005
-5	13	0.005
-5	14	0.004
-
-6	-15	0.004
-6	-14	0.005
-6	-13	0.006
-6	-12	0.007
-6	-11	0.008
-6	-10	0.009
-6	-9	0.008
-6	-8	0.007
-6	-7	0.006
-6	-6	0.005
-6	-5	0.004
-6	-4	0.005
-6	-3	0.006
-6	-2	0.007
-6	-1	0.008
-6	0	0.009
-6	1	0.008
-6	2	0.007
-6	3	0.006
-6	4	0.005
-6	5	0.004
-6	6	0.005
-6	7	0.006
-6	8	0.007
-6	9	0.008
-6	10	0.009
-6	11	0.008
-6	12	0.007
-6	13	0.006
-6	14	0.005
-
-7	-15	0.005
-7	-14	0.006
-7	-13	0.008
-7	-12	0.01
-7	-11	0.013
-7	-10	0.014
-7	-9	0.013
-7	-8	0.01
-7	-7	0.008
-7	-6	0.006
-7	-5	0.005
-7	-4	0.006
-7	-3	0.008
-7	-2	0.01
-7	-1	0.013
-7	0	0.014
-7	1	0.013
-7	2	0.01
-7	3	0.008
-7	4	0.006
-7	5	0.005
-7	6	0.006
-7	7	0.008
-7	8	0.01
-7	9	0.013
-7	10	0.014
-7	11	0.013
-7	12	0.01
-7	13	0.008
-7	14	0.006
-
-8	-15	0.005
-8	-14	0.007
-8	-13	0.01
-8	-12	0.016
-8	-11	0.023
-8	-10	0.027
-8	-9	0.023
-8	-8	0.016
-8	-7	0.01
-8	-6	0.007
-8	-5	0.005
-8	-4	0.007
-8	-3	0.01
-8	-2	0.016
-8	-1	0.023
-8	0	0.027
-8	1	0.023
-8	2	0.016
-8	3	0.01
-8	4	0.007
-8	5	0.005
-8	6	0.007
-8	7	0.01
-8	8	0.016
-8	9	0.023
-8	10	0.027
-8	11	0.023
-8	12	0.016
-8	13	0.01
-8	14	0.007
-
-9	-15	0.006
-9	-14	0.008
-9	-13	0.013
-9	-12	0.023
-9	-11	0.044
-9	-10	0.064
-9	-9	0.044
-9	-8	0.023
-9	-7	0.013
-9	-6	0.008
-9	-5	0.006
-9	-4	0.008
-9	-3	0.013
-9	-2	0.023
-9	-1	0.044
-9	0	0.064
-9	1	0.044
-9	2	0.023
-9	3	0.013
-9	4	0.008
-9	5	0.006
-9	6	0.008
-9	7	0.013
-9	8	0.023
-9	9	0.044
-9	10	0.064
-9	11	0.044
-9	12	0.023
-9	13	0.013
-9	14	0.008
-
-10	-15	0.006
-10	-14	0.009
-10	-13	0.014
-10	-12	0.027
-10	-11	0.064
-10	-10	0.117
-10	-9	0.064
-10	-8	0.027
-10	-7	0.014
-10	-6	0.009
-10	-5	0.006
-10	-4	0.009
-10	-3	0.014
-10	-2	0.027
-10	-1	0.064
-10	0	0.117
-10	1	0.064
-10	2	0.027
-10	3	0.014
-10	4	0.009
-10	5	0.006
-10	6	0.009
-10	7	0.014
-10	8	0.027
-10	9	0.064
-10	10	0.117
-10	11	0.064
-10	12	0.027
-10	13	0.014
-10	14	0.009
-
-11	-15	0.006
-11	-14	0.008
-11	-13	0.013
-11	-12	0.023
-11	-11	0.044
-11	-10	0.064
-11	-9	0.044
-11	-8	0.023
-11	-7	0.013
-11	-6	0.008
-11	-5	0.006
-11	-4	0.008
-11	-3	0.013
-11	-2	0.023
-11	-1	0.044
-11	0	0.064
-11	1	0.044
-11	2	0.023
-11	3	0.013
-11	4	0.008
-11	5	0.006
-11	6	0.008
-11	7	0.013
-11	8	0.023
-11	9	0.044
-11	10	0.064
-11	11	0.044
-11	12	0.023
-11	13	0.013
-11	14	0.008
-
-12	-15	0.005
-12	-14	0.007
-12	-13	0.01
-12	-12	0.016
-12	-11	0.023
-12	-10	0.027
-12	-9	0.023
-12	-8	0.016
-12	-7	0.01
-12	-6	0.007
-12	-5	0.005
-12	-4	0.007
-12	-3	0.01
-12	-2	0.016
-12	-1	0.023
-12	0	0.027
-12	1	0.023
-12	2	0.016
-12	3	0.01
-12	4	0.007
-12	5	0.005
-12	6	0.007
-12	7	0.01
-12	8	0.016
-12	9	0.023
-12	10	0.027
-12	11	0.023
-12	12	0.016
-12	13	0.01
-12	14	0.007
-
-13	-15	0.005
-13	-14	0.006
-13	-13	0.008
-13	-12	0.01
-13	-11	0.013
-13	-10	0.014
-13	-9	0.013
-13	-8	0.01
-13	-7	0.008
-13	-6	0.006
-13	-5	0.005
-13	-4	0.006
-13	-3	0.008
-13	-2	0.01
-13	-1	0.013
-13	0	0.014
-13	1	0.013
-13	2	0.01
-13	3	0.008
-13	4	0.006
-13	5	0.005
-13	6	0.006
-13	7	0.008
-13	8	0.01
-13	9	0.013
-13	10	0.014
-13	11	0.013
-13	12	0.01
-13	13	0.008
-13	14	0.006
-
-14	-15	0.004
-14	-14	0.005
-14	-13	0.006
-14	-12	0.007
-14	-11	0.008
-14	-10	0.009
-14	-9	0.008
-14	-8	0.007
-14	-7	0.006
-14	-6	0.005
-14	-5	0.004
-14	-4	0.005
-14	-3	0.006
-14	-2	0.007
-14	-1	0.008
-14	0	0.009
-14	1	0.008
-14	2	0.007
-14	3	0.006
-14	4	0.005
-14	5	0.004
-14	6	0.005
-14	7	0.006
-14	8	0.007
-14	9	0.008
-14	10	0.009
-14	11	0.008
-14	12	0.007
-14	13	0.006
-14	14	0.005
diff --git a/docs/examples/test_multi_d/chan1_chan2.dat b/docs/examples/test_multi_d/chan1_chan2.dat
deleted file mode 100644
index 1b2e51fe76e1..000000000000
--- a/docs/examples/test_multi_d/chan1_chan2.dat
+++ /dev/null
@@ -1,3032 +0,0 @@
-# chan1	chan2	amplitude_5_0
-# "Gate Channel 1 (mV)"	"Gate Channel 2 (mV)"	"Current (nA)"
-# 30	100
--15	-10	3.362
--15	-9.8	3.253
--15	-9.6	3.148
--15	-9.4	3.047
--15	-9.2	2.95
--15	-9	2.858
--15	-8.8	2.771
--15	-8.6	2.689
--15	-8.4	2.613
--15	-8.2	2.544
--15	-8	2.483
--15	-7.8	2.43
--15	-7.6	2.388
--15	-7.4	2.357
--15	-7.2	2.339
--15	-7	2.339
--15	-6.8	2.359
--15	-6.6	2.402
--15	-6.4	2.475
--15	-6.2	2.581
--15	-6	2.721
--15	-5.8	2.889
--15	-5.6	3.062
--15	-5.4	3.188
--15	-5.2	3.192
--15	-5	3.01
--15	-4.8	2.644
--15	-4.6	2.177
--15	-4.4	1.709
--15	-4.2	1.306
--15	-4	0.985
--15	-3.8	0.741
--15	-3.6	0.559
--15	-3.4	0.424
--15	-3.2	0.323
--15	-3	0.247
--15	-2.8	0.19
--15	-2.6	0.146
--15	-2.4	0.112
--15	-2.2	0.086
--15	-2	0.066
--15	-1.8	0.051
--15	-1.6	0.039
--15	-1.4	0.029
--15	-1.2	0.022
--15	-1	0.017
--15	-0.8	0.013
--15	-0.6	0.01
--15	-0.4	0.008
--15	-0.2	0.007
--15	0	0.006
--15	0.2	0.007
--15	0.4	0.008
--15	0.6	0.01
--15	0.8	0.013
--15	1	0.017
--15	1.2	0.022
--15	1.4	0.029
--15	1.6	0.039
--15	1.8	0.051
--15	2	0.066
--15	2.2	0.086
--15	2.4	0.112
--15	2.6	0.146
--15	2.8	0.19
--15	3	0.247
--15	3.2	0.323
--15	3.4	0.424
--15	3.6	0.559
--15	3.8	0.741
--15	4	0.985
--15	4.2	1.306
--15	4.4	1.709
--15	4.6	2.177
--15	4.8	2.644
--15	5	3.01
--15	5.2	3.192
--15	5.4	3.188
--15	5.6	3.062
--15	5.8	2.889
--15	6	2.721
--15	6.2	2.581
--15	6.4	2.475
--15	6.6	2.402
--15	6.8	2.359
--15	7	2.339
--15	7.2	2.339
--15	7.4	2.357
--15	7.6	2.388
--15	7.8	2.43
--15	8	2.483
--15	8.2	2.544
--15	8.4	2.613
--15	8.6	2.689
--15	8.8	2.771
--15	9	2.858
--15	9.2	2.95
--15	9.4	3.047
--15	9.6	3.148
--15	9.8	3.253
-
--14	-10	3.279
--14	-9.8	3.163
--14	-9.6	3.05
--14	-9.4	2.94
--14	-9.2	2.833
--14	-9	2.73
--14	-8.8	2.63
--14	-8.6	2.533
--14	-8.4	2.44
--14	-8.2	2.351
--14	-8	2.265
--14	-7.8	2.184
--14	-7.6	2.108
--14	-7.4	2.036
--14	-7.2	1.97
--14	-7	1.91
--14	-6.8	1.857
--14	-6.6	1.811
--14	-6.4	1.773
--14	-6.2	1.746
--14	-6	1.731
--14	-5.8	1.73
--14	-5.6	1.745
--14	-5.4	1.779
--14	-5.2	1.835
--14	-5	1.912
--14	-4.8	2.005
--14	-4.6	2.097
--14	-4.4	2.152
--14	-4.2	2.122
--14	-4	1.968
--14	-3.8	1.699
--14	-3.6	1.372
--14	-3.4	1.055
--14	-3.2	0.788
--14	-3	0.58
--14	-2.8	0.425
--14	-2.6	0.311
--14	-2.4	0.228
--14	-2.2	0.168
--14	-2	0.124
--14	-1.8	0.091
--14	-1.6	0.067
--14	-1.4	0.049
--14	-1.2	0.036
--14	-1	0.027
--14	-0.8	0.02
--14	-0.6	0.015
--14	-0.4	0.012
--14	-0.2	0.01
--14	0	0.009
--14	0.2	0.01
--14	0.4	0.012
--14	0.6	0.015
--14	0.8	0.02
--14	1	0.027
--14	1.2	0.036
--14	1.4	0.049
--14	1.6	0.067
--14	1.8	0.091
--14	2	0.124
--14	2.2	0.168
--14	2.4	0.228
--14	2.6	0.311
--14	2.8	0.425
--14	3	0.58
--14	3.2	0.788
--14	3.4	1.055
--14	3.6	1.372
--14	3.8	1.699
--14	4	1.968
--14	4.2	2.122
--14	4.4	2.152
--14	4.6	2.097
--14	4.8	2.005
--14	5	1.912
--14	5.2	1.835
--14	5.4	1.779
--14	5.6	1.745
--14	5.8	1.73
--14	6	1.731
--14	6.2	1.746
--14	6.4	1.773
--14	6.6	1.811
--14	6.8	1.857
--14	7	1.91
--14	7.2	1.97
--14	7.4	2.036
--14	7.6	2.108
--14	7.8	2.184
--14	8	2.265
--14	8.2	2.351
--14	8.4	2.44
--14	8.6	2.533
--14	8.8	2.63
--14	9	2.73
--14	9.2	2.833
--14	9.4	2.94
--14	9.6	3.05
--14	9.8	3.163
-
--13	-10	3.232
--13	-9.8	3.113
--13	-9.6	2.996
--13	-9.4	2.882
--13	-9.2	2.771
--13	-9	2.663
--13	-8.8	2.557
--13	-8.6	2.454
--13	-8.4	2.355
--13	-8.2	2.258
--13	-8	2.164
--13	-7.8	2.073
--13	-7.6	1.986
--13	-7.4	1.901
--13	-7.2	1.82
--13	-7	1.743
--13	-6.8	1.669
--13	-6.6	1.599
--13	-6.4	1.533
--13	-6.2	1.471
--13	-6	1.414
--13	-5.8	1.361
--13	-5.6	1.315
--13	-5.4	1.275
--13	-5.2	1.242
--13	-5	1.216
--13	-4.8	1.2
--13	-4.6	1.195
--13	-4.4	1.201
--13	-4.2	1.22
--13	-4	1.25
--13	-3.8	1.288
--13	-3.6	1.321
--13	-3.4	1.328
--13	-3.2	1.28
--13	-3	1.158
--13	-2.8	0.973
--13	-2.6	0.763
--13	-2.4	0.569
--13	-2.2	0.41
--13	-2	0.291
--13	-1.8	0.204
--13	-1.6	0.143
--13	-1.4	0.1
--13	-1.2	0.07
--13	-1	0.05
--13	-0.8	0.035
--13	-0.6	0.026
--13	-0.4	0.02
--13	-0.2	0.016
--13	0	0.014
--13	0.2	0.016
--13	0.4	0.02
--13	0.6	0.026
--13	0.8	0.035
--13	1	0.05
--13	1.2	0.07
--13	1.4	0.1
--13	1.6	0.143
--13	1.8	0.204
--13	2	0.291
--13	2.2	0.41
--13	2.4	0.569
--13	2.6	0.763
--13	2.8	0.973
--13	3	1.158
--13	3.2	1.28
--13	3.4	1.328
--13	3.6	1.321
--13	3.8	1.288
--13	4	1.25
--13	4.2	1.22
--13	4.4	1.201
--13	4.6	1.195
--13	4.8	1.2
--13	5	1.216
--13	5.2	1.242
--13	5.4	1.275
--13	5.6	1.315
--13	5.8	1.361
--13	6	1.414
--13	6.2	1.471
--13	6.4	1.533
--13	6.6	1.599
--13	6.8	1.669
--13	7	1.743
--13	7.2	1.82
--13	7.4	1.901
--13	7.6	1.986
--13	7.8	2.073
--13	8	2.164
--13	8.2	2.258
--13	8.4	2.355
--13	8.6	2.454
--13	8.8	2.557
--13	9	2.663
--13	9.2	2.771
--13	9.4	2.882
--13	9.6	2.996
--13	9.8	3.113
-
--12	-10	3.203
--12	-9.8	3.082
--12	-9.6	2.964
--12	-9.4	2.848
--12	-9.2	2.735
--12	-9	2.624
--12	-8.8	2.516
--12	-8.6	2.411
--12	-8.4	2.308
--12	-8.2	2.208
--12	-8	2.111
--12	-7.8	2.016
--12	-7.6	1.924
--12	-7.4	1.835
--12	-7.2	1.748
--12	-7	1.665
--12	-6.8	1.584
--12	-6.6	1.506
--12	-6.4	1.431
--12	-6.2	1.359
--12	-6	1.29
--12	-5.8	1.224
--12	-5.6	1.161
--12	-5.4	1.102
--12	-5.2	1.046
--12	-5	0.993
--12	-4.8	0.945
--12	-4.6	0.901
--12	-4.4	0.861
--12	-4.2	0.825
--12	-4	0.795
--12	-3.8	0.771
--12	-3.6	0.753
--12	-3.4	0.741
--12	-3.2	0.736
--12	-3	0.736
--12	-2.8	0.738
--12	-2.6	0.735
--12	-2.4	0.715
--12	-2.2	0.666
--12	-2	0.58
--12	-1.8	0.468
--12	-1.6	0.351
--12	-1.4	0.25
--12	-1.2	0.172
--12	-1	0.117
--12	-0.8	0.08
--12	-0.6	0.055
--12	-0.4	0.04
--12	-0.2	0.031
--12	0	0.027
--12	0.2	0.031
--12	0.4	0.04
--12	0.6	0.055
--12	0.8	0.08
--12	1	0.117
--12	1.2	0.172
--12	1.4	0.25
--12	1.6	0.351
--12	1.8	0.468
--12	2	0.58
--12	2.2	0.666
--12	2.4	0.715
--12	2.6	0.735
--12	2.8	0.738
--12	3	0.736
--12	3.2	0.736
--12	3.4	0.741
--12	3.6	0.753
--12	3.8	0.771
--12	4	0.795
--12	4.2	0.825
--12	4.4	0.861
--12	4.6	0.901
--12	4.8	0.945
--12	5	0.993
--12	5.2	1.046
--12	5.4	1.102
--12	5.6	1.161
--12	5.8	1.224
--12	6	1.29
--12	6.2	1.359
--12	6.4	1.431
--12	6.6	1.506
--12	6.8	1.584
--12	7	1.665
--12	7.2	1.748
--12	7.4	1.835
--12	7.6	1.924
--12	7.8	2.016
--12	8	2.111
--12	8.2	2.208
--12	8.4	2.308
--12	8.6	2.411
--12	8.8	2.516
--12	9	2.624
--12	9.2	2.735
--12	9.4	2.848
--12	9.6	2.964
--12	9.8	3.082
-
--11	-10	3.185
--11	-9.8	3.063
--11	-9.6	2.943
--11	-9.4	2.827
--11	-9.2	2.712
--11	-9	2.601
--11	-8.8	2.491
--11	-8.6	2.385
--11	-8.4	2.281
--11	-8.2	2.179
--11	-8	2.08
--11	-7.8	1.984
--11	-7.6	1.89
--11	-7.4	1.799
--11	-7.2	1.71
--11	-7	1.624
--11	-6.8	1.54
--11	-6.6	1.459
--11	-6.4	1.381
--11	-6.2	1.305
--11	-6	1.232
--11	-5.8	1.161
--11	-5.6	1.094
--11	-5.4	1.029
--11	-5.2	0.966
--11	-5	0.906
--11	-4.8	0.849
--11	-4.6	0.795
--11	-4.4	0.744
--11	-4.2	0.695
--11	-4	0.65
--11	-3.8	0.607
--11	-3.6	0.567
--11	-3.4	0.531
--11	-3.2	0.498
--11	-3	0.468
--11	-2.8	0.442
--11	-2.6	0.419
--11	-2.4	0.399
--11	-2.2	0.382
--11	-2	0.368
--11	-1.8	0.354
--11	-1.6	0.337
--11	-1.4	0.313
--11	-1.2	0.279
--11	-1	0.233
--11	-0.8	0.182
--11	-0.6	0.135
--11	-0.4	0.099
--11	-0.2	0.075
--11	0	0.064
--11	0.2	0.075
--11	0.4	0.099
--11	0.6	0.135
--11	0.8	0.182
--11	1	0.233
--11	1.2	0.279
--11	1.4	0.313
--11	1.6	0.337
--11	1.8	0.354
--11	2	0.368
--11	2.2	0.382
--11	2.4	0.399
--11	2.6	0.419
--11	2.8	0.442
--11	3	0.468
--11	3.2	0.498
--11	3.4	0.531
--11	3.6	0.567
--11	3.8	0.607
--11	4	0.65
--11	4.2	0.695
--11	4.4	0.744
--11	4.6	0.795
--11	4.8	0.849
--11	5	0.906
--11	5.2	0.966
--11	5.4	1.029
--11	5.6	1.094
--11	5.8	1.161
--11	6	1.232
--11	6.2	1.305
--11	6.4	1.381
--11	6.6	1.459
--11	6.8	1.54
--11	7	1.624
--11	7.2	1.71
--11	7.4	1.799
--11	7.6	1.89
--11	7.8	1.984
--11	8	2.08
--11	8.2	2.179
--11	8.4	2.281
--11	8.6	2.385
--11	8.8	2.491
--11	9	2.601
--11	9.2	2.712
--11	9.4	2.827
--11	9.6	2.943
--11	9.8	3.063
-
--10	-10	3.173
--10	-9.8	3.05
--10	-9.6	2.93
--10	-9.4	2.813
--10	-9.2	2.698
--10	-9	2.586
--10	-8.8	2.476
--10	-8.6	2.368
--10	-8.4	2.264
--10	-8.2	2.161
--10	-8	2.062
--10	-7.8	1.964
--10	-7.6	1.869
--10	-7.4	1.777
--10	-7.2	1.687
--10	-7	1.6
--10	-6.8	1.515
--10	-6.6	1.433
--10	-6.4	1.353
--10	-6.2	1.276
--10	-6	1.202
--10	-5.8	1.129
--10	-5.6	1.06
--10	-5.4	0.993
--10	-5.2	0.928
--10	-5	0.866
--10	-4.8	0.806
--10	-4.6	0.749
--10	-4.4	0.694
--10	-4.2	0.642
--10	-4	0.593
--10	-3.8	0.546
--10	-3.6	0.501
--10	-3.4	0.459
--10	-3.2	0.419
--10	-3	0.382
--10	-2.8	0.348
--10	-2.6	0.316
--10	-2.4	0.286
--10	-2.2	0.259
--10	-2	0.234
--10	-1.8	0.212
--10	-1.6	0.192
--10	-1.4	0.175
--10	-1.2	0.16
--10	-1	0.147
--10	-0.8	0.137
--10	-0.6	0.129
--10	-0.4	0.123
--10	-0.2	0.119
--10	0	0.117
--10	0.2	0.119
--10	0.4	0.123
--10	0.6	0.129
--10	0.8	0.137
--10	1	0.147
--10	1.2	0.16
--10	1.4	0.175
--10	1.6	0.192
--10	1.8	0.212
--10	2	0.234
--10	2.2	0.259
--10	2.4	0.286
--10	2.6	0.316
--10	2.8	0.348
--10	3	0.382
--10	3.2	0.419
--10	3.4	0.459
--10	3.6	0.501
--10	3.8	0.546
--10	4	0.593
--10	4.2	0.642
--10	4.4	0.694
--10	4.6	0.749
--10	4.8	0.806
--10	5	0.866
--10	5.2	0.928
--10	5.4	0.993
--10	5.6	1.06
--10	5.8	1.129
--10	6	1.202
--10	6.2	1.276
--10	6.4	1.353
--10	6.6	1.433
--10	6.8	1.515
--10	7	1.6
--10	7.2	1.687
--10	7.4	1.777
--10	7.6	1.869
--10	7.8	1.964
--10	8	2.062
--10	8.2	2.161
--10	8.4	2.264
--10	8.6	2.368
--10	8.8	2.476
--10	9	2.586
--10	9.2	2.698
--10	9.4	2.813
--10	9.6	2.93
--10	9.8	3.05
-
--9	-10	3.185
--9	-9.8	3.063
--9	-9.6	2.943
--9	-9.4	2.827
--9	-9.2	2.712
--9	-9	2.601
--9	-8.8	2.491
--9	-8.6	2.385
--9	-8.4	2.281
--9	-8.2	2.179
--9	-8	2.08
--9	-7.8	1.984
--9	-7.6	1.89
--9	-7.4	1.799
--9	-7.2	1.71
--9	-7	1.624
--9	-6.8	1.54
--9	-6.6	1.459
--9	-6.4	1.381
--9	-6.2	1.305
--9	-6	1.232
--9	-5.8	1.161
--9	-5.6	1.094
--9	-5.4	1.029
--9	-5.2	0.966
--9	-5	0.906
--9	-4.8	0.849
--9	-4.6	0.795
--9	-4.4	0.744
--9	-4.2	0.695
--9	-4	0.65
--9	-3.8	0.607
--9	-3.6	0.567
--9	-3.4	0.531
--9	-3.2	0.498
--9	-3	0.468
--9	-2.8	0.442
--9	-2.6	0.419
--9	-2.4	0.399
--9	-2.2	0.382
--9	-2	0.368
--9	-1.8	0.354
--9	-1.6	0.337
--9	-1.4	0.313
--9	-1.2	0.279
--9	-1	0.233
--9	-0.8	0.182
--9	-0.6	0.135
--9	-0.4	0.099
--9	-0.2	0.075
--9	0	0.064
--9	0.2	0.075
--9	0.4	0.099
--9	0.6	0.135
--9	0.8	0.182
--9	1	0.233
--9	1.2	0.279
--9	1.4	0.313
--9	1.6	0.337
--9	1.8	0.354
--9	2	0.368
--9	2.2	0.382
--9	2.4	0.399
--9	2.6	0.419
--9	2.8	0.442
--9	3	0.468
--9	3.2	0.498
--9	3.4	0.531
--9	3.6	0.567
--9	3.8	0.607
--9	4	0.65
--9	4.2	0.695
--9	4.4	0.744
--9	4.6	0.795
--9	4.8	0.849
--9	5	0.906
--9	5.2	0.966
--9	5.4	1.029
--9	5.6	1.094
--9	5.8	1.161
--9	6	1.232
--9	6.2	1.305
--9	6.4	1.381
--9	6.6	1.459
--9	6.8	1.54
--9	7	1.624
--9	7.2	1.71
--9	7.4	1.799
--9	7.6	1.89
--9	7.8	1.984
--9	8	2.08
--9	8.2	2.179
--9	8.4	2.281
--9	8.6	2.385
--9	8.8	2.491
--9	9	2.601
--9	9.2	2.712
--9	9.4	2.827
--9	9.6	2.943
--9	9.8	3.063
-
--8	-10	3.203
--8	-9.8	3.082
--8	-9.6	2.964
--8	-9.4	2.848
--8	-9.2	2.735
--8	-9	2.624
--8	-8.8	2.516
--8	-8.6	2.411
--8	-8.4	2.308
--8	-8.2	2.208
--8	-8	2.111
--8	-7.8	2.016
--8	-7.6	1.924
--8	-7.4	1.835
--8	-7.2	1.748
--8	-7	1.665
--8	-6.8	1.584
--8	-6.6	1.506
--8	-6.4	1.431
--8	-6.2	1.359
--8	-6	1.29
--8	-5.8	1.224
--8	-5.6	1.161
--8	-5.4	1.102
--8	-5.2	1.046
--8	-5	0.993
--8	-4.8	0.945
--8	-4.6	0.901
--8	-4.4	0.861
--8	-4.2	0.825
--8	-4	0.795
--8	-3.8	0.771
--8	-3.6	0.753
--8	-3.4	0.741
--8	-3.2	0.736
--8	-3	0.736
--8	-2.8	0.738
--8	-2.6	0.735
--8	-2.4	0.715
--8	-2.2	0.666
--8	-2	0.58
--8	-1.8	0.468
--8	-1.6	0.351
--8	-1.4	0.25
--8	-1.2	0.172
--8	-1	0.117
--8	-0.8	0.08
--8	-0.6	0.055
--8	-0.4	0.04
--8	-0.2	0.031
--8	0	0.027
--8	0.2	0.031
--8	0.4	0.04
--8	0.6	0.055
--8	0.8	0.08
--8	1	0.117
--8	1.2	0.172
--8	1.4	0.25
--8	1.6	0.351
--8	1.8	0.468
--8	2	0.58
--8	2.2	0.666
--8	2.4	0.715
--8	2.6	0.735
--8	2.8	0.738
--8	3	0.736
--8	3.2	0.736
--8	3.4	0.741
--8	3.6	0.753
--8	3.8	0.771
--8	4	0.795
--8	4.2	0.825
--8	4.4	0.861
--8	4.6	0.901
--8	4.8	0.945
--8	5	0.993
--8	5.2	1.046
--8	5.4	1.102
--8	5.6	1.161
--8	5.8	1.224
--8	6	1.29
--8	6.2	1.359
--8	6.4	1.431
--8	6.6	1.506
--8	6.8	1.584
--8	7	1.665
--8	7.2	1.748
--8	7.4	1.835
--8	7.6	1.924
--8	7.8	2.016
--8	8	2.111
--8	8.2	2.208
--8	8.4	2.308
--8	8.6	2.411
--8	8.8	2.516
--8	9	2.624
--8	9.2	2.735
--8	9.4	2.848
--8	9.6	2.964
--8	9.8	3.082
-
--7	-10	3.232
--7	-9.8	3.113
--7	-9.6	2.996
--7	-9.4	2.882
--7	-9.2	2.771
--7	-9	2.663
--7	-8.8	2.557
--7	-8.6	2.454
--7	-8.4	2.355
--7	-8.2	2.258
--7	-8	2.164
--7	-7.8	2.073
--7	-7.6	1.986
--7	-7.4	1.901
--7	-7.2	1.82
--7	-7	1.743
--7	-6.8	1.669
--7	-6.6	1.599
--7	-6.4	1.533
--7	-6.2	1.471
--7	-6	1.414
--7	-5.8	1.361
--7	-5.6	1.315
--7	-5.4	1.275
--7	-5.2	1.242
--7	-5	1.216
--7	-4.8	1.2
--7	-4.6	1.195
--7	-4.4	1.201
--7	-4.2	1.22
--7	-4	1.25
--7	-3.8	1.288
--7	-3.6	1.321
--7	-3.4	1.328
--7	-3.2	1.28
--7	-3	1.158
--7	-2.8	0.973
--7	-2.6	0.763
--7	-2.4	0.569
--7	-2.2	0.41
--7	-2	0.291
--7	-1.8	0.204
--7	-1.6	0.143
--7	-1.4	0.1
--7	-1.2	0.07
--7	-1	0.05
--7	-0.8	0.035
--7	-0.6	0.026
--7	-0.4	0.02
--7	-0.2	0.016
--7	0	0.014
--7	0.2	0.016
--7	0.4	0.02
--7	0.6	0.026
--7	0.8	0.035
--7	1	0.05
--7	1.2	0.07
--7	1.4	0.1
--7	1.6	0.143
--7	1.8	0.204
--7	2	0.291
--7	2.2	0.41
--7	2.4	0.569
--7	2.6	0.763
--7	2.8	0.973
--7	3	1.158
--7	3.2	1.28
--7	3.4	1.328
--7	3.6	1.321
--7	3.8	1.288
--7	4	1.25
--7	4.2	1.22
--7	4.4	1.201
--7	4.6	1.195
--7	4.8	1.2
--7	5	1.216
--7	5.2	1.242
--7	5.4	1.275
--7	5.6	1.315
--7	5.8	1.361
--7	6	1.414
--7	6.2	1.471
--7	6.4	1.533
--7	6.6	1.599
--7	6.8	1.669
--7	7	1.743
--7	7.2	1.82
--7	7.4	1.901
--7	7.6	1.986
--7	7.8	2.073
--7	8	2.164
--7	8.2	2.258
--7	8.4	2.355
--7	8.6	2.454
--7	8.8	2.557
--7	9	2.663
--7	9.2	2.771
--7	9.4	2.882
--7	9.6	2.996
--7	9.8	3.113
-
--6	-10	3.279
--6	-9.8	3.163
--6	-9.6	3.05
--6	-9.4	2.94
--6	-9.2	2.833
--6	-9	2.73
--6	-8.8	2.63
--6	-8.6	2.533
--6	-8.4	2.44
--6	-8.2	2.351
--6	-8	2.265
--6	-7.8	2.184
--6	-7.6	2.108
--6	-7.4	2.036
--6	-7.2	1.97
--6	-7	1.91
--6	-6.8	1.857
--6	-6.6	1.811
--6	-6.4	1.773
--6	-6.2	1.746
--6	-6	1.731
--6	-5.8	1.73
--6	-5.6	1.745
--6	-5.4	1.779
--6	-5.2	1.835
--6	-5	1.912
--6	-4.8	2.005
--6	-4.6	2.097
--6	-4.4	2.152
--6	-4.2	2.122
--6	-4	1.968
--6	-3.8	1.699
--6	-3.6	1.372
--6	-3.4	1.055
--6	-3.2	0.788
--6	-3	0.58
--6	-2.8	0.425
--6	-2.6	0.311
--6	-2.4	0.228
--6	-2.2	0.168
--6	-2	0.124
--6	-1.8	0.091
--6	-1.6	0.067
--6	-1.4	0.049
--6	-1.2	0.036
--6	-1	0.027
--6	-0.8	0.02
--6	-0.6	0.015
--6	-0.4	0.012
--6	-0.2	0.01
--6	0	0.009
--6	0.2	0.01
--6	0.4	0.012
--6	0.6	0.015
--6	0.8	0.02
--6	1	0.027
--6	1.2	0.036
--6	1.4	0.049
--6	1.6	0.067
--6	1.8	0.091
--6	2	0.124
--6	2.2	0.168
--6	2.4	0.228
--6	2.6	0.311
--6	2.8	0.425
--6	3	0.58
--6	3.2	0.788
--6	3.4	1.055
--6	3.6	1.372
--6	3.8	1.699
--6	4	1.968
--6	4.2	2.122
--6	4.4	2.152
--6	4.6	2.097
--6	4.8	2.005
--6	5	1.912
--6	5.2	1.835
--6	5.4	1.779
--6	5.6	1.745
--6	5.8	1.73
--6	6	1.731
--6	6.2	1.746
--6	6.4	1.773
--6	6.6	1.811
--6	6.8	1.857
--6	7	1.91
--6	7.2	1.97
--6	7.4	2.036
--6	7.6	2.108
--6	7.8	2.184
--6	8	2.265
--6	8.2	2.351
--6	8.4	2.44
--6	8.6	2.533
--6	8.8	2.63
--6	9	2.73
--6	9.2	2.833
--6	9.4	2.94
--6	9.6	3.05
--6	9.8	3.163
-
--5	-10	3.362
--5	-9.8	3.253
--5	-9.6	3.148
--5	-9.4	3.047
--5	-9.2	2.95
--5	-9	2.858
--5	-8.8	2.771
--5	-8.6	2.689
--5	-8.4	2.613
--5	-8.2	2.544
--5	-8	2.483
--5	-7.8	2.43
--5	-7.6	2.388
--5	-7.4	2.357
--5	-7.2	2.339
--5	-7	2.339
--5	-6.8	2.359
--5	-6.6	2.402
--5	-6.4	2.475
--5	-6.2	2.581
--5	-6	2.721
--5	-5.8	2.889
--5	-5.6	3.062
--5	-5.4	3.188
--5	-5.2	3.192
--5	-5	3.01
--5	-4.8	2.644
--5	-4.6	2.177
--5	-4.4	1.709
--5	-4.2	1.306
--5	-4	0.985
--5	-3.8	0.741
--5	-3.6	0.559
--5	-3.4	0.424
--5	-3.2	0.323
--5	-3	0.247
--5	-2.8	0.19
--5	-2.6	0.146
--5	-2.4	0.112
--5	-2.2	0.086
--5	-2	0.066
--5	-1.8	0.051
--5	-1.6	0.039
--5	-1.4	0.029
--5	-1.2	0.022
--5	-1	0.017
--5	-0.8	0.013
--5	-0.6	0.01
--5	-0.4	0.008
--5	-0.2	0.007
--5	0	0.006
--5	0.2	0.007
--5	0.4	0.008
--5	0.6	0.01
--5	0.8	0.013
--5	1	0.017
--5	1.2	0.022
--5	1.4	0.029
--5	1.6	0.039
--5	1.8	0.051
--5	2	0.066
--5	2.2	0.086
--5	2.4	0.112
--5	2.6	0.146
--5	2.8	0.19
--5	3	0.247
--5	3.2	0.323
--5	3.4	0.424
--5	3.6	0.559
--5	3.8	0.741
--5	4	0.985
--5	4.2	1.306
--5	4.4	1.709
--5	4.6	2.177
--5	4.8	2.644
--5	5	3.01
--5	5.2	3.192
--5	5.4	3.188
--5	5.6	3.062
--5	5.8	2.889
--5	6	2.721
--5	6.2	2.581
--5	6.4	2.475
--5	6.6	2.402
--5	6.8	2.359
--5	7	2.339
--5	7.2	2.339
--5	7.4	2.357
--5	7.6	2.388
--5	7.8	2.43
--5	8	2.483
--5	8.2	2.544
--5	8.4	2.613
--5	8.6	2.689
--5	8.8	2.771
--5	9	2.858
--5	9.2	2.95
--5	9.4	3.047
--5	9.6	3.148
--5	9.8	3.253
-
--4	-10	3.279
--4	-9.8	3.163
--4	-9.6	3.05
--4	-9.4	2.94
--4	-9.2	2.833
--4	-9	2.73
--4	-8.8	2.63
--4	-8.6	2.533
--4	-8.4	2.44
--4	-8.2	2.351
--4	-8	2.265
--4	-7.8	2.184
--4	-7.6	2.108
--4	-7.4	2.036
--4	-7.2	1.97
--4	-7	1.91
--4	-6.8	1.857
--4	-6.6	1.811
--4	-6.4	1.773
--4	-6.2	1.746
--4	-6	1.731
--4	-5.8	1.73
--4	-5.6	1.745
--4	-5.4	1.779
--4	-5.2	1.835
--4	-5	1.912
--4	-4.8	2.005
--4	-4.6	2.097
--4	-4.4	2.152
--4	-4.2	2.122
--4	-4	1.968
--4	-3.8	1.699
--4	-3.6	1.372
--4	-3.4	1.055
--4	-3.2	0.788
--4	-3	0.58
--4	-2.8	0.425
--4	-2.6	0.311
--4	-2.4	0.228
--4	-2.2	0.168
--4	-2	0.124
--4	-1.8	0.091
--4	-1.6	0.067
--4	-1.4	0.049
--4	-1.2	0.036
--4	-1	0.027
--4	-0.8	0.02
--4	-0.6	0.015
--4	-0.4	0.012
--4	-0.2	0.01
--4	0	0.009
--4	0.2	0.01
--4	0.4	0.012
--4	0.6	0.015
--4	0.8	0.02
--4	1	0.027
--4	1.2	0.036
--4	1.4	0.049
--4	1.6	0.067
--4	1.8	0.091
--4	2	0.124
--4	2.2	0.168
--4	2.4	0.228
--4	2.6	0.311
--4	2.8	0.425
--4	3	0.58
--4	3.2	0.788
--4	3.4	1.055
--4	3.6	1.372
--4	3.8	1.699
--4	4	1.968
--4	4.2	2.122
--4	4.4	2.152
--4	4.6	2.097
--4	4.8	2.005
--4	5	1.912
--4	5.2	1.835
--4	5.4	1.779
--4	5.6	1.745
--4	5.8	1.73
--4	6	1.731
--4	6.2	1.746
--4	6.4	1.773
--4	6.6	1.811
--4	6.8	1.857
--4	7	1.91
--4	7.2	1.97
--4	7.4	2.036
--4	7.6	2.108
--4	7.8	2.184
--4	8	2.265
--4	8.2	2.351
--4	8.4	2.44
--4	8.6	2.533
--4	8.8	2.63
--4	9	2.73
--4	9.2	2.833
--4	9.4	2.94
--4	9.6	3.05
--4	9.8	3.163
-
--3	-10	3.232
--3	-9.8	3.113
--3	-9.6	2.996
--3	-9.4	2.882
--3	-9.2	2.771
--3	-9	2.663
--3	-8.8	2.557
--3	-8.6	2.454
--3	-8.4	2.355
--3	-8.2	2.258
--3	-8	2.164
--3	-7.8	2.073
--3	-7.6	1.986
--3	-7.4	1.901
--3	-7.2	1.82
--3	-7	1.743
--3	-6.8	1.669
--3	-6.6	1.599
--3	-6.4	1.533
--3	-6.2	1.471
--3	-6	1.414
--3	-5.8	1.361
--3	-5.6	1.315
--3	-5.4	1.275
--3	-5.2	1.242
--3	-5	1.216
--3	-4.8	1.2
--3	-4.6	1.195
--3	-4.4	1.201
--3	-4.2	1.22
--3	-4	1.25
--3	-3.8	1.288
--3	-3.6	1.321
--3	-3.4	1.328
--3	-3.2	1.28
--3	-3	1.158
--3	-2.8	0.973
--3	-2.6	0.763
--3	-2.4	0.569
--3	-2.2	0.41
--3	-2	0.291
--3	-1.8	0.204
--3	-1.6	0.143
--3	-1.4	0.1
--3	-1.2	0.07
--3	-1	0.05
--3	-0.8	0.035
--3	-0.6	0.026
--3	-0.4	0.02
--3	-0.2	0.016
--3	0	0.014
--3	0.2	0.016
--3	0.4	0.02
--3	0.6	0.026
--3	0.8	0.035
--3	1	0.05
--3	1.2	0.07
--3	1.4	0.1
--3	1.6	0.143
--3	1.8	0.204
--3	2	0.291
--3	2.2	0.41
--3	2.4	0.569
--3	2.6	0.763
--3	2.8	0.973
--3	3	1.158
--3	3.2	1.28
--3	3.4	1.328
--3	3.6	1.321
--3	3.8	1.288
--3	4	1.25
--3	4.2	1.22
--3	4.4	1.201
--3	4.6	1.195
--3	4.8	1.2
--3	5	1.216
--3	5.2	1.242
--3	5.4	1.275
--3	5.6	1.315
--3	5.8	1.361
--3	6	1.414
--3	6.2	1.471
--3	6.4	1.533
--3	6.6	1.599
--3	6.8	1.669
--3	7	1.743
--3	7.2	1.82
--3	7.4	1.901
--3	7.6	1.986
--3	7.8	2.073
--3	8	2.164
--3	8.2	2.258
--3	8.4	2.355
--3	8.6	2.454
--3	8.8	2.557
--3	9	2.663
--3	9.2	2.771
--3	9.4	2.882
--3	9.6	2.996
--3	9.8	3.113
-
--2	-10	3.203
--2	-9.8	3.082
--2	-9.6	2.964
--2	-9.4	2.848
--2	-9.2	2.735
--2	-9	2.624
--2	-8.8	2.516
--2	-8.6	2.411
--2	-8.4	2.308
--2	-8.2	2.208
--2	-8	2.111
--2	-7.8	2.016
--2	-7.6	1.924
--2	-7.4	1.835
--2	-7.2	1.748
--2	-7	1.665
--2	-6.8	1.584
--2	-6.6	1.506
--2	-6.4	1.431
--2	-6.2	1.359
--2	-6	1.29
--2	-5.8	1.224
--2	-5.6	1.161
--2	-5.4	1.102
--2	-5.2	1.046
--2	-5	0.993
--2	-4.8	0.945
--2	-4.6	0.901
--2	-4.4	0.861
--2	-4.2	0.825
--2	-4	0.795
--2	-3.8	0.771
--2	-3.6	0.753
--2	-3.4	0.741
--2	-3.2	0.736
--2	-3	0.736
--2	-2.8	0.738
--2	-2.6	0.735
--2	-2.4	0.715
--2	-2.2	0.666
--2	-2	0.58
--2	-1.8	0.468
--2	-1.6	0.351
--2	-1.4	0.25
--2	-1.2	0.172
--2	-1	0.117
--2	-0.8	0.08
--2	-0.6	0.055
--2	-0.4	0.04
--2	-0.2	0.031
--2	0	0.027
--2	0.2	0.031
--2	0.4	0.04
--2	0.6	0.055
--2	0.8	0.08
--2	1	0.117
--2	1.2	0.172
--2	1.4	0.25
--2	1.6	0.351
--2	1.8	0.468
--2	2	0.58
--2	2.2	0.666
--2	2.4	0.715
--2	2.6	0.735
--2	2.8	0.738
--2	3	0.736
--2	3.2	0.736
--2	3.4	0.741
--2	3.6	0.753
--2	3.8	0.771
--2	4	0.795
--2	4.2	0.825
--2	4.4	0.861
--2	4.6	0.901
--2	4.8	0.945
--2	5	0.993
--2	5.2	1.046
--2	5.4	1.102
--2	5.6	1.161
--2	5.8	1.224
--2	6	1.29
--2	6.2	1.359
--2	6.4	1.431
--2	6.6	1.506
--2	6.8	1.584
--2	7	1.665
--2	7.2	1.748
--2	7.4	1.835
--2	7.6	1.924
--2	7.8	2.016
--2	8	2.111
--2	8.2	2.208
--2	8.4	2.308
--2	8.6	2.411
--2	8.8	2.516
--2	9	2.624
--2	9.2	2.735
--2	9.4	2.848
--2	9.6	2.964
--2	9.8	3.082
-
--1	-10	3.185
--1	-9.8	3.063
--1	-9.6	2.943
--1	-9.4	2.827
--1	-9.2	2.712
--1	-9	2.601
--1	-8.8	2.491
--1	-8.6	2.385
--1	-8.4	2.281
--1	-8.2	2.179
--1	-8	2.08
--1	-7.8	1.984
--1	-7.6	1.89
--1	-7.4	1.799
--1	-7.2	1.71
--1	-7	1.624
--1	-6.8	1.54
--1	-6.6	1.459
--1	-6.4	1.381
--1	-6.2	1.305
--1	-6	1.232
--1	-5.8	1.161
--1	-5.6	1.094
--1	-5.4	1.029
--1	-5.2	0.966
--1	-5	0.906
--1	-4.8	0.849
--1	-4.6	0.795
--1	-4.4	0.744
--1	-4.2	0.695
--1	-4	0.65
--1	-3.8	0.607
--1	-3.6	0.567
--1	-3.4	0.531
--1	-3.2	0.498
--1	-3	0.468
--1	-2.8	0.442
--1	-2.6	0.419
--1	-2.4	0.399
--1	-2.2	0.382
--1	-2	0.368
--1	-1.8	0.354
--1	-1.6	0.337
--1	-1.4	0.313
--1	-1.2	0.279
--1	-1	0.233
--1	-0.8	0.182
--1	-0.6	0.135
--1	-0.4	0.099
--1	-0.2	0.075
--1	0	0.064
--1	0.2	0.075
--1	0.4	0.099
--1	0.6	0.135
--1	0.8	0.182
--1	1	0.233
--1	1.2	0.279
--1	1.4	0.313
--1	1.6	0.337
--1	1.8	0.354
--1	2	0.368
--1	2.2	0.382
--1	2.4	0.399
--1	2.6	0.419
--1	2.8	0.442
--1	3	0.468
--1	3.2	0.498
--1	3.4	0.531
--1	3.6	0.567
--1	3.8	0.607
--1	4	0.65
--1	4.2	0.695
--1	4.4	0.744
--1	4.6	0.795
--1	4.8	0.849
--1	5	0.906
--1	5.2	0.966
--1	5.4	1.029
--1	5.6	1.094
--1	5.8	1.161
--1	6	1.232
--1	6.2	1.305
--1	6.4	1.381
--1	6.6	1.459
--1	6.8	1.54
--1	7	1.624
--1	7.2	1.71
--1	7.4	1.799
--1	7.6	1.89
--1	7.8	1.984
--1	8	2.08
--1	8.2	2.179
--1	8.4	2.281
--1	8.6	2.385
--1	8.8	2.491
--1	9	2.601
--1	9.2	2.712
--1	9.4	2.827
--1	9.6	2.943
--1	9.8	3.063
-
-0	-10	3.173
-0	-9.8	3.05
-0	-9.6	2.93
-0	-9.4	2.813
-0	-9.2	2.698
-0	-9	2.586
-0	-8.8	2.476
-0	-8.6	2.368
-0	-8.4	2.264
-0	-8.2	2.161
-0	-8	2.062
-0	-7.8	1.964
-0	-7.6	1.869
-0	-7.4	1.777
-0	-7.2	1.687
-0	-7	1.6
-0	-6.8	1.515
-0	-6.6	1.433
-0	-6.4	1.353
-0	-6.2	1.276
-0	-6	1.202
-0	-5.8	1.129
-0	-5.6	1.06
-0	-5.4	0.993
-0	-5.2	0.928
-0	-5	0.866
-0	-4.8	0.806
-0	-4.6	0.749
-0	-4.4	0.694
-0	-4.2	0.642
-0	-4	0.593
-0	-3.8	0.546
-0	-3.6	0.501
-0	-3.4	0.459
-0	-3.2	0.419
-0	-3	0.382
-0	-2.8	0.348
-0	-2.6	0.316
-0	-2.4	0.286
-0	-2.2	0.259
-0	-2	0.234
-0	-1.8	0.212
-0	-1.6	0.192
-0	-1.4	0.175
-0	-1.2	0.16
-0	-1	0.147
-0	-0.8	0.137
-0	-0.6	0.129
-0	-0.4	0.123
-0	-0.2	0.119
-0	0	0.117
-0	0.2	0.119
-0	0.4	0.123
-0	0.6	0.129
-0	0.8	0.137
-0	1	0.147
-0	1.2	0.16
-0	1.4	0.175
-0	1.6	0.192
-0	1.8	0.212
-0	2	0.234
-0	2.2	0.259
-0	2.4	0.286
-0	2.6	0.316
-0	2.8	0.348
-0	3	0.382
-0	3.2	0.419
-0	3.4	0.459
-0	3.6	0.501
-0	3.8	0.546
-0	4	0.593
-0	4.2	0.642
-0	4.4	0.694
-0	4.6	0.749
-0	4.8	0.806
-0	5	0.866
-0	5.2	0.928
-0	5.4	0.993
-0	5.6	1.06
-0	5.8	1.129
-0	6	1.202
-0	6.2	1.276
-0	6.4	1.353
-0	6.6	1.433
-0	6.8	1.515
-0	7	1.6
-0	7.2	1.687
-0	7.4	1.777
-0	7.6	1.869
-0	7.8	1.964
-0	8	2.062
-0	8.2	2.161
-0	8.4	2.264
-0	8.6	2.368
-0	8.8	2.476
-0	9	2.586
-0	9.2	2.698
-0	9.4	2.813
-0	9.6	2.93
-0	9.8	3.05
-
-1	-10	3.185
-1	-9.8	3.063
-1	-9.6	2.943
-1	-9.4	2.827
-1	-9.2	2.712
-1	-9	2.601
-1	-8.8	2.491
-1	-8.6	2.385
-1	-8.4	2.281
-1	-8.2	2.179
-1	-8	2.08
-1	-7.8	1.984
-1	-7.6	1.89
-1	-7.4	1.799
-1	-7.2	1.71
-1	-7	1.624
-1	-6.8	1.54
-1	-6.6	1.459
-1	-6.4	1.381
-1	-6.2	1.305
-1	-6	1.232
-1	-5.8	1.161
-1	-5.6	1.094
-1	-5.4	1.029
-1	-5.2	0.966
-1	-5	0.906
-1	-4.8	0.849
-1	-4.6	0.795
-1	-4.4	0.744
-1	-4.2	0.695
-1	-4	0.65
-1	-3.8	0.607
-1	-3.6	0.567
-1	-3.4	0.531
-1	-3.2	0.498
-1	-3	0.468
-1	-2.8	0.442
-1	-2.6	0.419
-1	-2.4	0.399
-1	-2.2	0.382
-1	-2	0.368
-1	-1.8	0.354
-1	-1.6	0.337
-1	-1.4	0.313
-1	-1.2	0.279
-1	-1	0.233
-1	-0.8	0.182
-1	-0.6	0.135
-1	-0.4	0.099
-1	-0.2	0.075
-1	0	0.064
-1	0.2	0.075
-1	0.4	0.099
-1	0.6	0.135
-1	0.8	0.182
-1	1	0.233
-1	1.2	0.279
-1	1.4	0.313
-1	1.6	0.337
-1	1.8	0.354
-1	2	0.368
-1	2.2	0.382
-1	2.4	0.399
-1	2.6	0.419
-1	2.8	0.442
-1	3	0.468
-1	3.2	0.498
-1	3.4	0.531
-1	3.6	0.567
-1	3.8	0.607
-1	4	0.65
-1	4.2	0.695
-1	4.4	0.744
-1	4.6	0.795
-1	4.8	0.849
-1	5	0.906
-1	5.2	0.966
-1	5.4	1.029
-1	5.6	1.094
-1	5.8	1.161
-1	6	1.232
-1	6.2	1.305
-1	6.4	1.381
-1	6.6	1.459
-1	6.8	1.54
-1	7	1.624
-1	7.2	1.71
-1	7.4	1.799
-1	7.6	1.89
-1	7.8	1.984
-1	8	2.08
-1	8.2	2.179
-1	8.4	2.281
-1	8.6	2.385
-1	8.8	2.491
-1	9	2.601
-1	9.2	2.712
-1	9.4	2.827
-1	9.6	2.943
-1	9.8	3.063
-
-2	-10	3.203
-2	-9.8	3.082
-2	-9.6	2.964
-2	-9.4	2.848
-2	-9.2	2.735
-2	-9	2.624
-2	-8.8	2.516
-2	-8.6	2.411
-2	-8.4	2.308
-2	-8.2	2.208
-2	-8	2.111
-2	-7.8	2.016
-2	-7.6	1.924
-2	-7.4	1.835
-2	-7.2	1.748
-2	-7	1.665
-2	-6.8	1.584
-2	-6.6	1.506
-2	-6.4	1.431
-2	-6.2	1.359
-2	-6	1.29
-2	-5.8	1.224
-2	-5.6	1.161
-2	-5.4	1.102
-2	-5.2	1.046
-2	-5	0.993
-2	-4.8	0.945
-2	-4.6	0.901
-2	-4.4	0.861
-2	-4.2	0.825
-2	-4	0.795
-2	-3.8	0.771
-2	-3.6	0.753
-2	-3.4	0.741
-2	-3.2	0.736
-2	-3	0.736
-2	-2.8	0.738
-2	-2.6	0.735
-2	-2.4	0.715
-2	-2.2	0.666
-2	-2	0.58
-2	-1.8	0.468
-2	-1.6	0.351
-2	-1.4	0.25
-2	-1.2	0.172
-2	-1	0.117
-2	-0.8	0.08
-2	-0.6	0.055
-2	-0.4	0.04
-2	-0.2	0.031
-2	0	0.027
-2	0.2	0.031
-2	0.4	0.04
-2	0.6	0.055
-2	0.8	0.08
-2	1	0.117
-2	1.2	0.172
-2	1.4	0.25
-2	1.6	0.351
-2	1.8	0.468
-2	2	0.58
-2	2.2	0.666
-2	2.4	0.715
-2	2.6	0.735
-2	2.8	0.738
-2	3	0.736
-2	3.2	0.736
-2	3.4	0.741
-2	3.6	0.753
-2	3.8	0.771
-2	4	0.795
-2	4.2	0.825
-2	4.4	0.861
-2	4.6	0.901
-2	4.8	0.945
-2	5	0.993
-2	5.2	1.046
-2	5.4	1.102
-2	5.6	1.161
-2	5.8	1.224
-2	6	1.29
-2	6.2	1.359
-2	6.4	1.431
-2	6.6	1.506
-2	6.8	1.584
-2	7	1.665
-2	7.2	1.748
-2	7.4	1.835
-2	7.6	1.924
-2	7.8	2.016
-2	8	2.111
-2	8.2	2.208
-2	8.4	2.308
-2	8.6	2.411
-2	8.8	2.516
-2	9	2.624
-2	9.2	2.735
-2	9.4	2.848
-2	9.6	2.964
-2	9.8	3.082
-
-3	-10	3.232
-3	-9.8	3.113
-3	-9.6	2.996
-3	-9.4	2.882
-3	-9.2	2.771
-3	-9	2.663
-3	-8.8	2.557
-3	-8.6	2.454
-3	-8.4	2.355
-3	-8.2	2.258
-3	-8	2.164
-3	-7.8	2.073
-3	-7.6	1.986
-3	-7.4	1.901
-3	-7.2	1.82
-3	-7	1.743
-3	-6.8	1.669
-3	-6.6	1.599
-3	-6.4	1.533
-3	-6.2	1.471
-3	-6	1.414
-3	-5.8	1.361
-3	-5.6	1.315
-3	-5.4	1.275
-3	-5.2	1.242
-3	-5	1.216
-3	-4.8	1.2
-3	-4.6	1.195
-3	-4.4	1.201
-3	-4.2	1.22
-3	-4	1.25
-3	-3.8	1.288
-3	-3.6	1.321
-3	-3.4	1.328
-3	-3.2	1.28
-3	-3	1.158
-3	-2.8	0.973
-3	-2.6	0.763
-3	-2.4	0.569
-3	-2.2	0.41
-3	-2	0.291
-3	-1.8	0.204
-3	-1.6	0.143
-3	-1.4	0.1
-3	-1.2	0.07
-3	-1	0.05
-3	-0.8	0.035
-3	-0.6	0.026
-3	-0.4	0.02
-3	-0.2	0.016
-3	0	0.014
-3	0.2	0.016
-3	0.4	0.02
-3	0.6	0.026
-3	0.8	0.035
-3	1	0.05
-3	1.2	0.07
-3	1.4	0.1
-3	1.6	0.143
-3	1.8	0.204
-3	2	0.291
-3	2.2	0.41
-3	2.4	0.569
-3	2.6	0.763
-3	2.8	0.973
-3	3	1.158
-3	3.2	1.28
-3	3.4	1.328
-3	3.6	1.321
-3	3.8	1.288
-3	4	1.25
-3	4.2	1.22
-3	4.4	1.201
-3	4.6	1.195
-3	4.8	1.2
-3	5	1.216
-3	5.2	1.242
-3	5.4	1.275
-3	5.6	1.315
-3	5.8	1.361
-3	6	1.414
-3	6.2	1.471
-3	6.4	1.533
-3	6.6	1.599
-3	6.8	1.669
-3	7	1.743
-3	7.2	1.82
-3	7.4	1.901
-3	7.6	1.986
-3	7.8	2.073
-3	8	2.164
-3	8.2	2.258
-3	8.4	2.355
-3	8.6	2.454
-3	8.8	2.557
-3	9	2.663
-3	9.2	2.771
-3	9.4	2.882
-3	9.6	2.996
-3	9.8	3.113
-
-4	-10	3.279
-4	-9.8	3.163
-4	-9.6	3.05
-4	-9.4	2.94
-4	-9.2	2.833
-4	-9	2.73
-4	-8.8	2.63
-4	-8.6	2.533
-4	-8.4	2.44
-4	-8.2	2.351
-4	-8	2.265
-4	-7.8	2.184
-4	-7.6	2.108
-4	-7.4	2.036
-4	-7.2	1.97
-4	-7	1.91
-4	-6.8	1.857
-4	-6.6	1.811
-4	-6.4	1.773
-4	-6.2	1.746
-4	-6	1.731
-4	-5.8	1.73
-4	-5.6	1.745
-4	-5.4	1.779
-4	-5.2	1.835
-4	-5	1.912
-4	-4.8	2.005
-4	-4.6	2.097
-4	-4.4	2.152
-4	-4.2	2.122
-4	-4	1.968
-4	-3.8	1.699
-4	-3.6	1.372
-4	-3.4	1.055
-4	-3.2	0.788
-4	-3	0.58
-4	-2.8	0.425
-4	-2.6	0.311
-4	-2.4	0.228
-4	-2.2	0.168
-4	-2	0.124
-4	-1.8	0.091
-4	-1.6	0.067
-4	-1.4	0.049
-4	-1.2	0.036
-4	-1	0.027
-4	-0.8	0.02
-4	-0.6	0.015
-4	-0.4	0.012
-4	-0.2	0.01
-4	0	0.009
-4	0.2	0.01
-4	0.4	0.012
-4	0.6	0.015
-4	0.8	0.02
-4	1	0.027
-4	1.2	0.036
-4	1.4	0.049
-4	1.6	0.067
-4	1.8	0.091
-4	2	0.124
-4	2.2	0.168
-4	2.4	0.228
-4	2.6	0.311
-4	2.8	0.425
-4	3	0.58
-4	3.2	0.788
-4	3.4	1.055
-4	3.6	1.372
-4	3.8	1.699
-4	4	1.968
-4	4.2	2.122
-4	4.4	2.152
-4	4.6	2.097
-4	4.8	2.005
-4	5	1.912
-4	5.2	1.835
-4	5.4	1.779
-4	5.6	1.745
-4	5.8	1.73
-4	6	1.731
-4	6.2	1.746
-4	6.4	1.773
-4	6.6	1.811
-4	6.8	1.857
-4	7	1.91
-4	7.2	1.97
-4	7.4	2.036
-4	7.6	2.108
-4	7.8	2.184
-4	8	2.265
-4	8.2	2.351
-4	8.4	2.44
-4	8.6	2.533
-4	8.8	2.63
-4	9	2.73
-4	9.2	2.833
-4	9.4	2.94
-4	9.6	3.05
-4	9.8	3.163
-
-5	-10	3.362
-5	-9.8	3.253
-5	-9.6	3.148
-5	-9.4	3.047
-5	-9.2	2.95
-5	-9	2.858
-5	-8.8	2.771
-5	-8.6	2.689
-5	-8.4	2.613
-5	-8.2	2.544
-5	-8	2.483
-5	-7.8	2.43
-5	-7.6	2.388
-5	-7.4	2.357
-5	-7.2	2.339
-5	-7	2.339
-5	-6.8	2.359
-5	-6.6	2.402
-5	-6.4	2.475
-5	-6.2	2.581
-5	-6	2.721
-5	-5.8	2.889
-5	-5.6	3.062
-5	-5.4	3.188
-5	-5.2	3.192
-5	-5	3.01
-5	-4.8	2.644
-5	-4.6	2.177
-5	-4.4	1.709
-5	-4.2	1.306
-5	-4	0.985
-5	-3.8	0.741
-5	-3.6	0.559
-5	-3.4	0.424
-5	-3.2	0.323
-5	-3	0.247
-5	-2.8	0.19
-5	-2.6	0.146
-5	-2.4	0.112
-5	-2.2	0.086
-5	-2	0.066
-5	-1.8	0.051
-5	-1.6	0.039
-5	-1.4	0.029
-5	-1.2	0.022
-5	-1	0.017
-5	-0.8	0.013
-5	-0.6	0.01
-5	-0.4	0.008
-5	-0.2	0.007
-5	0	0.006
-5	0.2	0.007
-5	0.4	0.008
-5	0.6	0.01
-5	0.8	0.013
-5	1	0.017
-5	1.2	0.022
-5	1.4	0.029
-5	1.6	0.039
-5	1.8	0.051
-5	2	0.066
-5	2.2	0.086
-5	2.4	0.112
-5	2.6	0.146
-5	2.8	0.19
-5	3	0.247
-5	3.2	0.323
-5	3.4	0.424
-5	3.6	0.559
-5	3.8	0.741
-5	4	0.985
-5	4.2	1.306
-5	4.4	1.709
-5	4.6	2.177
-5	4.8	2.644
-5	5	3.01
-5	5.2	3.192
-5	5.4	3.188
-5	5.6	3.062
-5	5.8	2.889
-5	6	2.721
-5	6.2	2.581
-5	6.4	2.475
-5	6.6	2.402
-5	6.8	2.359
-5	7	2.339
-5	7.2	2.339
-5	7.4	2.357
-5	7.6	2.388
-5	7.8	2.43
-5	8	2.483
-5	8.2	2.544
-5	8.4	2.613
-5	8.6	2.689
-5	8.8	2.771
-5	9	2.858
-5	9.2	2.95
-5	9.4	3.047
-5	9.6	3.148
-5	9.8	3.253
-
-6	-10	3.279
-6	-9.8	3.163
-6	-9.6	3.05
-6	-9.4	2.94
-6	-9.2	2.833
-6	-9	2.73
-6	-8.8	2.63
-6	-8.6	2.533
-6	-8.4	2.44
-6	-8.2	2.351
-6	-8	2.265
-6	-7.8	2.184
-6	-7.6	2.108
-6	-7.4	2.036
-6	-7.2	1.97
-6	-7	1.91
-6	-6.8	1.857
-6	-6.6	1.811
-6	-6.4	1.773
-6	-6.2	1.746
-6	-6	1.731
-6	-5.8	1.73
-6	-5.6	1.745
-6	-5.4	1.779
-6	-5.2	1.835
-6	-5	1.912
-6	-4.8	2.005
-6	-4.6	2.097
-6	-4.4	2.152
-6	-4.2	2.122
-6	-4	1.968
-6	-3.8	1.699
-6	-3.6	1.372
-6	-3.4	1.055
-6	-3.2	0.788
-6	-3	0.58
-6	-2.8	0.425
-6	-2.6	0.311
-6	-2.4	0.228
-6	-2.2	0.168
-6	-2	0.124
-6	-1.8	0.091
-6	-1.6	0.067
-6	-1.4	0.049
-6	-1.2	0.036
-6	-1	0.027
-6	-0.8	0.02
-6	-0.6	0.015
-6	-0.4	0.012
-6	-0.2	0.01
-6	0	0.009
-6	0.2	0.01
-6	0.4	0.012
-6	0.6	0.015
-6	0.8	0.02
-6	1	0.027
-6	1.2	0.036
-6	1.4	0.049
-6	1.6	0.067
-6	1.8	0.091
-6	2	0.124
-6	2.2	0.168
-6	2.4	0.228
-6	2.6	0.311
-6	2.8	0.425
-6	3	0.58
-6	3.2	0.788
-6	3.4	1.055
-6	3.6	1.372
-6	3.8	1.699
-6	4	1.968
-6	4.2	2.122
-6	4.4	2.152
-6	4.6	2.097
-6	4.8	2.005
-6	5	1.912
-6	5.2	1.835
-6	5.4	1.779
-6	5.6	1.745
-6	5.8	1.73
-6	6	1.731
-6	6.2	1.746
-6	6.4	1.773
-6	6.6	1.811
-6	6.8	1.857
-6	7	1.91
-6	7.2	1.97
-6	7.4	2.036
-6	7.6	2.108
-6	7.8	2.184
-6	8	2.265
-6	8.2	2.351
-6	8.4	2.44
-6	8.6	2.533
-6	8.8	2.63
-6	9	2.73
-6	9.2	2.833
-6	9.4	2.94
-6	9.6	3.05
-6	9.8	3.163
-
-7	-10	3.232
-7	-9.8	3.113
-7	-9.6	2.996
-7	-9.4	2.882
-7	-9.2	2.771
-7	-9	2.663
-7	-8.8	2.557
-7	-8.6	2.454
-7	-8.4	2.355
-7	-8.2	2.258
-7	-8	2.164
-7	-7.8	2.073
-7	-7.6	1.986
-7	-7.4	1.901
-7	-7.2	1.82
-7	-7	1.743
-7	-6.8	1.669
-7	-6.6	1.599
-7	-6.4	1.533
-7	-6.2	1.471
-7	-6	1.414
-7	-5.8	1.361
-7	-5.6	1.315
-7	-5.4	1.275
-7	-5.2	1.242
-7	-5	1.216
-7	-4.8	1.2
-7	-4.6	1.195
-7	-4.4	1.201
-7	-4.2	1.22
-7	-4	1.25
-7	-3.8	1.288
-7	-3.6	1.321
-7	-3.4	1.328
-7	-3.2	1.28
-7	-3	1.158
-7	-2.8	0.973
-7	-2.6	0.763
-7	-2.4	0.569
-7	-2.2	0.41
-7	-2	0.291
-7	-1.8	0.204
-7	-1.6	0.143
-7	-1.4	0.1
-7	-1.2	0.07
-7	-1	0.05
-7	-0.8	0.035
-7	-0.6	0.026
-7	-0.4	0.02
-7	-0.2	0.016
-7	0	0.014
-7	0.2	0.016
-7	0.4	0.02
-7	0.6	0.026
-7	0.8	0.035
-7	1	0.05
-7	1.2	0.07
-7	1.4	0.1
-7	1.6	0.143
-7	1.8	0.204
-7	2	0.291
-7	2.2	0.41
-7	2.4	0.569
-7	2.6	0.763
-7	2.8	0.973
-7	3	1.158
-7	3.2	1.28
-7	3.4	1.328
-7	3.6	1.321
-7	3.8	1.288
-7	4	1.25
-7	4.2	1.22
-7	4.4	1.201
-7	4.6	1.195
-7	4.8	1.2
-7	5	1.216
-7	5.2	1.242
-7	5.4	1.275
-7	5.6	1.315
-7	5.8	1.361
-7	6	1.414
-7	6.2	1.471
-7	6.4	1.533
-7	6.6	1.599
-7	6.8	1.669
-7	7	1.743
-7	7.2	1.82
-7	7.4	1.901
-7	7.6	1.986
-7	7.8	2.073
-7	8	2.164
-7	8.2	2.258
-7	8.4	2.355
-7	8.6	2.454
-7	8.8	2.557
-7	9	2.663
-7	9.2	2.771
-7	9.4	2.882
-7	9.6	2.996
-7	9.8	3.113
-
-8	-10	3.203
-8	-9.8	3.082
-8	-9.6	2.964
-8	-9.4	2.848
-8	-9.2	2.735
-8	-9	2.624
-8	-8.8	2.516
-8	-8.6	2.411
-8	-8.4	2.308
-8	-8.2	2.208
-8	-8	2.111
-8	-7.8	2.016
-8	-7.6	1.924
-8	-7.4	1.835
-8	-7.2	1.748
-8	-7	1.665
-8	-6.8	1.584
-8	-6.6	1.506
-8	-6.4	1.431
-8	-6.2	1.359
-8	-6	1.29
-8	-5.8	1.224
-8	-5.6	1.161
-8	-5.4	1.102
-8	-5.2	1.046
-8	-5	0.993
-8	-4.8	0.945
-8	-4.6	0.901
-8	-4.4	0.861
-8	-4.2	0.825
-8	-4	0.795
-8	-3.8	0.771
-8	-3.6	0.753
-8	-3.4	0.741
-8	-3.2	0.736
-8	-3	0.736
-8	-2.8	0.738
-8	-2.6	0.735
-8	-2.4	0.715
-8	-2.2	0.666
-8	-2	0.58
-8	-1.8	0.468
-8	-1.6	0.351
-8	-1.4	0.25
-8	-1.2	0.172
-8	-1	0.117
-8	-0.8	0.08
-8	-0.6	0.055
-8	-0.4	0.04
-8	-0.2	0.031
-8	0	0.027
-8	0.2	0.031
-8	0.4	0.04
-8	0.6	0.055
-8	0.8	0.08
-8	1	0.117
-8	1.2	0.172
-8	1.4	0.25
-8	1.6	0.351
-8	1.8	0.468
-8	2	0.58
-8	2.2	0.666
-8	2.4	0.715
-8	2.6	0.735
-8	2.8	0.738
-8	3	0.736
-8	3.2	0.736
-8	3.4	0.741
-8	3.6	0.753
-8	3.8	0.771
-8	4	0.795
-8	4.2	0.825
-8	4.4	0.861
-8	4.6	0.901
-8	4.8	0.945
-8	5	0.993
-8	5.2	1.046
-8	5.4	1.102
-8	5.6	1.161
-8	5.8	1.224
-8	6	1.29
-8	6.2	1.359
-8	6.4	1.431
-8	6.6	1.506
-8	6.8	1.584
-8	7	1.665
-8	7.2	1.748
-8	7.4	1.835
-8	7.6	1.924
-8	7.8	2.016
-8	8	2.111
-8	8.2	2.208
-8	8.4	2.308
-8	8.6	2.411
-8	8.8	2.516
-8	9	2.624
-8	9.2	2.735
-8	9.4	2.848
-8	9.6	2.964
-8	9.8	3.082
-
-9	-10	3.185
-9	-9.8	3.063
-9	-9.6	2.943
-9	-9.4	2.827
-9	-9.2	2.712
-9	-9	2.601
-9	-8.8	2.491
-9	-8.6	2.385
-9	-8.4	2.281
-9	-8.2	2.179
-9	-8	2.08
-9	-7.8	1.984
-9	-7.6	1.89
-9	-7.4	1.799
-9	-7.2	1.71
-9	-7	1.624
-9	-6.8	1.54
-9	-6.6	1.459
-9	-6.4	1.381
-9	-6.2	1.305
-9	-6	1.232
-9	-5.8	1.161
-9	-5.6	1.094
-9	-5.4	1.029
-9	-5.2	0.966
-9	-5	0.906
-9	-4.8	0.849
-9	-4.6	0.795
-9	-4.4	0.744
-9	-4.2	0.695
-9	-4	0.65
-9	-3.8	0.607
-9	-3.6	0.567
-9	-3.4	0.531
-9	-3.2	0.498
-9	-3	0.468
-9	-2.8	0.442
-9	-2.6	0.419
-9	-2.4	0.399
-9	-2.2	0.382
-9	-2	0.368
-9	-1.8	0.354
-9	-1.6	0.337
-9	-1.4	0.313
-9	-1.2	0.279
-9	-1	0.233
-9	-0.8	0.182
-9	-0.6	0.135
-9	-0.4	0.099
-9	-0.2	0.075
-9	0	0.064
-9	0.2	0.075
-9	0.4	0.099
-9	0.6	0.135
-9	0.8	0.182
-9	1	0.233
-9	1.2	0.279
-9	1.4	0.313
-9	1.6	0.337
-9	1.8	0.354
-9	2	0.368
-9	2.2	0.382
-9	2.4	0.399
-9	2.6	0.419
-9	2.8	0.442
-9	3	0.468
-9	3.2	0.498
-9	3.4	0.531
-9	3.6	0.567
-9	3.8	0.607
-9	4	0.65
-9	4.2	0.695
-9	4.4	0.744
-9	4.6	0.795
-9	4.8	0.849
-9	5	0.906
-9	5.2	0.966
-9	5.4	1.029
-9	5.6	1.094
-9	5.8	1.161
-9	6	1.232
-9	6.2	1.305
-9	6.4	1.381
-9	6.6	1.459
-9	6.8	1.54
-9	7	1.624
-9	7.2	1.71
-9	7.4	1.799
-9	7.6	1.89
-9	7.8	1.984
-9	8	2.08
-9	8.2	2.179
-9	8.4	2.281
-9	8.6	2.385
-9	8.8	2.491
-9	9	2.601
-9	9.2	2.712
-9	9.4	2.827
-9	9.6	2.943
-9	9.8	3.063
-
-10	-10	3.173
-10	-9.8	3.05
-10	-9.6	2.93
-10	-9.4	2.813
-10	-9.2	2.698
-10	-9	2.586
-10	-8.8	2.476
-10	-8.6	2.368
-10	-8.4	2.264
-10	-8.2	2.161
-10	-8	2.062
-10	-7.8	1.964
-10	-7.6	1.869
-10	-7.4	1.777
-10	-7.2	1.687
-10	-7	1.6
-10	-6.8	1.515
-10	-6.6	1.433
-10	-6.4	1.353
-10	-6.2	1.276
-10	-6	1.202
-10	-5.8	1.129
-10	-5.6	1.06
-10	-5.4	0.993
-10	-5.2	0.928
-10	-5	0.866
-10	-4.8	0.806
-10	-4.6	0.749
-10	-4.4	0.694
-10	-4.2	0.642
-10	-4	0.593
-10	-3.8	0.546
-10	-3.6	0.501
-10	-3.4	0.459
-10	-3.2	0.419
-10	-3	0.382
-10	-2.8	0.348
-10	-2.6	0.316
-10	-2.4	0.286
-10	-2.2	0.259
-10	-2	0.234
-10	-1.8	0.212
-10	-1.6	0.192
-10	-1.4	0.175
-10	-1.2	0.16
-10	-1	0.147
-10	-0.8	0.137
-10	-0.6	0.129
-10	-0.4	0.123
-10	-0.2	0.119
-10	0	0.117
-10	0.2	0.119
-10	0.4	0.123
-10	0.6	0.129
-10	0.8	0.137
-10	1	0.147
-10	1.2	0.16
-10	1.4	0.175
-10	1.6	0.192
-10	1.8	0.212
-10	2	0.234
-10	2.2	0.259
-10	2.4	0.286
-10	2.6	0.316
-10	2.8	0.348
-10	3	0.382
-10	3.2	0.419
-10	3.4	0.459
-10	3.6	0.501
-10	3.8	0.546
-10	4	0.593
-10	4.2	0.642
-10	4.4	0.694
-10	4.6	0.749
-10	4.8	0.806
-10	5	0.866
-10	5.2	0.928
-10	5.4	0.993
-10	5.6	1.06
-10	5.8	1.129
-10	6	1.202
-10	6.2	1.276
-10	6.4	1.353
-10	6.6	1.433
-10	6.8	1.515
-10	7	1.6
-10	7.2	1.687
-10	7.4	1.777
-10	7.6	1.869
-10	7.8	1.964
-10	8	2.062
-10	8.2	2.161
-10	8.4	2.264
-10	8.6	2.368
-10	8.8	2.476
-10	9	2.586
-10	9.2	2.698
-10	9.4	2.813
-10	9.6	2.93
-10	9.8	3.05
-
-11	-10	3.185
-11	-9.8	3.063
-11	-9.6	2.943
-11	-9.4	2.827
-11	-9.2	2.712
-11	-9	2.601
-11	-8.8	2.491
-11	-8.6	2.385
-11	-8.4	2.281
-11	-8.2	2.179
-11	-8	2.08
-11	-7.8	1.984
-11	-7.6	1.89
-11	-7.4	1.799
-11	-7.2	1.71
-11	-7	1.624
-11	-6.8	1.54
-11	-6.6	1.459
-11	-6.4	1.381
-11	-6.2	1.305
-11	-6	1.232
-11	-5.8	1.161
-11	-5.6	1.094
-11	-5.4	1.029
-11	-5.2	0.966
-11	-5	0.906
-11	-4.8	0.849
-11	-4.6	0.795
-11	-4.4	0.744
-11	-4.2	0.695
-11	-4	0.65
-11	-3.8	0.607
-11	-3.6	0.567
-11	-3.4	0.531
-11	-3.2	0.498
-11	-3	0.468
-11	-2.8	0.442
-11	-2.6	0.419
-11	-2.4	0.399
-11	-2.2	0.382
-11	-2	0.368
-11	-1.8	0.354
-11	-1.6	0.337
-11	-1.4	0.313
-11	-1.2	0.279
-11	-1	0.233
-11	-0.8	0.182
-11	-0.6	0.135
-11	-0.4	0.099
-11	-0.2	0.075
-11	0	0.064
-11	0.2	0.075
-11	0.4	0.099
-11	0.6	0.135
-11	0.8	0.182
-11	1	0.233
-11	1.2	0.279
-11	1.4	0.313
-11	1.6	0.337
-11	1.8	0.354
-11	2	0.368
-11	2.2	0.382
-11	2.4	0.399
-11	2.6	0.419
-11	2.8	0.442
-11	3	0.468
-11	3.2	0.498
-11	3.4	0.531
-11	3.6	0.567
-11	3.8	0.607
-11	4	0.65
-11	4.2	0.695
-11	4.4	0.744
-11	4.6	0.795
-11	4.8	0.849
-11	5	0.906
-11	5.2	0.966
-11	5.4	1.029
-11	5.6	1.094
-11	5.8	1.161
-11	6	1.232
-11	6.2	1.305
-11	6.4	1.381
-11	6.6	1.459
-11	6.8	1.54
-11	7	1.624
-11	7.2	1.71
-11	7.4	1.799
-11	7.6	1.89
-11	7.8	1.984
-11	8	2.08
-11	8.2	2.179
-11	8.4	2.281
-11	8.6	2.385
-11	8.8	2.491
-11	9	2.601
-11	9.2	2.712
-11	9.4	2.827
-11	9.6	2.943
-11	9.8	3.063
-
-12	-10	3.203
-12	-9.8	3.082
-12	-9.6	2.964
-12	-9.4	2.848
-12	-9.2	2.735
-12	-9	2.624
-12	-8.8	2.516
-12	-8.6	2.411
-12	-8.4	2.308
-12	-8.2	2.208
-12	-8	2.111
-12	-7.8	2.016
-12	-7.6	1.924
-12	-7.4	1.835
-12	-7.2	1.748
-12	-7	1.665
-12	-6.8	1.584
-12	-6.6	1.506
-12	-6.4	1.431
-12	-6.2	1.359
-12	-6	1.29
-12	-5.8	1.224
-12	-5.6	1.161
-12	-5.4	1.102
-12	-5.2	1.046
-12	-5	0.993
-12	-4.8	0.945
-12	-4.6	0.901
-12	-4.4	0.861
-12	-4.2	0.825
-12	-4	0.795
-12	-3.8	0.771
-12	-3.6	0.753
-12	-3.4	0.741
-12	-3.2	0.736
-12	-3	0.736
-12	-2.8	0.738
-12	-2.6	0.735
-12	-2.4	0.715
-12	-2.2	0.666
-12	-2	0.58
-12	-1.8	0.468
-12	-1.6	0.351
-12	-1.4	0.25
-12	-1.2	0.172
-12	-1	0.117
-12	-0.8	0.08
-12	-0.6	0.055
-12	-0.4	0.04
-12	-0.2	0.031
-12	0	0.027
-12	0.2	0.031
-12	0.4	0.04
-12	0.6	0.055
-12	0.8	0.08
-12	1	0.117
-12	1.2	0.172
-12	1.4	0.25
-12	1.6	0.351
-12	1.8	0.468
-12	2	0.58
-12	2.2	0.666
-12	2.4	0.715
-12	2.6	0.735
-12	2.8	0.738
-12	3	0.736
-12	3.2	0.736
-12	3.4	0.741
-12	3.6	0.753
-12	3.8	0.771
-12	4	0.795
-12	4.2	0.825
-12	4.4	0.861
-12	4.6	0.901
-12	4.8	0.945
-12	5	0.993
-12	5.2	1.046
-12	5.4	1.102
-12	5.6	1.161
-12	5.8	1.224
-12	6	1.29
-12	6.2	1.359
-12	6.4	1.431
-12	6.6	1.506
-12	6.8	1.584
-12	7	1.665
-12	7.2	1.748
-12	7.4	1.835
-12	7.6	1.924
-12	7.8	2.016
-12	8	2.111
-12	8.2	2.208
-12	8.4	2.308
-12	8.6	2.411
-12	8.8	2.516
-12	9	2.624
-12	9.2	2.735
-12	9.4	2.848
-12	9.6	2.964
-12	9.8	3.082
-
-13	-10	3.232
-13	-9.8	3.113
-13	-9.6	2.996
-13	-9.4	2.882
-13	-9.2	2.771
-13	-9	2.663
-13	-8.8	2.557
-13	-8.6	2.454
-13	-8.4	2.355
-13	-8.2	2.258
-13	-8	2.164
-13	-7.8	2.073
-13	-7.6	1.986
-13	-7.4	1.901
-13	-7.2	1.82
-13	-7	1.743
-13	-6.8	1.669
-13	-6.6	1.599
-13	-6.4	1.533
-13	-6.2	1.471
-13	-6	1.414
-13	-5.8	1.361
-13	-5.6	1.315
-13	-5.4	1.275
-13	-5.2	1.242
-13	-5	1.216
-13	-4.8	1.2
-13	-4.6	1.195
-13	-4.4	1.201
-13	-4.2	1.22
-13	-4	1.25
-13	-3.8	1.288
-13	-3.6	1.321
-13	-3.4	1.328
-13	-3.2	1.28
-13	-3	1.158
-13	-2.8	0.973
-13	-2.6	0.763
-13	-2.4	0.569
-13	-2.2	0.41
-13	-2	0.291
-13	-1.8	0.204
-13	-1.6	0.143
-13	-1.4	0.1
-13	-1.2	0.07
-13	-1	0.05
-13	-0.8	0.035
-13	-0.6	0.026
-13	-0.4	0.02
-13	-0.2	0.016
-13	0	0.014
-13	0.2	0.016
-13	0.4	0.02
-13	0.6	0.026
-13	0.8	0.035
-13	1	0.05
-13	1.2	0.07
-13	1.4	0.1
-13	1.6	0.143
-13	1.8	0.204
-13	2	0.291
-13	2.2	0.41
-13	2.4	0.569
-13	2.6	0.763
-13	2.8	0.973
-13	3	1.158
-13	3.2	1.28
-13	3.4	1.328
-13	3.6	1.321
-13	3.8	1.288
-13	4	1.25
-13	4.2	1.22
-13	4.4	1.201
-13	4.6	1.195
-13	4.8	1.2
-13	5	1.216
-13	5.2	1.242
-13	5.4	1.275
-13	5.6	1.315
-13	5.8	1.361
-13	6	1.414
-13	6.2	1.471
-13	6.4	1.533
-13	6.6	1.599
-13	6.8	1.669
-13	7	1.743
-13	7.2	1.82
-13	7.4	1.901
-13	7.6	1.986
-13	7.8	2.073
-13	8	2.164
-13	8.2	2.258
-13	8.4	2.355
-13	8.6	2.454
-13	8.8	2.557
-13	9	2.663
-13	9.2	2.771
-13	9.4	2.882
-13	9.6	2.996
-13	9.8	3.113
-
-14	-10	3.279
-14	-9.8	3.163
-14	-9.6	3.05
-14	-9.4	2.94
-14	-9.2	2.833
-14	-9	2.73
-14	-8.8	2.63
-14	-8.6	2.533
-14	-8.4	2.44
-14	-8.2	2.351
-14	-8	2.265
-14	-7.8	2.184
-14	-7.6	2.108
-14	-7.4	2.036
-14	-7.2	1.97
-14	-7	1.91
-14	-6.8	1.857
-14	-6.6	1.811
-14	-6.4	1.773
-14	-6.2	1.746
-14	-6	1.731
-14	-5.8	1.73
-14	-5.6	1.745
-14	-5.4	1.779
-14	-5.2	1.835
-14	-5	1.912
-14	-4.8	2.005
-14	-4.6	2.097
-14	-4.4	2.152
-14	-4.2	2.122
-14	-4	1.968
-14	-3.8	1.699
-14	-3.6	1.372
-14	-3.4	1.055
-14	-3.2	0.788
-14	-3	0.58
-14	-2.8	0.425
-14	-2.6	0.311
-14	-2.4	0.228
-14	-2.2	0.168
-14	-2	0.124
-14	-1.8	0.091
-14	-1.6	0.067
-14	-1.4	0.049
-14	-1.2	0.036
-14	-1	0.027
-14	-0.8	0.02
-14	-0.6	0.015
-14	-0.4	0.012
-14	-0.2	0.01
-14	0	0.009
-14	0.2	0.01
-14	0.4	0.012
-14	0.6	0.015
-14	0.8	0.02
-14	1	0.027
-14	1.2	0.036
-14	1.4	0.049
-14	1.6	0.067
-14	1.8	0.091
-14	2	0.124
-14	2.2	0.168
-14	2.4	0.228
-14	2.6	0.311
-14	2.8	0.425
-14	3	0.58
-14	3.2	0.788
-14	3.4	1.055
-14	3.6	1.372
-14	3.8	1.699
-14	4	1.968
-14	4.2	2.122
-14	4.4	2.152
-14	4.6	2.097
-14	4.8	2.005
-14	5	1.912
-14	5.2	1.835
-14	5.4	1.779
-14	5.6	1.745
-14	5.8	1.73
-14	6	1.731
-14	6.2	1.746
-14	6.4	1.773
-14	6.6	1.811
-14	6.8	1.857
-14	7	1.91
-14	7.2	1.97
-14	7.4	2.036
-14	7.6	2.108
-14	7.8	2.184
-14	8	2.265
-14	8.2	2.351
-14	8.4	2.44
-14	8.6	2.533
-14	8.8	2.63
-14	9	2.73
-14	9.2	2.833
-14	9.4	2.94
-14	9.6	3.05
-14	9.8	3.163
diff --git a/docs/examples/toymodel.py b/docs/examples/toymodel.py
index bccbeaae2dc2..3472f416191b 100644
--- a/docs/examples/toymodel.py
+++ b/docs/examples/toymodel.py
@@ -40,7 +40,7 @@ def gates_set(self, parameter, value):
 
     def gates_get(self, parameter):
         if parameter[0] == 'c':
-            return self.fmt(self.gates[int(parameter[1:])])
+            return self.fmt(self._gates[int(parameter[1:])])
         else:
             raise ValueError
 
@@ -94,8 +94,8 @@ def __init__(self, name, model=None, **kwargs):
                            set_cmd='ampl:{:.4f}',
                            get_parser=float,
                            vals=Numbers(0, 10),
-                           sweep_step=0.1,
-                           sweep_delay=0.05)
+                           step=0.1,
+                           delay=0.05)
 
 
 class MockMeter(MockInstrument):
diff --git a/qcodes/__init__.py b/qcodes/__init__.py
index 71920e94d0f6..886169bc75a5 100644
--- a/qcodes/__init__.py
+++ b/qcodes/__init__.py
@@ -5,6 +5,7 @@
 # separately import multiprocessing
 from multiprocessing import active_children
 
+from qcodes.version import __version__
 from qcodes.utils.multiprocessing import set_mp_method
 from qcodes.utils.helpers import in_notebook
 
@@ -14,23 +15,28 @@
 if in_notebook():  # pragma: no cover
     try:
         from qcodes.plots.matplotlib import MatPlot
-    except ImportError:
-        print('matplotlib plotting not supported')
+    except Exception:
+        print('matplotlib plotting not supported, '
+              'try "from qcodes.plots.matplotlib import MatPlot" '
+              'to see the full error')
 
     try:
         from qcodes.plots.pyqtgraph import QtPlot
-    except ImportError:
-        print('pyqtgraph plotting not supported')
+    except Exception:
+        print('pyqtgraph plotting not supported, '
+              'try "from qcodes.plots.pyqtgraph import QtPlot" '
+              'to see the full error')
 
     from qcodes.widgets.widgets import show_subprocess_widget
 
 from qcodes.station import Station
-from qcodes.loops import get_bg, halt_bg, Loop, Task, Wait
+from qcodes.loops import get_bg, halt_bg, Loop, Task, Wait, BreakIf
 
 from qcodes.data.manager import get_data_manager
 from qcodes.data.data_set import DataMode, DataSet, new_data, load_data
 from qcodes.data.data_array import DataArray
-from qcodes.data.format import Formatter, GNUPlotFormat
+from qcodes.data.format import Formatter
+from qcodes.data.gnuplot_format import GNUPlotFormat
 from qcodes.data.io import DiskIO
 
 from qcodes.instrument.base import Instrument
diff --git a/qcodes/data/data_array.py b/qcodes/data/data_array.py
index 1cbfb32e6255..43993fbf79cb 100644
--- a/qcodes/data/data_array.py
+++ b/qcodes/data/data_array.py
@@ -5,7 +5,7 @@
 
 
 class DataArray(DelegateAttributes):
-    '''
+    """
     A container for one parameter in a measurement loop
 
     If this is a measured parameter, This object doesn't contain
@@ -24,7 +24,7 @@ class DataArray(DelegateAttributes):
 
     Once the array is initialized, a DataArray acts a lot like a numpy array,
     because we delegate attributes through to the numpy array
-    '''
+    """
     def __init__(self, parameter=None, name=None, label=None, array_id=None,
                  set_arrays=(), size=None, action_indices=(),
                  preset_data=None):
@@ -67,7 +67,7 @@ def data_set(self, new_data_set):
         self._data_set = new_data_set
 
     def nest(self, size, action_index=None, set_array=None):
-        '''
+        """
         nest this array inside a new outer loop
 
         size: length of the new loop
@@ -76,7 +76,7 @@ def nest(self, size, action_index=None, set_array=None):
             if this DataArray *is* a setpoint array, you should omit both
             action_index and set_array, and it will reference itself as the
             set_array
-        '''
+        """
         if self.ndarray is not None and not self._preset:
             raise RuntimeError('Only preset arrays can be nested after data '
                                'is initialized! {}'.format(self))
@@ -105,11 +105,11 @@ def nest(self, size, action_index=None, set_array=None):
         return self
 
     def init_data(self, data=None):
-        '''
+        """
         create a data array (if one doesn't exist)
         if data is provided, this array is marked as a preset
         meaning it can still be nested around this data.
-        '''
+        """
         if data is not None:
             if not isinstance(data, np.ndarray):
                 if isinstance(data, collections.Iterator):
@@ -138,13 +138,13 @@ def init_data(self, data=None):
         self._set_index_bounds()
 
     def _set_index_bounds(self):
-        self._min_indices = tuple(0 for d in self.size)
-        self._max_indices = tuple(d - 1 for d in self.size)
+        self._min_indices = [0 for d in self.size]
+        self._max_indices = [d - 1 for d in self.size]
 
     def clear(self):
-        '''
+        """
         Fill the (already existing) data array with nan
-        '''
+        """
         # only floats can hold nan values. I guess we could
         # also raise an error in this case? But generally float is
         # what people want anyway.
@@ -153,22 +153,32 @@ def clear(self):
         self.ndarray.fill(float('nan'))
 
     def __setitem__(self, loop_indices, value):
-        '''
+        """
         set data values. Follows numpy syntax, allowing indices of lower
         dimensionality than the array, if value makes up the extra dimension(s)
 
         Also updates the record of modifications to the array. If you don't
         want this overhead, you can access self.ndarray directly.
-        '''
+        """
         if isinstance(loop_indices, collections.Iterable):
-            loop_indices_tuple = loop_indices
+            min_indices = list(loop_indices)
+            max_indices = list(loop_indices)
         else:
-            loop_indices_tuple = (loop_indices, )
-        min_li = self._flat_index(loop_indices_tuple, self._min_indices)
-        max_li = self._flat_index(loop_indices_tuple, self._max_indices)
+            min_indices = [loop_indices]
+            max_indices = [loop_indices]
+
+        for i, index in enumerate(min_indices):
+            if isinstance(index, slice):
+                start, stop, step = index.indices(self.size[i])
+                min_indices[i] = start
+                max_indices[i] = start + (
+                    ((stop - start - 1)//step) * step)
+
+        min_li = self._flat_index(min_indices, self._min_indices)
+        max_li = self._flat_index(max_indices, self._max_indices)
         self._update_modified_range(min_li, max_li)
 
-        self.ndarray[loop_indices] = value
+        self.ndarray.__setitem__(loop_indices, value)
 
     def __getitem__(self, loop_indices):
         return self.ndarray[loop_indices]
@@ -176,10 +186,10 @@ def __getitem__(self, loop_indices):
     delegate_attr_objects = ['ndarray']
 
     def __len__(self):
-        '''
+        """
         must be explicitly delegated, because len() will look for this
         attribute to already exist
-        '''
+        """
         return len(self.ndarray)
 
     def _flat_index(self, indices, index_fill):
@@ -193,26 +203,62 @@ def _update_modified_range(self, low, high):
         else:
             self.modified_range = (low, high)
 
-    def mark_saved(self):
-        '''
-        after saving data, mark any outstanding modifications as saved
-        '''
+    def mark_saved(self, last_saved_index):
+        """
+        after saving data, mark outstanding modifications up to
+        last_saved_index as saved
+        """
         if self.modified_range:
-            self.last_saved_index = max(self.last_saved_index or 0,
-                                        self.modified_range[1])
-
-        self.modified_range = None
+            if last_saved_index >= self.modified_range[1]:
+                self.modified_range = None
+            else:
+                self.modified_range = (max(self.modified_range[0],
+                                           last_saved_index + 1),
+                                       self.modified_range[1])
+        self.last_saved_index = last_saved_index
 
     def clear_save(self):
-        '''
+        """
         make this array look unsaved, so we can force overwrite
         or rewrite, like if we're moving or copying the DataSet
-        '''
+        """
         if self.last_saved_index is not None:
             self._update_modified_range(0, self.last_saved_index)
 
         self.last_saved_index = None
 
+    def get_synced_index(self):
+        if not hasattr(self, 'synced_index'):
+            self.init_data()
+            self.synced_index = -1
+
+        return self.synced_index
+
+    def get_changes(self, synced_index):
+        latest_index = self.last_saved_index
+        if latest_index is None:
+            latest_index = -1
+        if self.modified_range:
+            latest_index = max(latest_index, self.modified_range[1])
+
+        vals = [
+            self.ndarray[np.unravel_index(i, self.ndarray.shape)]
+            for i in range(synced_index + 1, latest_index + 1)
+        ]
+
+        if vals:
+            return {
+                'start': synced_index + 1,
+                'stop': latest_index,
+                'vals': vals
+            }
+
+    def apply_changes(self, start, stop, vals):
+        for i, val in enumerate(vals):
+            index = np.unravel_index(i + start, self.ndarray.shape)
+            self.ndarray[index] = val
+        self.synced_index = stop
+
     def __repr__(self):
         array_id_or_none = ' {}'.format(self.array_id) if self.array_id else ''
         return '{}[{}]:{}\n{}'.format(self.__class__.__name__,
diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 21f3da8d4498..60f2f4ed3752 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -1,8 +1,9 @@
 from enum import Enum
 from datetime import datetime
+import time
 
-from .manager import get_data_manager
-from .format import GNUPlotFormat
+from .manager import get_data_manager, NoData
+from .gnuplot_format import GNUPlotFormat
 from .io import DiskIO
 from qcodes.utils.helpers import DelegateAttributes
 
@@ -18,7 +19,7 @@ class DataMode(Enum):
 
 def new_data(location=None, name=None, overwrite=False, io=None,
              data_manager=None, mode=DataMode.LOCAL, **kwargs):
-    '''
+    """
     Create a new DataSet. Arguments are the same as DataSet constructor, plus:
 
     overwrite: Are we allowed to overwrite an existing location? default False
@@ -34,17 +35,17 @@ def new_data(location=None, name=None, overwrite=False, io=None,
 
     name: an optional string to be passed to location_provider to augment
         the automatic location with something meaningful
-    '''
+    """
     if io is None:
         io = DataSet.default_io
 
     if location is None:
         location = DataSet.location_provider(io, name)
     elif callable(location):
-        location = location(io)
+        location = location(io, name)
 
     if location and (not overwrite) and io.list(location):
-        raise FileExistsError
+        raise FileExistsError('"' + location + '" already has data')
 
     if data_manager is False:
         if mode != DataMode.LOCAL:
@@ -57,7 +58,7 @@ def new_data(location=None, name=None, overwrite=False, io=None,
 
 
 def load_data(location=None, data_manager=None, formatter=None, io=None):
-    '''
+    """
     Load an existing DataSet. Arguments are a subset of the DataSet
     constructor:
 
@@ -75,7 +76,7 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
 
     formatter: as in DataSet
     io: as in DataSet
-    '''
+    """
     if data_manager is None:
         data_manager = get_data_manager(only_existing=True)
 
@@ -86,18 +87,24 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
 
         return _get_live_data(data_manager)
 
+    elif location is False:
+        raise ValueError('location=False means a temporary DataSet, '
+                         'which is incompatible with load_data')
+
     elif (data_manager and
             location == data_manager.ask('get_data', 'location')):
         return _get_live_data(data_manager)
 
     else:
-        return DataSet(location=location, formatter=formatter, io=io,
+        data = DataSet(location=location, formatter=formatter, io=io,
                        mode=DataMode.LOCAL)
+        data.read()
+        return data
 
 
 def _get_live_data(data_manager):
     live_data = data_manager.ask('get_data')
-    if live_data is None:
+    if live_data is None or isinstance(live_data, NoData):
         raise RuntimeError('DataManager has no live data')
 
     live_data.mode = DataMode.PULL_FROM_SERVER
@@ -105,26 +112,31 @@ def _get_live_data(data_manager):
 
 
 class TimestampLocation:
-    '''
-    This is the default DataSet Location provider.
-    It provides a callable of one parameter (the io manager) that
-    returns a new location string, which is currently unused.
-    Uses `io.list(location)` to search for existing data at this location
-
-    Constructed with one parameter, a datetime.strftime format string,
-    which can include slashes (forward and backward are equivalent)
-    to create folder structure.
+    """
+    This is the default `DataSet.location_provider`.
+    A `location_provider` object should be a callable taking two parameters:
+    - an io manager `io` used to search for existing data using
+      `io.list(location)` so that the location returned is confirmed
+      to be unoccupied
+    - `name` - a string that should be incorporated somewhere into the
+      returned location.
+    returns a new, unoccupied location string
+
+    TimestampLocation is constructed with one parameter, a datetime.strftime
+    format string, which can include slashes (forward and backward are
+    equivalent) to create folder structure.
     Default format string is '%Y-%m-%d/%H-%M-%S'
-    '''
+    """
     def __init__(self, fmt='%Y-%m-%d/%H-%M-%S'):
         self.fmt = fmt
 
     def __call__(self, io, name=None):
-        location = base_location = datetime.now().strftime(self.fmt)
+        location = datetime.now().strftime(self.fmt)
 
         if name:
             location += '_' + name
 
+        base_location = location
         for char in map(chr, range(ord('a'), ord('z') + 2)):
             if not io.list(location):
                 break
@@ -136,7 +148,7 @@ def __call__(self, io, name=None):
 
 
 class DataSet(DelegateAttributes):
-    '''
+    """
     A container for one complete measurement loop
     May contain many individual arrays with potentially different
     sizes and dimensionalities.
@@ -172,7 +184,12 @@ class DataSet(DelegateAttributes):
         The default (stored in class attribute DataSet.default_io) is
         DiskIO('.') which says the root data storage directory is the
         current working directory, ie where you started the notebook or python.
-    '''
+
+    write_period: seconds (default 5) between saves to disk. This only applies
+        if mode=LOCAL, otherwise the DataManager handles this (and generally
+        writes more often because it's not tying up the main process to do so).
+        use None to disable writing from calls to self.store
+    """
 
     # ie data_array.arrays['vsd'] === data_array.vsd
     delegate_attr_dicts = ['arrays']
@@ -181,8 +198,8 @@ class DataSet(DelegateAttributes):
     default_formatter = GNUPlotFormat()
     location_provider = TimestampLocation()
 
-    def __init__(self, location=None, mode=None, arrays=None,
-                 data_manager=None, formatter=None, io=None):
+    def __init__(self, location=None, mode=DataMode.LOCAL, arrays=None,
+                 data_manager=None, formatter=None, io=None, write_period=5):
         if location is False or isinstance(location, str):
             self.location = location
         else:
@@ -193,13 +210,16 @@ def __init__(self, location=None, mode=None, arrays=None,
         self.formatter = formatter or self.default_formatter
         self.io = io or self.default_io
 
+        self.write_period = write_period
+        self.last_write = 0
+
         self.arrays = {}
         if arrays:
             self.action_id_map = self._clean_array_ids(arrays)
             for array in arrays:
                 self.add_array(array)
 
-        if data_manager is None:
+        if data_manager is None and mode in SERVER_MODES:
             data_manager = get_data_manager()
 
         if mode == DataMode.LOCAL:
@@ -217,8 +237,6 @@ def _init_local(self):
         if self.arrays:
             for array in self.arrays.values():
                 array.init_data()
-        else:
-            self.read()
 
     def _init_push_to_server(self, data_manager):
         self.mode = DataMode.PUSH_TO_SERVER
@@ -244,10 +262,10 @@ def _init_push_to_server(self, data_manager):
         self.data_manager = data_manager
 
     def init_on_server(self):
-        '''
+        """
         Configure this DataSet as the DataServer copy
         Should be run only by the DataServer itself.
-        '''
+        """
         if not self.arrays:
             raise RuntimeError('A server-side DataSet needs DataArrays.')
 
@@ -265,18 +283,18 @@ def _init_live(self, data_manager):
 
     @property
     def is_live_mode(self):
-        '''
+        """
         indicate whether this DataSet thinks it is live in the DataServer
         without actually talking to the DataServer or syncing with it
-        '''
+        """
         return self.mode in SERVER_MODES and self.data_manager and True
 
     @property
     def is_on_server(self):
-        '''
+        """
         Check whether this DataSet is being mirrored in the DataServer
         If it thought it was but isn't, convert it to mode=LOCAL
-        '''
+        """
         if not self.is_live_mode or self.location is False:
             return False
 
@@ -285,12 +303,12 @@ def is_on_server(self):
             return self.location == live_location
 
     def sync(self):
-        '''
+        """
         synchronize this data set with a possibly newer version either
         in storage or on the DataServer, depending on its mode
 
         returns: boolean, is this DataSet live on the server
-        '''
+        """
         # TODO: sync implies bidirectional... and it could be!
         # we should keep track of last sync timestamp and last modification
         # so we can tell whether this one, the other one, or both copies have
@@ -300,7 +318,11 @@ def sync(self):
         if not self.is_live_mode:
             # LOCAL DataSet - just read it in
             # TODO: compare timestamps to know if we need to read?
-            self.read()
+            try:
+                self.read()
+            except IOError:
+                # if no files exist, they probably haven't been created yet.
+                pass
             return False
             # TODO - for remote live plotting, maybe set some timestamp
             # threshold and call it static after it's been dormant a long time?
@@ -308,14 +330,15 @@ def sync(self):
 
         with self.data_manager.query_lock:
             if self.is_on_server:
-                # TODO: can we reduce the amount of data to send?
-                # seems like in the most general case this would need to
-                # remember each client DataSet on the server, and what has
-                # changed since that particular client last synced
-                # (at least first and last pt)
-                live_data = self.data_manager.ask('get_data').arrays
-                for array_id in self.arrays:
-                    self.arrays[array_id].ndarray = live_data[array_id].ndarray
+                synced_indices = {
+                    array_id: array.get_synced_index()
+                    for array_id, array in self.arrays.items()
+                }
+
+                changes = self.data_manager.ask('get_changes', synced_indices)
+
+                for array_id, array_changes in changes.items():
+                    self.arrays[array_id].apply_changes(**array_changes)
 
                 measuring = self.data_manager.ask('get_measuring')
                 if not measuring:
@@ -332,8 +355,18 @@ def sync(self):
                 self.read()
                 return False
 
+    def get_changes(self, synced_index):
+        changes = {}
+
+        for array_id, synced_index in synced_index.items():
+            array_changes = self.arrays[array_id].get_changes(synced_index)
+            if array_changes:
+                changes[array_id] = array_changes
+
+        return changes
+
     def add_array(self, data_array):
-        '''
+        """
         add one DataArray to this DataSet
 
         note: DO NOT just set data_set.arrays[id] = data_array
@@ -341,7 +374,7 @@ def add_array(self, data_array):
         reference back to this DataSet. It would also allow you to
         load the array in with different id than it holds itself.
 
-        '''
+        """
         # TODO: mask self.arrays so you *can't* set it directly
 
         if data_array.array_id in self.arrays:
@@ -353,10 +386,10 @@ def add_array(self, data_array):
         data_array.data_set = self
 
     def _clean_array_ids(self, arrays):
-        '''
+        """
         replace action_indices tuple with compact string array_ids
         stripping off as much extraneous info as possible
-        '''
+        """
         action_indices = [array.action_indices for array in arrays]
         array_names = set(array.name for array in arrays)
         for name in array_names:
@@ -399,33 +432,37 @@ def _clean_param_ids(self, arrays, name):
             array.array_id = name + ''.join('_' + str(i) for i in ai)
 
     def store(self, loop_indices, ids_values):
-        '''
+        """
         Set some collection of data points
 
         loop_indices: the indices within whatever loops we are inside
         values: a dict of action_index:value or array_id:value
             where value may be an arbitrarily nested list, to record
             many values at once into one array
-        '''
+        """
         if self.mode == DataMode.PUSH_TO_SERVER:
             self.data_manager.write('store_data', loop_indices, ids_values)
         else:
             for array_id, value in ids_values.items():
                 self.arrays[array_id][loop_indices] = value
+            if (self.write_period is not None and
+                    time.time() > self.last_write + self.write_period):
+                self.write()
+                self.last_write = time.time()
 
     def read(self):
-        '''
+        """
         Read the whole DataSet from storage, overwriting the local data
-        '''
+        """
         if self.location is False:
             return
         self.formatter.read(self)
 
     def write(self):
-        '''
+        """
         Write the whole (or only changed parts) DataSet to storage,
         overwriting the existing storage if any.
-        '''
+        """
         if self.mode != DataMode.LOCAL:
             raise RuntimeError('This object is connected to a DataServer, '
                                'which handles writing automatically.')
@@ -434,15 +471,17 @@ def write(self):
             return
         self.formatter.write(self)
 
-    def close(self):
-        '''
-        Tell the DataServer that the measurement is done
-        '''
+    def finalize(self):
+        """
+        Mark the DataSet as complete
+        """
         if self.mode == DataMode.PUSH_TO_SERVER:
             self.data_manager.ask('end_data')
-
-    def plot(self, cut=None):
-        pass  # TODO
+        elif self.mode == DataMode.LOCAL:
+            self.write()
+        else:
+            raise RuntimeError('This mode does not allow finalizing',
+                               self.mode)
 
     def __repr__(self):
         out = '{}: {}, location={}'.format(
diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index 828285b41b0f..c8c6bcd53ff2 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -1,14 +1,12 @@
 from collections import namedtuple
 import numpy as np
-import re
-import math
 from traceback import format_exc
-
-from .data_array import DataArray
+from operator import attrgetter
+import logging
 
 
 class Formatter:
-    '''
+    """
     Data file formatters
 
     Formatters translate between DataSets and data files.
@@ -32,49 +30,23 @@ class Formatter:
             - write will write ALL DataArrays in the DataSet, using
               last_saved_index and modified_range, as well as whether or not
               it found the specified file, to determine how much to write.
-    '''
+    """
     ArrayGroup = namedtuple('ArrayGroup', 'size set_arrays data name')
 
-    def find_changes(self, arrays):
-        '''
-        Collect changes made to any of these arrays and determine whether
-        the WHOLE group is elligible for appending or not.
-        Subclasses may choose to use or ignore this information.
-        '''
-        new_data = {}
-        can_append = True
-
-        for array in arrays.values():
-            if array.modified_range:
-                if array.modified_range[0] <= array.last_saved_index:
-                    can_append = False
-                    new_data[array.array_id] = 'overwrite'
-                else:
-                    new_data[array.array_id] = 'append'
-
-        return new_data, can_append
-
-    def mark_saved(self, arrays):
-        '''
-        Mark all DataArrays in this group as saved
-        '''
-        for array in arrays.values():
-            array.mark_saved()
-
     def write(self, data_set):
-        '''
+        """
         Write the DataSet to storage. It is up to the Formatter to decide
         when to overwrite completely, and when to just append or otherwise
         update the file(s).
-        '''
+        """
         raise NotImplementedError
 
     def read(self, data_set):
-        '''
+        """
         Read the entire DataSet by finding all files matching its location
         (using io_manager.list) and calling read_one_file from the Formatter
         subclass. Subclasses may alternatively override this entire method.
-        '''
+        """
         io_manager = data_set.io
         location = data_set.location
 
@@ -84,7 +56,7 @@ def read(self, data_set):
 
         # in case the DataArrays exist but haven't been initialized
         for array in data_set.arrays.values():
-            if array.data is None:
+            if array.ndarray is None:
                 array.init_data()
 
         ids_read = set()
@@ -93,14 +65,25 @@ def read(self, data_set):
                 try:
                     self.read_one_file(data_set, f, ids_read)
                 except ValueError:
-                    print(format_exc())
-                    print('error reading file ' + fn)
+                    logging.warning('error reading file ' + fn)
+                    logging.warning(format_exc())
 
     def read_one_file(self, data_set, f, ids_read):
+        """
+        Formatter subclasses that handle multiple data files may choose to
+        override this method, which handles one file at a time.
+
+        data_set: the DataSet we are reading into
+        f: a file-like object to read from
+        ids_read: a `set` of array_ids that we have already read.
+            when you read an array, check that it's not in this set (except
+            setpoints, which can be in several files with different inner loop)
+            then add it to the set so other files know not to read it again
+        """
         raise NotImplementedError
 
-    def match_save_range(self, group, file_exists):
-        '''
+    def match_save_range(self, group, file_exists, only_complete=True):
+        """
         Find the save range that will capture all changes in an array group.
         matches all full-sized arrays: the data arrays plus the inner loop
         setpoint array
@@ -110,7 +93,10 @@ def match_save_range(self, group, file_exists):
 
         use the inner setpoint as a base and look for differences
         in last_saved_index and modified_range in the data arrays
-        '''
+
+        if `only_complete` is True (default), will not mark any range to be
+        saved unless it contains no NaN values
+        """
         inner_setpoint = group.set_arrays[-1]
         last_saved_index = (inner_setpoint.last_saved_index if file_exists
                             else None)
@@ -129,10 +115,12 @@ def match_save_range(self, group, file_exists):
                 else:
                     modified_range = amr
 
-        # update all sources with the new matching values
-        for array in group.data + (inner_setpoint, ):
-            array.modified_range = modified_range
-            array.last_saved_index = last_saved_index
+        if only_complete and modified_range:
+            modified_range = self._get_completed_range(modified_range,
+                                                       inner_setpoint.shape,
+                                                       group.data)
+            if not modified_range:
+                return None
 
         # calculate the range to save
         if not modified_range:
@@ -145,14 +133,33 @@ def match_save_range(self, group, file_exists):
             # we can append! save only from last save to end of mods
             return (last_saved_index + 1, modified_range[1])
 
-        return last_saved_index, modified_range
+    def _get_completed_range(self, modified_range, shape, arrays):
+        """
+        check the last data point to see if it's complete.
+
+        If it's not complete, back up one point so that we don't need
+        to rewrite this point later on when it *is* complete
+
+        This should work for regular `Loop` data that comes in sequentially.
+        But if you have non-sequential data, such as a parallel simulation,
+        then you would want to look farther back.
+        """
+        last_pt = modified_range[1]
+        indices = np.unravel_index(last_pt, shape)
+        for array in arrays:
+            if np.isnan(array[indices]):
+                if last_pt == modified_range[0]:
+                    return None
+                else:
+                    return (modified_range[0], last_pt - 1)
+        return modified_range
 
     def group_arrays(self, arrays):
-        '''
+        """
         find the sets of arrays which share all the same setpoint arrays
         so each set can be grouped together into one file
         returns ArrayGroup namedtuples
-        '''
+        """
 
         set_array_sets = tuple(set(array.set_arrays
                                    for array in arrays.values()))
@@ -169,6 +176,7 @@ def group_arrays(self, arrays):
                 grouped_data[i].append(array)
 
         out = []
+        id_getter = attrgetter('array_id')
         for set_arrays, data in zip(set_array_sets, grouped_data):
             leni = len(set_arrays)
             if not data and any(1 for other_set_arrays in set_array_sets if
@@ -183,269 +191,6 @@ def group_arrays(self, arrays):
             group_name = '_'.join(sai.array_id for sai in set_arrays)
             out.append(self.ArrayGroup(size=set_arrays[-1].size,
                                        set_arrays=set_arrays,
-                                       data=tuple(data),
+                                       data=tuple(sorted(data, key=id_getter)),
                                        name=group_name))
         return out
-
-
-class GNUPlotFormat(Formatter):
-    '''
-    Saves data in one or more gnuplot-format files. We make one file for
-    each set of matching dependent variables in the loop.
-
-    These files are basically tab-separated values, but any quantity of
-    any whitespace characters is accepted.
-
-    Each row represents one setting of the setpoint variable(s)
-    the setpoint variable(s) are in the first column(s)
-    measured variable(s) come after.
-
-    The data is preceded by comment lines (starting with #).
-    We use three:
-    - one for the variable name
-    - the (longer) axis label, in quotes so a label can contain whitespace.
-    - for each dependent var, the (max) number of points in that dimension
-        (this also tells us how many dependent vars we have in this file)
-
-    # id1\tid2\t\id3...
-    # "label1"\t"label2"\t"label3"...
-    # 100\t250
-    1\t2\t3...
-    2\t3\t4...
-
-    For data of 2 dependent variables, gnuplot puts each inner loop into one
-    block, then increments the outer loop in the next block, separated by a
-    blank line.
-
-    We extend this to an arbitrary quantity of dependent variables by using
-    one blank line for each loop level that resets. (gnuplot *does* seem to
-    use 2 blank lines sometimes, to denote a whole new dataset, which sort
-    of corresponds to our situation.)
-    '''
-    def __init__(self, extension='dat', terminator='\n', separator='\t',
-                 comment='# ', number_format='g'):
-        # file extension: accept either with or without leading dot
-        self.extension = '.' + extension.lstrip('.')
-
-        # line terminator (only used for writing; will read any \r\n combo)
-        if terminator not in ('\r', '\n', '\r\n'):
-            raise ValueError(
-                r'GNUPlotFormat terminator must be \r, \n, or \r\n')
-        self.terminator = terminator
-
-        # field separator (only used for writing; will read any whitespace)
-        if not re.fullmatch(r'\s+', separator):
-            raise ValueError('GNUPlotFormat separator must be whitespace')
-        self.separator = separator
-
-        # beginning of a comment line. (when reading, just checks the
-        # non-whitespace character(s) of comment
-        self.comment = comment
-        self.comment_chars = comment.rstrip()
-        if not self.comment_chars:
-            raise ValueError('comment must have some non-whitespace')
-        self.comment_len = len(self.comment_chars)
-
-        # number format (only used for writing; will read any number)
-        self.number_format = '{:' + number_format + '}'
-
-    def read_one_file(self, data_set, f, ids_read):
-        '''
-        Called by Formatter.read to bring one data file into
-        a DataSet. Setpoint data may be duplicated across multiple files,
-        but each measured DataArray must only map to one file.
-        '''
-        arrays = data_set.arrays
-        ids = self._read_comment_line(f).split()
-        labels = self._get_labels(self._read_comment_line(f))
-        size = tuple(map(int, self._read_comment_line(f).split()))
-        ndim = len(size)
-
-        set_arrays = ()
-        data_arrays = []
-        indexed_ids = list(enumerate(ids))
-
-        for i, array_id in indexed_ids[:ndim]:
-            # setpoint arrays
-            set_size = size[: i + 1]
-            if array_id in arrays:
-                set_array = arrays[array_id]
-                if set_array.size != set_size:
-                    raise ValueError(
-                        'sizes do not match for set array: ' + array_id)
-                if array_id not in ids_read:
-                    # it's OK for setpoints to be duplicated across
-                    # multiple files, but we should only empty the
-                    # array out the first time we see it, so subsequent
-                    # reads can check for consistency
-                    set_array.clear()
-            else:
-                set_array = DataArray(label=labels[i], array_id=array_id,
-                                      set_arrays=set_arrays, size=set_size)
-                set_array.init_data()
-                data_set.add_array(set_array)
-
-            set_arrays = set_arrays + (set_array, )
-            ids_read.add(array_id)
-
-        for i, array_id in indexed_ids[ndim:]:
-            # data arrays
-            if array_id in ids_read:
-                raise ValueError('duplicate data id found: ' + array_id)
-
-            if array_id in arrays:
-                data_array = arrays[array_id]
-                data_array.clear()
-            else:
-                data_array = DataArray(label=labels[i], array_id=array_id,
-                                       set_arrays=set_arrays, size=size)
-                data_array.init_data()
-                data_set.add_array(data_array)
-            data_arrays.append(data_array)
-            ids_read.add(array_id)
-
-        indices = [0] * ndim
-        first_point = True
-        resetting = 0
-        for line in f:
-            if self._is_comment(line):
-                continue
-
-            # ignore leading or trailing whitespace (including in blank lines)
-            line = line.strip()
-
-            if not line:
-                # each consecutive blank line implies one more loop to reset
-                # when we read the next data point. Don't depend on the number
-                # of setpoints that change, as there could be weird cases, like
-                # bidirectional sweeps, or highly diagonal sweeps, where this
-                # is incorrect. Anyway this really only matters for >2D sweeps.
-                if not first_point:
-                    resetting += 1
-                continue
-
-            values = tuple(map(float, line.split()))
-
-            if resetting:
-                indices[-resetting - 1] += 1
-                indices[-resetting:] = [0] * resetting
-                resetting = 0
-
-            for value, set_array in zip(values[:ndim], set_arrays):
-                nparray = set_array.ndarray
-                myindices = tuple(indices[:nparray.ndim])
-                stored_value = nparray[myindices]
-                if math.isnan(stored_value):
-                    nparray[myindices] = value
-                elif stored_value != value:
-                    raise ValueError('inconsistent setpoint values',
-                                     stored_value, value, set_array.name,
-                                     myindices, indices)
-
-            for value, data_array in zip(values[ndim:], data_arrays):
-                data_array.ndarray[tuple(indices)] = value
-
-            indices[-1] += 1
-            first_point = False
-
-    def _is_comment(self, line):
-        return line[:self.comment_len] == self.comment_chars
-
-    def _read_comment_line(self, f):
-        s = f.readline()
-        if not self._is_comment(s):
-            raise ValueError('expected a comment line, found:\n' + s)
-        return s[self.comment_len:]
-
-    def _get_labels(self, labelstr):
-        labelstr = labelstr.strip()
-        if labelstr[0] != '"' or labelstr[-1] != '"':
-            # fields are *not* quoted
-            return labelstr.split()
-        else:
-            # fields *are* quoted (and escaped)
-            parts = re.split('"\s+"', labelstr[1:-1])
-            return [l.replace('\\"', '"').replace('\\\\', '\\') for l in parts]
-
-    def write(self, data_set):
-        '''
-        Write updates in this DataSet to storage. Will choose append if
-        possible, overwrite if not.
-        '''
-        io_manager = data_set.io
-        location = data_set.location
-        arrays = data_set.arrays
-
-        groups = self.group_arrays(arrays)
-        existing_files = set(io_manager.list(location))
-        written_files = set()
-
-        for group in groups:
-            if len(groups) == 1:
-                fn = location + self.extension
-            else:
-                fn = io_manager.join(location, group.name + self.extension)
-
-            written_files.add(fn)
-
-            file_exists = fn in existing_files
-            save_range = self.match_save_range(group, file_exists)
-
-            if save_range is None:
-                continue
-
-            overwrite = save_range[0] == 0
-            open_mode = 'w' if overwrite else 'a'
-            shape = group.set_arrays[-1].shape
-
-            with io_manager.open(fn, open_mode) as f:
-                if overwrite:
-                    f.write(self._make_header(group))
-
-                for i in range(save_range[0], save_range[1] + 1):
-                    indices = np.unravel_index(i, shape)
-
-                    # insert a blank line for each loop that reset (to index 0)
-                    # note that if *all* indices are zero (the first point)
-                    # we won't put any blanks
-                    for j, index in enumerate(reversed(indices)):
-                        if index != 0:
-                            if j:
-                                f.write(self.terminator * j)
-                            break
-
-                    one_point = self._data_point(group, indices)
-                    f.write(self.separator.join(one_point) + self.terminator)
-
-        extra_files = existing_files - written_files
-        if extra_files:
-            print('removing obsolete files: ' + ','.join(extra_files))
-            for fn in extra_files:
-                io_manager.remove(fn)
-
-    def _make_header(self, group):
-        ids, labels = [], []
-        for array in group.set_arrays + group.data:
-            ids.append(array.array_id)
-            label = getattr(array, 'label', array.array_id)
-            label = label.replace('\\', '\\\\').replace('"', '\\"')
-            labels.append('"' + label + '"')
-
-        sizes = [str(size) for size in group.set_arrays[-1].shape]
-        if len(sizes) != len(group.set_arrays):
-            raise ValueError('array dimensionality does not match setpoints')
-
-        out = (self._comment_line(ids) + self._comment_line(labels) +
-               self._comment_line(sizes))
-
-        return out
-
-    def _comment_line(self, items):
-        return self.comment + self.separator.join(items) + self.terminator
-
-    def _data_point(self, group, indices):
-        for array in group.set_arrays:
-            yield self.number_format.format(array[indices[:array.ndim]])
-
-        for array in group.data:
-            yield self.number_format.format(array[indices])
diff --git a/qcodes/data/gnuplot_format.py b/qcodes/data/gnuplot_format.py
new file mode 100644
index 000000000000..d3eefdcae9f0
--- /dev/null
+++ b/qcodes/data/gnuplot_format.py
@@ -0,0 +1,306 @@
+import numpy as np
+import re
+import math
+
+from .data_array import DataArray
+from .format import Formatter
+
+
+class GNUPlotFormat(Formatter):
+    """
+    Saves data in one or more gnuplot-format files. We make one file for
+    each set of matching dependent variables in the loop.
+
+    options:
+
+    extension (default 'dat'): file extension for data files
+
+    terminator (default '\\n'): newline character(s) to use on write
+        not used for reading, we will read any combination of \\r and \\n
+
+    separator (default '\\t'): field (column) separator, must be whitespace.
+        Only used for writing, we will read with any whitespace separation.
+
+    comment (default '# '): lines starting with this are not data
+        Comments are written with this full string, and identified on read
+        by just the string after stripping whitespace.
+
+    number_format (default 'g'): from the format mini-language, how to
+        format numeric data into a string
+
+    always_nest (default True): whether to always make a folder for files
+        or just make a single data file if all data has the same setpoints
+
+    These files are basically tab-separated values, but any quantity of
+    any whitespace characters is accepted.
+
+    Each row represents one setting of the setpoint variable(s)
+    the setpoint variable(s) are in the first column(s)
+    measured variable(s) come after.
+
+    The data is preceded by comment lines (starting with #).
+    We use three:
+    - one for the variable name
+    - the (longer) axis label, in quotes so a label can contain whitespace.
+    - for each dependent var, the (max) number of points in that dimension
+        (this also tells us how many dependent vars we have in this file)
+
+    # id1\tid2\t\id3...
+    # "label1"\t"label2"\t"label3"...
+    # 100\t250
+    1\t2\t3...
+    2\t3\t4...
+
+    For data of 2 dependent variables, gnuplot puts each inner loop into one
+    block, then increments the outer loop in the next block, separated by a
+    blank line.
+
+    We extend this to an arbitrary quantity of dependent variables by using
+    one blank line for each loop level that resets. (gnuplot *does* seem to
+    use 2 blank lines sometimes, to denote a whole new dataset, which sort
+    of corresponds to our situation.)
+    """
+    def __init__(self, extension='dat', terminator='\n', separator='\t',
+                 comment='# ', number_format='g', always_nest=True):
+        # file extension: accept either with or without leading dot
+        self.extension = '.' + extension.lstrip('.')
+
+        # line terminator (only used for writing; will read any \r\n combo)
+        if terminator not in ('\r', '\n', '\r\n'):
+            raise ValueError(
+                r'GNUPlotFormat terminator must be \r, \n, or \r\n')
+        self.terminator = terminator
+
+        # field separator (only used for writing; will read any whitespace)
+        if not re.fullmatch(r'\s+', separator):
+            raise ValueError('GNUPlotFormat separator must be whitespace')
+        self.separator = separator
+
+        # beginning of a comment line. (when reading, just checks the
+        # non-whitespace character(s) of comment
+        self.comment = comment
+        self.comment_chars = comment.rstrip()
+        if not self.comment_chars:
+            raise ValueError('comment must have some non-whitespace')
+        self.comment_len = len(self.comment_chars)
+
+        # number format (only used for writing; will read any number)
+        self.number_format = '{:' + number_format + '}'
+
+        self.always_nest = always_nest
+
+    def read_one_file(self, data_set, f, ids_read):
+        """
+        Called by Formatter.read to bring one data file into
+        a DataSet. Setpoint data may be duplicated across multiple files,
+        but each measured DataArray must only map to one file.
+
+        data_set: the DataSet we are reading into
+        f: a file-like object to read from
+        ids_read: a `set` of array_ids that we have already read.
+            when you read an array, check that it's not in this set (except
+            setpoints, which can be in several files with different inner loop)
+            then add it to the set so other files know not to read it again
+        """
+        if not f.name.endswith(self.extension):
+            return
+
+        arrays = data_set.arrays
+        ids = self._read_comment_line(f).split()
+        labels = self._get_labels(self._read_comment_line(f))
+        size = tuple(map(int, self._read_comment_line(f).split()))
+        ndim = len(size)
+
+        set_arrays = ()
+        data_arrays = []
+        indexed_ids = list(enumerate(ids))
+
+        for i, array_id in indexed_ids[:ndim]:
+            # setpoint arrays
+            set_size = size[: i + 1]
+            if array_id in arrays:
+                set_array = arrays[array_id]
+                if set_array.size != set_size:
+                    raise ValueError(
+                        'sizes do not match for set array: ' + array_id)
+                if array_id not in ids_read:
+                    # it's OK for setpoints to be duplicated across
+                    # multiple files, but we should only empty the
+                    # array out the first time we see it, so subsequent
+                    # reads can check for consistency
+                    set_array.clear()
+            else:
+                set_array = DataArray(label=labels[i], array_id=array_id,
+                                      set_arrays=set_arrays, size=set_size)
+                set_array.init_data()
+                data_set.add_array(set_array)
+
+            set_arrays = set_arrays + (set_array, )
+            ids_read.add(array_id)
+
+        for i, array_id in indexed_ids[ndim:]:
+            # data arrays
+            if array_id in ids_read:
+                raise ValueError('duplicate data id found: ' + array_id)
+
+            if array_id in arrays:
+                data_array = arrays[array_id]
+                data_array.clear()
+            else:
+                data_array = DataArray(label=labels[i], array_id=array_id,
+                                       set_arrays=set_arrays, size=size)
+                data_array.init_data()
+                data_set.add_array(data_array)
+            data_arrays.append(data_array)
+            ids_read.add(array_id)
+
+        indices = [0] * ndim
+        first_point = True
+        resetting = 0
+        for line in f:
+            if self._is_comment(line):
+                continue
+
+            # ignore leading or trailing whitespace (including in blank lines)
+            line = line.strip()
+
+            if not line:
+                # each consecutive blank line implies one more loop to reset
+                # when we read the next data point. Don't depend on the number
+                # of setpoints that change, as there could be weird cases, like
+                # bidirectional sweeps, or highly diagonal sweeps, where this
+                # is incorrect. Anyway this really only matters for >2D sweeps.
+                if not first_point:
+                    resetting += 1
+                continue
+
+            values = tuple(map(float, line.split()))
+
+            if resetting:
+                indices[-resetting - 1] += 1
+                indices[-resetting:] = [0] * resetting
+                resetting = 0
+
+            for value, set_array in zip(values[:ndim], set_arrays):
+                nparray = set_array.ndarray
+                myindices = tuple(indices[:nparray.ndim])
+                stored_value = nparray[myindices]
+                if math.isnan(stored_value):
+                    nparray[myindices] = value
+                elif stored_value != value:
+                    raise ValueError('inconsistent setpoint values',
+                                     stored_value, value, set_array.name,
+                                     myindices, indices)
+
+            for value, data_array in zip(values[ndim:], data_arrays):
+                data_array.ndarray[tuple(indices)] = value
+
+            indices[-1] += 1
+            first_point = False
+
+    def _is_comment(self, line):
+        return line[:self.comment_len] == self.comment_chars
+
+    def _read_comment_line(self, f):
+        s = f.readline()
+        if not self._is_comment(s):
+            raise ValueError('expected a comment line, found:\n' + s)
+        return s[self.comment_len:]
+
+    def _get_labels(self, labelstr):
+        labelstr = labelstr.strip()
+        if labelstr[0] != '"' or labelstr[-1] != '"':
+            # fields are *not* quoted
+            return labelstr.split()
+        else:
+            # fields *are* quoted (and escaped)
+            parts = re.split('"\s+"', labelstr[1:-1])
+            return [l.replace('\\"', '"').replace('\\\\', '\\') for l in parts]
+
+    def write(self, data_set):
+        """
+        Write updates in this DataSet to storage. Will choose append if
+        possible, overwrite if not.
+        """
+        io_manager = data_set.io
+        location = data_set.location
+        arrays = data_set.arrays
+
+        groups = self.group_arrays(arrays)
+        existing_files = set(io_manager.list(location))
+        written_files = set()
+
+        for group in groups:
+            if len(groups) == 1 and not self.always_nest:
+                fn = io_manager.join(location + self.extension)
+            else:
+                fn = io_manager.join(location, group.name + self.extension)
+
+            written_files.add(fn)
+
+            file_exists = fn in existing_files
+            save_range = self.match_save_range(group, file_exists)
+
+            if save_range is None:
+                continue
+
+            overwrite = save_range[0] == 0
+            open_mode = 'w' if overwrite else 'a'
+            shape = group.set_arrays[-1].shape
+
+            with io_manager.open(fn, open_mode) as f:
+                if overwrite:
+                    f.write(self._make_header(group))
+
+                for i in range(save_range[0], save_range[1] + 1):
+                    indices = np.unravel_index(i, shape)
+
+                    # insert a blank line for each loop that reset (to index 0)
+                    # note that if *all* indices are zero (the first point)
+                    # we won't put any blanks
+                    for j, index in enumerate(reversed(indices)):
+                        if index != 0:
+                            if j:
+                                f.write(self.terminator * j)
+                            break
+
+                    one_point = self._data_point(group, indices)
+                    f.write(self.separator.join(one_point) + self.terminator)
+
+            # now that we've saved the data, mark it as such in the data.
+            # we mark the data arrays and the inner setpoint array. Outer
+            # setpoint arrays have different dimension (so would need a
+            # different unraveled index) but more importantly could have
+            # a different saved range anyway depending on whether there
+            # is outer data taken before or after the inner loop. Anyway we
+            # never look at the outer setpoint last_saved_index or
+            # modified_range, we just assume it's got the values we need.
+            for array in group.data + (group.set_arrays[-1],):
+                array.mark_saved(save_range[1])
+
+    def _make_header(self, group):
+        ids, labels = [], []
+        for array in group.set_arrays + group.data:
+            ids.append(array.array_id)
+            label = getattr(array, 'label', array.array_id)
+            label = label.replace('\\', '\\\\').replace('"', '\\"')
+            labels.append('"' + label + '"')
+
+        sizes = [str(size) for size in group.set_arrays[-1].shape]
+        if len(sizes) != len(group.set_arrays):
+            raise ValueError('array dimensionality does not match setpoints')
+
+        out = (self._comment_line(ids) + self._comment_line(labels) +
+               self._comment_line(sizes))
+
+        return out
+
+    def _comment_line(self, items):
+        return self.comment + self.separator.join(items) + self.terminator
+
+    def _data_point(self, group, indices):
+        for array in group.set_arrays:
+            yield self.number_format.format(array[indices[:array.ndim]])
+
+        for array in group.data:
+            yield self.number_format.format(array[indices])
diff --git a/qcodes/data/io.py b/qcodes/data/io.py
index ea3cf9dc3fe2..cfb0e2a6b70b 100644
--- a/qcodes/data/io.py
+++ b/qcodes/data/io.py
@@ -84,7 +84,10 @@ def open(self, filename, mode):
             yield f
 
     def _normalize_slashes(self, location):
-        return os.path.join(*re.split('[\\\\/]', location))
+        # note that this is NOT os.path.join - the difference is os.path.join
+        # discards empty strings, so if you use it on a re.split absolute
+        # path you will get a relative path!
+        return os.sep.join(re.split('[\\\\/]', location))
 
     def _add_base(self, location):
         location = self._normalize_slashes(location)
@@ -100,7 +103,7 @@ def join(self, *args):
         '''
         the context-dependent version of os.path.join for this io manager
         '''
-        return os.path.join(*args)
+        return os.path.join(*list(map(self._normalize_slashes, args)))
 
     def isfile(self, location):
         '''
diff --git a/qcodes/data/manager.py b/qcodes/data/manager.py
index b7e0ee6985f3..c02e0f22dc3c 100644
--- a/qcodes/data/manager.py
+++ b/qcodes/data/manager.py
@@ -2,14 +2,14 @@
 from queue import Empty
 from traceback import format_exc
 
-from qcodes.utils.multiprocessing import ServerManager
+from qcodes.utils.multiprocessing import ServerManager, SERVER_ERR
 
 
 def get_data_manager(only_existing=False):
-    '''
+    """
     create or retrieve the storage manager
     makes sure we don't accidentally create multiple DataManager processes
-    '''
+    """
     dm = DataManager.default
     if dm and dm._server.is_alive():
         return dm
@@ -19,10 +19,10 @@ def get_data_manager(only_existing=False):
 
 
 class NoData:
-    '''
+    """
     A placeholder object for DataServer to hold
     when there is no loop running.
-    '''
+    """
     location = None
 
     def store(self, *args, **kwargs):
@@ -34,23 +34,23 @@ def write(self, *args, **kwargs):
 
 class DataManager(ServerManager):
     default = None
-    '''
+    """
     creates a separate process (DataServer) that holds running measurement
     and monitor data, and manages writing these to disk or other storage
 
     DataServer communicates with other processes through messages
     Written using multiprocessing Queue's, but should be easily
     extensible to other messaging systems
-    '''
-    def __init__(self, query_timeout=2):
+    """
+    def __init__(self):
         type(self).default = self
         super().__init__(name='DataServer', server_class=DataServer)
 
     def restart(self, force=False):
-        '''
+        """
         Restart the DataServer
         Use force=True to abort a running measurement.
-        '''
+        """
         if (not force) and self.ask('get_data', 'location'):
             raise RuntimeError('A measurement is running. Use '
                                'restart(force=True) to override.')
@@ -58,7 +58,7 @@ def restart(self, force=False):
 
 
 class DataServer:
-    '''
+    """
     Running in its own process, receives, holds, and returns current `Loop` and
     monitor data, and writes it to disk (or other storage)
 
@@ -69,7 +69,7 @@ class DataServer:
     they are nearly identical objects, but are configured differently so that
     the loop `DataSet` doesn't hold any data itself, it only passes that data
     on to the `DataServer`
-    '''
+    """
     default_storage_period = 1  # seconds between data storage calls
     queries_per_store = 5
     default_monitor_period = 60  # seconds between monitoring storage calls
@@ -122,7 +122,9 @@ def _reply(self, response):
 
     def _post_error(self, e):
         self._error_queue.put(format_exc())
-        self._response_queue.put('ERR')  # to short-circuit the timeout
+        # the caller is waiting on _response_queue, so put a signal there
+        # to say there's an error coming
+        self._response_queue.put(SERVER_ERR)
 
     ######################################################################
     # query handlers                                                     #
@@ -138,17 +140,17 @@ def _post_error(self, e):
     ######################################################################
 
     def handle_halt(self):
-        '''
+        """
         Quit this DataServer
-        '''
+        """
         self._running = False
         self._reply(True)
 
     def handle_new_data(self, data_set):
-        '''
+        """
         Load a new (normally empty) DataSet into the DataServer, and
         prepare it to start receiving and storing data
-        '''
+        """
         if self._measuring:
             raise RuntimeError('Already executing a measurement')
 
@@ -158,29 +160,35 @@ def handle_new_data(self, data_set):
         self._reply(True)
 
     def handle_end_data(self):
-        '''
+        """
         Mark this DataSet as complete and write its final changes to storage
-        '''
+        """
         self._data.write()
         self._measuring = False
         self._reply(True)
 
     def handle_store_data(self, *args):
-        '''
+        """
         Put some data into the DataSet
         This is the only query that does not return a value, so the measurement
         loop does not need to wait for a reply.
-        '''
+        """
         self._data.store(*args)
 
     def handle_get_measuring(self):
-        '''
+        """
         Is a measurement loop presently running?
-        '''
+        """
         self._reply(self._measuring)
 
     def handle_get_data(self, attr=None):
-        '''
+        """
         Return the active DataSet or some attribute of it
-        '''
+        """
         self._reply(getattr(self._data, attr) if attr else self._data)
+
+    def handle_get_changes(self, synced_indices):
+        """
+        Return all new data after the last sync
+        """
+        self._reply(self._data.get_changes(synced_indices))
diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index e5b591927bec..e625e01e13ad 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -3,9 +3,10 @@
 
 from qcodes.utils.metadata import Metadatable
 from qcodes.utils.helpers import DelegateAttributes, strip_attrs
-from .parameter import Parameter, StandardParameter
+from .parameter import StandardParameter
 from .function import Function
 from .remote import RemoteInstrument
+import logging
 
 
 class NoDefault:
@@ -28,6 +29,8 @@ class Instrument(Metadatable, DelegateAttributes):
         `default_server_name`, passing in all the constructor kwargs, to
         determine the name. If not overridden, this is just 'Instruments'.
 
+        ** see notes below about `server_name` in SUBCLASS CONSTRUCTORS **
+
         Use None to operate without a server - but then this Instrument
         will not work with qcodes Loops or other multiprocess procedures.
 
@@ -46,12 +49,16 @@ class Instrument(Metadatable, DelegateAttributes):
     `shared_kwargs` class attribute to a list of kwarg names that should
     be treated this way.
 
-    shared_kwargs must be provided ONLY as kwargs when constructing
-    instruments that need them, you CANNOT provide them as positional args.
+    It is an error to initialize two instruments on the same server with
+    different keys or values for `shared_kwargs`, unless the later
+    instruments have NO shared_kwargs at all.
 
-    It is an error to initialize two instruments on
-    the same server with different keys or values for these kwargs, unless
-    the later instruments have NO shared_kwargs at all.
+    SUBCLASS CONSTRUCTORS: `server_name` and any `shared_kwargs` must be
+    available as kwargs and kwargs ONLY (not positional) in all subclasses,
+    and not modified in the inheritance chain. This is because we need to
+    create the server before instantiating the actual instrument. The easiest
+    way to manage this is to accept **kwargs in your subclass and pass them
+    on to super().__init()
     '''
     shared_kwargs = []
 
@@ -87,8 +94,13 @@ def connect_message(self, param_name, begin_time=None):
         '''
         idn = self.get(param_name).replace(',', ', ').replace('\n', ' ')
 
-        return 'Connected to: {} in {:.2f}s'.format(
+        con_msg = 'Connected to: {} in {:.2f}s'.format(
             idn.strip(), time.time() - (begin_time or self._t0))
+        print(con_msg)
+        return con_msg
+
+    def __repr__(self):
+        return '<{}: {}>'.format(type(self).__name__, self.name)
 
     def getattr(self, attr, default=NoDefault):
         '''
@@ -221,10 +233,13 @@ def delattr(self, attr, prune=True):
                     delattr(self, attr[0])
 
     def __del__(self):
-        wr = weakref.ref(self)
-        if wr in getattr(self, '_instances', {}):
-            self._instances.remove(wr)
-        self.close()
+        try:
+            wr = weakref.ref(self)
+            if wr in getattr(self, '_instances', {}):
+                self._instances.remove(wr)
+            self.close()
+        except:
+            pass
 
     def close(self):
         '''
@@ -410,7 +425,9 @@ def _get_method_attrs(self):
 
         for attr in dir(self):
             value = getattr(self, attr)
-            if (not callable(value)) or isinstance(value, Function):
+            if ((not callable(value)) or
+                    value is self.parameters.get(attr) or
+                    value is self.functions.get(attr)):
                 # Functions are callable, and they show up in dir(),
                 # but we don't want them included in methods, they have
                 # their own listing. But we don't want to just exclude
diff --git a/qcodes/instrument/ip.py b/qcodes/instrument/ip.py
index 7b2e0a9292a7..e0433ce11a05 100644
--- a/qcodes/instrument/ip.py
+++ b/qcodes/instrument/ip.py
@@ -31,6 +31,7 @@ def __init__(self, name, address=None, port=None, timeout=5,
         self._confirmation = write_confirmation
 
         self._ensure_connection = EnsureConnection(self)
+        self._buffer_size = 1400
 
         self._socket = None
 
@@ -83,7 +84,7 @@ def set_timeout(self, timeout=None):
             self._timeout = timeout
 
         if self._socket is not None:
-            self.socket.settimeout(float(self.timeout))
+            self._socket.settimeout(float(self._timeout))
 
     def set_terminator(self, terminator):
         self._terminator = terminator
@@ -93,32 +94,43 @@ def _send(self, cmd):
         self._socket.send(data.encode())
 
     def _recv(self):
-        return self._socket.recv(512).decode()
+        return self._socket.recv(self._buffer_size).decode()
 
     def close(self):
         self._disconnect()
         super().close()
 
     def write(self, cmd):
-        with self._ensure_connection:
-            self._send(cmd)
-            if self._confirmation:
-                self._recv()
+        try:
+            with self._ensure_connection:
+                self._send(cmd)
+                if self._confirmation:
+                    self._recv()
+        except Exception as e:
+            e.args = e.args + ('writing ' + repr(cmd) + ' to ' + repr(self),)
+            raise e
 
     def ask(self, cmd):
-        with self._ensure_connection:
-            self._send(cmd)
-            return self._recv()
+        try:
+            with self._ensure_connection:
+                self._send(cmd)
+                return self._recv()
+        except Exception as e:
+            e.args = e.args + ('asking ' + repr(cmd) + ' to ' + repr(self),)
+            raise e
+
+    def __del__(self):
+        self.close()
 
 
 class EnsureConnection:
     def __init__(self, instrument):
-        self._instrument = instrument
+        self.instrument = instrument
 
     def __enter__(self):
         if not self.instrument._persistent or self.instrument._socket is None:
             self.instrument._connect()
 
-    def __exit__(self):
+    def __exit__(self, type, value, tb):
         if not self.instrument._persistent:
             self.instrument._disconnect()
diff --git a/qcodes/instrument/mock.py b/qcodes/instrument/mock.py
index ec73231c0635..0d8699df8063 100644
--- a/qcodes/instrument/mock.py
+++ b/qcodes/instrument/mock.py
@@ -14,7 +14,10 @@ class MockInstrument(Instrument):
     delay: the time (in seconds) to wait after any operation
         to simulate communication delay
     model: a MockModel object to connect this MockInstrument to.
-        should have one or two methods related directly to this instrument:
+        Subclasses MUST accept `model` as a constructor kwarg ONLY, even
+        though it is required. See notes in `Instrument` docstring.
+        A model should have one or two methods related directly to this
+        instrument:
         _set(param, value) -> set a parameter on the model
         _get(param) -> returns the value
     keep_history: record (in self.history) every command sent to this
diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 9a94c6536bef..45d4fbd26a3a 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -39,6 +39,7 @@
 import logging
 import os
 
+from qcodes.utils.deferred_operations import DeferredOperations
 from qcodes.utils.helpers import (permissive_range, wait_secs,
                                   DelegateAttributes)
 from qcodes.utils.metadata import Metadatable
@@ -57,7 +58,7 @@ def no_getter(*args, **kwargs):
         'set value.')
 
 
-class Parameter(Metadatable):
+class Parameter(Metadatable, DeferredOperations):
     '''
     defines one generic parameter, not necessarily part of
     an instrument. can be settable and/or gettable.
@@ -138,6 +139,9 @@ def __init__(self,
                  vals=None, docstring=None, **kwargs):
         super().__init__(**kwargs)
 
+        self.has_get = False
+        self.has_set = False
+
         if names is not None:
             # check for names first - that way you can provide both name
             # AND names for instrument parameters - name is how you get the
@@ -193,6 +197,28 @@ def __init__(self,
 
         self.get_latest = GetLatest(self)
 
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            str(self.name),
+            id(self))
+        return s
+
+    def __call__(self, *args):
+        if len(args) == 0:
+            if self.has_get:
+                return self.get()
+            else:
+                raise NoCommandError('no get cmd found in' +
+                                     ' Parameter {}'.format(self.name))
+        else:
+            if self.has_set:
+                self.set(*args)
+            else:
+                raise NoCommandError('no set cmd found in' +
+                                     ' Parameter {}'.format(self.name))
+
     def _latest(self):
         return {
             'value': self._latest_value,
@@ -219,13 +245,16 @@ def get_attrs(self):
 
         return out
 
-    def snapshot_base(self):
+    def snapshot_base(self, update=False, *args, **kwargs):
         '''
         json state of the Parameter
 
         optionally pass in the state, so if this is an instrument parameter
         we can collect all calls to the server into one
         '''
+        if update:
+            self.get()
+
         state = self._latest()
 
         if state['ts'] is not None:
@@ -309,19 +338,26 @@ class StandardParameter(Parameter):
 
     vals: a Validator object for this parameter
 
-    sweep_step: max increment of parameter value - larger changes
+    delay: time (in seconds) to wait after the *start* of each set,
+        whether part of a sweep or not. Can be set 0 to go maximum speed with
+        no errors.
+    max_delay: If > delay, we don't emit a warning unless the time
+        taken during a single set is greater than this, even though we aim for
+        delay. If delay
+    step: max increment of parameter value - larger changes
         are broken into steps this size
-    sweep_delay: time (in seconds) to wait after each sweep step
     max_val_age: max time (in seconds) to trust a saved value from
         this parameter as the starting point of a sweep
+
     docstring: documentation string for the __doc__ field of the object
-        The __doc__ field of the instance is used by some help systems, but not all
+        The __doc__ field of the instance is used by some help systems,
+        but not all
     '''
     def __init__(self, name, instrument=None,
                  get_cmd=None, async_get_cmd=None, get_parser=None,
                  set_cmd=None, async_set_cmd=None, set_parser=None,
-                 sweep_step=None, sweep_delay=None, max_sweep_delay=None,
-                 max_val_age=3600, vals=None, val_mapping=None, **kwargs):
+                 delay=None, max_delay=None, step=None, max_val_age=3600,
+                 vals=None, val_mapping=None, **kwargs):
         # handle val_mapping before super init because it impacts
         # vals / validation in the base class
         if val_mapping:
@@ -337,7 +373,8 @@ def __init__(self, name, instrument=None,
                 set_parser = self._set_mapping.__getitem__
 
         if get_parser is not None and not isinstance(get_cmd, str):
-            logging.warning('get_parser is set, but will not be used')
+            logging.warning('get_parser is set, but will not be used ' +
+                            '(name %s)' % name)
         super().__init__(name=name, vals=vals, **kwargs)
 
         self._instrument = instrument
@@ -347,23 +384,24 @@ def __init__(self, name, instrument=None,
         # having to call .get() for every .set()
         self._max_val_age = 0
 
-        self.has_get = False
-        self.has_set = False
-
         self._set_get(get_cmd, async_get_cmd, get_parser)
         self._set_set(set_cmd, async_set_cmd, set_parser)
-        self.set_sweep(sweep_step, sweep_delay,
-                       max_sweep_delay=max_sweep_delay,
-                       max_val_age=max_val_age)
+        self.set_delay(delay, max_delay)
+        self.set_step(step, max_val_age)
 
         if not (self.has_get or self.has_set):
             raise NoCommandError('neither set nor get cmd found in' +
                                  ' Parameter {}'.format(self.name))
 
     def get(self):
-        value = self._get()
-        self._save_val(value)
-        return value
+        try:
+            value = self._get()
+            self._save_val(value)
+            return value
+        except Exception as e:
+            e.args = e.args + (
+                'getting {}:{}'.format(self._instrument.name, self.name),)
+            raise e
 
     @asyncio.coroutine
     def get_async(self):
@@ -392,15 +430,29 @@ def _set_set(self, set_cmd, async_set_cmd, set_parser):
             self.has_set = True
 
     def _validate_and_set(self, value):
-        self.validate(value)
-        self._set(value)
-        self._save_val(value)
+        try:
+            clock = time.perf_counter()
+            self.validate(value)
+            self._set(value)
+            self._save_val(value)
+            if self._delay is not None:
+                clock, remainder = self._update_set_ts(clock)
+                time.sleep(remainder)
+        except Exception as e:
+            e.args = e.args + (
+                'setting {}:{} to {}'.format(self._instrument.name,
+                                             self.name, repr(value)),)
+            raise e
 
     @asyncio.coroutine
     def _validate_and_set_async(self, value):
+        clock = time.perf_counter()
         self.validate(value)
         yield from self._set_async(value)
         self._save_val(value)
+        if self._delay is not None:
+            clock, remainder = self._update_set_ts(clock)
+            yield from asyncio.sleep(remainder)
 
     def _sweep_steps(self, value):
         oldest_ok_val = datetime.now() - timedelta(seconds=self._max_val_age)
@@ -423,13 +475,13 @@ def _sweep_steps(self, value):
             return []
 
         # drop the initial value, we're already there
-        return permissive_range(start_value, value, self._sweep_step)[1:]
+        return permissive_range(start_value, value, self._step)[1:]
 
-    def _update_sweep_ts(self, step_clock):
+    def _update_set_ts(self, step_clock):
         # calculate the delay time to the *max* delay,
         # then take off up to the tolerance
-        tolerance = self._sweep_delay_tolerance
-        step_clock += self._sweep_delay
+        tolerance = self._delay_tolerance
+        step_clock += self._delay
         remainder = wait_secs(step_clock + tolerance)
         if remainder <= tolerance:
             # don't allow extra delays to compound
@@ -440,17 +492,28 @@ def _update_sweep_ts(self, step_clock):
         return step_clock, remainder
 
     def _validate_and_sweep(self, value):
-        self.validate(value)
-        step_clock = time.perf_counter()
+        try:
+            self.validate(value)
+            step_clock = time.perf_counter()
 
-        for step_val in self._sweep_steps(value):
-            self._set(step_val)
-            self._save_val(step_val)
-            step_clock, remainder = self._update_sweep_ts(step_clock)
-            time.sleep(remainder)
-
-        self._set(value)
-        self._save_val(value)
+            for step_val in self._sweep_steps(value):
+                self._set(step_val)
+                self._save_val(step_val)
+                if self._delay is not None:
+                    step_clock, remainder = self._update_set_ts(step_clock)
+                    time.sleep(remainder)
+
+            self._set(value)
+            self._save_val(value)
+
+            if self._delay is not None:
+                step_clock, remainder = self._update_set_ts(step_clock)
+                time.sleep(remainder)
+        except Exception as e:
+            e.args = e.args + (
+                'setting {}:{} to {}'.format(self._instrument.name,
+                                             self.name, repr(value)),)
+            raise e
 
     @asyncio.coroutine
     def _validate_and_sweep_async(self, value):
@@ -460,78 +523,102 @@ def _validate_and_sweep_async(self, value):
         for step_val in self._sweep_steps(value):
             yield from self._set_async(step_val)
             self._save_val(step_val)
-            step_clock, remainder = self._update_sweep_ts(step_clock)
-            yield from asyncio.sleep(remainder)
+            if self._delay is not None:
+                step_clock, remainder = self._update_set_ts(step_clock)
+                yield from asyncio.sleep(remainder)
 
         yield from self._set_async(value)
         self._save_val(value)
 
-    def set_sweep(self, sweep_step, sweep_delay, max_sweep_delay=None,
-                  max_val_age=None):
+    def set_step(self, step, max_val_age=None):
+        '''
+        Configure whether this Parameter uses steps during set operations.
+        If step is a positive number, this is the maximum value change
+        allowed in one hardware call, so a single set can result in many
+        calls to the hardware if the starting value is far from the target.
+
+        step: a positive number, the largest change allowed in one call
+            all but the final change will attempt to change by +/- step
+            exactly
+
+        max_val_age: Only used with stepping, the max time (in seconds) to
+            trust a saved value. If this parameter has not been set or measured
+            more recently than this, it will be measured before starting to
+            step, so we're confident in the value we're starting from.
         '''
-        configure this Parameter to set using a stair-step sweep
+        if not step:
+            # single-command setting
+            self.set = self._validate_and_set
+            self.set_async = self._validate_and_set_async
 
-        This means a single .set call will generate many instrument writes
-        so that the value only changes at most sweep_step in a time sweep_delay
+        elif not self._vals.is_numeric:
+            raise TypeError('you can only step numeric parameters')
+        elif step <= 0:
+            raise ValueError('step must be positive')
+        elif (isinstance(self._vals, Ints) and
+                not isinstance(step, int)):
+            raise TypeError(
+                'step must be a positive int for an Ints parameter')
+        elif not isinstance(step, (int, float)):
+            raise TypeError('step must be a positive number')
 
-        sweep_step: the biggest change in value allowed at once
+        else:
+            # stepped setting
+            if max_val_age is not None:
+                if not isinstance(max_val_age, (int, float)):
+                    raise TypeError(
+                        'max_val_age must be a non-negative number')
+                if max_val_age < 0:
+                    raise ValueError('max_val_age must be non-negative')
+                self._max_val_age = max_val_age
 
-        sweep_delay: the target time between steps. The actual time will not be
-            shorter than this, but may be longer if the underlying set call
-            takes longer than this time.
+            self._step = step
+            self.set = self._validate_and_sweep
+            self.set_async = self._validate_and_sweep_async
 
-        max_sweep_delay: if given, the longest time allowed between steps (due
-            to a slow set call, presumably) before we emit a warning
+    def get_delay(self):
+        ''' Return the delay time of this parameter. Also see `set_delay` '''
+        return self._delay
 
-        max_val_age: max time (in seconds) to trust a saved value. Important
-        since we need to know what value we're starting from in this sweep.
+    def set_delay(self, delay, max_delay=None):
         '''
-        if sweep_step is not None or sweep_delay is not None:
-            if not self._vals.is_numeric:
-                raise TypeError('you can only sweep numeric parameters')
+        Configure this parameter with a delay between set operations.
+        Typically used in conjunction with set_step to create an effective
+        ramp rate, but can also be used without a step to enforce a delay
+        after every set.
 
-            if (isinstance(self._vals, Ints) and
-                    not isinstance(sweep_step, int)):
-                raise TypeError(
-                    'sweep_step must be a positive int for an Ints parameter')
-            elif not isinstance(sweep_step, (int, float)):
-                raise TypeError('sweep_step must be a positive number')
-            if sweep_step <= 0:
-                raise ValueError('sweep_step must be positive')
-
-            if not isinstance(sweep_delay, (int, float)):
-                raise TypeError('sweep_delay must be a positive number')
-            if sweep_delay <= 0:
-                raise ValueError('sweep_delay must be positive')
-
-            self._sweep_step = sweep_step
-            self._sweep_delay = sweep_delay
-
-            if max_sweep_delay is not None:
-                if not isinstance(max_sweep_delay, (int, float)):
-                    raise TypeError(
-                        'max_sweep_delay must be a positive number')
-                if max_sweep_delay < sweep_delay:
-                    raise ValueError(
-                        'max_sweep_delay must not be shorter than sweep_delay')
-                self._sweep_delay_tolerance = max_sweep_delay - sweep_delay
-            else:
-                self._sweep_delay_tolerance = 0
+        delay: the target time between set calls. The actual time will not be
+            shorter than this, but may be longer if the underlying set call
+            takes longer.
 
-            # assign the setters with a sweep
-            self.set = self._validate_and_sweep
-            self.set_async = self._validate_and_sweep_async
+        max_delay: if given, the longest time allowed for the underlying set
+            call before we emit a warning.
+
+        If delay and max_delay are both None or 0, we never emit warnings
+        no matter how long the set takes.
+        '''
+        if delay is None:
+            delay = 0
+        if not isinstance(delay, (int, float)):
+            raise TypeError('delay must be a non-negative number')
+        if delay < 0:
+            raise ValueError('delay must not be negative')
+        self._delay = delay
+
+        if max_delay is not None:
+            if not isinstance(max_delay, (int, float)):
+                raise TypeError(
+                    'max_delay must be a number no shorter than delay')
+            if max_delay < delay:
+                raise ValueError('max_delay must be no shorter than delay')
+            self._delay_tolerance = max_delay - delay
         else:
-            # assign the setters as immediate jumps
-            self.set = self._validate_and_set
-            self.set_async = self._validate_and_set_async
+            self._delay_tolerance = 0
 
-        if max_val_age is not None:
-            if not isinstance(max_val_age, (int, float)):
-                raise TypeError('max_val_age must be a non-negative number')
-            if max_val_age < 0:
-                raise ValueError('max_val_age must be non-negative')
-            self._max_val_age = max_val_age
+        if not (self._delay or self._delay_tolerance):
+            # denotes that we shouldn't follow the wait code or
+            # emit any warnings
+            self._delay = None
 
 
 class ManualParameter(Parameter):
@@ -553,6 +640,9 @@ def __init__(self, name, instrument=None, initial_value=None, **kwargs):
             self.validate(initial_value)
             self._save_val(initial_value)
 
+        self.has_get = True
+        self.has_set = True
+
     def set(self, value):
         self.validate(value)
         self._save_val(value)
@@ -569,7 +659,7 @@ def get_async(self):
         return self.get()
 
 
-class GetLatest(DelegateAttributes):
+class GetLatest(DelegateAttributes, DeferredOperations):
     '''
     wrapper for a Parameter that just returns the last set or measured value
     stored in the Parameter itself.
diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index 43a2757d3fee..f6fc4869a4c9 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -1,3 +1,4 @@
+from qcodes.utils.deferred_operations import DeferredOperations
 from qcodes.utils.helpers import DelegateAttributes
 from .parameter import Parameter, GetLatest
 from .function import Function
@@ -81,6 +82,13 @@ def __getitem__(self, key):
         except KeyError:
             return self.functions[key]
 
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            str(self.name),
+            id(self))
+        return s
 
 class RemoteComponent:
     '''
@@ -108,11 +116,17 @@ def __call__(self, *args, **kwargs):
         return self._instrument.connection.ask(self.name, *args, **kwargs)
 
 
-class RemoteParameter(RemoteComponent):
+class RemoteParameter(RemoteComponent, DeferredOperations):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.get_latest = GetLatest(self)
 
+    def __call__(self, *args):
+        if len(args) == 0:
+            return self.get()
+        else:
+            self.set(*args)
+
     def get(self):
         return self._instrument.connection.ask('get', self.name)
 
@@ -135,9 +149,9 @@ def _latest(self):
         return self._instrument.connection.ask('param_call', self.name,
                                                '_latest')
 
-    def snapshot(self):
+    def snapshot(self, *args, **kwargs):
         return self._instrument.connection.ask('param_call', self.name,
-                                               'snapshot')
+                                               'snapshot',*args, **kwargs)
 
     def setattr(self, attr, value):
         self._instrument.connection.ask('param_setattr', self.name,
@@ -147,6 +161,14 @@ def getattr(self, attr):
         return self._instrument.connection.ask('param_getattr', self.name,
                                                attr)
 
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            str(self.name),
+            id(self))
+        return s
+
     # TODO: need set_sweep if it exists, and any methods a subclass defines.
 
 
@@ -159,3 +181,11 @@ def call(self, *args):
 
     def validate(self, *args):
         return Function.validate(self, *args)
+
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            str(self.name),
+            id(self))
+        return s
diff --git a/qcodes/instrument/server.py b/qcodes/instrument/server.py
index d586556c014b..61b4a932f269 100644
--- a/qcodes/instrument/server.py
+++ b/qcodes/instrument/server.py
@@ -122,10 +122,7 @@ class InstrumentConnection:
     def __init__(self, manager, instrument_class, new_id, args, kwargs):
         self.manager = manager
 
-        # long timeout on the initial call, to allow slow errors
-        # (like visa timeout) to get back to us
-        info = manager.ask('new', instrument_class, new_id, args, kwargs,
-                           timeout=20)
+        info = manager.ask('new', instrument_class, new_id, args, kwargs)
         for k, v in info.items():
             setattr(self, k, v)
 
@@ -190,7 +187,9 @@ def post_error(self, e, query=None):
         if query:
             e.args = e.args + ('error processing query ' + repr(query),)
         self._error_queue.put(format_exc())
-        self._response_queue.put(SERVER_ERR)  # to short-circuit timeout
+        # the caller is waiting on _response_queue, so put a signal there
+        # to say there's an error coming
+        self._response_queue.put(SERVER_ERR)
 
     def handle_halt(self, *args, **kwargs):
         '''
diff --git a/qcodes/instrument/sweep_values.py b/qcodes/instrument/sweep_values.py
index 768092179247..d22cfc051fd0 100644
--- a/qcodes/instrument/sweep_values.py
+++ b/qcodes/instrument/sweep_values.py
@@ -66,6 +66,14 @@ def __iter__(self):
         '''
         raise NotImplementedError
 
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            str(self.name),
+            id(self))
+        return s
+
 
 class SweepFixedValues(SweepValues):
     '''
diff --git a/qcodes/instrument/visa.py b/qcodes/instrument/visa.py
index 5d4e16f34ee6..0ac72e71c999 100644
--- a/qcodes/instrument/visa.py
+++ b/qcodes/instrument/visa.py
@@ -91,8 +91,16 @@ def check_error(self, ret_code):
             raise visa.VisaIOError(ret_code)
 
     def write(self, cmd):
-        nr_bytes_written, ret_code = self.visa_handle.write(cmd)
-        self.check_error(ret_code)
+        try:
+            nr_bytes_written, ret_code = self.visa_handle.write(cmd)
+            self.check_error(ret_code)
+        except Exception as e:
+            e.args = e.args + ('writing ' + repr(cmd) + ' to ' + repr(self),)
+            raise e
 
     def ask(self, cmd):
-        return self.visa_handle.ask(cmd)
+        try:
+            return self.visa_handle.ask(cmd)
+        except Exception as e:
+            e.args = e.args + ('asking ' + repr(cmd) + ' to ' + repr(self),)
+            raise e
diff --git a/qcodes/instrument_drivers/QuTech/IVVI.py b/qcodes/instrument_drivers/QuTech/IVVI.py
index 63fb5eefdcea..03c435c68415 100644
--- a/qcodes/instrument_drivers/QuTech/IVVI.py
+++ b/qcodes/instrument_drivers/QuTech/IVVI.py
@@ -2,6 +2,7 @@
 import logging
 import numpy as np
 import visa  # used for the parity constant
+import traceback
 
 from qcodes import VisaInstrument, validators as vals
 
@@ -13,7 +14,8 @@ class IVVI(VisaInstrument):
             - Add individual parameters for channel polarities
             - Test polarities different from BIP
             - Add adjustable range and rate protection per channel
-            - Add error handling for the specific error messages in the protocol
+            - Add error handling for the specific error messages in the
+              protocol
             - Remove/fine-tune manual sleep statements
 
     This is the python driver for the D5 module of the IVVI-rack
@@ -26,7 +28,8 @@ class IVVI(VisaInstrument):
     Fullrange = 4000
     Halfrange = Fullrange / 2
 
-    def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
+    def __init__(self, name, address, reset=False, numdacs=16, dac_step=10,
+                 dac_delay=.1, dac_max_delay=0.2, **kwargs):
                  # polarity=['BIP', 'BIP', 'BIP', 'BIP']):
                  # commented because still on the todo list
         '''
@@ -39,6 +42,9 @@ def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
             polarity (string[4]) : list of polarities of each set of 4 dacs
                                    choose from 'BIP', 'POS', 'NEG',
                                    default=['BIP', 'BIP', 'BIP', 'BIP']
+            dac_step (float)         : max step size for dac parameter
+            dac_delay (float)        : delay (in seconds) for dac
+            dac_max_delay (float)    : maximum delay before emitting a warning
         '''
         t0 = time.time()
         super().__init__(name, address, **kwargs)
@@ -70,14 +76,22 @@ def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
                 get_cmd=self._gen_ch_get_func(self._get_dac, i),
                 set_cmd=self._gen_ch_set_func(self._set_dac, i),
                 vals=vals.Numbers(-2000, 2000),
-                sweep_step=10,
-                sweep_delay=.1,
-                max_sweep_delay=.2,
+                step=dac_step,
+                delay=dac_delay,
+                max_delay=dac_max_delay,
                 max_val_age=10)
 
         self._update_time = 5  # seconds
         self._time_last_update = 0  # ensures first call will always update
         t1 = time.time()
+
+        # basic test to confirm we are properly connected
+        try:
+            self.get_all()
+        except Exception as ex:
+            print('IVVI: get_all() failed, maybe connected to wrong port?')
+            print(traceback.format_exc())
+
         print('Initialized IVVI-rack in %.2fs' % (t1-t0))
 
     def _get_version(self):
@@ -95,7 +109,9 @@ def set_dacs_zero(self):
     # Conversion of data
     def _mvoltage_to_bytes(self, mvoltage):
         '''
-        Converts a mvoltage on a 0mV-4000mV scale to a 16-bit integer equivalent
+        Converts a mvoltage on a 0mV-4000mV scale to a 16-bit integer
+        equivalent
+
         output is a list of two bytes
 
         Input:
@@ -187,7 +203,7 @@ def _get_dacs(self):
                     self._mvoltages = self._bytes_to_mvoltages(reply)
                     self._time_last_update = time.time()
                     break
-                except:
+                except Exception as ex:
                     logging.warning('IVVI communication error trying again')
             if i+1 == max_tries:  # +1 because range goes stops before end
                 raise('IVVI Communication error')
diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
new file mode 100644
index 000000000000..490b5cec7cda
--- /dev/null
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -0,0 +1,168 @@
+# Agilent_34401A.py driver for Agilent 34401A DMM
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+
+from qcodes.utils.validators import Enum, Strings, Anything
+from qcodes import VisaInstrument
+
+
+class Agilent_34400A(VisaInstrument):
+    '''
+    This is the qcodes driver for the Agilent_34400A DMM Series,
+    tested with Agilent_34401A
+
+    Status: beta-version.
+        TODO:
+        - Add all parameters that are in the manual
+        - Integration time does no value mapping
+        - Need a clear_cmd thing in the parameter
+        - Add labels
+
+    '''
+    def __init__(self, name, address, **kwargs):
+        super().__init__(name, address, terminator='\n', **kwargs)
+
+        self.add_parameter('IDN', get_cmd='*IDN?',
+                           get_parser=self._parse_idn,
+                           vals=Anything())
+        self.IDN.get()
+
+        # Async has to send 'INIT' and later ask for 'FETCH?'
+
+        self.add_parameter('volt',
+                           get_cmd='READ?',
+                           label='Voltage',
+                           get_parser=float,
+                           units='V')
+        self.add_parameter('fetch',
+                           get_cmd='FETCH?',
+                           label='Voltage',
+                           get_parser=float,
+                           units='V',
+                           snapshot_get=False,
+                           docstring=('Reads the data you asked for, i.e.'
+                                      'after an `init_measurement()` you can '
+                                      'read the data with fetch.\n'
+                                      'Do not call this when you didn\'t ask '
+                                      'for data in the first place!'))
+        self.add_parameter('NPLC',
+                           get_cmd='VOLT:NPLC?',
+                           get_parser=float,
+                           set_cmd='VOLT:NPLC {:f}',
+                           vals=Enum(0.02, 0.2, 1, 10, 100))
+        # For DC and resistance measurements, changing the number of digits
+        # does more than just change the resolution of the multimeter. It also
+        # changes the integration time!
+        # Resolution Choices          Integration Time
+        #   Fast 4 Digit                0.02 PLC
+        #   * Slow 4 Digit              1 PLC
+        #   Fast 5 Digit                0.2 PLC
+        #   * Slow 5 Digit (default)    10 PLC
+        #   * Fast 6 Digit              10 PLC
+        #   Slow 6 Digit                100 PLC
+        self.add_parameter('resolution',
+                           get_cmd='VOLT:DC:RES?',
+                           get_parser=float,
+                           set_cmd='VOLT:DC:RES {:.7f}',
+                           vals=Enum(3e-07, 1e-06, 3e-06, 1e-05, 1e-04),
+                           units='V')
+        # Integration Time    Resolutionc
+        self.add_parameter('integration_time',
+                           get_cmd='VOLT:DC:RES?',
+                           get_parser=float,
+                           set_cmd='VOLT:DC:RES {:f}',
+                           # vals=Enum(0.02,0.2,1,10,100),
+                           units='NPLC',
+                           val_mapping={0.02: 0.0001,
+                                        0.2:  0.00001,
+                                        1:    0.000003,
+                                        10:   0.000001,
+                                        100:  0.0000003})
+        self.add_parameter('terminals',
+                           get_cmd='ROUT:TERM?')
+        self.add_parameter('range_auto',
+                           get_cmd='VOLT:RANG:AUTO?',
+                           get_parser=self._onoff_parser,
+                           set_cmd='VOLT:RANG:AUTO {:d}',
+                           val_mapping={'ON': 1,
+                                        'OFF': 0,
+                                        1: 1,
+                                        0: 0})
+        self.add_parameter('range',
+                           get_cmd='SENS:VOLT:DC:RANG?',
+                           get_parser=float,
+                           set_cmd='SENS:VOLT:DC:RANG {:f}',
+                           vals=Enum(0.1, 1.0, 10.0, 100.0, 1000.0))
+
+        if self.model in ['34401A']:
+            self.add_parameter('display_text',
+                               get_cmd='DISP:TEXT?',
+                               set_cmd='DISP:TEXT "{}"',
+                               vals=Strings())
+        elif self.model in ['34410A', '34411A']:
+            self.add_parameter('display_text',
+                               get_cmd='DISP:WIND1:TEXT?',
+                               set_cmd='DISP:WIND1:TEXT "{}"',
+                               vals=Strings())
+            self.add_parameter('display_text_2',
+                               get_cmd='DISP:WIND2:TEXT?',
+                               set_cmd='DISP:WIND2:TEXT "{}"',
+                               vals=Strings())
+
+    def _parse_idn(self, msg):
+        vendor, model, serial, firmware = map(str.strip, msg.split(','))
+        self.model = model
+
+        IDN = {'vendor': vendor, 'model': model,
+               'serial': serial, 'firmware': firmware}
+        return IDN
+
+    def clear_errors(self):
+        while True:
+            err = self.ask('SYST:ERR?')
+            if 'No error' in err:
+                return
+            print(err)
+
+    def init_measurement(self):
+        self.write('INIT')
+
+    def display_clear(self):
+        if self.model in ['34401A']:
+            self.write('DISP:WIND:TEXT:CLE')
+            self.write('DISP:WIND:STAT 1')
+        elif self.model in ['34410A', '34411A']:
+            self.write('DISP:WIND1:TEXT:CLE')
+            self.write('DISP:WIND1:STAT 1')
+            self.write('DISP:WIND2:TEXT:CLE')
+            self.write('DISP:WIND2:STAT 1')
+
+    def reset(self):
+        self.write('*RST')
+
+    def _onoff_parser(self, msg):
+        if msg == '0':
+            return 'OFF'
+        elif msg == '1':
+            return 'ON'
+        return None
diff --git a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
new file mode 100644
index 000000000000..be75766dd5d0
--- /dev/null
+++ b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
@@ -0,0 +1,118 @@
+# Ithaco_1211.py driver for Ithaco 1211 Current-preamplifier
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+from qcodes import Instrument
+from qcodes.instrument.parameter import Parameter
+from qcodes.instrument.parameter import ManualParameter
+from qcodes.utils.validators import Enum, Bool, Anything
+
+
+
+class CurrentParameter(Parameter):
+    def __init__(self, measured_param, camp_ins, name='curr'):
+        p_name = measured_param.name
+        self.name = name
+        super().__init__(names=('camp_raw_'+p_name, name))
+
+        _p_label = None
+        _p_unit = None
+
+        self.measured_param = measured_param
+        self._instrument = camp_ins
+
+        if hasattr(measured_param, 'label'):
+            _p_label = measured_param.label
+        if hasattr(measured_param, 'units'):
+            _p_unit = measured_param.units
+
+        self.labels = (_p_label, 'Current')
+        self.units = (_p_unit, 'A')
+
+    def get(self):
+        volt = self.measured_param.get()
+        current = (self._instrument.sens.get() *
+                   self._instrument.sens_factor.get()) * volt
+
+        if self._instrument.invert.get():
+            current *= -1
+        return (volt, current)
+
+
+class Ithaco_1211(Instrument):
+    '''
+    dmm_parameter: The parameter used to measure the voltage output
+
+    This is the qcodes driver for the Ithaco 1211 Current-preamplifier,
+    This is a virtual driver only and will not talk to your instrument.
+    '''
+    def __init__(self, name, dmm_parameter=None, **kwargs):
+        super().__init__(name, **kwargs)
+        self.dmm_parameter = dmm_parameter
+
+        vendor = 'Ithaco (DL Instruments)'
+        model = '1211'
+        serial = None
+        firmware = None
+
+        self.add_parameter('IDN',
+                           parameter_class=ManualParameter,
+                           initial_value={'vendor': vendor, 'model': model,
+                                          'serial': serial, 'firmware': firmware},
+                           vals=Anything())
+
+        self.add_parameter('sens',
+                           parameter_class=ManualParameter,
+                           initial_value=1e-8,
+                           label='Sensitivity',
+                           units='A/V',
+                           vals=Enum(1e-11, 1e-10, 1e-09, 1e-08, 1e-07,
+                                     1e-06, 1e-05, 1e-4, 1e-3))
+
+        self.add_parameter('invert',
+                           parameter_class=ManualParameter,
+                           initial_value=True,
+                           label='Iverted output',
+                           vals=Bool())
+
+        self.add_parameter('sens_factor',
+                           parameter_class=ManualParameter,
+                           initial_value=1,
+                           label='sensitivity factor',
+                           units=None,
+                           vals=Enum(0.1, 1, 10))
+
+        self.add_parameter('suppression',
+                           parameter_class=ManualParameter,
+                           initial_value=1e-7,
+                           label='Suppression',
+                           units='A',
+                           vals=Enum(1e-10, 1e-09, 1e-08, 1e-07, 1e-06,
+                                     1e-05, 1e-4, 1e-3))
+
+        self.add_parameter('risetime',
+                           parameter_class=ManualParameter,
+                           initial_value=0.3,
+                           label='Rise Time',
+                           units='msec',
+                           vals=Enum(0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30,
+                                     100, 300, 1000))
diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS.py b/qcodes/instrument_drivers/oxford/mercuryiPS.py
new file mode 100644
index 000000000000..89419f3a0286
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS.py
@@ -0,0 +1,184 @@
+# mercuryiPS.py driver for Oxford MercuryiPS magnet power supply
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+from functools import partial
+import re
+
+from qcodes import VisaInstrument
+from qcodes.utils.validators import Strings, Enum
+
+
+class MercuryiPS(VisaInstrument):
+    '''
+    MercuryiPS Driver
+
+    This is the qcodes driver for the Oxford MercuryiPS magnet power supply.
+
+    Status: beta-version.
+        TODO:
+        - SAFETY!! we need to make sure the magnet is only ramped at certain
+          conditions!
+        - Add parameters that get data for all channels:
+          magnet.fld.get() should return [fx, fy, fz] or whatever axes are
+          available
+        - Fix this call = ''
+                   eval(call)
+          stuff, I guess there is a smarter way of doing that?
+        - this findall stuff in _get_cmd, is that smart?
+    '''
+    def __init__(self, name, axes=None, **kwargs):
+        super().__init__(name, terminator='\n', **kwargs)
+        self.axes = axes
+        self._ATOB = {}
+        self._latest_response = ''
+        # for some reason the first call is always invalid?! need some kind of init?
+        self.ask('*IDN?')
+        IDN = self.ask('*IDN?')[4:]
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':'))
+
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+
+        if axes is None:
+            self._determine_magnet_axes()
+        self._determine_current_to_field()
+
+        for ax in self.axes:
+            self.add_parameter(ax.lower()+'_fld',
+                               get_cmd=partial(self._get_fld, ax, 'FLD'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fldC',
+                               get_cmd=partial(self._get_fld_converted,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_ACTN',
+                               get_cmd=partial(self._get_cmd,
+                                               'READ:DEV:GRP{}:PSU:ACTN?'.format(ax)),
+                               set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+            self.add_parameter(ax.lower()+'_setpoint',
+                               get_cmd=partial(self._get_fld, ax, 'FSET'),
+                               set_cmd=partial(self._set_fld, ax, 'FSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_setpointC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'CSET'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'CSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_rate',
+                               get_cmd=partial(self._get_fld, ax, 'RFST'),
+                               set_cmd=partial(self._set_fld, ax, 'RFST'),
+                               units='T/m')
+            self.add_parameter(ax.lower()+'_rateC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'RCST'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'RCST'),
+                               units='T/m')
+    def hold(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("HOLD")'.format(ax.lower())
+            eval(call)
+
+    def to_zero(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOZ")'.format(ax.lower())
+            eval(call)
+
+    def _ramp_to_setpoint(self, ax, cmd, setpoint):
+        # There should be a blocking and non-blocking version of this
+        if cmd is 'CSET':
+            self._set_fld_converted(ax, cmd, setpoint)
+        elif cmd is 'FSET':
+            self._set_fld(ax, cmd, setpoint)
+        self.write('SET:DEV:GRP{}:PSU:ACTN:RTOS'.format(ax))
+
+    def _set_fld(self, ax, cmd, setpoint):
+        # Could be FSET for setpoint
+        #          RFST for rate
+        cmd = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'.format(ax, cmd, setpoint)
+        self.write(cmd)
+
+    def _get_fld(self, ax, cmd):
+        # Could be FSET for setpoint
+        #          FLD for field
+        #          RFLD for rate
+        #          PFLD persistent field reading
+        fld = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return fld
+
+    def _set_fld_converted(self, ax, cmd, setpoint):
+        # Could be CSET for setpoint
+        #          RCST for rate
+        #
+        # We set current, not field, this gives higher resolution due to
+        # limited number of digits
+        cur = setpoint * self._ATOB[ax]
+        cmd = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'.format(ax, cmd, cur)
+        self.write(cmd)
+
+    def _get_fld_converted(self, ax, cmd):
+        # Could be CSET for setpoint
+        #          CURR for field
+        #          RCUR for rate
+        #          PCUR persistent current reading
+        # We ask for current, not field, this gives higher resolution due to
+        # limited number of digits
+        # The conversion gives us a float with lots of digits, how to limit that?
+        curr = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return curr / self._ATOB[ax]
+
+    def _get_cmd(self, question, parser=None):
+        msg = self.ask(question)[len(question):]
+        # How would one macth this without specifying the units?
+        # m = re.match('STAT:DEV:GRPX:PSU:SIG:RFST:(.+?)T/m',
+        #              'STAT:DEV:GRPX:PSU:SIG:RFST:0.0200T/m')
+        # m.groups()[0]
+        if parser is float:
+            return(float(re.findall("[-+]?\d*\.\d+|\d+", msg)[0]))
+        return msg
+
+    def _float_parser(self, msg):
+        pass
+
+    def _determine_magnet_axes(self):
+        cat = self.ask('READ:SYS:CAT')
+        self.axes = re.findall('DEV:GRP(.+?):PSU', cat)
+
+    def _determine_current_to_field(self):
+        # This has a unit A/T
+        self._ATOB = {}
+        for ax in self.axes:
+            r = self._get_cmd('READ:DEV:GRP{}:PSU:ATOB?'.format(ax), float)
+            self._ATOB[ax] = r
+
+    def write(self, msg):
+        rep = self.ask(msg)
+        self._latest_response = rep
+        if 'INVALID' in rep:
+            raise Warning(rep)
diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS2.py b/qcodes/instrument_drivers/oxford/mercuryiPS2.py
new file mode 100644
index 000000000000..9f779807fe48
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS2.py
@@ -0,0 +1,461 @@
+# mercuryiPS.py driver for Oxford MercuryiPS magnet power supply
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+from functools import partial
+import re
+import time
+import numpy as np
+
+from qcodes import VisaInstrument
+from qcodes.utils.validators import Strings, Enum, Anything
+
+
+class MercuryiPS(VisaInstrument):
+    '''
+    MercuryiPS Driver
+
+    This is the qcodes driver for the Oxford MercuryiPS magnet power supply.
+
+    Status: beta-version.
+        TODO:
+        - SAFETY!! we need to make sure the magnet is only ramped at certain
+          conditions!
+        - Add parameters that get data for all channels:
+          magnet.fld.get() should return [fx, fy, fz] or whatever axes are
+          available
+        - Fix this call = ''
+                   eval(call)
+          stuff, I guess there is a smarter way of doing that?
+        - this findall stuff in _get_cmd, is that smart?
+    '''
+    def __init__(self, name, axes=None, **kwargs):
+        super().__init__(name, terminator='\n', **kwargs)
+    # def __init__(self, name, address=None, port=None, axes=None, **kwargs):
+    #     super().__init__(name, address=address, port=port, terminator='\n',
+    #                      **kwargs)
+        self.axes = axes
+        self._ATOB = {}
+        self._latest_response = ''
+        # for some reason the first call is always invalid?! need some kind of init?
+        self.ask('*IDN?')
+        IDN = self.ask('*IDN?')[4:]
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':'))
+
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+        return
+
+        if axes is None:
+            self._determine_magnet_axes()
+        self._determine_current_to_field()
+
+        self.add_parameter('setpoint',
+                           get_cmd=partial(self._get_fld, self.axes, 'FSET'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+        self.add_parameter('fld',
+                           get_cmd=partial(self._get_fld, self.axes, 'FLD'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('fldC',
+                           get_cmd=partial(self._get_fld_converted,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'CSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('rtp',
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'FLD'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'FSET'),
+                           labels=['radius', 'theta', 'phi'],
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        self.add_parameter('rtpC',
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'CSET'),
+                           labels=['radius', 'theta', 'phi'],
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        # so we have radius, theta and phi in buffer
+        self.rtp.get()
+
+        self.add_parameter('radius',
+                           get_cmd=self._get_r,
+                           set_cmd=self._set_r,
+                           label='radius',
+                           unit='|B|')
+        self.add_parameter('theta',
+                           get_cmd=self._get_theta,
+                           set_cmd=self._set_theta,
+                           label='theta',
+                           unit='rad')
+        self.add_parameter('phi',
+                           get_cmd=self._get_phi,
+                           set_cmd=self._set_phi,
+                           label='phi',
+                           unit='rad')
+
+        # self.add_parameter('ACTN',
+        #                    get_cmd=self._ACTN,
+        #                    set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+        #                    vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+        for ax in self.axes:
+            self.add_parameter(ax.lower()+'_fld',
+                               get_cmd=partial(self._get_fld, ax, 'FLD'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fldC',
+                               get_cmd=partial(self._get_fld_converted,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fld_wait',
+                               get_cmd=partial(self._get_fld_converted,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint_and_wait, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_ACTN',
+                               get_cmd=partial(self._get_cmd,
+                                               'READ:DEV:GRP{}:PSU:ACTN?'.format(ax)),
+                               set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+            self.add_parameter(ax.lower()+'_setpoint',
+                               get_cmd=partial(self._get_fld, ax, 'FSET'),
+                               set_cmd=partial(self._set_fld, ax, 'FSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_setpointC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'CSET'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'CSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_rate',
+                               get_cmd=partial(self._get_fld, ax, 'RFST'),
+                               set_cmd=partial(self._set_fld, ax, 'RFST'),
+                               units='T/m')
+            self.add_parameter(ax.lower()+'_rateC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'RCST'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'RCST'),
+                               units='T/m')
+
+    def hold(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("HOLD")'.format(ax.lower())
+            eval(call)
+
+    def rtos(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOS")'.format(ax.lower())
+            eval(call)
+
+    def to_zero(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOZ")'.format(ax.lower())
+            eval(call)
+
+    def _ACTN(self):
+        actn = self._read_cmd('ACTN', self.axes,
+                              fmt='READ:DEV:GRP{}:PSU:ACTN?')
+        return actn
+
+    def _ramp_to_setpoint(self, ax, cmd, setpoint):
+        if cmd is 'CSET':
+            self._set_fld_converted(ax, cmd, setpoint)
+        elif cmd is 'FSET':
+            self._set_fld(ax, cmd, setpoint)
+        msg = ''
+        # print(ax, cmd, setpoint)
+        # time.sleep(1)
+        # self.rtos()
+        for axis in ax:
+            msg = 'SET:DEV:GRP{}:PSU:ACTN:RTOS'.format(axis)
+            self.write(msg)
+        self.ask('')
+
+    def _ramp_to_setpoint_and_wait(self, ax, cmd, setpoint):
+        error = 0.2e-3
+        fldc = getattr(self, ax.lower()+'_fldC')
+        fldc.set(setpoint)
+        # self._ramp_to_setpoint(ax, cmd, setpoint)
+
+        while abs(fldc.get() - setpoint) > error:
+            time.sleep(0.5)
+        if setpoint == 0.0:
+            # This ensures that the magnet wont try to go hold
+            # some funny xe-5 value.
+            fld = getattr(self, ax.lower()+'_fld')
+            fld.set(setpoint)
+
+    def _set_fld(self, ax, cmd, setpoint):
+        # Could be FSET for setpoint
+        #          RFST for rate
+        msg = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'
+        if isinstance(ax, list):
+            msg2 = ''
+            for i, axis in enumerate(ax):
+                msg2 += msg.format(axis, cmd, setpoint[i])
+                msg2 += self._terminator
+                # self._set_fld_converted(axis, cmd, setpoint[i])
+            self.write(msg2)
+            return
+        msg2 = msg.format(ax, cmd, setpoint)
+        self.write(msg2)
+
+    def _get_fld(self, ax, cmd):
+        # Could be FSET for setpoint
+        #          FLD for field
+        #          RFLD for rate
+        #          PFLD persistent field reading
+        if isinstance(ax, list):
+            return [self._get_fld(axis, cmd) for axis in ax]
+        fld = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return fld
+
+    def _set_fld_converted(self, ax, cmd, setpoint):
+        # Could be CSET for setpoint
+        #          RCST for rate
+        #
+        # We set current, not field, this gives higher resolution due to
+        # limited number of digits
+        msg = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'
+        if isinstance(ax, list):
+            msg2 = ''
+            for i, axis in enumerate(ax):
+                msg2 += msg.format(axis, cmd, setpoint[i] * self._ATOB[axis])
+                msg2 += self._terminator
+                # self._set_fld_converted(axis, cmd, setpoint[i])
+            self.write(msg2)
+            return
+        cur = setpoint * self._ATOB[ax]
+        msg2 = msg.format(ax, cmd, cur)
+        self.write(msg2)
+
+    def _get_fld_converted(self, ax, cmd):
+        # Could be CSET for setpoint
+        #          CURR for field
+        #          RCUR for rate
+        #          PCUR persistent current reading
+        # We ask for current, not field, this gives higher resolution due to
+        # limited number of digits
+        # The conversion gives us a float with lots of digits, how to limit that?
+        if isinstance(ax, list):
+            fld = []
+            for axis in ax:
+                fld.append(self._get_fld_converted(axis, cmd))
+                # print(axis, cmd, fld[-1])
+            return fld
+        curr = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return curr / self._ATOB[ax]
+
+    def _get_rtp(self, ax, cmd):
+        if cmd == 'CURR':
+            fld = self._get_fld_converted(ax, cmd)
+        elif cmd == 'FLD':
+            fld = self._get_fld(ax, cmd)
+
+        sphere = self._carttosphere(fld)
+        self._radius, self._theta, self._phi = sphere
+        return sphere
+
+    def _set_rtp(self, ax, cmd, setpoint):
+        fld = self._spheretocart(setpoint)
+        self._ramp_to_setpoint(ax, cmd, fld)
+
+    def _get_r(self):
+        self.rtp.get()
+        return self._radius
+
+    def _set_r(self, val):
+        self.rtp.set([val, self._theta, self._phi])
+
+    def _get_theta(self):
+        self.rtp.get()
+        return self._theta
+
+    def _set_theta(self, val):
+        self.rtp.set([self._radius, val, self._phi])
+
+    def _get_phi(self):
+        self.rtp.get()
+        return self._phi
+
+    def _set_phi(self, val):
+        self.rtpC.set([self._radius, self._theta, val])
+
+    def _float_parser(self, msg):
+        pass
+
+    def _determine_magnet_axes(self):
+        cat = self.ask('READ:SYS:CAT')
+        self.axes = re.findall('DEV:GRP(.+?):PSU', cat)
+
+    def _determine_current_to_field(self):
+        # This has a unit A/T
+        self._ATOB = {}
+        for ax in self.axes:
+            r = self._get_cmd('READ:DEV:GRP{}:PSU:ATOB?'.format(ax), float)
+            self._ATOB[ax] = r
+
+    def _read_cmd(self, cmd, axes, parser=None, fmt='READ:DEV:GRP{}:PSU:SIG:{}?'):
+        msg = ''
+        msglist = []
+        for axis in axes:
+            msglist.append(fmt.format(axis, cmd))
+        msg = '\n'.join(msglist)
+
+        rep = self.ask(msg)
+        data = [None] * len(axes)
+        for i in range(20):
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[5:-1] in rep:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                # print(msg)
+                                return None
+                        data[ix] = val
+                    if all(data):
+                        break
+                if all(data):
+                    break
+            if all(data):
+                break
+            rep = self.ask('')
+
+        return data
+
+    def _write_cmd(self, cmd, axes, setpoint, fmt='SET:DEV:GRP{}:PSU:SIG:{}:{:6f}', parser=None):
+        msg = ''
+        msglist = []
+        for ix, axis in enumerate(axes):
+            msglist.append(fmt.format(axis, cmd, setpoint[ix]))
+        msg = '\n'.join(msglist)
+        rep = self.ask(msg)
+        data = [None] * len(axes)
+        for i in range(20):
+            print(rep)
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[-1] in rep:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                # print(msg)
+                                return None
+                        data[ix] = val
+                    if all(data):
+                        break
+                if all(data):
+                    break
+            if all(data):
+                break
+            rep = self.ask('')
+        print(data)
+        # return data
+
+
+
+    def _get_cmd(self, question, parser=None):
+        # print(question)
+        rep = self.ask(question)
+        # print(rep)
+        # print()
+        self._latest_response = rep
+        msg = rep[len(question):]
+        # How would one macth this without specifying the units?
+        # m = re.match('STAT:DEV:GRPX:PSU:SIG:RFST:(.+?)T/m',
+        #              'STAT:DEV:GRPX:PSU:SIG:RFST:0.0200T/m')
+        # m.groups()[0]
+        if parser is float:
+            try:
+                return(float(re.findall("[-+]?\d*\.\d+|\d+", msg)[0]))
+            except:
+                # print(msg)
+                return None
+        return msg.strip()
+
+    def write(self, msg):
+        rep = self.ask(msg)
+        self._latest_response = rep
+        if 'INVALID' in rep:
+            print('warning', msg, rep)
+
+    def ask(self, msg):
+        mc = msg.count(self._terminator)
+        rep = super().ask(msg)
+        for i in range(20):
+            # print(rep)
+            if not rep.startswith(':INVALID'):
+                for n in range(mc):
+                    rep2 = super().ask('')
+                    if 'INVALID' in rep2:
+                        break
+                    rep += self._terminator
+                    rep += rep2
+                break
+            rep = super().ask('')
+
+        return rep
+
+    def _spheretocart(self, sphere):
+        """
+        r,  theta,  phi = sphere
+        """
+        r,  theta,  phi = sphere
+        x = (r * np.sin(theta) * np.cos(phi))
+        y = (r * np.sin(theta) * np.sin(phi))
+        z = (r * np.cos(theta))
+        return [x,  y,  z]
+
+    def _carttosphere(self, field):
+        field = np.array(field)
+        r = np.sqrt(np.sum(field**2))
+        if r == 0:
+            theta = 0
+            phi = 0
+        else:
+            theta = np.arccos(field[2] / r);
+            phi = np.arctan2(field[1],  field[0])
+        return [r, theta, phi]
diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS3.py b/qcodes/instrument_drivers/oxford/mercuryiPS3.py
new file mode 100644
index 000000000000..0e67914836ed
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS3.py
@@ -0,0 +1,420 @@
+# mercuryiPS.py driver for Oxford MercuryiPS magnet power supply
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+from functools import partial
+import re
+import time
+import numpy as np
+
+from qcodes import IPInstrument
+from qcodes.utils.validators import Strings, Enum, Anything
+
+
+class MercuryiPS(IPInstrument):
+    '''
+    MercuryiPS Driver
+
+    This is the qcodes driver for the Oxford MercuryiPS magnet power supply.
+
+    Status: beta-version.
+        TODO:
+        - SAFETY!! we need to make sure the magnet is only ramped at certain
+          conditions!
+        - make ATOB a parameter, and move all possible to use _read_cmd, _write_cmd
+        - Fix this call = ''
+                   eval(call)
+          stuff, I guess there is a smarter way of doing that?
+        - this findall stuff in _get_cmd, is that smart?
+    '''
+    # def __init__(self, name, axes=None, **kwargs):
+    #     super().__init__(name, terminator='\n', **kwargs)
+    def __init__(self, name, address=None, port=None, axes=None, **kwargs):
+        super().__init__(name, address=address, port=port, terminator='\n',
+                         **kwargs)
+        self.axes = axes
+        self._ATOB = []
+        self._latest_response = ''
+        # for some reason the first call is always invalid?! need some kind of init?
+        self.ask('*IDN?')
+        IDN = self.ask('*IDN?')[4:]
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':'))
+
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+
+        if axes is None:
+            self._determine_magnet_axes()
+        self._determine_current_to_field()
+
+        self.add_parameter('setpoint',
+                           names=['B'+ax.lower()+'_setpoint' for ax in self.axes],
+                           get_cmd=partial(self._get_fld, self.axes, 'FSET'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('rate',
+                           names=['rate_B'+ax.lower() for ax in self.axes],
+                           get_cmd=partial(self._get_fld, self.axes, 'RFST'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'RFST'),
+                           units=['T/m'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('fld',
+                           names=['B'+ax.lower() for ax in self.axes],
+                           get_cmd=partial(self._get_fld, self.axes, 'FLD'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('fldC',
+                           names=['B'+ax.lower() for ax in self.axes],
+                           get_cmd=partial(self._get_fld,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'CSET'),
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('rtp',
+                           names=['radius', 'theta', 'phi'],
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'FLD'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'FSET'),
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        self.add_parameter('rtpC',
+                           names=['radius', 'theta', 'phi'],
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'CSET'),
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        # so we have radius, theta and phi in buffer
+        self.rtp.get()
+
+        self.add_parameter('radius',
+                           get_cmd=self._get_r,
+                           set_cmd=self._set_r,
+                           units='|B|')
+        self.add_parameter('theta',
+                           get_cmd=self._get_theta,
+                           set_cmd=self._set_theta,
+                           units='rad')
+        self.add_parameter('phi',
+                           get_cmd=self._get_phi,
+                           set_cmd=self._set_phi,
+                           units='rad')
+
+        # self.add_parameter('ACTN',
+        #                    get_cmd=self._ACTN,
+        #                    set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+        #                    vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+        for ax in self.axes:
+            self.add_parameter(ax.lower()+'_fld',
+                               get_cmd=partial(self._get_fld, ax, 'FLD'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fldC',
+                               get_cmd=partial(self._get_fld,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fld_wait',
+                               get_cmd=partial(self._get_fld,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint_and_wait, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_ACTN',
+                               get_cmd=partial(self._get_cmd,
+                                               'READ:DEV:GRP{}:PSU:ACTN?'.format(ax)),
+                               set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+            self.add_parameter(ax.lower()+'_setpoint',
+                               get_cmd=partial(self._get_fld, ax, 'FSET'),
+                               set_cmd=partial(self._set_fld, ax, 'FSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_setpointC',
+                               get_cmd=partial(self._get_fld, ax, 'CSET'),
+                               set_cmd=partial(self._set_fld, ax, 'CSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_rate',
+                               get_cmd=partial(self._get_fld, ax, 'RFST'),
+                               set_cmd=partial(self._set_fld, ax, 'RFST'),
+                               units='T/m')
+            self.add_parameter(ax.lower()+'_rateC',
+                               get_cmd=partial(self._get_fld, ax, 'RCST'),
+                               set_cmd=partial(self._set_fld, ax, 'RCST'),
+                               units='T/m')
+
+    def hold(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("HOLD")'.format(ax.lower())
+            eval(call)
+
+    def rtos(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOS")'.format(ax.lower())
+            eval(call)
+
+    def to_zero(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOZ")'.format(ax.lower())
+            eval(call)
+
+    def _ACTN(self):
+        actn = self._read_cmd('ACTN', self.axes,
+                              fmt='READ:DEV:GRP{}:PSU:ACTN?')
+        return actn
+
+    def _ramp_to_setpoint(self, ax, cmd, setpoint):
+        # if cmd is 'CSET':
+        #     self._set_fld(ax, cmd, setpoint)
+        # elif cmd is 'FSET':
+        #     self._set_fld(ax, cmd, setpoint)
+        self._set_fld(ax, cmd, setpoint)
+        msg = ''
+        # print(ax, cmd, setpoint)
+        # time.sleep(1)
+        # self.rtos()
+        for axis in ax:
+            msg = 'SET:DEV:GRP{}:PSU:ACTN:RTOS'.format(axis)
+            self.write(msg)
+        # self.ask('')
+
+    def _ramp_to_setpoint_and_wait(self, ax, cmd, setpoint):
+        error = 0.2e-3
+        fldc = getattr(self, ax.lower()+'_fldC')
+        fldc.set(setpoint)
+        # self._ramp_to_setpoint(ax, cmd, setpoint)
+
+        while abs(fldc.get() - setpoint) > error:
+            time.sleep(0.5)
+        if setpoint == 0.0:
+            # This ensures that the magnet wont try to go hold
+            # some funny xe-5 value.
+            fld = getattr(self, ax.lower()+'_fld')
+            fld.set(setpoint)
+
+    def _set_fld(self, ax, cmd, setpoint):
+        # Could be FSET for setpoint
+        #          RFST for rate
+        if not isinstance(setpoint, list):
+            setpoint = [setpoint]
+        if cmd in ['CSET', 'RCST', 'CURR', 'PCUR', 'RCUR']:
+            setpoint = np.array(self._ATOB) * np.array(setpoint)
+            # print('a', setpoint)
+
+        if len(ax) == 1:
+            # print('b', self.axes.index(ax))
+            setpoint = setpoint[self.axes.index(ax)]
+            # print('c', setpoint)
+
+        # print('d', ax, cmd, setpoint)
+        msg = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'
+        # print('e', msg)
+        self._write_cmd(cmd, ax, setpoint, msg)
+
+    def _get_fld(self, ax, cmd):
+        # Could be FSET for setpoint
+        #          FLD for field
+        #          RFLD for rate
+        #          PFLD persistent field reading
+        fld = list(self._read_cmd(cmd, ax, float))
+
+        if cmd in ['CSET', 'RCST', 'CURR', 'PCUR', 'RCUR']:
+            fld = np.array(fld) / np.array(self._ATOB)
+
+        # print(ax, cmd, fld)
+        if len(ax) == 1:
+            return fld[self.axes.index(ax)]
+        return list(fld)
+
+    def _get_rtp(self, ax, cmd):
+        fld = self._get_fld(ax, cmd)
+        sphere = self._carttosphere(fld)
+        self._radius, self._theta, self._phi = sphere
+        return sphere
+
+    def _set_rtp(self, ax, cmd, setpoint):
+        fld = self._spheretocart(setpoint)
+        self._ramp_to_setpoint(ax, cmd, fld)
+
+    def _get_r(self):
+        self.rtp.get()
+        return self._radius
+
+    def _set_r(self, val):
+        self.rtp.set([val, self._theta, self._phi])
+
+    def _get_theta(self):
+        self.rtp.get()
+        return self._theta
+
+    def _set_theta(self, val):
+        self.rtp.set([self._radius, val, self._phi])
+
+    def _get_phi(self):
+        self.rtp.get()
+        return self._phi
+
+    def _set_phi(self, val):
+        self.rtpC.set([self._radius, self._theta, val])
+
+    def _determine_magnet_axes(self):
+        cat = self.ask('READ:SYS:CAT')
+        self.axes = re.findall('DEV:GRP(.+?):PSU', cat)
+
+    def _determine_current_to_field(self):
+        # This has a unit A/T
+        self._ATOB = []
+        for ax in self.axes:
+            r = self._get_cmd('READ:DEV:GRP{}:PSU:ATOB?'.format(ax), float)
+            self._ATOB.append(r)
+
+    def _read_cmd(self, cmd, axes, parser=None, fmt=None):
+        fmt = fmt or 'READ:DEV:GRP{}:PSU:SIG:{}?'
+        msg = ''
+        msglist = []
+        for axis in axes:
+            msglist.append(fmt.format(axis, cmd))
+        msg = '\n'.join(msglist)
+        self._send(msg)
+        rep = self._recv()
+        data = [None] * len(axes)
+        for i in range(20):
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[5:-1] in ln:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                continue
+                        data[ix] = val
+                    if not (None in data):
+                        return data
+            rep = self._recv()
+        return data
+
+    def _write_cmd(self, cmd, axes, setpoint, fmt=None, parser=None):
+        fmt = fmt or 'SET:DEV:GRP{}:PSU:SIG:{}:{:4f}'
+        msg = ''
+        msglist = []
+        if len(axes) == 1:
+            setpoint = [setpoint]
+        for ix, axis in enumerate(axes):
+            msglist.append(fmt.format(axis, cmd, setpoint[ix]))
+        msg = '\n'.join(msglist)
+        self._send(msg)
+        rep = self._recv()
+        data = [None] * len(axes)
+        for i in range(20):
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[5:-1] in ln:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                continue
+                        data[ix] = val
+                    if not (None in data):
+                        return data
+            rep = self._recv()
+        # print(data)
+
+    def _get_cmd(self, question, parser=None):
+        # print(question)
+        rep = self.ask(question)
+        # print(rep)
+        # print()
+        self._latest_response = rep
+        msg = rep[len(question):]
+        # How would one macth this without specifying the units?
+        # m = re.match('STAT:DEV:GRPX:PSU:SIG:RFST:(.+?)T/m',
+        #              'STAT:DEV:GRPX:PSU:SIG:RFST:0.0200T/m')
+        # m.groups()[0]
+        if parser is float:
+            try:
+                return(float(re.findall("[-+]?\d*\.\d+|\d+", msg)[0]))
+            except:
+                # print(msg)
+                return None
+        return msg.strip()
+
+    def write(self, msg):
+        rep = self.ask(msg)
+        self._latest_response = rep
+        if 'INVALID' in rep:
+            print('warning', msg, rep)
+
+    # def ask(self, msg):
+    #     mc = msg.count(self._terminator)
+    #     rep = super().ask(msg)
+    #     for i in range(20):
+    #         # print(rep)
+    #         if not rep.startswith(':INVALID'):
+    #             for n in range(mc):
+    #                 rep2 = super().ask('')
+    #                 if 'INVALID' in rep2:
+    #                     break
+    #                 rep += self._terminator
+    #                 rep += rep2
+    #             break
+    #         rep = super().ask('')
+
+    #     return rep
+
+    def _spheretocart(self, sphere):
+        """
+        r,  theta,  phi = sphere
+        """
+        r,  theta,  phi = sphere
+        x = (r * np.sin(theta) * np.cos(phi))
+        y = (r * np.sin(theta) * np.sin(phi))
+        z = (r * np.cos(theta))
+        return [x,  y,  z]
+
+    def _carttosphere(self, field):
+        field = np.array(field)
+        r = np.sqrt(np.sum(field**2))
+        if r == 0:
+            theta = 0
+            phi = 0
+        else:
+            theta = np.arccos(field[2] / r);
+            phi = np.arctan2(field[1],  field[0])
+        return [r, theta, phi]
diff --git a/qcodes/instrument_drivers/oxford/triton.py b/qcodes/instrument_drivers/oxford/triton.py
new file mode 100644
index 000000000000..9ba16699048d
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/triton.py
@@ -0,0 +1,152 @@
+# triton.py driver for Oxford Triton fridges
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+import configparser
+from qcodes import IPInstrument
+
+
+class Triton(IPInstrument):
+    '''
+    Triton Driver
+    TODO: fetch registry directly from fridge-computer
+
+    Comment from Merlin:
+        I had to change the IP instrument, somehow the port does not get
+        transferred to the socket connection
+        And I had other problems with the _connect method,
+          check those changes :)
+        Further there was a problem with the EnsureConnection class
+    '''
+
+    def __init__(self, name, address=None, port=None, terminator='\r\n',
+                 tmpfile=None, **kwargs):
+        super().__init__(name, address=address, port=port,
+                         terminator=terminator, **kwargs)
+
+        IDN = self.ask('*IDN?')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':')[1:])
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+
+        self.add_parameter(name='time',
+                           label='System Time',
+                           units='',
+                           get_cmd='READ:SYS:TIME',
+                           get_parser=self._parse_time)
+
+        self.add_parameter(name='action',
+                           label='Current action',
+                           units='',
+                           get_cmd='READ:SYS:DR:ACTN',
+                           get_parser=self._parse_action)
+
+        self.add_parameter(name='status',
+                           label='Status',
+                           units='',
+                           get_cmd='READ:SYS:DR:STATUS',
+                           get_parser=self._parse_status)
+
+        self.chan_alias = {}
+        self.chan_temps = {}
+        if tmpfile is not None:
+            self._get_temp_channels(tmpfile)
+        self.get_pressure_channels()
+        self._get_named_channels()
+
+    def _get_named_channels(self):
+        allchans = self.ask('READ:SYS:DR:CHAN')
+        allchans = allchans.replace('STAT:SYS:DR:CHAN:', '', 1).split(':')
+        for ch in allchans:
+            msg = 'READ:SYS:DR:CHAN:%s' % ch
+            rep = self.ask(msg)
+            if 'INVALID' not in rep:
+                alias, chan = rep.split(':')[-2:]
+                self.chan_alias[alias] = chan
+                self.add_parameter(name=alias,
+                                   units='K',
+                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP' % chan,
+                                   get_parser=self._parse_temp)
+
+    def get_pressure_channels(self):
+        for i in range(1, 7):
+            chan = 'P%d' % i
+            self.add_parameter(name=chan,
+                               units='bar',
+                               get_cmd='READ:DEV:%s:PRES:SIG:PRES' % chan,
+                               get_parser=self._parse_pres)
+
+    def _get_temp_channels(self, file):
+        config = configparser.ConfigParser()
+        with open(file, 'r') as f:
+            next(f)
+            config.read_file(f)
+
+        for section in config.sections():
+            options = config.options(section)
+            namestr = '"m_lpszname"'
+            if namestr in options:
+                chan = 'T'+section.split('\\')[-1].split('[')[-1]
+                name = config.get(section, '"m_lpszname"').strip("\"")
+                self.chan_temps[chan] = {'name': name, 'value': None}
+                self.add_parameter(name=chan,
+                                   units='K',
+                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP' % chan,
+                                   get_parser=self._parse_temp)
+
+    def _parse_action(self, msg):
+        action = msg[17:]
+        if action == 'PCL':
+            action = 'Precooling'
+        elif action == 'EPCL':
+            action = 'Empty precool loop'
+        elif action == 'COND':
+            action = 'Condensing'
+        elif action == 'NONE':
+            if self.MC.get() < 2:
+                action = 'Circulating'
+            else:
+                action = 'Idle'
+        elif action == 'COLL':
+            action = 'Collecting mixture'
+        else:
+            action = 'Unknown'
+        return action
+
+    def _parse_status(self, msg):
+        return msg[19:]
+
+    def _parse_time(self, msg):
+        return msg[14:]
+
+    def _parse_temp(self, msg):
+        if 'NOT_FOUND' in msg:
+            return None
+        return float(msg.split('SIG:TEMP:')[-1].strip('K'))
+
+    def _parse_pres(self, msg):
+        if 'NOT_FOUND' in msg:
+            return None
+        return float(msg.split('SIG:PRES:')[-1].strip('mB'))*1e3
+
+    def _recv(self):
+        return super()._recv().rstrip()
diff --git a/qcodes/instrument_drivers/stanford_research/SR_560.py b/qcodes/instrument_drivers/stanford_research/SR_560.py
new file mode 100644
index 000000000000..98713f86c21a
--- /dev/null
+++ b/qcodes/instrument_drivers/stanford_research/SR_560.py
@@ -0,0 +1,107 @@
+# sr_560.py driver for SR 560 Voltage-preamplifier
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+from qcodes import Instrument
+from qcodes.instrument.parameter import ManualParameter
+from qcodes.utils.validators import Enum, Bool, Anything, Numbers
+
+from qcodes.instrument.parameter import Parameter
+
+
+class VoltageParameter(Parameter):
+    def __init__(self, measured_param, vamp_ins, name='volt'):
+        p_name = measured_param.name
+        self.name = name
+        super().__init__(names=('vamp_raw_'+p_name, name))
+
+        _p_label = None
+        _p_unit = None
+
+        self.measured_param = measured_param
+        self._instrument = vamp_ins
+
+        if hasattr(measured_param, 'label'):
+            _p_label = measured_param.label
+        if hasattr(measured_param, 'units'):
+            _p_unit = measured_param.units
+
+        self.labels = (_p_label, 'Voltage')
+        self.units = (_p_unit, 'V')
+
+    def get(self):
+        volt = self.measured_param.get()
+        volt_amp = (volt / self._instrument.gain.get())
+
+        if self._instrument.invert.get():
+            volt_amp *= -1
+        return (volt, volt_amp)
+
+
+class SR_560(Instrument):
+    '''
+    dmm_parameter: The parameter used to measure the voltage output
+
+    This is the qcodes driver for the SR 560 Voltage-preamplifier,
+    This is a virtual driver only and will not talk to your instrument.
+    '''
+    def __init__(self, name, dmm_parameter=None, **kwargs):
+        super().__init__(name, **kwargs)
+        self.dmm_parameter = dmm_parameter
+
+        vendor = 'Stanford Research Systems'
+        model = 'SR560'
+        serial = None
+        firmware = None
+
+        self.add_parameter('IDN',
+                           parameter_class=ManualParameter,
+                           initial_value={'vendor': vendor, 'model': model,
+                                          'serial': serial, 'firmware': firmware},
+                           vals=Anything())
+
+        self.add_parameter('cutoff_lo',
+                           parameter_class=ManualParameter,
+                           initial_value='DC',
+                           label='High pass',
+                           units='Hz',
+                           vals=Anything())
+
+        self.add_parameter('cutoff_hi',
+                           parameter_class=ManualParameter,
+                           initial_value='1e6',
+                           label='Low pass',
+                           units='Hz',
+                           vals=Anything())
+
+        self.add_parameter('invert',
+                           parameter_class=ManualParameter,
+                           initial_value=True,
+                           label='Iverted output',
+                           vals=Bool())
+
+        self.add_parameter('gain',
+                           parameter_class=ManualParameter,
+                           initial_value=10,
+                           label='gain',
+                           units=None,
+                           vals=Numbers())
diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index c34798932290..679bbcd4d537 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -23,10 +23,15 @@
 from io import BytesIO
 import os
 import logging
+import array as arr
 
 from qcodes import VisaInstrument, validators as vals
 
 
+def parsestr(v):
+    return v.strip().strip('"')
+
+
 class Tektronix_AWG5014(VisaInstrument):
     '''
     This is the python driver for the Tektronix AWG5014
@@ -47,7 +52,7 @@ class Tektronix_AWG5014(VisaInstrument):
 
     CHANGES:
     26-11-2008 by Gijs: Copied this plugin from the 520 and added support for
-        2 more channels, added setget marker delay functions and increased max
+        2 more channels, added set get marker delay functions and increased max
         sampling freq to 1.2 	GS/s
     28-11-2008 ''  '' : Added some functionality to manipulate and manoeuvre
         through the folders on the AWG
@@ -85,37 +90,56 @@ class Tektronix_AWG5014(VisaInstrument):
         'INTERLEAVE_ADJ_AMPLITUDE': 'd',
     }
     AWG_FILE_FORMAT_CHANNEL = {
-        'OUTPUT_WAVEFORM_NAME_N': 's',  # Include NULL.(Output Waveform Name for Non-Sequence mode)
+        # Include NULL.(Output Waveform Name for Non-Sequence mode)
+        'OUTPUT_WAVEFORM_NAME_N': 's',
         'CHANNEL_STATE_N': 'h',  # On | Off
         'ANALOG_DIRECT_OUTPUT_N': 'h',  # On | Off
         'ANALOG_FILTER_N': 'h',  # Enum type.
         'ANALOG_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'ANALOG_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'ANALOG_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'ANALOG_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'ANALOG_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'ANALOG_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'ANALOG_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'ANALOG_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'ANALOG_LOW_N': 'd',
         'MARKER1_SKEW_N': 'd',
         'MARKER1_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'MARKER1_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER1_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER1_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'MARKER1_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER1_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER1_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER1_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER1_LOW_N': 'd',
         'MARKER2_SKEW_N': 'd',
         'MARKER2_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'MARKER2_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER2_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER2_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'MARKER2_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER2_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER2_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER2_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER2_LOW_N': 'd',
         'DIGITAL_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'DIGITAL_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'DIGITAL_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'DIGITAL_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'DIGITAL_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'DIGITAL_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'DIGITAL_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'DIGITAL_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'DIGITAL_LOW_N': 'd',
         'EXTERNAL_ADD_N': 'h',  # AWG5000 only
         'PHASE_DELAY_INPUT_METHOD_N':   'h',  # Phase/DelayInme/DelayInints
         'PHASE_N': 'd',  # When the Input Method is not Phase, it is skipped.
-        'DELAY_IN_TIME_N': 'd',  # When the Input Method is not DelayInTime, it is skipped.
-        'DELAY_IN_POINTS_N': 'd',  # When the Input Method is not DelayInPoint, it is skipped.
+        # When the Input Method is not DelayInTime, it is skipped.
+        'DELAY_IN_TIME_N': 'd',
+        # When the Input Method is not DelayInPoint, it is skipped.
+        'DELAY_IN_POINTS_N': 'd',
         'CHANNEL_SKEW_N': 'd',
         'DC_OUTPUT_LEVEL_N': 'd',  # V
     }
@@ -129,7 +153,7 @@ def __init__(self, name, setup_folder, address, reset=False,
             name (string)           : name of the instrument
             setup_folder (string)   : folder where externally generate seqs
                                         are stored
-            address (string)        : GPIB address
+            address (string)        : GPIB or ethernet address
             reset (bool)            : resets to default values, default=false
             numpoints (int)         : sets the number of datapoints
 
@@ -163,40 +187,42 @@ def __init__(self, name, setup_folder, address, reset=False,
                            vals=vals.Enum('CONT', 'TRIG', 'SEQ', 'GAT'))
         self.add_parameter('trigger_impedance',
                            label='Trigger impedance (Ohm)',
+                           units='Ohm',
                            get_cmd='TRIG:IMP?',
-                           set_cmd='TRIG:IMP '+'{}',
+                           set_cmd='TRIG:IMP ' + '{}',
                            vals=vals.Enum(50, 1000),
                            get_parser=float)
         self.add_parameter('trigger_level',
+                           units='V',
                            label='Trigger level (V)',
                            get_cmd='TRIG:LEV?',
-                           set_cmd='TRIG:LEV '+'{:.3f}',
+                           set_cmd='TRIG:LEV ' + '{:.3f}',
                            vals=vals.Numbers(-5, 5),
                            get_parser=float)
         self.add_parameter('trigger_slope',
                            get_cmd='TRIG:SLOP?',
-                           set_cmd='TRIG:SLOP '+'{}',
-                           vals=vals.Enum('POS', 'NEG'))#,
+                           set_cmd='TRIG:SLOP ' + '{}',
+                           vals=vals.Enum('POS', 'NEG'))  # ,
                            # get_parser=self.parse_int_pos_neg)
         self.add_parameter('trigger_source',
                            get_cmd='TRIG:source?',
-                           set_cmd='TRIG:source '+'{}',
+                           set_cmd='TRIG:source ' + '{}',
                            vals=vals.Enum('INT', 'EXT'))
         # Event parameters #
         self.add_parameter('event_polarity',
                            get_cmd='EVEN:POL?',
-                           set_cmd='EVEN:POL '+'{}',
+                           set_cmd='EVEN:POL ' + '{}',
                            vals=vals.Enum('POS', 'NEG'))
         self.add_parameter('event_impedance',
                            label='Event impedance (Ohm)',
                            get_cmd='EVEN:IMP?',
-                           set_cmd='EVEN:IMP '+'{}',
+                           set_cmd='EVEN:IMP ' + '{}',
                            vals=vals.Enum(50, 1000),
                            get_parser=float)
         self.add_parameter('event_level',
                            label='Event level (V)',
                            get_cmd='EVEN:LEV?',
-                           set_cmd='EVEN:LEV '+'{:.3f}',
+                           set_cmd='EVEN:LEV ' + '{:.3f}',
                            vals=vals.Numbers(-5, 5),
                            get_parser=float)
         self.add_parameter('event_jump_timing',
@@ -207,7 +233,7 @@ def __init__(self, name, setup_folder, address, reset=False,
         self.add_parameter('clock_freq',
                            label='Clock frequency (Hz)',
                            get_cmd='SOUR:FREQ?',
-                           set_cmd='SOUR:FREQ '+'{}',
+                           set_cmd='SOUR:FREQ ' + '{}',
                            vals=vals.Numbers(1e6, 1.2e9),
                            get_parser=float)
 
@@ -228,24 +254,33 @@ def __init__(self, name, setup_folder, address, reset=False,
             amp_cmd = 'SOUR{}:VOLT:LEV:IMM:AMPL'.format(i)
             offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(i)
             state_cmd = 'OUTPUT{}:STATE'.format(i)
+            waveform_cmd = 'SOUR{}:WAV'.format(i)
             # Set channel first to ensure sensible sorting of pars
             self.add_parameter('ch{}_state'.format(i),
                                label='Status channel {}'.format(i),
-                               get_cmd=state_cmd+'?',
-                               set_cmd=state_cmd+' {}',
+                               get_cmd=state_cmd + '?',
+                               set_cmd=state_cmd + ' {}',
                                vals=vals.Ints(0, 1))
             self.add_parameter('ch{}_amp'.format(i),
                                label='Amplitude channel {} (V)'.format(i),
+                               units='V',
                                get_cmd=amp_cmd + '?',
                                set_cmd=amp_cmd + ' {:.6f}',
                                vals=vals.Numbers(0.02, 1.5),
                                get_parser=float)
             self.add_parameter('ch{}_offset'.format(i),
                                label='Offset channel {} (V)'.format(i),
+                               units='V',
                                get_cmd=offset_cmd + '?',
                                set_cmd=offset_cmd + ' {:.3f}',
                                vals=vals.Numbers(-.1, .1),
                                get_parser=float)
+            self.add_parameter('ch{}_waveform'.format(i),
+                               label='Waveform channel {}'.format(i),
+                               get_cmd=waveform_cmd + '?',
+                               set_cmd=waveform_cmd + ' "{}"',
+                               vals=vals.Strings(),
+                               get_parser=parsestr)
             # Marker channels
             for j in range(1, 3):
                 m_del_cmd = 'SOUR{}:MARK{}:DEL'.format(i, j)
@@ -256,21 +291,21 @@ def __init__(self, name, setup_folder, address, reset=False,
                     'ch{}_m{}_del'.format(i, j),
                     label='Channel {} Marker {} delay (ns)'.format(i, j),
                     get_cmd=m_del_cmd + '?',
-                    set_cmd=m_del_cmd + '{:.3f}e-9',
+                    set_cmd=m_del_cmd + ' {:.3f}e-9',
                     vals=vals.Numbers(0, 1),
                     get_parser=float)
                 self.add_parameter(
                     'ch{}_m{}_high'.format(i, j),
                     label='Channel {} Marker {} high level (V)'.format(i, j),
                     get_cmd=m_high_cmd + '?',
-                    set_cmd=m_high_cmd + '{:.3f}',
+                    set_cmd=m_high_cmd + ' {:.3f}',
                     vals=vals.Numbers(-2.7, 2.7),
                     get_parser=float)
                 self.add_parameter(
                     'ch{}_m{}_low'.format(i, j),
                     label='Channel {} Marker {} low level (V)'.format(i, j),
                     get_cmd=m_low_cmd + '?',
-                    set_cmd=m_low_cmd + '{:.3f}',
+                    set_cmd=m_low_cmd + ' {:.3f}',
                     vals=vals.Numbers(-2.7, 2.7),
                     get_parser=float)
 
@@ -515,8 +550,9 @@ def set_sq_length(self, seq_length):
     def set_sqel_event_jump_target_index(self, element_no, jtar_index_no):
         self.write('SEQ:ELEM%s:JTAR:INDex %s' % (element_no, jtar_index_no))
 
-    def set_sqel_event_jump_type(self, element_no,jtar_state):
-        self.write('SEQuence:ELEMent%s:JTAR:TYPE %s' % (element_no, jtar_state))
+    def set_sqel_event_jump_type(self, element_no, jtar_state):
+        self.write('SEQuence:ELEMent%s:JTAR:TYPE %s' %
+                   (element_no, jtar_state))
 
     def get_sq_mode(self):
         return self.ask('AWGC:SEQ:TYPE?')
@@ -550,33 +586,33 @@ def _load_new_style(self, wfname_l, nrep_l, wait_l, goto_l, logic_jump_l):
         '''
         load sequence not using sequence file
         '''
-        self.set_sq_length(0) # delete prev seq
-        #print wfname_l
+        self.set_sq_length(0)  # delete prev seq
+        # print wfname_l
         len_sq = len(nrep_l)
         self.set_sq_length(len_sq)
         n_ch = len(wfname_l)
         for k in range(len_sq):
-            #wfname_l[k]
-            #print k
+            # wfname_l[k]
+            # print k
             for n in range(n_ch):
-                #print n
-                #print wfname_l[n][k]
+                # print n
+                # print wfname_l[n][k]
                 if wfname_l[n][k] is not None:
 
-                    self.set_sqel_waveform(wfname_l[n][k], n+1, k+1)
-            self.set_sqel_trigger_wait(k+1, int(wait_l[k]!=0))
-            self.set_sqel_loopcnt_to_inf(k+1, False)
-            self.set_sqel_loopcnt(nrep_l[k],k+1)
+                    self.set_sqel_waveform(wfname_l[n][k], n + 1, k + 1)
+            self.set_sqel_trigger_wait(k + 1, int(wait_l[k] != 0))
+            self.set_sqel_loopcnt_to_inf(k + 1, False)
+            self.set_sqel_loopcnt(nrep_l[k], k + 1)
             qt.msleep()
-            if  goto_l[k] == 0:
-                self.set_sqel_goto_state(k+1, False)
+            if goto_l[k] == 0:
+                self.set_sqel_goto_state(k + 1, False)
             else:
-                self.set_sqel_goto_state(k+1, True)
-                self.set_sqel_goto_target_index(k+1, goto_l[k])
+                self.set_sqel_goto_state(k + 1, True)
+                self.set_sqel_goto_target_index(k + 1, goto_l[k])
             if logic_jump_l[k] == -1:
-                self.set_sqel_event_target_index_next(k+1)
+                self.set_sqel_event_target_index_next(k + 1)
             else:
-                self.set_sqel_event_target_index(k+1, logic_jump_l[k])
+                self.set_sqel_event_target_index(k + 1, logic_jump_l[k])
 
     def _load_old_style(self, wfs, rep, wait, goto, logic_jump, filename):
         '''
@@ -618,7 +654,7 @@ def _import_and_load_waveform_file_to_channel(self, channel_no,
         while not (self.visa_handle.ask("sour%s:wav?" % channel_no)
                    == '"%s"' % waveform_listname):
             sleep(0.01)
-            i = i+1
+            i = i + 1
         return
     ######################
     # AWG file functions #
@@ -641,15 +677,15 @@ def _pack_record(self, name, value, dtype):
            characters denoted in the documentation of the struct package
         '''
         if len(dtype) == 1:
-            record_data = struct.pack('<'+dtype, value)
+            record_data = struct.pack('<' + dtype, value)
         else:
             if dtype[-1] == 's':
                 record_data = value.encode('ASCII')
             else:
-                record_data = struct.pack('<'+dtype, *value)
+                record_data = struct.pack('<' + dtype, *value)
 
         # the zero byte at the end the record name is the "(Include NULL.)"
-        record_name = name.encode('ASCII')+b'\x00'
+        record_name = name.encode('ASCII') + b'\x00'
         record_name_size = len(record_name)
         record_data_size = len(record_data)
         size_struct = struct.pack(' 0:
             print(np.where(packed_wf == -1))
         return packed_wf
@@ -862,26 +897,27 @@ def send_waveform(self, w, m1, m2, filename, clock=None):
         self._values['files'][filename] = self._file_dict(w, m1, m2, clock)
 
         m = m1 + np.multiply(m2, 2)
-        ws = ''
+        ws = b''
         # this is probalbly verry slow and memmory consuming!
         for i in range(0, len(w)):
             ws = ws + struct.pack('  'MAGIC 1000\r\n' '#'  'CLOCK ' 
+            # string alsvolgt opgebouwd: '#'   'MAGIC 1000\r\n'
+            # '#'  'CLOCK ' 
             len1 = int(data[1])
-            len2 = int(data[2:2+len1])
+            len2 = int(data[2:2 + len1])
             i = len1
             tekst = ""
             while (tekst != '#'):
                 tekst = data[i]
-                i = i+1
+                i = i + 1
             len3 = int(data[i])
-            len4 = int(data[i+1:i+1+len3])
+            len4 = int(data[i + 1:i + 1 + len3])
             w = []
             m1 = []
             m2 = []
 
-            for q in range(i+1+len3, i+1+len3+len4,5):
-                j=int(q)
-                c,d = struct.unpack(', 2008
+# Martijn Schaafsma , 2008
+# Vishal Ranjan, 2012
+# Ron schutjens, 2012
+# Adriaan Rol, 2016 Ported to QCodes
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+import time
+import logging
+import numpy as np
+import struct
+from qcodes import VisaInstrument, validators as vals
+
+
+class Tektronix_AWG520(VisaInstrument):
+    '''
+    This is the python driver for the Tektronix AWG520
+    Arbitrary Waveform Generator
+
+    TODO:
+    1) Get All
+    2) Remove test_send??
+    3) Add docstrings
+
+    TODO: use inheritance for common use with 520, currently contains
+          a lot of repetition
+    '''
+
+    def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000,
+                 **kw):
+        '''
+        Initializes the AWG520.
+
+        Input:
+            name (string)    : name of the instrument
+            address (string) : GPIB address (Note: 520 cannot be controlled
+                               via ethernet)
+            reset (bool)     : resets to default values, default=false
+            numpoints (int)  : sets the number of datapoints
+
+        Output:
+            None
+        '''
+        super().__init__(name, address, **kw)
+
+        self._address = address
+        self._values = {}
+        self._values['files'] = {}
+        self._clock = clock
+        self._numpoints = numpoints
+        self._fname = ''
+
+        self.add_parameter('IDN', get_cmd='*IDN?')
+        self.add_function('reset', call_cmd='*RST')
+        self.add_parameter('state',
+                           get_cmd=self.get_state)
+
+        # Add parameters
+        self.add_parameter('trigger_mode',
+                           get_cmd='AWGC:RMOD?',
+                           set_cmd='AWGC:RMOD ' + '{}',
+                           vals=vals.Enum('CONT', 'TRIG', 'ENH', 'GAT'))
+        self.add_parameter('trigger_impedance',
+                           units='Ohm',
+                           label='Trigger impedance (Ohm)',
+                           get_cmd='TRIG:IMP?',
+                           set_cmd='TRIG:IMP '+'{}',
+                           vals=vals.Enum(50, 1000),
+                           get_parser=float)
+        self.add_parameter('trigger_level',
+                           units='V',
+                           label='Trigger level (V)',
+                           get_cmd='TRIG:LEV?',
+                           set_cmd='TRIG:LEV '+'{:.3f}',
+                           vals=vals.Numbers(-5, 5),
+                           get_parser=float)
+
+        self.add_parameter('clock_freq',
+                           label='Clock frequency (Hz)',
+                           get_cmd='SOUR:FREQ?',
+                           set_cmd='SOUR:FREQ '+'{}',
+                           vals=vals.Numbers(1e6, 1e9),
+                           get_parser=float)
+        # Todo check if max freq is 1.2 GHz for the AWG 520 aswell
+        self.add_parameter('numpoints',
+                           label='Number of datapoints per wave',
+                           get_cmd=self._do_get_numpoints,
+                           set_cmd=self._do_set_numpoints,
+                           vals=vals.Ints(100, int(1e9)))
+
+        for ch in [1, 2]:
+            amp_cmd = 'SOUR{}:VOLT:LEV:IMM:AMPL'.format(ch)
+            offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(ch)
+
+            self.add_parameter(
+                'ch{}_filename'.format(ch), set_cmd=self._gen_ch_set_func(
+                    self._do_set_filename, ch), vals=vals.Anything())
+            self.add_parameter('ch{}_amp'.format(ch),
+                               label='Amplitude channel {} (V)'.format(ch),
+                               units='V',
+                               get_cmd=amp_cmd + '?',
+                               set_cmd=amp_cmd + ' {:.6f}',
+                               vals=vals.Numbers(0.02, 1.5),
+                               get_parser=float)
+
+            self.add_parameter('ch{}_offset'.format(ch),
+                               label='Offset channel {} (V)'.format(ch),
+                               units='V',
+                               get_cmd=offset_cmd + '?',
+                               set_cmd=offset_cmd + ' {:.3f}',
+                               vals=vals.Numbers(-.1, .1),
+                               get_parser=float)
+            self.add_parameter('ch{}_status'.format(ch),
+                               get_cmd='OUTP{}?'.format(ch),
+                               set_cmd='OUTP{}'.format(ch) + ' {}',
+                               vals=vals.Enum('ON', 'OFF'),
+                               get_parser=float)
+
+            for j in [1, 2]:
+                # TODO: check that 520 does not have marker delay feature
+                # m_del_cmd = 'SOUR{}:MARK{}:DEL'.format(ch, j)
+                m_high_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:HIGH'.format(ch, j)
+                m_low_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:LOW'.format(ch, j)
+
+                self.add_parameter(
+                    'ch{}_m{}_high'.format(ch, j),
+                    label='Channel {} Marker {} high level (V)'.format(ch, j),
+                    get_cmd=m_high_cmd + '?',
+                    set_cmd=m_high_cmd + ' {:.3f}',
+                    vals=vals.Numbers(-2., 2.),
+                    get_parser=float)
+                self.add_parameter(
+                    'ch{}_m{}_low'.format(ch, j),
+                    label='Channel {} Marker {} low level (V)'.format(ch, j),
+                    get_cmd=m_low_cmd + '?',
+                    set_cmd=m_low_cmd + ' {:.3f}',
+                    vals=vals.Numbers(-2., 2.),
+                    get_parser=float)
+
+        # Add functions
+        if reset:
+            self.reset()
+        else:
+            self.get_all()
+        self.connect_message('IDN')
+
+
+    # Functions
+    def _gen_ch_set_func(self, fun, ch):
+        def set_func(val):
+            return fun(ch, val)
+        return set_func
+
+    def _gen_ch_get_func(self, fun, ch):
+        def get_func():
+            return fun(ch)
+        return get_func
+
+    # get state AWG
+    def get_state(self):
+        state = self.visa_handle.ask('AWGC:RSTATE?')
+        if state.startswith('0'):
+            return 'Idle'
+        elif state.startswith('1'):
+            return 'Waiting for trigger'
+        elif state.startswith('2'):
+            return 'Running'
+        else:
+            logging.error(__name__ + ' : AWG in undefined state')
+            return 'error'
+
+    def start(self):
+        self.visa_handle.write('AWGC:RUN')
+        return
+
+    def stop(self):
+        self.visa_handle.write('AWGC:STOP')
+
+    def get_folder_contents(self):
+        return self.visa_handle.ask('mmem:cat?')
+
+    def get_current_folder_name(self):
+        return self.visa_handle.ask('mmem:cdir?')
+
+    def set_current_folder_name(self, file_path):
+        self.visa_handle.write('mmem:cdir "%s"' % file_path)
+
+    def change_folder(self, dir):
+        self.visa_handle.write('mmem:cdir "%s"' % dir)
+
+    def goto_root(self):
+        self.visa_handle.write('mmem:cdir')
+
+    def make_directory(self, dir, root):
+        '''
+        makes a directory
+        if root = True, new dir in main folder
+        '''
+        if root:
+            self.goto_root()
+            self.visa_handle.write('MMEMory:MDIRectory "{}"'.format(dir))
+        else:
+            self.visa_handle.write('MMEMory:MDIRectory "{}"'.format(dir))
+
+    def get_all(self, update=True):
+        # TODO: fix bug in snapshot where it tries to get setable only param
+        # return self.snapshot(update=update)
+
+        return self.snapshot(update=False)
+
+    def clear_waveforms(self):
+        '''
+        Clears the waveform on both channels.
+
+        Input:
+            None
+
+        Output:
+            None
+        '''
+        logging.debug(__name__ + ' : Clear waveforms from channels')
+        self.visa_handle.write('SOUR1:FUNC:USER ""')
+        self.visa_handle.write('SOUR2:FUNC:USER ""')
+
+    def force_trigger(self):
+        '''
+        forces a trigger event (used for wait_trigger option in sequences)
+
+        Ron
+        '''
+        return self.visa_handle.write('TRIG:SEQ:IMM')
+
+    def force_logicjump(self):
+        '''
+        forces a jumplogic event (used as a conditional event during waveform
+        executions)
+
+        note: jump_logic events&mode have to be set properly!
+
+        Ron
+        '''
+        return self.visa_handle.write('AWGC:EVEN:SEQ:IMM')
+
+    def set_jumpmode(self, mode):
+        '''
+        sets the jump mode for jump logic events, possibilities:
+        LOGic,TABle,SOFTware
+        give mode as string
+
+        note: jump_logic events&mode have to be set properly!
+
+        Ron
+        '''
+        return self.visa_handle.write('AWGC:ENH:SEQ:JMOD %s' % mode)
+
+    def get_jumpmode(self, mode):
+        '''
+        get the jump mode for jump logic events
+
+        Ron
+        '''
+        return self.visa_handle.ask('AWGC:ENH:SEQ:JMOD?')
+
+    def _do_get_numpoints(self):
+        '''
+        Returns the number of datapoints in each wave
+
+        Input:
+            None
+
+        Output:
+            numpoints (int) : Number of datapoints in each wave
+        '''
+        return self._numpoints
+
+    def _do_set_numpoints(self, numpts):
+        '''
+        Sets the number of datapoints in each wave.
+        This acts on both channels.
+
+        Input:
+            numpts (int) : The number of datapoints in each wave
+
+        Output:
+            None
+        '''
+        logging.debug(__name__ + ' : Trying to set numpoints to %s' % numpts)
+        if numpts != self._numpoints:
+            logging.warning(__name__ + ' : changing numpoints. This will clear all waveforms!')
+
+        response = 'yes'  # raw_input('type "yes" to continue')
+        if response is 'yes':
+            logging.debug(__name__ + ' : Setting numpoints to %s' % numpts)
+            self._numpoints = numpts
+            self.clear_waveforms()
+        else:
+            print('aborted')
+
+
+
+    def set_setup_filename(self, fname, force_reload=False):
+        if self._fname == fname and not force_reload:
+            print('File %s already loaded in AWG520' % fname)
+            return
+        else:
+            self._fname = fname
+            filename = "\%s/%s.seq" % (fname, fname)
+            self.set_sequence(filename=filename)
+            print('Waiting for AWG to load file "%s"' % fname)
+            sleeptime = 0.5
+            # while state idle is not possible due to timeout error while loading
+            t0 = time.time()
+            while(time.time()-t0 < 360):
+                try:
+                    if self.get_state() == 'Idle':
+                        break
+                except:
+                    time.sleep(sleeptime)
+                    print('.')
+            self.get_state()
+            print('Loading file took %.2fs' % (time.time()-t0))
+            return
+
+    def _do_set_filename(self, name, channel):
+        '''
+        Specifies which file has to be set on which channel
+        Make sure the file exists, and the numpoints and clock of the file
+        matches the instrument settings.
+
+        If file doesn't exist an error is raised, if the numpoints doesn't match
+        the command is neglected
+
+        Input:
+            name (string) : filename of uploaded file
+            channel (int) : 1 or 2, the number of the designated channel
+
+        Output:
+            None
+        '''
+        logging.debug(__name__ + ' : Try to set {} on channel {}'.format(
+                      name, channel))
+        exists = False
+        if name in self._values['files']:
+            exists = True
+            logging.debug(__name__ + ' : File exists in loacal memory')
+            self._values['recent_channel_%s' % channel] = self._values[
+                'files'][name]
+            self._values['recent_channel_%s' % channel]['filename'] = name
+        else:
+            logging.debug(__name__ + ' : File does not exist in memory, \
+            reading from instrument')
+            lijst = self.visa_handle.ask('MMEM:CAT? "MAIN"')
+            bool = False
+            bestand = ""
+            for i in range(len(lijst)):
+                if (lijst[i] =='"'):
+                    bool = True
+                elif (lijst[i] == ','):
+                    bool = False
+                    if (bestand == name):
+                        exists = True
+                    bestand = ""
+                elif bool:
+                    bestand = bestand + lijst[i]
+        if exists:
+            data = self.visa_handle.ask('MMEM:DATA? "%s"' %name)
+            logging.debug(__name__  + ' : File exists on instrument, loading \
+            into local memory')
+            # string alsvolgt opgebouwd: '#'   'MAGIC 1000\r\n' '#'  'CLOCK ' 
+            len1 = int(data[1])
+            len2 = int(data[2:2+len1])
+            i = len1
+            tekst = ""
+            while (tekst !='#'):
+                tekst = data[i]
+                i = i+1
+            len3 = int(data[i])
+            len4 = int(data[i+1:i+1+len3])
+
+            w = []
+            m1 = []
+            m2 = []
+
+            for q in range(i+1+len3, i+1+len3+len4, 5):
+                j = int(q)
+                c, d = struct.unpack('
+#
+# 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 theSoftware 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.
+
+import re
+from qcodes import VisaInstrument
+from qcodes.utils.validators import Anything
+
+
+class Keithley_2600(VisaInstrument):
+    '''
+    channel: use channel 'a' or 'b'
+
+    This is the qcodes driver for the Keithley_2600 Source-Meter series,
+    tested with Keithley_2614B
+
+    Status: beta-version.
+        TODO:
+        - Add all parameters that are in the manual
+        - range and limit should be set according to mode
+        - add ramping and such stuff
+
+    '''
+    def __init__(self, name, address, channel, **kwargs):
+        super().__init__(name, address, terminator='\n', **kwargs)
+        self._channel = channel
+
+        self.add_parameter('IDN', get_cmd=self._get_IDN,
+                           vals=Anything())
+
+        self.add_parameter('volt', get_cmd='measure.v()',
+                           get_parser=float, set_cmd='source.levelv={:.8f}',
+                           label='Voltage',
+                           units='V')
+        self.add_parameter('curr', get_cmd='measure.i()',
+                           get_parser=float, set_cmd='source.leveli={:.8f}',
+                           label='Current',
+                           units='A')
+        self.add_parameter('mode',
+                           get_cmd='source.func',
+                           get_parser=self._mode_parser,
+                           set_cmd='source.func={:d}',
+                           val_mapping={'current': 0, 'curr': 0, 'AMPS': 0,
+                                        'voltage': 1, 'volt': 1, 'VOLT': 1})
+        self.add_parameter('output',
+                           get_cmd='source.output',
+                           get_parser=self._output_parser,
+                           set_cmd='source.output={:d}',
+                           val_mapping={'on':  1, 'ON':  1,
+                                        'off': 0, 'OFF': 0})
+        # Source range
+        # needs get after set
+        self.add_parameter('rangev',
+                           get_cmd='source.rangev',
+                           get_parser=float,
+                           set_cmd='source.rangev={:.4f}',
+                           units='V')
+        # Measure range
+        # needs get after set
+        self.add_parameter('rangei',
+                           get_cmd='source.rangei',
+                           get_parser=float,
+                           set_cmd='source.rangei={:.4f}',
+                           units='A')
+        # Compliance limit
+        self.add_parameter('limitv',
+                           get_cmd='source.limitv',
+                           get_parser=float,
+                           set_cmd='source.limitv={:.4f}',
+                           units='V')
+        # Compliance limit
+        self.add_parameter('limiti',
+                           get_cmd='source.limiti',
+                           get_parser=float,
+                           set_cmd='source.limiti={:.4f}',
+                           units='A')
+
+    def _get_IDN(self):
+        IDN = self.visa_handle.ask('*IDN?')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        model = model[6:]
+
+        self._IDN = {'vendor': vendor, 'model': model,
+                     'serial': serial, 'firmware': firmware}
+        return self._IDN
+
+    def _mode_parser(self, msg):
+        if msg[0] == '0':
+            return 'current'
+        elif msg[0] == '1':
+            return 'voltage'
+        return None
+
+    def _output_parser(self, msg):
+        if msg[0] == '0':
+            return 'OFF'
+        elif msg[0] == '1':
+            return 'ON'
+        return None
+
+    def reset(self):
+        self.write('reset()')
+
+    def ask_direct(self, cmd):
+        return self.visa_handle.ask(cmd)
+
+    def ask(self, cmd):
+        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel, cmd))
+
+    def write(self, cmd):
+        super().write('smu{:s}.{:s}'.format(self._channel, cmd))
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600_bak.py b/qcodes/instrument_drivers/tektronix/Keithley_2600_bak.py
new file mode 100644
index 000000000000..afd697880858
--- /dev/null
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600_bak.py
@@ -0,0 +1,127 @@
+# Keithley_2600.py driver for Keithley 2600 Source-Meter series
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# 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 theSoftware 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.
+
+import re
+from qcodes import VisaInstrument
+
+
+class Keithley_2600(VisaInstrument):
+    '''
+    channel: use channel 'a' or 'b'
+
+    This is the qcodes driver for the Keithley_2600 Source-Meter series,
+    tested with Keithley_2614B
+
+    Status: beta-version.
+        TODO:
+        - Add all parameters that are in the manual
+        - range and limit should be set according to mode
+        - add ramping and such stuff
+
+    '''
+    def __init__(self, name, address, channel, **kwargs):
+        super().__init__(name, address, terminator='\n', **kwargs)
+        self._channel = channel
+
+        self.add_parameter('IDN', get_cmd='*IDN?',
+                           get_parser=self._get_idn_dict)
+
+        self.add_parameter('volt', get_cmd='measure.v()',
+                           get_parser=float, set_cmd='source.levelv={:.8f}',
+                           label='Voltage',
+                           units='V')
+        self.add_parameter('curr', get_cmd='measure.i()',
+                           get_parser=float, set_cmd='source.leveli={:.8f}',
+                           label='Current',
+                           units='A')
+        self.add_parameter('mode',
+                           get_cmd='source.func',
+                           get_parser=self._mode_parser,
+                           set_cmd='source.func={:d}',
+                           val_mapping={'current': 0, 'curr': 0, 'AMPS': 0,
+                                        'voltage': 1, 'volt': 1, 'VOLT': 1})
+        self.add_parameter('output',
+                           get_cmd='source.output',
+                           get_parser=self._output_parser,
+                           set_cmd='source.output={:d}',
+                           val_mapping={'on':  1, 'ON':  1,
+                                        'off': 0, 'OFF': 0})
+        # Source range
+        self.add_parameter('rangev',
+                           get_cmd='source.rangev',
+                           get_parser=float,
+                           set_cmd='source.rangev={:.4f}',
+                           units='V')
+        # Measure range
+        self.add_parameter('rangei',
+                           get_cmd='source.rangei',
+                           get_parser=float,
+                           set_cmd='source.rangei={:.4f}',
+                           units='A')
+        # Compliance limit
+        self.add_parameter('limitv',
+                           get_cmd='source.limitv',
+                           get_parser=float,
+                           set_cmd='source.limitv={:.4f}',
+                           units='V')
+        # Compliance limit
+        self.add_parameter('limiti',
+                           get_cmd='source.limiti',
+                           get_parser=float,
+                           set_cmd='source.limiti={:.4f}',
+                           units='A')
+
+    def _get_idn_dict(self, msg):
+
+        IDN = self.ask_direct('print(*IDN?)')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        model = model[6:]
+
+        return {'vendor': vendor, 'model': model,
+                'serial': serial, 'firmware': firmware}
+
+    def _mode_parser(self, msg):
+        if msg[0] == '0':
+            return 'current'
+        elif msg[0] == '1':
+            return 'voltage'
+        return None
+
+    def _output_parser(self, msg):
+        if msg[0] == '0':
+            return 'OFF'
+        elif msg[0] == '1':
+            return 'ON'
+        return None
+
+    def reset(self):
+        self.write('reset()')
+
+    def ask_direct(self, cmd):
+        return self.visa_handle.ask(cmd)
+
+    def ask(self, cmd):
+        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel, cmd))
+
+    def write(self, cmd):
+        super().write('smu{:s}.{:s}'.format(self._channel, cmd))
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2700.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
index 39e11a2b8a04..e85d636db446 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2700.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
@@ -77,9 +77,9 @@ class Keithley_2700(VisaInstrument):
     This driver does not contain all commands available, but only the ones
     most commonly used.
     '''
-    def __init__(self, name, address, reset=False):
+    def __init__(self, name, address, reset=False, **kwargs):
         t0 = time.time()
-        super().__init__(name, address)
+        super().__init__(name, address, **kwargs)
 
         self.add_parameter('IDN', get_cmd='*IDN?')
 
@@ -203,10 +203,16 @@ def __init__(self, name, address, reset=False):
         '''
 
         # add functions
-        self.add_function('readnext',
+        self.add_parameter('amplitude',
                           units='arb.unit',
-                          call_cmd=':DATA:FRESH?',
-                          return_parser=float)
+                          label=name,
+                          get_cmd=':DATA:FRESH?',
+                          get_parser=float)
+        self.add_parameter('readnext',
+                          units='arb.unit',
+                          label=name,
+                          get_cmd=':DATA:FRESH?',
+                          get_parser=float)
 
         if reset:
             self.reset()
diff --git a/qcodes/loops.py b/qcodes/loops.py
index 3a1be4e12fd7..dbe87700f4c0 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -1,4 +1,4 @@
-'''
+"""
 Data acquisition loops
 
 The general scheme is:
@@ -36,7 +36,7 @@
     ActiveLoop (or Loop, will be activated with default measurement)
     Task: any callable that does not generate data
     Wait: a delay
-'''
+"""
 from datetime import datetime
 import multiprocessing as mp
 import time
@@ -45,6 +45,8 @@
 from qcodes.station import Station
 from qcodes.data.data_set import new_data, DataMode
 from qcodes.data.data_array import DataArray
+from qcodes.utils.deferred_operations import is_function
+from qcodes.data.manager import get_data_manager
 from qcodes.utils.helpers import wait_secs
 from qcodes.utils.multiprocessing import QcodesProcess
 from qcodes.utils.threading import thread_map
@@ -54,14 +56,14 @@
 
 
 def get_bg(return_first=False):
-    '''
+    """
     find the active background measurement process, if any
     returns None otherwise
 
     return_first: if there are multiple loops running return the first anyway.
         If false, multiple loops is a RuntimeError.
         default False
-    '''
+    """
     processes = mp.active_children()
     loops = [p for p in processes if getattr(p, 'name', '') == MP_NAME]
 
@@ -71,13 +73,16 @@ def get_bg(return_first=False):
     if loops:
         return loops[0]
 
+    # if we got here, there shouldn't be a loop running. Make sure the
+    # data manager, if there is one, agrees!
+    _clear_data_manager()
     return None
 
 
 def halt_bg(timeout=5):
-    '''
+    """
     Stop the active background measurement process, if any
-    '''
+    """
     loop = get_bg(return_first=True)
     if not loop:
         print('No loop running')
@@ -91,6 +96,14 @@ def halt_bg(timeout=5):
         loop.join(timeout/2)
         print('Background loop did not respond to halt signal, terminated')
 
+    _clear_data_manager()
+
+
+def _clear_data_manager():
+    dm = get_data_manager(only_existing=True)
+    if dm and dm.ask('get_measuring'):
+        dm.ask('end_data')
+
 
 # def measure(*actions):
 #     # measure has been moved into Station
@@ -100,13 +113,15 @@ def halt_bg(timeout=5):
 
 
 class Loop:
-    '''
+    """
     The entry point for creating measurement loops
 
     sweep_values - a SweepValues or compatible object describing what
         parameter to set in the loop and over what values
     delay - a number of seconds to wait after setting a value before
-        continuing.
+        continuing. 0 (default) means no waiting and no warnings. > 0
+        means to wait, potentially filling the delay time with monitoring,
+        and give an error if you wait longer than expected.
 
     After creating a Loop, you attach `action`s to it, making an `ActiveLoop`
     that you can `.run()`, or you can `.run()` a `Loop` directly, in which
@@ -116,33 +131,42 @@ class Loop:
     `Parameter`s to measure, `Task`s to do (any callable that does not yield
     data), `Wait` times, or other `ActiveLoop`s or `Loop`s to nest inside
     this one.
-    '''
-    def __init__(self, sweep_values, delay):
+    """
+    def __init__(self, sweep_values, delay=0):
+        if not delay >= 0:
+            raise ValueError('delay must be > 0, not {}'.format(repr(delay)))
         self.sweep_values = sweep_values
         self.delay = delay
         self.nested_loop = None
+        self.then_actions = ()
 
-    def loop(self, sweep_values, delay):
-        '''
+    def loop(self, sweep_values, delay=0):
+        """
         Nest another loop inside this one
 
         Loop(sv1, d1).loop(sv2, d2).each(*a) is equivalent to:
         Loop(sv1, d1).each(Loop(sv2, d2).each(*a))
 
         returns a new Loop object - the original is untouched
-        '''
-        out = Loop(self.sweep_values, self.delay)
+        """
+        out = self._copy()
 
-        if self.nested_loop:
+        if out.nested_loop:
             # nest this new loop inside the deepest level
-            out.nested_loop = self.nested_loop.loop(sweep_values, delay)
+            out.nested_loop = out.nested_loop.loop(sweep_values, delay)
         else:
             out.nested_loop = Loop(sweep_values, delay)
 
         return out
 
+    def _copy(self):
+        out = Loop(self.sweep_values, self.delay)
+        out.nested_loop = self.nested_loop
+        out.then_actions = self.then_actions
+        return out
+
     def each(self, *actions):
-        '''
+        """
         Perform a set of actions at each setting of this loop
 
         Each action can be:
@@ -150,7 +174,7 @@ def each(self, *actions):
         - a Task to execute
         - a Wait
         - another Loop or ActiveLoop
-        '''
+        """
         actions = list(actions)
 
         # check for nested Loops, and activate them with default measurement
@@ -159,44 +183,106 @@ def each(self, *actions):
                 default = Station.default.default_measurement
                 actions[i] = action.each(*default)
 
+        self.validate_actions(*actions)
+
         if self.nested_loop:
             # recurse into the innermost loop and apply these actions there
             actions = [self.nested_loop.each(*actions)]
 
-        return ActiveLoop(self.sweep_values, self.delay, *actions)
+        return ActiveLoop(self.sweep_values, self.delay, *actions,
+                          then_actions=self.then_actions)
+
+    @staticmethod
+    def validate_actions(*actions):
+        """
+        Whitelist acceptable actions, so we can give nice error messages
+        if an action is not recognized
+        """
+        for action in actions:
+            if isinstance(action, (Task, Wait, BreakIf, ActiveLoop)):
+                continue
+            if hasattr(action, 'get') and (hasattr(action, 'name') or
+                                           hasattr(action, 'names')):
+                continue
+            raise TypeError('Unrecognized action:', action,
+                            'Allowed actions are: objects (parameters) with '
+                            'a `get` method and `name` or `names` attribute, '
+                            'and `Task`, `Wait`, `BreakIf`, and `ActiveLoop` '
+                            'objects. `Loop` objects are OK too, except in '
+                            'Station default measurements.')
 
     def run(self, *args, **kwargs):
-        '''
+        """
         shortcut to run a loop with the default measurement set
         stored by Station.set_measurement
-        '''
+        """
         default = Station.default.default_measurement
         return self.each(*default).run(*args, **kwargs)
 
     def run_temp(self, *args, **kwargs):
-        '''
+        """
         shortcut to run a loop in the foreground as a temporary dataset
         using the default measurement set
-        '''
+        """
         return self.run(*args, background=False, quiet=True,
                         data_manager=False, location=False, **kwargs)
 
+    def then(self, *actions, overwrite=False):
+        """
+        Attach actions to be performed after the loop completes.
+        These can only be `Task` and `Wait` actions, as they may not generate
+        any data.
+
+        returns a new Loop object - the original is untouched
+
+        This is more naturally done to an ActiveLoop (ie after .each())
+        and can also be done there, but it's allowed at this stage too so that
+        you can define final actions and share them among several `Loop`s that
+        have different loop actions.
+
+        *actions: `Task` and `Wait` objects to execute in order
+
+        overwrite: (default False) whether subsequent .then() calls (including
+            calls in an ActiveLoop after .then() has already been called on
+            the Loop) will add to each other or overwrite the earlier ones.
+        """
+        return _attach_then_actions(self._copy(), actions, overwrite)
+
+
+def _attach_then_actions(loop, actions, overwrite):
+    """
+    inner code for both Loop.then and ActiveLoop.then
+    """
+    for action in actions:
+        if not isinstance(action, (Task, Wait)):
+            raise TypeError('Unrecognized action:', action,
+                            '.then() allows only `Task` and `Wait` '
+                            'actions.')
+
+    if overwrite:
+        loop.then_actions = actions
+    else:
+        loop.then_actions = loop.then_actions + actions
+
+    return loop
+
 
 class ActiveLoop:
-    '''
+    """
     Created by attaching actions to a `Loop`, this is the object that actually
     runs a measurement loop. An `ActiveLoop` can no longer be nested, only run,
     or used as an action inside another `Loop` which will run the whole thing.
 
     The `ActiveLoop` determines what `DataArray`s it will need to hold the data
     it collects, and it creates a `DataSet` holding these `DataArray`s
-    '''
+    """
     HALT = 'HALT LOOP'
 
-    def __init__(self, sweep_values, delay, *actions):
+    def __init__(self, sweep_values, delay, *actions, then_actions=()):
         self.sweep_values = sweep_values
         self.delay = delay
         self.actions = actions
+        self.then_actions = then_actions
 
         # compile now, but don't save the results
         # just used for preemptive error checking
@@ -218,13 +304,31 @@ def __init__(self, sweep_values, delay, *actions):
 
         self._monitor = None  # TODO: how to specify this?
 
+    def then(self, *actions, overwrite=False):
+        """
+        Attach actions to be performed after the loop completes.
+        These can only be `Task` and `Wait` actions, as they may not generate
+        any data.
+
+        returns a new ActiveLoop object - the original is untouched
+
+        *actions: `Task` and `Wait` objects to execute in order
+
+        overwrite: (default False) whether subsequent .then() calls (including
+            calls in an ActiveLoop after .then() has already been called on
+            the Loop) will add to each other or overwrite the earlier ones.
+        """
+        loop = ActiveLoop(self.sweep_values, self.delay, *self.actions,
+                          then_actions=self.then_actions)
+        return _attach_then_actions(loop, actions, overwrite)
+
     def containers(self):
-        '''
+        """
         Finds the data arrays that will be created by the actions in this
         loop, and nests them inside this level of the loop.
 
         Recursively calls `.containers` on any enclosed actions.
-        '''
+        """
         loop_size = len(self.sweep_values)
         loop_array = DataArray(parameter=self.sweep_values.parameter)
         loop_array.nest(size=loop_size)
@@ -377,12 +481,12 @@ def _default_setpoints(self, size):
         return sp
 
     def set_common_attrs(self, data_set, use_threads, signal_queue):
-        '''
+        """
         set a couple of common attributes that the main and nested loops
         all need to have:
         - the DataSet collecting all our measurements
         - a queue for communicating with the main process
-        '''
+        """
         self.data_set = data_set
         self.signal_queue = signal_queue
         self.use_threads = use_threads
@@ -397,17 +501,17 @@ def _check_signal(self):
                 raise KeyboardInterrupt('sweep was halted')
 
     def run_temp(self, **kwargs):
-        '''
+        """
         wrapper to run this loop in the foreground as a temporary data set,
         especially for use in composite parameters that need to run a Loop
         as part of their get method
-        '''
+        """
         return self.run(background=False, quiet=True,
                         data_manager=False, location=False, **kwargs)
 
-    def run(self, background=True, use_threads=True, enqueue=False,
+    def run(self, background=True, use_threads=True,
             quiet=False, data_manager=None, **kwargs):
-        '''
+        """
         execute this loop
 
         background: (default True) run this sweep in a separate process
@@ -415,11 +519,9 @@ def run(self, background=True, use_threads=True, enqueue=False,
         use_threads: (default True): whenever there are multiple `get` calls
             back-to-back, execute them in separate threads so they run in
             parallel (as long as they don't block each other)
-        enqueue: (default False): wait for a previous background sweep to
-            finish? If false, will raise an error if another sweep is running
         quiet: (default False): set True to not print anything except errors
         data_manager: a DataManager instance (omit to use default,
-            False to store locally and not write to disk)
+            False to store locally)
 
         kwargs are passed along to data_set.new_data. The key ones are:
         location: the location of the DataSet, a string whose meaning
@@ -432,19 +534,21 @@ def run(self, background=True, use_threads=True, enqueue=False,
         formatter: knows how to read and write the file format
             default can be set in DataSet.default_formatter
         io: knows how to connect to the storage (disk vs cloud etc)
+        write_period: how often to save to storage during the loop.
+            default 5 sec, use None to write only at the end
 
 
         returns:
             a DataSet object that we can use to plot
-        '''
+        """
 
         prev_loop = get_bg()
         if prev_loop:
-            if enqueue:
-                prev_loop.join()  # wait until previous loop finishes
-            else:
-                raise RuntimeError(
-                    'a loop is already running in the background')
+            if not quiet:
+                print('Waiting for the previous background Loop to finish...',
+                      flush=True)
+            prev_loop.join()
+
         if data_manager is False:
             data_mode = DataMode.LOCAL
         else:
@@ -455,6 +559,10 @@ def run(self, background=True, use_threads=True, enqueue=False,
         self.set_common_attrs(data_set=data_set, use_threads=use_threads,
                               signal_queue=self.signal_queue)
 
+        if prev_loop and not quiet:
+            print('...done. Starting ' + (data_set.location or 'new loop'),
+                  flush=True)
+
         if background:
             p = QcodesProcess(target=self._run_wrapper, name=MP_NAME)
             p.is_sweep = True
@@ -462,11 +570,22 @@ def run(self, background=True, use_threads=True, enqueue=False,
             p.start()
             self.process = p
 
+            # now that the data_set we created has been put in the loop
+            # process, this copy turns into a reader
+            # if you're not using a DataManager, it just stays local
+            # and sync() reads from disk
+            if self.data_set.mode == DataMode.PUSH_TO_SERVER:
+                self.data_set.mode = DataMode.PULL_FROM_SERVER
             self.data_set.sync()
-            self.data_set.mode = DataMode.PULL_FROM_SERVER
         else:
+            if hasattr(self, 'process'):
+                # in case this ActiveLoop was run before in the background
+                del self.process
+
             self._run_wrapper()
-            self.data_set.read()
+
+            if self.data_set.mode != DataMode.LOCAL:
+                self.data_set.sync()
 
         if not quiet:
             print(repr(self.data_set))
@@ -500,22 +619,20 @@ def _compile_one(self, action, new_action_indices):
             return Task(self._wait, action.delay)
         elif isinstance(action, ActiveLoop):
             return _Nest(action, new_action_indices)
-        elif callable(action):
-            return action
         else:
-            raise TypeError('unrecognized action', action)
+            return action
 
     def _run_wrapper(self, *args, **kwargs):
         try:
             self._run_loop(*args, **kwargs)
         finally:
-            if(hasattr(self, 'data_set') and hasattr(self.data_set, 'close')):
-                self.data_set.close()
+            if hasattr(self, 'data_set'):
+                self.data_set.finalize()
 
     def _run_loop(self, first_delay=0, action_indices=(),
                   loop_indices=(), current_values=(),
                   **ignore_kwargs):
-        '''
+        """
         the routine that actually executes the loop, and can be called
         from one loop to execute a nested loop
 
@@ -525,7 +642,7 @@ def _run_loop(self, first_delay=0, action_indices=(),
         current_values: setpoint values in any outer loops
         signal_queue: queue to communicate with main process directly
         ignore_kwargs: for compatibility with other loop tasks
-        '''
+        """
 
         # at the beginning of the loop, the time to wait after setting
         # the loop parameter may be increased if an outer loop requested longer
@@ -544,29 +661,39 @@ def _run_loop(self, first_delay=0, action_indices=(),
                 # only wait the delay time if an inner loop will not inherit it
                 self._wait(delay)
 
-            for f in callables:
-                f(first_delay=delay,
-                  loop_indices=new_indices,
-                  current_values=new_values)
+            try:
+                for f in callables:
+                    f(first_delay=delay,
+                      loop_indices=new_indices,
+                      current_values=new_values)
 
-                # after the first action, no delay is inherited
-                delay = 0
+                    # after the first action, no delay is inherited
+                    delay = 0
+            except _QcodesBreak:
+                break
 
             # after the first setpoint, delay reverts to the loop delay
             delay = self.delay
 
+        # the loop is finished - run the .then actions
+        for f in self._compile_actions(self.then_actions, ()):
+            f()
+
     def _wait(self, delay):
-        finish_clock = time.perf_counter() + delay
+        if delay:
+            finish_clock = time.perf_counter() + delay
 
-        if self._monitor:
-            self._monitor.call(finish_by=finish_clock)
+            if self._monitor:
+                self._monitor.call(finish_by=finish_clock)
 
-        self._check_signal()
-        time.sleep(wait_secs(finish_clock))
+            self._check_signal()
+            time.sleep(wait_secs(finish_clock))
+        else:
+            self._check_signal()
 
 
 class Task:
-    '''
+    """
     A predefined task to be executed within a measurement Loop
     This form is for a simple task that does not measure any data,
     and does not depend on the state of the loop when it is called.
@@ -576,7 +703,7 @@ class Task:
 
     kwargs passed when the Task is called are ignored,
     but are accepted for compatibility with other things happening in a Loop.
-    '''
+    """
     def __init__(self, func, *args, **kwargs):
         self.func = func
         self.args = args
@@ -587,35 +714,36 @@ def __call__(self, **ignore_kwargs):
 
 
 class Wait:
-    '''
+    """
     A simple class to tell a Loop to wait  seconds
 
     This is transformed into a Task within the Loop, such that
     it can do other things (monitor, check for halt) during the delay.
 
     But for use outside of a Loop, it is also callable (then it just sleeps)
-    '''
+    """
     def __init__(self, delay):
+        if not delay >= 0:
+            raise ValueError('delay must be > 0, not {}'.format(repr(delay)))
         self.delay = delay
 
     def __call__(self):
-        time.sleep(self.delay)
+        if self.delay:
+            time.sleep(self.delay)
 
 
 class _Measure:
-    '''
+    """
     A callable collection of parameters to measure.
     This should not be constructed manually, only by an ActiveLoop.
-    '''
+    """
     def __init__(self, params_indices, data_set, use_threads):
-        self.use_threads = use_threads
+        self.use_threads = use_threads and len(params_indices) > 1
         # the applicable DataSet.store function
         self.store = data_set.store
 
         # for performance, pre-calculate which params return data for
-        # multiple arrays, pre-create the dict to pass these to store fn
-        # and pre-calculate the name mappings
-        self.dict = {}
+        # multiple arrays, and the name mappings
         self.getters = []
         self.param_ids = []
         self.composite = []
@@ -627,16 +755,15 @@ def __init__(self, params_indices, data_set, use_threads):
                 for i in range(len(param.names)):
                     param_id = data_set.action_id_map[action_indices + (i,)]
                     part_ids.append(param_id)
-                    self.dict[param_id] = None
                 self.param_ids.append(None)
                 self.composite.append(part_ids)
             else:
                 param_id = data_set.action_id_map[action_indices]
-                self.dict[param_id] = None
                 self.param_ids.append(param_id)
                 self.composite.append(False)
 
     def __call__(self, loop_indices, **ignore_kwargs):
+        out_dict = {}
         if self.use_threads:
             out = thread_map(self.getters)
         else:
@@ -646,21 +773,46 @@ def __call__(self, loop_indices, **ignore_kwargs):
                                                   self.composite):
             if composite:
                 for val, part_id in zip(param_out, composite):
-                    self.dict[part_id] = val
+                    out_dict[part_id] = val
             else:
-                self.dict[param_id] = param_out
+                out_dict[param_id] = param_out
 
-        self.store(loop_indices, self.dict)
+        self.store(loop_indices, out_dict)
 
 
 class _Nest:
-    '''
+    """
     wrapper to make a callable nested ActiveLoop
     This should not be constructed manually, only by an ActiveLoop.
-    '''
+    """
     def __init__(self, inner_loop, action_indices):
         self.inner_loop = inner_loop
         self.action_indices = action_indices
 
     def __call__(self, **kwargs):
         self.inner_loop._run_loop(action_indices=self.action_indices, **kwargs)
+
+
+class BreakIf:
+    """
+    Loop action that breaks out of the loop if a condition is truthy
+
+    condition: a callable taking no arguments.
+        Can be a simple function that returns truthy when it's time to quit
+        May also be constructed by deferred operations on `Parameter`s, eg:
+            BreakIf(gates.chan1 >= 3)
+            BreakIf(abs(source.I * source.V) >= source.power_limit.get_latest)
+    """
+    def __init__(self, condition):
+        if not is_function(condition, 0):
+            raise TypeError('BreakIf condition must be a callable with '
+                            'no arguments')
+        self.condition = condition
+
+    def __call__(self, **ignore_kwargs):
+        if self.condition():
+            raise _QcodesBreak
+
+
+class _QcodesBreak(Exception):
+    pass
diff --git a/qcodes/plots/base.py b/qcodes/plots/base.py
index 7a8999a23387..22e4d5c449b0 100644
--- a/qcodes/plots/base.py
+++ b/qcodes/plots/base.py
@@ -7,6 +7,7 @@
 
 
 class BasePlot:
+
     '''
     create an auto-updating plot connected to a Jupyter notebook
 
@@ -18,14 +19,32 @@ class BasePlot:
         default 'xyz' (treated as a sequence) but add more if
         for example marker size or color can contain data
     '''
+
     def __init__(self, interval=1, data_keys='xyz'):
         self.data_keys = data_keys
         self.traces = []
         self.data_updaters = set()
 
-        self.interval = interval
-        self.update_widget = HiddenUpdateWidget(self.update, interval)
-        display(self.update_widget)
+        if interval:
+            self.interval = interval
+            self.update_widget = HiddenUpdateWidget(self.update, interval)
+            display(self.update_widget)
+
+    def clear(self):
+        '''
+        Clears the plot window and removes all subplots and traces
+        so that the window can be reused.
+        '''
+        # any derived class should implement this
+        raise NotImplementedError
+        # typically traces and subplots should be cleared as well as the
+        # figure window for the particular backend
+        self.traces = []
+        self.subplots = []
+
+    def replace(self, *args, updater=None, **kwargs):
+        self.clear()
+        self.add(*args, updater=updater, **kwargs)
 
     def add(self, *args, updater=None, **kwargs):
         '''
@@ -69,7 +88,8 @@ def add_updater(self, updater, plot_config):
             for key in self.data_keys:
                 data_array = plot_config.get(key, '')
                 if hasattr(data_array, 'data_set'):
-                    self.data_updaters.add(data_array.data_set.sync)
+                    if data_array.data_set is not None:
+                        self.data_updaters.add(data_array.data_set.sync)
 
         if self.data_updaters:
             self.update_widget.interval = self.interval
@@ -87,9 +107,10 @@ def get_default_title(self):
             for part in self.data_keys:
                 data_array = config.get(part, '')
                 if hasattr(data_array, 'data_set'):
-                    location = data_array.data_set.location
-                    if location not in title_parts:
-                        title_parts.append(location)
+                    if data_array.data_set is not None:
+                        location = data_array.data_set.location
+                        if location and location not in title_parts:
+                            title_parts.append(location)
         return ', '.join(title_parts)
 
     def get_label(self, data_array):
diff --git a/qcodes/plots/matplotlib.py b/qcodes/plots/matplotlib.py
index e159c618d336..1ea59edbda39 100644
--- a/qcodes/plots/matplotlib.py
+++ b/qcodes/plots/matplotlib.py
@@ -28,22 +28,42 @@ class MatPlot(BasePlot):
 
     kwargs: passed along to MatPlot.add() to add the first data trace
     '''
-    def __init__(self, *args, figsize=(8, 5), interval=1, subplots=(1, 1),
+    def __init__(self, *args, figsize=None, interval=1, subplots=None,
                  **kwargs):
 
         super().__init__(interval)
 
+        self._init_plot(subplots, figsize)
+
+        if args or kwargs:
+            self.add(*args, **kwargs)
+
+    def _init_plot(self, subplots=None, figsize=None, num=None):
+        if figsize is None:
+            figsize = (8, 5)
+
+        if subplots is None:
+            subplots = (1, 1)
+
         if isinstance(subplots, Mapping):
-            self.fig, self.subplots = plt.subplots(figsize=figsize, **subplots)
+            self.fig, self.subplots = plt.subplots(figsize=figsize, num=num,
+                                                   **subplots)
         else:
-            self.fig, self.subplots = plt.subplots(*subplots, figsize=figsize)
+            self.fig, self.subplots = plt.subplots(*subplots, num=num,
+                                                   figsize=figsize)
         if not hasattr(self.subplots, '__len__'):
             self.subplots = (self.subplots,)
 
         self.title = self.fig.suptitle('')
 
-        if args or kwargs:
-            self.add(*args, **kwargs)
+    def clear(self, subplots=None, figsize=None):
+        '''
+        Clears the plot window and removes all subplots and traces
+        so that the window can be reused.
+        '''
+        self.traces = []
+        self.fig.clf()
+        self._init_plot(subplots, figsize, num=self.fig.number)
 
     def add_to_plot(self, **kwargs):
         '''
diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index 8d6a3df41988..2075434631ed 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -38,14 +38,17 @@ class QtPlot(BasePlot):
     rpg = None
 
     def __init__(self, *args, figsize=(1000, 600), interval=0.25,
-                 windowTitle='', theme=((60, 60, 60), 'w'), **kwargs):
+                 windowTitle='', theme=((60, 60, 60), 'w'), show_window=True, remote=True, **kwargs):
         super().__init__(interval)
 
-        if not self.__class__.proc:
-            self._init_qt()
-
         self.theme = theme
 
+        if remote:
+            if not self.__class__.proc:
+                self._init_qt()
+        else:
+            # overrule the remote pyqtgraph class
+            self.rpg = pg
         self.win = self.rpg.GraphicsWindow(title=windowTitle)
         self.win.setBackground(theme[1])
         self.win.resize(*figsize)
@@ -54,6 +57,9 @@ def __init__(self, *args, figsize=(1000, 600), interval=0.25,
         if args or kwargs:
             self.add(*args, **kwargs)
 
+        if not show_window:
+            self.win.hide()
+
     def _init_qt(self):
         # starting the process for the pyqtgraph plotting
         # You do not want a new process to be created every time you start a
@@ -127,8 +133,13 @@ def _draw_plot(self, subplot_object, y, x=None, color=None, width=None,
             if 'symbolBrush' not in kwargs:
                 kwargs['symbolBrush'] = color
 
-        return subplot_object.plot(*self._line_data(x, y), antialias=antialias,
-                                   **kwargs)
+        # suppress warnings when there are only NaN to plot
+        with warnings.catch_warnings():
+            warnings.filterwarnings('ignore', 'All-NaN axis encountered')
+            warnings.filterwarnings('ignore', 'All-NaN slice encountered')
+            pl = subplot_object.plot(*self._line_data(x, y),
+                                     antialias=antialias, **kwargs)
+        return pl
 
     def _line_data(self, x, y):
         return [self._clean_array(arg) for arg in [x, y] if arg is not None]
@@ -160,6 +171,7 @@ def _draw_image(self, subplot_object, z, x=None, y=None, cmap='hot',
         }
 
         self._update_image(plot_object, {'x': x, 'y': y, 'z': z})
+        self._update_cmap(plot_object)
 
         return plot_object
 
@@ -185,8 +197,6 @@ def _update_image(self, plot_object, config):
                 return
         z[np.where(np.isnan(z))] = z_range[0]
 
-        self._update_cmap(plot_object)
-
         hist_range = hist.getLevels()
         if hist_range == plot_object['histlevels']:
             plot_object['histlevels'] = z_range
diff --git a/qcodes/station.py b/qcodes/station.py
index 4621f19a98ea..efc14620dbf4 100644
--- a/qcodes/station.py
+++ b/qcodes/station.py
@@ -31,8 +31,8 @@ def __init__(self, *instruments, monitor=None, default=True, **kwargs):
 
         self.monitor = monitor
 
-    def snapshot_base(self):
-        return {'instruments': {name: ins.snapshot()
+    def snapshot_base(self, *args, **kwargs):
+        return {'instruments': {name: ins.snapshot(*args, **kwargs)
                                 for name, ins in self.instruments.items()}}
 
     def add_instrument(self, instrument, name=None):
@@ -57,6 +57,13 @@ def set_measurement(self, *actions):
         default Station, and any measurements among them can be done once
         by .measure
         '''
+        # Validate now so the user gets an error message ASAP
+        # and so we don't accept `Loop` as an action here, where
+        # it would cause infinite recursion.
+        # We need to import Loop inside here to avoid circular import
+        from .loops import Loop
+        Loop.validate_actions(*actions)
+
         self.default_measurement = actions
 
     def measure(self, *actions):
diff --git a/qcodes/test.py b/qcodes/test.py
index 18c8d9258f20..062ca5368212 100644
--- a/qcodes/test.py
+++ b/qcodes/test.py
@@ -41,6 +41,11 @@ def _test_core(**kwargs):
                         help=('increase verbosity. default 1, '
                               '-v is the same as -v 2'))
 
+    parser.add_argument('-c', '--coverage', nargs='?', dest='show_coverage',
+                        const=1, default=1, type=int,
+                        help=('show coverage. default is True '
+                              '-c is the same as -c 1'))
+
     parser.add_argument('-f', '--failfast', nargs='?', dest='failfast',
                         const=1, default=0, type=int,
                         help=('halt on first error/failure? default 0 '
@@ -56,5 +61,5 @@ def _test_core(**kwargs):
 
     cov.stop()
 
-    if success:
+    if success and args.show_coverage:
         cov.report()
diff --git a/qcodes/tests/data_mocks.py b/qcodes/tests/data_mocks.py
new file mode 100644
index 000000000000..aee15f451140
--- /dev/null
+++ b/qcodes/tests/data_mocks.py
@@ -0,0 +1,126 @@
+import multiprocessing as mp
+
+from qcodes.data.data_array import DataArray
+from qcodes.data.data_set import new_data
+
+
+class MockDataManager:
+    query_lock = mp.RLock()
+
+    def __init__(self):
+        self.needs_restart = False
+
+    def ask(self, *args, timeout=None):
+        if args == ('get_data', 'location'):
+            return self.location
+        elif args == ('get_data',):
+            return self.live_data
+        elif args[0] == 'new_data' and len(args) == 2:
+            if self.needs_restart:
+                raise AttributeError('data_manager needs a restart')
+            else:
+                self.data_set = args[1]
+        else:
+            raise Exception('unexpected query to MockDataManager')
+
+    def restart(self):
+        self.needs_restart = False
+
+
+class MockFormatter:
+    def read(self, data_set):
+        data_set.has_read_data = True
+
+    def write(self, data_set):
+        data_set.has_written_data = True
+
+
+class FullIO:
+    def list(self, location):
+        return [location + '.whatever']
+
+
+class EmptyIO:
+    def list(self, location):
+        return []
+
+
+class MissingMIO:
+    def list(self, location):
+        if 'm' not in location:
+            return [location + '.whatever']
+        else:
+            return []
+
+
+class MockLive:
+    arrays = 'whole lotta data'
+
+
+class MockArray:
+    array_id = 'noise'
+
+    def init_data(self):
+        self.ready = True
+
+
+def DataSet1D(location=None):
+    # DataSet with one 1D array with 5 points
+    x = DataArray(name='x', label='X', preset_data=(1., 2., 3., 4., 5.))
+    y = DataArray(name='y', label='Y', preset_data=(3., 4., 5., 6., 7.),
+                  set_arrays=(x,))
+    return new_data(arrays=(x, y), location=location)
+
+
+def file_1d():
+    return '\n'.join([
+        '# x\ty',
+        '# "X"\t"Y"',
+        '# 5',
+        '1\t3',
+        '2\t4',
+        '3\t5',
+        '4\t6',
+        '5\t7', ''])
+
+
+def DataSetCombined(location=None):
+    # Complex DataSet with two 1D and two 2D arrays
+    x = DataArray(name='x', label='X!', preset_data=(16., 17.))
+    y1 = DataArray(name='y1', label='Y1 value', preset_data=(18., 19.),
+                   set_arrays=(x,))
+    y2 = DataArray(name='y2', label='Y2 value', preset_data=(20., 21.),
+                   set_arrays=(x,))
+
+    yset = DataArray(name='yset', label='Y', preset_data=(22., 23., 24.))
+    yset.nest(2, 0, x)
+    z1 = DataArray(name='z1', label='Z1',
+                   preset_data=((25., 26., 27.), (28., 29., 30.)),
+                   set_arrays=(x, yset))
+    z2 = DataArray(name='z2', label='Z2',
+                   preset_data=((31., 32., 33.), (34., 35., 36.)),
+                   set_arrays=(x, yset))
+    return new_data(arrays=(x, y1, y2, yset, z1, z2), location=location)
+
+
+def files_combined():
+    return [
+        '\n'.join([
+            '# x\ty1\ty2',
+            '# "X!"\t"Y1 value"\t"Y2 value"',
+            '# 2',
+            '16\t18\t20',
+            '17\t19\t21', '']),
+
+        '\n'.join([
+            '# x\tyset\tz1\tz2',
+            '# "X!"\t"Y"\t"Z1"\t"Z2"',
+            '# 2\t3',
+            '16\t22\t25\t31',
+            '16\t23\t26\t32',
+            '16\t24\t27\t33',
+            '',
+            '17\t22\t28\t34',
+            '17\t23\t29\t35',
+            '17\t24\t30\t36', ''])
+    ]
diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py
index 214d9f3ffdca..528090cbf1aa 100644
--- a/qcodes/tests/instrument_mocks.py
+++ b/qcodes/tests/instrument_mocks.py
@@ -95,6 +95,8 @@ def add5(self, b):
 
 class MockGates(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('gates', model=model, delay=0.001, **kwargs)
+
         for i in range(3):
             cmdbase = 'c{}'.format(i)
             self.add_parameter('chan{}'.format(i), get_cmd=cmdbase + '?',
@@ -106,25 +108,31 @@ def __init__(self, model=None, **kwargs):
                                set_cmd=cmdbase + ':{:.4f}',
                                get_parser=float,
                                vals=Numbers(-10, 10),
-                               sweep_step=0.1, sweep_delay=0.005)
+                               step=0.1, delay=0.005)
 
         self.add_parameter('chan0slow', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.02)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.02)
         self.add_parameter('chan0slow2', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.01, max_sweep_delay=0.02)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.01, max_delay=0.02)
         self.add_parameter('chan0slow3', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.01, max_sweep_delay=0.08)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.01, max_delay=0.08)
+        self.add_parameter('chan0slow4', get_cmd='c0?',
+                           set_cmd=self.slow_neg_set, get_parser=float,
+                           vals=Numbers(-10, 10),
+                           delay=0.01, max_delay=0.02)
+        self.add_parameter('chan0slow5', get_cmd='c0?',
+                           set_cmd=self.slow_neg_set, get_parser=float,
+                           vals=Numbers(-10, 10),
+                           delay=0.01, max_delay=0.08)
 
         self.add_function('reset', call_cmd='rst')
 
-        super().__init__('gates', model=model, delay=0.001, **kwargs)
-
     def slow_neg_set(self, val):
         if val < 0:
             time.sleep(0.05)
@@ -133,18 +141,18 @@ def slow_neg_set(self, val):
 
 class MockSource(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('source', model=model, delay=0.001, **kwargs)
+
         self.add_parameter('amplitude', get_cmd='ampl?',
                            set_cmd='ampl:{:.4f}', get_parser=float,
                            vals=Numbers(0, 1),
-                           sweep_step=0.2, sweep_delay=0.005)
-
-        super().__init__('source', model=model, delay=0.001, **kwargs)
+                           step=0.2, delay=0.005)
 
 
 class MockMeter(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('meter', model=model, delay=0.001, **kwargs)
+
         self.add_parameter('amplitude', get_cmd='ampl?', get_parser=float)
         self.add_function('echo', call_cmd='echo {:.2f}?',
                           args=[Numbers(0, 1000)], return_parser=float)
-
-        super().__init__('meter', model=model, delay=0.001, **kwargs)
diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index 64ac7596576b..c33ad6b85311 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -1,7 +1,17 @@
 from unittest import TestCase
+from unittest.mock import patch
 import numpy as np
+from datetime import datetime
 
 from qcodes.data.data_array import DataArray
+from qcodes.data.manager import get_data_manager, NoData
+from qcodes.data.data_set import (load_data, new_data, DataMode, DataSet,
+                                  TimestampLocation)
+from qcodes.utils.helpers import killprocesses
+from qcodes import active_children
+
+from .data_mocks import (MockDataManager, MockFormatter, FullIO, EmptyIO,
+                         MissingMIO, MockLive, MockArray)
 
 
 class TestDataArray(TestCase):
@@ -123,7 +133,14 @@ def test_edit_and_mark(self):
 
         self.assertEqual(data.modified_range, (0, 2))
 
-        data.mark_saved()
+        # as if we saved the first two points... the third should still
+        # show as modified
+        data.mark_saved(1)
+        self.assertEqual(data.last_saved_index, 1)
+        self.assertEqual(data.modified_range, (2, 2))
+
+        # now we save the third point... no modifications left.
+        data.mark_saved(2)
         self.assertEqual(data.last_saved_index, 2)
         self.assertEqual(data.modified_range, None)
 
@@ -131,6 +148,23 @@ def test_edit_and_mark(self):
         self.assertEqual(data.last_saved_index, None)
         self.assertEqual(data.modified_range, (0, 2))
 
+    def test_edit_and_mark_slice(self):
+        data = DataArray(preset_data=[[1] * 5] * 6)
+
+        self.assertEqual(data.size, (6, 5))
+        self.assertEqual(data.modified_range, None)
+
+        data[:4:2, 2:] = 2
+        self.assertEqual(data.tolist(), [
+            [1, 1, 2, 2, 2],
+            [1, 1, 1, 1, 1],
+            [1, 1, 2, 2, 2],
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1]
+        ])
+        self.assertEqual(data.modified_range, (2, 14))
+
     def test_repr(self):
         array2d = [[1, 2], [3, 4]]
         arrayrepr = repr(np.array(array2d))
@@ -198,3 +232,222 @@ def test_data_set_property(self):
         self.assertIsNone(data.data_set)
         data.data_set = mock_data_set2
         self.assertEqual(data.data_set, mock_data_set2)
+
+
+class TestLoadData(TestCase):
+    def setUp(self):
+        killprocesses()
+
+    def test_no_live_data(self):
+        # live data with no DataManager at all
+        with self.assertRaises(RuntimeError):
+            load_data()
+        self.assertEqual(len(active_children()), 0)
+
+        # now make a DataManager and try again
+        get_data_manager()
+        self.assertEqual(len(active_children()), 1)
+        # same result but different code path
+        with self.assertRaises(RuntimeError):
+            load_data()
+
+    def test_no_saved_data(self):
+        with self.assertRaises(IOError):
+            load_data('_no/such/file_')
+
+    def test_load_false(self):
+        with self.assertRaises(ValueError):
+            load_data(False)
+
+    def test_get_live(self):
+        loc = 'live from New York!'
+
+        class MockLive:
+            pass
+
+        live_data = MockLive()
+
+        dm = MockDataManager()
+        dm.location = loc
+        dm.live_data = live_data
+
+        data = load_data(data_manager=dm, location=loc)
+        self.assertEqual(data, live_data)
+
+        for nd in (None, NoData()):
+            dm.live_data = nd
+            with self.assertRaises(RuntimeError):
+                load_data(data_manager=dm, location=loc)
+            with self.assertRaises(RuntimeError):
+                load_data(data_manager=dm)
+
+    def test_get_read(self):
+        dm = MockDataManager()
+        dm.location = 'somewhere else'
+
+        data = load_data(formatter=MockFormatter(), data_manager=dm,
+                         location='here!')
+        self.assertEqual(data.has_read_data, True)
+
+
+class TestNewData(TestCase):
+    def setUp(self):
+        killprocesses()
+        self.original_lp = DataSet.location_provider
+
+    def tearDown(self):
+        DataSet.location_provider = self.original_lp
+
+    def test_overwrite(self):
+        io = FullIO()
+
+        with self.assertRaises(FileExistsError):
+            new_data(location='somewhere', io=io, data_manager=False)
+
+        data = new_data(location='somewhere', io=io, overwrite=True,
+                        data_manager=False)
+        self.assertEqual(data.location, 'somewhere')
+
+    def test_mode_error(self):
+        with self.assertRaises(ValueError):
+            new_data(mode=DataMode.PUSH_TO_SERVER, data_manager=False)
+
+    def test_location_functions(self):
+        def my_location(io, name):
+            return 'data/{}'.format(name or 'LOOP!')
+
+        def my_location2(io, name):
+            return 'data/{}/folder'.format(name or 'loop?')
+
+        DataSet.location_provider = my_location
+
+        self.assertEqual(new_data(data_manager=False).location, 'data/LOOP!')
+        self.assertEqual(new_data(data_manager=False, name='cheese').location,
+                         'data/cheese')
+
+        data = new_data(data_manager=False, location=my_location2)
+        self.assertEqual(data.location, 'data/loop?/folder')
+        data = new_data(data_manager=False, location=my_location2,
+                        name='iceCream')
+        self.assertEqual(data.location, 'data/iceCream/folder')
+
+
+class TestTimestampLocation(TestCase):
+    default_fmt = TimestampLocation().fmt
+    custom_fmt = 'DATA%Y/%B/%d/%I%p'
+
+    def check_cases(self, tsl, fmt):
+        self.assertEqual(tsl(EmptyIO()),
+                         datetime.now().strftime(fmt))
+        self.assertEqual(tsl(EmptyIO(), 'who?'),
+                         datetime.now().strftime(fmt) + '_who?')
+
+        self.assertEqual(tsl(MissingMIO()),
+                         datetime.now().strftime(fmt) + '_m')
+        self.assertEqual(tsl(MissingMIO(), 'you!'),
+                         datetime.now().strftime(fmt) + '_you!_m')
+
+        with self.assertRaises(FileExistsError):
+            tsl(FullIO())
+        with self.assertRaises(FileExistsError):
+            tsl(FullIO(), 'some_name')
+
+    def test_default(self):
+        self.check_cases(TimestampLocation(), self.default_fmt)
+
+    def test_fmt(self):
+        self.check_cases(TimestampLocation(self.custom_fmt), self.custom_fmt)
+
+
+class TestDataSet(TestCase):
+    def tearDown(self):
+        killprocesses()
+
+    def test_constructor_errors(self):
+        # no location - only allowed with load_data
+        with self.assertRaises(ValueError):
+            DataSet()
+        # wrong type
+        with self.assertRaises(ValueError):
+            DataSet(location=42)
+
+        # OK to have location=False, but wrong mode
+        with self.assertRaises(ValueError):
+            DataSet(location=False, mode='happy')
+
+    @patch('qcodes.data.data_set.get_data_manager')
+    def test_from_server(self, gdm_mock):
+        mock_dm = MockDataManager()
+        gdm_mock.return_value = mock_dm
+        mock_dm.location = 'Mars'
+        mock_dm.live_data = MockLive()
+
+        # wrong location or False location - converts to local
+        data = DataSet(location='Jupiter', mode=DataMode.PULL_FROM_SERVER)
+        self.assertEqual(data.mode, DataMode.LOCAL)
+
+        data = DataSet(location=False, mode=DataMode.PULL_FROM_SERVER)
+        self.assertEqual(data.mode, DataMode.LOCAL)
+
+        # location matching server - stays in server mode
+        data = DataSet(location='Mars', mode=DataMode.PULL_FROM_SERVER,
+                       formatter=MockFormatter())
+        self.assertEqual(data.mode, DataMode.PULL_FROM_SERVER)
+        self.assertEqual(data.arrays, MockLive.arrays)
+
+        # cannot write except in LOCAL mode
+        with self.assertRaises(RuntimeError):
+            data.write()
+
+        # cannot finalize in PULL_FROM_SERVER mode
+        with self.assertRaises(RuntimeError):
+            data.finalize()
+
+        # now test when the server says it's not there anymore
+        mock_dm.location = 'Saturn'
+        data.sync()
+        self.assertEqual(data.mode, DataMode.LOCAL)
+        self.assertEqual(data.has_read_data, True)
+
+        # now it's LOCAL so we *can* write.
+        data.write()
+        self.assertEqual(data.has_written_data, True)
+
+        # location=False: write, read and sync are noops.
+        data.has_read_data = False
+        data.has_written_data = False
+        data.location = False
+        data.write()
+        data.read()
+        data.sync()
+        self.assertEqual(data.has_read_data, False)
+        self.assertEqual(data.has_written_data, False)
+
+    @patch('qcodes.data.data_set.get_data_manager')
+    def test_to_server(self, gdm_mock):
+        mock_dm = MockDataManager()
+        mock_dm.needs_restart = True
+        gdm_mock.return_value = mock_dm
+
+        data = DataSet(location='Venus', mode=DataMode.PUSH_TO_SERVER)
+        self.assertEqual(mock_dm.needs_restart, False, data)
+        self.assertEqual(mock_dm.data_set, data)
+        self.assertEqual(data.data_manager, mock_dm)
+        self.assertEqual(data.mode, DataMode.PUSH_TO_SERVER)
+
+        # cannot write except in LOCAL mode
+        with self.assertRaises(RuntimeError):
+            data.write()
+
+        # now do what the DataServer does with this DataSet: init_on_server
+        # fails until there is an array
+        with self.assertRaises(RuntimeError):
+            data.init_on_server()
+
+        data.add_array(MockArray())
+        data.init_on_server()
+        self.assertEqual(data.noise.ready, True)
+
+        # we can only add a given array_id once
+        with self.assertRaises(ValueError):
+            data.add_array(MockArray())
diff --git a/qcodes/tests/test_deferred_operations.py b/qcodes/tests/test_deferred_operations.py
new file mode 100644
index 000000000000..9521d43cd20e
--- /dev/null
+++ b/qcodes/tests/test_deferred_operations.py
@@ -0,0 +1,105 @@
+from unittest import TestCase
+
+from qcodes.utils.deferred_operations import DeferredOperations
+
+
+class TestDeferredOperations(TestCase):
+    def test_basic(self):
+        d = DeferredOperations(lambda: 5)
+        self.assertEqual(d(), 5)
+        self.assertEqual(d.get(), 5)
+
+    def test_errors(self):
+        with self.assertRaises(TypeError):
+            DeferredOperations(lambda: 5, args=(1,))
+
+        with self.assertRaises(TypeError):
+            DeferredOperations(10)
+
+        # this one doesn't cause errors on definition, only on calling
+        d = DeferredOperations(lambda: 1 / 0)
+        with self.assertRaises(ZeroDivisionError):
+            d()
+
+        # you shouldn't evaluate the truthiness of the DeferredOperations
+        # object itself, only after it's called
+        d = DeferredOperations(lambda: 5)
+        with self.assertRaises(TypeError):
+            if d:
+                pass
+
+    def test_unary(self):
+        d = DeferredOperations(lambda: -3)
+        f = DeferredOperations(lambda: 4.221)
+
+        self.assertEqual((abs(d))(), 3)
+        self.assertEqual((-d)(), 3)
+        self.assertEqual((+d)(), -3)
+        self.assertEqual((round(f))(), 4)
+
+    def test_binary_constants(self):
+        d = DeferredOperations(lambda: -3)
+        f = DeferredOperations(lambda: 4.221)
+
+        self.assertEqual((d == -3)(), True)
+        self.assertEqual((d == -4)(), False)
+        self.assertEqual((d != -3)(), False)
+        self.assertEqual((d != -4)(), True)
+        self.assertEqual((d > -4)(), True)
+        self.assertEqual((d > -3)(), False)
+        self.assertEqual((d >= -3)(), True)
+        self.assertEqual((d >= -2)(), False)
+        self.assertEqual((d < -3)(), False)
+        self.assertEqual((d < -2)(), True)
+        self.assertEqual((d <= -3)(), True)
+        self.assertEqual((d <= -4)(), False)
+        self.assertEqual((d + 5)(), 2)
+        self.assertEqual((d & 10)(), 10)
+        self.assertEqual((d | 10)(), -3)
+        self.assertEqual((d // 2)(), -2)
+        self.assertEqual((d % 5)(), 2)
+        self.assertEqual((d * 4)(), -12)
+        self.assertEqual((d ** 3)(), -27)
+        self.assertEqual((d - 10)(), -13)
+        self.assertEqual((d / 2)(), -1.5)
+        self.assertEqual((7 + d)(), 4)
+        self.assertEqual((7 - d)(), 10)
+        self.assertEqual((7 * d)(), -21)
+        self.assertEqual((1.5 / d)(), -0.5)
+        self.assertEqual((7 // d)(), -3)
+        self.assertEqual((7 % d)(), -2)
+        self.assertEqual((10 ** d)(), 0.001)
+        self.assertEqual((8 & d)(), -3)
+        self.assertEqual((8 | d)(), 8)
+        self.assertEqual((round(f, 1))(), 4.2)
+
+    def test_binary_both(self):
+        d4 = DeferredOperations(lambda: 4)
+        d5 = DeferredOperations(lambda: 5)
+
+        self.assertEqual((d4 == d5)(), False)
+        self.assertEqual((d4 != d5)(), True)
+        self.assertEqual((d4 > d5)(), False)
+        self.assertEqual((d4 >= d5)(), False)
+        self.assertEqual((d4 < d5)(), True)
+        self.assertEqual((d4 <= d5)(), True)
+        self.assertEqual((d4 + d5)(), 9)
+        self.assertEqual((d4 & d5)(), 5)
+        self.assertEqual((d4 | d5)(), 4)
+        self.assertEqual((d4 // d5)(), 0)
+        self.assertEqual((d4 % d5)(), 4)
+        self.assertEqual((d4 * d5)(), 20)
+        self.assertEqual((d4 ** d5)(), 1024)
+        self.assertEqual((d4 - d5)(), -1)
+        self.assertEqual((d4 / d5)(), 0.8)
+        self.assertEqual((round(d4, d5))(), 4)
+
+    def test_complicated(self):
+        d2 = DeferredOperations(lambda: 2)
+        d3 = DeferredOperations(lambda: 3)
+
+        self.assertEqual((d2 + (d2 + d2))(), 6)
+        self.assertEqual(((d2 < 5) & (d3 > 1))(), True)
+        self.assertEqual(((d2 + 5) ** (d3 - d2 + 1))(), 49)
+        self.assertEqual((2 * d2 * d3 * d3 * d2 * 5)(), 360)
+        self.assertEqual(((1 / d3) < (1 / d2))(), True)
diff --git a/qcodes/tests/test_format.py b/qcodes/tests/test_format.py
new file mode 100644
index 000000000000..8b58c4c7527e
--- /dev/null
+++ b/qcodes/tests/test_format.py
@@ -0,0 +1,407 @@
+from unittest import TestCase
+import os
+
+from qcodes.data.format import Formatter
+from qcodes.data.gnuplot_format import GNUPlotFormat
+from qcodes.data.data_array import DataArray
+from qcodes.data.data_set import DataSet, new_data
+from qcodes.utils.helpers import LogCapture
+
+from .data_mocks import DataSet1D, file_1d, DataSetCombined, files_combined
+
+
+class TestBaseFormatter(TestCase):
+    def setUp(self):
+        self.io = DataSet.default_io
+        self.locations = ('_simple1d_', '_combined_')
+
+        for location in self.locations:
+            self.assertFalse(self.io.list(location))
+
+    def tearDown(self):
+        for location in self.locations:
+            self.io.remove_all(location)
+
+    def test_overridable_methods(self):
+        formatter = Formatter()
+        data = DataSet1D()
+
+        with self.assertRaises(NotImplementedError):
+            formatter.write(data)
+        with self.assertRaises(NotImplementedError):
+            formatter.read_one_file(data, 'a file!', set())
+
+    def test_no_files(self):
+        formatter = Formatter()
+        data = DataSet1D(self.locations[0])
+        with self.assertRaises(IOError):
+            formatter.read(data)
+
+    def test_init_and_bad_read(self):
+        location = self.locations[0]
+        path = './{}/bad.dat'.format(location)
+
+        class MyFormatter(Formatter):
+            def read_one_file(self, data_set, f, ids_read):
+                s = f.read()
+                if 'garbage' not in s:
+                    raise Exception('reading the wrong file?')
+
+                # mark this file as read, before generating an error
+                if not hasattr(data_set, 'files_read'):
+                    data_set.files_read = []
+                data_set.files_read.append(f.name)
+                raise ValueError('garbage in, garbage out')
+
+        formatter = MyFormatter()
+        data = DataSet1D(location)
+        data.x.ndarray = None
+        data.y.ndarray = None
+
+        os.makedirs(os.path.dirname(path), exist_ok=True)
+        with open(path, 'w') as f:
+            f.write('garbage')
+
+        with LogCapture() as s:
+            formatter.read(data)
+        logstr = s.getvalue()
+        s.close()
+        # we tried to read this file but it generated an error
+        self.assertEqual(logstr.count('error reading file'), 1, logstr)
+        self.assertEqual(data.files_read, [os.path.abspath(path)])
+
+        expected_array_repr = repr([float('nan')] * 5)
+        self.assertEqual(repr(data.x.tolist()), expected_array_repr)
+        self.assertEqual(repr(data.y.tolist()), expected_array_repr)
+
+    def test_group_arrays(self):
+        formatter = Formatter()
+        data = DataSetCombined()
+
+        groups = formatter.group_arrays(data.arrays)
+
+        self.assertEqual(len(groups), 2, groups)
+        groups.sort(key=lambda grp: len(grp.set_arrays))
+
+        g1d, g2d = groups
+
+        self.assertEqual(g1d.size, (2,))
+        self.assertEqual(g1d.set_arrays, (data.x,))
+        self.assertEqual(g1d.data, (data.y1, data.y2))
+        self.assertEqual(g1d.name, 'x')
+
+        self.assertEqual(g2d.size, (2, 3))
+        self.assertEqual(g2d.set_arrays, (data.x, data.yset))
+        self.assertEqual(g2d.data, (data.z1, data.z2))
+        self.assertEqual(g2d.name, 'x_yset')
+
+    def test_match_save_range(self):
+        formatter = Formatter()
+        data = DataSet1D()
+
+        group = formatter.group_arrays(data.arrays)[0]
+
+        # no matter what else, if nothing is listed as modified
+        # then save_range is None
+        for lsi_x in [None, 0, 3]:
+            data.x.last_saved_index = lsi_x
+            for lsi_y in [None, 1, 4]:
+                data.y.last_saved_index = lsi_y
+                for fe in [True, False]:
+                    save_range = formatter.match_save_range(
+                        group, file_exists=fe)
+                    self.assertEqual(save_range, None)
+
+        # consistent last_saved_index: if it's None or within the
+        # modified range, or if file does not exist, we need to overwrite
+        # otherwise start just after last_saved_index
+        for lsi, start in [(None, 0), (0, 1), (1, 2), (2, 3), (3, 0), (4, 0)]:
+            data.x.last_saved_index = data.y.last_saved_index = lsi
+
+            # inconsistent modified_range: expands to greatest extent
+            # so these situations are identical
+            for xmr, ymr in ([(4, 4), (3, 3)], [(3, 4), None], [None, (3, 4)]):
+                data.x.modified_range = xmr
+                data.y.modified_range = ymr
+
+                save_range = formatter.match_save_range(group,
+                                                        file_exists=False)
+                self.assertEqual(save_range, (0, 4))
+
+                save_range = formatter.match_save_range(group,
+                                                        file_exists=True)
+                self.assertEqual(save_range, (start, 4))
+
+        # inconsistent last_saved_index: need to overwrite no matter what
+        data.x.last_saved_index = 1
+        data.y.last_saved_index = 2
+        save_range = formatter.match_save_range(group, file_exists=True)
+        self.assertEqual(save_range, (0, 4))
+
+        # missing data point: don't write it unless only_complete is False
+        # but this will only back up one point!
+        data.y[4] = float('nan')
+        data.y[3] = float('nan')
+        data.x.last_saved_index = data.y.last_saved_index = 2
+
+        save_range = formatter.match_save_range(group, file_exists=True)
+        self.assertEqual(save_range, (3, 3))
+
+        save_range = formatter.match_save_range(group, file_exists=True,
+                                                only_complete=False)
+        self.assertEqual(save_range, (3, 4))
+
+
+class TestGNUPlotFormat(TestCase):
+    def setUp(self):
+        self.io = DataSet.default_io
+        self.locations = ('_simple1d_', '_combined_')
+
+        for location in self.locations:
+            self.assertFalse(self.io.list(location))
+
+    def tearDown(self):
+        for location in self.locations:
+            self.io.remove_all(location)
+
+    def checkArraysEqual(self, a, b):
+        self.checkArrayAttrs(a, b)
+
+        self.assertEqual(len(a.set_arrays), len(b.set_arrays))
+        for sa, sb in zip(a.set_arrays, b.set_arrays):
+            self.checkArrayAttrs(sa, sb)
+
+    def checkArrayAttrs(self, a, b):
+        self.assertEqual(a.tolist(), b.tolist())
+        self.assertEqual(a.label, b.label)
+        self.assertEqual(a.array_id, b.array_id)
+
+    def test_full_write(self):
+        formatter = GNUPlotFormat()
+        location = self.locations[0]
+        data = DataSet1D(location)
+
+        # mark the data set as modified by... modifying it!
+        # without actually changing it :)
+        # TODO - are there cases we should automatically mark the data as
+        # modified on construction?
+        data.y[4] = data.y[4]
+
+        formatter.write(data)
+
+        with open(location + '/x.dat', 'r') as f:
+            self.assertEqual(f.read(), file_1d())
+
+        # check that we can add comment lines randomly into the file
+        # as long as it's after the first three lines, which are comments
+        # with well-defined meaning,
+        # and that we can un-quote the labels
+        lines = file_1d().split('\n')
+        lines[1] = lines[1].replace('"', '')
+        lines[3:3] = ['# this data is awesome!']
+        lines[6:6] = ['# the next point is my favorite.']
+        with open(location + '/x.dat', 'w') as f:
+            f.write('\n'.join(lines))
+
+        # normally this would be just done by data2 = load_data(location)
+        # but we want to work directly with the Formatter interface here
+        data2 = DataSet(location=location)
+        formatter.read(data2)
+
+        self.checkArraysEqual(data2.x, data.x)
+        self.checkArraysEqual(data2.y, data.y)
+
+        # while we're here, check some errors on bad reads
+
+        # first: trying to read into a dataset that already has the
+        # wrong size
+        x = DataArray(name='x', label='X', preset_data=(1., 2.))
+        y = DataArray(name='y', label='Y', preset_data=(3., 4.),
+                      set_arrays=(x,))
+        data3 = new_data(arrays=(x, y), location=location + 'XX')
+        # initially give it a different location so we can make it without
+        # error, then change back to the location we want.
+        data3.location = location
+        with LogCapture() as s:
+            formatter.read(data3)
+        logstr = s.getvalue()
+        s.close()
+        self.assertTrue('ValueError' in logstr, logstr)
+
+        # no problem reading again if only data has changed, it gets
+        # overwritten with the disk copy
+        data2.x[2] = 42
+        data2.y[2] = 99
+        formatter.read(data2)
+        self.assertEqual(data2.x[2], 3)
+        self.assertEqual(data2.y[2], 5)
+
+    def test_no_nest(self):
+        formatter = GNUPlotFormat(always_nest=False)
+        location = self.locations[0]
+        data = DataSet1D(location)
+
+        # mark the data set as modified by... modifying it!
+        # without actually changing it :)
+        # TODO - are there cases we should automatically mark the data as
+        # modified on construction?
+        data.y[4] = data.y[4]
+
+        formatter.write(data)
+
+        with open(location + '.dat', 'r') as f:
+            self.assertEqual(f.read(), file_1d())
+
+    def test_format_options(self):
+        formatter = GNUPlotFormat(extension='.splat', terminator='\r',
+                                  separator='  ', comment='?:',
+                                  number_format='5.2f')
+        location = self.locations[0]
+        data = DataSet1D(location)
+
+        # mark the data set as modified by... modifying it!
+        # without actually changing it :)
+        # TODO - are there cases we should automatically mark the data as
+        # modified on construction?
+        data.y[4] = data.y[4]
+
+        formatter.write(data)
+
+        # TODO - Python3 uses universal newlines for read and write...
+        # which means '\n' gets converted on write to the OS standard
+        # (os.linesep) and all of the options we support get converted
+        # back to '\n' on read. So I'm tempted to just take out terminator
+        # as an option rather than turn this feature off.
+        odd_format = '\n'.join([
+            '?:x  y',
+            '?:"X"  "Y"',
+            '?:5',
+            ' 1.00   3.00',
+            ' 2.00   4.00',
+            ' 3.00   5.00',
+            ' 4.00   6.00',
+            ' 5.00   7.00', ''])
+
+        with open(location + '/x.splat', 'r') as f:
+            self.assertEqual(f.read(), odd_format)
+
+    def add_star(self, path):
+        try:
+            with open(path, 'a') as f:
+                f.write('*')
+        except FileNotFoundError:
+            self.stars_before_write += 1
+
+    def test_incremental_write(self):
+        formatter = GNUPlotFormat()
+        location = self.locations[0]
+        data = DataSet1D(location)
+        path = location + '/x.dat'
+
+        data_copy = DataSet1D(False)
+
+        # empty the data and mark it as unmodified
+        data.x[:] = float('nan')
+        data.y[:] = float('nan')
+        data.x.modified_range = None
+        data.y.modified_range = None
+
+        # simulate writing after every value comes in, even within
+        # one row (x comes first, it's the setpoint)
+        # we'll add a '*' after each write and check that they're
+        # in the right places afterward, ie we don't write any given
+        # row until it's done and we never totally rewrite the file
+        self.stars_before_write = 0
+        for i, (x, y) in enumerate(zip(data_copy.x, data_copy.y)):
+            data.x[i] = x
+            formatter.write(data)
+            self.add_star(path)
+
+            data.y[i] = y
+            formatter.write(data)
+            self.add_star(path)
+
+        starred_file = '\n'.join([
+            '# x\ty',
+            '# "X"\t"Y"',
+            '# 5',
+            '1\t3',
+            '**2\t4',
+            '**3\t5',
+            '**4\t6',
+            '**5\t7', '*'])
+
+        with open(path, 'r') as f:
+            self.assertEqual(f.read(), starred_file)
+        self.assertEqual(self.stars_before_write, 1)
+
+    def test_constructor_errors(self):
+        with self.assertRaises(AttributeError):
+            # extension must be a string
+            GNUPlotFormat(extension=5)
+
+        with self.assertRaises(ValueError):
+            # terminator must be \r, \n, or \r\n
+            GNUPlotFormat(terminator='\n\r')
+
+        with self.assertRaises(ValueError):
+            # this is not CSV - separator must be whitespace
+            GNUPlotFormat(separator=',')
+
+        with self.assertRaises(ValueError):
+            GNUPlotFormat(comment='  \r\n\t  ')
+
+    def test_read_errors(self):
+        formatter = GNUPlotFormat()
+
+        # non-comment line at the beginning
+        location = self.locations[0]
+        data = DataSet(location=location)
+        os.makedirs(location, exist_ok=True)
+        with open(location + '/x.dat', 'w') as f:
+            f.write('1\t2\n' + file_1d())
+        with LogCapture() as s:
+            formatter.read(data)
+        logstr = s.getvalue()
+        s.close()
+        self.assertTrue('ValueError' in logstr, logstr)
+
+        # same data array in 2 files
+        location = self.locations[1]
+        data = DataSet(location=location)
+        os.makedirs(location, exist_ok=True)
+        with open(location + '/x.dat', 'w') as f:
+            f.write('\n'.join(['# x\ty', '# "X"\t"Y"', '# 2', '1\t2', '3\t4']))
+        with open(location + '/q.dat', 'w') as f:
+            f.write('\n'.join(['# q\ty', '# "Q"\t"Y"', '# 2', '1\t2', '3\t4']))
+        with LogCapture() as s:
+            formatter.read(data)
+        logstr = s.getvalue()
+        s.close()
+        self.assertTrue('ValueError' in logstr, logstr)
+
+    def test_multifile(self):
+        formatter = GNUPlotFormat(always_nest=False)  # will nest anyway
+        location = self.locations[1]
+        data = DataSetCombined(location)
+
+        # mark one array in each file as completely modified
+        # that should cause the whole files to be written, even though
+        # the other data and setpoint arrays are not marked as modified
+        data.y1[:] += 0
+        data.z1[:, :] += 0
+        formatter.write(data)
+
+        filex, filexy = files_combined()
+
+        with open(location + '/x.dat', 'r') as f:
+            self.assertEqual(f.read(), filex)
+        with open(location + '/x_yset.dat', 'r') as f:
+            self.assertEqual(f.read(), filexy)
+
+        data2 = DataSet(location=location)
+        formatter.read(data2)
+
+        for array_id in ('x', 'y1', 'y2', 'yset', 'z1', 'z2'):
+            self.checkArraysEqual(data2.arrays[array_id],
+                                  data.arrays[array_id])
diff --git a/qcodes/tests/test_helpers.py b/qcodes/tests/test_helpers.py
index 788b811d757a..17b3b3f56a81 100644
--- a/qcodes/tests/test_helpers.py
+++ b/qcodes/tests/test_helpers.py
@@ -3,9 +3,10 @@
 from datetime import datetime
 import asyncio
 
-from qcodes.utils.helpers import (is_function, is_sequence, permissive_range,
-                                  wait_secs, make_unique, DelegateAttributes,
+from qcodes.utils.helpers import (is_sequence, permissive_range, wait_secs,
+                                  make_unique, DelegateAttributes,
                                   LogCapture, strip_attrs)
+from qcodes.utils.deferred_operations import is_function
 
 
 class TestIsFunction(TestCase):
diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index 15727f6f2ac4..24da5e220352 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -65,6 +65,16 @@ def test_name_s(self):
         self.assertEqual(p.setpoint_names, setpoint_names)
         self.assertEqual(p.setpoint_labels, setpoint_labels)
 
+    def test_repr(self):
+        for i in [0, "foo", "", "fåil"]:
+            with self.subTest(i=i):
+                param = Parameter(name=i)
+                s = param.__repr__()
+                st = '<{}.{}: {} at {}>'.format(
+                    param.__module__, param.__class__.__name__,
+                    param.name, id(param))
+                self.assertEqual(s, st)
+
 
 class GatesBadDelayType(MockGates):
     def __init__(self, *args, **kwargs):
@@ -72,9 +82,9 @@ def __init__(self, *args, **kwargs):
         self.add_parameter('chan0bad', get_cmd='c0?',
                            set_cmd=self.slow_neg_set,
                            get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.01,
-                           max_sweep_delay='forever')
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.01,
+                           max_delay='forever')
 
 
 class GatesBadDelayValue(MockGates):
@@ -83,9 +93,9 @@ def __init__(self, *args, **kwargs):
         self.add_parameter('chan0bad', get_cmd='c0?',
                            set_cmd=self.slow_neg_set,
                            get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.05,
-                           max_sweep_delay=0.03)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.05,
+                           max_delay=0.03)
 
 
 class TestParameters(TestCase):
@@ -122,11 +132,19 @@ def test_slow_set(self):
         # at least for now, need a local instrument to test logging
         gatesLocal = MockGates(model=self.model, server_name=None)
         for param, logcount in (('chan0slow', 2), ('chan0slow2', 2),
-                                ('chan0slow3', 0)):
+                                ('chan0slow3', 0), ('chan0slow4', 1),
+                                ('chan0slow5', 0)):
             gatesLocal.chan0.set(-0.5)
 
             with LogCapture() as s:
-                gatesLocal.set(param, 0.5)
+                if param in ('chan0slow', 'chan0slow2', 'chan0slow3'):
+                    # these are the stepped parameters
+                    gatesLocal.set(param, 0.5)
+                else:
+                    # these are the non-stepped parameters that
+                    # still have delays
+                    gatesLocal.set(param, -1)
+                    gatesLocal.set(param, 1)
 
             logs = s.getvalue().split('\n')[:-1]
             s.close()
@@ -136,7 +154,7 @@ def test_slow_set(self):
             for line in logs:
                 self.assertTrue(line.startswith('negative delay'), line)
 
-    def test_max_sweep_delay_errors(self):
+    def test_max_delay_errors(self):
         with self.assertRaises(TypeError):
             # add_parameter works remotely with string commands, but
             # function commands are not going to be picklable, since they
@@ -339,7 +357,7 @@ def test_sweep_steps_edge_case(self):
         source.add_parameter('amplitude2', get_cmd='ampl?',
                              set_cmd='ampl:{}', get_parser=float,
                              vals=MultiType(Numbers(0, 1), Strings()),
-                             sweep_step=0.2, sweep_delay=0.02)
+                             step=0.2, delay=0.02)
         self.assertEqual(len(source.getattr('history')), 0)
 
         # 2 history items - get then set, and one warning (cannot sweep
@@ -361,52 +379,44 @@ def test_set_sweep_errors(self):
 
         # for reference, some add_parameter's that should work
         gates.add_parameter('t0', set_cmd='{}', vals=Numbers(),
-                            sweep_step=0.1, sweep_delay=0.01)
+                            step=0.1, delay=0.01)
         gates.add_parameter('t2', set_cmd='{}', vals=Ints(),
-                            sweep_step=1, sweep_delay=0.01,
+                            step=1, delay=0.01,
                             max_val_age=0)
 
         with self.assertRaises(TypeError):
             # can't sweep non-numerics
             gates.add_parameter('t1', set_cmd='{}', vals=Strings(),
-                                sweep_step=1, sweep_delay=0.01)
+                                step=1, delay=0.01)
         with self.assertRaises(TypeError):
             # need a numeric step too
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step='a skosh', sweep_delay=0.01)
+                                step='a skosh', delay=0.01)
         with self.assertRaises(TypeError):
             # Ints requires and int step
             gates.add_parameter('t1', set_cmd='{}', vals=Ints(),
-                                sweep_step=0.1, sweep_delay=0.01)
-        with self.assertRaises(ValueError):
-            # need a positive step
-            gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0, sweep_delay=0.01)
+                                step=0.1, delay=0.01)
         with self.assertRaises(ValueError):
-            # need a positive step
+            # need a non-negative step
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=-0.1, sweep_delay=0.01)
+                                step=-0.1, delay=0.01)
         with self.assertRaises(TypeError):
             # need a numeric delay
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay='a tad')
-        with self.assertRaises(ValueError):
-            # need a positive delay
-            gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=-0.01)
+                                step=0.1, delay='a tad')
         with self.assertRaises(ValueError):
-            # need a positive delay
+            # need a non-negative delay
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=0)
+                                step=0.1, delay=-0.01)
         with self.assertRaises(TypeError):
             # need a numeric max_val_age
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=0.01,
+                                step=0.1, delay=0.01,
                                 max_val_age='an hour')
         with self.assertRaises(ValueError):
             # need a non-negative max_val_age
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=0.01,
+                                step=0.1, delay=0.01,
                                 max_val_age=-1)
 
     def getmem(self, key):
@@ -661,6 +671,21 @@ def test_manual_parameter(self):
                                       parameter_class=ManualParameter,
                                       initial_value='nearsighted')
 
+    def test_deferred_ops(self):
+        gates = self.gates
+        c0, c1, c2 = gates.chan0, gates.chan1, gates.chan2
+
+        c0.set(0)
+        c1.set(1)
+        c2.set(2)
+
+        self.assertEqual((c0 + c1 + c2)(), 3)
+        self.assertEqual((10 + (c0**2) + (c1**2) + (c2**2))(), 15)
+
+        d = c1.get_latest / c0.get_latest
+        with self.assertRaises(ZeroDivisionError):
+            d()
+
 
 class TestAttrAccess(TestCase):
     def tearDown(self):
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index e08711b9ca17..c1d4a48d4a03 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -1,9 +1,11 @@
 from unittest import TestCase
+from unittest.mock import patch
 import time
 import multiprocessing as mp
 import numpy as np
 
-from qcodes.loops import Loop, MP_NAME, get_bg, halt_bg, Task, Wait, ActiveLoop
+from qcodes.loops import (Loop, MP_NAME, get_bg, halt_bg, Task, Wait,
+                          ActiveLoop, BreakIf)
 from qcodes.station import Station
 from qcodes.data.io import DiskIO
 from qcodes.data.data_array import DataArray
@@ -11,7 +13,7 @@
 from qcodes.instrument.parameter import Parameter, ManualParameter
 from qcodes.utils.multiprocessing import QcodesProcess
 from qcodes.utils.validators import Numbers
-from qcodes.utils.helpers import killprocesses
+from qcodes.utils.helpers import killprocesses, LogCapture
 from .instrument_mocks import AMockModel, MockGates, MockSource, MockMeter
 
 
@@ -33,46 +35,100 @@ def setUp(self):
         self.location2 = '_loop_test2_'
         self.io = DiskIO('.')
 
+        c1 = self.gates.chan1
+        self.loop = Loop(c1[1:5:1], 0.001).each(c1)
+
+        self.assertFalse(self.io.list(self.location))
+        self.assertFalse(self.io.list(self.location2))
+
     def tearDown(self):
         for instrument in [self.gates, self.source, self.meter]:
             instrument.close()
 
+        get_data_manager().close()
+        self.model.close()
+
         self.io.remove_all(self.location)
         self.io.remove_all(self.location2)
 
-    def test_instruments_in_loop(self):
+    def check_empty_data(self, data):
+        expected = repr([float('nan')] * 4)
+        self.assertEqual(repr(data.chan1.tolist()), expected)
+        self.assertEqual(repr(data.chan1_set.tolist()), expected)
+
+    def check_loop_data(self, data):
+        self.assertEqual(data.chan1.tolist(), [1, 2, 3, 4])
+        self.assertEqual(data.chan1_set.tolist(), [1, 2, 3, 4])
+
+        self.assertTrue(self.io.list(self.location))
+
+    def test_background_and_datamanager(self):
         # make sure that an unpicklable instrument can indeed run in a loop
-        self.assertFalse(self.io.list(self.location))
-        c1 = self.gates.chan1
-        loop = Loop(c1[1:5:1], 0.001).each(c1)
 
         # TODO: if we don't save the dataset (location=False) then we can't
         # sync it when we're done. Should fix that - for now that just means
         # you can only do in-memory loops if you set data_manager=False
         # TODO: this is the one place we don't do quiet=True - test that we
         # really print stuff?
-        data = loop.run(location=self.location)
+        data = self.loop.run(location=self.location)
+        self.check_empty_data(data)
 
         # wait for process to finish (ensures that this was run in the bg,
         # because otherwise there *is* no loop.process)
-        loop.process.join()
+        self.loop.process.join()
 
         data.sync()
+        self.check_loop_data(data)
 
-        self.assertEqual(data.chan1.tolist(), [1, 2, 3, 4])
-        self.assertEqual(data.chan1_set.tolist(), [1, 2, 3, 4])
+    def test_background_no_datamanager(self):
+        data = self.loop.run(location=self.location, data_manager=False,
+                             quiet=True)
+        self.check_empty_data(data)
 
-        self.assertTrue(self.io.list(self.location))
+        self.loop.process.join()
+
+        data.sync()
+        self.check_loop_data(data)
+
+    def test_foreground_and_datamanager(self):
+        data = self.loop.run(location=self.location, background=False,
+                             quiet=True)
+        self.assertFalse(hasattr(self.loop, 'process'))
+
+        self.check_loop_data(data)
+
+    def test_foreground_no_datamanager(self):
+        data = self.loop.run(location=self.location, background=False,
+                             data_manager=False, quiet=True)
+        self.assertFalse(hasattr(self.loop, 'process'))
+
+        self.check_loop_data(data)
 
     def test_enqueue(self):
         c1 = self.gates.chan1
         loop = Loop(c1[1:5:1], 0.01).each(c1)
-        loop.run(location=self.location, quiet=True)
+        data1 = loop.run(location=self.location, quiet=True)
+
+        # second running of the loop should be enqueued, blocks until
+        # the first one finishes.
+        # TODO: check what it prints?
+        data2 = loop.run(location=self.location2, quiet=True)
+
+        data1.sync()
+        data2.sync()
+        self.assertEqual(data1.chan1.tolist(), [1, 2, 3, 4])
+        for v in data2.chan1:
+            self.assertTrue(np.isnan(v))
 
-        with self.assertRaises(RuntimeError):
-            loop.run(location=self.location2, quiet=True)
-        loop.run(location=self.location2, quiet=True, enqueue=True)
         loop.process.join()
+        data2.sync()
+        self.assertEqual(data2.chan1.tolist(), [1, 2, 3, 4])
+
+        # and while we're here, check that running a loop in the
+        # foreground *after* the background clears its .process
+        self.assertTrue(hasattr(loop, 'process'))
+        loop.run_temp()
+        self.assertFalse(hasattr(loop, 'process'))
 
 
 def sleeper(t):
@@ -199,8 +255,14 @@ def test_tasks_waits(self):
         delay_array = []
         loop._monitor = FakeMonitor(delay_array)
 
+        # give it a "process" as if it was run in the bg before,
+        # check that this gets cleared
+        loop.process = 'TDD'
+
         data = loop.run_temp()
 
+        self.assertFalse(hasattr(loop, 'process'))
+
         self.assertEqual(data.p1.tolist(), [1, 2])
         self.assertEqual(data.p2_2.tolist(), [-1, -1])
         self.assertEqual(data.p2_4.tolist(), [1, 1])
@@ -211,6 +273,29 @@ def test_tasks_waits(self):
             self.assertLessEqual(delay, target)
             self.assertGreater(delay, target - 0.001)
 
+    @patch('time.sleep')
+    def test_delay0(self, sleep_mock):
+        self.p2.set(3)
+
+        loop = Loop(self.p1[1:3:1]).each(self.p2)
+
+        self.assertEqual(loop.delay, 0)
+
+        data = loop.run_temp()
+        self.assertEqual(data.p1.tolist(), [1, 2])
+        self.assertEqual(data.p2.tolist(), [3, 3])
+
+        self.assertEqual(sleep_mock.call_count, 0)
+
+    def test_bad_delay(self):
+        for val, err in [(-1, ValueError), (-0.1, ValueError),
+                         (None, TypeError), ('forever', TypeError)]:
+            with self.assertRaises(err):
+                Loop(self.p1[1:3:1], val)
+
+            with self.assertRaises(err):
+                Wait(val)
+
     def test_bare_wait(self):
         # Wait gets transformed to a Task, but is also callable on its own
         t0 = time.perf_counter()
@@ -310,15 +395,158 @@ def test_composite_params(self):
         self.assertEqual(data.index1.tolist(), [[[0, 1]] * 2] * 2)
 
     def test_bad_actors(self):
-        # would be nice to find errors at .each, but for now we find them
-        # at .run
-        loop = Loop(self.p1[1:3:1], 0.001).each(self.p1, 42)
-        with self.assertRaises(TypeError):
-            loop.run_temp()
+        def f():
+            return 42
+
+        class NoName:
+            def get(self):
+                return 42
+
+        class HasName:
+            def get(self):
+                return 42
+
+            name = 'IHazName!'
+
+        class HasNames:
+            def get(self):
+                return 42
+
+            names = 'Namezz'
+
+        # first two minimal working gettables
+        Loop(self.p1[1:3:1]).each(HasName())
+        Loop(self.p1[1:3:1]).each(HasNames())
+
+        for bad_action in (f, 42, NoName()):
+            with self.assertRaises(TypeError):
+                # include a good action too, just to make sure we look
+                # at the whole list
+                Loop(self.p1[1:3:1]).each(self.p1, bad_action)
 
-        # at least invalid sweep values we find at .each
         with self.assertRaises(ValueError):
-            Loop(self.p1[-20:20:1], 0.001).each(self.p1)
+            # invalid sweep values
+            Loop(self.p1[-20:20:1]).each(self.p1)
+
+    def test_very_short_delay(self):
+        with LogCapture() as s:
+            Loop(self.p1[1:3:1], 1e-9).each(self.p1).run_temp()
+
+        logstr = s.getvalue()
+        s.close()
+        self.assertEqual(logstr.count('negative delay'), 2, logstr)
+
+    def test_zero_delay(self):
+        with LogCapture() as s:
+            Loop(self.p1[1:3:1]).each(self.p1).run_temp()
+
+        logstr = s.getvalue()
+        s.close()
+        self.assertEqual(logstr.count('negative delay'), 0, logstr)
+
+    def test_breakif(self):
+        nan = float('nan')
+        loop = Loop(self.p1[1:6:1])
+        data = loop.each(self.p1, BreakIf(self.p1 >= 3)).run_temp()
+        self.assertEqual(repr(data.p1.tolist()),
+                         repr([1., 2., 3., nan, nan]))
+
+        data = loop.each(BreakIf(self.p1.get_latest >= 3), self.p1).run_temp()
+        self.assertEqual(repr(data.p1.tolist()),
+                         repr([1., 2., nan, nan, nan]))
+
+        with self.assertRaises(TypeError):
+            BreakIf(True)
+        with self.assertRaises(TypeError):
+            BreakIf(self.p1.set)
+
+    def test_then_construction(self):
+        loop = Loop(self.p1[1:6:1])
+        task1 = Task(self.p1.set, 2)
+        task2 = Wait(0.02)
+        loop2 = loop.then(task1)
+        loop3 = loop2.then(task2, task1)
+        loop4 = loop3.then(task2, overwrite=True)
+        loop5 = loop4.each(self.p1, BreakIf(self.p1 >= 3))
+        loop6 = loop5.then(task1)
+        loop7 = loop6.then(task1, overwrite=True)
+
+        # original loop is untouched, same as .each and .loop
+        self.assertEqual(loop.then_actions, ())
+
+        # but loop2 has the task we asked for
+        self.assertEqual(loop2.then_actions, (task1,))
+
+        # loop3 gets the other tasks appended
+        self.assertEqual(loop3.then_actions, (task1, task2, task1))
+
+        # loop4 gets only the new one
+        self.assertEqual(loop4.then_actions, (task2,))
+
+        # tasks survive .each
+        self.assertEqual(loop5.then_actions, (task2,))
+
+        # and ActiveLoop.then works the same way as Loop.then
+        self.assertEqual(loop6.then_actions, (task2, task1))
+        self.assertEqual(loop7.then_actions, (task1,))
+
+        # .then rejects Loops and others that are valid loop actions
+        for action in (loop2, loop7, BreakIf(self.p1 >= 3), self.p1,
+                       True, 42):
+            with self.assertRaises(TypeError):
+                loop.then(action)
+
+    def test_then_action(self):
+        nan = float('nan')
+        self.p1.set(5)
+        f_calls, g_calls = [], []
+
+        def f():
+            f_calls.append(1)
+
+        def g():
+            g_calls.append(1)
+
+        data = Loop(self.p1[1:6:1]).each(
+            self.p1, BreakIf(self.p1 >= 3)
+        ).then(
+            Task(self.p1.set, 2), Wait(0.01), Task(f)
+        ).run_temp()
+
+        self.assertEqual(repr(data.p1.tolist()),
+                         repr([1., 2., 3., nan, nan]))
+        self.assertEqual(self.p1.get(), 2)
+        self.assertEqual(len(f_calls), 1)
+
+        # now test a nested loop with .then inside and outside
+        f_calls[:] = []
+
+        Loop(self.p1[1:3:1]).each(
+            Loop(self.p2[1:3:1]).each(self.p2).then(Task(g))
+        ).then(Task(f)).run_temp()
+
+        self.assertEqual(len(f_calls), 1)
+        self.assertEqual(len(g_calls), 2)
+
+        # Loop.loop nesting always just makes the .then actions run after
+        # the outer loop
+        f_calls[:] = []
+        Loop(self.p1[1:3:1]).then(Task(f)).loop(self.p2[1:3:1]).each(
+            self.p1
+        ).run_temp()
+        self.assertEqual(len(f_calls), 1)
+
+        f_calls[:] = []
+        Loop(self.p1[1:3:1]).loop(self.p2[1:3:1]).then(Task(f)).each(
+            self.p1
+        ).run_temp()
+        self.assertEqual(len(f_calls), 1)
+
+        f_calls[:] = []
+        Loop(self.p1[1:3:1]).loop(self.p2[1:3:1]).each(
+            self.p1
+        ).then(Task(f)).run_temp()
+        self.assertEqual(len(f_calls), 1)
 
 
 class AbortingGetter(ManualParameter):
diff --git a/qcodes/tests/test_multiprocessing.py b/qcodes/tests/test_multiprocessing.py
index 866cf7454059..ac720e5d0b9d 100644
--- a/qcodes/tests/test_multiprocessing.py
+++ b/qcodes/tests/test_multiprocessing.py
@@ -194,11 +194,14 @@ def test_qcodes_process(self, in_nb_patch):
                 sender('row row ')
                 sender('row your boat\n')
                 sender('gently down ')
+                time.sleep(0.01)
                 data = [line for line in self.sq.get().split('\n') if line]
                 expected = [
                     label + 'row row row your boat',
                     label + 'gently down '
                 ]
+                # TODO - intermittent error here
+                self.assertEqual(len(data), len(expected), data)
                 for line, expected_line in zip(data, expected):
                     self.assertIsNotNone(queue_format.match(line), data)
                     self.assertEqual(line[14:], expected_line, data)
@@ -211,6 +214,7 @@ def test_qcodes_process(self, in_nb_patch):
             p2.send_out('polo\n')  # we don't see these single terminators
             p1.send_out('marco\n')  # when we change streams
             p2.send_out('polo')
+            time.sleep(0.01)
 
             data = self.sq.get().split('\n')
             for line in data:
@@ -393,7 +397,8 @@ def test_mechanics(self):
                              '  OSError: your hard disk went floppy.')
         sm._error_queue.put(builtin_error_str)
         sm._response_queue.put(SERVER_ERR)
-        time.sleep(0.005)
+        while sm._error_queue.empty() or sm._response_queue.empty():
+            time.sleep(0.005)
         with self.assertRaises(OSError):
             sm.ask('which way does the wind blow?')
 
diff --git a/qcodes/tests/test_plots.py b/qcodes/tests/test_plots.py
new file mode 100644
index 000000000000..ff4408dc26f9
--- /dev/null
+++ b/qcodes/tests/test_plots.py
@@ -0,0 +1,44 @@
+from unittest import TestCase, skipIf
+
+try:
+    from qcodes.plots.pyqtgraph import QtPlot
+    noQtPlot = False
+except Exception:
+    noQtPlot = True
+
+try:
+    from qcodes.plots.matplotlib import MatPlot
+    import matplotlib.pyplot as plt
+    noMatPlot = False
+except Exception:
+    noMatPlot = True
+
+
+@skipIf(noQtPlot, '***pyqtgraph plotting cannot be tested***')
+class TestQtPlot(TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_creation(self):
+        ''' Simple test function which created a QtPlot window '''
+        plotQ = QtPlot(remote=False, show_window=False, interval=0)
+        _ = plotQ.add_subplot()
+
+
+@skipIf(noMatPlot, '***matplotlib plotting cannot be tested***')
+class TestMatPlot(TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_creation(self):
+        ''' Simple test function which created a QtPlot window '''
+        plotM = MatPlot(interval=0)
+        plt.close(plotM.fig)
diff --git a/qcodes/tests/test_validators.py b/qcodes/tests/test_validators.py
index 18ddd276353f..ac3ccd440efb 100644
--- a/qcodes/tests/test_validators.py
+++ b/qcodes/tests/test_validators.py
@@ -1,5 +1,6 @@
 from unittest import TestCase
 import math
+import numpy 
 
 from qcodes.utils.validators import (Validator, Anything, Bool, Strings,
                                      Numbers, Ints, Enum, MultiType)
@@ -174,7 +175,10 @@ class TestNumbers(TestCase):
                # warning: True==1 and False==0
                True, False,
                # warning: +/- inf are allowed if max & min are not specified!
-               -float("inf"), float("inf")]
+               -float("inf"), float("inf"),
+                # numpy scalars
+               numpy.int64(36), numpy.float32(-1.123)
+                ]
     not_numbers = ['', None, '1', [], {}, [1, 2], {1: 1},
                    b'good', AClass, AClass(), a_func]
 
@@ -264,7 +268,9 @@ class TestInts(TestCase):
     ints = [0, 1, 10, -1, 100, 1000000, int(-1e15), int(1e15),
             # warning: True==1 and False==0 - we *could* prohibit these, using
             # isinstance(v, bool)
-            True, False]
+            True, False,
+            # numpy scalars
+            numpy.int64(3)]
     not_ints = [0.1, -0.1, 1.0, 3.5, -2.3e6, 5.5e15, 1.34e-10, -2.5e-5,
                 math.pi, math.e, '', None, float("nan"), float("inf"),
                 -float("inf"), '1', [], {}, [1, 2], {1: 1}, b'good',
diff --git a/qcodes/tests/test_visa.py b/qcodes/tests/test_visa.py
new file mode 100644
index 000000000000..e07ee6363434
--- /dev/null
+++ b/qcodes/tests/test_visa.py
@@ -0,0 +1,149 @@
+from unittest import TestCase
+import visa
+from qcodes.instrument.visa import VisaInstrument
+from qcodes.utils.validators import Numbers
+
+
+class MockVisa(VisaInstrument):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.add_parameter('state',
+                           get_cmd='STAT?', get_parser=float,
+                           set_cmd='STAT:{:.3f}',
+                           vals=Numbers(-20, 20))
+
+    def set_address(self, address):
+        self.visa_handle = MockVisaHandle()
+
+
+class MockVisaHandle:
+    '''
+    mock the API needed for a visa handle that throws lots of errors:
+    - any write command sets a single "state" variable to a float
+      after the last : in the command
+      - a negative number results in an error raised here
+      - 0 results in a return code for visa timeout
+
+    - any ask command returns the state
+      - a state > 10 throws an error
+    '''
+    def __init__(self):
+        self.state = 0
+
+    def clear(self):
+        self.state = 0
+
+    def close(self):
+        # make it an error to ask or write after close
+        self.write = None
+        self.ask = None
+
+    def write(self, cmd):
+        num = float(cmd.split(':')[-1])
+        self.state = num
+
+        if num < 0:
+            raise ValueError('be more positive!')
+
+        if num == 0:
+            ret_code = visa.constants.VI_ERROR_TMO
+        else:
+            ret_code = 0
+
+        return len(cmd), ret_code
+
+    def ask(self, cmd):
+        if self.state > 10:
+            raise ValueError("I'm out of fingers")
+        return self.state
+
+
+class TestVisaInstrument(TestCase):
+    def test_default_server_name(self):
+        dsn = VisaInstrument.default_server_name
+        self.assertEqual(dsn(), 'VisaServer')
+        self.assertEqual(dsn(address='Gpib::10'), 'GPIBServer')
+        self.assertEqual(dsn(address='aSRL4'), 'SerialServer')
+
+    # error args for set(-10)
+    args1 = [
+        'be more positive!',
+        "writing 'STAT:-10.000' to ",
+        'setting Joe:state to -10'
+    ]
+
+    # error args for set(0)
+    args2 = [
+        "writing 'STAT:0.000' to ",
+        'setting Joe:state to 0'
+    ]
+
+    # error args for get -> 15
+    args3 = [
+        "I'm out of fingers",
+        "asking 'STAT?' to ",
+        'getting Joe:state'
+    ]
+
+    def test_ask_write_local(self):
+        mv = MockVisa('Joe', server_name=None)
+
+        # test normal ask and write behavior
+        mv.state.set(2)
+        self.assertEqual(mv.state.get(), 2)
+        mv.state.set(3.4567)
+        self.assertEqual(mv.state.get(), 3.457)  # driver rounds to 3 digits
+
+        # test ask and write errors
+        with self.assertRaises(ValueError) as e:
+            mv.state.set(-10)
+        for arg in self.args1:
+            self.assertIn(arg, e.exception.args)
+        self.assertEqual(mv.state.get(), -10)  # set still happened
+
+        with self.assertRaises(visa.VisaIOError) as e:
+            mv.state.set(0)
+        for arg in self.args2:
+            self.assertIn(arg, e.exception.args)
+        self.assertEqual(mv.state.get(), 0)
+
+        mv.state.set(15)
+        with self.assertRaises(ValueError) as e:
+            mv.state.get()
+        for arg in self.args3:
+            self.assertIn(arg, e.exception.args)
+
+    def test_ask_write_server(self):
+        # same thing as above but Joe is on a server now...
+        mv = MockVisa('Joe')
+
+        # test normal ask and write behavior
+        mv.state.set(2)
+        self.assertEqual(mv.state.get(), 2)
+        mv.state.set(3.4567)
+        self.assertEqual(mv.state.get(), 3.457)  # driver rounds to 3 digits
+
+        # test ask and write errors
+        with self.assertRaises(ValueError) as e:
+            mv.state.set(-10)
+        for arg in self.args1:
+            self.assertIn(repr(arg), e.exception.args[0])
+        self.assertEqual(mv.state.get(), -10)  # set still happened
+
+        # only built-in errors get propagated to the main process as the
+        # same type. Perhaps we could include some more common ones like
+        # this (visa.VisaIOError) in the future...
+        with self.assertRaises(RuntimeError) as e:
+            mv.state.set(0)
+        for arg in self.args2:
+            self.assertIn(repr(arg), e.exception.args[0])
+        # the error type isn't VisaIOError, but it should be in the message
+        self.assertIn('VisaIOError', e.exception.args[0])
+        self.assertIn('VI_ERROR_TMO', e.exception.args[0])
+        self.assertEqual(mv.state.get(), 0)
+
+        mv.state.set(15)
+        with self.assertRaises(ValueError) as e:
+            mv.state.get()
+        for arg in self.args3:
+            self.assertIn(repr(arg), e.exception.args[0])
diff --git a/qcodes/utils/deferred_operations.py b/qcodes/utils/deferred_operations.py
new file mode 100644
index 000000000000..9948de135fe5
--- /dev/null
+++ b/qcodes/utils/deferred_operations.py
@@ -0,0 +1,259 @@
+import operator
+from asyncio import iscoroutinefunction
+from inspect import signature
+
+
+def is_function(f, arg_count, coroutine=False):
+    '''
+    require a function that can accept the specified number of positional
+    arguments, which either is or is not a coroutine
+    type casting "functions" are allowed, but only in the 1-argument form
+    '''
+    if not isinstance(arg_count, int) or arg_count < 0:
+        raise TypeError('arg_count must be a non-negative integer')
+
+    if not (callable(f) and bool(coroutine) is iscoroutinefunction(f)):
+        return False
+
+    # shouldn't need to do this, but is_function fails for a
+    # DeferredOperations object, as signature implicitly does ==
+    # with it.
+    if isinstance(f, DeferredOperations):
+        return arg_count == 0
+
+    if isinstance(f, type):
+        # for type casting functions, eg int, str, float
+        # only support the one-parameter form of these,
+        # otherwise the user should make an explicit function.
+        return arg_count == 1
+
+    try:
+        sig = signature(f)
+    except ValueError:
+        # some built-in functions/methods don't describe themselves to inspect
+        # we already know it's a callable and coroutine is correct.
+        return True
+
+    try:
+        inputs = [0] * arg_count
+        sig.bind(*inputs)
+        return True
+    except TypeError:
+        return False
+
+
+class DeferredOperations:
+    """
+    make math and logic operations return callables to defer execution
+    of arbitrary formulae
+
+    Can be used as a mixin class - in which case you should NOT call __init__
+    and you SHOULD override __call__ and get with identical results
+
+    call_func: a callable taking no arguments
+    call_parts: the original callables, in case we want to
+        record them all (ie raw data)
+
+    You can evaluate a DeferredOperations by calling it or
+    by calling its .get() method
+
+    examples:
+        d = DeferredOperations(lambda:42)
+        d() -> 42
+        (d*5)() -> 210
+        (d>10)() -> True
+        ((84/d) + (d*d))() -> 1766
+
+    NOTE: and & or are special: there are no magic methods for
+    the regular and & or, so we need to use the bitwise operators &,| as
+    boolean operators. We DO NOT short-circuit them; the right side is
+    always evaluated.
+    """
+    def __init__(self, call_func, args=(), call_parts=()):
+        self._validate_callable(call_func, len(args))
+        self.call_func = call_func
+        self.args = args
+        self.call_parts = call_parts
+
+    def __call__(self):
+        return self.call_func(*self.args)
+
+    def get(self):
+        return self.call_func(*self.args)
+
+    def __bool__(self):
+        raise TypeError('This is a DeferredOperations object, you must '
+                        'call or .get() it before testing its truthiness',
+                        self)
+
+    def _validate_callable(self, func, arg_count=0):
+        if not is_function(func, arg_count):
+            raise TypeError(
+                'function must be a callable taking '
+                '{} arguments, not {}'.format(arg_count, repr(func)))
+
+    def _call_unary(self, op):
+        return op(self())
+
+    def _unary(self, op):
+        if not getattr(self, 'call_parts', None):
+            self.call_parts = (self,)
+
+        return DeferredOperations(self._call_unary, (op,), self.call_parts)
+
+    def _call_binary_callable(self, op, other):
+        return op(self(), other())
+
+    def _call_binary_constant(self, op, other):
+        return op(self(), other)
+
+    def _binary(self, op, other):
+        if not getattr(self, 'call_parts', None):
+            self.call_parts = (self,)
+
+        if callable(other):
+            self._validate_callable(other)
+            other_parts = getattr(other, 'call_parts', (other,))
+            return DeferredOperations(self._call_binary_callable, (op, other),
+                                      self.call_parts + other_parts)
+
+        # TODO: any other types we should support?
+        elif isinstance(other, (int, float, str, type(None))):
+            return DeferredOperations(self._call_binary_constant, (op, other),
+                                      self.call_parts)
+        else:
+            raise TypeError(
+                'DeferredOperations are not compatible with '
+                '{}, type {}'.format(repr(other), repr(type(other))))
+
+    def __eq__(self, other):
+        return self._binary(operator.eq, other)
+
+    def __ne__(self, other):
+        return self._binary(operator.ne, other)
+
+    def __ge__(self, other):
+        return self._binary(operator.ge, other)
+
+    def __gt__(self, other):
+        return self._binary(operator.gt, other)
+
+    def __le__(self, other):
+        return self._binary(operator.le, other)
+
+    def __lt__(self, other):
+        return self._binary(operator.lt, other)
+
+    def __abs__(self):
+        return self._unary(operator.abs)
+
+    def __add__(self, other):
+        return self._binary(operator.add, other)
+
+    def __and__(self, other):
+        """
+        uses the bitwise and operator & to do boolean and
+        """
+        return self._binary(_and, other)
+
+    def __floordiv__(self, other):
+        return self._binary(operator.floordiv, other)
+
+    def __mod__(self, other):
+        return self._binary(operator.mod, other)
+
+    def __mul__(self, other):
+        return self._binary(operator.mul, other)
+
+    def __neg__(self):
+        return self._unary(operator.neg)
+
+    def __or__(self, other):
+        """
+        uses the bitwise or operator | to do boolean or
+        """
+        return self._binary(_or, other)
+
+    def __pos__(self):
+        return self._unary(operator.pos)
+
+    def __pow__(self, other):
+        return self._binary(operator.pow, other)
+
+    def __sub__(self, other):
+        return self._binary(operator.sub, other)
+
+    def __truediv__(self, other):
+        return self._binary(operator.truediv, other)
+
+    def __radd__(self, other):
+        return self._binary(operator.add, other)
+
+    def __rsub__(self, other):
+        return self._binary(_rsub, other)
+
+    def __rmul__(self, other):
+        return self._binary(operator.mul, other)
+
+    def __rtruediv__(self, other):
+        return self._binary(_rtruediv, other)
+
+    def __rfloordiv__(self, other):
+        return self._binary(_rfloordiv, other)
+
+    def __rmod__(self, other):
+        return self._binary(_rmod, other)
+
+    def __rpow__(self, other):
+        return self._binary(_rpow, other)
+
+    def __rand__(self, other):
+        return self._binary(_rand, other)
+
+    def __ror__(self, other):
+        return self._binary(_ror, other)
+
+    def __round__(self, other=None):
+        if other is None:
+            return self._unary(round)
+        else:
+            return self._binary(round, other)
+
+
+# functional forms not in the operator module, so we get
+# the order of arguments correct
+
+def _and(a, b):
+    return a and b
+
+
+def _rand(a, b):
+    return b and a
+
+
+def _or(a, b):
+    return a or b
+
+
+def _ror(a, b):
+    return b or a
+
+
+def _rsub(a, b):
+    return b - a
+
+
+def _rtruediv(a, b):
+    return b / a
+
+
+def _rfloordiv(a, b):
+    return b // a
+
+
+def _rmod(a, b):
+    return b % a
+
+
+def _rpow(a, b):
+    return b ** a
diff --git a/qcodes/utils/helpers.py b/qcodes/utils/helpers.py
index bcad2bbae92f..aa6b6e4c1677 100644
--- a/qcodes/utils/helpers.py
+++ b/qcodes/utils/helpers.py
@@ -1,7 +1,5 @@
-from asyncio import iscoroutinefunction
 from collections import Iterable
 import time
-from inspect import signature
 import logging
 import math
 import sys
@@ -11,7 +9,8 @@
 
 def in_notebook():
     '''
-    is this code in a process directly connected to a jupyter notebook?
+    Returns True if the code is running with a ipython or jypyter
+    This could mean we are connected to a notebook, but this is not guaranteed.
     see: http://stackoverflow.com/questions/15411967
     '''
     return 'ipy' in repr(sys.stdout)
@@ -26,39 +25,6 @@ def is_sequence(obj):
     return isinstance(obj, Iterable) and not isinstance(obj, (str, bytes))
 
 
-def is_function(f, arg_count, coroutine=False):
-    '''
-    require a function that can accept the specified number of positional
-    arguments, which either is or is not a coroutine
-    type casting "functions" are allowed, but only in the 1-argument form
-    '''
-    if not isinstance(arg_count, int) or arg_count < 0:
-        raise TypeError('arg_count must be a non-negative integer')
-
-    if not (callable(f) and bool(coroutine) is iscoroutinefunction(f)):
-        return False
-
-    if isinstance(f, type):
-        # for type casting functions, eg int, str, float
-        # only support the one-parameter form of these,
-        # otherwise the user should make an explicit function.
-        return arg_count == 1
-
-    try:
-        sig = signature(f)
-    except ValueError:
-        # some built-in functions/methods don't describe themselves to inspect
-        # we already know it's a callable and coroutine is correct.
-        return True
-
-    try:
-        inputs = [0] * arg_count
-        sig.bind(*inputs)
-        return True
-    except TypeError:
-        return False
-
-
 # could use numpy.arange here, but
 # a) we don't want to require that as a dep so low level
 # b) I'd like to be more flexible with the sign of step
diff --git a/qcodes/utils/metadata.py b/qcodes/utils/metadata.py
index d2f3fcdd78f7..9ae4a861fe9b 100644
--- a/qcodes/utils/metadata.py
+++ b/qcodes/utils/metadata.py
@@ -20,7 +20,7 @@ def snapshot(self, *args, **kwargs):
 
         return snap
 
-    def snapshot_base(self):
+    def snapshot_base(self, *args, **kwargs):
         '''
         override this with the primary information for a subclass
         '''
diff --git a/qcodes/utils/multiprocessing.py b/qcodes/utils/multiprocessing.py
index 091108424943..1c2fbcadd899 100644
--- a/qcodes/utils/multiprocessing.py
+++ b/qcodes/utils/multiprocessing.py
@@ -225,10 +225,11 @@ class ServerManager:
 
     name: the name of the server. Can include .format specs to insert
         all or part of the uuid
-    query_timeout: the default time to wait for responses
+    query_timeout: (default None) the default time to wait for responses
     kwargs: passed along to the server constructor
     '''
-    def __init__(self, name, server_class, shared_attrs=None, query_timeout=2):
+    def __init__(self, name, server_class, shared_attrs=None,
+                 query_timeout=None):
         self._query_queue = mp.Queue()
         self._response_queue = mp.Queue()
         self._error_queue = mp.Queue()
@@ -276,7 +277,7 @@ def write(self, *query):
         self._query_queue.put(query)
         self._check_for_errors()
 
-    def _check_for_errors(self, expect_error=False):
+    def _check_for_errors(self, expect_error=False, query=None):
         if expect_error or not self._error_queue.empty():
             # clear the response queue whenever there's an error
             # and give it a little time to flush first
@@ -297,12 +298,18 @@ def _check_for_errors(self, expect_error=False):
             if err_type is None or not issubclass(err_type, Exception):
                 err_type = RuntimeError
 
+            if query:
+                errhead += '\nwhile executing query: ' + repr(query)
+
             raise err_type(errhead + '\n\n' + errstr)
 
-    def _check_response(self, timeout):
+    def _check_response(self, timeout, query=None):
         res = self._response_queue.get(timeout=timeout)
         if res == SERVER_ERR:
-            self._expect_error = True
+            # TODO: I think the way we're doing this now, I could get rid of
+            # _error_queue completely and just have errors and regular
+            # responses labeled differently in _response_queue
+            self._check_for_errors(expect_error=True, query=query)
         return res
 
     def ask(self, *query, timeout=None):
@@ -323,16 +330,16 @@ def ask(self, *query, timeout=None):
             self._query_queue.put(query)
 
             try:
-                res = self._check_response(timeout)
+                res = self._check_response(timeout, query)
 
                 while not self._response_queue.empty():
-                    res = self._check_response(timeout)
+                    res = self._check_response(timeout, query)
 
             except Empty as e:
                 if self._error_queue.empty():
                     # only raise if we're not about to find a deeper error
                     raise e
-            self._check_for_errors(self._expect_error)
+            self._check_for_errors(query=query)
 
             return res
 
diff --git a/qcodes/utils/sync_async.py b/qcodes/utils/sync_async.py
index 1ab8fbb68b05..ad1e1ed22f80 100644
--- a/qcodes/utils/sync_async.py
+++ b/qcodes/utils/sync_async.py
@@ -1,6 +1,6 @@
 import asyncio
 
-from .helpers import is_function
+from .deferred_operations import is_function
 
 
 def wait_for_async(f, *args, **kwargs):
diff --git a/qcodes/utils/validators.py b/qcodes/utils/validators.py
index 990868305703..4d9aca3e427f 100644
--- a/qcodes/utils/validators.py
+++ b/qcodes/utils/validators.py
@@ -1,4 +1,5 @@
 import math
+import numpy
 
 BIGSTRING = 1000000000
 BIGINT = int(1e18)
@@ -132,19 +133,21 @@ class Numbers(Validator):
     min_value <= value <= max_value
     '''
 
+    validtypes = (float, int, numpy.integer, numpy.floating)
+
     def __init__(self, min_value=-float("inf"), max_value=float("inf")):
-        if isinstance(min_value, (float, int)):
+        if isinstance(min_value, self.validtypes):
             self._min_value = min_value
         else:
             raise TypeError('min_value must be a number')
 
-        if isinstance(max_value, (float, int)) and max_value > min_value:
+        if isinstance(max_value, self.validtypes) and max_value > min_value:
             self._max_value = max_value
         else:
             raise TypeError('max_value must be a number bigger than min_value')
 
     def validate(self, value, context=''):
-        if not isinstance(value, (float, int)):
+        if not isinstance(value, self.validtypes):
             raise TypeError(
                 '{} is not an int or float; {}'.format(repr(value), context))
 
@@ -169,22 +172,24 @@ class Ints(Validator):
     min_value <= value <= max_value
     '''
 
+    validtypes = (int, numpy.integer)
+
     def __init__(self, min_value=-BIGINT, max_value=BIGINT):
-        if isinstance(min_value, int):
-            self._min_value = min_value
+        if isinstance(min_value, self.validtypes):
+            self._min_value = int(min_value)
         else:
             raise TypeError('min_value must be an integer')
 
-        if not isinstance(max_value, int):
+        if not isinstance(max_value, self.validtypes):
             raise TypeError('max_value must be an integer')
         if max_value > min_value:
-            self._max_value = max_value
+            self._max_value = int(max_value)
         else:
             raise TypeError(
                 'max_value must be an integer bigger than min_value')
 
     def validate(self, value, context=''):
-        if not isinstance(value, int):
+        if not isinstance(value, self.validtypes):
             raise TypeError(
                 '{} is not an int; {}'.format(repr(value), context))
 
diff --git a/qcodes/version.py b/qcodes/version.py
new file mode 100644
index 000000000000..b794fd409a5e
--- /dev/null
+++ b/qcodes/version.py
@@ -0,0 +1 @@
+__version__ = '0.1.0'
diff --git a/setup.py b/setup.py
index 0079a6e9e3c1..233a7c1bbfb1 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,23 @@
 from setuptools import setup, find_packages
 from distutils.version import StrictVersion
 from importlib import import_module
+import re
+
+def get_version(verbose=1):
+    """ Extract version information from source code """
+
+    try:
+        with open('qcodes/version.py', 'r') as f:
+            ln = f.readline()
+            # print(ln)
+            m = re.search('.* ''(.*)''', ln)
+            version = (m.group(1)).strip('\'')
+    except Exception as E:
+        print(E)
+        version = 'none'
+    if verbose:
+        print('get_version: %s' % version)
+    return version
 
 
 def readme():
@@ -15,7 +32,7 @@ def readme():
 extras_require = {k: '>='.join(v) for k, v in extras.items()}
 
 setup(name='qcodes',
-      version='0.1.0',
+      version=get_version(),
       use_2to3=False,
       author='Alex Johnson',
       author_email='johnson.alex.c@gmail.com',
@@ -91,4 +108,5 @@ def readme():
     except ImportError:
         print(missing_template.format(module_name, extra))
     except ValueError:
-        print(valueerror_template.format(module_name, module.__version__, min_version, extra))
+        print(valueerror_template.format(
+            module_name, module.__version__, min_version, extra))