├── .gitignore ├── actions ├── compile │ ├── index.js │ ├── javascript.js │ └── test │ │ ├── arms.js │ │ ├── cat.js │ │ ├── cat.min.js │ │ ├── eyes.js │ │ ├── hands.js │ │ ├── head.js │ │ └── legs.js ├── how.js ├── index.js ├── relabel.js ├── repeat.js ├── uglify.js ├── validate.js ├── watch.js ├── what.js └── who.js ├── bin ├── .DS_Store ├── classifier.json ├── lexicon.json └── nodebot ├── brain ├── analyze.js ├── formatter.js ├── interaction.js ├── language │ ├── .DS_Store │ └── index.js ├── lexicon.js └── time │ └── index.js ├── nodebot.js ├── package.json ├── readme.md ├── server ├── index.html ├── index.js ├── public │ ├── 404.html │ ├── config.rb │ ├── images │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon.png │ │ ├── brushed_alu.png │ │ ├── dark_dotted.png │ │ └── favicon.ico │ ├── javascripts │ │ ├── nodebot.js │ │ └── tabs.js │ ├── robots.txt │ ├── sass │ │ ├── partials │ │ │ ├── _base_type.scss │ │ │ ├── _buttons.scss │ │ │ ├── _custom.scss │ │ │ ├── _forms.scss │ │ │ ├── _grid.scss │ │ │ ├── _images.scss │ │ │ ├── _lists.scss │ │ │ ├── _misc.scss │ │ │ ├── _mixins.scss │ │ │ ├── _reset.scss │ │ │ ├── _tabs.scss │ │ │ └── _variables.scss │ │ └── style.scss │ └── stylesheets │ │ └── style.css └── routes.js ├── test ├── format-test.js ├── language-test.js └── lexicon-test.js └── validator ├── css.js ├── html.js ├── javascript.js ├── jshint_config.js ├── reporter.js └── website.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /actions/compile/index.js: -------------------------------------------------------------------------------- 1 | // Compile 2 | // -------------------------------------------------- // 3 | 4 | // Uglify reqs 5 | var fs = require('fs'); 6 | 7 | // Filters 8 | var lex = Nodebot.lexicon, 9 | fileEx = lex.file['regular expression'], 10 | urlEx = lex.url['regular expression'], 11 | jsEx = lex.javascript['regular expression'], 12 | 13 | supported = ['javascript']; 14 | 15 | 16 | // Compresses files 17 | // -------------------------------------------------- // 18 | 19 | function compressor (directory, filetype, filename) { 20 | 21 | var filter = Nodebot.lexicon[filetype]["regular expression"], 22 | newFile = filename || filetype + ".min" + lex[filetype].mime, 23 | compress = require("./" + filetype); 24 | 25 | fs.readdir(directory, function(err, files) { 26 | 27 | if (err) return false; 28 | 29 | files = files.map(function(f) { 30 | if (filename && f === filename) { 31 | } else { 32 | return directory + "/" + f; 33 | } 34 | }); 35 | 36 | try { 37 | var compressed = compress.all(directory, files, filename); 38 | return fs.writeFile(directory + "/" + newFile.trim(), compressed); 39 | } catch (x) { 40 | return false; 41 | } 42 | 43 | }); 44 | 45 | } 46 | 47 | 48 | // The Compiler 49 | // 50 | // Watches a directory for changes and compiles files 51 | // of a specific type 52 | // -------------------------------------------------- // 53 | 54 | module.exports = function compile (a) { 55 | 56 | var target = a.owner || "./" 57 | , filetype = a.subject 58 | , nodebot = this 59 | , stat; 60 | 61 | // We shouldn't compress files we don't support 62 | if (supported.indexOf(filetype) < 0) return nodebot.request("Sorry, I can't compile %s", filetype); 63 | 64 | try { 65 | stat = fs.statSync(target); 66 | } catch (err) { 67 | 68 | } 69 | 70 | // Watch directories 71 | // -------------------------------------------------- // 72 | 73 | // Is the target a directory? 74 | if (stat && stat.isDirectory()) { 75 | 76 | // Yes, watch the target 77 | fs.watch(target, { persistent: true, interval: 1000 }, function () { 78 | nodebot.say("Files have changed. Compiling all %s in %s.", filetype, target); 79 | compressor(target, filetype); 80 | }); 81 | compressor(target, filetype); 82 | nodebot.say("I am now compiling all %s in %s", filetype, target); 83 | 84 | } else { 85 | 86 | // No, use the current directory 87 | fs.watch(process.cwd(), { persistent: true, interval: 1000 }, function () { 88 | nodebot.say("Files have changed. Compiling all %s into %s.", filetype, target); 89 | compressor(process.cwd(), filetype, target); 90 | }); 91 | 92 | nodebot.say("I am now compiling all %s into %s", filetype, target); 93 | compressor(process.cwd(), filetype, target); 94 | } 95 | 96 | // Closeout 97 | // -------------------------------------------------- // 98 | 99 | compressor(target, filetype); 100 | 101 | // Make it so that when the user exits watching, it loads 102 | // up another prompt 103 | process.once('SIGINT', function () { 104 | nodebot.request("Okay, I am no longer compiling %s files.", filetype, target); 105 | }); 106 | 107 | }; 108 | -------------------------------------------------------------------------------- /actions/compile/javascript.js: -------------------------------------------------------------------------------- 1 | // Javascript Compressor 2 | // A simple module for uglifying javascripts 3 | // -------------------------------------------------- // 4 | 5 | var jsp = require("uglify-js").parser, 6 | pro = require("uglify-js").uglify, 7 | fs = require('fs') 8 | ; 9 | 10 | // Given an array, move the "from" to "to" 11 | // -------------------------------------------------- // 12 | 13 | function move (array, from, to) { 14 | array.splice(to, 0, array.splice(from, 1)[0]); 15 | }; 16 | 17 | 18 | // Get all requirements from files and sort accordingly 19 | // -------------------------------------------------- // 20 | 21 | function sortRequirements (files, directory) { 22 | 23 | var output = []; 24 | 25 | files.forEach(function (item) { 26 | 27 | var doc = item[1].split("\n\n")[0]; 28 | 29 | if (!doc) return false; 30 | 31 | var match = doc.match(/\/\/= require\s\S+(\s+|)/ig), 32 | matches = []; 33 | 34 | match && match.forEach(function(m) { 35 | var req = m.replace(/\/\/= require\s/ig, "").trim(); 36 | 37 | matches.push(directory + "/" + req); 38 | }); 39 | 40 | output.push({ 41 | filename : item[0], 42 | content : item[1], 43 | requirements : matches 44 | }); 45 | 46 | }); 47 | 48 | // For each file we output 49 | output.forEach(function(a, indexParent) { 50 | 51 | // Check each file for possible requirements 52 | output.forEach(function(b, indexChild) { 53 | 54 | // Yes? move the required child before the parent 55 | if (a.requirements.indexOf(b.filename) > -1) { 56 | move(output, indexChild, indexParent - 1); 57 | } 58 | 59 | }); 60 | 61 | }); 62 | 63 | return output; 64 | } 65 | 66 | 67 | 68 | // A simple uglifier script 69 | function compress (filename, content) { 70 | 71 | var ret = ""; 72 | 73 | content = jsp.parse(content.toString()); 74 | content = pro.ast_mangle(content); 75 | content = pro.ast_squeeze(content); 76 | 77 | // Add the records 78 | ret += "\/\/ " + filename; 79 | ret += "\n" + pro.gen_code(content) + ";\n\n"; 80 | 81 | return ret; 82 | 83 | }; 84 | 85 | 86 | // A simple uglifier script 87 | function compressAll (directory, files, filename) { 88 | 89 | var stack = [], 90 | newFile = directory + "/" + (filename || "javascript.min.js"), 91 | filter = Nodebot.lexicon.javascript["regular expression"]; 92 | 93 | // Filter down to only the non-hidden files of the type 94 | // And not the filtered file we'll create 95 | 96 | files.filter(function(f) { 97 | return f !== filename && filter.test(f); 98 | }).forEach(function(f) { 99 | try { 100 | stack.push([f, fs.readFileSync(f).toString()]); 101 | } catch (x) {} 102 | }); 103 | 104 | files = sortRequirements(stack, directory); 105 | 106 | var output = "// Uglified by Nodebot \n//\n// " + new Date().toString() 107 | + "\n\/\/" + Array(60).join("-") 108 | + "\n\n;" 109 | ; 110 | 111 | files.forEach(function(f) { 112 | output += compress(f.filename, f.content); 113 | }); 114 | 115 | return output; 116 | 117 | }; 118 | 119 | 120 | 121 | // Exports 122 | // -------------------------------------------------- // 123 | 124 | module.exports.all = compressAll; 125 | module.exports.single = compress; -------------------------------------------------------------------------------- /actions/compile/test/arms.js: -------------------------------------------------------------------------------- 1 | //= require cat.js -------------------------------------------------------------------------------- /actions/compile/test/cat.js: -------------------------------------------------------------------------------- 1 | // do something 2 | 3 | function cat () { 4 | 5 | } -------------------------------------------------------------------------------- /actions/compile/test/cat.min.js: -------------------------------------------------------------------------------- 1 | // Uglified by Nodebot 2 | // 3 | // Sun Jan 29 2012 21:56:00 GMT-0500 (EST) 4 | //----------------------------------------------------------- 5 | 6 | // /Users/nate/Sites/nodebot/actions/compile/test/cat.js 7 | function cat(){} 8 | 9 | // /Users/nate/Sites/nodebot/actions/compile/test/legs.js 10 | function legs(){} 11 | 12 | // /Users/nate/Sites/nodebot/actions/compile/test/arms.js 13 | 14 | 15 | // /Users/nate/Sites/nodebot/actions/compile/test/hands.js 16 | function hands(){} 17 | 18 | // /Users/nate/Sites/nodebot/actions/compile/test/head.js 19 | function head(){} 20 | 21 | // /Users/nate/Sites/nodebot/actions/compile/test/eyes.js 22 | function eyes(){} 23 | 24 | -------------------------------------------------------------------------------- /actions/compile/test/eyes.js: -------------------------------------------------------------------------------- 1 | // do something 2 | // 3 | //= require cat.js 4 | //= require head.js 5 | 6 | function eyes () { 7 | 8 | } -------------------------------------------------------------------------------- /actions/compile/test/hands.js: -------------------------------------------------------------------------------- 1 | //= require arms.js 2 | //= require cat.js 3 | 4 | function hands () { 5 | 6 | } -------------------------------------------------------------------------------- /actions/compile/test/head.js: -------------------------------------------------------------------------------- 1 | // do something 2 | //= require cat.js 3 | 4 | 5 | function head () { 6 | 7 | } -------------------------------------------------------------------------------- /actions/compile/test/legs.js: -------------------------------------------------------------------------------- 1 | //= require cat.js 2 | 3 | function legs () { 4 | 5 | } -------------------------------------------------------------------------------- /actions/how.js: -------------------------------------------------------------------------------- 1 | // How 2 | // Basically an alias for "what" 3 | // -------------------------------------------------- // 4 | 5 | module.exports = function how (a) { 6 | 7 | // Do we have success? 8 | if (a.owner && a.subject) { 9 | return this.actions.what.apply(this, [a]); 10 | } 11 | 12 | this.say("I don't know how to %s", a.subject); 13 | return this.request(); 14 | 15 | }; -------------------------------------------------------------------------------- /actions/index.js: -------------------------------------------------------------------------------- 1 | // Actions 2 | // 3 | // Tells the nodebot how to do a command 4 | // -------------------------------------------------- // 5 | 6 | var actions = {}; 7 | 8 | // Who 9 | actions.who = require("./who"); 10 | 11 | // Relabel 12 | // actions.relabel = actions.set = require("./relabel"); 13 | 14 | // What 15 | actions.what = require("./what"); 16 | 17 | // Validate, Wrong 18 | actions.validate = actions.wrong = require("./validate"); 19 | 20 | // Watch, Look 21 | actions.watch = actions.look = require("./watch"); 22 | 23 | // Compile 24 | actions.compile = actions.compress = require("./compile"); 25 | 26 | // How 27 | actions.how = require("./how"); 28 | 29 | actions.repeat = actions.again = require("./repeat"); 30 | 31 | // Export it all out 32 | // -------------------------------------------------- // 33 | 34 | module.exports = actions; -------------------------------------------------------------------------------- /actions/relabel.js: -------------------------------------------------------------------------------- 1 | // Relabel 2 | // -------------------------------------------------- // 3 | 4 | var lang = require("../brain/language"); 5 | 6 | module.exports = function relabel (a) { 7 | 8 | var nodebot = this 9 | , ownership = a.owner 10 | , subject = a.subject 11 | , description = lang.capitalize(a.description) 12 | ; 13 | 14 | console.log(a); 15 | 16 | if (ownership === subject) { 17 | subject = "definition"; 18 | } 19 | 20 | // Standard bullet proofing 21 | nodebot.lexicon[ownership] = nodebot.lexicon[ownership] || {}; 22 | 23 | nodebot.ask("Just to confirm," + " you said that " + lang.possessify(ownership) + " " + a.subject + " " + a.keyverb + " " + description.green.bold + "? (y/n)", function(data) { 24 | 25 | if (data[0].toLowerCase() === "y") { 26 | nodebot.say("Okay, thanks! Now I know that " + (lang.possessify(ownership) + " " + subject + " is " + description).green.bold); 27 | nodebot.lexicon[ownership][subject] = description; 28 | } else { 29 | nodebot.say("I must be confused, sorry."); 30 | } 31 | 32 | return nodebot.request(); 33 | 34 | }); 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /actions/repeat.js: -------------------------------------------------------------------------------- 1 | // Repeat actions 2 | // -------------------------------------------------- // 3 | 4 | module.exports = function repeat () { 5 | 6 | var action = ""; 7 | 8 | if (this.memory.tasks === []) { 9 | this.say("I haven't done anything yet."); 10 | return this.request(); 11 | } else { 12 | action = this.memory.tasks.slice(-1).toString(); 13 | } 14 | 15 | // Run the old action 16 | return this.analyze(action); 17 | 18 | }; -------------------------------------------------------------------------------- /actions/uglify.js: -------------------------------------------------------------------------------- 1 | // Uglify 2 | // -------------------------------------------------- // 3 | 4 | var fs = require('fs'); 5 | 6 | // Scanners 7 | var urlEx = Nodebot.lexicon.url['regular expression'] 8 | , fileEx = Nodebot.lexicon.file['regular expression'] 9 | ; 10 | 11 | var supported = ['javascript']; 12 | 13 | module.exports = function uglify (a) { 14 | 15 | var directory = a.owner || "./" 16 | , filetype = a.subject 17 | , nodebot = this 18 | , stat; 19 | 20 | console.log(a); 21 | 22 | // Bullet proof websites 23 | if (directory.match(urlEx)) return nodebot.request("Sorry, I can't compile websites"); 24 | 25 | try { 26 | stat = fs.statSync(directory); 27 | } catch (err) { 28 | nodebot.say("Hmm, I couldn't find %s. Does it exist?", directory); 29 | return nodebot.request(); 30 | } 31 | 32 | // Watch directories 33 | // -------------------------------------------------- // 34 | 35 | if (stat.isDirectory()) { 36 | 37 | fs.watch(directory, { persistent: true, interval: 1000 }, function (event, filename) { 38 | nodebot.say("Looks like something has changed in " + directory.blue.bold); 39 | }); 40 | 41 | } 42 | 43 | // Closeout 44 | // -------------------------------------------------- // 45 | 46 | nodebot.say("I am now compiling all %s in %s", filetype.blue.bold, directory.blue); 47 | 48 | // Make it so that when the user exits watching, it loads 49 | // up another prompt 50 | process.once('SIGINT', function () { 51 | nodebot.request("Okay, I am no longer watching", directory.blue.bold); 52 | }); 53 | 54 | }; 55 | -------------------------------------------------------------------------------- /actions/validate.js: -------------------------------------------------------------------------------- 1 | // Validate 2 | // -------------------------------------------------- // 3 | 4 | var fs = require('fs'); 5 | 6 | // Scanners 7 | var urlEx = Nodebot.lexicon.url['regular expression'] 8 | , fileEx = Nodebot.lexicon.file['regular expression'] 9 | , jsEx = Nodebot.lexicon.javascript['regular expression'] 10 | , cssEx = Nodebot.lexicon.css['regular expression'] 11 | , htmlEx = Nodebot.lexicon.html['regular expression'] 12 | ; 13 | 14 | 15 | module.exports = function validate (a, skipRequest) { 16 | 17 | var target = a.subject.split(" ").join("") 18 | , nodebot = this; 19 | 20 | if (!target.match(urlEx)) { 21 | 22 | try { 23 | fs.statSync(target); 24 | } catch (err) { 25 | nodebot.say("I had trouble finding " + target + ". Does it exist?".cyan); 26 | 27 | return nodebot.request(); 28 | } 29 | } 30 | 31 | function dispatch(fileType) { 32 | require("../validator/" + fileType).validate.apply(nodebot, [target, function cb() { 33 | return (skipRequest) ? false : nodebot.request(); 34 | }]); 35 | } 36 | 37 | // VALIDATORS 38 | // -------------------------------------------------- // 39 | 40 | // Javascript 41 | if (target.match(jsEx)) dispatch("javascript"); 42 | 43 | // CSS 44 | else if (target.match(cssEx)) dispatch("css"); 45 | 46 | // Websites 47 | else if (target.match(urlEx)) dispatch("website"); 48 | 49 | // HTML 50 | else if (target.match(htmlEx)) dispatch("html"); 51 | 52 | // Elsecase 53 | else { 54 | this.say("I'm sorry, I don't recognize that file format yet"); 55 | if (!skipRequest) return nodebot.request(); 56 | } 57 | 58 | }; 59 | -------------------------------------------------------------------------------- /actions/watch.js: -------------------------------------------------------------------------------- 1 | // Watch 2 | // -------------------------------------------------- // 3 | 4 | var fs = require('fs') 5 | , os = require('os'); 6 | 7 | // Scanners 8 | var urlEx = Nodebot.lexicon.url['regular expression'] 9 | , fileEx = Nodebot.lexicon.file['regular expression'] 10 | , jsEx = Nodebot.lexicon.javascript['regular expression'] 11 | , cssEx = Nodebot.lexicon.css['regular expression'] 12 | , htmlEx = Nodebot.lexicon.html['regular expression'] 13 | ; 14 | 15 | module.exports = function watch (a) { 16 | 17 | var file = a.subject || "./" 18 | , nodebot = this 19 | , stat; 20 | 21 | // Bullet proof websites 22 | if (file.match(urlEx)) { 23 | this.say("This is a website. I don't know how to watch these yet, so I'll pass it through the web validator"); 24 | return nodebot.actions.validate.apply(this, [a]); 25 | } 26 | 27 | try { 28 | stat = fs.statSync(file); 29 | } catch (err) { 30 | nodebot.say("I couldn't find that file, does it exist?"); 31 | return nodebot.request(); 32 | } 33 | 34 | // Watch files 35 | // -------------------------------------------------- // 36 | 37 | stat.isFile() && fs.watchFile(file, { persistent: true, interval: 1000 }, function (curr, prev) { 38 | 39 | var content = fs.readFileSync(file, "utf-8"); 40 | 41 | if (content !== nodebot.memory.watched_content) { 42 | nodebot.say("Looks like something has changed on " + file.blue.bold); 43 | nodebot.actions.validate.apply(nodebot, [a, true]); 44 | 45 | // Update with new content 46 | nodebot.memory.watched_content = content; 47 | } 48 | }); 49 | 50 | 51 | // Watch directories 52 | // -------------------------------------------------- // 53 | 54 | if (stat.isDirectory()) { 55 | 56 | // Are we dealing with OSX? 57 | switch(os.type()) { 58 | 59 | case "Darwin": 60 | return nodebot.say("Node v%s doesn't have good fs.watch support on %s, I'm sorry :(", process.versions.node, "OSX".cyan); 61 | break; 62 | 63 | default: 64 | fs.watch(file, { persistent: true, interval: 1000 }, function (event, filename) { 65 | 66 | if (!filename) return false; 67 | 68 | var content = fs.readFileSync(filename, "utf-8"); 69 | 70 | if (content !== nodebot.memory.watched_content) { 71 | nodebot.say("Looks like something has changed on " + file.blue.bold); 72 | actions.validate.apply(nodebot, [a, true]); 73 | 74 | // Update with new content 75 | nodebot.memory.watched_content = content; 76 | } 77 | }); 78 | } 79 | 80 | } 81 | 82 | 83 | // Closeout 84 | // -------------------------------------------------- // 85 | 86 | nodebot.say("I am now watching " + file.blue.bold); 87 | 88 | // Make it so that when the user exits watching, it loads 89 | // up another prompt 90 | process.once('SIGINT', function () { 91 | nodebot.say("I am no longer watching " + file.blue.bold); 92 | nodebot.request(); 93 | }); 94 | 95 | }; 96 | -------------------------------------------------------------------------------- /actions/what.js: -------------------------------------------------------------------------------- 1 | // What.js 2 | // "What is your name?", 3 | // "What is the capital of Spain?" 4 | // -------------------------------------------------- // 5 | 6 | var lang = require("../brain/language") 7 | , fileEx = Nodebot.lexicon.file["regular expression"] 8 | , request = require("request") 9 | , format = require("../brain/formatter") 10 | ; 11 | 12 | 13 | module.exports = function what (a) { 14 | 15 | if (a.owner === a.subject) a.subject = "definition"; 16 | 17 | var nodebot = this 18 | , owner = a.owner 19 | , subject = a.subject || "definition" 20 | 21 | , base = (owner) ? nodebot.lexicon[owner] : nodebot.lexicon 22 | , term = (subject && base) ? base[subject] : undefined 23 | ; 24 | 25 | // Just some more bullet proofing for the subject 26 | subject = (owner === subject) ? "definition" : subject; 27 | 28 | // If the term is a function, call it to determin the value 29 | if (typeof term === "function") term = term().toString(); 30 | 31 | // If it is a file, simply return that it is a file 32 | if (fileEx.test(subject)) { 33 | return nodebot.say(owner.cyan + " is a file.").request(); 34 | } 35 | 36 | 37 | // Do we have a definition for this subject? 38 | // -------------------------------------------------- // 39 | 40 | if (term) { 41 | 42 | switch (subject) { 43 | 44 | case "definition": 45 | nodebot.say(lang.capitalize(owner) + " is " + term.green.bold); 46 | break; 47 | default: 48 | nodebot.say(lang.possessify(lang.capitalize(owner)) + " " + subject + " is " + term.toString().green.bold); 49 | } 50 | 51 | return nodebot.request(); 52 | 53 | } 54 | 55 | 56 | // No, search WolframAlpha 57 | // 58 | // For more information visit: 59 | // http://www.wolframalpha.com/termsofuse.html#attributionandlicensing 60 | // -------------------------------------------------- // 61 | 62 | var app_id = "GVH84U-9YQ66P7PU3"; 63 | 64 | var qs = require('querystring') 65 | , sax = require("../sax-js") 66 | , strict = true 67 | , parser = sax.parser(strict) 68 | , request = require("request") 69 | , data = qs.stringify({ input: a.tokens.join(" ") }) 70 | ; 71 | 72 | nodebot.say("Hmm, I don't know off the top of my head. Let me ask around..."); 73 | 74 | request.get("http://api.wolframalpha.com/v2/query?" + data + "&appid=" + app_id, function(err, data) { 75 | 76 | var result = []; 77 | 78 | parser.ontext = function(t) { 79 | var proc = t.trim(); 80 | if (proc !== "" && proc !== "\n") result.push(proc); 81 | }; 82 | 83 | parser.onend = function () { 84 | 85 | // If nothing was found, then we have an issue 86 | // -------------------------------------------------- // 87 | 88 | if (result.length === 0) { 89 | nodebot.say("I couldn't find anything, sorry :("); 90 | return nodebot.request(); 91 | } 92 | 93 | nodebot.say("Here's what I found:\n"); 94 | 95 | var tidbit = []; 96 | 97 | format.drawLine(); 98 | console.log(format.align(result[0], 80).bold.red); 99 | format.drawLine(); 100 | 101 | console.log(""); 102 | 103 | var message = ""; 104 | 105 | result = result.filter(function(i) { return i.trim() !== ""; }); 106 | 107 | result.slice(1, 4).forEach(function(i) { 108 | 109 | if (i.split("|").length > 1) { 110 | message += "\n" + format.clump(i.split("|").join(": ")); 111 | 112 | } else { 113 | var tmp = i.split("\n").join(". ").trim(); 114 | message += "\n\n" + format.clump(tmp, 76); 115 | } 116 | 117 | }); 118 | 119 | var credit = "Courtesy of " + "WolframAlpha" + " (http://www.wolframalpha.com)"; 120 | 121 | nodebot.io && nodebot.io.sockets.emit('output', message); 122 | nodebot.io && nodebot.io.sockets.emit('output', credit); 123 | 124 | console.log(""); 125 | 126 | format.drawLine(); 127 | console.log(format.align(credit, 80)); 128 | format.drawLine(); 129 | 130 | return nodebot.request(); 131 | 132 | }; 133 | 134 | parser.write(data.body).close(); 135 | 136 | 137 | }); 138 | 139 | }; 140 | -------------------------------------------------------------------------------- /actions/who.js: -------------------------------------------------------------------------------- 1 | // Who 2 | // -------------------------------------------------- // 3 | 4 | var lang = require("../brain/language"); 5 | 6 | module.exports = function who(a) { 7 | 8 | var nodebot = this 9 | , owner = a.owner 10 | , key = a.subject 11 | ; 12 | 13 | // Special instances 14 | // -------------------------------------------------- // 15 | switch(owner){ 16 | 17 | case "nodebot": 18 | 19 | if (this.lexicon.nodebot[key]) { 20 | this.say("My " + key + " is " + this.lexicon.nodebot[key]); 21 | } else { 22 | this.say(this.lexicon.nodebot.name + " is " + this.lexicon.nodebot.definition); 23 | } 24 | 25 | return this.request(); 26 | 27 | case "user": 28 | 29 | if (this.lexicon.user[key]) { 30 | this.say("You are my master, " + this.lexicon.user.name); 31 | } else { 32 | this.say("Hmm... I can't remember, " + this.lexicon.user.name); 33 | } 34 | return this.request(); 35 | } 36 | 37 | 38 | // Typical cases 39 | // -------------------------------------------------- // 40 | 41 | if (nodebot.lexicon[owner] !== undefined) { 42 | this.say(lang.capitalize(owner) + " is " + this.lexicon[owner][key].green.bold); 43 | return this.request(); 44 | } 45 | 46 | 47 | return nodebot.actions.what.apply(nodebot, [a]); 48 | 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /bin/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/bin/.DS_Store -------------------------------------------------------------------------------- /bin/classifier.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/bin/classifier.json -------------------------------------------------------------------------------- /bin/lexicon.json: -------------------------------------------------------------------------------- 1 | {"you":"Lexicon","bird":"flying creatures","me":"Nate","app.j":"no","it":"no"} -------------------------------------------------------------------------------- /bin/nodebot: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require("../nodebot.js"); 4 | 5 | Nodebot.boot(process.argv[2] === "-s"); -------------------------------------------------------------------------------- /brain/analyze.js: -------------------------------------------------------------------------------- 1 | // The A Module 2 | // -------------------------------------------------- // 3 | 4 | var lang = require("./language"), 5 | n = Nodebot; 6 | 7 | module.exports = function (data) { 8 | 9 | var a = lang.classify(data); 10 | 11 | // let's filter the ownership 12 | switch(a.owner) { 13 | 14 | // Reverse user possession 15 | case "speaker": 16 | a.owner = "user"; 17 | break; 18 | 19 | // Reverse nodebot possession 20 | case "listener": 21 | a.owner = "nodebot"; 22 | break; 23 | 24 | // Tweak other non-specific possession cases to the last 25 | // recorded context 26 | case "it": case "its": case "they": case "their": 27 | case "he": case "she": case "his": case "hers": 28 | a.owner = Nodebot.memory.context; 29 | break; 30 | } 31 | 32 | 33 | // If there is no action, but the owner is the user or the robot, it 34 | // is a relabeling 35 | 36 | if (!a.action || (!a.owner && a.subject === "")) { 37 | n.say("I'm not sure what you are asking me to do, please clarify"); 38 | return n.request(); 39 | } 40 | 41 | // Now, let's also figure out the best action to take based upon 42 | // what the nodebot can actually do 43 | var action = lang.closest(a.action, Object.keys(this.actions)); 44 | 45 | // Unless we are repeating the action, store it for later recollection 46 | if (action !== "repeat") { 47 | n.memory.tasks.push(data); 48 | n.memory.context = a.ownership; 49 | } 50 | 51 | return n.actions[action].apply(n, [a]); 52 | 53 | }; -------------------------------------------------------------------------------- /brain/formatter.js: -------------------------------------------------------------------------------- 1 | 2 | // Formatter.js 3 | // 4 | // Provides some helper functions 5 | 6 | module.exports.align = function align (string, width, orientation) { 7 | 8 | var spacer = "" 9 | , count = 0 10 | ; 11 | 12 | // We need to make sure the width is long enough 13 | width = (width > string.length) ? width : string.length; 14 | 15 | switch(orientation) { 16 | 17 | case "left": 18 | count = Math.round(width - string.length + 1); 19 | spacer = Array(count).join(" "); 20 | return string + spacer; 21 | 22 | case "right": 23 | count = Math.round((width - string.length) + 1); 24 | spacer = Array(count).join(" "); 25 | return spacer + string; 26 | 27 | case "center": default: 28 | count = Math.round(((width / 2) - (string.length / 2)) + 1); 29 | spacer = Array(count).join(" "); 30 | return spacer + string + spacer; 31 | 32 | } 33 | 34 | }; 35 | 36 | 37 | 38 | // Draws a horizontal line, given a length 39 | // -------------------------------------------------- // 40 | 41 | module.exports.drawLine = function drawLine (length) { 42 | console.log(Array(length || 80).join("-")); 43 | } 44 | 45 | 46 | 47 | // Keeps lines at a specific word count 48 | // and keeps them in proper left alignment 49 | // -------------------------------------------------- // 50 | 51 | module.exports.clump = function clump (words, limit, lineOffset) { 52 | 53 | limit = limit || 80; 54 | lineOffset = lineOffset || 0; 55 | 56 | var clump = [] 57 | , offset = "" 58 | , line = [] 59 | ; 60 | 61 | // Run through a loop of all words 62 | words.split(" ").forEach(function(word) { 63 | 64 | // Get the length of the current line, which is: 65 | // the line offset + the current line + the new word 66 | var length = lineOffset + line.join(" ").length + word.length; 67 | 68 | // Is the length of the new line greater than the limit? 69 | if (length <= limit) { 70 | 71 | // no : push the new word into the current line 72 | line.push(word.trim()); 73 | 74 | } else { 75 | 76 | // yes : push the line in to the clump and reset 77 | // the line 78 | clump.push(line.join(" ")); 79 | line = [word]; 80 | } 81 | 82 | }); 83 | 84 | // This process skips the last line, so let's add it now: 85 | clump.push(line.join(" ")); 86 | 87 | 88 | // Now, create the left margin by compressing an array 89 | // into a string 90 | offset = Array(lineOffset).join(" "); 91 | 92 | // Filter whitespace and pull everthing together 93 | clump = clump.map(function(c) { 94 | return c.trim() 95 | }).join("\n" + offset).slice(0, -1); 96 | 97 | return clump; 98 | 99 | }; 100 | 101 | 102 | 103 | // A whitespace generator 104 | // Creates a blank Array and stitches it together 105 | // -------------------------------------------------- // 106 | 107 | module.exports.whitespace = function whitespace (length, max) { 108 | 109 | max = max || 12; 110 | 111 | var num = Math.abs(12 - (length || 0)) 112 | , space = Array(num); 113 | 114 | return space.join(" "); 115 | 116 | } 117 | -------------------------------------------------------------------------------- /brain/interaction.js: -------------------------------------------------------------------------------- 1 | // The Analysis Module 2 | // -------------------------------------------------- // 3 | 4 | var growl = require('growl'), 5 | util = require("util"); 6 | 7 | module.exports = function add_interaction_module(context) { 8 | 9 | var nodebot = Nodebot; 10 | 11 | // Handle Prompts 12 | // -------------------------------------------------- // 13 | 14 | nodebot.ask = function ask(question, callback) { 15 | var stdin = process.stdin 16 | , stdout = process.stdout; 17 | 18 | stdout.write("\n" + this.lexicon.nodebot.name.magenta.bold + ": " + question + "\n Response: ".blue.bold); 19 | stdin.resume(); 20 | 21 | stdin.once('data', function(data) { 22 | callback(data.toString()); 23 | }); 24 | }; 25 | 26 | nodebot.request = function() { 27 | 28 | if (arguments) nodebot.say.apply(nodebot, arguments); 29 | 30 | var statement = "What can I help you with?"; 31 | nodebot.ask(statement, function(command) { 32 | nodebot.analyze(command); 33 | }); 34 | }; 35 | 36 | nodebot.say = function() { 37 | 38 | var message = util.format.apply(null, arguments); 39 | 40 | if (nodebot.io) { 41 | nodebot.io.sockets.emit('output', message); 42 | } else { 43 | console.log(nodebot.lexicon.nodebot.name.magenta.bold + ": " + message); 44 | } 45 | 46 | return this; 47 | }; 48 | 49 | nodebot.growl = function (message, type) { 50 | growl(message, { title: 'NodeBot:' }); 51 | 52 | return this; 53 | }; 54 | 55 | }; -------------------------------------------------------------------------------- /brain/language/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/brain/language/.DS_Store -------------------------------------------------------------------------------- /brain/language/index.js: -------------------------------------------------------------------------------- 1 | // The Language Module 2 | // -------------------------------------------------- // 3 | 4 | var speak = require("speakeasy-nlp"); 5 | var lang = {}; 6 | 7 | lang.classify = speak.classify; 8 | lang.closest = speak.closest; 9 | 10 | lang.possessify = function (str) { 11 | 12 | if (!lang.isPossessive(str) && str !== "") { 13 | str = str + (str.slice(-1).toLowerCase() === "s" ? "'" : "'s"); 14 | } 15 | 16 | return str; 17 | 18 | }; 19 | 20 | lang.depossessify = function (string) { 21 | 22 | var str = string; 23 | 24 | if (lang.isPossessive(str)) { 25 | 26 | if (str.match("'s")) { 27 | str = str.slice(0, -2); 28 | } else { 29 | str = str.slice(0, -1); 30 | } 31 | 32 | } 33 | 34 | return str; 35 | }; 36 | 37 | lang.isPossessive = function (str) { 38 | str = str.slice(-2); 39 | 40 | return (str === "'s" || str === "s'"); 41 | }; 42 | 43 | lang.capitalize = function (string) { 44 | if (typeof string !== 'string') return string; 45 | return string[0].toUpperCase() + string.slice(1); 46 | }; 47 | 48 | module.exports = lang; -------------------------------------------------------------------------------- /brain/lexicon.js: -------------------------------------------------------------------------------- 1 | 2 | // The Nodebot Lexicon 3 | // -------------------------------------------------- // 4 | 5 | var lexicon = {} 6 | , os = require("os") 7 | , home = process.cwd() 8 | , system = os.type().replace("Darwin", "OSX") + os.release() + "(" + os.arch() + ")" 9 | ; 10 | 11 | 12 | module.exports = lexicon = { 13 | 14 | nodebot: { 15 | 16 | definition: "a robot, it lives to serve.", 17 | 18 | name: "Nodebot", 19 | 20 | 'favorite color': "green".green.bold, 21 | 22 | birthday: new Date().toString(), 23 | 24 | time : function() { 25 | return new Date().toString(); 26 | } 27 | }, 28 | 29 | user: { 30 | 31 | name : "Master", 32 | 33 | definition : "my master.", 34 | 35 | "current directory" : home, 36 | 37 | "operating system" : system, 38 | 39 | "host name" : os.hostname(), 40 | 41 | "free memory" : (os.freemem() / 1000000) + "MB", 42 | 43 | 'ip address' : function() { 44 | 45 | var os = require('os') 46 | , ifaces = os.networkInterfaces() 47 | , addresses = "" 48 | ; 49 | 50 | for (var dev in ifaces) { 51 | 52 | ifaces[dev].forEach(function(details){ 53 | if (details.family === 'IPv4') { 54 | addresses += "\n" + ((details.internal) ? " local - " : "external - ") + details.address; 55 | } 56 | }); 57 | } 58 | 59 | return "\n" + addresses; 60 | 61 | }, 62 | 63 | 'ip addresses' : function() { 64 | return self.lexicon.user['ip address'](); 65 | } 66 | 67 | }, 68 | 69 | 'up' : { 70 | definition: "What's up? I'm not really sure, it's so hard to explain to " 71 | + "4 dimensional beings" 72 | }, 73 | 74 | 75 | // OS Lex 76 | // ---------- // 77 | 78 | "current directory" : { 79 | definition: home 80 | }, 81 | 82 | "operating system" : { 83 | definition: system 84 | }, 85 | 86 | "time": { 87 | definition: function() { 88 | return new Date().toString(); 89 | } 90 | }, 91 | 92 | // Regular expression related items 93 | // -------------------------------------------------- // 94 | 95 | "email": { 96 | definition : "Messages sent across the internet", 97 | "regular expression" : /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\.+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 98 | }, 99 | 100 | "url": { 101 | definition : "The address for a website or location on the internet", 102 | "regular expression" : /\b(?:(?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))/ 103 | }, 104 | 105 | "file": { 106 | definition : "A place where information is stored on a computer", 107 | "regular expression" : /\S+\.\S+[^\/\?]/ 108 | }, 109 | 110 | "javascript": { 111 | definition : "The language of the internet", 112 | "regular expression" : /\.js$/, 113 | mime : ".js" 114 | }, 115 | 116 | "css": { 117 | definition : "The great beautifier of the internet", 118 | "regular expression" : /\.css$/, 119 | mime : ".css" 120 | }, 121 | 122 | "sass": { 123 | definition : "Syntaxually awesome stylesheets", 124 | "regular expression" : /\.sass$/, 125 | mime : ".sass" 126 | }, 127 | 128 | "scss": { 129 | definition : "Syntaxually awesome stylesheets", 130 | "regular expression" : /\.scss$/, 131 | mime : ".scss" 132 | }, 133 | 134 | "html": { 135 | definition : "The great information organizer of the internet", 136 | "regular expression" : /\.html$/, 137 | mime : ".html" 138 | } 139 | 140 | }; 141 | 142 | -------------------------------------------------------------------------------- /brain/time/index.js: -------------------------------------------------------------------------------- 1 | 2 | // The Time Module 3 | // -------------------------------------------------- // 4 | 5 | var moment = require("moment"); 6 | 7 | module.exports = function time () { 8 | 9 | this.tomorrow = moment().add("days", 1); 10 | 11 | }; -------------------------------------------------------------------------------- /nodebot.js: -------------------------------------------------------------------------------- 1 | // Nodebot.js 2 | // 3 | // Description: A helper robot that lives to serve 4 | // Author: Nate Hunzaker 5 | // -------------------------------------------------- // 6 | // Licence: MIT 7 | // -------------------------------------------------- // 8 | //-- require application.js 9 | //-- require nodebot.js 10 | 11 | 12 | require('colors'); 13 | 14 | // Get the initial action 15 | var command = process.argv.slice(2).join(" ").trim(); 16 | 17 | // -------------------------------------------------- // 18 | 19 | Nodebot = new(require("events").EventEmitter)(); 20 | 21 | // short term memory 22 | Nodebot.memory = { 23 | tasks : [], 24 | context : "nodebot" 25 | }; 26 | 27 | // long term memory 28 | Nodebot.lexicon = require("./brain/lexicon"); 29 | 30 | // The linguistics module 31 | Nodebot.language = require("./brain/language"); 32 | 33 | // All actions the nodebot can take 34 | Nodebot.actions = require("./actions"); 35 | 36 | // Adds the decision making module 37 | Nodebot.analyze = require("./brain/analyze"); 38 | 39 | // Adds common interactions, such as say, growl, ask and request 40 | require("./brain/interaction")(Nodebot); 41 | 42 | // -------------------------------------------------- // 43 | 44 | Nodebot.boot = function(server) { 45 | 46 | if (server) { 47 | var app = require("./server"); 48 | } else { 49 | (command !== "") ? Nodebot.analyze(command) : Nodebot.request(); 50 | } 51 | 52 | }; 53 | 54 | // Take the proper initial action 55 | 56 | if (!module.parent) { 57 | 58 | process.on("exit", function() { 59 | console.log(""); 60 | }); 61 | 62 | Nodebot.boot(command === "-s"); 63 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodebot", 3 | "description": "An artificial intelligence written for NodeJS", 4 | "version": "0.1.7", 5 | 6 | "homepage": "", 7 | 8 | "engines": { 9 | "node": ">=0.6.4" 10 | }, 11 | 12 | "dependencies": { 13 | 14 | "csslint" : "*", 15 | "colors" : "*", 16 | "growl" : "*", 17 | "jquery" : "*", 18 | "jshint" : "*", 19 | "request" : "*", 20 | "speakeasy-nlp" : "*", 21 | "flatiron" : "*", 22 | "connect" : "*", 23 | "socket.io" : "*", 24 | "union" : "*", 25 | "plates" : "*" 26 | }, 27 | 28 | "author": "Nate Hunzaker", 29 | 30 | "main": "./nodebot.js", 31 | "bin" : { "nodebot": "./bin/nodebot" } 32 | } 33 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #Nodebot 2 | 3 | A helper robot written for the busy developer. Nodebot can (currently): 4 | 5 | - Compile javascripts using Uglify.js (And all javascripts in a directory) 6 | - Validate html (websites too), css, and javascript 7 | - Watch files for changes and validate them there is a supported validator 8 | - Report system information such as ip addresses, free memory, and host names 9 | - Query Wolfram|Alpha for definitions and answers to complex questions. 10 | 11 | --- 12 | 13 | ``` 14 | npm install nodebot -g 15 | ``` 16 | 17 | ### Example commands 18 | 19 | ``` 20 | $ nodebot What is the capital of Spain? 21 | 22 | $ nodebot is nodebot.js valid? 23 | 24 | $ nodebot watch ./nodebot.js 25 | 26 | $ nodebot how much free memory do I have? 27 | ``` 28 | 29 | ### Validate Javascript, CSS, and HTML (websites work too) 30 | ``` 31 | $ nodebot is nodebot.js valid? 32 | 33 | Nodebot: Oh snap! I found 1 error in nodebot.js: 34 | ---------------------------------- 35 | 48:12 - Don't make functions within a loop. 36 | 37 | ``` 38 | 39 | 40 | ### General Information 41 | ``` 42 | $ nodebot 43 | 44 | Nodebot: What can I help you with? 45 | Response: what is the current directory 46 | 47 | Nodebot: The current directory is /Users/nate/Sites/nodebot 48 | 49 | Nodebot: What can I help you with? 50 | Response: what is my ip address? 51 | 52 | Nodebot: User's ip address is 53 | 54 | local - 127.0.0.1 55 | external - 172.30.9.66 56 | 57 | Nodebot: What can I help you with? 58 | Response: What is your name? 59 | 60 | Nodebot: Nodebot's name is Nodebot 61 | 62 | ``` 63 | 64 | ### Compiling javascript 65 | 66 | ``` 67 | $ nodebot compile all javascript as min.js 68 | 69 | Nodebot: I am now compiling all javascript into min.js 70 | 71 | Nodebot: Files have changed. Compiling all javascript into min.js. 72 | ``` 73 | 74 | -------------------------------------------------------------------------------- /server/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Nodebot 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |

Nodebot

22 |
23 | 24 |
25 | 26 |
27 | 28 |
29 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | var flatiron = require('flatiron'), 2 | connect = require("connect"), 3 | port = process.env.port || 8080, 4 | app = Nodebot.server = flatiron.app; 5 | 6 | // Plugins 7 | app.use(flatiron.plugins.log); 8 | app.use(flatiron.plugins.http, { 9 | before: [connect.static(__dirname + '/public')] 10 | }); 11 | 12 | // Routes 13 | require("./routes")(app); 14 | 15 | // Set the server to listen on port `8080`. 16 | app.start(port); 17 | app.log.info("Nodebot is listening on port", port); 18 | 19 | // Install socket.io 20 | Nodebot.io = require('socket.io').listen(app.server); 21 | 22 | Nodebot.io.configure(function() { 23 | Nodebot.io.set('log level', 0); 24 | }); 25 | 26 | Nodebot.io.sockets.on('connection', function(socket) { 27 | socket.emit('output', "Hello, master"); 28 | socket.on("input", function(d) { 29 | Nodebot.analyze(d); 30 | }); 31 | }); -------------------------------------------------------------------------------- /server/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | Your Page Title Here :) 12 | 13 | 14 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 |
41 |

Sorry. Couldn't Find That Page!

42 |
43 | 44 | 46 | 47 | -------------------------------------------------------------------------------- /server/public/config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | 3 | # Set this to the root of your project when deployed: 4 | http_path = "/" 5 | css_dir = "stylesheets" 6 | sass_dir = "sass" 7 | images_dir = "images" 8 | javascripts_dir = "javascripts" 9 | 10 | # You can select your preferred output style here (can be overridden via the command line): 11 | # output_style = :expanded or :nested or :compact or :compressed 12 | 13 | # To enable relative paths to assets via compass helper functions. Uncomment: 14 | # relative_assets = true 15 | 16 | # To disable debugging comments that display the original location of your selectors. Uncomment: 17 | # line_comments = false 18 | 19 | 20 | # If you prefer the indented syntax, you might want to regenerate this 21 | # project again passing --syntax sass, or you can uncomment this: 22 | # preferred_syntax = :sass 23 | # and then run: 24 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass 25 | -------------------------------------------------------------------------------- /server/public/images/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/server/public/images/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /server/public/images/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/server/public/images/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /server/public/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/server/public/images/apple-touch-icon.png -------------------------------------------------------------------------------- /server/public/images/brushed_alu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/server/public/images/brushed_alu.png -------------------------------------------------------------------------------- /server/public/images/dark_dotted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/server/public/images/dark_dotted.png -------------------------------------------------------------------------------- /server/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhunzaker/nodebot/fa3fc9d65475214ac3bc72548004d5eef63b0e25/server/public/images/favicon.ico -------------------------------------------------------------------------------- /server/public/javascripts/nodebot.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | var socket = io.connect(window.location.origin), 4 | $feed = $("#feed"); 5 | 6 | socket.on("output", function (data) { 7 | $("

").html("Nodebot: " + data) 8 | .css("opacity", 0) 9 | .appendTo($feed) 10 | .animate({ opacity : 1 }); 11 | 12 | $feed.animate({scrollTop : $feed.height() }); 13 | }); 14 | 15 | 16 | $("form").submit(function(e) { 17 | e.preventDefault(); 18 | socket.emit("input", $("#question").val()); 19 | 20 | $("#question").val("").focus(); 21 | }); 22 | 23 | }); -------------------------------------------------------------------------------- /server/public/javascripts/tabs.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V1.1 3 | * Copyright 2011, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8/17/2011 8 | */ 9 | 10 | 11 | $('body').on('click', 'ul.tabs > li > a', function(e) { 12 | 13 | //Get Location of tab's content 14 | var contentLocation = $(this).attr('href'); 15 | 16 | //Let go if not a hashed one 17 | if(contentLocation.charAt(0)=="#") { 18 | 19 | e.preventDefault(); 20 | 21 | //Make Tab Active 22 | $(this).parent().siblings().children('a').removeClass('active'); 23 | $(this).addClass('active'); 24 | 25 | //Show Tab Content & add active class 26 | $(contentLocation).show().addClass('active').siblings().hide().removeClass('active'); 27 | 28 | } 29 | }); -------------------------------------------------------------------------------- /server/public/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 3 | 4 | User-agent: * 5 | 6 | -------------------------------------------------------------------------------- /server/public/sass/partials/_base_type.scss: -------------------------------------------------------------------------------- 1 | // Basic Styles 2 | // ================================================== // 3 | 4 | body { 5 | background: #fff; 6 | font: 14px/21px $sans-serif; 7 | color: #444; 8 | -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ 9 | -webkit-text-size-adjust: 100%; 10 | } 11 | 12 | 13 | // Typography 14 | // ================================================== // 15 | 16 | h1, h2, h3, h4, h5, h6 { 17 | color: #181818; 18 | font-family: $display; 19 | font-weight: normal; 20 | 21 | a { 22 | font-weight: inherit; 23 | } 24 | } 25 | 26 | h1 { font-size: 46px; line-height: 50px; margin-bottom: 14px;} 27 | h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; } 28 | h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; } 29 | h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; } 30 | h5 { font-size: 17px; line-height: 24px; } 31 | h6 { font-size: 14px; line-height: 21px; } 32 | 33 | .subheader { color: #777; } 34 | 35 | p { 36 | margin: 0 0 20px 0; 37 | 38 | img { 39 | margin: 0; 40 | } 41 | 42 | &.lead { 43 | font-size: 21px; 44 | line-height: 27px; 45 | color: #777; 46 | } 47 | 48 | } 49 | 50 | 51 | em { font-style: italic; } 52 | strong { font-weight: bold; color: #333; } 53 | small { font-size: 80%; } 54 | 55 | /* Blockquotes */ 56 | blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; } 57 | blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px; border-left: 1px solid #ddd; } 58 | blockquote cite { display: block; font-size: 12px; color: #555; } 59 | blockquote cite:before { content: "\2014 \0020"; } 60 | blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; } 61 | 62 | hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; } 63 | 64 | 65 | // Links 66 | // ================================================== // 67 | 68 | a, a:visited { color: #333; text-decoration: underline; outline: 0; } 69 | a:hover, a:focus { color: #000; } 70 | p a, p a:visited { line-height: inherit; } 71 | -------------------------------------------------------------------------------- /server/public/sass/partials/_buttons.scss: -------------------------------------------------------------------------------- 1 | 2 | // #Buttons 3 | // ================================================== // 4 | 5 | $color-stops: color-stops( rgba(255,255,255,.2), rgba(0,0,0, 0.2)); 6 | $hover-stops: color-stops( rgba(255,255,255,.3), rgba(0,0,0, 0.3)); 7 | $active-stops: color-stops( rgba(255,255,255, 0.35), rgba(10,10,10, 0.4)); 8 | 9 | // ================================================== // 10 | 11 | 12 | .button, button, input[type="submit"], input[type="reset"], input[type="button"] { 13 | 14 | background: #eee; /* Old browsers */ 15 | border: 1px solid #aaa; 16 | border-color: #ccc #ccc #aaa #ccc; 17 | color: #444; 18 | cursor: pointer; 19 | font: bold 11px/normal $sans-serif; 20 | margin-bottom: 20px; 21 | text-decoration: none; 22 | text-shadow: 0 1px rgba(255, 255, 255, .75); 23 | padding: 8px 10px; 24 | 25 | @include inline-block; 26 | @include background( linear-gradient( $color-stops ), #eee ); 27 | @include border-radius(3px); 28 | 29 | &:hover { 30 | color: #222; 31 | background: #ddd; /* Old browsers */ 32 | @include background( linear-gradient( $hover-stops ), #222 ); 33 | border: 1px solid #888; 34 | border-color: #aaa #888 #888 #aaa; 35 | } 36 | 37 | &:active { 38 | background: #ccc; /* Old browsers */ 39 | border: 1px solid #666; 40 | @include background( linear-gradient( $active-stops ), #ccc ); 41 | } 42 | 43 | &.full-width { 44 | padding-left: 0 !important; 45 | padding-right: 0 !important; 46 | text-align: center; 47 | width: 100%; 48 | } 49 | } 50 | 51 | /* Fix for odd Mozilla border & padding issues */ 52 | button::-moz-focus-inner, 53 | input::-moz-focus-inner { 54 | border: 0; 55 | padding: 0; 56 | } -------------------------------------------------------------------------------- /server/public/sass/partials/_custom.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | body { 4 | background: #333 url("/images/dark_dotted.png"); 5 | padding-top: 60px; 6 | } 7 | 8 | section { 9 | background:#d9d9d9 url("/images/brushed_alu.png"); 10 | margin: 0 auto; 11 | padding: 10px; 12 | width: 45%; 13 | 14 | @include border-radius(3px); 15 | 16 | header { 17 | text-align: center; 18 | } 19 | } 20 | 21 | p { 22 | margin: 1em 0; 23 | } 24 | 25 | #feed { 26 | background: #222; 27 | border: 1px solid #111; 28 | border-bottom: 0; 29 | color: #fff; 30 | height: 400px; 31 | margin-top: 20px; 32 | overflow-y: scroll; 33 | 34 | padding: 1% 2%; 35 | width: 96%; 36 | 37 | @include box-shadow(inset 0 1px 3px rgba(0,0,0,0.45), 0 1px 1px rgba(255,255,255,0.75)); 38 | @include border-top-radius(3px); 39 | strong { 40 | color: #f0f0f0; 41 | } 42 | 43 | } 44 | 45 | input[type="text"] { 46 | background: #111; 47 | border-color: transparent #111 #000; 48 | color: #fff; 49 | display: block; 50 | margin: 0 auto; 51 | position: relative; 52 | width: 98.5%; 53 | 54 | @include border-top-radius(0); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /server/public/sass/partials/_forms.scss: -------------------------------------------------------------------------------- 1 | // #Forms 2 | // ================================================== // 3 | 4 | form, fieldset { 5 | margin-bottom: 20px; 6 | } 7 | 8 | input[type="number"] { 9 | -webkit-apperance: none; 10 | } 11 | 12 | input[type="text"], input[type="password"], input[type="email"], input[type="number"], textarea, select { 13 | 14 | background: #fff; 15 | border: 1px solid #ccc; 16 | color: #777; 17 | display: block; 18 | font: 13px $sans-serif; 19 | margin: 0 0 20px; 20 | max-width: 100%; 21 | outline: none; 22 | padding: 6px 4px; 23 | width: 210px; 24 | 25 | @include border-radius(2px); 26 | 27 | &:focus { 28 | border: 1px solid #aaa; 29 | color: #444; 30 | 31 | @include box-shadow( 0 0 3px rgba(0,0,0, 0.2)); 32 | } 33 | } 34 | 35 | select { 36 | padding: 0; 37 | width: 220px; 38 | } 39 | 40 | textarea { 41 | min-height: 60px; 42 | } 43 | 44 | label, legend { 45 | display: block; 46 | font-weight: bold; 47 | font-size: 13px; 48 | } 49 | 50 | input[type="checkbox"] { 51 | display: inline; 52 | } 53 | 54 | label span, legend span { 55 | font-weight: normal; 56 | font-size: 13px; 57 | color: #444; 58 | } -------------------------------------------------------------------------------- /server/public/sass/partials/_grid.scss: -------------------------------------------------------------------------------- 1 | // Grid 2 | // ================================================== // 3 | 4 | // Table of Contents 5 | // -------------------------------------------------- // 6 | // 7 | // Base 960 Grid 8 | // Tablet (Portrait) 9 | // Mobile (Portrait) 10 | // Mobile (Landscape) 11 | // Clearing 12 | 13 | // -------------------------------------------------- // 14 | 15 | // #Base 960 Grid 16 | // ================================================== // 17 | 18 | .container { position: relative; width: $grid-width; margin: 0 auto; padding: 0; } 19 | .row { margin-bottom: 20px; } 20 | 21 | // Base Grid 22 | .container { 23 | 24 | .one.column, 25 | .one.columns { @include grid(1); } 26 | .two.columns { @include grid(2); } 27 | .three.columns { @include grid(3); } 28 | .four.columns { @include grid(4); } 29 | .five.columns { @include grid(5); } 30 | .six.columns { @include grid(6); } 31 | .seven.columns { @include grid(7); } 32 | .eight.columns { @include grid(8); } 33 | .nine.columns { @include grid(9); } 34 | .ten.columns { @include grid(10); } 35 | .eleven.columns { @include grid(11); } 36 | .twelve.columns { @include grid(12); } 37 | .thirteen.columns { @include grid(13); } 38 | .fourteen.columns { @include grid(14); } 39 | .fifteen.columns { @include grid(15); } 40 | .sixteen.columns { @include grid(16); } 41 | 42 | .one-third.column { @extend .one.column; width: (($grid-width - $grid-offset) / 3); } 43 | .two-thirds.column { @extend .one.column; width: (($grid-width - $grid-offset) / 3) * 2; } 44 | 45 | // Offsets 46 | .offset-by-one { @include offset(1); } 47 | .offset-by-two { @include offset(2); } 48 | .offset-by-three { @include offset(3); } 49 | .offset-by-four { @include offset(4); } 50 | .offset-by-five { @include offset(5); } 51 | .offset-by-six { @include offset(6); } 52 | .offset-by-seven { @include offset(7); } 53 | .offset-by-eight { @include offset(8); } 54 | .offset-by-nine { @include offset(9); } 55 | .offset-by-ten { @include offset(10); } 56 | .offset-by-eleven { @include offset(11); } 57 | .offset-by-twelve { @include offset(12); } 58 | .offset-by-thirteen { @include offset(13); } 59 | .offset-by-fourteen { @include offset(14); } 60 | .offset-by-fifteen { @include offset(15); } 61 | 62 | /* Nested Column Classes */ 63 | .column.alpha, .columns.alpha { margin-left: 0; } 64 | .column.omega, .columns.omega { margin-right: 0; } 65 | 66 | } 67 | 68 | 69 | /* #Tablet (Portrait) 70 | ================================================== */ 71 | 72 | /* Note: Design for a width of 768px */ 73 | 74 | @media only screen and (min-width: 768px) and (max-width: 959px) { 75 | .container { width: 768px; } 76 | .container .column, 77 | .container .columns { margin-left: 10px; margin-right: 10px; } 78 | .column.alpha, .columns.alpha { margin-left: 0; margin-right: 10px; } 79 | .column.omega, .columns.omega { margin-right: 0; margin-left: 10px; } 80 | .alpha.omega { margin-left: 0; margin-right: 0; } 81 | 82 | .container .one.column, 83 | .container .one.columns { width: 28px; } 84 | .container .two.columns { width: 76px; } 85 | .container .three.columns { width: 124px; } 86 | .container .four.columns { width: 172px; } 87 | .container .five.columns { width: 220px; } 88 | .container .six.columns { width: 268px; } 89 | .container .seven.columns { width: 316px; } 90 | .container .eight.columns { width: 364px; } 91 | .container .nine.columns { width: 412px; } 92 | .container .ten.columns { width: 460px; } 93 | .container .eleven.columns { width: 508px; } 94 | .container .twelve.columns { width: 556px; } 95 | .container .thirteen.columns { width: 604px; } 96 | .container .fourteen.columns { width: 652px; } 97 | .container .fifteen.columns { width: 700px; } 98 | .container .sixteen.columns { width: 748px; } 99 | 100 | .container .one-third.column { width: 236px; } 101 | .container .two-thirds.column { width: 492px; } 102 | 103 | /* Offsets */ 104 | .container .offset-by-one { padding-left: 48px; } 105 | .container .offset-by-two { padding-left: 96px; } 106 | .container .offset-by-three { padding-left: 144px; } 107 | .container .offset-by-four { padding-left: 192px; } 108 | .container .offset-by-five { padding-left: 240px; } 109 | .container .offset-by-six { padding-left: 288px; } 110 | .container .offset-by-seven { padding-left: 336px; } 111 | .container .offset-by-eight { padding-left: 348px; } 112 | .container .offset-by-nine { padding-left: 432px; } 113 | .container .offset-by-ten { padding-left: 480px; } 114 | .container .offset-by-eleven { padding-left: 528px; } 115 | .container .offset-by-twelve { padding-left: 576px; } 116 | .container .offset-by-thirteen { padding-left: 624px; } 117 | .container .offset-by-fourteen { padding-left: 672px; } 118 | .container .offset-by-fifteen { padding-left: 720px; } 119 | } 120 | 121 | 122 | /* #Mobile (Portrait) 123 | ================================================== */ 124 | 125 | /* Note: Design for a width of 320px */ 126 | 127 | @media only screen and (max-width: 767px) { 128 | .container { width: 300px; } 129 | .container .columns, 130 | .container .column { margin: 0; } 131 | 132 | .container .one.column, 133 | .container .one.columns, 134 | .container .two.columns, 135 | .container .three.columns, 136 | .container .four.columns, 137 | .container .five.columns, 138 | .container .six.columns, 139 | .container .seven.columns, 140 | .container .eight.columns, 141 | .container .nine.columns, 142 | .container .ten.columns, 143 | .container .eleven.columns, 144 | .container .twelve.columns, 145 | .container .thirteen.columns, 146 | .container .fourteen.columns, 147 | .container .fifteen.columns, 148 | .container .sixteen.columns, 149 | .container .one-third.column, 150 | .container .two-thirds.column { width: 300px; } 151 | 152 | /* Offsets */ 153 | .container .offset-by-one, 154 | .container .offset-by-two, 155 | .container .offset-by-three, 156 | .container .offset-by-four, 157 | .container .offset-by-five, 158 | .container .offset-by-six, 159 | .container .offset-by-seven, 160 | .container .offset-by-eight, 161 | .container .offset-by-nine, 162 | .container .offset-by-ten, 163 | .container .offset-by-eleven, 164 | .container .offset-by-twelve, 165 | .container .offset-by-thirteen, 166 | .container .offset-by-fourteen, 167 | .container .offset-by-fifteen { padding-left: 0; } 168 | 169 | } 170 | 171 | 172 | /* #Mobile (Landscape) 173 | ================================================== */ 174 | 175 | /* Note: Design for a width of 480px */ 176 | 177 | @media only screen and (min-width: 480px) and (max-width: 767px) { 178 | .container { width: 420px; } 179 | .container .columns, 180 | .container .column { margin: 0; } 181 | 182 | .container .one.column, 183 | .container .one.columns, 184 | .container .two.columns, 185 | .container .three.columns, 186 | .container .four.columns, 187 | .container .five.columns, 188 | .container .six.columns, 189 | .container .seven.columns, 190 | .container .eight.columns, 191 | .container .nine.columns, 192 | .container .ten.columns, 193 | .container .eleven.columns, 194 | .container .twelve.columns, 195 | .container .thirteen.columns, 196 | .container .fourteen.columns, 197 | .container .fifteen.columns, 198 | .container .sixteen.columns, 199 | .container .one-third.column, 200 | .container .two-thirds.column { width: 420px; } 201 | } 202 | 203 | 204 | /* #Clearing 205 | ================================================== */ 206 | 207 | /* Self Clearing Goodness */ 208 | .container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; } 209 | 210 | /* Use clearfix class on parent to clear nested columns, 211 | or wrap each row of columns in a

*/ 212 | .clearfix:before, 213 | .clearfix:after, 214 | .row:before, 215 | .row:after { 216 | content: '\0020'; 217 | display: block; 218 | overflow: hidden; 219 | visibility: hidden; 220 | width: 0; 221 | height: 0; } 222 | .row:after, 223 | .clearfix:after { 224 | clear: both; } 225 | .row, 226 | .clearfix { 227 | zoom: 1; } 228 | 229 | /* You can also use a
to clear columns */ 230 | .clear { 231 | clear: both; 232 | display: block; 233 | overflow: hidden; 234 | visibility: hidden; 235 | width: 0; 236 | height: 0; 237 | } -------------------------------------------------------------------------------- /server/public/sass/partials/_images.scss: -------------------------------------------------------------------------------- 1 | // Images 2 | // ================================================== // 3 | 4 | img { 5 | max-width: 100%; 6 | height: auto; 7 | } -------------------------------------------------------------------------------- /server/public/sass/partials/_lists.scss: -------------------------------------------------------------------------------- 1 | // Lists 2 | // ================================================== // 3 | 4 | ul, ol { 5 | margin-bottom: 20px; 6 | } 7 | 8 | ul { 9 | list-style: none outside; 10 | } 11 | 12 | ol { 13 | list-style: decimal; 14 | } 15 | 16 | ol, ul.square, ul.circle, ul.disc { 17 | margin-left: 30px; 18 | } 19 | 20 | ul.square { 21 | list-style: square outside; 22 | } 23 | 24 | ul.circle { 25 | list-style: circle outside; 26 | } 27 | 28 | ul.disc { 29 | list-style: disc outside; 30 | } 31 | 32 | ul ul, ul ol, ol ol, ol ul { 33 | margin: 4px 0 5px 30px; 34 | font-size: 90%; 35 | } 36 | 37 | ul ul li, ul ol li, ol ol li, ol ul li { 38 | margin-bottom: 6px; 39 | } 40 | 41 | li { 42 | line-height: 18px; 43 | margin-bottom: 12px; 44 | } 45 | 46 | ul.large li { 47 | line-height: 21px; 48 | } 49 | 50 | li p { 51 | line-height: 21px; 52 | } -------------------------------------------------------------------------------- /server/public/sass/partials/_misc.scss: -------------------------------------------------------------------------------- 1 | // #Misc 2 | // ================================================== // 3 | 4 | .remove-bottom { margin-bottom: 0 !important; } 5 | .half-bottom { margin-bottom: 10px !important; } 6 | .add-bottom { margin-bottom: 20px !important; } 7 | -------------------------------------------------------------------------------- /server/public/sass/partials/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // ================================================== // 3 | 4 | 5 | // Grid Mixins 6 | // -------------------------------------------------- // 7 | 8 | @mixin alpha { 9 | margin-left: 0; 10 | } 11 | 12 | @mixin omega { 13 | margin-right: 0; 14 | } 15 | 16 | @mixin grid ($count:1, $pos:"") { 17 | 18 | $gutter : $grid-gutter-width; 19 | $base : $grid-column-width * $count; 20 | 21 | width: $base + (($count - 1) * $gutter); 22 | 23 | float: left; 24 | display: inline; 25 | 26 | margin: 0 ($gutter / 2) $grid-baseline-height ($gutter / 2); 27 | 28 | @if ($pos == "alpha") { 29 | @include alpha(); 30 | } 31 | 32 | @if ($pos == "omega") { 33 | @include omega(); 34 | } 35 | 36 | } 37 | 38 | @mixin offset ($cols:1) { 39 | padding-left: ($cols * $grid-offset) + 0px; 40 | } -------------------------------------------------------------------------------- /server/public/sass/partials/_reset.scss: -------------------------------------------------------------------------------- 1 | // Reset & Basics (Inspired by E. Meyers) 2 | // ================================================== // 3 | 4 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 5 | margin: 0; 6 | padding: 0; 7 | border: 0; 8 | font-size: 100%; 9 | font: inherit; 10 | vertical-align: baseline; } 11 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 12 | display: block; } 13 | body { 14 | line-height: 1; } 15 | ol, ul { 16 | list-style: none; } 17 | blockquote, q { 18 | quotes: none; } 19 | blockquote:before, blockquote:after, 20 | q:before, q:after { 21 | content: ''; 22 | content: none; } 23 | table { 24 | border-collapse: collapse; 25 | border-spacing: 0; } 26 | -------------------------------------------------------------------------------- /server/public/sass/partials/_tabs.scss: -------------------------------------------------------------------------------- 1 | // #Tabs (activate in tabs.js) 2 | // ================================================== // 3 | 4 | ul.tabs { 5 | 6 | display: block; 7 | margin: 0 0 20px 0; 8 | padding: 0; 9 | border-bottom: solid 1px #ddd; 10 | zoom: 1; 11 | 12 | li { 13 | display: block; 14 | width: auto; 15 | height: 30px; 16 | padding: 0; 17 | float: left; 18 | margin-bottom: 0; 19 | 20 | a { 21 | display: block; 22 | text-decoration: none; 23 | width: auto; 24 | height: 29px; 25 | padding: 0px 20px; 26 | line-height: 30px; 27 | border: solid 1px #ddd; 28 | border-width: 1px 1px 0 0; 29 | margin: 0; 30 | background: #f5f5f5; 31 | 32 | &.active { 33 | background: #fff; 34 | height: 30px; 35 | position: relative; 36 | top: -4px; 37 | padding-top: 4px; 38 | border-left-width: 1px; 39 | margin: 0 0 0 -1px; 40 | color: #111; 41 | 42 | @include border-top-radius(2px); 43 | } 44 | 45 | &:first-child { 46 | 47 | @include border-top-radius(2px); 48 | 49 | a { 50 | border-width: 1px 1px 0 1px; 51 | @include border-top-radius(2px); 52 | 53 | &.active { 54 | margin-left: 0; 55 | } 56 | } 57 | 58 | } 59 | } 60 | } 61 | 62 | 63 | // Clearfix for beautiful stacking 64 | &:before, &:after { 65 | content: '\0020'; 66 | display: block; 67 | overflow: hidden; 68 | visibility: hidden; 69 | width: 0; 70 | height: 0; 71 | } 72 | 73 | &:after { 74 | clear: both; 75 | } 76 | 77 | } 78 | 79 | ul.tabs-content { 80 | margin: 0; display: block; 81 | 82 | > li { 83 | display:none; 84 | 85 | &.active { 86 | display: block; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /server/public/sass/partials/_variables.scss: -------------------------------------------------------------------------------- 1 | // Variables 2 | // ================================================== // 3 | 4 | 5 | // Grid 6 | // -------------------------------------------------- // 7 | 8 | $grid-column-width : 40px; 9 | $grid-gutter-width : 20px; 10 | $grid-total-columns : 16; 11 | $grid-baseline-height : 20px; 12 | 13 | $grid-offset : ($grid-column-width + $grid-gutter-width); 14 | $grid-width : ($grid-offset * $grid-total-columns); 15 | 16 | 17 | // Grid Utility 18 | // -------------------------------------------------- // 19 | 20 | $grid-background-column-width : $grid-column-width; 21 | $grid-background-gutter-width : $grid-gutter-width; 22 | $grid-background-total-columns : $grid-total-columns; 23 | $grid-background-baseline-height: $grid-baseline-height; 24 | 25 | $grid-background-baseline-color : rgba(0,0,0,0.15); 26 | $grid-background-column-color : rgba(100, 100, 100, 0.05); 27 | 28 | 29 | // Typography 30 | // -------------------------------------------------- // 31 | 32 | $display : "VT323", sans-serif; 33 | $sans-serif : "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 34 | $serif : "Georgia", "Times New Roman", Helvetica, Arial, sans-serif; -------------------------------------------------------------------------------- /server/public/sass/style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V1.1 3 | * Copyright 2011, Dave Gamache 4 | * 5 | * Compass-sass edition by Nate Hunzaker 6 | * 7 | * www.getskeleton.com 8 | * Free to use under the MIT license. 9 | * http://www.opensource.org/licenses/mit-license.php 10 | * 8/17/2011 11 | */ 12 | 13 | @import url(http://fonts.googleapis.com/css?family=VT323); 14 | 15 | @import "compass/css3"; 16 | @import "compass/layout"; 17 | 18 | // Table of Content 19 | // ================================================== // 20 | 21 | // Variables and Mixins 22 | @import "partials/variables"; 23 | @import "partials/mixins"; 24 | 25 | // Reset & Basics 26 | @import "partials/reset"; 27 | 28 | // Basics and Typography Styles 29 | @import "partials/_base_type"; 30 | 31 | // Lists 32 | @import "partials/_lists"; 33 | 34 | //Images 35 | @import "partials/_images"; 36 | 37 | //Buttons 38 | @import "partials/buttons"; 39 | 40 | //Tabs 41 | @import "partials/tabs"; 42 | 43 | //Forms 44 | @import "partials/forms"; 45 | 46 | //Misc 47 | @import "partials/misc"; 48 | 49 | // Grid 50 | @import "partials/grid"; 51 | 52 | 53 | // User Styles 54 | // ================================================== // 55 | 56 | @import "partials/custom"; -------------------------------------------------------------------------------- /server/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V1.1 3 | * Copyright 2011, Dave Gamache 4 | * 5 | * Compass-sass edition by Nate Hunzaker 6 | * 7 | * www.getskeleton.com 8 | * Free to use under the MIT license. 9 | * http://www.opensource.org/licenses/mit-license.php 10 | * 8/17/2011 11 | */ 12 | @import url(http://fonts.googleapis.com/css?family=VT323); 13 | /* line 4, ../sass/partials/_reset.scss */ 14 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 15 | margin: 0; 16 | padding: 0; 17 | border: 0; 18 | font-size: 100%; 19 | font: inherit; 20 | vertical-align: baseline; 21 | } 22 | 23 | /* line 11, ../sass/partials/_reset.scss */ 24 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 25 | display: block; 26 | } 27 | 28 | /* line 13, ../sass/partials/_reset.scss */ 29 | body { 30 | line-height: 1; 31 | } 32 | 33 | /* line 15, ../sass/partials/_reset.scss */ 34 | ol, ul { 35 | list-style: none; 36 | } 37 | 38 | /* line 17, ../sass/partials/_reset.scss */ 39 | blockquote, q { 40 | quotes: none; 41 | } 42 | 43 | /* line 20, ../sass/partials/_reset.scss */ 44 | blockquote:before, blockquote:after, 45 | q:before, q:after { 46 | content: ''; 47 | content: none; 48 | } 49 | 50 | /* line 23, ../sass/partials/_reset.scss */ 51 | table { 52 | border-collapse: collapse; 53 | border-spacing: 0; 54 | } 55 | 56 | /* line 4, ../sass/partials/_base_type.scss */ 57 | body { 58 | background: #fff; 59 | font: 14px/21px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 60 | color: #444; 61 | -webkit-font-smoothing: antialiased; 62 | /* Fix for webkit rendering */ 63 | -webkit-text-size-adjust: 100%; 64 | } 65 | 66 | /* line 16, ../sass/partials/_base_type.scss */ 67 | h1, h2, h3, h4, h5, h6 { 68 | color: #181818; 69 | font-family: "VT323", sans-serif; 70 | font-weight: normal; 71 | } 72 | /* line 21, ../sass/partials/_base_type.scss */ 73 | h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { 74 | font-weight: inherit; 75 | } 76 | 77 | /* line 26, ../sass/partials/_base_type.scss */ 78 | h1 { 79 | font-size: 46px; 80 | line-height: 50px; 81 | margin-bottom: 14px; 82 | } 83 | 84 | /* line 27, ../sass/partials/_base_type.scss */ 85 | h2 { 86 | font-size: 35px; 87 | line-height: 40px; 88 | margin-bottom: 10px; 89 | } 90 | 91 | /* line 28, ../sass/partials/_base_type.scss */ 92 | h3 { 93 | font-size: 28px; 94 | line-height: 34px; 95 | margin-bottom: 8px; 96 | } 97 | 98 | /* line 29, ../sass/partials/_base_type.scss */ 99 | h4 { 100 | font-size: 21px; 101 | line-height: 30px; 102 | margin-bottom: 4px; 103 | } 104 | 105 | /* line 30, ../sass/partials/_base_type.scss */ 106 | h5 { 107 | font-size: 17px; 108 | line-height: 24px; 109 | } 110 | 111 | /* line 31, ../sass/partials/_base_type.scss */ 112 | h6 { 113 | font-size: 14px; 114 | line-height: 21px; 115 | } 116 | 117 | /* line 33, ../sass/partials/_base_type.scss */ 118 | .subheader { 119 | color: #777; 120 | } 121 | 122 | /* line 35, ../sass/partials/_base_type.scss */ 123 | p { 124 | margin: 0 0 20px 0; 125 | } 126 | /* line 38, ../sass/partials/_base_type.scss */ 127 | p img { 128 | margin: 0; 129 | } 130 | /* line 42, ../sass/partials/_base_type.scss */ 131 | p.lead { 132 | font-size: 21px; 133 | line-height: 27px; 134 | color: #777; 135 | } 136 | 137 | /* line 51, ../sass/partials/_base_type.scss */ 138 | em { 139 | font-style: italic; 140 | } 141 | 142 | /* line 52, ../sass/partials/_base_type.scss */ 143 | strong { 144 | font-weight: bold; 145 | color: #333; 146 | } 147 | 148 | /* line 53, ../sass/partials/_base_type.scss */ 149 | small { 150 | font-size: 80%; 151 | } 152 | 153 | /* Blockquotes */ 154 | /* line 56, ../sass/partials/_base_type.scss */ 155 | blockquote, blockquote p { 156 | font-size: 17px; 157 | line-height: 24px; 158 | color: #777; 159 | font-style: italic; 160 | } 161 | 162 | /* line 57, ../sass/partials/_base_type.scss */ 163 | blockquote { 164 | margin: 0 0 20px; 165 | padding: 9px 20px 0 19px; 166 | border-left: 1px solid #ddd; 167 | } 168 | 169 | /* line 58, ../sass/partials/_base_type.scss */ 170 | blockquote cite { 171 | display: block; 172 | font-size: 12px; 173 | color: #555; 174 | } 175 | 176 | /* line 59, ../sass/partials/_base_type.scss */ 177 | blockquote cite:before { 178 | content: "\2014 \0020"; 179 | } 180 | 181 | /* line 60, ../sass/partials/_base_type.scss */ 182 | blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { 183 | color: #555; 184 | } 185 | 186 | /* line 62, ../sass/partials/_base_type.scss */ 187 | hr { 188 | border: solid #ddd; 189 | border-width: 1px 0 0; 190 | clear: both; 191 | margin: 10px 0 30px; 192 | height: 0; 193 | } 194 | 195 | /* line 68, ../sass/partials/_base_type.scss */ 196 | a, a:visited { 197 | color: #333; 198 | text-decoration: underline; 199 | outline: 0; 200 | } 201 | 202 | /* line 69, ../sass/partials/_base_type.scss */ 203 | a:hover, a:focus { 204 | color: #000; 205 | } 206 | 207 | /* line 70, ../sass/partials/_base_type.scss */ 208 | p a, p a:visited { 209 | line-height: inherit; 210 | } 211 | 212 | /* line 4, ../sass/partials/_lists.scss */ 213 | ul, ol { 214 | margin-bottom: 20px; 215 | } 216 | 217 | /* line 8, ../sass/partials/_lists.scss */ 218 | ul { 219 | list-style: none outside; 220 | } 221 | 222 | /* line 12, ../sass/partials/_lists.scss */ 223 | ol { 224 | list-style: decimal; 225 | } 226 | 227 | /* line 16, ../sass/partials/_lists.scss */ 228 | ol, ul.square, ul.circle, ul.disc { 229 | margin-left: 30px; 230 | } 231 | 232 | /* line 20, ../sass/partials/_lists.scss */ 233 | ul.square { 234 | list-style: square outside; 235 | } 236 | 237 | /* line 24, ../sass/partials/_lists.scss */ 238 | ul.circle { 239 | list-style: circle outside; 240 | } 241 | 242 | /* line 28, ../sass/partials/_lists.scss */ 243 | ul.disc { 244 | list-style: disc outside; 245 | } 246 | 247 | /* line 32, ../sass/partials/_lists.scss */ 248 | ul ul, ul ol, ol ol, ol ul { 249 | margin: 4px 0 5px 30px; 250 | font-size: 90%; 251 | } 252 | 253 | /* line 37, ../sass/partials/_lists.scss */ 254 | ul ul li, ul ol li, ol ol li, ol ul li { 255 | margin-bottom: 6px; 256 | } 257 | 258 | /* line 41, ../sass/partials/_lists.scss */ 259 | li { 260 | line-height: 18px; 261 | margin-bottom: 12px; 262 | } 263 | 264 | /* line 46, ../sass/partials/_lists.scss */ 265 | ul.large li { 266 | line-height: 21px; 267 | } 268 | 269 | /* line 50, ../sass/partials/_lists.scss */ 270 | li p { 271 | line-height: 21px; 272 | } 273 | 274 | /* line 4, ../sass/partials/_images.scss */ 275 | img { 276 | max-width: 100%; 277 | height: auto; 278 | } 279 | 280 | /* line 12, ../sass/partials/_buttons.scss */ 281 | .button, button, input[type="submit"], input[type="reset"], input[type="button"] { 282 | background: #eee; 283 | /* Old browsers */ 284 | border: 1px solid #aaa; 285 | border-color: #ccc #ccc #aaa #ccc; 286 | color: #444; 287 | cursor: pointer; 288 | font: bold 11px/normal "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 289 | margin-bottom: 20px; 290 | text-decoration: none; 291 | text-shadow: 0 1px rgba(255, 255, 255, 0.75); 292 | padding: 8px 10px; 293 | display: -moz-inline-box; 294 | -moz-box-orient: vertical; 295 | display: inline-block; 296 | vertical-align: middle; 297 | *vertical-align: auto; 298 | background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(255, 255, 255, 0.2)), color-stop(100%, rgba(0, 0, 0, 0.2))), #eeeeee; 299 | background: -webkit-linear-gradient(rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0.2)), #eeeeee; 300 | background: -moz-linear-gradient(rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0.2)), #eeeeee; 301 | background: -o-linear-gradient(rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0.2)), #eeeeee; 302 | background: -ms-linear-gradient(rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0.2)), #eeeeee; 303 | background: linear-gradient(rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0.2)), #eeeeee; 304 | -moz-border-radius: 3px; 305 | -webkit-border-radius: 3px; 306 | -o-border-radius: 3px; 307 | -ms-border-radius: 3px; 308 | -khtml-border-radius: 3px; 309 | border-radius: 3px; 310 | } 311 | /* line 7, ../../../../../.rvm/gems/ruby-1.9.2-p290/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/css3/_inline-block.scss */ 312 | .button, button, input[type="submit"], input[type="reset"], input[type="button"] { 313 | *display: inline; 314 | } 315 | /* line 29, ../sass/partials/_buttons.scss */ 316 | .button:hover, button:hover, input[type="submit"]:hover, input[type="reset"]:hover, input[type="button"]:hover { 317 | color: #222; 318 | background: #ddd; 319 | /* Old browsers */ 320 | background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(255, 255, 255, 0.3)), color-stop(100%, rgba(0, 0, 0, 0.3))), #222222; 321 | background: -webkit-linear-gradient(rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0.3)), #222222; 322 | background: -moz-linear-gradient(rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0.3)), #222222; 323 | background: -o-linear-gradient(rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0.3)), #222222; 324 | background: -ms-linear-gradient(rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0.3)), #222222; 325 | background: linear-gradient(rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0.3)), #222222; 326 | border: 1px solid #888; 327 | border-color: #aaa #888 #888 #aaa; 328 | } 329 | /* line 37, ../sass/partials/_buttons.scss */ 330 | .button:active, button:active, input[type="submit"]:active, input[type="reset"]:active, input[type="button"]:active { 331 | background: #ccc; 332 | /* Old browsers */ 333 | border: 1px solid #666; 334 | background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(255, 255, 255, 0.35)), color-stop(100%, rgba(10, 10, 10, 0.4))), #cccccc; 335 | background: -webkit-linear-gradient(rgba(255, 255, 255, 0.35), rgba(10, 10, 10, 0.4)), #cccccc; 336 | background: -moz-linear-gradient(rgba(255, 255, 255, 0.35), rgba(10, 10, 10, 0.4)), #cccccc; 337 | background: -o-linear-gradient(rgba(255, 255, 255, 0.35), rgba(10, 10, 10, 0.4)), #cccccc; 338 | background: -ms-linear-gradient(rgba(255, 255, 255, 0.35), rgba(10, 10, 10, 0.4)), #cccccc; 339 | background: linear-gradient(rgba(255, 255, 255, 0.35), rgba(10, 10, 10, 0.4)), #cccccc; 340 | } 341 | /* line 43, ../sass/partials/_buttons.scss */ 342 | .button.full-width, button.full-width, input[type="submit"].full-width, input[type="reset"].full-width, input[type="button"].full-width { 343 | padding-left: 0 !important; 344 | padding-right: 0 !important; 345 | text-align: center; 346 | width: 100%; 347 | } 348 | 349 | /* Fix for odd Mozilla border & padding issues */ 350 | /* line 53, ../sass/partials/_buttons.scss */ 351 | button::-moz-focus-inner, 352 | input::-moz-focus-inner { 353 | border: 0; 354 | padding: 0; 355 | } 356 | 357 | /* line 4, ../sass/partials/_tabs.scss */ 358 | ul.tabs { 359 | display: block; 360 | margin: 0 0 20px 0; 361 | padding: 0; 362 | border-bottom: solid 1px #ddd; 363 | zoom: 1; 364 | } 365 | /* line 12, ../sass/partials/_tabs.scss */ 366 | ul.tabs li { 367 | display: block; 368 | width: auto; 369 | height: 30px; 370 | padding: 0; 371 | float: left; 372 | margin-bottom: 0; 373 | } 374 | /* line 20, ../sass/partials/_tabs.scss */ 375 | ul.tabs li a { 376 | display: block; 377 | text-decoration: none; 378 | width: auto; 379 | height: 29px; 380 | padding: 0px 20px; 381 | line-height: 30px; 382 | border: solid 1px #ddd; 383 | border-width: 1px 1px 0 0; 384 | margin: 0; 385 | background: #f5f5f5; 386 | } 387 | /* line 32, ../sass/partials/_tabs.scss */ 388 | ul.tabs li a.active { 389 | background: #fff; 390 | height: 30px; 391 | position: relative; 392 | top: -4px; 393 | padding-top: 4px; 394 | border-left-width: 1px; 395 | margin: 0 0 0 -1px; 396 | color: #111; 397 | -moz-border-radius-topleft: 2px; 398 | -webkit-border-top-left-radius: 2px; 399 | -o-border-top-left-radius: 2px; 400 | -ms-border-top-left-radius: 2px; 401 | -khtml-border-top-left-radius: 2px; 402 | border-top-left-radius: 2px; 403 | -moz-border-radius-topright: 2px; 404 | -webkit-border-top-right-radius: 2px; 405 | -o-border-top-right-radius: 2px; 406 | -ms-border-top-right-radius: 2px; 407 | -khtml-border-top-right-radius: 2px; 408 | border-top-right-radius: 2px; 409 | } 410 | /* line 45, ../sass/partials/_tabs.scss */ 411 | ul.tabs li a:first-child { 412 | -moz-border-radius-topleft: 2px; 413 | -webkit-border-top-left-radius: 2px; 414 | -o-border-top-left-radius: 2px; 415 | -ms-border-top-left-radius: 2px; 416 | -khtml-border-top-left-radius: 2px; 417 | border-top-left-radius: 2px; 418 | -moz-border-radius-topright: 2px; 419 | -webkit-border-top-right-radius: 2px; 420 | -o-border-top-right-radius: 2px; 421 | -ms-border-top-right-radius: 2px; 422 | -khtml-border-top-right-radius: 2px; 423 | border-top-right-radius: 2px; 424 | } 425 | /* line 49, ../sass/partials/_tabs.scss */ 426 | ul.tabs li a:first-child a { 427 | border-width: 1px 1px 0 1px; 428 | -moz-border-radius-topleft: 2px; 429 | -webkit-border-top-left-radius: 2px; 430 | -o-border-top-left-radius: 2px; 431 | -ms-border-top-left-radius: 2px; 432 | -khtml-border-top-left-radius: 2px; 433 | border-top-left-radius: 2px; 434 | -moz-border-radius-topright: 2px; 435 | -webkit-border-top-right-radius: 2px; 436 | -o-border-top-right-radius: 2px; 437 | -ms-border-top-right-radius: 2px; 438 | -khtml-border-top-right-radius: 2px; 439 | border-top-right-radius: 2px; 440 | } 441 | /* line 53, ../sass/partials/_tabs.scss */ 442 | ul.tabs li a:first-child a.active { 443 | margin-left: 0; 444 | } 445 | /* line 64, ../sass/partials/_tabs.scss */ 446 | ul.tabs:before, ul.tabs:after { 447 | content: '\0020'; 448 | display: block; 449 | overflow: hidden; 450 | visibility: hidden; 451 | width: 0; 452 | height: 0; 453 | } 454 | /* line 73, ../sass/partials/_tabs.scss */ 455 | ul.tabs:after { 456 | clear: both; 457 | } 458 | 459 | /* line 79, ../sass/partials/_tabs.scss */ 460 | ul.tabs-content { 461 | margin: 0; 462 | display: block; 463 | } 464 | /* line 82, ../sass/partials/_tabs.scss */ 465 | ul.tabs-content > li { 466 | display: none; 467 | } 468 | /* line 85, ../sass/partials/_tabs.scss */ 469 | ul.tabs-content > li.active { 470 | display: block; 471 | } 472 | 473 | /* line 4, ../sass/partials/_forms.scss */ 474 | form, fieldset { 475 | margin-bottom: 20px; 476 | } 477 | 478 | /* line 8, ../sass/partials/_forms.scss */ 479 | input[type="number"] { 480 | -webkit-apperance: none; 481 | } 482 | 483 | /* line 12, ../sass/partials/_forms.scss */ 484 | input[type="text"], input[type="password"], input[type="email"], input[type="number"], textarea, select { 485 | background: #fff; 486 | border: 1px solid #ccc; 487 | color: #777; 488 | display: block; 489 | font: 13px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 490 | margin: 0 0 20px; 491 | max-width: 100%; 492 | outline: none; 493 | padding: 6px 4px; 494 | width: 210px; 495 | -moz-border-radius: 2px; 496 | -webkit-border-radius: 2px; 497 | -o-border-radius: 2px; 498 | -ms-border-radius: 2px; 499 | -khtml-border-radius: 2px; 500 | border-radius: 2px; 501 | } 502 | /* line 27, ../sass/partials/_forms.scss */ 503 | input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, input[type="number"]:focus, textarea:focus, select:focus { 504 | border: 1px solid #aaa; 505 | color: #444; 506 | -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 507 | -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 508 | -o-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 509 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 510 | } 511 | 512 | /* line 35, ../sass/partials/_forms.scss */ 513 | select { 514 | padding: 0; 515 | width: 220px; 516 | } 517 | 518 | /* line 40, ../sass/partials/_forms.scss */ 519 | textarea { 520 | min-height: 60px; 521 | } 522 | 523 | /* line 44, ../sass/partials/_forms.scss */ 524 | label, legend { 525 | display: block; 526 | font-weight: bold; 527 | font-size: 13px; 528 | } 529 | 530 | /* line 50, ../sass/partials/_forms.scss */ 531 | input[type="checkbox"] { 532 | display: inline; 533 | } 534 | 535 | /* line 54, ../sass/partials/_forms.scss */ 536 | label span, legend span { 537 | font-weight: normal; 538 | font-size: 13px; 539 | color: #444; 540 | } 541 | 542 | /* line 4, ../sass/partials/_misc.scss */ 543 | .remove-bottom { 544 | margin-bottom: 0 !important; 545 | } 546 | 547 | /* line 5, ../sass/partials/_misc.scss */ 548 | .half-bottom { 549 | margin-bottom: 10px !important; 550 | } 551 | 552 | /* line 6, ../sass/partials/_misc.scss */ 553 | .add-bottom { 554 | margin-bottom: 20px !important; 555 | } 556 | 557 | /* line 18, ../sass/partials/_grid.scss */ 558 | .container { 559 | position: relative; 560 | width: 960px; 561 | margin: 0 auto; 562 | padding: 0; 563 | } 564 | 565 | /* line 19, ../sass/partials/_grid.scss */ 566 | .row { 567 | margin-bottom: 20px; 568 | } 569 | 570 | /* line 22, ../sass/partials/_grid.scss */ 571 | .container { 572 | /* Nested Column Classes */ 573 | } 574 | /* line 25, ../sass/partials/_grid.scss */ 575 | .container .one.column, .container .one-third.column, .container .two-thirds.column, 576 | .container .one.columns { 577 | width: 40px; 578 | float: left; 579 | display: inline; 580 | margin: 0 10px 20px 10px; 581 | } 582 | /* line 26, ../sass/partials/_grid.scss */ 583 | .container .two.columns { 584 | width: 100px; 585 | float: left; 586 | display: inline; 587 | margin: 0 10px 20px 10px; 588 | } 589 | /* line 27, ../sass/partials/_grid.scss */ 590 | .container .three.columns { 591 | width: 160px; 592 | float: left; 593 | display: inline; 594 | margin: 0 10px 20px 10px; 595 | } 596 | /* line 28, ../sass/partials/_grid.scss */ 597 | .container .four.columns { 598 | width: 220px; 599 | float: left; 600 | display: inline; 601 | margin: 0 10px 20px 10px; 602 | } 603 | /* line 29, ../sass/partials/_grid.scss */ 604 | .container .five.columns { 605 | width: 280px; 606 | float: left; 607 | display: inline; 608 | margin: 0 10px 20px 10px; 609 | } 610 | /* line 30, ../sass/partials/_grid.scss */ 611 | .container .six.columns { 612 | width: 340px; 613 | float: left; 614 | display: inline; 615 | margin: 0 10px 20px 10px; 616 | } 617 | /* line 31, ../sass/partials/_grid.scss */ 618 | .container .seven.columns { 619 | width: 400px; 620 | float: left; 621 | display: inline; 622 | margin: 0 10px 20px 10px; 623 | } 624 | /* line 32, ../sass/partials/_grid.scss */ 625 | .container .eight.columns { 626 | width: 460px; 627 | float: left; 628 | display: inline; 629 | margin: 0 10px 20px 10px; 630 | } 631 | /* line 33, ../sass/partials/_grid.scss */ 632 | .container .nine.columns { 633 | width: 520px; 634 | float: left; 635 | display: inline; 636 | margin: 0 10px 20px 10px; 637 | } 638 | /* line 34, ../sass/partials/_grid.scss */ 639 | .container .ten.columns { 640 | width: 580px; 641 | float: left; 642 | display: inline; 643 | margin: 0 10px 20px 10px; 644 | } 645 | /* line 35, ../sass/partials/_grid.scss */ 646 | .container .eleven.columns { 647 | width: 640px; 648 | float: left; 649 | display: inline; 650 | margin: 0 10px 20px 10px; 651 | } 652 | /* line 36, ../sass/partials/_grid.scss */ 653 | .container .twelve.columns { 654 | width: 700px; 655 | float: left; 656 | display: inline; 657 | margin: 0 10px 20px 10px; 658 | } 659 | /* line 37, ../sass/partials/_grid.scss */ 660 | .container .thirteen.columns { 661 | width: 760px; 662 | float: left; 663 | display: inline; 664 | margin: 0 10px 20px 10px; 665 | } 666 | /* line 38, ../sass/partials/_grid.scss */ 667 | .container .fourteen.columns { 668 | width: 820px; 669 | float: left; 670 | display: inline; 671 | margin: 0 10px 20px 10px; 672 | } 673 | /* line 39, ../sass/partials/_grid.scss */ 674 | .container .fifteen.columns { 675 | width: 880px; 676 | float: left; 677 | display: inline; 678 | margin: 0 10px 20px 10px; 679 | } 680 | /* line 40, ../sass/partials/_grid.scss */ 681 | .container .sixteen.columns { 682 | width: 940px; 683 | float: left; 684 | display: inline; 685 | margin: 0 10px 20px 10px; 686 | } 687 | /* line 42, ../sass/partials/_grid.scss */ 688 | .container .one-third.column { 689 | width: 300px; 690 | } 691 | /* line 43, ../sass/partials/_grid.scss */ 692 | .container .two-thirds.column { 693 | width: 600px; 694 | } 695 | /* line 46, ../sass/partials/_grid.scss */ 696 | .container .offset-by-one { 697 | padding-left: 60px; 698 | } 699 | /* line 47, ../sass/partials/_grid.scss */ 700 | .container .offset-by-two { 701 | padding-left: 120px; 702 | } 703 | /* line 48, ../sass/partials/_grid.scss */ 704 | .container .offset-by-three { 705 | padding-left: 180px; 706 | } 707 | /* line 49, ../sass/partials/_grid.scss */ 708 | .container .offset-by-four { 709 | padding-left: 240px; 710 | } 711 | /* line 50, ../sass/partials/_grid.scss */ 712 | .container .offset-by-five { 713 | padding-left: 300px; 714 | } 715 | /* line 51, ../sass/partials/_grid.scss */ 716 | .container .offset-by-six { 717 | padding-left: 360px; 718 | } 719 | /* line 52, ../sass/partials/_grid.scss */ 720 | .container .offset-by-seven { 721 | padding-left: 420px; 722 | } 723 | /* line 53, ../sass/partials/_grid.scss */ 724 | .container .offset-by-eight { 725 | padding-left: 480px; 726 | } 727 | /* line 54, ../sass/partials/_grid.scss */ 728 | .container .offset-by-nine { 729 | padding-left: 540px; 730 | } 731 | /* line 55, ../sass/partials/_grid.scss */ 732 | .container .offset-by-ten { 733 | padding-left: 600px; 734 | } 735 | /* line 56, ../sass/partials/_grid.scss */ 736 | .container .offset-by-eleven { 737 | padding-left: 660px; 738 | } 739 | /* line 57, ../sass/partials/_grid.scss */ 740 | .container .offset-by-twelve { 741 | padding-left: 720px; 742 | } 743 | /* line 58, ../sass/partials/_grid.scss */ 744 | .container .offset-by-thirteen { 745 | padding-left: 780px; 746 | } 747 | /* line 59, ../sass/partials/_grid.scss */ 748 | .container .offset-by-fourteen { 749 | padding-left: 840px; 750 | } 751 | /* line 60, ../sass/partials/_grid.scss */ 752 | .container .offset-by-fifteen { 753 | padding-left: 900px; 754 | } 755 | /* line 63, ../sass/partials/_grid.scss */ 756 | .container .column.alpha, .container .columns.alpha { 757 | margin-left: 0; 758 | } 759 | /* line 64, ../sass/partials/_grid.scss */ 760 | .container .column.omega, .container .columns.omega { 761 | margin-right: 0; 762 | } 763 | 764 | /* #Tablet (Portrait) 765 | ================================================== */ 766 | /* Note: Design for a width of 768px */ 767 | @media only screen and (min-width: 768px) and (max-width: 959px) { 768 | /* line 75, ../sass/partials/_grid.scss */ 769 | .container { 770 | width: 768px; 771 | } 772 | 773 | /* line 77, ../sass/partials/_grid.scss */ 774 | .container .column, 775 | .container .columns { 776 | margin-left: 10px; 777 | margin-right: 10px; 778 | } 779 | 780 | /* line 78, ../sass/partials/_grid.scss */ 781 | .column.alpha, .columns.alpha { 782 | margin-left: 0; 783 | margin-right: 10px; 784 | } 785 | 786 | /* line 79, ../sass/partials/_grid.scss */ 787 | .column.omega, .columns.omega { 788 | margin-right: 0; 789 | margin-left: 10px; 790 | } 791 | 792 | /* line 80, ../sass/partials/_grid.scss */ 793 | .alpha.omega { 794 | margin-left: 0; 795 | margin-right: 0; 796 | } 797 | 798 | /* line 83, ../sass/partials/_grid.scss */ 799 | .container .one.column, .container .one-third.column, .container .two-thirds.column, 800 | .container .one.columns { 801 | width: 28px; 802 | } 803 | 804 | /* line 84, ../sass/partials/_grid.scss */ 805 | .container .two.columns { 806 | width: 76px; 807 | } 808 | 809 | /* line 85, ../sass/partials/_grid.scss */ 810 | .container .three.columns { 811 | width: 124px; 812 | } 813 | 814 | /* line 86, ../sass/partials/_grid.scss */ 815 | .container .four.columns { 816 | width: 172px; 817 | } 818 | 819 | /* line 87, ../sass/partials/_grid.scss */ 820 | .container .five.columns { 821 | width: 220px; 822 | } 823 | 824 | /* line 88, ../sass/partials/_grid.scss */ 825 | .container .six.columns { 826 | width: 268px; 827 | } 828 | 829 | /* line 89, ../sass/partials/_grid.scss */ 830 | .container .seven.columns { 831 | width: 316px; 832 | } 833 | 834 | /* line 90, ../sass/partials/_grid.scss */ 835 | .container .eight.columns { 836 | width: 364px; 837 | } 838 | 839 | /* line 91, ../sass/partials/_grid.scss */ 840 | .container .nine.columns { 841 | width: 412px; 842 | } 843 | 844 | /* line 92, ../sass/partials/_grid.scss */ 845 | .container .ten.columns { 846 | width: 460px; 847 | } 848 | 849 | /* line 93, ../sass/partials/_grid.scss */ 850 | .container .eleven.columns { 851 | width: 508px; 852 | } 853 | 854 | /* line 94, ../sass/partials/_grid.scss */ 855 | .container .twelve.columns { 856 | width: 556px; 857 | } 858 | 859 | /* line 95, ../sass/partials/_grid.scss */ 860 | .container .thirteen.columns { 861 | width: 604px; 862 | } 863 | 864 | /* line 96, ../sass/partials/_grid.scss */ 865 | .container .fourteen.columns { 866 | width: 652px; 867 | } 868 | 869 | /* line 97, ../sass/partials/_grid.scss */ 870 | .container .fifteen.columns { 871 | width: 700px; 872 | } 873 | 874 | /* line 98, ../sass/partials/_grid.scss */ 875 | .container .sixteen.columns { 876 | width: 748px; 877 | } 878 | 879 | /* line 100, ../sass/partials/_grid.scss */ 880 | .container .one-third.column { 881 | width: 236px; 882 | } 883 | 884 | /* line 101, ../sass/partials/_grid.scss */ 885 | .container .two-thirds.column { 886 | width: 492px; 887 | } 888 | 889 | /* Offsets */ 890 | /* line 104, ../sass/partials/_grid.scss */ 891 | .container .offset-by-one { 892 | padding-left: 48px; 893 | } 894 | 895 | /* line 105, ../sass/partials/_grid.scss */ 896 | .container .offset-by-two { 897 | padding-left: 96px; 898 | } 899 | 900 | /* line 106, ../sass/partials/_grid.scss */ 901 | .container .offset-by-three { 902 | padding-left: 144px; 903 | } 904 | 905 | /* line 107, ../sass/partials/_grid.scss */ 906 | .container .offset-by-four { 907 | padding-left: 192px; 908 | } 909 | 910 | /* line 108, ../sass/partials/_grid.scss */ 911 | .container .offset-by-five { 912 | padding-left: 240px; 913 | } 914 | 915 | /* line 109, ../sass/partials/_grid.scss */ 916 | .container .offset-by-six { 917 | padding-left: 288px; 918 | } 919 | 920 | /* line 110, ../sass/partials/_grid.scss */ 921 | .container .offset-by-seven { 922 | padding-left: 336px; 923 | } 924 | 925 | /* line 111, ../sass/partials/_grid.scss */ 926 | .container .offset-by-eight { 927 | padding-left: 348px; 928 | } 929 | 930 | /* line 112, ../sass/partials/_grid.scss */ 931 | .container .offset-by-nine { 932 | padding-left: 432px; 933 | } 934 | 935 | /* line 113, ../sass/partials/_grid.scss */ 936 | .container .offset-by-ten { 937 | padding-left: 480px; 938 | } 939 | 940 | /* line 114, ../sass/partials/_grid.scss */ 941 | .container .offset-by-eleven { 942 | padding-left: 528px; 943 | } 944 | 945 | /* line 115, ../sass/partials/_grid.scss */ 946 | .container .offset-by-twelve { 947 | padding-left: 576px; 948 | } 949 | 950 | /* line 116, ../sass/partials/_grid.scss */ 951 | .container .offset-by-thirteen { 952 | padding-left: 624px; 953 | } 954 | 955 | /* line 117, ../sass/partials/_grid.scss */ 956 | .container .offset-by-fourteen { 957 | padding-left: 672px; 958 | } 959 | 960 | /* line 118, ../sass/partials/_grid.scss */ 961 | .container .offset-by-fifteen { 962 | padding-left: 720px; 963 | } 964 | } 965 | /* #Mobile (Portrait) 966 | ================================================== */ 967 | /* Note: Design for a width of 320px */ 968 | @media only screen and (max-width: 767px) { 969 | /* line 128, ../sass/partials/_grid.scss */ 970 | .container { 971 | width: 300px; 972 | } 973 | 974 | /* line 130, ../sass/partials/_grid.scss */ 975 | .container .columns, 976 | .container .column { 977 | margin: 0; 978 | } 979 | 980 | /* line 150, ../sass/partials/_grid.scss */ 981 | .container .one.column, .container .one-third.column, .container .two-thirds.column, 982 | .container .one.columns, 983 | .container .two.columns, 984 | .container .three.columns, 985 | .container .four.columns, 986 | .container .five.columns, 987 | .container .six.columns, 988 | .container .seven.columns, 989 | .container .eight.columns, 990 | .container .nine.columns, 991 | .container .ten.columns, 992 | .container .eleven.columns, 993 | .container .twelve.columns, 994 | .container .thirteen.columns, 995 | .container .fourteen.columns, 996 | .container .fifteen.columns, 997 | .container .sixteen.columns, 998 | .container .one-third.column, 999 | .container .two-thirds.column { 1000 | width: 300px; 1001 | } 1002 | 1003 | /* Offsets */ 1004 | /* line 167, ../sass/partials/_grid.scss */ 1005 | .container .offset-by-one, 1006 | .container .offset-by-two, 1007 | .container .offset-by-three, 1008 | .container .offset-by-four, 1009 | .container .offset-by-five, 1010 | .container .offset-by-six, 1011 | .container .offset-by-seven, 1012 | .container .offset-by-eight, 1013 | .container .offset-by-nine, 1014 | .container .offset-by-ten, 1015 | .container .offset-by-eleven, 1016 | .container .offset-by-twelve, 1017 | .container .offset-by-thirteen, 1018 | .container .offset-by-fourteen, 1019 | .container .offset-by-fifteen { 1020 | padding-left: 0; 1021 | } 1022 | } 1023 | /* #Mobile (Landscape) 1024 | ================================================== */ 1025 | /* Note: Design for a width of 480px */ 1026 | @media only screen and (min-width: 480px) and (max-width: 767px) { 1027 | /* line 178, ../sass/partials/_grid.scss */ 1028 | .container { 1029 | width: 420px; 1030 | } 1031 | 1032 | /* line 180, ../sass/partials/_grid.scss */ 1033 | .container .columns, 1034 | .container .column { 1035 | margin: 0; 1036 | } 1037 | 1038 | /* line 200, ../sass/partials/_grid.scss */ 1039 | .container .one.column, .container .one-third.column, .container .two-thirds.column, 1040 | .container .one.columns, 1041 | .container .two.columns, 1042 | .container .three.columns, 1043 | .container .four.columns, 1044 | .container .five.columns, 1045 | .container .six.columns, 1046 | .container .seven.columns, 1047 | .container .eight.columns, 1048 | .container .nine.columns, 1049 | .container .ten.columns, 1050 | .container .eleven.columns, 1051 | .container .twelve.columns, 1052 | .container .thirteen.columns, 1053 | .container .fourteen.columns, 1054 | .container .fifteen.columns, 1055 | .container .sixteen.columns, 1056 | .container .one-third.column, 1057 | .container .two-thirds.column { 1058 | width: 420px; 1059 | } 1060 | } 1061 | /* #Clearing 1062 | ================================================== */ 1063 | /* Self Clearing Goodness */ 1064 | /* line 208, ../sass/partials/_grid.scss */ 1065 | .container:after { 1066 | content: "\0020"; 1067 | display: block; 1068 | height: 0; 1069 | clear: both; 1070 | visibility: hidden; 1071 | } 1072 | 1073 | /* Use clearfix class on parent to clear nested columns, 1074 | or wrap each row of columns in a
*/ 1075 | /* line 215, ../sass/partials/_grid.scss */ 1076 | .clearfix:before, 1077 | .clearfix:after, 1078 | .row:before, 1079 | .row:after { 1080 | content: '\0020'; 1081 | display: block; 1082 | overflow: hidden; 1083 | visibility: hidden; 1084 | width: 0; 1085 | height: 0; 1086 | } 1087 | 1088 | /* line 223, ../sass/partials/_grid.scss */ 1089 | .row:after, 1090 | .clearfix:after { 1091 | clear: both; 1092 | } 1093 | 1094 | /* line 226, ../sass/partials/_grid.scss */ 1095 | .row, 1096 | .clearfix { 1097 | zoom: 1; 1098 | } 1099 | 1100 | /* You can also use a
to clear columns */ 1101 | /* line 230, ../sass/partials/_grid.scss */ 1102 | .clear { 1103 | clear: both; 1104 | display: block; 1105 | overflow: hidden; 1106 | visibility: hidden; 1107 | width: 0; 1108 | height: 0; 1109 | } 1110 | 1111 | /* line 3, ../sass/partials/_custom.scss */ 1112 | body { 1113 | background: #333333 url("/images/dark_dotted.png"); 1114 | padding-top: 60px; 1115 | } 1116 | 1117 | /* line 8, ../sass/partials/_custom.scss */ 1118 | section { 1119 | background: #d9d9d9 url("/images/brushed_alu.png"); 1120 | margin: 0 auto; 1121 | padding: 10px; 1122 | width: 45%; 1123 | -moz-border-radius: 3px; 1124 | -webkit-border-radius: 3px; 1125 | -o-border-radius: 3px; 1126 | -ms-border-radius: 3px; 1127 | -khtml-border-radius: 3px; 1128 | border-radius: 3px; 1129 | } 1130 | /* line 16, ../sass/partials/_custom.scss */ 1131 | section header { 1132 | text-align: center; 1133 | } 1134 | 1135 | /* line 21, ../sass/partials/_custom.scss */ 1136 | p { 1137 | margin: 1em 0; 1138 | } 1139 | 1140 | /* line 25, ../sass/partials/_custom.scss */ 1141 | #feed { 1142 | background: #222; 1143 | border: 1px solid #111; 1144 | border-bottom: 0; 1145 | color: #fff; 1146 | height: 400px; 1147 | margin-top: 20px; 1148 | overflow-y: scroll; 1149 | padding: 1% 2%; 1150 | width: 96%; 1151 | -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 1px rgba(255, 255, 255, 0.75); 1152 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 1px rgba(255, 255, 255, 0.75); 1153 | -o-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 1px rgba(255, 255, 255, 0.75); 1154 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 1px rgba(255, 255, 255, 0.75); 1155 | -moz-border-radius-topleft: 3px; 1156 | -webkit-border-top-left-radius: 3px; 1157 | -o-border-top-left-radius: 3px; 1158 | -ms-border-top-left-radius: 3px; 1159 | -khtml-border-top-left-radius: 3px; 1160 | border-top-left-radius: 3px; 1161 | -moz-border-radius-topright: 3px; 1162 | -webkit-border-top-right-radius: 3px; 1163 | -o-border-top-right-radius: 3px; 1164 | -ms-border-top-right-radius: 3px; 1165 | -khtml-border-top-right-radius: 3px; 1166 | border-top-right-radius: 3px; 1167 | } 1168 | /* line 39, ../sass/partials/_custom.scss */ 1169 | #feed strong { 1170 | color: #f0f0f0; 1171 | } 1172 | 1173 | /* line 45, ../sass/partials/_custom.scss */ 1174 | input[type="text"] { 1175 | background: #111; 1176 | border-color: transparent #111 #000; 1177 | color: #fff; 1178 | display: block; 1179 | margin: 0 auto; 1180 | position: relative; 1181 | width: 98.5%; 1182 | -moz-border-radius-topleft: 0; 1183 | -webkit-border-top-left-radius: 0; 1184 | -o-border-top-left-radius: 0; 1185 | -ms-border-top-left-radius: 0; 1186 | -khtml-border-top-left-radius: 0; 1187 | border-top-left-radius: 0; 1188 | -moz-border-radius-topright: 0; 1189 | -webkit-border-top-right-radius: 0; 1190 | -o-border-top-right-radius: 0; 1191 | -ms-border-top-right-radius: 0; 1192 | -khtml-border-top-right-radius: 0; 1193 | border-top-right-radius: 0; 1194 | } 1195 | -------------------------------------------------------------------------------- /server/routes.js: -------------------------------------------------------------------------------- 1 | // Routes 2 | 3 | var plates = require("plates"), 4 | fs = require("fs"); 5 | 6 | module.exports = function(app) { 7 | 8 | app.router.get("/", function() { 9 | 10 | var req = this.req, 11 | res = this.res; 12 | 13 | fs.readFile(__dirname + '/index.html', function (err, data) { 14 | 15 | if (err) { 16 | res.writeHead(500); 17 | return res.end('Error loading index.html'); 18 | } 19 | 20 | res.writeHead(200, { 'Content-Type': 'text/html' }); 21 | 22 | res.end(data); 23 | 24 | }); 25 | 26 | }); 27 | 28 | }; -------------------------------------------------------------------------------- /test/format-test.js: -------------------------------------------------------------------------------- 1 | require("../nodebot"); 2 | 3 | var vows = require('vows'), 4 | assert = require('assert'), 5 | align = require("../brain/formatter").align 6 | ; 7 | 8 | // -------------------------------------------------- // 9 | 10 | 11 | vows.describe("Text Formatting").addBatch({ 12 | 13 | 'It should calculate the best fit for a word within a group' : { 14 | 15 | "left orientation should work": function() { 16 | 17 | var orientation = align("foobar", 10, "left"); 18 | 19 | assert.equal(orientation, "foobar "); 20 | assert.equal(orientation.length, 10); 21 | }, 22 | 23 | "center orientation should work": function() { 24 | 25 | var orientation = align("foobar", 10, "center"); 26 | 27 | assert.equal(orientation, " foobar "); 28 | assert.equal(orientation.length, 10); 29 | }, 30 | 31 | "right orientation should work": function() { 32 | 33 | var orientation = align("foobar", 10, "right"); 34 | 35 | assert.equal(orientation, " foobar"); 36 | assert.equal(orientation.length, 10); 37 | }, 38 | 39 | } 40 | 41 | }).export(module); 42 | -------------------------------------------------------------------------------- /test/language-test.js: -------------------------------------------------------------------------------- 1 | require("../nodebot"); 2 | 3 | var vows = require('vows'), 4 | assert = require('assert'), 5 | lang = require("../brain/language") 6 | ; 7 | 8 | // -------------------------------------------------- // 9 | 10 | 11 | vows.describe("Language").addBatch({ 12 | 13 | 'It should be able to capitalize words' : { 14 | 15 | "The capitalized form of foobar should be Foobar": function() { 16 | assert.equal(lang.capitalize("foobar"), "Foobar"); 17 | } 18 | 19 | }, 20 | 21 | 'It should be able to possesify words' : { 22 | 23 | "The possessive form of Foobar should be \"Foobar's\"": function() { 24 | assert.equal(lang.possessify("Foobar"), "Foobar's"); 25 | }, 26 | 27 | "The possessive form of Foobars should be \"Foobars'\"": function() { 28 | assert.equal(lang.possessify("Foobars"), "Foobars'"); 29 | }, 30 | 31 | "The possessive form of Foobar's should be \"Foobar's\"": function() { 32 | assert.equal(lang.possessify("Foobar's"), "Foobar's"); 33 | } 34 | }, 35 | 36 | 'It should be able to deposessify a word' : { 37 | 38 | "The depossessed form of Foobar's should be \"Foobar\"": function() { 39 | assert.equal(lang.depossessify("Foobar's"), "Foobar"); 40 | }, 41 | 42 | "The depossessed form of Foobars' should be \"Foobars\"": function() { 43 | assert.equal(lang.depossessify("Foobars'"), "Foobars"); 44 | }, 45 | 46 | "The depossessed form of Foobar should be \"Foobar\"": function() { 47 | assert.equal(lang.depossessify("Foobar"), "Foobar"); 48 | } 49 | } 50 | 51 | }).export(module); 52 | -------------------------------------------------------------------------------- /test/lexicon-test.js: -------------------------------------------------------------------------------- 1 | require("../nodebot"); 2 | 3 | var vows = require('vows') 4 | , assert = require('assert') 5 | , tagger = require("../brain/language") 6 | ; 7 | 8 | // -------------------------------------------------- // 9 | 10 | 11 | vows.describe("Lexicon").addBatch({ 12 | 13 | 'It should be able to interpret lexical actions' : { 14 | 15 | topic: tagger.classify("Set wolframalpha to ABC-123"), 16 | 17 | "the action should be Set": function(topic) { 18 | assert.equal(topic.action, "set"); 19 | }, 20 | 21 | "the subject should be ACB-123": function(topic) { 22 | assert.equal(topic.subject, "ABC-123"); 23 | } 24 | 25 | } 26 | 27 | }).export(module); 28 | -------------------------------------------------------------------------------- /validator/css.js: -------------------------------------------------------------------------------- 1 | // NodeBot Javascript Validator 2 | 3 | var fs = require("fs"); 4 | 5 | module.exports.validate = function(file) { 6 | 7 | var data = fs.readFileSync(file, 'utf-8') 8 | , options = require("./jshint_config") 9 | , validator = require("csslint").CSSLint 10 | , nodebot = this; 11 | 12 | // Validate it 13 | var validation = validator.verify(data, options); 14 | 15 | if (validation.messages.length > 0) { 16 | 17 | var errors = ""; 18 | 19 | // Report errors 20 | validator.messages.forEach(function(message){ 21 | if (message.type === error) { 22 | errors += "\n" + (error.line.toString() + ":" + error.col.toString() + " - " + error.message).red.bold; 23 | } else { 24 | errors += "\n" + (error.line.toString() + ":" + error.col.toString() + " - " + error.message).yellow.bold; 25 | } 26 | }); 27 | 28 | nodebot.say(errors); 29 | nodebot.growl("Sorry. I found " + validation.messages.length + " errors in " + file + " (See terminal)", "error"); 30 | 31 | } else { 32 | nodebot.say(file.green.bold + " is valid".green.bold); 33 | } 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /validator/html.js: -------------------------------------------------------------------------------- 1 | // Nodebot HTML validator 2 | // 3 | // Validates HTML using validator.nu 4 | // -------------------------------------------------- // 5 | 6 | var request = require("request") 7 | , $ = require('jquery') 8 | , fs = require('fs') 9 | , report = require(__dirname + "/reporter"); 10 | 11 | var validate = module.exports.validate = function(file, callback) { 12 | 13 | var Nodebot = this 14 | , content = fs.readFileSync(file, "utf-8"); 15 | 16 | scan(content); 17 | 18 | }; 19 | 20 | var scan = module.exports.scan = function scan (string, callback) { 21 | 22 | callback = callback || Nodebot.request; 23 | 24 | request({ 25 | 26 | method: "POST", 27 | uri :'http://html5.validator.nu', 28 | body : string.trim(), 29 | headers: { 'content-type' : 'text/html'} 30 | 31 | }, function (error, response, body) { 32 | 33 | if (!error && response.statusCode === 200) { 34 | 35 | var errors = []; 36 | 37 | $(body).find("ol").children("li").each(function(i) { 38 | 39 | errors.push({ 40 | type : $(this).attr("class"), 41 | line : $(this).find(".last-line").text(), 42 | character : $(this).find(".last-col").text(), 43 | reason : $(this).children("p").first().text() 44 | }); 45 | 46 | }); 47 | 48 | report(errors); 49 | 50 | } else if (response.statusCode !== 200) { 51 | Nodebot.say(("I got a " + response.statusCode + " :(").red.bold); 52 | } else { 53 | Nodebot.say("Something went horribly wrong :(".red.bold); 54 | console.log(error); 55 | } 56 | 57 | callback(); 58 | 59 | }); 60 | }; 61 | -------------------------------------------------------------------------------- /validator/javascript.js: -------------------------------------------------------------------------------- 1 | // The Nodebot Javascript Validator 2 | // 3 | // Validates Javascript using jshint 4 | // -------------------------------------------------- // 5 | 6 | var fs = require("fs") 7 | , generate_report = require(__dirname + "/reporter"); 8 | 9 | module.exports.validate = function(file, callback) { 10 | 11 | var data = fs.readFileSync(file, 'utf-8') 12 | , options = require("./jshint_config") 13 | , validator = require("jshint").JSHINT 14 | , nodebot = this 15 | , report = []; 16 | 17 | // Validate it 18 | validator(data, options); 19 | 20 | errors = validator.errors; 21 | 22 | if (errors.length > 0) { 23 | 24 | // Report errors 25 | validator.errors.forEach(function(error){ 26 | 27 | if (error === null) return false; 28 | 29 | error.type = "error"; 30 | 31 | return report.push(error); 32 | }); 33 | 34 | generate_report(report); 35 | 36 | } else { 37 | nodebot.say(file.green.bold + " is valid".green.bold); 38 | } 39 | 40 | 41 | callback(); 42 | }; 43 | -------------------------------------------------------------------------------- /validator/jshint_config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | // Settings 4 | "passfail" : false, // Stop on first error. 5 | "maxerr" : 100, // Maximum error before stopping. 6 | 7 | 8 | // Predefined globals whom JSHint will ignore. 9 | "browser" : true, // Standard browser globals e.g. `window`, `document`. 10 | 11 | "node" : true, 12 | "rhino" : false, 13 | "couch" : false, 14 | "wsh" : true, // Windows Scripting Host. 15 | 16 | "jquery" : true, 17 | "prototypejs" : false, 18 | "mootools" : false, 19 | "dojo" : false, 20 | 21 | "predef" : [ // Custom globals. 22 | //"exampleVar", 23 | //"anotherCoolGlobal", 24 | //"iLoveDouglas" 25 | ], 26 | 27 | 28 | // Development. 29 | "debug" : false, // Allow debugger statements e.g. browser breakpoints. 30 | "devel" : true, // Allow developments statements e.g. `console.log();`. 31 | 32 | 33 | // ECMAScript 5. 34 | "es5" : true, // Allow ECMAScript 5 syntax. 35 | "strict" : false, // Require `use strict` pragma in every file. 36 | "globalstrict" : false, // Allow global "use strict" (also enables 'strict'). 37 | 38 | 39 | // The Good Parts. 40 | "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). 41 | "laxbreak" : true, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. 42 | "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). 43 | "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. 44 | "curly" : true, // Require {} for every new block or scope. 45 | "eqeqeq" : true, // Require triple equals i.e. `===`. 46 | "eqnull" : false, // Tolerate use of `== null`. 47 | "evil" : false, // Tolerate use of `eval`. 48 | "expr" : false, // Tolerate `ExpressionStatement` as Programs. 49 | "forin" : false, // Tolerate `for in` loops without `hasOwnPrototype`. 50 | "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 51 | "latedef" : true, // Prohipit variable use before definition. 52 | "loopfunc" : false, // Allow functions to be defined within loops. 53 | "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. 54 | "regexp" : true, // Prohibit `.` and `[^...]` in regular expressions. 55 | "regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`. 56 | "scripturl" : true, // Tolerate script-targeted URLs. 57 | "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. 58 | "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. 59 | "undef" : true, // Require all non-global variables be declared before they are used. 60 | 61 | 62 | // Personal styling preferences. 63 | "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. 64 | "noempty" : true, // Prohibit use of empty blocks. 65 | "nonew" : true, // Prohibit use of constructors for side-effects. 66 | "nomen" : true, // Prohibit use of initial or trailing underbars in names. 67 | "onevar" : false, // Allow only one `var` statement per function. 68 | "plusplus" : false, // Prohibit use of `++` & `--`. 69 | "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. 70 | "trailing" : true, // Prohibit trailing whitespaces. 71 | "white" : false, // Check against strict whitespace and indentation rules. 72 | "indent" : 4 // Specify indentation spacing 73 | } -------------------------------------------------------------------------------- /validator/reporter.js: -------------------------------------------------------------------------------- 1 | // The Reporter 2 | // Prints the validation report 3 | // --------------------------------------------------- // 4 | 5 | var colors = ['blue', 'yellow', 'red', 'white'] 6 | , width = 80 7 | , hr = Array(width).join("-") 8 | , clump = require("../brain/formatter").clump 9 | , space = require("../brain/formatter").whitespace 10 | ; 11 | 12 | 13 | module.exports = function(report) { 14 | 15 | var info = report.filter(function(i) { return (i.type === "info"); }) 16 | , warn = report.filter(function(i) { return (i.type === "warning"); }) 17 | , err = report.filter(function(i) { return (i.type === "error"); }); 18 | 19 | 20 | Nodebot.say("I was able to find " + report.length.toString().bold.red + " issues:"); 21 | 22 | console.log("%s \n Line: | Problem:\n%s", hr, hr); 23 | 24 | [info, warn, err].forEach(function(a, i) { 25 | 26 | var color = colors[i]; 27 | 28 | a.forEach(function(e) { 29 | 30 | // Protect ourselves from undefined values 31 | if (!e.line || !e.character) return false; 32 | 33 | var spot = (e.line + ":" + e.character) 34 | , message = (space(spot.length) + clump(e.reason, 75, spot.length + 7)); 35 | 36 | return console.log(" " + spot[color].bold + message[color]); 37 | 38 | }); 39 | 40 | if (a.length > 0) { 41 | console.log(hr); 42 | } 43 | 44 | }); 45 | 46 | }; 47 | -------------------------------------------------------------------------------- /validator/website.js: -------------------------------------------------------------------------------- 1 | // The Nodebot Website Validator 2 | // 3 | // Validates the HTML from a website 4 | // -------------------------------------------------- // 5 | 6 | var request = require("request") 7 | , scan = require(__dirname + "/html").scan; 8 | 9 | module.exports.validate = function(address, callback) { 10 | 11 | var nodebot = this; 12 | 13 | // Bind the approriate protocol if it wasn't included 14 | if (!address.match(/http(\S|):/i)) { 15 | address = "http://" + address; 16 | } 17 | 18 | nodebot.say("Searching for " + address.magenta.bold + "..." ); 19 | 20 | request(address, function (error, response, body) { 21 | 22 | // Bulletproof sites that don't exist 23 | if (response === undefined){ 24 | nodebot.say("I couldn't find anything, period. Does this site exist?"); 25 | return callback(); 26 | } 27 | 28 | if (!error && response.statusCode == 200) { 29 | nodebot.say("I found " + address.magenta.bold + ". I am now requesting the validator..."); 30 | 31 | return scan(body, callback); 32 | 33 | } else if (response.statusCode !== 200) { 34 | nodebot.say(("I got a " + response.statusCode + " :(").red.bold); 35 | } else { 36 | nodebot.say("I couldn't find this address, are you sure it exists?".red.bold); 37 | } 38 | 39 | return callback(); 40 | }); 41 | 42 | }; 43 | --------------------------------------------------------------------------------