diff --git a/app/views/experiments/_instructions.html.erb b/app/views/experiments/_instructions.html.erb
new file mode 100644
index 0000000..8227fcd
--- /dev/null
+++ b/app/views/experiments/_instructions.html.erb
@@ -0,0 +1,3 @@
+
+ <%= instruction.order_number %> | <%= instruction.information %>
+
diff --git a/app/views/experiments/instructions.js b/app/views/experiments/instructions.js
new file mode 100644
index 0000000..5154cce
--- /dev/null
+++ b/app/views/experiments/instructions.js
@@ -0,0 +1,21 @@
+var ready, set_positions;
+
+set_positions = function(){
+
+ // loop through and give each task a data-pos
+ // attribute that holds its position in the DOM
+ $('.panel.panel-default').each(function(i){
+ $(this).attr("data-pos",i+1);
+ });
+}
+
+ready = function(){
+
+ // call set_positions function
+ set_positions();
+
+ $('.sortable').sortable();
+
+}
+
+$(document).ready(ready);
diff --git a/vendor/assets/javascripts/html.sortable.js b/vendor/assets/javascripts/html.sortable.js
new file mode 100644
index 0000000..8a31a86
--- /dev/null
+++ b/vendor/assets/javascripts/html.sortable.js
@@ -0,0 +1,398 @@
+/*
+ * HTML5 Sortable jQuery Plugin
+ * https://github.com/voidberg/html5sortable
+ *
+ * Original code copyright 2012 Ali Farhadi.
+ * This version is mantained by Alexandru Badiu & Lukas Oppermann
+ *
+ *
+ * Released under the MIT license.
+ */
+'use strict';
+/*
+ * variables global to the plugin
+ */
+var dragging;
+var draggingHeight;
+var placeholders = $();
+var sortables = [];
+/*
+ * remove event handlers from items
+ * @param [jquery Collection] items
+ * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event)
+ */
+var _removeItemEvents = function(items) {
+ items.off('dragstart.h5s');
+ items.off('dragend.h5s');
+ items.off('selectstart.h5s');
+ items.off('dragover.h5s');
+ items.off('dragenter.h5s');
+ items.off('drop.h5s');
+};
+/*
+ * remove event handlers from sortable
+ * @param [jquery Collection] sortable
+ * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event)
+ */
+var _removeSortableEvents = function(sortable) {
+ sortable.off('dragover.h5s');
+ sortable.off('dragenter.h5s');
+ sortable.off('drop.h5s');
+};
+/*
+ * attache ghost to dataTransfer object
+ * @param [event] original event
+ * @param [object] ghost-object with item, x and y coordinates
+ */
+var _attachGhost = function(event, ghost) {
+ // this needs to be set for HTML5 drag & drop to work
+ event.dataTransfer.effectAllowed = 'move';
+ event.dataTransfer.setData('text', '');
+
+ // check if setDragImage method is available
+ if (event.dataTransfer.setDragImage) {
+ event.dataTransfer.setDragImage(ghost.item, ghost.x, ghost.y);
+ }
+};
+/**
+ * _addGhostPos clones the dragged item and adds it as a Ghost item
+ * @param [object] event - the event fired when dragstart is triggered
+ * @param [object] ghost - .item = node, draggedItem = jQuery collection
+ */
+var _addGhostPos = function(e, ghost) {
+ if (!ghost.x) {
+ ghost.x = parseInt(e.pageX - ghost.draggedItem.offset().left);
+ }
+ if (!ghost.y) {
+ ghost.y = parseInt(e.pageY - ghost.draggedItem.offset().top);
+ }
+ return ghost;
+};
+/**
+ * _makeGhost decides which way to make a ghost and passes it to attachGhost
+ * @param [jQuery selection] $draggedItem - the item that the user drags
+ */
+var _makeGhost = function($draggedItem) {
+ return {
+ item: $draggedItem[0],
+ draggedItem: $draggedItem
+ };
+};
+/**
+ * _getGhost constructs ghost and attaches it to dataTransfer
+ * @param [event] event - the original drag event object
+ * @param [jQuery selection] $draggedItem - the item that the user drags
+ * @param [object] ghostOpt - the ghost options
+ */
+// TODO: could $draggedItem be replaced by event.target in all instances
+var _getGhost = function(event, $draggedItem) {
+ // add ghost item & draggedItem to ghost object
+ var ghost = _makeGhost($draggedItem);
+ // attach ghost position
+ ghost = _addGhostPos(event, ghost);
+ // attach ghost to dataTransfer
+ _attachGhost(event, ghost);
+};
+/*
+ * return options if not set on sortable already
+ * @param [object] soptions
+ * @param [object] options
+ */
+var _getOptions = function(soptions, options) {
+ if (typeof soptions === 'undefined') {
+ return options;
+ }
+ return soptions;
+};
+/*
+ * remove data from sortable
+ * @param [jquery Collection] a single sortable
+ */
+var _removeSortableData = function(sortable) {
+ sortable.removeData('opts');
+ sortable.removeData('connectWith');
+ sortable.removeData('items');
+ sortable.removeAttr('aria-dropeffect');
+};
+/*
+ * remove data from items
+ * @param [jquery Collection] items
+ */
+var _removeItemData = function(items) {
+ items.removeAttr('aria-grabbed');
+ items.removeAttr('draggable');
+ items.removeAttr('role');
+};
+/*
+ * check if two lists are connected
+ * @param [jquery Collection] items
+ */
+var _listsConnected = function(curList, destList) {
+ if (curList[0] === destList[0]) {
+ return true;
+ }
+ if (curList.data('connectWith') !== undefined) {
+ return curList.data('connectWith') === destList.data('connectWith');
+ }
+ return false;
+};
+/*
+ * destroy the sortable
+ * @param [jquery Collection] a single sortable
+ */
+var _destroySortable = function(sortable) {
+ var opts = sortable.data('opts') || {};
+ var items = sortable.children(opts.items);
+ var handles = opts.handle ? items.find(opts.handle) : items;
+ // remove event handlers & data from sortable
+ _removeSortableEvents(sortable);
+ _removeSortableData(sortable);
+ // remove event handlers & data from items
+ handles.off('mousedown.h5s');
+ _removeItemEvents(items);
+ _removeItemData(items);
+};
+/*
+ * enable the sortable
+ * @param [jquery Collection] a single sortable
+ */
+var _enableSortable = function(sortable) {
+ var opts = sortable.data('opts');
+ var items = sortable.children(opts.items);
+ var handles = opts.handle ? items.find(opts.handle) : items;
+ sortable.attr('aria-dropeffect', 'move');
+ handles.attr('draggable', 'true');
+ // IE FIX for ghost
+ if (typeof document.createElement('span').dragDrop === 'function') {
+ handles.on('mousedown.h5s', function() {
+ if (items.index(this) !== -1) {
+ this.dragDrop();
+ } else {
+ $(this).parents(opts.items)[0].dragDrop();
+ }
+ });
+ }
+};
+/*
+ * disable the sortable
+ * @param [jquery Collection] a single sortable
+ */
+var _disableSortable = function(sortable) {
+ var opts = sortable.data('opts');
+ var items = sortable.children(opts.items);
+ var handles = opts.handle ? items.find(opts.handle) : items;
+ sortable.attr('aria-dropeffect', 'none');
+ handles.attr('draggable', false);
+ handles.off('mousedown.h5s');
+};
+/*
+ * reload the sortable
+ * @param [jquery Collection] a single sortable
+ * @description events need to be removed to not be double bound
+ */
+var _reloadSortable = function(sortable) {
+ var opts = sortable.data('opts');
+ var items = sortable.children(opts.items);
+ var handles = opts.handle ? items.find(opts.handle) : items;
+ // remove event handlers from items
+ _removeItemEvents(items);
+ handles.off('mousedown.h5s');
+ // remove event handlers from sortable
+ _removeSortableEvents(sortable);
+};
+/*
+ * public sortable object
+ * @param [object|string] options|method
+ */
+var sortable = function(selector, options) {
+
+ var $sortables = $(selector);
+ var method = String(options);
+
+ options = $.extend({
+ connectWith: false,
+ placeholder: null,
+ // dragImage can be null or a jQuery element
+ dragImage: null,
+ placeholderClass: 'sortable-placeholder',
+ draggingClass: 'sortable-dragging'
+ }, options);
+
+ /* TODO: maxstatements should be 25, fix and remove line below */
+ /*jshint maxstatements:false */
+ return $sortables.each(function() {
+
+ var $sortable = $(this);
+
+ if (/enable|disable|destroy/.test(method)) {
+ sortable[method]($sortable);
+ return;
+ }
+
+ // get options & set options on sortable
+ options = _getOptions($sortable.data('opts'), options);
+ $sortable.data('opts', options);
+ // reset sortable
+ _reloadSortable($sortable);
+ // initialize
+ var items = $sortable.children(options.items);
+ var index;
+ var startParent;
+ var newParent;
+ var placeholder = (options.placeholder === null) ? $('<' + (/^ul|ol$/i.test(this.tagName) ? 'li' : 'div') + ' class="' + options.placeholderClass + '"/>') : $(options.placeholder).addClass(options.placeholderClass);
+
+ // setup sortable ids
+ if (!$sortable.attr('data-sortable-id')) {
+ var id = sortables.length;
+ sortables[id] = $sortable;
+ $sortable.attr('data-sortable-id', id);
+ items.attr('data-item-sortable-id', id);
+ }
+
+ $sortable.data('items', options.items);
+ placeholders = placeholders.add(placeholder);
+ if (options.connectWith) {
+ $sortable.data('connectWith', options.connectWith);
+ }
+
+ _enableSortable($sortable);
+ items.attr('role', 'option');
+ items.attr('aria-grabbed', 'false');
+
+ // Handle drag events on draggable items
+ items.on('dragstart.h5s', function(e) {
+ e.stopImmediatePropagation();
+
+ if (options.dragImage) {
+ _attachGhost(e.originalEvent, {
+ item: options.dragImage,
+ x: 0,
+ y: 0
+ });
+ console.log('WARNING: dragImage option is deprecated' +
+ ' and will be removed in the future!');
+ } else {
+ // add transparent clone or other ghost to cursor
+ _getGhost(e.originalEvent, $(this), options.dragImage);
+ }
+ // cache selsection & add attr for dragging
+ dragging = $(this);
+ dragging.addClass(options.draggingClass);
+ dragging.attr('aria-grabbed', 'true');
+ // grab values
+ index = dragging.index();
+ draggingHeight = dragging.height();
+ startParent = $(this).parent();
+ // trigger sortstar update
+ dragging.parent().triggerHandler('sortstart', {
+ item: dragging,
+ startparent: startParent
+ });
+ });
+ // Handle drag events on draggable items
+ items.on('dragend.h5s', function() {
+ if (!dragging) {
+ return;
+ }
+ // remove dragging attributes and show item
+ dragging.removeClass(options.draggingClass);
+ dragging.attr('aria-grabbed', 'false');
+ dragging.show();
+
+ placeholders.detach();
+ newParent = $(this).parent();
+ dragging.parent().triggerHandler('sortstop', {
+ item: dragging,
+ startparent: startParent,
+ });
+ if (index !== dragging.index() ||
+ startParent.get(0) !== newParent.get(0)) {
+ dragging.parent().triggerHandler('sortupdate', {
+ item: dragging,
+ index: newParent.children(newParent.data('items')).index(dragging),
+ oldindex: items.index(dragging),
+ elementIndex: dragging.index(),
+ oldElementIndex: index,
+ startparent: startParent,
+ endparent: newParent
+ });
+ }
+ dragging = null;
+ draggingHeight = null;
+ });
+ // Handle drop event on sortable & placeholder
+ // TODO: REMOVE placeholder?????
+ $(this).add([placeholder]).on('drop.h5s', function(e) {
+ if (!_listsConnected($sortable, $(dragging).parent())) {
+ return;
+ }
+
+ e.stopPropagation();
+ placeholders.filter(':visible').after(dragging);
+ dragging.trigger('dragend.h5s');
+ return false;
+ });
+
+ // Handle dragover and dragenter events on draggable items
+ // TODO: REMOVE placeholder?????
+ items.add([this, placeholder]).on('dragover.h5s dragenter.h5s', function(e) {
+ if (!_listsConnected($sortable, $(dragging).parent())) {
+ return;
+ }
+
+ e.preventDefault();
+ e.originalEvent.dataTransfer.dropEffect = 'move';
+ if (items.is(this)) {
+ var thisHeight = $(this).height();
+ if (options.forcePlaceholderSize) {
+ placeholder.height(draggingHeight);
+ }
+
+ // Check if $(this) is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering
+ if (thisHeight > draggingHeight) {
+ // Dead zone?
+ var deadZone = thisHeight - draggingHeight;
+ var offsetTop = $(this).offset().top;
+ if (placeholder.index() < $(this).index() &&
+ e.originalEvent.pageY < offsetTop + deadZone) {
+ return false;
+ }
+ if (placeholder.index() > $(this).index() &&
+ e.originalEvent.pageY > offsetTop + thisHeight - deadZone) {
+ return false;
+ }
+ }
+
+ dragging.hide();
+ if (placeholder.index() < $(this).index()) {
+ $(this).after(placeholder);
+ } else {
+ $(this).before(placeholder);
+ }
+ placeholders.not(placeholder).detach();
+ } else {
+ if (!placeholders.is(this) && !$(this).children(options.items).length) {
+ placeholders.detach();
+ $(this).append(placeholder);
+ }
+ }
+ return false;
+ });
+ });
+};
+
+sortable.destroy = function(sortable) {
+ _destroySortable(sortable);
+};
+
+sortable.enable = function(sortable) {
+ _enableSortable(sortable);
+};
+
+sortable.disable = function(sortable) {
+ _disableSortable(sortable);
+};
+
+$.fn.sortable = function(options) {
+ return sortable(this, options);
+};