xoslib wip
diff --git a/planetstack/core/xoslib/static/js/sliverListTest.js b/planetstack/core/xoslib/static/js/sliverListTest.js
new file mode 100644
index 0000000..294ffd3
--- /dev/null
+++ b/planetstack/core/xoslib/static/js/sliverListTest.js
@@ -0,0 +1,177 @@
+(function(){
+
+window.SliverView = Backbone.View.extend({
+    tagName: 'li',
+    className: 'XOSLib.sliver',
+
+    events: {
+        'click .permalink': 'navigate'
+    },
+
+    initialize: function(){
+        this.model.bind('change', this.render, this);
+    },
+
+    navigate: function(e){
+        this.trigger('navigate', this.model);
+        e.preventDefault();
+    },
+
+    render: function(){
+        $(this.el).html(ich.sliverTemplate(this.model.toJSON()));
+        return this;
+    }
+});
+
+
+window.DetailApp = Backbone.View.extend({
+    events: {
+        'click .home': 'home'
+    },
+
+    home: function(e){
+        this.trigger('home');
+        e.preventDefault();
+    },
+
+    render: function(){
+        $(this.el).html(ich.detailApp(this.model.toJSON()));
+        return this;
+    }
+});
+
+window.InputView = Backbone.View.extend({
+    events: {
+        'click .sliver': 'createSliver',
+        'keypress #message': 'createOnEnter'
+    },
+
+    createOnEnter: function(e){
+        if((e.keyCode || e.which) == 13){
+            this.createSliver();
+            e.preventDefault();
+        }
+
+    },
+
+    createSliver: function(){
+        var message = this.$('#message').val();
+        if(message){
+            this.collection.create({
+                message: message
+            });
+            this.$('#message').val('');
+        }
+    }
+
+});
+
+window.ListView = Backbone.View.extend({
+    initialize: function(){
+        _.bindAll(this, 'addOne', 'addAll');
+
+        this.collection.bind('add', this.addOne);
+        this.collection.bind('reset', this.addAll, this);
+        this.views = [];
+    },
+
+    addAll: function(){
+        this.views = [];
+        this.collection.each(this.addOne);
+    },
+
+    addOne: function(sliver){
+        var view = new SliverView({
+            model: XOSLib.sliver
+        });
+        $(this.el).prepend(view.render().el);
+        this.views.push(view);
+        view.bind('all', this.rethrow, this);
+    },
+
+    rethrow: function(){
+        this.trigger.apply(this, arguments);
+    }
+
+});
+
+window.ListApp = Backbone.View.extend({
+    el: "#app",
+
+    rethrow: function(){
+        this.trigger.apply(this, arguments);
+    },
+
+    render: function(){
+        console.log("listApp.render");
+        $(this.el).html(ich.listApp({}));
+        var list = new ListView({
+            collection: this.collection,
+            el: this.$('#slivers')
+        });
+        list.addAll();
+        list.bind('all', this.rethrow, this);
+        new InputView({
+            collection: this.collection,
+            el: this.$('#input')
+        });
+    }
+});
+
+
+window.Router = Backbone.Router.extend({
+    routes: {
+        '': 'list',
+        ':id/': 'detail'
+    },
+
+    navigate_to: function(model){
+        var path = (model && model.get('id') + '/') || '';
+        console.log("Router.navigate_to");
+        this.navigate(path, true);
+    },
+
+    detail: function(){ console.log("Router.detail"); },
+
+    list: function(){ console.log("Router.list"); }
+});
+
+$(function(){
+    window.app = window.app || {};
+    app.router = new Router();
+    app.slivers = new XOSLib.slivers();
+    app.list = new ListApp({
+        el: $("#app"),
+        collection: app.slivers
+    });
+    app.detail = new DetailApp({
+        el: $("#app")
+    });
+    app.router.bind('route:list', function(){
+        console.log("Router:list2");
+        app.slivers.maybeFetch({
+            success: _.bind(app.list.render, app.list)
+        });
+    });
+    app.router.bind('route:detail', function(id){
+        console.log("Router:detail2");
+        app.slivers.getOrFetch(app.slivers.urlRoot + id + '/', {
+            success: function(model){
+                app.detail.model = model;
+                app.detail.render();
+            }
+        });
+    });
+
+    app.slivers.maybeFetch({
+        success: _.bind(app.list.render, app.list)
+    });
+
+    app.list.bind('navigate', app.router.navigate_to, app.router);
+    app.detail.bind('home', app.router.navigate_to, app.router);
+    Backbone.history.start({
+        pushState: true,
+        silent: app.loaded
+    });
+});
+})();
diff --git a/planetstack/core/xoslib/static/js/xos-backbone.js b/planetstack/core/xoslib/static/js/xos-backbone.js
new file mode 100644
index 0000000..99f0784
--- /dev/null
+++ b/planetstack/core/xoslib/static/js/xos-backbone.js
@@ -0,0 +1,49 @@
+SLIVER_API = "/plstackapi/slivers/";
+
+XOSCollection = Backbone.Collection.extend({
+    maybeFetch: function(options){
+            // Helper function to fetch only if this collection has not been fetched before.
+        if(this._fetched){
+                // If this has already been fetched, call the success, if it exists
+            options.success && options.success();
+            console.log("alreadyFetched");
+            return;
+        }
+
+            // when the original success function completes mark this collection as fetched
+        var self = this,
+        successWrapper = function(success){
+            return function(){
+                self._fetched = true;
+                success && success.apply(this, arguments);
+            };
+        };
+        options.success = successWrapper(options.success);
+        console.log("call fetch");
+        this.fetch(options);
+    },
+
+    getOrFetch: function(id, options){
+            // Helper function to use this collection as a cache for models on the server
+        var model = this.get(id);
+
+        if(model){
+            options.success && options.success(model);
+            return;
+        }
+
+        model = new Sliver({
+            resource_uri: id
+        });
+
+        model.fetch(options);
+    }
+});
+
+function xoslib() {
+    this.sliver = Backbone.Model.extend({ urlRoot: SLIVER_API });
+    this.slivers = XOSCollection.extend({ urlRoot: SLIVER_API,
+                                    model: this.sliver});
+};
+
+XOSLib = new xoslib();