├── .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 | 12 | 13 | # Functionality 14 | 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 | 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 |
17 |
18 | 19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 |
27 |
    28 |
      29 |
      30 |
      31 |
      32 |
        33 |
        34 |
        35 |
        36 | 37 |
        38 | 39 | 40 |
        41 | 44 | 49 |
        50 |
        51 |
        52 |
        53 |
          54 |
          55 |
          56 | 57 | 58 | 59 | 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 = "" + " " + ""; 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 | --------------------------------------------------------------------------------