diff --git a/src/main/webapp/WEB-INF/tags/page/head.tag b/src/main/webapp/WEB-INF/tags/page/head.tag
index ecd4589529d2a6947f6dbb6d2d37278751a7b588..67e051f33a773a6ea556ada94b2abe85d57eb0de 100755
--- a/src/main/webapp/WEB-INF/tags/page/head.tag
+++ b/src/main/webapp/WEB-INF/tags/page/head.tag
@@ -3,8 +3,8 @@
 <%@ taglib prefix="pg" tagdir="/WEB-INF/tags/page" %>
 
 <%@ attribute name="title" %>
-<%@ attribute name="headTop" fragment="true" %>
-<%@ attribute name="headBottom" fragment="true" %>
+<%@ attribute name="headTop" %>
+<%@ attribute name="headBottom" %>
 
 <head>
 
diff --git a/src/main/webapp/WEB-INF/tags/page/restricted.tag b/src/main/webapp/WEB-INF/tags/page/restricted.tag
index c1fa1e79dd38f853ad09f75dfb3c27e0ebf85706..dac0c39506843ab55776701d2b49337bd20aa8e5 100644
--- a/src/main/webapp/WEB-INF/tags/page/restricted.tag
+++ b/src/main/webapp/WEB-INF/tags/page/restricted.tag
@@ -6,6 +6,14 @@
 
 <%-- restricts access to only admin users --%>
 
+<c:if test="${empty hasInit}">
+    <pg:init>
+        <c:if test="${empty hasVars}">
+            <pg:jsvars/>
+        </c:if>
+    </pg:init>
+</c:if>
+
 <c:choose>
     <c:when test="${isAdmin == true}">
 
diff --git a/src/main/webapp/WEB-INF/tags/page/xnat.tag b/src/main/webapp/WEB-INF/tags/page/xnat.tag
index 2aff8706a75b7a70211f1ba68747e1ee2ad87b5e..5265f77e2f44a72e81258b6dcff6048de590fc12 100644
--- a/src/main/webapp/WEB-INF/tags/page/xnat.tag
+++ b/src/main/webapp/WEB-INF/tags/page/xnat.tag
@@ -76,8 +76,6 @@
     <script src="${_siteRoot}/scripts/lib/js.cookie.js"></script>
     <script src="${_siteRoot}/scripts/lib/yamljs/dist/yaml.js"></script>
 
-
-
     <%--<script src="${_siteRoot}/scripts/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>--%>
     <%--<script src="${_siteRoot}/scripts/yui/build/event/event-min.js"></script>--%>
     <%--<script src="${_siteRoot}/scripts/yui/build/container/container-min.js"></script>--%>
@@ -98,9 +96,6 @@
     <%--<script src="${_siteRoot}/scripts/LeftBarTreeView.js"></script>--%>
     <%--<script src="${_siteRoot}/scripts/justification/justification.js"></script>--%>
 
-
-
-
     <!-- XNAT utility functions -->
     <script src="${_siteRoot}/scripts/utils.js"></script>
 
@@ -218,72 +213,71 @@ ${headBottom}
 
 ${bodyTop}
 
-<div id="page_wrapper">
-
-    <div id="user_bar">
-        <div class="inner">
-            <img id="attention_icon" src="${_siteRoot}/images/attention.png" style="display:none;" alt="attention needed - click for more info" title="attention needed - click for more info">
+<div id="user_bar">
+    <div class="inner">
+        <img id="attention_icon" src="${_siteRoot}/images/attention.png" style="display:none;" alt="attention needed - click for more info" title="attention needed - click for more info">
             <span id="user_info">Logged in as: &nbsp;<a href="${_siteRoot}/app/template/XDATScreen_UpdateUser.vm">${_user}</a> <b>|</b>
                 <span class="tip_icon" style="margin-right:3px;left:2px;top:3px;">
                     <span class="tip shadowed" style="top:20px;z-index:10000;white-space:normal;left:-150px;width:300px;background-color:#ffc;">
-                        Your XNAT session will auto-logout after a certain period of inactivity. 
+                        Your XNAT session will auto-logout after a certain period of inactivity.
                         You can reset the timer without reloading thepage by clicking "renew."
                     </span>
                 </span>
-                Auto-logout in: 
+                Auto-logout in:
                 <b id="timeLeft">-:--:--</b> -
                 <a id="timeLeftRenew" href="#!">renew</a>
-                <b>|</b> 
+                <b>|</b>
                 <a id="logout_user" href="${_siteRoot}/app/action/LogoutUser">Logout</a>
             </span>
-            <%--<script type="text/javascript">--%>
-                <%--$('#timeLeftRenew').click(XNAT.app.timeout.handleOk);--%>
-                <%--Cookies.set('guest', 'false', {path: '/'});--%>
-            <%--</script>--%>
-            <div class="clear"></div>
-        </div>
-    </div><!-- /user_bar -->
-
-
-    <div id="main_nav">
-
-        <ul class="nav">
-            <!-- Sequence: 10 -->
-            <!-- allowGuest: true -->
-            <li>
-                <a id="nav-home" title="Home" href="${_siteRoot}/">&nbsp;</a>
-                <script>
-                    $('#nav-home').css({
-                        width: '30px',
-                        backgroundImage: "url('${_siteRoot}/images/xnat-nav-logo-white-lg.png')",
-                        backgroundRepeat: 'no-repeat',
-                        backgroundSize: '32px',
-                        backgroundPosition: 'center'
-                    });
-                </script>
-            </li>
-            <!-- Sequence: 20 -->
-            <li class="more"><a href="#new">New</a>
-                <ul class="" style="display: none;">
-                    <!-- Sequence: 10 -->
-                    <li><a href="${_siteRoot}/app/template/XDATScreen_add_xnat_projectData.vm">Project</a></li>
-                    <li><a href="${_siteRoot}/app/action/XDATActionRouter/xdataction/edit/search_element/xnat%3AsubjectData">Subject</a></li>
-                    <li><a href="${_siteRoot}/app/template/XDATScreen_add_experiment.vm">Experiment</a></li>
-                </ul>
-            </li>
-            <!-- Sequence: 30 -->
-            <li class="more"><a href="#upload">Upload</a>
-                <ul>
-                    <!-- Sequence: 10 -->
-                    <!-- Upload/Default -->
-                    <li><a href="${_siteRoot}/app/template/LaunchUploadApplet.vm">Images</a></li>
-                    <li><a href="${_siteRoot}/app/template/XMLUpload.vm">XML</a></li>
-                    <li><a href="${_siteRoot}/app/template/XDATScreen_uploadCSV.vm">Spreadsheet</a></li>
-                    <li><a href="${_siteRoot}/app/template/XDATScreen_prearchives.vm">Go to prearchive</a></li>
-                </ul>
-            </li>
+        <%--<script type="text/javascript">--%>
+        <%--$('#timeLeftRenew').click(XNAT.app.timeout.handleOk);--%>
+        <%--Cookies.set('guest', 'false', {path: '/'});--%>
+        <%--</script>--%>
+        <div class="clear"></div>
+    </div>
+</div><!-- /user_bar -->
 
-            <c:if test="${isAdmin == true}">
+<div id="main_nav">
+    <div class="inner">
+
+    <ul class="nav">
+        <!-- Sequence: 10 -->
+        <!-- allowGuest: true -->
+        <li>
+            <a id="nav-home" title="Home" href="${_siteRoot}/">&nbsp;</a>
+            <script>
+                $('#nav-home').css({
+                    width: '30px',
+                    backgroundImage: "url('${_siteRoot}/images/xnat-nav-logo-white-lg.png')",
+                    backgroundRepeat: 'no-repeat',
+                    backgroundSize: '32px',
+                    backgroundPosition: 'center'
+                });
+            </script>
+        </li>
+        <!-- Sequence: 20 -->
+        <li class="more"><a href="#new">New</a>
+            <ul class="" style="display: none;">
+                <!-- Sequence: 10 -->
+                <li><a href="${_siteRoot}/app/template/XDATScreen_add_xnat_projectData.vm">Project</a></li>
+                <li><a href="${_siteRoot}/app/action/XDATActionRouter/xdataction/edit/search_element/xnat:subjectData">Subject</a></li>
+                <li><a href="${_siteRoot}/app/template/XDATScreen_add_experiment.vm">Experiment</a></li>
+            </ul>
+        </li>
+        <!-- Sequence: 30 -->
+        <li class="more"><a href="#upload">Upload</a>
+            <ul>
+                <!-- Sequence: 10 -->
+                <!-- Upload/Default -->
+                <li><a href="${_siteRoot}/app/template/LaunchUploadApplet.vm">Images</a></li>
+                <li><a href="${_siteRoot}/app/template/XMLUpload.vm">XML</a></li>
+                <li><a href="${_siteRoot}/app/template/XDATScreen_uploadCSV.vm">Spreadsheet</a></li>
+                <li><a href="${_siteRoot}/app/template/XDATScreen_prearchives.vm">Go to prearchive</a></li>
+            </ul>
+        </li>
+
+
+        <c:if test="${isAdmin == true}">
             <!-- Sequence: 40 -->
             <li class="more"><a href="#adminbox">Administer</a>
                 <ul>
@@ -298,222 +292,229 @@ ${bodyTop}
                     <li><a href="${_siteRoot}/app/template/XDATScreen_admin_options.vm">More...</a></li>
                 </ul>
             </li>
-            </c:if>
-
-
-            <!-- Title: Tools -->
-            <!-- Sequence: 50 -->
-            <!-- allowGuest: true -->
-
-            <li class="more"><a href="#tools">Tools</a>
-                <ul>
-                    <!-- Sequence: 10 -->
-                    <!-- allowGuest: true -->
-                    <li><a href="https://wiki.xnat.org/display/XNAT16/XNAT+Desktop" target="_blank">XNAT Desktop (XND)</a></li>
-                    <li><a href="http://nrg.wustl.edu/projects/DICOM/DicomBrowser.jsp" target="_blank">DICOM Browser</a></li>
-                    <li><a href="https://wiki.xnat.org/display/XNAT16/XNAT+Client+Tools" target="_blank">Command Prompt Tools</a></li>
-                </ul>
-            </li>
-            <!-- Sequence: 60 -->
-            <li class="more"><a href="#help">Help</a>
-                <ul class="" style="display: none;">
-                    <!-- Sequence: 10 -->
-                    <!-- Home/Default -->
-                    <li><a href="${_siteRoot}/app/template/ReportIssue.vm">Report a Problem</a></li>
-                    <li><a href="http://wiki.xnat.org/display/XNAT16/Home" target="_blank">Documentation</a></li>
-                </ul>
-            </li>
-        </ul>
-        
-        <!-- search script -->
-        <script type="text/javascript">
-            <!--
-            function DefaultEnterKey(e, button){
-                var keynum, keychar, numcheck;
-
-                if (window.event) // IE
-                {
-                    keynum = e.keyCode;
-                    if (keynum == 13) {
-                        submitQuickSearch();
-                        return true;
-                    }
-                }
-                else if (e) // Netscape/Firefox/Opera
-                {
-                    keynum = e.which;
-                    if (keynum == 13) {
-                        submitQuickSearch();
-                        return false;
-                    }
+        </c:if>
+
+
+        <!-- Title: Tools -->
+        <!-- Sequence: 50 -->
+        <!-- allowGuest: true -->
+
+        <li class="more"><a href="#tools">Tools</a>
+            <ul>
+                <!-- Sequence: 10 -->
+                <!-- allowGuest: true -->
+                <li><a href="https://wiki.xnat.org/display/XNAT16/XNAT+Desktop" target="_blank">XNAT Desktop (XND)</a></li>
+                <li><a href="http://nrg.wustl.edu/projects/DICOM/DicomBrowser.jsp" target="_blank">DICOM Browser</a></li>
+                <li><a href="https://wiki.xnat.org/display/XNAT16/XNAT+Client+Tools" target="_blank">Command Prompt Tools</a></li>
+            </ul>
+        </li>
+        <!-- Sequence: 60 -->
+        <li class="more"><a href="#help">Help</a>
+            <ul class="" style="display: none;">
+                <!-- Sequence: 10 -->
+                <!-- Home/Default -->
+                <li><a href="${_siteRoot}/app/template/ReportIssue.vm">Report a Problem</a></li>
+                <li><a href="http://wiki.xnat.org/display/XNAT16/Home" target="_blank">Documentation</a></li>
+            </ul>
+        </li>
+    </ul>
+
+    <!-- search script -->
+    <script type="text/javascript">
+        <!--
+        function DefaultEnterKey(e, button){
+            var keynum, keychar, numcheck;
+
+            if (window.event) // IE
+            {
+                keynum = e.keyCode;
+                if (keynum == 13) {
+                    submitQuickSearch();
+                    return true;
                 }
-                return true;
             }
-
-            function submitQuickSearch(){
-                concealContent();
-                if (document.getElementById('quickSearchForm').value != "")
-                    document.getElementById('quickSearchForm').submit();
+            else if (e) // Netscape/Firefox/Opera
+            {
+                keynum = e.which;
+                if (keynum == 13) {
+                    submitQuickSearch();
+                    return false;
+                }
             }
+            return true;
+        }
 
-            //-->
-        </script>
-        <!-- end search script -->
+        function submitQuickSearch(){
+            concealContent();
+            if (document.getElementById('quickSearchForm').value != "")
+                document.getElementById('quickSearchForm').submit();
+        }
 
-        <style type="text/css">
-            #quickSearchForm .chosen-results {
-                max-height: 500px;
-            }
+        //-->
+    </script>
+    <!-- end search script -->
+
+    <style type="text/css">
+        #quickSearchForm .chosen-results {
+            max-height: 500px;
+        }
+
+        #quickSearchForm .chosen-results li {
+            padding-right: 20px;
+            white-space: nowrap;
+        }
+
+        #quickSearchForm .chosen-container .chosen-drop {
+            width: auto;
+            min-width: 180px;
+            max-width: 360px;
+        }
+
+        #quickSearchForm .chosen-container .chosen-drop .divider {
+            padding: 0;
+            overflow: hidden;
+        }
+    </style>
+
+    <form id="quickSearchForm" method="post" action="${_siteRoot}/app/action/QuickSearchAction">
+        <select id="stored-searches" data-placeholder="Stored Searches" style="display: none;">
+            <option></option>
+            <optgroup>
+                <option value="${_siteRoot}/app/template/XDATScreen_search_wizard1.vm">Advanced Search…</option>
+            </optgroup>
+            <optgroup class="stored-search-list">
+                <option disabled="">(no stored searches)</option>
+                <!-- stored searches will show up here -->
+            </optgroup>
+        </select>
+        <input id="searchValue" class="clean" name="searchValue" type="text" maxlength="40" size="20" value="">
+        <button type="button" id="search_btn" class="btn2" onclick="submitQuickSearch();">Go</button>
+
+        <script>
+
+            $('#searchValue').each(function(){
+                var _this = this;
+                _this.value = _this.value || 'search';
+                $(_this).focus(function(){
+                    $(_this).removeClass('clean');
+                    if (!_this.value || _this.value === 'search') {
+                        _this.value = '';
+                    }
+                })
+            });
 
-            #quickSearchForm .chosen-results li {
-                padding-right: 20px;
-                white-space: nowrap;
-            }
+            $('#stored-searches').on('change', function(){
+                if (this.value) {
+                    window.location.href = this.value;
+                }
+            }).chosen({
+                width: '150px',
+                disable_search_threshold: 9,
+                inherit_select_classes: true,
+                placeholder_text_single: 'Stored Searches',
+                search_contains: true
+            });
 
-            #quickSearchForm .chosen-container .chosen-drop {
-                width: auto;
-                min-width: 180px;
-                max-width: 360px;
-            }
+        </script>
+    </form>
 
-            #quickSearchForm .chosen-container .chosen-drop .divider {
-                padding: 0;
-                overflow: hidden;
-            }
-        </style>
-
-        <form id="quickSearchForm" method="post" action="${_siteRoot}/app/action/QuickSearchAction">
-            <select id="stored-searches" data-placeholder="Stored Searches" style="display: none;">
-                <option></option>
-                <optgroup>
-                    <option value="${_siteRoot}/app/template/XDATScreen_search_wizard1.vm">Advanced Search…</option>
-                </optgroup>
-                <optgroup class="stored-search-list">
-                    <option disabled="">(no stored searches)</option>
-                    <!-- stored searches will show up here -->
-                </optgroup>
-            </select>
-            <input id="searchValue" class="clean" name="searchValue" type="text" maxlength="40" size="20" value="">
-            <button type="button" id="search_btn" class="btn2" onclick="submitQuickSearch();">Go</button>
+    </div>
+    <!-- /.inner -->
 
-            <script>
-                $('#searchValue').each(function(){
-                    var _this = this;
-                    _this.value = _this.value || 'search';
-                    $(_this).focus(function(){
-                        $(_this).removeClass('clean');
-                        if (!_this.value || _this.value === 'search') {
-                            _this.value = '';
-                        }
-                    })
-                });
-                
-                $('#stored-searches').on('change', function(){
-                    if (this.value) {
-                        window.location.href = this.value;
-                    }
-                }).chosen({
-                    width: '150px',
-                    disable_search_threshold: 9,
-                    inherit_select_classes: true,
-                    placeholder_text_single: 'Stored Searches',
-                    search_contains: true
-                });
-            </script>
-        </form>
+</div>
+<!-- /#main_nav -->
 
-    </div>
-    <!-- /main_nav -->
+<!-- main_nav interactions -->
+<script type="text/javascript">
 
-    <!-- main_nav interactions -->
-    <script type="text/javascript">
+    (function(){
 
-        (function(){
+        // cache it
+        var main_nav$ = jq('#main_nav ul.nav');
 
-            // cache it
-            var main_nav$ = jq('#main_nav > ul');
-            
-            var body$ = jq('body');
+        var body$ = jq('body');
 
-            var cover_up_count = 1;
+        var cover_up_count = 1;
 
-            function coverApplet(el$){
-                var cover_up_id = 'cover_up' + cover_up_count++;
-                var jqObjPos = el$.offset(),
+        function coverApplet(el$){
+            var cover_up_id = 'cover_up' + cover_up_count++;
+            var jqObjPos = el$.offset(),
                     jqObjLeft = jqObjPos.left,
                     jqObjTop = jqObjPos.top,
                     jqObjMarginTop = el$.css('margin-top'),
                     jqObjWidth = el$.outerWidth() + 4,
                     jqObjHeight = el$.outerHeight() + 2;
 
-                el$.before('<iframe id="' + cover_up_id + '" class="applet_cover_up" src="about:blank" width="' + jqObjWidth + '" height="' + jqObjHeight + '"></iframe>');
-
-                jq('#' + cover_up_id).css({
-                    display: 'block',
-                    position: 'fixed',
-                    width: jqObjWidth,
-                    height: jqObjHeight,
-                    marginTop: jqObjMarginTop,
-                    left: jqObjLeft,
-                    top: jqObjTop,
-                    background: 'transparent',
-                    border: 'none',
-                    outline: 'none'
-                });
-            }
+            el$.before('<iframe id="' + cover_up_id + '" class="applet_cover_up" src="about:blank" width="' + jqObjWidth + '" height="' + jqObjHeight + '"></iframe>');
+
+            jq('#' + cover_up_id).css({
+                display: 'block',
+                position: 'fixed',
+                width: jqObjWidth,
+                height: jqObjHeight,
+                marginTop: jqObjMarginTop,
+                left: jqObjLeft,
+                top: jqObjTop,
+                background: 'transparent',
+                border: 'none',
+                outline: 'none'
+            });
+        }
 
-            function unCoverApplets(el$){
-                el$.prev('iframe.applet_cover_up').detach();
-            }
+        function unCoverApplets(el$){
+            el$.prev('iframe.applet_cover_up').detach();
+        }
 
-            function fadeInNav(el$){
+        function fadeInNav(el$){
 //            el$.stop('clearQueue','gotoEnd');
-                el$.find('> ul').show().addClass('open');
-            }
+            el$.find('> ul').show().addClass('open');
+        }
 
-            function fadeOutNav(el$){
+        function fadeOutNav(el$){
 //            el$.stop('clearQueue','gotoEnd');
-                el$.find('> ul').hide().removeClass('open');
-            }
-
-            // give menus with submenus a class of 'more'
-            main_nav$.find('li ul, li li ul').closest('li').addClass('more');
-            main_nav$.find('li li ul').addClass('subnav');
-
-            // no fancy fades on hover
-            main_nav$.find('li.more').on('mouseover',
-                    function(){
-                        var li$ = $(this);
-                        fadeInNav(li$);
-                        //jq('#main_nav li').removeClass('open');
-                        li$.find('ul.subnav').each(function(){
-                            var sub$ = $(this);
-                            var offsetL = sub$.closest('ul').outerWidth();
-                            sub$.css({'left': offsetL + -25})
-                        });
-                        if (body$.hasClass('applet')) {
-                            coverApplet(li$.find('> ul'));
-                        }
+            el$.find('> ul').hide().removeClass('open');
+        }
+
+        // give menus with submenus a class of 'more'
+        main_nav$.find('li ul, li li ul').closest('li').addClass('more');
+        main_nav$.find('li li ul').addClass('subnav');
+
+        // no fancy fades on hover
+        main_nav$.find('li.more').on('mouseover',
+                function(){
+                    var li$ = $(this);
+                    fadeInNav(li$);
+                    //jq('#main_nav li').removeClass('open');
+                    li$.find('ul.subnav').each(function(){
+                        var sub$ = $(this);
+                        var offsetL = sub$.closest('ul').outerWidth();
+                        sub$.css({'left': offsetL + -25})
+                    });
+                    if (body$.hasClass('applet')) {
+                        coverApplet(li$.find('> ul'));
                     }
-            ).on('mouseout',
-                    function(){
-                        var li$ = $(this);
-                        fadeOutNav(li$);
-                        if (body$.hasClass('applet')) {
-                            unCoverApplets(li$.find('> ul'));
-                        }
+                }
+        ).on('mouseout',
+                function(){
+                    var li$ = $(this);
+                    fadeOutNav(li$);
+                    if (body$.hasClass('applet')) {
+                        unCoverApplets(li$.find('> ul'));
                     }
-            );
+                }
+        );
 
-            // clicking the "Logout" link sets the warning bar cookie to 'OPEN' so it's available if needed on next login
-            jq('#logout_user').click(function(){
-                Cookies.set('WARNING_BAR', 'OPEN', {path: '/'});
-                Cookies.set('NOTIFICATION_MESSAGE', 'OPEN', {path: '/'});
-            });
+        // clicking the "Logout" link sets the warning bar cookie to 'OPEN' so it's available if needed on next login
+        jq('#logout_user').click(function(){
+            Cookies.set('WARNING_BAR', 'OPEN', {path: '/'});
+            Cookies.set('NOTIFICATION_MESSAGE', 'OPEN', {path: '/'});
+        });
 
-        })();
-    </script>
-    <!-- end main_nav interactions -->
+    })();
+</script>
+<!-- end main_nav interactions -->
+
+<div id="page_wrapper">
 
     <div id="header" class="main_header">
         <div class="pad">
diff --git a/src/main/webapp/page/admin/content.jsp b/src/main/webapp/page/admin/content.jsp
index e8ea27c257713ac42cebc5ace8025692fff3e852..c4eaa07b2f548b70ba47bcec4034bca7d0244046 100755
--- a/src/main/webapp/page/admin/content.jsp
+++ b/src/main/webapp/page/admin/content.jsp
@@ -31,6 +31,7 @@
                 </div>
 
                 <script src="${sessionScope.siteRoot}/scripts/lib/jquery-plugins/jquery.form.js"></script>
+                <script src="${sessionScope.siteRoot}/scripts/lib/yamljs/dist/yaml.js"></script>
 
                 <c:import url="/xapi/siteConfig" var="siteConfig"/>
 
@@ -38,9 +39,12 @@
                     XNAT.data = extend({}, XNAT.data, {
                         siteConfig: ${siteConfig}
                     });
+                    // get rid of the 'targetSource' property
+                    delete XNAT.data.siteConfig.targetSource;
                 </script>
 
                 <script src="${sessionScope.siteRoot}/scripts/xnat/ui/templates.js"></script>
+                <script src="${sessionScope.siteRoot}/scripts/xnat/spawner.js"></script>
                 <script src="${sessionScope.siteRoot}/page/admin/tabs.js"></script>
 
             </div>
diff --git a/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml b/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml
index 2cc8643fd85e5f95bf1db67d1a98e28914b4bccd..869eff80a5d00b4879efad14e962f75d15cc5232 100644
--- a/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml
+++ b/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml
@@ -20,7 +20,7 @@ siteAdmin:
             label: Site Setup
             group: xnatSetup
             active: true
-            config:
+            element:
                 data:
                     foo: bar
             contains: panels # the value for 'contains' can be a custom name for 'contents'
@@ -33,9 +33,10 @@ siteAdmin:
                     label: Site Information
                     method: POST
                     action: /xapi/siteConfig/batch
+                    contentType: application/json
                     load:
                         data: XNAT.data.siteConfig
-
+                        refresh: /xapi/siteConfig # url to use to get fresh data (uses GET)
                     contents:
 
                         # panel input
@@ -45,6 +46,8 @@ siteAdmin:
                             id: side-id
                             label: Site ID
                             value: XNAT
+                            load:
+                                url: /xapi/siteConfig/siteId
                             description: >
                                 The id used to refer to this site (also used to generate ids). The Site ID must start
                                 with a letter and contain only letters, numbers and underscores. It should be a short,
@@ -122,11 +125,15 @@ siteAdmin:
                 emailServerSettings:
                     kind: panel.form
                     method: POST
-                    action: /xapi/notifications/all
+#                    action: /xapi/notifications/smtp
+                    action: /xapi/siteConfig/smtpServer
+#                    action: '#@' # this character combo means submit each item individually
+                    contentType: json
                     load: # load data
-                        url: /xapi/siteConfig
-#                        method: GET      # defaults to GET if not set
-                        prop: smtpServer # which root property? gets the root object if not set
+#                        refresh: /xapi/siteConfig/smtpServer
+                        url: /xapi/siteConfig/smtpServer
+                        method: GET      # defaults to GET if not set
+#                        prop: smtpServer # which root property? gets the root object if not set
 #                        data: XNAT.data.siteConfig.smtpServer
                     name:  emailServerSettings
                     label: Mail Server Settings
@@ -153,7 +160,6 @@ siteAdmin:
                             kind: panel.input.text
                             name: username
                             label: Username
-                            url: /xapi/notifications/username
                             value: ''
                             element:
                                 placeholder: admin@localhost
@@ -167,10 +173,12 @@ siteAdmin:
                             name: protocol
                             label: Protocol
                             value: ''
-                            #data:
-                                #get: GET|/xapi/siteConfig|smtpServer.protocol
-                                #set: POST|/xapi/notifications/protocol
-                        # subhead breaks up panel items
+#                            data:
+#                                get: GET|/xapi/siteConfig|smtpServer.protocol
+#                                set: POST|/xapi/notifications/protocol
+
+#                        subhead breaks up panel items
+
                         mailServerProperties:
                             kind: panel.subhead
                             name: mailServerProperties
@@ -179,13 +187,13 @@ siteAdmin:
                             kind: panel.input.checkbox
                             name: mail.smtp.auth
                             label: SMTP Auth?
-                            #value: true
+                            value: true
                             checked: true
                         smtpStartTls:
                             kind: panel.input.checkbox
                             name: mail.smtp.starttls.enable
                             label: Smart TLS?
-                            #value: true
+                            value: true
                             checked: true
                         smtpSSLTrust:
                             kind: panel.input.text
@@ -221,6 +229,7 @@ siteAdmin:
                                         b:
                                             html: B
                                             selected: true
+
                         sectionA:
                             kind: panel.section
                             element:
diff --git a/src/main/webapp/page/admin/site-config/content.jsp b/src/main/webapp/page/admin/site-config/content.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..9103383d7f304d3b10f1e109c1b6e92bcd9a2513
--- /dev/null
+++ b/src/main/webapp/page/admin/site-config/content.jsp
@@ -0,0 +1,125 @@
+<%@ page session="true" contentType="text/html" pageEncoding="UTF-8" language="java" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="pg" tagdir="/WEB-INF/tags/page" %>
+
+<c:if test="${empty hasInit}">
+    <pg:init>
+        <c:if test="${empty hasVars}">
+            <pg:jsvars/>
+        </c:if>
+    </pg:init>
+</c:if>
+
+<c:set var="_msg">
+    Nope.
+</c:set>
+
+<pg:restricted msg="${_msg}">
+
+    <c:import url="/xapi/siteConfig" var="siteConfig"/>
+
+    <script>
+        XNAT.data = extend({}, XNAT.data, {
+            siteConfig: ${siteConfig}
+        });
+        // get rid of the 'targetSource' property
+        delete XNAT.data.siteConfig.targetSource;
+    </script>
+
+    <div id="page-body">
+        <div class="pad" style="padding:20px;">
+
+            <header id="content-header">
+                <h2 class="pull-left">XNAT Site Config Output</h2>
+                <div class="clear"></div>
+            </header>
+
+            <hr class="light">
+
+            <div class="panel panel-default">
+                <div class="panel-heading">
+                    <h3 class="panel-title">View Site Config Items</h3>
+                </div>
+                <div class="panel-body">
+                    <div class="panel-element">
+                        <label for="select-site-config-item" class="element-label">Select a property</label>
+                        <div class="element-wrapper">
+
+                            <select id="select-site-config-item" style="width:350px;">
+                                <option value="!"> &nbsp; </option>
+                            </select>
+
+                            <br><br>
+
+                            <textarea id="site-config-item" class="mono" style="width:400px;height:200px;"></textarea>
+
+                            <hr class="light">
+
+                            <button type="button" id="show-site-config-json">Show Site Config JSON</button>
+
+                            <form method="" action=""></form>
+                            <div class="description"></div>
+
+                        </div>
+                    </div>
+                </div>
+                <div class="hidden"></div>
+            </div>
+
+
+        </div>
+    </div>
+
+    <script>
+        (function(){
+
+            var siteConfigObj = XNAT.data.siteConfig;
+            var $siteConfigSelect = $('#select-site-config-item');
+            var siteConfigItems = '';
+
+            // populate the menu
+            forOwn(siteConfigObj, function(prop, val){
+                // having trouble with objects right now
+                // if (isPlainObject(val)) return;
+                siteConfigItems += ('<option value="' + prop + '">' + prop + '</div> \n');
+            });
+
+            $siteConfigSelect.append(siteConfigItems);
+
+            // select an item to show in the textarea
+            $siteConfigSelect.on('change', function(){
+                if (this.value === '!') return false;
+                var val = siteConfigObj[this.value];
+                if (isPlainObject(val) || Array.isArray(val)) {
+                    val = JSON.stringify(val, null, 4);
+                }
+                $('#site-config-item').text(val);
+                // don't need to do a REST call because we already have the object
+//                $.get(XNAT.url.restUrl('/xapi/siteConfig/' + this.value), function(data){
+//                    $('#site-config-item').val(data)
+//                });
+            });
+
+            // show the whole siteConfig object in an xmodal dialog
+            $('#show-site-config-json').click(function(){
+                xmodal.open({
+                    size: 'large',
+                    minWidth: 800,
+                    minHeight: '90%',
+                    //width: 600,
+                    //height: 500,
+                    maximize: true,
+                    title: 'Site Config JSON',
+                    content: prettifyJSON(siteConfigObj)
+                });
+            });
+
+            $(function(){
+                $siteConfigSelect.chosen();
+            })
+
+        })();
+    </script>
+
+</pg:restricted>
+
diff --git a/src/main/webapp/page/admin/site-config/index.jsp b/src/main/webapp/page/admin/site-config/index.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..9acf00fb6d9b9723cc42474f69693de4dca8964d
--- /dev/null
+++ b/src/main/webapp/page/admin/site-config/index.jsp
@@ -0,0 +1,11 @@
+<%@ page session="true" contentType="text/html" pageEncoding="UTF-8" language="java" %>
+<%@ taglib prefix="pg" tagdir="/WEB-INF/tags/page" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<pg:wrapper>
+    <pg:xnat>
+
+        <jsp:include page="content.jsp"/>
+
+    </pg:xnat>
+</pg:wrapper>
diff --git a/src/main/webapp/page/admin/site-config/siteConfig.js b/src/main/webapp/page/admin/site-config/siteConfig.js
new file mode 100644
index 0000000000000000000000000000000000000000..8f7b17c5b26fa51367ebeb531b350b3cc8fec8e4
--- /dev/null
+++ b/src/main/webapp/page/admin/site-config/siteConfig.js
@@ -0,0 +1,63 @@
+// prepare the form when the DOM is ready
+$(document).ready(function() {
+    var options = {
+        target:        '#output2',   // target element(s) to be updated with server response
+        beforeSubmit:  showRequest,  // pre-submit callback
+        success:       showResponse  // post-submit callback
+
+        // other available options:
+        //url:       url         // override for form's 'action' attribute
+        //type:      type        // 'get' or 'post', override for form's 'method' attribute
+        //dataType:  null        // 'xml', 'script', or 'json' (expected server response type)
+        //clearForm: true        // clear all form fields after successful submit
+        //resetForm: true        // reset the form after successful submit
+
+        // $.ajax options can be used here too, for example:
+        //timeout:   3000
+    };
+
+    // bind to the form's submit event
+    $('#myForm2').submit(function() {
+        // inside event callbacks 'this' is the DOM element so we first
+        // wrap it in a jQuery object and then invoke ajaxSubmit
+        $(this).ajaxSubmit(options);
+
+        // !!! Important !!!
+        // always return false to prevent standard browser submit and page navigation
+        return false;
+    });
+});
+
+// pre-submit callback
+function showRequest(formData, jqForm, options) {
+    // formData is an array; here we use $.param to convert it to a string to display it
+    // but the form plugin does this for you automatically when it submits the data
+    var queryString = $.param(formData);
+
+    // jqForm is a jQuery object encapsulating the form element.  To access the
+    // DOM element for the form do this:
+    // var formElement = jqForm[0];
+
+    alert('About to submit: \n\n' + queryString);
+
+    // here we could return false to prevent the form from being submitted;
+    // returning anything other than false will allow the form submit to continue
+    return true;
+}
+
+// post-submit callback
+function showResponse(responseText, statusText, xhr, $form)  {
+    // for normal html responses, the first argument to the success callback
+    // is the XMLHttpRequest object's responseText property
+
+    // if the ajaxSubmit method was passed an Options Object with the dataType
+    // property set to 'xml' then the first argument to the success callback
+    // is the XMLHttpRequest object's responseXML property
+
+    // if the ajaxSubmit method was passed an Options Object with the dataType
+    // property set to 'json' then the first argument to the success callback
+    // is the json data object returned by the server
+
+    alert('status: ' + statusText + '\n\nresponseText: \n' + responseText +
+        '\n\nThe output div should have already been updated with the responseText.');
+}
diff --git a/src/main/webapp/page/admin/spawner/content.jsp b/src/main/webapp/page/admin/spawner/content.jsp
index 9fbb0afce888f78c1c58dc0062e0c44648515d86..11d0a5b141e0c80ea2f208fa88cc6a09cb5c9f94 100644
--- a/src/main/webapp/page/admin/spawner/content.jsp
+++ b/src/main/webapp/page/admin/spawner/content.jsp
@@ -3,14 +3,6 @@
         <%@ taglib prefix="pg" tagdir="/WEB-INF/tags/page" %>
         <%--<%@ taglib prefix="sp" tagdir="/WEB-INF/tags/spawner" %>--%>
 
-        <c:if test="${empty hasInit}">
-            <pg:init>
-                <c:if test="${empty hasVars}">
-                    <pg:jsvars/>
-                </c:if>
-            </pg:init>
-        </c:if>
-
         <c:set var="MSG">
             No spawning allowed.
         </c:set>
diff --git a/src/main/webapp/scripts/xnat/ui/panel.js b/src/main/webapp/scripts/xnat/ui/panel.js
index cd0ab62d195ffc0b7c4aff44c789e0a3a999c720..1675c7a054beb554aaebf7f9ae2675eb99678f99 100644
--- a/src/main/webapp/scripts/xnat/ui/panel.js
+++ b/src/main/webapp/scripts/xnat/ui/panel.js
@@ -16,7 +16,7 @@ var XNAT = getObject(XNAT || {});
 
     XNAT.ui.panel = panel =
         getObject(XNAT.ui.panel || {});
-    
+
     // add new element class without destroying existing class
     function addClassName(el, newClass){
         el.className = [].concat(el.className||[], newClass).join(' ').trim();
@@ -33,7 +33,7 @@ var XNAT = getObject(XNAT || {});
     }
 
     panel.init = function panelInit(opts){
-        
+
         opts = getObject(opts);
         opts.element = opts.element || opts.config || {};
 
@@ -52,7 +52,7 @@ var XNAT = getObject(XNAT || {});
                 (hideFooter ? ['div.hidden'] : ['div.panel-footer', opts.footer])
 
             ]);
-        
+
         // add an id to the outer panel element if present
         if (opts.id || opts.element.id) {
             _panel.id = (opts.id || opts.element.id) + '-panel';
@@ -118,7 +118,14 @@ var XNAT = getObject(XNAT || {});
             }
             // find all form inputs with a name attribute
             $$(form).find(':input[name]').each(function(){
-                $(this).changeVal(dataObj[this.name]||'');
+                var val = '';
+                if (Array.isArray(dataObj)) {
+                    val = dataObj.join(', ');
+                }
+                else {
+                    val = /string|number/i.test(typeof dataObj) ? dataObj : dataObj[this.name] || '';
+                }
+                $(this).changeVal(val);
             });
             if (xmodal && xmodal.loading && xmodal.loading.close){
                 xmodal.loading.close();
@@ -140,11 +147,26 @@ var XNAT = getObject(XNAT || {});
             // need a form to put the data into
             if (!obj.form) return;
 
+            // // if there's a 'refresh' url, make that obj.url
+            // if (obj.refresh) obj.url = obj.refresh;
+
             // if we pass data in a 'data' property, just use that
             // to avoid doing a server request
 
-            if (obj.data) {
-                setValues(obj.form, eval(obj.data));
+            if (obj.data && !obj.url) {
+                if (Array.isArray(obj.data)) {
+                    obj.data = obj.data[0];
+                }
+                else {
+                    try {
+                        obj.data = eval(obj.data);
+                    }
+                    catch (e) {
+                        if (console && console.log) console.log(e);
+                        obj.data = ''
+                    }
+                }
+                setValues(obj.form, obj.data);
                 return obj.form;
             }
 
@@ -187,12 +209,13 @@ var XNAT = getObject(XNAT || {});
         //    loadData(opts.load);
         //}
 
-        // click 'Discard Changes' butotn to reload data
+        // click 'Discard Changes' button to reload data
         _resetBtn.onclick = function(){
             xmodal.loading.open();
+            opts.load.url = opts.load.refresh;
             loadData(opts.load);
         };
-        
+
         // intercept the form submit to do it via REST instead
         $(_formPanel).on('submit', function(e){
 
@@ -218,19 +241,63 @@ var XNAT = getObject(XNAT || {});
 
             };
 
-            $(this).ajaxSubmit({
-                success: function(){
+            function formToJSON(form){
+                var json = {};
+                $$(form).serializeArray().forEach(function(item) {
+                    if (typeof json[item.name] == 'undefined') {
+                        json[item.name] = item.value || '';
+                    }
+                    else {
+                        json[item.name] = [].concat(json[item.name], item.value||[]) ;
+                    }
+                });
+                return json;
+            }
+
+            var ajaxConfig = {
+                method: opts.method,
+                url: this.action,
+                success: function(data){
+                    var obj = {};
+                    // if a data object is returned,
+                    // just use that
+                    if (data) {
+                        // wrap the returned data in an array so the
+                        // loadData() function handles it properly
+                        obj.data = [data];
+                    }
+                    else {
+                        obj.url = opts.refresh;
+                    }
                     xmodal.loading.close();
                     xmodal.message('Data saved successfully.', {
-                        action: loadData()
+                        action: loadData(obj)
                     });
                 }
-            });
+            };
+
+            // if (!/form/i.test(opts.contentType||'')) {
+            //     ajaxConfig.contentType = opts.contentType;
+            // }
+
+            if (/json/i.test(opts.contentType||'')){
+                ajaxConfig.data = JSON.stringify(formToJSON(this));
+                ajaxConfig.processData = false;
+                ajaxConfig.contentType = 'application/json';
+                $.ajax(ajaxConfig);
+            }
+            else {
+                // ajaxConfig.data =  $(this).serialize();
+                // $.ajax(ajaxConfig);
+                $(this).ajaxSubmit(ajaxConfig);
+            }
+
+            // $.ajax(ajaxConfig);
 
             return false;
 
         });
-        
+
         // this object is returned to the XNAT.spawner() method
         return {
             load: loadData,
@@ -282,13 +349,13 @@ var XNAT = getObject(XNAT || {});
         }
 
     };
-    
+
     panel.subhead = function(opts){
         opts = getObject(opts);
         opts.html = opts.html || opts.text || opts.label;
-        return XNAT.ui.template.panelSubhead(opts).spawned;    
+        return XNAT.ui.template.panelSubhead(opts).spawned;
     };
-    
+
     // return a generic panel 'section'
     panel.section = function(opts){
 
@@ -297,23 +364,23 @@ var XNAT = getObject(XNAT || {});
         opts = getObject(opts);
         opts.element = opts.element || opts.config || {};
         opts.header = opts.header || opts.label || opts.title || '';
-        
+
         if (opts.header) {
             _inner.push(['header.section-header', opts.header]);
         }
-        
+
         // this needs to be spawned here to act as
         // the target for this elements 'contents'
         _body = spawn('div.section-body');
-        
+
         _inner.push(_body);
-        
+
         if (opts.footer) {
-            _inner.push(['footer.section-footer'], opts.footer);    
+            _inner.push(['footer.section-footer'], opts.footer);
         }
-        
+
         _section = spawn('div.panel-section', opts.element, _inner);
-        
+
         return {
             target: _body,
             element: _section,
@@ -404,9 +471,9 @@ var XNAT = getObject(XNAT || {});
     panel.select = {};
 
     panel.select.menu = function panelSelectSingle(opts, multi){
-        
+
         var _menu;
-        
+
         opts = getObject(opts);
         opts.element = opts.element || opts.config || {};
         opts.element.name = opts.element.name || opts.name || '';
@@ -435,12 +502,12 @@ var XNAT = getObject(XNAT || {});
     panel.select.multi = function panelSelectMulti(opts){
         return panel.select.menu(opts, true)
     };
-    
+
     panel.selectMenu = function panelSelectMenu(opts){
         opts = getObject(opts);
         return XNAT.ui.template.panelSelect(opts).spawned;
     };
-    
+
 
     function footerButton(text, type, disabled, classes){
         var button = {
diff --git a/src/main/webapp/scripts/xnat/ui/templates.js b/src/main/webapp/scripts/xnat/ui/templates.js
index 36c847f7d862b5efa7d0abcb3847d6229602e396..c1aa97c31162fa813952f0b5b569feff88ead35b 100644
--- a/src/main/webapp/scripts/xnat/ui/templates.js
+++ b/src/main/webapp/scripts/xnat/ui/templates.js
@@ -141,6 +141,32 @@ var XNAT = getObject(XNAT);
         if (/checkbox|radio/i.test(opts.type||'') && opts.checked) {
             element.checked = true;
         }
+
+        var dataGetParts;
+
+        // set the values of form elements
+        if (opts.data) {
+            if (opts.data.get){
+                dataGetParts = opts.data.get.split('|');
+                $.ajax({
+                    method: dataGetParts[0] || 'GET',
+                    url: XNAT.url.restUrl(dataGetParts[1] || ''),
+                    success: function(data){
+                        // split object path
+                        if (dataGetParts[2]) {
+                            dataGetParts[2].split('.').forEach(function(part){
+                                data = data[part]
+                            });
+                        }
+                        // element.value = data;
+                        // changeVal() changes the value and triggers
+                        // the 'onchange' event
+                        $(element).changeVal(data).dataAttr('value', data);
+                    }
+                })
+            }
+        }
+
         return template.panelElement(opts, [
             ['label.element-label|for='+element.id||opts.id, opts.label],
             ['div.element-wrapper', [
@@ -193,7 +219,54 @@ var XNAT = getObject(XNAT);
             ['div.element-wrapper', elements]
         ]);
     };
-
+    
+    
+    template.codeEditor = function(opts, contents){
+        // options for the 'div.editor-content' element
+        opts = extend(true, opts, {
+            style: {
+                width: '100%', height: '100%',
+                position: 'absolute',
+                top: 0, right: 0,
+                bottom: 0, left: 0,
+                border: '1px solid #ccc'
+            }
+        });
+        // don't pass 'before' and 'after' into the editor
+        var before = opts.before || '';
+        var after = opts.after || '';
+        delete opts.before;
+        delete opts.after;
+        var content = spawn('div.editor-content', opts, contents||'');
+        var _tmpl = ['form.code-editor', [
+            before,
+            ['div.editor-wrapper', {
+                style: {
+                    width:  opts.width  || '840px',
+                    height: opts.height || '482px',
+                    position: 'relative'
+                }
+            }, [content]],
+            after
+        ]];
+        var _spawned = spawn.apply(null, _tmpl);
+        var _html = _spawned.outerHTML;
+        return {
+            template: _tmpl, // the raw template (Spawn array)
+            spawned: _spawned, // pre-spawned
+            editor: content, // easy-to-remember name for the editor div
+            target: content, // for inserting content dynamically
+            inner: content,
+            html: _html, // pre-spawned HTML
+            outerHTML: _html,
+            get: function(){
+                return _spawned;
+            },
+            getHTML: function(){ // call to get the HTML
+                return _html;
+            }
+        }
+    };
 
     return XNAT.ui.templates = XNAT.ui.template = template;