Browse Source

Inital Commit

Andrew Magliozzi 8 years ago
commit
b15c7aa4e6
100 changed files with 24848 additions and 0 deletions
  1. 2 0
      README
  2. 1621 0
      app.js
  3. 9 0
      bruml/README.markdown
  4. 183 0
      bruml/archive/backchan-chatpage-orig.html
  5. 183 0
      bruml/archive/backchan.chatpage.html
  6. 108 0
      bruml/archive/bcfunctions.demo.html
  7. BIN
      bruml/images/accept.png
  8. BIN
      bruml/images/arrow_dn.png
  9. BIN
      bruml/images/arrow_up.png
  10. BIN
      bruml/images/delete.png
  11. BIN
      bruml/lib/paperboy/.package.json.un~
  12. 19 0
      bruml/lib/paperboy/LICENSE.txt
  13. 96 0
      bruml/lib/paperboy/README.md
  14. 38 0
      bruml/lib/paperboy/example/basic.js
  15. BIN
      bruml/lib/paperboy/example/webroot/img/paperboy.jpg
  16. 11 0
      bruml/lib/paperboy/example/webroot/index.html
  17. 1 0
      bruml/lib/paperboy/index.js
  18. 302 0
      bruml/lib/paperboy/lib/paperboy.js
  19. 11 0
      bruml/lib/paperboy/package.json
  20. 6 0
      bruml/lib/paperboy/seed.yml
  21. 236 0
      bruml/lib/socket.io/History.md
  22. 13 0
      bruml/lib/socket.io/Makefile
  23. 229 0
      bruml/lib/socket.io/README.md
  24. 61 0
      bruml/lib/socket.io/example/benchmark.html
  25. 21 0
      bruml/lib/socket.io/example/cert.crt
  26. 61 0
      bruml/lib/socket.io/example/chat-ssl.html
  27. 69 0
      bruml/lib/socket.io/example/chat.html
  28. 18 0
      bruml/lib/socket.io/example/json.js
  29. 27 0
      bruml/lib/socket.io/example/key.key
  30. 66 0
      bruml/lib/socket.io/example/server-ssl.js
  31. 77 0
      bruml/lib/socket.io/example/server.benchmark.js
  32. 63 0
      bruml/lib/socket.io/example/server.js
  33. 1 0
      bruml/lib/socket.io/index.js
  34. 197 0
      bruml/lib/socket.io/lib/socket.io/client.js
  35. 26 0
      bruml/lib/socket.io/lib/socket.io/index.js
  36. 166 0
      bruml/lib/socket.io/lib/socket.io/listener.js
  37. 89 0
      bruml/lib/socket.io/lib/socket.io/transports/flashsocket.js
  38. 49 0
      bruml/lib/socket.io/lib/socket.io/transports/htmlfile.js
  39. 35 0
      bruml/lib/socket.io/lib/socket.io/transports/jsonp-polling.js
  40. 208 0
      bruml/lib/socket.io/lib/socket.io/transports/websocket.js
  41. 67 0
      bruml/lib/socket.io/lib/socket.io/transports/xhr-multipart.js
  42. 80 0
      bruml/lib/socket.io/lib/socket.io/transports/xhr-polling.js
  43. 52 0
      bruml/lib/socket.io/lib/socket.io/utils.js
  44. 21 0
      bruml/lib/socket.io/package.json
  45. 128 0
      bruml/lib/socket.io/support/expresso/History.md
  46. 53 0
      bruml/lib/socket.io/support/expresso/Makefile
  47. 61 0
      bruml/lib/socket.io/support/expresso/Readme.md
  48. 856 0
      bruml/lib/socket.io/support/expresso/bin/expresso
  49. 339 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/COPYING
  50. 81 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.am
  51. 884 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/Makefile.in
  52. 8 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/Readme.md
  53. 872 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/aclocal.m4
  54. 1526 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/config.guess
  55. 92 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/config.h.in
  56. 666 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/config.rpath
  57. 1658 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/config.sub
  58. 7971 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/configure
  59. 88 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/configure.ac
  60. 589 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/depcomp
  61. 87 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/demo.html
  62. 45 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/doc.css
  63. 25 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/index.html
  64. 20 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/script.js
  65. 50 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/jsUnitStyle.css
  66. 10 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/readme
  67. 11 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/emptyPage.html
  68. 534 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitCore.js
  69. 81 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitMockTimeout.js
  70. 705 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestManager.js
  71. 44 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestSuite.js
  72. 102 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTracer.js
  73. 59 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitVersionCheck.js
  74. 12 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-errors.html
  75. 13 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-failures.html
  76. 13 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-runs.html
  77. 21 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts.html
  78. 189 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-data.html
  79. 23 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-errors.html
  80. 19 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-frame.html
  81. 45 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-loader.html
  82. 25 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-progress.html
  83. 67 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-results.html
  84. 13 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-status.html
  85. 16 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainer.html
  86. 77 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainerController.html
  87. 306 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/xbDebug.js
  88. 83 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/css/jsUnitStyle.css
  89. BIN
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/green.gif
  90. BIN
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/logo_jsunit.gif
  91. BIN
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/powerby-transparent.gif
  92. BIN
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/red.gif
  93. 56 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/JDOM_license.txt
  94. 213 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/Jetty_license.html
  95. 470 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/MPL-1.1.txt
  96. 340 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/gpl-2.txt
  97. 141 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/index.html
  98. 504 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/lgpl-2.1.txt
  99. 35 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-c.txt
  100. 0 0
      bruml/lib/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-html.txt

+ 2 - 0
README

@@ -0,0 +1,2 @@
+Finals Club Development 
+

File diff suppressed because it is too large
+ 1621 - 0
app.js


+ 9 - 0
bruml/README.markdown

@@ -0,0 +1,9 @@
+# backchannel
+
+is a reimplementation of the features of backchan.nl using a node.js 
+server with the socket.io module.  It is intended for HTML5 capable
+browsers supporting websockets.  The project will migrate towards a component
+stucture with a javascript library to be used on the HTML page and a node
+module to be used on the server, each containing no presentation.  Examples 
+of practical ways to skin the functionality will available as part of the 
+project.

+ 183 - 0
bruml/archive/backchan-chatpage-orig.html

@@ -0,0 +1,183 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />	<title>
+		backchan.nl -- Meetings	</title>
+	
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/fonts/fonts-min.css" />
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/container/assets/skins/sam/container.css" />
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/button/assets/skins/sam/button.css" />
+
+	<script type="text/javascript" src="/js/yui/build/utilities/utilities.js"></script>
+	<script type="text/javascript" src="/js/yui/build/container/container-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/button/button-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>
+	<script type="text/javascript" src="/js/yui/build/container/container_core-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/yahoo/yahoo-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/dom/dom-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/event/event-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/element/element-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/connection/connection-min.js"></script>
+	
+	<link rel="stylesheet" type="text/css" href="/css/cake.generic.css" />
+	<link rel="stylesheet" type="text/css" href="/css/backchannl.generic.css" />
+<script type="text/javascript">
+//<![CDATA[
+var initialPosts={"Post":[]};
+var showAdmin=true;
+var showIdentityDialog=false;
+
+//]]>
+</script>
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/datatable/assets/skins/sam/datatable.css" />
+	<link rel="stylesheet" type="text/css" href="/css/backchannl.generic.css" />
+	<link rel="stylesheet" type="text/css" href="/css/top.posts.css" />
+	<script type="text/javascript" src="/js/yui/build/datasource/datasource-beta-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/json/json-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/dragdrop/dragdrop-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/calendar/calendar-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/datatable/datatable-beta.js"></script>
+	<script type="text/javascript" src="/js/identity.js"></script>
+	<script type="text/javascript" src="/js/posting.js"></script>
+	<script type="text/javascript" src="/js/datatable.js"></script>
+	<script type="text/javascript" src="/js/top_posts.js"></script>
+	<script type="text/javascript" src="/js/voting.js"></script>
+	<script type="text/javascript" src="/js/util.js"></script>
+	<script type="text/javascript" src="/js/meetings_view.js"></script></head>
+<body class="yui-skin-sam">
+	<div id="container">
+		<div id="header">
+			<h2>
+				<a href="http://backchan.nl/">backchan.nl</a>			</h2>
+		</div>
+		<div id="content">
+			<!-- TODO: for production, delete following hidden div -->
+<div style="visibility:hidden; position:absolute; left:-1000px;">
+</div>
+
+
+
+
+<div id="MeetingHeader">
+<h1>Demo Conference</h1>
+<h2>First meeting (13:00 — 17:00)</h2>
+
+Welcome to backchan.nl! This tool is a way for people in the audience to <strong>post responses to the panel live</strong>, and in a <strong>publicly visible</strong> venue. These responses can be <strong>questions</strong>, <strong>comments</strong>, <strong>links to related resources</strong>, or whatever else you think other people might be interested in.
+
+Even if you don't have anything to say, you can <strong>vote posts up or down</strong> that you think are useful or problematic. Highly ranked and comments will get brought up during the discussion section of the panel.
+</div>
+<br />
+
+
+<div id="UserBox">
+
+	<div id="UserInfoHeader">
+		<div id="UserInfo">
+		<span id="UserInfoName">
+			b		</span><br />
+		<span id="UserInfoAffiliation">
+			student		</span>
+		</div>
+		<div id="UserButtons">
+		<input type="button" id="AdminPassword" value="" />
+		<input type="button" id="EditUser" value="Edit User" />
+		</div>
+	</div>
+
+	<div id="EnterUser">
+		<div class="hd">Who are you?</div>
+		<div class="bd">
+			<form id="UserAddForm" method="POST" action="/users/add">
+				<table>
+				<tr>
+					<td><label for="name">Name:</label></td>
+					<td>
+						<input type="text" id="UserName"
+							name="data[User][name]" value=""
+							maxlength="28" size="20" />
+					</td>
+				</tr>
+				<tr>
+					<td><label for="affiliation">Affiliation:</label></td>
+					<td>
+						<input type="text" id="UserAffiliation"
+							name="data[User][affiliation]" value=""
+							maxlength="48" size="20" />
+					</td>
+				</tr>
+				</table>
+			</form>
+		</div>
+	</div>
+
+	<div id="AdminUser">
+		<div class="hd">Conference Administration Password</div>
+		<div class="bd">
+			<form id="AdminUserForm" method="POST" action="/conferences/admin/346">
+				<table>
+				<tr>
+					<td><label for="conference">Conference:</label></td>
+					<td>
+						Demo Conference					</td>
+				</tr>
+				<tr>
+					<td><label for="AdminPassword">Password:</label></td>
+					<td>
+						<input type="password" id="AdminPassword"
+							name="data[adminPassword]" value=""
+							maxlength="48" size="20" />
+					</td>
+				</tr>
+				</table>
+			</form>
+		</div>
+	</div>
+
+	<div id="EnterPost">
+		<form id="PostAddForm">
+			<!-- onkeyup for cut or copy&paste, onkeypress for hold key down -->
+			<textarea id="PostBody" name="data[Post][body]"
+				onkeyup="updatePostCharCount();"
+				onkeypress="updatePostCharCount();"></textarea>
+			characters left: <span id="CharCount" class="char-count-good"></span>
+			<input type="hidden" id="PostMeetingId"
+				name="data[Post][meeting_id]"
+				value="926" />
+			<input type="button" id="SubmitPost"
+				name="SubmitPost" value="Submit Post" />
+		</form>
+	</div>
+
+</div>
+<br class="clear"/>
+
+<div id="alert" class="empty"></div>
+
+<br class="clear"/>
+<div class="hr"></div>
+<img class="label" src="/img/top_posts.png"/>
+<div id="TopPosts">
+</div>
+
+<br class="clear"/>
+<div class="hr"></div>
+<img class="label" src="/img/recent_posts.png"/>
+<div id="DataTable">
+</div>
+<br class="clear"/>
+		</div>
+		<div id="footer">
+						<a href="http://backchan.nl">backchan.nl</a> is an <a href="http://github.com/drewww/backchan.nl" title="The backchan.nl project is hosted at Github">open source project</a> from the <a href="http://media.mit.edu">MIT Media Lab</a>, designed by <a href="http://web.media.mit.edu/~dharry">Drew Harry</a> with <a href="http://trevorfilter.com/">Trevor Filter</a>, Cherrie Yang, and Joshua Green.
+		</div>
+	</div>
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+var pageTracker = _gat._getTracker("UA-841537-4");
+pageTracker._initData();
+pageTracker._trackPageview();
+</script>
+</body>
+</html>

+ 183 - 0
bruml/archive/backchan.chatpage.html

@@ -0,0 +1,183 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />	<title>
+		backchan.nl -- Meetings	</title>
+	
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/fonts/fonts-min.css" />
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/container/assets/skins/sam/container.css" />
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/button/assets/skins/sam/button.css" />
+
+	<script type="text/javascript" src="/js/yui/build/utilities/utilities.js"></script>
+	<script type="text/javascript" src="/js/yui/build/container/container-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/button/button-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>
+	<script type="text/javascript" src="/js/yui/build/container/container_core-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/yahoo/yahoo-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/dom/dom-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/event/event-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/element/element-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/connection/connection-min.js"></script>
+	
+	<link rel="stylesheet" type="text/css" href="/css/cake.generic.css" />
+	<link rel="stylesheet" type="text/css" href="/css/backchannl.generic.css" />
+<script type="text/javascript">
+//<![CDATA[
+var initialPosts={"Post":[]};
+var showAdmin=true;
+var showIdentityDialog=false;
+
+//]]>
+</script>
+	<link rel="stylesheet" type="text/css" href="/css/yui/build/datatable/assets/skins/sam/datatable.css" />
+	<link rel="stylesheet" type="text/css" href="/css/backchannl.generic.css" />
+	<link rel="stylesheet" type="text/css" href="/css/top.posts.css" />
+	<script type="text/javascript" src="/js/yui/build/datasource/datasource-beta-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/json/json-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/dragdrop/dragdrop-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/calendar/calendar-min.js"></script>
+	<script type="text/javascript" src="/js/yui/build/datatable/datatable-beta.js"></script>
+	<script type="text/javascript" src="/js/identity.js"></script>
+	<script type="text/javascript" src="/js/posting.js"></script>
+	<script type="text/javascript" src="/js/datatable.js"></script>
+	<script type="text/javascript" src="/js/top_posts.js"></script>
+	<script type="text/javascript" src="/js/voting.js"></script>
+	<script type="text/javascript" src="/js/util.js"></script>
+	<script type="text/javascript" src="/js/meetings_view.js"></script></head>
+<body class="yui-skin-sam">
+	<div id="container">
+		<div id="header">
+			<h2>
+				<a href="http://backchan.nl/">backchan.nl</a>			</h2>
+		</div>
+		<div id="content">
+			<!-- TODO: for production, delete following hidden div -->
+<div style="visibility:hidden; position:absolute; left:-1000px;">
+</div>
+
+
+
+
+<div id="MeetingHeader">
+<h1>Demo Conference</h1>
+<h2>First meeting (13:00 — 17:00)</h2>
+
+Welcome to backchan.nl! This tool is a way for people in the audience to <strong>post responses to the panel live</strong>, and in a <strong>publicly visible</strong> venue. These responses can be <strong>questions</strong>, <strong>comments</strong>, <strong>links to related resources</strong>, or whatever else you think other people might be interested in.
+
+Even if you don't have anything to say, you can <strong>vote posts up or down</strong> that you think are useful or problematic. Highly ranked and comments will get brought up during the discussion section of the panel.
+</div>
+<br />
+
+
+<div id="UserBox">
+
+	<div id="UserInfoHeader">
+		<div id="UserInfo">
+		<span id="UserInfoName">
+			b		</span><br />
+		<span id="UserInfoAffiliation">
+			student		</span>
+		</div>
+		<div id="UserButtons">
+		<input type="button" id="AdminPassword" value="" />
+		<input type="button" id="EditUser" value="Edit User" />
+		</div>
+	</div>
+
+	<div id="EnterUser">
+		<div class="hd">Who are you?</div>
+		<div class="bd">
+			<form id="UserAddForm" method="POST" action="/users/add">
+				<table>
+				<tr>
+					<td><label for="name">Name:</label></td>
+					<td>
+						<input type="text" id="UserName"
+							name="data[User][name]" value=""
+							maxlength="28" size="20" />
+					</td>
+				</tr>
+				<tr>
+					<td><label for="affiliation">Affiliation:</label></td>
+					<td>
+						<input type="text" id="UserAffiliation"
+							name="data[User][affiliation]" value=""
+							maxlength="48" size="20" />
+					</td>
+				</tr>
+				</table>
+			</form>
+		</div>
+	</div>
+
+	<div id="AdminUser">
+		<div class="hd">Conference Administration Password</div>
+		<div class="bd">
+			<form id="AdminUserForm" method="POST" action="/conferences/admin/346">
+				<table>
+				<tr>
+					<td><label for="conference">Conference:</label></td>
+					<td>
+						Demo Conference					</td>
+				</tr>
+				<tr>
+					<td><label for="AdminPassword">Password:</label></td>
+					<td>
+						<input type="password" id="AdminPassword"
+							name="data[adminPassword]" value=""
+							maxlength="48" size="20" />
+					</td>
+				</tr>
+				</table>
+			</form>
+		</div>
+	</div>
+
+	<div id="EnterPost">
+		<form id="PostAddForm">
+			<!-- onkeyup for cut or copy&paste, onkeypress for hold key down -->
+			<textarea id="PostBody" name="data[Post][body]"
+				onkeyup="updatePostCharCount();"
+				onkeypress="updatePostCharCount();"></textarea>
+			characters left: <span id="CharCount" class="char-count-good"></span>
+			<input type="hidden" id="PostMeetingId"
+				name="data[Post][meeting_id]"
+				value="926" />
+			<input type="button" id="SubmitPost"
+				name="SubmitPost" value="Submit Post" />
+		</form>
+	</div>
+
+</div>
+<br class="clear"/>
+
+<div id="alert" class="empty"></div>
+
+<br class="clear"/>
+<div class="hr"></div>
+<img class="label" src="/img/top_posts.png"/>
+<div id="TopPosts">
+</div>
+
+<br class="clear"/>
+<div class="hr"></div>
+<img class="label" src="/img/recent_posts.png"/>
+<div id="DataTable">
+</div>
+<br class="clear"/>
+		</div>
+		<div id="footer">
+						<a href="http://backchan.nl">backchan.nl</a> is an <a href="http://github.com/drewww/backchan.nl" title="The backchan.nl project is hosted at Github">open source project</a> from the <a href="http://media.mit.edu">MIT Media Lab</a>, designed by <a href="http://web.media.mit.edu/~dharry">Drew Harry</a> with <a href="http://trevorfilter.com/">Trevor Filter</a>, Cherrie Yang, and Joshua Green.
+		</div>
+	</div>
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+var pageTracker = _gat._getTracker("UA-841537-4");
+pageTracker._initData();
+pageTracker._trackPageview();
+</script>
+</body>
+</html>

+ 108 - 0
bruml/archive/bcfunctions.demo.html

@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!-- taken from http://backchan.nl/meetings/view/926 -->
+<!-- May 4, 2011 -->
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>FinalsClub -- BC functions</title>
+	<link rel="stylesheet" type="text/css" href="/css/backchannl.generic.css" />
+  <script type="text/javascript">
+    //<![CDATA[
+    var initialPosts={"Post":[]};
+    var showAdmin=true;
+    var showIdentityDialog=false;
+    //]]>
+  </script>
+</head>
+<body class="yui-skin-sam">
+	<div id="container">
+<!-- back to margin inside "container" -->
+
+<div id="meetingHeader">
+  <h1>The Human Mind</h1>
+  <h2>Lecture #6: April 3, 2001: Evolution</h2>
+  <p>Use this section to react to the lecture: your posts will be seen by others <strong>immediately</strong>, and they can <strong>respond</strong> or <strong>vote your post up or down</strong>. Your post can be a <strong>question</strong>, <strong>comment</strong>, <strong>link to something related to the lecture</strong>, or whatever else you think other people might be interested in.</p>
+  <p>Even if you don't have anything to say, you can <strong>vote posts up or down</strong> that you think are useful or problematic. Highly ranked and comments will get brought up during the discussion section of the panel.</p>
+</div>
+
+<div id="UserBox">
+	<div id="UserInfoHeader">
+		<div id="UserInfoName">Beardsley</div>
+		<div id="UserInfoAffiliation">student</div>
+		<div id="UserButtons">
+      <input type="button" id="AdminPassword" value="" />
+      <input type="button" id="EditUser" value="Edit User" />
+		</div>
+	</div>
+
+	<div id="EnterUser">
+		<div class="hd">Who are you?</div>
+		<div class="bd">
+			<form id="UserAddForm" method="POST" action="/users/add">
+				<table>
+				<tr>
+					<td><label for="name">Name:</label></td>
+					<td>
+						<input type="text" id="UserName"
+							name="data[User][name]" value=""
+							maxlength="28" size="20" />
+					</td>
+				</tr>
+				<tr>
+					<td><label for="affiliation">Affiliation:</label></td>
+					<td>
+						<input type="text" id="UserAffiliation"
+							name="data[User][affiliation]" value=""
+							maxlength="48" size="20" />
+					</td>
+				</tr>
+				</table>
+			</form>
+		</div>
+	</div>
+
+	<div id="AdminUser">
+		<div class="hd">Conference Administration Password</div>
+		<div class="bd">
+			<form id="AdminUserForm" method="POST" action="/conferences/admin/346">
+				<table>
+				<tr>
+					<td><label for="conference">Conference:</label></td>
+					<td>
+						Demo Conference					</td>
+				</tr>
+				<tr>
+					<td><label for="AdminPassword">Password:</label></td>
+					<td>
+						<input type="password" id="AdminPassword"
+							name="data[adminPassword]" value=""
+							maxlength="48" size="20" />
+					</td>
+				</tr>
+				</table>
+			</form>
+		</div>
+	</div>
+
+	<div id="EnterPost">
+		<form id="PostAddForm">
+			<!-- onkeyup for cut or copy&paste, onkeypress for hold key down -->
+			<textarea id="PostBody" name="data[Post][body]"
+				onkeyup="updatePostCharCount();"
+				onkeypress="updatePostCharCount();"></textarea>
+			characters left: <span id="CharCount" class="char-count-good"></span>
+			<input type="hidden" id="PostMeetingId"
+				name="data[Post][meeting_id]"
+				value="926" />
+			<input type="button" id="SubmitPost"
+				name="SubmitPost" value="Submit Post" />
+		</form>
+	</div>
+
+</div>
+<br class="clear"/>
+
+<div id="alert" class="empty"></div>
+
+<br class="clear"/>
+<div class="hr"></div>

BIN
bruml/images/accept.png


BIN
bruml/images/arrow_dn.png


BIN
bruml/images/arrow_up.png


BIN
bruml/images/delete.png


BIN
bruml/lib/paperboy/.package.json.un~


+ 19 - 0
bruml/lib/paperboy/LICENSE.txt

@@ -0,0 +1,19 @@
+Copyright (c) 2010 Debuggable Limited <felix@debuggable.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 96 - 0
bruml/lib/paperboy/README.md

@@ -0,0 +1,96 @@
+# Paperboy
+
+## Purpose
+
+A node.js module for delivering static files.
+
+## Features
+  
+ * Configurable callbacks on most events
+ * ETag / 304 Support
+ * Custom HTTP headers
+
+## Example
+
+Example from example/basic.js:
+
+    var
+      path = require('path'),
+      http = require('http'),
+      paperboy = require('../lib/paperboy'),
+    
+      PORT = 8003,
+      WEBROOT = path.join(path.dirname(__filename), 'webroot');
+    
+    http.createServer(function(req, res) {
+      var ip = req.connection.remoteAddress;
+      paperboy
+        .deliver(WEBROOT, req, res)
+        .addHeader('Expires', 300)
+        .addHeader('X-PaperRoute', 'Node')
+        .before(function() {
+          console.log('Received Request');
+        })
+        .after(function(statCode) {
+          log(statCode, req.url, ip);
+        })
+        .error(function(statCode, msg) {
+          res.writeHead(statCode, {'Content-Type': 'text/plain'});
+          res.end("Error " + statCode);
+          log(statCode, req.url, ip, msg);
+        })
+        .otherwise(function(err) {
+          res.writeHead(404, {'Content-Type': 'text/plain'});
+          res.end("Error 404: File not found");
+          log(404, req.url, ip, err);
+        });
+    }).listen(PORT);
+    
+    function log(statCode, url, ip, err) {
+      var logStr = statCode + ' - ' + url + ' - ' + ip;
+      if (err)
+        logStr += ' - ' + err;
+      console.log(logStr);
+    }
+
+## API Docs
+
+### paperboy.deliver(webroot, req, res)
+
+Checks the `webroot` folder if it has a file that matches the `req.url` and streams it to the client. If `req.url` ends with a '/' (slash), 'index.html' is appended automatically.
+
+Parameters:
+
+* `webroot`: Absolute path where too look for static files to serve
+* `req`: A `http.ServerRequest` object
+* `res`: A `http.ServerResponse` object
+
+This returns an object with several functions that you can call, to modify how the static content is delivered. Each of these functions returns the object, so you can chain them, as shown in the example above. They each take a callback function, whose arguments and expected behavior are detailed below.
+
+#### before(callback())
+
+Fires if a matching file was found in the `webroot` and is about to be delivered. The delivery can be canceled by returning `false` from within the callback.
+
+#### after(callback(statCode))
+
+Fires after a file has been successfully delivered from the `webroot`. `statCode` contains the numeric HTTP status code that was sent to the client. You must close the connection yourself if the error callback fires!
+
+#### error(callback(statCode, msg))
+
+Fires if there was an error delivering a file from the `webroot`. `statCode` contains the numeric HTTP status code that was sent to the client. `msg` contains the error message. You must close the connection yourself if the error callback fires! The default callback shows a minimal HTTP error page.
+
+#### otherwise(callback(err))
+
+Fires if no matching file was found in the `webroot`. Also fires if `false` was returned in the `delegate.before()` callback. If there was a problem stating the file, `err` is set to the contents of that error message. The default callback shows a simple "HTTP 404 File Not Found" page.
+
+#### addHeader(callback(name, value))
+
+Sets an arbitrary HTTP header. The header name `Expires` is special and expects the number of milliseconds till expiry, from which it will calculate the proper HTTP date.
+
+## License
+
+Paperboy is licensed under the MIT license.
+
+## Credits
+
+* [Jan Lehnardt](http://twitter.com/janl) for coming up with the name "Paperboy"

+ 38 - 0
bruml/lib/paperboy/example/basic.js

@@ -0,0 +1,38 @@
+var
+  path = require('path'),
+  http = require('http'),
+  paperboy = require('../lib/paperboy'),
+
+  PORT = 8003,
+  WEBROOT = path.join(path.dirname(__filename), 'webroot');
+
+http.createServer(function(req, res) {
+  var ip = req.connection.remoteAddress;
+  paperboy
+    .deliver(WEBROOT, req, res)
+    .addHeader('Expires', 300)
+    .addHeader('X-PaperRoute', 'Node')
+    .before(function() {
+      console.log('Received Request');
+    })
+    .after(function(statCode) {
+      log(statCode, req.url, ip);
+    })
+    // .error(function(statCode, msg) {
+    //   res.writeHead(statCode, {'Content-Type': 'text/plain'});
+    //   res.end("Error " + statCode);
+    //   log(statCode, req.url, ip, msg);
+    // })
+    // .otherwise(function(err) {
+    //   res.writeHead(404, {'Content-Type': 'text/plain'});
+    //   res.end("Error 404: File not found");
+    //   log(404, req.url, ip, err);
+    // });
+}).listen(PORT);
+
+function log(statCode, url, ip, err) {
+  var logStr = statCode + ' - ' + url + ' - ' + ip;
+  if (err)
+    logStr += ' - ' + err;
+  console.log(logStr);
+}

BIN
bruml/lib/paperboy/example/webroot/img/paperboy.jpg


+ 11 - 0
bruml/lib/paperboy/example/webroot/index.html

@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
+<html lang="en"> 
+<head> 
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
+  <title>Paperboy Example</title> 
+</head>
+<body>
+  <h1>It works!</h1>
+  <img src="/img/paperboy.jpg">
+</body>
+</html> 

+ 1 - 0
bruml/lib/paperboy/index.js

@@ -0,0 +1 @@
+module.exports = require('./lib/paperboy');

+ 302 - 0
bruml/lib/paperboy/lib/paperboy.js

@@ -0,0 +1,302 @@
+var
+  events = require('events'),
+  fs   = require('fs'),
+  url  = require('url'),
+  path = require('path');
+
+exports.filepath = function (webroot, url) {
+  // Unescape URL to prevent security holes
+  url = decodeURIComponent(url);
+  // Append index.html if path ends with '/'
+  fp = path.normalize(path.join(webroot, (url.match(/\/$/)=='/')  ? url+'index.html' : url));
+  // Sanitize input, make sure people can't use .. to get above webroot
+  if (webroot[webroot.length - 1] !== '/') webroot += '/';
+  if (fp.substr(0, webroot.length) != webroot)
+    return(['Permission Denied', null]);
+  else
+    return([null, fp]);
+};
+
+exports.streamFile = function (filepath, headerFields, stat, res, req, emitter) {
+  var
+    emitter = new events.EventEmitter(),
+    extension = filepath.split('.').pop(),
+    contentType = exports.contentTypes[extension] || 'application/octet-stream',
+    charset = exports.charsets[contentType];
+
+  process.nextTick( function() {
+    if (charset)
+      contentType += '; charset=' + charset;
+    headerFields['Content-Type'] = contentType;
+
+    var etag = '"' + stat.ino + '-' + stat.size + '-' + Date.parse(stat.mtime) +'"';
+    headerFields['ETag'] = etag;
+     
+    var statCode;
+    //Check to see if we can send a 304 and skip the send
+    if(req.headers['if-none-match'] == etag){
+      statCode = 304;
+      headerFields['Content-Length'] = 0;
+    }else {
+      headerFields['Content-Length'] = stat.size;
+      statCode = 200;
+      if (headerFields['Expires'] != undefined) {
+        var expires = new Date;
+        expires.setTime(expires.getTime() + headerFields['Expires']);
+        headerFields['Expires'] = expires.toUTCString();
+      }
+    }
+    
+    res.writeHead(statCode, headerFields);
+    
+    //If we sent a 304, skip sending a body
+    if (statCode == 304 || req.method === 'HEAD') {
+      res.end();
+      emitter.emit("success", statCode);
+    }
+    else {
+      fs.createReadStream(filepath,{'flags': 'r', 'encoding': 
+                                    'binary', 'mode': 0666, 'bufferSize': 4 * 1024})
+        .addListener("data", function(chunk){
+          res.write(chunk, 'binary');
+        })
+        .addListener("end", function(){
+          emitter.emit("success", statCode);
+        })
+        .addListener("close",function() {
+          res.end();
+        })
+        .addListener("error", function (e) {
+          emitter.emit("error", 500, e);
+        });
+    }
+  });
+  return emitter;
+};
+
+exports.deliver = function (webroot, req, res) {
+  var
+    stream,
+    fpRes = exports.filepath(webroot, url.parse(req.url).pathname),
+    fpErr = fpRes[0],
+    filepath = fpRes[1],
+    beforeCallback,
+    afterCallback,
+    otherwiseCallback,
+    errorCallback,
+    headerFields = {},
+    addHeaderCallback,
+    delegate = {
+      error: function (callback) {
+        errorCallback = callback;
+        return delegate;
+      },
+      before: function (callback) {
+        beforeCallback = callback;
+        return delegate;
+      },
+      after: function (callback) {
+        afterCallback = callback;
+        return delegate;
+      },
+      otherwise: function (callback) {
+        otherwiseCallback = callback;
+        return delegate;
+      },
+      addHeader: function (name, value) {
+        headerFields[name] = value;
+        return delegate;
+      }
+    };
+    
+  process.nextTick(function() {
+    // Create default error and otherwise callbacks if none were given.
+    errorCallback = errorCallback || function(statCode) {
+      res.writeHead(statCode, {'Content-Type': 'text/html'});
+      res.end("<h1>HTTP " + statCode + "</h1>");
+    };
+    otherwiseCallback = otherwiseCallback || function() {
+      res.writeHead(404, {'Content-Type': 'text/html'});
+      res.end("<h1>HTTP 404 File not found</h1>");
+    };
+
+    //If file is in a directory outside of the webroot, deny the request
+    if (fpErr) {
+      statCode = 403;
+      if (beforeCallback)
+        beforeCallback();
+      errorCallback(403, 'Forbidden');
+    }
+    else {
+      fs.stat(filepath, function (err, stat) {
+        if( (err || !stat.isFile())) {
+          var exactErr = err || 'File not found';
+          if (beforeCallback)
+            beforeCallback();
+          if (otherwiseCallback)
+            otherwiseCallback(exactErr);
+        } else {
+          //The before callback can abort the transfer by returning false
+          var cancel = beforeCallback && (beforeCallback() === false);
+          if (cancel && otherwiseCallback) {
+            otherwiseCallback();
+          }
+          else {
+            stream = exports.streamFile(filepath, headerFields, stat, res, req)
+           
+            if(afterCallback){
+              stream.addListener("success", afterCallback);
+            } 
+            if(errorCallback){
+              stream.addListener("error", errorCallback);
+            }
+          }
+        }
+      });
+    }
+  });
+  
+  return delegate;
+};
+
+exports.contentTypes = {
+  "aiff": "audio/x-aiff",
+  "arj": "application/x-arj-compressed",
+  "asf": "video/x-ms-asf",
+  "asx": "video/x-ms-asx",
+  "au": "audio/ulaw",
+  "avi": "video/x-msvideo",
+  "bcpio": "application/x-bcpio",
+  "ccad": "application/clariscad",
+  "cod": "application/vnd.rim.cod",
+  "com": "application/x-msdos-program",
+  "cpio": "application/x-cpio",
+  "cpt": "application/mac-compactpro",
+  "csh": "application/x-csh",
+  "css": "text/css",
+  "deb": "application/x-debian-package",
+  "dl": "video/dl",
+  "doc": "application/msword",
+  "drw": "application/drafting",
+  "dvi": "application/x-dvi",
+  "dwg": "application/acad",
+  "dxf": "application/dxf",
+  "dxr": "application/x-director",
+  "etx": "text/x-setext",
+  "ez": "application/andrew-inset",
+  "fli": "video/x-fli",
+  "flv": "video/x-flv",
+  "gif": "image/gif",
+  "gl": "video/gl",
+  "gtar": "application/x-gtar",
+  "gz": "application/x-gzip",
+  "hdf": "application/x-hdf",
+  "hqx": "application/mac-binhex40",
+  "html": "text/html",
+  "ice": "x-conference/x-cooltalk",
+  "ief": "image/ief",
+  "igs": "model/iges",
+  "ips": "application/x-ipscript",
+  "ipx": "application/x-ipix",
+  "jad": "text/vnd.sun.j2me.app-descriptor",
+  "jar": "application/java-archive",
+  "jpeg": "image/jpeg",
+  "jpg": "image/jpeg",
+  "js": "text/javascript",
+  "json": "application/json",
+  "latex": "application/x-latex",
+  "lsp": "application/x-lisp",
+  "lzh": "application/octet-stream",
+  "m": "text/plain",
+  "m3u": "audio/x-mpegurl",
+  "man": "application/x-troff-man",
+  "me": "application/x-troff-me",
+  "midi": "audio/midi",
+  "mif": "application/x-mif",
+  "mime": "www/mime",
+  "movie": "video/x-sgi-movie",
+  "mp4": "video/mp4",
+  "mpg": "video/mpeg",
+  "mpga": "audio/mpeg",
+  "ms": "application/x-troff-ms",
+  "nc": "application/x-netcdf",
+  "oda": "application/oda",
+  "ogm": "application/ogg",
+  "pbm": "image/x-portable-bitmap",
+  "pdf": "application/pdf",
+  "pgm": "image/x-portable-graymap",
+  "pgn": "application/x-chess-pgn",
+  "pgp": "application/pgp",
+  "pm": "application/x-perl",
+  "png": "image/png",
+  "pnm": "image/x-portable-anymap",
+  "ppm": "image/x-portable-pixmap",
+  "ppz": "application/vnd.ms-powerpoint",
+  "pre": "application/x-freelance",
+  "prt": "application/pro_eng",
+  "ps": "application/postscript",
+  "qt": "video/quicktime",
+  "ra": "audio/x-realaudio",
+  "rar": "application/x-rar-compressed",
+  "ras": "image/x-cmu-raster",
+  "rgb": "image/x-rgb",
+  "rm": "audio/x-pn-realaudio",
+  "rpm": "audio/x-pn-realaudio-plugin",
+  "rtf": "text/rtf",
+  "rtx": "text/richtext",
+  "scm": "application/x-lotusscreencam",
+  "set": "application/set",
+  "sgml": "text/sgml",
+  "sh": "application/x-sh",
+  "shar": "application/x-shar",
+  "silo": "model/mesh",
+  "sit": "application/x-stuffit",
+  "skt": "application/x-koan",
+  "smil": "application/smil",
+  "snd": "audio/basic",
+  "sol": "application/solids",
+  "spl": "application/x-futuresplash",
+  "src": "application/x-wais-source",
+  "stl": "application/SLA",
+  "stp": "application/STEP",
+  "sv4cpio": "application/x-sv4cpio",
+  "sv4crc": "application/x-sv4crc",
+  "svg": "image/svg+xml",
+  "swf": "application/x-shockwave-flash",
+  "tar": "application/x-tar",
+  "tcl": "application/x-tcl",
+  "tex": "application/x-tex",
+  "texinfo": "application/x-texinfo",
+  "tgz": "application/x-tar-gz",
+  "tiff": "image/tiff",
+  "tr": "application/x-troff",
+  "tsi": "audio/TSP-audio",
+  "tsp": "application/dsptype",
+  "tsv": "text/tab-separated-values",
+  "txt": "text/plain",
+  "unv": "application/i-deas",
+  "ustar": "application/x-ustar",
+  "vcd": "application/x-cdlink",
+  "vda": "application/vda",
+  "vivo": "video/vnd.vivo",
+  "vrm": "x-world/x-vrml",
+  "wav": "audio/x-wav",
+  "wax": "audio/x-ms-wax",
+  "wma": "audio/x-ms-wma",
+  "wmv": "video/x-ms-wmv",
+  "wmx": "video/x-ms-wmx",
+  "wrl": "model/vrml",
+  "wvx": "video/x-ms-wvx",
+  "xbm": "image/x-xbitmap",
+  "xlw": "application/vnd.ms-excel",
+  "xml": "text/xml",
+  "xpm": "image/x-xpixmap",
+  "xwd": "image/x-xwindowdump",
+  "xyz": "chemical/x-pdb",
+  "zip": "application/zip"
+};
+
+exports.charsets = {
+  'text/javascript': 'UTF-8',
+  'text/html': 'UTF-8'
+};

+ 11 - 0
bruml/lib/paperboy/package.json

@@ -0,0 +1,11 @@
+{
+  "name":"paperboy",
+  "author":"Felix Geisendörfer <felix@debuggable.com>",
+  "version":"0.0.2",
+  "description":"A node.js module for delivering static files.",
+  "keywords": ["web", "server"],
+  "directories": {
+    "lib": "lib"
+  },
+  "main": "lib/paperboy"
+}

+ 6 - 0
bruml/lib/paperboy/seed.yml

@@ -0,0 +1,6 @@
+---
+  name: paperboy
+  author: Felix Geisendörfer <felix@debuggable.com>
+  version: 0.0.1
+  description: A node.js module for delivering static files.
+  tags: web server

+ 236 - 0
bruml/lib/socket.io/History.md

@@ -0,0 +1,236 @@
+
+0.6.17 / 2011-03-30 
+==================
+
+  * Fixed the 'possible EventEmitter memory leak detected' bug for the XHR transport
+  * Reconnection support added to chat example. [3rd-Eden]
+
+0.6.16 / 2011-03-04
+===================
+
+  * Fixed cross domain xhr-polling in Safari [tifroz]
+
+0.6.15 / 2011-02-23
+===================
+
+  * Fixed memory leak in WebSocket transport [belorion]
+
+0.6.14 / 2011-02-18
+===================
+
+  * Fixed logging scope issue [shripad]
+
+0.6.13 / 2011-02-18
+===================
+
+  * Fixed references to listener when logging
+
+0.6.12 / 2011-02-18
+===================
+
+  * Fixed noDelay missing file descriptor problem
+
+0.6.11 / 2011-02-15
+===================
+
+  * Fixed; Make sure to not execute any other connection operations after WebSocket
+    write error.
+  * Added more error logging
+
+0.6.10 / 2011-02-09 
+===================
+
+  * Added SSL chat example (`make example-ssl`)
+  * Fixed; possible write errors when a connection error event fires
+
+0.6.9 / 2011-02-06 
+==================
+
+  * 0.3 compatibility
+  * Updated socket.io client to 0.6.2
+  * Fixed Flash inline policy serving for Firefox 4
+  * Updated expresso
+  * Added comments and version number to socket.io/index
+
+0.6.8 / 2011-01-10 
+==================
+
+  * Fixed issue with terminating connection twice
+
+0.6.7 / 2011-01-09 
+==================
+
+  * Fixed situation where the connection drops but the client can still autoreconnect
+    through a different socket. In this case we still want to clear the FD but not
+    call onDisconnect immediately.
+
+0.6.6 / 2011-01-09 
+==================
+
+  * Note for Flash socket and inline policy on Firefox
+  * Destroy the fds on disconnect
+  * Restored 20 secs of polling so that node doesn't timeout the connections
+
+0.6.5 / 2011-01-09 
+==================
+
+  * Make sure not to trigger multiple timeouts when closing
+  * Important fix for polling transports.
+
+0.6.4 / 2011-01-05 
+==================
+
+  * Don't destroy the connection in _onClose. Destroying it will prevent the buffers from being flushed and will result in corrupted responses for the xhr-polling transport.
+  * Added try/catch block around JSON.parse and return an empty object literal if JSON parsing fails.
+  * Added missing .connect() to example
+
+0.6.3 / 2010-12-23 
+==================
+
+  * Changed polling default duration to 50 seconds
+  * might > will Adjusted to 85 column limit
+  * Support for resources that include slashes. Thanks @schamane
+  * Lazy loading of transports. Thanks @technoweenie Fixed README transports list
+  * OpenSSL clarifications (thanks @bmnds)
+  * Support for HAProxy load balancing (thanks Brian McKelvey) Backported Parser from 0.7
+  * Fixed HTTP API in example (was outdated). Thanks deedubs
+  * 0.3 compatibility (thanks Arnout)
+  * `client.broadcast` now 300% faster Cleaned up chat example 
+  * fixed bad pluralization.
+  * cleaned up grammar, missing punctuation, etc.
+  * Restored global `netserver` for flashsocket Now supporting `flashPolicyServer` option (thanks Arnout) Tests passing with and without sudo/root user Fixed noDelay/timeout/utf-8 for draft 76 (accidental typo)
+  * Close the netServer when the main http server closes, this way the event loop does not keep running. NOTE: this is patch for node 0.2.X, this is not required for node 0.3.X
+  * Fallback to try{}catch handling for node < 0.2.4 , node 0.3.X seems to capture the errors correctly using the error event.
+  * Added the flash policy server, it's enabled by default but can be turned off if needed. Socket.io will automatically fallback to serving the policy file inline if server is disabled or unable to start up.
+  * Make sure to only write to open transports (thanks JohnDav)
+  * _open is still false, so destroy the connection immediately upon websocket error
+  * Make sure .connection is not null on 'end'
+  * Proper fix for invalid websocket key
+
+0.6.1 / 2010-11-08
+
+  * Restored flash policy server, but with these changes:
+    - It's contingent on the listener flashPolicyServer option 
+    - It's started by default if socket.io is started with root access
+    - It correctly closes the netserver upon all the dependent http servers being closed
+    - The handler for the inline request is still there regardless. This is important in the following circumstances, and has no performance hit
+      - The port 843 is filtered
+      - Flash at some point enables us to skip 843 checking altogether
+      - Tests compatibility
+  * Fixed connection timeout, noDelay and socket encoding for draft 76 (had been  accidentally moved into the `else` block)
+  * Some stylistic fixes
+
+0.6.0 / 2010-11-01 
+==================
+
+  * Make sure to only write to open transports (thanks JohnDav)
+  * _open is still false, so destroy the connection immediately upon websocket error
+  * Make sure to disconnect directly onClose if the client is not handshaked and he can't possibly reconnect
+  * Make sure to end and destroy connection onDisconnect (for timeouts)
+  * Added missing .listen() call to example. Fixes #80. Thanks @machee
+  * Invalid transport test completed
+  * Initial stab at trying to detect invalid transport responses
+  * Make sure to provide a default for `log` if no log key was provided (internal)
+  * Removed unnecessary file extension verification when serving the client
+  * Removed unnecessary Client check upon connection
+  * Added support for /socket.io/WebSocketMain.swf
+  * Added test for /socket.io/WebSocketMain.swf
+  * Client serving ETag testing
+  * Added htmlfile transport tests
+  * Added extra byte to IE iframe bytes padding
+  * Invalid session id test
+  * end() before destroy()ing the socket for non-WebSocket or non-valid Upgrade requests
+  * Added test for non-socket.io requests
+  * Simplified index.js tests
+  * Moved listener tests into listener.js
+  * Make sure to call .end() when listening on connection 'end' event
+  * Make sure the file descriptor is destroyed on disconnection
+  * Fix for websocket client tracking test
+  * Inline (same port) flash socket policy request.
+  * If the server is not run with root privileges, then the flashsocket
+  transport will instead listen to all new connections on the main port
+  for policy requests. Flash policy requests happen to both port 843 and
+  the destination port:
+  http://www.lightsphere.com/dev/articles/flash_socket_policy.html
+
+  * [websocket test] Fix sending message to client upon connecting
+  * [websocket test] Fix for connection and handshake test
+  * [client files serving] Leverage end() write() call
+  * [client serving] Make sure to not do a useless file lookup when file is cached
+  * Finished json encoding test
+  * Look for the heartbeat in the decoded message
+  * Refactored websocket transports tests to match polling/multipart helpers
+  * Added coverage testing to Makefile
+  * Added heartbeat test to multipart
+  * Added buffered messages test for multipart
+  * Added assertions for `connected` property for all the tests
+  * Multipart clients tracking test
+  * Multipart client>server message sending test
+  * Make sure to only close the client stream when the roundtrip is complete
+  * Multipart connection and handshake tests:
+    - Implemented HTTP client on top of net.Stream with multipart boundary parsing for testing
+    - Test for connection / server>client message sending
+  * Removed unnecessary check for this.connection (since we now access the socket through req.connection for all transports)
+  * Test for `duration` parameter
+  * Added `make example` to Makefile
+  * Added clients tracking test for long polling
+  * Added message buffering test for long polling
+  * Improve this.request/this.response/this.connection
+  * Add 'end' listener onConnect, applies to all transports
+  * Improved error handling onConnect
+  * Remove legacy `flush` calls
+  * Removed unnecessary closeTimeout clearing in jsonp polling
+  * Make sure to close on disconnect if _open = true
+  * Clear disconnection timeout on disconnection (double check)
+  * Make sure to clear closeTimeout for polling transports on close.
+  * Replaced empty with null in log option
+  * Comma first style for client serving tests
+  * Long polling integration tests
+  * Test for heartbeat message
+  * Added heartbeat timeout test
+  * Support for listener#log false
+  * Corrected onConnect signature to support a request and a socket, or a request and a response.
+  * Removed error checking for non-upgradeable sockets, since they'll be destroyed, and error handling is done onConnect
+  * Added tests for websocket client tracking
+  * Added tests for websocket message buffering
+  * Make sure disconnect timeout is cleared on websocket re-connect
+  * Updated the flash socket with error detection, and readystate detection.
+  * This is needed because when a error occures we close down the connection,
+  * and the stream will become unwriteable.
+  * Also changed to a single write instead of multiple writes.
+  * Moved error handling to onConnect to avoid messing with the http.Server global error handlers
+  * Do special error handling for websocket
+  * Clearing heartbeat interval upon closing the connection
+  * Added error listeners, if theses errors are not correcly caught, they will leak memory.
+  * This caused http://speedo.no.de/ to go up from 1mb per connection after a ECONNECTRESET message
+  * Added encode=UTF-8 in jsonp-polling.js and xhr-polling.js since UTF-8 is the default encoding for http.ServerResponse.write
+  * Replaced string.length with Buffer.byteLength in jsonp-polling.js, listener.js and xhr-polling.js because content-length header requires number of bytes and not the number of symbols in string
+  * Fix COR headers/requests for different ports on Safari.
+  * Clearing the references to request, response and connection upon disconnect.
+  * Every require is blocking and requiring the sys module over and over and over again just makes no sense + it hurt performance.. Not to mention.. that it's already included.
+  * Socket.IO-node now serves the client out of the box for easier implementation
+  * Memory caching and ETag support for static files
+  * Tests
+  * Simplified demo even further thanks to new static file serving
+  * Failing to pass an origin header would throw an exception and crash the server. Added some handling.
+  * .connected renamed to ._open, and adopted proper `connected` (fixes #41)
+  * example/client updated to latest socket.io client
+  * Better checking of WebSocket connections
+  * Better handling of SSL location (thanks @jdub)
+  * Fix for cross-domain websocket (fixes #42)
+  * Removed clients/clientsIndex and only using the index (fixes #28)
+  * Fixed WebSocket location header for ws/wss (Thanks @jdub, Fixes #40)
+  * Cross domain issues with xhr-polling addressed. Thanks Niko Kaiser (@nicokaiser)
+  * Added origin verification for incoming data.
+  * Make sure pathname is set (thanks steadicat & swarmation team)
+  * Fix for accessing routes that being with the namespace but are not a connection attempt. Thanks @steadicat from swarmation
+  * JSONP-polling support
+  * Graceful closing of connection for invalid websocket clients
+  * Make it possible to just require 'socket.io'
+  * Make sure to abort the connect() method upon bad upgrade / origin verification
+  * Support for automatic JSON encoding/decoding
+  * Simplified chat example to take advantage of JSON encoding/decoding
+  * Removed fs sync call from example
+  * Better `how to use`
+  * Make sure to send content-type text/plain to `ok` POST responses
+

+ 13 - 0
bruml/lib/socket.io/Makefile

@@ -0,0 +1,13 @@
+test:
+	./support/expresso/bin/expresso -I lib $(TESTFLAGS) tests/*.js
+
+test-cov:
+	@TESTFLAGS=--cov $(MAKE) test
+	
+example:
+	node ./example/server.js
+
+example-ssl:
+	node ./example/server-ssl.js
+
+.PHONY: example

+ 229 - 0
bruml/lib/socket.io/README.md

@@ -0,0 +1,229 @@
+Socket.IO Server: Sockets for the rest of us
+============================================
+
+The `Socket.IO` server provides seamless support for a variety of transports intended for realtime communication.
+
+- WebSocket 
+- WebSocket over Flash (+ XML security policy support)
+- XHR Polling
+- XHR Multipart Streaming
+- Forever Iframe
+- JSONP Polling (for cross domain)
+
+## Requirements
+
+- Node v0.1.103+ with `crypto` module support (make sure you have OpenSSL
+  headers when installing Node to get it)
+- The [Socket.IO client](http://github.com/LearnBoost/Socket.IO), to connect from the browser
+
+## How to use
+
+To run the demo, execute the following:
+
+	git clone git://github.com/LearnBoost/Socket.IO-node.git socket.io
+	cd socket.io/example/
+	sudo node server.js
+
+and point your browser to `http://localhost:8080`. In addition to `8080`, if the transport `flashsocket` is enabled, a server will be initialized to listen for requests on port `843`.
+
+### Implementing it on your project
+
+`Socket.IO` is designed not to take over an entire port or Node `http.Server` instance. This means that if you choose to have your HTTP server listen on port `80`, `socket.io` can intercept requests directed to it, and normal requests will still be served.
+
+By default, the server will intercept requests that contain `socket.io` in the path / resource part of the URI. You can change this as shown in the available options below.
+
+On the server:
+
+	var http = require('http'), 
+			io = require('./path/to/socket.io'),
+			
+	server = http.createServer(function(req, res){
+		// your normal server code
+		res.writeHead(200, {'Content-Type': 'text/html'});
+		res.end('<h1>Hello world</h1>');
+	});
+	
+	server.listen(80);
+			
+	// socket.io, I choose you
+	var socket = io.listen(server);
+	
+	socket.on('connection', function(client){
+	  // new client is here!
+	  client.on('message', function(){ … })
+	  client.on('disconnect', function(){ … })
+	});
+	
+On the client:
+
+	<script src="/socket.io/socket.io.js"></script>
+	<script>
+		var socket = new io.Socket();
+		socket.connect();
+		socket.on('connect', function(){ … })
+		socket.on('message', function(){ … })
+		socket.on('disconnect', function(){ … })
+	</script>
+
+The [client-side](http://github.com/learnboost/socket.io) files are served automatically by `Socket.IO-node`.
+
+## Documentation
+
+### Listener
+
+	io.listen(<http.Server>, [options])
+	
+Returns: a `Listener` instance
+	
+Public Properties:
+
+- *server*
+
+	An instance of _process.http.Server_.
+	
+- *options*
+
+	The passed-in options, combined with the defaults.
+	
+- *clients*
+	
+	An object of clients, indexed by session ID.
+	
+Methods:
+
+- *addListener(event, λ)*
+
+	Adds a listener for the specified event. Optionally, you can pass it as an option to `io.listen`, prefixed by `on`. For example: `onClientConnect: function(){}`
+	
+- *removeListener(event, λ)*	
+
+	Removes a listener from the listener array for the specified event.
+	
+- *broadcast(message, [except])*
+
+	Broadcasts a message to all clients. Optionally, you can pass a single session ID or array of session IDs to avoid broadcasting to, as the second argument.
+	
+Options:
+	
+- *resource*
+
+		socket.io
+
+  The resource is what allows the `socket.io` server to identify incoming connections from `socket.io` clients. Make sure they're in sync.
+  
+- *flashPolicyServer*
+
+		true
+		
+	Create a Flash Policy file server on port `843` (this is restricted port and you will need to have root permission). If you disable the FlashPolicy file server, Socket.IO will automatically fall back to serving the policy file inline.
+		
+
+- *transports*
+
+		['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling',
+    'jsonp-polling']
+		
+	A list of the accepted transports.
+	
+- *transportOptions*
+	
+	An object of options to pass to each transport. For example `{ websocket: { closeTimeout: 8000 }}`
+	
+- *log*
+	
+		ƒ(){ sys.log }
+		
+	The logging function. Defaults to outputting to `stdout` through `sys.log`
+
+Events:
+	
+- *clientConnect(client)*
+	
+	Fired when a client is connected. Receives the Client instance as parameter.
+	
+- *clientMessage(message, client)*
+
+	Fired when a message from a client is received. Receives the message and Client instance as parameters.
+	
+- *clientDisconnect(client)*
+
+	Fired when a client is disconnected. Receives the Client instance as a parameter.
+
+Important note: `this` in the event listener refers to the `Listener` instance.
+
+### Client
+	
+	Client(listener, req, res)
+	
+Public Properties:
+
+- *listener*
+
+	The `Listener` instance to which this client belongs.
+
+- *connected*
+
+	Whether the client is connected.
+	
+- *connections*
+
+	Number of times the client has connected.
+	
+Methods:
+
+- *send(message)*
+
+	Sends a message to the client.
+	
+- *broadcast(message)*
+
+	Sends a message to all other clients. Equivalent to Listener::broadcast(message, client.sessionId).
+
+## Protocol
+
+One of the design goals is that you should be able to implement whatever protocol you desire without `Socket.IO` getting in the way. `Socket.IO` has a minimal, unobtrusive protocol layer, consisting of two parts:
+
+* Connection handshake
+	
+	This is required to simulate a full duplex socket with transports such as XHR Polling or Server-sent Events (which is a "one-way socket"). The basic idea is that the first message received from the server will be a JSON object that contains a session ID used for further communications exchanged between the client and server. 
+	
+	The concept of session also naturally benefits a full-duplex WebSocket, in the event of an accidental disconnection and a quick reconnection. Messages that the server intends to deliver to the client are cached temporarily until reconnection.
+	
+	The implementation of reconnection logic (potentially with retries) is left for the user. By default, transports that are keep-alive or open all the time (like WebSocket) have a timeout of 0 if a disconnection is detected.
+	
+* Message batching
+
+	Messages are buffered in order to optimize resources. In the event of the server trying to send multiple messages while a client is temporarily disconnected (eg: xhr polling), the messages are stacked and then encoded in a lightweight way, and sent to the client whenever it becomes available.
+
+Despite this extra layer, the messages are delivered unaltered to the various event listeners. You can `JSON.stringify()` objects, send XML, or even plain text.
+
+## Credits
+
+- Guillermo Rauch &lt;guillermo@learnboost.com&gt; ([Guille](http://github.com/guille))
+
+- Arnout Kazemier ([3rd-Eden](http://github.com/3rd-Eden))
+
+## License 
+
+(The MIT License)
+
+Copyright (c) 2010 LearnBoost &lt;dev@learnboost.com&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 61 - 0
bruml/lib/socket.io/example/benchmark.html

@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+  <head>
+    <title>socket.io client test</title>
+        
+    <script src="/json.js"></script> <!-- for ie -->
+    <script src="/socket.io/socket.io.js"></script>
+  </head>
+  <body>
+    
+    <script>
+      function message(obj){
+        var el = document.createElement('p');
+        if ('announcement' in obj) el.innerHTML = '<em>' + esc(obj.announcement) + '</em>';
+        else if ('message' in obj) el.innerHTML = '<b>' + esc(obj.message[0]) + ':</b> ' + esc(obj.message[1]);
+        document.getElementById('chat').appendChild(el);
+        document.getElementById('chat').scrollTop = 1000000;
+      }
+      
+      function send(){
+        var val = document.getElementById('text').value;
+        socket.send(val);
+        message({ message: ['you', val] });
+        document.getElementById('text').value = '';
+      }
+      
+      function esc(msg){
+        return msg.replace(/</g, '&lt;').replace(/>/g, '&gt;');
+      };
+      
+      var socket = new io.Socket(null, {port: 8080, rememberTransport: false, transports: ['{transport}']});
+      socket.connect();
+      socket.on('message', function(obj){
+        if ('buffer' in obj){
+          document.getElementById('form').style.display='block';
+          document.getElementById('chat').innerHTML = '';
+          
+          for (var i in obj.buffer) message(obj.buffer[i]);
+        } else message(obj);
+      });
+    </script>
+    
+    <h1>Sample chat client</h1>
+    <div id="chat"><p>Connecting...</p></div>
+    <form id="form" onsubmit="send(); return false">
+      <input type="text" autocomplete="off" id="text"><input type="submit" value="Send">
+    </form>
+    
+    <style>
+      #chat { height: 300px; overflow: auto; width: 800px; border: 1px solid #eee; font: 13px Helvetica, Arial; }
+      #chat p { padding: 8px; margin: 0; }
+      #chat p:nth-child(odd) { background: #F6F6F6; }
+      #form { width: 782px; background: #333; padding: 5px 10px; display: none; }
+      #form input[type=text] { width: 700px; padding: 5px; background: #fff; border: 1px solid #fff; }
+      #form input[type=submit] { cursor: pointer; background: #999; border: none; padding: 6px 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; margin-left: 5px; text-shadow: 0 1px 0 #fff; }
+      #form input[type=submit]:hover { background: #A2A2A2; }
+      #form input[type=submit]:active { position: relative; top: 2px; }
+    </style>
+    
+  </body>
+</html>

+ 21 - 0
bruml/lib/socket.io/example/cert.crt

@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIJAMUSOvlaeyQHMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTAxMTE2MDkzMjQ5WhcNMTMxMTE1MDkzMjQ5WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEVwfPQQp4X
+wtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+1FAE0c5o
+exPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404WthquTqg
+S7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy25IyBK3QJ
+c+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWAQsqW+COL
+0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABo1AwTjAdBgNVHQ4EFgQUDnV4d6mD
+tOnluLoCjkUHTX/n4agwHwYDVR0jBBgwFoAUDnV4d6mDtOnluLoCjkUHTX/n4agw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAFwV4MQfTo+qMv9JMiyno
+IEiqfOz4RgtmBqRnXUffcjS2dhc7/z+FPZnM79Kej8eLHoVfxCyWRHFlzm93vEdv
+wxOCrD13EDOi08OOZfxWyIlCa6Bg8cMAKqQzd2OvQOWqlRWBTThBJIhWflU33izX
+Qn5GdmYqhfpc+9ZHHGhvXNydtRQkdxVK2dZNzLBvBlLlRmtoClU7xm3A+/5dddeP
+AQHEPtyFlUw49VYtZ3ru6KqPms7MKvcRhYLsy9rwSfuuniMlx4d0bDR7TOkw0QQS
+A0N8MGQRQpzl4mw4jLzyM5d5QtuGBh2P6hPGa0YQxtI3RPT/p6ENzzBiAKXiSfzo
+xw==
+-----END CERTIFICATE-----

+ 61 - 0
bruml/lib/socket.io/example/chat-ssl.html

@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+  <head>
+    <title>socket.io client test</title>
+        
+    <script src="/json.js"></script> <!-- for ie -->
+    <script src="/socket.io/socket.io.js"></script>
+  </head>
+  <body>
+    
+    <script>
+      function message(obj){
+        var el = document.createElement('p');
+        if ('announcement' in obj) el.innerHTML = '<em>' + esc(obj.announcement) + '</em>';
+        else if ('message' in obj) el.innerHTML = '<b>' + esc(obj.message[0]) + ':</b> ' + esc(obj.message[1]);
+        document.getElementById('chat').appendChild(el);
+        document.getElementById('chat').scrollTop = 1000000;
+      }
+      
+      function send(){
+        var val = document.getElementById('text').value;
+        socket.send(val);
+        message({ message: ['you', val] });
+        document.getElementById('text').value = '';
+      }
+      
+      function esc(msg){
+        return msg.replace(/</g, '&lt;').replace(/>/g, '&gt;');
+      };
+      
+      var socket = new io.Socket(null, {port: 443, secure: true, rememberTransport: false});
+      socket.connect();
+      socket.on('message', function(obj){
+        if ('buffer' in obj){
+          document.getElementById('form').style.display='block';
+          document.getElementById('chat').innerHTML = '';
+          
+          for (var i in obj.buffer) message(obj.buffer[i]);
+        } else message(obj);
+      });
+    </script>
+    
+    <h1>Sample chat client</h1>
+    <div id="chat"><p>Connecting...</p></div>
+    <form id="form" onsubmit="send(); return false">
+      <input type="text" autocomplete="off" id="text"><input type="submit" value="Send">
+    </form>
+    
+    <style>
+      #chat { height: 300px; overflow: auto; width: 800px; border: 1px solid #eee; font: 13px Helvetica, Arial; }
+      #chat p { padding: 8px; margin: 0; }
+      #chat p:nth-child(odd) { background: #F6F6F6; }
+      #form { width: 782px; background: #333; padding: 5px 10px; display: none; }
+      #form input[type=text] { width: 700px; padding: 5px; background: #fff; border: 1px solid #fff; }
+      #form input[type=submit] { cursor: pointer; background: #999; border: none; padding: 6px 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; margin-left: 5px; text-shadow: 0 1px 0 #fff; }
+      #form input[type=submit]:hover { background: #A2A2A2; }
+      #form input[type=submit]:active { position: relative; top: 2px; }
+    </style>
+    
+  </body>
+</html>

+ 69 - 0
bruml/lib/socket.io/example/chat.html

@@ -0,0 +1,69 @@
+<!doctype html>
+<html>
+  <head>
+    <title>socket.io client test</title>
+        
+    <script src="/json.js"></script> <!-- for ie -->
+    <script src="/socket.io/socket.io.js"></script>
+  </head>
+  <body>
+    
+    <script>
+      function message(obj){
+        var el = document.createElement('p');
+        if ('announcement' in obj) el.innerHTML = '<em>' + esc(obj.announcement) + '</em>';
+        else if ('message' in obj) el.innerHTML = '<b>' + esc(obj.message[0]) + ':</b> ' + esc(obj.message[1]);
+        
+        if( obj.message && window.console && console.log ) console.log(obj.message[0], obj.message[1]);
+        document.getElementById('chat').appendChild(el);
+        document.getElementById('chat').scrollTop = 1000000;
+      }
+      
+      function send(){
+        var val = document.getElementById('text').value;
+        socket.send(val);
+        message({ message: ['you', val] });
+        document.getElementById('text').value = '';
+      }
+      
+      function esc(msg){
+        return msg.replace(/</g, '&lt;').replace(/>/g, '&gt;');
+      };
+      
+      var socket = new io.Socket(null, {port: 8080, rememberTransport: false});
+      socket.connect();
+      socket.on('message', function(obj){
+        if ('buffer' in obj){
+          document.getElementById('form').style.display='block';
+          document.getElementById('chat').innerHTML = '';
+          
+          for (var i in obj.buffer) message(obj.buffer[i]);
+        } else message(obj);
+      });
+      
+      socket.on('connect', function(){ message({ message: ['System', 'Connected']})});
+      socket.on('disconnect', function(){ message({ message: ['System', 'Disconnected']})});
+      socket.on('reconnect', function(){ message({ message: ['System', 'Reconnected to server']})});
+      socket.on('reconnecting', function( nextRetry ){ message({ message: ['System', 'Attempting to re-connect to the server, next attempt in ' + nextRetry + 'ms']})});
+      socket.on('reconnect_failed', function(){ message({ message: ['System', 'Reconnected to server FAILED.']})});
+    </script>
+    
+    <h1>Sample chat client</h1>
+    <div id="chat"><p>Connecting...</p></div>
+    <form id="form" onSubmit="send(); return false">
+      <input type="text" autocomplete="off" id="text"><input type="submit" value="Send">
+    </form>
+    
+    <style>
+      #chat { height: 300px; overflow: auto; width: 800px; border: 1px solid #eee; font: 13px Helvetica, Arial; }
+      #chat p { padding: 8px; margin: 0; }
+      #chat p:nth-child(odd) { background: #F6F6F6; }
+      #form { width: 782px; background: #333; padding: 5px 10px; display: none; }
+      #form input[type=text] { width: 700px; padding: 5px; background: #fff; border: 1px solid #fff; }
+      #form input[type=submit] { cursor: pointer; background: #999; border: none; padding: 6px 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; margin-left: 5px; text-shadow: 0 1px 0 #fff; }
+      #form input[type=submit]:hover { background: #A2A2A2; }
+      #form input[type=submit]:active { position: relative; top: 2px; }
+    </style>
+    
+  </body>
+</html>

+ 18 - 0
bruml/lib/socket.io/example/json.js

@@ -0,0 +1,18 @@
+if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}
+Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+
+f(this.getUTCMonth()+1)+'-'+
+f(this.getUTCDate())+'T'+
+f(this.getUTCHours())+':'+
+f(this.getUTCMinutes())+':'+
+f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}
+c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+
+(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
+if(typeof value.toJSON==='function'){return stringify(value.toJSON());}
+a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}
+return'['+a.join(',')+']';}
+if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}
+return'{'+a.join(',')+'}';}}
+return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}}}}
+return filter(k,v);}
+if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}
+throw new SyntaxError('parseJSON');}};}();}

+ 27 - 0
bruml/lib/socket.io/example/key.key

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEV
+wfPQQp4XwtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+
+1FAE0c5oexPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404
+WthquTqgS7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy2
+5IyBK3QJc+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWA
+QsqW+COL0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABAoIBAGe4+9VqZfJN+dsq
+8Osyuz01uQ8OmC0sAWTIqUlQgENIyf9rCJsUBlYmwR5BT6Z69XP6QhHdpSK+TiAR
+XUz0EqG9HYzcxHIBaACP7j6iRoQ8R4kbbiWKo0z3WqQGIOqFjvD/mKEuQdE5mEYw
+eOUCG6BnX1WY2Yr8WKd2AA/tp0/Y4d8z04u9eodMpSTbHTzYMJb5SbBN1vo6FY7q
+8zSuO0BMzXlAxUsCwHsk1GQHFr8Oh3zIR7bQGtMBouI+6Lhh7sjFYsfxJboqMTBV
+IKaA216M6ggHG7MU1/jeKcMGDmEfqQLQoyWp29rMK6TklUgipME2L3UD7vTyAVzz
+xbVOpZkCgYEA8CXW4sZBBrSSrLR5SB+Ubu9qNTggLowOsC/kVKB2WJ4+xooc5HQo
+mFhq1v/WxPQoWIxdYsfg2odlL+JclK5Qcy6vXmRSdAQ5lK9gBDKxZSYc3NwAw2HA
+zyHCTK+I0n8PBYQ+yGcrxu0WqTGnlLW+Otk4CejO34WlgHwbH9bbY5UCgYEA3ZvT
+C4+OoMHXlmICSt29zUrYiL33IWsR3/MaONxTEDuvgkOSXXQOl/8Ebd6Nu+3WbsSN
+bjiPC/JyL1YCVmijdvFpl4gjtgvfJifs4G+QHvO6YfsYoVANk4u6g6rUuBIOwNK4
+RwYxwDc0oysp+g7tPxoSgDHReEVKJNzGBe9NGGsCgYEA4O4QP4gCEA3B9BF2J5+s
+n9uPVxmiyvZUK6Iv8zP4pThTBBMIzNIf09G9AHPQ7djikU2nioY8jXKTzC3xGTHM
+GJZ5m6fLsu7iH+nDvSreDSeNkTBfZqGAvoGYQ8uGE+L+ZuRfCcXYsxIOT5s6o4c3
+Dle2rVFpsuKzCY00urW796ECgYBn3go75+xEwrYGQSer6WR1nTgCV29GVYXKPooy
+zmmMOT1Yw80NSkEw0pFD4cTyqVYREsTrPU0mn1sPfrOXxnGfZSVFpcR/Je9QVfQ7
+eW7GYxwfom335aqHVj10SxRqteP+UoWWnHujCPz94VRKZMakBddYCIGSan+G6YdS
+7sdmwwKBgBc2qj0wvGXDF2kCLwSGfWoMf8CS1+5fIiUIdT1e/+7MfDdbmLMIFVjF
+QKS3zVViXCbrG5SY6wS9hxoc57f6E2A8vcaX6zy2xkZlGHQCpWRtEM5R01OWJQaH
+HsHMmQZGUQVoDm1oRkDhrTFK4K3ukc3rAxzeTZ96utOQN8/KJsTv
+-----END RSA PRIVATE KEY-----

+ 66 - 0
bruml/lib/socket.io/example/server-ssl.js

@@ -0,0 +1,66 @@
+/**
+ * Important note: this application is not suitable for benchmarks!
+ */
+
+var https = require('https')
+  , url = require('url')
+  , fs = require('fs')
+  , io = require('../')
+  , sys = require(process.binding('natives').util ? 'util' : 'sys')
+  , server;
+    
+server = https.createServer({
+    key: fs.readFileSync(__dirname + '/key.key')
+  , cert: fs.readFileSync(__dirname + '/cert.crt')
+}, function(req, res){
+  // your normal server code
+  var path = url.parse(req.url).pathname;
+  switch (path){
+    case '/':
+      res.writeHead(200, {'Content-Type': 'text/html'});
+      res.write('<h1>Welcome. Try the <a href="/chat-ssl.html">SSL Chat</a> example.</h1>');
+      res.end();
+      break;
+      
+    case '/json.js':
+    case '/chat-ssl.html':
+      fs.readFile(__dirname + path, function(err, data){
+        if (err) return send404(res);
+        res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})
+        res.write(data, 'utf8');
+        res.end();
+      });
+      break;
+      
+    default: send404(res);
+  }
+}),
+
+send404 = function(res){
+  res.writeHead(404);
+  res.write('404');
+  res.end();
+};
+
+server.listen(443);
+
+// socket.io, I choose you
+// simplest chat application evar
+var io = io.listen(server)
+  , buffer = [];
+  
+io.on('connection', function(client){
+  client.send({ buffer: buffer });
+  client.broadcast({ announcement: client.sessionId + ' connected' });
+  
+  client.on('message', function(message){
+    var msg = { message: [client.sessionId, message] };
+    buffer.push(msg);
+    if (buffer.length > 15) buffer.shift();
+    client.broadcast(msg);
+  });
+
+  client.on('disconnect', function(){
+    client.broadcast({ announcement: client.sessionId + ' disconnected' });
+  });
+});

+ 77 - 0
bruml/lib/socket.io/example/server.benchmark.js

@@ -0,0 +1,77 @@
+/**
+ * Important note: this application is not suitable for benchmarks!
+ */
+
+var http = require('http')
+  , url = require('url')
+  , fs = require('fs')
+  , io = require('../')
+  , sys = require(process.binding('natives').util ? 'util' : 'sys')
+  , server;
+    
+server = http.createServer(function(req, res){
+  // your normal server code
+  var path = url.parse(req.url).pathname;
+  switch (path){
+    case '/':
+      res.writeHead(200, {'Content-Type': 'text/html'});
+      res.write([
+          '<h1>Welcome.</h1>'
+        , '<h2>Transports:</h2>'
+        , '<ul>'
+        ,   '<li><a href="/benchmark.html?xhr-polling">Long polling</a></li>'
+        ,   '<li><a href="/benchmark.html?xhr-multipart">Multipart XHR</a></li>'
+        ,   '<li><a href="/benchmark.html?websocket">WebSocket</a></li>'
+        ,   '<li><a href="/benchmark.html?flashsocket">FlashSocket</a></li>'
+        ,   '<li><a href="/benchmark.html?htmlfile">HTMLFile</a></li>'
+        ,   '<li><a href="/benchmark.html?jsonp-polling">JSONP Polling</a></li>'
+        , '</ul>'
+      ].join(''));
+      res.end();
+      break;
+      
+    case '/json.js':
+    case '/benchmark.html':
+      fs.readFile(__dirname + path, function(err, data){
+        if (err) return send404(res);
+        res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})
+        res.write(data.toString().replace('{transport}'
+                    , req.url.replace('/benchmark.html', ''))
+                , 'utf8');
+        res.end();
+      });
+      break;
+      
+    default: send404(res);
+  }
+}),
+
+send404 = function(res){
+  res.writeHead(404);
+  res.write('404');
+  res.end();
+};
+
+server.listen(8080);
+
+// socket.io, I choose you
+// simplest chat application evar
+var io = io.listen(server)
+  , buffer = [];
+  
+io.on('connection', function(client){
+  // track latency and number of messages
+  client.latency = 0;
+  client.messages = 0;
+
+  client.send(Date.now());
+  
+  client.on('message', function(message){
+    client.latency += 
+    console.log('Message latency:', Date.now() - Number(message));
+  });
+
+  client.on('disconnect', function(){
+    console.log();
+  });
+});

+ 63 - 0
bruml/lib/socket.io/example/server.js

@@ -0,0 +1,63 @@
+/**
+ * Important note: this application is not suitable for benchmarks!
+ */
+
+var http = require('http')
+  , url = require('url')
+  , fs = require('fs')
+  , io = require('../')
+  , sys = require(process.binding('natives').util ? 'util' : 'sys')
+  , server;
+    
+server = http.createServer(function(req, res){
+  // your normal server code
+  var path = url.parse(req.url).pathname;
+  switch (path){
+    case '/':
+      res.writeHead(200, {'Content-Type': 'text/html'});
+      res.write('<h1>Welcome. Try the <a href="/chat.html">chat</a> example.</h1>');
+      res.end();
+      break;
+      
+    case '/json.js':
+    case '/chat.html':
+      fs.readFile(__dirname + path, function(err, data){
+        if (err) return send404(res);
+        res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})
+        res.write(data, 'utf8');
+        res.end();
+      });
+      break;
+      
+    default: send404(res);
+  }
+}),
+
+send404 = function(res){
+  res.writeHead(404);
+  res.write('404');
+  res.end();
+};
+
+server.listen(8080);
+
+// socket.io, I choose you
+// simplest chat application evar
+var io = io.listen(server)
+  , buffer = [];
+  
+io.on('connection', function(client){
+  client.send({ buffer: buffer });
+  client.broadcast({ announcement: client.sessionId + ' connected' });
+  
+  client.on('message', function(message){
+    var msg = { message: [client.sessionId, message] };
+    buffer.push(msg);
+    if (buffer.length > 15) buffer.shift();
+    client.broadcast(msg);
+  });
+
+  client.on('disconnect', function(){
+    client.broadcast({ announcement: client.sessionId + ' disconnected' });
+  });
+});

+ 1 - 0
bruml/lib/socket.io/index.js

@@ -0,0 +1 @@
+module.exports = require('./lib/socket.io');

+ 197 - 0
bruml/lib/socket.io/lib/socket.io/client.js

@@ -0,0 +1,197 @@
+var urlparse = require('url').parse
+  , OutgoingMessage = require('http').OutgoingMessage
+  , Stream = require('net').Stream
+  , options = require('./utils').options
+  , encode = require('./utils').encode
+  , decode = require('./utils').decode
+  , merge = require('./utils').merge
+  , util = require(process.binding('natives').util ? 'util' : 'sys');
+
+var Client = module.exports = function(listener, req, res, options, head){
+  process.EventEmitter.call(this);
+  this.listener = listener;
+  this.options(merge({
+    timeout: 8000,
+    heartbeatInterval: 10000,
+    closeTimeout: 0
+  }, this.getOptions ? this.getOptions() : {}), options);
+  this.connections = 0;
+  this._open = false;
+  this._heartbeats = 0;
+  this.connected = false;
+  this.upgradeHead = head;
+  this._onConnect(req, res);
+};
+
+util.inherits(Client, process.EventEmitter);
+
+Client.prototype.send = function(message){
+  if (!this._open || !(this.connection.readyState === 'open' || this.connection.readyState === 'writeOnly')){
+    return this._queue(message);
+  }
+  this._write(encode(message));
+  return this;
+};
+
+Client.prototype.broadcast = function(message){
+  if (!('sessionId' in this)) return this;
+  this.listener.broadcast(message, this.sessionId);
+  return this;
+};
+
+Client.prototype._onMessage = function(data){
+  var messages = decode(data);
+  if (messages === false) return this.listener.options.log('Bad message received from client ' + this.sessionId);
+  for (var i = 0, l = messages.length, frame; i < l; i++){
+    frame = messages[i].substr(0, 3);
+    switch (frame){
+      case '~h~':
+        return this._onHeartbeat(messages[i].substr(3));
+      case '~j~':
+        try {
+          messages[i] = JSON.parse(messages[i].substr(3));
+        } catch(e) {
+          messages[i] = {};
+        }
+        break;
+    }
+    this.emit('message', messages[i]);
+    this.listener._onClientMessage(messages[i], this);
+  }
+};
+
+Client.prototype._onConnect = function(req, res){
+  var self = this
+    , attachConnection = !this.connection;
+
+  this.request = req;
+  this.response = res;
+  this.connection = req.connection;
+
+  if(!attachConnection) attachConnection = !attachConnection && this.connection.eventsAttached === undefined;
+  this.connection.eventsAttached = true;
+  
+  if (attachConnection){
+    function destroyConnection(){
+      self._onClose();
+      self.connection && self.connection.destroy()
+    };
+    this.connection.addListener('end', destroyConnection);
+    this.connection.addListener('timeout', destroyConnection);
+    this.connection.addListener('error', destroyConnection);
+    }
+  
+  if (req){
+    function destroyRequest(){
+      req.destroy && req.destroy();
+    };
+    req.addListener('error', destroyRequest);
+    req.addListener('timeout', destroyRequest);
+    if (res){
+      function destroyResponse(){
+        res.destroy && res.destroy();
+      }
+      res.addListener('error', destroyResponse);
+      res.addListener('timeout', destroyResponse);
+    }
+    if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
+  }
+};
+
+
+Client.prototype._payload = function(){
+  var payload = [];
+  
+  this.connections++;
+  this.connected = true;
+  this._open = true;
+  
+  if (!this.handshaked){
+    this._generateSessionId();
+    payload.push(this.sessionId);
+    this.handshaked = true;
+  }
+  
+  payload = payload.concat(this._writeQueue || []);
+  this._writeQueue = [];
+
+  if (payload.length) this._write(encode(payload));
+  if (this.connections === 1) this.listener._onClientConnect(this);
+  if (this.options.timeout) this._heartbeat();
+};
+  
+Client.prototype._heartbeat = function(){
+  var self = this;
+  this._heartbeatInterval = setTimeout(function(){
+    self.send('~h~' + ++self._heartbeats);
+    self._heartbeatTimeout = setTimeout(function(){
+      self._onClose();
+    }, self.options.timeout);
+  }, self.options.heartbeatInterval);
+};
+  
+Client.prototype._onHeartbeat = function(h){
+  if (h == this._heartbeats){
+    clearTimeout(this._heartbeatTimeout);
+    this._heartbeat();
+  }
+};
+
+Client.prototype._onClose = function(skipDisconnect){
+  if (!this._open) return this;
+  var self = this;
+  if (this._heartbeatInterval) clearTimeout(this._heartbeatInterval);
+  if (this._heartbeatTimeout) clearTimeout(this._heartbeatTimeout);
+  this._open = false;
+  this.request = null;
+  this.response = null;
+  if (skipDisconnect !== false){
+    if (this.handshaked){
+      this._disconnectTimeout = setTimeout(function(){
+        self._onDisconnect();
+      }, this.options.closeTimeout);
+    } else
+      this._onDisconnect();
+  }
+};
+
+Client.prototype._onDisconnect = function(){
+  if (this._open) this._onClose(true);
+  if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
+  this._writeQueue = [];
+  this.connected = false;
+  if (this.handshaked){
+    this.emit('disconnect');
+    this.listener._onClientDisconnect(this);
+    this.handshaked = false;
+  }
+};
+
+Client.prototype._queue = function(message){
+  this._writeQueue = this._writeQueue || [];
+  this._writeQueue.push(message);
+  return this;
+};
+
+Client.prototype._generateSessionId = function(){
+  this.sessionId = Math.random().toString().substr(2);
+  return this;
+};
+
+Client.prototype._verifyOrigin = function(origin){
+  var origins = this.listener.options.origins;
+  if (origins.indexOf('*:*') !== -1) {
+    return true;
+  }
+  if (origin) {
+    try {
+      var parts = urlparse(origin);
+      return origins.indexOf(parts.host + ':' + parts.port) !== -1 ||
+          origins.indexOf(parts.host + ':*') !== -1 ||
+          origins.indexOf('*:' + parts.port) !== -1;  
+    } catch (ex) {}
+  }
+  return false;
+};
+
+for (var i in options) Client.prototype[i] = options[i];

+ 26 - 0
bruml/lib/socket.io/lib/socket.io/index.js

@@ -0,0 +1,26 @@
+
+/**
+ * Listener creation shorcut
+ *
+ * @param {Server} node HTTP server
+ * @param {Object} options
+ * @api public
+ */
+
+exports.listen = function(server, options){
+  return new exports.Listener(server, options);
+};
+
+/**
+ * Listener constructor
+ *
+ * @api public
+ */
+
+exports.Listener = require('./listener');
+
+/**
+ * Version
+ */
+
+exports.version = '0.6.17';

+ 166 - 0
bruml/lib/socket.io/lib/socket.io/listener.js

@@ -0,0 +1,166 @@
+var url = require('url')
+  , util = require(process.binding('natives').util ? 'util' : 'sys')
+  , fs = require('fs')
+  , options = require('./utils').options
+  , Client = require('./client')
+  , clientVersion = require('./../../support/socket.io-client/lib/io').io.version
+  , transports = {};
+
+var Listener = module.exports = function(server, options){
+  process.EventEmitter.call(this);
+  var self = this;
+  this.server = server;
+  this.options({
+    origins: '*:*',
+    resource: 'socket.io',
+    flashPolicyServer: true,
+    transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart',
+                 'xhr-polling', 'jsonp-polling'],
+    transportOptions: {},
+    log: util.log
+  }, options);
+  
+  if (!this.options.log) this.options.log = function(){};
+
+  this.clients = this.clientsIndex = {};
+  this._clientCount = 0;
+  this._clientFiles = {};
+  
+  var listeners = this.server.listeners('request');
+  this.server.removeAllListeners('request');
+  
+  this.server.addListener('request', function(req, res){
+    if (self.check(req, res)) return;
+    for (var i = 0, len = listeners.length; i < len; i++){
+      listeners[i].call(this, req, res);
+    }
+  });
+  
+  this.server.addListener('upgrade', function(req, socket, head){
+    if (!self.check(req, socket, true, head)){
+      socket.end();
+      socket.destroy();
+    }
+  });
+  
+  this.options.transports.forEach(function(name) {
+    if (!(name in transports))
+      transports[name] = require('./transports/' + name);
+    if ('init' in transports[name]) transports[name].init(self);
+  });
+
+  this.options.log('socket.io ready - accepting connections');
+};
+
+util.inherits(Listener, process.EventEmitter);
+for (var i in options) Listener.prototype[i] = options[i];
+
+Listener.prototype.broadcast = function(message, except){
+  for (var i = 0, k = Object.keys(this.clients), l = k.length; i < l; i++){
+    if (!except || ((typeof except == 'number' || typeof except == 'string') && k[i] != except)
+                || (Array.isArray(except) && except.indexOf(k[i]) == -1)){
+      this.clients[k[i]].send(message);
+    }
+  }
+  return this;
+};
+
+Listener.prototype.check = function(req, res, httpUpgrade, head){
+  var path = url.parse(req.url).pathname, parts, cn;
+  if (path && path.indexOf('/' + this.options.resource) === 0){
+    parts = path.substr(2 + this.options.resource.length).split('/');
+    if (this._serveClient(parts.join('/'), req, res)) return true;
+    if (!(parts[0] in transports)) return false;
+    if (parts[1]){
+      cn = this.clients[parts[1]];
+      if (cn){
+        cn._onConnect(req, res);
+      } else {
+        req.connection.end();
+        req.connection.destroy();
+        this.options.log('Couldnt find client with session id "' + parts[1] + '"');
+      }
+    } else {
+      this._onConnection(parts[0], req, res, httpUpgrade, head);
+    }
+    return true;
+  }
+  return false;
+};
+
+Listener.prototype._serveClient = function(file, req, res){
+  var self = this
+    , clientPaths = {
+        'socket.io.js': 'socket.io.js',
+        'lib/vendor/web-socket-js/WebSocketMain.swf': 'lib/vendor/web-socket-js/WebSocketMain.swf', // for compat with old clients
+        'WebSocketMain.swf': 'lib/vendor/web-socket-js/WebSocketMain.swf'
+      }
+    , types = {
+        swf: 'application/x-shockwave-flash',
+        js: 'text/javascript'
+      };
+  
+  function write(path){
+    if (req.headers['if-none-match'] == clientVersion){
+      res.writeHead(304);
+      res.end();
+    } else {
+      res.writeHead(200, self._clientFiles[path].headers);
+      res.end(self._clientFiles[path].content, self._clientFiles[path].encoding);
+    }
+  };
+  
+  var path = clientPaths[file];
+  
+  if (req.method == 'GET' && path !== undefined){
+    if (path in this._clientFiles){
+      write(path);
+      return true;
+    }
+    
+    fs.readFile(__dirname + '/../../support/socket.io-client/' + path, function(err, data){
+      if (err){
+        res.writeHead(404);
+        res.end('404');
+      } else {
+        var ext = path.split('.').pop();
+        self._clientFiles[path] = {
+          headers: {
+            'Content-Length': data.length,
+            'Content-Type': types[ext],
+            'ETag': clientVersion
+          },
+          content: data,
+          encoding: ext == 'swf' ? 'binary' : 'utf8'
+        };
+        write(path);
+      }
+    });
+    
+    return true;
+  }
+  
+  return false;
+};
+
+Listener.prototype._onClientConnect = function(client){
+  this.clients[client.sessionId] = client;
+  this.options.log('Client '+ client.sessionId +' connected');
+  this.emit('clientConnect', client);
+  this.emit('connection', client);
+};
+
+Listener.prototype._onClientMessage = function(data, client){
+  this.emit('clientMessage', data, client);
+};
+
+Listener.prototype._onClientDisconnect = function(client){
+  delete this.clients[client.sessionId];
+  this.options.log('Client '+ client.sessionId +' disconnected');
+  this.emit('clientDisconnect', client);
+};
+
+Listener.prototype._onConnection = function(transport, req, res, httpUpgrade, head){
+  this.options.log('Initializing client with transport "'+ transport +'"');
+  new transports[transport](this, req, res, this.options.transportOptions[transport], head);
+};

+ 89 - 0
bruml/lib/socket.io/lib/socket.io/transports/flashsocket.js

@@ -0,0 +1,89 @@
+var net = require('net')
+  , util = require(process.binding('natives').util ? 'util' : 'sys')
+  , WebSocket = require('./websocket')
+  , listeners = []
+  , netserver;
+
+var Flashsocket = module.exports = function(){
+  WebSocket.apply(this, arguments);
+};
+
+util.inherits(Flashsocket, WebSocket);
+
+Flashsocket.httpUpgrade = true;
+
+Flashsocket.init = function(listener){
+  listeners.push(listener);
+  
+  listener.server.on('close', function(){
+    listeners.splice(listeners.indexOf(listener), 1);
+
+    if (listeners.length === 0 && netserver){
+      try {
+        netserver.close();
+      } catch(e){
+	    listener.options.log('flashsocket netserver close error - ' + e.stack)
+      }
+    }
+  });
+  
+  if (listener.options.flashPolicyServer && netserver === undefined){
+    netserver = net.createServer(function(socket){
+      socket.addListener('error', function(err){
+        if (socket && socket.end){
+          socket.end();
+          socket.destroy();
+        }
+      });
+
+      if(socket && socket.readyState == 'open')
+        socket.end(policy(listeners));
+    });
+    
+    try {
+      netserver.listen(843);
+    } catch(e){
+      if (e.errno == 13)
+        listener.options.log('Your node instance does not have root privileges. ' 
+                           + 'This means that the flash XML policy file will be '
+                           + 'served inline instead of on port 843. This will slow '
+                           + 'down initial connections slightly.');
+      netserver = null;
+    }
+  }
+  
+  // Could not listen on port 843 so policy requests will be inline
+  listener.server.addListener('connection', function(stream){
+    var flashCheck = function (data) {
+      // Only check the initial data
+      stream.removeListener("data", flashCheck);
+      if (data[0] === 60 && data.length == 23) {
+        if (data == '<policy-file-request/>\0') {
+          listener.options.log("Answering flash policy request inline");
+          if (stream && stream.readyState == 'open'){
+            var xml = policy([listener]);
+            stream.write(xml);
+            stream.end();
+          }
+        }
+      }
+    };
+    
+    stream.on('data', flashCheck);
+  });
+};
+
+function policy(listeners) {
+  var xml = '<?xml version="1.0"?>\n<!DOCTYPE cross-domain-policy SYSTEM'
+          + ' "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">\n<cross-domain-policy>\n';
+
+  listeners.forEach(function(l){
+    [].concat(l.options.origins).forEach(function(origin){
+      var parts = origin.split(':');
+      xml += '<allow-access-from domain="' + parts[0] + '" to-ports="'+ parts[1] +'"/>\n';
+    });
+  });
+
+  xml += '</cross-domain-policy>\n';
+  return xml;
+};

+ 49 - 0
bruml/lib/socket.io/lib/socket.io/transports/htmlfile.js

@@ -0,0 +1,49 @@
+var Client = require('../client')
+  , util = require(process.binding('natives').util ? 'util' : 'sys')
+  , qs = require('querystring');
+
+var HTMLFile = module.exports = function(){
+  Client.apply(this, arguments);
+};
+
+util.inherits(HTMLFile, Client);
+  
+HTMLFile.prototype._onConnect = function(req, res){
+  var self = this, body = '';
+  switch (req.method){
+    case 'GET':
+      Client.prototype._onConnect.call(this, req, res);
+      this.response.useChunkedEncodingByDefault = true;
+      this.response.shouldKeepAlive = true;
+      this.response.writeHead(200, {
+        'Content-Type': 'text/html',
+        'Connection': 'keep-alive',
+        'Transfer-Encoding': 'chunked'
+      });
+      this.response.write('<html><body>' + new Array(245).join(' '));
+      this._payload();
+      break;
+      
+    case 'POST':
+      req.addListener('data', function(message){
+        body += message;
+      });
+      req.addListener('end', function(){
+        try {
+          var msg = qs.parse(body);
+          self._onMessage(msg.data);
+        } catch(e){
+          self.listener.options.log('htmlfile message handler error - ' + e.stack);
+        }
+        res.writeHead(200, {'Content-Type': 'text/plain'});
+        res.write('ok');
+        res.end();
+      });
+      break;
+  }
+};
+  
+HTMLFile.prototype._write = function(message){
+  if (this._open)
+    this.response.write('<script>parent.s._('+ JSON.stringify(message) +', document);</script>'); //json for escaping
+};

+ 35 - 0
bruml/lib/socket.io/lib/socket.io/transports/jsonp-polling.js

@@ -0,0 +1,35 @@
+var XHRPolling = require('./xhr-polling')
+  , util = require(process.binding('natives').util ? 'util' : 'sys');
+
+JSONPPolling = module.exports = function(){
+  XHRPolling.apply(this, arguments);
+};
+
+util.inherits(JSONPPolling, XHRPolling);
+  
+JSONPPolling.prototype.getOptions = function(){
+  return {
+    timeout: null, // no heartbeats
+    closeTimeout: 8000,
+    duration: 20000
+  };
+};
+  
+JSONPPolling.prototype._onConnect = function(req, res){
+  this._index = req.url.match(/\/([0-9]+)\/?$/).pop();
+  XHRPolling.prototype._onConnect.call(this, req, res);
+};
+  
+JSONPPolling.prototype._write = function(message){
+  if (this._open){
+    if (this.request.headers.origin && !this._verifyOrigin(this.request.headers.origin)){
+      message = "alert('Cross domain security restrictions not met');";
+    } else {
+      message = "io.JSONP["+ this._index +"]._("+ JSON.stringify(message) +");";
+    }
+    this.response.writeHead(200, {'Content-Type': 'text/javascript; charset=UTF-8', 'Content-Length': Buffer.byteLength(message)});
+    this.response.write(message);
+    this.response.end();
+    this._onClose();
+  }
+};

+ 208 - 0
bruml/lib/socket.io/lib/socket.io/transports/websocket.js

@@ -0,0 +1,208 @@
+var Client = require('../client')
+  , Stream = require('net').Stream
+  , EventEmitter = require('events').EventEmitter
+  , url = require('url')
+  , util = require(process.binding('natives').util ? 'util' : 'sys')
+  , crypto = require('crypto');
+
+WebSocket = module.exports = function(){
+  Client.apply(this, arguments);
+};
+
+util.inherits(WebSocket, Client);
+
+WebSocket.prototype._onConnect = function(req, socket){
+  var self = this
+    , headers = [];
+  
+  if (!req.connection.setTimeout){
+    req.connection.end();
+    return false;
+  }
+
+  this.parser = new Parser();
+  this.parser.on('data', self._onMessage.bind(this));
+  this.parser.on('error', self._onClose.bind(this));
+
+  Client.prototype._onConnect.call(this, req);
+    
+  if (this.request.headers.upgrade !== 'WebSocket' || !this._verifyOrigin(this.request.headers.origin)){
+    this.listener.options.log('WebSocket connection invalid or Origin not verified');
+    this._onClose();
+    return false;
+  }
+  
+  var origin = this.request.headers.origin,
+      location = (origin && origin.substr(0, 5) == 'https' ? 'wss' : 'ws')
+               + '://' + this.request.headers.host + this.request.url;
+  
+  this.waitingForNonce = false;
+  if ('sec-websocket-key1' in this.request.headers){
+    /*  We need to send the 101 response immediately when using Draft 76 with
+      	a load balancing proxy, such as HAProxy.  In order to protect an
+      	unsuspecting non-websocket HTTP server, HAProxy will not send the
+      	8-byte nonce through the connection until the Upgrade: WebSocket
+      	request has been confirmed by the WebSocket server by a 101 response
+      	indicating that the server can handle the upgraded protocol.  We
+      	therefore must send the 101 response immediately, and then wait for
+      	the nonce to be forwarded to us afterward in order to finish the
+      	Draft 76 handshake.
+      */
+    
+    // If we don't have the nonce yet, wait for it.
+    if (!(this.upgradeHead && this.upgradeHead.length >= 8)) {
+      this.waitingForNonce = true;
+    }
+    
+    headers = [
+      'HTTP/1.1 101 WebSocket Protocol Handshake',
+      'Upgrade: WebSocket',
+      'Connection: Upgrade',
+      'Sec-WebSocket-Origin: ' + origin,
+      'Sec-WebSocket-Location: ' + location
+    ];
+    
+    if ('sec-websocket-protocol' in this.request.headers){
+      headers.push('Sec-WebSocket-Protocol: ' + this.request.headers['sec-websocket-protocol']);
+    }
+  } else {
+    headers = [
+      'HTTP/1.1 101 Web Socket Protocol Handshake',
+      'Upgrade: WebSocket',
+      'Connection: Upgrade',
+      'WebSocket-Origin: ' + origin,
+      'WebSocket-Location: ' + location
+    ];
+    
+  }
+
+  try {
+    this.connection.write(headers.concat('', '').join('\r\n'));
+    this.connection.setTimeout(0);
+    this.connection.setNoDelay(true);
+    this.connection.setEncoding('utf-8');
+  } catch(e){
+    this._onClose();
+    return;
+  }
+  
+  if (this.waitingForNonce) {
+  	// Since we will be receiving the binary nonce through the normal HTTP
+  	// data event, set the connection to 'binary' temporarily
+  	this.connection.setEncoding('binary');
+  	this._headers = headers;
+  }
+  else {
+  	if (this._proveReception(headers)) this._payload();
+  }
+  
+  this.buffer = "";
+  
+  this.connection.addListener('data', function(data){
+    if (self.waitingForNonce) {
+    		self.buffer += data;
+
+  		if (self.buffer.length < 8) { return; }
+  		// Restore the connection to utf8 encoding after receiving the nonce
+  		self.connection.setEncoding('utf8');
+  		self.waitingForNonce = false;
+  		// Stuff the nonce into the location where it's expected to be
+  		self.upgradeHead = self.buffer.substr(0,8);
+                self.buffer = '';
+  		if (self._proveReception(self._headers)) { self._payload(); }
+  		return;
+  	}
+  	
+    self.parser.add(data);
+  });
+
+};
+
+// http://www.whatwg.org/specs/web-apps/current-work/complete/network.html#opening-handshake
+WebSocket.prototype._proveReception = function(headers){
+  var self = this
+    , k1 = this.request.headers['sec-websocket-key1']
+    , k2 = this.request.headers['sec-websocket-key2'];
+  
+  if (k1 && k2){
+    var md5 = crypto.createHash('md5');
+
+    [k1, k2].forEach(function(k){
+      var n = parseInt(k.replace(/[^\d]/g, '')),
+          spaces = k.replace(/[^ ]/g, '').length;
+          
+      if (spaces === 0 || n % spaces !== 0){
+        self.listener.options.log('Invalid WebSocket key: "' + k + '". Dropping connection');
+        self._onClose();
+        return false;
+      }
+
+      n /= spaces;
+      
+      md5.update(String.fromCharCode(
+        n >> 24 & 0xFF,
+        n >> 16 & 0xFF,
+        n >> 8  & 0xFF,
+        n       & 0xFF));
+    });
+
+    md5.update(this.upgradeHead.toString('binary'));
+    
+    try {
+      this.connection.write(md5.digest('binary'), 'binary');
+    } catch(e){
+      this._onClose();
+    }
+  }
+  
+  return true;
+};
+
+WebSocket.prototype._write = function(message){
+  try {
+    this.connection.write('\u0000', 'binary');
+    this.connection.write(message, 'utf8');
+    this.connection.write('\uffff', 'binary');
+  } catch(e){
+    this._onClose();
+  }
+};
+
+WebSocket.httpUpgrade = true;
+
+function Parser(){
+  this.buffer = '';
+  this.i = 0;
+};
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+Parser.prototype.add = function(data){
+  this.buffer += data;
+  this.parse();
+};
+
+Parser.prototype.parse = function(){
+  for (var i = this.i, chr, l = this.buffer.length; i < l; i++){
+    chr = this.buffer[i];
+    if (i === 0){
+      if (chr != '\u0000')
+        this.error('Bad framing. Expected null byte as first frame');
+      else
+        continue;
+    }