mad_chatter 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Andrew Havens
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
data/bin/mad_chatter ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "thor"
4
+
5
+ module MadChatter
6
+
7
+ class Cli < Thor
8
+ include Thor::Actions
9
+
10
+ def self.source_root
11
+ File.expand_path("../", File.dirname(__FILE__))
12
+ end
13
+
14
+ desc "new", "Creates a scaffold of a new Mad Chatter chatroom"
15
+ def new(name)
16
+ empty_directory "#{name}/extensions"
17
+ copy_file "README", "#{name}/README"
18
+ copy_file "LICENSE", "#{name}/LICENSE"
19
+ copy_file "templates/index.html", "#{name}/web/index.html"
20
+ copy_file "templates/javascript.js", "#{name}/web/javascript.js"
21
+ copy_file "templates/stylesheets/reset.css", "#{name}/web/stylesheets/reset.css"
22
+ copy_file "templates/stylesheets/styles.css", "#{name}/web/stylesheets/styles.css"
23
+ end
24
+
25
+ end
26
+ end
27
+
28
+ MadChatter::Cli.start
@@ -0,0 +1,36 @@
1
+ module MadChatter
2
+
3
+ module Actions
4
+
5
+ class Base
6
+
7
+ def initialize(message, user_token)
8
+ @message = message
9
+ @user_token = user_token
10
+ end
11
+
12
+ def process
13
+ send_message(@message)
14
+ end
15
+
16
+ def username
17
+ MadChatter::Users.username(@user_token)
18
+ end
19
+
20
+ def send_status(message)
21
+ MadChatter::Server.send_status(message)
22
+ end
23
+
24
+ def send_action(message)
25
+ MadChatter::Server.send_action(message)
26
+ end
27
+
28
+ def send_message(message)
29
+ MadChatter::Server.send_message(username, message)
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,26 @@
1
+ module MadChatter
2
+
3
+ module Actions
4
+
5
+ class Join < MadChatter::Actions::Base
6
+
7
+ @@command = '/join'
8
+
9
+ def process
10
+ username = parse_username_from_message
11
+ MadChatter::Users.update(@user_token, username)
12
+ MadChatter::Server.send_users_list
13
+ MadChatter::Server.send_status("#{username} has joined the chatroom")
14
+ end
15
+
16
+ def parse_username_from_message
17
+ # clear the command from the message string
18
+ # the rest will be the new username
19
+ username = @message.sub("#{@@command} ", '')
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,27 @@
1
+ module MadChatter
2
+
3
+ module Actions
4
+
5
+ class Rename < MadChatter::Actions::Base
6
+
7
+ @@command = '/nick'
8
+
9
+ def process
10
+ old_username = username
11
+ username = parse_username_from_message
12
+ MadChatter::Users.update(@user_token, username)
13
+ MadChatter::Server.send_users_list
14
+ MadChatter::Server.send_status("#{old_username} is now known as #{username}")
15
+ end
16
+
17
+ def parse_username_from_message
18
+ # clear the command from the message string
19
+ # the rest will be the new username
20
+ username = @message.sub("#{@@command} ", '')
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,61 @@
1
+ require 'mad_chatter/actions/base'
2
+ require 'mad_chatter/actions/join'
3
+ require 'mad_chatter/actions/rename'
4
+
5
+ module MadChatter
6
+
7
+ module Actions
8
+
9
+ class << self
10
+
11
+ def config(&block)
12
+ @config_block = block
13
+ end
14
+
15
+ def registered_actions
16
+ @registered_actions
17
+ end
18
+
19
+ def init
20
+ load_config_file
21
+ load_default_actions
22
+ load_action_extensions
23
+ end
24
+
25
+ def load_config_file
26
+ if File.exists?('config.rb')
27
+ load 'config.rb' # load up action extensions
28
+ end
29
+ end
30
+
31
+ def load_default_actions
32
+ @registered_actions = {}
33
+ @registered_actions['/join'] = 'MadChatter::Actions::Join'
34
+ @registered_actions['/nick'] = 'MadChatter::Actions::Rename'
35
+ end
36
+
37
+ def load_action_extensions
38
+ config = MadChatter::Actions::Config.new
39
+ @config_block.call(config) if @config_block
40
+ config.actions.each do |command, action_class|
41
+ @registered_actions[command] = action_class
42
+ end
43
+ end
44
+ end
45
+
46
+ class Config
47
+
48
+ attr_accessor :actions
49
+
50
+ def initialize
51
+ @actions = {}
52
+ end
53
+
54
+ def add(command, action_class)
55
+ @actions[command] = action_class
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,22 @@
1
+ require 'mad_chatter/actions'
2
+ require 'mad_chatter/actions/base'
3
+
4
+ module MadChatter
5
+
6
+ class Message < MadChatter::Actions::Base; end
7
+
8
+ class MessageFactory
9
+
10
+ def self.find(message, user_token)
11
+ MadChatter::Actions.registered_actions.each do |command, action_class|
12
+ # puts "looping through registered actions, command: #{command}, action_class: #{action_class}"
13
+ if message =~ /^#{command}/
14
+ return eval(action_class).new(message, user_token)
15
+ end
16
+ end
17
+ # puts 'could not find match for ' + message
18
+ MadChatter::Message.new(message, user_token)
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,116 @@
1
+ require 'digest/sha1'
2
+ require 'mad_chatter/users'
3
+ require 'mad_chatter/message'
4
+
5
+ module MadChatter
6
+
7
+ class Server
8
+
9
+ def initialize(options = {})
10
+ defaults = {
11
+ :host => "0.0.0.0",
12
+ :port => 8100
13
+ }
14
+ @options = defaults.merge!(options)
15
+ end
16
+
17
+ def self.main_channel
18
+ @main_channel ||= EventMachine::Channel.new
19
+ end
20
+
21
+ def start
22
+ EventMachine::WebSocket.start(@options) do |ws|
23
+
24
+ ws.onopen do
25
+
26
+ subscriber_id = MadChatter::Server.main_channel.subscribe { |msg| ws.send(msg) } #main send method, gets called when @main_channel.push gets called
27
+ token = generate_token()
28
+ send_client_token(ws, token)
29
+
30
+ ws.onclose do
31
+ username = MadChatter::Users.username(token)
32
+ if username
33
+ MadChatter::Server.send_status "#{username} has left the chatroom"
34
+ MadChatter::Users.remove(token)
35
+ end
36
+ MadChatter::Server.main_channel.unsubscribe(subscriber_id)
37
+ end
38
+
39
+ ws.onmessage do |msg_json|
40
+ msg = JSON.parse(msg_json)
41
+ if msg['token'].nil?
42
+ send_client_error(ws, 'Token is required')
43
+ else
44
+ message = MadChatter::MessageFactory.find(msg['message'], msg['token'])
45
+ message.process
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+
53
+ def generate_token
54
+ Digest::SHA1.hexdigest Time.now.to_s
55
+ end
56
+
57
+ def send_client_error(client, message)
58
+ data = JSON.generate({
59
+ type: 'error',
60
+ message: message
61
+ })
62
+ send_to_client(client, data)
63
+ end
64
+
65
+ def send_client_token(client, token)
66
+ data = JSON.generate({
67
+ type: 'token',
68
+ message: token
69
+ })
70
+ send_to_client(client, data)
71
+ end
72
+
73
+ def send_to_client(client, data)
74
+ client.send(data)
75
+ end
76
+
77
+ def self.send_users_list
78
+ data = JSON.generate({
79
+ type: 'users',
80
+ message: MadChatter::Users.current
81
+ })
82
+ MadChatter::Server.push_to_all_connections(data)
83
+ end
84
+
85
+ def self.send_status(message)
86
+ data = JSON.generate({
87
+ type: 'status',
88
+ message: message
89
+ })
90
+ MadChatter::Server.push_to_all_connections(data)
91
+ end
92
+
93
+ def self.send_message(username, message)
94
+ data = JSON.generate({
95
+ type: 'message',
96
+ username: username,
97
+ message: message
98
+ })
99
+ MadChatter::Server.push_to_all_connections(data)
100
+ end
101
+
102
+ def self.send_action(message)
103
+ data = JSON.generate({
104
+ type: 'action',
105
+ message: message
106
+ })
107
+ MadChatter::Server.push_to_all_connections(data)
108
+ end
109
+
110
+ def Server.push_to_all_connections(data)
111
+ # puts 'sending to all clients: ' + data
112
+ MadChatter::Server.main_channel.push(data)
113
+ end
114
+ end
115
+
116
+ end
@@ -0,0 +1,35 @@
1
+ module MadChatter
2
+
3
+ class Users
4
+
5
+ # Singleton storage for all current users
6
+ class << self
7
+
8
+ def users
9
+ @users ||= {}
10
+ end
11
+
12
+ def update(token, username)
13
+ MadChatter::Users.users[token] = username
14
+ end
15
+
16
+ def remove(token)
17
+ MadChatter::Users.users.delete(token)
18
+ end
19
+
20
+ def username(token)
21
+ MadChatter::Users.users[token]
22
+ end
23
+
24
+ def current
25
+ MadChatter::Users.users.values
26
+ end
27
+
28
+ def token_exists?(token)
29
+ MadChatter::Users.users[token].exists?
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,23 @@
1
+ $:.unshift(File.dirname(__FILE__)) # add this directory to load path
2
+ $:.unshift(Dir.pwd) # add current working directory for loading extensions
3
+
4
+ require 'bundler'
5
+ Bundler.setup
6
+ require 'em-websocket'
7
+ require 'json'
8
+
9
+ require 'mad_chatter/server'
10
+ require 'mad_chatter/actions'
11
+
12
+ EventMachine.run do
13
+
14
+ MadChatter::Actions.init
15
+
16
+ port = ENV['PORT'] || 8100
17
+
18
+ puts "Starting WebSocket server on port #{port}."
19
+
20
+ server = MadChatter::Server.new(:port => port)
21
+ server.start
22
+
23
+ end
@@ -0,0 +1,40 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Mad Chatter</title>
5
+ <link rel="stylesheet" href="stylesheets/reset.css">
6
+ <link rel="stylesheet" href="stylesheets/styles.css">
7
+ <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js'></script>
8
+ <script src='http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js'></script>
9
+ <script src='javascript.js'></script>
10
+ <script>
11
+ $(document).ready(function(){
12
+ MadChatter.init('ws://localhost:8100');
13
+ });
14
+ </script>
15
+ </head>
16
+ <body>
17
+
18
+ <div id="login_screen">
19
+ <header>
20
+ <h1>Welcome!</h1>
21
+ </header>
22
+ <div id="pick_a_username">
23
+ <p>What is your name?</p>
24
+ <input id="username" type="text"> <button id="join">Join</button>
25
+ </div>
26
+ </div>
27
+
28
+ <div id="chatroom">
29
+ <div id="sidebar">
30
+ <h2>Members</h2>
31
+ <ul id="members"></ul>
32
+ </div>
33
+ <div id="keyboard">
34
+ <input type="text">
35
+ </div>
36
+ <div id="messages"></div>
37
+ </div>
38
+
39
+ </body>
40
+ </html>
@@ -0,0 +1,128 @@
1
+ function get_current_time(){
2
+ var time = new Date();
3
+ var hours = time.getHours();
4
+ var minutes = time.getMinutes();
5
+ var ampm = 'am';
6
+ if (hours > 11) { ampm = 'pm'; }
7
+ if (minutes < 10) { minutes = "0" + minutes; }
8
+ if (hours == 0) { hours = 12; }
9
+ if (hours > 12) { hours = hours - 12; }
10
+ return hours + ':' + minutes + ampm;
11
+ }
12
+
13
+ var MadChatter = {
14
+
15
+ init: function(ws_host){
16
+ if (typeof WebSocket === 'undefined') {
17
+ alert("Your browser does not support websockets.")
18
+ return false;
19
+ }
20
+ MadChatter.init_websocket(ws_host);
21
+ $('#chatroom').hide();
22
+ MadChatter.wait_for_join();
23
+ MadChatter.wait_for_chat_submit();
24
+ },
25
+
26
+ init_websocket: function(ws_host){
27
+ var ws = new WebSocket(ws_host);
28
+ ws.onopen = function(){};
29
+ ws.onclose = function(){
30
+ MadChatter.display_status('You have been disconnected');
31
+ };
32
+ ws.onmessage = function(evt){
33
+ //console.log(evt.data)
34
+ var data = JSON.parse(evt.data);
35
+ MadChatter.message_received(data.type, data.username, data.message);
36
+ };
37
+ MadChatter.ws = ws;
38
+ },
39
+
40
+ wait_for_join: function(){
41
+ $('#username').keyup(function (event) {
42
+ if (event.keyCode == 13) { // The enter key.
43
+ MadChatter.join_chat();
44
+ }
45
+ });
46
+ $('#join').click(function(){
47
+ MadChatter.join_chat();
48
+ });
49
+ },
50
+
51
+ wait_for_chat_submit: function(){
52
+ var keyboard = $("#keyboard input");
53
+ keyboard.keyup(function (event) {
54
+ if (event.keyCode == 13) { // The enter key.
55
+ MadChatter.send_message(keyboard.val());
56
+ keyboard.val('');
57
+ }
58
+ });
59
+ },
60
+
61
+ join_chat: function(){
62
+ var username = $.trim($('#username').val());
63
+ if (username.length == 0) {
64
+ alert('Please enter your name.');
65
+ return false;
66
+ }
67
+ MadChatter.send_message('/join ' + username);
68
+ $('#login_screen').hide();
69
+ $('#chatroom').show();
70
+ },
71
+
72
+ message_received: function(type, username, message){
73
+ if (type == 'error') {
74
+ console.log('Client error: ' + message)
75
+ return;
76
+ }
77
+ if (type == 'token') {
78
+ MadChatter.client_token = message;
79
+ return;
80
+ }
81
+ if (type == 'users') {
82
+ MadChatter.update_users_list(message);
83
+ return;
84
+ }
85
+ if (type == 'status') {
86
+ MadChatter.display_status(message);
87
+ }
88
+ if (type == 'action') {
89
+ MadChatter.run_action(message);
90
+ }
91
+ if (type == 'message') {
92
+ MadChatter.display_message(username, message);
93
+ }
94
+ MadChatter.scroll_to_bottom_of_chat();
95
+ },
96
+
97
+ update_users_list: function(users){
98
+ $("#members").html('');
99
+ $.each(users, function(index, username) {
100
+ $("#members").append('<li>' + username + '</li>');
101
+ });
102
+ },
103
+
104
+ run_action: function(action){
105
+ eval(action);
106
+ },
107
+
108
+ display_status: function(message){
109
+ $("#messages").append("<p class='status'>" + message + "<time>" + get_current_time() + "</time></p>");
110
+ },
111
+
112
+ display_message: function(username, message){
113
+ $("#messages").append("<p><strong>" + username + ":</strong> " + message + "<time>" + get_current_time() + "</time></p>");
114
+ },
115
+
116
+ scroll_to_bottom_of_chat: function(){
117
+ $("body")[0].scrollTop = $("#messages")[0].scrollHeight;
118
+ },
119
+
120
+ send_message: function(message){
121
+ MadChatter.send_json('message', message);
122
+ },
123
+
124
+ send_json: function(type, msg){
125
+ var json = { type: type, token: MadChatter.client_token, message: msg };
126
+ MadChatter.ws.send(JSON.stringify(json));
127
+ }
128
+ };
@@ -0,0 +1,48 @@
1
+ /* http://meyerweb.com/eric/tools/css/reset/
2
+ v2.0 | 20110126
3
+ License: none (public domain)
4
+ */
5
+
6
+ html, body, div, span, applet, object, iframe,
7
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8
+ a, abbr, acronym, address, big, cite, code,
9
+ del, dfn, em, img, ins, kbd, q, s, samp,
10
+ small, strike, strong, sub, sup, tt, var,
11
+ b, u, i, center,
12
+ dl, dt, dd, ol, ul, li,
13
+ fieldset, form, label, legend,
14
+ table, caption, tbody, tfoot, thead, tr, th, td,
15
+ article, aside, canvas, details, embed,
16
+ figure, figcaption, footer, header, hgroup,
17
+ menu, nav, output, ruby, section, summary,
18
+ time, mark, audio, video {
19
+ margin: 0;
20
+ padding: 0;
21
+ border: 0;
22
+ font-size: 100%;
23
+ font: inherit;
24
+ vertical-align: baseline;
25
+ }
26
+ /* HTML5 display-role reset for older browsers */
27
+ article, aside, details, figcaption, figure,
28
+ footer, header, hgroup, menu, nav, section {
29
+ display: block;
30
+ }
31
+ body {
32
+ line-height: 1;
33
+ }
34
+ ol, ul {
35
+ list-style: none;
36
+ }
37
+ blockquote, q {
38
+ quotes: none;
39
+ }
40
+ blockquote:before, blockquote:after,
41
+ q:before, q:after {
42
+ content: '';
43
+ content: none;
44
+ }
45
+ table {
46
+ border-collapse: collapse;
47
+ border-spacing: 0;
48
+ }
@@ -0,0 +1,121 @@
1
+ #login_screen header {
2
+ padding: 150px 0 20px;
3
+ color: #fff;
4
+ background-color: #000;
5
+ text-align: center;
6
+ font: 25px Verdana, Geneva, Arial, Helvetica, sans-serif;
7
+ }
8
+
9
+ #pick_a_username {
10
+ text-align: center;
11
+ background: #fff;
12
+ padding: 5px 10px 10px;
13
+ font: 18px Verdana, Geneva, Arial, Helvetica, sans-serif;
14
+ }
15
+
16
+ #pick_a_username p {
17
+ margin: 10px;
18
+ }
19
+ #pick_a_username input, #pick_a_username button {
20
+ font: 14px Verdana, Geneva, Arial, Helvetica, sans-serif;
21
+ padding: 5px;
22
+ }
23
+ /*
24
+ #chatroom {
25
+ text-align: left;
26
+ background: #fff;
27
+ padding: 5px 10px 10px;
28
+ }
29
+
30
+ #chatroom #sidebar {
31
+ float: left;
32
+ width: 200px;
33
+ color: #fff;
34
+ background-color: #000;
35
+ height: 100%;
36
+ }
37
+
38
+ #chatroom #body {
39
+ float: right;
40
+ margin-left: 200px;
41
+ width: 580px;
42
+ height: 100%;
43
+ }
44
+ */
45
+
46
+ #chatroom{
47
+ margin:0;
48
+ padding:0 0 100px 200px;
49
+ font: 12px Verdana, Geneva, Arial, Helvetica, sans-serif;
50
+ }
51
+
52
+ #sidebar{
53
+ position:absolute;
54
+ top:0;
55
+ left:0;
56
+ width:200px;
57
+ height:100%;
58
+ color: #fff;
59
+ background-color: #000;
60
+ padding: 20px 5px 0 15px;
61
+ }
62
+
63
+ #sidebar h2 {
64
+ font: 14px Verdana, Geneva, Arial, Helvetica, sans-serif;
65
+ margin-bottom: 10px;
66
+ }
67
+
68
+ #sidebar ul#members li {
69
+ margin-left: 1em;
70
+ }
71
+
72
+ #messages {
73
+ padding: 20px 10px 0px 40px;
74
+ }
75
+
76
+ #messages p {
77
+ padding: 0.25em;
78
+ }
79
+
80
+ #messages time {
81
+ float: right;
82
+ color: #999;
83
+ }
84
+
85
+ #messages .status {
86
+ text-align: center;
87
+ color: #999;
88
+ }
89
+
90
+ #keyboard{
91
+ position:absolute;
92
+ bottom:0;
93
+ left:220px;
94
+ width:400%;
95
+ height:50px;
96
+ background-color: #eee;
97
+ padding: 10px 0 0 20px;
98
+ }
99
+
100
+ #keyboard input {
101
+ width: 15%;
102
+ padding: 5px;
103
+ }
104
+
105
+ @media screen{
106
+ #chatroom>div#sidebar{
107
+ position:fixed;
108
+ }
109
+ #chatroom>div#keyboard{
110
+ position:fixed;
111
+ }
112
+ }
113
+
114
+ * html #chatroom{
115
+ overflow:hidden;
116
+ }
117
+
118
+ * html div#messages{
119
+ height:100%;
120
+ overflow:auto;
121
+ }
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mad_chatter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.7
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andrew Havens
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-11 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &2169798480 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.14.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2169798480
25
+ - !ruby/object:Gem::Dependency
26
+ name: em-websocket
27
+ requirement: &2169797840 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.3.5
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2169797840
36
+ description: Mad Chatter is a fun, easy to customize chat server, written in Ruby,
37
+ utilizing HTML 5 Web Sockets
38
+ email: email@andrewhavens.com
39
+ executables:
40
+ - mad_chatter
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - lib/mad_chatter/actions/base.rb
45
+ - lib/mad_chatter/actions/join.rb
46
+ - lib/mad_chatter/actions/rename.rb
47
+ - lib/mad_chatter/actions.rb
48
+ - lib/mad_chatter/message.rb
49
+ - lib/mad_chatter/server.rb
50
+ - lib/mad_chatter/users.rb
51
+ - lib/mad_chatter.rb
52
+ - bin/mad_chatter
53
+ - templates/index.html
54
+ - templates/javascript.js
55
+ - templates/stylesheets/reset.css
56
+ - templates/stylesheets/styles.css
57
+ - LICENSE
58
+ - README
59
+ homepage: http://github.com/andrewhavens/mad_chatter
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.10
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Mad Chatter is a fun, easy to customize chat server, utilizing HTML 5 Web
83
+ Sockets
84
+ test_files: []