Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 65d655f72e7ffc5c95ba6d9d6ee499f5dd0b0313 Hugo Heuzard committed Jun 7, 2011
Showing with 1,411 additions and 0 deletions.
  1. +661 −0 LICENSE
  2. +9 −0 Makefile
  3. +16 −0 README
  4. BIN resources/cp_th.png
  5. BIN resources/opa-logo.png
  6. +270 −0 resources/style.css
  7. +68 −0 src/buffer.opa
  8. +79 −0 src/builder.opa
  9. +235 −0 src/client.opa
  10. +73 −0 src/main.opa
661 LICENSE

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,9 @@
+OPA=opa
+
+all: opawhiteboard.exe
+
+opawhiteboard.exe:
+ $(OPA) src/buffer.opa src/client.opa src/builder.opa src/main.opa -o opawhiteboard.exe
+
+clean:
+ rm -Rf *.exe _build _tracks *.log
16 README
@@ -0,0 +1,16 @@
+Collaborative white board
+
+BUILDING
+ make
+
+LAUNCHING
+ ./opawhiteboard.exe
+(launches on port 8080)
+or
+ ./opawhiteboard.exe -p nnnn
+
+Once started you can start drawing with people but it will not support reloading.
+In order to do so, start a browser at the following adress:
+http://myhost:myport/i_m_a_builder
+it aims to build the image and send it back to the server.
+When we have an image manipulation library on server side, it won't be needed anymore.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,270 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+html {background: #F2F2ED;}
+body {
+ color:#252525;
+ background: #F2F2ED;
+ font-size:95%;
+ line-height:1.4em;
+ font-weight: normal;
+ font-family: "ff-meta-serif-web-pro-1","ff-meta-serif-web-pro-Georgia", Georgia,"Times New Roman",Times,serif;
+ text-shadow: 0 1px 0 white;
+ text-align:center;
+}
+a, a:link, a:visited {color: #0B67B2;text-decoration: none;}
+a:hover {color: #0B4D86;text-decoration: underline;}
+a:active {color: #B30A0A;}
+
+ul, ol { margin: 0 0 1.5em 0; }
+ul li, ol li {list-style-type: disc;margin:0;}
+ul li ul, ol li ol {margin-left:20px;}
+ul, ol {list-style-image: none; list-style-position: inside;}
+textarea, input[type=text],input[type=password], select {
+ text-align:left;
+ border: 1px solid #ddd;
+ font-family: "Lucida Grande",Arial,sans-serif;
+ margin-bottom:2px;
+ padding:2px;
+ border-radius: 2px;
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ font-size:14px;
+}
+button, input[type=submit] {
+ background: #B30A0A;
+ border:0;
+ text-align:center;
+ color:white;
+ border-radius: 0.3em 0.3em 0.3em 0.3em;
+ -webkit-border-radius: 0.3em 0.3em 0.3em 0.3em;
+ -moz-border-radius: 0.3em 0.3em 0.3em 0.3em;
+ text-shadow: 0 1px 0 #777777;
+ padding:2px 6px 3px 6px;
+ font-size:1em;
+}
+table {
+ border-collapse: collapse;
+ margin: 5px 0;
+ width: 100%;
+}
+.search_container {display:none;}
+
+#sendit {clear: both;display: block;padding: 10px;text-align: left;}
+
+table td {vertical-align:top;border-bottom: 1px solid #c6c6c2;padding: 3px;color: #767672;font-size:0.9em;}
+table td:after {border-bottom: 1px solid #FFF;content:"";position:relative;top:5px;display:block;}
+
+p {margin: 0 0 1.5em 0;}
+li p, td p {display:inline;}
+h1 {color:#000; font-size: 2em; line-height:1.5em; margin: 0 0 0.7em 0;}
+h2 {color:#B30A0A; font-size: 1.7em; line-height:1.4em; margin: 0.5em 0;}
+h3 {color:#000; font-size: 1.5em; line-height:1em; margin: 1em 0;}
+h4 {color:#969692; font-size: 1.3em; line-height:1em; margin: 0.5em 0;}
+h5 {color:#B30A0A; font-size: 1.25em; line-height:1.2em; margin: 0 0 0.5em 0;}
+h6 {color:#969692; font-size: 1em; line-height:1em; margin: 0 0 0.5em 0; font-style: italic;}h6 {color:#969692; font-size: 1em; line-height:1em; margin: 0 0 0.5em 0; font-style: italic;font-weight:normal;}
+h1, h2, h3, h4, h5 {font-family: "proxima-nova", "Avenir", "Futura", "Helvetica", "Arial", sans-serif;font-weight: normal;}
+
+/***Header***/
+#header {
+ margin: 0;
+ padding: 10px;
+ position: relative;
+ text-align: left;
+}
+#logo {
+ background: url("/resources/opa-logo.png") no-repeat 0 0;
+ height: 41px;
+ margin: 5px 0 15px;
+ width: 100px;
+}
+
+/*CHAT*/
+#chat {
+ text-align: left;
+ position: relative;
+ float: left;
+ width: 200px;
+ background: rgba(255, 255, 255, 0.7);
+ padding: 5px;
+ color: #777;
+ border: 1px solid #CCC;
+ border-radius: 0.3em;
+ -moz-border-radius: 0.3em;
+ -webkit-border-radius: 0.3em;
+ box-shadow: 0 0 5px #ccc inset;
+ -moz-box-shadow: 0 0 5px #ccc inset;
+ -webkit-box-shadow: 0 0 5px #ccc inset;
+}
+.chat_line {display:block;padding:3px;border-bottom: 1px solid #ccc;}
+.chat_line:after {border-bottom: 1px solid #FFF;content:"";display:block;position:relative;top:5px;}
+.chat_author {display:inline-block;color: #B30A0A;font-variant:small-caps;}
+.chat_date {display:inline-block; color: #a6a6a2;font-size:0.9em;}
+.chat_message{display:inline-block;color:#252525;}
+.chat_actions{display:inline;}
+
+.chat_conversation {height:375px;overflow:auto;}
+.chat_entry {
+ width:140px;
+ font-size:1.1em;
+ border-radius: 2px;
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ margin-top:5px;
+}
+
+/*CANVAS*/
+#container{
+ position: relative;
+ text-align: center;
+ width:1124px;
+ margin: 0 auto;
+ padding: 0;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+#content {width:900px; display:block; position:relative;float:left;}
+
+#canvas_wrapper{
+ float:left;
+ display:block;
+ position:relative;
+ background:white;
+ border:1px solid #ccc;
+ border-radius:0.3em 0.3em 0.3em 0.3em;
+ -webkit-border-radius:0.3em;
+ -moz-border-radius:0.3em;
+ box-shadow: 0 0 5px #ccc inset;
+ -moz-box-shadow: 0 0 5px #ccc inset;
+ -webkit-box-shadow: 0 0 5px #ccc inset;
+}
+
+#canvas{
+ display: block;
+}
+#initial_image{
+ display: block;
+ margin-top: -450px;
+}
+
+#drawing_tools{
+ float: left;
+ display:block;
+ position:relative;
+ margin-left:10px;
+ padding:0 10px 10px;
+ border-radius:0.3em 0.3em 0.3em 0.3em;
+ -webkit-border-radius:0.3em;
+ -moz-border-radius:0.3em;
+ background: #d6d6d2;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#E6E6E2,endColorstr=#C6C6C2);
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#E6E6E2,endColorstr=#C6C6C2)";
+ background: -webkit-gradient(linear,0% 0%,0% 100%,from(#E6E6E2),to(#C6C6C2));
+ background: -moz-linear-gradient(-90deg,#E6E6E2,#C6C6C2);
+ background: -o-linear-gradient(#E6E6E2,#C6C6C2);
+ border: 1px solid #B6B6B2;
+ text-align: left;
+ width: 260px;
+ height:440px;
+ box-shadow: 0 1px 5px #B6B6B2 inset;
+ -moz-box-shadow: 0 1px 5px #B6B6B2 inset;
+ -webkit-box-shadow: 0 1px 5px #B6B6B2 inset;
+}
+
+#drawing_tools h4 {
+ border-bottom: 1px solid #BBB;
+ margin-bottom:0.7em;
+ padding: 5px 0;
+}
+#drawing_tools h4:after {
+ border-bottom: 1px solid #FFF;
+ content:"";
+ display:block;
+ position:relative;
+ top:7px;
+}
+
+/*Drawing tools*/
+.thumb, .thumb_over, .thumb_dragged{
+ height:16px;
+ width:6px;
+ border:1px solid #B6B6B2;
+ top:-8px;
+ position:absolute;
+ border-radius:0.3em 0.3em 0.3em 0.3em;
+ -webkit-border-radius:0.3em;
+ -moz-border-radius:0.3em;
+
+}
+.thumb{
+ background:#F6F6F2;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#F6F6F2,endColorstr=#E6E6E2);
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#F6F6F2,endColorstr=#E6E6E2)";
+ background: -webkit-gradient(linear,0% 0%,0% 100%,from(#F6F6F2),to(#E6E6E2));
+ background: -moz-linear-gradient(-90deg,#F6F6F2,#E6E6E2);
+ background: -o-linear-gradient(#F6F6F2,#E6E6E2);
+}
+
+.thumb_over{background:#E6E6E2;}
+
+.thumb_dragged{background:#C6C6C2;}
+
+.gauge{
+ position: relative;
+ width:256px;
+ height:3px;
+ background:#b6b6b2;
+ border-bottom:1px solid #f6f6f2;
+ border-radius:0.3em 0.3em 0.3em 0.3em;
+ -webkit-border-radius:0.3em;
+ -moz-border-radius:0.3em;
+}
+/*Coloricker*/
+
+.cp_thumb, .cp_thumb_over, .cp_thumb_dragged {
+ height:20px;
+ width:9px;
+ top:-2px;
+ position:absolute;
+ background: url("/resources/cp_th.png") no-repeat 0 0;
+}
+
+/*.cp_thumb{
+ border:1px solid #A6A6A2;
+}
+
+.cp_thumb_over{
+ border:1px solid #C6C6C2;
+}
+
+.cp_thumb_dragged{
+ border:1px solid #F6F6F62;
+}*/
+
+.cp_gauge{
+ margin-top:5px;
+ position: relative;
+ width:256px;
+ height:16px;
+ border:1px solid #A6A6A2;
+}
+
+.cp_cursor{
+ height:10px;
+ width:10px;
+ border:1px solid #A6A6A2;
+ border-radius:1em 1em 1em 1em;
+ -webkit-border-radius:1em;
+ -moz-border-radius:1em;
+}
+
+.cp_preview{
+ height:30px !important;
+ width:80px !important;
+ border:1px solid #A6A6A2 !important;
+ margin-bottom:5px;
+}
@@ -0,0 +1,68 @@
+/* Collaborative white board
+
+ Copyright (C) 2010-2011 MLstate
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ @author Hugo Heuzard
+*/
+
+/*
+ * Ugly implem of buffered session/netork
+ */
+
+type SessionBuffer.channel('msg) = channel(list('msg))
+
+SessionBuffer = {{
+
+ make(state : 'state ,treat_msg : ('state,'msg -> Session.instruction('state))) : SessionBuffer.channel('msg)=
+ ns = Session.make(state : 'state,treat_msg)
+ Session.make_callback(l -> List.iter(Session.send(ns,_),l))
+
+ make_send_to(session : SessionBuffer.channel('msg) ,timer : int) =
+ sess = Session.make([],(l,s ->
+ match s with
+ | {~add} -> {set=add++l}
+ | {dump} -> if l == [] then {unchanged} else do Session.send(session,l) {set=[]} ))
+ do Scheduler.timer(timer, ( -> Session.send(sess,{dump})))
+ Session.make_callback( add -> Session.send(sess,{~add}))
+}}
+
+type NetworkBuffer.network('a) = channel(NetworkBuffer.instruction('a))
+
+type NetworkBuffer.instruction('a) = {add: SessionBuffer.channel('a)} / {remove: SessionBuffer.channel('a)} / {broadcast: list('a)} / {dump}
+NetworkBuffer = {{
+ @publish
+ empty(timer : int): NetworkBuffer.network('a) =
+ Set = Set_make(channel_order)
+ s = Session.make_own((Set.empty,[]),
+ ((chans,lst), msg, own ->
+ match msg with
+ | {~add} ->
+ do Session.on_remove(add, (-> remove(add, own)))
+ {set = (Set.add(add,chans),lst)}
+ | {~remove} -> {set = (Set.remove(remove, chans),lst)}
+ | {~broadcast} ->
+ {set=(chans,broadcast++lst)}
+ | {dump} ->
+ if lst == [] then {unchanged} else do sleep(0, -> Set.iter(chan -> send(chan, lst), chans)) {set=(chans,[])}
+ ))
+ do Scheduler.timer(timer, ( -> Session.send(s,{dump})))
+ s
+
+ broadcast(message: list('a), network: NetworkBuffer.network('a)): void = send(network, {broadcast = message})
+ remove(channel: SessionBuffer.channel('a), network: NetworkBuffer.network('a)): void = send(network, {remove = channel})
+ add(channel: SessionBuffer.channel('a), network: NetworkBuffer.network('a)): void = send(network, {add = channel})
+
+}}
Oops, something went wrong.

0 comments on commit 65d655f

Please sign in to comment.