diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..30bdb0b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/tmp/ +/local/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..c9d5186 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,34 @@ +before_script: + - docker info + - '[ -d tmp ] || mkdir tmp' + - git clone https://github.com/OSC/ondemand-packaging.git tmp/ondemand-packaging + - cp /systems/osc_certs/gpg/ondemand/.gpgpass $CI_PROJECT_DIR/tmp/ondemand-packaging/ + - cp /systems/osc_certs/gpg/ondemand/ondemand.sec $CI_PROJECT_DIR/tmp/ondemand-packaging/ +stages: + - build + - deploy + +rpm-build: + stage: build + only: + - tags + script: + - ./tmp/ondemand-packaging/build.sh -w $CI_PROJECT_DIR/tmp/work -o $CI_PROJECT_DIR/tmp/output -V $CI_COMMIT_TAG -u -v $CI_PROJECT_DIR/packaging + artifacts: + paths: + - tmp/output + name: "$CI_PROJECT_NAME-$CI_COMMIT_TAG" + + +rpm-deploy: + variables: + RLS_SCRIPT: "./tmp/ondemand-packaging/release.py" + RLS_KEY: "/systems/osc_certs/ssh/ondemand-packaging/id_rsa" + RLS_OUTPUT: "./tmp/output/*" + SECTION: "main" + stage: deploy + only: + - tags + script: + - if [[ "$CI_COMMIT_TAG" =~ .*_.* ]]; then export SECTION=ci; fi + - $RLS_SCRIPT --debug --pkey $RLS_KEY -c $SECTION $RLS_OUTPUT diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..452d718 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] +## [0.0.1] - 2019-10-21 +### Added +- Initial release diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..32c6e9b --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2016-2019 Ohio Supercomputer Center + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cdd0912 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# Batch Connect - OSC Code Server + +![GitHub Release](https://img.shields.io/github/release/osc/bc_osc_codeserver.svg) +[![GitHub License](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT) + +An improved file viewer / editor for OSC OnDemand that launches a +Code Server within an Owens batch job. Code Server leverages VSCode as its +editor. + +## Prerequisites + +This Batch Connect app requires the following software be installed on the +**compute nodes** that the batch job is intended to run on (**NOT** the +OnDemand node): + +- [Lmod] 6.0.1+ or any other `module purge` and `module load ` based + CLI used to load appropriate environments within the batch job before + launching Code server. +- [Code Server] 2.x+ available from Github: https://github.com/cdr/code-server/releases + +[Code Server]: https://coder.com/ +[Lmod]: https://www.tacc.utexas.edu/research-development/tacc-projects/lmod +[VS Code]: https://code.visualstudio.com/ + +## Install + +Use Git to clone this app and checkout the desired branch/version you want to +use: + +```sh +scl enable git29 -- git clone +cd +scl enable git29 -- git checkout +``` + +You will not need to do anything beyond this as all necessary assets are +installed. You will also not need to restart this app as it isn't a Passenger +app. + +To update the app you would: + +```sh +cd +scl enable git29 -- git fetch +scl enable git29 -- git checkout +``` + +Again, you do not need to restart the app as it isn't a Passenger app. + +## Contributing + +1. Fork it ( https://github.com/OSC/bc_osc_codeserver/fork ) +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create a new Pull Request + +## Known Issues + +- In-app installation of extensions does not work diff --git a/form.js b/form.js new file mode 100644 index 0000000..05c7f62 --- /dev/null +++ b/form.js @@ -0,0 +1,6 @@ +!function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(r,i,function(e){return t[e]}.bind(null,i));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=10)}([function(t,e,n){(function(t){function n(t,e){for(var n=0,r=t.length-1;r>=0;r--){var i=t[r];"."===i?t.splice(r,1):".."===i?(t.splice(r,1),n++):n&&(t.splice(r,1),n--)}if(e)for(;n--;n)t.unshift("..");return t}function r(t,e){if(t.filter)return t.filter(e);for(var n=[],r=0;r=-1&&!i;o--){var a=o>=0?arguments[o]:t.cwd();if("string"!=typeof a)throw new TypeError("Arguments to path.resolve must be strings");a&&(e=a+"/"+e,i="/"===a.charAt(0))}return(i?"/":"")+(e=n(r(e.split("/"),function(t){return!!t}),!i).join("/"))||"."},e.normalize=function(t){var o=e.isAbsolute(t),a="/"===i(t,-1);return(t=n(r(t.split("/"),function(t){return!!t}),!o).join("/"))||o||(t="."),t&&a&&(t+="/"),(o?"/":"")+t},e.isAbsolute=function(t){return"/"===t.charAt(0)},e.join=function(){var t=Array.prototype.slice.call(arguments,0);return e.normalize(r(t,function(t,e){if("string"!=typeof t)throw new TypeError("Arguments to path.join must be strings");return t}).join("/"))},e.relative=function(t,n){function r(t){for(var e=0;e=0&&""===t[n];n--);return e>n?[]:t.slice(e,n-e+1)}t=e.resolve(t).substr(1),n=e.resolve(n).substr(1);for(var i=r(t.split("/")),o=r(n.split("/")),a=Math.min(i.length,o.length),s=a,c=0;c=1;--o)if(47===(e=t.charCodeAt(o))){if(!i){r=o;break}}else i=!1;return-1===r?n?"/":".":n&&1===r?"/":t.slice(0,r)},e.basename=function(t,e){var n=function(t){"string"!=typeof t&&(t+="");var e,n=0,r=-1,i=!0;for(e=t.length-1;e>=0;--e)if(47===t.charCodeAt(e)){if(!i){n=e+1;break}}else-1===r&&(i=!1,r=e+1);return-1===r?"":t.slice(n,r)}(t);return e&&n.substr(-1*e.length)===e&&(n=n.substr(0,n.length-e.length)),n},e.extname=function(t){"string"!=typeof t&&(t+="");for(var e=-1,n=0,r=-1,i=!0,o=0,a=t.length-1;a>=0;--a){var s=t.charCodeAt(a);if(47!==s)-1===r&&(i=!1,r=a+1),46===s?-1===e?e=a:1!==o&&(o=1):-1!==e&&(o=-1);else if(!i){n=a+1;break}}return-1===e||-1===r||0===o||1===o&&e===r-1&&e===n+1?"":t.slice(e,r)};var i="b"==="ab".substr(-1)?function(t,e,n){return t.substr(e,n)}:function(t,e,n){return e<0&&(e=t.length+e),t.substr(e,n)}}).call(this,n(4))},function(t,e,n){var r=n(6);"string"==typeof r&&(r=[[t.i,r,""]]),r.locals&&(t.exports=r.locals);(0,n(11).default)("176a63f5",r,!1,{})},function(t,e){function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(t){"object"===("undefined"==typeof window?"undefined":n(window))&&(r=window)}t.exports=r},function(t,e,n){"use strict";(function(t,n){function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)} +/*! + * Vue.js v2.6.10 + * (c) 2014-2019 Evan You + * Released under the MIT License. + */var i=Object.freeze({});function o(t){return null==t}function a(t){return null!=t}function s(t){return!0===t}function c(t){return"string"==typeof t||"number"==typeof t||"symbol"===r(t)||"boolean"==typeof t}function l(t){return null!==t&&"object"===r(t)}var u=Object.prototype.toString;function f(t){return"[object Object]"===u.call(t)}function d(t){return"[object RegExp]"===u.call(t)}function p(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function h(t){return a(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function v(t){return null==t?"":Array.isArray(t)||f(t)&&t.toString===u?JSON.stringify(t,null,2):String(t)}function m(t){var e=parseFloat(t);return isNaN(e)?t:e}function y(t,e){for(var n=Object.create(null),r=t.split(","),i=0;i-1)return t.splice(n,1)}}var b=Object.prototype.hasOwnProperty;function w(t,e){return b.call(t,e)}function C(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var x=/-(\w)/g,A=C(function(t){return t.replace(x,function(t,e){return e?e.toUpperCase():""})}),k=C(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),O=/\B([A-Z])/g,S=C(function(t){return t.replace(O,"-$1").toLowerCase()});var $=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function T(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function E(t,e){for(var n in e)t[n]=e[n];return t}function I(t){for(var e={},n=0;n0,Q=Y&&Y.indexOf("edge/")>0,tt=(Y&&Y.indexOf("android"),Y&&/iphone|ipad|ipod|ios/.test(Y)||"ios"===K),et=(Y&&/chrome\/\d+/.test(Y),Y&&/phantomjs/.test(Y),Y&&Y.match(/firefox\/(\d+)/)),nt={}.watch,rt=!1;if(G)try{var it={};Object.defineProperty(it,"passive",{get:function(){rt=!0}}),window.addEventListener("test-passive",null,it)}catch(t){}var ot=function(){return void 0===V&&(V=!G&&!X&&void 0!==t&&(t.process&&"server"===t.process.env.VUE_ENV)),V},at=G&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function st(t){return"function"==typeof t&&/native code/.test(t.toString())}var ct,lt="undefined"!=typeof Symbol&&st(Symbol)&&"undefined"!=typeof Reflect&&st(Reflect.ownKeys);ct="undefined"!=typeof Set&&st(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var ut=j,ft=0,dt=function(){this.id=ft++,this.subs=[]};dt.prototype.addSub=function(t){this.subs.push(t)},dt.prototype.removeSub=function(t){_(this.subs,t)},dt.prototype.depend=function(){dt.target&&dt.target.addDep(this)},dt.prototype.notify=function(){var t=this.subs.slice();for(var e=0,n=t.length;e-1)if(o&&!w(i,"default"))a=!1;else if(""===a||a===S(t)){var c=zt(String,i.type);(c<0||s0&&(fe((l=t(l,(n||"")+"_"+i))[0])&&fe(f)&&(r[u]=_t(f.text+l[0].text),l.shift()),r.push.apply(r,l)):c(l)?fe(f)?r[u]=_t(f.text+l):""!==l&&r.push(_t(l)):fe(l)&&fe(f)?r[u]=_t(f.text+l.text):(s(e._isVList)&&a(l.tag)&&o(l.key)&&a(n)&&(l.key="__vlist"+n+"_"+i+"__"),r.push(l)));return r}(t):void 0}function fe(t){return a(t)&&a(t.text)&&!1===t.isComment}function de(t,e){if(t){for(var n=Object.create(null),r=lt?Reflect.ownKeys(t):Object.keys(t),i=0;i0,a=t?!!t.$stable:!o,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&n&&n!==i&&s===n.$key&&!o&&!n.$hasNormal)return n;for(var c in r={},t)t[c]&&"$"!==c[0]&&(r[c]=me(e,c,t[c]))}else r={};for(var l in e)l in r||(r[l]=ye(e,l));return t&&Object.isExtensible(t)&&(t._normalized=r),B(r,"$stable",a),B(r,"$key",s),B(r,"$hasNormal",o),r}function me(t,e,n){var i=function(){var t=arguments.length?n.apply(null,arguments):n({});return(t=t&&"object"===r(t)&&!Array.isArray(t)?[t]:ue(t))&&(0===t.length||1===t.length&&t[0].isComment)?void 0:t};return n.proxy&&Object.defineProperty(t,e,{get:i,enumerable:!0,configurable:!0}),i}function ye(t,e){return function(){return t[e]}}function ge(t,e){var n,r,i,o,s;if(Array.isArray(t)||"string"==typeof t)for(n=new Array(t.length),r=0,i=t.length;rdocument.createEvent("Event").timeStamp&&(fn=function(){return dn.now()})}function pn(){var t,e;for(un=fn(),cn=!0,rn.sort(function(t,e){return t.id-e.id}),ln=0;lnln&&rn[n].id>t.id;)n--;rn.splice(n+1,0,t)}else rn.push(t);sn||(sn=!0,ne(pn))}}(this)},vn.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||l(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){Bt(t,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},vn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},vn.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},vn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||_(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var mn={enumerable:!0,configurable:!0,get:j,set:j};function yn(t,e,n){mn.get=function(){return this[e][n]},mn.set=function(t){this[e][n]=t},Object.defineProperty(t,n,mn)}function gn(t){t._watchers=[];var e=t.$options;e.props&&function(t,e){var n=t.$options.propsData||{},r=t._props={},i=t.$options._propKeys=[];t.$parent&&kt(!1);var o=function(o){i.push(o);var a=Rt(o,e,n,t);$t(r,o,a),o in t||yn(t,"_props",o)};for(var a in e)o(a);kt(!0)}(t,e.props),e.methods&&function(t,e){t.$options.props;for(var n in e)t[n]="function"!=typeof e[n]?j:$(e[n],t)}(t,e.methods),e.data?function(t){var e=t.$options.data;f(e=t._data="function"==typeof e?function(t,e){ht();try{return t.call(e,e)}catch(t){return Bt(t,e,"data()"),{}}finally{vt()}}(e,t):e||{})||(e={});var n=Object.keys(e),r=t.$options.props,i=(t.$options.methods,n.length);for(;i--;){var o=n[i];0,r&&w(r,o)||(a=void 0,36!==(a=(o+"").charCodeAt(0))&&95!==a&&yn(t,"_data",o))}var a;St(e,!0)}(t):St(t._data={},!0),e.computed&&function(t,e){var n=t._computedWatchers=Object.create(null),r=ot();for(var i in e){var o=e[i],a="function"==typeof o?o:o.get;0,r||(n[i]=new vn(t,a||j,j,_n)),i in t||bn(t,i,o)}}(t,e.computed),e.watch&&e.watch!==nt&&function(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var i=0;i-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!d(t)&&t.test(e)}function En(t,e){var n=t.cache,r=t.keys,i=t._vnode;for(var o in n){var a=n[o];if(a){var s=$n(a.componentOptions);s&&!e(s)&&In(n,o,r,i)}}}function In(t,e,n,r){var i=t[e];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),t[e]=null,_(n,e)}!function(t){t.prototype._init=function(t){var e=this;e._uid=An++,e._isVue=!0,t&&t._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(e,t):e.$options=Mt(kn(e.constructor),t||{},e),e._renderProxy=e,e._self=e,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(e),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&Je(t,e)}(e),function(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,r=n&&n.context;t.$slots=pe(e._renderChildren,r),t.$scopedSlots=i,t._c=function(e,n,r,i){return ze(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return ze(t,e,n,r,i,!0)};var o=n&&n.data;$t(t,"$attrs",o&&o.attrs||i,null,!0),$t(t,"$listeners",e._parentListeners||i,null,!0)}(e),nn(e,"beforeCreate"),function(t){var e=de(t.$options.inject,t);e&&(kt(!1),Object.keys(e).forEach(function(n){$t(t,n,e[n])}),kt(!0))}(e),gn(e),function(t){var e=t.$options.provide;e&&(t._provided="function"==typeof e?e.call(t):e)}(e),nn(e,"created"),e.$options.el&&e.$mount(e.$options.el)}}(On),function(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,"$data",e),Object.defineProperty(t.prototype,"$props",n),t.prototype.$set=Tt,t.prototype.$delete=Et,t.prototype.$watch=function(t,e,n){if(f(e))return xn(this,t,e,n);(n=n||{}).user=!0;var r=new vn(this,t,e,n);if(n.immediate)try{e.call(this,r.value)}catch(t){Bt(t,this,'callback for immediate watcher "'+r.expression+'"')}return function(){r.teardown()}}}(On),function(t){var e=/^hook:/;t.prototype.$on=function(t,n){var r=this;if(Array.isArray(t))for(var i=0,o=t.length;i1?T(n):n;for(var r=T(arguments,1),i='event handler for "'+t+'"',o=0,a=n.length;oparseInt(this.max)&&In(a,s[0],s,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={get:function(){return H}};Object.defineProperty(t,"config",e),t.util={warn:ut,extend:E,mergeOptions:Mt,defineReactive:$t},t.set=Tt,t.delete=Et,t.nextTick=ne,t.observable=function(t){return St(t),t},t.options=Object.create(null),R.forEach(function(e){t.options[e+"s"]=Object.create(null)}),t.options._base=t,E(t.options.components,Nn),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=T(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=Mt(this.options,t),this}}(t),Sn(t),function(t){R.forEach(function(e){t[e]=function(t,n){return n?("component"===e&&f(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}})}(t)}(On),Object.defineProperty(On.prototype,"$isServer",{get:ot}),Object.defineProperty(On.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(On,"FunctionalRenderContext",{value:Ne}),On.version="2.6.10";var Fn=y("style,class"),Ln=y("input,textarea,option,select,progress"),Dn=y("contenteditable,draggable,spellcheck"),Mn=y("events,caret,typing,plaintext-only"),Pn=function(t,e){return Bn(e)||"false"===e?"false":"contenteditable"===t&&Mn(e)?e:"true"},Rn=y("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),Un="http://www.w3.org/1999/xlink",Hn=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},zn=function(t){return Hn(t)?t.slice(6,t.length):""},Bn=function(t){return null==t||!1===t};function Wn(t){for(var e=t.data,n=t,r=t;a(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=Vn(r.data,e));for(;a(n=n.parent);)n&&n.data&&(e=Vn(e,n.data));return function(t,e){if(a(t)||a(e))return qn(t,Gn(e));return""}(e.staticClass,e.class)}function Vn(t,e){return{staticClass:qn(t.staticClass,e.staticClass),class:a(t.class)?[t.class,e.class]:e.class}}function qn(t,e){return t?e?t+" "+e:t:e||""}function Gn(t){return Array.isArray(t)?function(t){for(var e,n="",r=0,i=t.length;r-1?mr(t,e,n):Rn(e)?Bn(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):Dn(e)?t.setAttribute(e,Pn(e,n)):Hn(e)?Bn(n)?t.removeAttributeNS(Un,zn(e)):t.setAttributeNS(Un,e,n):mr(t,e,n)}function mr(t,e,n){if(Bn(n))t.removeAttribute(e);else{if(J&&!Z&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){t.addEventListener("input",function e(n){n.stopImmediatePropagation(),t.removeEventListener("input",e)}),t.__ieph=!0}t.setAttribute(e,n)}}var yr={create:hr,update:hr};function gr(t,e){var n=e.elm,r=e.data,i=t.data;if(!(o(r.staticClass)&&o(r.class)&&(o(i)||o(i.staticClass)&&o(i.class)))){var s=Wn(e),c=n._transitionClasses;a(c)&&(s=qn(s,Gn(c))),s!==n._prevClass&&(n.setAttribute("class",s),n._prevClass=s)}}var _r,br={create:gr,update:gr},wr="__r",Cr="__c";function xr(t,e,n){var r=_r;return function i(){var o=e.apply(null,arguments);null!==o&&Or(t,i,n,r)}}var Ar=Xt&&!(et&&Number(et[1])<=53);function kr(t,e,n,r){if(Ar){var i=un,o=e;e=o._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=i||t.timeStamp<=0||t.target.ownerDocument!==document)return o.apply(this,arguments)}}_r.addEventListener(t,e,rt?{capture:n,passive:r}:n)}function Or(t,e,n,r){(r||_r).removeEventListener(t,e._wrapper||e,n)}function Sr(t,e){if(!o(t.data.on)||!o(e.data.on)){var n=e.data.on||{},r=t.data.on||{};_r=e.elm,function(t){if(a(t[wr])){var e=J?"change":"input";t[e]=[].concat(t[wr],t[e]||[]),delete t[wr]}a(t[Cr])&&(t.change=[].concat(t[Cr],t.change||[]),delete t[Cr])}(n),se(n,r,kr,Or,xr,e.context),_r=void 0}}var $r,Tr={create:Sr,update:Sr};function Er(t,e){if(!o(t.data.domProps)||!o(e.data.domProps)){var n,r,i=e.elm,s=t.data.domProps||{},c=e.data.domProps||{};for(n in a(c.__ob__)&&(c=e.data.domProps=E({},c)),s)n in c||(i[n]="");for(n in c){if(r=c[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),r===s[n])continue;1===i.childNodes.length&&i.removeChild(i.childNodes[0])}if("value"===n&&"PROGRESS"!==i.tagName){i._value=r;var l=o(r)?"":String(r);Ir(i,l)&&(i.value=l)}else if("innerHTML"===n&&Yn(i.tagName)&&o(i.innerHTML)){($r=$r||document.createElement("div")).innerHTML=""+r+"";for(var u=$r.firstChild;i.firstChild;)i.removeChild(i.firstChild);for(;u.firstChild;)i.appendChild(u.firstChild)}else if(r!==s[n])try{i[n]=r}catch(t){}}}}function Ir(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,r=t._vModifiers;if(a(r)){if(r.number)return m(n)!==m(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var jr={create:Er,update:Er},Nr=C(function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach(function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}}),e});function Fr(t){var e=Lr(t.style);return t.staticStyle?E(t.staticStyle,e):e}function Lr(t){return Array.isArray(t)?I(t):"string"==typeof t?Nr(t):t}var Dr,Mr=/^--/,Pr=/\s*!important$/,Rr=function(t,e,n){if(Mr.test(e))t.style.setProperty(e,n);else if(Pr.test(n))t.style.setProperty(S(e),n.replace(Pr,""),"important");else{var r=Hr(e);if(Array.isArray(n))for(var i=0,o=n.length;i-1?e.split(Wr).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function qr(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(Wr).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function Gr(t){if(t){if("object"===r(t)){var e={};return!1!==t.css&&E(e,Xr(t.name||"v")),E(e,t),e}return"string"==typeof t?Xr(t):void 0}}var Xr=C(function(t){return{enterClass:t+"-enter",enterToClass:t+"-enter-to",enterActiveClass:t+"-enter-active",leaveClass:t+"-leave",leaveToClass:t+"-leave-to",leaveActiveClass:t+"-leave-active"}}),Kr=G&&!Z,Yr="transition",Jr="animation",Zr="transition",Qr="transitionend",ti="animation",ei="animationend";Kr&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Zr="WebkitTransition",Qr="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(ti="WebkitAnimation",ei="webkitAnimationEnd"));var ni=G?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function ri(t){ni(function(){ni(t)})}function ii(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),Vr(t,e))}function oi(t,e){t._transitionClasses&&_(t._transitionClasses,e),qr(t,e)}function ai(t,e,n){var r=ci(t,e),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===Yr?Qr:ei,c=0,l=function(){t.removeEventListener(s,u),n()},u=function(e){e.target===t&&++c>=a&&l()};setTimeout(function(){c0&&(n=Yr,u=a,f=o.length):e===Jr?l>0&&(n=Jr,u=l,f=c.length):f=(n=(u=Math.max(a,l))>0?a>l?Yr:Jr:null)?n===Yr?o.length:c.length:0,{type:n,timeout:u,propCount:f,hasTransform:n===Yr&&si.test(r[Zr+"Property"])}}function li(t,e){for(;t.length1}function vi(t,e){!0!==e.data.show&&fi(e)}var mi=function(t){var e,n,r={},i=t.modules,l=t.nodeOps;for(e=0;eh?_(t,o(n[y+1])?null:n[y+1].elm,n,p,y,r):p>y&&w(0,e,d,h)}(d,m,y,n,u):a(y)?(a(t.text)&&l.setTextContent(d,""),_(d,null,y,0,y.length-1,n)):a(m)?w(0,m,0,m.length-1):a(t.text)&&l.setTextContent(d,""):t.text!==e.text&&l.setTextContent(d,e.text),a(h)&&a(p=h.hook)&&a(p=p.postpatch)&&p(t,e)}}}function k(t,e,n){if(s(n)&&a(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r-1,a.selected!==o&&(a.selected=o);else if(L(wi(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));i||(t.selectedIndex=-1)}}function bi(t,e){return e.every(function(e){return!L(e,t)})}function wi(t){return"_value"in t?t._value:t.value}function Ci(t){t.target.composing=!0}function xi(t){t.target.composing&&(t.target.composing=!1,Ai(t.target,"input"))}function Ai(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function ki(t){return!t.componentInstance||t.data&&t.data.transition?t:ki(t.componentInstance._vnode)}var Oi={model:yi,show:{bind:function(t,e,n){var r=e.value,i=(n=ki(n)).data&&n.data.transition,o=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&i?(n.data.show=!0,fi(n,function(){t.style.display=o})):t.style.display=r?o:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=ki(n)).data&&n.data.transition?(n.data.show=!0,r?fi(n,function(){t.style.display=t.__vOriginalDisplay}):di(n,function(){t.style.display="none"})):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,i){i||(t.style.display=t.__vOriginalDisplay)}}},Si={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function $i(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?$i(Ge(e.children)):t}function Ti(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var i=n._parentListeners;for(var o in i)e[A(o)]=i[o];return e}function Ei(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var Ii=function(t){return t.tag||qe(t)},ji=function(t){return"show"===t.name},Ni={name:"transition",props:Si,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(Ii)).length){0;var r=this.mode;0;var i=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return i;var o=$i(i);if(!o)return i;if(this._leaving)return Ei(t,i);var a="__transition-"+this._uid+"-";o.key=null==o.key?o.isComment?a+"comment":a+o.tag:c(o.key)?0===String(o.key).indexOf(a)?o.key:a+o.key:o.key;var s=(o.data||(o.data={})).transition=Ti(this),l=this._vnode,u=$i(l);if(o.data.directives&&o.data.directives.some(ji)&&(o.data.show=!0),u&&u.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(o,u)&&!qe(u)&&(!u.componentInstance||!u.componentInstance._vnode.isComment)){var f=u.data.transition=E({},s);if("out-in"===r)return this._leaving=!0,ce(f,"afterLeave",function(){e._leaving=!1,e.$forceUpdate()}),Ei(t,i);if("in-out"===r){if(qe(o))return l;var d,p=function(){d()};ce(s,"afterEnter",p),ce(s,"enterCancelled",p),ce(f,"delayLeave",function(t){d=t})}}return i}}},Fi=E({tag:String,moveClass:String},Si);function Li(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function Di(t){t.data.newPos=t.elm.getBoundingClientRect()}function Mi(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,i=e.top-n.top;if(r||i){t.data.moved=!0;var o=t.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}delete Fi.mode;var Pi={Transition:Ni,TransitionGroup:{props:Fi,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var i=Qe(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,i(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],a=Ti(this),s=0;s-1?Zn[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Zn[t]=/HTMLUnknownElement/.test(e.toString())},E(On.options.directives,Oi),E(On.options.components,Pi),On.prototype.__patch__=G?mi:j,On.prototype.$mount=function(t,e){return function(t,e,n){var r;return t.$el=e,t.$options.render||(t.$options.render=gt),nn(t,"beforeMount"),r=function(){t._update(t._render(),n)},new vn(t,r,j,{before:function(){t._isMounted&&!t._isDestroyed&&nn(t,"beforeUpdate")}},!0),n=!1,null==t.$vnode&&(t._isMounted=!0,nn(t,"mounted")),t}(this,t=t&&G?function(t){if("string"==typeof t){var e=document.querySelector(t);return e||document.createElement("div")}return t}(t):void 0,e)},G&&setTimeout(function(){H.devtools&&at&&at.emit("init",On)},0),e.a=On}).call(this,n(2),n(8).setImmediate)},function(t,e){var n,r,i=t.exports={};function o(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function s(t){if(n===setTimeout)return setTimeout(t,0);if((n===o||!n)&&setTimeout)return n=setTimeout,setTimeout(t,0);try{return n(t,0)}catch(e){try{return n.call(null,t,0)}catch(e){return n.call(this,t,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:o}catch(t){n=o}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(t){r=a}}();var c,l=[],u=!1,f=-1;function d(){u&&c&&(u=!1,c.length?l=c.concat(l):f=-1,l.length&&p())}function p(){if(!u){var t=s(d);u=!0;for(var e=l.length;e;){for(c=l,l=[];++f1)for(var n=1;n=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},n(9),e.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==t&&t.setImmediate||this&&this.setImmediate,e.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==t&&t.clearImmediate||this&&this.clearImmediate}).call(this,n(2))},function(t,e,n){(function(t,e){!function(t,n){"use strict";if(!t.setImmediate){var r,i,o,a,s,c=1,l={},u=!1,f=t.document,d=Object.getPrototypeOf&&Object.getPrototypeOf(t);d=d&&d.setTimeout?d:t,"[object process]"==={}.toString.call(t.process)?r=function(t){e.nextTick(function(){h(t)})}:!function(){if(t.postMessage&&!t.importScripts){var e=!0,n=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=n,e}}()?t.MessageChannel?((o=new MessageChannel).port1.onmessage=function(t){h(t.data)},r=function(t){o.port2.postMessage(t)}):f&&"onreadystatechange"in f.createElement("script")?(i=f.documentElement,r=function(t){var e=f.createElement("script");e.onreadystatechange=function(){h(t),e.onreadystatechange=null,i.removeChild(e),e=null},i.appendChild(e)}):r=function(t){setTimeout(h,0,t)}:(a="setImmediate$"+Math.random()+"$",s=function(e){e.source===t&&"string"==typeof e.data&&0===e.data.indexOf(a)&&h(+e.data.slice(a.length))},t.addEventListener?t.addEventListener("message",s,!1):t.attachEvent("onmessage",s),r=function(e){t.postMessage(a+e,"*")}),d.setImmediate=function(t){"function"!=typeof t&&(t=new Function(""+t));for(var e=new Array(arguments.length-1),n=0;n1&&void 0!==arguments[1]?arguments[1]:"";window.localStorage.setItem("files_last_path"+e,""+t)}function c(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e0&&void 0!==arguments[0]?arguments[0]:[],e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=window.localStorage.getItem("files_last_path"+e),r=t.length>0&&t[0].href;return n||r||"/"}(this.fs_favorites,this.modalId)},is_entry_disabled:function(t){return"dir"!==t.size&&!this.is_entry_selectable(t)},is_entry_selectable:function(t){var e="dirs"===this.target_file_type||"both"===this.target_file_type,n="files"===this.target_file_type||"both"===this.target_file_type;return"dir"===t.size?!!e&&(!this.target_file_pattern||!!t.name.match(this.target_file_pattern)):!!n&&(!this.target_file_pattern||!!t.name.match(this.target_file_pattern))}},mounted:function(){this.path=this.get_current_path(),this.filter_input=this.$el.querySelector("#"+this.filterId)},computed:{modalId:function(){return this.input?"modal-for-"+this.input.id:""},filterId:function(){return"filter-for-"+this.input.id},slugs:function(){return this.path.split(o.sep)},showFsFavorites:function(){return this.fs_favorites.length>0},fsEntryColWidth:function(){return this.showFsFavorites?"col-sm-7":"col-sm-12"}}};n(5);var u=function(t,e,n,r,i,o,a,s){var c,l="function"==typeof t?t.options:t;if(e&&(l.render=e,l.staticRenderFns=n,l._compiled=!0),r&&(l.functional=!0),o&&(l._scopeId="data-v-"+o),a?(c=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),i&&i.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},l._ssrRegister=c):i&&(c=s?function(){i.call(this,this.$root.$options.shadowRoot)}:i),c)if(l.functional){l._injectStyles=c;var u=l.render;l.render=function(t,e){return c.call(e),u(t,e)}}else{var f=l.beforeCreate;l.beforeCreate=f?[].concat(f,c):[c]}return{exports:t,options:l}}(l,i,[],!1,null,null,null);u.options.__file="src/components/file_picker.vue";var f=u.exports;function d(t){var e=t.dataset.targetFileType;if(!e)return"both";var n={files:"files",dirs:"dirs",both:"both"}[e];return n||(console.error("".concat(e," is not one of [files, dirs, both]. Using both.")),"both")}function p(t){var e=t.dataset.targetFilePattern;try{return!!e&&new RegExp(e)}catch(t){return console.error("Unable to compile regular expression: ".concat(e,". Not using target-file-type.")),!1}}$(document).ready(function(){(window.file_picker_favorites?Promise.resolve(window.file_picker_favorites):window.location.href.match(new RegExp("pun/(sys|dev)/(ood-)?dashboard"))?Promise.resolve(a(document)):fetch("/pun/sys/dashboard",{credentials:"same-origin"}).then(function(t){return t.text()}).then(function(t){return a((new DOMParser).parseFromString(t,"text/html"))}).catch(function(t){return console.error(t),[]})).then(function(t){var e=!0,n=!1,i=void 0;try{for(var o,a=function(){var e=o.value,n=(e.id,document.createElement("div")),i=function(t){var e=t.dataset.file_picker_favorites;try{return!!e&&JSON.parse(e)}catch(t){return console.error("Unable to use favorites from the data attribute because: "+t),!1}}(e);e.parentElement.append(n),new r.a({el:n,render:function(n){return n(f,{props:{input:e,fs_favorites:i||t,show_hidden:(r=e,r.dataset.showHidden||!1),target_file_type:d(e),target_file_pattern:p(e)}});var r}})},s=document.querySelectorAll("input[data-filepicker]")[Symbol.iterator]();!(e=(o=s.next()).done);e=!0)a()}catch(t){n=!0,i=t}finally{try{e||null==s.return||s.return()}finally{if(n)throw i}}})})},function(t,e,n){"use strict";function r(t,e){for(var n=[],r={},i=0;in.parts.length&&(r.parts.length=n.parts.length)}else{var a=[];for(i=0;i %{buildroot}%{_localstatedir}/www/ood/apps/sys/%{app_name}/VERSION + + +%files +%defattr(-,root,root) +%{_localstatedir}/www/ood/apps/sys/%{app_name} +%{_localstatedir}/www/ood/apps/sys/%{app_name}/manifest.yml + + +%changelog diff --git a/submit.yml.erb b/submit.yml.erb new file mode 100644 index 0000000..4c9d20f --- /dev/null +++ b/submit.yml.erb @@ -0,0 +1,7 @@ +--- +batch_connect: + template: "basic" +script: + native: + resources: + nodes: "1:ppn=1:owens" \ No newline at end of file diff --git a/template/after.sh.erb b/template/after.sh.erb new file mode 100755 index 0000000..0cd988d --- /dev/null +++ b/template/after.sh.erb @@ -0,0 +1,9 @@ +# Wait for the Jupyter server to start +echo "Waiting for Jupyter server to open port ${port}..." +if wait_until_port_used "${host}:${port}" 600; then + echo "Discovered code-server listening on port ${port}!" +else + echo "Timed out waiting for Jupyter server to open port ${port}!" + clean_up 1 +fi +sleep 2 diff --git a/template/before.sh.erb b/template/before.sh.erb new file mode 100755 index 0000000..6607472 --- /dev/null +++ b/template/before.sh.erb @@ -0,0 +1,8 @@ +# # Export the module function if it exists +[[ $(type -t module) == "function" ]] && export -f module + +# # Find available port to run server on +export port=$(find_port ${host}) + +# # Generate SHA1 encrypted password (requires OpenSSL installed) +export password="$(create_passwd 16)" diff --git a/template/script.sh.erb b/template/script.sh.erb new file mode 100755 index 0000000..9a1933d --- /dev/null +++ b/template/script.sh.erb @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +<%- + working_dir = Pathname.new(context.working_dir) + if ! working_dir.exist? || working_dir.to_s.empty? + working_dir = Pathname.new(ENV['HOME']) + elsif working_dir.file? + working_dir = working_dir.parent + end +%> + +# Ensure a dataroot for Code Server +CODE_SERVER_DATAROOT="$HOME/.local/share/bc_osc_codeserver" +mkdir -p "$CODE_SERVER_DATAROOT/extensions" + +export PASSWORD="$password" + +# VSCode complains that system git is too old +module load git + +# +# Start Code Server +# + +/fs/project/PZS0714/mrodgers/bin/code-server-2.1523-vsc1.38.1 \ + --auth=password \ + --port="$port" \ + --extra-extensions-dir="$CODE_SERVER_DATAROOT/extensions" \ + --user-data-dir="$CODE_SERVER_DATAROOT" \ + "<%= working_dir.to_s %>" \ No newline at end of file diff --git a/view.html.erb b/view.html.erb new file mode 100644 index 0000000..ba4be26 --- /dev/null +++ b/view.html.erb @@ -0,0 +1,6 @@ +
+ + +