diff --git a/.travis.yml b/.travis.yml
index 3b2b98a4..4cf6f163 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,9 +3,8 @@ branches:
except:
- debug
node_js:
- - 4.0
- - 4.2
- - 5.0
- - 6.8
- - 7.9
- - 8.6
+ - 8
+ - 10
+cache:
+ directories:
+ - node_modules
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index be214ded..7eb3a7cd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:edge
+FROM alpine:latest
# Build-time metadata as defined at http://label-schema.org
ARG BUILD_DATE
ARG VCS_REF
@@ -22,4 +22,5 @@ RUN apk update && apk upgrade \
&& npm install \
&& apk del .build-dependencies && rm -rf /var/cache/* /tmp/npm*
EXPOSE 8080
+EXPOSE 8765
CMD ["npm","start"]
diff --git a/Procfile b/Procfile
index a5ffa97a..875fe822 100644
--- a/Procfile
+++ b/Procfile
@@ -1 +1 @@
-web: node --optimize_for_size --max_old_space_size=460 --gc_interval=100 examples/http.js
\ No newline at end of file
+web: node --optimize_for_size --gc_interval=100 examples/http.js
diff --git a/README.md b/README.md
index a0b470dc..c2438c08 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,4 @@
-
-
-
-
+
[](https://www.npmjs.com/package/gun)
[](https://travis-ci.org/amark/gun)
@@ -9,7 +6,9 @@
[](https://gitter.im/amark/gun)
[](https://www.jsdelivr.com/package/npm/gun)
-GUN is a realtime, distributed, offline-first, graph database engine. Doing **[20M+](https://github.com/amark/gun/wiki/100000-ops-sec-in-IE6-on-2GB-Atom-CPU) ops/sec** in just **~9KB** gzipped.
+**GUN** is an _ecosystem_ of tools that let you build tomorrow's dApps, today.
+
+Decentralized alternatives to [Reddit](https://notabug.io/t/whatever/comments/36588a16b9008da4e3f15663c2225e949eca4a15/gpu-bot-test), [YouTube](https://d.tube/), [Wikipedia](https://news.ycombinator.com/item?id=17685682), etc. are already pushing terabytes of daily P2P traffic on GUN. We are a [friendly community](https://gitter.im/amark/gun) creating a free fun future for freedom:
@@ -22,22 +21,16 @@ GUN is a realtime, distributed, offline-first, graph database engine. Doing **[2
-
-
-
-
-
+The ecosystem is one nice stack of technologies that looks like this:
-## Why?
+
+
- - **Realtime** - You might use socketio for realtime updates, but what happens if you reload the page? GUN solves *state synchronization* for you, no matter what, on reloads, across all your users, and even on conflicting updates.
- - **Distributed** - GUN is peer-to-peer by design, meaning you have no centralized database server to maintain or that could crash. This lets you sleep through the night without worrying about database DevOps - we call it "NoDB". From there, you can build decentralized, federated, or centralized apps.
- - **Offline-first** - GUN works even if your internet or cell reception doesn't. Users can still plug away and save data as normal, and then when the network comes back online GUN will automatically synchronize all the changes and handle any conflicts for you.
- - **Graph** - Most databases force you to bend over backwards to match their storage constraints. But graphs are different, they let you have any data structure you want. Whether that be traditional tables with relations, document oriented trees, or tons of circular references. You choose.
+For now, it is best to start with GUN and _just use it_ to learn the basics, since it is _**so easy**_: (**or** want to read more? Skip ahead to the "[What is GUN?](#what-is-gun)" section.)
## Quickstart
- - Try the [interactive tutorial](https://gun.eco/think.html) in the browser (**5min** ~ average developer).
+ - Try the [interactive tutorial](https://gun.eco/docs/Todo-Dapp) in the browser (**5min** ~ average developer).
- Or `npm install gun` and run the examples with `cd node_modules/gun && npm start` (**5min** ~ average developer).
> **Note:** If you don't have [node](http://nodejs.org/) or [npm](https://www.npmjs.com/), read [this](https://github.com/amark/gun/blob/master/examples/install.sh) first.
@@ -62,7 +55,7 @@ gun.get('mark').on(function(data, key){
});
```
-- Or try something mind blowing, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console))
+- Or try something **mind blowing**, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console))
```javascript
var cat = {name: "Fluffy", species: "kitty"};
var mark = {boss: cat};
@@ -72,7 +65,7 @@ cat.slave = mark;
gun.get('mark').put(mark);
// access the data as if it is a document.
-gun.get('mark').get('boss').get('name').val(function(data, key){
+gun.get('mark').get('boss').get('name').once(function(data, key){
// `val` grabs the data once, no subscriptions.
console.log("Mark's boss is", data);
});
@@ -95,20 +88,32 @@ gun.get('list').map().once(function(data, key){
gun.get('list').set({type: "cucumber", goal: "scare cat"});
```
-## Support
+Want to keep building more? **Jump to [THE DOCUMENTATION](#documentation)!**
+
+# What is GUN?
+
+First & foremost, GUN is **a community of the nicest and most helpful people** out there. So [I want to invite you](https://gitter.im/amark/gun) to come tell us about what **you** are working on & wanting to build (new or old school alike! Just be nice as well.) and ask us your questions directly. :)
+
+On that note, let's get some official shout outs covered first:
+
+### Support
- Join others in sponsoring code: https://www.patreon.com/gunDB !
@@ -116,19 +121,32 @@ Thanks to:
- Found a bug? Report at: https://github.com/amark/gun/issues ;
- **Need help**? Chat with us: https://gitter.im/amark/gun .
+### History
+
+[GUN](https://gun.eco) was created by [Mark Nadal](https://twitter.com/marknadal) in 2014 after he had spent 4 years trying to get his collaborative web app to scale up with traditional databases.
+
+ After he realized [Master-Slave database architecture causes one big bottleneck](https://gun.eco/distributed/matters.html), he (as a complete newbie outsider) naively decided **to question the status quo** and shake things up with controversial, heretical, and contrarian experiments:
+
+**The NoDB** - no master, no servers, no "single source of truth", not built with a real programming language or real hardware, no DevOps, no locking, not *just* SQL or NoSQL but both (**all** - graphs, documents, tables, key/value).
+
+The goal was to build a P2P database that could survive living inside **any** browser, and could correctly sync data between **any** device after assuming **any** offline-first activity.
+
+
+
+Technically, **GUN is a graph synchronization protocol** with a *lightweight embedded engine*, capable of doing *[20M+ API ops/sec](https://gun.eco/docs/Performance)* in **just ~9KB gzipped size**.
## Documentation
This would not be possible without **community contributors**, big shout out to:
-**[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; [sbeleidy](https://github.com/sbeleidy); **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[88dev](https://github.com/88dev) ([Database Viewer](https://github.com/88dev/gun-show))**;
+**[ajmeyghani](https://github.com/ajmeyghani) ([Learn GUN Basics with Diagrams](https://medium.com/@ajmeyghani/gundb-a-graph-database-in-javascript-3860a08d873c))**; **[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[Lightnet](https://github.com/Lightnet)** ([Awesome Vue User Examples](https://glitch.com/edit/#!/jsvuegunui?path=README.md:1:0) & [User Kitchen Sink Playground](https://gdb-auth-vue-node.glitch.me/)); **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; **[rogowski](https://github.com/rogowski) (AXE)**; [sbeleidy](https://github.com/sbeleidy); **[sbiaudet](https://github.com/sbiaudet) ([C# Port](https://github.com/sbiaudet/cs-gun))**; **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Shadyzpop](https://github.com/Shadyzpop) ([React Native example](https://github.com/amark/gun/tree/master/examples/react-native))**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[xmonader](https://github.com/xmonader) ([Python Port](https://github.com/xmonader/pygundb))**; **[88dev](https://github.com/88dev) ([Database Viewer](https://github.com/88dev/gun-show))**;
I am missing many others, apologies, will be adding them soon!
+## Testing
+
+Tests may be run with `npm test`. Tests will trigger persistent writes to the DB, so subsequent runs of the test will fail. You must clear the DB before running the tests again. This can be done by running the following command in the project directory.
+
+```bash
+rm -rf *data*
+```
+
+### Additional Cryptography Libraries
+
+To install with npm, first install `npm install gun -S`.
+For just the networking layer, import Gun:
+
+```javascript
+var Gun = require('gun/gun');
+```
+
+If you also need to install SEA for user auth and crypto, also install some of its dependencies like this:
+
+`npm install @trust/crypto text-encoding node-webcrypto-ossl --save`
+
+You will need to require it too (it will be automatically added to the Gun object):
+
+```javascript
+var Gun = require('gun/gun');
+var Sea = require('gun/sea');
+```
+
+
## Deploy
To quickly spin up a Gun test server for your development team, utilize either [Heroku](http://heroku.com) or [Docker](http://docker.com) or any variant thereof [Dokku](http://dokku.viewdocs.io/dokku/), [Flynn.io](http://flynn.io), [now.sh](https://zeit.co/now), etc. !
@@ -188,7 +235,7 @@ Then visit the URL in the output of the 'now --npm' step, in your browser.
Pull from the [Docker Hub](https://hub.docker.com/r/gundb/gun/) [](https://microbadger.com/images/gundb/gun). Or:
```bash
-docker run -p 8080:8080 gundb/gun
+docker run -p 8765:8765 gundb/gun
```
Or build the [Docker](https://docs.docker.com/engine/installation/) image locally:
@@ -197,17 +244,17 @@ Or build the [Docker](https://docs.docker.com/engine/installation/) image locall
git clone https://github.com/amark/gun.git
cd gun
docker build -t myrepo/gundb:v1 .
-docker run -p 8080:8080 myrepo/gundb:v1
+docker run -p 8765:8765 myrepo/gundb:v1
```
Or, if you prefer your Docker image with metadata labels (Linux/Mac only):
```bash
npm run docker
-docker run -p 8080:8080 usenameHere/gun:git
+docker run -p 8765:8765 username/gun:git
```
-Then visit [http://localhost:8080](http://localhost:8080) in your browser.
+Then visit [http://localhost:8765](http://localhost:8765) in your browser.
## License
diff --git a/as.js b/as.js
index fc869469..f6ac4f37 100644
--- a/as.js
+++ b/as.js
@@ -40,7 +40,7 @@
}
ref.get(function(at){
- var data = at.put, key = at.get, gui = at.gun, ui = name, back;
+ var data = at.put, key = at.get, gui = at.gun || at.$, ui = name, back;
if(model){
ui = model.has[(gui._).id];
if(!ui){
@@ -80,12 +80,11 @@
}, wait || 200);
}
}
- as.sort = function(sort, el) {
- var vs = $(el).find('.sort');
- vs = (vs[0] && u === vs[0].value)? vs.text() : vs.val();
- var id = sort;
- var test = id >= vs;
- return test ? el : as.sort(sort, el.prev());
+ as.sort = function sort(id, li){
+ var num = parseFloat(id);
+ var id = $(li).find('.sort').text() || -Infinity;
+ var at = num >= parseFloat(id);
+ return at ? li : sort(id, li.prev());
}
$(document).on('keyup', 'input, textarea, [contenteditable]', as.wait(function(){
var el = $(this);
@@ -147,4 +146,4 @@
;$(function(){
$('.page').not(':first').hide();
$.as.route(location.hash.slice(1));
-});
\ No newline at end of file
+});
diff --git a/axe.js b/axe.js
new file mode 100644
index 00000000..dbcb9c0f
--- /dev/null
+++ b/axe.js
@@ -0,0 +1,193 @@
+;(function(){
+
+ /* UNBUILD */
+ var root;
+ if(typeof window !== "undefined"){ root = window }
+ if(typeof global !== "undefined"){ root = global }
+ root = root || {};
+ var console = root.console || {log: function(){}};
+ function USE(arg, req){
+ return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
+ arg(mod = {exports: {}});
+ USE[R(path)] = mod.exports;
+ }
+ function R(p){
+ return p.split('/').slice(-1).toString().replace('.js','');
+ }
+ }
+ if(typeof module !== "undefined"){ var common = module }
+ /* UNBUILD */
+
+ ;USE(function(module){
+ if(typeof window !== "undefined"){ module.window = window }
+ var tmp = module.window || module;
+ var AXE = tmp.AXE || function(){};
+
+ if(AXE.window = module.window){ try{
+ AXE.window.AXE = AXE;
+ tmp = document.createEvent('CustomEvent');
+ tmp.initCustomEvent('extension', false, false, {type: "AXE"});
+ (window.dispatchEvent || window.fireEvent)(tmp);
+ window.postMessage({type: "AXE"}, '*');
+ } catch(e){} }
+
+ try{ if(typeof common !== "undefined"){ common.exports = AXE } }catch(e){}
+ module.exports = AXE;
+ })(USE, './root');
+
+ ;USE(function(module){
+
+ var AXE = USE('./root'), Gun = (AXE.window||{}).Gun || USE('./gun', 1);
+ (Gun.AXE = AXE).GUN = AXE.Gun = Gun;
+ Gun.on('opt', function(at){
+ if(!at.axe){
+ at.axe = {};
+ var peers = at.opt.peers, tmp;
+ // 1. If any remembered peers or from last cache or extension
+ // 2. Fallback to use hard coded peers from dApp
+ // 3. Or any offered peers.
+ //if(Gun.obj.empty(p)){
+ // Gun.obj.map(['http://localhost:8765/gun'/*, 'https://guntest.herokuapp.com/gun'*/], function(url){
+ // p[url] = {url: url, axe: {}};
+ // });
+ //}
+ // Our current hypothesis is that it is most optimal
+ // to take peers in a common network, and align
+ // them in a line, where you only have left and right
+ // peers, so messages propagate left and right in
+ // a linear manner with reduced overlap, and
+ // with one common superpeer (with ready failovers)
+ // in case the p2p linear latency is high.
+ // Or there could be plenty of other better options.
+ console.log("axe");
+
+ function verify(dht, msg, send, at) {
+ var puts = Object.keys(msg.put);
+ var soul = puts[0]; /// TODO: verify all souls in puts. Copy the msg only with subscribed souls?
+ var subs = dht(soul);
+// console.log('[AXE] VERIFY soul: %s, subs: %s, Peers: %s, msg: ', soul, subs, Object.keys(peers), msg);
+ if (!subs) { return; }
+ var tmp = [];
+ Gun.obj.map(subs.split(','), function(pid) {
+ if (pid in peers) {
+ tmp.push(pid);
+// console.log('[AXE] SEND TO >>>>> ', pid, msg.put.bob || msg.put);
+ send(msg, peers[pid]);
+ }
+ });
+ /// Only connected peers in the tmp array.
+ if (at.on.opt.super) {
+ dht(soul, tmp.join(','));
+ }
+ }
+
+ var Rad = (Gun.window||{}).Radix || USE('./lib/radix', 1);
+ at.opt.dht = Rad();
+ at.on('in', input/*USE('./lib/super', 1)*/, at);
+// at.on('out', function(msg, a) {
+// this.to.next(msg);
+// console.log('[AXE] out:', msg, a);
+// }, at);
+ if(at.opt.super){
+ AXE.say = function(msg, send, at) {
+ if (msg.rtc) {
+// console.log('[AXE] MSG WEBRTC: ', msg.rtc);
+ if (msg.rtc.to) {
+ /// Send announce to one peer only if the msg have 'to' attr
+ var peer = (at.on.opt.peers) ? at.on.opt.peers[msg.rtc.to] : null;
+// if (peer) { at.on.opt.mesh.say(msg, peer); }
+ if (peer) { send(msg, peer); }
+ return;
+ }
+ }
+ if (!msg.put) { send(msg); return; }
+ //console.log('AXE HOOK!! ', msg);
+ verify(at.on.opt.dht, msg, send, at);
+ };
+ } else {
+ AXE.say = function(msg, send, at) {
+ if (msg.rtc) {
+// console.log('[AXE] MSG WEBRTC: ', msg.rtc);
+ }
+ if (!msg.put) { send(msg); return; }
+ verify(at.on.opt.dht, msg, send, at);
+ /// Always send to superpeers?
+ Gun.obj.map(at.on.opt.peers, function(peer) {
+ if (peer.url) {
+// console.log('SEND TO SUPERPEER', msg);
+ send(msg, peer);
+ }
+ });
+ };
+ var connections = 0;
+ at.on('hi', function(opt) {
+ this.to.next(opt);
+ //console.log('AXE PEER [HI]', new Date(), opt);
+ connections++;
+ /// The first connection don't need to resubscribe the nodes.
+ if (connections === 1) { return; }
+ /// Resubscribe all nodes.
+ setTimeout(function() {
+ var souls = Object.keys(at.graph);
+ for (var i=0; i < souls.length; ++i) {
+ //at.gun.get(souls[i]).off();
+ at.next[souls[i]].ack = 0;
+ at.gun.get(souls[i]).once(function(){});
+ }
+ //location.reload();
+ }, 500);
+ }, at);
+ }
+ }
+ this.to.next(at); // make sure to call the "next" middleware adapter.
+ });
+ function joindht(dht, soul, pids) {
+ if (!pids || !soul || !dht) { return; }
+ var subs = dht(soul);
+ var tmp = subs ? subs.split(',') : [];
+ Gun.obj.map(pids.split(','), function(pid) {
+ if (pid && tmp.indexOf(pid) === -1) { tmp.push(pid); }
+ });
+ tmp = tmp.join(',');
+ dht(soul, tmp);
+ return tmp;
+ }
+ function input(msg){
+// console.log('[AXE] input: ', msg);
+ var at = this.as, to = this.to, peer = (msg._||{}).via;
+ var opt = at.opt;
+ var dht = opt.dht;
+ var get = msg.get, soul, key;
+ if(peer && get){
+ if(soul = get['#']){
+ if(key = get['.']){
+
+ } else {
+
+ }
+ if (!peer.id) {console.log('[*** WARN] no peer.id %s', soul);}
+ var pids = joindht(dht, soul, peer.id);
+ if (pids) {
+ var dht = {};
+ dht[soul] = pids;
+ at.opt.mesh.say({dht:dht}, opt.peers[peer.id]);
+ }
+ }
+ }
+ to.next(msg);
+
+ if (opt.rtc && msg.dht) {
+ Gun.obj.map(msg.dht, function(pids, soul) {
+ dht(soul, pids);
+ Gun.obj.map(pids.split(','), function(pid) {
+ /// TODO: here we can put an algorithm of who must connect?
+ if (!pid || pid in opt.peers || pid === opt.pid || opt.announce[pid]) { return; }
+ opt.announce[pid] = true; /// To try only one connection to the same peer.
+ opt.announce(pid);
+ });
+ });
+ }
+ }
+ module.exports = AXE;
+ })(USE, './axe');
+}());
diff --git a/examples/angular/server.js b/examples/angular/server.js
index f1d1c55e..f8a1978b 100644
--- a/examples/angular/server.js
+++ b/examples/angular/server.js
@@ -1,4 +1,4 @@
-var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8080;
+var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765;
var host = process.env.OPENSHIFT_NODEJS_HOST || process.env.VCAP_APP_HOST || process.env.HOST || 'localhost';
var express = require('express');
diff --git a/examples/axe.html b/examples/axe.html
new file mode 100644
index 00000000..5c2caa09
--- /dev/null
+++ b/examples/axe.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ Testing AXE
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/basic/private.html b/examples/basic/private.html
new file mode 100644
index 00000000..24325c8c
--- /dev/null
+++ b/examples/basic/private.html
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Public Key:
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/basic/space.html b/examples/basic/space.html
new file mode 100644
index 00000000..72a7f15e
--- /dev/null
+++ b/examples/basic/space.html
@@ -0,0 +1,50 @@
+
Search
+
+
+
+
+
+
+Note: No data is indexed by default, you need to add some!
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/basic/tables.html b/examples/basic/tables.html
new file mode 100644
index 00000000..dae5a90a
--- /dev/null
+++ b/examples/basic/tables.html
@@ -0,0 +1,130 @@
+
Tables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/user.html b/examples/basic/user.html
similarity index 52%
rename from test/user.html
rename to examples/basic/user.html
index 4837bf66..873d517c 100644
--- a/test/user.html
+++ b/examples/basic/user.html
@@ -5,41 +5,42 @@
+