diff --git a/www/TAB.inc b/www/TAB.inc
index 0d9534760..3f1368bc2 100644
--- a/www/TAB.inc
+++ b/www/TAB.inc
@@ -55,6 +55,7 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+
Tiny shopping cart
diff --git a/www/websockets.yaws b/www/websockets.yaws
new file mode 100644
index 000000000..b6e9edbfd
--- /dev/null
+++ b/www/websockets.yaws
@@ -0,0 +1,86 @@
+
+
+
+
+box(Str) ->
+ {'div',[{class,"box"}],
+ {pre,[],yaws_api:htmlize(Str)}}.
+
+tbox(T) ->
+ box(lists:flatten(io_lib:format("~p",[T]))).
+
+
+ssi(File) ->
+ {'div',[{class,"box"}],
+ {pre,[],
+ {ssi, File,[],[]}}}.
+
+
+out(A) ->
+ [{ssi, "TAB.inc", "%%",[{"websockets", "choosen"}]},
+ {ehtml,
+ {'div',[{id, "entry"}],
+ [{h1, [], "Web Sockets in Yaws"},
+
+ {p, [], ["Web Sockets! The new kid in town! Joe ", {a, [{href, "http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html"}], "loves it"}, ", maybe you should too?"]},
+
+ {p, [], "Web Sockets allow for *real* two-way communication between the browser and Yaws without the overhead and latency that come with polling/long-polling solutions. That should be enough for an introduction. Now... how to use it?"},
+
+ {p, [], "First start by returning:"},
+
+ box(" {websocket, OwnerPid, SocketMode}"),
+
+ {p,[], "from the out/1 function."
+ " This makes the erlang process within yaws processing that particular page do a protocol upgrade from HTTP to the Web Socket Protocol, after which the OwnerPid can use the socket to interface directly with the Web Sockets client."},
+
+ {p,[], "When yaws completes the Web Sockets handshake, it sends one of the following messages to OwnerPid:"},
+
+ {ul,[],
+ [{li,[]," {ok, WebSocket} indicates to OwnerPid that the handshake completed successfully and that the WebSocket is set up and can be used to communicate with the web sockets client."},
+ {li,[]," discard indicates to OwnerPid that the handshake failed and no web sockets connection is available."}]},
+
+ {p,[], "SocketMode defines how the messages sent by the client are to be delivered to the OwnerPid."},
+
+ {ul, [], [
+ {li, [], [
+ {p,[], "On passive mode (SocketMode=false) it is up to the receiving process to issue a synchronous request to: "},
+ box("yaws_api:websocket_receive(WebSocket)"),
+ {p, [], " to grab the incoming messages."}
+ ]},
+ {li, [], [
+ {p, [], "On active mode (SocketMode=true) the incoming Web Socket data frames are delivered to OwnerPid as messages. On this mode the following messages are to be expected:"},
+ box("{tcp, WebSocket, DataFrame}
+{tcp_closed, WebSocket}"),
+ {p, [], "To extract the data from a Web Socket data frame you can use this function: "},
+ box("yaws_api:websocket_unframe_data(DataFrame)")
+ ]},
+ {li, [], [
+ {p, [], "If SocketMode=once then only ONE message will be sent as if in active mode and after that we're back to passive mode."}
+ ]}
+ ]},
+
+ {p,[], "For switching between the various \"receive modes\" you can do this:"},
+
+ box("yaws_api:websocket_setopts(WebSocket, [{active, NewSocketMode}])"),
+
+ {p,[],
+ "This function just wraps (gen_tcp|ssl):setops/2 to absctract away from using a regular/secure http connection."},
+
+ {p, [], "Enough theory for now. Sample echo server follows!"},
+
+ ssi("websockets_example_endpoint.yaws"),
+
+ {p, [],
+ ["The above code can be executed ",
+ {a, [{href, "websockets_example.yaws"}], "Here"},
+ "."]}
+
+ ]}},
+ {ssi, "END2",[],[]}
+ ].
+
+
+
+
+
+