├── .gitignore ├── views ├── error.hjs ├── result.hjs ├── layout.hjs └── index.hjs ├── bower.json ├── package.json ├── app.js ├── bin └── www ├── routes └── index.js └── public └── stylesheets └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components 3 | -------------------------------------------------------------------------------- /views/error.hjs: -------------------------------------------------------------------------------- 1 |

{{ message }}

2 |

{{ error.status }}

3 |
{{ error.stack }}
4 | -------------------------------------------------------------------------------- /views/result.hjs: -------------------------------------------------------------------------------- 1 | 2 | {{< layout }}{{$ content }} 3 | 4 |
5 |
6 |
7 | 8 |
{{ size }} {{ unit }}
9 |
{{{ result }}}
10 | 11 |
12 |
13 |
14 | 15 | {{/ content }}{{/ layout }} 16 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ismydatabig", 3 | "description": "Your data is not big. Most likely.", 4 | "main": "", 5 | "authors": [ 6 | "Gábor Csárdi " 7 | ], 8 | "license": "MIT", 9 | "homepage": "https://github.com/gaborcsardi/ismydatabig", 10 | "private": true, 11 | "ignore": [ 12 | "**/.*", 13 | "node_modules", 14 | "bower_components", 15 | "test", 16 | "tests" 17 | ], 18 | "dependencies": { 19 | "pure": "^0.6.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ismydatabig", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www", 7 | "postinstall": "bower cache clean && bower install" 8 | }, 9 | "engines": { 10 | "node": "5.11.x" 11 | }, 12 | "dependencies": { 13 | "body-parser": "~1.13.2", 14 | "bower": "^1.7.9", 15 | "cookie-parser": "~1.3.5", 16 | "debug": "~2.2.0", 17 | "express": "~4.13.1", 18 | "hjs": "~0.0.6", 19 | "hogan-express": "^0.5.2", 20 | "morgan": "~1.6.1", 21 | "serve-favicon": "~2.3.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /views/layout.hjs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | {{ title }} 27 | 28 | 29 | 30 | 31 |
32 |
{{$ content }}{{/ content }} 33 |
34 |
35 | 36 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var index = require('./routes/index'); 9 | 10 | var app = express(); 11 | 12 | // view engine setup 13 | app.set('views', path.join(__dirname, 'views')); 14 | app.engine('hjs', require('hogan-express')); 15 | app.set('view engine', 'hjs'); 16 | app.set('partials', { 17 | 'layout': 'layout' 18 | }); 19 | 20 | // uncomment after placing your favicon in /public 21 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 22 | app.use(logger('dev')); 23 | app.use(bodyParser.json()); 24 | app.use(bodyParser.urlencoded({ extended: false })); 25 | app.use(cookieParser()); 26 | app.use(express.static(path.join(__dirname, 'public'))); 27 | app.use('/bower_components', 28 | express.static(__dirname + '/bower_components')); 29 | 30 | app.use('/', index); 31 | 32 | // catch 404 and forward to error handler 33 | app.use(function(req, res, next) { 34 | var err = new Error('Not Found'); 35 | err.status = 404; 36 | next(err); 37 | }); 38 | 39 | // error handlers 40 | 41 | // development error handler 42 | // will print stacktrace 43 | if (app.get('env') === 'development') { 44 | app.use(function(err, req, res, next) { 45 | res.status(err.status || 500); 46 | res.render('error', { 47 | message: err.message, 48 | error: err 49 | }); 50 | }); 51 | } 52 | 53 | // production error handler 54 | // no stacktraces leaked to user 55 | app.use(function(err, req, res, next) { 56 | res.status(err.status || 500); 57 | res.render('error', { 58 | message: err.message, 59 | error: {} 60 | }); 61 | }); 62 | 63 | 64 | module.exports = app; 65 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('ismydatabig:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /views/index.hjs: -------------------------------------------------------------------------------- 1 | 2 | {{< layout }}{{$ content }} 3 | 4 |
5 |
6 | 7 |
8 |

Is my data big?

9 | 12 | 21 | 22 | 25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 |

Is my data big?

33 | 34 |
35 |
36 | 39 |
40 |
41 | 50 |
51 |
52 | 53 |
54 | 57 |
58 |
59 | 60 |
61 | 62 |
63 | 64 | {{/ content }}{{/ layout }} 65 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | router.get('/', function(req, res, next) { 5 | res.render('index', { 'title': 'Is my data big?' }); 6 | }); 7 | 8 | results = { 9 | 'tiny': 'Your data is tiny.
' + 10 | '

We are sorry.

', 11 | 'small': 'Your data is small.
' + 12 | '

But it can still be useful!

', 13 | 'medium': 'Your data is not big.
' + 14 | '

You can probably analyze it on a single computer.

', 15 | 'biggish': 'Your data is biggish.
' + 16 | '

You can still rent a machine in the ' + 17 | 'cloud that can just load all of it at once.

', 18 | 'big': 'Congratulations, your data is big.
' + 19 | '

But there is still a good ' + 20 | 'chance that you can analyze it on a regular computer. Often you ' + 21 | 'can simply drop irrelevant variables. Or try sampling, ' + 22 | 'you can fit good predictive models with just ' + 23 | '1% of the data! Explore these options before buying a ' + 24 | 'huge computer cluster and hiring a team of 10 to manage it.

', 25 | 'huge': 'You are kidding, right?', 26 | 'unknown': 'Can you please just behave yourself and use the form to select the unit? Thanks much!', 27 | 'nodata': 'So you have no data? That\'s OK, you can still live a happy life.' 28 | }; 29 | 30 | router.get("/result", function(req, res, next) { 31 | var size = req.query.size || "0"; 32 | var unit = req.query.unit; 33 | var result = classify_size(size, unit); 34 | res.render('result', { 'title': 'Tadaaaaam', 35 | 'size': size, 36 | 'unit': unit, 37 | 'result': results[result] }); 38 | }); 39 | 40 | // We just calculate in TB 41 | function classify_size(size, unit) { 42 | if (unit == 'MB') { 43 | size = size / 1000 / 1000; 44 | } else if (unit == 'GB') { 45 | size = size / 1000; 46 | } else if (unit == 'PB') { 47 | size = size * 1000; 48 | } else if (unit == 'EB') { 49 | size = size * 1000 * 1000; 50 | } else if (unit == 'ZB') { 51 | size = size * 1000 * 1000 * 1000; 52 | } else if (unit == 'YB') { 53 | size = size * 1000 * 1000 * 1000 * 1000; 54 | } else if (unit == 'TB') { 55 | // do nothing, in TB 56 | } else { 57 | return 'unknown'; 58 | } 59 | 60 | // Unit is TB now 61 | if (size == 0) { 62 | return 'nodata'; 63 | } else if (size < .1) { 64 | return 'tiny'; 65 | } else if (size < .5) { 66 | return 'small'; 67 | } else if (size < 1) { 68 | return 'medium'; 69 | } else if (size < 2) { 70 | return 'biggish'; 71 | } else if (size < 1000 * 1000) { 72 | // 1000 PB (eBay has a 90PB data warehouse....) 73 | return 'big'; 74 | } else { 75 | return 'huge'; 76 | } 77 | } 78 | 79 | module.exports = router; 80 | -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | 2 | /* em pure-hidden values */ 3 | 4 | /* pure-hidden-xs */ 5 | @media screen and (max-width:35.438em) { 6 | .pure-visible-sm{display:none} 7 | .pure-visible-md{display:none} 8 | .pure-visible-lg{display:none} 9 | .pure-visible-xl{display:none} 10 | .pure-hidden-xs{display:none} 11 | body { font-size: 150%; } 12 | } 13 | /* pure-hidden-sm */ 14 | @media screen and (min-width:35.5em) and (max-width:47.938em) { 15 | .pure-visible-xs{display:none} 16 | .pure-visible-md{display:none} 17 | .pure-visible-lg{display:none} 18 | .pure-visible-xl{display:none} 19 | .pure-hidden-sm{display:none} 20 | body { font-size: 150%; } 21 | } 22 | /* pure-hidden-md */ 23 | @media screen and (min-width:48em) and (max-width:63.938em) { 24 | .pure-visible-xs{display:none} 25 | .pure-visible-sm{display:none} 26 | .pure-visible-lg{display:none} 27 | .pure-visible-xl{display:none} 28 | .pure-hidden-md{display:none} 29 | body { font-size: 200%; } 30 | } 31 | /* pure-hidden-lg */ 32 | @media screen and (min-width:64em) and (max-width:79.938em) { 33 | .pure-visible-xs{display:none} 34 | .pure-visible-sm{display:none} 35 | .pure-visible-md{display:none} 36 | .pure-visible-xl{display:none} 37 | .pure-hidden-lg{display:none} 38 | body { font-size: 300%; } 39 | } 40 | /* pure-hidden-xl */ 41 | @media screen and (min-width:80em) { 42 | .pure-visible-xs{display:none} 43 | .pure-visible-sm{display:none} 44 | .pure-visible-md{display:none} 45 | .pure-visible-lg{display:none} 46 | .pure-hidden-xl{display:none} 47 | body { font-size: 300%; } 48 | } 49 | 50 | /* 51 | When setting the primary font stack, apply it to the Pure grid units along 52 | with `html`, `button`, `input`, `select`, and `textarea`. Pure Grids use 53 | specific font stacks to ensure the greatest OS/browser compatibility. 54 | */ 55 | html, button, input, select, textarea, 56 | .pure-g [class *= "pure-u"] { 57 | /* Set your content font stack here: */ 58 | font-family: 'Exo 2', sans-serif; 59 | } 60 | 61 | .button-submit, 62 | .button-white { 63 | text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); 64 | } 65 | 66 | .button-submit { 67 | color: white; 68 | background: rgb(66, 184, 221); 69 | } 70 | 71 | .huge-form { 72 | margin-top: 100px; 73 | text-align: center; 74 | } 75 | 76 | .small-form { 77 | margin-top: 50px; 78 | margin-left: 10px; 79 | margin-right: 10px; 80 | text-align: center; 81 | } 82 | 83 | .small-form button { 84 | margin-top: 10px; 85 | } 86 | 87 | .right-input { 88 | text-align: right; 89 | } 90 | 91 | html { 92 | position: relative; 93 | min-height: 100%; 94 | } 95 | 96 | body { 97 | margin: 0 0 40px; /* bottom = footer height */ 98 | } 99 | 100 | footer { 101 | position: absolute; 102 | left: 0; 103 | bottom: 0; 104 | height: 30px; 105 | width: 100%; 106 | text-align: center; 107 | margin-bottom: 10px; 108 | font-size: 50%; 109 | } 110 | 111 | .result-size { 112 | margin-top: 80px; 113 | text-align: center; 114 | } 115 | 116 | .result { 117 | margin-top: 40px; 118 | text-align: center; 119 | } 120 | 121 | .result-result { 122 | color: red; 123 | font-weight: bold; 124 | } 125 | 126 | p.note { 127 | color: #555; 128 | font-size: 75%; 129 | } 130 | --------------------------------------------------------------------------------