diff --git a/opentech/apply/categories/blocks.py b/opentech/apply/categories/blocks.py
index 02359dc54c454236183c6407d962f59fc8e4c687..b8bf9a67c1180cd53a62490fae49aa46930fe6e9 100644
--- a/opentech/apply/categories/blocks.py
+++ b/opentech/apply/categories/blocks.py
@@ -74,12 +74,11 @@ class CategoryQuestionBlock(OptionalFormFieldBlock):
         else:
             return forms.RadioSelect
 
-    def render(self, value, context):
-        data = context['data']
+    def prepare_data(self, value, data, serialize):
         category = value['category']
         if data:
-            context['data'] = category.options.filter(id__in=data).values_list('value', flat=True)
-        return super().render(value, context)
+            data = category.options.filter(id__in=data).values_list('value', flat=True)
+        return data
 
     def get_searchable_content(self, value, data):
         return None
diff --git a/opentech/apply/funds/api_views.py b/opentech/apply/funds/api_views.py
index fa11fe29fbb57b9fc375c13ed6f37f7a784adcbd..4e294f673bb74547106e2521eff91bb93be5fc8a 100644
--- a/opentech/apply/funds/api_views.py
+++ b/opentech/apply/funds/api_views.py
@@ -1,6 +1,9 @@
+from django.db.models import Q
 from rest_framework import generics
 from rest_framework import permissions
-from django_filters.rest_framework import DjangoFilterBackend
+from django_filters import rest_framework as filters
+
+from wagtail.core.models import Page
 
 from opentech.api.pagination import StandardResultsSetPagination
 from .models import ApplicationSubmission
@@ -8,14 +11,31 @@ from .serializers import SubmissionListSerializer, SubmissionDetailSerializer
 from .permissions import IsApplyStaffUser
 
 
+class RoundLabFilter(filters.ModelChoiceFilter):
+    def filter(self, qs, value):
+        if not value:
+            return qs
+
+        return qs.filter(Q(round=value) | Q(page=value))
+
+
+class SubmissionsFilter(filters.FilterSet):
+    # TODO replace with better call to Round and Lab base class
+    round = RoundLabFilter(queryset=Page.objects.all())
+
+    class Meta:
+        model = ApplicationSubmission
+        fields = ('status', 'round')
+
+
 class SubmissionList(generics.ListAPIView):
     queryset = ApplicationSubmission.objects.current()
     serializer_class = SubmissionListSerializer
     permission_classes = (
         permissions.IsAuthenticated, IsApplyStaffUser,
     )
-    filter_backends = (DjangoFilterBackend,)
-    filter_fields = ('round', 'status')
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_class = SubmissionsFilter
     pagination_class = StandardResultsSetPagination
 
 
diff --git a/opentech/apply/funds/blocks.py b/opentech/apply/funds/blocks.py
index d6a87a5f919876520865192f3e1dde137a13a782..7ddff78f7ef5869c3f92078415d452ab913d88d3 100644
--- a/opentech/apply/funds/blocks.py
+++ b/opentech/apply/funds/blocks.py
@@ -39,6 +39,9 @@ class ValueBlock(ApplicationSingleIncludeFieldBlock):
     class Meta:
         label = _('Requested amount')
 
+    def prepare_data(self, value, data, serialize):
+        return '$' + str(data)
+
 
 class EmailBlock(ApplicationMustIncludeFieldBlock):
     name = 'email'
@@ -62,14 +65,29 @@ class AddressFieldBlock(ApplicationSingleIncludeFieldBlock):
 
     def format_data(self, data):
         # Based on the fields listed in addressfields/widgets.py
+        return ', '.join(
+            data[field]
+            for field in order_fields
+            if data[field]
+        )
+
+    def prepare_data(self, value, data, serialize):
         order_fields = [
             'thoroughfare', 'premise', 'localityname', 'administrativearea', 'postalcode', 'country'
         ]
-        address = json.loads(data)
-        return ', '.join(
-            address[field]
+        data = json.loads(data)
+        data = {
+            field: data[field]
             for field in order_fields
-            if address[field]
+        }
+
+        if serialize:
+            return data
+
+        return ', '.join(
+            value
+            for value in data.values()
+            if value
         )
 
 
@@ -108,7 +126,7 @@ class DurationBlock(ApplicationMustIncludeFieldBlock):
         field_kwargs['choices'] = self.DURATION_OPTIONS.items()
         return field_kwargs
 
-    def format_data(self, data):
+    def prepare_data(self, value, data, serialize):
         return self.DURATION_OPTIONS[int(data)]
 
     class Meta:
diff --git a/opentech/apply/funds/models/mixins.py b/opentech/apply/funds/models/mixins.py
index 87a1dd39ea31e63666f76fac46e9071fa3dd6d88..31a5b899affdd6817f197a886a099939f855dd7a 100644
--- a/opentech/apply/funds/models/mixins.py
+++ b/opentech/apply/funds/models/mixins.py
@@ -137,6 +137,22 @@ class AccessFormData:
             if isinstance(field.block, SingleIncludeMixin)
         }
 
+    @property
+    def normal_blocks(self):
+        return [
+            field_id
+            for field_id in self.question_field_ids
+            if field_id not in self.named_blocks
+        ]
+
+    def serialize(self, field_id):
+        field = self.field(field_id)
+        data = self.data(field_id)
+        return field.render(context={
+            'serialize': True,
+            'data': data,
+        })
+
     def render_answer(self, field_id, include_question=False):
         try:
             field = self.field(field_id)
@@ -149,8 +165,7 @@ class AccessFormData:
         # Returns a list of the rendered answers
         return [
             self.render_answer(field_id, include_question=True)
-            for field_id in self.question_field_ids
-            if field_id not in self.named_blocks
+            for field_id in self.normal_blocks
         ]
 
     def output_answers(self):
diff --git a/opentech/apply/funds/serializers.py b/opentech/apply/funds/serializers.py
index 6275248cfc21d4ed822560759e8c014628d9cdda..3203a7ecca0cefc53594d594c9b39964655dbf3e 100644
--- a/opentech/apply/funds/serializers.py
+++ b/opentech/apply/funds/serializers.py
@@ -4,12 +4,44 @@ from .models import ApplicationSubmission
 
 
 class SubmissionListSerializer(serializers.ModelSerializer):
+    url = serializers.HyperlinkedIdentityField(view_name='funds:submissions-api:detail')
+
     class Meta:
         model = ApplicationSubmission
-        fields = ('id', 'title', 'status')
+        fields = ('id', 'title', 'status', 'url')
 
 
 class SubmissionDetailSerializer(serializers.ModelSerializer):
+    questions = serializers.SerializerMethodField()
+    meta_questions = serializers.SerializerMethodField()
+    stage = serializers.CharField(source='stage.name')
+
     class Meta:
         model = ApplicationSubmission
-        fields = ('id', 'title',)
+        fields = ('id', 'title', 'stage', 'meta_questions', 'questions')
+
+    def serialize_questions(self, obj, fields):
+        for field_id in fields:
+            yield obj.serialize(field_id)
+
+    def get_meta_questions(self, obj):
+        meta_questions = {
+            'title': 'Project Name',
+            'full_name': 'Legal Name',
+            'email': 'Email',
+            'value': 'Requested Funding',
+            'duration': 'Project Duration',
+            'address': 'Address'
+        }
+        data = self.serialize_questions(obj, obj.named_blocks.values())
+        data = [
+            {
+                **response,
+                'question': meta_questions.get(response['type'], response['question'])
+            }
+            for response in data
+        ]
+        return data
+
+    def get_questions(self, obj):
+        return self.serialize_questions(obj, obj.normal_blocks)
diff --git a/opentech/apply/stream_forms/blocks.py b/opentech/apply/stream_forms/blocks.py
index 684a692e88e083c2ef4b63f16a75fe162113d62e..d911275742eb4d0f1f8444bce96aa649a2d2563f 100644
--- a/opentech/apply/stream_forms/blocks.py
+++ b/opentech/apply/stream_forms/blocks.py
@@ -1,5 +1,6 @@
 # Credit to https://github.com/BertrandBordage for initial implementation
 import bleach
+from django_bleach.templatetags.bleach_tags import bleach_value
 
 from django import forms
 from django.db.models import BLANK_CHOICE_DASH
@@ -50,17 +51,39 @@ class FormFieldBlock(StructBlock):
         field_kwargs = self.get_field_kwargs(struct_value)
         return self.get_field_class(struct_value)(**field_kwargs)
 
-    def get_context(self, value, parent_context):
-        context = super().get_context(value, parent_context)
-        parent_context['data'] = self.format_data(parent_context['data']) or self.no_response()
-        return context
+    def serialize(self, value, context):
+        return {
+            'question': value['field_label'],
+            'answer': context.get('data'),
+            'type': self.name,
+        }
+
+    def serialize_no_response(self, value, context):
+        return {
+            'question': value['field_label'],
+            'answer': 'No Response',
+            'type': 'no_response',
+        }
+
+    def prepare_data(self, value, data, serialize=False):
+        return bleach_value(str(data))
+
+    def render(self, value, context):
+        data = context.get('data')
+        data = self.prepare_data(value, data, context.get('serialize', False))
+
+        context.update(data=data or self.no_response())
+
+        if context.get('serialize'):
+            if not data:
+                return self.serialize_no_response(value, context)
+            return self.serialize(value, context)
+
+        return super().render(value, context)
 
     def get_searchable_content(self, value, data):
         return str(data)
 
-    def format_data(self, data):
-        return data
-
     def no_response(self):
         return "No response"
 
@@ -273,6 +296,12 @@ class UploadableMediaBlock(OptionalFormFieldBlock):
     def get_searchable_content(self, value, data):
         return None
 
+    def prepare_data(self, value, data, serialize):
+        if serialize:
+            return data.serialize()
+
+        return data
+
 
 class ImageFieldBlock(UploadableMediaBlock):
     field_class = forms.ImageField
@@ -301,6 +330,11 @@ class MultiFileFieldBlock(UploadableMediaBlock):
         label = _('Multiple File field')
         template = 'stream_forms/render_multi_file_field.html'
 
+    def prepare_data(self, value, data, serialize):
+        if serialize:
+            return [file.serialize() for file in data]
+        return data
+
     def no_response(self):
         return [super().no_response()]
 
diff --git a/opentech/apply/stream_forms/files.py b/opentech/apply/stream_forms/files.py
index 1d5b8ce5d7df2b780b2e70269fa8bffc227dfe73..8fdf2febd2906c7baf65f19efe2f9dcb45db596e 100644
--- a/opentech/apply/stream_forms/files.py
+++ b/opentech/apply/stream_forms/files.py
@@ -66,6 +66,12 @@ class StreamFieldFile(File):
             return self.file.size
         return self.storage.size(self.name)
 
+    def serialize(self):
+        return {
+            'url': self.url,
+            'filename': self.filename,
+        }
+
     def open(self, mode='rb'):
         if getattr(self, '_file', None) is None:
             self.file = self.storage.open(self.name, mode)
diff --git a/opentech/static_src/src/app/.eslintrc b/opentech/static_src/src/app/.eslintrc
new file mode 100644
index 0000000000000000000000000000000000000000..4217ad2a7fec678e4574f84dd1ffbe0ed10bf833
--- /dev/null
+++ b/opentech/static_src/src/app/.eslintrc
@@ -0,0 +1,31 @@
+{
+    "parser": "babel-eslint",
+    "plugins": [
+        "react"
+    ],
+    "parserOptions": {
+        "ecmaVersion": 6,
+        "sourceType": "module",
+        "ecmaFeatures": {
+            "jsx": true
+        }
+    },
+    "env": {
+        "es6":     true,
+        "browser": true,
+        "node":    true,
+        "mocha":   true
+    },
+    "extends": [
+        "eslint:recommended",
+        "plugin:react/recommended"
+    ],
+    "settings": {
+        "react": {
+            "version": "detect"
+        }
+    },
+    "rules": {
+        "no-console": "off"
+    }
+}
diff --git a/opentech/static_src/src/app/src/SubmissionsByRoundApp.js b/opentech/static_src/src/app/src/SubmissionsByRoundApp.js
index d3ccafd766a6e79de63450a32021f841a6f73e8c..133ec908ac6d5d229408761c8f6bb708eae82fed 100644
--- a/opentech/static_src/src/app/src/SubmissionsByRoundApp.js
+++ b/opentech/static_src/src/app/src/SubmissionsByRoundApp.js
@@ -9,10 +9,17 @@ import { setCurrentSubmissionRound } from '@actions/submissions';
 
 
 class SubmissionsByRoundApp extends React.Component {
+    static propTypes = {
+        roundID: PropTypes.number,
+        setSubmissionRound: PropTypes.func,
+        pageContent: PropTypes.node.isRequired,
+    };
+
+
     state = { detailOpened: false };
 
     componentDidMount() {
-        this.props.setSubmissionRound(this.props.roundId);
+        this.props.setSubmissionRound(this.props.roundID);
     }
 
     openDetail = () => {
@@ -41,18 +48,13 @@ class SubmissionsByRoundApp extends React.Component {
                 <div style={this.state.style} ref={this.setOriginalContentRef} dangerouslySetInnerHTML={{ __html: this.props.pageContent }} />
 
                 {this.state.detailOpened &&
-                    <GroupByStatusDetailView roundId={this.props.roundId} />
+                    <GroupByStatusDetailView roundId={this.props.roundID} />
                 }
             </>
         )
     }
 }
 
-SubmissionsByRoundApp.propTypes = {
-    roundId: PropTypes.number,
-    setSubmissionRound: PropTypes.func,
-};
-
 const mapDispatchToProps = dispatch => {
     return {
         setSubmissionRound: id => {
diff --git a/opentech/static_src/src/app/src/api/index.js b/opentech/static_src/src/app/src/api/index.js
index 770802352d45563c36a504bc8c3fa7b55a39bb7a..6fcd16016bf03484a9777a09772ecd92b46f4507 100644
--- a/opentech/static_src/src/app/src/api/index.js
+++ b/opentech/static_src/src/app/src/api/index.js
@@ -1,5 +1,6 @@
-import { fetchSubmissionsByRound } from '@api/submissions';
+import { fetchSubmission, fetchSubmissionsByRound } from '@api/submissions';
 
 export default {
     fetchSubmissionsByRound,
+    fetchSubmission,
 };
diff --git a/opentech/static_src/src/app/src/api/submissions.js b/opentech/static_src/src/app/src/api/submissions.js
index 166600d4f66b3a970d6909fab38a756eecd03eed..8d7f95f776558bdb14a68dc874901214de1dcceb 100644
--- a/opentech/static_src/src/app/src/api/submissions.js
+++ b/opentech/static_src/src/app/src/api/submissions.js
@@ -6,3 +6,8 @@ export async function fetchSubmissionsByRound(id) {
         'page_size': 1000,
     });
 }
+
+
+export async function fetchSubmission(id) {
+    return apiFetch(`/apply/api/submissions/${id}/`, 'GET');
+}
diff --git a/opentech/static_src/src/app/src/components/ApplicationDisplay/index.js b/opentech/static_src/src/app/src/components/ApplicationDisplay/index.js
deleted file mode 100644
index bdb5e1f9a3d3ef7dd4e59e970497070591fb5498..0000000000000000000000000000000000000000
--- a/opentech/static_src/src/app/src/components/ApplicationDisplay/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-const ApplicationDisplay = () => <div>Application Display</div>
-
-export default ApplicationDisplay;
diff --git a/opentech/static_src/src/app/src/components/DetailView/index.js b/opentech/static_src/src/app/src/components/DetailView/index.js
index 41935c9ba4e2ca335439b11df0d123f707a1e5c6..b392e211ef577a62aaa64ad8a674b62544cf83cf 100644
--- a/opentech/static_src/src/app/src/components/DetailView/index.js
+++ b/opentech/static_src/src/app/src/components/DetailView/index.js
@@ -1,18 +1,101 @@
-import React from 'react';
+import React, { Component } from 'react'
+import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
+import { withWindowSizeListener } from 'react-window-size-listener';
+
+import { clearCurrentSubmission } from '@actions/submissions';
+import DisplayPanel from '@containers/DisplayPanel';
+import SlideInRight from '@components/Transitions/SlideInRight'
+import SlideOutLeft from '@components/Transitions/SlideOutLeft'
+import { getCurrentSubmissionID } from '@selectors/submissions';
 
-import DisplayPanel from '@components/DisplayPanel';
 import './style.scss';
 
-const DetailView = ({ listing, display }) => (
-    <div className="detail-view">
-        {listing}
-        <DisplayPanel />
-    </div>
-);
+class DetailView extends Component {
+    static propTypes = {
+        listing: PropTypes.element.isRequired,
+        submissionID: PropTypes.number,
+        windowSize: PropTypes.objectOf(PropTypes.number),
+        clearSubmission: PropTypes.func.isRequired,
+    };
+
+    state = {
+        listingShown: true,
+        firstRender: true,
+    }
+
+    isMobile = (width) => (width ? width : this.props.windowSize.windowWidth) < 1024
+
+    renderDisplay () {
+        return <DisplayPanel />
+    }
+
+    componentDidUpdate (prevProps, prevState) {
+        if (this.isMobile()) {
+            const haveCleared = prevProps.submissionID && !this.props.submissionID
+            const haveUpdated = !prevProps.submissionID && this.props.submissionID
+
+            if ( haveCleared ) {
+                this.setState({listingShown: true})
+            } else if ( haveUpdated && this.state.firstRender ) {
+                // Listing automatically updating after update
+                // clear, but dont run again
+                this.props.clearSubmission()
+                this.setState({firstRender: false})
+            } else if ( prevProps.submissionID !== this.props.submissionID) {
+                // Submission has changed and we want to show it
+                // reset the firstRender so that we can clear it again
+                this.setState({
+                    listingShown: false,
+                    firstRender: true,
+                })
+            }
+        }
+    }
+
+    render() {
+        const { listing } = this.props;
+
+        if (this.isMobile()) {
+            var activeDisplay;
+            if (this.state.listingShown){
+                activeDisplay = (
+                    <SlideOutLeft key={"listing"}>
+                        {listing}
+                    </SlideOutLeft>
+                )
+            } else {
+                activeDisplay = (
+                    <SlideInRight key={"display"}>
+                        { this.renderDisplay() }
+                    </SlideInRight>
+                )
+            }
+
+            return (
+                <div className="detail-view">
+                    { activeDisplay }
+                </div>
+            )
+        } else {
+            return (
+                <div className="detail-view">
+                    {listing}
+                    { this.renderDisplay() }
+                </div>
+            )
+        }
+
+    }
+}
+
+const mapStateToProps = state => ({
+    submissionID: getCurrentSubmissionID(state),
+});
+
+const mapDispatchToProps = {
+    clearSubmission: clearCurrentSubmission
+}
 
-DetailView.propTypes = {
-    listing: PropTypes.node.isRequired,
-};
 
-export default DetailView;
+export default connect(mapStateToProps, mapDispatchToProps)(withWindowSizeListener(DetailView));
diff --git a/opentech/static_src/src/app/src/components/DisplayPanel/index.js b/opentech/static_src/src/app/src/components/DisplayPanel/index.js
deleted file mode 100644
index d3d719c4ab0799fccc8a71905e7a5a92d1d0bc28..0000000000000000000000000000000000000000
--- a/opentech/static_src/src/app/src/components/DisplayPanel/index.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import ApplicationDisplay from '@components/ApplicationDisplay'
-import Tabber from '@components/Tabber'
-import './style.scss';
-
-const DisplayPanel = () => (
-    <div className="display-panel">
-        <ApplicationDisplay />
-        <Tabber />
-    </div>
-);
-
-export default DisplayPanel;
diff --git a/opentech/static_src/src/app/src/components/DisplayPanel/style.scss b/opentech/static_src/src/app/src/components/DisplayPanel/style.scss
deleted file mode 100644
index 00e22068d32b078b04289db1b407af6e54dd20ce..0000000000000000000000000000000000000000
--- a/opentech/static_src/src/app/src/components/DisplayPanel/style.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-.display-panel {
-    // temporary to visualise middle column
-    > div:first-child {
-        background-color: $color--white;
-    }
-
-    @include media-query(tablet-landscape) {
-        display: grid;
-        grid-template-columns: 1fr 250px;
-    }
-
-    @include media-query(desktop) {
-        grid-template-columns: 1fr 390px;
-    @include target-ie11 {
-        display: flex;
-        flex-wrap: wrap;
-    }
-    }
-}
diff --git a/opentech/static_src/src/app/src/components/Listing/index.js b/opentech/static_src/src/app/src/components/Listing/index.js
index 791a42f834f2df5511286ebe3ccd7588a203975d..06b733e44906a40ef8cb4eb9544c42c0121a5063 100644
--- a/opentech/static_src/src/app/src/components/Listing/index.js
+++ b/opentech/static_src/src/app/src/components/Listing/index.js
@@ -1,31 +1,76 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import ListingHeading from '@components/ListingHeading';
 import ListingGroup from '@components/ListingGroup';
 import ListingItem from '@components/ListingItem';
 
 import './style.scss';
 
 export default class Listing extends React.Component {
+    static propTypes = {
+        items: PropTypes.array,
+        activeItem: PropTypes.number,
+        isLoading: PropTypes.bool,
+        error: PropTypes.string,
+        groupBy: PropTypes.string,
+        order: PropTypes.arrayOf(PropTypes.string),
+        onItemSelection: PropTypes.func,
+    };
+
+    state = {
+        orderedItems: [],
+    };
+
+    componentDidMount() {
+        this.orderItems();
+    }
+
+    componentDidUpdate(prevProps, prevState) {
+        // Order items
+        if (this.props.items !== prevProps.items) {
+            this.orderItems();
+        }
+
+        const oldItem = prevProps.activeItem
+        const newItem = this.props.activeItem
+
+        // If we have never activated a submission, get the first item
+        if ( !newItem && !oldItem ) {
+            const firstGroup = this.state.orderedItems[0]
+            if ( firstGroup && firstGroup.items[0] ) {
+                this.setState({firstUpdate: false})
+                this.props.onItemSelection(firstGroup.items[0].id)
+            }
+        }
+    }
+
     renderListItems() {
-        const { isLoading, isError, items } = this.props;
+        const { isLoading, error, items, onItemSelection, activeItem } = this.props;
 
         if (isLoading) {
             return <p>Loading...</p>;
-        } else if (isError) {
-            return <p>Something went wrong. Please try again later.</p>;
+        } else if (error) {
+            return (
+                <>
+                    <p>Something went wrong. Please try again later.</p>
+                    <p>{ error }</p>
+                </>
+            );
         } else if (items.length === 0) {
             return <p>No results found.</p>;
         }
 
         return (
             <ul className="listing__list">
-                {this.getOrderedItems().filter(v => v.items.length !== 0).map(v => {
+                {this.state.orderedItems.map(group => {
                     return (
-                        <ListingGroup key={`listing-group-${v.group}`} item={v}>
-                            {v.items.map(item => {
-                                return <ListingItem key={`listing-item-${item.id}`} item={item}/>;
+                        <ListingGroup key={`listing-group-${group.name}`} item={group}>
+                            {group.items.map(item => {
+                                return <ListingItem
+                                    selected={!!activeItem && activeItem===item.id}
+                                    onClick={() => onItemSelection(item.id)}
+                                    key={`listing-item-${item.id}`}
+                                    item={item}/>;
                             })}
                         </ListingGroup>
                     );
@@ -47,19 +92,19 @@ export default class Listing extends React.Component {
         }, {});
     }
 
-    getOrderedItems() {
+    orderItems() {
         const groupedItems = this.getGroupedItems();
         const { order = [] } = this.props;
-        const orderedItems = [];
         const leftOverKeys = Object.keys(groupedItems).filter(v => !order.includes(v));
-        return order.concat(leftOverKeys).map(key => ({
-            group: key,
-            items: groupedItems[key] || []
-        }));
+        this.setState({
+            orderedItems: order.concat(leftOverKeys).filter(key => groupedItems[key] ).map(key => ({
+                name: key,
+                items: groupedItems[key] || []
+            })),
+        });
     }
 
     render() {
-        const { isLoading, isError } = this.props;
         return (
             <div className="listing">
                 <div className="listing__header"></div>
@@ -68,11 +113,3 @@ export default class Listing extends React.Component {
         );
     }
 }
-
-Listing.propTypes = {
-    items: PropTypes.array,
-    isLoading: PropTypes.bool,
-    isError: PropTypes.bool,
-    groupBy: PropTypes.string,
-    order: PropTypes.arrayOf(PropTypes.string),
-};
diff --git a/opentech/static_src/src/app/src/components/ListingGroup.js b/opentech/static_src/src/app/src/components/ListingGroup.js
index 72c97d53b4f24946f99b0bf83752c3ebb3ca99a1..6508a18b13c4c5574109451211c0fcd6c4af8f6f 100644
--- a/opentech/static_src/src/app/src/components/ListingGroup.js
+++ b/opentech/static_src/src/app/src/components/ListingGroup.js
@@ -3,21 +3,24 @@ import PropTypes from 'prop-types';
 
 import ListingHeading from '@components/ListingHeading';
 
+
 export default class ListingGroup extends React.Component {
+    static propTypes = {
+        children: PropTypes.arrayOf(PropTypes.node),
+        item: PropTypes.shape({
+            name: PropTypes.string,
+        }),
+    };
+
     render() {
+        const {item, children} = this.props
         return (
             <>
-                <ListingHeading title={this.props.item.group} count={this.props.children.length} />
+                <ListingHeading title={item.name} count={children.length} />
                 <ul>
-                    {this.props.children}
+                    {children}
                 </ul>
             </>
         );
     }
 }
-
-ListingGroup.propTypes = {
-    item: PropTypes.shape({
-        group: PropTypes.string,
-    }),
-};
diff --git a/opentech/static_src/src/app/src/components/ListingItem.js b/opentech/static_src/src/app/src/components/ListingItem.js
index 1207c65e8a44b087b97d2c3ed2baf437e05579e5..65969c7deae3a1ddb5e54a1dc0fd6cf19ebacbc8 100644
--- a/opentech/static_src/src/app/src/components/ListingItem.js
+++ b/opentech/static_src/src/app/src/components/ListingItem.js
@@ -4,9 +4,12 @@ import PropTypes from 'prop-types';
 
 export default class ListingItem extends React.Component {
     render() {
+        const { onClick, item, selected} = this.props;
         return (
-            <li className="listing__item">
-                <a className="listing__link">{this.props.item.title}</a>
+            <li className={"listing__item " + (selected ? "is-active" : "")}>
+                <a className="listing__link" onClick={onClick}>
+                    {item.title}
+                </a>
             </li>
         );
     }
@@ -16,4 +19,6 @@ ListingItem.propTypes = {
     item: PropTypes.shape({
         title: PropTypes.string,
     }),
+    onClick: PropTypes.func,
+    selected: PropTypes.bool,
 };
diff --git a/opentech/static_src/src/app/src/components/SubmissionDisplay/answers.js b/opentech/static_src/src/app/src/components/SubmissionDisplay/answers.js
new file mode 100644
index 0000000000000000000000000000000000000000..e2a50ee55e3b4119a2a9681912d617b0cc170542
--- /dev/null
+++ b/opentech/static_src/src/app/src/components/SubmissionDisplay/answers.js
@@ -0,0 +1,96 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Download from 'images/download.svg';
+import File from 'images/file.svg';
+
+const answerType = {answer: PropTypes.string.isRequired}
+const arrayAnswerType = {answer: PropTypes.arrayOf(PropTypes.string)}
+const fileType = {answer: PropTypes.shape({
+    filename: PropTypes.string.isRequired,
+    url:PropTypes.string.isRequired,
+})}
+
+const ListAnswer = ({Wrapper, answers}) => (
+    <ul>{
+        answers.map((answer, index) => <li key={index}><Wrapper answer={answer} /></li>)
+    }</ul>
+);
+ListAnswer.propTypes = {
+    Wrapper: PropTypes.element,
+    ...arrayAnswerType,
+}
+
+const BasicAnswer = ({answer}) => <p>{ answer }</p>;
+BasicAnswer.propTypes = answerType
+
+const BasicListAnswer = ({answer}) => <ListAnswer Wrapper={BasicAnswer} answers={answer} />;
+BasicListAnswer.propTypes = arrayAnswerType
+
+const RichTextAnswer = ({answer}) => <div dangerouslySetInnerHTML={{ __html: answer }} />;
+RichTextAnswer.propTypes = answerType
+
+const FileAnswer = ({answer}) => (
+    <a className="link link--download" href={answer.url}>
+        <div>
+            <File /><span>{answer.filename}</span>
+        </div>
+        <Download />
+    </a>
+);
+FileAnswer.propTypes = fileType
+
+const MultiFileAnswer = ({answer}) => <ListAnswer Wrapper={FileAnswer} answers={answer} />;
+MultiFileAnswer.propTypes = {answer: PropTypes.arrayOf(fileType)}
+
+const AddressAnswer = ({answer}) => (
+        <div>{
+            Object.entries(answer)
+                .filter(([key, value]) => !!value )
+                  .map(([key, value]) => <p key={key}>{value}</p> )}
+        </div>
+)
+AddressAnswer.propTypes = {answer: PropTypes.objectOf(PropTypes.string)}
+
+
+const answerTypes = {
+    'no_response': BasicAnswer,
+    'char': BasicAnswer,
+    'email': BasicAnswer,
+    'name': BasicAnswer,
+    'value': BasicAnswer,
+    'title': BasicAnswer,
+    'full_name': BasicAnswer,
+    'duration': BasicAnswer,
+    'date': BasicAnswer,
+    'checkbox': BasicAnswer,
+    'dropdown': BasicAnswer,
+    'radios': BasicAnswer,
+
+    // SPECIAL
+    'rich_text': RichTextAnswer,
+    'address': AddressAnswer,
+    'category': BasicListAnswer,
+    // Files
+    'file': FileAnswer,
+    'multi_file': MultiFileAnswer,
+}
+
+export const answerPropTypes = PropTypes.oneOfType([
+    PropTypes.string,
+    PropTypes.object,
+    PropTypes.arrayOf(PropTypes.string),
+    PropTypes.arrayOf(PropTypes.object),
+])
+
+const Answer = ({ answer, type }) => {
+    const AnswerType = answerTypes[type];
+
+    return <AnswerType answer={answer} />;
+}
+Answer.propTypes = {
+    answer: answerPropTypes,
+    type: PropTypes.string.isRequired,
+}
+
+export default Answer;
diff --git a/opentech/static_src/src/app/src/components/SubmissionDisplay/index.js b/opentech/static_src/src/app/src/components/SubmissionDisplay/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e78303d8cd5286bcb2625fe4080f3703d037ea12
--- /dev/null
+++ b/opentech/static_src/src/app/src/components/SubmissionDisplay/index.js
@@ -0,0 +1,73 @@
+import React, {Component} from 'react';
+import PropTypes from 'prop-types';
+
+import Answer, { answerPropTypes } from './answers'
+import './styles.scss'
+
+
+const MetaResponse = ({ question, answer, type }) => {
+    return (
+        <div>
+            <h5>{question}</h5>
+            <Answer type={type} answer={answer} />
+        </div>
+    )
+}
+MetaResponse.propTypes = {
+    question: PropTypes.string.isRequired,
+    answer: answerPropTypes,
+    type: PropTypes.string.isRequired,
+}
+
+
+const Response = ({question, answer, type}) => {
+    return (
+        <section>
+            <h4>{question}</h4>
+            <Answer type={type} answer={answer} />
+        </section>
+    )
+}
+Response.propTypes = {
+    question: PropTypes.string.isRequired,
+    answer: answerPropTypes,
+    type: PropTypes.string.isRequired,
+}
+
+
+export default class SubmissionDisplay extends Component {
+    static propTypes = {
+        isLoading: PropTypes.bool,
+        isError: PropTypes.bool,
+        submission: PropTypes.object,
+    }
+
+    render() {
+        if (this.props.isLoading) {
+            return <div>Loading...</div>;
+        } else if (this.props.isError) {
+            return <div>Error occured...</div>;
+        } else if (this.props.submission === undefined) {
+            return <div>Not selected</div>;
+        }
+        const { meta_questions = [], questions = [], stage} = this.props.submission;
+
+        return (
+            <div className="application-display">
+                <h3>{stage} Information</h3>
+
+                <div className="grid grid--proposal-info">
+                    {meta_questions.map((response, index) => (
+                        <MetaResponse key={index} {...response} />
+                    ))}
+                </div>
+
+                <div className="rich-text rich-text--answers">
+                    {questions.map((response, index) => (
+                        <Response key={index} {...response} />
+                    ))}
+                </div>
+            </div>
+        )
+    }
+}
diff --git a/opentech/static_src/src/app/src/components/SubmissionDisplay/styles.scss b/opentech/static_src/src/app/src/components/SubmissionDisplay/styles.scss
new file mode 100644
index 0000000000000000000000000000000000000000..02ea2a95ec5535773cccf9c255b15828c6bdab09
--- /dev/null
+++ b/opentech/static_src/src/app/src/components/SubmissionDisplay/styles.scss
@@ -0,0 +1,6 @@
+$application-header-height: 42px;
+
+.application-display {
+    height: calc(100vh - var(--header-admin-height) - #{$application-header-height});
+    overflow-y: scroll;
+}
diff --git a/opentech/static_src/src/app/src/components/Switcher/index.js b/opentech/static_src/src/app/src/components/Switcher/index.js
index e3c04e79fc44495eb1a50e6656ce558f1a585ebd..3f3aec96ded51b4be0178daf3fcb8edd3122c7c0 100644
--- a/opentech/static_src/src/app/src/components/Switcher/index.js
+++ b/opentech/static_src/src/app/src/components/Switcher/index.js
@@ -1,11 +1,20 @@
 import React from 'react'
 import ReactDOM from 'react-dom';
+import PropTypes from 'prop-types';
+
 import ArrayIcon from 'images/icon-array.svg'
 import GridIcon from 'images/icon-grid.svg';
 
 import './styles.scss';
 
 class Switcher extends React.Component {
+    static propTypes = {
+        handleOpen: PropTypes.func.isRequired,
+        handleClose: PropTypes.func.isRequired,
+        selector: PropTypes.string.isRequired,
+        open: PropTypes.bool,
+    }
+
     constructor(props) {
         super(props);
         this.el = document.getElementById(props.selector);
diff --git a/opentech/static_src/src/app/src/components/Tabber/index.js b/opentech/static_src/src/app/src/components/Tabber/index.js
index 1fb0d353784635de2c102c026d4ca09043732add..1b1ee8a357ddc3c527d589305bed96414800805c 100644
--- a/opentech/static_src/src/app/src/components/Tabber/index.js
+++ b/opentech/static_src/src/app/src/components/Tabber/index.js
@@ -1,5 +1,59 @@
-import React from 'react';
+import React, {Component} from 'react';
+import PropTypes from 'prop-types';
 
-const Tabber = () => <div>Tabber</div>
+
+
+export const Tab = ({button, children, handleClick}) => <div>{children}</div>
+Tab.propTypes = {
+    button: PropTypes.node,
+    children: PropTypes.node,
+    handleClick: PropTypes.func,
+}
+
+class Tabber extends Component {
+    static propTypes = {
+        children: PropTypes.arrayOf(PropTypes.element),
+    }
+
+    constructor() {
+        super();
+
+        this.state = {
+            activeTab: 0
+        }
+    }
+
+    componentDidUpdate(prevProps, prevState) {
+        const { children } = this.props;
+        if ( !children[prevState.activeTab].props.children ) {
+            this.setState({activeTab: children.findIndex(child => child.props.children)})
+        }
+    }
+
+    handleClick = (child) => {
+        this.setState({
+            activeTab: child
+        })
+    }
+
+    render() {
+        const { children } = this.props;
+
+        return (
+            <div className="tabber">
+                <div className="tabber__navigation">
+                    {children.map((child, i) => {
+                            return <a onClick={child.props.handleClick ? child.props.handleClick : () => this.handleClick(i)} className="display-panel__link" key={child.key}>{child.props.button}</a>
+                        })
+                    }
+                </div>
+                <div className="tabber-tab__active">
+                    { children[this.state.activeTab] }
+                </div>
+            </div>
+        )
+    }
+
+}
 
 export default Tabber;
diff --git a/opentech/static_src/src/app/src/components/Transitions/SlideInRight.js b/opentech/static_src/src/app/src/components/Transitions/SlideInRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..3d02d4bf40da82afb2d8e009540f4e26950176ef
--- /dev/null
+++ b/opentech/static_src/src/app/src/components/Transitions/SlideInRight.js
@@ -0,0 +1,40 @@
+import React from 'react'
+import PropTypes from 'prop-types';
+import Transition from 'react-transition-group/Transition';
+
+
+const SlideInRight = ({ children, in: inProp }) => {
+    const duration = 250;
+
+    const defaultStyle = {
+        transition: `transform ${duration}ms ease-in-out`,
+        transform: 'translate3d(0, 0, 0)',
+        position: 'absolute',
+        zIndex: 2,
+        width: '100%'
+    }
+
+    const transitionStyles = {
+        entering: { transform: 'translate3d(0, 0, 0)' },
+        entered: { transform: 'translate3d(100%, 0, 0)' },
+        exiting: { transform: 'translate3d(100%, 0, 0)' },
+        exited: { transform: 'translate3d(0, 0, 0)' }
+    };
+
+    return (
+        <Transition in={inProp} timeout={duration}>
+            {(state) => (
+                <div style={{ ...defaultStyle, ...transitionStyles[state] }}>
+                    {children}
+                </div>
+            )}
+        </Transition>
+    )
+}
+
+SlideInRight.propTypes = {
+    children: PropTypes.node,
+    in: PropTypes.bool,
+}
+
+export default SlideInRight
diff --git a/opentech/static_src/src/app/src/components/Transitions/SlideOutLeft.js b/opentech/static_src/src/app/src/components/Transitions/SlideOutLeft.js
new file mode 100644
index 0000000000000000000000000000000000000000..49345eb18fa0ddc1501f9a6ca1b901c1621ea02b
--- /dev/null
+++ b/opentech/static_src/src/app/src/components/Transitions/SlideOutLeft.js
@@ -0,0 +1,39 @@
+import React from 'react'
+import PropTypes from 'prop-types';
+import Transition from 'react-transition-group/Transition';
+
+
+const SlideOutLeft = ({ children, in: inProp }) => {
+    const duration = 250;
+
+    const defaultStyle = {
+        transition: `transform ${duration}ms ease-in-out`,
+        transform: 'translate3d(0, 0, 0)',
+        position: 'absolute',
+        width: '100%'
+    }
+
+    const transitionStyles = {
+        entering: { transform: 'translate3d(0, 0, 0)' },
+        entered: { transform: 'translate3d(-100%, 0, 0)' },
+        exiting: { transform: 'translate3d(-100%, 0, 0)' },
+        exited: { transform: 'translate3d(0, 0, 0)' }
+    };
+
+    return (
+        <Transition in={inProp} timeout={duration}>
+            {(state) => (
+                <div style={{ ...defaultStyle, ...transitionStyles[state] }}>
+                    {children}
+                </div>
+            )}
+        </Transition>
+    )
+}
+
+SlideOutLeft.propTypes = {
+    children: PropTypes.node,
+    in: PropTypes.bool,
+}
+
+export default SlideOutLeft
diff --git a/opentech/static_src/src/app/src/containers/ByStatusListing.js b/opentech/static_src/src/app/src/containers/ByStatusListing.js
index aaeb99202707af65dc5056500d1e609e7ba4d246..873036c9467564588ebc4fba69d8bba81002c29c 100644
--- a/opentech/static_src/src/app/src/containers/ByStatusListing.js
+++ b/opentech/static_src/src/app/src/containers/ByStatusListing.js
@@ -4,37 +4,58 @@ import { connect } from 'react-redux'
 
 import Listing from '@components/Listing';
 import {
+    loadCurrentRound,
+    setCurrentSubmission,
+} from '@actions/submissions';
+import {
+    getCurrentRound,
     getCurrentRoundID,
     getCurrentRoundSubmissions,
-    getSubmissionsByRoundErrorState,
-    getSubmissionsByRoundLoadingState,
+    getCurrentSubmissionID,
+    getSubmissionsByRoundError,
 } from '@selectors/submissions';
-import { setCurrentSubmissionRound, fetchSubmissionsByRound } from '@actions/submissions';
 
 
+const loadData = props => {
+    props.loadSubmissions(['submissions'])
+}
+
 class ByStatusListing extends React.Component {
+    static propTypes = {
+        loadSubmissions: PropTypes.func,
+        submissions: PropTypes.arrayOf(PropTypes.object),
+        roundID: PropTypes.number,
+        round: PropTypes.object,
+        error: PropTypes.string,
+        setCurrentItem: PropTypes.func,
+        activeSubmission: PropTypes.number,
+    };
+
     componentDidMount() {
-        const { roundId } = this.props;
         // Update items if round ID is defined.
-        if (roundId !== null && roundId !== undefined) {
-            this.props.loadSubmissions(roundId);
+        if ( this.props.roundID ) {
+            loadData(this.props)
         }
     }
 
     componentDidUpdate(prevProps) {
-        const { roundId } = this.props;
+        const { roundID } = this.props;
         // Update entries if round ID is changed or is not null.
-        if (roundId !== null && roundId !== undefined && prevProps.roundId !== roundId) {
-            this.props.loadSubmissions(roundId);
+        if (roundID && prevProps.roundID !== roundID) {
+            console.log('wooop')
+            loadData(this.props)
         }
     }
 
     render() {
-        const { isLoading, isError } = this.props;
+        const { error, submissions, round, setCurrentItem, activeSubmission } = this.props;
+        const isLoading = round && round.isFetching
         return <Listing
                     isLoading={isLoading}
-                    isError={isError}
-                    items={this.props.items}
+                    error={error}
+                    items={submissions}
+                    activeItem={activeSubmission}
+                    onItemSelection={setCurrentItem}
                     groupBy={'status'}
                     order={[
                         // TODO: Set the proper order of statuses.
@@ -52,22 +73,18 @@ class ByStatusListing extends React.Component {
 }
 
 const mapStateToProps = state => ({
-    items: getCurrentRoundSubmissions(state),
-    roundId: getCurrentRoundID(state),
-    isError: getSubmissionsByRoundErrorState(state),
-    isLoading: getSubmissionsByRoundLoadingState(state),
-});
+    roundID: getCurrentRoundID(state),
+    submissions: getCurrentRoundSubmissions(state),
+    round: getCurrentRound(state),
+    error: getSubmissionsByRoundError(state),
+    activeSubmission: getCurrentSubmissionID(state),
+})
 
 const mapDispatchToProps = dispatch => ({
-    loadSubmissions: id => dispatch(fetchSubmissionsByRound(id)),
+    loadSubmissions: () => dispatch(loadCurrentRound()),
+    setCurrentItem: id => dispatch(setCurrentSubmission(id)),
 });
 
-ByStatusListing.propTypes = {
-    loadSubmissions: PropTypes.func,
-    roundId: PropTypes.number,
-};
-
-
 export default connect(
     mapStateToProps,
     mapDispatchToProps
diff --git a/opentech/static_src/src/app/src/containers/CurrentSubmissionDisplay.js b/opentech/static_src/src/app/src/containers/CurrentSubmissionDisplay.js
new file mode 100644
index 0000000000000000000000000000000000000000..75a4a018e0597651c70d9524b9c08c112980da89
--- /dev/null
+++ b/opentech/static_src/src/app/src/containers/CurrentSubmissionDisplay.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux'
+
+import { loadCurrentSubmission } from '@actions/submissions'
+import {
+    getCurrentSubmission,
+    getCurrentSubmissionID,
+} from '@selectors/submissions'
+import SubmissionDisplay from '@components/SubmissionDisplay';
+
+const loadData = props => {
+    props.loadCurrentSubmission(['questions'])
+
+}
+
+class CurrentSubmissionDisplay extends React.Component {
+    static propTypes = {
+        submission: PropTypes.object,
+        submissionID: PropTypes.number,
+    }
+
+    componentDidMount() {
+        loadData(this.props)
+    }
+
+    componentDidUpdate(prevProps) {
+        if (this.props.submissionID !== prevProps.submissionID ) {
+            loadData(this.props)
+        }
+    }
+
+    render () {
+        const { submission } = this.props
+        if ( !submission ) {
+            return <p>Loading</p>
+        }
+        return <SubmissionDisplay
+                   submission={submission}
+                   isLoading={submission.isFetching}
+                   isError={submission.isErrored} />
+    }
+
+}
+
+const mapStateToProps = state => ({
+    submissionID: getCurrentSubmissionID(state),
+    submission: getCurrentSubmission(state),
+})
+
+
+export default connect(mapStateToProps, {loadCurrentSubmission})(CurrentSubmissionDisplay)
diff --git a/opentech/static_src/src/app/src/containers/DisplayPanel/index.js b/opentech/static_src/src/app/src/containers/DisplayPanel/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e09e83f962d083bafa4acb743007b7443aef068b
--- /dev/null
+++ b/opentech/static_src/src/app/src/containers/DisplayPanel/index.js
@@ -0,0 +1,92 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { withWindowSizeListener } from 'react-window-size-listener';
+
+import { clearCurrentSubmission } from '@actions/submissions';
+import {
+    getCurrentSubmission,
+    getCurrentSubmissionID,
+    getSubmissionErrorState,
+    getSubmissionLoadingState,
+
+} from '@selectors/submissions';
+
+import CurrentSubmissionDisplay from '@containers/CurrentSubmissionDisplay'
+import Tabber, {Tab} from '@components/Tabber'
+import './style.scss';
+
+
+class DisplayPanel extends React.Component  {
+    static propTypes = {
+        submissionID: PropTypes.number,
+        loadSubmission: PropTypes.func,
+        isLoading: PropTypes.bool,
+        isError: PropTypes.bool,
+        clearSubmission: PropTypes.func.isRequired,
+        windowSize: PropTypes.objectOf(PropTypes.number)
+    };
+
+    render() {
+        const { windowSize: {windowWidth: width} } = this.props;
+        const { clearSubmission } = this.props;
+
+        const isMobile = width < 1024;
+
+        const submission = <CurrentSubmissionDisplay />
+
+        let tabs = [
+            <Tab button="Notes" key="note">
+                <p>Notes</p>
+            </Tab>,
+            <Tab button="Status" key="status">
+                <p>Status</p>
+            </Tab>
+        ]
+
+        if ( isMobile ) {
+            tabs = [
+                <Tab button="Back" key="back" handleClick={ clearSubmission } />,
+                <Tab button="Application" key="application">
+                    { submission }
+                </Tab>,
+                ...tabs
+            ]
+        }
+
+        return (
+            <div className="display-panel">
+                { !isMobile && (
+                    <div className="display-panel__column">
+                        <div className="display-panel__header display-panel__header--spacer"></div>
+                        <div className="display-panel__body">
+                            { submission }
+                        </div>
+                    </div>
+                )}
+                <div className="display-panel__column">
+                    <div className="display-panel__body">
+                        <Tabber>
+                            { tabs }
+                        </Tabber>
+                    </div>
+                </div>
+            </div>
+
+        )
+    }
+}
+
+const mapStateToProps = state => ({
+    isLoading: getSubmissionLoadingState(state),
+    isError: getSubmissionErrorState(state),
+    submissionID: getCurrentSubmissionID(state),
+    submission: getCurrentSubmission(state),
+});
+
+const mapDispatchToProps = {
+    clearSubmission: clearCurrentSubmission
+}
+
+
+export default connect(mapStateToProps, mapDispatchToProps)(withWindowSizeListener(DisplayPanel));
diff --git a/opentech/static_src/src/app/src/containers/DisplayPanel/style.scss b/opentech/static_src/src/app/src/containers/DisplayPanel/style.scss
new file mode 100644
index 0000000000000000000000000000000000000000..048c4907a51dab2757a023c9e4cb0a51fe7c06fa
--- /dev/null
+++ b/opentech/static_src/src/app/src/containers/DisplayPanel/style.scss
@@ -0,0 +1,45 @@
+.display-panel {
+    background-color: $color--white;
+
+    @include media-query(tablet-landscape) {
+        display: grid;
+        grid-template-columns: 1fr 250px;
+    }
+
+    @include media-query(desktop) {
+        grid-template-columns: 1fr 390px;
+        grid-template-rows: 75px 1fr;
+    }
+
+    @include target-ie11 {
+        display: flex;
+        flex-wrap: wrap;
+    }
+
+    &__body,
+    &__header {
+        @include submission-list-item;
+        padding: 20px;
+    }
+
+    &__header {
+        &--spacer {
+            display: none;
+            min-height: 75px;
+
+            @include media-query(tablet-landscape) {
+                display: block;
+            }
+        }
+    }
+
+    &__links {
+        display: flex;
+        align-items: center;
+        padding: 0;
+    }
+
+    &__link {
+        padding: 20px;
+    }
+}
diff --git a/opentech/static_src/src/app/src/containers/GroupByStatusDetailView.js b/opentech/static_src/src/app/src/containers/GroupByStatusDetailView.js
index 4f2c88ec7cb1dbd795495ab429879d5885ed2982..d0ce02e5378e383edd7bfe8b75010f97870ae939 100644
--- a/opentech/static_src/src/app/src/containers/GroupByStatusDetailView.js
+++ b/opentech/static_src/src/app/src/containers/GroupByStatusDetailView.js
@@ -1,5 +1,4 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
 import DetailView from '@components/DetailView';
 import ByStatusListing from '@containers/ByStatusListing';
diff --git a/opentech/static_src/src/app/src/index.js b/opentech/static_src/src/app/src/index.js
index ce8b1d05f83bbd7b4f75b574a8387aafe54db289..96cb05daa85321660990598ae80cf8a252dda7d2 100644
--- a/opentech/static_src/src/app/src/index.js
+++ b/opentech/static_src/src/app/src/index.js
@@ -12,7 +12,7 @@ const store = createStore();
 
 ReactDOM.render(
     <Provider store={store}>
-        <SubmissionsByRoundApp pageContent={container.innerHTML} roundId={parseInt(container.dataset.roundId)} />
+        <SubmissionsByRoundApp pageContent={container.innerHTML} roundID={parseInt(container.dataset.roundId)} />
     </Provider>,
     container
 );
diff --git a/opentech/static_src/src/app/src/redux/actions/submissions.js b/opentech/static_src/src/app/src/redux/actions/submissions.js
index 980bf516e298386ee747af882ca282adcb618de6..db35aec0678e3239cec174980b3de9ff6a8d6459 100644
--- a/opentech/static_src/src/app/src/redux/actions/submissions.js
+++ b/opentech/static_src/src/app/src/redux/actions/submissions.js
@@ -1,4 +1,10 @@
 import api from '@api';
+import {
+    getCurrentSubmission,
+    getCurrentSubmissionID,
+    getCurrentRoundID,
+    getCurrentRound,
+} from '@selectors/submissions';
 
 
 // Submissions by round
@@ -7,46 +13,122 @@ export const UPDATE_SUBMISSIONS_BY_ROUND = 'UPDATE_SUBMISSIONS_BY_ROUND';
 export const START_LOADING_SUBMISSIONS_BY_ROUND = 'START_LOADING_SUBMISSIONS_BY_ROUND';
 export const FAIL_LOADING_SUBMISSIONS_BY_ROUND = 'FAIL_LOADING_SUBMISSIONS_BY_ROUND';
 
+// Submissions
+export const SET_CURRENT_SUBMISSION = 'SET_CURRENT_SUBMISSION';
+export const START_LOADING_SUBMISSION = 'START_LOADING_SUBMISSION';
+export const FAIL_LOADING_SUBMISSION = 'FAIL_LOADING_SUBMISSION';
+export const UPDATE_SUBMISSION = 'UPDATE_SUBMISSION';
+export const CLEAR_CURRENT_SUBMISSION = 'CLEAR_CURRENT_SUBMISSION';
 
 export const setCurrentSubmissionRound = id => ({
     type: SET_CURRENT_SUBMISSION_ROUND,
     id,
 });
 
-export const fetchSubmissionsByRound = roundId => {
+export const setCurrentSubmission = id => ({
+    type: SET_CURRENT_SUBMISSION,
+    id,
+});
+
+export const loadCurrentRound = (requiredFields=[]) => (dispatch, getState) => {
+    const round = getCurrentRound(getState())
+
+    if (round && requiredFields.every(key => round.hasOwnProperty(key))) {
+        return null
+    }
+
+    return dispatch(fetchSubmissionsByRound(getCurrentRoundID(getState())))
+}
+
+
+export const fetchSubmissionsByRound = roundID => {
     return async function(dispatch) {
-        dispatch(startLoadingSubmissionsByRound(roundId));
+        dispatch(startLoadingSubmissionsByRound(roundID));
         try {
-            const response = await api.fetchSubmissionsByRound(roundId);
+            const response = await api.fetchSubmissionsByRound(roundID);
             const json = await response.json();
-            if (!response.ok) {
-                dispatch(failLoadingSubmissionsByRound(roundId));
-                return;
+            if (response.ok) {
+                dispatch(updateSubmissionsByRound(roundID, json));
+            } else {
+                dispatch(failLoadingSubmissionsByRound(json.meta.error));
             }
-            dispatch(updateSubmissionsByRound(roundId, json));
         } catch (e) {
-            console.error(e);
-            dispatch(failLoadingSubmissionsByRound(roundId));
+            dispatch(failLoadingSubmissionsByRound(e.message));
         }
     };
 };
 
 
-const updateSubmissionsByRound = (roundId, data) => ({
+const updateSubmissionsByRound = (roundID, data) => ({
     type: UPDATE_SUBMISSIONS_BY_ROUND,
-    roundId,
+    roundID,
     data,
 });
 
 
-const startLoadingSubmissionsByRound = roundId => ({
+const startLoadingSubmissionsByRound = (roundID) => ({
     type: START_LOADING_SUBMISSIONS_BY_ROUND,
-    roundId,
+    roundID,
 });
 
 
-
-const failLoadingSubmissionsByRound = roundId => ({
+const failLoadingSubmissionsByRound = (message) => ({
     type: FAIL_LOADING_SUBMISSIONS_BY_ROUND,
-    roundId,
+    message,
+});
+
+
+export const loadCurrentSubmission = (requiredFields=[]) => (dispatch, getState) => {
+    const submissionID = getCurrentSubmissionID(getState())
+    if ( !submissionID ) {
+        return null
+    }
+    const submission = getCurrentSubmission(getState())
+
+    if (submission && requiredFields.every(key => submission.hasOwnProperty(key))) {
+        return null
+    }
+
+    return dispatch(fetchSubmission(getCurrentSubmissionID(getState())))
+}
+
+
+export const fetchSubmission = submissionID => {
+    return async function(dispatch) {
+
+        dispatch(startLoadingSubmission(submissionID));
+        try {
+            const response = await api.fetchSubmission(submissionID);
+            const json = await response.json();
+            if (response.ok) {
+                dispatch(updateSubmission(submissionID, json));
+            } else {
+                dispatch(failLoadingSubmission(json.meta.error));
+            }
+        } catch (e) {
+            dispatch(failLoadingSubmission(e.message));
+        }
+    };
+};
+
+
+const startLoadingSubmission = submissionID => ({
+    type: START_LOADING_SUBMISSION,
+    submissionID,
+});
+
+const failLoadingSubmission = submissionID => ({
+    type: FAIL_LOADING_SUBMISSION,
+    submissionID,
+});
+
+
+const updateSubmission = (submissionID, data) => ({
+    type: UPDATE_SUBMISSION,
+    submissionID,
+    data,
+});
+
+export const clearCurrentSubmission = () => ({
+    type: CLEAR_CURRENT_SUBMISSION,
 });
diff --git a/opentech/static_src/src/app/src/redux/reducers/index.js b/opentech/static_src/src/app/src/redux/reducers/index.js
index b2c6861e4606ac7c820ee8dd4e870366d82aa8a2..d1e5e237467ee34a6e305045c469b99560e3e92b 100644
--- a/opentech/static_src/src/app/src/redux/reducers/index.js
+++ b/opentech/static_src/src/app/src/redux/reducers/index.js
@@ -1,7 +1,9 @@
 import { combineReducers } from 'redux'
 
 import submissions from '@reducers/submissions';
+import rounds from '@reducers/rounds';
 
 export default combineReducers({
     submissions,
+    rounds,
 });
diff --git a/opentech/static_src/src/app/src/redux/reducers/rounds.js b/opentech/static_src/src/app/src/redux/reducers/rounds.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f4253b713fa386196a99315fa6221bb47e12630
--- /dev/null
+++ b/opentech/static_src/src/app/src/redux/reducers/rounds.js
@@ -0,0 +1,82 @@
+import { combineReducers } from 'redux';
+
+import {
+    FAIL_LOADING_SUBMISSIONS_BY_ROUND,
+    SET_CURRENT_SUBMISSION_ROUND,
+    START_LOADING_SUBMISSIONS_BY_ROUND,
+    UPDATE_SUBMISSIONS_BY_ROUND,
+} from '@actions/submissions';
+
+
+function round(state={id: null, submissions: [], isFetching: false}, action) {
+    switch(action.type) {
+        case UPDATE_SUBMISSIONS_BY_ROUND:
+            return {
+                ...state,
+                id: action.roundID,
+                submissions: action.data.results.map(submission => submission.id),
+                isFetching: false,
+            };
+        case FAIL_LOADING_SUBMISSIONS_BY_ROUND:
+            return {
+                ...state,
+                isFetching: false,
+            };
+        case START_LOADING_SUBMISSIONS_BY_ROUND:
+            return {
+                ...state,
+                id: action.roundID,
+                isFetching: true,
+            };
+        default:
+            return state;
+    }
+}
+
+
+function roundsByID(state = {}, action) {
+    switch(action.type) {
+        case UPDATE_SUBMISSIONS_BY_ROUND:
+        case FAIL_LOADING_SUBMISSIONS_BY_ROUND:
+        case START_LOADING_SUBMISSIONS_BY_ROUND:
+            return {
+                ...state,
+                [action.roundID]: round(state[action.roundID], action)
+            };
+        default:
+            return state;
+    }
+}
+
+
+function errorMessage(state = null, action) {
+    switch(action.type) {
+    case FAIL_LOADING_SUBMISSIONS_BY_ROUND:
+        return action.message;
+    case UPDATE_SUBMISSIONS_BY_ROUND:
+    case START_LOADING_SUBMISSIONS_BY_ROUND:
+        return null;
+    default:
+        return state;
+    }
+
+}
+
+
+function currentRound(state = null, action) {
+    switch(action.type) {
+        case SET_CURRENT_SUBMISSION_ROUND:
+            return action.id;
+        default:
+            return state;
+    }
+}
+
+
+const rounds = combineReducers({
+    byID: roundsByID,
+    current: currentRound,
+    error: errorMessage,
+});
+
+export default rounds;
diff --git a/opentech/static_src/src/app/src/redux/reducers/submissions.js b/opentech/static_src/src/app/src/redux/reducers/submissions.js
index 4970ddeb302aeb18a240de7462bdedbf54c13da7..7563d1e25f0ac19364f82d0c96af3624f2125d4c 100644
--- a/opentech/static_src/src/app/src/redux/reducers/submissions.js
+++ b/opentech/static_src/src/app/src/redux/reducers/submissions.js
@@ -1,58 +1,86 @@
+import { combineReducers } from 'redux';
+
 import {
-    FAIL_LOADING_SUBMISSIONS_BY_ROUND,
-    SET_CURRENT_SUBMISSION_ROUND,
-    START_LOADING_SUBMISSIONS_BY_ROUND,
+    CLEAR_CURRENT_SUBMISSION,
+    FAIL_LOADING_SUBMISSION,
+    START_LOADING_SUBMISSION,
     UPDATE_SUBMISSIONS_BY_ROUND,
+    UPDATE_SUBMISSION,
+    SET_CURRENT_SUBMISSION,
 } from '@actions/submissions';
 
-const initialState = {
-    currentRound: null,
-    submissionsByID: {},
-    submissionsByRoundID: {},
-    itemsLoadingError: false,
-    itemsLoading: false,
-};
 
-export default function submissions(state = initialState, action) {
+function submission(state, action) {
     switch(action.type) {
-        case SET_CURRENT_SUBMISSION_ROUND:
+        case START_LOADING_SUBMISSION:
             return {
                 ...state,
-                currentRound: action.id,
+                isFetching: true,
+                isErrored: false,
             };
-        case UPDATE_SUBMISSIONS_BY_ROUND:
+        case FAIL_LOADING_SUBMISSION:
             return {
                 ...state,
-                submissionsByID: {
-                    ...state.submissionsByID,
-                    ...action.data.results.reduce((newItems, v) => {
-                        newItems[v.id] = {
-                            ...state.submissionsByID[v.id],
-                            ...v
-                        };
-                        return newItems;
-                    }, {}),
-                },
-                submissionsByRoundID: {
-                    ...state.submissionsByRoundID,
-                    [action.roundId]: action.data.results.map(v => v.id),
-                },
-                itemsLoading: false,
-                itemsLoadingError: false,
+                isFetching: false,
+                isErrored: true,
             };
-        case FAIL_LOADING_SUBMISSIONS_BY_ROUND:
+        case UPDATE_SUBMISSION:
             return {
                 ...state,
-                itemsLoading: false,
-                itemsLoadingError: true,
+                ...action.data,
+                isFetching: false,
+                isErrored: false,
             };
-        case START_LOADING_SUBMISSIONS_BY_ROUND:
+        default:
+            return state;
+    }
+}
+
+
+function submissionsByID(state = {}, action) {
+    switch(action.type) {
+        case START_LOADING_SUBMISSION:
+        case FAIL_LOADING_SUBMISSION:
+        case UPDATE_SUBMISSION:
             return {
                 ...state,
-                itemsLoading: true,
-                itemsLoadingError: false,
+                [action.submissionID]: submission(state[action.submissionID], action),
+            };
+        case UPDATE_SUBMISSIONS_BY_ROUND:
+            return {
+                ...state,
+                ...action.data.results.reduce((newItems, newSubmission) => {
+                    newItems[newSubmission.id] = submission(
+                        state[newSubmission.id],
+                        {
+                            type: UPDATE_SUBMISSION,
+                            data: newSubmission,
+                        }
+                    );
+                    return newItems;
+                }, {}),
             };
         default:
             return state;
     }
 }
+
+
+function currentSubmission(state = null, action) {
+    switch(action.type) {
+        case SET_CURRENT_SUBMISSION:
+            return action.id;
+        case CLEAR_CURRENT_SUBMISSION:
+            return null;
+        default:
+            return state;
+    }
+}
+
+
+const submissions = combineReducers({
+    byID: submissionsByID,
+    current: currentSubmission,
+});
+
+export default submissions;
diff --git a/opentech/static_src/src/app/src/redux/selectors/submissions.js b/opentech/static_src/src/app/src/redux/selectors/submissions.js
index cd43114ec79bd4743e51eb615e5abeb1f3ccbc32..09124b6896da42c2c177f2e706a8b2528deaca54 100644
--- a/opentech/static_src/src/app/src/redux/selectors/submissions.js
+++ b/opentech/static_src/src/app/src/redux/selectors/submissions.js
@@ -1,26 +1,53 @@
 import { createSelector } from 'reselect';
 
-const getSubmissions = state => state.submissions.submissionsByID;
+const getSubmissions = state => state.submissions.byID;
 
-const getSubmissionIDsByRound = state => state.submissions.submissionsByRoundID;
+const getRounds = state => state.rounds.byID;
 
-const getCurrentRoundID = state => state.submissions.currentRound;
+const getCurrentRoundID = state => state.rounds.current;
+
+const getCurrentRound = createSelector(
+    [ getCurrentRoundID, getRounds],
+    (id, rounds) => {
+        return rounds[id];
+    }
+);
+
+const getCurrentSubmissionID = state => state.submissions.current;
 
 
 const getCurrentRoundSubmissions = createSelector(
-    [ getSubmissionIDsByRound, getCurrentRoundID , getSubmissions],
-    (submissionsByRound, currentRoundID, submissions) => {
-        return (submissionsByRound[currentRoundID] || []).map(submissionID => submissions[submissionID]);
+    [ getCurrentRound, getSubmissions],
+    (round, submissions) => {
+        const roundSubmissions = round ? round.submissions : [];
+        return roundSubmissions.map(submissionID => submissions[submissionID]);
+    }
+);
+
+
+const getCurrentSubmission = createSelector(
+    [ getCurrentSubmissionID, getSubmissions ],
+    (id, submissions) => {
+        return submissions[id];
     }
 );
 
-const getSubmissionsByRoundErrorState = state => state.submissions.itemsLoadingError;
+const getSubmissionLoadingState = state => state.submissions.itemLoading === true;
+
+const getSubmissionErrorState = state => state.submissions.itemLoadingError === true;
+
+const getSubmissionsByRoundError = state => state.rounds.error;
 
-const getSubmissionsByRoundLoadingState = state => state.submissions.itemsLoading;
+const getSubmissionsByRoundLoadingState = state => state.submissions.itemsLoading === true;
 
 export {
     getCurrentRoundID,
+    getCurrentRound,
     getCurrentRoundSubmissions,
-    getSubmissionsByRoundErrorState,
+    getCurrentSubmission,
+    getCurrentSubmissionID,
+    getSubmissionsByRoundError,
     getSubmissionsByRoundLoadingState,
+    getSubmissionLoadingState,
+    getSubmissionErrorState,
 };
diff --git a/opentech/static_src/src/app/webpack.base.config.js b/opentech/static_src/src/app/webpack.base.config.js
index 5e8e561a5948027544ac51a6396423adff7116df..b6017a03190fc4870e014265d069f79bdd48d734 100644
--- a/opentech/static_src/src/app/webpack.base.config.js
+++ b/opentech/static_src/src/app/webpack.base.config.js
@@ -23,7 +23,16 @@ module.exports = {
                         'react-hot-loader/babel',
                         '@babel/plugin-proposal-class-properties'
                     ]
-                }
+                },
+            },
+            {
+                test: /\.js$/,
+                exclude: /node_modules/,
+                include: [path.resolve(__dirname, './src')],
+                loader: 'eslint-loader',
+                options: {
+                    configFile: path.resolve(__dirname, './.eslintrc'),
+                },
             },
             {
                 test: /\.scss$/,
diff --git a/opentech/static_src/src/images/download.svg b/opentech/static_src/src/images/download.svg
new file mode 100644
index 0000000000000000000000000000000000000000..9c729aba1bcd0ea17eb1bb8ea72babcc9366bf40
--- /dev/null
+++ b/opentech/static_src/src/images/download.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg viewBox="0 0 16 21" height="21" width="16" xmlns="http://www.w3.org/2000/svg">
+  <g stroke-width="3" fill="none" fill-rule="evenodd" stroke-linecap="square">
+      <path d="M8.176 13.833V2.167M8.303 14l4.991-4.714M8 14L3.009 9.286M13.824 19.5H2.176" />
+  </g>
+</svg>
diff --git a/opentech/static_src/src/images/file.svg b/opentech/static_src/src/images/file.svg
new file mode 100644
index 0000000000000000000000000000000000000000..936d57b3b18cd09fbe4b54a8c053bf21cd707a3b
--- /dev/null
+++ b/opentech/static_src/src/images/file.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg viewBox="0 0 27 32" height="32" width="27" xmlns="http://www.w3.org/2000/svg">
+    <g stroke-width="2" fill="none" fill-rule="evenodd">
+        <path d="M1.296 1v29.25H25V9.429h-8.218V1H1.296z" />
+        <path d="M5.5 20h15M5.5 15H12" stroke-linecap="square" />
+        <path d="M16.828.729l8.551 8.5" />
+    </g>
+</svg>
diff --git a/package-lock.json b/package-lock.json
index 20f5a048a4296536a409c71a33cc00f095e9ab04..c03d14147002a5f8545753a762f00216e4b07807 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1369,6 +1369,16 @@
             "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
             "dev": true
         },
+        "array-includes": {
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
+            "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.2",
+                "es-abstract": "^1.7.0"
+            }
+        },
         "array-initial": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
@@ -1556,6 +1566,32 @@
             "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
             "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
         },
+        "babel-eslint": {
+            "version": "10.0.1",
+            "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz",
+            "integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==",
+            "dev": true,
+            "requires": {
+                "@babel/code-frame": "^7.0.0",
+                "@babel/parser": "^7.0.0",
+                "@babel/traverse": "^7.0.0",
+                "@babel/types": "^7.0.0",
+                "eslint-scope": "3.7.1",
+                "eslint-visitor-keys": "^1.0.0"
+            },
+            "dependencies": {
+                "eslint-scope": {
+                    "version": "3.7.1",
+                    "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+                    "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+                    "dev": true,
+                    "requires": {
+                        "esrecurse": "^4.1.0",
+                        "estraverse": "^4.1.1"
+                    }
+                }
+            }
+        },
         "babel-loader": {
             "version": "8.0.4",
             "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.4.tgz",
@@ -3023,6 +3059,14 @@
                 "esutils": "^2.0.2"
             }
         },
+        "dom-helpers": {
+            "version": "3.4.0",
+            "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
+            "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
+            "requires": {
+                "@babel/runtime": "^7.1.2"
+            }
+        },
         "dom-serializer": {
             "version": "0.1.0",
             "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
@@ -3389,6 +3433,45 @@
                 }
             }
         },
+        "eslint-loader": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.1.tgz",
+            "integrity": "sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==",
+            "dev": true,
+            "requires": {
+                "loader-fs-cache": "^1.0.0",
+                "loader-utils": "^1.0.2",
+                "object-assign": "^4.0.1",
+                "object-hash": "^1.1.4",
+                "rimraf": "^2.6.1"
+            }
+        },
+        "eslint-plugin-react": {
+            "version": "7.12.4",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz",
+            "integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==",
+            "dev": true,
+            "requires": {
+                "array-includes": "^3.0.3",
+                "doctrine": "^2.1.0",
+                "has": "^1.0.3",
+                "jsx-ast-utils": "^2.0.1",
+                "object.fromentries": "^2.0.0",
+                "prop-types": "^15.6.2",
+                "resolve": "^1.9.0"
+            },
+            "dependencies": {
+                "resolve": {
+                    "version": "1.9.0",
+                    "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz",
+                    "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==",
+                    "dev": true,
+                    "requires": {
+                        "path-parse": "^1.0.6"
+                    }
+                }
+            }
+        },
         "eslint-scope": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
@@ -4173,9 +4256,9 @@
             "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
         },
         "fsevents": {
-            "version": "1.2.4",
-            "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
-            "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
+            "version": "1.2.7",
+            "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
+            "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
             "optional": true,
             "requires": {
                 "nan": "^2.9.2",
@@ -4184,25 +4267,21 @@
             "dependencies": {
                 "abbrev": {
                     "version": "1.1.1",
-                    "resolved": false,
-                    "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+                    "bundled": true,
                     "optional": true
                 },
                 "ansi-regex": {
                     "version": "2.1.1",
-                    "resolved": false,
-                    "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+                    "bundled": true
                 },
                 "aproba": {
                     "version": "1.2.0",
-                    "resolved": false,
-                    "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+                    "bundled": true,
                     "optional": true
                 },
                 "are-we-there-yet": {
-                    "version": "1.1.4",
-                    "resolved": false,
-                    "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+                    "version": "1.1.5",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "delegates": "^1.0.0",
@@ -4211,76 +4290,64 @@
                 },
                 "balanced-match": {
                     "version": "1.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+                    "bundled": true
                 },
                 "brace-expansion": {
                     "version": "1.1.11",
-                    "resolved": false,
-                    "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+                    "bundled": true,
                     "requires": {
                         "balanced-match": "^1.0.0",
                         "concat-map": "0.0.1"
                     }
                 },
                 "chownr": {
-                    "version": "1.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
+                    "version": "1.1.1",
+                    "bundled": true,
                     "optional": true
                 },
                 "code-point-at": {
                     "version": "1.1.0",
-                    "resolved": false,
-                    "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+                    "bundled": true
                 },
                 "concat-map": {
                     "version": "0.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+                    "bundled": true
                 },
                 "console-control-strings": {
                     "version": "1.1.0",
-                    "resolved": false,
-                    "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+                    "bundled": true
                 },
                 "core-util-is": {
                     "version": "1.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+                    "bundled": true,
                     "optional": true
                 },
                 "debug": {
                     "version": "2.6.9",
-                    "resolved": false,
-                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "ms": "2.0.0"
                     }
                 },
                 "deep-extend": {
-                    "version": "0.5.1",
-                    "resolved": false,
-                    "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==",
+                    "version": "0.6.0",
+                    "bundled": true,
                     "optional": true
                 },
                 "delegates": {
                     "version": "1.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+                    "bundled": true,
                     "optional": true
                 },
                 "detect-libc": {
                     "version": "1.0.3",
-                    "resolved": false,
-                    "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+                    "bundled": true,
                     "optional": true
                 },
                 "fs-minipass": {
                     "version": "1.2.5",
-                    "resolved": false,
-                    "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "minipass": "^2.2.1"
@@ -4288,14 +4355,12 @@
                 },
                 "fs.realpath": {
                     "version": "1.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+                    "bundled": true,
                     "optional": true
                 },
                 "gauge": {
                     "version": "2.7.4",
-                    "resolved": false,
-                    "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "aproba": "^1.0.3",
@@ -4309,9 +4374,8 @@
                     }
                 },
                 "glob": {
-                    "version": "7.1.2",
-                    "resolved": false,
-                    "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+                    "version": "7.1.3",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "fs.realpath": "^1.0.0",
@@ -4324,23 +4388,20 @@
                 },
                 "has-unicode": {
                     "version": "2.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+                    "bundled": true,
                     "optional": true
                 },
                 "iconv-lite": {
-                    "version": "0.4.21",
-                    "resolved": false,
-                    "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
+                    "version": "0.4.24",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
-                        "safer-buffer": "^2.1.0"
+                        "safer-buffer": ">= 2.1.2 < 3"
                     }
                 },
                 "ignore-walk": {
                     "version": "3.0.1",
-                    "resolved": false,
-                    "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "minimatch": "^3.0.4"
@@ -4348,8 +4409,7 @@
                 },
                 "inflight": {
                     "version": "1.0.6",
-                    "resolved": false,
-                    "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "once": "^1.3.0",
@@ -4358,55 +4418,47 @@
                 },
                 "inherits": {
                     "version": "2.0.3",
-                    "resolved": false,
-                    "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+                    "bundled": true
                 },
                 "ini": {
                     "version": "1.3.5",
-                    "resolved": false,
-                    "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+                    "bundled": true,
                     "optional": true
                 },
                 "is-fullwidth-code-point": {
                     "version": "1.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+                    "bundled": true,
                     "requires": {
                         "number-is-nan": "^1.0.0"
                     }
                 },
                 "isarray": {
                     "version": "1.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+                    "bundled": true,
                     "optional": true
                 },
                 "minimatch": {
                     "version": "3.0.4",
-                    "resolved": false,
-                    "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+                    "bundled": true,
                     "requires": {
                         "brace-expansion": "^1.1.7"
                     }
                 },
                 "minimist": {
                     "version": "0.0.8",
-                    "resolved": false,
-                    "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+                    "bundled": true
                 },
                 "minipass": {
-                    "version": "2.2.4",
-                    "resolved": false,
-                    "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
+                    "version": "2.3.5",
+                    "bundled": true,
                     "requires": {
-                        "safe-buffer": "^5.1.1",
+                        "safe-buffer": "^5.1.2",
                         "yallist": "^3.0.0"
                     }
                 },
                 "minizlib": {
-                    "version": "1.1.0",
-                    "resolved": false,
-                    "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
+                    "version": "1.2.1",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "minipass": "^2.2.1"
@@ -4414,22 +4466,19 @@
                 },
                 "mkdirp": {
                     "version": "0.5.1",
-                    "resolved": false,
-                    "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+                    "bundled": true,
                     "requires": {
                         "minimist": "0.0.8"
                     }
                 },
                 "ms": {
                     "version": "2.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+                    "bundled": true,
                     "optional": true
                 },
                 "needle": {
-                    "version": "2.2.0",
-                    "resolved": false,
-                    "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
+                    "version": "2.2.4",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "debug": "^2.1.2",
@@ -4438,18 +4487,17 @@
                     }
                 },
                 "node-pre-gyp": {
-                    "version": "0.10.0",
-                    "resolved": false,
-                    "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==",
+                    "version": "0.10.3",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "detect-libc": "^1.0.2",
                         "mkdirp": "^0.5.1",
-                        "needle": "^2.2.0",
+                        "needle": "^2.2.1",
                         "nopt": "^4.0.1",
                         "npm-packlist": "^1.1.6",
                         "npmlog": "^4.0.2",
-                        "rc": "^1.1.7",
+                        "rc": "^1.2.7",
                         "rimraf": "^2.6.1",
                         "semver": "^5.3.0",
                         "tar": "^4"
@@ -4457,8 +4505,7 @@
                 },
                 "nopt": {
                     "version": "4.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "abbrev": "1",
@@ -4466,15 +4513,13 @@
                     }
                 },
                 "npm-bundled": {
-                    "version": "1.0.3",
-                    "resolved": false,
-                    "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==",
+                    "version": "1.0.5",
+                    "bundled": true,
                     "optional": true
                 },
                 "npm-packlist": {
-                    "version": "1.1.10",
-                    "resolved": false,
-                    "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
+                    "version": "1.2.0",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "ignore-walk": "^3.0.1",
@@ -4483,8 +4528,7 @@
                 },
                 "npmlog": {
                     "version": "4.1.2",
-                    "resolved": false,
-                    "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "are-we-there-yet": "~1.1.2",
@@ -4495,39 +4539,33 @@
                 },
                 "number-is-nan": {
                     "version": "1.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+                    "bundled": true
                 },
                 "object-assign": {
                     "version": "4.1.1",
-                    "resolved": false,
-                    "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+                    "bundled": true,
                     "optional": true
                 },
                 "once": {
                     "version": "1.4.0",
-                    "resolved": false,
-                    "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+                    "bundled": true,
                     "requires": {
                         "wrappy": "1"
                     }
                 },
                 "os-homedir": {
                     "version": "1.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+                    "bundled": true,
                     "optional": true
                 },
                 "os-tmpdir": {
                     "version": "1.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+                    "bundled": true,
                     "optional": true
                 },
                 "osenv": {
                     "version": "0.1.5",
-                    "resolved": false,
-                    "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "os-homedir": "^1.0.0",
@@ -4536,23 +4574,20 @@
                 },
                 "path-is-absolute": {
                     "version": "1.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+                    "bundled": true,
                     "optional": true
                 },
                 "process-nextick-args": {
                     "version": "2.0.0",
-                    "resolved": false,
-                    "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+                    "bundled": true,
                     "optional": true
                 },
                 "rc": {
-                    "version": "1.2.7",
-                    "resolved": false,
-                    "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==",
+                    "version": "1.2.8",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
-                        "deep-extend": "^0.5.1",
+                        "deep-extend": "^0.6.0",
                         "ini": "~1.3.0",
                         "minimist": "^1.2.0",
                         "strip-json-comments": "~2.0.1"
@@ -4560,16 +4595,14 @@
                     "dependencies": {
                         "minimist": {
                             "version": "1.2.0",
-                            "resolved": false,
-                            "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+                            "bundled": true,
                             "optional": true
                         }
                     }
                 },
                 "readable-stream": {
                     "version": "2.3.6",
-                    "resolved": false,
-                    "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "core-util-is": "~1.0.0",
@@ -4582,53 +4615,45 @@
                     }
                 },
                 "rimraf": {
-                    "version": "2.6.2",
-                    "resolved": false,
-                    "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+                    "version": "2.6.3",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
-                        "glob": "^7.0.5"
+                        "glob": "^7.1.3"
                     }
                 },
                 "safe-buffer": {
-                    "version": "5.1.1",
-                    "resolved": false,
-                    "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+                    "version": "5.1.2",
+                    "bundled": true
                 },
                 "safer-buffer": {
                     "version": "2.1.2",
-                    "resolved": false,
-                    "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+                    "bundled": true,
                     "optional": true
                 },
                 "sax": {
                     "version": "1.2.4",
-                    "resolved": false,
-                    "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+                    "bundled": true,
                     "optional": true
                 },
                 "semver": {
-                    "version": "5.5.0",
-                    "resolved": false,
-                    "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+                    "version": "5.6.0",
+                    "bundled": true,
                     "optional": true
                 },
                 "set-blocking": {
                     "version": "2.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+                    "bundled": true,
                     "optional": true
                 },
                 "signal-exit": {
                     "version": "3.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+                    "bundled": true,
                     "optional": true
                 },
                 "string-width": {
                     "version": "1.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+                    "bundled": true,
                     "requires": {
                         "code-point-at": "^1.0.0",
                         "is-fullwidth-code-point": "^1.0.0",
@@ -4637,8 +4662,7 @@
                 },
                 "string_decoder": {
                     "version": "1.1.1",
-                    "resolved": false,
-                    "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "safe-buffer": "~5.1.0"
@@ -4646,57 +4670,50 @@
                 },
                 "strip-ansi": {
                     "version": "3.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+                    "bundled": true,
                     "requires": {
                         "ansi-regex": "^2.0.0"
                     }
                 },
                 "strip-json-comments": {
                     "version": "2.0.1",
-                    "resolved": false,
-                    "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+                    "bundled": true,
                     "optional": true
                 },
                 "tar": {
-                    "version": "4.4.1",
-                    "resolved": false,
-                    "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==",
+                    "version": "4.4.8",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
-                        "chownr": "^1.0.1",
+                        "chownr": "^1.1.1",
                         "fs-minipass": "^1.2.5",
-                        "minipass": "^2.2.4",
-                        "minizlib": "^1.1.0",
+                        "minipass": "^2.3.4",
+                        "minizlib": "^1.1.1",
                         "mkdirp": "^0.5.0",
-                        "safe-buffer": "^5.1.1",
+                        "safe-buffer": "^5.1.2",
                         "yallist": "^3.0.2"
                     }
                 },
                 "util-deprecate": {
                     "version": "1.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+                    "bundled": true,
                     "optional": true
                 },
                 "wide-align": {
-                    "version": "1.1.2",
-                    "resolved": false,
-                    "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+                    "version": "1.1.3",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
-                        "string-width": "^1.0.2"
+                        "string-width": "^1.0.2 || 2"
                     }
                 },
                 "wrappy": {
                     "version": "1.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+                    "bundled": true
                 },
                 "yallist": {
-                    "version": "3.0.2",
-                    "resolved": false,
-                    "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
+                    "version": "3.0.3",
+                    "bundled": true
                 }
             }
         },
@@ -6421,6 +6438,15 @@
                 "verror": "1.10.0"
             }
         },
+        "jsx-ast-utils": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz",
+            "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=",
+            "dev": true,
+            "requires": {
+                "array-includes": "^3.0.3"
+            }
+        },
         "just-debounce": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
@@ -6525,6 +6551,38 @@
                 }
             }
         },
+        "loader-fs-cache": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz",
+            "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=",
+            "dev": true,
+            "requires": {
+                "find-cache-dir": "^0.1.1",
+                "mkdirp": "0.5.1"
+            },
+            "dependencies": {
+                "find-cache-dir": {
+                    "version": "0.1.1",
+                    "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
+                    "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
+                    "dev": true,
+                    "requires": {
+                        "commondir": "^1.0.1",
+                        "mkdirp": "^0.5.1",
+                        "pkg-dir": "^1.0.0"
+                    }
+                },
+                "pkg-dir": {
+                    "version": "1.0.0",
+                    "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
+                    "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
+                    "dev": true,
+                    "requires": {
+                        "find-up": "^1.0.0"
+                    }
+                }
+            }
+        },
         "loader-runner": {
             "version": "2.3.1",
             "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.1.tgz",
@@ -6571,6 +6629,11 @@
             "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
             "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
         },
+        "lodash._getnative": {
+            "version": "3.9.1",
+            "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+            "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+        },
         "lodash.assign": {
             "version": "4.2.0",
             "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
@@ -7403,6 +7466,12 @@
                 }
             }
         },
+        "object-hash": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz",
+            "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==",
+            "dev": true
+        },
         "object-keys": {
             "version": "1.0.12",
             "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
@@ -7438,6 +7507,18 @@
                 "isobject": "^3.0.0"
             }
         },
+        "object.fromentries": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz",
+            "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.2",
+                "es-abstract": "^1.11.0",
+                "function-bind": "^1.1.1",
+                "has": "^1.0.1"
+            }
+        },
         "object.getownpropertydescriptors": {
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
@@ -8287,8 +8368,7 @@
         "react-lifecycles-compat": {
             "version": "3.0.4",
             "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
-            "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
-            "dev": true
+            "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
         },
         "react-redux": {
             "version": "6.0.0",
@@ -8313,6 +8393,37 @@
                 }
             }
         },
+        "react-transition-group": {
+            "version": "2.5.3",
+            "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz",
+            "integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==",
+            "requires": {
+                "dom-helpers": "^3.3.1",
+                "loose-envify": "^1.4.0",
+                "prop-types": "^15.6.2",
+                "react-lifecycles-compat": "^3.0.4"
+            }
+        },
+        "react-window-size-listener": {
+            "version": "1.2.3",
+            "resolved": "https://registry.npmjs.org/react-window-size-listener/-/react-window-size-listener-1.2.3.tgz",
+            "integrity": "sha512-95lyZTMBBqH0xuhBEP0LshEKlHVF+VHQO7UojfDYmyMoO9jriTAY9Ktr5p9ZF4yR8QKzWZBAUdOEndY/JuMmwA==",
+            "requires": {
+                "lodash.debounce": "^3.1.1",
+                "prop-types": "^15.6.0",
+                "randomatic": ">=3.0.0"
+            },
+            "dependencies": {
+                "lodash.debounce": {
+                    "version": "3.1.1",
+                    "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz",
+                    "integrity": "sha1-gSIRw3ipTMKdWqTjNGzwv846ffU=",
+                    "requires": {
+                        "lodash._getnative": "^3.0.0"
+                    }
+                }
+            }
+        },
         "read-pkg": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
diff --git a/package.json b/package.json
index d1dc670a25bdc1440792d8c521ab9a13fe41c74c..7ad0fcfa4597981cdb4b18bee2f73c21963125a2 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,8 @@
         "react": "^16.7.0",
         "react-dom": "^16.7.0",
         "react-redux": "^6.0.0",
+        "react-transition-group": "^2.5.3",
+        "react-window-size-listener": "^1.2.3",
         "redux": "^4.0.1",
         "redux-logger": "^3.0.6",
         "redux-thunk": "^2.3.0",
@@ -38,8 +40,11 @@
         "@babel/plugin-proposal-class-properties": "^7.2.3",
         "@babel/preset-env": "^7.2.3",
         "@babel/preset-react": "^7.0.0",
+        "babel-eslint": "^10.0.1",
         "babel-loader": "^8.0.4",
         "css-loader": "^2.1.0",
+        "eslint-loader": "^2.1.1",
+        "eslint-plugin-react": "^7.12.4",
         "gulp-eslint": "^5.0.0",
         "gulp-sass-lint": "^1.4.0",
         "gulp-sourcemaps": "^2.6.4",