From f8c647344ea45c2f65b0ef5394408dc9d69a081f Mon Sep 17 00:00:00 2001
From: Rob DiMarco <rob@firebase.com>
Date: Tue, 18 Feb 2014 12:22:27 -0800
Subject: [PATCH] Fixes #9 - Bug impacting 'Accepted' modal, bump version to
 v0.1.5

---
 dist/0.1.5/firechat-default.css     |  944 ++++++++++++++
 dist/0.1.5/firechat-default.js      | 1831 +++++++++++++++++++++++++++
 dist/0.1.5/firechat-default.min.css |    1 +
 dist/0.1.5/firechat-default.min.js  |    2 +
 examples/anonymous_auth.html        |    4 +-
 src/js/firechat-ui.js               |    4 +-
 6 files changed, 2782 insertions(+), 4 deletions(-)
 create mode 100644 dist/0.1.5/firechat-default.css
 create mode 100644 dist/0.1.5/firechat-default.js
 create mode 100644 dist/0.1.5/firechat-default.min.css
 create mode 100644 dist/0.1.5/firechat-default.min.js

diff --git a/dist/0.1.5/firechat-default.css b/dist/0.1.5/firechat-default.css
new file mode 100644
index 0000000..91a6c1a
--- /dev/null
+++ b/dist/0.1.5/firechat-default.css
@@ -0,0 +1,944 @@
+@charset "UTF-8";
+/* Boilerplate: Reset
+============================================================ */
+#firechat div,
+#firechat span,
+#firechat applet,
+#firechat object,
+#firechat iframe,
+#firechat h1,
+#firechat h2,
+#firechat h3,
+#firechat h4,
+#firechat h5,
+#firechat h6,
+#firechat p,
+#firechat blockquote,
+#firechat pre,
+#firechat a,
+#firechat abbr,
+#firechat acronym,
+#firechat address,
+#firechat big,
+#firechat cite,
+#firechat code,
+#firechat del,
+#firechat dfn,
+#firechat em,
+#firechat img,
+#firechat ins,
+#firechat kbd,
+#firechat q,
+#firechat s,
+#firechat samp,
+#firechat small,
+#firechat strike,
+#firechat strong,
+#firechat sub,
+#firechat sup,
+#firechat tt,
+#firechat var,
+#firechat b,
+#firechat u,
+#firechat i,
+#firechat center,
+#firechat dl,
+#firechat dt,
+#firechat dd,
+#firechat ol,
+#firechat ul,
+#firechat li,
+#firechat fieldset,
+#firechat form,
+#firechat label,
+#firechat legend,
+#firechat table,
+#firechat caption,
+#firechat tbody,
+#firechat tfoot,
+#firechat thead,
+#firechat tr,
+#firechat th,
+#firechat td,
+#firechat article,
+#firechat aside,
+#firechat canvas,
+#firechat details,
+#firechat embed,
+#firechat figure,
+#firechat figcaption,
+#firechat footer,
+#firechat header,
+#firechat hgroup,
+#firechat menu,
+#firechat nav,
+#firechat output,
+#firechat ruby,
+#firechat section,
+#firechat summary,
+#firechat time,
+#firechat mark,
+#firechat audio,
+#firechat video {
+  border: 0;
+  font-size: 12px;
+  font-family: arial, helvetica, sans-serif;
+  vertical-align: baseline;
+  margin: 0;
+  padding: 0;
+}
+#firechat article,
+#firechat aside,
+#firechat details,
+#firechat figcaption,
+#firechat figure,
+#firechat footer,
+#firechat header,
+#firechat hgroup,
+#firechat menu,
+#firechat nav,
+#firechat section {
+  display: block;
+}
+#firechat body {
+  line-height: 1;
+}
+#firechat ol,
+#firechat ul {
+  list-style: none;
+}
+#firechat blockquote,
+#firechat q {
+  quotes: none;
+}
+#firechat blockquote:before,
+#firechat blockquote:after,
+#firechat q:before,
+#firechat q:after {
+  content: none;
+}
+#firechat table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+/* Boilerplate: Mixins
+============================================================ */
+.clearfix {
+  *zoom: 1;
+}
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  content: "";
+  line-height: 0;
+}
+.clearfix:after {
+  clear: both;
+}
+/* Boilerplate: Responsive Layout
+============================================================ */
+#firechat {
+  color: #333;
+  text-align: left;
+}
+#firechat .center {
+  float: none !important;
+  margin-left: auto !important;
+  margin-right: auto !important;
+}
+#firechat .left {
+  float: left !important;
+}
+#firechat .right {
+  float: right !important;
+}
+#firechat .alignleft {
+  text-align: left !important;
+}
+#firechat .alignright {
+  text-align: right !important;
+}
+#firechat .aligncenter {
+  text-align: center !important;
+}
+#firechat .hidden {
+  display: none !important;
+}
+#firechat .row {
+  clear: both;
+}
+#firechat .fifth,
+#firechat .fivesixth,
+#firechat .fourfifth,
+#firechat .half,
+#firechat .ninetenth,
+#firechat .quarter,
+#firechat .sevententh,
+#firechat .sixth,
+#firechat .tenth,
+#firechat .third,
+#firechat .threefifth,
+#firechat .threequarter,
+#firechat .threetenth,
+#firechat .twofifth,
+#firechat .twothird,
+#firechat .full {
+  margin-left: 2.127659574468085%;
+  float: left;
+  min-height: 1px;
+}
+#firechat .fifth:first-child,
+#firechat .fivesixth:first-child,
+#firechat .fourfifth:first-child,
+#firechat .half:first-child,
+#firechat .ninetenth:first-child,
+#firechat .quarter:first-child,
+#firechat .sevententh:first-child,
+#firechat .sixth:first-child,
+#firechat .tenth:first-child,
+#firechat .third:first-child,
+#firechat .threefifth:first-child,
+#firechat .threequarter:first-child,
+#firechat .threetenth:first-child,
+#firechat .twofifth:first-child,
+#firechat .twothird:first-child,
+#firechat .full:first-child {
+  margin-left: 0;
+}
+#firechat .tenth {
+  width: 8.08510638297872%;
+}
+#firechat .sixth {
+  width: 14.893617021276595%;
+}
+#firechat .fifth {
+  width: 18.297872340425535%;
+}
+#firechat .quarter {
+  width: 23.404255319148938%;
+}
+#firechat .threetenth {
+  width: 26.3829787235%;
+}
+#firechat .third {
+  width: 31.914893617021278%;
+}
+#firechat .twofifth {
+  width: 38.72340425531915%;
+}
+#firechat .half {
+  width: 48.93617021276596%;
+}
+#firechat .sevententh {
+  width: 58.7234042555%;
+}
+#firechat .threefifth {
+  width: 59.14893617021278%;
+}
+#firechat .twothird {
+  width: 65.95744680851064%;
+}
+#firechat .threequarter {
+  width: 74.46808510638297%;
+}
+#firechat .ninetenth {
+  width: 74.8936170215%;
+}
+#firechat .fourfifth {
+  width: 79.57446808510639%;
+}
+#firechat .fivesixth {
+  width: 82.9787234042553%;
+}
+#firechat .full {
+  width: 100%;
+}
+#firechat .clipped {
+  overflow: hidden;
+}
+#firechat strong {
+  font-weight: bold;
+}
+#firechat em {
+  font-style: italic;
+}
+#firechat label {
+  display: block;
+}
+#firechat a {
+  color: #005580;
+}
+#firechat a:visited,
+#firechat a:hover,
+#firechat a:active {
+  color: #005580;
+}
+#firechat p {
+  margin: 10px 0;
+}
+#firechat h1,
+#firechat h2,
+#firechat h3,
+#firechat h4,
+#firechat h5,
+#firechat h6 {
+  margin: 10px 0;
+  font-family: inherit;
+  font-weight: bold;
+  line-height: 20px;
+  color: inherit;
+}
+#firechat h1,
+#firechat h2,
+#firechat h3 {
+  line-height: 40px;
+}
+#firechat h1 {
+  font-size: 38.5px;
+}
+#firechat h2 {
+  font-size: 31.5px;
+}
+#firechat h3 {
+  font-size: 24.5px;
+}
+#firechat h4 {
+  font-size: 17.5px;
+}
+#firechat h5 {
+  font-size: 14px;
+}
+#firechat h6 {
+  font-size: 11.9px;
+}
+#firechat small {
+  font-size: 90%;
+}
+/* Component: Tabs
+============================================================ */
+#firechat .nav {
+  list-style: none;
+}
+#firechat .nav > li > a {
+  display: block;
+  background-color: #eeeeee;
+  text-decoration: none;
+  overflow: hidden;
+  white-space: nowrap;
+}
+#firechat .nav > li > a:hover,
+#firechat .nav > li > a:focus {
+  background-color: #ffffff;
+}
+#firechat .nav-tabs {
+  border-bottom: 1px solid #ddd;
+  clear: both;
+}
+#firechat .nav-tabs > li {
+  float: left;
+  margin-bottom: -1px;
+  max-width: 45%;
+}
+#firechat .nav-tabs > li > a {
+  -webkit-border-top-right-radius: 4px;
+  -webkit-border-bottom-right-radius: 0;
+  -webkit-border-bottom-left-radius: 0;
+  -webkit-border-top-left-radius: 4px;
+  -moz-border-radius-topright: 4px;
+  -moz-border-radius-bottomright: 0;
+  -moz-border-radius-bottomleft: 0;
+  -moz-border-radius-topleft: 4px;
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 4px;
+  padding: 4px 8px;
+  margin-right: 2px;
+  line-height: 20px;
+  border: 1px solid transparent;
+  border-color: #cccccc;
+}
+#firechat .nav-tabs > .active > a,
+#firechat .nav-tabs > .active > a:hover,
+#firechat .nav-tabs > .active > a:focus {
+  border-bottom-color: transparent;
+  background-color: #ffffff;
+  cursor: default;
+}
+#firechat .tab-content {
+  overflow: auto;
+}
+#firechat .tab-content > .tab-pane {
+  display: none;
+}
+#firechat .tab-content > .active {
+  display: block;
+  background-color: #ffffff;
+}
+/* Component: Dropdowns
+============================================================ */
+#firechat .caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  vertical-align: top;
+  border-top: 4px solid #000000;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+  content: "";
+  margin-top: 8px;
+  margin-left: 2px;
+}
+#firechat .dropdown {
+  position: relative;
+}
+#firechat .dropdown-toggle {
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  text-decoration: none;
+}
+#firechat .dropdown-toggle:focus,
+#firechat .dropdown-toggle:active {
+  outline: none;
+  text-decoration: none;
+}
+#firechat .dropdown-toggle.btn {
+  padding: 4px 0 0;
+  height: 22px;
+}
+#firechat .dropdown-menu {
+  *zoom: 1;
+  -webkit-border-top-right-radius: 0;
+  -webkit-border-bottom-right-radius: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 0;
+  -moz-border-radius-topright: 0;
+  -moz-border-radius-bottomright: 4px;
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 0;
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+  border-top-left-radius: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  position: absolute;
+  top: 100%;
+  left: 0;
+  width: 100%;
+  background-color: #ffffff;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  -webkit-background-clip: padding-box;
+  -moz-background-clip: padding;
+  background-clip: padding-box;
+  border: 1px solid #ccc;
+  min-width: 98%;
+  padding: 0;
+  margin: -1px 0 0;
+}
+#firechat .dropdown-menu:before,
+#firechat .dropdown-menu:after {
+  display: table;
+  content: "";
+  line-height: 0;
+}
+#firechat .dropdown-menu:after {
+  clear: both;
+}
+#firechat .dropdown-menu ul {
+  background-color: #ffffff;
+  list-style: none;
+  overflow-y: scroll;
+  max-height: 300px;
+}
+#firechat .dropdown-menu ul > li > a {
+  display: block;
+  padding: 1px 1px 1px 3px;
+  clear: both;
+  font-weight: normal;
+  line-height: 20px;
+  color: #333333;
+  white-space: nowrap;
+}
+#firechat .dropdown-menu ul > li > a.highlight {
+  background-color: #d9edf7;
+}
+#firechat .dropdown-menu ul > li > a:hover,
+#firechat .dropdown-menu ul > li > a:focus,
+#firechat .dropdown-menu ul > .active > a,
+#firechat .dropdown-menu ul > .active > a:hover,
+#firechat .dropdown-menu ul > .active > a:focus {
+  text-decoration: none;
+  color: #000000;
+  background-color: #d9edf7;
+  outline: 0;
+}
+#firechat .dropdown-menu ul > .disabled > a,
+#firechat .dropdown-menu ul > .disabled > a:hover,
+#firechat .dropdown-menu ul > .disabled > a:focus {
+  color: #999999;
+  text-decoration: none;
+  background-color: transparent;
+  background-image: none;
+  cursor: default;
+}
+#firechat .dropdown-header {
+  position: relative;
+  width: 100%;
+  padding: 10px 0;
+  background-color: #eeeeee;
+  border-bottom: 1px solid #cccccc;
+}
+#firechat .dropdown-footer {
+  position: relative;
+  width: 100%;
+  padding: 10px 0px;
+  background-color: #eeeeee;
+  border-top: 1px solid #cccccc;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+#firechat .open {
+  *z-index: 1000;
+}
+#firechat .open > .dropdown-menu {
+  display: block;
+  border: 1px solid #cccccc;
+  -webkit-border-top-right-radius: 0;
+  -webkit-border-bottom-right-radius: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 0;
+  -moz-border-radius-topright: 0;
+  -moz-border-radius-bottomright: 4px;
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 0;
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+  border-top-left-radius: 0;
+}
+#firechat .open > .dropdown-toggle {
+  outline: none;
+  text-decoration: none;
+  -webkit-border-top-right-radius: 4px;
+  -webkit-border-bottom-right-radius: 0;
+  -webkit-border-bottom-left-radius: 0;
+  -webkit-border-top-left-radius: 4px;
+  -moz-border-radius-topright: 4px;
+  -moz-border-radius-bottomright: 0;
+  -moz-border-radius-bottomleft: 0;
+  -moz-border-radius-topleft: 4px;
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 4px;
+}
+/* Component: Prompts
+============================================================ */
+#firechat .prompt-wrapper {
+  position: absolute;
+  z-index: 1000;
+}
+#firechat .prompt {
+  position: absolute;
+  z-index: 1001;
+  background-color: #ffffff;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45);
+  -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45);
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45);
+}
+#firechat .prompt-header {
+  padding: 4px 8px;
+  font-weight: bold;
+  background-color: #eeeeee;
+  border: 1px solid #cccccc;
+  -webkit-border-top-right-radius: 4px;
+  -webkit-border-bottom-right-radius: 0;
+  -webkit-border-bottom-left-radius: 0;
+  -webkit-border-top-left-radius: 4px;
+  -moz-border-radius-topright: 4px;
+  -moz-border-radius-bottomright: 0;
+  -moz-border-radius-bottomleft: 0;
+  -moz-border-radius-topleft: 4px;
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 4px;
+}
+#firechat .prompt-header a.close {
+  opacity: 0.6;
+  font-size: 13px;
+  margin-top: 2px;
+}
+#firechat .prompt-header a.close:hover {
+  opacity: 0.9;
+}
+#firechat .prompt-body {
+  background-color: #ffffff;
+  padding: 4px 8px;
+  border-left: 1px solid #cccccc;
+  border-right: 1px solid #cccccc;
+}
+#firechat .prompt-footer {
+  padding: 4px 8px;
+  background-color: #eeeeee;
+  border: 1px solid #cccccc;
+  -webkit-border-top-right-radius: 0;
+  -webkit-border-bottom-right-radius: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 0;
+  -moz-border-radius-topright: 0;
+  -moz-border-radius-bottomright: 4px;
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 0;
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+  border-top-left-radius: 0;
+}
+#firechat .prompt-background {
+  background-color: #333333;
+  border: 1px solid #333333;
+  opacity: 0.8;
+  z-index: 1000;
+  height: 100%;
+  width: 100%;
+}
+/* Component: Buttons
+============================================================ */
+#firechat .btn {
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+  height: 24px;
+  display: inline-block;
+  *display: inline;
+  *zoom: 1;
+  padding: 2px 5px;
+  margin-bottom: 0;
+  text-align: center;
+  vertical-align: middle;
+  cursor: pointer;
+  color: #333333;
+  font-size: 12px;
+  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+  background-color: #f5f5f5;
+  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
+  border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  *background-color: #e6e6e6;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+  border: 1px solid #cccccc;
+  *border: 0;
+  border-bottom-color: #b3b3b3;
+  *margin-left: .3em;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+  -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+#firechat .btn:hover,
+#firechat .btn:focus,
+#firechat .btn:active,
+#firechat .btn.active,
+#firechat .btn.disabled,
+#firechat .btn[disabled] {
+  color: #333333;
+  background-color: #e6e6e6;
+  *background-color: #d9d9d9;
+  outline: 0;
+}
+#firechat .btn:active,
+#firechat .btn.active {
+  background-color: #cccccc;
+}
+#firechat .btn:first-child {
+  *margin-left: 0;
+}
+#firechat .btn:hover,
+#firechat .btn:focus {
+  color: #333333;
+  text-decoration: none;
+  background-position: 0 -15px;
+  -webkit-transition: background-position 0.1s linear;
+  -moz-transition: background-position 0.1s linear;
+  -o-transition: background-position 0.1s linear;
+  transition: background-position 0.1s linear;
+}
+#firechat .btn.active,
+#firechat .btn:active {
+  background-image: none;
+  outline: 0;
+  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+  -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+#firechat .btn.disabled,
+#firechat .btn[disabled] {
+  cursor: default;
+  background-image: none;
+  opacity: 0.65;
+  filter: alpha(opacity=65);
+}
+#firechat .btn.disabled:active,
+#firechat .btn[disabled]:active {
+  -webkit-box-shadow: inherit;
+  -moz-box-shadow: inherit;
+  box-shadow: inherit;
+  background-color: #e6e6e6;
+}
+/* Component: Context Menu
+============================================================ */
+#firechat .contextmenu {
+  position: fixed;
+  z-index: 1001;
+  min-width: 150px;
+  border: 1px solid #cccccc;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+}
+#firechat .contextmenu ul {
+  background-color: #ffffff;
+  list-style: none;
+}
+#firechat .contextmenu ul > li > a {
+  display: block;
+  padding: 3px 10px;
+  clear: both;
+  font-weight: normal;
+  line-height: 20px;
+  color: #333333;
+  white-space: nowrap;
+}
+#firechat .contextmenu ul > li > a.highlight {
+  background-color: #d9edf7;
+}
+#firechat .contextmenu ul > li > a:hover,
+#firechat .contextmenu ul > li > a:focus {
+  text-decoration: none;
+  color: #ffffff;
+  background-color: #0081c2;
+  outline: 0;
+}
+/* Custom Styles
+============================================================ */
+#firechat {
+  padding: 0;
+  font-family: sans-serif;
+  font-size: 12px;
+  line-height: 18px;
+}
+#firechat input,
+#firechat textarea {
+  width: 100%;
+  font-family: sans-serif;
+  font-size: 12px;
+  line-height: 18px;
+  padding: 2px 5px;
+  border: 1px solid #cccccc;
+  -webkit-border-radius: 1px;
+  -moz-border-radius: 1px;
+  border-radius: 1px;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+#firechat input:-moz-placeholder,
+#firechat textarea:-moz-placeholder {
+  color: #aaaaaa;
+}
+#firechat input:-ms-input-placeholder,
+#firechat textarea:-ms-input-placeholder {
+  color: #aaaaaa;
+}
+#firechat input::-webkit-input-placeholder,
+#firechat textarea::-webkit-input-placeholder {
+  color: #aaaaaa;
+}
+#firechat input[disabled],
+#firechat textarea[disabled] {
+  background-color: #eeeeee;
+}
+#firechat input {
+  height: 24px;
+}
+#firechat textarea {
+  resize: none;
+  height: 40px;
+}
+#firechat .search-wrapper {
+  -webkit-border-radius: 15px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+  border: 1px solid #cccccc;
+  margin: 0 5px;
+  padding: 2px 5px;
+  background: #ffffff;
+}
+#firechat .search-wrapper > input[type=text] {
+  padding-left: 0px;
+  border: none;
+}
+#firechat .search-wrapper > input[type=text]:focus,
+#firechat .search-wrapper > input[type=text]:active {
+  outline: 0;
+}
+#firechat .chat {
+  overflow: auto;
+  -ms-overflow-x: hidden;
+  overflow-x: hidden;
+  height: 290px;
+  position: relative;
+  margin-bottom: 5px;
+  border: 1px solid #cccccc;
+  border-top: none;
+  overflow-y: scroll;
+}
+#firechat .chat textarea {
+  overflow: auto;
+  vertical-align: top;
+}
+#firechat .message {
+  color: #333;
+  padding: 3px 5px;
+  border-bottom: 1px solid #ccc;
+}
+#firechat .message.highlighted {
+  background-color: #d9edf7;
+}
+#firechat .message .name {
+  font-weight: bold;
+  overflow-x: hidden;
+}
+#firechat .message.message-self {
+  color: #2675ab;
+}
+#firechat .message:nth-child(odd) {
+  background-color: #f9f9f9;
+}
+#firechat .message:nth-child(odd).highlighted {
+  background-color: #d9edf7;
+}
+#firechat .message:nth-child(odd).message-local {
+  background-color: #effafc;
+}
+#firechat .message-content {
+  word-wrap: break-word;
+  padding-right: 45px;
+}
+#firechat .message-content.red {
+  color: red;
+}
+#firechat .message.message-notification .message-content {
+  font-style: italic;
+}
+#firechat ul::-webkit-scrollbar {
+  -webkit-appearance: none;
+  width: 7px;
+}
+#firechat ul::-webkit-scrollbar-thumb {
+  border-radius: 4px;
+  -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, 0.5);
+}
+#firechat #firechat-header {
+  padding: 6px 0 0 0;
+  height: 40px;
+}
+#firechat #firechat-tabs {
+  height: 435px;
+}
+#firechat #firechat-tab-list {
+  background-color: #ffffff;
+}
+#firechat #firechat-tab-content {
+  width: 100%;
+  background-color: #ffffff;
+}
+#firechat .tab-pane-menu {
+  border: 1px solid #ccc;
+  border-top: none;
+  vertical-align: middle;
+  padding-bottom: 5px;
+}
+#firechat .tab-pane-menu .dropdown {
+  margin: 5px 0 0 5px;
+}
+#firechat .tab-pane-menu > .icon {
+  margin: 5px 2px 0;
+}
+#firechat .icon {
+  display: inline-block;
+  *margin-right: .3em;
+  line-height: 20px;
+  vertical-align: middle;
+  background-repeat: no-repeat;
+  padding: 0;
+  background: url(data:image/png;base64,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) no-repeat top left;
+  opacity: 0.3;
+  font-size: 22px;
+  font-family: Arial;
+  font-weight: bold;
+  overflow: hidden;
+}
+#firechat .icon.plus {
+  margin-top: 0;
+  vertical-align: top;
+  background: transparent;
+}
+#firechat .icon.search {
+  background-position: 0 0;
+  width: 13px;
+  height: 13px;
+}
+#firechat .icon.close {
+  background-position: -120px 0;
+  width: 13px;
+  height: 13px;
+}
+#firechat .icon.user-chat {
+  background-position: -138px 0;
+  width: 17px;
+  height: 13px;
+}
+#firechat .icon.user-group {
+  background-position: -18px 0;
+  width: 17px;
+  height: 13px;
+}
+#firechat .icon.user-mute {
+  background-position: -84px 0;
+  width: 13px;
+  height: 13px;
+}
+#firechat .icon.user-mute.red {
+  background-position: -102px 0;
+  width: 13px;
+  height: 13px;
+}
+#firechat .icon:hover,
+#firechat .btn:hover > .icon {
+  opacity: 0.6;
+}
+#firechat a > .icon {
+  margin: 3px 1px;
+}
diff --git a/dist/0.1.5/firechat-default.js b/dist/0.1.5/firechat-default.js
new file mode 100644
index 0000000..f1c2824
--- /dev/null
+++ b/dist/0.1.5/firechat-default.js
@@ -0,0 +1,1831 @@
+(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index<t.index?-1:1}),"value")};var F=function(n,t,r,e){var u={},i=k(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return F(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return F(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n","	":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
+this["FirechatDefaultTemplates"] = this["FirechatDefaultTemplates"] || {};
+
+this["FirechatDefaultTemplates"]["templates/layout-full.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div id=\'firechat\' class=\'full\'>\n<div id=\'firechat-header\' class=\'clearfix\'>\n<div class=\'clearfix\'><div class=\'half dropdown\' style=\'\'>\n<a id=\'firechat-btn-rooms\' class=\'dropdown-toggle btn full\' data-toggle="dropdown" href=\'#\'>\n<span class=\'icon user-chat\'></span>\nChat Rooms\n<span class=\'caret\'></span>\n</a>\n<div class=\'dropdown-menu full\' role=\'menu\'><ul id=\'firechat-room-list\'></ul><div class=\'dropdown-footer aligncenter\'>\n<button type=\'button\' class=\'btn twothird center\' id=\'firechat-btn-create-room-prompt\'>Create Room</button>\n</div></div></div>\n<div class=\'half dropdown\' style=\'\'>\n<a data-event=\'firechat-user-search-btn\' class=\'btn full dropdown-toggle\' data-toggle="dropdown" href=\'#\'>\n<span class=\'icon user-group\'></span>\nVisitors\n<span class=\'caret\'></span>\n</a>\n<div class=\'dropdown-menu\' role=\'menu\'>\n<div class=\'dropdown-header aligncenter clearfix\'>\n<div class=\'search-wrapper\'>\n<span class=\'icon search\'></span>\n<input type=\'text\' data-event=\'firechat-user-search\' data-template=\'templates/user-search-list-item.html\' data-target=\'firechat-user-search\' data-controls=\'firechat-user-search-controls\' class=\'center fivesixth\'>\n</div>\n</div>\n<ul id=\'firechat-user-search\'></ul><div class=\'dropdown-footer aligncenter clearfix\'>\n<div id=\'firechat-user-search-controls\' class=\'clearfix\'>\n<span class="quarter"></span>\n<button type=\'button\' class=\'btn half\' data-event=\'firechat-user-search\' data-toggle=\'firechat-pagination-next\' data-template=\'templates/user-search-list-item.html\' data-target=\'firechat-user-search\' data-controls=\'firechat-user-search-controls\' disabled=disabled>Next</button>\n</div><label class=\'center full\'>\n<small>Use "+ Invite" button within chat rooms for regular invites.</small>\n</label>\n</div>\n</div>\n</div>\n</div>\n</div>\n<div id=\'firechat-tabs\' class=\'clearfix\'>\n<ul id=\'firechat-tab-list\' class=\'nav nav-tabs clearfix\'></ul>\n<div id=\'firechat-tab-content\' class=\'tab-content\'></div>\n</div><div id=\'firechat-footer\' class=\'clearfix\'></div>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/layout-popout.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div id=\'firechat\' class=\'full\'>\n<div id=\'firechat-tabs\' class=\'clearfix\'>\n<ul id=\'firechat-tab-list\' class=\'nav nav-tabs clearfix\'></ul>\n<div id=\'firechat-tab-content\' class=\'tab-content\'></div>\n</div>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/message-context-menu.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '<div data-toggle=\'firechat-contextmenu\' class=\'contextmenu\' data-message-id=\'' +__e( id ) +'\'>\n<ul>\n<li><a href=\'#!\' data-event=\'firechat-user-warn\'>Warn User</a></li>\n'; if (allowKick) { ;__p += '\n<li><a href=\'#!\' data-event=\'firechat-user-kick\'>Kick User</a></li>\n'; } ;__p += '\n<li><a href=\'#!\' data-event=\'firechat-user-suspend-hour\'>Suspend User (1 Hour)</a></li>\n<li><a href=\'#!\' data-event=\'firechat-user-suspend-day\'>Suspend User (1 Day)</a></li>\n<li><a href=\'#!\' data-event=\'firechat-message-delete\'>Delete Message</a></li>\n</ul>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/message.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '<div class=\'message message-' +__e( type ) +' '; if (isSelfMessage) { ;__p += ' message-self '; } ;__p += '\' data-message-id=\'' +__e( id ) +'\' data-user-id=\'' +__e( userId ) +'\' data-user-name=\'' +__e( name ) +'\' data-class="firechat-message">\n<div class=\'clearfix\'>\n<label class=\'fourfifth\'>\n<strong class=\'name\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</strong>\n<em>(' +__e( localtime ) +')</em>:\n</label>'; if (!disableActions) { ;__p += '\n<label class=\'fifth alignright\'>\n<a href=\'#!\' data-event=\'firechat-user-chat\' class=\'icon user-chat\' title=\'Invite to Private Chat\'>&nbsp;</a>\n<a href=\'#!\' data-event=\'firechat-user-mute-toggle\' class=\'icon user-mute\' title=\'Mute User\'>&nbsp;</a>\n</label>\n'; } ;__p += '</div>\n<div class=\'clearfix message-content\'>\n' +((__t = ( message )) == null ? '' : __t) +'\n</div>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/prompt-alert.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div class=\'aligncenter clearfix\'>\n<h6>' +__e( message ) +'</h6>\n<p class=\'clearfix\'>\n<button type=\'button\' class=\'btn quarter right close\'>Close</button>\n</p>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/prompt-create-room.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div class=\'clearfix\'>\n<h6>Give your chat room a name:</h6>\n<input data-input=\'firechat-room-name\' type=\'text\' placeholder=\'Room name...\' style=\'margin-bottom: 5px;\' maxlength=\'' +__e( maxLengthRoomName ) +'\'>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/prompt-invitation.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div class=\'aligncenter clearfix\'>\n<h5>' +__e( fromUserName ) +'</h5>\n<p>invited you to join</p>\n<h5>' +__e( toRoomName ) +'</h5>\n<p class=\'clearfix\'>\n<button data-toggle=\'accept\' type=\'button\' class=\'btn\'>Accept</button>\n<button data-toggle=\'decline\' type=\'button\' class=\'btn\'>Decline</button>\n</p>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/prompt-invite-private.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div class=\'aligncenter clearfix\'>\n<h6>Invite <strong>' +__e( userName ) +'</strong> to ' +__e( roomName ) +'?</h6>\n<p class=\'clearfix\'>\n<button data-toggle=\'accept\' type=\'button\' class=\'btn\'>Invite</button>\n<button data-toggle=\'decline\' type=\'button\' class=\'close btn\'>Cancel</button>\n</p>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/prompt-invite-reply.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '<div class=\'aligncenter clearfix\'>\n<h5>' +__e( toUserName ) +'</h5>\n<p>\n'; if (status === 'accepted') { ;__p += ' accepted your invite. '; } else { ;__p += ' declined your invite. '; } ;__p += '\n</p>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/prompt-user-mute.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div class=\'aligncenter clearfix\'>\n<h5>' +__e( userName ) +'</h5>\n<p class=\'clearfix\'>\n<button data-toggle=\'accept\' type=\'button\' class=\'btn\'>Mute</button>\n<button data-toggle=\'decline\' type=\'button\' class=\'btn\'>Cancel</button>\n</p>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/prompt.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div class=\'prompt hidden\'>\n<div class=\'prompt-header\'>\n' +__e( title ) +'\n<a href=\'#!\' class=\'close right\'>X</a>\n</div>\n<div class=\'prompt-body clearfix\'>\n' +((__t = ( content )) == null ? '' : __t) +'\n</div>\n<div class=\'prompt-footer\'></div>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/room-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '<li data-room-type=\'' +__e( type ) +'\' data-room-id=\'' +__e( id ) +'\' data-room-name=\'' +__e( name ) +'\'>\n<a href=\'#!\' class=\'clearfix '; if (isRoomOpen) { ;__p += ' highlight '; } ;__p += '\'>\n<span class=\'left\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</span>\n</a>\n</li>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '<li data-user-id=\'' +__e( id ) +'\' data-user-name=\'' +__e( name ) +'\'>\n<a href=\'#!\' class=\'clearfix\'>\n<span class=\'left twothird clipped\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</span>'; if (!disableActions) { ;__p += '\n<span data-event=\'firechat-user-mute-toggle\' class=\'icon user-mute right '; if (isMuted) { ;__p += ' red '; } ;__p += '\' title=\'Toggle User Mute\'>&nbsp;</span>\n<span data-event=\'firechat-user-chat\' class=\'icon user-chat right\' title=\'Invite to Private Chat\'>&nbsp;</span>\n'; } ;__p += '\n</a>\n</li>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '<li data-user-id=\'' +__e( id ) +'\' data-user-name=\'' +__e( name ) +'\'>\n<a href=\'#!\' class=\'clearfix\'>\n'; if (disableActions) { ;__p += '\n<span class=\'left fourfifth clipped\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</span>\n'; } else { ;__p += '\n<span data-event=\'firechat-user-invite\' class=\'left fourfifth clipped\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</span>\n<span data-event=\'firechat-user-invite\' class=\'icon plus right\' title=\'Invite to Room\'>+</span>\n'; } ;__p += '\n</a>\n</li>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<div id=\'' +__e( id ) +'\' data-room-id=\'' +__e( id ) +'\' class=\'tab-pane\'>\n<div class=\'tab-pane-menu clearfix\'><div class=\'dropdown twofifth\'>\n<a data-event=\'firechat-user-room-list-btn\' class=\'full btn dropdown-toggle\' data-toggle="dropdown" href=\'#\' data-target=\'firechat-room-user-list-' +__e( id ) +'\'>\n<span class=\'icon user-group\'></span>\nIn Room\n<span class=\'caret\'></span>\n</a>\n<div class=\'dropdown-menu\' role=\'menu\'>\n<ul id=\'firechat-room-user-list-' +__e( id ) +'\' class=\'full\'></ul>\n</div>\n</div><div class=\'dropdown twofifth\'>\n<a data-event=\'firechat-user-search-btn\' class=\'full btn dropdown-toggle\' data-toggle="dropdown" href=\'#\'>\n<span class=\'icon plus\'>+</span>\nInvite\n<span class=\'caret\'></span>\n</a><div class=\'dropdown-menu\' role=\'menu\'>\n<div class=\'dropdown-header aligncenter clearfix\'>\n<div class=\'search-wrapper\'>\n<span class=\'icon search\'></span>\n<input type=\'text\' data-event=\'firechat-user-search\' data-template=\'templates/room-user-search-list-item.html\' data-target=\'firechat-room-user-search-' +__e( id ) +'\' data-controls=\'firechat-room-user-search-controls-' +__e( id ) +'\' class=\'center fivesixth\'>\n</div>\n</div>\n<ul id=\'firechat-room-user-search-' +__e( id ) +'\'></ul><div class=\'dropdown-footer aligncenter clearfix\'>\n<div id=\'firechat-room-user-search-controls-' +__e( id ) +'\' class=\'clearfix\'><span class="quarter"></span>\n<!--\n<button type=\'button\' class=\'btn third disabled\' data-event=\'firechat-user-search\' data-template=\'templates/room-user-search-list-item.html\' data-target=\'firechat-room-user-search-' +__e( id ) +'\' data-controls=\'firechat-room-user-search-controls-' +__e( id ) +'\' data-toggle=\'firechat-pagination-prev\' disabled=disabled>Prev</button>\n-->\n<button type=\'button\' class=\'btn half disabled\' data-event=\'firechat-user-search\' data-template=\'templates/room-user-search-list-item.html\' data-target=\'firechat-room-user-search-' +__e( id ) +'\' data-controls=\'firechat-room-user-search-controls-' +__e( id ) +'\' data-toggle=\'firechat-pagination-next\'  disabled=disabled>Next</button>\n</div>\n</div>\n</div>\n</div><a href=\'#!\' data-event=\'firechat-close-tab\' class=\'icon close right\' style=\'15px 5px\' title=\'Leave Room\'></a></div><div class=\'clearfix\'>\n<div id=\'firechat-messages' +__e( id ) +'\' class=\'chat\'></div>\n</div><div class=\'clearfix\'>\n<label>Your message:</label>\n<textarea id=\'textarea' +__e( id ) +'\' placeholder=\'Type your message here...\'></textarea>\n</div>\n</div>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '<li data-room-id=\'' +__e( id ) +'\'>\n<a href=\'#' +__e( id ) +'\' data-toggle=\'tab\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</a>\n</li>';}return __p};
+
+this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '<li data-user-id=\'' +__e( id ) +'\' data-user-name=\'' +__e( name ) +'\'>\n<a href=\'#!\' class=\'clearfix\'>\n'; if (disableActions) { ;__p += '\n<span class=\'left fivesixth clipped\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</span>\n'; } else { ;__p += '\n<span data-event=\'firechat-user-chat\' class=\'left fivesixth clipped\' title=\'' +__e( name ) +'\'>' +__e( name ) +'</span>\n<span data-event=\'firechat-user-chat\' class=\'icon user-chat right\' title=\'Invite to Private Chat\'>&nbsp;</span>\n'; } ;__p += '\n</a>\n</li>';}return __p};
+(function($) {
+
+  // Shim for Function.bind(...) - (Required by IE < 9, FF < 4, SF < 6)
+  if (!Function.prototype.bind) {
+    Function.prototype.bind = function(oThis) {
+      if (typeof this !== "function") {
+        throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
+      }
+  
+      var aArgs = Array.prototype.slice.call(arguments, 1), 
+          fToBind = this, 
+          fNOP = function() {},
+          fBound = function() {
+            return fToBind.apply(this instanceof fNOP && oThis ? this : oThis,
+                                 aArgs.concat(Array.prototype.slice.call(arguments)));
+          };
+   
+      fNOP.prototype = this.prototype;
+      fBound.prototype = new fNOP();
+      return fBound;
+    };
+  }
+
+  // Shim for Object.keys(...) - (Required by IE < 9, FF < 4)
+  Object.keys = Object.keys || function(oObj) {  
+    var result = [];  
+    for (var name in oObj) {  
+      if (oObj.hasOwnProperty(name)) {
+        result.push(name);  
+      }
+    }  
+    return result;  
+  };
+
+})();
+
+// Firechat is a simple, easily-extensible data layer for multi-user,
+// multi-room chat, built entirely on [Firebase](https://firebase.com).
+//
+// The Firechat object is the primary conduit for all underlying data events.
+// It exposes a number of methods for binding event listeners, creating,
+// entering, or leaving chat rooms, initiating chats, sending messages,
+// and moderator actions such as warning, kicking, or suspending users.
+//
+//     Firechat.js 0.1.0
+//     https://firebase.com
+//     (c) 2013 Firebase
+//     License: MIT
+
+// Setup
+// --------------
+(function(Firebase) {
+
+  // Establish a reference to the `window` object, and save the previous value
+  // of the `Firechat` variable.
+  var root = this,
+      previousFirechat = root.Firechat;
+
+  function Firechat(firebaseRef, options) {
+
+    // Instantiate a new connection to Firebase.
+    this._firebase = firebaseRef;
+
+    // User-specific instance variables.
+    this._user = null;
+    this._userId = null;
+    this._userName = null;
+    this._isModerator = false;
+
+    // A unique id generated for each session.
+    this._sessionId = null;
+
+    // A mapping of event IDs to an array of callbacks.
+    this._events = {};
+
+    // A mapping of room IDs to a boolean indicating presence.
+    this._rooms = {};
+
+    // A mapping of operations to re-queue on disconnect.
+    this._presenceBits = {};
+
+    // Commonly-used Firebase references.
+    this._userRef        = null;
+    this._messageRef     = this._firebase.child('room-messages');
+    this._roomRef        = this._firebase.child('room-metadata');
+    this._privateRoomRef = this._firebase.child('room-private-metadata');
+    this._moderatorsRef  = this._firebase.child('moderators');
+    this._suspensionsRef = this._firebase.child('suspensions');
+    this._usersOnlineRef = this._firebase.child('user-names-online');
+
+    // Setup and establish default options.
+    this._options = options || {};
+
+    // The number of historical messages to load per room.
+    this._options.numMaxMessages = this._options.numMaxMessages || 50;
+  }
+
+  // Run Firechat in *noConflict* mode, returning the `Firechat` variable to
+  // its previous owner, and returning a reference to the Firechat object.
+  Firechat.noConflict = function noConflict() {
+    root.Firechat = previousFirechat;
+    return Firechat;
+  };
+
+  // Export the Firechat object as a global.
+  root.Firechat = Firechat;
+
+  // Firechat Internal Methods
+  // --------------
+  Firechat.prototype = {
+
+    // Load the initial metadata for the user's account and set initial state.
+    _loadUserMetadata: function(onComplete) {
+      var self = this;
+
+      // Update the user record with a default name on user's first visit.
+      this._userRef.transaction(function(current) {
+        if (!current || !current.id || !current.name) {
+          return {
+            id: self._userId,
+            name: self._userName
+          };
+        }
+      }, function(error, committed, snapshot) {
+        self._user = snapshot.val();
+        self._moderatorsRef.child(self._userId).once('value', function(snapshot) {
+          self._isModerator = !!snapshot.val();
+          root.setTimeout(onComplete, 0);
+        });
+      });
+    },
+
+    // Initialize Firebase listeners and callbacks for the supported bindings.
+    _setupDataEvents: function() {
+      // Monitor connection state so we can requeue disconnect operations if need be.
+      this._firebase.root().child('.info/connected').on('value', function(snapshot) {
+        if (snapshot.val() === true) {
+          // We're connected (or reconnected)! Set up our presence state.
+          for (var i = 0; i < this._presenceBits; i++) {
+            var op = this._presenceBits[i],
+                ref = this._firebase.root().child(op.ref);
+
+            ref.onDisconnect().set(op.offlineValue);
+            ref.set(op.onlineValue);
+          }
+        }
+      }, this);
+
+      // Generate a unique session id for the visit.
+      var sessionRef = this._userRef.child('sessions').push();
+      this._sessionId = sessionRef.name();
+      this._queuePresenceOperation(sessionRef, true, null);
+
+      // Register our username in the public user listing.
+      var usernameRef = this._usersOnlineRef.child(this._userName.toLowerCase());
+      var usernameSessionRef = usernameRef.child(this._sessionId);
+      this._queuePresenceOperation(usernameSessionRef, {
+        id: this._userId,
+        name: this._userName
+      }, null);
+
+      // Listen for state changes for the given user.
+      this._userRef.on('value', this._onUpdateUser, this);
+
+      // Listen for chat invitations from other users.
+      this._userRef.child('invites').on('child_added', this._onFirechatInvite, this);
+
+      // Listen for messages from moderators and adminstrators.
+      this._userRef.child('notifications').on('child_added', this._onNotification, this);
+    },
+
+    // Append the new callback to our list of event handlers.
+    _addEventCallback: function(eventId, callback) {
+      this._events[eventId] = this._events[eventId] || [];
+      this._events[eventId].push(callback);
+    },
+
+    // Retrieve the list of event handlers for a given event id.
+    _getEventCallbacks: function(eventId) {
+      if (this._events.hasOwnProperty(eventId)) {
+        return this._events[eventId];
+      }
+      return [];
+    },
+
+    // Invoke each of the event handlers for a given event id with specified data.
+    _invokeEventCallbacks: function(eventId) {
+      var args = [],
+          callbacks = this._getEventCallbacks(eventId);
+
+      Array.prototype.push.apply(args, arguments);
+      args = args.slice(1);
+
+      for (var i = 0; i < callbacks.length; i += 1) {
+        callbacks[i].apply(null, args);
+      }
+    },
+
+    // Keep track of on-disconnect events so they can be requeued if we disconnect the reconnect.
+    _queuePresenceOperation: function(ref, onlineValue, offlineValue) {
+      ref.onDisconnect().set(offlineValue);
+      ref.set(onlineValue);
+      this._presenceBits[ref.toString()] = {
+        ref: ref,
+        onlineValue: onlineValue,
+        offlineValue: offlineValue
+      };
+    },
+
+    // Remove an on-disconnect event from firing upon future disconnect and reconnect.
+    _removePresenceOperation: function(path, value) {
+      var ref = new Firebase(path);
+      ref.onDisconnect().cancel();
+      ref.set(value);
+      delete this._presenceBits[path];
+    },
+
+    // Event to monitor current user state.
+    _onUpdateUser: function(snapshot) {
+      this._user = snapshot.val();
+      this._invokeEventCallbacks('user-update', this._user);
+    },
+
+    // Event to monitor current auth + user state.
+    _onAuthRequired: function() {
+      this._invokeEventCallbacks('auth-required');
+    },
+
+    // Events to monitor room entry / exit and messages additional / removal.
+    _onEnterRoom: function(room) {
+      this._invokeEventCallbacks('room-enter', room);
+    },
+    _onNewMessage: function(roomId, snapshot) {
+      var message = snapshot.val();
+      message.id = snapshot.name();
+      this._invokeEventCallbacks('message-add', roomId, message);
+    },
+    _onRemoveMessage: function(roomId, snapshot) {
+      var messageId = snapshot.name();
+      this._invokeEventCallbacks('message-remove', roomId, messageId);
+    },
+    _onLeaveRoom: function(roomId) {
+      this._invokeEventCallbacks('room-exit', roomId);
+    },
+
+    // Event to listen for notifications from administrators and moderators.
+    _onNotification: function(snapshot) {
+      var notification = snapshot.val();
+      if (!notification.read) {
+        if (notification.notificationType !== 'suspension' || notification.data.suspendedUntil < new Date().getTime()) {
+          snapshot.ref().child('read').set(true);
+        }
+        this._invokeEventCallbacks('notification', notification);
+      }
+    },
+
+    // Events to monitor chat invitations and invitation replies.
+    _onFirechatInvite: function(snapshot) {
+      var self = this,
+          invite = snapshot.val();
+
+      // Skip invites we've already responded to.
+      if (invite.status) {
+        return;
+      }
+
+      invite.id = invite.id || snapshot.name();
+      self.getRoom(invite.roomId, function(room) {
+        invite.toRoomName = room.name;
+        self._invokeEventCallbacks('room-invite', invite);
+      });
+    },
+    _onFirechatInviteResponse: function(snapshot) {
+      var self = this,
+          invite = snapshot.val();
+
+      invite.id = invite.id || snapshot.name();
+      this._invokeEventCallbacks('room-invite-response', invite);
+    }
+  };
+
+  // Firechat External Methods
+  // --------------
+
+  // Initialize the library and setup data listeners.
+  Firechat.prototype.setUser = function(userId, userName, callback) {
+    var self = this;
+
+    self._firebase.root().child('.info/authenticated').on('value', function(snapshot) {
+      if (snapshot.val() === true) {
+        self._firebase.root().child('.info/authenticated').off();
+
+        self._userId = userId.toString();
+        self._userName = userName.toString();
+        self._userRef = self._firebase.child('users').child(self._userId);
+        self._loadUserMetadata(function() {
+          root.setTimeout(function() {
+            callback(self._user);
+            self._setupDataEvents();
+          }, 0);
+        });
+      }
+    });
+  };
+
+  // Resumes the previous session by automatically entering rooms.
+  Firechat.prototype.resumeSession = function() {
+    this._userRef.child('rooms').once('value', function(snapshot) {
+      var rooms = snapshot.val();
+      for (var roomId in rooms) {
+        this.enterRoom(rooms[roomId].id);
+      }
+    }, /* onError */ function(){}, /* context */ this);
+  };
+
+  // Callback registration. Supports each of the following events:
+  Firechat.prototype.on = function(eventType, cb) {
+    this._addEventCallback(eventType, cb);
+  };
+
+  // Create and automatically enter a new chat room.
+  Firechat.prototype.createRoom = function(roomName, roomType, callback) {
+    var self = this,
+        newRoomRef = this._roomRef.push();
+
+    var newRoom = {
+      id: newRoomRef.name(),
+      name: roomName,
+      type: roomType || 'public',
+      createdByUserId: this._userId,
+      createdAt: Firebase.ServerValue.TIMESTAMP
+    };
+
+    if (roomType === 'private') {
+      newRoom.authorizedUsers = {};
+      newRoom.authorizedUsers[this._userId] = true;
+    }
+
+    newRoomRef.set(newRoom, function(error) {
+      if (!error) {
+        self.enterRoom(newRoomRef.name());
+      }
+      if (callback) {
+        callback(newRoomRef.name());
+      }
+    });
+  };
+
+  // Enter a chat room.
+  Firechat.prototype.enterRoom = function(roomId) {
+    var self = this;
+    self.getRoom(roomId, function(room) {
+      var roomName = room.name;
+
+      if (!roomId || !roomName) return;
+
+      // Skip if we're already in this room.
+      if (self._rooms[roomId]) {
+        return;
+      }
+
+      self._rooms[roomId] = true;
+
+      if (self._user) {
+        // Save entering this room to resume the session again later.
+        self._userRef.child('rooms').child(roomId).set({
+          id: roomId,
+          name: roomName,
+          active: true
+        });
+
+        // Set presence bit for the room and queue it for removal on disconnect.
+        var presenceRef = self._firebase.child('room-users').child(roomId).child(self._userId).child(self._sessionId);
+        self._queuePresenceOperation(presenceRef, {
+          id: self._userId,
+          name: self._userName
+        }, null);
+      }
+
+      // Invoke our callbacks before we start listening for new messages.
+      self._onEnterRoom({ id: roomId, name: roomName });
+
+      // Setup message listeners
+      self._roomRef.child(roomId).once('value', function(snapshot) {
+        self._messageRef.child(roomId).limit(self._options.numMaxMessages).on('child_added', function(snapshot) {
+          self._onNewMessage(roomId, snapshot);
+        }, /* onCancel */ function() {
+          // Turns out we don't have permission to access these messages.
+          self.leaveRoom(roomId);
+        }, /* context */ self);
+
+        self._messageRef.child(roomId).limit(self._options.numMaxMessages).on('child_removed', function(snapshot) {
+          self._onRemoveMessage(roomId, snapshot);
+        }, /* onCancel */ function(){}, /* context */ self);
+      }, /* onFailure */ function(){}, self);
+    });
+  };
+
+  // Leave a chat room.
+  Firechat.prototype.leaveRoom = function(roomId) {
+    var self = this,
+        userRoomRef = self._firebase.child('room-users').child(roomId);
+
+    // Remove listener for new messages to this room.
+    self._messageRef.child(roomId).off();
+
+    if (self._user) {
+      var presenceRef = userRoomRef.child(self._userId).child(self._sessionId);
+
+      // Remove presence bit for the room and cancel on-disconnect removal.
+      self._removePresenceOperation(presenceRef.toString(), null);
+
+      // Remove session bit for the room.
+      self._userRef.child('rooms').child(roomId).remove();
+    }
+
+    delete self._rooms[roomId];
+
+    // Invoke event callbacks for the room-exit event.
+    self._onLeaveRoom(roomId);
+  };
+
+  Firechat.prototype.sendMessage = function(roomId, messageContent, messageType, cb) {
+    var self = this,
+        message = {
+          userId: self._userId,
+          name: self._userName,
+          timestamp: Firebase.ServerValue.TIMESTAMP,
+          message: messageContent,
+          type: messageType || 'default'
+        },
+        newMessageRef;
+
+    if (!self._user) {
+      self._onAuthRequired();
+      if (cb) {
+        cb(new Error('Not authenticated or user not set!'));
+      }
+      return;
+    }
+
+    newMessageRef = self._messageRef.child(roomId).push();
+    newMessageRef.setWithPriority(message, Firebase.ServerValue.TIMESTAMP, cb);
+  };
+
+  Firechat.prototype.deleteMessage = function(roomId, messageId, cb) {
+    var self = this;
+
+    self._messageRef.child(roomId).child(messageId).remove(cb);
+  };
+
+  // Mute or unmute a given user by id. This list will be stored internally and
+  // all messages from the muted clients will be filtered client-side after
+  // receipt of each new message.
+  Firechat.prototype.toggleUserMute = function(userId, cb) {
+    var self = this;
+
+    if (!self._user) {
+      self._onAuthRequired();
+      if (cb) {
+        cb(new Error('Not authenticated or user not set!'));
+      }
+      return;
+    }
+
+    self._userRef.child('muted').child(userId).transaction(function(isMuted) {
+      return (isMuted) ? null : true;
+    }, cb);
+  };
+
+  // Send a moderator notification to a specific user.
+  Firechat.prototype.sendSuperuserNotification = function(userId, notificationType, data, cb) {
+    var self = this,
+        userNotificationsRef = self._firebase.child('users').child(userId).child('notifications');
+
+    userNotificationsRef.push({
+      fromUserId: self._userId,
+      timestamp: Firebase.ServerValue.TIMESTAMP,
+      notificationType: notificationType,
+      data: data || {}
+    }, cb);
+  };
+
+  // Warn a user for violating the terms of service or being abusive.
+  Firechat.prototype.warnUser = function(userId) {
+    var self = this;
+
+    self.sendSuperuserNotification(userId, 'warning');
+  };
+
+  // Suspend a user by putting the user into read-only mode for a period.
+  Firechat.prototype.suspendUser = function(userId, timeLengthSeconds, cb) {
+    var self = this,
+        suspendedUntil = new Date().getTime() + 1000*timeLengthSeconds;
+
+    self._suspensionsRef.child(userId).set(suspendedUntil, function(error) {
+      if (error && cb) {
+        return cb(error);
+      } else {
+        self.sendSuperuserNotification(userId, 'suspension', {
+          suspendedUntil: suspendedUntil
+        });
+        return cb(null);
+      }
+    });
+  };
+
+  // Invite a user to a specific chat room.
+  Firechat.prototype.inviteUser = function(userId, roomId) {
+    var self = this,
+        sendInvite = function() {
+          var inviteRef = self._firebase.child('users').child(userId).child('invites').push();
+          inviteRef.set({
+            id: inviteRef.name(),
+            fromUserId: self._userId,
+            fromUserName: self._userName,
+            roomId: roomId
+          });
+
+          // Handle listen unauth / failure in case we're kicked.
+          inviteRef.on('value', self._onFirechatInviteResponse, function(){}, self);
+        };
+
+    if (!self._user) {
+      self._onAuthRequired();
+      return;
+    }
+
+    self.getRoom(roomId, function(room) {
+      if (room.type === 'private') {
+        var authorizedUserRef = self._roomRef.child(roomId).child('authorizedUsers');
+        authorizedUserRef.child(userId).set(true, function(error) {
+          if (!error) {
+            sendInvite();
+          }
+        });
+      } else {
+        sendInvite();
+      }
+    });
+  };
+
+  Firechat.prototype.acceptInvite = function(inviteId, cb) {
+    var self = this;
+
+    self._userRef.child('invites').child(inviteId).once('value', function(snapshot) {
+      var invite = snapshot.val();
+      if (invite === null && cb) {
+        return cb(new Error('acceptInvite(' + inviteId + '): invalid invite id'));
+      } else {
+        self.enterRoom(invite.roomId);
+        self._userRef.child('invites').child(inviteId).update({
+          'status': 'accepted',
+          'toUserName': self._userName
+        }, cb);
+      }
+    }, self);
+  };
+
+  Firechat.prototype.declineInvite = function(inviteId, cb) {
+    var self = this,
+        updates = {
+          'status': 'declined',
+          'toUserName': self._userName
+        };
+
+    self._userRef.child('invites').child(inviteId).update(updates, cb);
+  };
+
+  Firechat.prototype.getRoomList = function(cb) {
+    var self = this;
+
+    self._roomRef.once('value', function(snapshot) {
+      cb(snapshot.val());
+    });
+  };
+
+  Firechat.prototype.getUsersByRoom = function() {
+    var self = this,
+        roomId = arguments[0],
+        query = self._firebase.child('room-users').child(roomId),
+        cb = arguments[arguments.length - 1],
+        limit = null;
+
+    if (arguments.length > 2) {
+      limit = arguments[1];
+    }
+
+    query = (limit) ? query.limit(limit) : query;
+
+    query.once('value', function(snapshot) {
+      var usernames = snapshot.val() || {},
+          usernamesUnique = {};
+
+      for (var username in usernames) {
+        for (var session in usernames[username]) {
+          // Skip all other sessions for this user as we only need one.
+          usernamesUnique[username] = usernames[username][session];
+          break;
+        }
+      }
+
+      root.setTimeout(function() {
+        cb(usernamesUnique);
+      }, 0);
+    });
+  };
+
+  Firechat.prototype.getUsersByPrefix = function(prefix, startAt, endAt, limit, cb) {
+    var self = this,
+        query = this._usersOnlineRef,
+        prefixLower = prefix.toLowerCase();
+
+    if (startAt) {
+      query = query.startAt(null, startAt);
+    } else if (endAt) {
+      query = query.endAt(null, endAt);
+    } else {
+      query = (prefixLower) ? query.startAt(null, prefixLower) : query.startAt();
+    }
+
+    query = (limit) ? query.limit(limit) : query;
+
+    query.once('value', function(snapshot) {
+      var usernames = snapshot.val() || {},
+          usernamesFiltered = {};
+
+      for (var userNameKey in usernames) {
+        var sessions = usernames[userNameKey],
+            userName, userId, usernameClean;
+
+        // Grab the user data from the first registered active session.
+        for (var sessionId in sessions) {
+          userName = sessions[sessionId].name;
+          userId = sessions[sessionId].id;
+
+          // Skip all other sessions for this user as we only need one.
+          break;
+        }
+
+        // Filter out any usernames that don't match our prefix and break.
+        if ((prefix.length > 0) && (userName.toLowerCase().indexOf(prefixLower) !== 0))
+          continue;
+
+        usernamesFiltered[userName] = {
+          name: userName,
+          id: userId
+        };
+      }
+
+      root.setTimeout(function() {
+        cb(usernamesFiltered);
+      }, 0);
+    });
+  };
+
+  // Miscellaneous helper methods.
+  Firechat.prototype.getRoom = function(roomId, callback) {
+    this._roomRef.child(roomId).once('value', function(snapshot) {
+      callback(snapshot.val());
+    });
+  };
+
+  Firechat.prototype.userIsModerator = function() {
+    return this._isModerator;
+  };
+})(Firebase);
+(function($) {
+
+
+  if (!$ || (parseInt($().jquery.replace(/\./g, ""), 10) < 170)) {
+    throw new Error("jQuery 1.7 or later required!");
+  }
+
+  var root = this,
+      previousFirechatUI = root.FirechatUI;
+
+  root.FirechatUI = FirechatUI;
+
+  if (!self.FirechatDefaultTemplates) {
+    throw new Error("Unable to find chat templates!");
+  }
+
+  function FirechatUI(firebaseRef, el, options) {
+    var self = this;
+
+    if (!firebaseRef) {
+      throw new Error('FirechatUI: Missing required argument `firebaseRef`');
+    }
+
+    if (!el) {
+      throw new Error('FirechatUI: Missing required argument `el`');
+    }
+
+    options = options || {};
+    this._options = options;
+
+    this._el = el;
+    this._user = null;
+    this._chat = new Firechat(firebaseRef, options);
+
+    // A list of rooms to enter once we've made room for them (once we've hit the max room limit).
+    this._roomQueue = [];
+
+    // Define some constants regarding maximum lengths, client-enforced.
+    this.maxLengthUsername = 15;
+    this.maxLengthUsernameDisplay = 15;
+    this.maxLengthRoomName = 24;
+    this.maxLengthMessage = 120;
+    this.maxUserSearchResults = 100;
+
+    // Define some useful regexes.
+    this.urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;
+    this.pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
+
+    this._renderLayout();
+
+    // Grab shortcuts to commonly used jQuery elements.
+    this.$wrapper = $('#firechat');
+    this.$roomList = $('#firechat-room-list');
+    this.$tabList = $('#firechat-tab-list');
+    this.$tabContent = $('#firechat-tab-content');
+    this.$messages = {};
+
+    // Rate limit messages from a given user with some defaults.
+    this.$rateLimit = {
+      limitCount: 10,         // max number of events
+      limitInterval: 10000,   // max interval for above count in milliseconds
+      limitWaitTime: 30000,   // wait time if a user hits the wait limit
+      history: {}
+    };
+
+    // Setup UI bindings for chat controls.
+    this._bindUIEvents();
+
+    // Setup bindings to internal methods
+    this._bindDataEvents();
+  }
+
+  // Run FirechatUI in *noConflict* mode, returning the `FirechatUI` variable to
+  // its previous owner, and returning a reference to the FirechatUI object.
+  FirechatUI.noConflict = function noConflict() {
+    root.FirechatUI = previousFirechatUI;
+    return FirechatUI;
+  };
+
+  FirechatUI.prototype = {
+
+    _bindUIEvents: function() {
+      // Chat-specific custom interactions and functionality.
+      this._bindForHeightChange();
+      this._bindForTabControls();
+      this._bindForRoomList();
+      this._bindForUserRoomList();
+      this._bindForUserSearch();
+      this._bindForUserMuting();
+      this._bindForChatInvites();
+      this._bindForRoomListing();
+
+      // Generic, non-chat-specific interactive elements.
+      this._setupTabs();
+      this._setupDropdowns();
+      this._bindTextInputFieldLimits();
+    },
+
+    _bindDataEvents: function() {
+      this._chat.on('user-update', this._onUpdateUser.bind(this));
+
+      // Bind events for new messages, enter / leaving rooms, and user metadata.
+      this._chat.on('room-enter', this._onEnterRoom.bind(this));
+      this._chat.on('room-exit', this._onLeaveRoom.bind(this));
+      this._chat.on('message-add', this._onNewMessage.bind(this));
+      this._chat.on('message-remove', this._onRemoveMessage.bind(this));
+
+      // Bind events related to chat invitations.
+      this._chat.on('room-invite', this._onChatInvite.bind(this));
+      this._chat.on('room-invite-response', this._onChatInviteResponse.bind(this));
+
+      // Binds events related to admin or moderator notifications.
+      this._chat.on('notification', this._onNotification.bind(this));
+    },
+
+    _renderLayout: function() {
+      var template = FirechatDefaultTemplates["templates/layout-full.html"];
+      $(this._el).html(template({
+        maxLengthUsername: this.maxLengthUsername
+      }));
+    },
+
+    _onUpdateUser: function(user) {
+      // Update our current user state and render latest user name.
+      this._user = user;
+
+      // Update our interface to reflect which users are muted or not.
+      var mutedUsers = this._user.muted || {};
+      $('[data-event="firechat-user-mute-toggle"]').each(function(i, el) {
+        var userId = $(this).closest('[data-user-id]').data('user-id');
+        $(this).toggleClass('red', !!mutedUsers[userId]);
+      });
+
+      // Ensure that all messages from muted users are removed.
+      for (var userId in mutedUsers) {
+        $('.message[data-user-id="' + userId + '"]').fadeOut();
+      }
+    },
+
+    _onEnterRoom: function(room) {
+      this.attachTab(room.id, room.name);
+    },
+    _onLeaveRoom: function(roomId) {
+      this.removeTab(roomId);
+
+      // Auto-enter rooms in the queue
+      if ((this._roomQueue.length > 0)) {
+        this._chat.enterRoom(this._roomQueue.shift(roomId));
+      }
+    },
+    _onNewMessage: function(roomId, message) {
+      var userId = message.userId;
+      if (!this._user || !this._user.muted || !this._user.muted[userId]) {
+        this.showMessage(roomId, message);
+      }
+    },
+    _onRemoveMessage: function(roomId, messageId) {
+      this.removeMessage(roomId, messageId);
+    },
+
+    // Events related to chat invitations.
+    _onChatInvite: function(invitation) {
+      var self = this;
+      var template = FirechatDefaultTemplates["templates/prompt-invitation.html"];
+      var $prompt = this.prompt('Invite', template(invitation));
+      $prompt.find('a.close').click(function() {
+        $prompt.remove();
+        self._chat.declineInvite(invitation.id);
+      });
+
+      $prompt.find('[data-toggle=accept]').click(function() {
+        $prompt.remove();
+        self._chat.acceptInvite(invitation.id);
+      });
+
+      $prompt.find('[data-toggle=decline]').click(function() {
+        $prompt.remove();
+        self._chat.declineInvite(invitation.id);
+      });
+    },
+    _onChatInviteResponse: function(invitation) {
+      if (!invitation.status) return;
+
+      var self = this,
+          template = FirechatDefaultTemplates["templates/prompt-invite-reply.html"],
+          $prompt;
+
+      if (invitation.status && invitation.status === 'accepted') {
+        $prompt = this.prompt('Accepted', template(invitation));
+        this._chat.getRoom(invitation.roomId, function(room) {
+          self.attachTab(invitation.roomId, room.name);
+        });
+      } else {
+        $prompt = this.prompt('Declined', template(invitation));
+      }
+
+      $prompt.find('a.close').click(function() {
+        $prompt.remove();
+      });
+    },
+
+    // Events related to admin or moderator notifications.
+    _onNotification: function(notification) {
+      if (notification.notificationType === 'warning') {
+        this.renderAlertPrompt('Warning', 'You are being warned for inappropriate messaging. Further violation may result in temporary or permanent ban of service.');
+      } else if (notification.notificationType === 'suspension') {
+        var suspendedUntil = notification.data.suspendedUntil,
+            secondsLeft = Math.round((suspendedUntil - new Date().getTime()) / 1000),
+            timeLeft = '';
+
+        if (secondsLeft > 0) {
+          if (secondsLeft > 2*3600) {
+            var hours = Math.floor(secondsLeft / 3600);
+            timeLeft = hours + ' hours, ';
+            secondsLeft -= 3600*hours;
+          }
+          timeLeft += Math.floor(secondsLeft / 60) + ' minutes';
+          this.renderAlertPrompt('Suspended', 'A moderator has suspended you for violating site rules. You cannot send messages for another ' + timeLeft + '.');
+        }
+      }
+    }
+  };
+
+  /**
+   * Initialize an authenticated session with a user id and name.
+   * This method assumes that the underlying Firebase reference has
+   * already been authenticated.
+   */
+  FirechatUI.prototype.setUser = function(userId, userName) {
+    var self = this;
+
+    // Initialize data events
+    self._chat.setUser(userId, userName, function(user) {
+      self._user = user;
+
+      if (self._chat.userIsModerator()) {
+        self._bindSuperuserUIEvents();
+      }
+
+      self._chat.resumeSession();
+    });
+  };
+
+  /**
+   * Exposes internal chat bindings via this external interface.
+   */
+  FirechatUI.prototype.on = function(eventType, cb) {
+    var self = this;
+
+    this._chat.on(eventType, cb);
+  };
+
+  /**
+   * Binds a custom context menu to messages for superusers to warn or ban
+   * users for violating terms of service.
+   */
+  FirechatUI.prototype._bindSuperuserUIEvents = function() {
+    var self = this,
+        parseMessageVars = function(event) {
+          var $this = $(this),
+          messageId = $this.closest('[data-message-id]').data('message-id'),
+          userId = $('[data-message-id="' + messageId + '"]').closest('[data-user-id]').data('user-id'),
+          roomId = $('[data-message-id="' + messageId + '"]').closest('[data-room-id]').data('room-id');
+
+          return { messageId: messageId, userId: userId, roomId: roomId };
+        },
+        clearMessageContextMenus = function() {
+          // Remove any context menus currently showing.
+          $('[data-toggle="firechat-contextmenu"]').each(function() {
+            $(this).remove();
+          });
+
+          // Remove any messages currently highlighted.
+          $('#firechat .message.highlighted').each(function() {
+            $(this).removeClass('highlighted');
+          });
+        },
+        showMessageContextMenu = function(event) {
+          var $this = $(this),
+              $message = $this.closest('[data-message-id]'),
+              template = FirechatDefaultTemplates["templates/message-context-menu.html"],
+              messageVars = parseMessageVars.call(this, event),
+              $template;
+
+          event.preventDefault();
+
+          // Clear existing menus.
+          clearMessageContextMenus();
+
+          // Highlight the relevant message.
+          $this.addClass('highlighted');
+
+          self._chat.getRoom(messageVars.roomId, function(room) {
+            // Show the context menu.
+            $template = $(template({
+              id: $message.data('message-id')
+            }));
+            $template.css({
+              left: event.clientX,
+              top: event.clientY
+            }).appendTo(self.$wrapper);
+          });
+        };
+
+    // Handle dismissal of message context menus (any non-right-click click event).
+    $(document).bind('click', { self: this }, function(event) {
+      if (!event.button || event.button != 2) {
+        clearMessageContextMenus();
+      }
+    });
+
+    // Handle display of message context menus (via right-click on a message).
+    $(document).delegate('[data-class="firechat-message"]', 'contextmenu', showMessageContextMenu);
+
+    // Handle click of the 'Warn User' contextmenu item.
+    $(document).delegate('[data-event="firechat-user-warn"]', 'click', function(event) {
+      var messageVars = parseMessageVars.call(this, event);
+      self._chat.warnUser(messageVars.userId);
+    });
+
+    // Handle click of the 'Suspend User (1 Hour)' contextmenu item.
+    $(document).delegate('[data-event="firechat-user-suspend-hour"]', 'click', function(event) {
+      var messageVars = parseMessageVars.call(this, event);
+      self._chat.suspendUser(messageVars.userId, /* 1 Hour = 3600s */ 60*60);
+    });
+
+    // Handle click of the 'Suspend User (1 Day)' contextmenu item.
+    $(document).delegate('[data-event="firechat-user-suspend-day"]', 'click', function(event) {
+      var messageVars = parseMessageVars.call(this, event);
+      self._chat.suspendUser(messageVars.userId, /* 1 Day = 86400s */ 24*60*60);
+    });
+
+    // Handle click of the 'Delete Message' contextmenu item.
+    $(document).delegate('[data-event="firechat-message-delete"]', 'click', function(event) {
+      var messageVars = parseMessageVars.call(this, event);
+      self._chat.deleteMessage(messageVars.roomId, messageVars.messageId);
+    });
+  };
+
+  /**
+   * Binds to height changes in the surrounding div.
+   */
+  FirechatUI.prototype._bindForHeightChange = function() {
+    var self = this,
+        $el = $(this._el),
+        lastHeight = null;
+
+    setInterval(function() {
+      var height = $el.height();
+      if (height != lastHeight) {
+        lastHeight = height;
+        $('.chat').each(function(i, el) {
+
+        });
+      }
+    }, 500);
+  };
+
+  /**
+   * Binds custom inner-tab events.
+   */
+  FirechatUI.prototype._bindForTabControls = function() {
+    var self = this;
+
+    // Handle click of tab close button.
+    $(document).delegate('[data-event="firechat-close-tab"]', 'click', function(event) {
+      var roomId = $(this).closest('[data-room-id]').data('room-id');
+      self._chat.leaveRoom(roomId);
+    });
+  };
+
+  /**
+   * Binds room list dropdown to populate room list on-demand.
+   */
+  FirechatUI.prototype._bindForRoomList = function() {
+    var self = this;
+
+    $('#firechat-btn-rooms').bind('click', function() {
+      if ($(this).parent().hasClass('open')) {
+        return;
+      }
+
+      var $this = $(this),
+          template = FirechatDefaultTemplates["templates/room-list-item.html"],
+          selectRoomListItem = function() {
+            var parent = $(this).parent(),
+                roomId = parent.data('room-id'),
+                roomName = parent.data('room-name');
+
+            if (self.$messages[roomId]) {
+              self.focusTab(roomId);
+            } else {
+              self._chat.enterRoom(roomId, roomName);
+            }
+          };
+
+      self._chat.getRoomList(function(rooms) {
+        self.$roomList.empty();
+        for (var roomId in rooms) {
+          var room = rooms[roomId];
+          if (room.type != "public") continue;
+          room.isRoomOpen = !!self.$messages[room.id];
+          var $roomItem = $(template(room));
+          $roomItem.children('a').bind('click', selectRoomListItem);
+          self.$roomList.append($roomItem.toggle(true));
+        }
+      });
+    });
+  };
+
+  /**
+   * Binds user list dropdown per room to populate user list on-demand.
+   */
+  FirechatUI.prototype._bindForUserRoomList = function() {
+    var self = this;
+
+    // Upon click of the dropdown, autofocus the input field and trigger list population.
+    $(document).delegate('[data-event="firechat-user-room-list-btn"]', 'click', function(event) {
+      event.stopPropagation();
+
+      var $this = $(this),
+          roomId = $this.closest('[data-room-id]').data('room-id'),
+          template = FirechatDefaultTemplates["templates/room-user-list-item.html"],
+          targetId = $this.data('target'),
+          $target = $('#' + targetId);
+
+      $target.empty();
+      self._chat.getUsersByRoom(roomId, function(users) {
+        for (var username in users) {
+          user = users[username];
+          user.disableActions = (!self._user || user.id === self._user.id);
+          user.nameTrimmed = self.trimWithEllipsis(user.name, self.maxLengthUsernameDisplay);
+          user.isMuted = (self._user && self._user.muted && self._user.muted[user.id]);
+          $target.append($(template(user)));
+        }
+        self.sortListLexicographically('#' + targetId);
+      });
+    });
+  };
+
+  /**
+   * Binds user search buttons, dropdowns, and input fields for searching all
+   * active users currently in chat.
+   */
+  FirechatUI.prototype._bindForUserSearch = function() {
+    var self = this,
+        handleUserSearchSubmit = function(event) {
+          var $this = $(this),
+              targetId = $this.data('target'),
+              controlsId = $this.data('controls'),
+              templateId = $this.data('template'),
+              prefix = $this.val() || $this.data('prefix') || '',
+              startAt = $this.data('startAt') || null,
+              endAt = $this.data('endAt') || null;
+
+          event.preventDefault();
+
+          userSearch(targetId, templateId, controlsId, prefix, startAt, endAt);
+        },
+        userSearch = function(targetId, templateId, controlsId, prefix, startAt, endAt) {
+          var $target = $('#' + targetId),
+              $controls = $('#' + controlsId),
+              template = FirechatDefaultTemplates[templateId];
+
+          // Query results, filtered by prefix, using the defined startAt and endAt markets.
+          self._chat.getUsersByPrefix(prefix, startAt, endAt, self.maxUserSearchResults, function(users) {
+            var numResults = 0,
+                $prevBtn, $nextBtn, username, firstResult, lastResult;
+
+            $target.empty();
+
+            for (username in users) {
+              var user = users[username];
+
+              // Disable buttons for <me>.
+              user.disableActions = (!self._user || user.id === self._user.id);
+
+              numResults += 1;
+
+              $target.append(template(user));
+
+              // If we've hit our result limit, the additional value signifies we should paginate.
+              if (numResults === 1) {
+                firstResult = user.name.toLowerCase();
+              } else if (numResults >= self.maxUserSearchResults) {
+                lastResult = user.name.toLowerCase();
+                break;
+              }
+            }
+
+            if ($controls) {
+              $prevBtn = $controls.find('[data-toggle="firechat-pagination-prev"]');
+              $nextBtn = $controls.find('[data-toggle="firechat-pagination-next"]');
+
+              // Sort out configuration for the 'next' button
+              if (lastResult) {
+                $nextBtn
+                  .data('event', 'firechat-user-search')
+                  .data('startAt', lastResult)
+                  .data('prefix', prefix)
+                  .removeClass('disabled').removeAttr('disabled');
+              } else {
+                $nextBtn
+                  .data('event', null)
+                  .data('startAt', null)
+                  .data('prefix', null)
+                  .addClass('disabled').attr('disabled', 'disabled');
+              }
+            }
+          });
+        };
+
+    $(document).delegate('[data-event="firechat-user-search"]', 'keyup', handleUserSearchSubmit);
+    $(document).delegate('[data-event="firechat-user-search"]', 'click', handleUserSearchSubmit);
+
+    // Upon click of the dropdown, autofocus the input field and trigger list population.
+    $(document).delegate('[data-event="firechat-user-search-btn"]', 'click', function(event) {
+      event.stopPropagation();
+      var $input = $(this).next('div.dropdown-menu').find('input');
+      $input.focus();
+      $input.trigger(jQuery.Event('keyup'));
+    });
+
+    // Ensure that the dropdown stays open despite clicking on the input element.
+    $(document).delegate('[data-event="firechat-user-search"]', 'click', function(event) {
+      event.stopPropagation();
+    });
+  };
+
+  /**
+   * Binds user mute toggles and removes all messages for a given user upon mute.
+   */
+  FirechatUI.prototype._bindForUserMuting = function() {
+    var self = this;
+    $(document).delegate('[data-event="firechat-user-mute-toggle"]', 'click', function(event) {
+      var $this = $(this),
+          userId = $this.closest('[data-user-id]').data('user-id'),
+          userName = $this.closest('[data-user-name]').data('user-name'),
+          isMuted = $this.hasClass('red'),
+          template = FirechatDefaultTemplates["templates/prompt-user-mute.html"];
+
+      event.preventDefault();
+
+      // Require user confirmation for muting.
+      if (!isMuted) {
+        var $prompt = self.prompt('Mute User?', template({
+          userName: userName
+        }));
+
+        $prompt.find('a.close').first().click(function() {
+          $prompt.remove();
+        });
+
+        $prompt.find('[data-toggle=decline]').first().click(function() {
+          $prompt.remove();
+        });
+
+        $prompt.find('[data-toggle=accept]').first().click(function() {
+          self._chat.toggleUserMute(userId);
+          $prompt.remove();
+        });
+      } else {
+        self._chat.toggleUserMute(userId);
+      }
+    });
+  };
+
+  /**
+   * Binds to elements with the data-event='firechat-user-(private)-invite' and
+   * handles invitations as well as room creation and entering.
+   */
+  FirechatUI.prototype._bindForChatInvites = function() {
+    var self = this,
+        renderInvitePrompt = function(event) {
+          var $this = $(this),
+              userId = $this.closest('[data-user-id]').data('user-id'),
+              roomId = $this.closest('[data-room-id]').data('room-id'),
+              userName = $this.closest('[data-user-name]').data('user-name'),
+              template = FirechatDefaultTemplates["templates/prompt-invite-private.html"],
+              $prompt;
+
+          self._chat.getRoom(roomId, function(room) {
+            $prompt = self.prompt('Invite', template({
+              userName: userName,
+              roomName: room.name
+            }));
+
+            $prompt.find('a.close').click(function() {
+              $prompt.remove();
+            });
+
+            $prompt.find('[data-toggle=decline]').click(function() {
+              $prompt.remove();
+            });
+
+            $prompt.find('[data-toggle=accept]').first().click(function() {
+              $prompt.remove();
+              self._chat.inviteUser(userId, roomId, room.name);
+            });
+          });
+        },
+        renderPrivateInvitePrompt = function(event) {
+          var $this = $(this),
+              userId = $this.closest('[data-user-id]').data('user-id'),
+              userName = $this.closest('[data-user-name]').data('user-name'),
+              template = FirechatDefaultTemplates["templates/prompt-invite-private.html"],
+              $prompt;
+
+          if (userId && userName) {
+            $prompt = self.prompt('Private Invite', template({
+              userName: userName,
+              roomName: 'Private Chat'
+            }));
+
+            $prompt.find('a.close').click(function() {
+              $prompt.remove();
+            });
+
+            $prompt.find('[data-toggle=decline]').click(function() {
+              $prompt.remove();
+            });
+
+            $prompt.find('[data-toggle=accept]').first().click(function() {
+              $prompt.remove();
+              var roomName = 'Private Chat';
+              self._chat.createRoom(roomName, 'private', function(roomId) {
+                self._chat.inviteUser(userId, roomId, roomName);
+              });
+            });
+          }
+        };
+
+    $(document).delegate('[data-event="firechat-user-chat"]', 'click', renderPrivateInvitePrompt);
+    $(document).delegate('[data-event="firechat-user-invite"]', 'click', renderInvitePrompt);
+  };
+
+  /**
+   * Binds to room dropdown button, menu items, and create room button.
+   */
+  FirechatUI.prototype._bindForRoomListing = function() {
+    var self = this,
+        $createRoomPromptButton = $('#firechat-btn-create-room-prompt'),
+        $createRoomButton = $('#firechat-btn-create-room'),
+        renderRoomList = function(event) {
+          var type = $(this).data('room-type');
+
+          self.sortListLexicographically('#firechat-room-list');
+        };
+
+    // Handle click of the create new room prompt-button.
+    $createRoomPromptButton.bind('click', function(event) {
+      self.promptCreateRoom();
+    });
+
+    // Handle click of the create new room button.
+    $createRoomButton.bind('click', function(event) {
+      var roomName = $('#firechat-input-room-name').val();
+      $('#firechat-prompt-create-room').remove();
+      self._chat.createRoom(roomName);
+    });
+  };
+
+  /**
+   * A stripped-down version of bootstrap-tab.js.
+   *
+   * Original bootstrap-tab.js Copyright 2012 Twitter, Inc.,licensed under the Apache v2.0
+   */
+  FirechatUI.prototype._setupTabs = function() {
+    var self = this,
+        show = function($el) {
+          var $this = $el,
+              $ul = $this.closest('ul:not(.dropdown-menu)'),
+              selector = $this.attr('data-target'),
+              previous = $ul.find('.active:last a')[0],
+              $target,
+              e;
+
+          if (!selector) {
+            selector = $this.attr('href');
+            selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '');
+          }
+
+          if ($this.parent('li').hasClass('active')) return;
+
+          e = $.Event('show', { relatedTarget: previous });
+
+          $this.trigger(e);
+
+          if (e.isDefaultPrevented()) return;
+
+          $target = $(selector);
+
+          activate($this.parent('li'), $ul);
+          activate($target, $target.parent(), function () {
+            $this.trigger({
+              type: 'shown',
+              relatedTarget: previous
+            });
+          });
+        },
+        activate = function (element, container, callback) {
+          var $active = container.find('> .active'),
+              transition = callback && $.support.transition && $active.hasClass('fade');
+
+          function next() {
+            $active
+              .removeClass('active')
+              .find('> .dropdown-menu > .active')
+              .removeClass('active');
+
+            element.addClass('active');
+
+            if (transition) {
+              element.addClass('in');
+            } else {
+              element.removeClass('fade');
+            }
+
+            if (element.parent('.dropdown-menu')) {
+              element.closest('li.dropdown').addClass('active');
+            }
+
+            if (callback) {
+              callback();
+            }
+          }
+
+          if (transition) {
+            $active.one($.support.transition.end, next);
+          } else {
+            next();
+          }
+
+          $active.removeClass('in');
+      };
+
+    $(document).delegate('[data-toggle="tab"]', 'click', function(event) {
+      event.preventDefault();
+      show($(this));
+    });
+  };
+
+  /**
+   * A stripped-down version of bootstrap-dropdown.js.
+   *
+   * Original bootstrap-dropdown.js Copyright 2012 Twitter, Inc., licensed under the Apache v2.0
+   */
+  FirechatUI.prototype._setupDropdowns = function() {
+    var self = this,
+        toggle = '[data-toggle=dropdown]',
+        toggleDropdown = function(event) {
+          var $this = $(this),
+              $parent = getParent($this),
+              isActive = $parent.hasClass('open');
+
+          if ($this.is('.disabled, :disabled')) return;
+
+          clearMenus();
+
+          if (!isActive) {
+            $parent.toggleClass('open');
+          }
+
+          $this.focus();
+
+          return false;
+        },
+        clearMenus = function() {
+          $('[data-toggle=dropdown]').each(function() {
+            getParent($(this)).removeClass('open');
+          });
+        },
+        getParent = function($this) {
+          var selector = $this.attr('data-target'),
+              $parent;
+
+          if (!selector) {
+            selector = $this.attr('href');
+            selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '');
+          }
+
+          $parent = selector && $(selector);
+
+          if (!$parent || !$parent.length) $parent = $this.parent();
+
+          return $parent;
+        };
+
+      $(document)
+        .bind('click', clearMenus)
+        .delegate('.dropdown-menu', 'click', function(event) { event.stopPropagation(); })
+        .delegate('[data-toggle=dropdown]', 'click', toggleDropdown);
+  };
+
+  /**
+   * Binds to any text input fields with data-provide='limit' and
+   * data-counter='<selector>', and upon value change updates the selector
+   * content to reflect the number of characters remaining, as the 'maxlength'
+   * attribute less the current value length.
+   */
+  FirechatUI.prototype._bindTextInputFieldLimits = function() {
+    $('body').delegate('input[data-provide="limit"], textarea[data-provide="limit"]', 'keyup', function(event) {
+      var $this = $(this),
+          $target = $($this.data('counter')),
+          limit = $this.attr('maxlength'),
+          count = $this.val().length;
+
+      $target.html(Math.max(0, limit - count));
+    });
+  };
+
+  /**
+   * Given a title and message content, show an alert prompt to the user.
+   *
+   * @param    {string}    title
+   * @param    {string}    message
+   */
+  FirechatUI.prototype.renderAlertPrompt = function(title, message) {
+    var template = FirechatDefaultTemplates["templates/prompt-alert.html"],
+        $prompt = this.prompt(title, template({ message: message }));
+
+      $prompt.find('.close').click(function() {
+        $prompt.remove();
+      });
+      return;
+  };
+
+  /**
+   * Toggle input field s if we want limit / unlimit input fields.
+   */
+  FirechatUI.prototype.toggleInputs = function(isEnabled) {
+    $('#firechat-tab-content textarea').each(function() {
+      var $this = $(this);
+      if (isEnabled) {
+        $(this).val('');
+      } else {
+        $(this).val('You have exceeded the message limit, please wait before sending.');
+      }
+      $this.prop('disabled', !isEnabled);
+    });
+    $('#firechat-input-name').prop('disabled', !isEnabled);
+  };
+
+  /**
+   * Given a room id and name, attach the tab to the interface and setup events.
+   *
+   * @param    {string}    roomId
+   * @param    {string}    roomName
+   */
+  FirechatUI.prototype.attachTab = function(roomId, roomName) {
+    var self = this;
+
+    // If this tab already exists, give it focus.
+    if (this.$messages[roomId]) {
+      this.focusTab(roomId);
+      return;
+    }
+
+    var room = {
+      id: roomId,
+      name: roomName
+    };
+
+    // Populate and render the tab content template.
+    var tabTemplate = FirechatDefaultTemplates["templates/tab-content.html"];
+    var $tabContent = $(tabTemplate(room));
+    this.$tabContent.prepend($tabContent);
+    var $messages = $('#firechat-messages' + roomId);
+
+    // Keep a reference to the message listing for later use.
+    this.$messages[roomId] = $messages;
+
+    // Attach on-enter event to textarea.
+    var $textarea = $tabContent.find('textarea').first();
+    $textarea.bind('keydown', function(e) {
+      var message = self.trimWithEllipsis($textarea.val(), self.maxLengthMessage);
+      if ((e.which === 13) && (message !== '')) {
+        $textarea.val('');
+        self._chat.sendMessage(roomId, message);
+        return false;
+      }
+    });
+
+    // Populate and render the tab menu template.
+    var tabListTemplate = FirechatDefaultTemplates["templates/tab-menu-item.html"];
+    var $tab = $(tabListTemplate(room));
+    this.$tabList.prepend($tab);
+
+    // Attach on-shown event to move tab to front and scroll to bottom.
+    $tab.bind('shown', function(event) {
+      $messages.scrollTop($messages[0].scrollHeight);
+    });
+
+    // Dynamically update the width of each tab based upon the number open.
+    var tabs = this.$tabList.children('li');
+    var tabWidth = Math.floor($('#firechat-tab-list').width() / tabs.length);
+    this.$tabList.children('li').css('width', tabWidth);
+
+    // Update the room listing to reflect that we're now in the room.
+    this.$roomList.children('[data-room-id=' + roomId + ']').children('a').addClass('highlight');
+
+    // Sort each item in the user list alphabetically on click of the dropdown.
+    $('#firechat-btn-room-user-list-' + roomId).bind('click', function() {
+      self.sortListLexicographically('#firechat-room-user-list-' + roomId);
+    });
+
+    // Automatically select the new tab.
+    this.focusTab(roomId);
+  };
+
+  /**
+   * Given a room id, focus the given tab.
+   *
+   * @param    {string}    roomId
+   */
+  FirechatUI.prototype.focusTab = function(roomId) {
+    if (this.$messages[roomId]) {
+      var $tabLink = this.$tabList.find('[data-room-id=' + roomId + ']').find('a');
+      if ($tabLink.length) {
+        $tabLink.first().trigger('click');
+      }
+    }
+  };
+
+  /**
+   * Given a room id, remove the tab and all child elements from the interface.
+   *
+   * @param    {string}    roomId
+   */
+  FirechatUI.prototype.removeTab = function(roomId) {
+    delete this.$messages[roomId];
+
+    // Remove the inner tab content.
+    this.$tabContent.find('[data-room-id=' + roomId + ']').remove();
+
+    // Remove the tab from the navigation menu.
+    this.$tabList.find('[data-room-id=' + roomId + ']').remove();
+
+    // Dynamically update the width of each tab based upon the number open.
+    var tabs = this.$tabList.children('li');
+    var tabWidth = Math.floor($('#firechat-tab-list').width() / tabs.length);
+    this.$tabList.children('li').css('width', tabWidth);
+
+    // Automatically select the next tab if there is one.
+    this.$tabList.find('[data-toggle=tab]').first().trigger('click');
+
+    // Update the room listing to reflect that we're now in the room.
+    this.$roomList.children('[data-room-id=' + roomId + ']').children('a').removeClass('highlight');
+  };
+
+  /**
+   * Render a new message in the specified chat room.
+   *
+   * @param    {string}    roomId
+   * @param    {string}    message
+   */
+  FirechatUI.prototype.showMessage = function(roomId, rawMessage) {
+    var self = this;
+
+    // Setup defaults
+    var message = {
+      id              : rawMessage.id,
+      localtime       : self.formatTime(rawMessage.timestamp),
+      message         : rawMessage.message || '',
+      userId          : rawMessage.userId,
+      name            : rawMessage.name,
+      type            : rawMessage.type || 'default',
+      isSelfMessage   : (self._user && rawMessage.userId == self._user.id),
+      disableActions  : (!self._user || rawMessage.userId == self._user.id)
+    };
+
+    // While other data is escaped in the Underscore.js templates, escape and
+    // process the message content here to add additional functionality (add links).
+    // Also trim the message length to some client-defined maximum.
+    var messageConstructed = '';
+    message.message = _.map(message.message.split(' '), function(token) {
+      if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) {
+        return self.linkify(encodeURI(token));
+      } else {
+        return _.escape(token);
+      }
+    }).join(' ');
+    message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage);
+
+    // Populate and render the message template.
+    var template = FirechatDefaultTemplates["templates/message.html"];
+    var $message = $(template(message));
+    var $messages = self.$messages[roomId];
+    if ($messages) {
+
+      var scrollToBottom = false;
+      if ($messages.scrollTop() / ($messages[0].scrollHeight - $messages[0].offsetHeight) >= 0.95) {
+        // Pinned to bottom
+        scrollToBottom = true;
+      } else if ($messages[0].scrollHeight <= $messages.height()) {
+        // Haven't added the scrollbar yet
+        scrollToBottom = true;
+      }
+
+      $messages.append($message);
+
+      if (scrollToBottom) {
+        $messages.scrollTop($messages[0].scrollHeight);
+      }
+    }
+  };
+
+  /**
+   * Remove a message by id.
+   *
+   * @param    {string}    roomId
+   * @param    {string}    messageId
+   */
+  FirechatUI.prototype.removeMessage = function(roomId, messageId) {
+    $('.message[data-message-id="' + messageId + '"]').remove();
+  };
+
+  /**
+   * Given a selector for a list element, sort the items alphabetically.
+   *
+   * @param    {string}    selector
+   */
+  FirechatUI.prototype.sortListLexicographically = function(selector) {
+    $(selector).children("li").sort(function(a, b) {
+        var upA = $(a).text().toUpperCase();
+        var upB = $(b).text().toUpperCase();
+        return (upA < upB) ? -1 : (upA > upB) ? 1 : 0;
+    }).appendTo(selector);
+  };
+
+  /**
+   * Remove leading and trailing whitespace from a string and shrink it, with
+   * added ellipsis, if it exceeds a specified length.
+   *
+   * @param    {string}    str
+   * @param    {number}    length
+   * @return   {string}
+   */
+  FirechatUI.prototype.trimWithEllipsis = function(str, length) {
+    str = str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+    return (length && str.length <= length) ? str : str.substring(0, length) + '...';
+  };
+
+  /**
+   * Given a timestamp, format it in the form hh:mm am/pm. Defaults to now
+   * if the timestamp is undefined.
+   *
+   * @param    {Number}    timestamp
+   * @param    {string}    date
+   */
+  FirechatUI.prototype.formatTime = function(timestamp) {
+    var date = (timestamp) ? new Date(timestamp) : new Date(),
+        hours = date.getHours() || 12,
+        minutes = '' + date.getMinutes(),
+        ampm = (date.getHours() >= 12) ? 'pm' : 'am'; 
+
+    hours = (hours > 12) ? hours - 12 : hours;
+    minutes = (minutes.length < 2) ? '0' + minutes : minutes;
+    return '' + hours + ':' + minutes + ampm;
+  };
+
+  /**
+   * Launch a prompt to allow the user to create a new room.
+   */
+  FirechatUI.prototype.promptCreateRoom = function() {
+    var self = this;
+    var template = FirechatDefaultTemplates["templates/prompt-create-room.html"];
+
+    var $prompt = this.prompt('Create Public Room', template({
+      maxLengthRoomName: this.maxLengthRoomName,
+      isModerator: self._chat.userIsModerator()
+    }));
+    $prompt.find('a.close').first().click(function() {
+      $prompt.remove();
+    });
+
+
+    $prompt.find('[data-toggle=submit]').first().click(function() {
+      var name = $prompt.find('[data-input=firechat-room-name]').first().val();
+      if (name !== '') {
+        self._chat.createRoom(name, 'public');
+        $prompt.remove();
+      }
+    });
+
+    $prompt.find('[data-input=firechat-room-name]').first().focus();
+    $prompt.find('[data-input=firechat-room-name]').first().bind('keydown', function(e) {
+      if (e.which === 13) {
+        var name = $prompt.find('[data-input=firechat-room-name]').first().val();
+        if (name !== '') {
+          self._chat.createRoom(name, 'public');
+          $prompt.remove();
+          return false;
+        }
+      }
+    });
+  };
+
+  /**
+   * Inner method to launch a prompt given a specific title and HTML content.
+   * @param    {string}    title
+   * @param    {string}    content
+   */
+  FirechatUI.prototype.prompt = function(title, content) {
+    var template = FirechatDefaultTemplates["templates/prompt.html"],
+        $prompt;
+
+    $prompt = $(template({
+      title: title,
+      content: content
+    })).css({
+      top: this.$wrapper.position().top + (0.333 * this.$wrapper.height()),
+      left: this.$wrapper.position().left + (0.125 * this.$wrapper.width()),
+      width: 0.75 * this.$wrapper.width()
+    });
+    this.$wrapper.append($prompt.removeClass('hidden'));
+    return $prompt;
+  };
+
+  // see http://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links
+  FirechatUI.prototype.linkify = function(str) {
+    var self = this;
+    return str
+      .replace(self.urlPattern, '<a target="_blank" href="$&">$&</a>')
+      .replace(self.pseudoUrlPattern, '$1<a target="_blank" href="http://$2">$2</a>');
+  };
+
+})(jQuery);
diff --git a/dist/0.1.5/firechat-default.min.css b/dist/0.1.5/firechat-default.min.css
new file mode 100644
index 0000000..34b54b6
--- /dev/null
+++ b/dist/0.1.5/firechat-default.min.css
@@ -0,0 +1 @@
+@charset "UTF-8";#firechat div,#firechat span,#firechat applet,#firechat object,#firechat iframe,#firechat h1,#firechat h2,#firechat h3,#firechat h4,#firechat h5,#firechat h6,#firechat p,#firechat blockquote,#firechat pre,#firechat a,#firechat abbr,#firechat acronym,#firechat address,#firechat big,#firechat cite,#firechat code,#firechat del,#firechat dfn,#firechat em,#firechat img,#firechat ins,#firechat kbd,#firechat q,#firechat s,#firechat samp,#firechat small,#firechat strike,#firechat strong,#firechat sub,#firechat sup,#firechat tt,#firechat var,#firechat b,#firechat u,#firechat i,#firechat center,#firechat dl,#firechat dt,#firechat dd,#firechat ol,#firechat ul,#firechat li,#firechat fieldset,#firechat form,#firechat label,#firechat legend,#firechat table,#firechat caption,#firechat tbody,#firechat tfoot,#firechat thead,#firechat tr,#firechat th,#firechat td,#firechat article,#firechat aside,#firechat canvas,#firechat details,#firechat embed,#firechat figure,#firechat figcaption,#firechat footer,#firechat header,#firechat hgroup,#firechat menu,#firechat nav,#firechat output,#firechat ruby,#firechat section,#firechat summary,#firechat time,#firechat mark,#firechat audio,#firechat video{border:0;font-size:12px;font-family:arial,helvetica,sans-serif;vertical-align:baseline;margin:0;padding:0}#firechat article,#firechat aside,#firechat details,#firechat figcaption,#firechat figure,#firechat footer,#firechat header,#firechat hgroup,#firechat menu,#firechat nav,#firechat section{display:block}#firechat body{line-height:1}#firechat ol,#firechat ul{list-style:none}#firechat blockquote,#firechat q{quotes:none}#firechat blockquote:before,#firechat blockquote:after,#firechat q:before,#firechat q:after{content:none}#firechat table{border-collapse:collapse;border-spacing:0}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}#firechat{color:#333;text-align:left}#firechat .center{float:none!important;margin-left:auto!important;margin-right:auto!important}#firechat .left{float:left!important}#firechat .right{float:right!important}#firechat .alignleft{text-align:left!important}#firechat .alignright{text-align:right!important}#firechat .aligncenter{text-align:center!important}#firechat .hidden{display:none!important}#firechat .row{clear:both}#firechat .fifth,#firechat .fivesixth,#firechat .fourfifth,#firechat .half,#firechat .ninetenth,#firechat .quarter,#firechat .sevententh,#firechat .sixth,#firechat .tenth,#firechat .third,#firechat .threefifth,#firechat .threequarter,#firechat .threetenth,#firechat .twofifth,#firechat .twothird,#firechat .full{margin-left:2.127659574468085%;float:left;min-height:1px}#firechat .fifth:first-child,#firechat .fivesixth:first-child,#firechat .fourfifth:first-child,#firechat .half:first-child,#firechat .ninetenth:first-child,#firechat .quarter:first-child,#firechat .sevententh:first-child,#firechat .sixth:first-child,#firechat .tenth:first-child,#firechat .third:first-child,#firechat .threefifth:first-child,#firechat .threequarter:first-child,#firechat .threetenth:first-child,#firechat .twofifth:first-child,#firechat .twothird:first-child,#firechat .full:first-child{margin-left:0}#firechat .tenth{width:8.08510638297872%}#firechat .sixth{width:14.893617021276595%}#firechat .fifth{width:18.297872340425535%}#firechat .quarter{width:23.404255319148938%}#firechat .threetenth{width:26.3829787235%}#firechat .third{width:31.914893617021278%}#firechat .twofifth{width:38.72340425531915%}#firechat .half{width:48.93617021276596%}#firechat .sevententh{width:58.7234042555%}#firechat .threefifth{width:59.14893617021278%}#firechat .twothird{width:65.95744680851064%}#firechat .threequarter{width:74.46808510638297%}#firechat .ninetenth{width:74.8936170215%}#firechat .fourfifth{width:79.57446808510639%}#firechat .fivesixth{width:82.9787234042553%}#firechat .full{width:100%}#firechat .clipped{overflow:hidden}#firechat strong{font-weight:bold}#firechat em{font-style:italic}#firechat label{display:block}#firechat a{color:#005580}#firechat a:visited,#firechat a:hover,#firechat a:active{color:#005580}#firechat p{margin:10px 0}#firechat h1,#firechat h2,#firechat h3,#firechat h4,#firechat h5,#firechat h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit}#firechat h1,#firechat h2,#firechat h3{line-height:40px}#firechat h1{font-size:38.5px}#firechat h2{font-size:31.5px}#firechat h3{font-size:24.5px}#firechat h4{font-size:17.5px}#firechat h5{font-size:14px}#firechat h6{font-size:11.9px}#firechat small{font-size:90%}#firechat .nav{list-style:none}#firechat .nav>li>a{display:block;background-color:#eee;text-decoration:none;overflow:hidden;white-space:nowrap}#firechat .nav>li>a:hover,#firechat .nav>li>a:focus{background-color:#fff}#firechat .nav-tabs{border-bottom:1px solid #ddd;clear:both}#firechat .nav-tabs>li{float:left;margin-bottom:-1px;max-width:45%}#firechat .nav-tabs>li>a{-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px;padding:4px 8px;margin-right:2px;line-height:20px;border:1px solid transparent;border-color:#ccc}#firechat .nav-tabs>.active>a,#firechat .nav-tabs>.active>a:hover,#firechat .nav-tabs>.active>a:focus{border-bottom-color:transparent;background-color:#fff;cursor:default}#firechat .tab-content{overflow:auto}#firechat .tab-content>.tab-pane{display:none}#firechat .tab-content>.active{display:block;background-color:#fff}#firechat .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";margin-top:8px;margin-left:2px}#firechat .dropdown{position:relative}#firechat .dropdown-toggle{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none}#firechat .dropdown-toggle:focus,#firechat .dropdown-toggle:active{outline:0;text-decoration:none}#firechat .dropdown-toggle.btn{padding:4px 0 0;height:22px}#firechat .dropdown-menu{*zoom:1;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0;z-index:1000;display:none;float:left;position:absolute;top:100%;left:0;width:100%;background-color:#fff;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;min-width:98%;padding:0;margin:-1px 0 0}#firechat .dropdown-menu:before,#firechat .dropdown-menu:after{display:table;content:"";line-height:0}#firechat .dropdown-menu:after{clear:both}#firechat .dropdown-menu ul{background-color:#fff;list-style:none;overflow-y:scroll;max-height:300px}#firechat .dropdown-menu ul>li>a{display:block;padding:1px 1px 1px 3px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}#firechat .dropdown-menu ul>li>a.highlight{background-color:#d9edf7}#firechat .dropdown-menu ul>li>a:hover,#firechat .dropdown-menu ul>li>a:focus,#firechat .dropdown-menu ul>.active>a,#firechat .dropdown-menu ul>.active>a:hover,#firechat .dropdown-menu ul>.active>a:focus{text-decoration:none;color:#000;background-color:#d9edf7;outline:0}#firechat .dropdown-menu ul>.disabled>a,#firechat .dropdown-menu ul>.disabled>a:hover,#firechat .dropdown-menu ul>.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;background-image:none;cursor:default}#firechat .dropdown-header{position:relative;width:100%;padding:10px 0;background-color:#eee;border-bottom:1px solid #ccc}#firechat .dropdown-footer{position:relative;width:100%;padding:10px 0;background-color:#eee;border-top:1px solid #ccc;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#firechat .open{*z-index:1000}#firechat .open>.dropdown-menu{display:block;border:1px solid #ccc;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0}#firechat .open>.dropdown-toggle{outline:0;text-decoration:none;-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px}#firechat .prompt-wrapper{position:absolute;z-index:1000}#firechat .prompt{position:absolute;z-index:1001;background-color:#fff;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.45);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.45);box-shadow:0 5px 10px rgba(0,0,0,0.45)}#firechat .prompt-header{padding:4px 8px;font-weight:bold;background-color:#eee;border:1px solid #ccc;-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px}#firechat .prompt-header a.close{opacity:.6;font-size:13px;margin-top:2px}#firechat .prompt-header a.close:hover{opacity:.9}#firechat .prompt-body{background-color:#fff;padding:4px 8px;border-left:1px solid #ccc;border-right:1px solid #ccc}#firechat .prompt-footer{padding:4px 8px;background-color:#eee;border:1px solid #ccc;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0}#firechat .prompt-background{background-color:#333;border:1px solid #333;opacity:.8;z-index:1000;height:100%;width:100%}#firechat .btn{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;height:24px;display:inline-block;*display:inline;*zoom:1;padding:2px 5px;margin-bottom:0;text-align:center;vertical-align:middle;cursor:pointer;color:#333;font-size:12px;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}#firechat .btn:hover,#firechat .btn:focus,#firechat .btn:active,#firechat .btn.active,#firechat .btn.disabled,#firechat .btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9;outline:0}#firechat .btn:active,#firechat .btn.active{background-color:#ccc}#firechat .btn:first-child{*margin-left:0}#firechat .btn:hover,#firechat .btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}#firechat .btn.active,#firechat .btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}#firechat .btn.disabled,#firechat .btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65)}#firechat .btn.disabled:active,#firechat .btn[disabled]:active{-webkit-box-shadow:inherit;-moz-box-shadow:inherit;box-shadow:inherit;background-color:#e6e6e6}#firechat .contextmenu{position:fixed;z-index:1001;min-width:150px;border:1px solid #ccc;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}#firechat .contextmenu ul{background-color:#fff;list-style:none}#firechat .contextmenu ul>li>a{display:block;padding:3px 10px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}#firechat .contextmenu ul>li>a.highlight{background-color:#d9edf7}#firechat .contextmenu ul>li>a:hover,#firechat .contextmenu ul>li>a:focus{text-decoration:none;color:#fff;background-color:#0081c2;outline:0}#firechat{padding:0;font-family:sans-serif;font-size:12px;line-height:18px}#firechat input,#firechat textarea{width:100%;font-family:sans-serif;font-size:12px;line-height:18px;padding:2px 5px;border:1px solid #ccc;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#firechat input:-moz-placeholder,#firechat textarea:-moz-placeholder{color:#aaa}#firechat input:-ms-input-placeholder,#firechat textarea:-ms-input-placeholder{color:#aaa}#firechat input::-webkit-input-placeholder,#firechat textarea::-webkit-input-placeholder{color:#aaa}#firechat input[disabled],#firechat textarea[disabled]{background-color:#eee}#firechat input{height:24px}#firechat textarea{resize:none;height:40px}#firechat .search-wrapper{-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;border:1px solid #ccc;margin:0 5px;padding:2px 5px;background:#fff}#firechat .search-wrapper>input[type=text]{padding-left:0;border:0}#firechat .search-wrapper>input[type=text]:focus,#firechat .search-wrapper>input[type=text]:active{outline:0}#firechat .chat{overflow:auto;-ms-overflow-x:hidden;overflow-x:hidden;height:290px;position:relative;margin-bottom:5px;border:1px solid #ccc;border-top:0;overflow-y:scroll}#firechat .chat textarea{overflow:auto;vertical-align:top}#firechat .message{color:#333;padding:3px 5px;border-bottom:1px solid #ccc}#firechat .message.highlighted{background-color:#d9edf7}#firechat .message .name{font-weight:bold;overflow-x:hidden}#firechat .message.message-self{color:#2675ab}#firechat .message:nth-child(odd){background-color:#f9f9f9}#firechat .message:nth-child(odd).highlighted{background-color:#d9edf7}#firechat .message:nth-child(odd).message-local{background-color:#effafc}#firechat .message-content{word-wrap:break-word;padding-right:45px}#firechat .message-content.red{color:red}#firechat .message.message-notification .message-content{font-style:italic}#firechat ul::-webkit-scrollbar{-webkit-appearance:none;width:7px}#firechat ul::-webkit-scrollbar-thumb{border-radius:4px;-webkit-box-shadow:0 0 1px rgba(255,255,255,0.5)}#firechat #firechat-header{padding:6px 0 0 0;height:40px}#firechat #firechat-tabs{height:435px}#firechat #firechat-tab-list{background-color:#fff}#firechat #firechat-tab-content{width:100%;background-color:#fff}#firechat .tab-pane-menu{border:1px solid #ccc;border-top:0;vertical-align:middle;padding-bottom:5px}#firechat .tab-pane-menu .dropdown{margin:5px 0 0 5px}#firechat .tab-pane-menu>.icon{margin:5px 2px 0}#firechat .icon{display:inline-block;*margin-right:.3em;line-height:20px;vertical-align:middle;background-repeat:no-repeat;padding:0;background:url(data:image/png;base64,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) no-repeat top left;opacity:.3;font-size:22px;font-family:Arial;font-weight:bold;overflow:hidden}#firechat .icon.plus{margin-top:0;vertical-align:top;background:transparent}#firechat .icon.search{background-position:0 0;width:13px;height:13px}#firechat .icon.close{background-position:-120px 0;width:13px;height:13px}#firechat .icon.user-chat{background-position:-138px 0;width:17px;height:13px}#firechat .icon.user-group{background-position:-18px 0;width:17px;height:13px}#firechat .icon.user-mute{background-position:-84px 0;width:13px;height:13px}#firechat .icon.user-mute.red{background-position:-102px 0;width:13px;height:13px}#firechat .icon:hover,#firechat .btn:hover>.icon{opacity:.6}#firechat a>.icon{margin:3px 1px}
\ No newline at end of file
diff --git a/dist/0.1.5/firechat-default.min.js b/dist/0.1.5/firechat-default.min.js
new file mode 100644
index 0000000..ab710ac
--- /dev/null
+++ b/dist/0.1.5/firechat-default.min.js
@@ -0,0 +1,2 @@
+(function(){var e=this,t=e._,n={},a=Array.prototype,i=Object.prototype,r=Function.prototype,s=a.push,o=a.slice,c=a.concat,l=i.toString,u=i.hasOwnProperty,d=a.forEach,h=a.map,p=a.reduce,f=a.reduceRight,m=a.filter,v=a.every,_=a.some,g=a.indexOf,b=a.lastIndexOf,y=Array.isArray,w=Object.keys,x=r.bind,R=function(e){return e instanceof R?e:this instanceof R?(this._wrapped=e,void 0):new R(e)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=R),exports._=R):e._=R,R.VERSION="1.4.4";var j=R.each=R.forEach=function(e,t,a){if(null!=e)if(d&&e.forEach===d)e.forEach(t,a);else if(e.length===+e.length){for(var i=0,r=e.length;r>i;i++)if(t.call(a,e[i],i,e)===n)return}else for(var s in e)if(R.has(e,s)&&t.call(a,e[s],s,e)===n)return};R.map=R.collect=function(e,t,n){var a=[];return null==e?a:h&&e.map===h?e.map(t,n):(j(e,function(e,i,r){a[a.length]=t.call(n,e,i,r)}),a)};var I="Reduce of empty array with no initial value";R.reduce=R.foldl=R.inject=function(e,t,n,a){var i=arguments.length>2;if(null==e&&(e=[]),p&&e.reduce===p)return a&&(t=R.bind(t,a)),i?e.reduce(t,n):e.reduce(t);if(j(e,function(e,r,s){i?n=t.call(a,n,e,r,s):(n=e,i=!0)}),!i)throw new TypeError(I);return n},R.reduceRight=R.foldr=function(e,t,n,a){var i=arguments.length>2;if(null==e&&(e=[]),f&&e.reduceRight===f)return a&&(t=R.bind(t,a)),i?e.reduceRight(t,n):e.reduceRight(t);var r=e.length;if(r!==+r){var s=R.keys(e);r=s.length}if(j(e,function(o,c,l){c=s?s[--r]:--r,i?n=t.call(a,n,e[c],c,l):(n=e[c],i=!0)}),!i)throw new TypeError(I);return n},R.find=R.detect=function(e,t,n){var a;return k(e,function(e,i,r){return t.call(n,e,i,r)?(a=e,!0):void 0}),a},R.filter=R.select=function(e,t,n){var a=[];return null==e?a:m&&e.filter===m?e.filter(t,n):(j(e,function(e,i,r){t.call(n,e,i,r)&&(a[a.length]=e)}),a)},R.reject=function(e,t,n){return R.filter(e,function(e,a,i){return!t.call(n,e,a,i)},n)},R.every=R.all=function(e,t,a){t||(t=R.identity);var i=!0;return null==e?i:v&&e.every===v?e.every(t,a):(j(e,function(e,r,s){return(i=i&&t.call(a,e,r,s))?void 0:n}),!!i)};var k=R.some=R.any=function(e,t,a){t||(t=R.identity);var i=!1;return null==e?i:_&&e.some===_?e.some(t,a):(j(e,function(e,r,s){return i||(i=t.call(a,e,r,s))?n:void 0}),!!i)};R.contains=R.include=function(e,t){return null==e?!1:g&&e.indexOf===g?-1!=e.indexOf(t):k(e,function(e){return e===t})},R.invoke=function(e,t){var n=o.call(arguments,2),a=R.isFunction(t);return R.map(e,function(e){return(a?t:e[t]).apply(e,n)})},R.pluck=function(e,t){return R.map(e,function(e){return e[t]})},R.where=function(e,t,n){return R.isEmpty(t)?n?null:[]:R[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},R.findWhere=function(e,t){return R.where(e,t,!0)},R.max=function(e,t,n){if(!t&&R.isArray(e)&&e[0]===+e[0]&&65535>e.length)return Math.max.apply(Math,e);if(!t&&R.isEmpty(e))return-1/0;var a={computed:-1/0,value:-1/0};return j(e,function(e,i,r){var s=t?t.call(n,e,i,r):e;s>=a.computed&&(a={value:e,computed:s})}),a.value},R.min=function(e,t,n){if(!t&&R.isArray(e)&&e[0]===+e[0]&&65535>e.length)return Math.min.apply(Math,e);if(!t&&R.isEmpty(e))return 1/0;var a={computed:1/0,value:1/0};return j(e,function(e,i,r){var s=t?t.call(n,e,i,r):e;a.computed>s&&(a={value:e,computed:s})}),a.value},R.shuffle=function(e){var t,n=0,a=[];return j(e,function(e){t=R.random(n++),a[n-1]=a[t],a[t]=e}),a};var T=function(e){return R.isFunction(e)?e:function(t){return t[e]}};R.sortBy=function(e,t,n){var a=T(t);return R.pluck(R.map(e,function(e,t,i){return{value:e,index:t,criteria:a.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,a=t.criteria;if(n!==a){if(n>a||void 0===n)return 1;if(a>n||void 0===a)return-1}return e.index<t.index?-1:1}),"value")};var F=function(e,t,n,a){var i={},r=T(t||R.identity);return j(e,function(t,s){var o=r.call(n,t,s,e);a(i,o,t)}),i};R.groupBy=function(e,t,n){return F(e,t,n,function(e,t,n){(R.has(e,t)?e[t]:e[t]=[]).push(n)})},R.countBy=function(e,t,n){return F(e,t,n,function(e,t){R.has(e,t)||(e[t]=0),e[t]++})},R.sortedIndex=function(e,t,n,a){n=null==n?R.identity:T(n);for(var i=n.call(a,t),r=0,s=e.length;s>r;){var o=r+s>>>1;i>n.call(a,e[o])?r=o+1:s=o}return r},R.toArray=function(e){return e?R.isArray(e)?o.call(e):e.length===+e.length?R.map(e,R.identity):R.values(e):[]},R.size=function(e){return null==e?0:e.length===+e.length?e.length:R.keys(e).length},R.first=R.head=R.take=function(e,t,n){return null==e?void 0:null==t||n?e[0]:o.call(e,0,t)},R.initial=function(e,t,n){return o.call(e,0,e.length-(null==t||n?1:t))},R.last=function(e,t,n){return null==e?void 0:null==t||n?e[e.length-1]:o.call(e,Math.max(e.length-t,0))},R.rest=R.tail=R.drop=function(e,t,n){return o.call(e,null==t||n?1:t)},R.compact=function(e){return R.filter(e,R.identity)};var U=function(e,t,n){return j(e,function(e){R.isArray(e)?t?s.apply(n,e):U(e,t,n):n.push(e)}),n};R.flatten=function(e,t){return U(e,t,[])},R.without=function(e){return R.difference(e,o.call(arguments,1))},R.uniq=R.unique=function(e,t,n,a){R.isFunction(t)&&(a=n,n=t,t=!1);var i=n?R.map(e,n,a):e,r=[],s=[];return j(i,function(n,a){(t?a&&s[s.length-1]===n:R.contains(s,n))||(s.push(n),r.push(e[a]))}),r},R.union=function(){return R.uniq(c.apply(a,arguments))},R.intersection=function(e){var t=o.call(arguments,1);return R.filter(R.uniq(e),function(e){return R.every(t,function(t){return R.indexOf(t,e)>=0})})},R.difference=function(e){var t=c.apply(a,o.call(arguments,1));return R.filter(e,function(e){return!R.contains(t,e)})},R.zip=function(){for(var e=o.call(arguments),t=R.max(R.pluck(e,"length")),n=Array(t),a=0;t>a;a++)n[a]=R.pluck(e,""+a);return n},R.object=function(e,t){if(null==e)return{};for(var n={},a=0,i=e.length;i>a;a++)t?n[e[a]]=t[a]:n[e[a][0]]=e[a][1];return n},R.indexOf=function(e,t,n){if(null==e)return-1;var a=0,i=e.length;if(n){if("number"!=typeof n)return a=R.sortedIndex(e,t),e[a]===t?a:-1;a=0>n?Math.max(0,i+n):n}if(g&&e.indexOf===g)return e.indexOf(t,n);for(;i>a;a++)if(e[a]===t)return a;return-1},R.lastIndexOf=function(e,t,n){if(null==e)return-1;var a=null!=n;if(b&&e.lastIndexOf===b)return a?e.lastIndexOf(t,n):e.lastIndexOf(t);for(var i=a?n:e.length;i--;)if(e[i]===t)return i;return-1},R.range=function(e,t,n){1>=arguments.length&&(t=e||0,e=0),n=arguments[2]||1;for(var a=Math.max(Math.ceil((t-e)/n),0),i=0,r=Array(a);a>i;)r[i++]=e,e+=n;return r},R.bind=function(e,t){if(e.bind===x&&x)return x.apply(e,o.call(arguments,1));var n=o.call(arguments,2);return function(){return e.apply(t,n.concat(o.call(arguments)))}},R.partial=function(e){var t=o.call(arguments,1);return function(){return e.apply(this,t.concat(o.call(arguments)))}},R.bindAll=function(e){var t=o.call(arguments,1);return 0===t.length&&(t=R.functions(e)),j(t,function(t){e[t]=R.bind(e[t],e)}),e},R.memoize=function(e,t){var n={};return t||(t=R.identity),function(){var a=t.apply(this,arguments);return R.has(n,a)?n[a]:n[a]=e.apply(this,arguments)}},R.delay=function(e,t){var n=o.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},R.defer=function(e){return R.delay.apply(R,[e,1].concat(o.call(arguments,1)))},R.throttle=function(e,t){var n,a,i,r,s=0,o=function(){s=new Date,i=null,r=e.apply(n,a)};return function(){var c=new Date,l=t-(c-s);return n=this,a=arguments,0>=l?(clearTimeout(i),i=null,s=c,r=e.apply(n,a)):i||(i=setTimeout(o,l)),r}},R.debounce=function(e,t,n){var a,i;return function(){var r=this,s=arguments,o=function(){a=null,n||(i=e.apply(r,s))},c=n&&!a;return clearTimeout(a),a=setTimeout(o,t),c&&(i=e.apply(r,s)),i}},R.once=function(e){var t,n=!1;return function(){return n?t:(n=!0,t=e.apply(this,arguments),e=null,t)}},R.wrap=function(e,t){return function(){var n=[e];return s.apply(n,arguments),t.apply(this,n)}},R.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},R.after=function(e,t){return 0>=e?t():function(){return 1>--e?t.apply(this,arguments):void 0}},R.keys=w||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)R.has(e,n)&&(t[t.length]=n);return t},R.values=function(e){var t=[];for(var n in e)R.has(e,n)&&t.push(e[n]);return t},R.pairs=function(e){var t=[];for(var n in e)R.has(e,n)&&t.push([n,e[n]]);return t},R.invert=function(e){var t={};for(var n in e)R.has(e,n)&&(t[e[n]]=n);return t},R.functions=R.methods=function(e){var t=[];for(var n in e)R.isFunction(e[n])&&t.push(n);return t.sort()},R.extend=function(e){return j(o.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},R.pick=function(e){var t={},n=c.apply(a,o.call(arguments,1));return j(n,function(n){n in e&&(t[n]=e[n])}),t},R.omit=function(e){var t={},n=c.apply(a,o.call(arguments,1));for(var i in e)R.contains(n,i)||(t[i]=e[i]);return t},R.defaults=function(e){return j(o.call(arguments,1),function(t){if(t)for(var n in t)null==e[n]&&(e[n]=t[n])}),e},R.clone=function(e){return R.isObject(e)?R.isArray(e)?e.slice():R.extend({},e):e},R.tap=function(e,t){return t(e),e};var M=function(e,t,n,a){if(e===t)return 0!==e||1/e==1/t;if(null==e||null==t)return e===t;e instanceof R&&(e=e._wrapped),t instanceof R&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==t+"";case"[object Number]":return e!=+e?t!=+t:0==e?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("object"!=typeof e||"object"!=typeof t)return!1;for(var r=n.length;r--;)if(n[r]==e)return a[r]==t;n.push(e),a.push(t);var s=0,o=!0;if("[object Array]"==i){if(s=e.length,o=s==t.length)for(;s--&&(o=M(e[s],t[s],n,a)););}else{var c=e.constructor,u=t.constructor;if(c!==u&&!(R.isFunction(c)&&c instanceof c&&R.isFunction(u)&&u instanceof u))return!1;for(var d in e)if(R.has(e,d)&&(s++,!(o=R.has(t,d)&&M(e[d],t[d],n,a))))break;if(o){for(d in t)if(R.has(t,d)&&!s--)break;o=!s}}return n.pop(),a.pop(),o};R.isEqual=function(e,t){return M(e,t,[],[])},R.isEmpty=function(e){if(null==e)return!0;if(R.isArray(e)||R.isString(e))return 0===e.length;for(var t in e)if(R.has(e,t))return!1;return!0},R.isElement=function(e){return!(!e||1!==e.nodeType)},R.isArray=y||function(e){return"[object Array]"==l.call(e)},R.isObject=function(e){return e===Object(e)},j(["Arguments","Function","String","Number","Date","RegExp"],function(e){R["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),R.isArguments(arguments)||(R.isArguments=function(e){return!(!e||!R.has(e,"callee"))}),true&&(R.isFunction=function(e){return"function"==typeof e}),R.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},R.isNaN=function(e){return R.isNumber(e)&&e!=+e},R.isBoolean=function(e){return e===!0||e===!1||"[object Boolean]"==l.call(e)},R.isNull=function(e){return null===e},R.isUndefined=function(e){return void 0===e},R.has=function(e,t){return u.call(e,t)},R.noConflict=function(){return e._=t,this},R.identity=function(e){return e},R.times=function(e,t,n){for(var a=Array(e),i=0;e>i;i++)a[i]=t.call(n,i);return a},R.random=function(e,t){return null==t&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var C={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};C.unescape=R.invert(C.escape);var D={escape:RegExp("["+R.keys(C.escape).join("")+"]","g"),unescape:RegExp("("+R.keys(C.unescape).join("|")+")","g")};R.each(["escape","unescape"],function(e){R[e]=function(t){return null==t?"":(""+t).replace(D[e],function(t){return C[e][t]})}}),R.result=function(e,t){if(null==e)return null;var n=e[t];return R.isFunction(n)?n.call(e):n},R.mixin=function(e){j(R.functions(e),function(t){var n=R[t]=e[t];R.prototype[t]=function(){var e=[this._wrapped];return s.apply(e,arguments),$.call(this,n.apply(R,e))}})};var E=0;R.uniqueId=function(e){var t=++E+"";return e?e+t:t},R.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var A=/(.)^/,L={"'":"'","\\":"\\","\r":"r","\n":"n","	":"t","\u2028":"u2028","\u2029":"u2029"},N=/\\|'|\r|\n|\t|\u2028|\u2029/g;R.template=function(e,t,n){var a;n=R.defaults({},n,R.templateSettings);var i=RegExp([(n.escape||A).source,(n.interpolate||A).source,(n.evaluate||A).source].join("|")+"|$","g"),r=0,s="__p+='";e.replace(i,function(t,n,a,i,o){return s+=e.slice(r,o).replace(N,function(e){return"\\"+L[e]}),n&&(s+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),a&&(s+="'+\n((__t=("+a+"))==null?'':__t)+\n'"),i&&(s+="';\n"+i+"\n__p+='"),r=o+t.length,t}),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{a=Function(n.variable||"obj","_",s)}catch(o){throw o.source=s,o}if(t)return a(t,R);var c=function(e){return a.call(this,e,R)};return c.source="function("+(n.variable||"obj")+"){\n"+s+"}",c},R.chain=function(e){return R(e).chain()};var $=function(e){return this._chain?R(e).chain():e};R.mixin(R),j(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=a[e];R.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),"shift"!=e&&"splice"!=e||0!==n.length||delete n[0],$.call(this,n)}}),j(["concat","join","slice"],function(e){var t=a[e];R.prototype[e]=function(){return $.call(this,t.apply(this._wrapped,arguments))}}),R.extend(R.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),this.FirechatDefaultTemplates=this.FirechatDefaultTemplates||{},this.FirechatDefaultTemplates["templates/layout-full.html"]=function(obj){obj||(obj={});var __p="";with(_.escape,obj)__p+="<div id='firechat' class='full'>\n<div id='firechat-header' class='clearfix'>\n<div class='clearfix'><div class='half dropdown' style=''>\n<a id='firechat-btn-rooms' class='dropdown-toggle btn full' data-toggle=\"dropdown\" href='#'>\n<span class='icon user-chat'></span>\nChat Rooms\n<span class='caret'></span>\n</a>\n<div class='dropdown-menu full' role='menu'><ul id='firechat-room-list'></ul><div class='dropdown-footer aligncenter'>\n<button type='button' class='btn twothird center' id='firechat-btn-create-room-prompt'>Create Room</button>\n</div></div></div>\n<div class='half dropdown' style=''>\n<a data-event='firechat-user-search-btn' class='btn full dropdown-toggle' data-toggle=\"dropdown\" href='#'>\n<span class='icon user-group'></span>\nVisitors\n<span class='caret'></span>\n</a>\n<div class='dropdown-menu' role='menu'>\n<div class='dropdown-header aligncenter clearfix'>\n<div class='search-wrapper'>\n<span class='icon search'></span>\n<input type='text' data-event='firechat-user-search' data-template='templates/user-search-list-item.html' data-target='firechat-user-search' data-controls='firechat-user-search-controls' class='center fivesixth'>\n</div>\n</div>\n<ul id='firechat-user-search'></ul><div class='dropdown-footer aligncenter clearfix'>\n<div id='firechat-user-search-controls' class='clearfix'>\n<span class=\"quarter\"></span>\n<button type='button' class='btn half' data-event='firechat-user-search' data-toggle='firechat-pagination-next' data-template='templates/user-search-list-item.html' data-target='firechat-user-search' data-controls='firechat-user-search-controls' disabled=disabled>Next</button>\n</div><label class='center full'>\n<small>Use \"+ Invite\" button within chat rooms for regular invites.</small>\n</label>\n</div>\n</div>\n</div>\n</div>\n</div>\n<div id='firechat-tabs' class='clearfix'>\n<ul id='firechat-tab-list' class='nav nav-tabs clearfix'></ul>\n<div id='firechat-tab-content' class='tab-content'></div>\n</div><div id='firechat-footer' class='clearfix'></div>\n</div>";return __p},this.FirechatDefaultTemplates["templates/layout-popout.html"]=function(obj){obj||(obj={});var __p="";with(_.escape,obj)__p+="<div id='firechat' class='full'>\n<div id='firechat-tabs' class='clearfix'>\n<ul id='firechat-tab-list' class='nav nav-tabs clearfix'></ul>\n<div id='firechat-tab-content' class='tab-content'></div>\n</div>\n</div>";return __p},this.FirechatDefaultTemplates["templates/message-context-menu.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(Array.prototype.join,obj)__p+="<div data-toggle='firechat-contextmenu' class='contextmenu' data-message-id='"+__e(id)+"'>\n<ul>\n<li><a href='#!' data-event='firechat-user-warn'>Warn User</a></li>\n",allowKick&&(__p+="\n<li><a href='#!' data-event='firechat-user-kick'>Kick User</a></li>\n"),__p+="\n<li><a href='#!' data-event='firechat-user-suspend-hour'>Suspend User (1 Hour)</a></li>\n<li><a href='#!' data-event='firechat-user-suspend-day'>Suspend User (1 Day)</a></li>\n<li><a href='#!' data-event='firechat-message-delete'>Delete Message</a></li>\n</ul>\n</div>";return __p},this.FirechatDefaultTemplates["templates/message.html"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;with(Array.prototype.join,obj)__p+="<div class='message message-"+__e(type)+" ",isSelfMessage&&(__p+=" message-self "),__p+="' data-message-id='"+__e(id)+"' data-user-id='"+__e(userId)+"' data-user-name='"+__e(name)+"' data-class=\"firechat-message\">\n<div class='clearfix'>\n<label class='fourfifth'>\n<strong class='name' title='"+__e(name)+"'>"+__e(name)+"</strong>\n<em>("+__e(localtime)+")</em>:\n</label>",disableActions||(__p+="\n<label class='fifth alignright'>\n<a href='#!' data-event='firechat-user-chat' class='icon user-chat' title='Invite to Private Chat'>&nbsp;</a>\n<a href='#!' data-event='firechat-user-mute-toggle' class='icon user-mute' title='Mute User'>&nbsp;</a>\n</label>\n"),__p+="</div>\n<div class='clearfix message-content'>\n"+(null==(__t=message)?"":__t)+"\n</div>\n</div>";return __p},this.FirechatDefaultTemplates["templates/prompt-alert.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="<div class='aligncenter clearfix'>\n<h6>"+__e(message)+"</h6>\n<p class='clearfix'>\n<button type='button' class='btn quarter right close'>Close</button>\n</p>\n</div>";return __p},this.FirechatDefaultTemplates["templates/prompt-create-room.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="<div class='clearfix'>\n<h6>Give your chat room a name:</h6>\n<input data-input='firechat-room-name' type='text' placeholder='Room name...' style='margin-bottom: 5px;' maxlength='"+__e(maxLengthRoomName)+"'>\n</div>";return __p},this.FirechatDefaultTemplates["templates/prompt-invitation.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="<div class='aligncenter clearfix'>\n<h5>"+__e(fromUserName)+"</h5>\n<p>invited you to join</p>\n<h5>"+__e(toRoomName)+"</h5>\n<p class='clearfix'>\n<button data-toggle='accept' type='button' class='btn'>Accept</button>\n<button data-toggle='decline' type='button' class='btn'>Decline</button>\n</p>\n</div>";return __p},this.FirechatDefaultTemplates["templates/prompt-invite-private.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="<div class='aligncenter clearfix'>\n<h6>Invite <strong>"+__e(userName)+"</strong> to "+__e(roomName)+"?</h6>\n<p class='clearfix'>\n<button data-toggle='accept' type='button' class='btn'>Invite</button>\n<button data-toggle='decline' type='button' class='close btn'>Cancel</button>\n</p>\n</div>";return __p},this.FirechatDefaultTemplates["templates/prompt-invite-reply.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(Array.prototype.join,obj)__p+="<div class='aligncenter clearfix'>\n<h5>"+__e(toUserName)+"</h5>\n<p>\n",__p+="accepted"===status?" accepted your invite. ":" declined your invite. ",__p+="\n</p>\n</div>";return __p},this.FirechatDefaultTemplates["templates/prompt-user-mute.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="<div class='aligncenter clearfix'>\n<h5>"+__e(userName)+"</h5>\n<p class='clearfix'>\n<button data-toggle='accept' type='button' class='btn'>Mute</button>\n<button data-toggle='decline' type='button' class='btn'>Cancel</button>\n</p>\n</div>";return __p},this.FirechatDefaultTemplates["templates/prompt.html"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;with(obj)__p+="<div class='prompt hidden'>\n<div class='prompt-header'>\n"+__e(title)+"\n<a href='#!' class='close right'>X</a>\n</div>\n<div class='prompt-body clearfix'>\n"+(null==(__t=content)?"":__t)+"\n</div>\n<div class='prompt-footer'></div>\n</div>";return __p},this.FirechatDefaultTemplates["templates/room-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(Array.prototype.join,obj)__p+="<li data-room-type='"+__e(type)+"' data-room-id='"+__e(id)+"' data-room-name='"+__e(name)+"'>\n<a href='#!' class='clearfix ",isRoomOpen&&(__p+=" highlight "),__p+="'>\n<span class='left' title='"+__e(name)+"'>"+__e(name)+"</span>\n</a>\n</li>";return __p},this.FirechatDefaultTemplates["templates/room-user-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(Array.prototype.join,obj)__p+="<li data-user-id='"+__e(id)+"' data-user-name='"+__e(name)+"'>\n<a href='#!' class='clearfix'>\n<span class='left twothird clipped' title='"+__e(name)+"'>"+__e(name)+"</span>",disableActions||(__p+="\n<span data-event='firechat-user-mute-toggle' class='icon user-mute right ",isMuted&&(__p+=" red "),__p+="' title='Toggle User Mute'>&nbsp;</span>\n<span data-event='firechat-user-chat' class='icon user-chat right' title='Invite to Private Chat'>&nbsp;</span>\n"),__p+="\n</a>\n</li>";return __p},this.FirechatDefaultTemplates["templates/room-user-search-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(Array.prototype.join,obj)__p+="<li data-user-id='"+__e(id)+"' data-user-name='"+__e(name)+"'>\n<a href='#!' class='clearfix'>\n",__p+=disableActions?"\n<span class='left fourfifth clipped' title='"+__e(name)+"'>"+__e(name)+"</span>\n":"\n<span data-event='firechat-user-invite' class='left fourfifth clipped' title='"+__e(name)+"'>"+__e(name)+"</span>\n<span data-event='firechat-user-invite' class='icon plus right' title='Invite to Room'>+</span>\n",__p+="\n</a>\n</li>";return __p},this.FirechatDefaultTemplates["templates/tab-content.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="<div id='"+__e(id)+"' data-room-id='"+__e(id)+"' class='tab-pane'>\n<div class='tab-pane-menu clearfix'><div class='dropdown twofifth'>\n<a data-event='firechat-user-room-list-btn' class='full btn dropdown-toggle' data-toggle=\"dropdown\" href='#' data-target='firechat-room-user-list-"+__e(id)+"'>\n<span class='icon user-group'></span>\nIn Room\n<span class='caret'></span>\n</a>\n<div class='dropdown-menu' role='menu'>\n<ul id='firechat-room-user-list-"+__e(id)+"' class='full'></ul>\n</div>\n</div><div class='dropdown twofifth'>\n<a data-event='firechat-user-search-btn' class='full btn dropdown-toggle' data-toggle=\"dropdown\" href='#'>\n<span class='icon plus'>+</span>\nInvite\n<span class='caret'></span>\n</a><div class='dropdown-menu' role='menu'>\n<div class='dropdown-header aligncenter clearfix'>\n<div class='search-wrapper'>\n<span class='icon search'></span>\n<input type='text' data-event='firechat-user-search' data-template='templates/room-user-search-list-item.html' data-target='firechat-room-user-search-"+__e(id)+"' data-controls='firechat-room-user-search-controls-"+__e(id)+"' class='center fivesixth'>\n</div>\n</div>\n<ul id='firechat-room-user-search-"+__e(id)+"'></ul><div class='dropdown-footer aligncenter clearfix'>\n<div id='firechat-room-user-search-controls-"+__e(id)+"' class='clearfix'><span class=\"quarter\"></span>\n<!--\n<button type='button' class='btn third disabled' data-event='firechat-user-search' data-template='templates/room-user-search-list-item.html' data-target='firechat-room-user-search-"+__e(id)+"' data-controls='firechat-room-user-search-controls-"+__e(id)+"' data-toggle='firechat-pagination-prev' disabled=disabled>Prev</button>\n-->\n<button type='button' class='btn half disabled' data-event='firechat-user-search' data-template='templates/room-user-search-list-item.html' data-target='firechat-room-user-search-"+__e(id)+"' data-controls='firechat-room-user-search-controls-"+__e(id)+"' data-toggle='firechat-pagination-next'  disabled=disabled>Next</button>\n</div>\n</div>\n</div>\n</div><a href='#!' data-event='firechat-close-tab' class='icon close right' style='15px 5px' title='Leave Room'></a></div><div class='clearfix'>\n<div id='firechat-messages"+__e(id)+"' class='chat'></div>\n</div><div class='clearfix'>\n<label>Your message:</label>\n<textarea id='textarea"+__e(id)+"' placeholder='Type your message here...'></textarea>\n</div>\n</div>";return __p},this.FirechatDefaultTemplates["templates/tab-menu-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="<li data-room-id='"+__e(id)+"'>\n<a href='#"+__e(id)+"' data-toggle='tab' title='"+__e(name)+"'>"+__e(name)+"</a>\n</li>";return __p},this.FirechatDefaultTemplates["templates/user-search-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(Array.prototype.join,obj)__p+="<li data-user-id='"+__e(id)+"' data-user-name='"+__e(name)+"'>\n<a href='#!' class='clearfix'>\n",__p+=disableActions?"\n<span class='left fivesixth clipped' title='"+__e(name)+"'>"+__e(name)+"</span>\n":"\n<span data-event='firechat-user-chat' class='left fivesixth clipped' title='"+__e(name)+"'>"+__e(name)+"</span>\n<span data-event='firechat-user-chat' class='icon user-chat right' title='Invite to Private Chat'>&nbsp;</span>\n",__p+="\n</a>\n</li>";return __p},function(){Function.prototype.bind||(Function.prototype.bind=function(e){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var t=Array.prototype.slice.call(arguments,1),n=this,a=function(){},i=function(){return n.apply(this instanceof a&&e?this:e,t.concat(Array.prototype.slice.call(arguments)))};return a.prototype=this.prototype,i.prototype=new a,i}),Object.keys=Object.keys||function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(n);return t}}(),function(e){function t(e,t){this._firebase=e,this._user=null,this._userId=null,this._userName=null,this._isModerator=!1,this._sessionId=null,this._events={},this._rooms={},this._presenceBits={},this._userRef=null,this._messageRef=this._firebase.child("room-messages"),this._roomRef=this._firebase.child("room-metadata"),this._privateRoomRef=this._firebase.child("room-private-metadata"),this._moderatorsRef=this._firebase.child("moderators"),this._suspensionsRef=this._firebase.child("suspensions"),this._usersOnlineRef=this._firebase.child("user-names-online"),this._options=t||{},this._options.numMaxMessages=this._options.numMaxMessages||50}var n=this,a=n.Firechat;t.noConflict=function(){return n.Firechat=a,t},n.Firechat=t,t.prototype={_loadUserMetadata:function(e){var t=this;this._userRef.transaction(function(e){return e&&e.id&&e.name?void 0:{id:t._userId,name:t._userName}},function(a,i,r){t._user=r.val(),t._moderatorsRef.child(t._userId).once("value",function(a){t._isModerator=!!a.val(),n.setTimeout(e,0)})})},_setupDataEvents:function(){this._firebase.root().child(".info/connected").on("value",function(e){if(e.val()===!0)for(var t=0;this._presenceBits>t;t++){var n=this._presenceBits[t],a=this._firebase.root().child(n.ref);a.onDisconnect().set(n.offlineValue),a.set(n.onlineValue)}},this);var e=this._userRef.child("sessions").push();this._sessionId=e.name(),this._queuePresenceOperation(e,!0,null);var t=this._usersOnlineRef.child(this._userName.toLowerCase()),n=t.child(this._sessionId);this._queuePresenceOperation(n,{id:this._userId,name:this._userName},null),this._userRef.on("value",this._onUpdateUser,this),this._userRef.child("invites").on("child_added",this._onFirechatInvite,this),this._userRef.child("notifications").on("child_added",this._onNotification,this)},_addEventCallback:function(e,t){this._events[e]=this._events[e]||[],this._events[e].push(t)},_getEventCallbacks:function(e){return this._events.hasOwnProperty(e)?this._events[e]:[]},_invokeEventCallbacks:function(e){var t=[],n=this._getEventCallbacks(e);Array.prototype.push.apply(t,arguments),t=t.slice(1);for(var a=0;n.length>a;a+=1)n[a].apply(null,t)},_queuePresenceOperation:function(e,t,n){e.onDisconnect().set(n),e.set(t),this._presenceBits[""+e]={ref:e,onlineValue:t,offlineValue:n}},_removePresenceOperation:function(t,n){var a=new e(t);a.onDisconnect().cancel(),a.set(n),delete this._presenceBits[t]},_onUpdateUser:function(e){this._user=e.val(),this._invokeEventCallbacks("user-update",this._user)},_onAuthRequired:function(){this._invokeEventCallbacks("auth-required")},_onEnterRoom:function(e){this._invokeEventCallbacks("room-enter",e)},_onNewMessage:function(e,t){var n=t.val();n.id=t.name(),this._invokeEventCallbacks("message-add",e,n)},_onRemoveMessage:function(e,t){var n=t.name();this._invokeEventCallbacks("message-remove",e,n)},_onLeaveRoom:function(e){this._invokeEventCallbacks("room-exit",e)},_onNotification:function(e){var t=e.val();t.read||(("suspension"!==t.notificationType||t.data.suspendedUntil<(new Date).getTime())&&e.ref().child("read").set(!0),this._invokeEventCallbacks("notification",t))},_onFirechatInvite:function(e){var t=this,n=e.val();n.status||(n.id=n.id||e.name(),t.getRoom(n.roomId,function(e){n.toRoomName=e.name,t._invokeEventCallbacks("room-invite",n)}))},_onFirechatInviteResponse:function(e){var t=e.val();t.id=t.id||e.name(),this._invokeEventCallbacks("room-invite-response",t)}},t.prototype.setUser=function(e,t,a){var i=this;i._firebase.root().child(".info/authenticated").on("value",function(r){r.val()===!0&&(i._firebase.root().child(".info/authenticated").off(),i._userId=""+e,i._userName=""+t,i._userRef=i._firebase.child("users").child(i._userId),i._loadUserMetadata(function(){n.setTimeout(function(){a(i._user),i._setupDataEvents()},0)}))})},t.prototype.resumeSession=function(){this._userRef.child("rooms").once("value",function(e){var t=e.val();for(var n in t)this.enterRoom(t[n].id)},function(){},this)},t.prototype.on=function(e,t){this._addEventCallback(e,t)},t.prototype.createRoom=function(t,n,a){var i=this,r=this._roomRef.push(),s={id:r.name(),name:t,type:n||"public",createdByUserId:this._userId,createdAt:e.ServerValue.TIMESTAMP};"private"===n&&(s.authorizedUsers={},s.authorizedUsers[this._userId]=!0),r.set(s,function(e){e||i.enterRoom(r.name()),a&&a(r.name())})},t.prototype.enterRoom=function(e){var t=this;t.getRoom(e,function(n){var a=n.name;if(e&&a&&!t._rooms[e]){if(t._rooms[e]=!0,t._user){t._userRef.child("rooms").child(e).set({id:e,name:a,active:!0});var i=t._firebase.child("room-users").child(e).child(t._userId).child(t._sessionId);t._queuePresenceOperation(i,{id:t._userId,name:t._userName},null)}t._onEnterRoom({id:e,name:a}),t._roomRef.child(e).once("value",function(){t._messageRef.child(e).limit(t._options.numMaxMessages).on("child_added",function(n){t._onNewMessage(e,n)},function(){t.leaveRoom(e)},t),t._messageRef.child(e).limit(t._options.numMaxMessages).on("child_removed",function(n){t._onRemoveMessage(e,n)},function(){},t)},function(){},t)}})},t.prototype.leaveRoom=function(e){var t=this,n=t._firebase.child("room-users").child(e);if(t._messageRef.child(e).off(),t._user){var a=n.child(t._userId).child(t._sessionId);t._removePresenceOperation(""+a,null),t._userRef.child("rooms").child(e).remove()}delete t._rooms[e],t._onLeaveRoom(e)},t.prototype.sendMessage=function(t,n,a,i){var r,s=this,o={userId:s._userId,name:s._userName,timestamp:e.ServerValue.TIMESTAMP,message:n,type:a||"default"};return s._user?(r=s._messageRef.child(t).push(),r.setWithPriority(o,e.ServerValue.TIMESTAMP,i),void 0):(s._onAuthRequired(),i&&i(Error("Not authenticated or user not set!")),void 0)},t.prototype.deleteMessage=function(e,t,n){var a=this;a._messageRef.child(e).child(t).remove(n)},t.prototype.toggleUserMute=function(e,t){var n=this;return n._user?(n._userRef.child("muted").child(e).transaction(function(e){return e?null:!0},t),void 0):(n._onAuthRequired(),t&&t(Error("Not authenticated or user not set!")),void 0)},t.prototype.sendSuperuserNotification=function(t,n,a,i){var r=this,s=r._firebase.child("users").child(t).child("notifications");
+s.push({fromUserId:r._userId,timestamp:e.ServerValue.TIMESTAMP,notificationType:n,data:a||{}},i)},t.prototype.warnUser=function(e){var t=this;t.sendSuperuserNotification(e,"warning")},t.prototype.suspendUser=function(e,t,n){var a=this,i=(new Date).getTime()+1e3*t;a._suspensionsRef.child(e).set(i,function(t){return t&&n?n(t):(a.sendSuperuserNotification(e,"suspension",{suspendedUntil:i}),n(null))})},t.prototype.inviteUser=function(e,t){var n=this,a=function(){var a=n._firebase.child("users").child(e).child("invites").push();a.set({id:a.name(),fromUserId:n._userId,fromUserName:n._userName,roomId:t}),a.on("value",n._onFirechatInviteResponse,function(){},n)};return n._user?(n.getRoom(t,function(i){if("private"===i.type){var r=n._roomRef.child(t).child("authorizedUsers");r.child(e).set(!0,function(e){e||a()})}else a()}),void 0):(n._onAuthRequired(),void 0)},t.prototype.acceptInvite=function(e,t){var n=this;n._userRef.child("invites").child(e).once("value",function(a){var i=a.val();return null===i&&t?t(Error("acceptInvite("+e+"): invalid invite id")):(n.enterRoom(i.roomId),n._userRef.child("invites").child(e).update({status:"accepted",toUserName:n._userName},t),void 0)},n)},t.prototype.declineInvite=function(e,t){var n=this,a={status:"declined",toUserName:n._userName};n._userRef.child("invites").child(e).update(a,t)},t.prototype.getRoomList=function(e){var t=this;t._roomRef.once("value",function(t){e(t.val())})},t.prototype.getUsersByRoom=function(){var e=this,t=arguments[0],a=e._firebase.child("room-users").child(t),i=arguments[arguments.length-1],r=null;arguments.length>2&&(r=arguments[1]),a=r?a.limit(r):a,a.once("value",function(e){var t=e.val()||{},a={};for(var r in t)for(var s in t[r]){a[r]=t[r][s];break}n.setTimeout(function(){i(a)},0)})},t.prototype.getUsersByPrefix=function(e,t,a,i,r){var s=this._usersOnlineRef,o=e.toLowerCase();s=t?s.startAt(null,t):a?s.endAt(null,a):o?s.startAt(null,o):s.startAt(),s=i?s.limit(i):s,s.once("value",function(t){var a=t.val()||{},i={};for(var s in a){var c,l,u=a[s];for(var d in u){c=u[d].name,l=u[d].id;break}e.length>0&&0!==c.toLowerCase().indexOf(o)||(i[c]={name:c,id:l})}n.setTimeout(function(){r(i)},0)})},t.prototype.getRoom=function(e,t){this._roomRef.child(e).once("value",function(e){t(e.val())})},t.prototype.userIsModerator=function(){return this._isModerator}}(Firebase),function(e){function t(t,n,a){if(!t)throw Error("FirechatUI: Missing required argument `firebaseRef`");if(!n)throw Error("FirechatUI: Missing required argument `el`");a=a||{},this._options=a,this._el=n,this._user=null,this._chat=new Firechat(t,a),this._roomQueue=[],this.maxLengthUsername=15,this.maxLengthUsernameDisplay=15,this.maxLengthRoomName=24,this.maxLengthMessage=120,this.maxUserSearchResults=100,this.urlPattern=/\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim,this.pseudoUrlPattern=/(^|[^\/])(www\.[\S]+(\b|$))/gim,this._renderLayout(),this.$wrapper=e("#firechat"),this.$roomList=e("#firechat-room-list"),this.$tabList=e("#firechat-tab-list"),this.$tabContent=e("#firechat-tab-content"),this.$messages={},this.$rateLimit={limitCount:10,limitInterval:1e4,limitWaitTime:3e4,history:{}},this._bindUIEvents(),this._bindDataEvents()}if(!e||170>parseInt(e().jquery.replace(/\./g,""),10))throw Error("jQuery 1.7 or later required!");var n=this,a=n.FirechatUI;if(n.FirechatUI=t,!self.FirechatDefaultTemplates)throw Error("Unable to find chat templates!");t.noConflict=function(){return n.FirechatUI=a,t},t.prototype={_bindUIEvents:function(){this._bindForHeightChange(),this._bindForTabControls(),this._bindForRoomList(),this._bindForUserRoomList(),this._bindForUserSearch(),this._bindForUserMuting(),this._bindForChatInvites(),this._bindForRoomListing(),this._setupTabs(),this._setupDropdowns(),this._bindTextInputFieldLimits()},_bindDataEvents:function(){this._chat.on("user-update",this._onUpdateUser.bind(this)),this._chat.on("room-enter",this._onEnterRoom.bind(this)),this._chat.on("room-exit",this._onLeaveRoom.bind(this)),this._chat.on("message-add",this._onNewMessage.bind(this)),this._chat.on("message-remove",this._onRemoveMessage.bind(this)),this._chat.on("room-invite",this._onChatInvite.bind(this)),this._chat.on("room-invite-response",this._onChatInviteResponse.bind(this)),this._chat.on("notification",this._onNotification.bind(this))},_renderLayout:function(){var t=FirechatDefaultTemplates["templates/layout-full.html"];e(this._el).html(t({maxLengthUsername:this.maxLengthUsername}))},_onUpdateUser:function(t){this._user=t;var n=this._user.muted||{};e('[data-event="firechat-user-mute-toggle"]').each(function(){var t=e(this).closest("[data-user-id]").data("user-id");e(this).toggleClass("red",!!n[t])});for(var a in n)e('.message[data-user-id="'+a+'"]').fadeOut()},_onEnterRoom:function(e){this.attachTab(e.id,e.name)},_onLeaveRoom:function(e){this.removeTab(e),this._roomQueue.length>0&&this._chat.enterRoom(this._roomQueue.shift(e))},_onNewMessage:function(e,t){var n=t.userId;this._user&&this._user.muted&&this._user.muted[n]||this.showMessage(e,t)},_onRemoveMessage:function(e,t){this.removeMessage(e,t)},_onChatInvite:function(e){var t=this,n=FirechatDefaultTemplates["templates/prompt-invitation.html"],a=this.prompt("Invite",n(e));a.find("a.close").click(function(){a.remove(),t._chat.declineInvite(e.id)}),a.find("[data-toggle=accept]").click(function(){a.remove(),t._chat.acceptInvite(e.id)}),a.find("[data-toggle=decline]").click(function(){a.remove(),t._chat.declineInvite(e.id)})},_onChatInviteResponse:function(e){if(e.status){var t,n=this,a=FirechatDefaultTemplates["templates/prompt-invite-reply.html"];e.status&&"accepted"===e.status?(t=this.prompt("Accepted",a(e)),this._chat.getRoom(e.roomId,function(t){n.attachTab(e.roomId,t.name)})):t=this.prompt("Declined",a(e)),t.find("a.close").click(function(){t.remove()})}},_onNotification:function(e){if("warning"===e.notificationType)this.renderAlertPrompt("Warning","You are being warned for inappropriate messaging. Further violation may result in temporary or permanent ban of service.");else if("suspension"===e.notificationType){var t=e.data.suspendedUntil,n=Math.round((t-(new Date).getTime())/1e3),a="";if(n>0){if(n>7200){var i=Math.floor(n/3600);a=i+" hours, ",n-=3600*i}a+=Math.floor(n/60)+" minutes",this.renderAlertPrompt("Suspended","A moderator has suspended you for violating site rules. You cannot send messages for another "+a+".")}}}},t.prototype.setUser=function(e,t){var n=this;n._chat.setUser(e,t,function(e){n._user=e,n._chat.userIsModerator()&&n._bindSuperuserUIEvents(),n._chat.resumeSession()})},t.prototype.on=function(e,t){this._chat.on(e,t)},t.prototype._bindSuperuserUIEvents=function(){var t=this,n=function(){var t=e(this),n=t.closest("[data-message-id]").data("message-id"),a=e('[data-message-id="'+n+'"]').closest("[data-user-id]").data("user-id"),i=e('[data-message-id="'+n+'"]').closest("[data-room-id]").data("room-id");return{messageId:n,userId:a,roomId:i}},a=function(){e('[data-toggle="firechat-contextmenu"]').each(function(){e(this).remove()}),e("#firechat .message.highlighted").each(function(){e(this).removeClass("highlighted")})},i=function(i){var r,s=e(this),o=s.closest("[data-message-id]"),c=FirechatDefaultTemplates["templates/message-context-menu.html"],l=n.call(this,i);i.preventDefault(),a(),s.addClass("highlighted"),t._chat.getRoom(l.roomId,function(){r=e(c({id:o.data("message-id")})),r.css({left:i.clientX,top:i.clientY}).appendTo(t.$wrapper)})};e(document).bind("click",{self:this},function(e){e.button&&2==e.button||a()}),e(document).delegate('[data-class="firechat-message"]',"contextmenu",i),e(document).delegate('[data-event="firechat-user-warn"]',"click",function(e){var a=n.call(this,e);t._chat.warnUser(a.userId)}),e(document).delegate('[data-event="firechat-user-suspend-hour"]',"click",function(e){var a=n.call(this,e);t._chat.suspendUser(a.userId,3600)}),e(document).delegate('[data-event="firechat-user-suspend-day"]',"click",function(e){var a=n.call(this,e);t._chat.suspendUser(a.userId,86400)}),e(document).delegate('[data-event="firechat-message-delete"]',"click",function(e){var a=n.call(this,e);t._chat.deleteMessage(a.roomId,a.messageId)})},t.prototype._bindForHeightChange=function(){var t=e(this._el),n=null;setInterval(function(){var a=t.height();a!=n&&(n=a,e(".chat").each(function(){}))},500)},t.prototype._bindForTabControls=function(){var t=this;e(document).delegate('[data-event="firechat-close-tab"]',"click",function(){var n=e(this).closest("[data-room-id]").data("room-id");t._chat.leaveRoom(n)})},t.prototype._bindForRoomList=function(){var t=this;e("#firechat-btn-rooms").bind("click",function(){if(!e(this).parent().hasClass("open")){var n=(e(this),FirechatDefaultTemplates["templates/room-list-item.html"]),a=function(){var n=e(this).parent(),a=n.data("room-id"),i=n.data("room-name");t.$messages[a]?t.focusTab(a):t._chat.enterRoom(a,i)};t._chat.getRoomList(function(i){t.$roomList.empty();for(var r in i){var s=i[r];if("public"==s.type){s.isRoomOpen=!!t.$messages[s.id];var o=e(n(s));o.children("a").bind("click",a),t.$roomList.append(o.toggle(!0))}}})}})},t.prototype._bindForUserRoomList=function(){var t=this;e(document).delegate('[data-event="firechat-user-room-list-btn"]',"click",function(n){n.stopPropagation();var a=e(this),i=a.closest("[data-room-id]").data("room-id"),r=FirechatDefaultTemplates["templates/room-user-list-item.html"],s=a.data("target"),o=e("#"+s);o.empty(),t._chat.getUsersByRoom(i,function(n){for(var a in n)user=n[a],user.disableActions=!t._user||user.id===t._user.id,user.nameTrimmed=t.trimWithEllipsis(user.name,t.maxLengthUsernameDisplay),user.isMuted=t._user&&t._user.muted&&t._user.muted[user.id],o.append(e(r(user)));t.sortListLexicographically("#"+s)})})},t.prototype._bindForUserSearch=function(){var t=this,n=function(t){var n=e(this),i=n.data("target"),r=n.data("controls"),s=n.data("template"),o=n.val()||n.data("prefix")||"",c=n.data("startAt")||null,l=n.data("endAt")||null;t.preventDefault(),a(i,s,r,o,c,l)},a=function(n,a,i,r,s,o){var c=e("#"+n),l=e("#"+i),u=FirechatDefaultTemplates[a];t._chat.getUsersByPrefix(r,s,o,t.maxUserSearchResults,function(e){var n,a,i,s,o,d=0;c.empty();for(i in e){var h=e[i];if(h.disableActions=!t._user||h.id===t._user.id,d+=1,c.append(u(h)),1===d)s=h.name.toLowerCase();else if(d>=t.maxUserSearchResults){o=h.name.toLowerCase();break}}l&&(n=l.find('[data-toggle="firechat-pagination-prev"]'),a=l.find('[data-toggle="firechat-pagination-next"]'),o?a.data("event","firechat-user-search").data("startAt",o).data("prefix",r).removeClass("disabled").removeAttr("disabled"):a.data("event",null).data("startAt",null).data("prefix",null).addClass("disabled").attr("disabled","disabled"))})};e(document).delegate('[data-event="firechat-user-search"]',"keyup",n),e(document).delegate('[data-event="firechat-user-search"]',"click",n),e(document).delegate('[data-event="firechat-user-search-btn"]',"click",function(t){t.stopPropagation();var n=e(this).next("div.dropdown-menu").find("input");n.focus(),n.trigger(jQuery.Event("keyup"))}),e(document).delegate('[data-event="firechat-user-search"]',"click",function(e){e.stopPropagation()})},t.prototype._bindForUserMuting=function(){var t=this;e(document).delegate('[data-event="firechat-user-mute-toggle"]',"click",function(n){var a=e(this),i=a.closest("[data-user-id]").data("user-id"),r=a.closest("[data-user-name]").data("user-name"),s=a.hasClass("red"),o=FirechatDefaultTemplates["templates/prompt-user-mute.html"];if(n.preventDefault(),s)t._chat.toggleUserMute(i);else{var c=t.prompt("Mute User?",o({userName:r}));c.find("a.close").first().click(function(){c.remove()}),c.find("[data-toggle=decline]").first().click(function(){c.remove()}),c.find("[data-toggle=accept]").first().click(function(){t._chat.toggleUserMute(i),c.remove()})}})},t.prototype._bindForChatInvites=function(){var t=this,n=function(){var n,a=e(this),i=a.closest("[data-user-id]").data("user-id"),r=a.closest("[data-room-id]").data("room-id"),s=a.closest("[data-user-name]").data("user-name"),o=FirechatDefaultTemplates["templates/prompt-invite-private.html"];t._chat.getRoom(r,function(e){n=t.prompt("Invite",o({userName:s,roomName:e.name})),n.find("a.close").click(function(){n.remove()}),n.find("[data-toggle=decline]").click(function(){n.remove()}),n.find("[data-toggle=accept]").first().click(function(){n.remove(),t._chat.inviteUser(i,r,e.name)})})},a=function(){var n,a=e(this),i=a.closest("[data-user-id]").data("user-id"),r=a.closest("[data-user-name]").data("user-name"),s=FirechatDefaultTemplates["templates/prompt-invite-private.html"];i&&r&&(n=t.prompt("Private Invite",s({userName:r,roomName:"Private Chat"})),n.find("a.close").click(function(){n.remove()}),n.find("[data-toggle=decline]").click(function(){n.remove()}),n.find("[data-toggle=accept]").first().click(function(){n.remove();var e="Private Chat";t._chat.createRoom(e,"private",function(n){t._chat.inviteUser(i,n,e)})}))};e(document).delegate('[data-event="firechat-user-chat"]',"click",a),e(document).delegate('[data-event="firechat-user-invite"]',"click",n)},t.prototype._bindForRoomListing=function(){var t=this,n=e("#firechat-btn-create-room-prompt"),a=e("#firechat-btn-create-room");n.bind("click",function(){t.promptCreateRoom()}),a.bind("click",function(){var n=e("#firechat-input-room-name").val();e("#firechat-prompt-create-room").remove(),t._chat.createRoom(n)})},t.prototype._setupTabs=function(){var t=function(t){var a,i,r=t,s=r.closest("ul:not(.dropdown-menu)"),o=r.attr("data-target"),c=s.find(".active:last a")[0];o||(o=r.attr("href"),o=o&&o.replace(/.*(?=#[^\s]*$)/,"")),r.parent("li").hasClass("active")||(i=e.Event("show",{relatedTarget:c}),r.trigger(i),i.isDefaultPrevented()||(a=e(o),n(r.parent("li"),s),n(a,a.parent(),function(){r.trigger({type:"shown",relatedTarget:c})})))},n=function(t,n,a){function i(){r.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?t.addClass("in"):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),a&&a()}var r=n.find("> .active"),s=a&&e.support.transition&&r.hasClass("fade");s?r.one(e.support.transition.end,i):i(),r.removeClass("in")};e(document).delegate('[data-toggle="tab"]',"click",function(n){n.preventDefault(),t(e(this))})},t.prototype._setupDropdowns=function(){var t=function(){var t=e(this),i=a(t),r=i.hasClass("open");if(!t.is(".disabled, :disabled"))return n(),r||i.toggleClass("open"),t.focus(),!1},n=function(){e("[data-toggle=dropdown]").each(function(){a(e(this)).removeClass("open")})},a=function(t){var n,a=t.attr("data-target");return a||(a=t.attr("href"),a=a&&/#/.test(a)&&a.replace(/.*(?=#[^\s]*$)/,"")),n=a&&e(a),n&&n.length||(n=t.parent()),n};e(document).bind("click",n).delegate(".dropdown-menu","click",function(e){e.stopPropagation()}).delegate("[data-toggle=dropdown]","click",t)},t.prototype._bindTextInputFieldLimits=function(){e("body").delegate('input[data-provide="limit"], textarea[data-provide="limit"]',"keyup",function(){var t=e(this),n=e(t.data("counter")),a=t.attr("maxlength"),i=t.val().length;n.html(Math.max(0,a-i))})},t.prototype.renderAlertPrompt=function(e,t){var n=FirechatDefaultTemplates["templates/prompt-alert.html"],a=this.prompt(e,n({message:t}));a.find(".close").click(function(){a.remove()})},t.prototype.toggleInputs=function(t){e("#firechat-tab-content textarea").each(function(){var n=e(this);t?e(this).val(""):e(this).val("You have exceeded the message limit, please wait before sending."),n.prop("disabled",!t)}),e("#firechat-input-name").prop("disabled",!t)},t.prototype.attachTab=function(t,n){var a=this;if(this.$messages[t])return this.focusTab(t),void 0;var i={id:t,name:n},r=FirechatDefaultTemplates["templates/tab-content.html"],s=e(r(i));this.$tabContent.prepend(s);var o=e("#firechat-messages"+t);this.$messages[t]=o;var c=s.find("textarea").first();c.bind("keydown",function(e){var n=a.trimWithEllipsis(c.val(),a.maxLengthMessage);return 13===e.which&&""!==n?(c.val(""),a._chat.sendMessage(t,n),!1):void 0});var l=FirechatDefaultTemplates["templates/tab-menu-item.html"],u=e(l(i));this.$tabList.prepend(u),u.bind("shown",function(){o.scrollTop(o[0].scrollHeight)});var d=this.$tabList.children("li"),h=Math.floor(e("#firechat-tab-list").width()/d.length);this.$tabList.children("li").css("width",h),this.$roomList.children("[data-room-id="+t+"]").children("a").addClass("highlight"),e("#firechat-btn-room-user-list-"+t).bind("click",function(){a.sortListLexicographically("#firechat-room-user-list-"+t)}),this.focusTab(t)},t.prototype.focusTab=function(e){if(this.$messages[e]){var t=this.$tabList.find("[data-room-id="+e+"]").find("a");t.length&&t.first().trigger("click")}},t.prototype.removeTab=function(t){delete this.$messages[t],this.$tabContent.find("[data-room-id="+t+"]").remove(),this.$tabList.find("[data-room-id="+t+"]").remove();var n=this.$tabList.children("li"),a=Math.floor(e("#firechat-tab-list").width()/n.length);this.$tabList.children("li").css("width",a),this.$tabList.find("[data-toggle=tab]").first().trigger("click"),this.$roomList.children("[data-room-id="+t+"]").children("a").removeClass("highlight")},t.prototype.showMessage=function(t,n){var a=this,i={id:n.id,localtime:a.formatTime(n.timestamp),message:n.message||"",userId:n.userId,name:n.name,type:n.type||"default",isSelfMessage:a._user&&n.userId==a._user.id,disableActions:!a._user||n.userId==a._user.id};i.message=_.map(i.message.split(" "),function(e){return a.urlPattern.test(e)||a.pseudoUrlPattern.test(e)?a.linkify(encodeURI(e)):_.escape(e)}).join(" "),i.message=a.trimWithEllipsis(i.message,a.maxLengthMessage);var r=FirechatDefaultTemplates["templates/message.html"],s=e(r(i)),o=a.$messages[t];if(o){var c=!1;o.scrollTop()/(o[0].scrollHeight-o[0].offsetHeight)>=.95?c=!0:o[0].scrollHeight<=o.height()&&(c=!0),o.append(s),c&&o.scrollTop(o[0].scrollHeight)}},t.prototype.removeMessage=function(t,n){e('.message[data-message-id="'+n+'"]').remove()},t.prototype.sortListLexicographically=function(t){e(t).children("li").sort(function(t,n){var a=e(t).text().toUpperCase(),i=e(n).text().toUpperCase();return i>a?-1:a>i?1:0}).appendTo(t)},t.prototype.trimWithEllipsis=function(e,t){return e=e.replace(/^\s\s*/,"").replace(/\s\s*$/,""),t&&t>=e.length?e:e.substring(0,t)+"..."},t.prototype.formatTime=function(e){var t=e?new Date(e):new Date,n=t.getHours()||12,a=""+t.getMinutes(),i=t.getHours()>=12?"pm":"am";return n=n>12?n-12:n,a=2>a.length?"0"+a:a,""+n+":"+a+i},t.prototype.promptCreateRoom=function(){var e=this,t=FirechatDefaultTemplates["templates/prompt-create-room.html"],n=this.prompt("Create Public Room",t({maxLengthRoomName:this.maxLengthRoomName,isModerator:e._chat.userIsModerator()}));n.find("a.close").first().click(function(){n.remove()}),n.find("[data-toggle=submit]").first().click(function(){var t=n.find("[data-input=firechat-room-name]").first().val();""!==t&&(e._chat.createRoom(t,"public"),n.remove())}),n.find("[data-input=firechat-room-name]").first().focus(),n.find("[data-input=firechat-room-name]").first().bind("keydown",function(t){if(13===t.which){var a=n.find("[data-input=firechat-room-name]").first().val();if(""!==a)return e._chat.createRoom(a,"public"),n.remove(),!1}})},t.prototype.prompt=function(t,n){var a,i=FirechatDefaultTemplates["templates/prompt.html"];return a=e(i({title:t,content:n})).css({top:this.$wrapper.position().top+.333*this.$wrapper.height(),left:this.$wrapper.position().left+.125*this.$wrapper.width(),width:.75*this.$wrapper.width()}),this.$wrapper.append(a.removeClass("hidden")),a},t.prototype.linkify=function(e){var t=this;return e.replace(t.urlPattern,'<a target="_blank" href="$&">$&</a>').replace(t.pseudoUrlPattern,'$1<a target="_blank" href="http://$2">$2</a>')}}(jQuery);
\ No newline at end of file
diff --git a/examples/anonymous_auth.html b/examples/anonymous_auth.html
index 7333466..18a04f5 100644
--- a/examples/anonymous_auth.html
+++ b/examples/anonymous_auth.html
@@ -7,8 +7,8 @@
   <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
 
   <!-- Download from https://github.com/firebase/Firechat -->
-  <link rel="stylesheet" href="../dist/0.1.4/firechat-default.min.css" />
-  <script src="../dist/0.1.4/firechat-default.min.js"></script>
+  <link rel="stylesheet" href="../dist/0.1.5/firechat-default.min.css" />
+  <script src="../dist/0.1.5/firechat-default.min.js"></script>
   <style>
     #firechat-wrapper {
       height: 475px;
diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js
index 0b4437e..3a95423 100644
--- a/src/js/firechat-ui.js
+++ b/src/js/firechat-ui.js
@@ -187,8 +187,8 @@
 
       if (invitation.status && invitation.status === 'accepted') {
         $prompt = this.prompt('Accepted', template(invitation));
-        this._chat.getRoom(invitation.toRoomId, function(room) {
-          self.attachTab(invitation.toRoomId, room.name);
+        this._chat.getRoom(invitation.roomId, function(room) {
+          self.attachTab(invitation.roomId, room.name);
         });
       } else {
         $prompt = this.prompt('Declined', template(invitation));