Browse Source

init original n2o v4.4

221V 1 year ago
commit
f56791f2c9
37 changed files with 1064 additions and 0 deletions
  1. 82 0
      README.md
  2. 11 0
      apps/n2o_sample/README.md
  3. 13 0
      apps/n2o_sample/include/users.hrl
  4. 11 0
      apps/n2o_sample/priv/snippets/lobby/bpmn.flow.htm
  5. 15 0
      apps/n2o_sample/priv/snippets/lobby/bpmn.htm
  6. 1 0
      apps/n2o_sample/priv/snippets/lobby/erlang.processing.htm
  7. 18 0
      apps/n2o_sample/priv/snippets/lobby/erlang.setup.htm
  8. 30 0
      apps/n2o_sample/priv/snippets/lobby/rebol.htm
  9. 18 0
      apps/n2o_sample/priv/snippets/n2o/template.htm
  10. 29 0
      apps/n2o_sample/priv/snippets/n2o/utf8.htm
  11. 24 0
      apps/n2o_sample/priv/static/N2O.svg
  12. 14 0
      apps/n2o_sample/priv/static/S.svg
  13. 22 0
      apps/n2o_sample/priv/static/feed.css
  14. 45 0
      apps/n2o_sample/priv/static/spa/index.htm
  15. 50 0
      apps/n2o_sample/priv/static/spa/login.htm
  16. 62 0
      apps/n2o_sample/priv/static/synrc.css
  17. 26 0
      apps/n2o_sample/priv/templates/dev.html
  18. 47 0
      apps/n2o_sample/priv/templates/doc.html
  19. 37 0
      apps/n2o_sample/priv/templates/index.html
  20. 47 0
      apps/n2o_sample/priv/templates/login.html
  21. 3 0
      apps/n2o_sample/priv/templates/message.html
  22. 10 0
      apps/n2o_sample/rebar.config
  23. 22 0
      apps/n2o_sample/src/config.erl
  24. 53 0
      apps/n2o_sample/src/doc.erl
  25. 82 0
      apps/n2o_sample/src/index.erl
  26. 93 0
      apps/n2o_sample/src/interlogin.erl
  27. 28 0
      apps/n2o_sample/src/login.erl
  28. 9 0
      apps/n2o_sample/src/n2o_sample.app.src
  29. 37 0
      apps/n2o_sample/src/n2o_sample.erl
  30. 31 0
      apps/n2o_sample/src/routes.erl
  31. 15 0
      apps/n2o_sample/src/users.erl
  32. 3 0
      apps/rebar.config
  33. BIN
      mad
  34. 18 0
      rebar.config
  35. 46 0
      sys.config
  36. 7 0
      vm.args
  37. 5 0
      xen.config

+ 82 - 0
README.md

@@ -0,0 +1,82 @@
+N2O: Erlang Web Framework on WebSockets
+=======================================
+
+![ScreenShot](http://synrc.com/images/n2o_sample_screen.png)
+
+Samples
+-------
+
+Samples provided as Erlang release packaged
+with *web* Erlang application which contains modules:
+
+* REST samples
+* N2O samples
+* XEN support
+
+Prerequisites
+-------------
+
+* erlang
+* mad
+* inotify-tools (Linux, for filesystem watching)
+* uglify (assets)
+
+Run
+---
+
+To run just perform on Windows, Linux and Mac
+
+    $ ./mad deps compile plan repl
+
+On BSD you should use gmake
+
+And open it in browser [http://localhost:8000](http://localhost:8000)
+If you want to try pure Single Page Application (SPA) wich
+connects to Erlang N2O Application Server you should use
+[http://localhost:8000/static/spa/spa.htm](http://localhost:8000/static/spa/spa.htm)
+
+For full features of make please refer to [https://github.com/synrc/otp.mk](https://github.com/synrc/otp.mk)
+
+Production Assets
+-----------------
+
+    $ ./mad static min
+    > application:set_env(n2o,mode,prod).
+
+Xen
+---
+
+To run on Xen is a bit tricky:
+
+    $ sudo apt-get install xen-hypervisor-amd64
+    $ echo XENTOOLSTACK=xl > /etc/default/xen
+
+Boot into Xen 4.2 Domain-0 and create network bridge:
+
+    $ sudo brctl addbr docker0
+    $ sudo ip addr add 172.16.42.1/24 dev docker0
+
+Compile Image at Erlang on Xen builder:
+
+    $ rebar get-deps compile
+    $ ./nitrogen_static.sh
+    $ rebar ling-build-image
+    $ sudo xl create -c xen.config
+
+Inside Ling start n2o_sample application:
+
+    Ling 0.2.2 is here
+    Started in 49438 us
+    Erlang [ling-0.2.2]
+
+    Eshell V5.10.2  (abort with ^G)
+    1> application:start(n2o_sample).
+
+And open it in browser [http://172.16.42.108:8000](http://172.16.42.108:8000)
+
+Credits
+-------
+
+* Maxim Sokhatsky
+
+OM A HUM

+ 11 - 0
apps/n2o_sample/README.md

@@ -0,0 +1,11 @@
+Simple Review Application
+=========================
+
+Just leave a comment to a published file 
+or to a realm anonymously or on behalf.
+Create you own realms and files. 
+Discuss and Review with other users realtime.
+
+Credits
+-------
+* Brought to you by 5HT

+ 13 - 0
apps/n2o_sample/include/users.hrl

@@ -0,0 +1,13 @@
+-record(user, {id, name, email, proplist = [{facebook, udefined},
+                                            {github, "github.com/b0oh"},
+                                            {local, undefined},
+                                            {twitter, udefined}],
+               string = "common",
+               number = 12,
+               list_of_strings = ["one", "two", "three"],
+               list_of_numbers = [34958726345, 12],
+               nested_proplists = [{nested, [{number, 12},
+                                             {string, "common"},
+                                             {list_of_strings, ["one", "two", "three"]},
+                                             {list_of_atoms, [one, two, three]},
+                                             {list_of_numbers, [100000, 2,3 ]}]}]}).

+ 11 - 0
apps/n2o_sample/priv/snippets/lobby/bpmn.flow.htm

@@ -0,0 +1,11 @@
+<code>
+bpe:start(
+   #process{name="Order11",
+       flows=[ #sequenceFlow{source="begin",target="end2"},
+               #sequenceFlow{source="end2",target="end"}],
+       tasks=[ #userTask{name="begin"},
+               #userTask{name="end2"},
+               #endEvent{name="end"}],
+       task="begin",beginEvent="begin",endEvent="end"},[]).
+       
+</code>       

+ 15 - 0
apps/n2o_sample/priv/snippets/lobby/bpmn.htm

@@ -0,0 +1,15 @@
+<code>
+-record(task,         { name, id, roles, module }).
+-record(userTask,     { name, id, roles, module }).
+-record(serviceTask,  { name, id, roles, module }).
+-record(messageEvent, { name, id, payload }).
+-record(beginEvent ,   { name, id }).
+-record(endEvent,      { name, id }).
+-record(sequenceFlow, { name, id, source, target }).
+-record(history,      { ?ITERATOR(feed,true), name, task }).
+-record(process,      { ?ITERATOR(feed,true), name,
+                        roles=[], tasks=[], events=[], history=[], flows=[],
+                        rules, docs=[],
+                        task,
+                        beginEvent, endEvent }).
+</code>                        

+ 1 - 0
apps/n2o_sample/priv/snippets/lobby/erlang.processing.htm

@@ -0,0 +1 @@
+<img src="https://d324imu86q1bqn.cloudfront.net/uploads/asset/attachment/549899/optimized.jpg" width=600>

+ 18 - 0
apps/n2o_sample/priv/snippets/lobby/erlang.setup.htm

@@ -0,0 +1,18 @@
+<code>
+Erlang 6.2 
+msys2.github.com
+font14
+pacman -S make
+pacman -S git
+git clone https://github.com/synrc/skyline
+git clone https://github.com/synrc/mad
+cp mad/mad web 
+cd web
+./mad deps compile plan repl
+> ^C
+./mad bundle web_app
+cp web_app /install
+. /install/web_app
+>
+
+</code>

+ 30 - 0
apps/n2o_sample/priv/snippets/lobby/rebol.htm

@@ -0,0 +1,30 @@
+<h1> REBOL/View 2.7</h1>
+
+<code>
+
+REBOL [] view layout [ h2 "Demo" area btn "Click Me" ]
+
+the-form: layout [
+across space 2x8
+style label vtext bold 100x24 middle right
+style bar box 306x3 edge [size: 1x1 color: water effect: 'bevel]
+backcolor water bar return
+
+    label "Full Name"     f1: field 200 return
+    pad 120 c1: check vtext "Programmer" bold return
+    pad 120 c2: check vtext "Operator" bold return
+    label "Email Address" f2: field return
+    label "Phone Number"  f3: field return
+    label "Your Comments" f4: area wrap 200x100 return
+
+    bar return
+    pad 40 space 100
+    btn-enter 60 "Submit" [
+        unview/only the-form
+        show-results
+    ]
+    btn-cancel 60 "Close" [unview/only the-form]
+]
+the-form/effect: [gradient 0x1]
+
+</code>

+ 18 - 0
apps/n2o_sample/priv/snippets/n2o/template.htm

@@ -0,0 +1,18 @@
+<code>function template(html, data) { // template("{this.name}",{name:"Maxim"})
+    var re = /{([^}]+)?}/g, code = 'var r=[];', cursor = 0;
+    var add = function(line,js) {
+        js? (code += 'r.push(' + line + ');') :
+            (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");' : ''); // "
+        return add; }
+    while(match = re.exec(html)) {
+        add(html.slice(cursor, match.index))(match[1],true);
+        cursor = match.index + match[0].length; }
+    add(html.substr(cursor, html.length - cursor));
+    code += 'return r.join("");';
+    return new Function(code.replace(/[\r\t\n]/g, '')).apply(data); }
+
+function xml(html) { return new DOMParser().parseFromString(html, "application/xhtml+xml").firstChild; }
+function dom(html) {
+    var dom =  new DOMParser().parseFromString(html, "text/html")
+              .firstChild.getElementsByTagName("body")[0].firstChild; return dom; }
+</code>              

+ 29 - 0
apps/n2o_sample/priv/snippets/n2o/utf8.htm

@@ -0,0 +1,29 @@
+<h1>UTF-8</h1>
+
+<h2>Erlang</h2>
+	
+The main thing you should know about Erlang unicode is that
+<code>
+1> unicode:characters_to_binary("UniText") == <<"UniText"/utf8>>.
+</code>
+I.e. in N2O DSL you should use:
+<code>
+2> io:format("~tp",[ #button{body= <<"Unicode Name"/utf8>>} ]).
+</code>
+
+<h2>JavaScript</h2>
+Whenever you want to send to server the value from DOM element you should use utf8_toByteArray.
+
+<code>    
+> utf_toByteArray(document.getElementById('phone').value);
+</code>
+<p>However we created shortcut for that purposes which knows about radio, fieldset and other types of DOM nodes. So you should use just:</p>
+<code>
+> querySource('phone');
+</code>
+<p>querySource JavaScript function ships in nitrogen.js which is part of N2O JavaScript library.
+Whenever you get unicode data from server you should prepare it before place in DOM with utf8_decode:</p>
+<code>    
+> console.log(utf8_decode(receivedMessage));
+</code>
+    

+ 24 - 0
apps/n2o_sample/priv/static/N2O.svg

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="451px" height="567px" viewBox="0 0 451 567" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+    <!-- Generator: Sketch 3.0.4 (8054) - http://www.bohemiancoding.com/sketch -->
+    <title>Scene</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="N2O" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+        <g id="Scene" sketch:type="MSLayerGroup">
+            <rect id="Base" fill="#4990E2" sketch:type="MSShapeGroup" x="0" y="0" width="451" height="567"></rect>
+            <text id="N2O-2" sketch:type="MSTextLayer" font-family="Open Sans" font-size="130" font-weight="bold" letter-spacing="-1.10000014" fill="#FFFFFF">
+                <tspan x="85" y="184">N2O</tspan>
+            </text>
+            <text id="Web-Stack" sketch:type="MSTextLayer" font-family="Open Sans" font-size="48" font-weight="bold" fill="#FFFFFF">
+                <tspan x="101" y="477">Web Stack</tspan>
+            </text>
+            <g id="nitroxyde" transform="translate(95.000000, 222.000000)" stroke="#FFFFFF" stroke-width="10" sketch:type="MSShapeGroup">
+                <circle id="O" fill="#D0011B" cx="195" cy="65" r="65"></circle>
+                <circle id="N2" fill="#163D6B" cx="130" cy="65" r="65"></circle>
+                <circle id="N1" fill="#163D6B" cx="65" cy="65" r="65"></circle>
+            </g>
+            <rect id="Rectangle-2" fill="#FFFFFF" sketch:type="MSShapeGroup" x="94" y="393" width="264" height="18"></rect>
+        </g>
+    </g>
+</svg>

+ 14 - 0
apps/n2o_sample/priv/static/S.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="159px" height="155px" viewBox="0 0 159 155" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+    <!-- Generator: Sketch 3.1.1 (8761) - http://www.bohemiancoding.com/sketch -->
+    <title>g20</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+        <g id="g14" sketch:type="MSLayerGroup" transform="translate(331.250000, 254.093750) scale(1, -1) translate(-331.250000, -254.093750) translate(1.250000, 0.593750)" fill="#4990E2">
+            <g id="g20" transform="translate(-0.328375, 353.000000)" sketch:type="MSShapeGroup">
+                <path d="M55,1.25 L56.21875,9.81625 C56.62375,12.4575 56.87,15.1225 56.95125,17.81 C57.03,20.49625 57.115,26.1475 57.19625,34.765 L58.3275,35.9125 L63.74875,35.9125 L64.88125,34.77 C65.0525,27.645 65.48125,21.54375 66.17875,16.45375 C68.855,12.47 73.475,9.2275 80.04,6.72875 C86.605,4.22375 93.0775,2.97625 99.47,2.97625 C108.625,2.97625 115.945,5.4125 121.43,10.29625 C126.9125,15.17375 129.6575,20.995 129.6575,27.76 C129.6575,31.44125 128.66875,34.6275 126.695,37.32625 C124.71625,40.02 121.73875,42.24375 117.745,44 C113.755,45.755 106.6125,47.83 96.315,50.23375 C87.47375,52.285 81.2925,53.89125 77.77625,55.0475 C74.2525,56.2025 70.86125,58.14625 67.6025,60.88625 C64.34375,63.625 61.85,66.9875 60.13375,70.96625 C58.41875,74.94625 57.5625,79.3325 57.5625,84.13 C57.5625,95.5725 62.11875,104.7325 71.23375,111.60625 C80.34875,118.48 91.71625,121.91625 105.32625,121.91625 C111.05625,121.91625 117.30625,121.12625 124.07125,119.555 C130.83,117.9825 135.97,116.4725 139.48125,115.03125 L140.63625,113.2475 C139.8525,109.845 139.36625,100.91875 139.1725,86.47 L137.9775,85.32 L132.6825,85.32 L131.48625,86.47 C131.14375,91.66125 130.675,95.2975 130.08,97.385 C129.485,99.46625 127.9525,101.725 125.48875,104.14875 C123.01875,106.575 119.53,108.61625 115.025,110.27375 C110.5175,111.9325 105.755,112.7675 100.74125,112.7675 C95.5475,112.7675 91.19,111.995 87.6625,110.4575 C84.12875,108.9125 81.28,106.58 79.11375,103.45875 C76.94125,100.33625 75.86,96.54375 75.86,92.09625 C75.86,88.84125 76.52375,85.93125 77.855,83.36375 C79.1825,80.79125 81.22375,78.715 83.96875,77.13 C86.7125,75.5475 89.58375,74.41375 92.585,73.73375 L106.6125,70.1375 C118.62125,67.22125 127.215,64.69375 132.4075,62.555 C137.6,60.41625 141.6075,57.185 144.43875,52.86375 C146.9375,49.04875 148.2675,44.47375 148.5625,39.225 C154.1025,50.0125 157.24875,62.22875 157.24875,75.1925 C157.24875,118.73375 121.95,154.03 78.41125,154.03 C34.86,154.03 -0.43375,118.73375 -0.43375,75.1925 C-0.43375,39.5725 22.41,9.73 54.8325,-0.05 L55,1.25 L55,1.25 Z" id="path22"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 22 - 0
apps/n2o_sample/priv/static/feed.css

@@ -0,0 +1,22 @@
+
+// Feed UI styles
+
+.fd-label{}
+
+.fd-table{}
+.fd-tbody{}
+.fd-body{}
+
+.fd-traverse-ctl{}
+.fd-sel-toolbar{}
+
+.fd-alert{}
+.fd-entry-sel{}
+.fd-btn-delete{}
+.fd-trash{}
+.fd-btn-prev{}
+.fd-btn-next{}
+.fd-chevron-right{}
+.fd-checkbox{}
+
+.text-warning{}

+ 45 - 0
apps/n2o_sample/priv/static/spa/index.htm

@@ -0,0 +1,45 @@
+<html>
+    <head>
+        <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+        <link href='/static/synrc.css' type='text/css' rel='stylesheet'>
+        <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
+        <title>Chat</title>
+    </head>
+    <body>
+        <table cellpadding='20' align='center'>
+            <tr>
+                <td valign='top' align='center' height='230' width='300'>
+                    <br><img src='/static/S.svg' border='0' height='200' style='margin-top:0px;'><br>
+                </td>
+                <td colspan='2' width='700' valign='top'>
+                    <h1><b id='heading'>Roster</b></h1>
+                    <h2>Unique Feed<br><button id='logout'></button></h2>
+                </td>
+            </tr>
+            <tr>
+                <td width='300' valign='top'>
+                    <p>Just type what you think about this:</p>
+                    <textarea id='message' style='margin-left:5px; width:490px; font-size:16pt;'
+                      value='' rows='5' autofocus></textarea>
+                    <div id='upload'></div>
+                    <div id='history'></div>
+                    <button id=send>Send</body>
+                </td>
+            </tr>
+        </table>
+        <script>var transition = {pid: '', host: 'localhost', port:'8000'};</script>
+        <script src='/n2o/protocols/bert.js'></script>
+        <script src='/n2o/protocols/binary.js'></script>
+        <script src='/n2o/protocols/client.js'></script>
+        <script src='/n2o/protocols/nitrogen.js'></script>
+        <script src='/n2o/bullet.js'></script>
+        <script src='/n2o/xhr.js'></script>
+        <script src='/n2o/utf8.js'></script>
+        <script src='/n2o/template.js'></script>
+        <script src='/n2o/n2o.js'></script>
+        <script src='/n2o/validation.js'></script>
+        <script src='/n2o/ftp.js'></script>
+        <!--script src='https://synrc.com/hi.js'></script-->
+        <script>protos = [$client,$bert]; N2O_start();</script>
+    </body>
+</html>

+ 50 - 0
apps/n2o_sample/priv/static/spa/login.htm

@@ -0,0 +1,50 @@
+<html>
+    <head>
+        <meta name='viewport' content='initial-scale=0.5'>
+        <link href='/static/synrc.css' type='text/css' rel='stylesheet'>
+        <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
+        <title>Login</title>
+    </head>
+    <body>
+
+        <table cellpadding='20' align='center'>
+            <tr>
+                <td valign='top' align='center' height='230' width='300'>
+                    <img src='/static/S.svg' border='0' height='200' style='margin-top:0px;'><br>
+                </td>
+                <td colspan='2' width='700' valign='top'>
+                    <h1><b>N2O</b></h1>
+                    <h2>Simple Review Application</h2>
+                </td>
+            </tr>
+            <tr>
+                <td width='300' valign='top'>
+                    <p>List of spawned feeds:</p>
+                    <div id='history' class='feed'></div><br><br>
+                </td>
+                <td colspan='2' width='700' valign='top' height='550' bgcolor='#eeeeee'>
+                    <h1>Anyname Login</h1>
+                    <span id="display"></span><br>
+                    <span>Login: </span>
+                    <input id="user" type="text" autofocus="true"><br>
+                    <span>Join/Create Feed: </span>
+                    <input id="pass" type="text">
+                    <button id="loginButton" type="button">Login</button>
+                </td>
+                </td>
+            </tr>
+        </table>
+        <script>var transition = {pid: '', host: 'localhost', port:'8000'};</script>
+        <script src='/n2o/protocols/bert.js'></script>
+        <script src='/n2o/protocols/binary.js'></script>
+        <script src='/n2o/protocols/client.js'></script>
+        <script src='/n2o/protocols/nitrogen.js'></script>
+        <script src='/n2o/bullet.js'></script>
+        <script src='/n2o/xhr.js'></script>
+        <script src='/n2o/utf8.js'></script>
+        <script src='/n2o/template.js'></script>
+        <script src='/n2o/n2o.js'></script>
+        <script src='/n2o/validation.js'></script>
+        <script>protos = [$client,$bert]; N2O_start();</script>
+    </body>
+</html>

+ 62 - 0
apps/n2o_sample/priv/static/synrc.css

@@ -0,0 +1,62 @@
+A { font-size:18pt; }
+A:link { color: blue; }
+A:visited { color: darkblue; }
+A:hover { color: blue; }
+SUP { font-size:10pt; }
+html { zoom: 0.8; }
+body { font-size:14pt; font-family: Lato, sans-serif; font-weight:300;}
+TD { font-size:18pt; margin: 0 auto; padding-right: 20px; }
+textarea { font-family: "Lucida Console", Monaco, monospace; padding: 10px; }
+input { font-size:28pt; width: 50%; margin:15px 15px 5px 5px; }
+button { font-size:20pt; margin-top:15px; padding: 10px; }
+H1 { color: blue; font-weight: bold; font-size:26pt; margin-top:20px; margin-bottom:10px; margin-right:6px; }
+H2 { color: darkblue; font-size:18pt; margin-top:20px; margin-bottom:10px; margin-right:6px; }
+H3 { font-size:14pt; margin-top:20px; margin-bottom:10px; margin-right:6px; } 
+P { font-size:18pt; margin-top: 0px; margin-bottom: 8px; }
+#frame { width: 700px; height: 1000px; border: 1px solid black; }
+.poem { font-size:14pt; margin-top: 0px; margin-bottom: 8px; white-space: pre;}
+LI { font-size:12pt; }
+pre { font-size:10pt; font-family: Calibri, Lucida Console; }
+.small_infoblock { font-family: Calibri, Lucida Sans Unicode; font-size:8pt; }
+.block  { background-color: #EEEEEE; padding-top:6;padding-bottom:10;padding-right:10;padding-left:10;}
+.threecol { float:left; }
+.left { float:left; }
+.hints { width:59px;float:left;margin-right:6px; }
+.main { width:843px;float:left;margin-right:26px; }
+.contents { width:270px;float:left; }
+.numbox { padding:10px 10px 10px 10px;background-color:black;color:white; }
+.feed { margin-top:20px; }
+
+code, div.lstlisting { font-size:14pt; margin: 20px 20px 20px 0px;
+                        padding: 0px 20px 20px 20px; font-family: monospace;
+                        white-space: pre; background-color: white; display: inline-block;
+                         border-left:60px solid #afafaf; }
+code, div.lstlisting .keyword              { font-weight: bold }
+code, div.lstlisting .string, code .regexp { color: green }
+code, div.lstlisting .class { color: darkblue }
+code, div.lstlisting .record { color: purple }
+code, div.lstlisting .special { color: royalblue }
+code, div.lstlisting .number               { color: pink }
+code, div.lstlisting .comment              { color: grey }
+
+
+/* seahawks
+ #03263a - college navy
+ #90918c - wolf gray
+ #4ea701 - action green
+ #ffffff - white
+ #36578c - blue
+*/
+.center{text-align: center;}
+.main{ width:100%;z-index:2;background: #ffffff;}
+.section{ border-bottom: 1px solid lightgray;}
+.section-header{font-weight:300;}
+.content{ margin-right:auto;margin-left:auto; max-width:1024px;padding: 1em 2em;}
+.header{ height:2.2em; }
+.profile-pic{padding:0 24px 0 24px;}
+.profile-pic img{width:2.2em;height: 2.2em;border-radius:2em;}
+.footer{text-align:center;color:90918c}
+.menu{display: flex;}
+.menu .pure-menu-heading{height:2em;line-height:2em;padding:0.1em 24px;display:flex;}
+.pure-button-group .google-button{display:inline-block;}
+.pure-button-group .avz-button{font-size:125%;color:#36578c;margin: 0 5px 0 5px;border-bottom:1px solid #90918c;}

+ 26 - 0
apps/n2o_sample/priv/templates/dev.html

@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta name='viewport'  content="width=device-width, initial-scale=1.0">
+  <link href='http://fonts.googleapis.com/css?family=Lato:300'    rel='stylesheet' type='text/css'/>
+  <link href="https://unpkg.com/purecss@0.6.2/build/pure-min.css" rel="stylesheet" type='text/css'/>
+  <link href='/static/synrc.css'  rel='stylesheet' type='text/css'/>
+  <link href='/static/feed.css'   rel='stylesheet' type='text/css'/>
+  <title>{{title}}</title>
+</head>
+<body>
+  {{body}}
+  <script>{{script}}</script>
+  <script src='/n2o/protocols/bert.js'></script>
+  <script src='/n2o/protocols/client.js'></script>
+  <script src='/n2o/protocols/nitrogen.js'></script>
+  <script src='/n2o/bullet.js'></script>
+  <script src='/n2o/xhr.js'></script>
+  <script src='/n2o/utf8.js'></script>
+  <script src='/n2o/template.js'></script>
+  <script src='/n2o/n2o.js'></script>
+  <script src='/n2o/validation.js'></script>
+  <script src='/n2o/ftp.js'></script>
+  <script>protos = [$client,$bert]; N2O_start();</script>
+</body>
+</html>

+ 47 - 0
apps/n2o_sample/priv/templates/doc.html

@@ -0,0 +1,47 @@
+<html>
+    <head>
+        <meta name='viewport' content='initial-scale=0.5'>
+        <link href='/static/synrc.css' type='text/css' rel='stylesheet'>
+        <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
+        <title>Login</title>
+    </head>
+    <body>
+
+        <table cellpadding='20' align='center'>
+            <tr>
+                <td valign='top' align='center' height='230' width='300'>
+                    <a href="/"><img src='/static/S.svg' border='0' height='200' style='margin-top:0px;'></a><br>
+                </td>
+                <td colspan='2' width='700' valign='top'>
+                    <h1><b>N2O</b></h1>
+                    <h2>Simple Review Application</h2>
+                </td>
+            </tr>
+            <tr>
+                <td width='300' valign='top'>
+                    <p>List of spawned feeds:</p>
+                    <div id='history' class='feed'></div><br><br>
+                    <p>List of inhabited realms:</p>
+                    <div class='feed'>
+                        {{folders}}
+                    </div>
+                </td>
+                <td colspan='2' width='700' valign='top' height='550' bgcolor='#eeeeee'>
+                    <h1>Anyname Login</h1>
+                    {{body}}
+                </td>
+            </tr>
+        </table>
+        <script>{{script}}</script>
+        <script src='/n2o/protocols/bert.js'></script>
+        <script src='/n2o/protocols/client.js'></script>
+        <script src='/n2o/protocols/nitrogen.js'></script>
+        <script src='/n2o/bullet.js'></script>
+        <script src='/n2o/xhr.js'></script>
+        <script src='/n2o/utf8.js'></script>
+        <script src='/n2o/template.js'></script>
+        <script src='/n2o/n2o.js'></script>
+        <script src='/n2o/validation.js'></script>
+        <script>protos = [$client,$bert]; N2O_start();</script>
+    </body>
+</html>

+ 37 - 0
apps/n2o_sample/priv/templates/index.html

@@ -0,0 +1,37 @@
+<html>
+    <head>
+        <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+        <link href='/static/synrc.css' type='text/css' rel='stylesheet'>
+        <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
+        <title>Chat</title>
+    </head>
+    <body>
+        <table cellpadding='20' align='center'>
+            <tr>
+                <td valign='top' align='center' height='230' width='300'>
+                    <br><a href="/doc"><img src='/static/S.svg' border='0' height='200' style='margin-top:0px;'></a><br>
+                </td>
+                <td colspan='2' width='700' valign='top'>
+                    <h1><b id='heading'>Roster</b></h1>
+                    <h2>Unique Feed<br><button id='logout'></button></h2>
+                </td>
+            </tr>
+            <tr>
+                <td width='300' valign='top'>
+                    <p>Just type what you think about this:</p>
+                    <textarea id='message' style='margin-left:5px; width:490px; font-size:16pt;' 
+          value='' rows='5' autofocus></textarea>
+                    {{body}}
+                    <div id='history'></div>
+                </td>
+                <td colspan='2' width='700' valign='top' height='550' bgcolor='#eeeeee'>
+                    {{list}}
+                </td>
+            </tr>
+        </table>
+        <!--script>var transition = {pid: '', host: 'localhost', port:'8000'};</script-->
+        <script>{{script}}</script>
+        {{javascript}}
+        <script>protos = [$bert]; N2O_start();</script>
+    </body>
+</html>

+ 47 - 0
apps/n2o_sample/priv/templates/login.html

@@ -0,0 +1,47 @@
+<html>
+    <head>
+        <meta name='viewport' content='initial-scale=0.5'>
+        <link href='/static/synrc.css' type='text/css' rel='stylesheet'>
+        <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
+        <title>Login</title>
+    </head>
+    <body>
+
+        <table cellpadding='20' align='center'>
+            <tr>
+                <td valign='top' align='center' height='230' width='300'>
+                    <a href="/doc"><img src='/static/S.svg' border='0' height='200' style='margin-top:0px;'></a><br>
+                </td>
+                <td colspan='2' width='700' valign='top'>
+                    <h1><b>N2O</b></h1>
+                    <h2>Simple Review Application</h2>
+                </td>
+            </tr>
+            <tr>
+                <td width='300' valign='top'>
+                    <p>List of spawned feeds:</p>
+                    <div id='history' class='feed'></div><br><br>
+                    <p>List of inhabited realms:</p>
+                    <div class='feed'>
+                        {{folders}}
+                    </div>
+                </td>
+                <td colspan='2' width='700' valign='top' height='550' bgcolor='#eeeeee'>
+                    <h1>Anyname Login</h1>
+                    {{body}}
+                </td>
+            </tr>
+        </table>
+        <script>{{script}}</script>
+        <script src='/n2o/protocols/bert.js'></script>
+        <script src='/n2o/protocols/client.js'></script>
+        <script src='/n2o/protocols/nitrogen.js'></script>
+        <script src='/n2o/bullet.js'></script>
+        <script src='/n2o/xhr.js'></script>
+        <script src='/n2o/utf8.js'></script>
+        <script src='/n2o/template.js'></script>
+        <script src='/n2o/n2o.js'></script>
+        <script src='/n2o/validation.js'></script>
+        <script>protos = [$client,$bert]; N2O_start();</script>
+    </body>
+</html>

+ 3 - 0
apps/n2o_sample/priv/templates/message.html

@@ -0,0 +1,3 @@
+<table width="500" cellpadding="20" cellspacing="3">
+<tr><td bgcolor="{{color}}" style='color:white;'><b>{{user}}</b>: {{message}}</td></tr>
+</table>

+ 10 - 0
apps/n2o_sample/rebar.config

@@ -0,0 +1,10 @@
+{deps_dir, ["../../deps"]}.
+{lib_dirs, ["../../apps"]}.
+{deps, []}.
+{erlydtl_opts, [
+    {doc_root,   "priv/templates"},
+    {out_dir,    "ebin"},
+   {compiler_options, [report, return, debug_info]},
+    {source_ext, ".html"},
+    {module_ext, "_view"}
+]}.

+ 22 - 0
apps/n2o_sample/src/config.erl

@@ -0,0 +1,22 @@
+-module(config).
+-compile(export_all).
+
+log_level() -> info.
+log_modules() -> % any
+  [
+    login,
+%    wf_convert,
+%    n2o_file,
+    n2o_async,
+    n2o_proto,
+%    n2o_client,
+%    n2o_static,
+    n2o_stream,
+    n2o_nitrogen,
+    n2o_session,
+    doc,
+    kvs,
+    store_mnesia,
+    index2,
+    index
+  ].

+ 53 - 0
apps/n2o_sample/src/doc.erl

@@ -0,0 +1,53 @@
+-module(doc).
+-compile(export_all).
+-include_lib("kvs/include/feed.hrl").
+-include_lib("nitro/include/nitro.hrl").
+-include_lib("n2o/include/wf.hrl").
+
+main() -> #dtl{file="doc", app=n2o_sample, bindings=[{body, body()}]}.
+
+body() ->
+  case wf:user() of
+    undefined -> wf:user("anonymous");
+    _ -> skip
+  end,
+  [#h2     { body = "Docs search" },
+   #textbox{ id   = query },
+   #button { body = "Search", postback=search, source=[query]},
+   #panel  { id   = results }].
+
+event({client, Panel}) -> wf:insert_top(results, Panel);
+event(search) ->
+  wf:update(results, #panel{id=results}),
+  Pid = self(),
+  Query = wf:q(query),
+  spawn(fun() -> search(Pid, Query) end),
+  ok;
+event(_) -> [].
+
+sections(Path,Match,Pid)  ->
+  Page = filename:basename(Path),
+  App = lists:nth(4, lists:reverse(filename:split(Path))),
+  Forms=#panel{body=[
+    #h5{body=filename:join([App, filename:basename(Page, ".htm")])},
+    [ begin
+      Url = ["index.htm?code=",
+             wf:pickle(iolist_to_binary([wf:to_binary(App), "/doc/web/", Page, $#, Sec])) ],
+      #panel{body = #link{body=T, href=Url}}
+    end || [Sec, T] <- Match]]},
+  Pid ! {client, Forms}.
+
+
+re(Q) -> <<"(?:<h\\d[^>]*?\\ id=[\'\"](sec\\d{1,3})[\'\"][^>]*?>(.*?)<\\/h\\d>.*?)+", Q/binary, "[^>]+<">>.
+
+search(Pid,Q) ->
+  lists:map(fun(Path) ->
+    spawn(fun() ->
+      {ok,Bin} = file:read_file(Path),
+      case re:run(Bin, re(Q), [unicode, global, {capture, [1, 2], binary}, dotall, caseless]) of
+        {match, Match} -> sections(Path, Match, Pid);
+        nomatch -> []
+      end
+    end)
+  end, filelib:wildcard(application:get_env(n2o, search, "/var/www/sites/synrc.com/apps/*/doc/web/*.htm")) ).
+

+ 82 - 0
apps/n2o_sample/src/index.erl

@@ -0,0 +1,82 @@
+-module(index).
+-compile(export_all).
+-include_lib("kvs/include/entry.hrl").
+-include_lib("nitro/include/nitro.hrl").
+-include_lib("n2o/include/wf.hrl").
+
+main() ->
+  case wf:user() of
+    undefined ->
+      wf:redirect("login.htm"),
+      redirect_wait();
+    _ ->
+      #dtl{file = "index", app = n2o_sample, bindings = [{body, body()}, {list, list()}, {javascript, (?MODULE:(wf:config(n2o, mode, dev)))()}]}
+  end.
+
+prod() ->   [ #script{src="/static/n2o_sample.min.js"} ].
+dev()  -> [ [ #script{src=lists:concat(["/n2o/protocols/",X,".js"])} || X <- [bert, nitrogen] ],
+            [ #script{src=lists:concat(["/n2o/",Y,".js"])}           || Y <- [bullet, n2o, ftp, utf8, validation] ] ].
+
+redirect_wait() -> #dtl{}.
+list() -> "<iframe src=http://synrc.com/apps/" ++ code() ++ " frameborder=0 width=700 height=1250></iframe>".
+code() ->
+  case wf:q(<<"code">>) of
+    undefined -> "../privacy.htm";
+    Code -> wf:to_list(wf:depickle(Code))
+  end.
+
+
+body() ->
+  wf:update(heading,  #b{id=heading, body="Review: " ++ code()}),
+  wf:update(logout,   #button{id=logout, body="Logout " ++ wf:user(), postback=logout}),
+  [ #span{id=upload}, #button{id=send, body= <<"Chat">>, postback=chat, source=[message] } ].
+
+event(init) ->
+  Room = code(),
+  wf:update(upload, #upload{id=upload}),
+  wf:reg(n2o_session:session_id()),
+  wf:reg({topic, Room}),
+  Res = wf:async("looper", fun index:loop/1),
+  n2o_async:send("looper", "waterline"),
+  wf:info(?MODULE, "Async Process Created: ~p at Page Pid ~p~n", [Res, self()]),
+  [ event({client, {E#entry.from, E#entry.media}}) || E <- kvs:entries(kvs:get(feed, {room, Room}), entry, 10) ];
+
+event(logout) ->
+  wf:logout(),
+  wf:redirect("login.htm");
+
+event(chat) ->
+  User = wf:user(),
+  Message = wf:q(message),
+  wf:info(?MODULE, "Chat pressed: ~p~n", [Message]),
+  Room = code(),
+  kvs:add(#entry{id=kvs:next_id("entry", 1), from=wf:user(), feed_id={room, Room}, media=Message}),
+  wf:send({topic, Room}, #client{data={User, Message}});
+
+event(#client{data={User, Message}}) ->
+  wf:wire(#jq{target=message, method=[focus, select]}),
+  HTML = wf:to_list(Message),
+  wf:info(?MODULE, "HTML: ~tp~n", [HTML]),
+  DTL = #dtl{file="message", app=n2o_sample, bindings=[{user, User}, {color, "gray"}, {message, HTML}]},
+  wf:insert_top(history, wf:jse(wf:render(DTL)));
+
+event(#bin{data=Data}) ->
+  wf:info(?MODULE, "Binary Delivered ~p~n", [Data]),
+  #bin{data = "SERVER"};
+
+event(#ftp{sid=Sid, filename=Filename, status={event, stop}}=Data) ->
+  wf:info(?MODULE, "FTP Delivered ~p~n", [Data]),
+  Name = hd(lists:reverse(string:tokens(wf:to_list(Filename), "/"))),
+  erlang:put(message, wf:render(#link{href=iolist_to_binary(["/static/", Sid, "/", wf:url_encode(Name)]), body=Name})),
+  wf:info(?MODULE, "Message ~p~n", [wf:q(message)]),
+  event(chat);
+
+event(Event) ->
+  wf:info(?MODULE,"Event: ~p", [Event]),
+  ok.
+
+loop(M) ->
+  DTL = #dtl{file="message", app=n2o_sample, bindings=[{user, "system"}, {message, M}, {color, "silver"}]},
+  wf:insert_top(history, wf:jse(wf:render(DTL))),
+  wf:flush().
+

+ 93 - 0
apps/n2o_sample/src/interlogin.erl

@@ -0,0 +1,93 @@
+-module(interlogin).
+-compile(export_all).
+-include_lib("nitro/include/nitro.hrl").
+-include_lib("n2o/include/wf.hrl").
+-include_lib("kvs/include/user.hrl").
+-include_lib("avz/include/avz.hrl").
+-include_lib("kvs/include/user.hrl").
+
+-define(LOGIN, [facebook, twitter, google, github, microsoft]).
+
+main() ->
+ avz:callbacks(?LOGIN),
+ #dtl{file="dev", app=n2o_sample, bindings=[{title, <<"Login">>}, {body, body()}, {folders, folders()}]}.
+folders() -> string:join([filename:basename(F) || F <- filelib:wildcard(code:priv_dir(n2o_sample) ++ "/snippets/*/")], ",").
+
+body() ->
+  header() ++
+  [#panel{class=main, body=[
+     #panel{class=section, body=[
+       #panel{class=[content,center], body=[
+         #span{ id=display },
+         #link{href="/", body=[#image{src="/static/S.svg", style="margin-top:0px;"}]},
+         #h1{body= <<"Sign In/Up">>},
+         #h2{body= <<"Select provider to enter through">>},
+         #br{},
+         #panel{class=["pure-button-group"], role=group, body=[
+           avz:buttons(?LOGIN)
+         ]}
+       ]}
+     ]},
+     footer()
+  ]} | avz:sdk(?LOGIN)].
+
+event(init) ->
+  [wf:wire(#jq{target=Id, method=["classList.add"], args=["'pure-button','avz-button'"]})
+    || Id <- [loginfb, twlogin, github_btn, microsoftbtn]],
+  wf:wire(#jq{target=gloginbtn, method=["classList.add"], args=["'google-button'"]});
+
+event({register, U=#user{}}) ->
+  case kvs:add(U#user{id=kvs:next_id("user", 1)}) of
+    {ok, U1} -> avz:login_user(U1);
+    {error, E} -> event({login_failed, E})
+  end;
+
+event({login, #user{}=U, N}) ->
+  Updated = avz:merge(U,N),
+  ok = kvs:put(Updated),
+  avz:login_user(Updated);
+
+event({login_failed, E}) ->
+  wf:update(display, #span{id=display, body=[E]});
+
+event(X) ->
+  wf:info(?MODULE, "Event:~p~n", [X]),
+  avz:event(X).
+
+api_event(X,Y,Z) -> avz:api_event(X,Y,Z).
+
+
+header() -> 
+  [#header{class=[header], body=[
+     #panel{class=["menu", "pure-menu", "pure-menu-horizontal", "pure-menu-fixed"], body=[
+       #link{class=["pure-menu-heading"], href= <<"/">>, body=[#image{src="/static/S.svg"}, <<"Home">>]},
+
+       #list{class=["pure-menu-list"], body=[
+         case wf:user() of 
+           undefined -> [
+             #li{class=["pure-menu-item", "pure-menu-selected"], 
+                 body=[#link{class=["pure-menu-link"], body= <<"Sign In">>, url= <<"/login.html">>}]} ];
+           User ->
+             Email = wf:to_list(User#user.email),
+             Avatar = case User#user.images of
+               [] -> "holder.js/50x50";
+               [{_,A}|_] -> A
+             end,
+             [
+              #li{class=["pure-menu-item"], body=[#link{class=["pure-menu-link"], body= [<<"Profile">>], url= <<"/profile.html">>}]},
+              #li{class=["pure-menu-item"], body=[
+                #link{class=["pure-menu-link"], body= ["Sign Out"], postback=logout, delegate=index} ]},
+              #li{class=["pure-menu-item"], body=[Email]},
+              #li{class=["pure-menu-item"], body=[
+                #link{class=["pure-menu-link", "profile-pic"], body=[
+                  #image{class=["pure-img"], image = Avatar} ]}
+              ]}
+             ]
+         end
+       ]}
+     ]}
+  ]}].
+
+
+footer() -> #footer{class=[footer], body=[ <<"&copy; 2017">> ]}.
+

+ 28 - 0
apps/n2o_sample/src/login.erl

@@ -0,0 +1,28 @@
+-module(login).
+-compile(export_all).
+-include_lib("kvs/include/feed.hrl").
+-include_lib("nitro/include/nitro.hrl").
+-include_lib("n2o/include/wf.hrl").
+
+main() -> #dtl{file="login", app=n2o_sample, bindings=[{body, body()}, {folders, folders()}]}.
+folders() -> string:join([filename:basename(F) || F <- filelib:wildcard(code:priv_dir(n2o_sample) ++ "/snippets/*/")], ",").
+
+body() ->
+ [#span  { id=display },                 #br{},
+  #span  { body="Login: " },             #textbox{id=user, autofocus=true}, #br{},
+  #span  { body="Join/Create Feed: " },  #textbox{id=pass},
+  #button{ id=loginButton, body="Login", postback=login, source=[user, pass]} ].
+
+event(login) ->
+  User = case wf:q(user) of
+    <<>> -> "anonymous";
+    undefined -> "anonymous";
+    E -> wf:to_list(E)
+  end,
+  wf:user(User),
+  wf:info(?MODULE, "User: ~p", [wf:user()]),
+  wf:redirect("index.htm?room=" ++ wf:to_list(wf:q(pass))),
+  ok;
+
+event(_) -> [].
+

+ 9 - 0
apps/n2o_sample/src/n2o_sample.app.src

@@ -0,0 +1,9 @@
+{application, n2o_sample,
+ [
+  {description, "N2O Simple Sample Application"},
+  {vsn, "2.9"},
+  {registered, []},
+  {applications, [kernel, stdlib, n2o, kvs]},
+  {mod, { n2o_sample, []}},
+  {env, []}
+ ]}.

+ 37 - 0
apps/n2o_sample/src/n2o_sample.erl

@@ -0,0 +1,37 @@
+-module(n2o_sample).
+-behaviour(supervisor).
+-behaviour(application).
+-export([init/1, start/2, stop/1, main/1]).
+-include_lib("kvs/include/user.hrl").
+
+main(A)    -> mad:main(A).
+start()    -> start(normal,[]).
+start(_,_) -> supervisor:start_link({local, n2o_sample}, n2o_sample,[]).
+stop(_)    -> ok.
+
+-define(USERS, [#user{id="maxim",  email="maxim@synrc.com"},
+                #user{id="doxtop", email="doxtop@synrc.com"},
+                #user{id="roman",  email="roman@github.com"}]).
+
+init([]) ->
+  users:init(),
+  users:populate(?USERS),
+  kvs:join(),
+  {ok, {{one_for_one, 5, 10}, [spec()]}}.
+
+spec()   -> ranch:child_spec(http, 100, ranch_tcp, port(), cowboy_protocol, env()).
+env()    -> [ { env, [ { dispatch, points() } ] } ].
+static() ->   { dir, "apps/n2o_sample/priv/static", mime() }.
+n2o()    ->   { dir, "deps/n2o/priv",           mime() }.
+mime()   -> [ { mimetypes, cow_mimetypes, all   } ].
+port()   -> [ { port, wf:config(n2o, port, 8000)  } ].
+points() -> cowboy_router:compile([{'_', [
+    {"/static/[...]",       n2o_static,    static()},
+    {"/n2o/[...]",          n2o_static,    n2o()},
+    {"/multipart/[...]",    n2o_multipart, []},
+    {"/rest/:resource",     rest_cowboy,   []},
+    {"/rest/:resource/:id", rest_cowboy,   []},
+    {"/ws/[...]",           n2o_stream,    []},
+    {'_',                   n2o_cowboy,    []}
+  ]}]).
+

+ 31 - 0
apps/n2o_sample/src/routes.erl

@@ -0,0 +1,31 @@
+-module(routes).
+-author('Maxim Sokhatsky').
+-include_lib("n2o/include/wf.hrl").
+-export([init/2, finish/2]).
+
+%% U can use default dynamic routes or define custom static as this
+%% Just put needed module name to sys.config:
+%% {n2o, [{route,routes}]}
+%% Also with dynamic routes u must load all modules before starting Cowboy
+%% [code:ensure_loaded(M) || M <- [index, login, ... ]]
+
+finish(State, Ctx) -> {ok, State, Ctx}.
+init(State, Ctx) ->
+  Path = wf:path(Ctx#cx.req),
+  wf:info(?MODULE,"Route: ~p~n",[Path]),
+  {ok, State, Ctx#cx{path=Path, module=route_prefix(Path)}}.
+
+route_prefix(<<"/ws/",P/binary>>) -> route(P);
+route_prefix(<<"/",P/binary>>) -> route(P);
+route_prefix(P) -> route(P).
+
+route(<<>>)              -> login;
+route(<<"counter",_/binary>>) -> counter;
+route(<<"chat",_/binary>>) -> chat;
+route(<<"doc",_/binary>>) -> doc;
+route(<<"index",_/binary>>) -> index;
+route(<<"static/spa/index",_/binary>>) -> index;
+route(<<"static/spa/login",_/binary>>) -> login;
+route(<<"login",_/binary>>) -> login;
+route(<<"interlogin",_/binary>>) -> interlogin;
+route(_) -> login.

+ 15 - 0
apps/n2o_sample/src/users.erl

@@ -0,0 +1,15 @@
+-module(users).
+-behaviour(rest).
+-compile({parse_transform, rest}).
+-include_lib("kvs/include/user.hrl").
+-export([init/0, populate/1, exists/1, get/0, get/1, post/1, delete/1]).
+-rest_record(user).
+
+init()               -> ets:new(users, [public, named_table, {keypos, #user.id}]).
+populate(Users)      -> ets:insert(users, Users).
+exists(Id)           -> ets:member(users, wf:to_list(Id)).
+get()                -> ets:tab2list(users).
+get(Id)              -> #user{id=Id}.
+delete(Id)           -> ets:delete(users, wf:to_list(Id)).
+post(#user{} = User) -> ets:insert(users, User), true;
+post(Data)           -> post(from_json(Data, #user{})), true.

+ 3 - 0
apps/rebar.config

@@ -0,0 +1,3 @@
+{sub_dirs, [ "n2o_sample" ]}.
+{lib_dirs, ["../apps"]}.
+{deps_dir, ["../deps"]}.

BIN
mad


+ 18 - 0
rebar.config

@@ -0,0 +1,18 @@
+{sub_dirs,["apps"]}.
+{lib_dirs,["apps","deps"]}.
+{deps_dir,"deps"}.
+{deps, [
+    {gproc,  ".*", {git, "git://github.com/uwiger/gproc",       {tag, "0.6.1"}}},
+    {rest,   ".*", {git, "git://github.com/synrc/rest",         {tag, "2.9"}  }},
+    {erlydtl,".*", {git, "git://github.com/evanmiller/erlydtl", {tag, "0.8.0"}}},
+    {nitro,  ".*", {git, "git://github.com/synrc/nitro",        {tag, "2.4"}  }},
+    {mad,    ".*", {git, "git://github.com/synrc/mad",          {tag, "1.9"}  }},
+    {fs,     ".*", {git, "git://github.com/synrc/fs",           {tag, "1.9"}  }},
+    {sh,     ".*", {git, "git://github.com/synrc/sh",           {tag, "1.9"}  }},
+    {active, ".*", {git, "git://github.com/synrc/active",       {tag, "1.9"}  }},
+    {avz,    ".*", {git, "git://github.com/synrc/avz",          {tag, "4.4"}  }},
+    {n2o,    ".*", {git, "git://github.com/synrc/n2o",          {tag, "4.4"}  }},
+    {kvs,    ".*", {git, "git://github.com/synrc/kvs",          {tag, "3.9.1"}}}
+]}.
+{fetch_speed,fast_master}.
+{verbose,1}.

+ 46 - 0
sys.config

@@ -0,0 +1,46 @@
+[
+ {n2o, [{port,4000},{websocket_port,443},
+        {app,n2o_sample},
+        {upload,"./apps/n2o_sample/priv/static/"},
+        {search,"/Users/5HT/depot/synrc/synrc.com/apps/*/doc/web/*.htm"},
+        {mode,dev},
+        {route,routes},
+        {mq,n2o_mq},
+        {formatter,bert},
+        {minify,{"apps/n2o_sample/priv/static",
+                ["deps/n2o/priv/bullet.js",
+                 "deps/n2o/priv/n2o.js",
+                 "deps/n2o/priv/ftp.js",
+                 "deps/n2o/priv/protocols/bert.js",
+                 "deps/n2o/priv/protocols/nitrogen.js",
+                 "deps/n2o/priv/utf8.js",
+                 "deps/n2o/priv/validation.js"]}},
+        {log_modules,config},
+        {log_level,config},
+        {log_backend,n2o_log},
+        {session,n2o_session},
+        {origin,<<"*">>},
+        {bridge,n2o_cowboy},
+        {pickler,n2o_pickle},
+        {erroring,n2o_error},
+        {event,pickle}]},
+ {avz, [{after_login_page, "/index"},
+        {login_page, "/interlogin"},
+        {fb_id, "176025532423202"},
+        {tw_consumer_key, "YwfU5qj5AYY0uwPumcw1Q"},
+        {tw_consumer_secret, "O7VjRYLWxwMgtSXZbiiY6kc1Og2il9gbo1KAIqZk"},
+        {g_client_id, "158344909038-j6c0rbvpi09kdaqq03j2eddlf047ht3d.apps.googleusercontent.com"}, 
+        {g_cookiepolicy, "http://localhost:8000"},
+        {g_btn_width, 240},
+        {g_btn_height, 50},
+        {g_btn_theme, "light"},
+        {g_btn_longtitle, true},
+        {github_client_id, "591bfe2556ee60ca8c32"},
+        {github_client_secret, "01411884e3c51624d3ea729ed6b047db52973e8e"},
+        {ms_client_id, "54385d15-f1e0-4fcf-9bf4-042d740e0df4"},
+        {ms_client_secret, "jU0tStEzRdDPFwL9NdVGYxo"},
+        {ms_redirect_uri, "http://localhost:8000/interlogin"}
+      ]},
+ {kvs, [{dba,store_mnesia},
+        {schema, [kvs_user, kvs_acl, kvs_feed, kvs_subscription ]} ]}
+].

+ 7 - 0
vm.args

@@ -0,0 +1,7 @@
+-name n2o_sample@127.0.0.1
+-setcookie node_runner
++pc unicode
++K true
++A 5
+-env ERL_MAX_PORTS 4096
+-env ERL_FULLSWEEP_AFTER 10

+ 5 - 0
xen.config

@@ -0,0 +1,5 @@
+kernel = "vmling"
+name = "skyline"
+memory = 512
+extra = "-ipaddr 172.16.42.108 -netmask 255.255.255.0 -gateway 172.16.42.108 -root /erlang -pz /deps/erlydtl/ebin -pz /apps/n2o_sample/ebin -pz /deps/n2o/ebin -pz /deps/cowboy/ebin -pz /deps/ranch/ebin -pz /deps/mimetypes/ebin -home /deps/n2o_sample/ebin"
+vif =  [ 'bridge=docker0', ]