Merge branch 'development'
authorDarren <darren@darrenwhitlen.com>
Wed, 21 Nov 2012 23:13:09 +0000 (23:13 +0000)
committerDarren <darren@darrenwhitlen.com>
Wed, 21 Nov 2012 23:13:09 +0000 (23:13 +0000)
16 files changed:
client/assets/css/style.css
client/assets/dev/build.js
client/assets/dev/index.html.tmpl
client/assets/dev/model_application.js
client/assets/dev/model_gateway.js
client/assets/dev/view.js
client/assets/lodash.min.js [new file with mode: 0644]
client/assets/underscore.min.js [deleted file]
package.json
server/client.js
server/clientcommands.js
server/irc/commands.js
server/irc/connection.js
server/kiwi.js
server/rehash.js
server/weblistener.js

index 477464a1957d138d4ce84f42ddcb4cf992a93820..61af74b36b1083c4fd2b964ea5651aa193ad7688 100644 (file)
-* { margin:0px; padding:0px; }
 html, body { height:100%; }
-p { margin:0.5em 0; }
-a { color:#36C; text-decoration:none; cursor:pointer; }
-a img { border:none; }
-
+* { margin:0; padding:0; }
 
 
 
+/* Few resets for within the kiwi container */
 #kiwi {
     overflow:hidden; position:relative; 
     height:100%;
-    background: url(../img/background-light.png) left top repeat-x #E3E3E3;
-    color: #555555;
-}
-
-#kiwi, #kiwi input, #kiwi button, #kiwi textarea {
-    font-family:Arial, Helvetica, sans-serif;
-    font-size:14px; line-height:1.4em;
 }
+#kiwi * { margin:0px; padding:0px; }
+#kiwi p { margin:0.5em 0; }
+#kiwi a { color:#36C; text-decoration:none; cursor:pointer; }
+#kiwi a img { border:none; }
 
 
-
-#kiwi input, textarea {
-    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5),0 1px 0px rgba(255, 255, 255, 0.3);
-    border: none;
-    border-radius: 3px;
-}
-
 /**
  * Main layout blocks
  */
-#toolbar { position:absolute; top:0px; width:100%; background-color:#1B1B1B; font-size:0.9em; display:none; }
-#panels { position:absolute; left:0px; right:200px; bottom:100px; top:100px; }
-#memberlists { position:absolute; right:0px; width:200px; bottom:100px; top:100px; overflow-y:auto; }
-#controlbox { position: absolute; bottom:0px; width:100%; background-color:#1B1B1B; display:none; }
-#memberlists_resize_handle {
+#kiwi #toolbar { position:absolute; top:0px; width:100%; display:none; }
+#kiwi #panels { position:absolute; left:0px; right:200px; bottom:100px; top:100px; }
+#kiwi #memberlists { position:absolute; right:0px; width:200px; bottom:100px; top:100px; overflow-y:auto; }
+#kiwi #controlbox { position: absolute; bottom:0px; width:100%; display:none; }
+#kiwi #memberlists_resize_handle {
     position: absolute; width:10px; z-index:1; cursor:w-resize;
-    background:url('../img/resize_handle.png') no-repeat; background-position:center;
 }
 
 
-#toolbar #tabs { margin-right: 200px; }
-#toolbar .panellist {
+#kiwi #toolbar #tabs { margin-right: 200px; }
+#kiwi #toolbar .panellist {
     overflow: hidden;
     white-space: nowrap;
     display:block;
-    /*height: 35px;*/
 }
-#toolbar .panellist li {
+#kiwi #toolbar .panellist li {
     float: left; list-style: inline;
     display:inline; position:relative;
     padding:5px; margin:3px;
-    border: 1px solid #333;
-    background-color: #eee;
-    
     cursor: pointer;
+}
 
-    line-height: 1.4em;
-    vertical-align: middle;
-    
-    border-radius:5px;
-    -moz-border-radius:5px;
-    -webkit-border-radius:5px;
-    -khtml-border-radius:5px;
-    behavior: url(border-radius.htc);
+#kiwi #toolbar .panellist .active { padding-right:23px; }
+#kiwi #toolbar .panellist .alert_highlight { font-weight: bold; }
+#kiwi #toolbar .panellist .alert_activity { font-weight: bold; }
+#kiwi #toolbar .panellist .alert_action { font-weight: bold; }
 
-       background-image: -webkit-gradient(
-           linear,
-           left top,
-           left bottom,
-           color-stop(0.38, rgb(238,238,238)),
-           color-stop(0.68, rgb(209,209,209))
-       );
-       background-image: -moz-linear-gradient(
-           center top,
-           rgb(238,238,238) 38%,
-           rgb(209,209,209) 68%
-       );
-}
-
-#toolbar .panellist .active { padding-right:23px; }
-#toolbar .panellist .alert_highlight {
-    background: #990000;
-    font-weight: bold;
-}
-#toolbar .panellist .alert_activity { font-weight: bold; background: #009900; }
-#toolbar .panellist .alert_action { font-weight: bold; }
-
-#toolbar .panellist li .part { top:8px; right:5px; position:absolute; background:url('../img/redcross.png'); width:14px; height:14px; }
-#toolbar .panellist li img.icon { left:5px; top:2px; height:auto; width:auto; }
-
-#toolbar .panellist li.server span { background:url(../img/server_tab.png) no-repeat; padding-left:23px; }
-#toolbar .panellist li span  { line-height:20px; vertical-align:middle; display:block; }
-#status_message {
-    background: #FEEFB3; color: #9F6000;
+#kiwi #toolbar .panellist li .part { position: absolute; top: 8px; right: 5px; }
+#kiwi #toolbar .panellist li .part:after { content:"[x]"; }
+#kiwi #toolbar .panellist li img.icon { left:5px; top:2px; height:auto; width:auto; }
+
+#kiwi #status_message {
+    background: #FFF;
     border-bottom: 1px solid;
-    padding: 0.9em;
-    text-align: center; font-size:1.1em;
+    text-align: center;
 }
-#status_message.err { color:#D8000C; background:#FFBABA; }
 
 
-.panel_container { overflow-y:auto; height:100%; }
+#kiwi .panel_container { overflow-y:auto; height:100%; }
 
 
 
-.messages {
+#kiwi .messages {
     overflow-x:wrap;
     border:none; display: none;
-    /*height: 100%;*/
-    color: #333333;
-}
-.messages a {
-    text-decoration:none;
-}
-.messages.active { display:block; }
-
-.messages .msg { border-bottom: 1px solid #CCC; padding:1px; font-family:arial; font-size:0.9em; }
-.messages .msg .time { width:6em; float:left; color:#777; }
-.messages .msg .nick { width:7em; text-align:right; float:left; font-size:12px; }
-.messages .msg .text { margin-left:15em; white-space:pre-wrap; word-wrap:break-word; font-family:monospace;  }
-
-.messages .msg.action .nick { display:none; }
-.messages .msg.action .text { margin-left:9em; color:#009900; font-style:italic; }
-.messages .msg.action.join { color:#009900; }
-.messages .msg.action.part .text { color:#900; }
-.messages .msg.action.quit .text { color:#900; }
-.messages .msg.action.kick .text { color:#900; }
-.messages .msg.status .nick { display:none; }
-.messages .msg.status .text { color:#990000; margin-left:9em; font-weight:bold; }
-.messages .msg.topic .nick { display:none; }
-.messages .msg.topic .text { color:#009900; margin-left:9em; font-style: italic; }
-/*.messages .msg.motd .nick { display:none; }*/
-.messages .msg.motd { border:none; }
-.messages .msg.motd .text { color:#666; }
-.messages .msg.whois .nick { font-weight:normal; }
-.messages .msg.whois .text { margin-left:18em; padding-left:1em; border-left:1px dashed #999; }
-.messages .msg.error .text {
-    border:1px solid #A33F3F; background-color:#D28A8A;
-    padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
 }
+#kiwi .messages a {}
+#kiwi .messages.active { display:block; }
 
-.messages .msg.global_nick_highlight,
-.messages .msg.highlight { background:#D9D9D9; }
+#kiwi .messages .msg {}
+#kiwi .messages .msg .time { display:inline; }
+#kiwi .messages .msg .nick { display:inline; }
+#kiwi .messages .msg .text { display:inline; }
 
+#kiwi .messages .msg.action .nick { display:none; }
+#kiwi .messages .msg.action .text { }
+#kiwi .messages .msg.action.join { }
+#kiwi .messages .msg.action.part .text { }
+#kiwi .messages .msg.action.quit .text { }
+#kiwi .messages .msg.action.kick .text { }
+#kiwi .messages .msg.status .nick { display:none; }
+#kiwi .messages .msg.status .text { }
+#kiwi .messages .msg.topic .nick { display:none; }
+#kiwi .messages .msg.topic .text { }
+#kiwi .messages .msg.motd { }
+#kiwi .messages .msg.motd .nick { }
+#kiwi .messages .msg.motd .text { }
+#kiwi .messages .msg.whois .nick { }
+#kiwi .messages .msg.whois .text { }
+#kiwi .messages .msg.error .text { }
 
+#kiwi .messages .msg.global_nick_highlight { }
+#kiwi .messages .msg.highlight { }
 
 
-#memberlists ul { list-style: none; display:none; }
-#memberlists ul.active { display:block; }
-#memberlists ul li { padding: 0.2em 1em; overflow-y:auto; overflow-x:hidden; cursor:pointer; }
-#memberlists ul li a.nick { display:block; color:black; }
 
-#memberlists ul li .userbox { position:relative; margin:0 1em 5px 1em; padding-bottom:0.7em; font-size:.9em; }
-#memberlists ul li .userbox a { display:block; text-decoration:none; margin-bottom:2px; }
-#memberlists ul li .userbox a i { font-size:1.1em; margin-right:5px; }
+/* A member/nick list per channel */
+#kiwi #memberlists { border-left: 1px solid #8A8A8A; }
+#kiwi #memberlists ul { display:none; }
 
+/* The active channels nicklist */
+#kiwi #memberlists ul.active { display:block; }
+#kiwi #memberlists ul li { overflow-y:auto; overflow-x:hidden; cursor:pointer; }
+#kiwi #memberlists ul li a.nick { }
 
-#controlbox .input {
-    background:#fff; margin:3px;
-    height:1.7em;
-    border-radius:5px;
-    -moz-border-radius:5px;
-    -webkit-border-radius:5px;
-    -khtml-border-radius:5px;
-}
-#controlbox .input .nick { text-align: right; width:11em; left:0px; position:absolute; padding:2px; cursor: pointer; }
-#controlbox .input .nick a { text-decoration:none; color:black; }
-#controlbox .input .input_wrap {
-    position:absolute;
-    right:7px; left: 12.2em;
+/* The userbox shown when clicking a nick */
+#kiwi #memberlists ul li .userbox { position:relative; }
+#kiwi #memberlists ul li .userbox a { }
+#kiwi #memberlists ul li .userbox a i { }
+
+
+
+/**
+ * Control box
+ */
+#kiwi #controlbox .input {
     height:1.7em;
 }
-#controlbox .input .inp {
-    line-height:1.7em;
-    display: block;
-    border: medium none;
-    box-shadow: none;
-    border-radius: 0;
-    outline:none; resize:none;
-    overflow:hidden;
-    position:relative;
-    height:100%; width:100%;
-}
 
-#controlbox .nickchange {
+/* The nick label */
+#kiwi #controlbox .input .nick { cursor: pointer; }
+#kiwi #controlbox .input .nick a { }
+
+/* Wrapper div around the text area input */
+#kiwi #controlbox .input .input_wrap { display:inline; }
+
+/* The textarea input */
+#kiwi #controlbox .input .inp { }
+
+
+/* Nick change dialog showed when clicking the nick label */
+#kiwi #controlbox .nickchange {
     position: absolute;
-    left: 0px;
-    background: #1B1B1B; color:#eeeeee;
-    padding:10px;
+    background: #FFF;
 }
-#controlbox .nickchange input { padding:0.3em 0.5em; }
-#controlbox .nickchange button { padding:0.5em; }
+#kiwi #controlbox .nickchange input { }
+#kiwi #controlbox .nickchange button { }
 
 
 
-#topic { background-color:#1B1B1B; height:2em; position:relative; }
-#topic div {
+/**
+ * Topic bar
+ */
+#kiwi #topic { position:relative; height:2em; }
+#kiwi #topic div {
     position:absolute;
-    top:2; bottom:2px; left:0; width:100%;
-    padding: 0.2em 1em;
-    text-align: center;
-    box-shadow: none;
-    border-radius: 0;
-    background-color:#FFF;
-    height: 1.5em;
+    top:0; bottom:0; left:0; right:0;
     overflow: hidden;
-    outline: none;
 }
 
 
 
 
 
+/**
+ * Server selection dialog
+ */
+#kiwi .server_select { width:800px; margin:0 auto; overflow:hidden; }
+#kiwi .server_select .more { display: none; }
+#kiwi .server_select button {  }
+#kiwi .server_select input { }
+#kiwi .server_select label { float:left; width:5em; }
+#kiwi .server_select br { clear:both; }
+#kiwi .server_select .basic input { }
+#kiwi .server_select .basic label { }
+#kiwi .server_select .basic { border-bottom: 1px solid gray; margin-bottom:1em; }
+#kiwi .server_select .basic .show_more { }
+#kiwi .server_select.single_server .basic { border:none; }
+#kiwi .server_select .status {  }
 
-.server_select { width:730px;  padding:3em 0 2em 0; margin: 0 auto; overflow:hidden; }
-.server_select .more { display: none; width:270px; margin:0 auto; }
-.server_select button { float:right; padding:3px 7px; margin-top:10px; }
-.server_select input { float:right; margin-bottom:5px; padding:3px 7px; width:150px; }
-.server_select label { float:left; width:5em; padding-top:3px }
-.server_select br { clear:both; }
-.server_select .basic input, .server_select .basic button { font-size:1em; padding:0.5em 1em; }
-.server_select .basic input { width:170px; }
-.server_select .basic label { font-size:1.3em; margin-top:4px; }
-.server_select .basic { border-bottom: 1px dashed gray; margin-bottom:1em; }
-.server_select .basic .show_more { display: block; width:40px; margin:10px 0 0 0; font-size:0.8em; background: url(../img/more.png) no-repeat right 7px; }
-.server_select.single_server .basic { border:none; }
-.server_select .status { text-align: center; font-weight: bold; padding:1em; }
-.server_select .status .ok {
-    border:1px solid #A33F3F; background-color:#D28A8A;
-    padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
-}
+/* When connected to an IRC server, .ok is set on the status div */
+#kiwi .server_select .status.ok { }
 
+/* IRC server connection error, .error is set on the status div */
+#kiwi .server_select .status.error { }
 
 
 
-.server_select .kiwi_logo { text-align: center; display:block; }
-.server_select .kiwi_logo h1 {
-    font-size:20px;
-    line-height:48px; vertical-align: middle;
-    color: #555555;
-}
-.server_select .kiwi_logo img { }
+/* Logo and title in the server selection dialog */
+#kiwi .server_select .kiwi_logo { text-align: center; display:block; }
+#kiwi .server_select .kiwi_logo h1 { }
+#kiwi .server_select .kiwi_logo img { }
 
 
 
-#toolbar .app_tools { float:right; width:200px; padding-left:10px; color:#D4D4D4; }
-#toolbar .app_tools ul li {
-    display:inline;
-    font-size:26px;
-    cursor:pointer;
-    -webkit-transition: all .3s ease;
-    -moz-transition: all .3s ease;
-    transition: all .3s ease;
-    margin-left:10px;
+/* Icons in the top right corner */
+#kiwi #toolbar .app_tools { float:right; }
+#kiwi #toolbar .app_tools ul li {
+    display:inline; cursor:pointer;
 }
-#toolbar .app_tools ul li:hover { color:#88C56A; }
-#toolbar .app_tools img { height:25px; width:25px; margin: 6px 0.7em 0 0; }
-
+#kiwi #toolbar .app_tools img { height:25px; width:25px; margin: 6px 0.7em 0 0; }
 
 
 
+/* Settings applet */
 #kiwi .settings {
     width:900px;
     margin:1em auto;
@@ -276,7 +207,7 @@ a img { border:none; }
  * Reusable componants
  */
 
-.divider-verticle {
+#kiwi .divider-verticle {
     border-left: 1px solid #CFCFCF;
     border-right: 1px solid #FFFFFF;
     position: absolute;
@@ -285,7 +216,7 @@ a img { border:none; }
     width:0;
 }
 
-.divider-horizontal {
+#kiwi .divider-horizontal {
     border-top: 1px solid #CFCFCF;
     border-bottom: 1px solid #FFFFFF;
     position: absolute;
@@ -303,42 +234,101 @@ a img { border:none; }
  */
 
 
-/* Default */
-#kiwi #memberlists {
-    background-color: #DADADA;
-    border-left: 1px solid #8A8A8A;
+/* Relaxed theme */
+#kiwi.theme_relaxed {
+    background: url(../img/background-light.png) left top repeat-x #E3E3E3;
+    color: #555555;
 }
-#kiwi #memberlists ul li:hover {
-    border-left: 5px solid #88C56A;
-    /* background: #88C56A; */
-    -webkit-transition: 0.2s ease;
-    -moz-transition: 0.2s ease;
-    -ms-transition: 0.2s ease;
-    -o-transition: 0.2s ease;
-    transition: 0.2s ease; 
+#kiwi.theme_relaxed,
+#kiwi.theme_relaxed input,
+#kiwi.theme_relaxed button,
+#kiwi.theme_relaxed textarea {
+    font-family:Arial, Helvetica, sans-serif;
+    font-size:14px; line-height:1.4em;
+}
+#kiwi.theme_relaxed input, textarea {
+    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5),0 1px 0px rgba(255, 255, 255, 0.3);
+    border: none;
+    border-radius: 3px;
+}
+#kiwi.theme_relaxed #toolbar {
+    background-color:#1B1B1B; font-size:0.9em;
 }
+#kiwi.theme_relaxed #controlbox { background-color:#1B1B1B; }
+#kiwi.theme_relaxed #memberlists_resize_handle {
+    /*background:url('../img/resize_handle.png') no-repeat; background-position:center;*/
+}
+#kiwi.theme_relaxed #toolbar .panellist li {
+    line-height: 1.4em;
+    vertical-align: middle;
+    
+    border-radius:5px;
+    -moz-border-radius:5px;
+    -webkit-border-radius:5px;
+    -khtml-border-radius:5px;
+    behavior: url(border-radius.htc);
+
+    background-image: -webkit-gradient(
+        linear,
+        left top,
+        left bottom,
+        color-stop(0.38, rgb(238,238,238)),
+        color-stop(0.68, rgb(209,209,209))
+    );
+    background-image: -moz-linear-gradient(
+        center top,
+        rgb(238,238,238) 38%,
+        rgb(209,209,209) 68%
+    );
+
+    border: 1px solid #333;
+    background-color: #eee;
+}
+
+#kiwi.theme_relaxed #toolbar .panellist .alert_highlight { background: #990000; }
+#kiwi.theme_relaxed #toolbar .panellist .alert_activity { background: #009900; }
+#kiwi.theme_relaxed #toolbar .panellist .alert_action { }
 
+#kiwi.theme_relaxed #toolbar .panellist .active { padding-right:23px; }
+#kiwi.theme_relaxed #toolbar .panellist li .part {
+    background:url('../img/redcross.png'); width:14px; height:14px;
+}
+#kiwi.theme_relaxed #toolbar .panellist li .part:after { content:""; }
 
+#kiwi.theme_relaxed #toolbar .panellist li.server span { background:url(../img/server_tab.png) no-repeat; padding-left:23px; }
 
+/* Tab texts are within a span */
+#kiwi.theme_relaxed #toolbar .panellist li span  { line-height:20px; vertical-align:middle; display:block; }
 
-/* Relaxed theme */
-#kiwi.theme_relaxed .messages .msg { border-bottom: 1px solid #DEDEDE; font-family:arial; font-size:0.9em; }
+#kiwi.theme_relaxed #status_message {
+    background: #FEEFB3; color: #9F6000;
+    border-bottom: 1px solid;
+    padding: 0.9em;
+    text-align: center; font-size:1.1em;
+}
+#kiwi.theme_relaxed #status_message.err { color:#D8000C; background:#FFBABA; }
+
+#kiwi.theme_relaxed .messages { color: #333333; }
+#kiwi.theme_relaxed .messages.active { }
+#kiwi.theme_relaxed .messages a { text-decoration:none; }
+
+#kiwi.theme_relaxed .messages .msg { border-bottom: 1px solid #DEDEDE; padding: 1px; font-family:arial; font-size:0.9em; }
 #kiwi.theme_relaxed .messages .msg .time { width:6em; float:left; color:#777; display:none; }
 #kiwi.theme_relaxed .messages .msg .nick { width:11em; float:left; font-size:12px; font-family:Arial; text-align:left; padding: 5px; }
-#kiwi.theme_relaxed .messages .msg .text { margin-left:12em; border-left: 1px solid #DEDEDE; white-space:pre-wrap; word-wrap:break-word; font-family:Arial; padding:5px; }
+#kiwi.theme_relaxed .messages .msg .text { display:block; margin-left:12em; border-left: 1px solid #DEDEDE; white-space:pre-wrap; word-wrap:break-word; font-family:arial; padding:5px; }
 
-#kiwi.theme_relaxed .messages .msg.action .nick { display:none; }
+#kiwi.theme_relaxed .messages .msg.action .nick { }
 #kiwi.theme_relaxed .messages .msg.action .text { margin-left:9em; color:#009900; border-left:none; font-style:italic; }
 #kiwi.theme_relaxed .messages .msg.action.join { color:#009900; }
 #kiwi.theme_relaxed .messages .msg.action.part .text { color:#900; }
 #kiwi.theme_relaxed .messages .msg.action.quit .text { color:#900; }
 #kiwi.theme_relaxed .messages .msg.action.kick .text { color:#900; }
-#kiwi.theme_relaxed .messages .msg.status .nick { display:none; }
+#kiwi.theme_relaxed .messages .msg.status .nick { }
 #kiwi.theme_relaxed .messages .msg.status .text { color:#990000; margin-left:9em; border-left:none; font-weight:bold; }
 #kiwi.theme_relaxed .messages .msg.topic .nick { display:none; }
 #kiwi.theme_relaxed .messages .msg.topic .text { color:#009900; margin-left:9em; font-style: italic; border-left:none; }
-/*#kiwi.theme_relaxed .messages .msg.motd .nick { display:none; }*/
 #kiwi.theme_relaxed .messages .msg.motd { border:none; }
+/*#kiwi.theme_relaxed .messages .msg.motd .nick { display:none; }*/
 #kiwi.theme_relaxed .messages .msg.motd .text { color:#666; }
 #kiwi.theme_relaxed .messages .msg.whois .nick { font-weight:normal; }
 #kiwi.theme_relaxed .messages .msg.whois .text { margin-left:18em; padding-left:1em; border-left:1px dashed #999; }
@@ -347,49 +337,544 @@ a img { border:none; }
     padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
 }
 
+#kiwi.theme_relaxed .messages .msg.global_nick_highlight,
+#kiwi.theme_relaxed .messages .msg.highlight { background:#D9D9D9; }
+
+
+
+#kiwi.theme_relaxed #memberlists {
+    background-color: #DADADA;
+    border-left: 1px solid #8A8A8A;
+}
+#kiwi.theme_relaxed #memberlists ul { list-style: none; }
+#kiwi.theme_relaxed #memberlists ul.active { }
+#kiwi.theme_relaxed #memberlists ul li { padding: 0.2em 1em; }
+#kiwi.theme_relaxed #memberlists ul li:hover {
+    border-left: 5px solid #88C56A;
+    -webkit-transition: 0.2s ease;
+    -moz-transition: 0.2s ease;
+    -ms-transition: 0.2s ease;
+    -o-transition: 0.2s ease;
+    transition: 0.2s ease; 
+}
+#kiwi.theme_relaxed #memberlists ul li a.nick { display:block; color:black; }
+
+#kiwi.theme_relaxed #memberlists ul li .userbox { margin:0 1em 5px 1em; padding-bottom:0.7em; font-size:.9em; }
+#kiwi.theme_relaxed #memberlists ul li .userbox a { display:block; text-decoration:none; margin-bottom:2px; }
+#kiwi.theme_relaxed #memberlists ul li .userbox a i { font-size:1.1em; margin-right:5px; }
+
+
+#kiwi.theme_relaxed #controlbox .input {
+    background:#fff; margin:3px;
+    height:1.7em;
+    border-radius:5px;
+    -moz-border-radius:5px;
+    -webkit-border-radius:5px;
+    -khtml-border-radius:5px;
+}
+#kiwi.theme_relaxed #controlbox .input .nick { text-align: right; width:11em; left:0px; position:absolute; padding:2px; }
+#kiwi.theme_relaxed #controlbox .input .nick a { text-decoration:none; color:black; }
+#kiwi.theme_relaxed #controlbox .input .input_wrap {
+    position:absolute;
+    right:7px; left: 12.2em;
+    height:1.7em;
+}
+#kiwi.theme_relaxed #controlbox .input .inp {
+    line-height:1.7em;
+    border: medium none;
+    box-shadow: none;
+    border-radius: 0;
+    outline:none; resize:none;
+    overflow:hidden;
+    position:relative;
+    height:100%; width:100%;
+    display: block;
+}
+
+
+#kiwi.theme_relaxed #controlbox .nickchange {
+    padding:10px; left: 0px;
+    background: #1B1B1B; color:#eeeeee;
+}
+#kiwi.theme_relaxed #controlbox .nickchange input { padding:0.3em 0.5em; }
+#kiwi.theme_relaxed #controlbox .nickchange button { padding:0.5em; }
+
+
+
+#kiwi.theme_relaxed #topic { background-color:#1B1B1B; padding-bottom:2px; }
+#kiwi.theme_relaxed #topic div {
+    padding: 0.2em 1em;
+    text-align: center;
+    box-shadow: none;
+    border-radius: 0;
+    background-color:#FFF;
+    height: 1.5em;
+    overflow: hidden;
+    outline: none;
+    white-space: nowrap;
+}
+#kiwi.theme_relaxed #topic:hover div {
+    min-height:1.5em;
+    white-space:pre-wrap; word-wrap:break-word;
+    overflow:visible;
+    background-color:#FFF;
+    z-index: 1;
+    height:auto; bottom:auto;
+    border-bottom: 2px solid #1B1B1B;
+}
+
+
+#kiwi.theme_relaxed #toolbar .app_tools { width:200px; padding-left:10px; color:#D4D4D4; }
+#kiwi.theme_relaxed #toolbar .app_tools ul li {
+    font-size:26px;
+    -webkit-transition: all .3s ease;
+    -moz-transition: all .3s ease;
+    transition: all .3s ease;
+    margin-left:10px;
+}
+#kiwi.theme_relaxed #toolbar .app_tools ul li:hover { color:#88C56A; }
+#kiwi.theme_relaxed #toolbar .app_tools img { }
+
+
+/* The server select dialog */
+#kiwi.theme_relaxed .server_select { width:730px;  padding:3em 0 2em 0; margin: 0 auto; }
+#kiwi.theme_relaxed .server_select .more { display: none; width:270px; margin:0 auto; }
+#kiwi.theme_relaxed .server_select button { float:right; padding:3px 7px; margin-top:10px; }
+#kiwi.theme_relaxed .server_select input { float:right; margin-bottom:5px; padding:3px 7px; width:150px; }
+#kiwi.theme_relaxed .server_select label { float:left; width:5em; padding-top:3px }
+#kiwi.theme_relaxed .server_select br { clear:both; }
+#kiwi.theme_relaxed .server_select .basic input, .server_select .basic button { font-size:1em; padding:0.5em 1em; }
+#kiwi.theme_relaxed .server_select .basic input { width:170px; }
+#kiwi.theme_relaxed .server_select .basic label { font-size:1.3em; margin-top:4px; }
+#kiwi.theme_relaxed .server_select .basic { border-bottom: 1px dashed gray; margin-bottom:1em; }
+#kiwi.theme_relaxed .server_select .basic .show_more { display: block; width:40px; margin:10px 0 0 0; font-size:0.8em; background: url(../img/more.png) no-repeat right 7px; }
+#kiwi.theme_relaxed .server_select.single_server .basic { border:none; }
+#kiwi.theme_relaxed .server_select .status { text-align: center; font-weight: bold; padding:1em; }
+#kiwi.theme_relaxed .server_select .status.ok { }
+#kiwi.theme_relaxed .server_select .status.error {
+    border:1px solid #A33F3F; background-color:#D28A8A;
+    padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
+}
+
+
+#kiwi.theme_relaxed .server_select .kiwi_logo { text-align: center; display:block; }
+#kiwi.theme_relaxed .server_select .kiwi_logo h1 {
+    font-size:20px;
+    line-height:48px; vertical-align: middle;
+    color: #555555;
+}
+#kiwi.theme_relaxed .server_select .kiwi_logo img { }
+
+
+
+
+
+
+
+
+/**
+ * Mini theme
+ */
+#kiwi.theme_mini {
+    background: #FFF;
+    color: #555555;
+}
+#kiwi.theme_mini,
+#kiwi.theme_mini input,
+#kiwi.theme_mini button,
+#kiwi.theme_mini textarea {
+    font-family:Arial, Helvetica, sans-serif;
+    font-size:14px; line-height:1.4em;
+}
+#kiwi.theme_mini input, textarea {
+    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5),0 1px 0px rgba(255, 255, 255, 0.3);
+    border: none;
+    border-radius: 3px;
+}
+#kiwi.theme_mini #toolbar {
+    background-color:#1B1B1B; font-size:0.9em;
+}
+#kiwi.theme_mini #controlbox { background-color:#1B1B1B; }
+#kiwi.theme_mini #memberlists_resize_handle {
+    display:none; width:0;
+}
+#kiwi.theme_mini #toolbar .panellist li {
+    line-height: 1.4em;
+    vertical-align: middle;
+    
+    border-radius:5px;
+    -moz-border-radius:5px;
+    -webkit-border-radius:5px;
+    -khtml-border-radius:5px;
+
+    border: 1px solid #333;
+    background-color: #eee;
+}
+
+#kiwi.theme_mini #toolbar #tabs { margin-right:0 !important; }
+#kiwi.theme_mini #toolbar .panellist .alert_highlight { background: #990000; }
+#kiwi.theme_mini #toolbar .panellist .alert_activity { background: #009900; }
+#kiwi.theme_mini #toolbar .panellist .alert_action { }
+
+#kiwi.theme_mini #toolbar .panellist .active { padding-right:23px; }
+#kiwi.theme_mini #toolbar .panellist li .part {
+    background:url('../img/redcross.png'); width:14px; height:14px;
+}
+#kiwi.theme_mini #toolbar .panellist li .part:after { content:""; }
+
+#kiwi.theme_mini #toolbar .panellist li.server span { background:url(../img/server_tab.png) no-repeat; padding-left:23px; }
+
+/* Tab texts are within a span */
+#kiwi.theme_mini #toolbar .panellist li span  { line-height:20px; vertical-align:middle; display:block; }
+
+#kiwi.theme_mini #status_message {
+    background: #FEEFB3; color: #9F6000;
+    border-bottom: 1px solid;
+    padding: 0.9em;
+    text-align: center; font-size:1.1em;
+}
+#kiwi.theme_mini #status_message.err { color:#D8000C; background:#FFBABA; }
+
+#kiwi.theme_mini .messages { color: #333333; }
+#kiwi.theme_mini .messages.active { }
+#kiwi.theme_mini .messages a { text-decoration:none; }
+
+#kiwi.theme_mini .messages .msg { border-bottom: 1px solid #DEDEDE; padding: 5px; font-family:arial; font-size:0.9em; }
+#kiwi.theme_mini .messages .msg .time { display:none; }
+#kiwi.theme_mini .messages .msg .nick { display:block; font-family:Arial; text-transform:capitalize; }
+#kiwi.theme_mini .messages .msg .text { display:block; white-space:pre-wrap; word-wrap:break-word; font-family:arial; }
+
+#kiwi.theme_mini .messages .msg.action .nick { }
+#kiwi.theme_mini .messages .msg.action .text { color:#009900; border-left:none; font-style:italic; }
+#kiwi.theme_mini .messages .msg.action.join { color:#009900; }
+#kiwi.theme_mini .messages .msg.action.part .text { color:#900; }
+#kiwi.theme_mini .messages .msg.action.quit .text { color:#900; }
+#kiwi.theme_mini .messages .msg.action.kick .text { color:#900; }
+#kiwi.theme_mini .messages .msg.status .nick { }
+#kiwi.theme_mini .messages .msg.status .text { color:#990000; border-left:none; font-weight:bold; }
+#kiwi.theme_mini .messages .msg.topic .nick { display:none; }
+#kiwi.theme_mini .messages .msg.topic .text { color:#009900; font-style: italic; border-left:none; }
+#kiwi.theme_mini .messages .msg.motd { border:none; }
+/*#kiwi.theme_mini .messages .msg.motd .nick { display:none; }*/
+#kiwi.theme_mini .messages .msg.motd .text { color:#666; }
+#kiwi.theme_mini .messages .msg.whois .nick { font-weight:normal; }
+#kiwi.theme_mini .messages .msg.whois .text { padding-left:1em; border-left:1px dashed #999; }
+#kiwi.theme_mini .messages .msg.error .text {
+    border:1px solid #A33F3F; background-color:#D28A8A;
+    padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
+}
+
+#kiwi.theme_mini .messages .msg.global_nick_highlight,
+#kiwi.theme_mini .messages .msg.highlight { background:#D9D9D9; }
+
+
+
+#kiwi.theme_mini #memberlists {
+    background-color: #DADADA;
+    border-left: 1px solid #8A8A8A;
+    display:none;
+    width:0px;
+}
+#kiwi.theme_mini #memberlists ul { list-style: none; }
+#kiwi.theme_mini #memberlists ul.active { }
+#kiwi.theme_mini #memberlists ul li { padding: 0.2em 1em; }
+#kiwi.theme_mini #memberlists ul li:hover {
+    border-left: 5px solid #88C56A;
+    -webkit-transition: 0.2s ease;
+    -moz-transition: 0.2s ease;
+    -ms-transition: 0.2s ease;
+    -o-transition: 0.2s ease;
+    transition: 0.2s ease; 
+}
+#kiwi.theme_mini #memberlists ul li a.nick { display:block; color:black; }
+
+#kiwi.theme_mini #memberlists ul li .userbox { margin:0 1em 5px 1em; padding-bottom:0.7em; font-size:.9em; }
+#kiwi.theme_mini #memberlists ul li .userbox a { display:block; text-decoration:none; margin-bottom:2px; }
+#kiwi.theme_mini #memberlists ul li .userbox a i { font-size:1.1em; margin-right:5px; }
+
+
+#kiwi.theme_mini #controlbox .input {
+    background:#fff; margin:3px;
+    height:1.7em;
+}
+#kiwi.theme_mini #controlbox .input .nick { display:none; }
+#kiwi.theme_mini #controlbox .input .nick a { text-decoration:none; color:black; }
+#kiwi.theme_mini #controlbox .input .input_wrap {
+    position:absolute;
+    right:3px; left:3px;
+    height:1.7em;
+}
+#kiwi.theme_mini #controlbox .input .inp {
+    line-height:1.7em;
+    border: medium none;
+    box-shadow: none;
+    border-radius: 0;
+    resize:none;
+    overflow:hidden;
+    position:relative;
+    height:100%; width:100%;
+    display: block;
+}
+
+
+#kiwi.theme_mini #controlbox .nickchange {
+    padding:10px; left: 0px;
+    background: #1B1B1B; color:#eeeeee;
+}
+#kiwi.theme_mini #controlbox .nickchange input { padding:0.3em 0.5em; }
+#kiwi.theme_mini #controlbox .nickchange button { padding:0.5em; }
+
+
+
+#kiwi.theme_mini #topic { display:none; }
+#kiwi.theme_mini #topic div {
+    top:2; bottom:2px; left:0; width:100%;
+    padding: 0.2em 1em;
+    text-align: center;
+    box-shadow: none;
+    border-radius: 0;
+    background-color:#FFF;
+    height: 1.5em;
+    overflow: hidden;
+    outline: none;
+}
+
+
+#kiwi.theme_mini #toolbar .app_tools { padding-left:10px; color:#D4D4D4; }
+#kiwi.theme_mini #toolbar .app_tools ul li {
+    font-size:26px;
+    -webkit-transition: all .3s ease;
+    -moz-transition: all .3s ease;
+    transition: all .3s ease;
+    margin-left:10px;
+}
+#kiwi.theme_mini #toolbar .app_tools ul li:hover { color:#88C56A; }
+#kiwi.theme_mini #toolbar .app_tools img { }
+
+
+/* The server select dialog */
+#kiwi.theme_mini .server_select { padding:3em 0 2em 0; margin: 0 auto; width:100%; }
+#kiwi.theme_mini .server_select .more { display:none; }
+#kiwi.theme_mini .server_select button { display:block; padding:3px 7px; margin:0 auto; }
+#kiwi.theme_mini .server_select input.nick {
+    float:none; display:block; width:80%;
+    padding:0.5em 1em; margin:0 auto;
+    text-align: center;
+}
+#kiwi.theme_mini .server_select label { display:none; }
+#kiwi.theme_mini .server_select br { clear:both; }
+#kiwi.theme_mini .server_select .basic { border:none; }
+#kiwi.theme_mini .server_select .basic .show_more { display:none !important; }
+#kiwi.theme_mini .server_select.single_server .basic { border:none; }
+#kiwi.theme_mini .server_select .status { text-align: center; font-weight: bold; padding:1em; }
+#kiwi.theme_mini .server_select .status.ok { }
+#kiwi.theme_mini .server_select .status.error {
+    border:1px solid #A33F3F; background-color:#D28A8A;
+    padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
+}
+
+#kiwi.theme_mini .server_select .divider-verticle {
+    display:none;
+}
+#kiwi.theme_mini .server_select .server_details {
+    position: relative !important;
+    float: none !important;
+    width: auto !important;
+    padding: 0 !important;
+    margin: 2em 0 0 0 !important;
+}
+#kiwi.theme_mini .server_select .about_kiwi { display:none; }
+
+
+
+
+
 
 
 
 
 /* CLI theme */
 #kiwi.theme_cli { background:#222222; color:#6d6d6d; }
-#kiwi.theme_cli #controlbox { background:#111111; border-top:1px solid #444444; color:#909090; font-size:1.3em; line-height:2em; }
+#kiwi.theme_cli,
+#kiwi.theme_cli input,
+#kiwi.theme_cli button,
+#kiwi.theme_cli textarea {
+    font-family:Arial, Helvetica, sans-serif;
+    font-size:14px; line-height:1.4em;
+}
+
+#kiwi.theme_cli #controlbox { background:#111111; border-top:1px solid #444444; color:#909090; font-size:1.3em; line-height:2em; margin:3px; }
 #kiwi.theme_cli #controlbox .input_wrap:before { content:"> " }
-#kiwi.theme_cli #controlbox .input { background:none; border:none; border-radius: none; }
-#kiwi.theme_cli #controlbox .input .nick { line-height:1.7em; padding:0; }
-#kiwi.theme_cli #controlbox .input .inp { background:transparent; color:#909090; font-size:1.3em; width:92%; display:inline; }
-/* #kiwi.theme_cli #controlbox .input .inp:before { content:">"; } */
+#kiwi.theme_cli #controlbox .input { background:none; border:none;}
+#kiwi.theme_cli #controlbox .input .nick { line-height:1.7em; padding:0; text-align: right; width:11em; left:0px; position:absolute; }
+#kiwi.theme_cli #controlbox .input .input_wrap {
+    position:absolute;
+    right:7px; left: 12.2em;
+    height:1.7em;
+}
+#kiwi.theme_cli #controlbox .input .inp {
+    line-height:1.7em;
+    font-size:1.3em;
+    background:transparent; color:#909090;
+    border: medium none;
+    box-shadow: none;
+    border-radius: 0;
+    outline:none; resize:none;
+    overflow:hidden;
+    position:absolute;
+    height:100%; width:98%;
+    display: inline;
+    padding-left:0.5em;
+}
+
+#kiwi.theme_cli #topic { background:#111111; height:2em; border-bottom:1px solid #444444; border-top:1px solid #444444; }
+#kiwi.theme_cli #topic div {
+    width:100%; height: 1.5em;
+    padding: 0.2em 1em;
+    text-align: center;
+    color:#6d6d6d;
+    border:none; outline:none;
+    overflow: hidden;
+    white-space: nowrap;
+}
+#kiwi.theme_cli #topic:hover div {
+    min-height:1.5em;
+    white-space:pre-wrap; word-wrap:break-word;
+    overflow:visible;
+    background-color:#111111;
+    z-index: 1;
+    height:auto; bottom:auto;
+    border-bottom: 1px solid #444444;
+}
+
+#kiwi.theme_cli #toolbar .app_tools { width:200px; padding-left:10px; color:#D4D4D4; }
+#kiwi.theme_cli #toolbar .app_tools ul li {
+    font-size:26px;
+    -webkit-transition: all .3s ease;
+    -moz-transition: all .3s ease;
+    transition: all .3s ease;
+    margin-left:10px;
+}
+#kiwi.theme_cli #toolbar .app_tools ul li:hover { color:#88C56A; }
+#kiwi.theme_cli #toolbar .app_tools img { }
+
+#kiwi.theme_cli #toolbar .panellist li {
+    line-height: 1.4em;
+    vertical-align: middle;
+    
+    border-radius:5px;
+    -moz-border-radius:5px;
+    -webkit-border-radius:5px;
+    -khtml-border-radius:5px;
+    behavior: url(border-radius.htc);
+
+    background-image: -webkit-gradient(
+        linear,
+        left top,
+        left bottom,
+        color-stop(0.38, rgb(238,238,238)),
+        color-stop(0.68, rgb(209,209,209))
+    );
+    background-image: -moz-linear-gradient(
+        center top,
+        rgb(238,238,238) 38%,
+        rgb(209,209,209) 68%
+    );
+
+    border: 1px solid #333;
+    background-color: #eee;
+}
+
+#kiwi.theme_cli #toolbar .panellist .alert_highlight { background: #990000; }
+#kiwi.theme_cli #toolbar .panellist .alert_activity { background: #009900; }
+#kiwi.theme_cli #toolbar .panellist .alert_action { }
+
+#kiwi.theme_cli #toolbar .panellist .active { padding-right:23px; }
+#kiwi.theme_cli #toolbar .panellist li .part {
+    background:url('../img/redcross.png'); width:14px; height:14px;
+}
+#kiwi.theme_cli #toolbar .panellist li .part:after { content:""; }
+
+#kiwi.theme_cli #toolbar .panellist li.server span { background:url(../img/server_tab.png) no-repeat; padding-left:23px; }
+
+/* Tab texts are within a span */
+#kiwi.theme_cli #toolbar .panellist li span  { line-height:20px; vertical-align:middle; display:block; }
 
-#kiwi.theme_cli #topic { background:#111111; border-bottom:1px solid #444444; border-top:1px solid #444444; }
-#kiwi.theme_cli #topic div { background:transparent; color:#6d6d6d; border:none; outline:none; height:1.5em; }
 
 #kiwi.theme_cli #memberlists { background:#222222; }
+#kiwi.theme_cli #memberlists ul li { padding: 0.2em 1em; }
 #kiwi.theme_cli #memberlists ul li a.nick { color:#6d6d6d; }
+#kiwi.theme_cli #memberlists ul li:hover {
+    border-left: 5px solid #88C56A;
+    -webkit-transition: 0.2s ease;
+    -moz-transition: 0.2s ease;
+    -ms-transition: 0.2s ease;
+    -o-transition: 0.2s ease;
+    transition: 0.2s ease; 
+}
+
+#kiwi.theme_cli #memberlists ul li .userbox { margin:0 1em 0 1em; padding-bottom:0.4em; font-size:.9em; }
+#kiwi.theme_cli #memberlists ul li .userbox a { display:block; text-decoration:none; margin-bottom:2px; }
+#kiwi.theme_cli #memberlists ul li .userbox a i { font-size:1.1em; margin-right:5px; }
+#kiwi.theme_cli #memberlists ul li .userbox .divider-horizontal { display:none; }
+
 
 #kiwi.theme_cli .messages .msg > div { color:#6d6d6d; font-family: Inconsolata, Consolas, 'courier new', monospace; }
 #kiwi.theme_cli .messages .msg { border: none; }
-#kiwi.theme_cli .messages .msg .time { width:6em; }
-#kiwi.theme_cli .messages .msg .nick {  }
+#kiwi.theme_cli .messages .msg .time { display:inline; margin-right:1em; color:#777; }
+#kiwi.theme_cli .messages .msg .nick { display:inline; margin-right:1em; }
+#kiwi.theme_cli .messages .msg .nick:before { content:"<"; }
+#kiwi.theme_cli .messages .msg .nick:after { content:">"; }
 #kiwi.theme_cli .messages .msg .text { white-space:pre-wrap; word-wrap:break-word; }
 
 #kiwi.theme_cli .messages .msg.action .nick { display:none; }
-#kiwi.theme_cli .messages .msg.action .text { margin-left:9em; color:#009900; border-left:none; font-style:italic; }
+#kiwi.theme_cli .messages .msg.action .text { color:#009900; border-left:none; font-style:italic; }
 #kiwi.theme_cli .messages .msg.action.join { color:#009900; }
 #kiwi.theme_cli .messages .msg.action.part .text { color:#900; }
 #kiwi.theme_cli .messages .msg.action.quit .text { color:#900; }
 #kiwi.theme_cli .messages .msg.action.kick .text { color:#900; }
 #kiwi.theme_cli .messages .msg.status .nick { display:none; }
-#kiwi.theme_cli .messages .msg.status .text { color:#990000; margin-left:9em; border-left:none; font-weight:bold; }
+#kiwi.theme_cli .messages .msg.status .text { color:#990000; border-left:none; font-weight:bold; }
 #kiwi.theme_cli .messages .msg.topic .nick { display:none; }
-#kiwi.theme_cli .messages .msg.topic .text { color:#009900; margin-left:9em; font-style: italic; border-left:none; }
+#kiwi.theme_cli .messages .msg.topic .text { color:#009900; font-style: italic; border-left:none; }
 /*#kiwi.theme_cli .messages .msg.motd .nick { display:none; }*/
 #kiwi.theme_cli .messages .msg.motd { border:none; }
 #kiwi.theme_cli .messages .msg.motd .text { color:#666; }
 #kiwi.theme_cli .messages .msg.whois .nick { font-weight:normal; }
-#kiwi.theme_cli .messages .msg.whois .text { margin-left:18em; padding-left:1em; border-left:1px dashed #999; }
+#kiwi.theme_cli .messages .msg.whois .text { padding-left:1em; border-left:1px dashed #999; }
 #kiwi.theme_cli .messages .msg.error .text {
     border:1px solid #A33F3F; background-color:#D28A8A;
     padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
 }
 
-#kiwi.theme_cli .messages .msg.global_nick_highlight { background:#111111; }
\ No newline at end of file
+#kiwi.theme_cli .messages .msg.global_nick_highlight { background:#111111; }
+
+
+/* The server select dialog */
+#kiwi.theme_cli .server_select { width:730px;  padding:3em 0 2em 0; margin: 0 auto; }
+#kiwi.theme_cli .server_select .more { display: none; width:270px; margin:0 auto; }
+#kiwi.theme_cli .server_select button { float:right; padding:3px 7px; margin-top:10px; }
+#kiwi.theme_cli .server_select input { float:right; margin-bottom:5px; padding:3px 7px; width:150px; }
+#kiwi.theme_cli .server_select label { float:left; width:5em; padding-top:3px }
+#kiwi.theme_cli .server_select br { clear:both; }
+#kiwi.theme_cli .server_select .basic input, .server_select .basic button { font-size:1em; padding:0.5em 1em; }
+#kiwi.theme_cli .server_select .basic input { width:170px; }
+#kiwi.theme_cli .server_select .basic label { font-size:1.3em; margin-top:4px; }
+#kiwi.theme_cli .server_select .basic { border-bottom: 1px dashed gray; margin-bottom:1em; }
+#kiwi.theme_cli .server_select .basic .show_more { display: block; width:40px; margin:10px 0 0 0; font-size:0.8em; background: url(../img/more.png) no-repeat right 7px; }
+#kiwi.theme_cli .server_select.single_server .basic { border:none; }
+#kiwi.theme_cli .server_select .status { text-align: center; font-weight: bold; padding:1em; }
+#kiwi.theme_cli .server_select .status.ok { }
+#kiwi.theme_cli .server_select .status.error {
+    border:1px solid #A33F3F; background-color:#D28A8A;
+    padding:0.5em; margin-top:1em; margin-bottom:1em; margin-right:2em;
+}
+
+
+#kiwi.theme_cli .server_select .kiwi_logo { text-align: center; display:block; }
+#kiwi.theme_cli .server_select .kiwi_logo h1 {
+    font-size:20px;
+    line-height:48px; vertical-align: middle;
+    color: #555555;
+}
+#kiwi.theme_cli .server_select .kiwi_logo img { }
\ No newline at end of file
index 5fc84a29860d5bd5b8b85aca3821e646e3b0124b..2f0c5b8e3f4f87c82ef6abe1f20f9fada4fbdd4b 100644 (file)
@@ -1,6 +1,6 @@
 var fs        = require('fs'),\r
     uglyfyJS  = require('uglify-js'),\r
-    _         = require('underscore'),\r
+    _         = require('lodash'),\r
     config    = require('./../../../server/configuration.js');\r
 \r
 var FILE_ENCODING = 'utf-8',\r
index 95afef54496bea0da294fbc69373ccba939e5e86..fbe29496907b5637fdc068a9a8c6ab15e8f206c4 100644 (file)
@@ -74,7 +74,7 @@
     <script type="text/html" id="tmpl_server_select">\r
         <div class="server_select">\r
 \r
-            <div style="position:relative;float:left;width:320px;padding-right:3em;margin-top:50px;">\r
+            <div class="server_details" style="position:relative;float:left;width:320px;padding-right:3em;margin-top:50px;">\r
                 <div class="status">Think of a nickname..</div>\r
 \r
                 <form>\r
                 <div class="divider-verticle"></div>\r
             </div>\r
 \r
-            <div style="position:relative;float:left;width:320px;margin-left:3em;color:#555555;">\r
+            <div class="about_kiwi" style="position:relative;float:left;width:320px;margin-left:3em;color:#555555;">\r
                 <a class="kiwi_logo" href="http://www.kiwiirc.com/" target="_blank">\r
                     <img src="<%base_path%>/assets/img/ico.png" alt="KiwiIRC Logo" title="Kiwi IRC" /> <br />\r
                     <h1>Powered by Kiwi IRC</h1>\r
                     <td>Theme</td>\r
                     <td>\r
                         <select class="setting-theme">\r
-                            <option value="default">Default</option>\r
                             <option value="relaxed">Relaxed</option>\r
+                            <option value="mini">Mini</option>\r
                             <option value="cli">CLI</option>\r
                         </select>\r
                     </td>\r
 \r
         // Common dependancies that are required at all times\r
         var scripts = [\r
-            ['jquery-1.8.2.min.js', 'underscore.min.js'],\r
+            ['jquery-1.8.2.min.js', 'lodash.min.js'],\r
             'backbone.min.js'\r
         ];\r
 \r
index b83f3343c40a2b5f357d42003d82435082743687..262383b4567929d8959b194ee9ce6b4a526d2def 100644 (file)
@@ -639,6 +639,17 @@ _kiwi.model.Application = function () {
                 }\r
             });\r
 \r
+            gw.on('onaway', function (event) {\r
+                $.each(that.panels.models, function (index, panel) {\r
+                    if (!panel.isChannel()) return;\r
+\r
+                    member = panel.get('members').getByNick(event.nick);\r
+                    if (member) {\r
+                        member.set('away', !(!event.trailing));\r
+                    }\r
+                });\r
+            });
+\r
 \r
             gw.on('onlist_start', function (data) {\r
                 if (_kiwi.app.channel_list) {\r
index 47c41a49803e9f00b661661fd7987a26104d0d5d..5b9ffe9fee520aa6e0d4a2a1cda3d025ed94269e 100644 (file)
@@ -197,6 +197,7 @@ _kiwi.model.Gateway = function () {
                         break;\r
                     }\r
                 });\r
+                that.set('cap', data.cap);\r
                 break;\r
 \r
             case 'connect':\r
index 091669e814d106c2c1a685ffb82e56a3b68138aa..cb67ad081d716ea75aff42640439a53a8f32ff5a 100644 (file)
@@ -979,7 +979,7 @@ _kiwi.view.Application = Backbone.View.extend({
 \r
         // Change the theme when the config is changed\r
         _kiwi.global.settings.on('change:theme', this.updateTheme, this);\r
-        this.updateTheme();\r
+        this.updateTheme(getQueryVariable('theme'));\r
 \r
         this.doLayout();\r
 \r
@@ -1006,7 +1006,7 @@ _kiwi.view.Application = Backbone.View.extend({
 \r
         // Clear any current theme\r
         this.$el.removeClass(function (i, css) {\r
-            return (css.match (/\btheme_\S+/g) || []).join(' ');\r
+            return (css.match(/\btheme_\S+/g) || []).join(' ');\r
         });\r
 \r
         // Apply the new theme\r
diff --git a/client/assets/lodash.min.js b/client/assets/lodash.min.js
new file mode 100644 (file)
index 0000000..757b77c
--- /dev/null
@@ -0,0 +1,39 @@
+/*!
+ Lo-Dash 0.9.1 lodash.com/license
+ Underscore.js 1.4.2 underscorejs.org/LICENSE
+*/
+;(function(e,t){function s(e){if(e&&e.__wrapped__)return e;if(!(this instanceof s))return new s(e);this.__wrapped__=e}function o(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||Q),s=i?{}:e;if(i)for(n=t-1;++n<r;){var o=e[n]+"";(dt.call(s,o)?s[o]:s[o]=[]).push(e[n])}return function(e){if(i){var n=e+"";return dt.call(s,n)&&-1<j(s[n],e)}return-1<j(s,e,t)}}function u(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function a(e,t,n){function r(){var u=arguments
+,a=s?this:t;return i||(e=t[o]),n.length&&(u=u.length?n.concat(gt.call(u)):n),this instanceof r?(p.prototype=e.prototype,a=new p,(u=e.apply(a,u))&&$t[typeof u]?u:a):e.apply(a,u)}var i=S(e),s=!n,o=e;return s&&(n=t),r}function f(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:U}function l(){for(var e={b:"",c:"",e:Ht,f:Xt,g:"",h:Ft,i:Rt,j:ft,k:"",l:n},t,r=0;t=arguments[r];r++)for(var i in t)e[i]=t[i];t=e.a,e.d=/^[^,]+/.exec(t)[0],r="var h,w,j="+
+e.d+",r="+e.d+";if(!"+e.d+")return r;"+e.k+";",e.b?(r+="var k=j.length;h=-1;if(typeof k=='number'){",e.i&&(r+="if(v.call(j)==t){j=j.split('')}"),r+="while(++h<k){w=j[h];"+e.b+"}}else {"):e.h&&(r+="var k=j.length;h=-1;if(k&&i(j)){while(++h<k){w=j[h+=''];"+e.g+"}}else {"),e.e||(r+="var s=typeof j=='function'&&q.call(j,'prototype');");if(e.f&&e.l)r+="var o=-1,p=n[typeof j]?l(j):[],k=p.length;while(++o<k){h=p[o];",e.e||(r+="if(!(s&&h=='prototype')){"),r+="w=j[h];"+e.g+"",e.e||(r+="}");else{r+="for(h in j){"
+;if(!e.e||e.l)r+="if(",e.e||(r+="!(s&&h=='prototype')"),!e.e&&e.l&&(r+="&&"),e.l&&(r+="g.call(j,h)"),r+="){";r+="w=j[h];"+e.g+";";if(!e.e||e.l)r+="}"}r+="}";if(e.e){r+="var f=j.constructor;";for(i=0;7>i;i++)r+="h='"+e.j[i]+"';if(","constructor"==e.j[i]&&(r+="!(f&&f.prototype===j)&&"),r+="g.call(j,h)){w=j[h];"+e.g+"}"}if(e.b||e.h)r+="}";return r+=e.c+";return r",Function("e,g,i,n,l,q,t,v","return function("+t+"){"+r+"}")(f,dt,v,$t,xt,mt,Pt,yt)}function c(e){return"\\"+Jt[e]}function h(e){return en
+[e]}function p(){}function d(e){return tn[e]}function v(e){return yt.call(e)==kt}function m(e){var t=i;if(!e||"object"!=typeof e||v(e))return t;var n=e.constructor;return(!Ut||"function"==typeof e.toString||"string"!=typeof (e+""))&&(!S(n)||n instanceof n)?Bt?(Yt(e,function(e,n,r){return t=!dt.call(r,n),i}),t===i):(Yt(e,function(e,n){t=n}),t===i||dt.call(e,t)):t}function g(e){var t=[];return Zt(e,function(e,n){t.push(n)}),t}function y(e,t,n,s,o){if(e==r)return e;n&&(t=i);if(n=$t[typeof e]){var u=
+yt.call(e);if(!Vt[u]||It&&v(e))return e;var a=u==Lt,n=a||(u==_t?on(e):n)}if(!n||!t)return n?a?gt.call(e):rn({},e):e;n=e.constructor;switch(u){case At:case Ot:return new n(+e);case Mt:case Pt:return new n(e);case Dt:return n(e.source,rt.exec(e))}s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u];var f=a?n(e.length):{};return s.push(e),o.push(f),(a?an:Zt)(e,function(e,n){f[n]=y(e,t,r,s,o)}),f}function b(e){var t=[];return Yt(e,function(e,n){S(e)&&t.push(n)}),t.sort()}function w(e){var t=
+{};return Zt(e,function(e,n){t[e]=n}),t}function E(e,t,s,o){if(e===t)return 0!==e||1/e==1/t;if(e==r||t==r)return e===t;var u=yt.call(e);if(u!=yt.call(t))return i;switch(u){case At:case Ot:return+e==+t;case Mt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case Dt:case Pt:return e==t+""}var a=u==Lt||u==kt;if(It&&!a&&(a=v(e))&&!v(t))return i;if(!a){if(e.__wrapped__||t.__wrapped__)return E(e.__wrapped__||e,t.__wrapped__||t);if(u!=_t||Ut&&("function"!=typeof e.toString&&"string"==typeof (e+"")||"function"!=typeof 
+t.toString&&"string"==typeof (t+"")))return i;var u=e.constructor,f=t.constructor;if(u!=f&&(!S(u)||!(u instanceof u&&S(f)&&f instanceof f)))return i}s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var u=-1,f=n,l=0;s.push(e),o.push(t);if(a){l=e.length;if(f=l==t.length)for(;l--&&(f=E(e[l],t[l],s,o)););return f}for(var c in e)if(dt.call(e,c)&&(l++,!dt.call(t,c)||!E(e[c],t[c],s,o)))return i;for(c in t)if(dt.call(t,c)&&!(l--))return i;if(Ht)for(;7>++u;)if(c=ft[u],dt.call(e,c)&&(!dt.call
+(t,c)||!E(e[c],t[c],s,o)))return i;return n}function S(e){return"function"==typeof e}function x(e,t,n){var i=arguments,s=0,o=2,u=i[3],a=i[4];n!==K&&(u=[],a=[],o=i.length);for(;++s<o;)Zt(i[s],function(t,n){var i,s,o;if(t&&((s=sn(t))||on(t))){for(var f=u.length;f--;)if(i=u[f]==t)break;i?e[n]=a[f]:(u.push(t),a.push(o=(o=e[n],s)?sn(o)?o:[]:on(o)?o:{}),e[n]=x(o,t,K,u,a))}else t!=r&&(e[n]=t)});return e}function T(e){var t=[];return Zt(e,function(e){t.push(e)}),t}function N(e,t){return"number"==typeof (
+e?e.length:0)?-1<(yt.call(e)==Pt?e.indexOf(t):j(e,t)):P(e,function(e){return e===t})}function C(e,t,r){var i=n,t=f(t,r);return an(e,function(e,n,r){return i=!!t(e,n,r)}),i}function k(e,t,n){var r=[],t=f(t,n);return an(e,function(e,n,i){t(e,n,i)&&r.push(e)}),r}function L(e,t,r){var i,t=f(t,r);return P(e,function(e,r,s){return t(e,r,s)&&(i=e,n)}),i}function A(e,t,n){var r=-1,i=e?e.length:0,s=Array("number"==typeof i?i:0),t=f(t,n);if(sn(e))for(;++r<i;)s[r]=t(e[r],r,e);else an(e,function(e,n,i){s[++r
+]=t(e,n,i)});return s}function O(e,t,n){var r=-Infinity,i=-1,s=e?e.length:0,o=r;if(t||"number"!=typeof s)t=f(t,n),an(e,function(e,n,i){n=t(e,n,i),n>r&&(r=n,o=e)});else for(;++i<s;)e[i]>o&&(o=e[i]);return o}function M(e,t){var n=[];return an(e,function(e){n.push(e[t])}),n}function _(e,t,n,r){var s=3>arguments.length,t=f(t,r);return an(e,function(e,r,o){n=s?(s=i,e):t(n,e,r,o)}),n}function D(e,t,n,r){var s=e,o=e?e.length:0,u=3>arguments.length;if("number"!=typeof o)var a=un(e),o=a.length;else Rt&&yt
+.call(e)==Pt&&(s=e.split(""));return an(e,function(e,f,l){f=a?a[--o]:--o,n=u?(u=i,s[f]):t.call(r,n,s[f],f,l)}),n}function P(e,t,n){var r,t=f(t,n);return an(e,function(e,n,i){return!(r=t(e,n,i))}),!!r}function H(e,t,n){if(e)return t==r||n?e[0]:gt.call(e,0,t)}function B(e,t){for(var n=-1,r=e?e.length:0,i=[];++n<r;){var s=e[n];sn(s)?vt.apply(i,t?s:B(s)):i.push(s)}return i}function j(e,t,n){var r=-1,i=e?e.length:0;if("number"==typeof n)r=(0>n?Tt(0,i+n):n||0)-1;else if(n)return r=I(e,t),e[r]===t?r:-1;
+for(;++r<i;)if(e[r]===t)return r;return-1}function F(e,t,n){return e?gt.call(e,t==r||n?1:t):[]}function I(e,t,n,r){for(var i=0,s=e?e.length:i,n=n?f(n,r):U,t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r;return i}function q(e,t,n,r){var s=-1,o=e?e.length:0,u=[],a=u;"function"==typeof t&&(r=n,n=t,t=i),n&&(a=[],n=f(n,r));for(;++s<o;){var r=e[s],l=n?n(r,s,e):r;if(t?!s||a[a.length-1]!==l:0>j(a,l))n&&a.push(l),u.push(r)}return u}function R(e,t){return Wt||bt&&2<arguments.length?bt.call.apply(bt,arguments):a(
+e,t,gt.call(arguments,2))}function U(e){return e}function z(e){an(b(e),function(t){var r=s[t]=e[t];s.prototype[t]=function(){var e=[this.__wrapped__];return vt.apply(e,arguments),e=r.apply(s,e),this.__chain__&&(e=new s(e),e.__chain__=n),e}})}var n=!0,r=null,i=!1,W="object"==typeof exports&&exports,X="object"==typeof global&&global;X.global===X&&(e=X);var V=[],$={},J=0,K={},Q=30,G=e._,Y=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,Z=/&(?:amp|lt|gt|quot|#x27);/g,et=/\b__p\+='';/g
+,tt=/\b(__p\+=)''\+/g,nt=/(__e\(.*?\)|\b__t\))\+'';/g,rt=/\w*$/,it=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,st=RegExp("^"+($.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),ot=/($^)/,ut=/[&<>"']/g,at=/['\n\r\t\u2028\u2029\\]/g,ft="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),lt=Math.ceil,ct=V.concat,ht=Math.floor,pt=st.test(pt=Object.getPrototypeOf)&&pt,dt=$.hasOwnProperty,vt=V.push,mt=$.propertyIsEnumerable
+,gt=V.slice,yt=$.toString,bt=st.test(bt=gt.bind)&&bt,wt=st.test(wt=Array.isArray)&&wt,Et=e.isFinite,St=e.isNaN,xt=st.test(xt=Object.keys)&&xt,Tt=Math.max,Nt=Math.min,Ct=Math.random,kt="[object Arguments]",Lt="[object Array]",At="[object Boolean]",Ot="[object Date]",Mt="[object Number]",_t="[object Object]",Dt="[object RegExp]",Pt="[object String]",Ht,Bt,jt=(jt={0:1,length:1},V.splice.call(jt,0,1),jt[0]),Ft=n;(function(){function e(){this.x=1}var t=[];e.prototype={valueOf:1,y:1};for(var n in new e
+)t.push(n);for(n in arguments)Ft=!n;Ht=!/valueOf/.test(t),Bt="x"!=t[0]})(1);var It=!v(arguments),qt="x"!=gt.call("x")[0],Rt="xx"!="x"[0]+Object("x")[0];try{var Ut=("[object Object]",yt.call(e.document||0)==_t)}catch(zt){}var Wt=bt&&/\n|Opera/.test(bt+yt.call(e.opera)),Xt=xt&&/^.+$|true/.test(xt+!!e.attachEvent),Vt={};Vt[kt]=Vt["[object Function]"]=i,Vt[Lt]=Vt[At]=Vt[Ot]=Vt[Mt]=Vt[_t]=Vt[Dt]=Vt[Pt]=n;var $t={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i},Jt={"\\":"\\","'":"'","\n"
+:"n","\r":"r","        ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var Kt={a:"d,c,u",k:"c=e(c,u)",b:"if(c(w,h,d)===false)return r",g:"if(c(w,h,d)===false)return r"},Qt={l:i,a:"m",k:"for(var a=1,b=arguments.length;a<b;a++){if(j=arguments[a]){",g:"r[h]=w",c:"}}"},Gt={b:r};It&&(v=function(e){return e?dt.call(e,"callee"):i});var Yt=l(Kt,Gt,{l:i}),Zt=l(Kt,Gt),en={"&":"&amp;","<":"&lt;",">":"&gt;"
+,'"':"&quot;","'":"&#x27;"},tn=w(en),nn=l(Qt,{g:"if(r[h]==null)"+Qt.g}),rn=l(Qt),sn=wt||function(e){return yt.call(e)==Lt};S(/x/)&&(S=function(e){return"[object Function]"==yt.call(e)});var on=pt?function(e){if(!e||"object"!=typeof e)return i;var t=e.valueOf,n="function"==typeof t&&(n=pt(t))&&pt(n);return n?e==n||pt(e)==n&&!v(e):m(e)}:m,un=xt?function(e){var t=typeof e;return"function"==t&&mt.call(e,"prototype")?g(e):e&&$t[t]?xt(e):[]}:g,an=l(Kt);s.VERSION="0.9.1",s.after=function(e,t){return 1>e?
+t():function(){if(1>--e)return t.apply(this,arguments)}},s.bind=R,s.bindAll=function(e){for(var t=arguments,n=1<t.length?0:(t=b(e),-1),r=t.length;++n<r;){var i=t[n];e[i]=R(e[i],e)}return e},s.chain=function(e){return e=new s(e),e.__chain__=n,e},s.clone=y,s.compact=function(e){for(var t=-1,n=e?e.length:0,r=[];++t<n;){var i=e[t];i&&r.push(i)}return r},s.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},s.contains=N,s.countBy=
+function(e,t,n){var r={},t=f(t,n);return an(e,function(e,n,i){n=t(e,n,i),dt.call(r,n)?r[n]++:r[n]=1}),r},s.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,clearTimeout(a),a=setTimeout(i,t),r&&(o=e.apply(u,s)),o}},s.defaults=nn,s.defer=function(e){var n=gt.call(arguments,1);return setTimeout(function(){e.apply(t,n)},1)},s.delay=function(e,n){var r=gt.call(arguments,2);return setTimeout(function(){e.apply(t,r)},n)},s.
+difference=function(e){for(var t=-1,n=e?e.length:0,r=ct.apply(V,arguments),r=o(r,n),i=[];++t<n;){var s=e[t];r(s)||i.push(s)}return i},s.escape=function(e){return e==r?"":(e+"").replace(ut,h)},s.every=C,s.extend=rn,s.filter=k,s.find=L,s.first=H,s.flatten=B,s.forEach=an,s.forIn=Yt,s.forOwn=Zt,s.functions=b,s.groupBy=function(e,t,n){var r={},t=f(t,n);return an(e,function(e,n,i){n=t(e,n,i),(dt.call(r,n)?r[n]:r[n]=[]).push(e)}),r},s.has=function(e,t){return e?dt.call(e,t):i},s.identity=U,s.indexOf=j,s
+.initial=function(e,t,n){return e?gt.call(e,0,-(t==r||n?1:t)):[]},s.intersection=function(e){var t=arguments,n=t.length,r={},i=[];return an(e,function(e){if(0>j(i,e)){for(var s=n;--s;)if(!(r[s]||(r[s]=o(t[s])))(e))return;i.push(e)}}),i},s.invert=w,s.invoke=function(e,t){var n=gt.call(arguments,2),r="function"==typeof t,i=[];return an(e,function(e){i.push((r?t:e[t]).apply(e,n))}),i},s.isArguments=v,s.isArray=sn,s.isBoolean=function(e){return e===n||e===i||yt.call(e)==At},s.isDate=function(e){return yt
+.call(e)==Ot},s.isElement=function(e){return e?1===e.nodeType:i},s.isEmpty=function(e){var t=n;if(!e)return t;var r=yt.call(e),s=e.length;return r==Lt||r==Pt||r==kt||It&&v(e)||r==_t&&"number"==typeof s&&S(e.splice)?!s:(Zt(e,function(){return t=i}),t)},s.isEqual=E,s.isFinite=function(e){return Et(e)&&!St(parseFloat(e))},s.isFunction=S,s.isNaN=function(e){return yt.call(e)==Mt&&e!=+e},s.isNull=function(e){return e===r},s.isNumber=function(e){return yt.call(e)==Mt},s.isObject=function(e){return e?$t
+[typeof e]:i},s.isPlainObject=on,s.isRegExp=function(e){return yt.call(e)==Dt},s.isString=function(e){return yt.call(e)==Pt},s.isUndefined=function(e){return e===t},s.keys=un,s.last=function(e,t,n){if(e){var i=e.length;return t==r||n?e[i-1]:gt.call(e,-t||i)}},s.lastIndexOf=function(e,t,n){var r=e?e.length:0;for("number"==typeof n&&(r=(0>n?Tt(0,r+n):Nt(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.lateBind=function(e,t){return a(t,e,gt.call(arguments,2))},s.map=A,s.max=O,s.memoize=function(e,t)
+{var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return dt.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=x,s.min=function(e,t,n){var r=Infinity,i=-1,s=e?e.length:0,o=r;if(t||"number"!=typeof s)t=f(t,n),an(e,function(e,n,i){n=t(e,n,i),n<r&&(r=n,o=e)});else for(;++i<s;)e[i]<o&&(o=e[i]);return o},s.mixin=z,s.noConflict=function(){return e._=G,this},s.object=function(e,t){for(var n=-1,r=e?e.length:0,i={};++n<r;){var s=e[n];t?i[s]=t[n]:i[s[0]]=s[1]}return i},s.omit=function(
+e,t,n){var r="function"==typeof t,i={};if(r)t=f(t,n);else var s=ct.apply(V,arguments);return Yt(e,function(e,n,o){if(r?!t(e,n,o):0>j(s,n,1))i[n]=e}),i},s.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},s.pairs=function(e){var t=[];return Zt(e,function(e,n){t.push([n,e])}),t},s.partial=function(e){return a(e,gt.call(arguments,1))},s.pick=function(e,t,n){var r={};if("function"!=typeof t)for(var i=0,s=ct.apply(V,arguments),o=s.length;++i<o;){var u=s[i]
+;u in e&&(r[u]=e[u])}else t=f(t,n),Yt(e,function(e,n,i){t(e,n,i)&&(r[n]=e)});return r},s.pluck=M,s.random=function(e,t){return e==r&&t==r&&(t=1),e=+e||0,t==r&&(t=e,e=0),e+ht(Ct()*((+t||0)-e+1))},s.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=Tt(0,lt((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},s.reduce=_,s.reduceRight=D,s.reject=function(e,t,n){return t=f(t,n),k(e,function(e,n,r){return!t(e,n,r)})},s.rest=F,s.result=function(e,t){var n=e?e[t]:r;return S(n)?e[t]():n},s
+.shuffle=function(e){var t=-1,n=Array(e?e.length:0);return an(e,function(e){var r=ht(Ct()*(++t+1));n[t]=n[r],n[r]=e}),n},s.size=function(e){var t=e?e.length:0;return"number"==typeof t?t:un(e).length},s.some=P,s.sortBy=function(e,t,n){var r=[],t=f(t,n);an(e,function(e,n,i){r.push({a:t(e,n,i),b:n,c:e})}),e=r.length;for(r.sort(u);e--;)r[e]=r[e].c;return r},s.sortedIndex=I,s.tap=function(e,t){return t(e),e},s.template=function(e,t,n){e||(e=""),n||(n={});var r,i,o=0,u=s.templateSettings,a="__p += '",f=
+n.variable||u.variable,l=f;e.replace(RegExp((n.escape||u.escape||ot).source+"|"+(n.interpolate||u.interpolate||ot).source+"|"+(n.evaluate||u.evaluate||ot).source+"|$","g"),function(t,n,i,s,u){a+=e.slice(o,u).replace(at,c),a+=n?"'+__e("+n+")+'":s?"';"+s+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=s||Y.test(n||i)),o=u+t.length}),a+="';",l||(f="obj",r?a="with("+f+"){"+a+"}":(n=RegExp("(\\(\\s*)"+f+"\\."+f+"\\b","g"),a=a.replace(it,"$&"+f+".").replace(n,"$1__d"))),a=(r?a.replace(et,""):a)
+.replace(tt,"$1").replace(nt,"$1;"),a="function("+f+"){"+(l?"":f+"||("+f+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=[].join;function print(){__p+=__j.call(arguments,'')}":(l?"":",__d="+f+"."+f+"||"+f)+";")+a+"return __p}";try{i=Function("_","return "+a)(s)}catch(h){throw h.source=a,h}return t?i(t):(i.source=a,i)},s.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(clearTimeout
+(u),a=r,s=e.apply(o,i)):u||(u=setTimeout(n,f)),s}},s.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},s.toArray=function(e){return e&&"number"==typeof e.length?(qt?yt.call(e)==Pt:"string"==typeof e)?e.split(""):gt.call(e):T(e)},s.unescape=function(e){return e==r?"":(e+"").replace(Z,d)},s.union=function(){return q(ct.apply(V,arguments))},s.uniq=q,s.uniqueId=function(e){var t=J++;return e?e+t:t},s.values=T,s.where=function(e,t){var n=[];return Yt(t,function(e,
+t){n.push(t)}),k(e,function(e){for(var r=n.length;r--;){var i=e[n[r]]===t[n[r]];if(!i)break}return!!i})},s.without=function(e){for(var t=-1,n=e?e.length:0,r=o(arguments,1,20),i=[];++t<n;){var s=e[t];r(s)||i.push(s)}return i},s.wrap=function(e,t){return function(){var n=[e];return vt.apply(n,arguments),t.apply(this,n)}},s.zip=function(e){for(var t=-1,n=e?O(M(arguments,"length")):0,r=Array(n);++t<n;)r[t]=M(arguments,t);return r},s.all=C,s.any=P,s.collect=A,s.detect=L,s.drop=F,s.each=an,s.foldl=_,s.
+foldr=D,s.head=H,s.include=N,s.inject=_,s.methods=b,s.select=k,s.tail=F,s.take=H,s.unique=q,z(s),s.prototype.chain=function(){return this.__chain__=n,this},s.prototype.value=function(){return this.__wrapped__},an("pop push reverse shift sort splice unshift".split(" "),function(e){var t=V[e];s.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),jt&&e.length===0&&delete e[0],this.__chain__&&(e=new s(e),e.__chain__=n),e}}),an(["concat","join","slice"],function(e){var t=V[e];s.
+prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new s(e),e.__chain__=n),e}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e._=s,define(function(){return s})):W?"object"==typeof module&&module&&module.exports==W?(module.exports=s)._=s:W._=s:e._=s})(this);
\ No newline at end of file
diff --git a/client/assets/underscore.min.js b/client/assets/underscore.min.js
deleted file mode 100644 (file)
index 3315341..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-//     Underscore.js 1.4.2\r
-//     http://underscorejs.org\r
-//     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.\r
-//     Underscore may be freely distributed under the MIT license.\r
-(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=r.unshift,l=i.toString,c=i.hasOwnProperty,h=r.forEach,p=r.map,d=r.reduce,v=r.reduceRight,m=r.filter,g=r.every,y=r.some,b=r.indexOf,w=r.lastIndexOf,E=Array.isArray,S=Object.keys,x=s.bind,T=function(e){if(e instanceof T)return e;if(!(this instanceof T))return new T(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=T),exports._=T):e._=T,T.VERSION="1.4.2";var N=T.each=T.forEach=function(e,t,r){if(e==null)return;if(h&&e.forEach===h)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(T.has(e,o)&&t.call(r,e[o],o,e)===n)return};T.map=T.collect=function(e,t,n){var r=[];return e==null?r:p&&e.map===p?e.map(t,n):(N(e,function(e,i,s){r[r.length]=t.call(n,e,i,s)}),r)},T.reduce=T.foldl=T.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduce===d)return r&&(t=T.bind(t,r)),i?e.reduce(t,n):e.reduce(t);N(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.reduceRight=T.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(v&&e.reduceRight===v)return r&&(t=T.bind(t,r)),arguments.length>2?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=T.keys(e);s=o.length}N(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.find=T.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},T.filter=T.select=function(e,t,n){var r=[];return e==null?r:m&&e.filter===m?e.filter(t,n):(N(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},T.reject=function(e,t,n){var r=[];return e==null?r:(N(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r)},T.every=T.all=function(e,t,r){t||(t=T.identity);var i=!0;return e==null?i:g&&e.every===g?e.every(t,r):(N(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=T.some=T.any=function(e,t,r){t||(t=T.identity);var i=!1;return e==null?i:y&&e.some===y?e.some(t,r):(N(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};T.contains=T.include=function(e,t){var n=!1;return e==null?n:b&&e.indexOf===b?e.indexOf(t)!=-1:(n=C(e,function(e){return e===t}),n)},T.invoke=function(e,t){var n=u.call(arguments,2);return T.map(e,function(e){return(T.isFunction(t)?t:e[t]).apply(e,n)})},T.pluck=function(e,t){return T.map(e,function(e){return e[t]})},T.where=function(e,t){return T.isEmpty(t)?[]:T.filter(e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},T.max=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&T.isEmpty(e))return-Infinity;var r={computed:-Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},T.min=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&T.isEmpty(e))return Infinity;var r={computed:Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},T.shuffle=function(e){var t,n=0,r=[];return N(e,function(e){t=T.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return T.isFunction(e)?e:function(t){return t[e]}};T.sortBy=function(e,t,n){var r=k(t);return T.pluck(T.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t);return N(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};T.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(T.has(e,t)?e[t]:e[t]=[]).push(n)})},T.countBy=function(e,t,n){return L(e,t,n,function(e,t,n){T.has(e,t)||(e[t]=0),e[t]++})},T.sortedIndex=function(e,t,n,r){n=n==null?T.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},T.toArray=function(e){return e?e.length===+e.length?u.call(e):T.values(e):[]},T.size=function(e){return e.length===+e.length?e.length:T.keys(e).length},T.first=T.head=T.take=function(e,t,n){return t!=null&&!n?u.call(e,0,t):e[0]},T.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},T.last=function(e,t,n){return t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},T.rest=T.tail=T.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},T.compact=function(e){return T.filter(e,function(e){return!!e})};var A=function(e,t,n){return N(e,function(e){T.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};T.flatten=function(e,t){return A(e,t,[])},T.without=function(e){return T.difference(e,u.call(arguments,1))},T.uniq=T.unique=function(e,t,n,r){var i=n?T.map(e,n,r):e,s=[],o=[];return N(i,function(n,r){if(t?!r||o[o.length-1]!==n:!T.contains(o,n))o.push(n),s.push(e[r])}),s},T.union=function(){return T.uniq(a.apply(r,arguments))},T.intersection=function(e){var t=u.call(arguments,1);return T.filter(T.uniq(e),function(e){return T.every(t,function(t){return T.indexOf(t,e)>=0})})},T.difference=function(e){var t=a.apply(r,u.call(arguments,1));return T.filter(e,function(e){return!T.contains(t,e)})},T.zip=function(){var e=u.call(arguments),t=T.max(T.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=T.pluck(e,""+r);return n},T.object=function(e,t){var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},T.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=T.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(b&&e.indexOf===b)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},T.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(w&&e.lastIndexOf===w)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},T.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};T.bind=function(t,n){var r,i;if(t.bind===x&&x)return x.apply(t,u.call(arguments,1));if(!T.isFunction(t))throw new TypeError;return i=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=t.prototype;var e=new O,s=t.apply(e,i.concat(u.call(arguments)));return Object(s)===s?s:e}return t.apply(n,i.concat(u.call(arguments)))}},T.bindAll=function(e){var t=u.call(arguments,1);return t.length==0&&(t=T.functions(e)),N(t,function(t){e[t]=T.bind(e[t],e)}),e},T.memoize=function(e,t){var n={};return t||(t=T.identity),function(){var r=t.apply(this,arguments);return T.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},T.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},T.defer=function(e){return T.delay.apply(T,[e,1].concat(u.call(arguments,1)))},T.throttle=function(e,t){var n,r,i,s,o,u,a=T.debounce(function(){o=s=!1},t);return function(){n=this,r=arguments;var f=function(){i=null,o&&(u=e.apply(n,r)),a()};return i||(i=setTimeout(f,t)),s?o=!0:(s=!0,u=e.apply(n,r)),a(),u}},T.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},T.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},T.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},T.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},T.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},T.keys=S||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)T.has(e,n)&&(t[t.length]=n);return t},T.values=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push(e[n]);return t},T.pairs=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push([n,e[n]]);return t},T.invert=function(e){var t={};for(var n in e)T.has(e,n)&&(t[e[n]]=n);return t},T.functions=T.methods=function(e){var t=[];for(var n in e)T.isFunction(e[n])&&t.push(n);return t.sort()},T.extend=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]=t[n]}),e},T.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return N(n,function(n){n in e&&(t[n]=e[n])}),t},T.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)T.contains(n,i)||(t[i]=e[i]);return t},T.defaults=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]==null&&(e[n]=t[n])}),e},T.clone=function(e){return T.isObject(e)?T.isArray(e)?e.slice():T.extend({},e):e},T.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof T&&(e=e._wrapped),t instanceof T&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,f=t.constructor;if(a!==f&&!(T.isFunction(a)&&a instanceof a&&T.isFunction(f)&&f instanceof f))return!1;for(var c in e)if(T.has(e,c)){o++;if(!(u=T.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(T.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};T.isEqual=function(e,t){return M(e,t,[],[])},T.isEmpty=function(e){if(e==null)return!0;if(T.isArray(e)||T.isString(e))return e.length===0;for(var t in e)if(T.has(e,t))return!1;return!0},T.isElement=function(e){return!!e&&e.nodeType===1},T.isArray=E||function(e){return l.call(e)=="[object Array]"},T.isObject=function(e){return e===Object(e)},N(["Arguments","Function","String","Number","Date","RegExp"],function(e){T["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),T.isArguments(arguments)||(T.isArguments=function(e){return!!e&&!!T.has(e,"callee")}),typeof /./!="function"&&(T.isFunction=function(e){return typeof e=="function"}),T.isFinite=function(e){return T.isNumber(e)&&isFinite(e)},T.isNaN=function(e){return T.isNumber(e)&&e!=+e},T.isBoolean=function(e){return e===!0||e===!1||l.call(e)=="[object Boolean]"},T.isNull=function(e){return e===null},T.isUndefined=function(e){return e===void 0},T.has=function(e,t){return c.call(e,t)},T.noConflict=function(){return e._=t,this},T.identity=function(e){return e},T.times=function(e,t,n){for(var r=0;r<e;r++)t.call(n,r)},T.random=function(e,t){return t==null&&(t=e,e=0),e+(0|Math.random()*(t-e+1))};var _={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};_.unescape=T.invert(_.escape);var D={escape:new RegExp("["+T.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+T.keys(_.unescape).join("|")+")","g")};T.each(["escape","unescape"],function(e){T[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),T.result=function(e,t){if(e==null)return null;var n=e[t];return T.isFunction(n)?n.call(e):n},T.mixin=function(e){N(T.functions(e),function(t){var n=T[t]=e[t];T.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(T,e))}})};var P=0;T.uniqueId=function(e){var t=P++;return e?e+t:t},T.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;T.template=function(e,t,n){n=T.defaults({},n,T.templateSettings);var r=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),i=0,s="__p+='";e.replace(r,function(t,n,r,o,u){s+=e.slice(i,u).replace(j,function(e){return"\\"+B[e]}),s+=n?"'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?"'+\n((__t=("+r+"))==null?'':__t)+\n'":o?"';\n"+o+"\n__p+='":"",i=u+t.length}),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{var o=new Function(n.variable||"obj","_",s)}catch(u){throw u.source=s,u}if(t)return o(t,T);var a=function(e){return o.call(this,e,T)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},T.chain=function(e){return T(e).chain()};var F=function(e){return this._chain?T(e).chain():e};T.mixin(T),N(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];T.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),N(["concat","join","slice"],function(e){var t=r[e];T.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),T.extend(T.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
\ No newline at end of file
index 20480d6ad7ae4e2f4cc3cf636e1f333ca683e83e..431e742c9dd74df20810e59cc74529d549c8cb01 100644 (file)
@@ -8,8 +8,8 @@
     "node-static": "0.5.9",\r
     "uglify-js": "1.2.3",\r
     "socket.io": "0.8.7",\r
-    "underscore": "1.3.3",\r
-    "daemonize2": "0.4.0-rc.5",\r
-    "range_check": "0.0.1"\r
+    "range_check": "0.0.1",\r
+    "lodash": "0.9.1",\r
+    "daemonize2": "0.4.0-rc.5"\r
   }\r
 }\r
index 27aa0565b70ba361340979e8e0edd7a890c2cb2f..36edf0c0254088b4a797f7c90b48cd172a24bb31 100755 (executable)
@@ -1,7 +1,7 @@
 var util             = require('util'),
     events           = require('events'),
     crypto           = require('crypto'),
-    _                = require('underscore'),
+    _                = require('lodash'),
     IrcConnection    = require('./irc/connection.js').IrcConnection,
     IrcCommands      = require('./irc/commands.js'),
     ClientCommands   = require('./clientcommands.js');
index 065aac2b2e676c44aee67864dbda89e57ebcc63d..779b44e717ab722a4bfeb10aa4c690c04f62089b 100644 (file)
@@ -1,4 +1,4 @@
-var _ = require('underscore');\r
+var _ = require('lodash');\r
 \r
 \r
 \r
index 1750635899d571247049bb58192e329e42b2059d..36e8e63f826018f4926f7e1d1480105e1090eb97 100644 (file)
@@ -1,4 +1,4 @@
-var _ = require('underscore');
+var _ = require('lodash');
 
 var irc_numerics = {
     RPL_WELCOME:            '001',
@@ -38,7 +38,13 @@ var irc_numerics = {
     ERR_BANNEDFROMCHAN:     '474',
     ERR_BADCHANNELKEY:      '475',
     ERR_CHANOPRIVSNEEDED:   '482',
-    RPL_STARTTLS:           '670'
+    RPL_STARTTLS:           '670',
+    RPL_SASLAUTHENTICATED:  '900',
+    RPL_SASLLOGGEDIN:       '903',
+    ERR_SASLNOTAUTHORISED:  '904',
+    ERR_SASLABORTED:        '906',
+    ERR_SASLALREADYAUTHED:  '907'
+    
 };
 
 
@@ -70,460 +76,392 @@ IrcCommands.prototype.dispose = function () {
 
 
 var listeners = {
-    'RPL_WELCOME':            function (command) {
-                var nick =  command.params[0];
-                this.irc_connection.registered = true;
-                this.client.sendIrcCommand('connect', {server: this.con_num, nick: nick});
-            },
-    'RPL_ISUPPORT':           function (command) {
-                var options, i, option, matches, j;
-                options = command.params;
-                for (i = 1; i < options.length; i++) {
-                    option = options[i].split("=", 2);
-                    option[0] = option[0].toUpperCase();
-                    this.irc_connection.options[option[0]] = (typeof option[1] !== 'undefined') ? option[1] : true;
-                    if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES', 'CHANMODES', 'NAMESX'], option[0])) {
-                        if (option[0] === 'PREFIX') {
-                            matches = /\(([^)]*)\)(.*)/.exec(option[1]);
-                            if ((matches) && (matches.length === 3)) {
-                                this.irc_connection.options.PREFIX = [];
-                                for (j = 0; j < matches[2].length; j++) {
-                                    this.irc_connection.options.PREFIX.push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
-                                }
-                            }
-                                               } else if (option[0] === 'CHANTYPES') {
-                                                       this.irc_connection.options.CHANTYPES = this.irc_connection.options.CHANTYPES.split('');
-                                               } else if (option[0] === 'CHANMODES') {
-                                                       this.irc_connection.options.CHANMODES = option[1].split(',');
-                        } else if (option[0] === 'NAMESX') {
-                            this.irc_connection.write('PROTOCTL NAMESX');
+    'RPL_WELCOME': function (command) {
+        var nick =  command.params[0];
+        this.irc_connection.registered = true;
+        this.cap_negotation = false;
+        this.client.sendIrcCommand('connect', {server: this.con_num, nick: nick});
+    },
+    'RPL_ISUPPORT': function (command) {
+        var options, i, option, matches, j;
+        options = command.params;
+        for (i = 1; i < options.length; i++) {
+            option = options[i].split("=", 2);
+            option[0] = option[0].toUpperCase();
+            this.irc_connection.options[option[0]] = (typeof option[1] !== 'undefined') ? option[1] : true;
+            if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES', 'CHANMODES', 'NAMESX'], option[0])) {
+                if (option[0] === 'PREFIX') {
+                    matches = /\(([^)]*)\)(.*)/.exec(option[1]);
+                    if ((matches) && (matches.length === 3)) {
+                        this.irc_connection.options.PREFIX = [];
+                        for (j = 0; j < matches[2].length; j++) {
+                            this.irc_connection.options.PREFIX.push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
                         }
                     }
+                } else if (option[0] === 'CHANTYPES') {
+                    this.irc_connection.options.CHANTYPES = this.irc_connection.options.CHANTYPES.split('');
+                } else if (option[0] === 'CHANMODES') {
+                    this.irc_connection.options.CHANMODES = option[1].split(',');
+                } else if ((option[0] === 'NAMESX') && (!_.contains(this.irc_connection.cap.enabled, 'multi-prefix'))) {
+                    this.irc_connection.write('PROTOCTL NAMESX');
                 }
-                //this.client.sendIrcCommand({server: this.con_num, command: 'RPL_ISUPPORT', options: this.irc_connection.options});
-                //websocket.sendClientEvent('options', {server: '', "options": irc_connection.IRC.options});
-                this.client.sendIrcCommand('options', {server: this.con_num, options: this.irc_connection.options});
-            },
-    'RPL_ENDOFWHOIS':         function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_ENDOFWHOIS';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: true});
-                this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: true});
-            },
-    'RPL_WHOISUSER':          function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_WHOISUSER';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
-                this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], ident: command.params[2], host: command.params[3], msg: command.trailing, end: false});
-            },
-    'RPL_WHOISSERVER':        function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_WHOISSERVER';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
-                this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], irc_server: command.params[2], end: false});
-            },
-    'RPL_WHOISOPERATOR':      function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_WHOISOPERATOR';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
-                this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
-            },
-    'RPL_WHOISCHANNELS':      function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_WHOISCHANNELS';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
-                this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], chans: command.trailing, end: false});
-            },
-    'RPL_WHOISMODES':         function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_WHOISMODES';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
-                this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
-            },
-    'RPL_WHOISIDLE':          function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_WHOISIDLE';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
-                if (command.params[3]) {
-                    this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], logon: command.params[3], end: false});
-                } else {
-                    this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], end: false});
-                }
-            },
-    'RPL_WHOISREGNICK':       function (command) {
-                this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
-            },
-    'RPL_LISTSTART':          function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_LISTSTART';
-                               this.client.sendIrcCommand(command);*/
-                this.client.sendIrcCommand('list_start', {server: this.con_num});
-                this.client.buffer.list = [];
-            },
-    'RPL_LISTEND':            function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_LISTEND';
-                               this.client.sendIrcCommand(command);*/
-                if (this.client.buffer.list.length > 0) {
-                    this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
-                        return channel.num_users;
-                    });
-                    this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
-                    this.client.buffer.list = [];
-                }
-                this.client.sendIrcCommand('list_end', {server: this.con_num});
-            },
-    'RPL_LIST':               function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_LIST';
-                               this.client.sendIrcCommand(command);*/
-                this.client.buffer.list.push({server: this.con_num, channel: command.params[1], num_users: parseInt(command.params[2], 10), topic: command.trailing});
-                if (this.client.buffer.list.length > 200){
-                    this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
-                        return channel.num_users;
-                    });
-                    this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
-                    this.client.buffer.list = [];
-                }
-            },
-    'RPL_MOTD':               function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_MOTD';
-                               this.client.sendIrcCommand(command);*/
-                this.client.buffer.motd += command.trailing + '\n';
-            },
-    'RPL_MOTDSTART':          function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_MOTDSTART';
-                               this.client.sendIrcCommand(command);*/
-                this.client.buffer.motd = '';
-            },
-    'RPL_ENDOFMOTD':          function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_ENDOFMOTD';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('motd', {server: '', 'msg': websocket.kiwi.buffer.motd});
-                this.client.sendIrcCommand('motd', {server: this.con_num, msg: this.client.buffer.motd});
-            },
-    'RPL_NAMEREPLY':          function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_NAMEREPLY';
-                               this.client.sendIrcCommand(command);*/
-                var members = command.trailing.split(' ');
-                var member_list = [];
-                var that = this;
-                var i = 0;
-                _.each(members, function (member) {
-                    var j, k, modes = [];
-                    for (j = 0; j < member.length; j++) {
-                        for (k = 0; k < that.irc_connection.options.PREFIX.length; k++) {
-                            if (member.charAt(j) === that.irc_connection.options.PREFIX[k].symbol) {
-                                modes.push(that.irc_connection.options.PREFIX[k].mode);
-                                i++;
-                            }
-                        }
-                    }
-                    member_list.push({nick: member, modes: modes});
-                    if (i++ >= 50) {
-                        that.client.sendIrcCommand('userlist', {server: that.con_num, users: member_list, channel: command.params[2]});
-                        member_list = [];
-                        i = 0;
+            }
+        }
+        this.client.sendIrcCommand('options', {server: this.con_num, options: this.irc_connection.options, cap: this.irc_connection.cap.enabled});
+    },
+    'RPL_ENDOFWHOIS': function (command) {
+        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: true});
+    },
+    'RPL_WHOISUSER': function (command) {
+        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], ident: command.params[2], host: command.params[3], msg: command.trailing, end: false});
+    },
+    'RPL_WHOISSERVER': function (command) {
+        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], irc_server: command.params[2], end: false});
+    },
+    'RPL_WHOISOPERATOR': function (command) {
+        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
+    },
+    'RPL_WHOISCHANNELS':       function (command) {
+        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], chans: command.trailing, end: false});
+    },
+    'RPL_WHOISMODES': function (command) {
+        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
+    },
+    'RPL_WHOISIDLE': function (command) {
+        if (command.params[3]) {
+            this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], logon: command.params[3], end: false});
+        } else {
+            this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], end: false});
+        }
+    },
+    'RPL_WHOISREGNICK': function (command) {
+        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
+    },
+    'RPL_LISTSTART': function (command) {
+        this.client.sendIrcCommand('list_start', {server: this.con_num});
+        this.client.buffer.list = [];
+    },
+    'RPL_LISTEND': function (command) {
+        if (this.client.buffer.list.length > 0) {
+            this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
+                return channel.num_users;
+            });
+            this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
+            this.client.buffer.list = [];
+        }
+        this.client.sendIrcCommand('list_end', {server: this.con_num});
+    },
+    'RPL_LIST': function (command) {
+        this.client.buffer.list.push({server: this.con_num, channel: command.params[1], num_users: parseInt(command.params[2], 10), topic: command.trailing});
+        if (this.client.buffer.list.length > 200){
+            this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
+                return channel.num_users;
+            });
+            this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
+            this.client.buffer.list = [];
+        }
+    },
+    'RPL_MOTD': function (command) {
+        this.client.buffer.motd += command.trailing + '\n';
+    },
+    'RPL_MOTDSTART': function (command) {
+        this.client.buffer.motd = '';
+    },
+    'RPL_ENDOFMOTD': function (command) {
+        this.client.sendIrcCommand('motd', {server: this.con_num, msg: this.client.buffer.motd});
+    },
+    'RPL_NAMEREPLY': function (command) {
+        var members = command.trailing.split(' ');
+        var member_list = [];
+        var that = this;
+        var i = 0;
+        _.each(members, function (member) {
+            var j, k, modes = [];
+            for (j = 0; j < member.length; j++) {
+                for (k = 0; k < that.irc_connection.options.PREFIX.length; k++) {
+                    if (member.charAt(j) === that.irc_connection.options.PREFIX[k].symbol) {
+                        modes.push(that.irc_connection.options.PREFIX[k].mode);
+                        i++;
                     }
-                });
-                if (i > 0) {
-                    this.client.sendIrcCommand('userlist', {server: this.con_num, users: member_list, channel: command.params[2]});
-                }
-            },
-    'RPL_ENDOFNAMES':         function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_ENDOFNAMES';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('userlist_end', {server: '', channel: msg.params.split(" ")[1]});
-                this.client.sendIrcCommand('userlist_end', {server: this.con_num, channel: command.params[1]});
-            },
-    'RPL_BANLIST':            function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_BANLIST';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('banlist', {server: '', channel: params[1], banned: params[2], banned_by: params[3], banned_at: params[4]});
-                this.client.sendIrcCommand('banlist', {server: this.con_num, channel: command.params[1], banned: command.params[2], banned_by: command.params[3], banned_at: command.params[4]});
-            },
-    'RPL_ENDOFBANLIST':       function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_ENDOFBANLIST';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('banlist_end', {server: '', channel: msg.params.split(" ")[1]});
-                this.client.sendIrcCommand('banlist_end', {server: this.con_num, channel: command.params[1]});
-            },
-    'RPL_TOPIC':              function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_TOPIC';
-                               this.client.sendIrcCommand(command);*/
-                //{nick: '', channel: msg.params.split(" ")[1], topic: msg.trailing};
-                this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: command.trailing});
-            },
-    'RPL_NOTOPIC':            function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_NOTOPIC';
-                               this.client.sendIrcCommand(command);*/
-                this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: ''});
-            },
-    'RPL_TOPICWHOTIME':       function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'RPL_TOPICWHOTIME';
-                               this.client.sendIrcCommand(command);*/
-                //{nick: nick, channel: channel, when: when};
-                this.client.sendIrcCommand('topicsetby', {server: this.con_num, nick: command.params[2], channel: command.params[1], when: command.params[3]});
-            },
-    'PING':                 function (command) {
-                this.irc_connection.write('PONG ' + command.trailing);
-            },
-    'JOIN':                 function (command) {
-                               var channel;
-                               if (typeof command.trailing === 'string' && command.trailing !== '') {
-                                       channel = command.trailing;
-                               } else if (typeof command.params[0] === 'string' && command.params[0] !== '') {
-                                       channel = command.params[0];
-                               }
-                               /*command.server = this.con_num;
-                               command.command = 'JOIN';
-                               command.params = [channel];
-                this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('join', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: channel});
-                this.client.sendIrcCommand('join', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: channel});
-                
-                if (command.nick === this.nick) {
-                    this.irc_connection.write('NAMES ' + channel);
                 }
-            },
-    'PART':                 function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'PART';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('part', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), message: msg.trailing});
-                this.client.sendIrcCommand('part', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], message: command.trailing});
-            },
-    'KICK':                 function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'KICK';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('kick', {kicked: params[1], nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: params[0].trim(), message: msg.trailing});
-                this.client.sendIrcCommand('kick', {server: this.con_num, kicked: command.params[1], nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], message: command.trailing});
-            },
-    'QUIT':                 function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'QUIT';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('quit', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, message: msg.trailing});
-                this.client.sendIrcCommand('quit', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, message: command.trailing});
-            },
-    'NOTICE':               function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'NOTICE';
-                               this.client.sendIrcCommand(command);*/
-                if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
-                    // It's a CTCP response
-                    //websocket.sendClientEvent('ctcp_response', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(1, msg.trailing.length - 2)});
-                    this.client.sendIrcCommand('ctcp_response', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(1, command.trailing.length - 2)});
-                } else {
-                    //websocket.sendClientEvent('notice', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, target: msg.params.trim(), msg: msg.trailing});
-                    this.client.sendIrcCommand('notice', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, target: command.params[0], msg: command.trailing});
-                }
-            },
-    'NICK':                 function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'NICK';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('nick', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, newnick: msg.trailing});
-                this.client.sendIrcCommand('nick', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, newnick: command.trailing || command.params[0]});
-            },
-    'TOPIC':                function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'TOPIC';
-                               this.client.sendIrcCommand(command);*/
-                //{nick: msg.nick, channel: msg.params, topic: msg.trailing};
-                this.client.sendIrcCommand('topic', {server: this.con_num, nick: command.nick, channel: command.params[0], topic: command.trailing});
-            },
-    'MODE':                 function (command) {                
-                var chanmodes = this.irc_connection.options.CHANMODES,
-                    prefixes = this.irc_connection.options.PREFIX,
-                    always_param = chanmodes[0].concat(chanmodes[1]),
-                    modes = [],
-                    has_param, i, j, add;
-                
-                prefixes = _.reduce(prefixes, function (list, prefix) {
-                    list.push(prefix.mode);
-                    return list;
-                }, []);
-                always_param = always_param.split('').concat(prefixes);
-                
-                has_param = function (mode, add) {
-                    if (_.find(always_param, function (m) {
-                        return m === mode;
-                    })) {
-                        return true;
-                    } else if (add && _.find(chanmodes[2].split(''), function (m) {
-                        return m === mode;
-                    })) {
-                        return true;
+            }
+            member_list.push({nick: member, modes: modes});
+            if (i++ >= 50) {
+                that.client.sendIrcCommand('userlist', {server: that.con_num, users: member_list, channel: command.params[2]});
+                member_list = [];
+                i = 0;
+            }
+        });
+        if (i > 0) {
+            this.client.sendIrcCommand('userlist', {server: this.con_num, users: member_list, channel: command.params[2]});
+        }
+    },
+    'RPL_ENDOFNAMES': function (command) {
+        this.client.sendIrcCommand('userlist_end', {server: this.con_num, channel: command.params[1]});
+    },
+    'RPL_BANLIST': function (command) {
+        this.client.sendIrcCommand('banlist', {server: this.con_num, channel: command.params[1], banned: command.params[2], banned_by: command.params[3], banned_at: command.params[4]});
+    },
+    'RPL_ENDOFBANLIST': function (command) {
+        this.client.sendIrcCommand('banlist_end', {server: this.con_num, channel: command.params[1]});
+    },
+    'RPL_TOPIC': function (command) {
+        this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: command.trailing});
+    },
+    'RPL_NOTOPIC': function (command) {
+        this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: ''});
+    },
+    'RPL_TOPICWHOTIME': function (command) {
+        this.client.sendIrcCommand('topicsetby', {server: this.con_num, nick: command.params[2], channel: command.params[1], when: command.params[3]});
+    },
+    'PING': function (command) {
+        this.irc_connection.write('PONG ' + command.trailing);
+    },
+    'JOIN': function (command) {
+        var channel;
+        if (typeof command.trailing === 'string' && command.trailing !== '') {
+            channel = command.trailing;
+        } else if (typeof command.params[0] === 'string' && command.params[0] !== '') {
+            channel = command.params[0];
+        }
+        
+        this.client.sendIrcCommand('join', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: channel});
+        
+        if (command.nick === this.nick) {
+            this.irc_connection.write('NAMES ' + channel);
+        }
+    },
+    'PART': function (command) {
+        this.client.sendIrcCommand('part', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], message: command.trailing});
+    },
+    'KICK': function (command) {
+        this.client.sendIrcCommand('kick', {server: this.con_num, kicked: command.params[1], nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], message: command.trailing});
+    },
+    'QUIT': function (command) {
+        this.client.sendIrcCommand('quit', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, message: command.trailing});
+    },
+    'NOTICE': function (command) {
+        if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
+            // It's a CTCP response
+            this.client.sendIrcCommand('ctcp_response', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(1, command.trailing.length - 2)});
+        } else {
+            this.client.sendIrcCommand('notice', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, target: command.params[0], msg: command.trailing});
+        }
+    },
+    'NICK': function (command) {
+        this.client.sendIrcCommand('nick', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, newnick: command.trailing || command.params[0]});
+    },
+    'TOPIC': function (command) {
+        this.client.sendIrcCommand('topic', {server: this.con_num, nick: command.nick, channel: command.params[0], topic: command.trailing});
+    },
+    'MODE': function (command) {                
+        var chanmodes = this.irc_connection.options.CHANMODES,
+            prefixes = this.irc_connection.options.PREFIX,
+            always_param = chanmodes[0].concat(chanmodes[1]),
+            modes = [],
+            has_param, i, j, add;
+        
+        prefixes = _.reduce(prefixes, function (list, prefix) {
+            list.push(prefix.mode);
+            return list;
+        }, []);
+        always_param = always_param.split('').concat(prefixes);
+        
+        has_param = function (mode, add) {
+            if (_.find(always_param, function (m) {
+                return m === mode;
+            })) {
+                return true;
+            } else if (add && _.find(chanmodes[2].split(''), function (m) {
+                return m === mode;
+            })) {
+                return true;
+            } else {
+                return false;
+            }
+        };
+        
+        if (!command.params[1]) {
+            command.params[1] = command.trailing;
+        }
+        j = 0;
+        for (i = 0; i < command.params[1].length; i++) {
+            switch (command.params[1][i]) {
+                case '+':
+                    add = true;
+                    break;
+                case '-':
+                    add = false;
+                    break;
+                default:
+                    if (has_param(command.params[1][i], add)) {
+                        modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: command.params[2 + j]});
+                        j++;
                     } else {
-                        return false;
+                        modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: null});
                     }
-                };
-                
-                if (!command.params[1]) {
-                    command.params[1] = command.trailing;
+            }
+        }
+        
+        this.client.sendIrcCommand('mode', {
+            server: this.con_num,
+            target: command.params[0],
+            nick: command.nick || command.prefix || '',
+            modes: modes
+        });
+    },
+    'PRIVMSG': function (command) {
+        var tmp, namespace;
+        if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
+            //CTCP request
+            if (command.trailing.substr(1, 6) === 'ACTION') {
+                this.client.sendIrcCommand('action', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(7, command.trailing.length - 2)});
+            } else if (command.trailing.substr(1, 4) === 'KIWI') {
+                tmp = command.trailing.substr(6, command.trailing.length - 2);
+                namespace = tmp.split(' ', 1)[0];
+                this.client.sendIrcCommand('kiwi', {server: this.con_num, namespace: namespace, data: tmp.substr(namespace.length + 1)});
+            } else if (command.trailing.substr(1, 7) === 'VERSION') {
+                this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1));
+            } else {
+                this.client.sendIrcCommand('ctcp_request', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(1, command.trailing.length - 2)});
+            }
+        } else {
+            //{nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing}
+            this.client.sendIrcCommand('msg', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing});
+        }
+    },
+    'CAP': function (command) {
+        // TODO: capability modifiers
+        // i.e. - for disable, ~ for requires ACK, = for sticky
+        var capabilities = command.trailing.replace(/[\-~=]/, '').split(' ');
+        var request;
+        var want = ['multi-prefix', 'away-notify'];
+        
+        if (this.irc_connection.password) {
+            want.push('sasl');
+        }
+        
+        switch (command.params[1]) {
+            case 'LS':
+                request = _.intersection(capabilities, want);
+                if (request.length > 0) {
+                    this.irc_connection.cap.requested = request;
+                    this.irc_connection.write('CAP REQ :' + request.join(' '));
+                } else {
+                    this.irc_connection.write('CAP END');
+                    this.irc_connection.cap_negotation = false;
                 }
-                j = 0;
-                for (i = 0; i < command.params[1].length; i++) {
-                    switch (command.params[1][i]) {
-                        case '+':
-                            add = true;
-                            break;
-                        case '-':
-                            add = false;
-                            break;
-                        default:
-                            if (has_param(command.params[1][i], add)) {
-                                modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: command.params[2 + j]});
-                                j++;
-                            } else {
-                                modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: null});
-                            }
-                    }
+                break;
+            case 'ACK':
+                if (capabilities.length > 0) {
+                    this.irc_connection.cap.enabled = capabilities;
+                    this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
                 }
-                
-                this.client.sendIrcCommand('mode', {
-                    server: this.con_num,
-                    target: command.params[0],
-                    nick: command.nick || command.prefix || '',
-                    modes: modes
-                });
-            },
-    'PRIVMSG':              function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'PRIVMSG';
-                               this.client.sendIrcCommand(command);*/
-                var tmp, namespace;
-                if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
-                    //CTCP request
-                    if (command.trailing.substr(1, 6) === 'ACTION') {
-                        this.client.sendIrcCommand('action', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(7, command.trailing.length - 2)});
-                    } else if (command.trailing.substr(1, 4) === 'KIWI') {
-                        tmp = command.trailing.substr(6, command.trailing.length - 2);
-                        namespace = tmp.split(' ', 1)[0];
-                        this.client.sendIrcCommand('kiwi', {server: this.con_num, namespace: namespace, data: tmp.substr(namespace.length + 1)});
-                    } else if (command.trailing.substr(1, 7) === 'VERSION') {
-                        this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1));
+                if (this.irc_connection.cap.requested.length > 0) {
+                    if (_.contains(this.irc_connection.cap.enabled, 'sasl')) {
+                        this.irc_connection.sasl = true;
+                        this.irc_connection.write('AUTHENTICATE PLAIN');
                     } else {
-                        this.client.sendIrcCommand('ctcp_request', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(1, command.trailing.length - 2)});
+                        this.irc_connection.write('CAP END');
+                        this.irc_connection.cap_negotation = false;
                     }
-                } else {
-                    //{nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing}
-                    this.client.sendIrcCommand('msg', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing});
                 }
-            },
-    'ERROR':                function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERROR';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'error', reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'error', reason: command.trailing});
-            },
-    ERR_LINKCHANNEL:        function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_LINKCHANNEL';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('channel_redirect', {from: params[1], to: params[2]});
-                this.client.sendIrcCommand('channel_redirect', {server: this.con_num, from: command.params[1], to: command.params[2]});
-            },
-    ERR_NOSUCHNICK:         function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_NOSUCHNICK';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'no_such_nick', nick: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'no_such_nick', nick: command.params[1], reason: command.trailing});
-            },
-    ERR_CANNOTSENDTOCHAN:   function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_CANNOTSENDTOCHAN';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'cannot_send_to_chan', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'cannot_send_to_chan', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_TOOMANYCHANNELS:    function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_TOOMANYCHANNELS';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'too_many_channels', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'too_many_channels', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_USERNOTINCHANNEL:   function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_USERNOTINCHANNEL';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'user_not_in_channel', nick: params[0], channel: params[1], reason: msg.trainling});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'user_not_in_channel', nick: command.params[0], channel: command.params[1], reason: command.trailing});
-            },
-    ERR_NOTONCHANNEL:       function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_NOTONCHANNEL';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'not_on_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'not_on_channel', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_CHANNELISFULL:      function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_CHANNELISFULL';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'channel_is_full', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'channel_is_full', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_INVITEONLYCHAN:     function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_INVITEONLYCHAN';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'invite_only_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'invite_only_channel', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_BANNEDFROMCHAN:     function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_BANNEDFROMCHAN';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'banned_from_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'banned_from_channel', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_BADCHANNELKEY:      function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_BADCHANNELKEY';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'bad_channel_key', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'bad_channel_key', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_CHANOPRIVSNEEDED:   function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_CHANOPRIVSNEEDED';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'chanop_privs_needed', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'chanop_privs_needed', channel: command.params[1], reason: command.trailing});
-            },
-    ERR_NICKNAMEINUSE:      function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_NICKNAMEINUSE';
-                               this.client.sendIrcCommand(command);*/
-                //websocket.sendClientEvent('irc_error', {error: 'nickname_in_use', nick: _.last(msg.params.split(" ")), reason: msg.trailing});
-                this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'nickname_in_use', nick: command.params[1], reason: command.trailing});
-            },
-    ERR_NOTREGISTERED:      function (command) {
-                               /*command.server = this.con_num;
-                               command.command = 'ERR_NOTREGISTERED';
-                               this.client.sendIrcCommand(command);*/
+                break;
+            case 'NAK':
+                if (capabilities.length > 0) {
+                    this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
+                }
+                if (this.irc_connection.cap.requested.length > 0) {
+                    this.irc_connection.write('CAP END');
+                    this.irc_connection.cap_negotation = false;
+                }
+                break;
+            case 'LIST':
+                // should we do anything here?
+                break;
+        }
+    },
+    'AUTHENTICATE': function (command) {
+        var b = new Buffer(this.irc_connection.nick + "\0" + this.irc_connection.nick + "\0" + this.irc_connection.password, 'utf8');
+        var b64 = b.toString('base64');
+        if (command.params[0] === '+') {
+            while (b64.length >= 400) {
+                this.irc_connection.write('AUTHENTICATE ' + b64.slice(0, 399));
+                b64 = b64.slice(399);
+            }
+            if (b64.length > 0) {
+                this.irc_connection.write('AUTHENTICATE ' + b64);
+            } else {
+                this.irc_connection.write('AUTHENTICATE +');
             }
+        } else {
+            this.irc_connection.write('CAP END');
+            this.irc_connection.cap_negotation = false;
+        }
+    },
+    'AWAY': function (command) {
+        this.client.sendIrcCommand('away', {server: this.con_num, nick: command.nick, msg: command.trailing});
+    },
+    'RPL_SASLAUTHENTICATED': function (command) {
+        this.irc_connection.write('CAP END');
+        this.irc_connection.cap_negotation = false;
+        this.irc_connection.sasl = true;
+    },
+    'RPL_SASLLOGGEDIN': function (command) {
+        if (this.irc_connection.cap_negotation === false) {
+            this.irc_connection.write('CAP END');
+        }
+    },
+    'ERR_SASLNOTAUTHORISED': function (command) {
+            this.irc_connection.write('CAP END');
+            this.irc_connection.cap_negotation = false;
+        },
+    'ERR_SASLABORTED': function (command) {
+        this.irc_connection.write('CAP END');
+        this.irc_connection.cap_negotation = false;
+    },
+    'ERR_SASLALREADYAUTHED': function (command) {
+        // noop
+    },
+    'ERROR': function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'error', reason: command.trailing});
+    },
+    ERR_LINKCHANNEL: function (command) {
+        this.client.sendIrcCommand('channel_redirect', {server: this.con_num, from: command.params[1], to: command.params[2]});
+    },
+    ERR_NOSUCHNICK: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'no_such_nick', nick: command.params[1], reason: command.trailing});
+    },
+    ERR_CANNOTSENDTOCHAN: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'cannot_send_to_chan', channel: command.params[1], reason: command.trailing});
+    },
+    ERR_TOOMANYCHANNELS: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'too_many_channels', channel: command.params[1], reason: command.trailing});
+    },
+    ERR_USERNOTINCHANNEL: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'user_not_in_channel', nick: command.params[0], channel: command.params[1], reason: command.trailing});
+    },
+    ERR_NOTONCHANNEL: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'not_on_channel', channel: command.params[1], reason: command.trailing});
+    },
+    ERR_CHANNELISFULL: function (command) {
+            this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'channel_is_full', channel: command.params[1], reason: command.trailing});
+        },
+    ERR_INVITEONLYCHAN: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'invite_only_channel', channel: command.params[1], reason: command.trailing});
+    },
+    ERR_BANNEDFROMCHAN: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'banned_from_channel', channel: command.params[1], reason: command.trailing});
+    },
+    ERR_BADCHANNELKEY: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'bad_channel_key', channel: command.params[1], reason: command.trailing});
+    },
+    ERR_CHANOPRIVSNEEDED: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'chanop_privs_needed', channel: command.params[1], reason: command.trailing});
+    },
+    ERR_NICKNAMEINUSE: function (command) {
+        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'nickname_in_use', nick: command.params[1], reason: command.trailing});
+    },
+    ERR_NOTREGISTERED: function (command) {
+    }
 };
index e7a4895a6621311b80d542ffffc4bdd815dba89c..887903d2e73a90e52a8a35e0de924d695e8c13de 100644 (file)
@@ -2,12 +2,12 @@ var net     = require('net'),
     tls     = require('tls'),
     events  = require('events'),
     util    = require('util'),
-    _       = require('underscore');
+    _       = require('lodash');
 
 var IrcConnection = function (hostname, port, ssl, nick, user, pass) {
     var that = this;
     events.EventEmitter.call(this);
-    
+
     if (ssl) {
         this.socket = tls.connect({
             host: hostname,
@@ -39,11 +39,15 @@ var IrcConnection = function (hostname, port, ssl, nick, user, pass) {
     
     this.connected = false;
     this.registered = false;
+    this.cap_negotiation = true;
     this.nick = nick;
     this.user = user;
+    this.username = this.nick.replace(/[^0-9a-zA-Z\-_.]/, ''),
     this.irc_host = {hostname: hostname, port: port};
     this.ssl = !(!ssl);
     this.options = Object.create(null);
+    this.cap = {requested: [], enabled: []};
+    this.sasl = false;
     
     this.password = pass;
     this.hold_last = false;
@@ -85,12 +89,12 @@ var connect_handler = function () {
         user: this.user,
         nick: this.nick,
         realname: '[www.kiwiirc.com] ' + this.nick,
-        username: this.nick.replace(/[^0-9a-zA-Z\-_.]/, ''),
+        username: this.username,
         irc_host: this.irc_host
     };
 
     // Let the webirc/etc detection modify any required parameters
-    connect_data = findWebIrc(connect_data);
+    connect_data = findWebIrc.call(this, connect_data);
 
     // Send any initial data for webirc/etc
     if (connect_data.prepend_data) {
@@ -99,20 +103,19 @@ var connect_handler = function () {
         });
     }
 
+    this.write('CAP LS');
+
     if (this.password) {
         this.write('PASS ' + this.password);
     }
-    
-    this.write('NICK ' + connect_data.nick);
-    this.write('USER ' + connect_data.username + ' 0 0 :' + connect_data.realname);
+    this.write('NICK ' + this.nick);
+    this.write('USER ' + this.username + ' 0 0 :' + '[www.kiwiirc.com] ' + this.nick);
     
     this.connected = true;
     this.emit('connected');
 };
 
 
-
-
 function findWebIrc(connect_data) {
     var webirc_pass = global.config.webirc_pass;
     var ip_as_username = global.config.ip_as_username;
@@ -129,7 +132,7 @@ function findWebIrc(connect_data) {
     // Check if we need to pass the users IP as its username/ident
     if (ip_as_username && ip_as_username.indexOf(connect_data.irc_host.hostname) > -1) {
         // Get a hex value of the clients IP
-        connect_data.username = connect_data.user.address.split('.').map(function(i, idx){
+        this.username = connect_data.user.address.split('.').map(function(i, idx){
             return parseInt(i, 10).toString(16);
         }).join('');
 
@@ -140,12 +143,15 @@ function findWebIrc(connect_data) {
 
 
 
-parse_regex = /^(?::(?:([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)|([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)!([a-z0-9~\.\-_|]+)@?([a-z0-9\.\-:\/]+)?) )?(\S+)(?: (?!:)(.+?))?(?: :(.+))?$/i;
+parse_regex = /^(?:(?:(?:(@[^ ]+) )?):(?:([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)|([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)!([a-z0-9~\.\-_|]+)@?([a-z0-9\.\-:\/]+)?) )?(\S+)(?: (?!:)(.+?))?(?: :(.+))?$/i;
 var parse = function (data) {
     var i,
         msg,
-               msg2,
-               trm;
+        msg2,
+        trm,
+        j,
+        tags = [],
+        tag;
     
     if ((this.hold_last) && (this.held_data !== '')) {
         data = this.held_data + data;
@@ -166,14 +172,22 @@ var parse = function (data) {
             // We have a complete line of data, parse it!
             msg = parse_regex.exec(data[i].replace(/^\r+|\r+$/, ''));
             if (msg) {
+                if (msg[1]) {
+                    tags = msg[1].split(';');
+                    for (j = 0; j < tags.length; j++) {
+                        tag = tags[j].split('=');
+                        tags[j] = {tag: tag[0], value: tag[1]};
+                    }
+                }
                 msg = {
-                    prefix:     msg[1],
-                    nick:       msg[2],
-                    ident:      msg[3],
-                    hostname:   msg[4] || '',
-                    command:    msg[5],
-                    params:     msg[6] || '',
-                    trailing:   (msg[7]) ? msg[7].trim() : ''
+                    tags:       tags,
+                    prefix:     msg[2],
+                    nick:       msg[3],
+                    ident:      msg[4],
+                    hostname:   msg[5] || '',
+                    command:    msg[6],
+                    params:     msg[7] || '',
+                    trailing:   (msg[8]) ? msg[8].trim() : ''
                 };
                 msg.params = msg.params.split(' ');
 
index 1acb7d0186256b5a6fd6ad2817fe6e326ca2abe5..8151db4aa9459a8c547a8ecc8e41735a80b189ed 100755 (executable)
@@ -1,5 +1,5 @@
 var fs          = require('fs'),
-    _           = require('underscore'),
+    _           = require('lodash'),
     WebListener = require('./weblistener.js'),
     config      = require('./configuration.js'),
     rehash      = require('./rehash.js');
index 0823eda044e9c6dfe5dc985e036399c5b4d4f40a..7ffbe45115f165bab93aa476a54299cbddc68689 100644 (file)
@@ -1,6 +1,6 @@
 var util   = require('util'),\r
     events = require('events'),\r
-    _      = require('underscore');\r
+    _      = require('lodash');\r
 \r
 \r
 \r
index 08536fc7f8a671b316ce4922a798f0b39b13f3ae..3ab24370abd52d5318a0927ad4cfca5b38bfa550 100644 (file)
@@ -6,7 +6,7 @@ var ws          = require('socket.io'),
     fs          = require('fs'),
     dns         = require('dns'),
     url         = require('url'),
-    _           = require('underscore'),
+    _           = require('lodash'),
     Client      = require('./client.js').Client,
     HttpHandler = require('./httphandler.js').HttpHandler,
     rehash      = require('./rehash.js'),