├── .bowerrc
├── .gitignore
├── .openshift
├── action_hooks
│ └── README.md
├── cron
│ ├── README.cron
│ ├── daily
│ │ └── .gitignore
│ ├── hourly
│ │ └── .gitignore
│ ├── minutely
│ │ └── .gitignore
│ ├── monthly
│ │ └── .gitignore
│ └── weekly
│ │ ├── README
│ │ ├── chrono.dat
│ │ ├── chronograph
│ │ ├── jobs.allow
│ │ └── jobs.deny
└── markers
│ └── .gitkeep
├── README.md
├── bower.json
├── license.md
├── node_modules
└── .gitkeep
├── npm-shrinkwrap.json
├── package.json
├── public
├── css
│ ├── app.css
│ ├── flags.css
│ ├── flags.png
│ └── flags.zip
├── index.html
└── js
│ └── client.js
├── room.js
└── server.js
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory" : "components"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | components/
3 |
--------------------------------------------------------------------------------
/.openshift/action_hooks/README.md:
--------------------------------------------------------------------------------
1 | For information about action hooks supported by OpenShift, consult the documentation:
2 |
3 | http://openshift.github.io/documentation/oo_user_guide.html#the-openshift-directory
4 |
--------------------------------------------------------------------------------
/.openshift/cron/README.cron:
--------------------------------------------------------------------------------
1 | Run scripts or jobs on a periodic basis
2 | =======================================
3 | Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly
4 | directories will be run on a scheduled basis (frequency is as indicated by the
5 | name of the directory) using run-parts.
6 |
7 | run-parts ignores any files that are hidden or dotfiles (.*) or backup
8 | files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved}
9 |
10 | The presence of two specially named files jobs.deny and jobs.allow controls
11 | how run-parts executes your scripts/jobs.
12 | jobs.deny ===> Prevents specific scripts or jobs from being executed.
13 | jobs.allow ===> Only execute the named scripts or jobs (all other/non-named
14 | scripts that exist in this directory are ignored).
15 |
16 | The principles of jobs.deny and jobs.allow are the same as those of cron.deny
17 | and cron.allow and are described in detail at:
18 | http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access
19 |
20 | See: man crontab or above link for more details and see the the weekly/
21 | directory for an example.
22 |
23 | PLEASE NOTE: The Cron cartridge must be installed in order to run the configured jobs.
24 |
--------------------------------------------------------------------------------
/.openshift/cron/daily/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/.openshift/cron/daily/.gitignore
--------------------------------------------------------------------------------
/.openshift/cron/hourly/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/.openshift/cron/hourly/.gitignore
--------------------------------------------------------------------------------
/.openshift/cron/minutely/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/.openshift/cron/minutely/.gitignore
--------------------------------------------------------------------------------
/.openshift/cron/monthly/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/.openshift/cron/monthly/.gitignore
--------------------------------------------------------------------------------
/.openshift/cron/weekly/README:
--------------------------------------------------------------------------------
1 | Run scripts or jobs on a weekly basis
2 | =====================================
3 | Any scripts or jobs added to this directory will be run on a scheduled basis
4 | (weekly) using run-parts.
5 |
6 | run-parts ignores any files that are hidden or dotfiles (.*) or backup
7 | files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles
8 | the files named jobs.deny and jobs.allow specially.
9 |
10 | In this specific example, the chronograph script is the only script or job file
11 | executed on a weekly basis (due to white-listing it in jobs.allow). And the
12 | README and chrono.dat file are ignored either as a result of being black-listed
13 | in jobs.deny or because they are NOT white-listed in the jobs.allow file.
14 |
15 | For more details, please see ../README.cron file.
16 |
17 |
--------------------------------------------------------------------------------
/.openshift/cron/weekly/chrono.dat:
--------------------------------------------------------------------------------
1 | Time And Relative D...n In Execution (Open)Shift!
2 |
--------------------------------------------------------------------------------
/.openshift/cron/weekly/chronograph:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "`date`: `cat $(dirname \"$0\")/chrono.dat`"
4 |
--------------------------------------------------------------------------------
/.openshift/cron/weekly/jobs.allow:
--------------------------------------------------------------------------------
1 | #
2 | # Script or job files listed in here (one entry per line) will be
3 | # executed on a weekly-basis.
4 | #
5 | # Example: The chronograph script will be executed weekly but the README
6 | # and chrono.dat files in this directory will be ignored.
7 | #
8 | # The README file is actually ignored due to the entry in the
9 | # jobs.deny which is checked before jobs.allow (this file).
10 | #
11 | chronograph
12 |
13 |
--------------------------------------------------------------------------------
/.openshift/cron/weekly/jobs.deny:
--------------------------------------------------------------------------------
1 | #
2 | # Any script or job files listed in here (one entry per line) will NOT be
3 | # executed (read as ignored by run-parts).
4 | #
5 |
6 | README
7 |
8 |
--------------------------------------------------------------------------------
/.openshift/markers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/.openshift/markers/.gitkeep
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Chat app written in node.js and socket.io
2 |
3 | ## Libraries used
4 |
5 | node.js / npm
6 | socket.io
7 | express
8 | node-uuid
9 | underscore
10 | ejs
11 |
12 |
13 | # Functionality
14 |
15 | People are able to join the chat server after entering their names
16 | Usernames are unique - if a username is taken, a new suggestion is generated
17 | User agent and geo location are both detected
18 | People can setup a room. Room names are unique. One person can create on room and join one room
19 | Users have to join a room to chat, except for the whisper feature.
20 | Whisper messages are private messages sent between two users
21 | With a WebSpeech enabled browsers, users can record their messages
22 | Users can leave a room and/or disconnect from the server anytime
23 | New: People joining the room will see the past 10 messages (chat history).
24 | New: People will see an 'is typing' message when someone is typing a message.
25 |
26 |
27 | ## Setup and configuration
28 |
29 | Make sure that you update server.js :
30 | server.listen(app.get('port'), function(){
31 | console.log('Express server listening on port ' + app.get('port'));
32 | });
33 | and add your own IP address/hostname if required, i.e.:
34 | server.listen(app.get('port'), "192.168.56.102", function(){
35 | console.log('Express server listening on port ' + app.get('port'));
36 | });
37 |
38 | (the port is defined in the app.set('port', process.env.PORT || 3000);
section.)
39 |
40 | Please also update public/js/client.js :
41 | var socket = io.connect("192.168.56.102:3000");
42 | with the right IP address/hostname.
43 |
44 | To install npm install && bower install
and to launch run npm start
.
45 |
46 | ### Whisper
47 |
48 | To send a 'private' message, use the following format in the chat message input box:
49 | w:USERNAME:MESSAGE
(where 'USERNAME' is the exact name of the user who you wish to whisper to (case-sensitive). For your convenience you can use the whipser link next to the person's username on the left hand side.)
50 |
51 | New up to date post: http://tamas.io/further-additions-to-the-node-jssocket-io-chat-app/
52 |
53 | Previous articles related to this topic:
54 |
55 | http://tamas.io/node-jssocket-io-chat-app-with-geolocation-and-user-agent-support/
56 | http://tamas.io/chat-2-0-supercharged-chat-written-in-node-js-and-socket-io/
57 | http://tamas.io/simple-chat-application-using-node-js-and-socket-io/
58 | http://tamas.io/advanced-chat-using-node-js-and-socket-io-episode-1/
59 |
60 |
61 | # Learn the latest on web development
62 | https://fullstack-developer.academy
63 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chat-20",
3 | "version": "0.0.1",
4 | "dependencies": {
5 | "bootstrap": "latest",
6 | "jquery": "latest",
7 | "typeahead.js": "latest",
8 | "font-awesome": "latest"
9 | },
10 | "directory": "components",
11 | "homepage": "https://github.com/tamaspiros/advanced-chat",
12 | "authors": [
13 | "Tamas Piros "
14 | ],
15 | "main": "server.js",
16 | "moduleType": [
17 | "node"
18 | ],
19 | "license": "free"
20 | }
21 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/node_modules/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/node_modules/.gitkeep
--------------------------------------------------------------------------------
/npm-shrinkwrap.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chat",
3 | "version": "0.0.1",
4 | "dependencies": {
5 | "ejs": {
6 | "version": "0.8.8",
7 | "from": "ejs@~0.8.5",
8 | "resolved": "https://registry.npmjs.org/ejs/-/ejs-0.8.8.tgz"
9 | },
10 | "express": {
11 | "version": "3.4.8",
12 | "from": "express@~3.4.8",
13 | "dependencies": {
14 | "connect": {
15 | "version": "2.12.0",
16 | "from": "connect@2.12.0",
17 | "dependencies": {
18 | "batch": {
19 | "version": "0.5.0",
20 | "from": "batch@0.5.0"
21 | },
22 | "qs": {
23 | "version": "0.6.6",
24 | "from": "qs@0.6.6"
25 | },
26 | "bytes": {
27 | "version": "0.2.1",
28 | "from": "bytes@0.2.1"
29 | },
30 | "pause": {
31 | "version": "0.0.1",
32 | "from": "pause@0.0.1"
33 | },
34 | "uid2": {
35 | "version": "0.0.3",
36 | "from": "uid2@0.0.3"
37 | },
38 | "raw-body": {
39 | "version": "1.1.2",
40 | "from": "raw-body@1.1.2"
41 | },
42 | "negotiator": {
43 | "version": "0.3.0",
44 | "from": "negotiator@0.3.0"
45 | },
46 | "multiparty": {
47 | "version": "2.2.0",
48 | "from": "multiparty@2.2.0",
49 | "dependencies": {
50 | "readable-stream": {
51 | "version": "1.1.13",
52 | "from": "readable-stream@~1.1.9",
53 | "dependencies": {
54 | "core-util-is": {
55 | "version": "1.0.1",
56 | "from": "core-util-is@~1.0.0"
57 | },
58 | "isarray": {
59 | "version": "0.0.1",
60 | "from": "isarray@0.0.1",
61 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
62 | },
63 | "string_decoder": {
64 | "version": "0.10.31",
65 | "from": "string_decoder@~0.10.x"
66 | },
67 | "inherits": {
68 | "version": "2.0.1",
69 | "from": "inherits@~2.0.1"
70 | }
71 | }
72 | },
73 | "stream-counter": {
74 | "version": "0.2.0",
75 | "from": "stream-counter@~0.2.0"
76 | }
77 | }
78 | }
79 | }
80 | },
81 | "commander": {
82 | "version": "1.3.2",
83 | "from": "commander@1.3.2",
84 | "dependencies": {
85 | "keypress": {
86 | "version": "0.1.0",
87 | "from": "keypress@0.1.x"
88 | }
89 | }
90 | },
91 | "range-parser": {
92 | "version": "0.0.4",
93 | "from": "range-parser@0.0.4"
94 | },
95 | "mkdirp": {
96 | "version": "0.3.5",
97 | "from": "mkdirp@0.3.5"
98 | },
99 | "cookie": {
100 | "version": "0.1.0",
101 | "from": "cookie@0.1.0"
102 | },
103 | "buffer-crc32": {
104 | "version": "0.2.1",
105 | "from": "buffer-crc32@0.2.1"
106 | },
107 | "fresh": {
108 | "version": "0.2.0",
109 | "from": "fresh@0.2.0"
110 | },
111 | "methods": {
112 | "version": "0.1.0",
113 | "from": "methods@0.1.0"
114 | },
115 | "send": {
116 | "version": "0.1.4",
117 | "from": "send@0.1.4",
118 | "dependencies": {
119 | "mime": {
120 | "version": "1.2.11",
121 | "from": "mime@~1.2.9"
122 | }
123 | }
124 | },
125 | "cookie-signature": {
126 | "version": "1.0.1",
127 | "from": "cookie-signature@1.0.1"
128 | },
129 | "merge-descriptors": {
130 | "version": "0.0.1",
131 | "from": "merge-descriptors@0.0.1"
132 | },
133 | "debug": {
134 | "version": "0.8.1",
135 | "from": "debug@>= 0.7.3 < 1"
136 | }
137 | }
138 | },
139 | "node-uuid": {
140 | "version": "1.4.3",
141 | "from": "node-uuid@~1.4.1",
142 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
143 | },
144 | "nodemon": {
145 | "version": "1.0.20",
146 | "from": "nodemon@~1.0.13",
147 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.0.20.tgz",
148 | "dependencies": {
149 | "update-notifier": {
150 | "version": "0.1.10",
151 | "from": "update-notifier@~0.1.8",
152 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.1.10.tgz",
153 | "dependencies": {
154 | "chalk": {
155 | "version": "0.4.0",
156 | "from": "chalk@^0.4.0",
157 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz",
158 | "dependencies": {
159 | "has-color": {
160 | "version": "0.1.7",
161 | "from": "has-color@~0.1.0",
162 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz"
163 | },
164 | "ansi-styles": {
165 | "version": "1.0.0",
166 | "from": "ansi-styles@~1.0.0",
167 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz"
168 | },
169 | "strip-ansi": {
170 | "version": "0.1.1",
171 | "from": "strip-ansi@~0.1.0",
172 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz"
173 | }
174 | }
175 | },
176 | "configstore": {
177 | "version": "0.3.2",
178 | "from": "configstore@^0.3.0",
179 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-0.3.2.tgz",
180 | "dependencies": {
181 | "graceful-fs": {
182 | "version": "3.0.6",
183 | "from": "graceful-fs@~3.0.2",
184 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.6.tgz"
185 | },
186 | "js-yaml": {
187 | "version": "3.2.7",
188 | "from": "js-yaml@^3.1.0",
189 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.2.7.tgz",
190 | "dependencies": {
191 | "argparse": {
192 | "version": "1.0.1",
193 | "from": "argparse@~ 1.0.0",
194 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.1.tgz",
195 | "dependencies": {
196 | "lodash": {
197 | "version": "3.2.0",
198 | "from": "lodash@~3.2",
199 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.2.0.tgz"
200 | },
201 | "sprintf-js": {
202 | "version": "1.0.2",
203 | "from": "sprintf-js@~1.0.2",
204 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.2.tgz"
205 | }
206 | }
207 | },
208 | "esprima": {
209 | "version": "2.0.0",
210 | "from": "esprima@~ 2.0.0",
211 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.0.0.tgz"
212 | }
213 | }
214 | },
215 | "mkdirp": {
216 | "version": "0.5.0",
217 | "from": "mkdirp@0.5",
218 | "dependencies": {
219 | "minimist": {
220 | "version": "0.0.8",
221 | "from": "minimist@0.0.8",
222 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
223 | }
224 | }
225 | },
226 | "object-assign": {
227 | "version": "2.0.0",
228 | "from": "object-assign@^2.0.0",
229 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.0.0.tgz"
230 | },
231 | "osenv": {
232 | "version": "0.1.0",
233 | "from": "osenv@^0.1.0",
234 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.0.tgz"
235 | },
236 | "user-home": {
237 | "version": "1.1.1",
238 | "from": "user-home@^1.0.0",
239 | "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz"
240 | },
241 | "uuid": {
242 | "version": "2.0.1",
243 | "from": "uuid@^2.0.1",
244 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz"
245 | },
246 | "xdg-basedir": {
247 | "version": "1.0.1",
248 | "from": "xdg-basedir@^1.0.0",
249 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-1.0.1.tgz"
250 | }
251 | }
252 | },
253 | "request": {
254 | "version": "2.53.0",
255 | "from": "request@^2.36.0",
256 | "resolved": "https://registry.npmjs.org/request/-/request-2.53.0.tgz",
257 | "dependencies": {
258 | "bl": {
259 | "version": "0.9.4",
260 | "from": "bl@~0.9.0",
261 | "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.4.tgz",
262 | "dependencies": {
263 | "readable-stream": {
264 | "version": "1.0.33",
265 | "from": "readable-stream@~1.0.26",
266 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
267 | "dependencies": {
268 | "core-util-is": {
269 | "version": "1.0.1",
270 | "from": "core-util-is@~1.0.0"
271 | },
272 | "isarray": {
273 | "version": "0.0.1",
274 | "from": "isarray@0.0.1",
275 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
276 | },
277 | "string_decoder": {
278 | "version": "0.10.31",
279 | "from": "string_decoder@~0.10.x"
280 | },
281 | "inherits": {
282 | "version": "2.0.1",
283 | "from": "inherits@~2.0.1"
284 | }
285 | }
286 | }
287 | }
288 | },
289 | "caseless": {
290 | "version": "0.9.0",
291 | "from": "caseless@~0.9.0",
292 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.9.0.tgz"
293 | },
294 | "forever-agent": {
295 | "version": "0.5.2",
296 | "from": "forever-agent@~0.5.0",
297 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz"
298 | },
299 | "form-data": {
300 | "version": "0.2.0",
301 | "from": "form-data@~0.2.0",
302 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz",
303 | "dependencies": {
304 | "async": {
305 | "version": "0.9.0",
306 | "from": "async@~0.9.0",
307 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
308 | }
309 | }
310 | },
311 | "json-stringify-safe": {
312 | "version": "5.0.0",
313 | "from": "json-stringify-safe@~5.0.0"
314 | },
315 | "mime-types": {
316 | "version": "2.0.10",
317 | "from": "mime-types@~2.0.1",
318 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.10.tgz",
319 | "dependencies": {
320 | "mime-db": {
321 | "version": "1.8.0",
322 | "from": "mime-db@~1.8.0",
323 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.8.0.tgz"
324 | }
325 | }
326 | },
327 | "qs": {
328 | "version": "2.3.3",
329 | "from": "qs@~2.3.1"
330 | },
331 | "tunnel-agent": {
332 | "version": "0.4.0",
333 | "from": "tunnel-agent@~0.4.0",
334 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.0.tgz"
335 | },
336 | "tough-cookie": {
337 | "version": "0.12.1",
338 | "from": "tough-cookie@>=0.12.0",
339 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-0.12.1.tgz",
340 | "dependencies": {
341 | "punycode": {
342 | "version": "1.3.2",
343 | "from": "punycode@>=0.2.0",
344 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
345 | }
346 | }
347 | },
348 | "http-signature": {
349 | "version": "0.10.1",
350 | "from": "http-signature@~0.10.0",
351 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
352 | "dependencies": {
353 | "assert-plus": {
354 | "version": "0.1.5",
355 | "from": "assert-plus@^0.1.5",
356 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
357 | },
358 | "asn1": {
359 | "version": "0.1.11",
360 | "from": "asn1@0.1.11"
361 | },
362 | "ctype": {
363 | "version": "0.5.3",
364 | "from": "ctype@0.5.3",
365 | "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
366 | }
367 | }
368 | },
369 | "oauth-sign": {
370 | "version": "0.6.0",
371 | "from": "oauth-sign@~0.6.0",
372 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.6.0.tgz"
373 | },
374 | "hawk": {
375 | "version": "2.3.1",
376 | "from": "hawk@~2.3.0",
377 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz",
378 | "dependencies": {
379 | "hoek": {
380 | "version": "2.11.1",
381 | "from": "hoek@2.x.x",
382 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.11.1.tgz"
383 | },
384 | "boom": {
385 | "version": "2.6.1",
386 | "from": "boom@2.x.x",
387 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.6.1.tgz"
388 | },
389 | "cryptiles": {
390 | "version": "2.0.4",
391 | "from": "cryptiles@2.x.x",
392 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.4.tgz"
393 | },
394 | "sntp": {
395 | "version": "1.0.9",
396 | "from": "sntp@1.x.x",
397 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
398 | }
399 | }
400 | },
401 | "aws-sign2": {
402 | "version": "0.5.0",
403 | "from": "aws-sign2@~0.5.0",
404 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz"
405 | },
406 | "stringstream": {
407 | "version": "0.0.4",
408 | "from": "stringstream@~0.0.4",
409 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.4.tgz"
410 | },
411 | "combined-stream": {
412 | "version": "0.0.7",
413 | "from": "combined-stream@~0.0.4",
414 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
415 | "dependencies": {
416 | "delayed-stream": {
417 | "version": "0.0.5",
418 | "from": "delayed-stream@0.0.5"
419 | }
420 | }
421 | },
422 | "isstream": {
423 | "version": "0.1.2",
424 | "from": "isstream@~0.1.1",
425 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
426 | }
427 | }
428 | },
429 | "semver": {
430 | "version": "2.3.2",
431 | "from": "semver@^2.3.0",
432 | "resolved": "https://registry.npmjs.org/semver/-/semver-2.3.2.tgz"
433 | }
434 | }
435 | },
436 | "minimatch": {
437 | "version": "0.2.14",
438 | "from": "minimatch@~0.2.14",
439 | "dependencies": {
440 | "lru-cache": {
441 | "version": "2.5.0",
442 | "from": "lru-cache@2"
443 | },
444 | "sigmund": {
445 | "version": "1.0.0",
446 | "from": "sigmund@~1.0.0"
447 | }
448 | }
449 | },
450 | "ps-tree": {
451 | "version": "0.0.3",
452 | "from": "ps-tree@0.0.3",
453 | "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-0.0.3.tgz",
454 | "dependencies": {
455 | "event-stream": {
456 | "version": "0.5.3",
457 | "from": "event-stream@~0.5",
458 | "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-0.5.3.tgz",
459 | "dependencies": {
460 | "optimist": {
461 | "version": "0.2.8",
462 | "from": "optimist@0.2",
463 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.2.8.tgz",
464 | "dependencies": {
465 | "wordwrap": {
466 | "version": "0.0.2",
467 | "from": "wordwrap@>=0.0.1 <0.1.0"
468 | }
469 | }
470 | }
471 | }
472 | }
473 | }
474 | }
475 | }
476 | },
477 | "npid": {
478 | "version": "0.4.0",
479 | "from": "npid@~0.4.0"
480 | },
481 | "socket.io": {
482 | "version": "0.9.17",
483 | "from": "socket.io@~0.9.16",
484 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-0.9.17.tgz",
485 | "dependencies": {
486 | "socket.io-client": {
487 | "version": "0.9.16",
488 | "from": "socket.io-client@0.9.16",
489 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-0.9.16.tgz",
490 | "dependencies": {
491 | "uglify-js": {
492 | "version": "1.2.5",
493 | "from": "uglify-js@1.2.5",
494 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.5.tgz"
495 | },
496 | "ws": {
497 | "version": "0.4.32",
498 | "from": "ws@0.4.x",
499 | "dependencies": {
500 | "commander": {
501 | "version": "2.1.0",
502 | "from": "commander@~2.1.0"
503 | },
504 | "nan": {
505 | "version": "1.0.0",
506 | "from": "nan@~1.0.0"
507 | },
508 | "tinycolor": {
509 | "version": "0.0.1",
510 | "from": "tinycolor@0.x"
511 | },
512 | "options": {
513 | "version": "0.0.6",
514 | "from": "options@>=0.0.5"
515 | }
516 | }
517 | },
518 | "xmlhttprequest": {
519 | "version": "1.4.2",
520 | "from": "xmlhttprequest@1.4.2",
521 | "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.4.2.tgz"
522 | },
523 | "active-x-obfuscator": {
524 | "version": "0.0.1",
525 | "from": "active-x-obfuscator@0.0.1",
526 | "resolved": "https://registry.npmjs.org/active-x-obfuscator/-/active-x-obfuscator-0.0.1.tgz",
527 | "dependencies": {
528 | "zeparser": {
529 | "version": "0.0.5",
530 | "from": "zeparser@0.0.5",
531 | "resolved": "https://registry.npmjs.org/zeparser/-/zeparser-0.0.5.tgz"
532 | }
533 | }
534 | }
535 | }
536 | },
537 | "policyfile": {
538 | "version": "0.0.4",
539 | "from": "policyfile@0.0.4",
540 | "resolved": "https://registry.npmjs.org/policyfile/-/policyfile-0.0.4.tgz"
541 | },
542 | "base64id": {
543 | "version": "0.1.0",
544 | "from": "base64id@0.1.0",
545 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz"
546 | },
547 | "redis": {
548 | "version": "0.7.3",
549 | "from": "redis@0.7.3",
550 | "resolved": "https://registry.npmjs.org/redis/-/redis-0.7.3.tgz"
551 | }
552 | }
553 | },
554 | "shrinkwrap": {
555 | "version": "0.0.3",
556 | "from": "shrinkwrap@~0.0.3",
557 | "dependencies": {
558 | "semver": {
559 | "version": "2.1.0",
560 | "from": "semver@~2.1.0"
561 | },
562 | "request": {
563 | "version": "2.27.0",
564 | "from": "request@~2.27.0",
565 | "dependencies": {
566 | "qs": {
567 | "version": "0.6.6",
568 | "from": "qs@~0.6.0"
569 | },
570 | "json-stringify-safe": {
571 | "version": "5.0.0",
572 | "from": "json-stringify-safe@~5.0.0"
573 | },
574 | "forever-agent": {
575 | "version": "0.5.2",
576 | "from": "forever-agent@~0.5.0",
577 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz"
578 | },
579 | "tunnel-agent": {
580 | "version": "0.3.0",
581 | "from": "tunnel-agent@~0.3.0"
582 | },
583 | "http-signature": {
584 | "version": "0.10.1",
585 | "from": "http-signature@~0.10.0",
586 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
587 | "dependencies": {
588 | "assert-plus": {
589 | "version": "0.1.5",
590 | "from": "assert-plus@^0.1.5",
591 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
592 | },
593 | "asn1": {
594 | "version": "0.1.11",
595 | "from": "asn1@0.1.11"
596 | },
597 | "ctype": {
598 | "version": "0.5.3",
599 | "from": "ctype@0.5.3",
600 | "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
601 | }
602 | }
603 | },
604 | "hawk": {
605 | "version": "1.0.0",
606 | "from": "hawk@~1.0.0",
607 | "dependencies": {
608 | "hoek": {
609 | "version": "0.9.1",
610 | "from": "hoek@0.9.x"
611 | },
612 | "boom": {
613 | "version": "0.4.2",
614 | "from": "boom@0.4.x"
615 | },
616 | "cryptiles": {
617 | "version": "0.2.2",
618 | "from": "cryptiles@0.2.x"
619 | },
620 | "sntp": {
621 | "version": "0.2.4",
622 | "from": "sntp@0.2.x"
623 | }
624 | }
625 | },
626 | "aws-sign": {
627 | "version": "0.3.0",
628 | "from": "aws-sign@~0.3.0"
629 | },
630 | "oauth-sign": {
631 | "version": "0.3.0",
632 | "from": "oauth-sign@~0.3.0"
633 | },
634 | "cookie-jar": {
635 | "version": "0.3.0",
636 | "from": "cookie-jar@~0.3.0"
637 | },
638 | "mime": {
639 | "version": "1.2.11",
640 | "from": "mime@~1.2.9"
641 | },
642 | "form-data": {
643 | "version": "0.1.4",
644 | "from": "form-data@~0.1.0",
645 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz",
646 | "dependencies": {
647 | "combined-stream": {
648 | "version": "0.0.7",
649 | "from": "combined-stream@~0.0.4",
650 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
651 | "dependencies": {
652 | "delayed-stream": {
653 | "version": "0.0.5",
654 | "from": "delayed-stream@0.0.5"
655 | }
656 | }
657 | },
658 | "async": {
659 | "version": "0.9.0",
660 | "from": "async@~0.9.0",
661 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
662 | }
663 | }
664 | }
665 | }
666 | },
667 | "async": {
668 | "version": "0.2.10",
669 | "from": "async@~0.2.9"
670 | },
671 | "assign": {
672 | "version": "0.0.2",
673 | "from": "assign@~0.0.1"
674 | },
675 | "eventemitter3": {
676 | "version": "0.1.6",
677 | "from": "eventemitter3@~0.1.1",
678 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-0.1.6.tgz"
679 | }
680 | }
681 | },
682 | "underscore": {
683 | "version": "1.5.2",
684 | "from": "underscore@~1.5.2"
685 | },
686 | "bower": {
687 | "version": "1.2.8",
688 | "from": "bower@~1.2.8",
689 | "dependencies": {
690 | "abbrev": {
691 | "version": "1.0.5",
692 | "from": "abbrev@~1.0.4",
693 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
694 | },
695 | "archy": {
696 | "version": "0.0.2",
697 | "from": "archy@0.0.2",
698 | "resolved": "https://registry.npmjs.org/archy/-/archy-0.0.2.tgz"
699 | },
700 | "bower-config": {
701 | "version": "0.5.2",
702 | "from": "bower-config@~0.5.0",
703 | "resolved": "https://registry.npmjs.org/bower-config/-/bower-config-0.5.2.tgz",
704 | "dependencies": {
705 | "mout": {
706 | "version": "0.9.1",
707 | "from": "mout@~0.9.0",
708 | "resolved": "https://registry.npmjs.org/mout/-/mout-0.9.1.tgz"
709 | },
710 | "optimist": {
711 | "version": "0.6.1",
712 | "from": "optimist@~0.6.0",
713 | "dependencies": {
714 | "wordwrap": {
715 | "version": "0.0.2",
716 | "from": "wordwrap@~0.0.2"
717 | },
718 | "minimist": {
719 | "version": "0.0.10",
720 | "from": "minimist@~0.0.1"
721 | }
722 | }
723 | }
724 | }
725 | },
726 | "bower-endpoint-parser": {
727 | "version": "0.2.2",
728 | "from": "bower-endpoint-parser@~0.2.0",
729 | "resolved": "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz"
730 | },
731 | "bower-json": {
732 | "version": "0.4.0",
733 | "from": "bower-json@~0.4.0",
734 | "dependencies": {
735 | "deep-extend": {
736 | "version": "0.2.11",
737 | "from": "deep-extend@~0.2.5",
738 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
739 | },
740 | "intersect": {
741 | "version": "0.0.3",
742 | "from": "intersect@~0.0.3"
743 | }
744 | }
745 | },
746 | "bower-logger": {
747 | "version": "0.2.2",
748 | "from": "bower-logger@~0.2.1"
749 | },
750 | "bower-registry-client": {
751 | "version": "0.1.6",
752 | "from": "bower-registry-client@~0.1.4",
753 | "dependencies": {
754 | "async": {
755 | "version": "0.2.10",
756 | "from": "async@~0.2.8"
757 | },
758 | "bower-config": {
759 | "version": "0.4.5",
760 | "from": "bower-config@~0.4.3",
761 | "dependencies": {
762 | "mout": {
763 | "version": "0.6.0",
764 | "from": "mout@~0.6.0"
765 | },
766 | "optimist": {
767 | "version": "0.6.1",
768 | "from": "optimist@~0.6.0",
769 | "dependencies": {
770 | "wordwrap": {
771 | "version": "0.0.2",
772 | "from": "wordwrap@~0.0.2"
773 | },
774 | "minimist": {
775 | "version": "0.0.10",
776 | "from": "minimist@~0.0.1"
777 | }
778 | }
779 | }
780 | }
781 | },
782 | "request-replay": {
783 | "version": "0.2.0",
784 | "from": "request-replay@~0.2.0"
785 | }
786 | }
787 | },
788 | "cardinal": {
789 | "version": "0.4.4",
790 | "from": "cardinal@~0.4.0",
791 | "dependencies": {
792 | "redeyed": {
793 | "version": "0.4.4",
794 | "from": "redeyed@~0.4.0",
795 | "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-0.4.4.tgz",
796 | "dependencies": {
797 | "esprima": {
798 | "version": "1.0.4",
799 | "from": "esprima@~1.0.4"
800 | }
801 | }
802 | },
803 | "ansicolors": {
804 | "version": "0.2.1",
805 | "from": "ansicolors@~0.2.1"
806 | }
807 | }
808 | },
809 | "chalk": {
810 | "version": "0.2.1",
811 | "from": "chalk@~0.2.0",
812 | "dependencies": {
813 | "has-color": {
814 | "version": "0.1.7",
815 | "from": "has-color@~0.1.0",
816 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz"
817 | },
818 | "ansi-styles": {
819 | "version": "0.2.0",
820 | "from": "ansi-styles@~0.2.0"
821 | }
822 | }
823 | },
824 | "chmodr": {
825 | "version": "0.1.0",
826 | "from": "chmodr@~0.1.0"
827 | },
828 | "decompress-zip": {
829 | "version": "0.0.8",
830 | "from": "decompress-zip@~0.0.3",
831 | "resolved": "https://registry.npmjs.org/decompress-zip/-/decompress-zip-0.0.8.tgz",
832 | "dependencies": {
833 | "q": {
834 | "version": "1.0.1",
835 | "from": "q@~1.0.0"
836 | },
837 | "mkpath": {
838 | "version": "0.1.0",
839 | "from": "mkpath@~0.1.0"
840 | },
841 | "binary": {
842 | "version": "0.3.0",
843 | "from": "binary@~0.3.0",
844 | "dependencies": {
845 | "chainsaw": {
846 | "version": "0.1.0",
847 | "from": "chainsaw@~0.1.0",
848 | "dependencies": {
849 | "traverse": {
850 | "version": "0.3.9",
851 | "from": "traverse@>=0.3.0 <0.4"
852 | }
853 | }
854 | },
855 | "buffers": {
856 | "version": "0.1.1",
857 | "from": "buffers@~0.1.1"
858 | }
859 | }
860 | },
861 | "touch": {
862 | "version": "0.0.2",
863 | "from": "touch@0.0.2",
864 | "resolved": "https://registry.npmjs.org/touch/-/touch-0.0.2.tgz",
865 | "dependencies": {
866 | "nopt": {
867 | "version": "1.0.10",
868 | "from": "nopt@~1.0.10"
869 | }
870 | }
871 | },
872 | "readable-stream": {
873 | "version": "1.1.13",
874 | "from": "readable-stream@~1.1.8",
875 | "dependencies": {
876 | "core-util-is": {
877 | "version": "1.0.1",
878 | "from": "core-util-is@~1.0.0"
879 | },
880 | "isarray": {
881 | "version": "0.0.1",
882 | "from": "isarray@0.0.1",
883 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
884 | },
885 | "string_decoder": {
886 | "version": "0.10.31",
887 | "from": "string_decoder@~0.10.x"
888 | },
889 | "inherits": {
890 | "version": "2.0.1",
891 | "from": "inherits@~2.0.1"
892 | }
893 | }
894 | },
895 | "nopt": {
896 | "version": "2.2.1",
897 | "from": "nopt@~2.2.0",
898 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz"
899 | },
900 | "graceful-fs": {
901 | "version": "3.0.6",
902 | "from": "graceful-fs@~3.0.2",
903 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.6.tgz"
904 | }
905 | }
906 | },
907 | "fstream": {
908 | "version": "0.1.31",
909 | "from": "fstream@~0.1.22",
910 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-0.1.31.tgz",
911 | "dependencies": {
912 | "graceful-fs": {
913 | "version": "3.0.6",
914 | "from": "graceful-fs@~3.0.2",
915 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.6.tgz"
916 | },
917 | "inherits": {
918 | "version": "2.0.1",
919 | "from": "inherits@~2.0.0"
920 | },
921 | "mkdirp": {
922 | "version": "0.5.0",
923 | "from": "mkdirp@0.5",
924 | "dependencies": {
925 | "minimist": {
926 | "version": "0.0.8",
927 | "from": "minimist@0.0.8",
928 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
929 | }
930 | }
931 | }
932 | }
933 | },
934 | "fstream-ignore": {
935 | "version": "0.0.10",
936 | "from": "fstream-ignore@~0.0.6",
937 | "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-0.0.10.tgz",
938 | "dependencies": {
939 | "inherits": {
940 | "version": "2.0.1",
941 | "from": "inherits@2"
942 | },
943 | "minimatch": {
944 | "version": "0.3.0",
945 | "from": "minimatch@0.3",
946 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
947 | "dependencies": {
948 | "sigmund": {
949 | "version": "1.0.0",
950 | "from": "sigmund@~1.0.0"
951 | }
952 | }
953 | }
954 | }
955 | },
956 | "glob": {
957 | "version": "3.2.11",
958 | "from": "glob@~3.2.1",
959 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz",
960 | "dependencies": {
961 | "inherits": {
962 | "version": "2.0.1",
963 | "from": "inherits@2"
964 | },
965 | "minimatch": {
966 | "version": "0.3.0",
967 | "from": "minimatch@0.3",
968 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
969 | "dependencies": {
970 | "sigmund": {
971 | "version": "1.0.0",
972 | "from": "sigmund@~1.0.0"
973 | }
974 | }
975 | }
976 | }
977 | },
978 | "graceful-fs": {
979 | "version": "2.0.3",
980 | "from": "graceful-fs@~2.0.0"
981 | },
982 | "handlebars": {
983 | "version": "1.0.12",
984 | "from": "handlebars@~1.0.11",
985 | "dependencies": {
986 | "optimist": {
987 | "version": "0.3.7",
988 | "from": "optimist@~0.3",
989 | "dependencies": {
990 | "wordwrap": {
991 | "version": "0.0.2",
992 | "from": "wordwrap@~0.0.2"
993 | }
994 | }
995 | },
996 | "uglify-js": {
997 | "version": "2.3.6",
998 | "from": "uglify-js@~2.3",
999 | "dependencies": {
1000 | "async": {
1001 | "version": "0.2.10",
1002 | "from": "async@~0.2.6"
1003 | },
1004 | "source-map": {
1005 | "version": "0.1.43",
1006 | "from": "source-map@~0.1.7",
1007 | "dependencies": {
1008 | "amdefine": {
1009 | "version": "0.1.0",
1010 | "from": "amdefine@>=0.0.4"
1011 | }
1012 | }
1013 | }
1014 | }
1015 | }
1016 | }
1017 | },
1018 | "inquirer": {
1019 | "version": "0.3.5",
1020 | "from": "inquirer@~0.3.0",
1021 | "dependencies": {
1022 | "lodash": {
1023 | "version": "1.2.1",
1024 | "from": "lodash@~1.2.1"
1025 | },
1026 | "async": {
1027 | "version": "0.2.10",
1028 | "from": "async@~0.2.8"
1029 | },
1030 | "cli-color": {
1031 | "version": "0.2.3",
1032 | "from": "cli-color@~0.2.2",
1033 | "dependencies": {
1034 | "es5-ext": {
1035 | "version": "0.9.2",
1036 | "from": "es5-ext@~0.9.2"
1037 | },
1038 | "memoizee": {
1039 | "version": "0.2.6",
1040 | "from": "memoizee@~0.2.5",
1041 | "dependencies": {
1042 | "event-emitter": {
1043 | "version": "0.2.2",
1044 | "from": "event-emitter@~0.2.2"
1045 | },
1046 | "next-tick": {
1047 | "version": "0.1.0",
1048 | "from": "next-tick@0.1.x"
1049 | }
1050 | }
1051 | }
1052 | }
1053 | },
1054 | "mute-stream": {
1055 | "version": "0.0.3",
1056 | "from": "mute-stream@0.0.3",
1057 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.3.tgz"
1058 | }
1059 | }
1060 | },
1061 | "junk": {
1062 | "version": "0.2.2",
1063 | "from": "junk@~0.2.0"
1064 | },
1065 | "mkdirp": {
1066 | "version": "0.3.5",
1067 | "from": "mkdirp@~0.3.5"
1068 | },
1069 | "mout": {
1070 | "version": "0.7.1",
1071 | "from": "mout@~0.7.0"
1072 | },
1073 | "nopt": {
1074 | "version": "2.1.2",
1075 | "from": "nopt@~2.1.1"
1076 | },
1077 | "lru-cache": {
1078 | "version": "2.3.1",
1079 | "from": "lru-cache@~2.3.0"
1080 | },
1081 | "open": {
1082 | "version": "0.0.5",
1083 | "from": "open@~0.0.3",
1084 | "resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz"
1085 | },
1086 | "osenv": {
1087 | "version": "0.0.3",
1088 | "from": "osenv@0.0.3"
1089 | },
1090 | "promptly": {
1091 | "version": "0.2.1",
1092 | "from": "promptly@~0.2.0",
1093 | "resolved": "https://registry.npmjs.org/promptly/-/promptly-0.2.1.tgz",
1094 | "dependencies": {
1095 | "read": {
1096 | "version": "1.0.5",
1097 | "from": "read@~1.0.4",
1098 | "dependencies": {
1099 | "mute-stream": {
1100 | "version": "0.0.4",
1101 | "from": "mute-stream@~0.0.4"
1102 | }
1103 | }
1104 | }
1105 | }
1106 | },
1107 | "q": {
1108 | "version": "0.9.7",
1109 | "from": "q@~0.9.2"
1110 | },
1111 | "request": {
1112 | "version": "2.27.0",
1113 | "from": "request@~2.27.0",
1114 | "dependencies": {
1115 | "qs": {
1116 | "version": "0.6.6",
1117 | "from": "qs@~0.6.0"
1118 | },
1119 | "json-stringify-safe": {
1120 | "version": "5.0.0",
1121 | "from": "json-stringify-safe@~5.0.0"
1122 | },
1123 | "forever-agent": {
1124 | "version": "0.5.2",
1125 | "from": "forever-agent@~0.5.0",
1126 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz"
1127 | },
1128 | "tunnel-agent": {
1129 | "version": "0.3.0",
1130 | "from": "tunnel-agent@~0.3.0"
1131 | },
1132 | "http-signature": {
1133 | "version": "0.10.1",
1134 | "from": "http-signature@~0.10.0",
1135 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
1136 | "dependencies": {
1137 | "assert-plus": {
1138 | "version": "0.1.5",
1139 | "from": "assert-plus@^0.1.5",
1140 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
1141 | },
1142 | "asn1": {
1143 | "version": "0.1.11",
1144 | "from": "asn1@0.1.11"
1145 | },
1146 | "ctype": {
1147 | "version": "0.5.3",
1148 | "from": "ctype@0.5.3",
1149 | "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
1150 | }
1151 | }
1152 | },
1153 | "hawk": {
1154 | "version": "1.0.0",
1155 | "from": "hawk@~1.0.0",
1156 | "dependencies": {
1157 | "hoek": {
1158 | "version": "0.9.1",
1159 | "from": "hoek@0.9.x"
1160 | },
1161 | "boom": {
1162 | "version": "0.4.2",
1163 | "from": "boom@0.4.x"
1164 | },
1165 | "cryptiles": {
1166 | "version": "0.2.2",
1167 | "from": "cryptiles@0.2.x"
1168 | },
1169 | "sntp": {
1170 | "version": "0.2.4",
1171 | "from": "sntp@0.2.x"
1172 | }
1173 | }
1174 | },
1175 | "aws-sign": {
1176 | "version": "0.3.0",
1177 | "from": "aws-sign@~0.3.0"
1178 | },
1179 | "oauth-sign": {
1180 | "version": "0.3.0",
1181 | "from": "oauth-sign@~0.3.0"
1182 | },
1183 | "cookie-jar": {
1184 | "version": "0.3.0",
1185 | "from": "cookie-jar@~0.3.0"
1186 | },
1187 | "mime": {
1188 | "version": "1.2.11",
1189 | "from": "mime@~1.2.9"
1190 | },
1191 | "form-data": {
1192 | "version": "0.1.4",
1193 | "from": "form-data@~0.1.0",
1194 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz",
1195 | "dependencies": {
1196 | "combined-stream": {
1197 | "version": "0.0.7",
1198 | "from": "combined-stream@~0.0.4",
1199 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
1200 | "dependencies": {
1201 | "delayed-stream": {
1202 | "version": "0.0.5",
1203 | "from": "delayed-stream@0.0.5"
1204 | }
1205 | }
1206 | },
1207 | "async": {
1208 | "version": "0.9.0",
1209 | "from": "async@~0.9.0",
1210 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
1211 | }
1212 | }
1213 | }
1214 | }
1215 | },
1216 | "request-progress": {
1217 | "version": "0.3.1",
1218 | "from": "request-progress@~0.3.0",
1219 | "dependencies": {
1220 | "throttleit": {
1221 | "version": "0.0.2",
1222 | "from": "throttleit@~0.0.2"
1223 | }
1224 | }
1225 | },
1226 | "retry": {
1227 | "version": "0.6.1",
1228 | "from": "retry@~0.6.0",
1229 | "resolved": "https://registry.npmjs.org/retry/-/retry-0.6.1.tgz"
1230 | },
1231 | "rimraf": {
1232 | "version": "2.2.8",
1233 | "from": "rimraf@~2.2.0",
1234 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
1235 | },
1236 | "semver": {
1237 | "version": "2.1.0",
1238 | "from": "semver@~2.1.0"
1239 | },
1240 | "stringify-object": {
1241 | "version": "0.1.8",
1242 | "from": "stringify-object@~0.1.4",
1243 | "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-0.1.8.tgz"
1244 | },
1245 | "sudo-block": {
1246 | "version": "0.2.1",
1247 | "from": "sudo-block@~0.2.0",
1248 | "dependencies": {
1249 | "chalk": {
1250 | "version": "0.1.1",
1251 | "from": "chalk@~0.1.1",
1252 | "dependencies": {
1253 | "has-color": {
1254 | "version": "0.1.7",
1255 | "from": "has-color@~0.1.0",
1256 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz"
1257 | },
1258 | "ansi-styles": {
1259 | "version": "0.1.2",
1260 | "from": "ansi-styles@~0.1.0"
1261 | }
1262 | }
1263 | }
1264 | }
1265 | },
1266 | "tar": {
1267 | "version": "0.1.20",
1268 | "from": "tar@~0.1.17",
1269 | "resolved": "https://registry.npmjs.org/tar/-/tar-0.1.20.tgz",
1270 | "dependencies": {
1271 | "block-stream": {
1272 | "version": "0.0.7",
1273 | "from": "block-stream@*"
1274 | },
1275 | "inherits": {
1276 | "version": "2.0.1",
1277 | "from": "inherits@2"
1278 | }
1279 | }
1280 | },
1281 | "tmp": {
1282 | "version": "0.0.25",
1283 | "from": "tmp@~0.0.20",
1284 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.25.tgz"
1285 | },
1286 | "update-notifier": {
1287 | "version": "0.1.10",
1288 | "from": "update-notifier@~0.1.3",
1289 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.1.10.tgz",
1290 | "dependencies": {
1291 | "chalk": {
1292 | "version": "0.4.0",
1293 | "from": "chalk@^0.4.0",
1294 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz",
1295 | "dependencies": {
1296 | "has-color": {
1297 | "version": "0.1.7",
1298 | "from": "has-color@~0.1.0",
1299 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz"
1300 | },
1301 | "ansi-styles": {
1302 | "version": "1.0.0",
1303 | "from": "ansi-styles@~1.0.0",
1304 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz"
1305 | },
1306 | "strip-ansi": {
1307 | "version": "0.1.1",
1308 | "from": "strip-ansi@~0.1.0",
1309 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz"
1310 | }
1311 | }
1312 | },
1313 | "configstore": {
1314 | "version": "0.3.2",
1315 | "from": "configstore@^0.3.0",
1316 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-0.3.2.tgz",
1317 | "dependencies": {
1318 | "graceful-fs": {
1319 | "version": "3.0.6",
1320 | "from": "graceful-fs@~3.0.2",
1321 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.6.tgz"
1322 | },
1323 | "js-yaml": {
1324 | "version": "3.2.7",
1325 | "from": "js-yaml@^3.1.0",
1326 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.2.7.tgz",
1327 | "dependencies": {
1328 | "argparse": {
1329 | "version": "1.0.1",
1330 | "from": "argparse@~ 1.0.0",
1331 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.1.tgz",
1332 | "dependencies": {
1333 | "lodash": {
1334 | "version": "3.2.0",
1335 | "from": "lodash@~3.2",
1336 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.2.0.tgz"
1337 | },
1338 | "sprintf-js": {
1339 | "version": "1.0.2",
1340 | "from": "sprintf-js@~1.0.2",
1341 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.2.tgz"
1342 | }
1343 | }
1344 | },
1345 | "esprima": {
1346 | "version": "2.0.0",
1347 | "from": "esprima@~ 2.0.0",
1348 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.0.0.tgz"
1349 | }
1350 | }
1351 | },
1352 | "mkdirp": {
1353 | "version": "0.5.0",
1354 | "from": "mkdirp@0.5",
1355 | "dependencies": {
1356 | "minimist": {
1357 | "version": "0.0.8",
1358 | "from": "minimist@0.0.8",
1359 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
1360 | }
1361 | }
1362 | },
1363 | "object-assign": {
1364 | "version": "2.0.0",
1365 | "from": "object-assign@^2.0.0",
1366 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.0.0.tgz"
1367 | },
1368 | "osenv": {
1369 | "version": "0.1.0",
1370 | "from": "osenv@^0.1.0",
1371 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.0.tgz"
1372 | },
1373 | "user-home": {
1374 | "version": "1.1.1",
1375 | "from": "user-home@^1.0.0",
1376 | "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz"
1377 | },
1378 | "uuid": {
1379 | "version": "2.0.1",
1380 | "from": "uuid@^2.0.1",
1381 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz"
1382 | },
1383 | "xdg-basedir": {
1384 | "version": "1.0.1",
1385 | "from": "xdg-basedir@^1.0.0",
1386 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-1.0.1.tgz"
1387 | }
1388 | }
1389 | },
1390 | "request": {
1391 | "version": "2.53.0",
1392 | "from": "request@^2.36.0",
1393 | "resolved": "https://registry.npmjs.org/request/-/request-2.53.0.tgz",
1394 | "dependencies": {
1395 | "bl": {
1396 | "version": "0.9.4",
1397 | "from": "bl@~0.9.0",
1398 | "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.4.tgz",
1399 | "dependencies": {
1400 | "readable-stream": {
1401 | "version": "1.0.33",
1402 | "from": "readable-stream@~1.0.26",
1403 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
1404 | "dependencies": {
1405 | "core-util-is": {
1406 | "version": "1.0.1",
1407 | "from": "core-util-is@~1.0.0"
1408 | },
1409 | "isarray": {
1410 | "version": "0.0.1",
1411 | "from": "isarray@0.0.1",
1412 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
1413 | },
1414 | "string_decoder": {
1415 | "version": "0.10.31",
1416 | "from": "string_decoder@~0.10.x"
1417 | },
1418 | "inherits": {
1419 | "version": "2.0.1",
1420 | "from": "inherits@~2.0.1"
1421 | }
1422 | }
1423 | }
1424 | }
1425 | },
1426 | "caseless": {
1427 | "version": "0.9.0",
1428 | "from": "caseless@~0.9.0",
1429 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.9.0.tgz"
1430 | },
1431 | "forever-agent": {
1432 | "version": "0.5.2",
1433 | "from": "forever-agent@~0.5.0",
1434 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz"
1435 | },
1436 | "form-data": {
1437 | "version": "0.2.0",
1438 | "from": "form-data@~0.2.0",
1439 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz",
1440 | "dependencies": {
1441 | "async": {
1442 | "version": "0.9.0",
1443 | "from": "async@~0.9.0",
1444 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
1445 | }
1446 | }
1447 | },
1448 | "json-stringify-safe": {
1449 | "version": "5.0.0",
1450 | "from": "json-stringify-safe@~5.0.0"
1451 | },
1452 | "mime-types": {
1453 | "version": "2.0.10",
1454 | "from": "mime-types@~2.0.1",
1455 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.10.tgz",
1456 | "dependencies": {
1457 | "mime-db": {
1458 | "version": "1.8.0",
1459 | "from": "mime-db@~1.8.0",
1460 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.8.0.tgz"
1461 | }
1462 | }
1463 | },
1464 | "qs": {
1465 | "version": "2.3.3",
1466 | "from": "qs@~2.3.1"
1467 | },
1468 | "tunnel-agent": {
1469 | "version": "0.4.0",
1470 | "from": "tunnel-agent@~0.4.0",
1471 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.0.tgz"
1472 | },
1473 | "tough-cookie": {
1474 | "version": "0.12.1",
1475 | "from": "tough-cookie@>=0.12.0",
1476 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-0.12.1.tgz",
1477 | "dependencies": {
1478 | "punycode": {
1479 | "version": "1.3.2",
1480 | "from": "punycode@>=0.2.0",
1481 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
1482 | }
1483 | }
1484 | },
1485 | "http-signature": {
1486 | "version": "0.10.1",
1487 | "from": "http-signature@~0.10.0",
1488 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
1489 | "dependencies": {
1490 | "assert-plus": {
1491 | "version": "0.1.5",
1492 | "from": "assert-plus@^0.1.5",
1493 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
1494 | },
1495 | "asn1": {
1496 | "version": "0.1.11",
1497 | "from": "asn1@0.1.11"
1498 | },
1499 | "ctype": {
1500 | "version": "0.5.3",
1501 | "from": "ctype@0.5.3",
1502 | "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
1503 | }
1504 | }
1505 | },
1506 | "oauth-sign": {
1507 | "version": "0.6.0",
1508 | "from": "oauth-sign@~0.6.0",
1509 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.6.0.tgz"
1510 | },
1511 | "hawk": {
1512 | "version": "2.3.1",
1513 | "from": "hawk@~2.3.0",
1514 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz",
1515 | "dependencies": {
1516 | "hoek": {
1517 | "version": "2.11.1",
1518 | "from": "hoek@2.x.x",
1519 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.11.1.tgz"
1520 | },
1521 | "boom": {
1522 | "version": "2.6.1",
1523 | "from": "boom@2.x.x",
1524 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.6.1.tgz"
1525 | },
1526 | "cryptiles": {
1527 | "version": "2.0.4",
1528 | "from": "cryptiles@2.x.x",
1529 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.4.tgz"
1530 | },
1531 | "sntp": {
1532 | "version": "1.0.9",
1533 | "from": "sntp@1.x.x",
1534 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
1535 | }
1536 | }
1537 | },
1538 | "aws-sign2": {
1539 | "version": "0.5.0",
1540 | "from": "aws-sign2@~0.5.0",
1541 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz"
1542 | },
1543 | "stringstream": {
1544 | "version": "0.0.4",
1545 | "from": "stringstream@~0.0.4",
1546 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.4.tgz"
1547 | },
1548 | "combined-stream": {
1549 | "version": "0.0.7",
1550 | "from": "combined-stream@~0.0.4",
1551 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
1552 | "dependencies": {
1553 | "delayed-stream": {
1554 | "version": "0.0.5",
1555 | "from": "delayed-stream@0.0.5"
1556 | }
1557 | }
1558 | },
1559 | "isstream": {
1560 | "version": "0.1.2",
1561 | "from": "isstream@~0.1.1",
1562 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
1563 | }
1564 | }
1565 | },
1566 | "semver": {
1567 | "version": "2.3.2",
1568 | "from": "semver@^2.3.0",
1569 | "resolved": "https://registry.npmjs.org/semver/-/semver-2.3.2.tgz"
1570 | }
1571 | }
1572 | },
1573 | "which": {
1574 | "version": "1.0.9",
1575 | "from": "which@~1.0.5",
1576 | "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz"
1577 | },
1578 | "p-throttler": {
1579 | "version": "0.0.1",
1580 | "from": "p-throttler@~0.0.1"
1581 | }
1582 | }
1583 | }
1584 | }
1585 | }
1586 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chat",
3 | "version": "0.0.1",
4 | "description": "node.js/socket.io chat app",
5 | "main": "server.js",
6 | "dependencies": {
7 | "ejs": "~0.8.5",
8 | "express": "~3.4.8",
9 | "node-uuid": "~1.4.1",
10 | "nodemon": "~1.0.13",
11 | "npid": "~0.4.0",
12 | "socket.io": "~0.9.16",
13 | "shrinkwrap": "~0.0.3",
14 | "underscore": "~1.5.2",
15 | "bower": "~1.2.8"
16 | },
17 | "devDependencies": {},
18 | "scripts": {
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/satrapade/advanced-chat.git"
23 | },
24 | "author": "Tamas Piros",
25 | "url": "http://tamas.io",
26 | "email": "me@tamas.io",
27 | "license": "free",
28 | "bugs": {
29 | "url": "https://github.com/satrapade/advanced-chat/issues"
30 | },
31 | "homepage": "https://github.com/satrapade/advanced-chat"
32 | }
33 |
--------------------------------------------------------------------------------
/public/css/app.css:
--------------------------------------------------------------------------------
1 | #login-screen, #main-chat-screen {
2 | padding-top: 10px;
3 | }
4 | .main {
5 | padding-top: 10px;
6 | text-align: center;
7 | }
8 | #conversation {
9 | font-size: 18px;
10 | margin: 0px;
11 | height: 300px;
12 | overflow: scroll;
13 | }
14 | .final {
15 | font-color: #000;
16 | }
17 | .interim {
18 | font-color: #f00;
19 | }
--------------------------------------------------------------------------------
/public/css/flags.css:
--------------------------------------------------------------------------------
1 | .flag {
2 | width: 16px;
3 | height: 11px;
4 | background:url(flags.png) no-repeat
5 | }
6 |
7 | .flag.flag-ad {background-position: -16px 0}
8 | .flag.flag-ae {background-position: -32px 0}
9 | .flag.flag-af {background-position: -48px 0}
10 | .flag.flag-ag {background-position: -64px 0}
11 | .flag.flag-ai {background-position: -80px 0}
12 | .flag.flag-al {background-position: -96px 0}
13 | .flag.flag-am {background-position: -112px 0}
14 | .flag.flag-an {background-position: -128px 0}
15 | .flag.flag-ao {background-position: -144px 0}
16 | .flag.flag-ar {background-position: -160px 0}
17 | .flag.flag-as {background-position: -176px 0}
18 | .flag.flag-at {background-position: -192px 0}
19 | .flag.flag-au {background-position: -208px 0}
20 | .flag.flag-aw {background-position: -224px 0}
21 | .flag.flag-az {background-position: -240px 0}
22 | .flag.flag-ba {background-position: 0 -11px}
23 | .flag.flag-bb {background-position: -16px -11px}
24 | .flag.flag-bd {background-position: -32px -11px}
25 | .flag.flag-be {background-position: -48px -11px}
26 | .flag.flag-bf {background-position: -64px -11px}
27 | .flag.flag-bg {background-position: -80px -11px}
28 | .flag.flag-bh {background-position: -96px -11px}
29 | .flag.flag-bi {background-position: -112px -11px}
30 | .flag.flag-bj {background-position: -128px -11px}
31 | .flag.flag-bm {background-position: -144px -11px}
32 | .flag.flag-bn {background-position: -160px -11px}
33 | .flag.flag-bo {background-position: -176px -11px}
34 | .flag.flag-br {background-position: -192px -11px}
35 | .flag.flag-bs {background-position: -208px -11px}
36 | .flag.flag-bt {background-position: -224px -11px}
37 | .flag.flag-bv {background-position: -240px -11px}
38 | .flag.flag-bw {background-position: 0 -22px}
39 | .flag.flag-by {background-position: -16px -22px}
40 | .flag.flag-bz {background-position: -32px -22px}
41 | .flag.flag-ca {background-position: -48px -22px}
42 | .flag.flag-catalonia {background-position: -64px -22px}
43 | .flag.flag-cd {background-position: -80px -22px}
44 | .flag.flag-cf {background-position: -96px -22px}
45 | .flag.flag-cg {background-position: -112px -22px}
46 | .flag.flag-ch {background-position: -128px -22px}
47 | .flag.flag-ci {background-position: -144px -22px}
48 | .flag.flag-ck {background-position: -160px -22px}
49 | .flag.flag-cl {background-position: -176px -22px}
50 | .flag.flag-cm {background-position: -192px -22px}
51 | .flag.flag-cn {background-position: -208px -22px}
52 | .flag.flag-co {background-position: -224px -22px}
53 | .flag.flag-cr {background-position: -240px -22px}
54 | .flag.flag-cu {background-position: 0 -33px}
55 | .flag.flag-cv {background-position: -16px -33px}
56 | .flag.flag-cw {background-position: -32px -33px}
57 | .flag.flag-cy {background-position: -48px -33px}
58 | .flag.flag-cz {background-position: -64px -33px}
59 | .flag.flag-de {background-position: -80px -33px}
60 | .flag.flag-dj {background-position: -96px -33px}
61 | .flag.flag-dk {background-position: -112px -33px}
62 | .flag.flag-dm {background-position: -128px -33px}
63 | .flag.flag-do {background-position: -144px -33px}
64 | .flag.flag-dz {background-position: -160px -33px}
65 | .flag.flag-ec {background-position: -176px -33px}
66 | .flag.flag-ee {background-position: -192px -33px}
67 | .flag.flag-eg {background-position: -208px -33px}
68 | .flag.flag-eh {background-position: -224px -33px}
69 | .flag.flag-england {background-position: -240px -33px}
70 | .flag.flag-er {background-position: 0 -44px}
71 | .flag.flag-es {background-position: -16px -44px}
72 | .flag.flag-et {background-position: -32px -44px}
73 | .flag.flag-eu {background-position: -48px -44px}
74 | .flag.flag-fi {background-position: -64px -44px}
75 | .flag.flag-fj {background-position: -80px -44px}
76 | .flag.flag-fk {background-position: -96px -44px}
77 | .flag.flag-fm {background-position: -112px -44px}
78 | .flag.flag-fo {background-position: -128px -44px}
79 | .flag.flag-fr {background-position: -144px -44px}
80 | .flag.flag-ga {background-position: -160px -44px}
81 | .flag.flag-gb {background-position: -176px -44px}
82 | .flag.flag-gd {background-position: -192px -44px}
83 | .flag.flag-ge {background-position: -208px -44px}
84 | .flag.flag-gf {background-position: -224px -44px}
85 | .flag.flag-gg {background-position: -240px -44px}
86 | .flag.flag-gh {background-position: 0 -55px}
87 | .flag.flag-gi {background-position: -16px -55px}
88 | .flag.flag-gl {background-position: -32px -55px}
89 | .flag.flag-gm {background-position: -48px -55px}
90 | .flag.flag-gn {background-position: -64px -55px}
91 | .flag.flag-gp {background-position: -80px -55px}
92 | .flag.flag-gq {background-position: -96px -55px}
93 | .flag.flag-gr {background-position: -112px -55px}
94 | .flag.flag-gs {background-position: -128px -55px}
95 | .flag.flag-gt {background-position: -144px -55px}
96 | .flag.flag-gu {background-position: -160px -55px}
97 | .flag.flag-gw {background-position: -176px -55px}
98 | .flag.flag-gy {background-position: -192px -55px}
99 | .flag.flag-hk {background-position: -208px -55px}
100 | .flag.flag-hm {background-position: -224px -55px}
101 | .flag.flag-hn {background-position: -240px -55px}
102 | .flag.flag-hr {background-position: 0 -66px}
103 | .flag.flag-ht {background-position: -16px -66px}
104 | .flag.flag-hu {background-position: -32px -66px}
105 | .flag.flag-ic {background-position: -48px -66px}
106 | .flag.flag-id {background-position: -64px -66px}
107 | .flag.flag-ie {background-position: -80px -66px}
108 | .flag.flag-il {background-position: -96px -66px}
109 | .flag.flag-im {background-position: -112px -66px}
110 | .flag.flag-in {background-position: -128px -66px}
111 | .flag.flag-io {background-position: -144px -66px}
112 | .flag.flag-iq {background-position: -160px -66px}
113 | .flag.flag-ir {background-position: -176px -66px}
114 | .flag.flag-is {background-position: -192px -66px}
115 | .flag.flag-it {background-position: -208px -66px}
116 | .flag.flag-je {background-position: -224px -66px}
117 | .flag.flag-jm {background-position: -240px -66px}
118 | .flag.flag-jo {background-position: 0 -77px}
119 | .flag.flag-jp {background-position: -16px -77px}
120 | .flag.flag-ke {background-position: -32px -77px}
121 | .flag.flag-kg {background-position: -48px -77px}
122 | .flag.flag-kh {background-position: -64px -77px}
123 | .flag.flag-ki {background-position: -80px -77px}
124 | .flag.flag-km {background-position: -96px -77px}
125 | .flag.flag-kn {background-position: -112px -77px}
126 | .flag.flag-kp {background-position: -128px -77px}
127 | .flag.flag-kr {background-position: -144px -77px}
128 | .flag.flag-kurdistan {background-position: -160px -77px}
129 | .flag.flag-kw {background-position: -176px -77px}
130 | .flag.flag-ky {background-position: -192px -77px}
131 | .flag.flag-kz {background-position: -208px -77px}
132 | .flag.flag-la {background-position: -224px -77px}
133 | .flag.flag-lb {background-position: -240px -77px}
134 | .flag.flag-lc {background-position: 0 -88px}
135 | .flag.flag-li {background-position: -16px -88px}
136 | .flag.flag-lk {background-position: -32px -88px}
137 | .flag.flag-lr {background-position: -48px -88px}
138 | .flag.flag-ls {background-position: -64px -88px}
139 | .flag.flag-lt {background-position: -80px -88px}
140 | .flag.flag-lu {background-position: -96px -88px}
141 | .flag.flag-lv {background-position: -112px -88px}
142 | .flag.flag-ly {background-position: -128px -88px}
143 | .flag.flag-ma {background-position: -144px -88px}
144 | .flag.flag-mc {background-position: -160px -88px}
145 | .flag.flag-md {background-position: -176px -88px}
146 | .flag.flag-me {background-position: -192px -88px}
147 | .flag.flag-mg {background-position: -208px -88px}
148 | .flag.flag-mh {background-position: -224px -88px}
149 | .flag.flag-mk {background-position: -240px -88px}
150 | .flag.flag-ml {background-position: 0 -99px}
151 | .flag.flag-mm {background-position: -16px -99px}
152 | .flag.flag-mn {background-position: -32px -99px}
153 | .flag.flag-mo {background-position: -48px -99px}
154 | .flag.flag-mp {background-position: -64px -99px}
155 | .flag.flag-mq {background-position: -80px -99px}
156 | .flag.flag-mr {background-position: -96px -99px}
157 | .flag.flag-ms {background-position: -112px -99px}
158 | .flag.flag-mt {background-position: -128px -99px}
159 | .flag.flag-mu {background-position: -144px -99px}
160 | .flag.flag-mv {background-position: -160px -99px}
161 | .flag.flag-mw {background-position: -176px -99px}
162 | .flag.flag-mx {background-position: -192px -99px}
163 | .flag.flag-my {background-position: -208px -99px}
164 | .flag.flag-mz {background-position: -224px -99px}
165 | .flag.flag-na {background-position: -240px -99px}
166 | .flag.flag-nc {background-position: 0 -110px}
167 | .flag.flag-ne {background-position: -16px -110px}
168 | .flag.flag-nf {background-position: -32px -110px}
169 | .flag.flag-ng {background-position: -48px -110px}
170 | .flag.flag-ni {background-position: -64px -110px}
171 | .flag.flag-nl {background-position: -80px -110px}
172 | .flag.flag-no {background-position: -96px -110px}
173 | .flag.flag-np {background-position: -112px -110px}
174 | .flag.flag-nr {background-position: -128px -110px}
175 | .flag.flag-nu {background-position: -144px -110px}
176 | .flag.flag-nz {background-position: -160px -110px}
177 | .flag.flag-om {background-position: -176px -110px}
178 | .flag.flag-pa {background-position: -192px -110px}
179 | .flag.flag-pe {background-position: -208px -110px}
180 | .flag.flag-pf {background-position: -224px -110px}
181 | .flag.flag-pg {background-position: -240px -110px}
182 | .flag.flag-ph {background-position: 0 -121px}
183 | .flag.flag-pk {background-position: -16px -121px}
184 | .flag.flag-pl {background-position: -32px -121px}
185 | .flag.flag-pm {background-position: -48px -121px}
186 | .flag.flag-pn {background-position: -64px -121px}
187 | .flag.flag-pr {background-position: -80px -121px}
188 | .flag.flag-ps {background-position: -96px -121px}
189 | .flag.flag-pt {background-position: -112px -121px}
190 | .flag.flag-pw {background-position: -128px -121px}
191 | .flag.flag-py {background-position: -144px -121px}
192 | .flag.flag-qa {background-position: -160px -121px}
193 | .flag.flag-re {background-position: -176px -121px}
194 | .flag.flag-ro {background-position: -192px -121px}
195 | .flag.flag-rs {background-position: -208px -121px}
196 | .flag.flag-ru {background-position: -224px -121px}
197 | .flag.flag-rw {background-position: -240px -121px}
198 | .flag.flag-sa {background-position: 0 -132px}
199 | .flag.flag-sb {background-position: -16px -132px}
200 | .flag.flag-sc {background-position: -32px -132px}
201 | .flag.flag-scotland {background-position: -48px -132px}
202 | .flag.flag-sd {background-position: -64px -132px}
203 | .flag.flag-se {background-position: -80px -132px}
204 | .flag.flag-sg {background-position: -96px -132px}
205 | .flag.flag-sh {background-position: -112px -132px}
206 | .flag.flag-si {background-position: -128px -132px}
207 | .flag.flag-sk {background-position: -144px -132px}
208 | .flag.flag-sl {background-position: -160px -132px}
209 | .flag.flag-sm {background-position: -176px -132px}
210 | .flag.flag-sn {background-position: -192px -132px}
211 | .flag.flag-so {background-position: -208px -132px}
212 | .flag.flag-somaliland {background-position: -224px -132px}
213 | .flag.flag-sr {background-position: -240px -132px}
214 | .flag.flag-ss {background-position: 0 -143px}
215 | .flag.flag-st {background-position: -16px -143px}
216 | .flag.flag-sv {background-position: -32px -143px}
217 | .flag.flag-sx {background-position: -48px -143px}
218 | .flag.flag-sy {background-position: -64px -143px}
219 | .flag.flag-sz {background-position: -80px -143px}
220 | .flag.flag-tc {background-position: -96px -143px}
221 | .flag.flag-td {background-position: -112px -143px}
222 | .flag.flag-tf {background-position: -128px -143px}
223 | .flag.flag-tg {background-position: -144px -143px}
224 | .flag.flag-th {background-position: -160px -143px}
225 | .flag.flag-tj {background-position: -176px -143px}
226 | .flag.flag-tk {background-position: -192px -143px}
227 | .flag.flag-tl {background-position: -208px -143px}
228 | .flag.flag-tm {background-position: -224px -143px}
229 | .flag.flag-tn {background-position: -240px -143px}
230 | .flag.flag-to {background-position: 0 -154px}
231 | .flag.flag-tr {background-position: -16px -154px}
232 | .flag.flag-tt {background-position: -32px -154px}
233 | .flag.flag-tv {background-position: -48px -154px}
234 | .flag.flag-tw {background-position: -64px -154px}
235 | .flag.flag-tz {background-position: -80px -154px}
236 | .flag.flag-ua {background-position: -96px -154px}
237 | .flag.flag-ug {background-position: -112px -154px}
238 | .flag.flag-um {background-position: -128px -154px}
239 | .flag.flag-us {background-position: -144px -154px}
240 | .flag.flag-uy {background-position: -160px -154px}
241 | .flag.flag-uz {background-position: -176px -154px}
242 | .flag.flag-va {background-position: -192px -154px}
243 | .flag.flag-vc {background-position: -208px -154px}
244 | .flag.flag-ve {background-position: -224px -154px}
245 | .flag.flag-vg {background-position: -240px -154px}
246 | .flag.flag-vi {background-position: 0 -165px}
247 | .flag.flag-vn {background-position: -16px -165px}
248 | .flag.flag-vu {background-position: -32px -165px}
249 | .flag.flag-wales {background-position: -48px -165px}
250 | .flag.flag-wf {background-position: -64px -165px}
251 | .flag.flag-ws {background-position: -80px -165px}
252 | .flag.flag-ye {background-position: -96px -165px}
253 | .flag.flag-yt {background-position: -112px -165px}
254 | .flag.flag-za {background-position: -128px -165px}
255 | .flag.flag-zanzibar {background-position: -144px -165px}
256 | .flag.flag-zm {background-position: -160px -165px}
257 | .flag.flag-zw {background-position: -176px -165px}
258 |
--------------------------------------------------------------------------------
/public/css/flags.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/public/css/flags.png
--------------------------------------------------------------------------------
/public/css/flags.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpiros/advanced-chat/8ff534ba1476fdf70418b0421c5aa8ea1a786238/public/css/flags.zip
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Chat 2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Chat application - using node.js and socket.io
15 |
Please enter your name below and click 'Join' or hit the 'Enter' key.
16 |
22 |
23 |
24 |
25 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
66 |
67 | You can create a chat room here. Names have to be unique.
68 |
69 |
70 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/public/js/client.js:
--------------------------------------------------------------------------------
1 | /* HTML5 magic
2 | - GeoLocation
3 | - WebSpeech
4 | */
5 |
6 | //WebSpeech API
7 | var final_transcript = '';
8 | var recognizing = false;
9 | var last10messages = []; //to be populated later
10 |
11 | if (!('webkitSpeechRecognition' in window)) {
12 | console.log("webkitSpeechRecognition is not available");
13 | } else {
14 | var recognition = new webkitSpeechRecognition();
15 | recognition.continuous = true;
16 | recognition.interimResults = true;
17 |
18 | recognition.onstart = function() {
19 | recognizing = true;
20 | };
21 |
22 | recognition.onresult = function(event) {
23 | var interim_transcript = '';
24 | for (var i = event.resultIndex; i < event.results.length; ++i) {
25 | if (event.results[i].isFinal) {
26 | final_transcript += event.results[i][0].transcript;
27 | $('#msg').addClass("final");
28 | $('#msg').removeClass("interim");
29 | } else {
30 | interim_transcript += event.results[i][0].transcript;
31 | $("#msg").val(interim_transcript);
32 | $('#msg').addClass("interim");
33 | $('#msg').removeClass("final");
34 | }
35 | }
36 | $("#msg").val(final_transcript);
37 | };
38 | }
39 |
40 | function startButton(event) {
41 | if (recognizing) {
42 | recognition.stop();
43 | recognizing = false;
44 | $("#start_button").prop("value", "Record");
45 | return;
46 | }
47 | final_transcript = '';
48 | recognition.lang = "en-GB"
49 | recognition.start();
50 | $("#start_button").prop("value", "Recording ... Click to stop.");
51 | $("#msg").val();
52 | }
53 | //end of WebSpeech
54 |
55 | /*
56 | Functions
57 | */
58 | function toggleNameForm() {
59 | $("#login-screen").toggle();
60 | }
61 |
62 | function toggleChatWindow() {
63 | $("#main-chat-screen").toggle();
64 | }
65 |
66 | // Pad n to specified size by prepending a zeros
67 | function zeroPad(num, size) {
68 | var s = num + "";
69 | while (s.length < size)
70 | s = "0" + s;
71 | return s;
72 | }
73 |
74 | // Format the time specified in ms from 1970 into local HH:MM:SS
75 | function timeFormat(msTime) {
76 | var d = new Date(msTime);
77 | return zeroPad(d.getHours(), 2) + ":" +
78 | zeroPad(d.getMinutes(), 2) + ":" +
79 | zeroPad(d.getSeconds(), 2) + " ";
80 | }
81 |
82 | $(document).ready(function() {
83 | //setup "global" variables first
84 | var socket = io.connect("127.0.0.1:3000");
85 | var myRoomID = null;
86 |
87 | $("form").submit(function(event) {
88 | event.preventDefault();
89 | });
90 |
91 | $("#conversation").bind("DOMSubtreeModified",function() {
92 | $("#conversation").animate({
93 | scrollTop: $("#conversation")[0].scrollHeight
94 | });
95 | });
96 |
97 | $("#main-chat-screen").hide();
98 | $("#errors").hide();
99 | $("#name").focus();
100 | $("#join").attr('disabled', 'disabled');
101 |
102 | if ($("#name").val() === "") {
103 | $("#join").attr('disabled', 'disabled');
104 | }
105 |
106 | //enter screen
107 | $("#nameForm").submit(function() {
108 | var name = $("#name").val();
109 | var device = "desktop";
110 | if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
111 | device = "mobile";
112 | }
113 | if (name === "" || name.length < 2) {
114 | $("#errors").empty();
115 | $("#errors").append("Please enter a name");
116 | $("#errors").show();
117 | } else {
118 | socket.emit("joinserver", name, device);
119 | toggleNameForm();
120 | toggleChatWindow();
121 | $("#msg").focus();
122 | }
123 | });
124 |
125 | $("#name").keypress(function(e){
126 | var name = $("#name").val();
127 | if(name.length < 2) {
128 | $("#join").attr('disabled', 'disabled');
129 | } else {
130 | $("#errors").empty();
131 | $("#errors").hide();
132 | $("#join").removeAttr('disabled');
133 | }
134 | });
135 |
136 | //main chat screen
137 | $("#chatForm").submit(function() {
138 | var msg = $("#msg").val();
139 | if (msg !== "") {
140 | socket.emit("send", new Date().getTime(), msg);
141 | $("#msg").val("");
142 | }
143 | });
144 |
145 | //'is typing' message
146 | var typing = false;
147 | var timeout = undefined;
148 |
149 | function timeoutFunction() {
150 | typing = false;
151 | socket.emit("typing", false);
152 | }
153 |
154 | $("#msg").keypress(function(e){
155 | if (e.which !== 13) {
156 | if (typing === false && myRoomID !== null && $("#msg").is(":focus")) {
157 | typing = true;
158 | socket.emit("typing", true);
159 | } else {
160 | clearTimeout(timeout);
161 | timeout = setTimeout(timeoutFunction, 5000);
162 | }
163 | }
164 | });
165 |
166 | socket.on("isTyping", function(data) {
167 | if (data.isTyping) {
168 | if ($("#"+data.person+"").length === 0) {
169 | $("#updates").append(" " + data.person + " is typing. ");
170 | timeout = setTimeout(timeoutFunction, 5000);
171 | }
172 | } else {
173 | $("#"+data.person+"").remove();
174 | }
175 | });
176 |
177 |
178 | /*
179 | $("#msg").keypress(function(){
180 | if ($("#msg").is(":focus")) {
181 | if (myRoomID !== null) {
182 | socket.emit("isTyping");
183 | }
184 | } else {
185 | $("#keyboard").remove();
186 | }
187 | });
188 |
189 | socket.on("isTyping", function(data) {
190 | if (data.typing) {
191 | if ($("#keyboard").length === 0)
192 | $("#updates").append(" " + data.person + " is typing. ");
193 | } else {
194 | socket.emit("clearMessage");
195 | $("#keyboard").remove();
196 | }
197 | console.log(data);
198 | });
199 | */
200 |
201 | $("#showCreateRoom").click(function() {
202 | $("#createRoomForm").toggle();
203 | });
204 |
205 | $("#createRoomBtn").click(function() {
206 | var roomExists = false;
207 | var roomName = $("#createRoomName").val();
208 | socket.emit("check", roomName, function(data) {
209 | roomExists = data.result;
210 | if (roomExists) {
211 | $("#errors").empty();
212 | $("#errors").show();
213 | $("#errors").append("Room " + roomName + " already exists");
214 | } else {
215 | if (roomName.length > 0) { //also check for roomname
216 | socket.emit("createRoom", roomName);
217 | $("#errors").empty();
218 | $("#errors").hide();
219 | }
220 | }
221 | });
222 | });
223 |
224 | $("#rooms").on('click', '.joinRoomBtn', function() {
225 | var roomName = $(this).siblings("span").text();
226 | var roomID = $(this).attr("id");
227 | socket.emit("joinRoom", roomID);
228 | });
229 |
230 | $("#rooms").on('click', '.removeRoomBtn', function() {
231 | var roomName = $(this).siblings("span").text();
232 | var roomID = $(this).attr("id");
233 | socket.emit("removeRoom", roomID);
234 | $("#createRoom").show();
235 | });
236 |
237 | $("#leave").click(function() {
238 | var roomID = myRoomID;
239 | socket.emit("leaveRoom", roomID);
240 | $("#createRoom").show();
241 | });
242 |
243 | $("#people").on('click', '.whisper', function() {
244 | var name = $(this).siblings("span").text();
245 | $("#msg").val("w:"+name+":");
246 | $("#msg").focus();
247 | });
248 | /*
249 | $("#whisper").change(function() {
250 | var peopleOnline = [];
251 | if ($("#whisper").prop('checked')) {
252 | console.log("checked, going to get the peeps");
253 | //peopleOnline = ["Tamas", "Steve", "George"];
254 | socket.emit("getOnlinePeople", function(data) {
255 | $.each(data.people, function(clientid, obj) {
256 | console.log(obj.name);
257 | peopleOnline.push(obj.name);
258 | });
259 | console.log("adding typeahead")
260 | $("#msg").typeahead({
261 | local: peopleOnline
262 | }).each(function() {
263 | if ($(this).hasClass('input-lg'))
264 | $(this).prev('.tt-hint').addClass('hint-lg');
265 | });
266 | });
267 |
268 | console.log(peopleOnline);
269 | } else {
270 | console.log('remove typeahead');
271 | $('#msg').typeahead('destroy');
272 | }
273 | });
274 | // $( "#whisper" ).change(function() {
275 | // var peopleOnline = [];
276 | // console.log($("#whisper").prop('checked'));
277 | // if ($("#whisper").prop('checked')) {
278 | // console.log("checked, going to get the peeps");
279 | // peopleOnline = ["Tamas", "Steve", "George"];
280 | // // socket.emit("getOnlinePeople", function(data) {
281 | // // $.each(data.people, function(clientid, obj) {
282 | // // console.log(obj.name);
283 | // // peopleOnline.push(obj.name);
284 | // // });
285 | // // });
286 | // //console.log(peopleOnline);
287 | // }
288 | // $("#msg").typeahead({
289 | // local: peopleOnline
290 | // }).each(function() {
291 | // if ($(this).hasClass('input-lg'))
292 | // $(this).prev('.tt-hint').addClass('hint-lg');
293 | // });
294 | // });
295 | */
296 |
297 | //socket-y stuff
298 | socket.on("exists", function(data) {
299 | $("#errors").empty();
300 | $("#errors").show();
301 | $("#errors").append(data.msg + " Try " + data.proposedName + " ");
302 | toggleNameForm();
303 | toggleChatWindow();
304 | });
305 |
306 | socket.on("joined", function() {
307 | $("#errors").hide();
308 | if (navigator.geolocation) { //get lat lon of user
309 | navigator.geolocation.getCurrentPosition(positionSuccess, positionError, { enableHighAccuracy: true });
310 | } else {
311 | $("#errors").show();
312 | $("#errors").append("Your browser is ancient and it doesn't support GeoLocation.");
313 | }
314 | function positionError(e) {
315 | console.log(e);
316 | }
317 |
318 | function positionSuccess(position) {
319 | var lat = position.coords.latitude;
320 | var lon = position.coords.longitude;
321 | //consult the yahoo service
322 | $.ajax({
323 | type: "GET",
324 | url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.placefinder%20where%20text%3D%22"+lat+"%2C"+lon+"%22%20and%20gflags%3D%22R%22&format=json",
325 | dataType: "json",
326 | success: function(data) {
327 | socket.emit("countryUpdate", {country: data.query.results.Result.countrycode});
328 | }
329 | });
330 | }
331 | });
332 |
333 | socket.on("history", function(data) {
334 | if (data.length !== 0) {
335 | $("#msgs").append("Last 10 messages: ");
336 | $.each(data, function(data, msg) {
337 | $("#msgs").append("" + msg + " ");
338 | });
339 | } else {
340 | $("#msgs").append("No past messages in this room. ");
341 | }
342 | });
343 |
344 | socket.on("update", function(msg) {
345 | $("#msgs").append("" + msg + " ");
346 | });
347 |
348 | socket.on("update-people", function(data){
349 | //var peopleOnline = [];
350 | $("#people").empty();
351 | $('#people').append("People online "+data.count+" ");
352 | $.each(data.people, function(a, obj) {
353 | if (!("country" in obj)) {
354 | html = "";
355 | } else {
356 | html = " ";
357 | }
358 | $('#people').append("" + obj.name + " " + html + " whisper ");
359 | //peopleOnline.push(obj.name);
360 | });
361 |
362 | /*var whisper = $("#whisper").prop('checked');
363 | if (whisper) {
364 | $("#msg").typeahead({
365 | local: peopleOnline
366 | }).each(function() {
367 | if ($(this).hasClass('input-lg'))
368 | $(this).prev('.tt-hint').addClass('hint-lg');
369 | });
370 | }*/
371 | });
372 |
373 | socket.on("chat", function(msTime, person, msg) {
374 | $("#msgs").append("" + timeFormat(msTime) + person.name + " : " + msg + " ");
375 | //clear typing field
376 | $("#"+person.name+"").remove();
377 | clearTimeout(timeout);
378 | timeout = setTimeout(timeoutFunction, 0);
379 | });
380 |
381 | socket.on("whisper", function(msTime, person, msg) {
382 | if (person.name === "You") {
383 | s = "whisper"
384 | } else {
385 | s = "whispers"
386 | }
387 | $("#msgs").append("" + timeFormat(msTime) + person.name + " "+s+": " + msg + " ");
388 | });
389 |
390 | socket.on("roomList", function(data) {
391 | $("#rooms").text("");
392 | $("#rooms").append("List of rooms "+data.count+" ");
393 | if (!jQuery.isEmptyObject(data.rooms)) {
394 | $.each(data.rooms, function(id, room) {
395 | var html = "Join " + " " + "Remove ";
396 | $('#rooms').append("" + room.name + " " + html + " ");
397 | });
398 | } else {
399 | $("#rooms").append("There are no rooms yet. ");
400 | }
401 | });
402 |
403 | socket.on("sendRoomID", function(data) {
404 | myRoomID = data.id;
405 | });
406 |
407 | socket.on("disconnect", function(){
408 | $("#msgs").append("The server is not available ");
409 | $("#msg").attr("disabled", "disabled");
410 | $("#send").attr("disabled", "disabled");
411 | });
412 |
413 | });
414 |
--------------------------------------------------------------------------------
/room.js:
--------------------------------------------------------------------------------
1 | function Room(name, id, owner) {
2 | this.name = name;
3 | this.id = id;
4 | this.owner = owner;
5 | this.people = [];
6 | this.peopleLimit = 4;
7 | this.status = "available";
8 | this.private = false;
9 | };
10 |
11 | Room.prototype.addPerson = function(personID) {
12 | if (this.status === "available") {
13 | this.people.push(personID);
14 | }
15 | };
16 |
17 | Room.prototype.removePerson = function(person) {
18 | var personIndex = -1;
19 | for(var i = 0; i < this.people.length; i++){
20 | if(this.people[i].id === person.id){
21 | personIndex = i;
22 | break;
23 | }
24 | }
25 | this.people.remove(personIndex);
26 | };
27 |
28 | Room.prototype.getPerson = function(personID) {
29 | var person = null;
30 | for(var i = 0; i < this.people.length; i++) {
31 | if(this.people[i].id == personID) {
32 | person = this.people[i];
33 | break;
34 | }
35 | }
36 | return person;
37 | };
38 |
39 | Room.prototype.isAvailable = function() {
40 | return this.available === "available";
41 | };
42 |
43 | Room.prototype.isPrivate = function() {
44 | return this.private;
45 | };
46 |
47 | module.exports = Room;
48 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express')
2 | , app = express()
3 | , server = require('http').createServer(app)
4 | , io = require("socket.io").listen(server)
5 | , npid = require("npid")
6 | , uuid = require('node-uuid')
7 | , Room = require('./room.js')
8 | , _ = require('underscore')._;
9 |
10 | app.configure(function() {
11 | app.set('port', process.env.OPENSHIFT_NODEJS_PORT || 3000);
12 | app.set('ipaddr', process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1");
13 | app.use(express.bodyParser());
14 | app.use(express.methodOverride());
15 | app.use(express.static(__dirname + '/public'));
16 | app.use('/components', express.static(__dirname + '/components'));
17 | app.use('/js', express.static(__dirname + '/js'));
18 | app.use('/icons', express.static(__dirname + '/icons'));
19 | app.set('views', __dirname + '/views');
20 | app.engine('html', require('ejs').renderFile);
21 |
22 | /* Store process-id (as priviledged user) */
23 | try {
24 | npid.create('/var/run/advanced-chat.pid', true);
25 | } catch (err) {
26 | console.log(err);
27 | //process.exit(1);
28 | }
29 |
30 | });
31 |
32 | app.get('/', function(req, res) {
33 | res.render('index.html');
34 | });
35 |
36 | server.listen(app.get('port'), app.get('ipaddr'), function(){
37 | console.log('Express server listening on IP: ' + app.get('ipaddr') + ' and port ' + app.get('port'));
38 | });
39 |
40 | io.set("log level", 1);
41 | var people = {};
42 | var rooms = {};
43 | var sockets = [];
44 | var chatHistory = {};
45 |
46 | function purge(s, action) {
47 | /*
48 | The action will determine how we deal with the room/user removal.
49 | These are the following scenarios:
50 | if the user is the owner and (s)he:
51 | 1) disconnects (i.e. leaves the whole server)
52 | - advise users
53 | - delete user from people object
54 | - delete room from rooms object
55 | - delete chat history
56 | - remove all users from room that is owned by disconnecting user
57 | 2) removes the room
58 | - same as above except except not removing user from the people object
59 | 3) leaves the room
60 | - same as above
61 | if the user is not an owner and (s)he's in a room:
62 | 1) disconnects
63 | - delete user from people object
64 | - remove user from room.people object
65 | 2) removes the room
66 | - produce error message (only owners can remove rooms)
67 | 3) leaves the room
68 | - same as point 1 except not removing user from the people object
69 | if the user is not an owner and not in a room:
70 | 1) disconnects
71 | - same as above except not removing user from room.people object
72 | 2) removes the room
73 | - produce error message (only owners can remove rooms)
74 | 3) leaves the room
75 | - n/a
76 | */
77 | if (people[s.id].inroom) { //user is in a room
78 | var room = rooms[people[s.id].inroom]; //check which room user is in.
79 | if (s.id === room.owner) { //user in room and owns room
80 | if (action === "disconnect") {
81 | io.sockets.in(s.room).emit("update", "The owner (" +people[s.id].name + ") has left the server. The room is removed and you have been disconnected from it as well.");
82 | var socketids = [];
83 | for (var i=0; i 10) {
268 | chatHistory[socket.room].splice(0,1);
269 | } else {
270 | chatHistory[socket.room].push(people[socket.id].name + ": " + msg);
271 | }
272 | } else {
273 | socket.emit("update", "Please connect to a room.");
274 | }
275 | }
276 | });
277 |
278 | socket.on("disconnect", function() {
279 | if (typeof people[socket.id] !== "undefined") { //this handles the refresh of the name screen
280 | purge(socket, "disconnect");
281 | }
282 | });
283 |
284 | //Room functions
285 | socket.on("createRoom", function(name) {
286 | if (people[socket.id].inroom) {
287 | socket.emit("update", "You are in a room. Please leave it first to create your own.");
288 | } else if (!people[socket.id].owns) {
289 | var id = uuid.v4();
290 | var room = new Room(name, id, socket.id);
291 | rooms[id] = room;
292 | sizeRooms = _.size(rooms);
293 | io.sockets.emit("roomList", {rooms: rooms, count: sizeRooms});
294 | //add room to socket, and auto join the creator of the room
295 | socket.room = name;
296 | socket.join(socket.room);
297 | people[socket.id].owns = id;
298 | people[socket.id].inroom = id;
299 | room.addPerson(socket.id);
300 | socket.emit("update", "Welcome to " + room.name + ".");
301 | socket.emit("sendRoomID", {id: id});
302 | chatHistory[socket.room] = [];
303 | } else {
304 | socket.emit("update", "You have already created a room.");
305 | }
306 | });
307 |
308 | socket.on("check", function(name, fn) {
309 | var match = false;
310 | _.find(rooms, function(key,value) {
311 | if (key.name === name)
312 | return match = true;
313 | });
314 | fn({result: match});
315 | });
316 |
317 | socket.on("removeRoom", function(id) {
318 | var room = rooms[id];
319 | if (socket.id === room.owner) {
320 | purge(socket, "removeRoom");
321 | } else {
322 | socket.emit("update", "Only the owner can remove a room.");
323 | }
324 | });
325 |
326 | socket.on("joinRoom", function(id) {
327 | if (typeof people[socket.id] !== "undefined") {
328 | var room = rooms[id];
329 | if (socket.id === room.owner) {
330 | socket.emit("update", "You are the owner of this room and you have already been joined.");
331 | } else {
332 | if (_.contains((room.people), socket.id)) {
333 | socket.emit("update", "You have already joined this room.");
334 | } else {
335 | if (people[socket.id].inroom !== null) {
336 | socket.emit("update", "You are already in a room ("+rooms[people[socket.id].inroom].name+"), please leave it first to join another room.");
337 | } else {
338 | room.addPerson(socket.id);
339 | people[socket.id].inroom = id;
340 | socket.room = room.name;
341 | socket.join(socket.room);
342 | user = people[socket.id];
343 | io.sockets.in(socket.room).emit("update", user.name + " has connected to " + room.name + " room.");
344 | socket.emit("update", "Welcome to " + room.name + ".");
345 | socket.emit("sendRoomID", {id: id});
346 | var keys = _.keys(chatHistory);
347 | if (_.contains(keys, socket.room)) {
348 | socket.emit("history", chatHistory[socket.room]);
349 | }
350 | }
351 | }
352 | }
353 | } else {
354 | socket.emit("update", "Please enter a valid name first.");
355 | }
356 | });
357 |
358 | socket.on("leaveRoom", function(id) {
359 | var room = rooms[id];
360 | if (room)
361 | purge(socket, "leaveRoom");
362 | });
363 | });
364 |
--------------------------------------------------------------------------------