From 0377f7c050452d0d999a56bc189baf77091bd49b Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 11 Mar 2010 21:04:12 -0500 Subject: [PATCH 001/267] Initial commit --- README | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..2bc7f22 --- /dev/null +++ b/README @@ -0,0 +1,9 @@ +HUMMINGBIRD + +Site tracking and analytics storage + + +Description + +Hummingbird serves a 1x1 tracking pixel to users. In the browser's GET request it +sends back tracking data generated by javascript. From e300d520edc9d9022252d47332f6e4fac6b74444 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 23 Mar 2010 20:33:46 -0400 Subject: [PATCH 002/267] Initial code --- .gitmodules | 6 ++++++ hummingbird.js | 19 +++++++++++++++++++ images/tracking.gif | Bin 0 -> 43 bytes server.js | 25 +++++++++++++++++++++++++ vendor/node-mongodb-native | 1 + 5 files changed, 51 insertions(+) create mode 100644 .gitmodules create mode 100644 hummingbird.js create mode 100644 images/tracking.gif create mode 100644 server.js create mode 160000 vendor/node-mongodb-native diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ea5d21d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "vendor/node-mongodb"] + path = vendor/node-mongodb + url = git://github.com/orlandov/node-mongodb.git +[submodule "vendor/node-mongodb-native"] + path = vendor/node-mongodb-native + url = git://github.com/christkv/node-mongodb-native.git diff --git a/hummingbird.js b/hummingbird.js new file mode 100644 index 0000000..f752de9 --- /dev/null +++ b/hummingbird.js @@ -0,0 +1,19 @@ +var Gilt; +if (!Gilt) { + Gilt = {}; +} + +Gilt.Hummingbird = {}; + +Gilt.Hummingbird.track = function(env) { + delete env.trackingServer; + delete env.trackingServerSecure; + env.u = document.location.href; + env.bw = window.innerWidth; + env.bh = window.innerHeight; + env.guid = document.cookie.match(/guid=([^\_]*)_([^;]*)/)[2]; + env.gen = document.cookie.match(/gender=([^;]*);/)[1]; + env.uid = document.cookie.match(/user_id=([^\_]*)_([^;]*)/)[2]; + + $('body').append(''); +}; diff --git a/images/tracking.gif b/images/tracking.gif new file mode 100644 index 0000000000000000000000000000000000000000..8624666d94348cf14ec3425b5018e8d8d5e4d358 GIT binary patch literal 43 ocmZ?wbhEHbWMp7uXkY+=|Ns9h{$v3&bwDIYhJlI6g^|G;0Kc9F_y7O^ literal 0 HcmV?d00001 diff --git a/server.js b/server.js new file mode 100644 index 0000000..ca27589 --- /dev/null +++ b/server.js @@ -0,0 +1,25 @@ +var sys = require('sys'), + http = require('http'), + fs = require('fs'), + querystring = require('querystring'), + mongo = require('./vendor/node-mongodb-native/lib/mongodb'); + +var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); + +var pixel = fs.readFileSync("images/tracking.gif", 'binary'); +db.open(function(db) { + db.collection('visits', function(err, collection) { + http.createServer(function (req, res) { + + var env = querystring.parse(req.url.split('?')[1]); + env.timestamp = (new Date()); + collection.insert(env); + sys.puts(JSON.stringify(env, null, 2)); + + res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); + res.write(pixel, 'binary'); + res.close(); + }).listen(8000); + }); +}); +sys.puts('Server running at http://127.0.0.1:8000/'); diff --git a/vendor/node-mongodb-native b/vendor/node-mongodb-native new file mode 160000 index 0000000..1e6826f --- /dev/null +++ b/vendor/node-mongodb-native @@ -0,0 +1 @@ +Subproject commit 1e6826ffd7fc7853944ce782a40c23271602a9a4 From 20d71909382ad7efce48afc9da9324e2953b4101 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 10 Apr 2010 16:10:27 -0400 Subject: [PATCH 003/267] Stream output via web sockets --- client/index.html | 90 +++++++++++++++++++++++++++++++ server.js | 55 ++++++++++++++++--- vendor/arrays.js | 8 +++ vendor/node-mongodb-native | 2 +- vendor/ws.js | 106 +++++++++++++++++++++++++++++++++++++ 5 files changed, 253 insertions(+), 8 deletions(-) create mode 100644 client/index.html create mode 100644 vendor/arrays.js create mode 100644 vendor/ws.js diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..786f3c7 --- /dev/null +++ b/client/index.html @@ -0,0 +1,90 @@ + + + + + + + + + + +
+

4000

+

3500

+

3000

+

2500

+

2000

+

1500

+

1000

+

500

+

0

+
+ + + diff --git a/server.js b/server.js index ca27589..a84dffe 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,27 @@ var sys = require('sys'), - http = require('http'), - fs = require('fs'), - querystring = require('querystring'), - mongo = require('./vendor/node-mongodb-native/lib/mongodb'); + http = require('http'), + fs = require('fs'), + ws = require('./vendor/ws'), + querystring = require('querystring'), + arrays = require('./vendor/arrays'), + mongo = require('./vendor/node-mongodb-native/lib/mongodb'); var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); +var clients = []; + +var urls = { total: 0 }; + +setInterval(function() { + // sys.puts("Writing to clients..."); + + clients.each(function(c) { + c.write(urls.total); + }); + + urls = { total: 0 }; +}, 50); + var pixel = fs.readFileSync("images/tracking.gif", 'binary'); db.open(function(db) { db.collection('visits', function(err, collection) { @@ -13,13 +29,38 @@ db.open(function(db) { var env = querystring.parse(req.url.split('?')[1]); env.timestamp = (new Date()); - collection.insert(env); - sys.puts(JSON.stringify(env, null, 2)); + // collection.insert(env); + // sys.puts(JSON.stringify(env, null, 2)); res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); res.write(pixel, 'binary'); res.close(); + + if(urls[env.u]) { + urls[env.u] += 1; + } else { + urls[env.u] = 1; + } + urls.total += 1 + }).listen(8000); }); }); -sys.puts('Server running at http://127.0.0.1:8000/'); + +sys.puts('Tracking server running on port 8000'); + +// Websocket TCP server +ws.createServer(function (websocket) { + clients.push(websocket); + + websocket.addListener("connect", function (resource) { + // emitted after handshake + sys.debug("connect: " + resource); + }).addListener("close", function () { + // emitted when server or client closes connection + clients.remove(websocket); + sys.debug("close"); + }); +}).listen(8080); + +sys.puts('Web Socket server running on port 8080'); \ No newline at end of file diff --git a/vendor/arrays.js b/vendor/arrays.js new file mode 100644 index 0000000..fd57e32 --- /dev/null +++ b/vendor/arrays.js @@ -0,0 +1,8 @@ +Array.prototype.remove = function(e) { + for (var i = 0; i < this.length; i++) + if (e == this[i]) return this.splice(i, 1); +} + +Array.prototype.each = function(fn) { + for (var i = 0; i < this.length; i++) fn(this[i]); +} diff --git a/vendor/node-mongodb-native b/vendor/node-mongodb-native index 1e6826f..e30aa02 160000 --- a/vendor/node-mongodb-native +++ b/vendor/node-mongodb-native @@ -1 +1 @@ -Subproject commit 1e6826ffd7fc7853944ce782a40c23271602a9a4 +Subproject commit e30aa02f58971dba2ba01e697fe7e4684f11afda diff --git a/vendor/ws.js b/vendor/ws.js new file mode 100644 index 0000000..bc8033d --- /dev/null +++ b/vendor/ws.js @@ -0,0 +1,106 @@ +// Based on: +// http://github.com/alexanderte/websocket-server-node.js +// http://github.com/Guille/node.websocket.js + +function nano(template, data) { + return template.replace(/\{([\w\.]*)}/g, function (str, key) { + var keys = key.split("."), value = data[keys.shift()]; + keys.forEach(function (key) { value = value[key] }); + return value; + }); +} + +var sys = require("sys"), + tcp = require("tcp"), + headerExpressions = [ + /^GET (\/[^\s]*) HTTP\/1\.1$/, + /^Upgrade: WebSocket$/, + /^Connection: Upgrade$/, + /^Host: (.+)$/, + /^Origin: (.+)$/ + ], + handshakeTemplate = [ + 'HTTP/1.1 101 Web Socket Protocol Handshake', + 'Upgrade: WebSocket', + 'Connection: Upgrade', + 'WebSocket-Origin: {origin}', + 'WebSocket-Location: ws://{host}{resource}', + '', + '' + ].join("\r\n"), + policy_file = ''; + +exports.createServer = function (websocketListener) { + return tcp.createServer(function (socket) { + socket.setTimeout(0); + socket.setNoDelay(true); + socket.setEncoding("utf8"); + + var emitter = new process.EventEmitter(), + handshaked = false; + + function handle(data) { + if(data[0] == "\u0000" && data[data.length - 1] == "\ufffd") { + emitter.emit("receive", data.substr(1, data.length - 2)); + } else { + socket.close(); + } + } + + function handshake(data) { + var headers = data.split("\r\n"); + + if(//.exec(headers[0])) { + socket.write(policy_file); + socket.close(); + return; + } + + var matches = [], match; + for (var i = 0, l = headerExpressions.length; i < l; i++) { + match = headerExpressions[i].exec(headers[i]); + + if (match) { + if(match.length > 1) { + matches.push(match[1]); + } + } else { + socket.close(); + } + } + + socket.write(nano(handshakeTemplate, { + resource: matches[0], + host: matches[1], + origin: matches[2], + })); + + handshaked = true; + emitter.emit("connect", matches[0]); + } + + socket.addListener("data", function (data) { + if(handshaked) { + handle(data); + } else { + handshake(data); + } + }).addListener("end", function () { + socket.close(); + }).addListener("close", function () { + if (handshaked) { // don't emit close from policy-requests + emitter.emit("close"); + } + }); + + emitter.write = function (data) { + socket.write('\u0000' + data + '\uffff'); + } + + emitter.close = function () { + socket.close(); + } + + websocketListener(emitter); // emits: "connect", "receive", "close", provides: send(data), close() + }); +} From 0eb0debfefdbcc19abd8f834a483b9aa0ed88fcc Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 10 Apr 2010 21:44:05 -0400 Subject: [PATCH 004/267] Add static file serving and clean up output --- .gitmodules | 3 ++ client/index.html | 90 -------------------------------------------- public/analytics.js | 77 +++++++++++++++++++++++++++++++++++++ public/helpers.js | 4 ++ public/index.html | 56 +++++++++++++++++++++++++++ server.js | 30 ++++++++++++--- vendor/node-paperboy | 1 + 7 files changed, 165 insertions(+), 96 deletions(-) delete mode 100644 client/index.html create mode 100644 public/analytics.js create mode 100644 public/helpers.js create mode 100644 public/index.html create mode 160000 vendor/node-paperboy diff --git a/.gitmodules b/.gitmodules index ea5d21d..159f10f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "vendor/node-mongodb-native"] path = vendor/node-mongodb-native url = git://github.com/christkv/node-mongodb-native.git +[submodule "vendor/node-paperboy"] + path = vendor/node-paperboy + url = git://github.com/felixge/node-paperboy diff --git a/client/index.html b/client/index.html deleted file mode 100644 index 786f3c7..0000000 --- a/client/index.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - -
-

4000

-

3500

-

3000

-

2500

-

2000

-

1500

-

1000

-

500

-

0

-
- - - diff --git a/public/analytics.js b/public/analytics.js new file mode 100644 index 0000000..cd4d43b --- /dev/null +++ b/public/analytics.js @@ -0,0 +1,77 @@ +if(!Hummingbird) { var Hummingbird = {}; } + +Hummingbird.Graph = function(canvas, url) { + if ( !(this instanceof Hummingbird.Graph) ) { + return new Hummingbird.Graph(canvas, url); + } + + this.url = url; + this.canvas = canvas; + this.trafficLog = []; + + this.init(); +}; + +Hummingbird.Graph.prototype = { + init: function() { + this.setupContext(); + + this.ws = new WebSocket(this.url); + this.ws.onmessage = $.proxy(function(evt) { + this.drawLogPath(evt.data * 20 / 4000.0); + }, this); + this.ws.onclose = function() { + alert("socket closed"); + }; + this.ws.onopen = function() { + //alert("connected..."); + }; + }, + + addValue: function(value) { + this.trafficLog.push(value); + if(this.trafficLog.length > 20) { + this.trafficLog.shift(); + } + }, + + shiftCanvas: function(x, y) { + var canvasData = this.context.getImageData(x, y, this.canvas.width, this.canvas.height); + this.context.putImageData(canvasData, 0, 0); + }, + + setupContext: function() { + if(this.canvas.getContext) { + this.context = this.canvas.getContext('2d'); + } else { + alert("Sorry, this browser doesn't support canvas"); + } + + this.context.lineWidth = 3; + }, + + runningAverage: function() { + return this.trafficLog.sum() / this.trafficLog.length; + }, + + drawLogPath: function(percent) { + this.addValue(percent); + var height = Math.max(this.runningAverage() * 400, 1); + var endingPoint = 400 - height; + + this.shiftCanvas(6, 0); + this.context.beginPath(); + this.context.strokeStyle = '#FF1438'; + this.context.moveTo(750, 400); + this.context.lineTo(750, endingPoint); + this.context.stroke(); + this.context.closePath(); + + this.context.beginPath(); + this.context.strokeStyle = '#C7F8FF'; + this.context.moveTo(750, endingPoint); + this.context.lineTo(750, 0); + this.context.stroke(); + this.context.closePath(); + } +}; diff --git a/public/helpers.js b/public/helpers.js new file mode 100644 index 0000000..9eb9612 --- /dev/null +++ b/public/helpers.js @@ -0,0 +1,4 @@ +Array.prototype.sum = function() { + return (! this.length) ? 0 : this.slice(1).sum() + + ((typeof this[0] == 'number') ? this[0] : 0); +}; diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..bb300f2 --- /dev/null +++ b/public/index.html @@ -0,0 +1,56 @@ + + + + + + + + + + + + +
+

4000

+

3500

+

3000

+

2500

+

2000

+

1500

+

1000

+

500

+

0

+
+ +
+

4000

+

3500

+

3000

+

2500

+

2000

+

1500

+

1000

+

500

+

0

+
+ + + diff --git a/server.js b/server.js index a84dffe..4616753 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,18 @@ var sys = require('sys'), http = require('http'), fs = require('fs'), + path = require('path'), ws = require('./vendor/ws'), querystring = require('querystring'), arrays = require('./vendor/arrays'), + paperboy = require('./vendor/node-paperboy'), mongo = require('./vendor/node-mongodb-native/lib/mongodb'); +var WEBROOT = path.join(path.dirname(__filename), 'public'), + TRACKING_PORT = 8000, + WEB_SOCKET_PORT = 8080, + MONITOR_PORT = 8088; + var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); var clients = []; @@ -16,7 +23,11 @@ setInterval(function() { // sys.puts("Writing to clients..."); clients.each(function(c) { - c.write(urls.total); + try { + c.write(urls.total); + } catch(e) { + sys.log(e.description); + } }); urls = { total: 0 }; @@ -43,11 +54,11 @@ db.open(function(db) { } urls.total += 1 - }).listen(8000); + }).listen(TRACKING_PORT); }); }); -sys.puts('Tracking server running on port 8000'); +sys.puts('Tracking server running at http://localhost:' + TRACKING_PORT + '/tracking_pixel.gif'); // Websocket TCP server ws.createServer(function (websocket) { @@ -55,12 +66,19 @@ ws.createServer(function (websocket) { websocket.addListener("connect", function (resource) { // emitted after handshake - sys.debug("connect: " + resource); + sys.log("ws connect: " + resource); }).addListener("close", function () { // emitted when server or client closes connection clients.remove(websocket); - sys.debug("close"); + sys.log("ws close"); }); }).listen(8080); -sys.puts('Web Socket server running on port 8080'); \ No newline at end of file +sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); + +http.createServer(function(req, res) { + paperboy.deliver(WEBROOT, req, res) + .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); +}).listen(MONITOR_PORT); + +sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); diff --git a/vendor/node-paperboy b/vendor/node-paperboy new file mode 160000 index 0000000..c42a84c --- /dev/null +++ b/vendor/node-paperboy @@ -0,0 +1 @@ +Subproject commit c42a84cdd36ad3da33cad9904652484368daa7dc From be1da001e66d0af06f45b2285d5b3be12517b4bc Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 10 Apr 2010 22:55:27 -0400 Subject: [PATCH 005/267] Fork node-paperboy to remove process.mixin deprecation warning --- vendor/node-paperboy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/node-paperboy b/vendor/node-paperboy index c42a84c..f4e7ced 160000 --- a/vendor/node-paperboy +++ b/vendor/node-paperboy @@ -1 +1 @@ -Subproject commit c42a84cdd36ad3da33cad9904652484368daa7dc +Subproject commit f4e7cedb816130dbc85dbd79b72d0585346bdbbc From c8bb024c1a19da82f7e586fa9c8f8d2d7acfd3d5 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 10 Apr 2010 22:58:20 -0400 Subject: [PATCH 006/267] Generalize hummingbird tracker --- hummingbird.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/hummingbird.js b/hummingbird.js index f752de9..5a55c49 100644 --- a/hummingbird.js +++ b/hummingbird.js @@ -1,11 +1,6 @@ -var Gilt; -if (!Gilt) { - Gilt = {}; -} +HummingbirdTracker = {}; -Gilt.Hummingbird = {}; - -Gilt.Hummingbird.track = function(env) { +HummingbirdTracker.track = function(env) { delete env.trackingServer; delete env.trackingServerSecure; env.u = document.location.href; From 88941f3c5619dd186d97f65c66a45262f9609160 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 11 Apr 2010 02:26:49 -0400 Subject: [PATCH 007/267] Move css/js into assets --- public/css/main.css | 29 +++++++ public/index.html | 67 ++++++++------- public/{ => js}/analytics.js | 7 +- public/{ => js}/helpers.js | 0 public/js/jquery-1.4.2.min.js | 154 ++++++++++++++++++++++++++++++++++ 5 files changed, 223 insertions(+), 34 deletions(-) create mode 100644 public/css/main.css rename public/{ => js}/analytics.js (92%) rename public/{ => js}/helpers.js (100%) create mode 100644 public/js/jquery-1.4.2.min.js diff --git a/public/css/main.css b/public/css/main.css new file mode 100644 index 0000000..f1d771b --- /dev/null +++ b/public/css/main.css @@ -0,0 +1,29 @@ +body { + + background-color: #2F2C2B; + font-family: "Lucida Grande", Helvetica, sans-serif; +} + +div.hummingbird_graph canvas { + float: left; + padding: 28px 0 20px 0; + color: #F00; +} + +div.hummingbird_graph div.axis_left, +div.hummingbird_graph div.axis_right { + float: left; + line-height: 2.9em; + color: #4F4C4B; + font-weight: bold; + font-size: 0.8em; +} + +div.hummingbird_graph div.axis_left { + padding: 0 15px; + text-align: right; +} + +div.hummingbird_graph div.axis_right { + padding: 0 10px; +} diff --git a/public/index.html b/public/index.html index bb300f2..53d86bf 100644 --- a/public/index.html +++ b/public/index.html @@ -1,10 +1,13 @@ + - - - + + + + + - + -
-

4000

-

3500

-

3000

-

2500

-

2000

-

1500

-

1000

-

500

-

0

-
- -
-

4000

-

3500

-

3000

-

2500

-

2000

-

1500

-

1000

-

500

-

0

+
+ +
+

4000

+

3500

+

3000

+

2500

+

2000

+

1500

+

1000

+

500

+

0

+
+ + + +
+

4000

+

3500

+

3000

+

2500

+

2000

+

1500

+

1000

+

500

+

0

+
+
diff --git a/public/analytics.js b/public/js/analytics.js similarity index 92% rename from public/analytics.js rename to public/js/analytics.js index cd4d43b..931ba7d 100644 --- a/public/analytics.js +++ b/public/js/analytics.js @@ -16,6 +16,9 @@ Hummingbird.Graph.prototype = { init: function() { this.setupContext(); + this.lineColor = "#FFF"; + this.bgLineColor = "#555"; + this.ws = new WebSocket(this.url); this.ws.onmessage = $.proxy(function(evt) { this.drawLogPath(evt.data * 20 / 4000.0); @@ -61,14 +64,14 @@ Hummingbird.Graph.prototype = { this.shiftCanvas(6, 0); this.context.beginPath(); - this.context.strokeStyle = '#FF1438'; + this.context.strokeStyle = this.lineColor; this.context.moveTo(750, 400); this.context.lineTo(750, endingPoint); this.context.stroke(); this.context.closePath(); this.context.beginPath(); - this.context.strokeStyle = '#C7F8FF'; + this.context.strokeStyle = this.bgLineColor; this.context.moveTo(750, endingPoint); this.context.lineTo(750, 0); this.context.stroke(); diff --git a/public/helpers.js b/public/js/helpers.js similarity index 100% rename from public/helpers.js rename to public/js/helpers.js diff --git a/public/js/jquery-1.4.2.min.js b/public/js/jquery-1.4.2.min.js new file mode 100644 index 0000000..7c24308 --- /dev/null +++ b/public/js/jquery-1.4.2.min.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); From 848cc688410227e7cd9ca17269acaee85d72e8fb Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 11 Apr 2010 16:17:35 -0400 Subject: [PATCH 008/267] Turn mongo back on; write out json hash instead of just value --- public/js/analytics.js | 3 ++- server.js | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/public/js/analytics.js b/public/js/analytics.js index 931ba7d..6ee0c55 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -21,7 +21,8 @@ Hummingbird.Graph.prototype = { this.ws = new WebSocket(this.url); this.ws.onmessage = $.proxy(function(evt) { - this.drawLogPath(evt.data * 20 / 4000.0); + var data = JSON.parse(evt.data); + this.drawLogPath(data.total * 20 / 4000.0); }, this); this.ws.onclose = function() { alert("socket closed"); diff --git a/server.js b/server.js index 4616753..0397bb9 100644 --- a/server.js +++ b/server.js @@ -24,7 +24,7 @@ setInterval(function() { clients.each(function(c) { try { - c.write(urls.total); + c.write(JSON.stringify({total: urls.total})); } catch(e) { sys.log(e.description); } @@ -40,8 +40,8 @@ db.open(function(db) { var env = querystring.parse(req.url.split('?')[1]); env.timestamp = (new Date()); - // collection.insert(env); - // sys.puts(JSON.stringify(env, null, 2)); + collection.insert(env); + // sys.puts(JSON.stringify(env, null, 2)); res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); res.write(pixel, 'binary'); @@ -78,7 +78,7 @@ sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); http.createServer(function(req, res) { paperboy.deliver(WEBROOT, req, res) - .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); + .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); }).listen(MONITOR_PORT); sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); From 30a06ef164ee6d31c31c7082ccbae698358db001 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 11 Apr 2010 16:20:40 -0400 Subject: [PATCH 009/267] move hummingbird client js --- hummingbird.js => client/hummingbird.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hummingbird.js => client/hummingbird.js (100%) diff --git a/hummingbird.js b/client/hummingbird.js similarity index 100% rename from hummingbird.js rename to client/hummingbird.js From ce695e8127f26af4b79af69cb4353c4fad34a09a Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 12 Apr 2010 00:59:55 -0400 Subject: [PATCH 010/267] Style analytics page; add sales from pagegen --- lib/proxy.js | 11 ++ lib/service_json.js | 24 +++ lib/view.js | 13 ++ public/css/main.css | 40 ++++- public/fonts/SIL Open Font License 1.1.txt | 91 ++++++++++ public/fonts/TitilliumText800wt-cufon.js | 10 ++ public/fonts/TitilliumText800wt.eot | Bin 0 -> 18686 bytes public/fonts/TitilliumText800wt.svg | 199 +++++++++++++++++++++ public/fonts/TitilliumText800wt.ttf | Bin 0 -> 18464 bytes public/fonts/TitilliumText800wt.woff | Bin 0 -> 11920 bytes public/index.html | 31 +++- public/js/analytics.js | 25 ++- server.js | 27 ++- 13 files changed, 451 insertions(+), 20 deletions(-) create mode 100644 lib/proxy.js create mode 100644 lib/service_json.js create mode 100644 lib/view.js create mode 100755 public/fonts/SIL Open Font License 1.1.txt create mode 100755 public/fonts/TitilliumText800wt-cufon.js create mode 100755 public/fonts/TitilliumText800wt.eot create mode 100755 public/fonts/TitilliumText800wt.svg create mode 100755 public/fonts/TitilliumText800wt.ttf create mode 100755 public/fonts/TitilliumText800wt.woff diff --git a/lib/proxy.js b/lib/proxy.js new file mode 100644 index 0000000..81966b2 --- /dev/null +++ b/lib/proxy.js @@ -0,0 +1,11 @@ +var services = require('./service_json'); +var sys = require('sys'); + +exports.route = function(path, remoteURL, req, res) { + sys.log("Routing " + path + " to " + remoteURL); + services.fetchJSON(remoteURL, function(data) { + res.writeHead(200, {'Content-type': "text/plain"}); + res.write(data); + res.close(); + }); +}; \ No newline at end of file diff --git a/lib/service_json.js b/lib/service_json.js new file mode 100644 index 0000000..e25768c --- /dev/null +++ b/lib/service_json.js @@ -0,0 +1,24 @@ +var url = require('url'); +var http = require('http'); +var sys = require('sys'); + +exports.fetchJSON = function(remoteURL, callback) { + remoteURL = url.parse(remoteURL); + + var pagegen = http.createClient(remoteURL.port, remoteURL.hostname); + // TODO: remoteURL.search + var request = pagegen.request('GET', remoteURL.pathname, {"host": remoteURL.hostname}); + request.addListener('response', function(response) { + + response.client.responseBodyParts = ''; + + response.addListener('data', function(chunk) { + response.client.responseBodyParts += chunk; + }); + + response.addListener('end', function() { + callback(response.client.responseBodyParts); + }); + }); + request.close(); +}; \ No newline at end of file diff --git a/lib/view.js b/lib/view.js new file mode 100644 index 0000000..3908724 --- /dev/null +++ b/lib/view.js @@ -0,0 +1,13 @@ +var View = function(env) { + if(!this instanceof View) { + return new View(env); + } + + this.env = env; + this.urlKey = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/)[1]; +} + +View.prototype = { +}; + +exports.View = View; \ No newline at end of file diff --git a/public/css/main.css b/public/css/main.css index f1d771b..370c552 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -1,19 +1,27 @@ +@charset "utf-8"; + body { background-color: #2F2C2B; font-family: "Lucida Grande", Helvetica, sans-serif; } +h1 { + color: #FFF; + text-transform: uppercase; + font-family: 'TitilliumText14L800wt', sans-serif; +} + div.hummingbird_graph canvas { float: left; - padding: 28px 0 20px 0; + padding: 14px 0 20px 0; color: #F00; } div.hummingbird_graph div.axis_left, div.hummingbird_graph div.axis_right { float: left; - line-height: 2.9em; + line-height: 1em; color: #4F4C4B; font-weight: bold; font-size: 0.8em; @@ -27,3 +35,31 @@ div.hummingbird_graph div.axis_left { div.hummingbird_graph div.axis_right { padding: 0 10px; } + +#sales { +} + +#sales div.sale { + float: left; + width: 180px; + height: 140px; + overflow: hidden; + padding: 10px; +} + +#sales div.sale h2 { + color: #CCC; + font-size: 0.7em; +} + +#sales div.sale img.editorial { + width: 180px; +} + +/* Fonts */ + +@font-face { + font-family: 'TitilliumText14L800wt'; + src: url('/fonts/TitilliumText800wt.eot'); + src: local('TitilliumText14L'), local('TitilliumText14L-800wt'), url('/fonts/TitilliumText800wt.woff') format('woff'), url('/fonts/TitilliumText800wt.ttf') format('truetype'), url('/fonts/TitilliumText800wt.svg#TitilliumText14L-800wt') format('svg'); +} diff --git a/public/fonts/SIL Open Font License 1.1.txt b/public/fonts/SIL Open Font License 1.1.txt new file mode 100755 index 0000000..e4b0c4f --- /dev/null +++ b/public/fonts/SIL Open Font License 1.1.txt @@ -0,0 +1,91 @@ +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/public/fonts/TitilliumText800wt-cufon.js b/public/fonts/TitilliumText800wt-cufon.js new file mode 100755 index 0000000..0d41108 --- /dev/null +++ b/public/fonts/TitilliumText800wt-cufon.js @@ -0,0 +1,10 @@ +/*! + * The following copyright notice may not be removed under any circumstances. + * + * Copyright: + * Generated in 2009 by FontLab Studio. Copyright info pending. + * + * Full name: + * TitilliumText14L-800wt + */ +Cufon.registerFont({"w":530,"face":{"font-family":"TitilliumText14L","font-weight":800,"font-stretch":"normal","units-per-em":"1000","panose-1":"0 0 0 0 0 0 0 0 0 0","ascent":"750","descent":"-250","x-height":"11","bbox":"-60 -966 941 242","underline-thickness":"50","underline-position":"-50","unicode-range":"U+0020-U+2122"},"glyphs":{" ":{"w":235},"C":{"d":"494,-120r3,106v0,0,-117,25,-196,25v-209,0,-257,-120,-257,-356v0,-252,61,-358,257,-358v87,0,197,27,197,27r-4,103v0,0,-117,-15,-177,-15v-121,0,-152,58,-152,243v0,176,24,241,156,241v54,0,173,-16,173,-16","w":535},"c":{"d":"250,-511v54,0,152,19,152,19r-4,99v0,0,-79,-9,-117,-9v-102,0,-125,38,-125,146v0,120,21,159,126,159v38,0,117,-9,117,-9r3,99v0,0,-102,18,-155,18v-152,0,-207,-77,-207,-267v0,-179,61,-255,210,-255","w":436},"d":{"d":"475,-700r0,700r-115,0r0,-24v0,0,-71,35,-130,35v-133,0,-190,-75,-190,-264v0,-179,66,-258,208,-258v39,0,107,12,112,13r0,-202r115,0xm248,-95v49,0,112,-22,112,-22r0,-281v-5,0,-62,-9,-104,-9v-69,0,-100,45,-100,155v0,121,31,157,92,157","w":548},"e":{"d":"267,-93v79,0,184,-9,184,-9r2,89v0,0,-114,24,-203,24v-151,0,-210,-79,-210,-255v0,-182,78,-267,217,-267v142,0,213,73,213,228r-8,82r-307,0v1,73,31,108,112,108xm155,-290r202,0v0,-87,-29,-119,-100,-119v-71,0,-102,36,-102,119","w":507},"f":{"d":"192,-396r0,396r-114,0r0,-396r-57,0r0,-103r57,0r0,-31v0,-144,36,-186,142,-186v33,0,109,11,109,11r-1,94v0,0,-48,-2,-79,-2v-44,0,-57,20,-57,84r0,30r129,0r0,103r-129,0","w":340},"g":{"d":"271,240v-150,0,-232,-30,-232,-151v0,-50,23,-83,74,-122v-21,-14,-33,-42,-33,-73v0,-23,37,-79,37,-79v-37,-23,-72,-61,-72,-150v0,-127,87,-175,202,-175v46,0,102,13,102,13r152,-3r0,93r-72,0v11,15,21,35,21,72v0,137,-70,174,-205,174v-10,0,-34,-2,-44,-4v0,0,-12,32,-12,45v0,30,11,37,105,37v161,0,210,35,210,150v0,124,-100,173,-233,173xm285,16v-31,0,-97,-6,-97,-6v-25,22,-36,38,-36,67v0,43,33,60,120,60v77,0,116,-18,116,-64v0,-51,-24,-56,-103,-57xm245,-257v64,0,92,-20,92,-78v0,-59,-26,-77,-91,-77v-60,0,-86,21,-86,77v0,53,21,78,85,78","w":531},"h":{"d":"188,0r-114,0r0,-710r114,0r0,228v0,0,79,-29,134,-29v139,0,174,82,174,249r0,262r-115,0r0,-261v0,-94,-11,-143,-81,-143v-45,0,-112,17,-112,17r0,387","w":562},"i":{"d":"72,0r0,-499r114,0r0,499r-114,0xm72,-580r0,-121r114,0r0,121r-114,0","w":257},"j":{"d":"78,-6r0,-493r114,0r0,494v0,134,-37,178,-174,247r-51,-95v90,-53,111,-71,111,-153xm78,-587r0,-121r114,0r0,121r-114,0","w":263},"k":{"d":"188,0r-114,0r0,-706r114,0r0,400r60,-8r115,-185r128,0r-141,234r147,265r-129,0r-118,-202r-62,8r0,194","w":511},"l":{"d":"73,0r0,-706r114,0r0,706r-114,0","w":259},"m":{"d":"188,0r-114,0r0,-499r113,0r0,27v0,0,42,-21,87,-31v65,-15,132,0,164,35v44,-17,115,-43,174,-43v136,0,174,75,174,250r0,261r-114,0r0,-216v0,-135,-2,-188,-82,-188v-49,0,-108,24,-109,25v12,88,5,269,7,379r-114,0r0,-257v0,-106,-10,-147,-82,-147v-44,0,-104,23,-104,23r0,381","w":853},"A":{"d":"23,0r165,-692r231,0r163,692r-118,0r-38,-136r-251,0r-34,136r-118,0xm279,-584r-79,335r203,0r-77,-335r-47,0","w":605},"p":{"d":"74,214r0,-713r114,0r0,27v0,0,68,-39,125,-39v130,0,192,69,192,256v0,208,-71,266,-224,266v-41,0,-88,-8,-93,-9r0,212r-114,0xm292,-406v-44,0,-104,26,-104,26r0,281v4,1,52,7,85,7v90,0,116,-44,116,-163v0,-113,-37,-151,-97,-151","w":545},"q":{"d":"258,11v-158,0,-218,-94,-218,-254v0,-165,57,-268,228,-268v56,0,195,12,195,12r0,714r-115,0r0,-221v0,0,-35,17,-90,17xm268,-407v-82,0,-113,54,-113,164v0,97,30,151,103,151v45,0,90,-21,90,-21r0,-292v0,0,-53,-2,-80,-2","w":536},"r":{"d":"74,0r0,-499r114,0r0,53v0,0,66,-49,151,-65r0,122v-90,18,-151,52,-151,52r0,337r-114,0","w":359},"s":{"d":"429,-488r-2,97v0,0,-120,-16,-180,-16v-59,0,-83,13,-83,51v0,31,21,39,104,52v132,21,176,56,176,155v0,117,-76,160,-199,160v-71,0,-190,-23,-190,-23r4,-97v0,0,124,17,175,17v70,0,96,-14,96,-54v0,-32,-16,-41,-96,-54v-128,-21,-184,-49,-184,-153v0,-114,89,-158,189,-158v73,0,190,23,190,23","w":494},"u":{"d":"372,-499r114,0r0,499r-114,0r0,-25v0,0,-78,36,-132,36v-144,0,-173,-74,-173,-249r0,-261r114,0r0,260v0,106,6,147,82,147v44,0,109,-23,109,-23r0,-384","w":560},"w":{"d":"17,-499r113,0r74,396r22,0r90,-387r120,0r90,387r22,0r74,-396r113,0r-102,499r-185,0r-73,-334r-73,334r-183,0","w":752},"y":{"d":"13,-499r113,0r103,388r26,0r103,-388r113,0r-133,505r-53,207r-113,0r55,-213r-84,0","w":484},"z":{"d":"53,-397r0,-103r371,0r0,103r-233,294r233,0r0,103r-371,0r0,-103r234,-294r-234,0","w":478},"Z":{"d":"60,-579r0,-113r450,0r0,120r-301,443r0,16r301,0r0,113r-450,0r0,-120r301,-442r0,-17r-301,0","w":570},"0":{"d":"264,-672v161,0,251,91,251,348v0,251,-91,335,-251,335v-159,0,-251,-84,-251,-335v0,-257,91,-348,251,-348xm265,-559v-90,0,-126,54,-126,235v0,177,38,223,126,223v88,0,124,-46,124,-223v0,-181,-34,-235,-124,-235"},"1":{"d":"40,-518r214,-142r110,0r0,660r-118,0r0,-523r-151,99"},"2":{"d":"479,0r-428,0r0,-108r157,-156v85,-85,137,-138,137,-207v0,-61,-37,-84,-120,-84v-70,0,-162,17,-162,17r-8,-108v0,0,105,-26,198,-26v147,0,213,62,213,185v0,103,-42,162,-137,256r-121,118r271,0r0,113"},"3":{"d":"55,-646v0,0,112,-26,196,-26v168,0,225,58,225,179v0,82,-46,118,-85,144v59,28,98,58,98,153v0,137,-65,207,-222,207v-100,0,-220,-23,-220,-23r12,-106v0,0,110,15,192,15v78,0,117,-29,117,-90v0,-63,-46,-86,-109,-86r-134,0r0,-107r133,0v47,0,96,-44,96,-90v0,-60,-41,-82,-111,-82v-82,0,-177,15,-177,15"},"5":{"d":"74,-661r397,0r0,113r-291,0r-16,153v0,0,68,-24,112,-24v140,0,217,59,217,203v0,146,-82,227,-224,227v-103,0,-229,-31,-229,-31r13,-105v0,0,126,24,211,24v64,0,108,-41,108,-109v0,-70,-43,-99,-108,-99v-66,0,-120,23,-120,23r-91,-19"},"7":{"d":"49,-548r0,-113r418,0r0,139r-244,538r-109,-31r232,-509r0,-24r-297,0"},"8":{"d":"268,-672v144,0,242,62,242,178v0,81,-21,110,-85,152v59,40,95,76,95,163v0,141,-112,190,-252,190v-139,0,-249,-41,-249,-179v0,-95,36,-132,94,-174v-61,-42,-83,-79,-83,-153v0,-114,92,-177,238,-177xm268,-101v80,0,126,-30,126,-95v0,-47,-31,-72,-79,-88r-93,0v-51,17,-77,44,-77,90v0,63,44,93,123,93xm270,-559v-74,0,-114,22,-114,82v0,42,23,67,66,89r93,0v44,-22,69,-47,69,-89v0,-59,-39,-82,-114,-82"},"E":{"d":"77,0r0,-692r432,0r0,112r-316,0r0,181r256,0r0,110r-256,0r0,177r316,0r0,112r-432,0","w":557},"F":{"d":"77,0r0,-692r432,0r0,112r-316,0r0,223r256,0r0,111r-256,0r0,246r-116,0","w":543},"G":{"d":"353,-257r0,-105r195,0r0,350v0,0,-142,23,-229,23v-214,0,-275,-128,-275,-358v0,-242,67,-356,271,-356v105,0,233,28,233,28r-3,102v0,0,-122,-16,-213,-16v-132,0,-167,59,-167,242v0,178,28,244,164,244v47,0,102,-7,103,-7r0,-147r-79,0","w":599},"H":{"d":"480,0r0,-295r-286,0r0,295r-117,0r0,-692r117,0r0,284r286,0r0,-284r118,0r0,692r-118,0","w":674},"K":{"d":"431,0r-137,-283r-100,8r0,275r-117,0r0,-692r117,0r0,304r98,-8r134,-296r135,0r-164,345r171,347r-137,0","w":594},"Q":{"d":"470,152r-90,-145v-17,3,-36,4,-57,4v-214,0,-279,-120,-279,-352v0,-232,65,-362,279,-362v214,0,279,130,279,362v0,153,-27,256,-106,309r82,134xm323,-102v128,0,158,-76,158,-239v0,-161,-31,-249,-158,-249v-127,0,-158,88,-158,249v0,161,30,239,158,239","w":646},"R":{"d":"348,-236r-154,0r0,236r-117,0r0,-692r261,0v158,0,234,65,234,223v0,104,-38,164,-109,199r109,270r-129,0xm451,-467v0,-76,-37,-113,-113,-113r-144,0r0,232r146,0v81,0,111,-48,111,-119","w":617},"S":{"d":"466,-679r-9,106v0,0,-124,-16,-182,-16v-66,0,-106,24,-106,76v0,60,27,73,136,113v124,46,176,81,176,201v0,144,-80,210,-220,210v-76,0,-211,-26,-211,-26r12,-106v0,0,127,17,198,17v66,0,103,-25,103,-92v0,-54,-24,-68,-116,-101v-150,-54,-196,-90,-196,-214v0,-131,91,-193,224,-193v77,0,191,25,191,25","w":531},"T":{"d":"-8,-579r0,-113r500,0r0,113r-190,0r0,579r-118,0r0,-579r-192,0","w":484},"V":{"d":"460,-692r123,0r-167,692r-227,0r-166,-692r123,0r133,580r48,0","w":606},"N":{"d":"77,0r0,-692r190,0r220,546r17,0r0,-546r118,0r0,692r-185,0r-226,-546r-17,0r0,546r-117,0","w":698},"\u2013":{"w":833},"\u00af":{"w":833},"$":{"d":"196,113r14,-109v-70,-4,-144,-13,-144,-13r4,-35v0,0,76,10,144,15r39,-298v-120,-22,-192,-49,-192,-178v-1,-136,95,-169,237,-166r16,-119r35,0r-16,121v69,5,141,14,141,14r-3,34v0,0,-79,-9,-142,-14r-36,277v132,24,200,45,200,178v0,145,-95,196,-248,186r-14,114v0,0,-35,-3,-35,-7xm454,-179v0,-109,-52,-123,-166,-142r-38,294v127,6,204,-37,204,-152xm100,-507v0,103,50,123,158,143r36,-273v-118,-2,-194,25,-194,130"},"!":{"d":"210,0r0,-149r123,0r0,149r-123,0xm213,-251r-4,-449r125,0r-4,449r-117,0"},"a":{"d":"448,-342r0,206v1,35,12,45,41,50r-4,97v-78,0,-104,-12,-134,-35v0,0,-86,35,-163,35v-95,0,-145,-61,-145,-160v0,-107,59,-144,167,-152r124,-10v5,-54,-12,-90,-62,-90v-74,0,-193,12,-193,12r-4,-100v0,0,129,-22,203,-22v110,0,170,46,170,169xm334,-222r-110,6v-43,4,-66,23,-66,64v0,42,18,65,51,65v53,0,125,-20,125,-20r0,-115","w":526},"o":{"d":"265,-511v166,0,224,100,224,259v0,161,-52,263,-224,263v-172,0,-225,-100,-225,-263v0,-160,56,-259,225,-259xm265,-92v89,0,108,-54,108,-160v0,-105,-27,-155,-108,-155v-85,0,-109,48,-109,155v0,108,20,160,109,160","w":529},"J":{"d":"236,-692v0,212,1,365,1,579v0,153,-62,184,-206,184r0,-110v61,0,88,-13,88,-82r0,-571r117,0","w":312},"t":{"d":"331,-396r-135,0r0,204v0,69,2,95,52,95v28,0,81,-3,81,-3r5,98v0,0,-67,14,-102,14v-115,0,-150,-44,-150,-188r0,-220r-63,0r0,-103r63,0r0,-145r114,0r0,145r135,0r0,103","w":354},"n":{"d":"188,0r-114,0r0,-499r114,0r0,25v0,0,79,-37,134,-37v139,0,174,82,174,250r0,261r-114,0r0,-260v0,-95,-12,-144,-82,-144v-44,0,-112,23,-112,23r0,381","w":563},"#":{"d":"526,-170r-101,0r0,170r-100,0r0,-170r-121,0r0,170r-100,0r0,-170r-101,0r0,-96r101,0r0,-130r-101,0r0,-96r101,0r0,-170r100,0r0,170r121,0r0,-170r100,0r0,170r101,0r0,96r-101,0r0,130r101,0r0,96xm325,-266r0,-130r-121,0r0,130r121,0"},"W":{"d":"28,-692r123,0r112,572r20,0r114,-570r133,0r116,570r19,0r111,-572r123,0r-152,692r-183,0r-101,-518r-99,518r-183,0","w":927},"@":{"d":"504,-727v303,0,437,151,437,439v0,233,-68,298,-187,298v-59,0,-99,-12,-125,-47v-38,19,-104,46,-159,46v-110,0,-184,-56,-184,-251v0,-164,39,-267,195,-267v34,0,101,23,101,23r0,-14r114,0r0,200v0,184,13,200,58,200v47,0,72,-25,72,-188v0,-234,-89,-328,-322,-328v-229,0,-345,116,-345,355v0,260,96,357,345,357v40,0,143,-9,143,-9r5,110v0,0,-100,10,-148,10v-296,0,-460,-107,-460,-468v0,-322,180,-466,460,-466xm478,-103v38,0,82,-13,112,-24v-12,-67,-7,-177,-8,-261v0,0,-50,-13,-77,-13v-86,0,-103,39,-103,159v0,111,31,139,76,139","w":985},"`":{"d":"142,-766r243,93r-40,103r-245,-89","w":545},"\u00b4":{"d":"92,-673r244,-93r41,107r-244,89","w":833},"\u00a8":{"d":"53,-593r0,-131r118,0r0,131r-118,0xm258,-593r0,-131r118,0r0,131r-118,0","w":833},"\u02c6":{"d":"235,-576r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":833},"\u02dc":{"d":"362,-702r22,17v-27,29,-55,55,-83,55v-60,0,-82,-54,-129,-54v-21,0,-51,24,-69,41r-25,-18v30,-29,62,-54,95,-54v62,0,86,53,128,53v17,0,44,-24,61,-40","w":833},"\u00ff":{"d":"30,-500r155,500r61,0r-72,230r37,0r229,-730r-37,0r-148,468r-41,0r-147,-468r-37,0xm137,-638r0,-62r35,0r0,62r-35,0xm307,-638r0,-62r35,0r0,62r-35,0","w":480},"\u00fd":{"d":"5,-499r113,0r103,388r26,0r103,-388r113,0r-133,505r-53,207r-113,0r55,-213r-84,0xm104,-673r244,-93r41,107r-244,89","w":480},"M":{"d":"77,0r0,-692r191,0r157,526r157,-526r190,0r0,692r-118,0r0,-546r-14,0r-155,518r-120,0r-156,-518r-15,0r0,546r-117,0","w":849},"U":{"d":"184,-223v0,90,54,117,134,117v82,0,137,-28,137,-117r0,-469r118,0r0,469v0,166,-89,232,-255,232v-164,0,-252,-66,-252,-232r0,-469r118,0r0,469","w":639},"X":{"d":"151,-692r140,258r139,-258r131,0r-191,349r191,343r-131,0r-139,-254r-140,254r-131,0r194,-343r-194,-349r131,0","w":581},"Y":{"d":"343,-295r0,295r-118,0r0,-296r-212,-396r131,0r139,265r138,-265r131,0","w":565},"\u00b0":{"d":"97,-564v0,-87,60,-147,147,-147v87,0,147,60,147,147v0,87,-60,146,-147,146v-87,0,-147,-59,-147,-146xm164,-564v0,48,32,81,80,81v48,0,82,-33,82,-81v0,-48,-34,-82,-82,-82v-48,0,-80,34,-80,82"},"\u00a7":{"d":"421,-605r-2,32v0,0,-106,-13,-154,-13v-89,0,-140,31,-140,109v0,95,49,108,148,124v106,17,166,38,166,140v0,45,-20,96,-38,126v23,20,35,48,35,94v0,110,-62,158,-173,158v-60,0,-168,-13,-168,-13r3,-32v0,0,110,14,165,14v88,0,138,-36,138,-126v0,-83,-51,-91,-137,-104v-113,-18,-176,-36,-176,-154v0,-48,25,-86,46,-111v-29,-21,-44,-55,-44,-114v0,-106,66,-143,175,-143v63,0,156,13,156,13xm266,-321v-43,-7,-79,-13,-107,-26v-18,22,-36,64,-36,95v0,95,49,108,148,124v43,7,78,13,104,25v15,-23,29,-71,29,-107v0,-83,-54,-98,-138,-111"},"\u00a9":{"d":"10,-434v0,-147,108,-266,255,-266v147,0,256,119,256,266v0,147,-109,265,-256,265v-147,0,-255,-118,-255,-265xm42,-434v0,129,94,233,223,233v129,0,224,-104,224,-233v0,-129,-95,-234,-224,-234v-129,0,-223,105,-223,234xm338,-321r1,32v0,0,-43,8,-74,8v-88,0,-109,-61,-109,-152v0,-91,19,-154,109,-154v38,0,74,7,74,7r-1,32v0,0,-41,-7,-73,-7v-70,0,-77,45,-77,122v0,76,13,120,77,120v28,0,73,-8,73,-8"},"\u2122":{"d":"7,-590r0,-31r200,0r0,31r-83,0r0,258r-33,0r0,-258r-84,0xm242,-331r0,-290r50,0r84,242r87,-242r50,0r0,290r-32,0r0,-258r-88,247r-35,0r-84,-247r0,258r-32,0"},"\u00ae":{"d":"10,-434v0,-147,108,-266,255,-266v147,0,256,119,256,266v0,147,-109,265,-256,265v-147,0,-255,-118,-255,-265xm42,-434v0,129,94,233,223,233v129,0,224,-104,224,-233v0,-129,-95,-234,-224,-234v-129,0,-223,105,-223,234xm340,-276r-66,-131r-79,0r0,131r-32,0r0,-315r91,0v85,0,115,24,115,90v0,47,-15,80,-59,91r65,134r-35,0xm275,-439v44,0,62,-14,62,-62v0,-45,-26,-58,-80,-58r-62,0r0,120r80,0"},"\u00e1":{"d":"433,-136r0,-206v0,-123,-60,-169,-170,-169v-74,0,-203,22,-203,22r4,100v0,0,119,-12,193,-12v50,0,68,35,62,90r-124,10v-108,8,-167,45,-167,152v0,99,50,160,145,160v77,0,163,-35,163,-35v30,23,56,35,134,35r4,-97v-29,-5,-41,-15,-41,-50xm209,-216r110,-6r0,115v0,0,-72,20,-125,20v-33,0,-51,-23,-51,-65v0,-41,23,-62,66,-64xm141,-673r244,-93r41,107r-244,89","w":536},"\u00e0":{"d":"433,-342r0,206v1,35,12,45,41,50r-4,97v-78,0,-104,-12,-134,-35v0,0,-86,35,-163,35v-95,0,-145,-61,-145,-160v0,-107,59,-144,167,-152r124,-10v5,-54,-12,-90,-62,-90v-74,0,-193,12,-193,12r-4,-100v0,0,129,-22,203,-22v110,0,170,46,170,169xm319,-222r-110,6v-43,4,-66,23,-66,64v0,42,18,65,51,65v53,0,125,-20,125,-20r0,-115xm131,-766r243,93r-40,103r-245,-89","w":536},"\u00e2":{"d":"433,-136r0,-206v0,-123,-60,-169,-170,-169v-74,0,-203,22,-203,22r4,100v0,0,119,-12,193,-12v50,0,68,35,62,90r-124,10v-108,8,-167,45,-167,152v0,99,50,160,145,160v77,0,163,-35,163,-35v30,23,56,35,134,35r4,-97v-29,-5,-41,-15,-41,-50xm209,-216r110,-6r0,115v0,0,-72,20,-125,20v-33,0,-51,-23,-51,-65v0,-41,23,-62,66,-64xm70,-576r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":536},"\u00e4":{"d":"433,-136r0,-206v0,-123,-60,-169,-170,-169v-74,0,-203,22,-203,22r4,100v0,0,119,-12,193,-12v50,0,68,35,62,90r-124,10v-108,8,-167,45,-167,152v0,99,50,160,145,160v77,0,163,-35,163,-35v30,23,56,35,134,35r4,-97v-29,-5,-41,-15,-41,-50xm209,-216r110,-6r0,115v0,0,-72,20,-125,20v-33,0,-51,-23,-51,-65v0,-41,23,-62,66,-64xm82,-593r0,-131r118,0r0,131r-118,0xm287,-593r0,-131r118,0r0,131r-118,0","w":536},"\u00e3":{"d":"433,-136r0,-206v0,-123,-60,-169,-170,-169v-74,0,-203,22,-203,22r4,100v0,0,119,-12,193,-12v50,0,68,35,62,90r-124,10v-108,8,-167,45,-167,152v0,99,50,160,145,160v77,0,163,-35,163,-35v30,23,56,35,134,35r4,-97v-29,-5,-41,-15,-41,-50xm209,-216r110,-6r0,115v0,0,-72,20,-125,20v-33,0,-51,-23,-51,-65v0,-41,23,-62,66,-64xm376,-702r22,17v-27,29,-55,55,-83,55v-60,0,-82,-54,-129,-54v-21,0,-51,24,-69,41r-25,-18v30,-29,62,-54,95,-54v62,0,86,53,128,53v17,0,44,-24,61,-40","w":536},"\u00e5":{"d":"433,-136r0,-206v0,-123,-60,-169,-170,-169v-74,0,-203,22,-203,22r4,100v0,0,119,-12,193,-12v50,0,68,35,62,90r-124,10v-108,8,-167,45,-167,152v0,99,50,160,145,160v77,0,163,-35,163,-35v30,23,56,35,134,35r4,-97v-29,-5,-41,-15,-41,-50xm209,-216r110,-6r0,115v0,0,-72,20,-125,20v-33,0,-51,-23,-51,-65v0,-41,23,-62,66,-64xm151,-648v0,-53,40,-94,94,-94v53,0,94,41,94,94v0,54,-41,94,-94,94v-54,0,-94,-40,-94,-94xm185,-648v0,35,26,62,61,62v34,0,60,-27,60,-62v0,-34,-26,-61,-60,-61v-35,0,-61,27,-61,61","w":536},"\u00e9":{"d":"265,-93v79,0,184,-9,184,-9r2,89v0,0,-114,24,-203,24v-151,0,-210,-79,-210,-255v0,-182,78,-267,217,-267v142,0,213,73,213,228r-8,82r-307,0v1,73,31,108,112,108xm153,-290r202,0v0,-87,-29,-119,-100,-119v-71,0,-102,36,-102,119xm115,-673r244,-93r41,107r-244,89","w":497},"\u00e8":{"d":"265,-93v79,0,184,-9,184,-9r2,89v0,0,-114,24,-203,24v-151,0,-210,-79,-210,-255v0,-182,78,-267,217,-267v142,0,213,73,213,228r-8,82r-307,0v1,73,31,108,112,108xm153,-290r202,0v0,-87,-29,-119,-100,-119v-71,0,-102,36,-102,119xm123,-766r243,93r-40,103r-245,-89","w":497},"\u00ea":{"d":"265,-93v79,0,184,-9,184,-9r2,89v0,0,-114,24,-203,24v-151,0,-210,-79,-210,-255v0,-182,78,-267,217,-267v142,0,213,73,213,228r-8,82r-307,0v1,73,31,108,112,108xm153,-290r202,0v0,-87,-29,-119,-100,-119v-71,0,-102,36,-102,119xm90,-576r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":497},"\u00eb":{"d":"265,-93v79,0,184,-9,184,-9r2,89v0,0,-114,24,-203,24v-151,0,-210,-79,-210,-255v0,-182,78,-267,217,-267v142,0,213,73,213,228r-8,82r-307,0v1,73,31,108,112,108xm153,-290r202,0v0,-87,-29,-119,-100,-119v-71,0,-102,36,-102,119xm106,-593r0,-131r118,0r0,131r-118,0xm311,-593r0,-131r118,0r0,131r-118,0","w":497},"\u00ef":{"d":"-31,-593r0,-131r118,0r0,131r-118,0xm174,-593r0,-131r118,0r0,131r-118,0xm76,0r0,-499r114,0r0,499r-114,0","w":261},"\u00f1":{"d":"82,0r114,0r0,-381v0,0,68,-23,112,-23v70,0,82,49,82,144r0,260r114,0r0,-261v0,-168,-35,-250,-174,-250v-55,0,-134,37,-134,37r0,-25r-114,0r0,499xm429,-702r22,17v-27,29,-55,55,-83,55v-60,0,-82,-54,-129,-54v-21,0,-51,24,-69,41r-25,-18v30,-29,62,-54,95,-54v62,0,86,53,128,53v17,0,44,-24,61,-40","w":574},"\u00f3":{"d":"307,-511v-169,0,-225,99,-225,259v0,163,53,263,225,263v172,0,224,-102,224,-263v0,-159,-58,-259,-224,-259xm307,-92v-89,0,-109,-52,-109,-160v0,-107,24,-155,109,-155v81,0,108,50,108,155v0,106,-19,160,-108,160xm121,-673r244,-93r41,107r-244,89","w":536},"\u00f2":{"d":"307,-511v166,0,224,100,224,259v0,161,-52,263,-224,263v-172,0,-225,-100,-225,-263v0,-160,56,-259,225,-259xm307,-92v89,0,108,-54,108,-160v0,-105,-27,-155,-108,-155v-85,0,-109,48,-109,155v0,108,20,160,109,160xm131,-766r243,93r-40,103r-245,-89","w":536},"\u00f4":{"d":"307,-511v-169,0,-225,99,-225,259v0,163,53,263,225,263v172,0,224,-102,224,-263v0,-159,-58,-259,-224,-259xm307,-92v-89,0,-109,-52,-109,-160v0,-107,24,-155,109,-155v81,0,108,50,108,155v0,106,-19,160,-108,160xm88,-576r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":536},"\u00f6":{"d":"307,-511v-169,0,-225,99,-225,259v0,163,53,263,225,263v172,0,224,-102,224,-263v0,-159,-58,-259,-224,-259xm307,-92v-89,0,-109,-52,-109,-160v0,-107,24,-155,109,-155v81,0,108,50,108,155v0,106,-19,160,-108,160xm102,-593r0,-131r118,0r0,131r-118,0xm307,-593r0,-131r118,0r0,131r-118,0","w":536},"\u00f5":{"d":"307,-511v-169,0,-225,99,-225,259v0,163,53,263,225,263v172,0,224,-102,224,-263v0,-159,-58,-259,-224,-259xm307,-92v-89,0,-109,-52,-109,-160v0,-107,24,-155,109,-155v81,0,108,50,108,155v0,106,-19,160,-108,160xm394,-702r22,17v-27,29,-55,55,-83,55v-60,0,-82,-54,-129,-54v-21,0,-51,24,-69,41r-25,-18v30,-29,62,-54,95,-54v62,0,86,53,128,53v17,0,44,-24,61,-40","w":536},"\u00fa":{"d":"499,-499r-114,0r0,384v0,0,-65,23,-109,23v-76,0,-82,-41,-82,-147r0,-260r-114,0r0,261v0,175,29,249,173,249v54,0,132,-36,132,-36r0,25r114,0r0,-499xm130,-673r244,-93r41,107r-244,89","w":511},"\u00f9":{"d":"385,-499r114,0r0,499r-114,0r0,-25v0,0,-78,36,-132,36v-144,0,-173,-74,-173,-249r0,-261r114,0r0,260v0,106,6,147,82,147v44,0,109,-23,109,-23r0,-384xm140,-766r243,93r-40,103r-245,-89","w":511},"\u00fb":{"d":"499,-499r-114,0r0,384v0,0,-65,23,-109,23v-76,0,-82,-41,-82,-147r0,-260r-114,0r0,261v0,175,29,249,173,249v54,0,132,-36,132,-36r0,25r114,0r0,-499xm97,-576r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":511},"\u00fc":{"d":"499,-499r-114,0r0,384v0,0,-65,23,-109,23v-76,0,-82,-41,-82,-147r0,-260r-114,0r0,261v0,175,29,249,173,249v54,0,132,-36,132,-36r0,25r114,0r0,-499xm111,-593r0,-131r118,0r0,131r-118,0xm316,-593r0,-131r118,0r0,131r-118,0","w":511},"\u00d7":{"d":"243,-543r178,181r179,-181r75,74r-179,181r179,181r-75,73r-179,-180r-178,180r-74,-73r178,-181r-178,-181","w":591},"\u00ed":{"d":"-1,-673r244,-93r41,107r-244,89xm76,0r0,-499r114,0r0,499r-114,0","w":261},"\u00ec":{"d":"-13,-766r243,93r-40,103r-245,-89xm76,0r0,-499r114,0r0,499r-114,0","w":261},"\u00ee":{"d":"76,0r0,-499r114,0r0,499r-114,0xm-45,-576r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":261},"\u00c3":{"d":"26,0r165,-692r231,0r163,692r-118,0r-38,-136r-251,0r-34,136r-118,0xm282,-584r-79,335r203,0r-77,-335r-47,0xm435,-902r22,17v-27,29,-55,55,-83,55v-60,0,-82,-54,-129,-54v-21,0,-51,24,-69,41r-25,-18v30,-29,62,-54,95,-54v62,0,86,53,128,53v17,0,44,-24,61,-40","w":604},"\u00c0":{"d":"26,0r165,-692r231,0r163,692r-118,0r-38,-136r-251,0r-34,136r-118,0xm282,-584r-79,335r203,0r-77,-335r-47,0xm183,-966r243,93r-40,103r-245,-89","w":604},"\u00d5":{"d":"328,-102v128,0,158,-76,158,-239v0,-161,-31,-249,-158,-249v-127,0,-158,88,-158,249v0,161,30,239,158,239xm328,11v-214,0,-279,-120,-279,-352v0,-232,65,-362,279,-362v214,0,279,130,279,362v0,234,-65,352,-279,352xm459,-902r22,17v-27,29,-55,55,-83,55v-60,0,-82,-54,-129,-54v-21,0,-51,24,-69,41r-25,-18v30,-29,62,-54,95,-54v62,0,86,53,128,53v17,0,44,-24,61,-40","w":656},"\u00c2":{"d":"26,0r165,-692r231,0r163,692r-118,0r-38,-136r-251,0r-34,136r-118,0xm282,-584r-79,335r203,0r-77,-335r-47,0xm129,-776r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":604},"\u00ca":{"d":"81,0r0,-692r432,0r0,112r-316,0r0,181r256,0r0,110r-256,0r0,177r316,0r0,112r-432,0xm136,-776r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":572},"\u00c1":{"d":"26,0r165,-692r231,0r163,692r-118,0r-38,-136r-251,0r-34,136r-118,0xm282,-584r-79,335r203,0r-77,-335r-47,0xm153,-873r244,-93r41,107r-244,89","w":604},"\u00cb":{"d":"81,0r0,-692r432,0r0,112r-316,0r0,181r256,0r0,110r-256,0r0,177r316,0r0,112r-432,0xm150,-793r0,-131r118,0r0,131r-118,0xm355,-793r0,-131r118,0r0,131r-118,0","w":572},"\u00c8":{"d":"103,0r0,-700r409,0r0,34r-373,0r0,289r313,0r0,34r-313,0r0,309r373,0r0,34r-409,0xm219,-932r192,96r-15,27r-193,-92","w":572},"\u00d4":{"d":"328,-102v128,0,158,-76,158,-239v0,-161,-31,-249,-158,-249v-127,0,-158,88,-158,249v0,161,30,239,158,239xm328,11v-214,0,-279,-120,-279,-352v0,-232,65,-362,279,-362v214,0,279,130,279,362v0,234,-65,352,-279,352xm153,-776r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":656},"\u00d3":{"d":"328,-102v128,0,158,-76,158,-239v0,-161,-31,-249,-158,-249v-127,0,-158,88,-158,249v0,161,30,239,158,239xm328,11v-214,0,-279,-120,-279,-352v0,-232,65,-362,279,-362v214,0,279,130,279,362v0,234,-65,352,-279,352xm166,-873r244,-93r41,107r-244,89","w":656},"\u00cc":{"d":"75,0r0,-692r118,0r0,692r-118,0xm1,-966r243,93r-40,103r-245,-89","w":226},"\u00cf":{"d":"75,0r0,-692r118,0r0,692r-118,0xm-48,-793r0,-131r118,0r0,131r-118,0xm157,-793r0,-131r118,0r0,131r-118,0","w":226},"\u00ce":{"d":"77,0r0,-692r118,0r0,692r-118,0xm-60,-776r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":231},"\u00cd":{"d":"75,0r0,-692r118,0r0,692r-118,0xm-49,-873r244,-93r41,107r-244,89","w":226},"\u00d2":{"d":"328,-102v128,0,158,-76,158,-239v0,-161,-31,-249,-158,-249v-127,0,-158,88,-158,249v0,161,30,239,158,239xm328,11v-214,0,-279,-120,-279,-352v0,-232,65,-362,279,-362v214,0,279,130,279,362v0,234,-65,352,-279,352xm216,-966r243,93r-40,103r-245,-89","w":656},"\u00da":{"d":"188,-223v0,90,54,117,134,117v82,0,137,-28,137,-117r0,-469r118,0r0,469v0,166,-89,232,-255,232v-164,0,-252,-66,-252,-232r0,-469r118,0r0,469xm163,-873r244,-93r41,107r-244,89","w":642},"\u00db":{"d":"188,-223v0,90,54,117,134,117v82,0,137,-28,137,-117r0,-469r118,0r0,469v0,166,-89,232,-255,232v-164,0,-252,-66,-252,-232r0,-469r118,0r0,469xm150,-776r129,-172r92,0r130,172r-114,0r-61,-82r-62,82r-114,0","w":642},"\u00d9":{"d":"188,-223v0,90,54,117,134,117v82,0,137,-28,137,-117r0,-469r118,0r0,469v0,166,-89,232,-255,232v-164,0,-252,-66,-252,-232r0,-469r118,0r0,469xm213,-966r243,93r-40,103r-245,-89","w":642},"\u00b8":{"d":"478,107v0,61,-35,71,-92,60r2,-26v9,2,27,2,28,2v27,0,28,-9,28,-36v0,-27,-1,-32,-28,-32r-24,0r0,-76r33,0r0,48v41,1,53,15,53,60","w":833},"\u00df":{"d":"249,0r-36,0r0,-532v0,-137,32,-178,153,-178v139,0,190,41,190,135v0,59,-21,83,-64,100v-56,22,-69,23,-69,45v0,13,1,14,84,64v95,58,134,74,134,115v0,177,-37,260,-238,260v-30,0,-78,-4,-78,-4r4,-34v0,0,57,4,74,4v183,0,200,-75,200,-226v0,-16,-31,-38,-121,-89v-91,-51,-97,-58,-97,-90v0,-51,29,-49,87,-74v44,-19,46,-26,46,-71v0,-75,-42,-101,-152,-101v-95,0,-117,26,-117,157r0,519","w":833},"\u00dc":{"d":"188,-223v0,90,54,117,134,117v82,0,137,-28,137,-117r0,-469r118,0r0,469v0,166,-89,232,-255,232v-164,0,-252,-66,-252,-232r0,-469r118,0r0,469xm165,-793r0,-131r118,0r0,131r-118,0xm370,-793r0,-131r118,0r0,131r-118,0","w":642},"\u00d6":{"d":"328,-102v128,0,158,-76,158,-239v0,-161,-31,-249,-158,-249v-127,0,-158,88,-158,249v0,161,30,239,158,239xm328,11v-214,0,-279,-120,-279,-352v0,-232,65,-362,279,-362v214,0,279,130,279,362v0,234,-65,352,-279,352xm167,-793r0,-131r118,0r0,131r-118,0xm372,-793r0,-131r118,0r0,131r-118,0","w":656},"\u00d1":{"d":"68,0r0,-692r190,0r220,546r17,0r0,-546r118,0r0,692r-185,0r-226,-546r-17,0r0,546r-117,0xm473,-902r22,17v-27,29,-55,55,-83,55v-60,0,-82,-54,-129,-54v-21,0,-51,24,-69,41r-25,-18v30,-29,62,-54,95,-54v62,0,86,53,128,53v17,0,44,-24,61,-40","w":687},"\u00c9":{"d":"81,0r0,-692r432,0r0,112r-316,0r0,181r256,0r0,110r-256,0r0,177r316,0r0,112r-432,0xm169,-873r244,-93r41,107r-244,89","w":572},"\u00c7":{"d":"494,-120r3,106v0,0,-117,25,-196,25v-209,0,-257,-120,-257,-356v0,-252,61,-358,257,-358v87,0,197,27,197,27r-4,103v0,0,-117,-15,-177,-15v-121,0,-152,58,-152,243v0,176,24,241,156,241v54,0,173,-16,173,-16xm341,107v0,61,-35,71,-92,60r2,-26v9,2,27,2,28,2v27,0,28,-9,28,-36v0,-27,-1,-32,-28,-32r-24,0r0,-76r33,0r0,48v41,1,53,15,53,60","w":537},"\u00c5":{"d":"26,0r165,-692r231,0r163,692r-118,0r-38,-136r-251,0r-34,136r-118,0xm282,-584r-79,335r203,0r-77,-335r-47,0xm211,-848v0,-53,40,-94,94,-94v53,0,94,41,94,94v0,54,-41,94,-94,94v-54,0,-94,-40,-94,-94xm245,-848v0,35,26,62,61,62v34,0,60,-27,60,-62v0,-34,-26,-61,-60,-61v-35,0,-61,27,-61,61","w":604},"\u00c4":{"d":"26,0r165,-692r231,0r163,692r-118,0r-38,-136r-251,0r-34,136r-118,0xm282,-584r-79,335r203,0r-77,-335r-47,0xm143,-793r0,-131r118,0r0,131r-118,0xm348,-793r0,-131r118,0r0,131r-118,0","w":604},"\u00e7":{"d":"250,-511v54,0,152,19,152,19r-4,99v0,0,-79,-9,-117,-9v-102,0,-125,38,-125,146v0,120,21,159,126,159v38,0,117,-9,117,-9r3,99v0,0,-102,18,-155,18v-152,0,-207,-77,-207,-267v0,-179,61,-255,210,-255xm305,107v0,61,-35,71,-92,60r2,-26v9,2,27,2,28,2v27,0,28,-9,28,-36v0,-27,-1,-32,-28,-32r-24,0r0,-76r33,0r0,48v41,1,53,15,53,60","w":436},"\u00f0":{},"\u00d0":{"d":"18,-288r0,-112r312,0r0,112r-312,0xm310,0r-233,0r0,-692r233,0v225,0,278,116,278,334v0,222,-47,358,-278,358xm467,-358v0,-142,-20,-222,-157,-222r-117,0r0,468r117,0v137,0,157,-103,157,-246","w":631},"\u00dd":{"d":"331,-295r0,295r-118,0r0,-296r-212,-396r131,0r139,265r138,-265r131,0xm96,-873r244,-93r41,107r-244,89","w":540},"\u00de":{"d":"288,-220v80,0,118,-52,118,-136v0,-83,-38,-121,-118,-121r-132,0r0,257r132,0xm289,-106r-133,0r0,106r-118,0r0,-692r118,0r0,103r133,0v157,0,237,76,237,233v0,157,-80,250,-237,250","w":547},"\u00fe":{"d":"272,-92v107,0,129,-46,129,-164v0,-110,-30,-149,-94,-149v-44,0,-106,14,-106,14r0,294v0,0,52,5,71,5xm322,-511v136,0,195,68,195,255v0,208,-67,267,-245,267v-19,0,-46,-2,-71,-3r0,206r-114,0r0,-920r114,0r0,222v0,0,68,-27,121,-27","w":538},"\u0178":{"d":"289,-301r0,301r-36,0r0,-301r-228,-399r41,0r205,359r202,-359r42,0xm167,-838r0,-62r35,0r0,62r-35,0xm337,-838r0,-62r35,0r0,62r-35,0","w":540},"\u00f8":{"d":"108,94r42,-104v-71,-32,-90,-108,-90,-251v0,-185,57,-248,205,-248v31,0,59,4,83,12r40,-96r30,11r-40,98v59,34,88,105,88,225v0,187,-36,268,-201,268v-33,0,-61,-3,-85,-9r-42,104xm97,-261v0,120,10,189,66,219r173,-424v-21,-7,-44,-11,-71,-11v-128,0,-168,48,-168,216xm265,-23v147,0,164,-77,164,-236v0,-101,-21,-161,-65,-192r-171,421v20,5,43,7,72,7","w":526},"\u00a6":{"d":"201,-750r117,0r0,409r-117,0r0,-409xm201,-211r117,0r0,407r-117,0r0,-407"},"\u00b1":{"d":"24,-306r0,-104r190,0r0,-122r104,0r0,122r193,0r0,104r-193,0r0,117r-104,0r0,-117r-190,0xm24,-144r487,0r0,104r-487,0r0,-104"},"\u2022":{"d":"247,0r0,-80r40,0r0,80r-40,0"},"\u00aa":{"d":"346,-571r0,134v5,16,16,21,37,23r-2,28v-25,-1,-38,-7,-54,-22v0,0,-63,22,-119,22v-41,0,-70,-31,-70,-80v0,-48,24,-72,75,-76r102,-7r0,-23v0,-44,-16,-55,-52,-55v-34,0,-104,7,-104,7r-2,-31v0,0,69,-8,106,-8v57,0,83,25,83,88xm315,-520r-97,6v-34,3,-47,17,-47,50v0,32,15,46,40,46v45,0,104,-17,104,-17r0,-85","w":518},"\u00ba":{"d":"259,-659v76,0,113,41,113,135v0,94,-37,138,-113,138v-76,0,-115,-44,-115,-138v0,-94,39,-135,115,-135xm259,-418v57,0,79,-30,79,-106v0,-76,-22,-103,-79,-103v-57,0,-81,27,-81,103v0,76,24,106,81,106","w":526},"\u2039":{"w":833},"I":{"d":"75,0r0,-692r118,0r0,692r-118,0","w":268},"O":{"d":"323,-102v128,0,158,-76,158,-239v0,-161,-31,-249,-158,-249v-127,0,-158,88,-158,249v0,161,30,239,158,239xm323,11v-214,0,-279,-120,-279,-352v0,-232,65,-362,279,-362v214,0,279,130,279,362v0,234,-65,352,-279,352","w":646},"\u00ab":{"d":"387,-380r-135,106r135,117r0,41v0,0,-133,-113,-167,-138r0,-36r167,-129r0,39xm594,-380r-135,106r135,117r0,41v0,0,-133,-113,-167,-138r0,-36r167,-129r0,39","w":833},"\u00bb":{"d":"582,-274r-135,-106r0,-39r167,129r0,36v-34,25,-167,138,-167,138r0,-41xm375,-274r-135,-106r0,-39r167,129r0,36v-34,25,-167,138,-167,138r0,-41","w":833},"\u201c":{"w":833},"~":{"w":833},"\u2014":{"w":833},"L":{"d":"462,0r-385,0r0,-692r117,0r0,579r268,0r0,113","w":496},"B":{"d":"77,-692r260,0v126,0,210,50,210,174v0,92,-25,132,-80,163v62,25,95,66,95,160v0,139,-84,195,-218,195r-267,0r0,-692xm336,-295r-143,0r0,187r145,0v66,0,103,-25,103,-96v0,-72,-50,-91,-105,-91xm331,-584r-138,0r0,183r141,0v65,0,92,-33,92,-97v0,-61,-31,-86,-95,-86","w":609},"D":{"d":"310,0r-233,0r0,-692r233,0v225,0,278,116,278,334v0,222,-47,358,-278,358xm467,-358v0,-142,-20,-222,-157,-222r-117,0r0,468r117,0v137,0,157,-103,157,-246","w":631},"P":{"d":"328,-209r-134,0r0,209r-117,0r0,-692r251,0v157,0,235,78,235,235v0,157,-78,248,-235,248xm194,-322r133,0v79,0,116,-51,116,-135v0,-83,-37,-122,-116,-122r-133,0r0,257","w":597},"b":{"d":"309,-511v136,0,195,68,195,255v0,208,-66,267,-244,267v-52,0,-186,-13,-186,-13r0,-704r114,0r0,222v0,0,68,-27,121,-27xm259,-92v107,0,129,-46,129,-164v0,-110,-30,-149,-94,-149v-44,0,-106,14,-106,14r0,294v0,0,52,5,71,5","w":544},"v":{"d":"13,-499r119,0r95,404r30,0r97,-404r116,0r-128,499r-202,0","w":483},"x":{"d":"16,-499r122,0r94,168r95,-168r122,0r-143,250r143,249r-122,0r-95,-167r-94,167r-122,0r142,-249","w":465},"6":{"d":"478,-650r-10,107v0,0,-96,-15,-180,-15v-99,0,-140,55,-140,168v0,1,75,-30,131,-30v148,0,223,66,223,211v0,146,-87,220,-236,220v-172,0,-239,-118,-239,-340v0,-260,96,-343,261,-343v84,0,190,22,190,22xm269,-312v-61,0,-122,24,-122,24v1,108,25,189,119,189v75,0,115,-35,115,-110v0,-72,-40,-103,-112,-103"},"9":{"d":"44,-10r11,-108v0,0,98,16,182,16v99,0,139,-55,139,-160v0,-1,-75,21,-131,21v-142,0,-224,-70,-224,-212v0,-143,95,-219,238,-219v171,0,238,132,238,348v0,260,-95,335,-260,335v-84,0,-193,-21,-193,-21xm255,-348v59,0,122,-19,122,-19v-1,-109,-29,-194,-118,-194v-71,0,-116,37,-116,108v0,72,40,105,112,105"},"\u00a5":{"d":"48,-299r0,-96r108,0r-155,-265r131,0r139,231r138,-231r131,0r-153,265r105,0r0,96r-159,0v-2,15,-2,33,-2,51r161,0r0,96r-161,0r0,152r-118,0r0,-152r-165,0r0,-96r165,0v0,-18,1,-37,-3,-51r-162,0","w":540},"<":{"d":"410,-439r-235,129r235,134r0,120v-93,-48,-247,-139,-347,-192r0,-120r347,-191r0,120"},">":{"d":"298,-310r-235,-129r0,-120r347,191r0,120v-100,53,-254,144,-347,192r0,-120"},"[":{"d":"271,-749r0,112r-121,0r0,648r121,0r0,112r-238,0r-1,-872r239,0","w":300},"\\":{"d":"631,-3r-126,3r-307,-699r127,-3","w":833},"]":{"d":"-45,-637r0,-112r239,0r-1,872r-238,0r0,-112r121,0r0,-648r-121,0","w":300},"|":{"d":"201,196r0,-936r118,0r0,936r-118,0"},"\u00c6":{"d":"428,0r0,-136r-225,0r-39,136r-119,0r198,-692r617,0r0,112r-316,0r0,172r256,0r0,112r-256,0r0,184r316,0r0,112r-432,0xm321,-562r-89,313r196,0r0,-313r-107,0","w":898},"\u00b5":{"d":"62,226r0,-726r114,0r0,282v1,92,11,126,82,126v44,0,110,-23,110,-23r0,-384r114,0r0,499r-114,0r0,-25v0,0,-78,36,-132,36v-26,0,-45,-4,-60,-12r0,227r-114,0"},"\u03bc":{"d":"62,226r0,-726r114,0r0,282v1,92,11,126,82,126v44,0,110,-23,110,-23r0,-384r114,0r0,499r-114,0r0,-25v0,0,-78,36,-132,36v-26,0,-45,-4,-60,-12r0,227r-114,0"},"\u00e6":{"d":"569,-93v80,0,185,-9,185,-9r2,89v0,0,-115,24,-204,24v-68,0,-117,-16,-151,-50v-49,23,-100,50,-204,50v-95,0,-144,-60,-144,-160v0,-112,63,-145,176,-153r115,-9r0,-30v0,-39,-25,-60,-62,-60v-74,0,-193,10,-193,10r-4,-100v0,0,129,-20,203,-20v60,0,104,16,131,49v34,-33,83,-49,141,-49v142,0,212,73,212,228r-8,82r-306,0v1,73,30,108,111,108xm219,-87v51,0,127,-21,130,-22v-4,-34,-6,-72,-6,-113v-72,9,-175,-14,-175,70v0,43,17,65,51,65xm458,-290r201,0v0,-87,-28,-119,-99,-119v-72,0,-102,36,-102,119","w":828},"\u0152":{"d":"877,0r-429,0v-38,6,-89,11,-126,11v-212,0,-262,-118,-262,-356v0,-254,65,-358,262,-358v37,0,88,11,125,11r430,0r0,113r-314,0r0,171r254,0r0,112r-254,0r0,183r314,0r0,113xm341,-104v22,0,71,-4,106,-7r0,-470v-35,-3,-84,-7,-109,-7v-122,0,-157,56,-157,243v0,178,27,241,160,241","w":944},"\u0153":{"d":"618,-93v80,0,184,-9,184,-9r2,89v0,0,-114,24,-203,24v-73,0,-123,-19,-156,-59v-34,39,-84,59,-162,59v-172,0,-225,-100,-225,-263v0,-160,57,-259,225,-259v79,0,133,23,167,68v36,-47,90,-68,159,-68v142,0,212,73,212,228r-8,82r-306,0v1,73,30,108,111,108xm283,-92v89,0,108,-54,108,-160v0,-105,-26,-155,-108,-155v-84,0,-108,48,-108,155v0,108,20,160,108,160xm506,-290r202,0v0,-87,-28,-119,-99,-119v-72,0,-103,37,-103,119","w":876},"4":{"d":"318,8r0,-111r-294,0r0,-96r174,-461r130,0r-171,444r161,0r0,-171r118,0r0,171r67,0r0,113r-67,0r0,111r-118,0"},"\"":{"d":"305,-452r-104,0r-2,-240r110,0xm143,-452r-105,0r-2,-240r111,0","w":340},"'":{"d":"-8,-450r-2,-242r111,0r-5,242r-104,0","w":100},"(":{"d":"112,-750r124,0v0,0,-95,260,-95,449v0,186,95,426,95,426r-124,0v0,0,-97,-226,-97,-426v0,-200,97,-449,97,-449","w":260},")":{"d":"132,120r-124,0v0,0,95,-260,95,-449v0,-186,-95,-426,-95,-426r124,0v0,0,97,226,97,426v0,200,-97,449,-97,449","w":260},",":{"d":"5,123r50,-250r123,0r-59,250r-114,0","w":170},"-":{"d":"68,-225r0,-112r304,0r0,112r-304,0","w":440},".":{"d":"56,0r0,-149r123,0r0,149r-123,0","w":248},"\/":{"d":"67,-18r281,-698r109,38r-281,697"},":":{"d":"43,-300r0,-149r124,0r0,149r-124,0xm43,0r0,-149r124,0r0,149r-124,0","w":212},";":{"d":"68,-143r-57,258r106,0r75,-258r-124,0xm60,-300r0,-149r123,0r0,149r-123,0","w":227},"=":{"d":"25,-335r0,-104r469,0r0,104r-469,0xm25,-128r0,-104r469,0r0,104r-469,0"},"?":{"d":"396,-523v0,178,-181,201,-181,279r0,38r-123,0r0,-41v0,-134,179,-145,179,-262v0,-58,-17,-84,-100,-84v-50,0,-151,20,-151,20r-14,-112v0,0,116,-28,170,-28v151,0,220,49,220,190xm92,0r0,-149r123,0r0,149r-123,0","w":386},"_":{"d":"27,-5r428,0r0,104r-428,0r0,-104","w":520},"{":{"d":"238,-171v0,31,-7,82,-7,116v0,50,14,70,86,75r-1,112v-144,-5,-208,-54,-208,-173v0,-122,39,-191,-89,-223r0,-96v77,-19,96,-47,96,-96v0,-28,-7,-91,-7,-128v0,-127,64,-170,208,-175r1,112v-72,5,-86,21,-86,71v0,33,7,98,7,127v0,81,-27,112,-100,136v73,24,100,61,100,142","w":328},"}":{"d":"88,-452v0,-31,7,-82,7,-116v0,-50,-14,-70,-86,-75r1,-112v144,5,208,54,208,173v0,122,-39,191,89,223r0,96v-77,19,-96,47,-96,96v0,28,7,91,7,128v0,127,-64,170,-208,175r-1,-112v72,-5,86,-21,86,-71v0,-33,-7,-98,-7,-127v0,-81,27,-112,100,-136v-73,-24,-100,-61,-100,-142","w":328},"\u00a2":{"d":"202,77r0,-108v-116,-8,-181,-68,-181,-218v0,-146,69,-211,181,-219r0,-107r96,0r0,111v42,4,85,10,85,10r-3,99v0,0,-84,-4,-122,-4v-89,0,-120,24,-120,110v0,86,30,109,123,109v38,0,119,-5,119,-5r4,99r-85,11r0,112r-97,0","w":437},"\u2018":{"d":"154,-727r-47,238r-117,0r56,-238r108,0","w":170},"\u2019":{"d":"15,-527r47,-238r117,0r-56,238r-108,0","w":170},"\u00f7":{"d":"167,-388r0,-113r173,0r0,113r-173,0xm44,-280r0,-113r413,0r0,113r-413,0xm197,-65r0,-121r114,0r0,121r-114,0"},"\u20ac":{"d":"55,-455r61,0v19,-157,84,-218,244,-218v87,0,178,19,178,19r-4,104v0,0,-99,-7,-158,-7v-88,0,-123,25,-137,103r229,0r0,89r-237,0r0,74r237,0r0,90r-228,0v14,71,49,97,139,97v54,0,155,-8,155,-8r3,106v0,0,-98,17,-177,17v-167,0,-226,-66,-244,-212r-61,0r0,-90r55,0r0,-74r-55,0r0,-90","w":580},"\u00d8":{"d":"66,79r63,-134v-59,-58,-79,-154,-79,-286v0,-232,65,-362,279,-362v37,0,68,4,97,12r55,-119r106,40r-62,134v61,60,83,160,83,295v0,234,-65,352,-279,352v-39,0,-72,-4,-101,-12r-58,126xm171,-341v0,63,5,112,23,146r181,-388v-24,-8,-60,-7,-85,-2v-95,18,-119,103,-119,244xm329,-102v128,0,158,-76,158,-239v0,-67,-6,-122,-25,-160r-184,393v15,4,31,6,51,6","w":656},"&":{"d":"323,-710v127,0,194,60,194,169v0,92,-41,139,-139,202r100,101v7,-25,22,-90,25,-122r111,2v-9,63,-30,146,-47,192r117,110r-69,77r-108,-97v-69,65,-127,96,-233,96v-149,0,-237,-79,-237,-220v0,-103,60,-163,144,-204v-41,-53,-51,-82,-51,-146v0,-100,74,-160,193,-160xm278,-87v60,0,97,-16,143,-60r-170,-178v-58,27,-96,69,-96,124v0,71,47,114,123,114xm245,-534v0,50,29,92,63,123v64,-38,93,-64,93,-118v0,-52,-26,-74,-78,-74v-49,0,-78,21,-78,69","w":700},"*":{"d":"450,-503r-126,0r39,122r-65,19r-41,-122r-104,79r-42,-53r106,-78r-103,-75r41,-56r101,72r41,-120r66,22r-38,124r125,0r0,66"},"\u00a3":{"d":"471,-658r0,115v0,0,-56,-18,-89,-18v-69,0,-89,8,-93,123r134,0r0,106r-134,0v0,75,-1,151,-1,226r126,0r72,-16r18,104r-81,17v-103,0,-206,1,-309,1r0,-106r62,0r0,-228r-39,0r0,-104r39,0r0,-57v0,-151,60,-185,153,-185v38,0,142,22,142,22","w":570},"\u00b6":{"d":"390,0r0,-587r-86,0r0,587r-114,0r0,-315v-117,3,-192,-76,-193,-191v0,-113,75,-194,186,-194r388,0r0,113r-67,0r0,587r-114,0","w":591},"%":{"d":"128,-701v84,0,121,54,121,147v0,84,-38,140,-121,140v-84,0,-121,-56,-121,-145v0,-88,37,-142,121,-142xm406,-289v84,0,122,54,122,143v0,89,-38,144,-122,144v-83,0,-121,-55,-121,-144v0,-89,37,-143,121,-143xm116,-6r225,-710r76,25r-225,710xm92,-559v0,51,6,75,36,75v29,0,36,-24,36,-74v0,-51,-7,-73,-36,-73v-29,0,-36,22,-36,72xm371,-146v0,50,6,74,35,74v30,0,36,-24,36,-74v0,-50,-6,-72,-36,-72v-29,0,-35,22,-35,72"},"+":{"d":"3,-231r0,-104r198,0r0,-197r104,0r0,197r200,0r0,104r-200,0r0,199r-104,0r0,-199r-198,0","w":506},"^":{"d":"379,-439r-110,-215r-113,215r-140,0r181,-347r140,0r182,347r-140,0","w":591},"\u00a0":{"w":235}}}); diff --git a/public/fonts/TitilliumText800wt.eot b/public/fonts/TitilliumText800wt.eot new file mode 100755 index 0000000000000000000000000000000000000000..fc36be6272c5c1b61e59025a09246f9cf69b3f05 GIT binary patch literal 18686 zcmb7s3qVxI)&I=gdv|dK+y#~u5!rPGLMS4v3n4yGBuEG%CDal^j2c8VA`&EqSVE{F zlp1P`#whV4mQqWtrPTPh)bg2!F@DzA)KY4xv4&byj8P=U^5O36|2KCR#YZ0B!t8y` zoH=vmoHOS!dwCimW)w;ox&1?lSrT_LvVKFzi|HdC8qh>s?m4$=%!u2bQ!~jS%gGv) zmH1mu%1JTqEG5t3UM!hPGEmQ(JV2)4&rH_ht^l_HHJ%}5s9!=>;aWV6C6hfzGwMwK zM!4oXprR2)@gXk~iDadw=FH3a$=F8;Nt1DR{QO5_;$A#``>}lTMRhjZCakJF!S-NU-!5Qq0~Gw4gh1^pjoy{Eehf{w`tS9_X=8^Gi~U zV}Lw~1_RGS>iG%g%}KHwVC{8BQ>b{c^?m*l?^`@M=bhUCkSfIgc^C(5qj zLjUC2gR+BmyJ~Q31iizQ7sv)Bi4@#f_7Wf~G_A&qyg~<_lIAx>l6&1oDZ`2e=Yv;~^H%MWv+) z=Q`_p$92%v;rfH?_pWx=?_6)Y_PQ3iraP}V|MBTtpT6;_@0sl$d;s#BK2#&rg!@B< z8n|5*s1GGs(P+I!=|+3|_>R#V{QLuqfu^xRetoEbsCBCl)@r zh>*3NalK{Q4VPw>9i|^S>H*zV*|lpZ&afSIaN<{OZ@O^4h|FG)i zT2fR0lUK<9+buGi7bvSVb8Li z>>q4Ux=$*UejvRoIb^*YF3*&+ZMV8NBvb7 zr_0e5>VBx(soSGFH`;4-+~`H4Ume{t`d{7}@B6%`d*^#U@4dx)kM{-d>poL_7Wn+w zr`_ix-zmN+zOVRx=zDQY+?eb!tH-=Jrg_Y}V?Nb0{X~7b{uzCv{?B@cVX7hD&}{g? z@NYkz-xR-8zkI)E{a*Du=y%C~ynlxO5B(4NUkeBf$Paiqpe^8^MsMR}V~(-SI24#1 z_>;hYnI@ZlWcv5m@Ui)0UmN?UAYG6-C_X4FXk}1S(BH=C#wCw?aa{YjzXS&cCkL+z zZVdiYaQ}Go_|)+)jQ?=_#qm63T*&<)4}_$Iyb!VrQ^3U9!3vb`L4veo@^2}LnZ8#m zlh5ORt5H6gzE@&6CBK!#ZAIMPtJP4)^u1u&&*N+ciy_Qnu%s|EpG3FuBISESzepsgYGEb?&;c&3xRHLQ)`i^2b|r%ZlTZkW)!_NF+YD9|&!5q1uvzd(wtxK5;PH>~IX?Ii zzWLHYn$Mfv$$^lS#4DpBd3nRqOY!H|kXq-WB zo#@X-Q4^H{0^{PRhQo?*pI9gQ(*DYIgHr6!&>*G!7xbeY+;%*4K`8#&^zjQq$4`z@ zcJR)c1{&!+$xrca8bQOH9ZIWhC|ll{lbYH*XO3fEGmf)`CeCnmDHTeqiUDjM8W#xi zXif16CVXone5rNfB)dLrG6fO+;GB$ z=N-K+LL-vy|Lf!VKb*^(57)-!MXbo-?6w=L0!Zu)Nk3WG3W!$@diB$p^Oq2;an7) zZ{)peo~5QTWfA`!ujcjq13I0S(MtNr`4haK55D&<9Yy^B9{p#dlRhO4bRhl|iol>` z)BQbH`7t?+T8G-@m}BmG&^A&R@CYI#lG^D^W}g~vov0Z@BjRl;&yInP>T+zR$txCT zmRBeJ!e-N-Jb0$7^36dOb(+pvQCy#rpXKl6b=uzX&bEIv4505tu0E*`FvHQe8;UR0 zPN1rO2#=u&fwnmN)Ch~+5*Kfus&-b|yT@^2dXlYZQTOM0|C*B$)YH=cDZfnh>Fds> z?~k`DQTDcjnU#sw*yMq4=!m6IWli+qfx0^V*~3zs;~DxS|LOU&9$Eq40VSP;0AH|)&foP-(TYr)w`!#da#RrOnsZ(#ccL(Z}gRT1Arry`8gJ(CE?a$9g*5 zV=Hi-kvcFoP)W!El$O0f%H=+v(of_i7x>v5duPdhv7)X-B7kQk@C?K{azE~vWuddg z#K~5(Vd_kpAk-B#WAdy}R}{ktFxfDN;WU|kNWJGSD|~|Y_HkxQpR+K7UZAY$U?U~v zWF&3D&GFmL1}kpUg<-rt8=qJuPDsN z&@jD{DA*<5t`!FBSv)(Uc+zDzYe^gONZc{}4n z2#39L(j@tE$qNDhv@|!5)&-uTt$of1xPyPR)}&+a1dP(r`mz-##rPR4EkYMa+dv6H zEwGP-lFK<~g*1-;$=RUFHX|li0Ij=OPqO(_)Z4J8dpjR+U`@Ef40N_=Ao#MHlu2oF z1^j0+iW$R6gq=!hd;fc0^jw2l?k;Vs*D&r?tSrMm5qkX}t#rXd8-RliqVA zN$;`Nt}dS2)paLa$gNRBw05?Hhq5CJoi_^DI_h7O>7%-t32SI$8)u{$_Wxjl7OO7kI9J;Q)STmf!9MRjFAAr;PEr4(02a# z3d3?ZaZmX*T)$eWxqD4hdt z57QlAa*6+Du!0WI4ynqKv8YC0_&{}b7Av*#-Td03h39E7)lrUyee1uJx}mky#QWqu&TQ6-nQKJbDzx<`0a*W`Q-lE`}5)UGKJ0`WUUI8)$a0@0h=Y(i8ks-rK1kC1gR2VV^n%lUNym>;%{XzRZ7Wcof(q zZYE>vxRsvX-BTGGQ*m~467$xC(fFfG4P_ zuEkm=#DH$AvGtR`>$MK=>sg^*{sw#|G*v^S}Slv zM2c=eeUE+6a8+;%?kBlQXs;U%4e%37qa9k#K+m#{iv{0R>bjl&pY*)ZGiRy1>1MwI z4&>NEwQ9c!)G~@nW&Hf{D_4$EKWgM{bRkPIIFAE?*Ys?mbEY#<-~if7d(jrrILssv zmi9U>U14EL-HnBw=bC6d$J&X9qrjr@ASnI}jkFf3ESc5}jOXuv$=?k{lVh@dXsx{P z#wj`MM$=8)hTLO8dsrLdTQshr?^_3W4Ue^=U6Z^}Z7145S75C>i@7hGwFNh*i|q@eOsX+F8R9U0zGci5_P7@=N|7KE& zPo}2_QF&8m-sb+M!OqkVl9ZBe3w<*;Gdbg@tvs6s`}lTSJF+rtxx0RU=zoHIM1QV+ z@KZnV$0{jdbrSgNWx}7oDmR@!e`BHC1e|JJm*uUfgW074>Ix372#_u2Np^#cR@B$j zzBa&bU@Gw$phwpimsCsdI%W;^^bASwqP@_+yWM?Ip?+;}R9YQS>oI(fgX*6WVg#lV zp=<&s*T$kQ_}AZtKa2RL7I@c*j&qTHRDU_*tb-rrbsrz&KSrZsdE<>zc{8{%?8Ygy zk3?UUXb;^qiV6N#|FNou(h%y+D`+jh#?SH|evQ`iG6+{c(>v|XWai}@WCs~6X^M4~ z$SVK?Dv5#~Dhzh;D$k_e05Xnx3&p?|N>R=p7K-}oP(Q%kr|>DL5p=Xu`#Nd6a~msi zEMr9==5a6>p_c z=$tTxhAG~hJ71x)Mx$)g;JK?AzD~Ux4(3m?U|r6qeT)YUDnY&ftLasyxcjq6>*WYd zy6_<=h>1VRtLFm$7kvhlDVNsMcAmzLxOGf|%Put&o#-7kCIWN#g35Qz5K|&7qLKjQ4YPkm55D-vJqdaOB=6fPOLot-Z9zauhSj# ztKNOE*6&!D1J--Mf86*Ac*hY-@)ceSIL_{d0z=DWkOX-Q6DPxB7M7HB{L-e13C|Ye=0LW=-pOaGKoryWXR;gYKgS=LWX?Y1+83q`2VVXj$GLONX%b zT6uI!+0%4OO-VWE5e1?*!9NxnP%Jlg8|K<(QpplRArN(a<>gh)XV{WiDY4W`igI*G zQJqPrngZXGAAV{Eyc^`?c!2CB2S9$OsuripFA3oZf@#7d08ZFKVMeP6y$Dkjw7@NR zGm_^VvkF?NgTONub-g!jehLlq57F3is40WY^@tezQN6p%e(LjKA2R&T9Vb8y;Y$F_SVkBbRe-?snP^q5a_T5{t0 zj0hH+)|Q&KASXl2A0-IINP|i%VpPN;jEH#fb`Ta#53keezP_f_$G2UYy)^QfurQ^S zM^B^ue8730nHpc#k5X;4%>Y!X>;NU85yYx1*=@$n7cX9vxP!^fgM);*I=G(JDZ8;Q zLU$(!9jwtt%%ld?+}T%ua`~o5`@E$Ahxf7fiw`YWp@gE*P5g!+55nFM_$BxYtte>) zV(UJmT7HH`^TB~CWtZc)p048-XAf^?sBnHkesbitd1tGSHC(ipMXyR`zJ0TbB3D=}5>JTH`)aas z=_P*2*+&nYZx|cIEM3ma%(t~_>}X&9)1-YW>~UBLCJMJe6$KDh zBS9tT0T~J+oarz9<)p)QB>j=k((>08cSb%DG_Kf0M^S=BE67Kq8A_)gSf$6B_wZxX zIC?Z&01MJhQ??)Qq1Z6Lm`0-rT^P3Y)wX7D7ep*Bm^h@5_w#pVs`Z6^QjhwR(0Ewy zsRoLwVMRDd=+_YzN{Mp)`TWf6^)OMEC%->?mKQH7&P`u;qUDocBp;e3o&V4>B{3!< zz*4)Fw<8$zp*3zsY^2fp!nWp}CNb^6F~W5ovGxd6zgP?qe7BypdqUzCwu^seP1~ib zOKV$SUEN2GQWRfUK2LKrr1>;G)JY@xNfk~Va6c{tV|$#!A*93t zow5z>F)#kMU}_sht)sEnT87>|Gz7;oZ0OLtL-1ocZ=t!Ia7GvK-ITlO70ffF!)S}; z(1W97^|uC}@3ePb;8#{&DBXiDd!^tT*Lg18=WbJs{t9FmO=u%*7}bO+X8#d>p>q^H zBSm+1I(Kz;vOIVF2tL5-G=3s3NCSj6HfdF>R7}2I#J$COpJ4Juz)6jkPoVU?Z|Vwm z=Gd48C8arIj+|x1bA0ojDMhr)x@SUGvRALyu6Xl1EABpvx?zqZJw3UN+N{JuuW95id11JBfDjO!KkxGFb*xG{$ zG^Pi;$#mbC)Te=xuRzK7!+*2llrec_rTJ3hSE4lPoY%C>ngxJn6!=U^d# z8KBP31{j&@IwqtHlVqhkuHd5~jsyI<;~i0t?BlJlNC&W~CmATg(=i(ZCNQB%0v^2-ebwj&)wgcnZ_Fve*NHsnx0Yw zj4Zj28*q9JB@g@1>>|lB(Ezch08?ySf>gpNmd55o7 zGdqM*HX}32&qp6RyDYbCb#lv&Iv=g`?ciW*S+rU`cx+g;z5M$aN3ncRV#+c1c%l2% zzv8QV2jqj)hkqdo#w(EknkPrW#uK?L@TVW#V|ce_<~h2pG4}|CK^dW1d$s@?Mc={V z+{tJ6VcDsp8hBZ2X&%c>s#^SHwe=BW0Lz(O@L+O2+lr{|O#VK9kbl4~@KyX04WO^l zKxg7?J#B2*@s>uGlYMDfZ52Wpn5SULB$b~ z4tpob$=|6iOUl}QA~vy0uFuHLo^`|)ogMkK*&=V^mm@WaEGjzh;f+4NG08E$NqYLd z|M8Zm*cR$_&?@Nj5V5=U*L@}D zye*x2WeuNT=fg-^y0e0JQd1IXQ`J7y`ok)OyhmXi_a^4T+NRkD)-SK9Ii8xBxuEK+ z2n!vYT+k#Z%A(&iqQpFZA@QF+8v0vC=8%b=c;DJJpaa z>;=#A7h$OCV>62)OA(Xp+gXws&1031od>tB#A+w`iS;jt!+VFH33pW91pWnvLPy{a z5&U=?urx@aZ5MracXsZU#?{GtZ)CEXZkqq;g&Qy!sAS?zQYXfUHCItB_XH$s)%n0E z;dXSQi*VU5(@!56J11%Ksq{oIyBrc76}V#wvw>$KBoi9~pQ^DX_;N;l1k%2K?u0M6 z-*0W{g-eufX-iLUo2R7KyozuuTy!J%E4a9DQCYd*yG!7^KJcAJ*v&Ky5q4^ia35sB zYgjrrLtb!TvE5mGFrA;vxiWkL*|lTrt=Ksy;>Q@j2w@CIkcAIy_e7EBIe97#ZbB59 zcd1_S?ZITp_h9FK(DLiyVGi#B?+y2~-WHr@SqD#zgtt}24=KZu_>Dra#Tuc#2gpL| z_1{$2SBc>E$dEU5%wqmlOUo@hvsJi=OOJ%>Z_)^t6j}mO7I!!J?&zYIwny6^vz29~ zzL|b|7i@#Il&;DND=CI7yJ=hCp)I&%WG{kG#oyiV`TBvqYWVe5u%7P0N_9;XOqU0) zJLVrCqRAuSvZ?WLfr1;uRnt#+D0g=;P}00=Rd!Cq+<04Bn$3Ru80axPY%aO}^urH7 zohD=$!7EJMroE4N@_;WnH6N9!kVn@14Uw@aNzq@OG~fxhiy`po1W|*u zq2?C(va$GOLhJzRa<^Ip#$xAp?xr9$Spx5+k@kG zN#)Mx)Xc$;oJk&5_aqQB4#DNa?YE-6;P4UcJsds)gu_9-Iy|gB48=ao)q=0xxD=?k z2#y;8ZJ6UmfOC!=*gJ4Dp`ppW#buZ$*B)q;YZ%u}zg^Iy;VKsCfo!f5Ort&EmV4&f zfx2gJtBbLtu7Q4$!+k_u_h<#&8hqtww*oG#cp(FxaW-CcURNde;ty2G)!ZDJ z*|Y^JE^dF$Fgzag;(zsRRbobtKob7Dnj4Z}jUZYkY=1E8-5H`VRuy@#91+Xx?R6p{ zad)POkqv--UYiX%3+*u?n*eKPg!b5g+`=L2RsJ$^3oP>v#c?aupiQ``HZZ~h#Q08u zmSSBn-ZSeUqLXLu&OA8Is5A3b2?))zVz#~we9YZF;a8{({8jLkcEQiX@VBb?!w$bY zYvP&jdv>vqj&d{jSM?%a9m(%*T4k$!VOQDRece7E_v(_Lh%Q>+5N*$$sw(ua>R0*V z)*Q*6IV$kX5qRJpJ$p3#z4~;lgW!E-PXQz4kkUMosuW@$Hu!!NGmWC!Q8Z!{MK*aQ zE!oarqpP;_O?=BXTFf`gxxAj1y@5S9^{>;_{MFa7@1{)Xg+dpRPixjegNF#YF!>`q zitQZOsU#ts!z>dcB>w>6e}rQP1GX#}rbf`f+Uh36Sf&?0R@z;)oAX2Ed26vlsw~uM zOWd%WrgYTWcc5lzQY5*8u4VJfE&LH)$9DyBE*gStbN`j;Bf+_6DJ7Ll? zx9M>c=2qYdF1{Pj2)F%lC)mtkm`C06SN{-Z;cS)HFZ~)8ef|!VdIhL6TTwl>D9mQ+&l9jeRx2yH=I}& zT@{iUVGo+%;}y32-G;Zk$|u&fWSfdN)Xnq>8VjOP@)^GZK{S2>%yzDP+ULQ0sD>E@JG(5yNL>CgBR`&RFM^#%k z5izx6@IOSp=R1Ou-!kJPmPu(X3q#hYWH{?HXL`y9vy+ka+1A=Rob};VDp!A-urak|$`o5ksaJFuxAkl;E|OJ_z&^mAxBtvE+WVs*nlyce(YwB}q1Ec|7hyT# zb^qUeE=AU?mG-G#mLZGkWy&t;Hkd&CG9sq||RMErEwXS3<q}f%6_` zUjZ*gtZ~JzK20>@_ae{sAUuoVOkji-B5-Gp770iZ1u}{Rp%RBZgW;%V45Y{vPSnWt z=^fJ^lrQc7xX|AE&c-*|+ApOhrW|$)@PX{YKb$(Lch<8a=dWXGGIZYbOf6;Kr8}ND zy~LA9To#o1>o=S0y#0~L)hWvH$fX7J+~>$EdYk;@q8EL16*Y9H$S}gJMINNdlXJyx zM#KT`m32iR8Y!3C0}P0++?9!?Ia41Fije*0dx8%4%FN#Iy~70p?J}Y34no(794a!k zH)*G4Q4J%qs1lSL3%xCqsvnU^ouR6#O^kC$yFKz58ODgo5() z1^pz(W&YZ6xfRmabXPsBiSFGaJ?2q9m{ZwJPsp{Ko|doe*(1nb)Ab@)i(k>}=Qo8` z@RDmIIOwDrGZVXBge3*&!EWoxr%&C>Fmynqe^3`G6_$FlE@&;HXiPQn)BDso+l^AS zD(W_)ZW-u!r_Z*dkB17Ebo9l_Dp6P7F-!%?^&Z+R@WhW{yGovM3XGBvMdqn}w*tvG zlHEO_iTE8Das}{qU8D07Gf{nigukDS?!2Xah0bV!uayKEh@2_1kTmX|SyPqi%Wun^F3LZr zQuXWdr^-_I){%Skqh>qJqBBWVO>Ucr3WhHq>^eaQ|Ma(O>+=^?RTShS0e0My#rLbsKxjF~%DDbzRHmqhYNjnpDD%%-~A7JE32*u#&2tIdeW{t{=CluiGbfFwx%PtEF3SbCy%bhk9^>Hfw!r!fc0>^PA@3RI(TkT zdiIR$eJx)Uq%X*^XVWDq^Nwtyxg~XTj4$)12jA<8xqOZWe>(Pqz@tU{P2Tw*zbpP>2UkUw zOtSLP^lCOAEd=xSWU*rR@b#T=k+{dk8zisYn|hO|(I!}0;umZ3N)r3(yJBmjqAohU zRUHGkmt*LizixE)OY^(8Qy1Ft-E;f z#~ru!c1e%B_kC%3o;Dx*zJ%_Z!6T&_K4345cb%(GD=Ryp1)#GdDU22T7RxU7d7Ey= zij}wogJ5$ohgNpHwsB3=Xr%~k_q*7<4x=V5Wjs3ALEeQu|Uo<^-kh1q^J_U518u-nZ?UIA#L1<#cCq!gdNCG4lNaIAZN(Nurusemu7w*}+EO}qr z9=UziEOkTdWtNS-X8q1qrsopX9$AdnkSrwy z=xMq7`jI&G#UqKhUP3DHovOZ;WDVXpu^4yE^G zLn_35GoFZkMD100IvH;eS-NWJGmF7 znQWd@f|q41UskjRl?qGDtCy}SSiWi*T7TpFRdSZES-x`R^77)GrO&O2oti;ze=*7f zQ>K{LuEBdm$b5veaxkdb*pTrcu5xhiA^eOg3+LImBB}H7YoXc656;g?eJD3;el~7> zQ}1`Yh2>6M%)`BZ;~QTVEPbYIdC4mClqs>3QOw`mb+l)k>Puzr>^K@7i&1|Q{^ZVv zUqLJH9(`E%x0=;7$cxuZ0dA1)FR%c-RMf#Ku5|43IB>NU9O*gNclV zFE$REdpvBS3HS}48EeKw>?)gt$TWU=hDcH*e%BWTy&erNiUE(t;r}GM&sIGqIy~mO8O>5MO)<6FZlrk%#dnmPat*^Dy!AG0oq_G(QTGd=D?+`93E8 zG1zjClYH_7SxBBFi^xl)2D?EokeA6%klFb!@=Nk#vYu=v_2dolRs+&Vc9UO|qvQzQ zG_eFPQg{_yehl3HKje?(WAYI>PX2@)PKC%M{+XP>n_!laezJ-Djr^5#K}tR&pOZSW z0&?**UJ|qt(yQ-S^VmE;F_lf_R-6?uWYh~MQQ!;g0| zwBbz{e;|K{Hrfv@fp7zPMSiIKnG!J>6mP;1vqZ(khku>CT^tXeS#A}_BY02F{|9a2 BXZHXA literal 0 HcmV?d00001 diff --git a/public/fonts/TitilliumText800wt.svg b/public/fonts/TitilliumText800wt.svg new file mode 100755 index 0000000..d5eaaea --- /dev/null +++ b/public/fonts/TitilliumText800wt.svg @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/TitilliumText800wt.ttf b/public/fonts/TitilliumText800wt.ttf new file mode 100755 index 0000000000000000000000000000000000000000..4fbc5aa0bb6887656ecf1e0c6ab5368dbaa2e627 GIT binary patch literal 18464 zcmb7s4M0@Kwg1fAdw16ra2HrsL}b?$2%(6uE`<1jB0)lsP(m#s#Hc|;BO)R(#2P{k zq0~@gG)9S!SV}FmmQv&2Qp+c=i!WLNRXmoz^hG3dHrK;*vGb1n+v-f$MfcSpSOBCl{F>*6IQO8Qgoe zWYIILs6?K|IdCABm5WN2C`*2bwsU3?B899fEnm~nwj+{|v;x$5gNU(FGJDL*Pxd}B zX8IRov<^22Ir@+1w+$cNHQb=B)gDAW9RVil2ko>6xqB(#R%}2KF3Dmft3g(tk*!=8vRN zc@-rZZQu7Eub_T1DU!~*`<3yeR_-RT+T|ok{yB+~Yk=b>vW^vz6wNQ`Hdf?rmJbrE zd=E*K3&;uCLGt8$vR(QC#<3X1kK}+J(SVmNKS#DRKeC05b9cx=IQJ*pG=Cx6(kFkH zFmVs`*su8|DZw#NoB zdiNxR)OI5vXb;mUJlqmoPtZ!hvenvZ)$%0#khWKnTmNV3rX zevCcoZbkD3DG~IP{+DEpEG)>q35BCHqr4-(Mq1GR&N2hIJIFfFym@4iP7%F4kL<&7 zhPIxp(=xIa_}GC<4`{TD7Pv2gN5eqVA^B&d3^eltt3$7-Wjuj=;`1J^#MyX=1@sY# zfLzE#L)Md@kzbKk@>_C%w39!OE5uD7q0g}Q*+-UO%S6jw>qKZNg4#{w=cw04_M_fG z@;13jbG-G&4%c&^bHC+2GTW``GX74lh0c z`Ar|H5o*Hop+XIOSrw=cC0WsEb))p7eSH1K7>xb_fu^4tBO;qa$o z{hH_2JzxF9suycXP5n<^BLDAzc(ls%TwOEBcf8*el1F|-{z)g&RrEQ!i@r<$MTeM< z1+j@No-Jlivt8^TY*4yKDw2L6y)8LqgB&5xlyl_e@=k>*7A05tp|VGLSNXffPZObu z*JNmlHP2|aYxZgWp>b-bX!Eo$Yn!z1YX7bs)Q!`{>oRoE=$A*gjQ*F8#^)ZN={^NM&-!fj+3Rz` z=eq9{-}$~j_HFn5z;B9Qs^3d~@B3XG6F(+r%&IZZk7*wB_Lz?i%rMcAVOVWwH2m4% zG)^@Z7@Ljn8UO9C_n+dQ=3n6dwExTghx{)Ej1R~R_+h}IfNOz4fdzpt2DSzM)8u2C zY|1sYnTCQ=f_@V8FY{#ckIerb8!@(E>?>pc6s!-n1SbS%2d@Zj3jW(T{kW8I&yQ;# z_m_~Mkd%;>A&nt_3h5tj8J{-(x$*Chzc`+Ujtjjv^uEy4(C0#TV+xp9J6NIeJxGw2 zO#Uq;vD5cyW%614Z#BwC)AvaXr{uSixUGoW`?MPBoW2h%`&qo*Xf=jgjn-6V;gjfg zUaWj?=vS%o2?3Yx#lO8+qXb-HHQJ4%sa2w_&g(j?uQZN-$e6URT&{5sY1>%d^WTQ3c0a)^z@5ZEV5Vt8VZIbgEn zn3^z+Cfc=%HX>4*AejO+wuzD22s(AL6e-y!5d&)3CeqEJyj!<(V|MZS^0=PUQPy-T zwQ8EGGb*aq#-9F1%(&2WW(stS*`vx{1`Amy?9qXPY0yQ#dKcb8e&6wpE;e(r8LNjV4#k0Alje&K}p zTZ{rTBaJs2Y!d_6C~BrsU{HL*)CgD+o)g3-JldVG&D#l{{{VEC%2ynn;(Wh zHhuj3uaEs^><8VvD7|+`Wu**`TSc9d`VB1Tw+z(GS&WWAh1Mq?ZfA!}BX;C>C=)QT2>eWdU?D~Wv8w-Ni^gaOvLqM{ zER-@z+=O#caK4H6u6df8%aw)vcf6X{^Y`d7WA%pil%xC5Im9xyp~r;nX(NF2^4C)PuH>x`0P8AyL#pXEMjs2-`%>7#f*iS9x{} zbX1pf3r$(RD6676`4@J(;nbnCUF%;TWYK5ntmP&3sRh{qI^7vZ$6MR~(J+9%7rOhT zKERAX-ySG_R6BvH`XM5gCI;E#9aAH%4r_dZW2)L&S?^xw$?3`V;)UIx<^O9=YH&|W z|Hu3?HDs(imvJD$p+q~{4rQ%Rvc*;Z=+sHGk8gKa`(F8@)oCq8Ep#dRjC1$P8jKhG zqByJ$3LPUfpUGxo8=)hXK$SJo2M6lv4CjtWZO+y73I5ab=e)E6z5_}I2?f4j6UjSr z+eCq^Y`=+Rwb!~a|IEkzrx#pIn;Sw|YhmS?X+H?F98@wc@S|}@yUz}U84ai6 zDvOSreSF|;VXhM~*D~la78;aLt)QBz6P z)!ln2q#u$DGIKWisX`-DD57tku29OUDg z&4NddZa?1B=^0z0`>fP~v4KiL4xqFgg;E~({g{3vFTTLf-Pkuv_Ky>FB@zidqkv}+ z){%R0$07@zB_>X`S&UO>(nO)Is0EW}gSw&^Mxfb_IgFqw^nL0xcWKe%ytj`td&Zmv zne+l>O@|sOsi^qTq59Rz!b7c<>r&Hxy#B=RY3YKR?6{QLvQ}sGyHyE}7Y<2#vhvFw zNL!Vc4SGdmK8A+rl}y1d2@b8$m=T6ac1wVPL7PWJ()fgA$^&#`U z>7nOobnBZ;FPA%8*1ou9FPp^nW5 z6CADV_u2@7eo`p4Ii}9U8a_hY#WrX^^(I<8XU=N8N$LtvzAIlP2|foS6%23`O@<=VY@o8{fmPEnIM(hEN0b5AyL1 zv9DeVr}HsGQM`=58PF3*3%Y3~HPRm1eS^j2@22JuT6<{MdW`*5*3AP$aEZm@Onl+H+;t$YqKc#Q{mr^&hmYR8=yw{b(S}}8tXj_H0J|qz9KXi&P zK!h9_qA1jos`eyt1o0bLAZ^XeD|~{dxXv(tews!tU)IBWskLK)Qpb1JZH$=*Bvd$75qv`KIFuy>=L?L&{1d-e`u00s2I=?s|ZM)C|%R^H}MmvFVKkW zV>4#z`q#Brt$#P}&E)Idc1j{{Es3DM3oz`~&@M?L)^GvNHo+&e`dk zn^jx|Jb%Cw)Ku4Eu^wAZjnW!dCG&NC&T5sqUS8kBUlj{0Rr?q9fy}M?H*1T!iRUQL(lBvM+S#z+``N0b2UQ;kJZ;44@tI1`}#4z zQ?9A8lrEzc;I8~ozcGKd(oWaWQ%u%SN@H%~b<8sk;E#1xSp1NhQ?3J7uCR;&R^Vz@ z>Rf+d4-BmpxFI4%H=@4RK4`cqxCQr<-KDhG1BV9si>1*4EoY?XSjWY}?<#fOu7Hnv zUhA2&MBaR}UjYYlY^7SY-$ZI1MWu3n{=}6l$EZIw@iw}Er5ar)fWRvTw!k&hl_YQg z?WKKai)b8X5(rECoR_Y!aHa0X0`GH844z}{#KTcwQFss(Ut=S!g(^#-H3Q@MyI=6P z!_efo>=;@rFSv194!_ZK6SpDHSkNBUhWIZU*U)!u1H6XE+0d>@UZA!UZJ;Z#)|^y! zK`$b9H_4J zetaJPj5giG{3fnjfU7U`1EDrSZiubPpbfAFz%DXcgV?bUe)b9ry54v8EFUypfVUC- zZ+ec0f-$b}Q>Cs`Qpb79!ztiVQUpEFtu&E|xDcWb?P(U;Mj19>pl2dgPXlV$EFJXc zYr6~IJn=f8nRY58BbdsYJM*{nHw|{Cy_c+%c3bJ|d08o$KW*hXG{o1h+t!htY0umJ z`@{be>?`_n_k*AMfj?GB39FO9-yjqI>{Yqx{P`OT%J^+LmkX64OCZfa7CbO zwM=pt?XM9{@vs0g9`O)hojQ!gj$c~ zd!5wqq!1%8l?Y`MFu67kb-}*@c6_bkKefWUPI7({)kh7NBhNYcF<$rKasFd8Dv>wc zD3iB<8^dp$M*ArAwI1!En?^Cg|LPxB)i4@LeRw6U<=6N*-ovladR`9U>SqR*!H{F-sE<$#Y=IQ*>S1B1zYg^SJ$(wFf|@`_ z2X(BIcDS~)V&_s;3}Rk)R#?wpm+D|Piat`@GK*HYpgR@rJWN##b`74po8jx!d*ERHBrDeC0@}xT@Sqah`@foA zWs0XitF%Fm)MN-Bf`XX%O1hp4{9kl6C{rPApzS=J9rfs#M7Kj~CVJ6lB8HMEl{mNP zVX2@g;?J9;K#f&Aqly;(2fg}TuGd)K>iiv^!|nqA_Q_`G?|V?gIDwkAu}ag_G0m7Z%SWU6Acp>oKjQ1Nw#KB_3mh5Q4t=Ckc7um7lQcfa zXwX=N_<(DLe?E+ZF^E-mcAVjTv4_&<_HEQOKJ|EE)QX7{m&@jU-ph|(90Mvh@ud5l zKi}H1d!wIL>)H*rfE0KNXWfAyY2wf@J$ov_{m|Kq_|z&n9hlArKez;O-_6c}1&qa?^Hg`$n@+Tit8itDE(w&%9f8q|IjW?o#M*Fa2-RNyC`!=dH z5q%s6&i<-}A%F^N4dxtdH?4I7tRZz~m@U2I{%LaG?|P5X4!WNjT^rf5r)cAX(vreM zqhL4u1pioQK(X97?3io2StUy-g+SExRa8_ppJj_@ zrN&X66z%MiqC1mMHwC>TKltPfcsIz&@jzK82SR?QsuripFNqO}f@vZm0Z!OL;U=31 zy$Dkjw7@NRGm`flvkF?NgTONueZ4pR;ZzzP5V(c*{C8Bb#X=LeL?1gH7ZsdQKX`yU zJC0_Q)m+Z$EX>O-T9A{)17B>*Ts1SMI520zgo0D;tv*_<=Fqf9kMGc>jEfE3(01V0 z^tf+IdP>rU%t#iO-j;xsC5yYx1Iqaq_7cX9vxRc4vgM);* zJGg)V(UJoT7H(s@WFv9Ww-N$fv)3LR}XE3vKM26{-JmvJdZ_-V59=p}y1)khDWZx|cQtX;0l%&)a->}X&Rf`^%&HM`1 zHh6b%F!WTWW1K&4Xx+Vi>z=mlLf`NV#HY+2eG>p(E)av#0iPNJMEu1VWLDMA_P&i3 zCpu1DTU^j3Mx9hqyL1W9Q1&Ng4?y7@zZAf;C%1`_BgBr z6NOu#iUJ6$k)RR`fD8o@!3>xFa>{8xn(@%5=>_XbI-?#B9#>+fqbR|m73{0g3}w*w zY|^96d--u{8a2M_y@SM)cV3c zsYm@uXgsX%)W-m>n9hJN~2aznj{3zp7C!wj+tGb?pqfum{7G1q{DzAq6)%3fo&4<`QaHy zFZ2K9Pol{YX&PdUR78iA9@HDQW7N8muw!iJx5u~nG%J!nmUMb|pb)HA}d)kzszd{*C6WRzHMm1qd z*nfmy=o&@ON->?CuHBuTEZ(f?~guU&R!h$UT9u+$h%R8 zcH!RidA1|t*R2f?-=OwOck)tJuUr!PNUY~{=T%;+T|bDYl=$;LR)JVGa0-~JvSFec zsTA0Ot-Y8)V|uZhO!tpTdkQG|36%Wa|2Hd19g|;PRvVuWZ2to-f3H=uH*4ea<*$6MYi&H^^VhR<_qdP#9e7-~ zfDaYuj|Y7M{QF=>>Xb4u_tX?2(imDyLm-0*1}jPy2_WyZS0|NjAFk3O*X*Jjky*-xBr6e%=a;bbw4DDL@IHj>Qx> zfeB3#h-Jgz)h3A+Y3gJaDbiC2C#hC|8RmePOH>Xrt5Yd0kh>T29&3I<-hsxfbl#Zw z>-+E5^pqiBWX*dhx3Ki7=mq(|YfIW?=hvH(LSsb5#>C)>FUY56htRX>`Ho<}&{eNg zSI^kMJN&eo*`buO8ClW(zJ{>b<$2|+Qd)M_`D$HnhJ@J4W7O&)W5cT*72n4=O5{Tl zQ;vJa3*E1NORnx4kPlH`{<$a^uS5cAz8no3Pvo+|pZ;)<;oVx8_vo?4JR=kaWu$8D z*#l`beG7|oC!gJiWv7m6;AO3)`7AHFYS9zbwuelCEO&O{{V4@(8=|%|`Mdmn{vNx) zSMp0VkiJ5LTuHMHw6S658yZGvgl_m$l9_6(}a9zMa&hmo}OWCd@hrX>2kH$FePRs?hO|uVfSXNnc zA}uLve$`hI(s@SAC9BCP+BpGsKvrUUs{J~K1s*sm?R%|UO*ou%1+Q(sMj#p?wv~b7pyo$$3r=izj zn+xt#L$FERHHeOtx=VX;uu6Q$BPZ+O`6#o#ZdpzhDmU9eyUuIu_gF&CPO6B zzW$zsFSy@-ZP|rOlx}Uy$Y`6Vq}9BPa4TGN6ZbE?xL{#WK6lWWj4#I=4VxaA0xW*?cgAf0BD;_yn@+z}Q={b56vMF@6!k7>*zdAK2lIBF}U2 zG#b)`C^GL-z2YwilO?}Hod-b6uZM>@ybHY7Jk$E6;55rVbb2JbZ7P098IHtn6oM_b zNbOxf7E#@QQ+?lh1h+?qyrE+j@i$spZsD1u!bMzqB-{YAM!2NV5|Fa^JHdCy6u+<| z#__1VJUi|6j4yY=HrmSQ%G~hM63DWLwuN5Wf=fpBBKTB%?}X1c4D3_GueXBrbT3w_ zYocJfyl_1+|3DE<9toFCO^6Q?+!&#ne!@e!vx|Y!=9MdRawF#^*wfSPjxUda9>>Gx z((6w>_~29NLWU8%()1t(Bz7u5LaY*OHLRwd0`J-=m2i9ZHM&i{f*`q%>l&-Q(RKhD z8p#F`0pIlrukDqqTveOWj9|9Tj zNYKdk;P~BAh3gqLbMPZqvX|Ap2?UK(aQSfiZD=nzd_;RMhmQc^bW&Z1m$iqXIEJ}e z@U;h*LKPRmaU-A&bKD4UuCW9A25u%aG8P|8lk402fxgkOA*F8?U;qtCD;12dd<1 zZjMZHBW}*@+CmikW-_85^(fVDG1du&8*;jry0e-XI_mUWxrxRq+qCf-yV z7-1n|e5XN6u`ZbInspG-$#ZvR9-L>@nfa;&gyv~6Ti*sg=I*ZWD^&*mD)>sf;OAlZ z+f@8vhu@hs@y_>MyI4R+c^LewdXcY=yn?0Dc;Z!?;C*FJfg|OR(tMJp6k#7W_D|hhCeCu{v!neqIyq=c7hCMg+uhLcg-pfI#7YL|_L4wk#N@M$(|#>L$ckrk6Zg)?KxS^TQSS zYq3MBJj`ZK+PI9ScGTK=?c^pJu#5guB)NjGk=TiyV{d^aU%2}GB0+Ov2V}6usDzU`DU1s;OIMG z3VZT)n6%tudfbG$4S0f!@5D3GV}INZHfz}UxE=D|k$mf+L7_?maL-+!4|C6LSjWOR zxE=C`Bl(2^bNIlj{t#gu*s~rt7$ji32fUdcxW3MERX2}J_zVx85g54Gt10qCu&%)m zFl%jAqati#Snwic$+9Y+d3qhcN{#%=Rs5&D|DlIB*Hl%y1}=6hb)DRHO_(c$(*5qs ziWM>BR9Fv)nF_N?Y}oPBiQvTqtw`6~B1L#j-PNVW*JeuCcqICSuSj`D_3u0P&3wQR z5g6hFCzi!jg=R%Mf+zUu!k4|>@P@8pVqHs)xnyJAOyBTvS-~me>-TJVTu$kFZNuig z$Hr;K==2)B)<>@kob-@k%2=yuyg9_M`SoaG1>U*x{&XJ zfj^8_yNXxB{{b&77ZbsCF#bW$_-{s!p1HMnq`sc@Es&J@ZDpnK5a~yA$ImSGCK8thXZ`y1<~pAMBy#nNaw2L;A^qeto9`a+iM8Y^OzZCaJ2)V-r!q@D+nyC+Xmy{&sCc!NRJ_!U80~ zu06ti(a}|G2)>RjVF6S}88te8zP)YF*6q7n8|2-dps05|m?tqFvE$l22-+7MWo-)!nw(!)d}Eegs_YCPelZyPBjd*QXby zkn`vNdEo+2#});NtaC?82jxSsqC-g}{4TLI9kFHMcxk4|ybTiE>t(#+dkvHA{PFL*ZPiV-;W8VupR?J`L zo&WLgVwaAch?WY?2VG+mUwosMMnB>FDYCSXsb=VR4n7YcX3)tSA|II{R*lxcix-h4 zuJ5~lWmM@T8y`)t=J3%%Fu$BERvccwz8x+S_tMlJDv(4>Y^g zUwcA=0CzKIeTxSBu=m2I?rj;bt{)zMNNl+X7~c4$=7Nj~ET(aJL19$MMCBK7cc&}oWJX^nk`&!s~n_=sPAma$%?54dU5`CVHB<6%k9_voFsNSo{ zI);0!yMc_3q$H*9cc+&WpL1d>%;nld-zw6WmK67Q;8DYoCM zyJKG3=rQD&casbkR-8oaShK>kcKFLa>ds!_bz@_LT_^`ZN|v3$V{&OTZJh5)Os9eA zFdngiQi^w3*vE97myne9$UEgW@IBJZ!%;FsPCVI+Tl`DOE=4c-L+^^L&zF^Juh${5 zmp`1kbDq+8Q(=MSupZpUe@qDI}XT9fmN04-T&l%=q z(0eWsBei+YWn!jFyypsbgnNFm0x1&`M2BG-h=G~Cb&N#A5Ar++TxVoLGcA7V-$rD^PzK?oY<`92{4n=4#wo zN{aE+1E~o2EqEgO5w%z1>16zZ$dZ*yRxet!q|mZ#r6qpKlqAdIN=sVl$~Bpb7F!-! zQ&G6Abh2emDSj+t+0x=Qs8m#HS+!(k;j)!W(K;7^)}XAwcNx$q!JQ=_*cv32rvgQi zyKK#}6)Toil;kdXW=-5w+__I3kAYg@wU+Hl=~mfO?x0O`{5ki`ljA3U+(O7Tr9)A&sPawju8mbT2ut%Kpa8% zI9!wYOIDXJD_v=sG9_*@3hsPU*D>C%)luHwaSS>Zqy8o!-f z_y8t$E=ea3;+I$+!i3Mm#6OH_{w}8Z5s>72WIp*mCjL>_a*vS$@;F&Qo*)a!3#10S zK`)RO$xo2k`7iQI@?)}rY$5gJHSwzkq>=0)zb41XQT)=xV*HT8%i!|knArazeo5|nEUr86FpmFRMv8 z7<&zV4QDMF`&mfVI{fm*5AaJCKP6S*O8cc;xIdn>ZfD@8tY{i3v?n literal 0 HcmV?d00001 diff --git a/public/fonts/TitilliumText800wt.woff b/public/fonts/TitilliumText800wt.woff new file mode 100755 index 0000000000000000000000000000000000000000..7c6a6caaada9738968eaa8b61d2ac50f5333f66e GIT binary patch literal 11920 zcmY*i@m}|3gwzUE#~l<%=c!59)EaYD#L%Y+zvE zC13j2H!xu8h-`wft)T-L807sIZ~ujHEky9|#%?a8U|`TDUp7$x1950Hb3^AZJ0_bi z9rizbeu6=o+jyFRfx+y9fl;=Af$_;#68_AvFg5)0184cNVgCZxzg>9_i!btv`)@wd zFHjpx&A0pM*7J-*_Chy0%}DL5pU zo1LMpDHs?-&KIBfl{*2nX%MD^z4O<AzlArePH2vGty$BU?!GUm;@L<-4F^39#REW%O3i-%kpgWNZk`g)YIw#RUgk zAbk6u`D~MvEHFfHM?jN4T?kZAbX3q3DORPj$Re@{)OG@aa9<)j3~WQt$7NT1NG$;lyeK%`c%G^Y za84%XJ}H>LS!8}m>@NcDoAM|r60@L;6bU@ngtfI{_bG2RV!UGaf76daLwUiXxZ-Jf z2KK)R1MA4^FB36Wdbj85&SwU>Yp%0fP~1&0ERWbE58#mHLW!$rElI{M!m^h9G}EbJ z4p0TWJZSLtDdV#`WI#AFgnuU~M&768@HmOaVzvotrGs3V%`P|>O_B(W>!bumKCoB( z!|PT&K?E6W`3cR?fJrtO1q7L! zZWntBDRiGT%Jy>Xn~elz25eRt0z_I;X52X({5(UtX4i@Q@6lc)ObI+Kcp4SpcY+qF zthS~qPdJv9{7Y>Q#p_e8M{qGWZ&cg9F5Ksyn8o~4N-?g*7>22D)ULOxmw)kIKgUWR z5oIU4w`13Y<8y|{ms~H4_APYF^U=I4*^8yd5%_$HAtznri2usor+tFiD>Nkhx1WGO zvj89-j3f-|cZhw~pyzLh3<1sf!4L@}qskNY8HSugykW738@O&P=Vl%=*ZHg&4M8Wk z3q;T|&{UzEQL>+(kV_0K-;6Zj)!PCM5tO%>!XObz@PZ3YDS@XSLLYsfpS_>nA6FlJ zcb{>e8=v+ceJB2d{@Hz3pW9w6p9A**pGR}iEiovdiE#jfnF$2C{4sohzKNl!@zKuy z-r?@SUmR3SbZj&%jP!(*q_o7;{-J!rD!Xv{WA;d?-M8!qMMk@hYf%T*8g+VO3Aq_5o$UUq8ZVcd9AV>jVT3SYCJ|?B@OWmmL7f~; z5rKv6)y4~EsOGP6sfYw^U_+=dvet5^l?3?NryJ{d+TO2TxUF`Oa5!MBU|@TmLSSHD zciq>q`}Tj2D3~T#1lTq>Ik*G3A9w-yAow2m3j{0#HUv2Y8-x*r8$ZwsEuG7L2g8;mTB1&jww223N&I?Nk@ z1)vE?02BcR0jq!~SbSJESb10=tOINaY!++0uUhqp#otK5eAVKksnbP(F-vJu^RCh@d1eiNdqYgsU2w&nFU!KIR<$Y z`4oi>MHR&XB><%ar5|Mn6#|tURTk9=H4k+b^$m>!O&6^MZ5VAI9Uh$pT@qav-3>hf zy%+r)gAhX=BM74x;~ojhgBI}UpfhY2SFXCIduR~I)4 zcNz~Kj}(s!PZ`e!uLy4$A0A&6KLEcSf1UuFK$O6aAdg_0;F^$>P?FG(aFpkvNebQQ3d@XR0@fuKG&qC*NZaH+vk*v;nm=>L^-S2zj7m26{0qx+pBV>@PW3 zvgHCYe9912ImU_GrV!Qf8T=ZuVXCy!l>C+ye4#LH*$>m9Ph9i3fn@>fkW5)##_{?{EcU_KubmsrRYP>yWZ1&(8${5d0gajv1G$JUQe5%=qL8VX2jR#ZGdVm>gDM_ZKDP5gjf;879z+v z%1D{{oO$^FM%#T)vOB{UXk(e;&*!&|8L!j_ZF$&|-;)(DyAPiKuBJb~AjerMA$^Vn z6ixCP5J+dADF2GxjPFc<-dapZp(T;1VMLW5>=6wi#T`PDXM-FjxPKU-W<#ka%?jSb zNRwdFfEy=xH6n`nVV95kmzstK?3j7y-FI<~q?HNrGZ}EDhvRlNZ{bNoRACuJ3$pYI zLk@%__t|m^cV^RB&ri-;?=*{jbYS?Rq(jDBfujqG>yk76(VvJ_N_RNkw~;V- zHNH*cwk6vi8^hGHBvpU#bh$YaoY~6V7-5sF=2_QNyFXJKxAI4nd!=F`O=K9T5bhjF zn6Rz65bpf2&WS>P9X0fzf|&=LO;#o)m4{1dr0E68NcFxG)u;VAJ0WP! z;+l2e6`>85^>DezBr3+R?}NVUulSuBE6?wQKLmq8ii*2$^PSBn^+5&=n17yR^qS%t z!L>&^j`j^!WhW?gcqB-q1&k0*@v;d4wHT(Si_G(`jcuYT*>Bh7ROvB?pxVbZNIXCE zM|L!U>TQ!e{*>0w$L!e81&%n56(vt`l=&F(ZFnrA3LNmU@ZXva0G_{k6NFspjDiC# zG3*RPJjVk6fJsdj@3SHMk%o_ao#1|)^r1Kiwp8X7bzrd#A&SqrAE(A?~mf6bGLDJ z=w6!U?)>x$yZ<_MqDI{oWk-DEG7QR2NJz^wLmi*+UtPEk>h3KsHu9D|ji-P0N1%e{)N=gOQcARa z>|TkkD|C#8Vse-&nDXLdhkeR`f5FOAQ%4DFgssdz9J9#m7?yn>k~s=~11BS#!8GN$ zjM2BLGqLFUz*Z4vh*=qKFyny|JoKZ(B+{j0-(bqWp`~?t1tvETIsVFeQ4Rz$TT0@d zx@(?QZhdayg>pC^2?OI7CL?R>b+cT!g;J)EF3+xD5e{6>TKqSg{;& zr4cxLi@9P1Ln34(d02rp%f*FvTWL()W89s7Ad@ub|CzKqMZ2Ao*duWG!(H_Fpe7yQ z+tsaVV`y#Y=H_CiIQn33f>p=#o5Q+=A~H7_exEF!KdY)XRSE7!6#cgTc~sh-S_U!>bL2iND)P;xbUK;plstY(?Saw2uzUG*N=3EjL zvGvyh3jGLdebNA{7O{_?eXwsA_ZLtB|2xa5;mN+da?I^p!^;<)vVH>YW$QaY8xlYq zBLW^+=%VH>b*{uL(a+ngjLBG9mmM~hAOwX43^2s)6xq97@5hH|5qM>AWNy$@YcY;f zZ$jJ?|K1R-S+&cK-Dn8QHpcFIPp0|A?r{M+==@^~EG0fEV9s_aILNwLr|;$xW-m>Nim|4o?#Iq5CM9XNtH!bBo`!pZ7qR|!&O!vP;~uCh^|*8q8NL2) ztSx(M>AIa(Oc}lW@9>DWAvfG{FZGfA+|0{F+NhaTqAC-aHM*d3YmakD6X8P08JxUH zv0C#N-p2NiAJ2-LXEH0{IbiW(oQq;^5q1OlLpzx732}(WN31%H0)&U&^^KDOgG__k z!cy`R8_g6v(zQD7Ce=;WjrIaOe1gY%xvf>H z6XVBtiNp)kGb7_oT5qj&K~OJ(R4q<{C{cmv`#y#Q;mlQ$w_m zAY7WQTDY=^R7yBR6ENrFHL?4rVanl}zMO}8tJ~wqu&mw$N^_TjxMRiFv=In?go9%} z&%#b<|HgrUx<`&gbud(RiWN9h5?YMI9~w8ti#ZQO9ZsPo@yR|0Rk}y7M4lE-1UjG) z=6|v^Bd5V-Rg*f`cO}2jaaE23)_ym}B5VzU9mzb74AxD!iU}?NhL}<6)@U!Xc6DYh z$X11?o;wG)P=?uf*ZmL1;aGw~-9*78+moD# zu}Nlcg>F?M=xc}BZirvN$2T84(=LJV(?b}eFl$n?V2=f&hEVOoy+~_3!txV@A$TD+ zM6L5`8%S09a$-U?B88|84PURB-(R^Tb?(SKaoGf;cTSk2m%X=Sy+-H#h-rt!cBLG| zW@c*I`0e-d2TK(Aqz1yoWg4QnhbJuI!37$w91qiKQe(aG4wz~OWJ-alMAD|foKz?b zHplEWfJOzy;}z&cvC`UJ(cc^AF;Ghbvy0|B&zkKS-=Vb4DDx9txySJ%o&w(Saj+SX zd)7_Z4fRawp%XF4?l-Z}UACMr33FL=`|T)R>>cvLii~v&%jJB^M=n(g(E9)N!8rn@ z?a;9APDOig=N86iCG(hosOE&-3&OaqQBtuk8_K(9?{)L3zseUDf<@Lj6WYA1O^rzZ zZBcfZ{D!GJG@~|us}433lP<9Py`7u7J8AoR(eR0gy#GFg`?7#LCMn`V=h~u=e*9P~ z%UE2@4PSzt^2_bCu^DFtH^cu9F;3qw&1P5b8cCgFaj};}(Y}E02J}5=RYg~ovG+ia zlZT(5t~Ydr{Y{|Y8VsgS(MFxO8}_W>z5wT5sfk6jeBAt1ist7S-G{Z)-q5K2K-iXR z(PJ?!$}uzFwD$>|wtHjz2P`vvn%g#Qs#`I)6sr{aNyD=WKb+X zQfQ-Q`;3s?my7o8>g#>2?I16gK>(c)S(f}9 zz_m4C^)**-?9C@=|v2AZ_j$VR3JhqU`LrI%4PSuTto zGE}O~#P)8{Xensh<~O_uE7deG4@NI_Jzqt2$LRNMhTMiZ#XC=7YHI}lUNqM1#>B)n z`YhGMde@_wsjkC|q|>pXL9utS@q2;muyj(>&BCd%!YmUlc$QS3eFIA>$?R);SAIu~ zH>Pb${D~VwTeX~kuxw|wL0%o!t`Q+n^BQ=NbQGJ2F^d#Fuv0}dV;6WBl(aXP_nhQH ziA>Ge0}ZgP2#X%UBoyu5v`jTxTU9#Z@gE2^ouf zL4;WhNSbbj>R}YPy^jK4t}{_-DoLEg?VIoz`SU(PbYiB6ak6891A~U$H9yJI-l=6y z6Z!FI@k52@-LNnD_>96bzEn8mPd7oBKgkbFV&u!MIhyHV3FvZedBVc&%kBI5tcf+q z&<>t#_(t|$&m+?@M?Xg~Gn;T2$Az|*&qG7DGc$`?1y{2-8r<-gGi9CGq~Wc((= z(c^ae6wPdd#hJgH>vojtbXRI#&}ps`=?jgodn3{0|ImNA8i|ssZK%sVL3 zcGf-fn78sWlf*%7=Jx`})B;a=9&@c<*ojujbPOx+;T@{8bFSzh2>>y_S@s?u$!m~d z5>FR6jp26D_bJU;4ntFUhrm$T`>({L^e0Q3p?f$|7&fKm&bz0Yl+NEg$lO>&dyCEz zi7Y~UdA|WvmsuqwYG}*q9G~Ly-tNBF`xd07Sj@5seH01a-}haH(RNF8d>e6zFECRmzdE_xRW^>)SO1EYU3+ydv~W&sBk>(x z&B$?gPsTTBZhs=@mlD3ids5~CihrO{wji=>dy6PtVx2#;5W6=Zjdq5*ugNPl3>)jH z%wA~eV}Lm+z6M1D770Z!Lg_uj(g-kMe;}G;-V*dpjHgC(!(9MT!@B9$g7Oci(^^!R=SMvrIhAy9xqFU2CHC3 zfLFA8X_;}a)){W)bbqU zju10aA>N*2w+0_Yu?6>u+ zP5xv0MHIyUon{mf@o60fMmi5f?UJ+jE9P7mb#fDKar1EUiOKD9>Sm)7@=cbNRwDx&Pd;U3L;Ijr7Y%(+Q)JMwfbK3|}H z+3#)pVuPIAjrQNHptdOfzFhZ*@WxPYRkOGrPebq@lM-Up+WFfiSqXG*pCmi(NpeNmfKQU2bt{ThL_pvr1+)OVbqNXoCWd1 z92%G>HzjLZhOBIH3g}=wSZ4vfGvX1Q+9`vnlQ~>i?0X?86(Pa zB7R588u2&ypd!3UC^?quBFaxx3*P#;^imVS{e*sLW(?9UiuEXq?X=1l&_S9S zlSGIe6UlhVduFQ$A6`)4z-=KmL!ANa?Vq#-O>+|`9#2mM&45Zq*>`*AHQhKQ^AlG6 z%P`>5rgs)`Drqh;UO7=h4SDF846bW`g8h@naMs^d`i}Uz$epM03$;4*wRupM##>JHeP! zz#2LZK&yjp1j5n+lBo6I;E33ATE2Md(m>!kz^WZnqU}I1OHH$ps+068c6#_-(W{4w zl_QMN#tp#y5$NLO3Y#N0;S7Byn(zOs(`y8Iy+*A{BOD?DD|2pC*mw1`akKF#dE;>j zy3)5UJY;pk=;=1Wo4iu*;4|ozHqA?%{Beul+$4UlDtxq*7`7z8kwz$#W;@v~etw&Tq;j(5HgGsP?-jGL7QWp;^Jp3k*lkja{0KXJ39(q7<)t^cAC zHBS`+iS#s$_pX4Z45$!g*8LB3XR1B~dpDFw@9>hBh28pNmTXdztFnepOY8=ncyp8& z&ys&!ES#)>UMYh_=lX!tGX$_wWA?^FI4R|A>9nz=`lsRu6|yW6UdLLMS1#+Ciq4?z zJd+oXY^rpT@h$NhUPZJ*+!EEvZuTc0>DJY^S?eRmys?mp`3)oDl|ZmSpw^y)2I7SlUTt8bg|4xXt`231I?=quVsmVB z{9A>smaofL6Bg(DugJ`^%F8n8D=jlQ)#M&a5P3Bu+mi+eB4?aT7Kbw<^LHZEFFa(-WVfB^}OiJXQYNV|Uy2Mvm1&d8k= zGcGtwZ(mP(9EOGlFgAL;D-t)fwHhxYD`XZ`KfdL_7!LEBV4MFgENI~e zha!J)yPZaNGRYb>>;C@9jA6xXLaKyHsazWHlHpHGq2sNL!OZp%%SNPR+GmjEHzAsS zH}&;UUW5MW@h537#}dJTNLBpd`swISNJvP)aH#8iAwgz|8SJf4w*y5oQMaaL^!EVo z;T(p$@hzhLHoztNMjW^a8XX>c>`O&Er;OZ835}Jms)fAEY%kJqq~KrF8WZ&Qlzhg9 zKULcetKu=^{Wv|K_L}=assMr9lapNQgT<`;S+suaEz#Ie9E9ccRQA5E5WgdlKDCBU zJaSzic)Hj#8LPq2Vh6!gjF9xEGIp+XImv-;reAQD>+Uw+qSW*AO^}XKf)>j8Z9aM3 zzd3bS%fOY7T;$u@r{y6Nl@)e}5aWTPIWdB1kt@@Y>b6-5Edg`0g^h_5Jo{2^lpLUY z#Sv)-97i9Zro8b~qY@VzR8-f}1}e#(I)MSnu9*C2NK>DZLb`EJB8j4V8DLA!*_Xjc}c>>n=VNfdsv*2S1Jz!nHr4hv+ihg;8p8nGYatdXuQk&#TSQ@0vh zIG>V&U$L~XW|m(b*L;@TbEPgvuI_&Kbg(;C;?+6s^@@L%L_1zz0Xi~jd#5SP9+1V; z1fFfAhr98L7C(G)Twg3tJN*JKWD`yHJZ3*2Vk zw9f^cdhTQZSdeE#{xIBAt-io-Nj!3hvTiXR%)`)nXL8Mkf`H)HeDgR_UILem zPd&1wXi&yBbEjSwLZI7fQPl2ghL(Tb{bXGWt}|VjxVTr*mf8rS!-_}Vk0Qg5v=AHh zeMAX1d&0ZQ1dGYdRZA~5yBE6jbyw7rpX{ni{S%%35v-)2v)N#u-jdaBSTf`Ob_Z%L zS+;z7&dLgG*xEfDx;nXQNiFg&^)E02&(eS22oz%=nU~5EgQ$Mz#uh)@o9YcnRbm zKjl=%Dc*P1hQz>uVyP>%+C$-Ct6^s3qiIsXq)vdJtno1HuH-;KrRX^C- zjrwBvWv}0y6CV_hf|*INIuOrJ{16)~J38BS;S5BX_3F*6QuK+H7o7yVv4YCC#2kPP+8Ox4P0+>t6E-pu}GD|5li0Fv(Z zoxYV?i~#J&D$s}MLBP{3*gxS(-r=xL-?j#U#qgW8X@`)NF`3W3jQ3g^Sd|L>OPjE* z1k$-VhNNKIfS+_`$F}>*FNVoE#3|0m&>YivC_c)+#vfwg9n?+SE^RHs6c9iF7GL?SIq^{86%^hREjIbdan1`ZEtGn*BCuZq^cKRkbkhDU~ z!!)A|Z_b`{0rx!TmF0;Rc5$;u0FuCwmch1}KB^^b>fSuwADV=V0ri<^|qzE+pv;qO5gp zN)i8gc+a%Xhz)7V@qQYaVv!tOW-kYQ|Hq}@H0|#f({gq%m?UyDwK9CtBUyI1P-_z%a?@>w4VVzaLnk&zK6gNca&kwMJMTx%%K376AbR zuXm%(y8JPPH;2(tKR>-3P*T?|`<78X z-|Fa=O$=+e-=*Xyud(2tnXZ|-1qt_+QZ6J}&bxTBMZ#;7pS#hy{heKeQg8a@`fiSnH@(WOPtUM6ti_^ua7w^;{gmyDC zw^Wp=;5WMv@T1?$rhB@UVf^&j!q@8|>U`)TAG@q>!qIdnETyHVi?pr8F7`lT{kDH2 zxFKCAC;{clllxd4%{LYKZR@)%f<5vX?GXtqpESt7^;?tg`a0KG{mZs;|*PC0r)h{J*F3A^KIr2wWy9CGj zRu)|VDcG@PZVty6oX|Mo@<4OdFGACYnAb@VqS*Px0i=ZUzB*iNirndk(;M6TIQ)&J zGxz12&F#X~U#IX*iQ5y1GcIfj*imPdd`?V?pft0HaL?{DyG(WVj3s?s2c($!hP}CY z11g0oBQrB!H9)vUr^(S{>*mDW*i?3x`~tV%jaC9#;4p{%G;<8SzRkua%k``CqOq^O z_sw2>r~UQ@m0;oKV`-V^sZZ7uXIU^7hir9X_LBfN%*P}5`OM?Bp^+NCPi;VIsy7>u zB{*-q5K_n!_Zx~_(9Z&uTTA=KRYUlviWY%?(}da~)|AFO759_PIQP zDSx+MS|QaNv~PQx?=~3ynd0A}iYCrRR1K*5HgfG>g>TRi6+Oq-dA6JiOeEiq1X% zPL3Ac=|kO5NM!HA)*a{lD~0^y|KgnrBDbB*@pmg0I@3^>FMf?bOBIcK63J_%SH!H3 zN*Y{L+;%>D*W-Rv>7$p?;Enwgs9~XhRBx~xB{{6e^{)da4yihoN6z8_(-wp_*bMC#yGVT^0dx9u>Dx zt_D;WoLY&&m~4Jk&4J&Dqj($yl7?pBi;1Wr0fxtg7( zC-`k2Y-Yg#_krvWnKppLwb7ti@3Xtx#}t_6COd0`C77(zv*>ljrv z{e=fwua}GNXjInY{jPUaTotW%*Li`g+~j4H9S;L+9+7v&&eRRW^7To3Nawm^H>?Uu z+{CK7Qk?JURa{kt2Z4nM#qRiQuxZSRNd;^x>h%`QKh^_oaoMe+sd2$O=i7{bVP3h< zaDO9G@lwHSJNV9AB=p*oUx!24fCAdQb6PW}n)2j2BK6Ggzd|gHHhOw13YmRB(PfITY?~91^|LvWfT~k5< z1M9z0>MIhP6N!pQaFU4IByve;B5zBh_(^{7TfqHKMl6j+yiIL7M>hhQ*hIAX6zeDW zRMX7EJD?Zh<5|tL{L^#pXF>pw?B#@6J;MPFCIZv6K%{6S0?WLfY!4}wbdF_+3eT{_ zq&OzcD5halhEqSw1w)?WkBOQ|hEZ8|CyJKI^gZI~Ktxq=|; zy6=@sZEH6!V~KdXAN0%Hwofiz?^M!Jh=1K~AZ-ag+oWIlbsEKQJyf>N_%T`$x(L^Z zoi6d5M-<}|I&aF*G+Vo_)0yY|8)BZ}e;9Ta=(V_8EG-DAB76SV!s!owkEPK6wRm4m f)L%W`|21cW|EG*DGG+cJM?jVo|H-lSfVBSy8$Q)~ literal 0 HcmV?d00001 diff --git a/public/index.html b/public/index.html index 53d86bf..d8c807b 100644 --- a/public/index.html +++ b/public/index.html @@ -3,8 +3,6 @@ - - @@ -13,18 +11,39 @@ $(document).ready(function(){ if(!("WebSocket" in window)) { - alert("Sorry, the build of your browser does not support WebSockets. Please use latest Chrome or Webkit nightly"); + console.log("Sorry, the build of your browser does not support WebSockets. Please use latest Chrome or Webkit nightly"); return; } var canvas = $("#log").get(0); + canvas.width = $(window).width() - 160; var graph = new Hummingbird.Graph(canvas, "ws://" + document.location.host.replace(/8088/, '8080')); + + }); + + $(document).ready(function() { + $.getJSON("/sale_list", function(data) { + $.each(data.data.active_sales, function() { + var editorialImage = "http://www.gilt.com" + this.sale_editorial_image; + var name = this.name; + var url = "http://www.gilt.com/s/" + this.url_key; + + var saleDiv = $("
"); + saleDiv.append(""); + saleDiv.append("

" + name + "

"); + $("#sales").append(saleDiv); + }); + }); + }); + +

Hummingbird

+
@@ -39,7 +58,7 @@

0

- +

4000

@@ -55,5 +74,9 @@
+
+ +
+ diff --git a/public/js/analytics.js b/public/js/analytics.js index 6ee0c55..2533d96 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -18,11 +18,22 @@ Hummingbird.Graph.prototype = { this.lineColor = "#FFF"; this.bgLineColor = "#555"; + this.canvasHeight = $(this.canvas).height(); + this.canvasWidth = $(this.canvas).width(); this.ws = new WebSocket(this.url); this.ws.onmessage = $.proxy(function(evt) { var data = JSON.parse(evt.data); - this.drawLogPath(data.total * 20 / 4000.0); + + if(typeof(data.total) != "undefined") { + $.each(data.sales, function(key) { + console.log(JSON.stringify(data.sales)); + $("#sale_" + key).hide(); + }); + this.drawLogPath(data.total * 20 / 4000.0); + } else { + console.log(JSON.stringify(data)); + } }, this); this.ws.onclose = function() { alert("socket closed"); @@ -60,21 +71,21 @@ Hummingbird.Graph.prototype = { drawLogPath: function(percent) { this.addValue(percent); - var height = Math.max(this.runningAverage() * 400, 1); - var endingPoint = 400 - height; + var height = Math.max(this.runningAverage() * this.canvasHeight, 1); + var endingPoint = this.canvasHeight - height; this.shiftCanvas(6, 0); this.context.beginPath(); this.context.strokeStyle = this.lineColor; - this.context.moveTo(750, 400); - this.context.lineTo(750, endingPoint); + this.context.moveTo(this.canvasWidth - 10, this.canvasHeight); + this.context.lineTo(this.canvasWidth - 10, endingPoint); this.context.stroke(); this.context.closePath(); this.context.beginPath(); this.context.strokeStyle = this.bgLineColor; - this.context.moveTo(750, endingPoint); - this.context.lineTo(750, 0); + this.context.moveTo(this.canvasWidth - 10, endingPoint); + this.context.lineTo(this.canvasWidth - 10, 0); this.context.stroke(); this.context.closePath(); } diff --git a/server.js b/server.js index 0397bb9..643f6d4 100644 --- a/server.js +++ b/server.js @@ -3,6 +3,8 @@ var sys = require('sys'), fs = require('fs'), path = require('path'), ws = require('./vendor/ws'), + proxy = require('./lib/proxy'), + pageview = require('./lib/view'), querystring = require('querystring'), arrays = require('./vendor/arrays'), paperboy = require('./vendor/node-paperboy'), @@ -18,19 +20,21 @@ var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), { var clients = []; var urls = { total: 0 }; +var sales = {}; setInterval(function() { // sys.puts("Writing to clients..."); clients.each(function(c) { try { - c.write(JSON.stringify({total: urls.total})); + c.write(JSON.stringify({total: urls.total, sales: sales})); } catch(e) { sys.log(e.description); } }); urls = { total: 0 }; + sales = {}; }, 50); var pixel = fs.readFileSync("images/tracking.gif", 'binary'); @@ -47,10 +51,13 @@ db.open(function(db) { res.write(pixel, 'binary'); res.close(); - if(urls[env.u]) { - urls[env.u] += 1; - } else { - urls[env.u] = 1; + var view = new pageview.View(env); + if(view.urlKey) { + if(sales[view.urlKey]) { + sales[view.urlKey] += 1; + } else { + sales[view.urlKey] = 1; + } } urls.total += 1 @@ -77,8 +84,14 @@ ws.createServer(function (websocket) { sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); http.createServer(function(req, res) { - paperboy.deliver(WEBROOT, req, res) - .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); + if(req.url.match(/\/sale_list/)) { + sys.log("YAY"); + proxy.route("/sale_list", "http://localhost:6701/pagegen_service/sales/sale_list", req, res); + } else { + paperboy.deliver(WEBROOT, req, res) + .addHeader('Content-Type', "text/plain") + .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); + } }).listen(MONITOR_PORT); sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); From 403787cfd98f263bcf8d91a7e9c89b274665dc1e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 12 Apr 2010 18:17:27 -0400 Subject: [PATCH 011/267] Split out client websocket into its own js, only send sale hiit data every 500ms --- public/css/main.css | 6 ++++- public/index.html | 32 ++---------------------- public/js/analytics.js | 26 ++------------------ public/js/sales.js | 27 +++++++++++++++++++++ public/js/websocket.js | 55 ++++++++++++++++++++++++++++++++++++++++++ server.js | 15 ++++++++++-- 6 files changed, 104 insertions(+), 57 deletions(-) create mode 100644 public/js/sales.js create mode 100644 public/js/websocket.js diff --git a/public/css/main.css b/public/css/main.css index 370c552..a7face0 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -42,14 +42,18 @@ div.hummingbird_graph div.axis_right { #sales div.sale { float: left; width: 180px; - height: 140px; + height: 180px; overflow: hidden; padding: 10px; } +#sales div.sale canvas { +} + #sales div.sale h2 { color: #CCC; font-size: 0.7em; + height: 1.8em; } #sales div.sale img.editorial { diff --git a/public/index.html b/public/index.html index d8c807b..5814a9d 100644 --- a/public/index.html +++ b/public/index.html @@ -7,36 +7,8 @@ - + + diff --git a/public/js/analytics.js b/public/js/analytics.js index 2533d96..2fc041b 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -1,11 +1,10 @@ if(!Hummingbird) { var Hummingbird = {}; } -Hummingbird.Graph = function(canvas, url) { +Hummingbird.Graph = function(canvas) { if ( !(this instanceof Hummingbird.Graph) ) { - return new Hummingbird.Graph(canvas, url); + return new Hummingbird.Graph(canvas); } - this.url = url; this.canvas = canvas; this.trafficLog = []; @@ -20,27 +19,6 @@ Hummingbird.Graph.prototype = { this.bgLineColor = "#555"; this.canvasHeight = $(this.canvas).height(); this.canvasWidth = $(this.canvas).width(); - - this.ws = new WebSocket(this.url); - this.ws.onmessage = $.proxy(function(evt) { - var data = JSON.parse(evt.data); - - if(typeof(data.total) != "undefined") { - $.each(data.sales, function(key) { - console.log(JSON.stringify(data.sales)); - $("#sale_" + key).hide(); - }); - this.drawLogPath(data.total * 20 / 4000.0); - } else { - console.log(JSON.stringify(data)); - } - }, this); - this.ws.onclose = function() { - alert("socket closed"); - }; - this.ws.onopen = function() { - //alert("connected..."); - }; }, addValue: function(value) { diff --git a/public/js/sales.js b/public/js/sales.js new file mode 100644 index 0000000..ae426ef --- /dev/null +++ b/public/js/sales.js @@ -0,0 +1,27 @@ +if(!Hummingbird) { var Hummingbird = {}; } + +Hummingbird.saleGraphs = {}; + +Hummingbird.getSales = function() { + $.getJSON("/sale_list", function(data) { + $.each(data.data.active_sales, function() { + var editorialImage = "http://www.gilt.com" + this.sale_editorial_image; + var name = this.name; + var url = "http://www.gilt.com/s/" + this.url_key; + + var saleDiv = $("
"); + saleDiv.append(""); + saleDiv.append("

" + name + "

"); + + var canvas = $(""); + saleDiv.append(canvas); + $("#sales").append(saleDiv); + var saleGraph = new Hummingbird.Graph(canvas.get(0)); + Hummingbird.saleGraphs[this.url_key] = saleGraph; + }); + }); +}; + +$(document).ready(function() { + Hummingbird.getSales(); +}); \ No newline at end of file diff --git a/public/js/websocket.js b/public/js/websocket.js new file mode 100644 index 0000000..e599d98 --- /dev/null +++ b/public/js/websocket.js @@ -0,0 +1,55 @@ +if(!Hummingbird) { var Hummingbird = {}; } + +Hummingbird.WebSocket = {}; +Hummingbird.WebSocket.state = "stopped"; +Hummingbird.WebSocket.start = function() { + if(!("WebSocket" in window)) { + console.log("Sorry, the build of your browser does not support WebSockets. Please use latest Chrome or Webkit nightly"); + return; + } + + var canvas = $("#log").get(0); + canvas.width = $(window).width() - 160; + var totalGraph = new Hummingbird.Graph(canvas); + + + var ws = new WebSocket("ws://" + document.location.host.replace(/8088/, '8080')); + ws.onmessage = function(evt) { + var data = JSON.parse(evt.data); + + if(typeof(data.sales) != "undefined") { + console.log(JSON.stringify(data.sales)); + // console.log(JSON.stringify(data.sales)); + $.each(Hummingbird.saleGraphs, function(key) { + if(data.sales[key]) { + Hummingbird.saleGraphs[key].drawLogPath(data.sales[key] / 200.0); + } else { + Hummingbird.saleGraphs[key].drawLogPath(0.0); + } + }); + } else if(typeof(data.total) != "undefined") { + totalGraph.drawLogPath(data.total * 20 / 4000.0); + } + } + ws.onclose = function() { + if(Hummingbird.WebSocket.state == "retrying") { + // Wait a while to try restarting + console.log("still no socket, retrying in 3 seconds"); + setTimeout(Hummingbird.WebSocket.start, 3000); + } else { + // First attempt at restarting, try immediately + Hummingbird.WebSocket.state = "retrying"; + console.log("socket lost, retrying immediately"); + setTimeout(Hummingbird.WebSocket.start, 200); + } + }; + ws.onopen = function() { + Hummingbird.WebSocket.state = "started"; + console.log("socket started"); + //alert("connected..."); + }; +}; + +$(document).ready(function(){ + Hummingbird.WebSocket.start(); +}); \ No newline at end of file diff --git a/server.js b/server.js index 643f6d4..de0d604 100644 --- a/server.js +++ b/server.js @@ -22,6 +22,18 @@ var clients = []; var urls = { total: 0 }; var sales = {}; +setInterval(function() { + clients.each(function(c) { + try { + c.write(JSON.stringify({total: urls.total})); + } catch(e) { + sys.log(e.description); + } + }); + + urls = { total: 0 }; +}, 50); + setInterval(function() { // sys.puts("Writing to clients..."); @@ -33,9 +45,8 @@ setInterval(function() { } }); - urls = { total: 0 }; sales = {}; -}, 50); +}, 500); var pixel = fs.readFileSync("images/tracking.gif", 'binary'); db.open(function(db) { From 2eb5edc4ffb1121724bc30dd9ef64f1fb58ef7b5 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 11:08:14 -0400 Subject: [PATCH 012/267] Color graphs --- public/index.html | 4 +++- public/js/analytics.js | 10 +++++++--- public/js/websocket.js | 3 --- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/public/index.html b/public/index.html index 5814a9d..51ee15a 100644 --- a/public/index.html +++ b/public/index.html @@ -10,6 +10,8 @@ + Hummingbird + @@ -22,7 +24,7 @@

Hummingbird

4000

3500

3000

-

2500

+

2500

2000

1500

1000

diff --git a/public/js/analytics.js b/public/js/analytics.js index 2fc041b..59f045f 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -15,7 +15,8 @@ Hummingbird.Graph.prototype = { init: function() { this.setupContext(); - this.lineColor = "#FFF"; + this.lineColors = [ "#FFFFFF", "#3BA496", "#65B88A", + "#F1E29F", "#C44939", "#983839" ]; this.bgLineColor = "#555"; this.canvasHeight = $(this.canvas).height(); this.canvasWidth = $(this.canvas).width(); @@ -49,12 +50,15 @@ Hummingbird.Graph.prototype = { drawLogPath: function(percent) { this.addValue(percent); - var height = Math.max(this.runningAverage() * this.canvasHeight, 1); + var average = this.runningAverage(); + var height = Math.max(average * this.canvasHeight, 1); + var colorIndex = Math.min(Math.ceil((average / 2) * 10), 5); + var color = this.lineColors[colorIndex]; var endingPoint = this.canvasHeight - height; this.shiftCanvas(6, 0); this.context.beginPath(); - this.context.strokeStyle = this.lineColor; + this.context.strokeStyle = color; this.context.moveTo(this.canvasWidth - 10, this.canvasHeight); this.context.lineTo(this.canvasWidth - 10, endingPoint); this.context.stroke(); diff --git a/public/js/websocket.js b/public/js/websocket.js index e599d98..a383dac 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -12,14 +12,11 @@ Hummingbird.WebSocket.start = function() { canvas.width = $(window).width() - 160; var totalGraph = new Hummingbird.Graph(canvas); - var ws = new WebSocket("ws://" + document.location.host.replace(/8088/, '8080')); ws.onmessage = function(evt) { var data = JSON.parse(evt.data); if(typeof(data.sales) != "undefined") { - console.log(JSON.stringify(data.sales)); - // console.log(JSON.stringify(data.sales)); $.each(Hummingbird.saleGraphs, function(key) { if(data.sales[key]) { Hummingbird.saleGraphs[key].drawLogPath(data.sales[key] / 200.0); From 467d76c931321324e0771f6da9ac9ad5659b6276 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 11:08:29 -0400 Subject: [PATCH 013/267] Use public gilt sale list --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index de0d604..341acd0 100644 --- a/server.js +++ b/server.js @@ -39,7 +39,7 @@ setInterval(function() { clients.each(function(c) { try { - c.write(JSON.stringify({total: urls.total, sales: sales})); + c.write(JSON.stringify({sales: sales})); } catch(e) { sys.log(e.description); } @@ -97,7 +97,7 @@ sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); http.createServer(function(req, res) { if(req.url.match(/\/sale_list/)) { sys.log("YAY"); - proxy.route("/sale_list", "http://localhost:6701/pagegen_service/sales/sale_list", req, res); + proxy.route("/sale_list", "http://www.gilt.com/pagegen_service/sales/sale_list", req, res); } else { paperboy.deliver(WEBROOT, req, res) .addHeader('Content-Type', "text/plain") From 71eb816b9e9c032840054b548ec14f4f6a502d02 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 11:42:27 -0400 Subject: [PATCH 014/267] Add check for view env url --- lib/view.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/view.js b/lib/view.js index 3908724..18e61ef 100644 --- a/lib/view.js +++ b/lib/view.js @@ -4,10 +4,12 @@ var View = function(env) { } this.env = env; - this.urlKey = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/)[1]; + if(this.env.u) { + this.urlKey = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/)[1]; + } } View.prototype = { }; -exports.View = View; \ No newline at end of file +exports.View = View; From c741729a01051136b8400599b5c9e5f1a5893d18 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 12:03:56 -0400 Subject: [PATCH 015/267] Default proxy to port 80 --- lib/service_json.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/service_json.js b/lib/service_json.js index e25768c..4c49307 100644 --- a/lib/service_json.js +++ b/lib/service_json.js @@ -5,7 +5,7 @@ var sys = require('sys'); exports.fetchJSON = function(remoteURL, callback) { remoteURL = url.parse(remoteURL); - var pagegen = http.createClient(remoteURL.port, remoteURL.hostname); + var pagegen = http.createClient(remoteURL.port || 80, remoteURL.hostname); // TODO: remoteURL.search var request = pagegen.request('GET', remoteURL.pathname, {"host": remoteURL.hostname}); request.addListener('response', function(response) { @@ -21,4 +21,4 @@ exports.fetchJSON = function(remoteURL, callback) { }); }); request.close(); -}; \ No newline at end of file +}; From 47363098f6530643e5bef24036dbe342eedadf6d Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 12:19:49 -0400 Subject: [PATCH 016/267] Make websocket upgrade work with port 80 --- public/js/websocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/websocket.js b/public/js/websocket.js index a383dac..adcd92d 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -12,7 +12,7 @@ Hummingbird.WebSocket.start = function() { canvas.width = $(window).width() - 160; var totalGraph = new Hummingbird.Graph(canvas); - var ws = new WebSocket("ws://" + document.location.host.replace(/8088/, '8080')); + var ws = new WebSocket("ws://" + document.location.hostname + ':8080'); ws.onmessage = function(evt) { var data = JSON.parse(evt.data); From 56a4f68775ed2006e42150d4e08bb24c380299fa Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 23:30:52 -0400 Subject: [PATCH 017/267] Protect against urls that don't have a sale name in them --- lib/view.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/view.js b/lib/view.js index 18e61ef..5036de9 100644 --- a/lib/view.js +++ b/lib/view.js @@ -6,6 +6,10 @@ var View = function(env) { this.env = env; if(this.env.u) { this.urlKey = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/)[1]; + var match = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/); + if(match && match.length > 0) { + this.urlKey = match[1]; + } } } From 85b9316571625d227ebd5b1e6756c9802041d17e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 23:38:58 -0400 Subject: [PATCH 018/267] Reduce scale to 400 req/s --- public/index.html | 32 ++++++++++++++++---------------- public/js/websocket.js | 9 +++++---- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/public/index.html b/public/index.html index 51ee15a..f6c6629 100644 --- a/public/index.html +++ b/public/index.html @@ -21,28 +21,28 @@

Hummingbird

-

4000

-

3500

-

3000

-

2500

-

2000

-

1500

-

1000

-

500

+

400

+

350

+

300

+

250

+

200

+

150

+

100

+

50

0

-

4000

-

3500

-

3000

-

2500

-

2000

-

1500

-

1000

-

500

+

400

+

350

+

300

+

250

+

200

+

150

+

100

+

50

0

diff --git a/public/js/websocket.js b/public/js/websocket.js index adcd92d..7972a8d 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -12,20 +12,21 @@ Hummingbird.WebSocket.start = function() { canvas.width = $(window).width() - 160; var totalGraph = new Hummingbird.Graph(canvas); - var ws = new WebSocket("ws://" + document.location.hostname + ':8080'); + var wsServer = "ws://" + document.location.hostname + ":8080"; + var ws = new WebSocket(wsServer); ws.onmessage = function(evt) { var data = JSON.parse(evt.data); if(typeof(data.sales) != "undefined") { $.each(Hummingbird.saleGraphs, function(key) { if(data.sales[key]) { - Hummingbird.saleGraphs[key].drawLogPath(data.sales[key] / 200.0); + Hummingbird.saleGraphs[key].drawLogPath(data.sales[key] * 2 / 200.0); } else { Hummingbird.saleGraphs[key].drawLogPath(0.0); } }); } else if(typeof(data.total) != "undefined") { - totalGraph.drawLogPath(data.total * 20 / 4000.0); + totalGraph.drawLogPath(data.total * 20 / 400.0); } } ws.onclose = function() { @@ -49,4 +50,4 @@ Hummingbird.WebSocket.start = function() { $(document).ready(function(){ Hummingbird.WebSocket.start(); -}); \ No newline at end of file +}); From 3028dac0e27307abca8e0bf2c37e883dbb1f3ea5 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 23:45:21 -0400 Subject: [PATCH 019/267] Don't fail if something else is already running on the hummingbird monitor port --- server.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/server.js b/server.js index 341acd0..0992f52 100644 --- a/server.js +++ b/server.js @@ -90,19 +90,25 @@ ws.createServer(function (websocket) { clients.remove(websocket); sys.log("ws close"); }); -}).listen(8080); +}).listen(WEB_SOCKET_PORT); sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); -http.createServer(function(req, res) { - if(req.url.match(/\/sale_list/)) { - sys.log("YAY"); - proxy.route("/sale_list", "http://www.gilt.com/pagegen_service/sales/sale_list", req, res); - } else { - paperboy.deliver(WEBROOT, req, res) - .addHeader('Content-Type', "text/plain") - .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); - } -}).listen(MONITOR_PORT); +try { + http.createServer(function(req, res) { + if(req.url.match(/\/sale_list/)) { + sys.log("YAY"); + proxy.route("/sale_list", "http://www.gilt.com/pagegen_service/sales/sale_list", req, res); + } else { + paperboy.deliver(WEBROOT, req, res) + .addHeader('Content-Type', "text/plain") + .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); + } + }).listen(MONITOR_PORT); -sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); + sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); +} catch(e) { + if(e && e.errno == 48) { + sys.log('Detected port ' + MONITOR_PORT + ' in use; assuming it is being served by another webserver.'); + } +} From d61c1823454ec99be34c2634c1f5b33366b8baac Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 23:46:02 -0400 Subject: [PATCH 020/267] Add log dir --- log/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 log/.gitignore diff --git a/log/.gitignore b/log/.gitignore new file mode 100644 index 0000000..50e1322 --- /dev/null +++ b/log/.gitignore @@ -0,0 +1 @@ +/*.log From 21cee71f616a8b62be18c5c5ccaa3d9d92311a53 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 15 Apr 2010 23:50:40 -0400 Subject: [PATCH 021/267] Warn if address is in use, otherwise error --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 0992f52..de061d7 100644 --- a/server.js +++ b/server.js @@ -108,7 +108,7 @@ try { sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); } catch(e) { - if(e && e.errno == 48) { + if(e && e.message == "Address already in use") { sys.log('Detected port ' + MONITOR_PORT + ' in use; assuming it is being served by another webserver.'); - } + } else { throw(e); } } From 21b26479b461839219e9b4b457218c61a783ed87 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 00:35:28 -0400 Subject: [PATCH 022/267] remove broken submodule --- vendor/node-paperboy | 1 - 1 file changed, 1 deletion(-) delete mode 160000 vendor/node-paperboy diff --git a/vendor/node-paperboy b/vendor/node-paperboy deleted file mode 160000 index f4e7ced..0000000 --- a/vendor/node-paperboy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f4e7cedb816130dbc85dbd79b72d0585346bdbbc From f4a3241cb24674fe32e09480087dd644f05e8a83 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 00:35:37 -0400 Subject: [PATCH 023/267] add it back --- vendor/node-paperboy | 1 + 1 file changed, 1 insertion(+) create mode 160000 vendor/node-paperboy diff --git a/vendor/node-paperboy b/vendor/node-paperboy new file mode 160000 index 0000000..5189eed --- /dev/null +++ b/vendor/node-paperboy @@ -0,0 +1 @@ +Subproject commit 5189eed907feda959f92cd6837b0ba038545ddd8 From 1d1edc23751c3a0caa05f1f9d708102eaf395947 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 00:54:43 -0400 Subject: [PATCH 024/267] Try to decrease memory usage on chrome --- public/js/analytics.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/js/analytics.js b/public/js/analytics.js index 59f045f..8bda0d1 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -30,8 +30,7 @@ Hummingbird.Graph.prototype = { }, shiftCanvas: function(x, y) { - var canvasData = this.context.getImageData(x, y, this.canvas.width, this.canvas.height); - this.context.putImageData(canvasData, 0, 0); + this.context.putImageData(this.context.getImageData(x, y, this.canvas.width, this.canvas.height), 0, 0); }, setupContext: function() { From fa13f17955676ecb8c23af034f14c0dec9694d33 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 12:01:23 -0400 Subject: [PATCH 025/267] Forgot to delete a line from last commit --- lib/view.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/view.js b/lib/view.js index 5036de9..587d655 100644 --- a/lib/view.js +++ b/lib/view.js @@ -5,7 +5,6 @@ var View = function(env) { this.env = env; if(this.env.u) { - this.urlKey = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/)[1]; var match = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/); if(match && match.length > 0) { this.urlKey = match[1]; From f246d7680683f2d4937200f7233a9043d515e765 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 13:21:43 -0400 Subject: [PATCH 026/267] Add cartAdds metric; fix sale list url for local proxy --- lib/view.js | 32 ++++++++++++++++++++++++++------ server.js | 51 +++++++++++++++++++++++++++++---------------------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/lib/view.js b/lib/view.js index 587d655..4c279a3 100644 --- a/lib/view.js +++ b/lib/view.js @@ -1,18 +1,38 @@ +var sys = require('sys'); + var View = function(env) { if(!this instanceof View) { return new View(env); } this.env = env; - if(this.env.u) { - var match = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/); - if(match && match.length > 0) { - this.urlKey = match[1]; - } - } } View.prototype = { + urlKey: function() { + if(this.env.u) { + var match = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/); + if(match && match.length > 0) { + this._urlKey = match[1]; + } + } + + this.urlKey = function() { return this._urlKey; } + return this._urlKey; + }, + + event: function() { + if(this.env.events) { + if(this.env.events.match(/scAdd/)) { + this._event = "cart_add"; + } else if(this.env.events === "purchase") { + this._event = "purchase"; + } + } + + this.event = function() { return this._event; } + return this._event; + } }; exports.View = View; diff --git a/server.js b/server.js index de061d7..4e79958 100644 --- a/server.js +++ b/server.js @@ -19,19 +19,22 @@ var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), { var clients = []; -var urls = { total: 0 }; +var totalPages = 0; +var totalCartAdds = 0; var sales = {}; setInterval(function() { clients.each(function(c) { try { - c.write(JSON.stringify({total: urls.total})); + c.write(JSON.stringify({total: totalPages, cartAdds: totalCartAdds})); + // sys.log(JSON.stringify({total: totalPages, cartAdds: totalCartAdds})); } catch(e) { sys.log(e.description); } }); - urls = { total: 0 }; + totalPages = 0; + totalCartAdds = 0; }, 50); setInterval(function() { @@ -52,26 +55,31 @@ var pixel = fs.readFileSync("images/tracking.gif", 'binary'); db.open(function(db) { db.collection('visits', function(err, collection) { http.createServer(function (req, res) { + try { + var env = querystring.parse(req.url.split('?')[1]); + env.timestamp = (new Date()); + collection.insert(env); + sys.puts(JSON.stringify(env, null, 2)); + + res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); + res.write(pixel, 'binary'); + res.close(); + + var view = new pageview.View(env); + if(view.urlKey()) { + if(sales[view.urlKey()]) { + sales[view.urlKey()] += 1; + } else { + sales[view.urlKey()] = 1; + } + } - var env = querystring.parse(req.url.split('?')[1]); - env.timestamp = (new Date()); - collection.insert(env); - // sys.puts(JSON.stringify(env, null, 2)); - - res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); - res.write(pixel, 'binary'); - res.close(); - - var view = new pageview.View(env); - if(view.urlKey) { - if(sales[view.urlKey]) { - sales[view.urlKey] += 1; - } else { - sales[view.urlKey] = 1; + if(view.event() && view.event() === "cart_add") { + totalCartAdds += 1; } - } - urls.total += 1 + totalPages += 1; + } catch(e) { e.stack = e.stack.split('\n'); sys.log(JSON.stringify(e, null, 2)); } }).listen(TRACKING_PORT); }); }); @@ -97,8 +105,7 @@ sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); try { http.createServer(function(req, res) { if(req.url.match(/\/sale_list/)) { - sys.log("YAY"); - proxy.route("/sale_list", "http://www.gilt.com/pagegen_service/sales/sale_list", req, res); + proxy.route("/sale_list", "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); } else { paperboy.deliver(WEBROOT, req, res) .addHeader('Content-Type', "text/plain") From 8390082193244b4edddef0c59af85d7fd7f78464 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 13:47:05 -0400 Subject: [PATCH 027/267] Turn logging of every request off (need to find a better way) --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 4e79958..4258c5a 100644 --- a/server.js +++ b/server.js @@ -59,7 +59,7 @@ db.open(function(db) { var env = querystring.parse(req.url.split('?')[1]); env.timestamp = (new Date()); collection.insert(env); - sys.puts(JSON.stringify(env, null, 2)); + // sys.log(JSON.stringify(env, null, 2)); res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); res.write(pixel, 'binary'); From 1fafd30422012f2d60ae74a4b96e461f8aed552a Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 13:47:16 -0400 Subject: [PATCH 028/267] Show cart adds in ui --- public/css/main.css | 13 +++++++++++++ public/index.html | 28 ++++++++++++++++++++++++++++ public/js/websocket.js | 9 +++++++++ 3 files changed, 50 insertions(+) diff --git a/public/css/main.css b/public/css/main.css index a7face0..5a863ef 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -12,6 +12,14 @@ h1 { font-family: 'TitilliumText14L800wt', sans-serif; } +div.hummingbird_graph h2 { + color: #CCC; + text-transform: uppercase; + font-size: 0.9em; + margin-bottom: 0.2em; + margin-left: 55px; +} + div.hummingbird_graph canvas { float: left; padding: 14px 0 20px 0; @@ -36,6 +44,11 @@ div.hummingbird_graph div.axis_right { padding: 0 10px; } +#hummingbird_cart_adds div.axis_left, +#hummingbird_cart_adds div.axis_right { + line-height: 0.3em; +} + #sales { } diff --git a/public/index.html b/public/index.html index f6c6629..141038c 100644 --- a/public/index.html +++ b/public/index.html @@ -20,6 +20,8 @@

Hummingbird

+

Total Pageviews

+

400

350

@@ -50,6 +52,32 @@

Hummingbird

+
+ +

Total Cart Adds

+ +
+

200

+

150

+

100

+

50

+

0

+
+ + + +
+

200

+

150

+

100

+

50

+

0

+
+ +
+ +
+
diff --git a/public/js/websocket.js b/public/js/websocket.js index 7972a8d..47d72af 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -12,6 +12,10 @@ Hummingbird.WebSocket.start = function() { canvas.width = $(window).width() - 160; var totalGraph = new Hummingbird.Graph(canvas); + var cartAdds = $("#cart_adds").get(0); + cartAdds.width = $(window).width() - 160; + var cartAddsGraph = new Hummingbird.Graph(cartAdds); + var wsServer = "ws://" + document.location.hostname + ":8080"; var ws = new WebSocket(wsServer); ws.onmessage = function(evt) { @@ -27,6 +31,11 @@ Hummingbird.WebSocket.start = function() { }); } else if(typeof(data.total) != "undefined") { totalGraph.drawLogPath(data.total * 20 / 400.0); + if(data.cartAdds) { + cartAddsGraph.drawLogPath(data.cartAdds * 20 / 200); + } else { + cartAddsGraph.drawLogPath(0.0); + } } } ws.onclose = function() { From c5a2bb66bf88e0793b6422b70b758b47f8744243 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 23:15:24 -0400 Subject: [PATCH 029/267] Move vendor libraries to deps/ to make app more node-like --- .gitmodules | 16 ++++++++-------- {vendor => deps}/arrays.js | 0 deps/node-mongodb-native | 1 + {vendor => deps}/node-paperboy | 0 deps/nodeunit | 1 + {vendor => deps}/ws.js | 0 server.js | 8 ++++---- vendor/node-mongodb-native | 1 - 8 files changed, 14 insertions(+), 13 deletions(-) rename {vendor => deps}/arrays.js (100%) create mode 160000 deps/node-mongodb-native rename {vendor => deps}/node-paperboy (100%) create mode 160000 deps/nodeunit rename {vendor => deps}/ws.js (100%) delete mode 160000 vendor/node-mongodb-native diff --git a/.gitmodules b/.gitmodules index 159f10f..49200f2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ -[submodule "vendor/node-mongodb"] - path = vendor/node-mongodb - url = git://github.com/orlandov/node-mongodb.git -[submodule "vendor/node-mongodb-native"] - path = vendor/node-mongodb-native - url = git://github.com/christkv/node-mongodb-native.git -[submodule "vendor/node-paperboy"] - path = vendor/node-paperboy +[submodule "deps/nodeunit"] + path = deps/nodeunit + url = git://github.com/caolan/nodeunit.git +[submodule "deps/node-paperboy"] + path = deps/node-paperboy url = git://github.com/felixge/node-paperboy +[submodule "deps/node-mongodb-native"] + path = deps/node-mongodb-native + url = git://github.com/christkv/node-mongodb-native.git diff --git a/vendor/arrays.js b/deps/arrays.js similarity index 100% rename from vendor/arrays.js rename to deps/arrays.js diff --git a/deps/node-mongodb-native b/deps/node-mongodb-native new file mode 160000 index 0000000..123bc52 --- /dev/null +++ b/deps/node-mongodb-native @@ -0,0 +1 @@ +Subproject commit 123bc52df8f7e58d1890ad2d112e55af2c21ca34 diff --git a/vendor/node-paperboy b/deps/node-paperboy similarity index 100% rename from vendor/node-paperboy rename to deps/node-paperboy diff --git a/deps/nodeunit b/deps/nodeunit new file mode 160000 index 0000000..daa9986 --- /dev/null +++ b/deps/nodeunit @@ -0,0 +1 @@ +Subproject commit daa9986ee6a5266c2e02eae5e3a8bd6904bbcee8 diff --git a/vendor/ws.js b/deps/ws.js similarity index 100% rename from vendor/ws.js rename to deps/ws.js diff --git a/server.js b/server.js index 4258c5a..07a08ae 100644 --- a/server.js +++ b/server.js @@ -2,13 +2,13 @@ var sys = require('sys'), http = require('http'), fs = require('fs'), path = require('path'), - ws = require('./vendor/ws'), + ws = require('./deps/ws'), proxy = require('./lib/proxy'), pageview = require('./lib/view'), querystring = require('querystring'), - arrays = require('./vendor/arrays'), - paperboy = require('./vendor/node-paperboy'), - mongo = require('./vendor/node-mongodb-native/lib/mongodb'); + arrays = require('./deps/arrays'), + paperboy = require('./deps/node-paperboy'), + mongo = require('./deps/node-mongodb-native/lib/mongodb'); var WEBROOT = path.join(path.dirname(__filename), 'public'), TRACKING_PORT = 8000, diff --git a/vendor/node-mongodb-native b/vendor/node-mongodb-native deleted file mode 160000 index e30aa02..0000000 --- a/vendor/node-mongodb-native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e30aa02f58971dba2ba01e697fe7e4684f11afda From 3b74cc96cc68272fbb321e359c28faa498c22ec9 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 16 Apr 2010 23:43:35 -0400 Subject: [PATCH 030/267] upgrade to node v0.1.91 --- .gitmodules | 2 +- deps/node-mongodb-native | 2 +- deps/node-paperboy | 2 +- deps/ws.js | 2 +- server.js | 54 +++++++++++++++++++++------------------- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/.gitmodules b/.gitmodules index 49200f2..5d36676 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = git://github.com/caolan/nodeunit.git [submodule "deps/node-paperboy"] path = deps/node-paperboy - url = git://github.com/felixge/node-paperboy + url = git://github.com/mnutt/node-paperboy [submodule "deps/node-mongodb-native"] path = deps/node-mongodb-native url = git://github.com/christkv/node-mongodb-native.git diff --git a/deps/node-mongodb-native b/deps/node-mongodb-native index 123bc52..5401a62 160000 --- a/deps/node-mongodb-native +++ b/deps/node-mongodb-native @@ -1 +1 @@ -Subproject commit 123bc52df8f7e58d1890ad2d112e55af2c21ca34 +Subproject commit 5401a62e7a139f9d0f379e46e6ad3107810f7c7c diff --git a/deps/node-paperboy b/deps/node-paperboy index 5189eed..f4e7ced 160000 --- a/deps/node-paperboy +++ b/deps/node-paperboy @@ -1 +1 @@ -Subproject commit 5189eed907feda959f92cd6837b0ba038545ddd8 +Subproject commit f4e7cedb816130dbc85dbd79b72d0585346bdbbc diff --git a/deps/ws.js b/deps/ws.js index bc8033d..4105123 100644 --- a/deps/ws.js +++ b/deps/ws.js @@ -11,7 +11,7 @@ function nano(template, data) { } var sys = require("sys"), - tcp = require("tcp"), + tcp = require("net"), headerExpressions = [ /^GET (\/[^\s]*) HTTP\/1\.1$/, /^Upgrade: WebSocket$/, diff --git a/server.js b/server.js index 07a08ae..a08ae75 100644 --- a/server.js +++ b/server.js @@ -52,35 +52,37 @@ setInterval(function() { }, 500); var pixel = fs.readFileSync("images/tracking.gif", 'binary'); -db.open(function(db) { - db.collection('visits', function(err, collection) { - http.createServer(function (req, res) { - try { - var env = querystring.parse(req.url.split('?')[1]); - env.timestamp = (new Date()); - collection.insert(env); - // sys.log(JSON.stringify(env, null, 2)); - - res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); - res.write(pixel, 'binary'); - res.close(); - - var view = new pageview.View(env); - if(view.urlKey()) { - if(sales[view.urlKey()]) { - sales[view.urlKey()] += 1; - } else { - sales[view.urlKey()] = 1; +db.open(function(p_db) { + db.createCollection('visits', function(err, collection) { + db.collection('visits', function(err, collection) { + http.createServer(function (req, res) { + try { + var env = querystring.parse(req.url.split('?')[1]); + env.timestamp = (new Date()); + collection.insert(env); + // sys.log(JSON.stringify(env, null, 2)); + + res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); + res.write(pixel, 'binary'); + res.end(); + + var view = new pageview.View(env); + if(view.urlKey()) { + if(sales[view.urlKey()]) { + sales[view.urlKey()] += 1; + } else { + sales[view.urlKey()] = 1; + } } - } - if(view.event() && view.event() === "cart_add") { - totalCartAdds += 1; - } + if(view.event() && view.event() === "cart_add") { + totalCartAdds += 1; + } - totalPages += 1; - } catch(e) { e.stack = e.stack.split('\n'); sys.log(JSON.stringify(e, null, 2)); } - }).listen(TRACKING_PORT); + totalPages += 1; + } catch(e) { e.stack = e.stack.split('\n'); sys.log(JSON.stringify(e, null, 2)); } + }).listen(TRACKING_PORT); + }); }); }); From 035624bef5b8bff89869012ee5bcbb71a46c0771 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 17 Apr 2010 15:45:36 -0400 Subject: [PATCH 031/267] Split setInterval metrics out into their own lib --- lib/metric.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ server.js | 53 ++++++++++++++------------------------------------- 2 files changed, 64 insertions(+), 39 deletions(-) create mode 100644 lib/metric.js diff --git a/lib/metric.js b/lib/metric.js new file mode 100644 index 0000000..2f74835 --- /dev/null +++ b/lib/metric.js @@ -0,0 +1,50 @@ +var sys = require('sys'); + +var Metric = function(initialData, interval) { + if(!this instanceof Metric) { + return new Metric(initialData, interval); + } + + this.initialData = this.data = initialData; + this.interval = interval; + this.job = null; + this.clients = []; +} + +Metric.prototype = { + run: function() { + this.job = setInterval(this.runner, this.interval, this); + }, + + runner: function(metric) { +// sys.log(JSON.stringify(metric.data)); + // NOTE: using 'metric' in place of 'this', since run from setInterval + metric.clients.each(function(client) { + try { + client.write(JSON.stringify(metric.data)); + } catch(e) { + sys.log(e.description); + } + }); + + metric.resetData(); + }, + + removeClient: function(client) { + this.clients.remove(client); + }, + + addClient: function(client) { + this.clients.push(client); + }, + + resetData: function() { + this.data = this.initialData; + }, + + stop: function() { + clearInterval(this.job); + } +}; + +exports.Metric = Metric; \ No newline at end of file diff --git a/server.js b/server.js index a08ae75..2cf7792 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ var sys = require('sys'), ws = require('./deps/ws'), proxy = require('./lib/proxy'), pageview = require('./lib/view'), + metric = require('./lib/metric'), querystring = require('querystring'), arrays = require('./deps/arrays'), paperboy = require('./deps/node-paperboy'), @@ -17,39 +18,11 @@ var WEBROOT = path.join(path.dirname(__filename), 'public'), var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); -var clients = []; +var allViewsMetric = new metric.Metric({total: 0, cartAdds: 0}, 50); +var salesMetric = new metric.Metric({sales: {}}, 500); -var totalPages = 0; -var totalCartAdds = 0; -var sales = {}; - -setInterval(function() { - clients.each(function(c) { - try { - c.write(JSON.stringify({total: totalPages, cartAdds: totalCartAdds})); - // sys.log(JSON.stringify({total: totalPages, cartAdds: totalCartAdds})); - } catch(e) { - sys.log(e.description); - } - }); - - totalPages = 0; - totalCartAdds = 0; -}, 50); - -setInterval(function() { - // sys.puts("Writing to clients..."); - - clients.each(function(c) { - try { - c.write(JSON.stringify({sales: sales})); - } catch(e) { - sys.log(e.description); - } - }); - - sales = {}; -}, 500); +allViewsMetric.run(); +salesMetric.run(); var pixel = fs.readFileSync("images/tracking.gif", 'binary'); db.open(function(p_db) { @@ -68,18 +41,18 @@ db.open(function(p_db) { var view = new pageview.View(env); if(view.urlKey()) { - if(sales[view.urlKey()]) { - sales[view.urlKey()] += 1; + if(salesMetric.data.sales[view.urlKey()]) { + salesMetric.data.sales[view.urlKey()] += 1; } else { - sales[view.urlKey()] = 1; + salesMetric.data.sales[view.urlKey()] = 1; } } if(view.event() && view.event() === "cart_add") { - totalCartAdds += 1; + allViewsMetric.data.cartAdds += 1; } - totalPages += 1; + allViewsMetric.data.total += 1; } catch(e) { e.stack = e.stack.split('\n'); sys.log(JSON.stringify(e, null, 2)); } }).listen(TRACKING_PORT); }); @@ -90,14 +63,16 @@ sys.puts('Tracking server running at http://localhost:' + TRACKING_PORT + '/trac // Websocket TCP server ws.createServer(function (websocket) { - clients.push(websocket); + allViewsMetric.addClient(websocket); + salesMetric.addClient(websocket); websocket.addListener("connect", function (resource) { // emitted after handshake sys.log("ws connect: " + resource); }).addListener("close", function () { // emitted when server or client closes connection - clients.remove(websocket); + allViewsMetric.removeClient(websocket); + salesMetric.removeClient(websocket); sys.log("ws close"); }); }).listen(WEB_SOCKET_PORT); From 54cb9036652712dc37e663b383972c3886be4eb4 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 17 Apr 2010 15:46:21 -0400 Subject: [PATCH 032/267] More work to upgrade to 0.1.91 api --- lib/proxy.js | 4 ++-- lib/service_json.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/proxy.js b/lib/proxy.js index 81966b2..7e6dbcf 100644 --- a/lib/proxy.js +++ b/lib/proxy.js @@ -6,6 +6,6 @@ exports.route = function(path, remoteURL, req, res) { services.fetchJSON(remoteURL, function(data) { res.writeHead(200, {'Content-type': "text/plain"}); res.write(data); - res.close(); + res.end(); }); -}; \ No newline at end of file +}; diff --git a/lib/service_json.js b/lib/service_json.js index 4c49307..8009183 100644 --- a/lib/service_json.js +++ b/lib/service_json.js @@ -20,5 +20,5 @@ exports.fetchJSON = function(remoteURL, callback) { callback(response.client.responseBodyParts); }); }); - request.close(); + request.end(); }; From fba0e8b817e2a5bc5874de51894374e4a8811a02 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 17 Apr 2010 15:53:01 -0400 Subject: [PATCH 033/267] Fix paperboy and ws to work with node v0.1.91 --- .gitmodules | 3 ++ deps/node-paperboy | 2 +- deps/node-ws | 1 + deps/ws.js | 106 --------------------------------------------- server.js | 2 +- 5 files changed, 6 insertions(+), 108 deletions(-) create mode 160000 deps/node-ws delete mode 100644 deps/ws.js diff --git a/.gitmodules b/.gitmodules index 5d36676..ceb74d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "deps/node-mongodb-native"] path = deps/node-mongodb-native url = git://github.com/christkv/node-mongodb-native.git +[submodule "deps/node-ws"] + path = deps/node-ws + url = git://github.com/mnutt/node.ws.js diff --git a/deps/node-paperboy b/deps/node-paperboy index f4e7ced..2f2568b 160000 --- a/deps/node-paperboy +++ b/deps/node-paperboy @@ -1 +1 @@ -Subproject commit f4e7cedb816130dbc85dbd79b72d0585346bdbbc +Subproject commit 2f2568b6abc649e2d1d8d0e575a2b08e33ae1a30 diff --git a/deps/node-ws b/deps/node-ws new file mode 160000 index 0000000..3cda892 --- /dev/null +++ b/deps/node-ws @@ -0,0 +1 @@ +Subproject commit 3cda89274a7e2084f07a68820f09228be05fd077 diff --git a/deps/ws.js b/deps/ws.js deleted file mode 100644 index 4105123..0000000 --- a/deps/ws.js +++ /dev/null @@ -1,106 +0,0 @@ -// Based on: -// http://github.com/alexanderte/websocket-server-node.js -// http://github.com/Guille/node.websocket.js - -function nano(template, data) { - return template.replace(/\{([\w\.]*)}/g, function (str, key) { - var keys = key.split("."), value = data[keys.shift()]; - keys.forEach(function (key) { value = value[key] }); - return value; - }); -} - -var sys = require("sys"), - tcp = require("net"), - headerExpressions = [ - /^GET (\/[^\s]*) HTTP\/1\.1$/, - /^Upgrade: WebSocket$/, - /^Connection: Upgrade$/, - /^Host: (.+)$/, - /^Origin: (.+)$/ - ], - handshakeTemplate = [ - 'HTTP/1.1 101 Web Socket Protocol Handshake', - 'Upgrade: WebSocket', - 'Connection: Upgrade', - 'WebSocket-Origin: {origin}', - 'WebSocket-Location: ws://{host}{resource}', - '', - '' - ].join("\r\n"), - policy_file = ''; - -exports.createServer = function (websocketListener) { - return tcp.createServer(function (socket) { - socket.setTimeout(0); - socket.setNoDelay(true); - socket.setEncoding("utf8"); - - var emitter = new process.EventEmitter(), - handshaked = false; - - function handle(data) { - if(data[0] == "\u0000" && data[data.length - 1] == "\ufffd") { - emitter.emit("receive", data.substr(1, data.length - 2)); - } else { - socket.close(); - } - } - - function handshake(data) { - var headers = data.split("\r\n"); - - if(//.exec(headers[0])) { - socket.write(policy_file); - socket.close(); - return; - } - - var matches = [], match; - for (var i = 0, l = headerExpressions.length; i < l; i++) { - match = headerExpressions[i].exec(headers[i]); - - if (match) { - if(match.length > 1) { - matches.push(match[1]); - } - } else { - socket.close(); - } - } - - socket.write(nano(handshakeTemplate, { - resource: matches[0], - host: matches[1], - origin: matches[2], - })); - - handshaked = true; - emitter.emit("connect", matches[0]); - } - - socket.addListener("data", function (data) { - if(handshaked) { - handle(data); - } else { - handshake(data); - } - }).addListener("end", function () { - socket.close(); - }).addListener("close", function () { - if (handshaked) { // don't emit close from policy-requests - emitter.emit("close"); - } - }); - - emitter.write = function (data) { - socket.write('\u0000' + data + '\uffff'); - } - - emitter.close = function () { - socket.close(); - } - - websocketListener(emitter); // emits: "connect", "receive", "close", provides: send(data), close() - }); -} diff --git a/server.js b/server.js index 2cf7792..3903948 100644 --- a/server.js +++ b/server.js @@ -2,7 +2,7 @@ var sys = require('sys'), http = require('http'), fs = require('fs'), path = require('path'), - ws = require('./deps/ws'), + ws = require('./deps/node-ws/ws'), proxy = require('./lib/proxy'), pageview = require('./lib/view'), metric = require('./lib/metric'), From 71a36eddee9551dca1e4d34334bbcace24b5a761 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 18 Apr 2010 13:01:52 -0400 Subject: [PATCH 034/267] Add content-length to tracking pixel --- server.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 3903948..c86b8de 100644 --- a/server.js +++ b/server.js @@ -35,7 +35,9 @@ db.open(function(p_db) { collection.insert(env); // sys.log(JSON.stringify(env, null, 2)); - res.writeHead(200, {'Content-Type': 'image/gif', 'Content-Disposition': 'inline'}); + res.writeHead(200, { 'Content-Type': 'image/gif', + 'Content-Disposition': 'inline', + 'Content-Length': '43' }); res.write(pixel, 'binary'); res.end(); From a8828d0fa7810e4590ef7a833c706794313267ed Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 18 Apr 2010 17:26:07 -0400 Subject: [PATCH 035/267] Refactor in preparation for jspec --- lib/hummingbird.js | 80 +++++++++++++++++++++++++++++++++++++ lib/metric.js | 4 +- server.js | 98 +++++++++++++++++----------------------------- 3 files changed, 117 insertions(+), 65 deletions(-) create mode 100644 lib/hummingbird.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js new file mode 100644 index 0000000..f04c59e --- /dev/null +++ b/lib/hummingbird.js @@ -0,0 +1,80 @@ +var sys = require('sys'), + fs = require('fs'), + pageview = require('view'), + metric = require('metric'), + querystring = require('querystring'); + +var Hummingbird = function() { + this.pixel = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); + this.test = "true"; + + this.init(); +}; + +Hummingbird.prototype = { + init: function() { + this.allViewsMetric = new metric.Metric({total: 0, cartAdds: 0}, 50); + this.salesMetric = new metric.Metric({sales: {}}, 500); + + this.allViewsMetric.run(); + this.salesMetric.run(); + }, + + setCollection: function(collection) { + this.collection = collection; + }, + + addClient: function(client) { + this.allViewsMetric.clients.push(client); + this.salesMetric.clients.push(client); + }, + + removeClient: function(client) { + this.allViewsMetric.clients.remove(client); + this.salesMetric.clients.remove(client); + }, + + serveRequest: function(req, res) { + var env = querystring.parse(req.url.split('?')[1]); + env.timestamp = (new Date()); + // sys.log(JSON.stringify(env, null, 2)); + + this.writePixel(res); + + this.collection.insert(env); + + var view = new pageview.View(env); + if(view.urlKey()) { + if(this.salesMetric.data.sales[view.urlKey()]) { + this.salesMetric.data.sales[view.urlKey()] += 1; + } else { + this.salesMetric.data.sales[view.urlKey()] = 1; + } + } + + if(view.event() && view.event() === "cart_add") { + this.allViewsMetric.data.cartAdds += 1; + } + + this.allViewsMetric.data.total += 1; + }, + + writePixel: function(res) { + res.writeHead(200, { 'Content-Type': 'image/gif', + 'Content-Disposition': 'inline', + 'Content-Length': '43' }); + res.write(this.pixel, 'binary'); + res.end(); + }, + + handleError: function(req, res, e) { + res.writeHead(500, {}); + res.end(); + + e.stack = e.stack.split('\n'); + e.url = req.url; + sys.log(JSON.stringify(e, null, 2)); + } +}; + +exports.Hummingbird = Hummingbird; \ No newline at end of file diff --git a/lib/metric.js b/lib/metric.js index 2f74835..7d16fa4 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -17,7 +17,7 @@ Metric.prototype = { }, runner: function(metric) { -// sys.log(JSON.stringify(metric.data)); + // sys.log(JSON.stringify(metric.data)); // NOTE: using 'metric' in place of 'this', since run from setInterval metric.clients.each(function(client) { try { @@ -39,7 +39,7 @@ Metric.prototype = { }, resetData: function() { - this.data = this.initialData; + this.data = JSON.parse(JSON.stringify(this.initialData)); }, stop: function() { diff --git a/server.js b/server.js index c86b8de..f7505f4 100644 --- a/server.js +++ b/server.js @@ -1,15 +1,14 @@ +require.paths.unshift(__dirname + '/lib'); + var sys = require('sys'), - http = require('http'), - fs = require('fs'), - path = require('path'), - ws = require('./deps/node-ws/ws'), - proxy = require('./lib/proxy'), - pageview = require('./lib/view'), - metric = require('./lib/metric'), - querystring = require('querystring'), - arrays = require('./deps/arrays'), - paperboy = require('./deps/node-paperboy'), - mongo = require('./deps/node-mongodb-native/lib/mongodb'); + http = require('http'), + path = require('path'), + ws = require('./deps/node-ws/ws'), + proxy = require('proxy'), + arrays = require('./deps/arrays'), + paperboy = require('./deps/node-paperboy'), + mongo = require('./deps/node-mongodb-native/lib/mongodb'), + hb = require('hummingbird'); var WEBROOT = path.join(path.dirname(__filename), 'public'), TRACKING_PORT = 8000, @@ -18,44 +17,19 @@ var WEBROOT = path.join(path.dirname(__filename), 'public'), var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); -var allViewsMetric = new metric.Metric({total: 0, cartAdds: 0}, 50); -var salesMetric = new metric.Metric({sales: {}}, 500); -allViewsMetric.run(); -salesMetric.run(); +var hummingbird = new hb.Hummingbird(); -var pixel = fs.readFileSync("images/tracking.gif", 'binary'); db.open(function(p_db) { db.createCollection('visits', function(err, collection) { db.collection('visits', function(err, collection) { - http.createServer(function (req, res) { + hummingbird.setCollection(collection); + http.createServer(function(req, res) { try { - var env = querystring.parse(req.url.split('?')[1]); - env.timestamp = (new Date()); - collection.insert(env); - // sys.log(JSON.stringify(env, null, 2)); - - res.writeHead(200, { 'Content-Type': 'image/gif', - 'Content-Disposition': 'inline', - 'Content-Length': '43' }); - res.write(pixel, 'binary'); - res.end(); - - var view = new pageview.View(env); - if(view.urlKey()) { - if(salesMetric.data.sales[view.urlKey()]) { - salesMetric.data.sales[view.urlKey()] += 1; - } else { - salesMetric.data.sales[view.urlKey()] = 1; - } - } - - if(view.event() && view.event() === "cart_add") { - allViewsMetric.data.cartAdds += 1; - } - - allViewsMetric.data.total += 1; - } catch(e) { e.stack = e.stack.split('\n'); sys.log(JSON.stringify(e, null, 2)); } + hummingbird.serveRequest(req, res); + } catch(e) { + hummingbird.handleError(req, res, e); + } }).listen(TRACKING_PORT); }); }); @@ -65,36 +39,34 @@ sys.puts('Tracking server running at http://localhost:' + TRACKING_PORT + '/trac // Websocket TCP server ws.createServer(function (websocket) { - allViewsMetric.addClient(websocket); - salesMetric.addClient(websocket); + hummingbird.addClient(websocket); websocket.addListener("connect", function (resource) { // emitted after handshake sys.log("ws connect: " + resource); }).addListener("close", function () { // emitted when server or client closes connection - allViewsMetric.removeClient(websocket); - salesMetric.removeClient(websocket); + hummingbird.removeClient(websocket); sys.log("ws close"); }); }).listen(WEB_SOCKET_PORT); sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); -try { - http.createServer(function(req, res) { - if(req.url.match(/\/sale_list/)) { - proxy.route("/sale_list", "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); - } else { - paperboy.deliver(WEBROOT, req, res) - .addHeader('Content-Type', "text/plain") - .after(function(statCode) { sys.log([statCode, req.method, req.url, req.connection.remoteAddress].join(' ')); }); - } - }).listen(MONITOR_PORT); +http.createServer(function(req, res) { + if(req.url.match(/\/sale_list/)) { + proxy.route("/sale_list", + "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); + } else { + paperboy.deliver(WEBROOT, req, res) + .addHeader('Content-Type', "text/plain") + .after(function(statCode) { + sys.log([statCode, + req.method, + req.url, + req.connection.remoteAddress].join(' ')); + }); + } +}).listen(MONITOR_PORT); - sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); -} catch(e) { - if(e && e.message == "Address already in use") { - sys.log('Detected port ' + MONITOR_PORT + ' in use; assuming it is being served by another webserver.'); - } else { throw(e); } -} +sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); \ No newline at end of file From 4e2d70f0c4e0d7b4ee9198afa741d4ab5bc692a1 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 18 Apr 2010 18:12:55 -0400 Subject: [PATCH 036/267] Add some specs --- lib/hummingbird.js | 3 +-- server.js | 8 +++---- spec/node.js | 43 +++++++++++++++++++++++++++++++++++ spec/unit/hummingbird_spec.js | 38 +++++++++++++++++++++++++++++++ spec/unit/spec.helper.js | 0 spec/unit/view_spec.js | 33 +++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 spec/node.js create mode 100644 spec/unit/hummingbird_spec.js create mode 100644 spec/unit/spec.helper.js create mode 100644 spec/unit/view_spec.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js index f04c59e..5922774 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -2,12 +2,11 @@ var sys = require('sys'), fs = require('fs'), pageview = require('view'), metric = require('metric'), + arrays = require('deps/arrays'), querystring = require('querystring'); var Hummingbird = function() { this.pixel = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); - this.test = "true"; - this.init(); }; diff --git a/server.js b/server.js index f7505f4..34255f8 100644 --- a/server.js +++ b/server.js @@ -1,13 +1,13 @@ require.paths.unshift(__dirname + '/lib'); +require.paths.unshift(__dirname); var sys = require('sys'), http = require('http'), path = require('path'), - ws = require('./deps/node-ws/ws'), + ws = require('deps/node-ws/ws'), proxy = require('proxy'), - arrays = require('./deps/arrays'), - paperboy = require('./deps/node-paperboy'), - mongo = require('./deps/node-mongodb-native/lib/mongodb'), + paperboy = require('deps/node-paperboy'), + mongo = require('deps/node-mongodb-native/lib/mongodb'), hb = require('hummingbird'); var WEBROOT = path.join(path.dirname(__filename), 'public'), diff --git a/spec/node.js b/spec/node.js new file mode 100644 index 0000000..41b5888 --- /dev/null +++ b/spec/node.js @@ -0,0 +1,43 @@ + +require.paths.unshift('spec', '/usr/local/Cellar/ruby-enterprise-edition/2009.10/lib/ruby/gems/1.8/gems/jspec-4.2.1/lib', 'lib') +require.paths.unshift(__dirname + '/../lib'); +require.paths.unshift(__dirname + '/..'); + +require('jspec') +require('unit/spec.helper') +hb = require('hummingbird') +http = require('http'); +v = require('view'); + +MockRequest = function(url) { + this.url = url; +} + +MockResponse = function() { + this.data = null; + this.headers = null; + this.statusCode = null; + this.state = "open"; +}; + +MockResponse.prototype = { + writeHead: function(statusCode, headers) { + this.statusCode = statusCode; + this.headers = headers; + }, + + write: function(data, dataType) { + this.data = data; + this.dataType = dataType; + }, + + end: function() { + this.state = "closed"; + } +}; + +JSpec + .exec('spec/unit/hummingbird_spec.js') + .exec('spec/unit/view_spec.js') + .run({ reporter: JSpec.reporters.Terminal, fixturePath: 'spec/fixtures', failuresOnly: true }) + .report() diff --git a/spec/unit/hummingbird_spec.js b/spec/unit/hummingbird_spec.js new file mode 100644 index 0000000..6ef58c5 --- /dev/null +++ b/spec/unit/hummingbird_spec.js @@ -0,0 +1,38 @@ +describe 'Hummingbird' + describe '.writePixel' + it 'outputs a 1x1 tracking pixel to the response' + var req = new MockRequest("/tracking.gif") + var res = new MockResponse() + var hummingbird = new hb.Hummingbird() + + hummingbird.writePixel(res) + + res.data.length.should.equal 43 + res.state.should.equal "closed" + res.data.should.match /GIF/ + end + end + + describe '.addClient' + it 'increases the allViewsMetric client count by 1' + var hummingbird = new hb.Hummingbird(); + var mockClient = {}; + + hummingbird.allViewsMetric.clients.length.should.equal 0 + hummingbird.addClient(mockClient); + hummingbird.allViewsMetric.clients.length.should.equal 1 + end + end + + describe '.removeClient' + it 'decreases the allViewsMetric client count by 1' + var hummingbird = new hb.Hummingbird(); + var mockClient = {}; + hummingbird.addClient(mockClient); + + hummingbird.allViewsMetric.clients.length.should.equal 1 + hummingbird.removeClient(mockClient); + hummingbird.allViewsMetric.clients.length.should.equal 0 + end + end +end diff --git a/spec/unit/spec.helper.js b/spec/unit/spec.helper.js new file mode 100644 index 0000000..e69de29 diff --git a/spec/unit/view_spec.js b/spec/unit/view_spec.js new file mode 100644 index 0000000..555408d --- /dev/null +++ b/spec/unit/view_spec.js @@ -0,0 +1,33 @@ +describe 'View' + describe '.urlKey()' + it 'extracts a url_key from a sale url' + var env = { u: "http://localhost/s/gucci" } + + var view = new v.View(env) + view.urlKey().should.equal "gucci" + end + + it 'extracts a url_key from a product url' + var env = { u: "http://localhost/s/gucci/product/12345" } + + var view = new v.View(env) + view.urlKey().should.equal "gucci" + end + + it 'handles bad urls gracefully' + var env = { u: "asdfasfasd/sdfof/foo" } + + var view = new v.View(env) + view.urlKey().should.be_null + end + end + + describe '.event()' + it 'extracts the cart_add event' + var env = { events: "scAdd,scJunk" } + var view = new v.View(env); + + view.event().should.equal "cart_add" + end + end +end \ No newline at end of file From bfba6e39f25cac99ee6db074ddb3351dc30ec0c5 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 18 Apr 2010 18:39:38 -0400 Subject: [PATCH 037/267] Add logic to detect is UI webserver is already running --- server.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/server.js b/server.js index 34255f8..d151525 100644 --- a/server.js +++ b/server.js @@ -53,20 +53,24 @@ ws.createServer(function (websocket) { sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); -http.createServer(function(req, res) { - if(req.url.match(/\/sale_list/)) { - proxy.route("/sale_list", - "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); - } else { - paperboy.deliver(WEBROOT, req, res) - .addHeader('Content-Type', "text/plain") - .after(function(statCode) { - sys.log([statCode, - req.method, - req.url, - req.connection.remoteAddress].join(' ')); - }); - } -}).listen(MONITOR_PORT); +try { + http.createServer(function(req, res) { + if(req.url.match(/\/sale_list/)) { + proxy.route("/sale_list", + "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); + } else { + paperboy.deliver(WEBROOT, req, res) + .addHeader('Content-Type', "text/plain") + .after(function(statCode) { + sys.log([statCode, + req.method, + req.url, + req.connection.remoteAddress].join(' ')); + }); + } + }).listen(MONITOR_PORT); -sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); \ No newline at end of file + sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); +} catch(e) { + sys.puts('Detected webserver already running on http://localhost:' + MONITOR_PORT + '.'); +} \ No newline at end of file From a7e379eca558e9837a1253aea7e77fa6bc30bb67 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 18 Apr 2010 18:39:54 -0400 Subject: [PATCH 038/267] Have to write a body when outputting 500 errors --- lib/hummingbird.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 5922774..6077731 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -68,6 +68,7 @@ Hummingbird.prototype = { handleError: function(req, res, e) { res.writeHead(500, {}); + res.write("Server error"); res.end(); e.stack = e.stack.split('\n'); From b2f374ecbd7207b731ce7820d3780f72039408fd Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 18 Apr 2010 20:16:30 -0400 Subject: [PATCH 039/267] Roll back to node v0.1.33 until ry fixes bug in node v0.1.91 http parser --- deps/node-mongodb-native | 2 +- deps/node-paperboy | 2 +- deps/node-ws | 2 +- lib/hummingbird.js | 6 +++--- lib/proxy.js | 2 +- lib/service_json.js | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/deps/node-mongodb-native b/deps/node-mongodb-native index 5401a62..921d13c 160000 --- a/deps/node-mongodb-native +++ b/deps/node-mongodb-native @@ -1 +1 @@ -Subproject commit 5401a62e7a139f9d0f379e46e6ad3107810f7c7c +Subproject commit 921d13cd0696fbf3bafa718d54e16f55bc788f52 diff --git a/deps/node-paperboy b/deps/node-paperboy index 2f2568b..f4e7ced 160000 --- a/deps/node-paperboy +++ b/deps/node-paperboy @@ -1 +1 @@ -Subproject commit 2f2568b6abc649e2d1d8d0e575a2b08e33ae1a30 +Subproject commit f4e7cedb816130dbc85dbd79b72d0585346bdbbc diff --git a/deps/node-ws b/deps/node-ws index 3cda892..2634e78 160000 --- a/deps/node-ws +++ b/deps/node-ws @@ -1 +1 @@ -Subproject commit 3cda89274a7e2084f07a68820f09228be05fd077 +Subproject commit 2634e78c7371017460ca6b8040027d729ab0434c diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 6077731..f035f50 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -63,13 +63,13 @@ Hummingbird.prototype = { 'Content-Disposition': 'inline', 'Content-Length': '43' }); res.write(this.pixel, 'binary'); - res.end(); + res.close(); }, handleError: function(req, res, e) { res.writeHead(500, {}); res.write("Server error"); - res.end(); + res.close(); e.stack = e.stack.split('\n'); e.url = req.url; @@ -77,4 +77,4 @@ Hummingbird.prototype = { } }; -exports.Hummingbird = Hummingbird; \ No newline at end of file +exports.Hummingbird = Hummingbird; diff --git a/lib/proxy.js b/lib/proxy.js index 7e6dbcf..8a580c7 100644 --- a/lib/proxy.js +++ b/lib/proxy.js @@ -6,6 +6,6 @@ exports.route = function(path, remoteURL, req, res) { services.fetchJSON(remoteURL, function(data) { res.writeHead(200, {'Content-type': "text/plain"}); res.write(data); - res.end(); + res.close(); }); }; diff --git a/lib/service_json.js b/lib/service_json.js index 8009183..4c49307 100644 --- a/lib/service_json.js +++ b/lib/service_json.js @@ -20,5 +20,5 @@ exports.fetchJSON = function(remoteURL, callback) { callback(response.client.responseBodyParts); }); }); - request.end(); + request.close(); }; From a10ed8119c8400694c2173de1e622a933024246f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 18 Apr 2010 22:51:42 -0400 Subject: [PATCH 040/267] Switch timestamp to integer for easier parsing in mongo --- lib/hummingbird.js | 2 +- spec/node.js | 13 +++++++++++++ spec/unit/hummingbird_spec.js | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index f035f50..7e8e8b6 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -35,7 +35,7 @@ Hummingbird.prototype = { serveRequest: function(req, res) { var env = querystring.parse(req.url.split('?')[1]); - env.timestamp = (new Date()); + env.timestamp = (new Date()).getTime(); // sys.log(JSON.stringify(env, null, 2)); this.writePixel(res); diff --git a/spec/node.js b/spec/node.js index 41b5888..99e3db1 100644 --- a/spec/node.js +++ b/spec/node.js @@ -8,6 +8,7 @@ require('unit/spec.helper') hb = require('hummingbird') http = require('http'); v = require('view'); +sys = require('sys'); MockRequest = function(url) { this.url = url; @@ -31,11 +32,23 @@ MockResponse.prototype = { this.dataType = dataType; }, + close: function() { this.end(); }, + end: function() { this.state = "closed"; } }; +MockCollection = function() { + this.inserts = []; +} + +MockCollection.prototype = { + insert: function(data) { + this.inserts.push(data) + } +} + JSpec .exec('spec/unit/hummingbird_spec.js') .exec('spec/unit/view_spec.js') diff --git a/spec/unit/hummingbird_spec.js b/spec/unit/hummingbird_spec.js index 6ef58c5..5d3692d 100644 --- a/spec/unit/hummingbird_spec.js +++ b/spec/unit/hummingbird_spec.js @@ -35,4 +35,19 @@ describe 'Hummingbird' hummingbird.allViewsMetric.clients.length.should.equal 0 end end + + describe '.serveRequest' + it 'adds a timestamp to the environment' + var hummingbird = new hb.Hummingbird() + var req = new MockRequest("http://localhost/t.gif?u=foobar") + var res = new MockResponse() + var collection = new MockCollection() + hummingbird.setCollection(collection) + + hummingbird.serveRequest(req, res) + + collection.inserts[0].timestamp.should.be_greater_than 1270000000000 + collection.inserts[0].timestamp.should.be_less_than 1970000000000 + end + end end From 2d8f2f4064369c43b29e64586f1c9fb9dda005c3 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 19 Apr 2010 00:01:29 -0400 Subject: [PATCH 041/267] update readme --- README | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README b/README index 2bc7f22..ae31b9e 100644 --- a/README +++ b/README @@ -7,3 +7,18 @@ Description Hummingbird serves a 1x1 tracking pixel to users. In the browser's GET request it sends back tracking data generated by javascript. + + +Requirements + + * node.js v0.1.33 + * mongodb + + +Installation + + git clone git://github.com/mnutt/hummingbird.git + cd hummingbird + git submodule update --init + mongod & (or start mongo some other way) + node server.js From f1c3801203e0d4c2133ae21e3c90077e50b3b9bd Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 19 Apr 2010 15:22:39 -0400 Subject: [PATCH 042/267] Allow local UI to use prod server --- public/js/websocket.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/js/websocket.js b/public/js/websocket.js index 47d72af..ba72c84 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -16,7 +16,11 @@ Hummingbird.WebSocket.start = function() { cartAdds.width = $(window).width() - 160; var cartAddsGraph = new Hummingbird.Graph(cartAdds); - var wsServer = "ws://" + document.location.hostname + ":8080"; + if(document.location.search.match(/use_prod/)) { + var wsServer = "ws://hummingbird.giltrunway.com:8080"; + } else { + var wsServer = "ws://" + document.location.hostname + ":8080"; + } var ws = new WebSocket(wsServer); ws.onmessage = function(evt) { var data = JSON.parse(evt.data); From 7a91ca3542a8cb731eba59e3a90e3e3451dd492e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 19 Apr 2010 15:46:35 -0400 Subject: [PATCH 043/267] Draw empty graph to start --- public/js/analytics.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/public/js/analytics.js b/public/js/analytics.js index 8bda0d1..9dcb1b1 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -20,6 +20,8 @@ Hummingbird.Graph.prototype = { this.bgLineColor = "#555"; this.canvasHeight = $(this.canvas).height(); this.canvasWidth = $(this.canvas).width(); + + this.drawEmptyGraph(); }, addValue: function(value) { @@ -47,6 +49,13 @@ Hummingbird.Graph.prototype = { return this.trafficLog.sum() / this.trafficLog.length; }, + drawEmptyGraph: function() { + var dataPoints = Math.ceil(this.canvasWidth / 6) + while(dataPoints--) { + this.drawLogPath(0); + } + }, + drawLogPath: function(percent) { this.addValue(percent); var average = this.runningAverage(); From b54f64fac4cc363d8f65e18d3ea88052d7e6ba94 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 19 Apr 2010 17:25:40 -0400 Subject: [PATCH 044/267] Add date timestamps to graph --- public/js/analytics.js | 43 ++++++++++++++++++++++++++++++++++++++---- public/js/helpers.js | 20 ++++++++++++++++++++ public/js/websocket.js | 2 +- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/public/js/analytics.js b/public/js/analytics.js index 9dcb1b1..a915ed7 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -1,10 +1,12 @@ if(!Hummingbird) { var Hummingbird = {}; } -Hummingbird.Graph = function(canvas) { +Hummingbird.Graph = function(canvas, options) { if ( !(this instanceof Hummingbird.Graph) ) { return new Hummingbird.Graph(canvas); } + this.options = options || {}; + this.canvas = canvas; this.trafficLog = []; @@ -18,10 +20,13 @@ Hummingbird.Graph.prototype = { this.lineColors = [ "#FFFFFF", "#3BA496", "#65B88A", "#F1E29F", "#C44939", "#983839" ]; this.bgLineColor = "#555"; - this.canvasHeight = $(this.canvas).height(); + this.canvasHeight = $(this.canvas).height() - 15; this.canvasWidth = $(this.canvas).width(); + this.lineWidth = 3; + this.drawEmptyGraph(); + this.tick = 0; }, addValue: function(value) { @@ -42,7 +47,8 @@ Hummingbird.Graph.prototype = { alert("Sorry, this browser doesn't support canvas"); } - this.context.lineWidth = 3; + this.context.font = "10px Lucida Grande"; + this.context.textAlign = "right"; }, runningAverage: function() { @@ -56,15 +62,44 @@ Hummingbird.Graph.prototype = { } }, + logDate: function() { + // Draw text background + this.context.lineCap = "round"; + this.context.lineWidth = 12; + this.context.beginPath(); + this.context.moveTo(this.canvasWidth - 16, this.canvasHeight + 8); + this.context.strokeStyle = "#000"; + this.context.lineTo(this.canvasWidth - 70, this.canvasHeight + 8); + this.context.stroke(); + this.context.closePath(); + + // Draw date text + this.context.fillStyle = "#FFF"; + var date = new Date(); + + this.context.fillText(date.formattedTime(), this.canvasWidth - 20, this.canvasHeight + 12); + }, + drawLogPath: function(percent) { + if(this.options.logDate) { + this.tick++; + + if(this.tick % 100 == 0) { + this.logDate(); + this.tick = 0; + } + } + this.addValue(percent); + var average = this.runningAverage(); var height = Math.max(average * this.canvasHeight, 1); var colorIndex = Math.min(Math.ceil((average / 2) * 10), 5); var color = this.lineColors[colorIndex]; var endingPoint = this.canvasHeight - height; - this.shiftCanvas(6, 0); + this.shiftCanvas(this.lineWidth * 2, 0); + this.context.lineWidth = this.lineWidth; this.context.beginPath(); this.context.strokeStyle = color; this.context.moveTo(this.canvasWidth - 10, this.canvasHeight); diff --git a/public/js/helpers.js b/public/js/helpers.js index 9eb9612..44d570d 100644 --- a/public/js/helpers.js +++ b/public/js/helpers.js @@ -2,3 +2,23 @@ Array.prototype.sum = function() { return (! this.length) ? 0 : this.slice(1).sum() + ((typeof this[0] == 'number') ? this[0] : 0); }; + +Date.prototype.formattedTime = function() { + var formattedDate = this.getHours(); + + var minutes = this.getMinutes(); + if(minutes > 9) { + formattedDate += ":" + minutes; + } else { + formattedDate += ":0" + minutes; + } + + var seconds = this.getSeconds(); + if(seconds > 9) { + formattedDate += ":" + seconds; + } else { + formattedDate += ":0" + seconds; + } + + return formattedDate; +}; \ No newline at end of file diff --git a/public/js/websocket.js b/public/js/websocket.js index ba72c84..8a51b2a 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -10,7 +10,7 @@ Hummingbird.WebSocket.start = function() { var canvas = $("#log").get(0); canvas.width = $(window).width() - 160; - var totalGraph = new Hummingbird.Graph(canvas); + var totalGraph = new Hummingbird.Graph(canvas, {logDate: true}); var cartAdds = $("#cart_adds").get(0); cartAdds.width = $(window).width() - 160; From dfb7718b3f688d60bf1cbb9f27b413f05dc33ad2 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 19 Apr 2010 17:29:00 -0400 Subject: [PATCH 045/267] Add 'per second' to make graphs clearer --- public/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/index.html b/public/index.html index 141038c..c93e720 100644 --- a/public/index.html +++ b/public/index.html @@ -20,7 +20,7 @@

Hummingbird

-

Total Pageviews

+

Total Pageviews / Second

400

@@ -54,7 +54,7 @@

Total Pageviews

-

Total Cart Adds

+

Total Cart Adds / Second

200

From c671d9cc4cfa366f39a14274fd047c0b8a3f9611 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 20 Apr 2010 01:54:45 -0400 Subject: [PATCH 046/267] Auto-scale graphs --- public/css/main.css | 6 ++- public/index.html | 58 +++++---------------- public/js/analytics.js | 115 +++++++++++++++++++++++++++++++++-------- public/js/sales.js | 2 +- public/js/websocket.js | 18 +++---- 5 files changed, 121 insertions(+), 78 deletions(-) diff --git a/public/css/main.css b/public/css/main.css index 5a863ef..67b7903 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -10,6 +10,7 @@ h1 { color: #FFF; text-transform: uppercase; font-family: 'TitilliumText14L800wt', sans-serif; + margin-left: 58px; } div.hummingbird_graph h2 { @@ -17,13 +18,14 @@ div.hummingbird_graph h2 { text-transform: uppercase; font-size: 0.9em; margin-bottom: 0.2em; - margin-left: 55px; + margin-left: 58px; } div.hummingbird_graph canvas { float: left; padding: 14px 0 20px 0; color: #F00; + font-weight: bold; } div.hummingbird_graph div.axis_left, @@ -33,6 +35,7 @@ div.hummingbird_graph div.axis_right { color: #4F4C4B; font-weight: bold; font-size: 0.8em; + width: 30px; } div.hummingbird_graph div.axis_left { @@ -50,6 +53,7 @@ div.hummingbird_graph div.axis_right { } #sales { + margin-left: 50px; } #sales div.sale { diff --git a/public/index.html b/public/index.html index c93e720..3e6f342 100644 --- a/public/index.html +++ b/public/index.html @@ -18,61 +18,27 @@

Hummingbird

-
- -

Total Pageviews / Second

- -
-

400

-

350

-

300

-

250

-

200

-

150

-

100

-

50

-

0

-
- - - -
-

400

-

350

-

300

-

250

-

200

-

150

-

100

-

50

-

0

-
+
+ +

Total Pageviews / Second

+ +
+ +
-
+
-

Total Cart Adds / Second

+

Total Cart Adds / Second

-
-

200

-

150

-

100

-

50

-

0

-
+
- + -
-

200

-

150

-

100

-

50

-

0

-
+
diff --git a/public/js/analytics.js b/public/js/analytics.js index a915ed7..b321573 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -1,13 +1,22 @@ if(!Hummingbird) { var Hummingbird = {}; } -Hummingbird.Graph = function(canvas, options) { +Hummingbird.Graph = function(el, options) { if ( !(this instanceof Hummingbird.Graph) ) { return new Hummingbird.Graph(canvas); } - this.options = options || {}; + var defaults = { + showLogDate: false, + showMarkers: true, + ratePerSecond: 10 + } + + this.options = $.extend(defaults, options); - this.canvas = canvas; + this.scale = 800; + this.el = $(el); + this.canvas = $(el).find('canvas').get(0); + this.valueElement = this.el.find('span.value'); this.trafficLog = []; this.init(); @@ -17,21 +26,49 @@ Hummingbird.Graph.prototype = { init: function() { this.setupContext(); - this.lineColors = [ "#FFFFFF", "#3BA496", "#65B88A", - "#F1E29F", "#C44939", "#983839" ]; + this.lineColors = { + 25: "#5BC4B6", + 50: "#3BA496", + 100: "#65B88A", + 200: "#F1E29F", + 400: "#C44939", + 800: "#983839", + 1600: "#333", + def: "#7BF4D6" + }; this.bgLineColor = "#555"; - this.canvasHeight = $(this.canvas).height() - 15; + this.canvasHeight = $(this.canvas).height() - 16; this.canvasWidth = $(this.canvas).width(); + this.numMarkers = Math.floor(this.canvasHeight / 23); + this.resetMarkers(); + this.lineWidth = 3; this.drawEmptyGraph(); this.tick = 0; }, + resetMarkers: function() { + var leftMarkerContainer = this.el.find('div.axis_left'); + var rightMarkerContainer = this.el.find('div.axis_right'); + + if(leftMarkerContainer.length == 0) { return; } + + leftMarkerContainer.html(''); + rightMarkerContainer.html(''); + + var incr = this.scale / this.numMarkers; + for(var i = 0; i <= this.numMarkers; i++) { + var markerValue = Math.floor(this.scale - (i * incr)); + leftMarkerContainer.append('

' + markerValue + '

'); + rightMarkerContainer.append('

' + markerValue + '

'); + } + }, + addValue: function(value) { this.trafficLog.push(value); - if(this.trafficLog.length > 20) { + if(this.trafficLog.length > this.options.ratePerSecond) { this.trafficLog.shift(); } }, @@ -47,7 +84,7 @@ Hummingbird.Graph.prototype = { alert("Sorry, this browser doesn't support canvas"); } - this.context.font = "10px Lucida Grande"; + this.context.font = "bold 10px Andale Mono, sans-serif"; this.context.textAlign = "right"; }, @@ -56,7 +93,7 @@ Hummingbird.Graph.prototype = { }, drawEmptyGraph: function() { - var dataPoints = Math.ceil(this.canvasWidth / 6) + var dataPoints = Math.ceil(this.canvasWidth / (this.lineWidth * 2)) while(dataPoints--) { this.drawLogPath(0); } @@ -67,35 +104,65 @@ Hummingbird.Graph.prototype = { this.context.lineCap = "round"; this.context.lineWidth = 12; this.context.beginPath(); - this.context.moveTo(this.canvasWidth - 16, this.canvasHeight + 8); + this.context.moveTo(this.canvasWidth - 16, this.canvasHeight + 10); this.context.strokeStyle = "#000"; - this.context.lineTo(this.canvasWidth - 70, this.canvasHeight + 8); + this.context.lineTo(this.canvasWidth - 70, this.canvasHeight + 10); this.context.stroke(); this.context.closePath(); + this.context.lineCap = "square"; // Draw date text this.context.fillStyle = "#FFF"; var date = new Date(); - this.context.fillText(date.formattedTime(), this.canvasWidth - 20, this.canvasHeight + 12); + this.context.fillText(date.formattedTime(), this.canvasWidth - 16, this.canvasHeight + 14); + }, + + rescale: function(percent) { + if(percent == 0) { return; } + if(percent > 0.9) { + this.scale = this.scale * 2; + } else if(percent < 0.08) { + this.scale = this.scale / 4; + } else if(percent < 0.16) { + this.scale = this.scale / 2; + } else { + return; + } + + console.log((this.el.attr('id') || "element") + " set scale to " + this.scale); + this.drawSeparator(); + this.resetMarkers(); }, - drawLogPath: function(percent) { - if(this.options.logDate) { - this.tick++; + drawSeparator: function() { + this.shiftCanvas(this.lineWidth * 2, 0); + + this.context.lineWidth = this.lineWidth; + this.context.beginPath(); + this.context.strokeStyle = "#000"; + this.context.moveTo(this.canvasWidth - 10, this.canvasHeight); + this.context.lineTo(this.canvasWidth - 10, 0); + this.context.stroke(); + this.context.closePath(); + }, + + drawLogPath: function(value) { + this.tick++; + + if(this.options.showLogDate) { if(this.tick % 100 == 0) { this.logDate(); - this.tick = 0; } } - this.addValue(percent); + this.addValue(value); - var average = this.runningAverage(); - var height = Math.max(average * this.canvasHeight, 1); - var colorIndex = Math.min(Math.ceil((average / 2) * 10), 5); - var color = this.lineColors[colorIndex]; + var average = this.runningAverage() * this.options.ratePerSecond; + var percent = average / this.scale; + var height = Math.max(percent * this.canvasHeight, 1); + var color = this.lineColors[this.scale] || this.lineColors.def; var endingPoint = this.canvasHeight - height; this.shiftCanvas(this.lineWidth * 2, 0); @@ -113,5 +180,11 @@ Hummingbird.Graph.prototype = { this.context.lineTo(this.canvasWidth - 10, 0); this.context.stroke(); this.context.closePath(); + + if(this.tick % 50 == 0) { + this.valueElement.text(average); + this.rescale(percent); + if(this.tick % 1000 == 0) { this.tick = 0; } + } } }; diff --git a/public/js/sales.js b/public/js/sales.js index ae426ef..121a21e 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -16,7 +16,7 @@ Hummingbird.getSales = function() { var canvas = $(""); saleDiv.append(canvas); $("#sales").append(saleDiv); - var saleGraph = new Hummingbird.Graph(canvas.get(0)); + var saleGraph = new Hummingbird.Graph(saleDiv, { ratePerSecond: 2 }); Hummingbird.saleGraphs[this.url_key] = saleGraph; }); }); diff --git a/public/js/websocket.js b/public/js/websocket.js index 8a51b2a..ca3bf1a 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -8,13 +8,13 @@ Hummingbird.WebSocket.start = function() { return; } - var canvas = $("#log").get(0); - canvas.width = $(window).width() - 160; - var totalGraph = new Hummingbird.Graph(canvas, {logDate: true}); + var totalDiv = $("#log"); + totalDiv.find('canvas').get(0).width = $(window).width() - 160; + var totalGraph = new Hummingbird.Graph(totalDiv, { ratePerSecond: 20, logDate: true }); - var cartAdds = $("#cart_adds").get(0); - cartAdds.width = $(window).width() - 160; - var cartAddsGraph = new Hummingbird.Graph(cartAdds); + var cartAdds = $("#cart_adds");; + cartAdds.find('canvas').get(0).width = $(window).width() - 160; + var cartAddsGraph = new Hummingbird.Graph(cartAdds, { ratePerSecond: 20 }); if(document.location.search.match(/use_prod/)) { var wsServer = "ws://hummingbird.giltrunway.com:8080"; @@ -28,15 +28,15 @@ Hummingbird.WebSocket.start = function() { if(typeof(data.sales) != "undefined") { $.each(Hummingbird.saleGraphs, function(key) { if(data.sales[key]) { - Hummingbird.saleGraphs[key].drawLogPath(data.sales[key] * 2 / 200.0); + Hummingbird.saleGraphs[key].drawLogPath(data.sales[key]); } else { Hummingbird.saleGraphs[key].drawLogPath(0.0); } }); } else if(typeof(data.total) != "undefined") { - totalGraph.drawLogPath(data.total * 20 / 400.0); + totalGraph.drawLogPath(data.total); if(data.cartAdds) { - cartAddsGraph.drawLogPath(data.cartAdds * 20 / 200); + cartAddsGraph.drawLogPath(data.cartAdds); } else { cartAddsGraph.drawLogPath(0.0); } From 8fb8cb1eda77d734bb8678601f5144b8cc93f526 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 20 Apr 2010 16:29:56 -0400 Subject: [PATCH 047/267] Combine sales graphs with sales images --- public/css/main.css | 21 +++++++++++++++++++-- public/js/analytics.js | 21 ++++++++++++--------- public/js/sales.js | 9 ++++++--- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/public/css/main.css b/public/css/main.css index 67b7903..b79f8b3 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -59,12 +59,29 @@ div.hummingbird_graph div.axis_right { #sales div.sale { float: left; width: 180px; - height: 180px; + height: 100px; overflow: hidden; padding: 10px; + position: relative; } -#sales div.sale canvas { +#sales div.sale div.hummingbird_graph { + position: absolute; + top: -5px; + left: 10px; + width: 180px; +} + +#sales div.sale img { + opacity: 0.5; +} + +#sales div.sale div.axis_right { + float: left; +} + +#sales div.sale div.axis_left { + display: none; } #sales div.sale h2 { diff --git a/public/js/analytics.js b/public/js/analytics.js index b321573..b5ba120 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -8,7 +8,8 @@ Hummingbird.Graph = function(el, options) { var defaults = { showLogDate: false, showMarkers: true, - ratePerSecond: 10 + ratePerSecond: 10, + showBackgroundBars: true } this.options = $.extend(defaults, options); @@ -37,7 +38,7 @@ Hummingbird.Graph.prototype = { def: "#7BF4D6" }; this.bgLineColor = "#555"; - this.canvasHeight = $(this.canvas).height() - 16; + this.canvasHeight = $(this.canvas).height(); this.canvasWidth = $(this.canvas).width(); this.numMarkers = Math.floor(this.canvasHeight / 23); @@ -174,14 +175,16 @@ Hummingbird.Graph.prototype = { this.context.stroke(); this.context.closePath(); - this.context.beginPath(); - this.context.strokeStyle = this.bgLineColor; - this.context.moveTo(this.canvasWidth - 10, endingPoint); - this.context.lineTo(this.canvasWidth - 10, 0); - this.context.stroke(); - this.context.closePath(); + if(this.options.showBackgroundBars) { + this.context.beginPath(); + this.context.strokeStyle = this.bgLineColor; + this.context.moveTo(this.canvasWidth - 10, endingPoint); + this.context.lineTo(this.canvasWidth - 10, 0); + this.context.stroke(); + this.context.closePath(); + } - if(this.tick % 50 == 0) { + if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds this.valueElement.text(average); this.rescale(percent); if(this.tick % 1000 == 0) { this.tick = 0; } diff --git a/public/js/sales.js b/public/js/sales.js index 121a21e..a6703e3 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -13,10 +13,13 @@ Hummingbird.getSales = function() { saleDiv.append(""); saleDiv.append("

" + name + "

"); - var canvas = $(""); - saleDiv.append(canvas); + var graph = $("
"); + + var canvas = $(""); + graph.append(canvas); + saleDiv.append(graph); $("#sales").append(saleDiv); - var saleGraph = new Hummingbird.Graph(saleDiv, { ratePerSecond: 2 }); + var saleGraph = new Hummingbird.Graph(graph, { ratePerSecond: 2, initialScope: 200, backgroundImage: editorialImage, showBackgroundBars: false }); Hummingbird.saleGraphs[this.url_key] = saleGraph; }); }); From 657d6f7bbcf10e8173afba4cc47f1459479f4d0c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 20 Apr 2010 18:04:32 -0400 Subject: [PATCH 048/267] Resort sales by view rate --- public/js/analytics.js | 4 ++-- public/js/helpers.js | 25 ++++++++++++++++++++++++- public/js/sales.js | 16 +++++++++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/public/js/analytics.js b/public/js/analytics.js index b5ba120..92d4062 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -46,7 +46,7 @@ Hummingbird.Graph.prototype = { this.lineWidth = 3; - this.drawEmptyGraph(); + // this.drawEmptyGraph(); this.tick = 0; }, @@ -131,7 +131,6 @@ Hummingbird.Graph.prototype = { return; } - console.log((this.el.attr('id') || "element") + " set scale to " + this.scale); this.drawSeparator(); this.resetMarkers(); }, @@ -186,6 +185,7 @@ Hummingbird.Graph.prototype = { if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds this.valueElement.text(average); + this.el.attr('data-value', average); this.rescale(percent); if(this.tick % 1000 == 0) { this.tick = 0; } } diff --git a/public/js/helpers.js b/public/js/helpers.js index 44d570d..6cc3806 100644 --- a/public/js/helpers.js +++ b/public/js/helpers.js @@ -21,4 +21,27 @@ Date.prototype.formattedTime = function() { } return formattedDate; -}; \ No newline at end of file +}; + +// Custom sorting plugin +(function($) { + $.fn.sorted = function(customOptions) { + var options = { + reversed: false, + by: function(a) { return a.text(); } + }; + $.extend(options, customOptions); + $data = $(this); + arr = $data.get(); + arr.sort(function(a, b) { + var valA = options.by($(a)); + var valB = options.by($(b)); + if (options.reversed) { + return (valA < valB) ? 1 : (valA > valB) ? -1 : 0; + } else { + return (valA < valB) ? -1 : (valA > valB) ? 1 : 0; + } + }); + return $(arr); + }; +})(jQuery); diff --git a/public/js/sales.js b/public/js/sales.js index a6703e3..cf39e5b 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -9,7 +9,7 @@ Hummingbird.getSales = function() { var name = this.name; var url = "http://www.gilt.com/s/" + this.url_key; - var saleDiv = $("
"); + var saleDiv = $("
"); saleDiv.append(""); saleDiv.append("

" + name + "

"); @@ -25,6 +25,20 @@ Hummingbird.getSales = function() { }); }; +Hummingbird.resortSales = function() { + var sortedSales = $("div#sales div.sale").sorted({ + by: function(a) { + return a.find('div.hummingbird_graph').attr('data-value'); + } + }); + + $.each(sortedSales, function() { + $(this).prependTo("div#sales"); + }); +}; + $(document).ready(function() { Hummingbird.getSales(); + + setInterval(Hummingbird.resortSales, 3000); }); \ No newline at end of file From 6b75d92f7e87e2222f36932dba7bb8c9ce845889 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 21 Apr 2010 01:48:40 -0400 Subject: [PATCH 049/267] Add values to individual sales --- public/css/main.css | 13 +++++++++++++ public/js/analytics.js | 32 +++++++++++++++++++++++--------- public/js/sales.js | 3 ++- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/public/css/main.css b/public/css/main.css index b79f8b3..a41b534 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -72,6 +72,19 @@ div.hummingbird_graph div.axis_right { width: 180px; } +#sales div.sale div.hummingbird_graph div.req_s { + position: absolute; + top: 15px; + left: 0; + background-color: rgba(0, 0, 0, 0.8); + color: #FFF; + font-weight: bold; + padding: 5px; + font-size: 0.6em; + -moz-border-radius-bottomright: 5px; + -webkit-border-bottom-right-radius: 5px; +} + #sales div.sale img { opacity: 0.5; } diff --git a/public/js/analytics.js b/public/js/analytics.js index 92d4062..7ee828c 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -9,7 +9,8 @@ Hummingbird.Graph = function(el, options) { showLogDate: false, showMarkers: true, ratePerSecond: 10, - showBackgroundBars: true + showBackgroundBars: true, + barColor: null } this.options = $.extend(defaults, options); @@ -19,6 +20,7 @@ Hummingbird.Graph = function(el, options) { this.canvas = $(el).find('canvas').get(0); this.valueElement = this.el.find('span.value'); this.trafficLog = []; + this.longTrafficLog = []; this.init(); }; @@ -28,13 +30,16 @@ Hummingbird.Graph.prototype = { this.setupContext(); this.lineColors = { - 25: "#5BC4B6", - 50: "#3BA496", - 100: "#65B88A", - 200: "#F1E29F", - 400: "#C44939", + 1600: "#FFF", 800: "#983839", - 1600: "#333", + 400: "#C44939", + 200: "#F1E29F", + 100: "#7BE4D6", + 50: "#65B88A", + 25: "#5BC4B6", + 12.5: "#3BA496", + 6.25: "#1B8476", + 3.125: "#006456", def: "#7BF4D6" }; this.bgLineColor = "#555"; @@ -72,6 +77,11 @@ Hummingbird.Graph.prototype = { if(this.trafficLog.length > this.options.ratePerSecond) { this.trafficLog.shift(); } + + this.longTrafficLog.push(value); + if(this.longTrafficLog.length > 200) { + this.longTrafficLog.shift(); + } }, shiftCanvas: function(x, y) { @@ -93,6 +103,10 @@ Hummingbird.Graph.prototype = { return this.trafficLog.sum() / this.trafficLog.length; }, + longAverage: function() { + return this.longTrafficLog.sum() / this.longTrafficLog.length; + }, + drawEmptyGraph: function() { var dataPoints = Math.ceil(this.canvasWidth / (this.lineWidth * 2)) while(dataPoints--) { @@ -162,7 +176,7 @@ Hummingbird.Graph.prototype = { var average = this.runningAverage() * this.options.ratePerSecond; var percent = average / this.scale; var height = Math.max(percent * this.canvasHeight, 1); - var color = this.lineColors[this.scale] || this.lineColors.def; + var color = this.options.barColor || this.lineColors[this.scale] || this.lineColors.def; var endingPoint = this.canvasHeight - height; this.shiftCanvas(this.lineWidth * 2, 0); @@ -185,7 +199,7 @@ Hummingbird.Graph.prototype = { if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds this.valueElement.text(average); - this.el.attr('data-value', average); + this.el.attr('data-average', this.longAverage()); this.rescale(percent); if(this.tick % 1000 == 0) { this.tick = 0; } } diff --git a/public/js/sales.js b/public/js/sales.js index cf39e5b..15882b5 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -14,6 +14,7 @@ Hummingbird.getSales = function() { saleDiv.append("

" + name + "

"); var graph = $("
"); + graph.append("
0 pages/sec
"); var canvas = $(""); graph.append(canvas); @@ -28,7 +29,7 @@ Hummingbird.getSales = function() { Hummingbird.resortSales = function() { var sortedSales = $("div#sales div.sale").sorted({ by: function(a) { - return a.find('div.hummingbird_graph').attr('data-value'); + return a.find('div.hummingbird_graph').attr('data-average'); } }); From 5941373527c29facb37ace65287ba92dc5609a52 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 21 Apr 2010 02:14:18 -0400 Subject: [PATCH 050/267] Add product_id parsing; store parsed values in mongo --- lib/hummingbird.js | 7 +++++-- lib/view.js | 17 ++++++++++++++++- spec/unit/view_spec.js | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 7e8e8b6..6244754 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -40,8 +40,6 @@ Hummingbird.prototype = { this.writePixel(res); - this.collection.insert(env); - var view = new pageview.View(env); if(view.urlKey()) { if(this.salesMetric.data.sales[view.urlKey()]) { @@ -51,6 +49,11 @@ Hummingbird.prototype = { } } + env.url_key = view.urlKey(); + env.product_id = view.productId(); + + this.collection.insert(env); + if(view.event() && view.event() === "cart_add") { this.allViewsMetric.data.cartAdds += 1; } diff --git a/lib/view.js b/lib/view.js index 4c279a3..477caf6 100644 --- a/lib/view.js +++ b/lib/view.js @@ -11,7 +11,7 @@ var View = function(env) { View.prototype = { urlKey: function() { if(this.env.u) { - var match = this.env.u.match(/^http:\/\/[^\/]+\/s\/([^\/]+)/); + var match = View.urlKeyRegexp.exec(this.env.u); if(match && match.length > 0) { this._urlKey = match[1]; } @@ -21,6 +21,18 @@ View.prototype = { return this._urlKey; }, + productId: function() { + if(this.env.u) { + var match = View.productIdRegexp.exec(this.env.u); + if(match && match.length > 0) { + this._productId = parseInt(match[1]); + } + } + + this.productId = function() { return this._productId; } + return this._productId; + }, + event: function() { if(this.env.events) { if(this.env.events.match(/scAdd/)) { @@ -35,4 +47,7 @@ View.prototype = { } }; +View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+\/s\/([^\/]+)\/?/); +View.productIdRegexp = new RegExp(/\/product\/([0-9]+)/); + exports.View = View; diff --git a/spec/unit/view_spec.js b/spec/unit/view_spec.js index 555408d..7c505bc 100644 --- a/spec/unit/view_spec.js +++ b/spec/unit/view_spec.js @@ -22,6 +22,22 @@ describe 'View' end end + describe '.productId()' + it 'extracts the product id' + var env = { u: "http://localhost/s/gucci/product/12345" } + + var view = new v.View(env) + view.productId().should.equal 12345 + end + + it 'handles other stuff at the end of the url' + var env = { u: "http://localhost/s/gucci/product/12345?foobar" } + + var view = new v.View(env) + view.productId().should.equal 12345 + end + end + describe '.event()' it 'extracts the cart_add event' var env = { events: "scAdd,scJunk" } From 9e18095a04b9a9d02f4999c1c73bc1037288042b Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 23 Apr 2010 11:29:19 -0400 Subject: [PATCH 051/267] Add metrics logging to hummingbird; pass in the mongo db to hummingbird; refactor server.js --- lib/hummingbird.js | 25 +++++++---- lib/metric.js | 25 ++++++++++- lib/static_assets.js | 33 +++++++++++++++ public/js/sales.js | 2 +- server.js | 79 +++++++++++------------------------ spec/node.js | 14 ++++--- spec/unit/hummingbird_spec.js | 8 ++-- 7 files changed, 113 insertions(+), 73 deletions(-) create mode 100644 lib/static_assets.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 6244754..7f629a4 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -5,18 +5,29 @@ var sys = require('sys'), arrays = require('deps/arrays'), querystring = require('querystring'); -var Hummingbird = function() { +var Hummingbird = function(db, callback) { this.pixel = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); - this.init(); + this.init(db, callback); }; Hummingbird.prototype = { - init: function() { - this.allViewsMetric = new metric.Metric({total: 0, cartAdds: 0}, 50); - this.salesMetric = new metric.Metric({sales: {}}, 500); + init: function(db, callback) { + var self = this; + self.allViewsMetric = new metric.Metric('all_views', {total: 0, cartAdds: 0}, 50, db); + self.salesMetric = new metric.Metric('sales', {sales: {}}, 500, db); + self.setupDb(db, function() { + callback(); + }); + }, - this.allViewsMetric.run(); - this.salesMetric.run(); + setupDb: function(db, callback) { + var self = this; + db.createCollection('visits', function(err, collection) { + db.collection('visits', function(err, collection) { + self.collection = collection; + callback(); + }); + }); }, setCollection: function(collection) { diff --git a/lib/metric.js b/lib/metric.js index 7d16fa4..bd4c170 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -1,14 +1,24 @@ var sys = require('sys'); -var Metric = function(initialData, interval) { +var Metric = function(name, initialData, interval, db) { if(!this instanceof Metric) { - return new Metric(initialData, interval); + return new Metric(name, initialData, interval, db); } + this.name = name; this.initialData = this.data = initialData; this.interval = interval; this.job = null; this.clients = []; + + var metric = this; + + db.createCollection('metrics', function(err, collection) { + db.collection('metrics', function(err, collection) { + metric.collection = collection; + metric.run(); + }); + }); } Metric.prototype = { @@ -27,9 +37,20 @@ Metric.prototype = { } }); + metric.insertData(); metric.resetData(); }, + insertData: function() { + var mongoData = { + data: this.data, + name: this.name, + timestamp: (new Date()).getTime() + }; + + this.collection.insert(mongoData); + }, + removeClient: function(client) { this.clients.remove(client); }, diff --git a/lib/static_assets.js b/lib/static_assets.js new file mode 100644 index 0000000..6b5f601 --- /dev/null +++ b/lib/static_assets.js @@ -0,0 +1,33 @@ +var sys = require('sys'), + paperboy = require('deps/node-paperboy'), + proxy = require('proxy'), + path = require('path'), + http = require('http'); + +var WEBROOT = path.join(path.dirname(__filename), 'public'); + +var serveStatic = function(port) { + try { + http.createServer(function(req, res) { + if(req.url.match(/\/sale_list/)) { + proxy.route("/sale_list", + "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); + } else { + paperboy.deliver(WEBROOT, req, res) + .addHeader('Content-Type', "text/plain") + .after(function(statCode) { + sys.log([statCode, + req.method, + req.url, + req.connection.remoteAddress].join(' ')); + }); + } + }).listen(port); + + sys.puts('Analytics server running at http://localhost:' + port + '/'); + } catch(e) { + sys.puts('Detected webserver already running on http://localhost:' + port + '.'); + } +}; + +exports.serveStatic = serveStatic; diff --git a/public/js/sales.js b/public/js/sales.js index 15882b5..0816d5a 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -29,7 +29,7 @@ Hummingbird.getSales = function() { Hummingbird.resortSales = function() { var sortedSales = $("div#sales div.sale").sorted({ by: function(a) { - return a.find('div.hummingbird_graph').attr('data-average'); + return a.find('div.hummingbird_graph').attr('data-average') || -1; } }); diff --git a/server.js b/server.js index d151525..b1f696a 100644 --- a/server.js +++ b/server.js @@ -3,74 +3,45 @@ require.paths.unshift(__dirname); var sys = require('sys'), http = require('http'), - path = require('path'), ws = require('deps/node-ws/ws'), - proxy = require('proxy'), - paperboy = require('deps/node-paperboy'), mongo = require('deps/node-mongodb-native/lib/mongodb'), hb = require('hummingbird'); -var WEBROOT = path.join(path.dirname(__filename), 'public'), - TRACKING_PORT = 8000, +var TRACKING_PORT = 8000, WEB_SOCKET_PORT = 8080, MONITOR_PORT = 8088; var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); - -var hummingbird = new hb.Hummingbird(); - db.open(function(p_db) { - db.createCollection('visits', function(err, collection) { - db.collection('visits', function(err, collection) { - hummingbird.setCollection(collection); - http.createServer(function(req, res) { - try { - hummingbird.serveRequest(req, res); - } catch(e) { - hummingbird.handleError(req, res, e); - } - }).listen(TRACKING_PORT); - }); + var hummingbird = new hb.Hummingbird(db, function() { + http.createServer(function(req, res) { + try { + hummingbird.serveRequest(req, res); + } catch(e) { + hummingbird.handleError(req, res, e); + } + }).listen(TRACKING_PORT); }); -}); -sys.puts('Tracking server running at http://localhost:' + TRACKING_PORT + '/tracking_pixel.gif'); + sys.puts('Tracking server running at http://localhost:' + TRACKING_PORT + '/tracking_pixel.gif'); -// Websocket TCP server -ws.createServer(function (websocket) { - hummingbird.addClient(websocket); + // Websocket TCP server + ws.createServer(function (websocket) { + hummingbird.addClient(websocket); - websocket.addListener("connect", function (resource) { - // emitted after handshake - sys.log("ws connect: " + resource); - }).addListener("close", function () { - // emitted when server or client closes connection - hummingbird.removeClient(websocket); - sys.log("ws close"); - }); -}).listen(WEB_SOCKET_PORT); + websocket.addListener("connect", function (resource) { + // emitted after handshake + sys.log("ws connect: " + resource); + }).addListener("close", function () { + // emitted when server or client closes connection + hummingbird.removeClient(websocket); + sys.log("ws close"); + }); + }).listen(WEB_SOCKET_PORT); +}); sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); -try { - http.createServer(function(req, res) { - if(req.url.match(/\/sale_list/)) { - proxy.route("/sale_list", - "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); - } else { - paperboy.deliver(WEBROOT, req, res) - .addHeader('Content-Type', "text/plain") - .after(function(statCode) { - sys.log([statCode, - req.method, - req.url, - req.connection.remoteAddress].join(' ')); - }); - } - }).listen(MONITOR_PORT); - - sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); -} catch(e) { - sys.puts('Detected webserver already running on http://localhost:' + MONITOR_PORT + '.'); -} \ No newline at end of file +var staticAssets = require('static_assets'); +staticAssets.serveStatic(MONITOR_PORT); \ No newline at end of file diff --git a/spec/node.js b/spec/node.js index 99e3db1..ba83278 100644 --- a/spec/node.js +++ b/spec/node.js @@ -9,6 +9,8 @@ hb = require('hummingbird') http = require('http'); v = require('view'); sys = require('sys'); +mongo = require('deps/node-mongodb-native/lib/mongodb'); +db = new mongo.Db('hummingbird_test', new mongo.Server('localhost', 27017, {}), {}); MockRequest = function(url) { this.url = url; @@ -49,8 +51,10 @@ MockCollection.prototype = { } } -JSpec - .exec('spec/unit/hummingbird_spec.js') - .exec('spec/unit/view_spec.js') - .run({ reporter: JSpec.reporters.Terminal, fixturePath: 'spec/fixtures', failuresOnly: true }) - .report() +db.open(function(p_db) { + JSpec + .exec('spec/unit/hummingbird_spec.js') + .exec('spec/unit/view_spec.js') + .run({ reporter: JSpec.reporters.Terminal, fixturePath: 'spec/fixtures', failuresOnly: true }) + .report() +}); diff --git a/spec/unit/hummingbird_spec.js b/spec/unit/hummingbird_spec.js index 5d3692d..4ebfacd 100644 --- a/spec/unit/hummingbird_spec.js +++ b/spec/unit/hummingbird_spec.js @@ -3,7 +3,7 @@ describe 'Hummingbird' it 'outputs a 1x1 tracking pixel to the response' var req = new MockRequest("/tracking.gif") var res = new MockResponse() - var hummingbird = new hb.Hummingbird() + var hummingbird = new hb.Hummingbird(db, function() {}) hummingbird.writePixel(res) @@ -15,7 +15,7 @@ describe 'Hummingbird' describe '.addClient' it 'increases the allViewsMetric client count by 1' - var hummingbird = new hb.Hummingbird(); + var hummingbird = new hb.Hummingbird(db, function() {}); var mockClient = {}; hummingbird.allViewsMetric.clients.length.should.equal 0 @@ -26,7 +26,7 @@ describe 'Hummingbird' describe '.removeClient' it 'decreases the allViewsMetric client count by 1' - var hummingbird = new hb.Hummingbird(); + var hummingbird = new hb.Hummingbird(db, function() {}); var mockClient = {}; hummingbird.addClient(mockClient); @@ -38,7 +38,7 @@ describe 'Hummingbird' describe '.serveRequest' it 'adds a timestamp to the environment' - var hummingbird = new hb.Hummingbird() + var hummingbird = new hb.Hummingbird(db, function() {}) var req = new MockRequest("http://localhost/t.gif?u=foobar") var res = new MockResponse() var collection = new MockCollection() From 3e110a307f99eb39ae63629e7857b53f1f2772ae Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 25 Apr 2010 01:06:28 -0400 Subject: [PATCH 052/267] Stop hard-coding specific metrics into hummingbird --- lib/hummingbird.js | 47 +++++++++++++++++++++-------------- lib/metric.js | 9 +++++-- lib/static_assets.js | 3 +-- server.js | 3 +-- spec/node.js | 4 ++- spec/unit/hummingbird_spec.js | 8 +++--- spec/unit/metric_spec.js | 47 +++++++++++++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 spec/unit/metric_spec.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 7f629a4..2b03d46 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -7,15 +7,31 @@ var sys = require('sys'), var Hummingbird = function(db, callback) { this.pixel = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); + this.metrics = []; this.init(db, callback); }; Hummingbird.prototype = { init: function(db, callback) { - var self = this; - self.allViewsMetric = new metric.Metric('all_views', {total: 0, cartAdds: 0}, 50, db); - self.salesMetric = new metric.Metric('sales', {sales: {}}, 500, db); - self.setupDb(db, function() { + this.metrics.push(new metric.Metric('all_views', {total: 0, cartAdds: 0}, 50, db, function(view) { + this.data.total += 1; + + if(view.event() && view.event() === "cart_add") { + this.data.cartAdds += 1; + } + })); + + this.metrics.push(new metric.Metric('sales', {sales: {}}, 500, db, function(view) { + if(view.urlKey()) { + if(this.data.sales[view.urlKey()]) { + this.data.sales[view.urlKey()] += 1; + } else { + this.data.sales[view.urlKey()] = 1; + } + } + })); + + this.setupDb(db, function() { callback(); }); }, @@ -35,13 +51,15 @@ Hummingbird.prototype = { }, addClient: function(client) { - this.allViewsMetric.clients.push(client); - this.salesMetric.clients.push(client); + for(var i = 0; i < this.metrics.length; i++) { + this.metrics[i].clients.push(client); + } }, removeClient: function(client) { - this.allViewsMetric.clients.remove(client); - this.salesMetric.clients.remove(client); + for(var i = 0; i < this.metrics.length; i++) { + this.metrics[i].clients.remove(client); + } }, serveRequest: function(req, res) { @@ -52,24 +70,15 @@ Hummingbird.prototype = { this.writePixel(res); var view = new pageview.View(env); - if(view.urlKey()) { - if(this.salesMetric.data.sales[view.urlKey()]) { - this.salesMetric.data.sales[view.urlKey()] += 1; - } else { - this.salesMetric.data.sales[view.urlKey()] = 1; - } - } env.url_key = view.urlKey(); env.product_id = view.productId(); this.collection.insert(env); - if(view.event() && view.event() === "cart_add") { - this.allViewsMetric.data.cartAdds += 1; + for(var i = 0; i < this.metrics.length; i++) { + this.metrics[i].addValue(view); } - - this.allViewsMetric.data.total += 1; }, writePixel: function(res) { diff --git a/lib/metric.js b/lib/metric.js index bd4c170..238c599 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -1,8 +1,8 @@ var sys = require('sys'); -var Metric = function(name, initialData, interval, db) { +var Metric = function(name, initialData, interval, db, addHandler) { if(!this instanceof Metric) { - return new Metric(name, initialData, interval, db); + return new Metric(name, initialData, interval, db, addHandler); } this.name = name; @@ -10,6 +10,7 @@ var Metric = function(name, initialData, interval, db) { this.interval = interval; this.job = null; this.clients = []; + this.addHandler = addHandler; var metric = this; @@ -41,6 +42,10 @@ Metric.prototype = { metric.resetData(); }, + addValue: function(view) { + this.addHandler(view); + }, + insertData: function() { var mongoData = { data: this.data, diff --git a/lib/static_assets.js b/lib/static_assets.js index 6b5f601..8ed92d3 100644 --- a/lib/static_assets.js +++ b/lib/static_assets.js @@ -4,7 +4,7 @@ var sys = require('sys'), path = require('path'), http = require('http'); -var WEBROOT = path.join(path.dirname(__filename), 'public'); +var WEBROOT = path.join(path.dirname(__filename), '..', 'public'); var serveStatic = function(port) { try { @@ -23,7 +23,6 @@ var serveStatic = function(port) { }); } }).listen(port); - sys.puts('Analytics server running at http://localhost:' + port + '/'); } catch(e) { sys.puts('Detected webserver already running on http://localhost:' + port + '.'); diff --git a/server.js b/server.js index b1f696a..9b7f5bc 100644 --- a/server.js +++ b/server.js @@ -42,6 +42,5 @@ db.open(function(p_db) { }); sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); - var staticAssets = require('static_assets'); -staticAssets.serveStatic(MONITOR_PORT); \ No newline at end of file +staticAssets.serveStatic(MONITOR_PORT); diff --git a/spec/node.js b/spec/node.js index ba83278..beef020 100644 --- a/spec/node.js +++ b/spec/node.js @@ -1,5 +1,5 @@ -require.paths.unshift('spec', '/usr/local/Cellar/ruby-enterprise-edition/2009.10/lib/ruby/gems/1.8/gems/jspec-4.2.1/lib', 'lib') +require.paths.unshift('spec', '/opt/local/lib/ruby/gems/1.8/gems/jspec-4.2.1/lib', 'lib') require.paths.unshift(__dirname + '/../lib'); require.paths.unshift(__dirname + '/..'); @@ -8,6 +8,7 @@ require('unit/spec.helper') hb = require('hummingbird') http = require('http'); v = require('view'); +m = require('metric'); sys = require('sys'); mongo = require('deps/node-mongodb-native/lib/mongodb'); db = new mongo.Db('hummingbird_test', new mongo.Server('localhost', 27017, {}), {}); @@ -55,6 +56,7 @@ db.open(function(p_db) { JSpec .exec('spec/unit/hummingbird_spec.js') .exec('spec/unit/view_spec.js') + .exec('spec/unit/metric_spec.js') .run({ reporter: JSpec.reporters.Terminal, fixturePath: 'spec/fixtures', failuresOnly: true }) .report() }); diff --git a/spec/unit/hummingbird_spec.js b/spec/unit/hummingbird_spec.js index 4ebfacd..9561853 100644 --- a/spec/unit/hummingbird_spec.js +++ b/spec/unit/hummingbird_spec.js @@ -18,9 +18,9 @@ describe 'Hummingbird' var hummingbird = new hb.Hummingbird(db, function() {}); var mockClient = {}; - hummingbird.allViewsMetric.clients.length.should.equal 0 + hummingbird.metrics[0].clients.length.should.equal 0 hummingbird.addClient(mockClient); - hummingbird.allViewsMetric.clients.length.should.equal 1 + hummingbird.metrics[0].clients.length.should.equal 1 end end @@ -30,9 +30,9 @@ describe 'Hummingbird' var mockClient = {}; hummingbird.addClient(mockClient); - hummingbird.allViewsMetric.clients.length.should.equal 1 + hummingbird.metrics[0].clients.length.should.equal 1 hummingbird.removeClient(mockClient); - hummingbird.allViewsMetric.clients.length.should.equal 0 + hummingbird.metrics[0].clients.length.should.equal 0 end end diff --git a/spec/unit/metric_spec.js b/spec/unit/metric_spec.js new file mode 100644 index 0000000..735ab6c --- /dev/null +++ b/spec/unit/metric_spec.js @@ -0,0 +1,47 @@ +describe 'Metric' + describe '.addValue' + it 'calls the passed "addHandler" function' + var metric = new m.Metric('test', {foo: 0}, 100, db, function(view) { + this.data.foo = view; + }); + var view = 5; + metric.addValue(view); + + metric.data.foo.should.equal 5 + end + end + + describe '.insertData' + it 'inserts the metric\'s data into the database with a timestamp' + var metric = new m.Metric('test', {foo: 0}, 100, db, function(view) { + this.data.foo = view; + metric.insertData(); + }); + + // metric.addValue(5); + // TODO + end + end + + describe '.addClient' + it 'adds the client to the client array' + var metric = new m.Metric('test', {foo: 0}, 100, db, function() {}); + var client = {}; + metric.addClient(client); + metric.clients.length.should.equal 1 + metric.clients[0].should.equal client + end + end + + describe '.removeClient' + it 'removes the client from the client array' + var metric = new m.Metric('test', {foo: 0}, 100, db, function() {}); + var client = {}; + metric.addClient(client); + + metric.removeClient(client); + + metric.clients.length.should.equal 0 + end + end +end \ No newline at end of file From f8ed645f7b248039b5d5930699b6973a091773d6 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 25 Apr 2010 01:37:14 -0400 Subject: [PATCH 053/267] Move metrics out into their own files --- lib/hummingbird.js | 39 +++++++++++++++++++++------------------ lib/metrics/all.js | 15 +++++++++++++++ lib/metrics/sales.js | 17 +++++++++++++++++ 3 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 lib/metrics/all.js create mode 100644 lib/metrics/sales.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 2b03d46..db07f77 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -2,6 +2,7 @@ var sys = require('sys'), fs = require('fs'), pageview = require('view'), metric = require('metric'), + path = require('path'), arrays = require('deps/arrays'), querystring = require('querystring'); @@ -13,27 +14,11 @@ var Hummingbird = function(db, callback) { Hummingbird.prototype = { init: function(db, callback) { - this.metrics.push(new metric.Metric('all_views', {total: 0, cartAdds: 0}, 50, db, function(view) { - this.data.total += 1; - - if(view.event() && view.event() === "cart_add") { - this.data.cartAdds += 1; - } - })); - - this.metrics.push(new metric.Metric('sales', {sales: {}}, 500, db, function(view) { - if(view.urlKey()) { - if(this.data.sales[view.urlKey()]) { - this.data.sales[view.urlKey()] += 1; - } else { - this.data.sales[view.urlKey()] = 1; - } - } - })); - this.setupDb(db, function() { callback(); }); + + this.addAllMetrics(db); }, setupDb: function(db, callback) { @@ -46,6 +31,24 @@ Hummingbird.prototype = { }); }, + addAllMetrics: function(db) { + var files = fs.readdirSync(path.join(__dirname, 'metrics')); + + for(var i = 0; i < files.length; i++) { + var file = files[i]; + var filename = file.replace(/\.js$/, ''); + + var m = require(path.join(__dirname, 'metrics', filename)); + + var hmetric = new metric.Metric(m.name, + m.defaultData, + m.interval, + db, + m.addValueCallback); + this.metrics.push(hmetric); + } + }, + setCollection: function(collection) { this.collection = collection; }, diff --git a/lib/metrics/all.js b/lib/metrics/all.js new file mode 100644 index 0000000..c461e5b --- /dev/null +++ b/lib/metrics/all.js @@ -0,0 +1,15 @@ +var AllViewsMetric = { + name: 'all_views', + defaultData: {total: 0, cartAdds: 0}, + interval: 50, + addValueCallback: function(view) { + this.data.total += 1; + + if(view.event() && view.event() === "cart_add") { + this.data.cartAdds += 1; + } + } +}; + +for (var i in AllViewsMetric) + exports[i] = AllViewsMetric[i]; \ No newline at end of file diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js new file mode 100644 index 0000000..dca1932 --- /dev/null +++ b/lib/metrics/sales.js @@ -0,0 +1,17 @@ +var SalesMetric = { + name: 'sales', + defaultData: {sales: {}}, + interval: 500, + addValueCallback: function(view) { + if(view.urlKey()) { + if(this.data.sales[view.urlKey()]) { + this.data.sales[view.urlKey()] += 1; + } else { + this.data.sales[view.urlKey()] = 1; + } + } + } +}; + +for (var i in SalesMetric) + exports[i] = SalesMetric[i]; \ No newline at end of file From 85177ddb9d025c1a79395d67599ef6f1cef1ac4c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 25 Apr 2010 01:47:46 -0400 Subject: [PATCH 054/267] clean up class requiring --- lib/hummingbird.js | 18 +++++++++--------- server.js | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index db07f77..d58726d 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -1,7 +1,7 @@ var sys = require('sys'), fs = require('fs'), - pageview = require('view'), - metric = require('metric'), + View = require('view').View, + Metric = require('metric').Metric, path = require('path'), arrays = require('deps/arrays'), querystring = require('querystring'); @@ -40,12 +40,12 @@ Hummingbird.prototype = { var m = require(path.join(__dirname, 'metrics', filename)); - var hmetric = new metric.Metric(m.name, - m.defaultData, - m.interval, - db, - m.addValueCallback); - this.metrics.push(hmetric); + var metric = new Metric(m.name, + m.defaultData, + m.interval, + db, + m.addValueCallback); + this.metrics.push(metric); } }, @@ -72,7 +72,7 @@ Hummingbird.prototype = { this.writePixel(res); - var view = new pageview.View(env); + var view = new View(env); env.url_key = view.urlKey(); env.product_id = view.productId(); diff --git a/server.js b/server.js index 9b7f5bc..7c5a225 100644 --- a/server.js +++ b/server.js @@ -5,7 +5,7 @@ var sys = require('sys'), http = require('http'), ws = require('deps/node-ws/ws'), mongo = require('deps/node-mongodb-native/lib/mongodb'), - hb = require('hummingbird'); + Hummingbird = require('hummingbird').Hummingbird; var TRACKING_PORT = 8000, WEB_SOCKET_PORT = 8080, @@ -14,7 +14,7 @@ var TRACKING_PORT = 8000, var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); db.open(function(p_db) { - var hummingbird = new hb.Hummingbird(db, function() { + var hummingbird = new Hummingbird(db, function() { http.createServer(function(req, res) { try { hummingbird.serveRequest(req, res); From b47bafa66971632909eca5bebdc49fca9b46bd80 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 23 Apr 2010 11:49:24 -0400 Subject: [PATCH 055/267] Forgot to change static asset dir --- lib/static_assets.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/static_assets.js b/lib/static_assets.js index 8ed92d3..edcc313 100644 --- a/lib/static_assets.js +++ b/lib/static_assets.js @@ -23,6 +23,7 @@ var serveStatic = function(port) { }); } }).listen(port); + sys.puts('Analytics server running at http://localhost:' + port + '/'); } catch(e) { sys.puts('Detected webserver already running on http://localhost:' + port + '.'); From c6117a0d88789906a7e9bdb511296aa3ef49c87c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 25 Apr 2010 15:42:45 -0400 Subject: [PATCH 056/267] Change sales alignment to justified, below the cart adds canvas --- public/css/main.css | 7 +++---- public/js/sales.js | 8 ++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/public/css/main.css b/public/css/main.css index a41b534..ccc84cd 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -1,7 +1,6 @@ @charset "utf-8"; body { - background-color: #2F2C2B; font-family: "Lucida Grande", Helvetica, sans-serif; } @@ -53,7 +52,7 @@ div.hummingbird_graph div.axis_right { } #sales { - margin-left: 50px; + margin-left: 60px; } #sales div.sale { @@ -61,13 +60,13 @@ div.hummingbird_graph div.axis_right { width: 180px; height: 100px; overflow: hidden; - padding: 10px; + padding: 10px 0; position: relative; } #sales div.sale div.hummingbird_graph { position: absolute; - top: -5px; + top: -6px; left: 10px; width: 180px; } diff --git a/public/js/sales.js b/public/js/sales.js index 0816d5a..24e2561 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -23,6 +23,14 @@ Hummingbird.getSales = function() { var saleGraph = new Hummingbird.Graph(graph, { ratePerSecond: 2, initialScope: 200, backgroundImage: editorialImage, showBackgroundBars: false }); Hummingbird.saleGraphs[this.url_key] = saleGraph; }); + + var canvasWidth = $("#log canvas").width() - 8; + var salesPerRow = Math.floor(canvasWidth / 190); + var extraSpace = canvasWidth % 190; + var extraSpacePerSale = (extraSpace + 10) / (salesPerRow - 1); + + $("#sales div.sale").css({marginRight: extraSpacePerSale + 10}); + $("body").css({minWidth: $("#log").width()}); }); }; From 24fefc163696fdfa4fd0d2e10f4a4f1d2acb106d Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 25 Apr 2010 15:43:21 -0400 Subject: [PATCH 057/267] Show scale change separator between old scale and new scale --- public/js/analytics.js | 20 ++++++++++++-------- public/js/sales.js | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/public/js/analytics.js b/public/js/analytics.js index 7ee828c..2bddb47 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -104,7 +104,7 @@ Hummingbird.Graph.prototype = { }, longAverage: function() { - return this.longTrafficLog.sum() / this.longTrafficLog.length; + return this.longTrafficLog.sum() * 1.0 / this.longTrafficLog.length; }, drawEmptyGraph: function() { @@ -134,6 +134,8 @@ Hummingbird.Graph.prototype = { }, rescale: function(percent) { + var oldScale = this.scale; + if(percent == 0) { return; } if(percent > 0.9) { this.scale = this.scale * 2; @@ -145,18 +147,20 @@ Hummingbird.Graph.prototype = { return; } - this.drawSeparator(); + this.drawSeparator(percent, oldScale, this.scale); this.resetMarkers(); }, - drawSeparator: function() { + drawSeparator: function(percent, oldScale, newScale) { this.shiftCanvas(this.lineWidth * 2, 0); + var newHeight = percent * this.canvasHeight; + var oldHeight = percent * (oldScale/newScale) * this.canvasHeight; this.context.lineWidth = this.lineWidth; this.context.beginPath(); - this.context.strokeStyle = "#000"; - this.context.moveTo(this.canvasWidth - 10, this.canvasHeight); - this.context.lineTo(this.canvasWidth - 10, 0); + this.context.strokeStyle = "#CCC"; + this.context.moveTo(this.canvasWidth - 10, this.canvasHeight - oldHeight); + this.context.lineTo(this.canvasWidth - 10, this.canvasHeight - newHeight); this.context.stroke(); this.context.closePath(); }, @@ -198,8 +202,8 @@ Hummingbird.Graph.prototype = { } if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds - this.valueElement.text(average); - this.el.attr('data-average', this.longAverage()); + this.valueElement.text(Math.round(this.longAverage() * 60)); + this.el.attr('data-average', this.longAverage() * 60); this.rescale(percent); if(this.tick % 1000 == 0) { this.tick = 0; } } diff --git a/public/js/sales.js b/public/js/sales.js index 24e2561..c39e4e7 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -14,7 +14,7 @@ Hummingbird.getSales = function() { saleDiv.append("

" + name + "

"); var graph = $("
"); - graph.append("
0 pages/sec
"); + graph.append("
0 pages/min
"); var canvas = $(""); graph.append(canvas); From 7ae7838a47bc3b3ee372c3c1a44bec5e36a56580 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Sun, 25 Apr 2010 21:13:14 +0000 Subject: [PATCH 058/267] Parse the data average as a float when sorting sales --- public/js/sales.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/sales.js b/public/js/sales.js index c39e4e7..fdf94aa 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -37,7 +37,7 @@ Hummingbird.getSales = function() { Hummingbird.resortSales = function() { var sortedSales = $("div#sales div.sale").sorted({ by: function(a) { - return a.find('div.hummingbird_graph').attr('data-average') || -1; + return parseFloat(a.find('div.hummingbird_graph').attr('data-average')) || -1; } }); From eaad5ca2ef083dcb0c5d4d61ea506bf0583b410d Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 25 Apr 2010 18:44:40 -0400 Subject: [PATCH 059/267] Trying out gource log script --- deps/arrays.js | 8 ++++++++ scripts/gource.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 scripts/gource.js diff --git a/deps/arrays.js b/deps/arrays.js index fd57e32..b08b428 100644 --- a/deps/arrays.js +++ b/deps/arrays.js @@ -6,3 +6,11 @@ Array.prototype.remove = function(e) { Array.prototype.each = function(fn) { for (var i = 0; i < this.length; i++) fn(this[i]); } + +Array.prototype.compact = function(fn) { + for (var i = 0; i < this.length; i++) + if (this[i] == null) { + this.splice(i, 1); + } + return this; +} \ No newline at end of file diff --git a/scripts/gource.js b/scripts/gource.js new file mode 100644 index 0000000..de85c69 --- /dev/null +++ b/scripts/gource.js @@ -0,0 +1,32 @@ +require.paths.unshift(__dirname + "/.."); + +var sys = require('sys'), + arrays = require('deps/arrays'), + mongo = require('deps/node-mongodb-native/lib/mongodb'); + +var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); + +db.open(function(p_db) { + db.collection('visits', function(err, collection) { + collection.find({}, {limit: 1000, order: {timestamp: -1}}, function(err, cursor) { + cursor.each(function(err, item) { + if(item) { + if(!item.timestamp) { return; } + var itemString = ""; + + var path = [item.channel, item.prop1, item.url_key, item.product_id].compact().join('/'); + sys.log(path); + + [ Math.round(item.timestamp / 1000), + item.guid, + 'A', + path ].join('|'); + + sys.log(itemString); + } else { + sys.puts('FINISHED'); + } + }); + }); + }); +}); From b52116580172420f67d10ca2f9fd76dbc39820fd Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 25 Apr 2010 18:46:21 -0400 Subject: [PATCH 060/267] Better regex for determining url_key and product_id --- lib/view.js | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/view.js b/lib/view.js index 477caf6..c5c7e34 100644 --- a/lib/view.js +++ b/lib/view.js @@ -6,30 +6,22 @@ var View = function(env) { } this.env = env; + + if(this.env.u) { + var match = View.urlKeyRegexp.exec(this.env.u); + if(match && match.length > 2) { + this._urlKey = match[2]; + this._productId = match[4]; + } + } } View.prototype = { urlKey: function() { - if(this.env.u) { - var match = View.urlKeyRegexp.exec(this.env.u); - if(match && match.length > 0) { - this._urlKey = match[1]; - } - } - - this.urlKey = function() { return this._urlKey; } return this._urlKey; }, productId: function() { - if(this.env.u) { - var match = View.productIdRegexp.exec(this.env.u); - if(match && match.length > 0) { - this._productId = parseInt(match[1]); - } - } - - this.productId = function() { return this._productId; } return this._productId; }, @@ -47,7 +39,6 @@ View.prototype = { } }; -View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+\/s\/([^\/]+)\/?/); -View.productIdRegexp = new RegExp(/\/product\/([0-9]+)/); +View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/)([^\/\?]+)\/?(product\/)?(\d+)?/); exports.View = View; From 55f410eca192c3d05bcd7f35568d7333f1aa39c1 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 26 Apr 2010 00:20:59 -0400 Subject: [PATCH 061/267] Switching back to pages/second for sales graphs; having different scales is just too confusing --- public/js/analytics.js | 18 +++++------------- public/js/sales.js | 2 +- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/public/js/analytics.js b/public/js/analytics.js index 2bddb47..df675f3 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -20,7 +20,6 @@ Hummingbird.Graph = function(el, options) { this.canvas = $(el).find('canvas').get(0); this.valueElement = this.el.find('span.value'); this.trafficLog = []; - this.longTrafficLog = []; this.init(); }; @@ -77,11 +76,6 @@ Hummingbird.Graph.prototype = { if(this.trafficLog.length > this.options.ratePerSecond) { this.trafficLog.shift(); } - - this.longTrafficLog.push(value); - if(this.longTrafficLog.length > 200) { - this.longTrafficLog.shift(); - } }, shiftCanvas: function(x, y) { @@ -100,11 +94,7 @@ Hummingbird.Graph.prototype = { }, runningAverage: function() { - return this.trafficLog.sum() / this.trafficLog.length; - }, - - longAverage: function() { - return this.longTrafficLog.sum() * 1.0 / this.longTrafficLog.length; + return this.trafficLog.sum() * 1.0 / this.trafficLog.length; }, drawEmptyGraph: function() { @@ -202,9 +192,11 @@ Hummingbird.Graph.prototype = { } if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds - this.valueElement.text(Math.round(this.longAverage() * 60)); - this.el.attr('data-average', this.longAverage() * 60); + this.valueElement.text(average); + this.el.attr('data-average', average); + this.rescale(percent); + if(this.tick % 1000 == 0) { this.tick = 0; } } } diff --git a/public/js/sales.js b/public/js/sales.js index fdf94aa..75eb175 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -14,7 +14,7 @@ Hummingbird.getSales = function() { saleDiv.append("

" + name + "

"); var graph = $("
"); - graph.append("
0 pages/min
"); + graph.append("
0 pages/sec
"); var canvas = $(""); graph.append(canvas); From 37d9dbdd0e9521094dfda8abf7844778ae3ec226 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 26 Apr 2010 00:27:40 -0400 Subject: [PATCH 062/267] Update readme --- README | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README b/README index ae31b9e..f614238 100644 --- a/README +++ b/README @@ -22,3 +22,19 @@ Installation git submodule update --init mongod & (or start mongo some other way) node server.js + + +Specs + + sudo gem install jspec + jspec run --node + + +Tips + + * To run the UI locally but get some production data, use the url http://localhost:8088/?use_prod + + +Known Issues + + * node-paperboy has issues with returning 304's that cause some weirdness in some browsers. Try shift-reload until it's fixed. From 6c0db01fa5b17b037a1500fa74d75aa91f263616 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 26 Apr 2010 00:36:04 -0400 Subject: [PATCH 063/267] Freeze jspec libs --- spec/lib/images/bg.png | Bin 0 -> 154 bytes spec/lib/images/hr.png | Bin 0 -> 321 bytes spec/lib/images/loading.gif | Bin 0 -> 2608 bytes spec/lib/images/sprites.bg.png | Bin 0 -> 4876 bytes spec/lib/images/sprites.png | Bin 0 -> 3629 bytes spec/lib/images/vr.png | Bin 0 -> 145 bytes spec/lib/jspec.css | 149 +++ spec/lib/jspec.growl.js | 115 ++ spec/lib/jspec.jquery.js | 79 ++ spec/lib/jspec.js | 1889 ++++++++++++++++++++++++++++++++ spec/lib/jspec.nodejs.js | 18 + spec/lib/jspec.shell.js | 39 + spec/lib/jspec.timers.js | 90 ++ spec/lib/jspec.xhr.js | 208 ++++ spec/node.js | 3 +- 15 files changed, 2588 insertions(+), 2 deletions(-) create mode 100644 spec/lib/images/bg.png create mode 100644 spec/lib/images/hr.png create mode 100644 spec/lib/images/loading.gif create mode 100644 spec/lib/images/sprites.bg.png create mode 100644 spec/lib/images/sprites.png create mode 100644 spec/lib/images/vr.png create mode 100644 spec/lib/jspec.css create mode 100644 spec/lib/jspec.growl.js create mode 100644 spec/lib/jspec.jquery.js create mode 100644 spec/lib/jspec.js create mode 100644 spec/lib/jspec.nodejs.js create mode 100644 spec/lib/jspec.shell.js create mode 100644 spec/lib/jspec.timers.js create mode 100644 spec/lib/jspec.xhr.js diff --git a/spec/lib/images/bg.png b/spec/lib/images/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..947804ff6acaaf93986a0a11d205df3113656816 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^j0_CS3LH#8R&M_M3qVS;#5JNMI6tkVJh3R1!7(L2 zDOJHUH!(dmC^a#qvhZZ84N#Gdr;B4q#jT`Y|Nq+yGczC7kaMcgIDRvs>~})ZZHL{d z3*N|ke!F!0+{6dRCuY6RkTi>G?|T$zbHu=*fssL9)snBgXWIv$ISihzelF{r5}E+; Cx;4N6 literal 0 HcmV?d00001 diff --git a/spec/lib/images/hr.png b/spec/lib/images/hr.png new file mode 100644 index 0000000000000000000000000000000000000000..4a94d12fd8405c32b4c20abe777c1a9a7e6a30cb GIT binary patch literal 321 zcmV-H0lxl;P)A5E2-vx}KFiT96$Z17UamL`af0P}@7%Vq>XUIGjN-4D7? ThAmXZ00000NkvXXu0mjfvYCee literal 0 HcmV?d00001 diff --git a/spec/lib/images/loading.gif b/spec/lib/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..c69e937232b24ea30f01c68bbd2ebc798dcecfcb GIT binary patch literal 2608 zcmdVcdr(tX9tZGC9yiG~=H_*Q-0%n(kWqP*D#hw{AQu8;1%gl-Hrf&{2?48KX;hHy z3Ze*zEz4t3XdUFyLbNPUYlA`|B}P=N1fqtL1*}S;87#|-W9v<#G;ul(e%d3)N(^9c$d2Dz{7}?ErjNd;{EMKkCsk21~b9Gvg zDo<7L=3Z5HNbVlZUcm1eg#o#CZCJU`3IYHwM->zCd?uYrF3vKFeM}v?f+%s?E>ly|3W25ry9#NNbTx-}0ON58dTrs^ix{_1O0Wh~SVSBlH)Ajn zPn^Gbjz}PCtN@#keR&hK&Dhl-b$kZ8^S)x#dh0{7X=X%CCJk7P1PSO>T&S8I4{#Lg zb5#)o=;!ZP*1nM{cI4@(x7o27*SA()NHmrn67aN@Pmi~(i_SnrjYnwh36aG%!@i0d zqbvfa44f|?OG4ntP|nbjhEl1)Yp6ZN@yjy zy4==QmLy%t;ps3R?~f2KfTTI|2?q8dFd6^z5GF+Xa&Y)sjG)hxit80pPcOP zJ z*LW{SyGHD%hUotV+W%I}fBLAIx!8|7#}$;clKQ+{&FjDqGQ2ZNx(lYM3*%~}ILnao zM`aui55~ZFJlu^!5rdA9Q_7H68H_;##u{x(Yn-vSfIRCb^Nqsg zGRS!Egm>h+o<}LeV4&CLReo9FrDjDvs}8?JwC)#Qs|ie=r?~xUh)&*d`Fx>FG}%X# zNdtDHBKhLPC0wpooFDAQKL%*6T|ULH$=wX!NhcasgD3d;-d$I6yRK3yN+E~C1335_iLOt+*9uvSZ`>*KA}vm}08wRq=>5l|t*Na&jR z-C1&C`nkEk#sB|@yyt-#fXngP04My zm7u$Q%EJbHp`>~`5W&L{W!6`y&}LMS;jfUpgO~7TLVMRZ9IC)IZp0A${`yp0{&wco z#1nx@XMkhqeK%7?RE7JdLr1^nwFfaJ0Q&Lv?WNJ%9}VSJsNY2+UYs2%EU0J~ayFXv zi*?7KCXQHkD)O6!0Q%4N+HTODHxJ{kQSuQX$l-rSwkwh(zMkdfzxyGwl@yHC)C4p< z&n2%8#M?)Q@mgHL1ot8`SFdSEj9ye|jHy+U8#@HoUExG=@AVkRAe_qYm4EpzK6L*& zh`)26?V#f4#_h^P9G^%>h2-H3)$QP zQovu6J9qDvsxqweDdNNa!Lb?L4_UF{tLX_nN7r0U_vF14YKcGR-*Gl} zx3oG)bzf|65dBxD-;2ZCp??K;+TuQ9onnK?==5hzbkb^r_g>z4#D8mcv8(+XdoszA zCx-qhdgxMNMotj}SiL_6V(tLcsK7(M(r(%u<}QrVfOvyK6_;~NOTlPGfX@M7S5YQF z&*$(ylJMHJt^_aQeu{C6NaTE$G3HNN@_SnN8YcaKn%`)F@~L1x+ah7-gEJPpc6w%3 zyX}r+Qk$4RHZzfH){e~F*qJ{d*L8a6n4;U?+{de0-t)mal#TVxe)3F}^UBh+zd T)6_**#cgp_+?JL9(ew3BlNF>u literal 0 HcmV?d00001 diff --git a/spec/lib/images/sprites.bg.png b/spec/lib/images/sprites.bg.png new file mode 100644 index 0000000000000000000000000000000000000000..dc8790f338c4fce6611e0c2d2f811882a4136b32 GIT binary patch literal 4876 zcma)AYgAKL7QTt7h!xN>MFk5}M_Q((YAZp6lE`RVTY)U;s*Zq26>P(l+-gO4~V|-c!N~y{MGtpHvVBhI;gHY zgsljhedU(>{lqO9JkK!q%3V?IdF+u!j~J`c%3Gh+S2pe(O5j z{H6lCAKG^vX^m^m8~yBtKBdNS^C82N!4_e-i?g%A_{)XYnY|&08A4UdkZxRe`|-7` z=}VK--OP~5In}YuY2K*7c)y^2SiO0+u_o_xIp@dmw<>16J`T%v4_6G_=p9sNH8fti zrgPKlbJZbSMK=FLOkBeiLjy;hvAZj-eW?9k(m!NF6O5dU$h?&OIr9l^`hf6e#?8Lq z@Qq&l(7n7D0(o;i16vu7xG(GCq^$!+7xN%(g*o)!6kQo^Jua?Z>gLH6z+>6AWLKG->X;Cu>9Fzb}4}Hrki>Mt#tY z>F=vD^vjwn`|nGQxr*h%ilBf2ncfHM-u z?H>KZO&li;y|Y;>I+W-nFidF`>FMb~eIlMNy*^QG>{s>H=^p;xdg+}rljUdh;|(IN zs;94`e7`<>iNFq~+@-*e-{Z4mN6)P0VN;)Os4ay*Z=4g`T^3ACs(KZnVgWyP%3ck& zo@`8GxUA=|{ZyPV+UfO=db?Ur2xo=P}T(j8#6c2&{{f+c|#=r4m0D?ly+eM!)ugO0aP zFkS={CD`(0KS%iRwLjcVlFPv}+8tU<#`^RCGeqi=M%AbAdk5Pj@QKaVTPH=sOI%%* z6=%Uqk|e$8&@_z}YXz^Q)BCL9tyWf|)$o|Lb<#$7k-fdPUiPqVaUB@z1LTi~blfiFBKFoFB11j>%CLc339 zIzyAIp_>*r=eaMy4c!Lmj)TCtx+()GUrfB9UZXTyBoyKVNQ0fQ5@8kugP4&QHqqzC zk=t~XMFbK`Hrec;$^Hg$mQ2L1Jxi5b}|l zS0PICe{UfNSR6(*w4F=hx3Z%z`hZQ=hcOn5K`_DJdKSaKz^SStMzry7%HAS)70aWd zI}6=T2=4=oSRXvYW|@rh2|NhbW9S~)04A^!FRwsgF=KpICSeo!Pk^7}X>hcp6sHib zt?OZRl(aa&7w@lFs6O!5qA~(GLr^SA3JMAVZjtV*zXxU`<*=7{WB7b#f^ITr z2un?_O;SBoy1gi)bhBMaTF>=FBuF%rJBQB63M@+(F-r=a&L-MI_Q?jFVKg8N=)PIl z-h2}qCx#HN_Q)8z;C>p8NrGUow!p4;xKmOW1niLcf%Ha?FCpf~s}Tt>yV(~pg|Q-; zY8&{1t4bDy1a2R?28aumFAI#!Ol4hohMN|99QTJz3f5?J(+@o8;QpnxQB;{AAdrQ_ z$7pI4wWWYLox)t-io`b6dpRuCFVKDfj`U~95SFC(Cs@c9NMrURbUs=^B?J@*W@ChE zU^_lZpjZm4Vr&|aXqS`<{jr=Me;Zxsj!Xc;EUscFiuwOXv77U6fyV-`*av*P15q-` z^JHw37R15wz~WEF*zjkqz!xQVk=#Gkqzbf=`WB_DNF z_5q=1ES8Kad#)T`1xRIcg(j@qyF?jTAQ*i^@VI2@U1+^DzA*KnY^O z>d8cwK7gNuXF@ck!uhvQHLy4cd~_VerhIFu=*R%rTIfa<5?*j2xzi};DS==IQ(AdG zU<{mbC2?m*wNGvJaTf^tW~ zu+R*Vx;_)$xD>_(_ORwUj#3)KXa7 zIfmO8ft&;s2LVx?ZS?}(Vd_Cgz#YrXYdHLvnue(&7SC!BVT(3k8n!46INlP2$n4M= z)k3|(bcLQEjx$sj0*e)z)L?6Pk$?1Ilj1JY!G>v{w^#F>>BdurgC8kmZlR74G z09CC>FfA(#p@7(>boNG*G93`A8x1v7dxY^}#s|n9PNVFxgYi8w8G1p~VuIjCYMQNa zbHHufOkHv%7AO0{-k&NvU}>`3FSL6?O|$$dhO%KAgvb~)2vTfBuNF;0r`BjV+fkRg zEc92T^@H4z`BWLp*W)pfEyP;5g>}1=CUa)Y@Pe9v-d`!d^Tw4SwR@8`J$&nUXXy z(ov8tR(=dk`e$cnPaYBr=7x&o>E!&lwqL5Sr7;b+uLKo5@COG^X2V~;a~jP__2c#{ z3R_hp)6mwGZa2>;XcG%G%G>Jf3 z&k1(v7y2HOhNe~Po634)gtM`~itESq%@;>&#(0cJT2Z<5aaq?$fcVDnOm;&HS9|98 zh>p{(5|4AgJ-wmWcxhc6-;3AiQ6F3E7jwnW(Tle?i{Dl?GVT4yxK?*4PCj%boLOwJ zl@I8(WzF7$6Hy~`4J!5dYOzxtKPKjho^dm9)Ocb<-OmYkxg(nI?wB|@Id!ljy4U#K z)~-30N9sQr8*M5ZGIlf1fPXmD=WPx*KDvAU)s*C?!@q^6b6t#+8f}MG z+Lpr2Dm@c-n< literal 0 HcmV?d00001 diff --git a/spec/lib/images/sprites.png b/spec/lib/images/sprites.png new file mode 100644 index 0000000000000000000000000000000000000000..010b98eeef699c0d0f4d0136d7d2d352b2b51d4c GIT binary patch literal 3629 zcmcJSc{tQ-8^=)+DkW>S!X(?+5@U%%lAU3)r!f@9zJ(!*4kMim#$fECVuZ0TEq0Zy zEHic!LktmP%Xn4SIj6UC&U@Z}&UM|__5AMZe!ll}|E}k`f1l?UV`8LxnB@cu9Ua|a zz02BWd!q*(9fRn>1A9-qOoBsu1FxUXRX=l2XTLy49~j*QC(rA!lX`GR7nm8$(dm|V z2TW~G+^wg50UShJAcn+&`vqPsk0ahTjsq8g6AZ|#NXDmABE)OfHqfN^?86+lzVvFO zrc7nRQM7*AyR-1)$5X*+XCLZj%jh46!=L=ZXfsc9G;pGiih@PJj!_TSm9LNa8g)06 z=ZX-hY}!li+dDuMb`;Bt`n;STvN+-$CwI|T27QVy{K+n~QC$*rcZU9zJ}y)ms4G+l<*Xqb@my)!w{*z24HmFms;FLn)eMPmG|^ zbSQ%kOM?UbCyLDtRrlS;`dQnyRrm=fC0RVmDeDvx34}+*PAehs@Jy+K&(`D`C<$78D6rKl;IX^=4cETX7KxLOo$lk; zNvmYhI=@Hjh;ifRRrqs?@*})W7Bdp+-FnQ(U6!lypI<^_*V)1FeDYg2a+9=GlhsMm z5GjT6Seq{Z)DGZF?qd_guwRBgKty;3ViTop-E*8A@o7ivLgJvyYD-#qy!B3xYH+Ii z;AT#pTRdVJSgkIm*U(yit_N_V$)V(Hr!5&xwo_!C@a560wrzt~K+Gl#D0j`+a!Eul zX1l`~piX`kF2t91trOM=mQX(-39}vCo{i4?5H{%&@}=CtqCbi1cg-nfvWo{-QQ_}( zJ@nPGz%ou-zma=MOrfN<%>GhzE7-zfS|?f+s;u!Tzp-?AsHZ(;?IfHl;JB!7=}!R*$2u_Wa*AX%2>-MTnxUGyEw18XmQG;k(#I3u;7 zO{FpsMu%pV5XC!mUf=9kmX`COEE^Kk^B~nK*9z=|f#{Ki%;wh?vP4Xi1qZGe0AUdB z=9B^2GxsPg*`==9akh2gKfHAwXEoF8JOM=O6Z!zAA?$UgEa)sw<4%-KnRal%rCP2* zCSXW43oANnqfye719`+JC#g)o0P9b!MyCgF8K{<6_kJS}AG?H(wy+cKMP0L@7AAMGhFjobX^m z$8_(=oDVVcIn~b*klbR`W@dGyt$Nkk#?g|qq|K@+p*yX5j&WeWhllq1tJi&6@WmK(hq{R&$Ze;Viv!;qjq~SV#jZzw8qs;e+yNp^2o6hz+>| zW5sX6AXW_EbpIAMrlclz|PcKGv^a7e8!my50VS(q&8ic62X5PK>G<&c#`KjN<0La=1H466oV-~&4aFphS4 zmDXPVF$;FD{rr1Iulr)pj(P3bpM83!-{aqd-~1mY|Lp&m><94+x&6QA|9>T4>-izY zAM0lt(Ap3Y?~K*^VTof$kwo`bg@#Bj=+p&3@V#@c>#+`$Iao>wB3^FhNoJ_?y!kw| zxUzq|9^c@+=IVW7UT5W2Ocz`GC&`lb_D?+^*!zLufCWTGHt=}$enat!hD}yCH&;u< zrS~yS!enFQ-E8Fw!>JLkJBJ!JxIv?VU&<_(lU3L2_uCJ6?buWSOJ9>-CU=j%Gexw) zbEwZxqRel3gGD)OH2LApcW*tkIWNgg+bT;3jca5XhVC{zN38AF%9xyK&Vd&#-k2+_ zUE?xkvS(LR2LuP3MRs`i=4$1%-qRtA0aP~1@aI3>22U5LCR+0GF2*T|5lz!vEyqN+ z+K1&qKBiNFEZYw{Bn8oKZoh6gmEcPnA(z+$hMdCJw4&9tl@jWRd{T3q((aY^r6?#f>DkQ30?xo@a%!u=-FZQ(8I zTCdsM5vrCG&=jagmKDeO1*!<@>$&&$^3fV5d@Jk5quA93*NOk<+V<+OvQCwM zGkCs@$G6{@)~TR7aL*AB_r7z};T_@38c1emX9z6C^Z<(vJOIor-;F9B)!6v*`H(;6 zMe(*y_m-Cgkv4I^Ur~}g*g?oPInee<`=-d@{tUmf;LcLy@v=aNC75bSm7hk#k@})Z z!JSQ2{hTxBHzxX0NeFz`$lyZUv)=-$bHl_j+j-PLjrCNj30mNz5oK*xMxLc|7ZCr?MK zlI-%aj-S&$hJpgRfDf)v2Bw6{;RpE^(8&T1C|lBqOaDF*;f; zemxR0G|PkJLRRV*R_Z%z8AhcGWgczo-Rs4o$yY(-hzx~3f;F_eoRV;(Uaj(hg@3xg?()^3ZKN=|H&=m={ABSt-1H%-}XUudS^7-oeS$(K2EvR%!>~vPF}`u zzik*NfA3U(70utc^_QIZ&b2?d@!RA-LGKX#-=XGjB|mZVuh;*VIhiRx(mkf;@-fV> zC)B(9RMRtg(kv?avn?c!?-x=~+(+9;Uu|SBF3Ojuzh*yVdYHE$4jjxsb^bm-6z7pO zNZWe$ctv2FLAVhM7i$#(fs)ZgTcZI#a65P*cBxuk1#2v{TO$25C3aAD*EMrvVA(sy zTp5Pe(~WD8p(+P!uL-JxroJ8UbaXQR;qd*aTan;tkc6_VYNc( z%?wAnUcB!d+8In{x6Kn-CYb<@6$)VupzPg;y#IV(=@sjF&d5V|bw=gv8|G%sz5hQt NJsl%$+{J5={{f-$rB(m{ literal 0 HcmV?d00001 diff --git a/spec/lib/images/vr.png b/spec/lib/images/vr.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e76175d3e8a4b5092757c9cbbfb81802804bc6 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yVEzDPGjgy2$;wJseIO-S;u=vBoS#-wo>-L1;Fyx1 zl&avFo0y&&l$w}QS$Hzl2B^r`)5S5Q;?|q%hN29LJggh+4ZdAv`VrpRF7+Vg&V(H& syf&pj3kwA*Y^eWvZr(dP{{}_|Ay#%3&0R090!0}-UHx3vIVCg!0D1l{cmMzZ literal 0 HcmV?d00001 diff --git a/spec/lib/jspec.css b/spec/lib/jspec.css new file mode 100644 index 0000000..629d41c --- /dev/null +++ b/spec/lib/jspec.css @@ -0,0 +1,149 @@ +body.jspec { + margin: 45px 0; + font: 12px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; + background: #efefef url(images/bg.png) top left repeat-x; + text-align: center; +} +#jspec { + margin: 0 auto; + padding-top: 30px; + width: 1008px; + background: url(images/vr.png) top left repeat-y; + text-align: left; +} +#jspec-top { + position: relative; + margin: 0 auto; + width: 1008px; + height: 40px; + background: url(images/sprites.bg.png) top left no-repeat; +} +#jspec-bottom { + margin: 0 auto; + width: 1008px; + height: 15px; + background: url(images/sprites.bg.png) bottom left no-repeat; +} +#jspec .loading { + margin-top: -45px; + width: 1008px; + height: 80px; + background: url(images/loading.gif) 50% 50% no-repeat; +} +#jspec-title { + position: absolute; + top: 15px; + left: 20px; + width: 160px; + font-size: 22px; + font-weight: normal; + background: url(images/sprites.png) 0 -126px no-repeat; + text-align: center; +} +#jspec-title em { + font-size: 10px; + font-style: normal; + color: #BCC8D1; +} +#jspec-report * { + margin: 0; + padding: 0; + background: none; + border: none; +} +#jspec-report { + padding: 15px 40px; + font: 11px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; + color: #7B8D9B; +} +#jspec-report.has-failures { + padding-bottom: 30px; +} +#jspec-report .hidden { + display: none; +} +#jspec-report .heading { + margin-bottom: 15px; +} +#jspec-report .heading span { + padding-right: 10px; +} +#jspec-report .heading .passes em { + color: #0ea0eb; +} +#jspec-report .heading .failures em { + color: #FA1616; +} +#jspec-report table { + font-size: 11px; + border-collapse: collapse; +} +#jspec-report td { + padding: 8px; + text-indent: 30px; + color: #7B8D9B; +} +#jspec-report tr.body { + display: none; +} +#jspec-report tr.body pre { + margin: 0; + padding: 0 0 5px 25px; +} +#jspec-report tr.even:hover + tr.body, +#jspec-report tr.odd:hover + tr.body { + display: block; +} +#jspec-report tr td:first-child em { + display: block; + clear: both; + font-style: normal; + font-weight: normal; + color: #7B8D9B; +} +#jspec-report tr.even:hover, +#jspec-report tr.odd:hover { + text-shadow: 1px 1px 1px #fff; + background: #F2F5F7; +} +#jspec-report td + td { + padding-right: 0; + width: 15px; +} +#jspec-report td.pass { + background: url(images/sprites.png) 3px -7px no-repeat; +} +#jspec-report td.fail { + background: url(images/sprites.png) 3px -158px no-repeat; + font-weight: bold; + color: #FC0D0D; +} +#jspec-report td.requires-implementation { + background: url(images/sprites.png) 3px -333px no-repeat; +} +#jspec-report tr.description td { + margin-top: 25px; + padding-top: 25px; + font-size: 12px; + font-weight: bold; + text-indent: 0; + color: #1a1a1a; +} +#jspec-report tr.description:first-child td { + border-top: none; +} +#jspec-report .assertion { + display: block; + float: left; + margin: 0 0 0 1px; + padding: 0; + width: 1px; + height: 5px; + background: #7B8D9B; +} +#jspec-report .assertion.failed { + background: red; +} +.jspec-sandbox { + display: none; +} \ No newline at end of file diff --git a/spec/lib/jspec.growl.js b/spec/lib/jspec.growl.js new file mode 100644 index 0000000..a150257 --- /dev/null +++ b/spec/lib/jspec.growl.js @@ -0,0 +1,115 @@ + +// JSpec - Growl - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + Growl = { + + // --- Version + + version: '1.0.0', + + /** + * Execute the given _cmd_, returning an array of lines from stdout. + * + * Examples: + * + * Growl.exec('growlnotify', '-m', msg) + * + * @param {string ...} cmd + * @return {array} + * @api public + */ + + exec: function(cmd) { + var lines = [], line + with (JavaImporter(java.lang, java.io)) { + var proccess = Runtime.getRuntime().exec(Array.prototype.slice.call(arguments)) + var stream = new DataInputStream(proccess.getInputStream()) + while (line = stream.readLine()) + lines.push(line + '') + stream.close() + } + return lines + }, + + /** + * Return the extension of the given _path_ or null. + * + * @param {string} path + * @return {string} + * @api private + */ + + extname: function(path) { + return path.lastIndexOf('.') != -1 ? + path.slice(path.lastIndexOf('.') + 1, path.length) : + null + }, + + /** + * Version of the 'growlnotify' binary. + * + * @return {string} + * @api private + */ + + binVersion: function() { + try { return this.exec('growlnotify', '-v')[0].split(' ')[1] } catch (e) {} + }, + + /** + * Send growl notification _msg_ with _options_. + * + * Options: + * + * - title Notification title + * - sticky Make the notification stick (defaults to false) + * - name Application name (defaults to growlnotify) + * - image + * - path to an icon sets --iconpath + * - path to an image sets --image + * - capitalized word sets --appIcon + * - filename uses extname as --icon + * - otherwise treated as --icon + * + * Examples: + * + * Growl.notify('New email') + * Growl.notify('5 new emails', { title: 'Thunderbird' }) + * + * @param {string} msg + * @param {options} hash + * @api public + */ + + notify: function(msg, options) { + options = options || {} + var args = ['growlnotify', '-m', msg] + if (!this.binVersion()) throw new Error('growlnotify executable is required') + if (image = options.image) { + var flag, ext = this.extname(image) + flag = flag || ext == 'icns' && 'iconpath' + flag = flag || /^[A-Z]/.test(image) && 'appIcon' + flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' + flag = flag || ext && (image = ext) && 'icon' + flag = flag || 'icon' + args.push('--' + flag, image) + } + if (options.sticky) args.push('--sticky') + if (options.name) args.push('--name', options.name) + if (options.title) args.push(options.title) + this.exec.apply(this, args) + } + } + + JSpec.include({ + name: 'Growl', + reporting: function(options){ + var stats = JSpec.stats + if (stats.failures) Growl.notify('failed ' + stats.failures + ' assertions', { title: 'JSpec'}) + else Growl.notify('passed ' + stats.passes + ' assertions', { title: 'JSpec' }) + } + }) + +})() \ No newline at end of file diff --git a/spec/lib/jspec.jquery.js b/spec/lib/jspec.jquery.js new file mode 100644 index 0000000..46422ec --- /dev/null +++ b/spec/lib/jspec.jquery.js @@ -0,0 +1,79 @@ + +// JSpec - jQuery - Copyright TJ Holowaychuk (MIT Licensed) + +JSpec +.requires('jQuery', 'when using jspec.jquery.js') +.include({ + name: 'jQuery', + + // --- Initialize + + init : function() { + jQuery.ajaxSetup({ async: false }) + }, + + // --- Utilities + + utilities : { + element: jQuery, + elements: jQuery, + sandbox : function() { + return jQuery('
') + } + }, + + // --- Matchers + + matchers : { + have_tag : "jQuery(expected, actual).length === 1", + have_one : "alias have_tag", + have_tags : "jQuery(expected, actual).length > 1", + have_many : "alias have_tags", + have_any : "alias have_tags", + have_child : "jQuery(actual).children(expected).length === 1", + have_children : "jQuery(actual).children(expected).length > 1", + have_text : "jQuery(actual).text() === expected", + have_value : "jQuery(actual).val() === expected", + be_enabled : "!jQuery(actual).attr('disabled')", + have_class : "jQuery(actual).hasClass(expected)", + be_animated : "jQuery(actual).queue().length > 0", + + be_visible : function(actual) { + return jQuery(actual).css('display') != 'none' && + jQuery(actual).css('visibility') != 'hidden' && + jQuery(actual).attr('type') != 'hidden' + }, + + be_hidden : function(actual) { + return !JSpec.does(actual, 'be_visible') + }, + + have_classes : function(actual) { + return !JSpec.any(JSpec.toArray(arguments, 1), function(arg){ + return !JSpec.does(actual, 'have_class', arg) + }) + }, + + have_attr : function(actual, attr, value) { + return value ? jQuery(actual).attr(attr) == value: + jQuery(actual).attr(attr) + }, + + have_event_handlers : function(actual, expected) { + return jQuery(actual).data('events') ? + jQuery(actual).data('events').hasOwnProperty(expected) : + false + }, + + 'be disabled selected checked' : function(attr) { + return 'jQuery(actual).attr("' + attr + '")' + }, + + 'have type id title alt href src sel rev name target' : function(attr) { + return function(actual, value) { + return JSpec.does(actual, 'have_attr', attr, value) + } + } + } +}) + diff --git a/spec/lib/jspec.js b/spec/lib/jspec.js new file mode 100644 index 0000000..79d7077 --- /dev/null +++ b/spec/lib/jspec.js @@ -0,0 +1,1889 @@ + +// JSpec - Core - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + JSpec = { + version : '4.2.1', + assert : true, + cache : {}, + suites : [], + modules : [], + allSuites : [], + sharedBehaviors: [], + matchers : {}, + stubbed : [], + options : {}, + request : 'XMLHttpRequest' in this ? XMLHttpRequest : null, + stats : { specs: 0, assertions: 0, failures: 0, passes: 0, specsFinished: 0, suitesFinished: 0 }, + + /** + * Default context in which bodies are evaluated. + * + * Replace context simply by setting JSpec.context + * to your own like below: + * + * JSpec.context = { foo : 'bar' } + * + * Contexts can be changed within any body, this can be useful + * in order to provide specific helper methods to specific suites. + * + * To reset (usually in after hook) simply set to null like below: + * + * JSpec.context = null + * + */ + + defaultContext : { + + /** + * Return an object used for proxy assertions. + * This object is used to indicate that an object + * should be an instance of _object_, not the constructor + * itself. + * + * @param {function} constructor + * @return {hash} + * @api public + */ + + an_instance_of : function(constructor) { + return { an_instance_of : constructor } + }, + + /** + * Load fixture at _path_. + * + * Fixtures are resolved as: + * + * - + * - .html + * + * @param {string} path + * @return {string} + * @api public + */ + + fixture : function(path) { + if (JSpec.cache[path]) return JSpec.cache[path] + return JSpec.cache[path] = + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) || + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.html') + }, + + /** + * Load json fixture at _path_. + * + * JSON fixtures are resolved as: + * + * - + * - .json + * + * @param {string} path + * @return {object} + * @api public + */ + + json_fixture: function(path) { + if (!JSpec.cache['json:' + path]) + JSpec.cache['json:' + path] = + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path) || + JSpec.tryLoading(JSpec.options.fixturePath + '/' + path + '.json') + try { + return eval('(' + JSpec.cache['json:' + path] + ')') + } catch (e) { + throw 'json_fixture("' + path + '"): ' + e + } + } + }, + + // --- Objects + + reporters : { + + /** + * Report to server. + * + * Options: + * - uri specific uri to report to. + * - verbose weither or not to output messages + * - failuresOnly output failure messages only + * + * @api public + */ + + Server : function(results, options) { + var uri = options.uri || 'http://' + window.location.host + '/results' + JSpec.post(uri, { + stats: JSpec.stats, + options: options, + results: map(results.allSuites, function(suite) { + if (suite.isExecutable()) + return { + description: suite.description, + specs: map(suite.specs, function(spec) { + return { + description: spec.description, + message: !spec.passed() ? spec.failure().message : null, + status: spec.requiresImplementation() ? 'pending' : + spec.passed() ? 'pass' : + 'fail', + assertions: map(spec.assertions, function(assertion){ + return { + passed: assertion.passed + } + }) + } + }) + } + }) + }) + if ('close' in main) main.close() + }, + + /** + * Default reporter, outputting to the DOM. + * + * Options: + * - reportToId id of element to output reports to, defaults to 'jspec' + * - failuresOnly displays only suites with failing specs + * + * @api public + */ + + DOM : function(results, options) { + var id = option('reportToId') || 'jspec', + report = document.getElementById(id), + failuresOnly = option('failuresOnly'), + classes = results.stats.failures ? 'has-failures' : '' + if (!report) throw 'JSpec requires the element #' + id + ' to output its reports' + + function bodyContents(body) { + return JSpec. + escape(JSpec.contentsOf(body)). + replace(/^ */gm, function(a){ return (new Array(Math.round(a.length / 3))).join(' ') }). + replace(/\r\n|\r|\n/gm, '
') + } + + report.innerHTML = '
\ + Passes: ' + results.stats.passes + ' \ + Failures: ' + results.stats.failures + ' \ + Duration: ' + results.duration + ' ms \ +
' + map(results.allSuites, function(suite) { + var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran + if (displaySuite && suite.isExecutable()) + return '' + + map(suite.specs, function(i, spec) { + return '' + + (spec.requiresImplementation() ? + '' : + (spec.passed() && !failuresOnly) ? + '' : + !spec.passed() ? + '' : + '') + + '' + }).join('') + '' + }).join('') + '
' + escape(suite.description) + '
' + escape(spec.description) + '' + escape(spec.description)+ '' + spec.assertionsGraph() + '' + escape(spec.description) + + map(spec.failures(), function(a){ return '' + escape(a.message) + '' }).join('') + + '' + spec.assertionsGraph() + '
' + bodyContents(spec.body) + '
' + }, + + /** + * Terminal reporter. + * + * @api public + */ + + Terminal : function(results, options) { + var failuresOnly = option('failuresOnly') + print(color("\n Passes: ", 'bold') + color(results.stats.passes, 'green') + + color(" Failures: ", 'bold') + color(results.stats.failures, 'red') + + color(" Duration: ", 'bold') + color(results.duration, 'green') + " ms \n") + + function indent(string) { + return string.replace(/^(.)/gm, ' $1') + } + + each(results.allSuites, function(suite) { + var displaySuite = failuresOnly ? suite.ran && !suite.passed() : suite.ran + if (displaySuite && suite.isExecutable()) { + print(color(' ' + suite.description, 'bold')) + each(suite.specs, function(spec){ + var assertionsGraph = inject(spec.assertions, '', function(graph, assertion){ + return graph + color('.', assertion.passed ? 'green' : 'red') + }) + if (spec.requiresImplementation()) + print(color(' ' + spec.description, 'blue') + assertionsGraph) + else if (spec.passed() && !failuresOnly) + print(color(' ' + spec.description, 'green') + assertionsGraph) + else if (!spec.passed()) + print(color(' ' + spec.description, 'red') + assertionsGraph + + "\n" + indent(map(spec.failures(), function(a){ return a.message }).join("\n")) + "\n") + }) + print("") + } + }) + + quit(results.stats.failures) + } + }, + + Assertion : function(matcher, actual, expected, negate) { + extend(this, { + message: '', + passed: false, + actual: actual, + negate: negate, + matcher: matcher, + expected: expected, + + // Report assertion results + + report : function() { + if (JSpec.assert) + this.passed ? JSpec.stats.passes++ : JSpec.stats.failures++ + return this + }, + + // Run the assertion + + run : function() { + // TODO: remove unshifting + expected.unshift(actual) + this.result = matcher.match.apply(this, expected) + this.passed = negate ? !this.result : this.result + if (!this.passed) this.message = matcher.message.call(this, actual, expected, negate, matcher.name) + return this + } + }) + }, + + ProxyAssertion : function(object, method, times, negate) { + var self = this, + old = object[method] + + // Proxy + + object[method] = function(){ + var args = toArray(arguments), + result = old.apply(object, args) + self.calls.push({ args : args, result : result }) + return result + } + + // Times + + this.times = { + once : 1, + twice : 2 + }[times] || times || 1 + + extend(this, { + calls: [], + message: '', + defer: true, + passed: false, + negate: negate, + object: object, + method: method, + + // Proxy return value + + and_return : function(result) { + this.expectedResult = result + return this + }, + + // Proxy arguments passed + + with_args : function() { + this.expectedArgs = toArray(arguments) + return this + }, + + // Check if any calls have failing results + + anyResultsFail : function() { + return any(this.calls, function(call){ + return self.expectedResult.an_instance_of ? + call.result.constructor != self.expectedResult.an_instance_of: + !equal(self.expectedResult, call.result) + }) + }, + + // Check if any calls have passing results + + anyResultsPass : function() { + return any(this.calls, function(call){ + return self.expectedResult.an_instance_of ? + call.result.constructor == self.expectedResult.an_instance_of: + equal(self.expectedResult, call.result) + }) + }, + + // Return the passing result + + passingResult : function() { + return this.anyResultsPass().result + }, + + // Return the failing result + + failingResult : function() { + return this.anyResultsFail().result + }, + + // Check if any arguments fail + + anyArgsFail : function() { + return any(this.calls, function(call){ + return any(self.expectedArgs, function(i, arg){ + if (arg == null) return call.args[i] == null + return arg.an_instance_of ? + call.args[i].constructor != arg.an_instance_of: + !equal(arg, call.args[i]) + + }) + }) + }, + + // Check if any arguments pass + + anyArgsPass : function() { + return any(this.calls, function(call){ + return any(self.expectedArgs, function(i, arg){ + return arg.an_instance_of ? + call.args[i].constructor == arg.an_instance_of: + equal(arg, call.args[i]) + + }) + }) + }, + + // Return the passing args + + passingArgs : function() { + return this.anyArgsPass().args + }, + + // Return the failing args + + failingArgs : function() { + return this.anyArgsFail().args + }, + + // Report assertion results + + report : function() { + if (JSpec.assert) + this.passed ? ++JSpec.stats.passes : ++JSpec.stats.failures + return this + }, + + // Run the assertion + + run : function() { + var methodString = 'expected ' + object.toString() + '.' + method + '()' + (negate ? ' not' : '' ) + + function times(n) { + return n > 2 ? n + ' times' : { 1: 'once', 2: 'twice' }[n] + } + + if (this.expectedResult != null && (negate ? this.anyResultsPass() : this.anyResultsFail())) + this.message = methodString + ' to return ' + puts(this.expectedResult) + + ' but ' + (negate ? 'it did' : 'got ' + puts(this.failingResult())) + + if (this.expectedArgs && (negate ? !this.expectedResult && this.anyArgsPass() : this.anyArgsFail())) + this.message = methodString + ' to be called with ' + puts.apply(this, this.expectedArgs) + + ' but was' + (negate ? '' : ' called with ' + puts.apply(this, this.failingArgs())) + + if (negate ? !this.expectedResult && !this.expectedArgs && this.calls.length >= this.times : this.calls.length != this.times) + this.message = methodString + ' to be called ' + times(this.times) + + ', but ' + (this.calls.length == 0 ? ' was not called' : ' was called ' + times(this.calls.length)) + + if (!this.message.length) + this.passed = true + + return this + } + }) + }, + + /** + * Specification Suite block object. + * + * @param {string} description + * @param {function} body + * @api private + */ + + Suite : function(description, body, isShared) { + var self = this + extend(this, { + body: body, + description: description, + suites: [], + sharedBehaviors: [], + specs: [], + ran: false, + shared: isShared, + hooks: { 'before' : [], 'after' : [], + 'before_each' : [], 'after_each' : [], + 'before_nested' : [], 'after_nested' : []}, + + // Add a spec to the suite + + addSpec : function(description, body) { + var spec = new JSpec.Spec(description, body) + this.specs.push(spec) + JSpec.stats.specs++ // TODO: abstract + spec.suite = this + }, + + // Add a before hook to the suite + + addBefore : function(options, body) { + body.options = options || {} + this.befores.push(body) + }, + + // Add an after hook to the suite + + addAfter : function(options, body) { + body.options = options || {} + this.afters.unshift(body) + }, + + // Add a hook to the suite + + addHook : function(hook, body) { + this.hooks[hook].push(body) + }, + + // Add a nested suite + + addSuite : function(description, body, isShared) { + var suite = new JSpec.Suite(description, body, isShared) + JSpec.allSuites.push(suite) + suite.name = suite.description + suite.description = this.description + ' ' + suite.description + this.suites.push(suite) + suite.suite = this + }, + + // Invoke a hook in context to this suite + + hook : function(hook) { + if (hook != 'before' && hook != 'after') + if (this.suite) this.suite.hook(hook) + + each(this.hooks[hook], function(body) { + JSpec.evalBody(body, "Error in hook '" + hook + "', suite '" + self.description + "': ") + }) + }, + + // Check if nested suites are present + + hasSuites : function() { + return this.suites.length + }, + + // Check if this suite has specs + + hasSpecs : function() { + return this.specs.length + }, + + // Check if the entire suite passed + + passed : function() { + return !any(this.specs, function(spec){ + return !spec.passed() + }) + }, + + isShared : function(){ + return this.shared + }, + + isExecutable : function() { + return !this.isShared() && this.hasSpecs() + } + }) + }, + + /** + * Specification block object. + * + * @param {string} description + * @param {function} body + * @api private + */ + + Spec : function(description, body) { + extend(this, { + body: body, + description: description, + assertions: [], + + // Add passing assertion + + pass : function(message) { + this.assertions.push({ passed: true, message: message }) + if (JSpec.assert) ++JSpec.stats.passes + }, + + // Add failing assertion + + fail : function(message) { + this.assertions.push({ passed: false, message: message }) + if (JSpec.assert) ++JSpec.stats.failures + }, + + // Run deferred assertions + + runDeferredAssertions : function() { + each(this.assertions, function(assertion){ + if (assertion.defer) assertion.run().report(), hook('afterAssertion', assertion) + }) + }, + + // Find first failing assertion + + failure : function() { + return find(this.assertions, function(assertion){ + return !assertion.passed + }) + }, + + // Find all failing assertions + + failures : function() { + return select(this.assertions, function(assertion){ + return !assertion.passed + }) + }, + + // Weither or not the spec passed + + passed : function() { + return !this.failure() + }, + + // Weither or not the spec requires implementation (no assertions) + + requiresImplementation : function() { + return this.assertions.length == 0 + }, + + // Sprite based assertions graph + + assertionsGraph : function() { + return map(this.assertions, function(assertion){ + return '' + }).join('') + } + }) + }, + + Module : function(methods) { + extend(this, methods) + }, + + JSON : { + + /** + * Generic sequences. + */ + + meta : { + '\b' : '\\b', + '\t' : '\\t', + '\n' : '\\n', + '\f' : '\\f', + '\r' : '\\r', + '"' : '\\"', + '\\' : '\\\\' + }, + + /** + * Escapable sequences. + */ + + escapable : /[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + + /** + * JSON encode _object_. + * + * @param {mixed} object + * @return {string} + * @api private + */ + + encode : function(object) { + var self = this + if (object == undefined || object == null) return 'null' + if (object === true) return 'true' + if (object === false) return 'false' + switch (typeof object) { + case 'number': return object + case 'string': return this.escapable.test(object) ? + '"' + object.replace(this.escapable, function (a) { + return typeof self.meta[a] === 'string' ? self.meta[a] : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) + }) + '"' : + '"' + object + '"' + case 'object': + if (object.constructor == Array) + return '[' + map(object, function(val){ + return self.encode(val) + }).join(', ') + ']' + else if (object) + return '{' + map(object, function(key, val){ + return self.encode(key) + ':' + self.encode(val) + }).join(', ') + '}' + } + return 'null' + } + }, + + // --- DSLs + + DSLs : { + snake : { + expect : function(actual){ + return JSpec.expect(actual) + }, + + describe : function(description, body) { + return JSpec.currentSuite.addSuite(description, body, false) + }, + + it : function(description, body) { + return JSpec.currentSuite.addSpec(description, body) + }, + + before : function(body) { + return JSpec.currentSuite.addHook('before', body) + }, + + after : function(body) { + return JSpec.currentSuite.addHook('after', body) + }, + + before_each : function(body) { + return JSpec.currentSuite.addHook('before_each', body) + }, + + after_each : function(body) { + return JSpec.currentSuite.addHook('after_each', body) + }, + + before_nested : function(body) { + return JSpec.currentSuite.addHook('before_nested', body) + }, + + after_nested : function(body){ + return JSpec.currentSuite.addhook('after_nested', body) + }, + + shared_behaviors_for : function(description, body){ + return JSpec.currentSuite.addSuite(description, body, true) + }, + + should_behave_like : function(description) { + return JSpec.shareBehaviorsOf(description) + } + } + }, + + // --- Methods + + /** + * Check if _value_ is 'stop'. For use as a + * utility callback function. + * + * @param {mixed} value + * @return {bool} + * @api public + */ + + haveStopped : function(value) { + return value === 'stop' + }, + + /** + * Include _object_ which may be a hash or Module instance. + * + * @param {hash, Module} object + * @return {JSpec} + * @api public + */ + + include : function(object) { + var module = object.constructor == JSpec.Module ? object : new JSpec.Module(object) + this.modules.push(module) + if ('init' in module) module.init() + if ('utilities' in module) extend(this.defaultContext, module.utilities) + if ('matchers' in module) this.addMatchers(module.matchers) + if ('reporters' in module) extend(this.reporters, module.reporters) + if ('DSLs' in module) + each(module.DSLs, function(name, methods){ + JSpec.DSLs[name] = JSpec.DSLs[name] || {} + extend(JSpec.DSLs[name], methods) + }) + return this + }, + + /** + * Add a module hook _name_, which is immediately + * called per module with the _args_ given. An array of + * hook return values is returned. + * + * @param {name} string + * @param {...} args + * @return {array} + * @api private + */ + + hook : function(name, args) { + args = toArray(arguments, 1) + return inject(JSpec.modules, [], function(results, module){ + if (typeof module[name] == 'function') + results.push(JSpec.evalHook(module, name, args)) + }) + }, + + /** + * Eval _module_ hook _name_ with _args_. Evaluates in context + * to the module itself, JSpec, and JSpec.context. + * + * @param {Module} module + * @param {string} name + * @param {array} args + * @return {mixed} + * @api private + */ + + evalHook : function(module, name, args) { + hook('evaluatingHookBody', module, name) + return module[name].apply(module, args) + }, + + /** + * Same as hook() however accepts only one _arg_ which is + * considered immutable. This function passes the arg + * to the first module, then passes the return value of the last + * module called, to the following module. + * + * @param {string} name + * @param {mixed} arg + * @return {mixed} + * @api private + */ + + hookImmutable : function(name, arg) { + return inject(JSpec.modules, arg, function(result, module){ + if (typeof module[name] == 'function') + return JSpec.evalHook(module, name, [result]) + }) + }, + + /** + * Find a shared example suite by its description or name. + * First searches parent tree of suites for shared behavior + * before falling back to global scoped nested behaviors. + * + * @param {string} description + * @return {Suite} + * @api private + */ + + findSharedBehavior : function(description) { + var behavior + return (behavior = JSpec.findLocalSharedBehavior(description)) + ? behavior + : JSpec.findGlobalSharedBehavior(description) + }, + + /** + * Find a shared example suite within the current suite's + * parent tree by its description or name. + * + * @param {string} description + * @return {Suite} + * @api private + */ + + findLocalSharedBehavior : function(description) { + var behavior, + currentSuite = JSpec.currentSuite.suite + while (currentSuite) + if (behavior = find(currentSuite.suites, JSpec.suiteDescriptionPredicate(description))) + return behavior + else + currentSuite = currentSuite.suite + }, + + /** + * Find a shared example suite within the global + * scope by its description or name. + * + * @param {string} description + * @return {Suite} + * @api private + */ + + findGlobalSharedBehavior : function(description) { + return find(JSpec.suites, JSpec.suiteDescriptionPredicate(description)) + }, + + /** + * Build a predicate that will match a suite based on name or description + * + * @param {string} description + * @return {function} + * @api private + */ + + suiteDescriptionPredicate : function(description) { + return function(suite){ + return suite.name === description || + suite.description === description + } + }, + + /** + * Share behaviors (specs) of the given suite with + * the current suite. + * + * @param {string} description + * @api public + */ + + shareBehaviorsOf : function(description) { + var suite = JSpec.findSharedBehavior(description) + if (suite) + JSpec.evalBody(suite.body) + else + throw new Error("failed to find shared behaviors named `" + description + "'") + }, + + + /** + * Convert arguments to an array. + * + * @param {object} arguments + * @param {int} offset + * @return {array} + * @api public + */ + + toArray : function(arguments, offset) { + return Array.prototype.slice.call(arguments, offset || 0) + }, + + /** + * Return ANSI-escaped colored string. + * + * @param {string} string + * @param {string} color + * @return {string} + * @api public + */ + + color : function(string, color) { + if (option('disableColors')) { + return string + } else { + return "\u001B[" + { + bold : 1, + black : 30, + red : 31, + green : 32, + yellow : 33, + blue : 34, + magenta : 35, + cyan : 36, + white : 37 + }[color] + 'm' + string + "\u001B[0m" + } + }, + + /** + * Default matcher message callback. + * + * @api private + */ + + defaultMatcherMessage : function(actual, expected, negate, name) { + return 'expected ' + puts(actual) + ' to ' + + (negate ? 'not ' : '') + + name.replace(/_/g, ' ') + + ' ' + (expected.length > 1 ? + puts.apply(this, expected.slice(1)) : + '') + }, + + /** + * Normalize a matcher message. + * + * When no messge callback is present the defaultMatcherMessage + * will be assigned, will suffice for most matchers. + * + * @param {hash} matcher + * @return {hash} + * @api public + */ + + normalizeMatcherMessage : function(matcher) { + if (typeof matcher.message != 'function') + matcher.message = this.defaultMatcherMessage + return matcher + }, + + /** + * Normalize a matcher body + * + * This process allows the following conversions until + * the matcher is in its final normalized hash state. + * + * - '==' becomes 'actual == expected' + * - 'actual == expected' becomes 'return actual == expected' + * - function(actual, expected) { return actual == expected } becomes + * { match : function(actual, expected) { return actual == expected }} + * + * @param {mixed} body + * @return {hash} + * @api public + */ + + normalizeMatcherBody : function(body) { + var captures + switch (body.constructor) { + case String: + if (captures = body.match(/^alias (\w+)/)) return JSpec.matchers[last(captures)] + if (body.length < 4) body = 'actual ' + body + ' expected' + return { match: function(actual, expected) { return eval(body) }} + + case Function: + return { match: body } + + default: + return body + } + }, + + /** + * Get option value. This method first checks if + * the option key has been set via the query string, + * otherwise returning the options hash value. + * + * @param {string} key + * @return {mixed} + * @api public + */ + + option : function(key) { + return (value = query(key)) !== null ? value : + JSpec.options[key] || null + }, + + /** + * Check if object _a_, is equal to object _b_. + * + * @param {object} a + * @param {object} b + * @return {bool} + * @api private + */ + + equal: function(a, b) { + if (typeof a != typeof b) return + if (a === b) return true + if (a instanceof RegExp) + return a.toString() === b.toString() + if (a instanceof Date) + return Number(a) === Number(b) + if (typeof a != 'object') return + if (a.length !== undefined) + if (a.length !== b.length) return + else + for (var i = 0, len = a.length; i < len; ++i) + if (!equal(a[i], b[i])) + return + for (var key in a) + if (!equal(a[key], b[key])) + return + return true + }, + + /** + * Return last element of an array. + * + * @param {array} array + * @return {object} + * @api public + */ + + last : function(array) { + return array[array.length - 1] + }, + + /** + * Convert object(s) to a print-friend string. + * + * @param {...} object + * @return {string} + * @api public + */ + + puts : function(object) { + if (arguments.length > 1) + return map(toArray(arguments), function(arg){ + return puts(arg) + }).join(', ') + if (object === undefined) return 'undefined' + if (object === null) return 'null' + if (object === true) return 'true' + if (object === false) return 'false' + if (object.an_instance_of) return 'an instance of ' + object.an_instance_of.name + if (object.jquery && object.selector.length > 0) return 'selector ' + puts(object.selector) + if (object.jquery) return object.get(0).outerHTML + if (object.nodeName) return object.outerHTML + switch (object.constructor) { + case Function: return object.name || object + case String: + return '"' + object + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + '"' + case Array: + return inject(object, '[', function(b, v){ + return b + ', ' + puts(v) + }).replace('[,', '[') + ' ]' + case Object: + object.__hit__ = true + return inject(object, '{', function(b, k, v) { + if (k == '__hit__') return b + return b + ', ' + k + ': ' + (v && v.__hit__ ? '' : puts(v)) + }).replace('{,', '{') + ' }' + default: + return object.toString() + } + }, + + /** + * Parse an XML String and return a 'document'. + * + * @param {string} text + * @return {document} + * @api public + */ + + parseXML : function(text) { + var xmlDoc + if (window.DOMParser) + xmlDoc = (new DOMParser()).parseFromString(text, "text/xml") + else { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM") + xmlDoc.async = "false" + xmlDoc.loadXML(text) + } + return xmlDoc + }, + + /** + * Escape HTML. + * + * @param {string} html + * @return {string} + * @api public + */ + + escape : function(html) { + return html.toString() + .replace(/&/gmi, '&') + .replace(/"/gmi, '"') + .replace(/>/gmi, '>') + .replace(/ current) while (++current <= end) values.push(current) + else while (--current >= end) values.push(current) + return '[' + values + ']' + }, + + /** + * Report on the results. + * + * @api public + */ + + report : function() { + this.duration = Number(new Date) - this.start + hook('reporting', JSpec.options) + new (JSpec.options.reporter || JSpec.reporters.DOM)(JSpec, JSpec.options) + }, + + /** + * Run the spec suites. Options are merged + * with JSpec options when present. + * + * @param {hash} options + * @return {JSpec} + * @api public + */ + + run : function(options) { + if (any(hook('running'), haveStopped)) return this + if (options) extend(this.options, options) + this.start = Number(new Date) + each(this.suites, function(suite) { JSpec.runSuite(suite) }) + return this + }, + + /** + * Run a suite. + * + * @param {Suite} suite + * @api public + */ + + runSuite : function(suite) { + if (!suite.isShared()) + { + this.currentSuite = suite + this.evalBody(suite.body) + suite.ran = true + hook('beforeSuite', suite), suite.hook('before'), suite.hook('before_nested') + each(suite.specs, function(spec) { + hook('beforeSpec', spec) + suite.hook('before_each') + JSpec.runSpec(spec) + hook('afterSpec', spec) + suite.hook('after_each') + }) + if (suite.hasSuites()) { + each(suite.suites, function(suite) { + JSpec.runSuite(suite) + }) + } + hook('afterSuite', suite), suite.hook('after_nested'), suite.hook('after') + this.stats.suitesFinished++ + } + }, + + /** + * Report a failure for the current spec. + * + * @param {string} message + * @api public + */ + + fail : function(message) { + JSpec.currentSpec.fail(message) + }, + + /** + * Report a passing assertion for the current spec. + * + * @param {string} message + * @api public + */ + + pass : function(message) { + JSpec.currentSpec.pass(message) + }, + + /** + * Run a spec. + * + * @param {Spec} spec + * @api public + */ + + runSpec : function(spec) { + this.currentSpec = spec + try { this.evalBody(spec.body) } + catch (e) { fail(e) } + spec.runDeferredAssertions() + destub() + this.stats.specsFinished++ + this.stats.assertions += spec.assertions.length + }, + + /** + * Require a dependency, with optional message. + * + * @param {string} dependency + * @param {string} message (optional) + * @return {JSpec} + * @api public + */ + + requires : function(dependency, message) { + hook('requiring', dependency, message) + try { eval(dependency) } + catch (e) { throw 'JSpec depends on ' + dependency + ' ' + message } + return this + }, + + /** + * Query against the current query strings keys + * or the queryString specified. + * + * @param {string} key + * @param {string} queryString + * @return {string, null} + * @api private + */ + + query : function(key, queryString) { + var queryString = (queryString || (main.location ? main.location.search : null) || '').substring(1) + return inject(queryString.split('&'), null, function(value, pair){ + parts = pair.split('=') + return parts[0] == key ? parts[1].replace(/%20|\+/gmi, ' ') : value + }) + }, + + /** + * Ad-hoc POST request for JSpec server usage. + * + * @param {string} uri + * @param {string} data + * @api private + */ + + post : function(uri, data) { + if (any(hook('posting', uri, data), haveStopped)) return + var request = this.xhr() + request.open('POST', uri, false) + request.setRequestHeader('Content-Type', 'application/json') + request.send(JSpec.JSON.encode(data)) + }, + + /** + * Instantiate an XMLHttpRequest. + * + * Here we utilize IE's lame ActiveXObjects first which + * allow IE access serve files via the file: protocol, otherwise + * we then default to XMLHttpRequest. + * + * @return {XMLHttpRequest, ActiveXObject} + * @api private + */ + + xhr : function() { + return this.ieXhr() || new JSpec.request + }, + + /** + * Return Microsoft piece of crap ActiveXObject. + * + * @return {ActiveXObject} + * @api public + */ + + ieXhr : function() { + function object(str) { + try { return new ActiveXObject(str) } catch(e) {} + } + return object('Msxml2.XMLHTTP.6.0') || + object('Msxml2.XMLHTTP.3.0') || + object('Msxml2.XMLHTTP') || + object('Microsoft.XMLHTTP') + }, + + /** + * Check for HTTP request support. + * + * @return {bool} + * @api private + */ + + hasXhr : function() { + return JSpec.request || 'ActiveXObject' in main + }, + + /** + * Try loading _file_ returning the contents + * string or null. Chain to locate / read a file. + * + * @param {string} file + * @return {string} + * @api public + */ + + tryLoading : function(file) { + try { return JSpec.load(file) } catch (e) {} + }, + + /** + * Load a _file_'s contents. + * + * @param {string} file + * @param {function} callback + * @return {string} + * @api public + */ + + load : function(file, callback) { + if (any(hook('loading', file), haveStopped)) return + if ('readFile' in main) + return readFile(file) + else if (this.hasXhr()) { + var request = this.xhr() + request.open('GET', file, false) + request.send(null) + if (request.readyState == 4 && + (request.status == 0 || + request.status.toString().charAt(0) == 2)) + return request.responseText + } + else + throw new Error("failed to load `" + file + "'") + }, + + /** + * Load, pre-process, and evaluate a file. + * + * @param {string} file + * @param {JSpec} + * @api public + */ + + exec : function(file) { + if (any(hook('executing', file), haveStopped)) return this + eval('with (JSpec){' + this.preprocess(this.load(file)) + '}') + return this + } + } + + // --- Node.js support + + if (typeof GLOBAL === 'object' && typeof exports === 'object') + quit = process.exit, + print = require('sys').puts, + readFile = require('fs').readFileSync + + // --- Utility functions + + var main = this, + find = JSpec.any, + utils = 'haveStopped stub hookImmutable hook destub map any last pass fail range each option inject select \ + error escape extend puts query strip color does addMatchers callIterator toArray equal'.split(/\s+/) + while (utils.length) eval('var ' + utils[0] + ' = JSpec.' + utils.shift()) + if (!main.setTimeout) main.setTimeout = function(callback){ callback() } + + // --- Matchers + + addMatchers({ + equal : "===", + eql : "equal(actual, expected)", + be : "alias equal", + be_greater_than : ">", + be_less_than : "<", + be_at_least : ">=", + be_at_most : "<=", + be_a : "actual.constructor == expected", + be_an : "alias be_a", + be_an_instance_of : "actual instanceof expected", + be_null : "actual == null", + be_true : "actual == true", + be_false : "actual == false", + be_undefined : "typeof actual == 'undefined'", + be_type : "typeof actual == expected", + match : "typeof actual == 'string' ? actual.match(expected) : false", + respond_to : "typeof actual[expected] == 'function'", + have_length : "actual.length == expected", + be_within : "actual >= expected[0] && actual <= last(expected)", + have_length_within : "actual.length >= expected[0] && actual.length <= last(expected)", + + receive : { defer : true, match : function(actual, method, times) { + var proxy = new JSpec.ProxyAssertion(actual, method, times, this.negate) + JSpec.currentSpec.assertions.push(proxy) + return proxy + }}, + + be_empty : function(actual) { + if (actual.constructor == Object && actual.length == undefined) + for (var key in actual) + return false; + return !actual.length + }, + + include : function(actual) { + for (var state = true, i = 1; i < arguments.length; i++) { + var arg = arguments[i] + switch (actual.constructor) { + case String: + case Number: + case RegExp: + case Function: + state = actual.toString().indexOf(arg) !== -1 + break + + case Object: + state = arg in actual + break + + case Array: + state = any(actual, function(value){ return equal(value, arg) }) + break + } + if (!state) return false + } + return true + }, + + throw_error : { match : function(actual, expected, message) { + try { actual() } + catch (e) { + this.e = e + var assert = function(arg) { + switch (arg.constructor) { + case RegExp : return arg.test(e.message || e.toString()) + case String : return arg == (e.message || e.toString()) + case Function : return e instanceof arg || e.name == arg.name + } + } + return message ? assert(expected) && assert(message) : + expected ? assert(expected) : + true + } + }, message : function(actual, expected, negate) { + // TODO: refactor when actual is not in expected [0] + var message_for = function(i) { + if (expected[i] == undefined) return 'exception' + switch (expected[i].constructor) { + case RegExp : return 'exception matching ' + puts(expected[i]) + case String : return 'exception of ' + puts(expected[i]) + case Function : return expected[i].name || 'Error' + } + } + var exception = message_for(1) + (expected[2] ? ' and ' + message_for(2) : '') + return 'expected ' + exception + (negate ? ' not ' : '' ) + + ' to be thrown, but ' + (this.e ? 'got ' + puts(this.e) : 'nothing was') + }}, + + have : function(actual, length, property) { + return actual[property] == null ? false : actual[property].length == length + }, + + have_at_least : function(actual, length, property) { + return actual[property] == null ? (length === 0) : actual[property].length >= length + }, + + have_at_most :function(actual, length, property) { + return actual[property] == null || actual[property].length <= length + }, + + have_within : function(actual, range, property) { + var length = actual[property] == undefined ? 0 : actual[property].length + return length >= range.shift() && length <= range.pop() + }, + + have_prop : function(actual, property, value) { + return actual[property] === undefined || + actual[property] instanceof Function ? false: + value === undefined ? true: + does(actual[property], 'eql', value) + }, + + have_property : function(actual, property, value) { + return actual[property] === undefined || + actual[property] instanceof Function ? false: + value === undefined ? true: + value === actual[property] + } + }) + +})() diff --git a/spec/lib/jspec.nodejs.js b/spec/lib/jspec.nodejs.js new file mode 100644 index 0000000..6765273 --- /dev/null +++ b/spec/lib/jspec.nodejs.js @@ -0,0 +1,18 @@ + +// JSpec - node - Copyright TJ Holowaychuk (MIT Licensed) + +JSpec +.include({ + name: 'node', + + // --- Matchers + + matchers : { + have_enumerable_property: 'actual.propertyIsEnumerable(expected)', + have_writable_property: 'Object.getOwnPropertyDescriptor(actual, expected).writable === true', + have_configurable_property: 'Object.getOwnPropertyDescriptor(actual, expected).configurable === true', + have_keys: 'does(Object.keys(actual), "eql", expected)', + have_prototype: 'Object.getPrototypeOf(actual) === expected' + } +}) + diff --git a/spec/lib/jspec.shell.js b/spec/lib/jspec.shell.js new file mode 100644 index 0000000..cb19c69 --- /dev/null +++ b/spec/lib/jspec.shell.js @@ -0,0 +1,39 @@ + +// JSpec - Shell - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + var _quit = quit + + Shell = { + + // --- Global + + main: this, + + // --- Commands + + commands: { + quit: ['Terminate the shell', function(){ _quit() }], + exit: ['Terminate the shell', function(){ _quit() }], + p: ['Inspect an object', function(o){ return o.toSource() }] + }, + + /** + * Start the interactive shell. + * + * @api public + */ + + start : function() { + for (var name in this.commands) + if (this.commands.hasOwnProperty(name)) + this.commands[name][1].length ? + this.main[name] = this.commands[name][1] : + this.main.__defineGetter__(name, this.commands[name][1]) + } + } + + Shell.start() + +})() \ No newline at end of file diff --git a/spec/lib/jspec.timers.js b/spec/lib/jspec.timers.js new file mode 100644 index 0000000..c88d10b --- /dev/null +++ b/spec/lib/jspec.timers.js @@ -0,0 +1,90 @@ + +// JSpec - Mock Timers - Copyright TJ Holowaychuk (MIT Licensed) + +;(function(){ + + /** + * Version. + */ + + mockTimersVersion = '1.0.2' + + /** + * Localized timer stack. + */ + + var timers = [] + + /** + * Set mock timeout with _callback_ and timeout of _ms_. + * + * @param {function} callback + * @param {int} ms + * @return {int} + * @api public + */ + + setTimeout = function(callback, ms) { + var id + return id = setInterval(function(){ + callback() + clearInterval(id) + }, ms) + } + + /** + * Set mock interval with _callback_ and interval of _ms_. + * + * @param {function} callback + * @param {int} ms + * @return {int} + * @api public + */ + + setInterval = function(callback, ms) { + callback.step = ms, callback.current = callback.last = 0 + return timers[timers.length] = callback, timers.length + } + + /** + * Destroy timer with _id_. + * + * @param {int} id + * @return {bool} + * @api public + */ + + clearInterval = clearTimeout = function(id) { + return delete timers[--id] + } + + /** + * Reset timers. + * + * @return {array} + * @api public + */ + + resetTimers = function() { + return timers = [] + } + + /** + * Increment each timers internal clock by _ms_. + * + * @param {int} ms + * @api public + */ + + tick = function(ms) { + for (var i = 0, len = timers.length; i < len; ++i) + if (timers[i] && (timers[i].current += ms)) + if (timers[i].current - timers[i].last >= timers[i].step) { + var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step) + var remainder = (timers[i].current - timers[i].last) % timers[i].step + timers[i].last = timers[i].current - remainder + while (times-- && timers[i]) timers[i]() + } + } + +})() \ No newline at end of file diff --git a/spec/lib/jspec.xhr.js b/spec/lib/jspec.xhr.js new file mode 100644 index 0000000..482a3c4 --- /dev/null +++ b/spec/lib/jspec.xhr.js @@ -0,0 +1,208 @@ + +// JSpec - XHR - Copyright TJ Holowaychuk (MIT Licensed) + +(function(){ + + var lastRequest + + // --- Original XMLHttpRequest + + var OriginalXMLHttpRequest = 'XMLHttpRequest' in this ? + XMLHttpRequest : + function(){} + var OriginalActiveXObject = 'ActiveXObject' in this ? + ActiveXObject : + undefined + + // --- MockXMLHttpRequest + + var MockXMLHttpRequest = function() { + this.requestHeaders = {} + } + + MockXMLHttpRequest.prototype = { + status: 0, + async: true, + readyState: 0, + responseXML: null, + responseText: '', + abort: function(){}, + onreadystatechange: function(){}, + + /** + * Return response headers hash. + */ + + getAllResponseHeaders : function(){ + return this.responseHeaders + }, + + /** + * Return case-insensitive value for header _name_. + */ + + getResponseHeader : function(name) { + return this.responseHeaders[name.toLowerCase()] + }, + + /** + * Set case-insensitive _value_ for header _name_. + */ + + setRequestHeader : function(name, value) { + this.requestHeaders[name.toLowerCase()] = value + }, + + /** + * Open mock request. + */ + + open : function(method, url, async, user, password) { + this.user = user + this.password = password + this.url = url + this.readyState = 1 + this.method = method.toUpperCase() + if (async != undefined) this.async = async + if (this.async) this.onreadystatechange() + }, + + /** + * Send request _data_. + */ + + send : function(data) { + var self = this + this.data = data + this.readyState = 4 + if (this.method == 'HEAD') this.responseText = null + this.responseHeaders['content-length'] = (this.responseText || '').length + if(this.async) this.onreadystatechange() + this.populateResponseXML() + lastRequest = function(){ + return self + } + }, + + /** + * Parse request body and populate responseXML if response-type is xml + * Based on the standard specification : http://www.w3.org/TR/XMLHttpRequest/ + */ + populateResponseXML: function() { + var type = this.getResponseHeader("content-type") + if (!type || !this.responseText || !type.match(/(text\/xml|application\/xml|\+xml$)/g)) + return + this.responseXML = JSpec.parseXML(this.responseText) + } + } + + // --- Response status codes + + JSpec.statusCodes = { + 100: 'Continue', + 101: 'Switching Protocols', + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non-Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 300: 'Multiple Choice', + 301: 'Moved Permanently', + 302: 'Found', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 307: 'Temporary Redirect', + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Request Entity Too Large', + 414: 'Request-URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Requested Range Not Satisfiable', + 417: 'Expectation Failed', + 422: 'Unprocessable Entity', + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported' + } + + /** + * Mock XMLHttpRequest requests. + * + * mockRequest().and_return('some data', 'text/plain', 200, { 'X-SomeHeader' : 'somevalue' }) + * + * @return {hash} + * @api public + */ + + function mockRequest() { + return { and_return : function(body, type, status, headers) { + XMLHttpRequest = MockXMLHttpRequest + ActiveXObject = false + status = status || 200 + headers = headers || {} + headers['content-type'] = type + JSpec.extend(XMLHttpRequest.prototype, { + responseText: body, + responseHeaders: headers, + status: status, + statusText: JSpec.statusCodes[status] + }) + }} + } + + /** + * Unmock XMLHttpRequest requests. + * + * @api public + */ + + function unmockRequest() { + XMLHttpRequest = OriginalXMLHttpRequest + ActiveXObject = OriginalActiveXObject + } + + JSpec.include({ + name: 'Mock XHR', + + // --- Utilities + + utilities : { + mockRequest: mockRequest, + unmockRequest: unmockRequest + }, + + // --- Hooks + + afterSpec : function() { + unmockRequest() + }, + + // --- DSLs + + DSLs : { + snake : { + mock_request: mockRequest, + unmock_request: unmockRequest, + last_request: function(){ return lastRequest() } + } + } + + }) +})() diff --git a/spec/node.js b/spec/node.js index beef020..bb7d352 100644 --- a/spec/node.js +++ b/spec/node.js @@ -1,5 +1,4 @@ - -require.paths.unshift('spec', '/opt/local/lib/ruby/gems/1.8/gems/jspec-4.2.1/lib', 'lib') +require.paths.unshift('spec', './spec/lib', 'lib') require.paths.unshift(__dirname + '/../lib'); require.paths.unshift(__dirname + '/..'); From ce16fb79c3cfa0e8eb7c37f9e5bfa4b94af85711 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 26 Apr 2010 00:36:41 -0400 Subject: [PATCH 064/267] Fix broken spec --- lib/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/view.js b/lib/view.js index c5c7e34..715cb68 100644 --- a/lib/view.js +++ b/lib/view.js @@ -22,7 +22,7 @@ View.prototype = { }, productId: function() { - return this._productId; + return parseInt(this._productId); }, event: function() { From 13f23af764ae0d13cbb01b43a9c7f7ab9479496a Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Mon, 26 Apr 2010 23:00:53 +0000 Subject: [PATCH 065/267] Adding an aggregates page. Kind of really ugly right now, but just trying to get the functionality right --- lib/aggregates.js | 87 +++++++++++++++++++++++++++++++++++++++++ lib/hummingbird.js | 16 ++++++++ public/aggregates.html | 55 ++++++++++++++++++++++++++ public/js/aggregates.js | 51 ++++++++++++++++++++++++ server.js | 8 +++- 5 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 lib/aggregates.js create mode 100644 public/aggregates.html create mode 100644 public/js/aggregates.js diff --git a/lib/aggregates.js b/lib/aggregates.js new file mode 100644 index 0000000..00eaab1 --- /dev/null +++ b/lib/aggregates.js @@ -0,0 +1,87 @@ +var sys = require('sys'); + +var TimeBucketers; +if (!TimeBucketers) { TimeBucketers = {} }; + +TimeBucketers.closestSecondFor = function(floatApprox) { + // Truncate + return parseInt(floatApprox / 1000) * 1000; +} + +TimeBucketers.closestMinuteFor = function(floatApprox) { + return parseInt(floatApprox / 100000) * 100000; +}; + +TimeBucketers.closestHourFor = function(floatApprox) { + // This function seems really inefficient + var date = new Date(parseInt(floatApprox / 100000) * 100000); + var minutes = date.getMinutes(); + var minutesInMilliseconds = minutes * 60 * 1000; + return (date - minutesInMilliseconds); +}; + +TimeBucketers.closestDayFor = function(floatApprox) { + // Ditto + var date = new Date(parseInt(floatApprox / 100000) * 100000); + var minutes = date.getMinutes(); + var hours = date.getHours(); + var minutesInMilliseconds = minutes * 60 * 1000; + var hoursInMilliseconds = hours * 60 * 60 * 1000; + return (date - hoursInMilliseconds - minutesInMilliseconds); +} + +Aggregates = function(collection) { + if ( !(this instanceof Aggregates) ) { + return new Aggregates(collection); + } + this.collection = collection; +} + +Aggregates.prototype = { + mapper: function() { + var timestamp = this.timestamp.floatApprox; + // var timeBucket = timeBucketer(timestamp); + var timeBucket = parseInt(timestamp / 100000) * 100000; + emit(timeBucket, 1); + }, + + reducer: function(key, values) { + var total = 0; + for (var count = 0; count < values.length; ++count) { + total += values[count]; + } + return { count: total }; + }, + + lastHour: function(dataCallback) { + var result = this.collection.mapReduce(this.mapper, this.reducer, { scope: { timeBucketer: TimeBucketers.closestMinuteFor } }, function(err, mrCollection) { + var metrics = []; + mrCollection.find(function(err, cursor) { + cursor.toArray(function(err, items) { + var visitsByMinute = {}; + + for (var i = 0; i < items.length; ++i) { + visitsByMinute[items[i]._id] = items[i].value.count; + } + + var visits = []; + var now = new Date(); + var oneHourAgo = now - (60 * 60 * 1000); + + for (var i = 0; i < 60; ++i) { + var minuteTimestamp = oneHourAgo + (i * 60 * 1000); + var value = 0; + if (visitsByMinute[minuteTimestamp]) { + value = visitsByMinute[minuteTimestamp]; + } + visits.push(value); + } + + dataCallback(visits); + }); + }); + }); + } +}; + +exports.Aggregates = Aggregates; diff --git a/lib/hummingbird.js b/lib/hummingbird.js index d58726d..b069362 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -2,6 +2,7 @@ var sys = require('sys'), fs = require('fs'), View = require('view').View, Metric = require('metric').Metric, + Aggregates = require('aggregates').Aggregates, path = require('path'), arrays = require('deps/arrays'), querystring = require('querystring'); @@ -92,6 +93,21 @@ Hummingbird.prototype = { res.close(); }, + serveAggregates: function(client) { + var aggregates = new Aggregates(this.collection); + aggregates.lastHour(function(values) { + client.write(JSON.stringify({ metric: 'lastHour', values: values })); + }); + /* + aggregates.lastDay(client, function(values) { + client.write({ metric: 'lastDay', values: values }); + }); + aggregates.lastWeek(client, function(values) { + client.write({ metric: 'lastWeek', values: values }); + }); + */ + }, + handleError: function(req, res, e) { res.writeHead(500, {}); res.write("Server error"); diff --git a/public/aggregates.html b/public/aggregates.html new file mode 100644 index 0000000..1e23149 --- /dev/null +++ b/public/aggregates.html @@ -0,0 +1,55 @@ + + + + + + + + + + + Hummingbird + + + + + +

Hummingbird

+ +
+ +

Pageviews in the last hour

+ +
+ +
+ +
+ +
+ +
+ +

Pageviews in the last day

+ +
+ +
+ +
+ +
+ +
+ +

Pageviews in the last week

+ +
+ +
+ +
+ + + diff --git a/public/js/aggregates.js b/public/js/aggregates.js new file mode 100644 index 0000000..e894d2d --- /dev/null +++ b/public/js/aggregates.js @@ -0,0 +1,51 @@ +if(!Hummingbird) { var Hummingbird = {}; } + +Hummingbird.Aggregates = {}; +Hummingbird.Aggregates.state = "stopped"; +Hummingbird.Aggregates.start = function() { + if(!("WebSocket" in window)) { + console.log("Sorry, the build of your browser does not support WebSockets. Please use latest Chrome or Webkit nightly"); + return; + } + + var lastHourDiv = $("#pageviews_last_hour"); + lastHourDiv.find('canvas').get(0).width = $(window).width() - 160; + var lastHourGraph = new Hummingbird.Graph(lastHourDiv, { ratePerSecond: 20, logDate: true }); + + var wsServer = "ws://" + document.location.hostname + ":8080/aggregates"; + var ws = new WebSocket(wsServer); + + ws.onmessage = function(evt) { + var data = JSON.parse(evt.data); + + if (typeof(data.metric) != "undefined") { + var values = data.values; + $.each(values, function(idx, visit) { + lastHourGraph.drawLogPath(visit); + lastHourGraph.drawLogPath(visit); + lastHourGraph.drawLogPath(visit); + }); + } + } + ws.onclose = function() { + if(Hummingbird.Aggregates.state == "retrying") { + // Wait a while to try restarting + console.log("still no socket, retrying in 3 seconds"); + setTimeout(Hummingbird.Aggregates.start, 3000); + } else { + // First attempt at restarting, try immediately + Hummingbird.Aggregates.state = "retrying"; + console.log("socket lost, retrying immediately"); + setTimeout(Hummingbird.Aggregates.start, 200); + } + }; + ws.onopen = function() { + Hummingbird.Aggregates.state = "started"; + console.log("socket started"); + }; + Hummingbird.Aggregates.ws = ws; +}; + +$(document).ready(function(){ + Hummingbird.Aggregates.start(); +}); diff --git a/server.js b/server.js index 7c5a225..e28bcb4 100644 --- a/server.js +++ b/server.js @@ -28,11 +28,15 @@ db.open(function(p_db) { // Websocket TCP server ws.createServer(function (websocket) { - hummingbird.addClient(websocket); - websocket.addListener("connect", function (resource) { // emitted after handshake sys.log("ws connect: " + resource); + if (resource === '/') { + hummingbird.addClient(websocket); + } + else if (resource === '/aggregates') { + hummingbird.serveAggregates(websocket); + } }).addListener("close", function () { // emitted when server or client closes connection hummingbird.removeClient(websocket); From 3997051807dd0e1a9f6c32c390af8229f2d49907 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Tue, 27 Apr 2010 04:56:41 +0000 Subject: [PATCH 066/267] Make sure we push limits on the MR set --- lib/aggregates.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/aggregates.js b/lib/aggregates.js index 00eaab1..7198fae 100644 --- a/lib/aggregates.js +++ b/lib/aggregates.js @@ -54,9 +54,12 @@ Aggregates.prototype = { }, lastHour: function(dataCallback) { - var result = this.collection.mapReduce(this.mapper, this.reducer, { scope: { timeBucketer: TimeBucketers.closestMinuteFor } }, function(err, mrCollection) { + var now = new Date(); + var oneHourAgo = now - (60 * 60 * 1000); + var result = this.collection.mapReduce(this.mapper, this.reducer, { query: { 'timestamp': { '$gte': oneHourAgo } }, scope: { timeBucketer: TimeBucketers.closestMinuteFor } }, function(err, mrCollection) { var metrics = []; - mrCollection.find(function(err, cursor) { + + mrCollection.find({ 'timestamp': { '$gte': oneHourAgo } }, function(err, cursor) { cursor.toArray(function(err, items) { var visitsByMinute = {}; @@ -65,9 +68,6 @@ Aggregates.prototype = { } var visits = []; - var now = new Date(); - var oneHourAgo = now - (60 * 60 * 1000); - for (var i = 0; i < 60; ++i) { var minuteTimestamp = oneHourAgo + (i * 60 * 1000); var value = 0; From 9987c8c166a24b561143a977b1de1a2fe6b91128 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 27 Apr 2010 11:31:17 -0400 Subject: [PATCH 067/267] Show 1-second axis marks on the graph; when changing scale, don't show the bar for that line to keep things even --- public/js/analytics.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/public/js/analytics.js b/public/js/analytics.js index df675f3..d3ada87 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -10,6 +10,8 @@ Hummingbird.Graph = function(el, options) { showMarkers: true, ratePerSecond: 10, showBackgroundBars: true, + tickLineColor: '#666', + bgLineColor: '#555', barColor: null } @@ -41,7 +43,6 @@ Hummingbird.Graph.prototype = { 3.125: "#006456", def: "#7BF4D6" }; - this.bgLineColor = "#555"; this.canvasHeight = $(this.canvas).height(); this.canvasWidth = $(this.canvas).width(); @@ -173,6 +174,17 @@ Hummingbird.Graph.prototype = { var color = this.options.barColor || this.lineColors[this.scale] || this.lineColors.def; var endingPoint = this.canvasHeight - height; + if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds + this.valueElement.text(average); + this.el.attr('data-average', average); + + this.rescale(percent); + + if(this.tick % 1000 == 0) { this.tick = 0; } + + return; + } + this.shiftCanvas(this.lineWidth * 2, 0); this.context.lineWidth = this.lineWidth; this.context.beginPath(); @@ -184,20 +196,17 @@ Hummingbird.Graph.prototype = { if(this.options.showBackgroundBars) { this.context.beginPath(); - this.context.strokeStyle = this.bgLineColor; + + if(this.tick % this.options.ratePerSecond == 0) { + this.context.strokeStyle = this.options.tickLineColor; + } else { + this.context.strokeStyle = this.options.bgLineColor; + } + this.context.moveTo(this.canvasWidth - 10, endingPoint); this.context.lineTo(this.canvasWidth - 10, 0); this.context.stroke(); this.context.closePath(); } - - if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds - this.valueElement.text(average); - this.el.attr('data-average', average); - - this.rescale(percent); - - if(this.tick % 1000 == 0) { this.tick = 0; } - } } }; From 1d038e493c813d41459ecbbeb3f5e64ed406562c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 27 Apr 2010 11:51:28 -0400 Subject: [PATCH 068/267] Show upcoming sales as well as active sales --- public/js/sales.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/sales.js b/public/js/sales.js index 75eb175..ff941b2 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -4,6 +4,7 @@ Hummingbird.saleGraphs = {}; Hummingbird.getSales = function() { $.getJSON("/sale_list", function(data) { + data.data.active_sales.concat(data.data.upcoming_sales); $.each(data.data.active_sales, function() { var editorialImage = "http://www.gilt.com" + this.sale_editorial_image; var name = this.name; From 29e65b10e634281a938ef930283ffe96526c3f5c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 27 Apr 2010 23:09:38 -0400 Subject: [PATCH 069/267] Only parseInt once --- lib/view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/view.js b/lib/view.js index 715cb68..50f15c5 100644 --- a/lib/view.js +++ b/lib/view.js @@ -11,7 +11,7 @@ var View = function(env) { var match = View.urlKeyRegexp.exec(this.env.u); if(match && match.length > 2) { this._urlKey = match[2]; - this._productId = match[4]; + this._productId = parseInt(match[4]); } } } @@ -22,7 +22,7 @@ View.prototype = { }, productId: function() { - return parseInt(this._productId); + return this._productId; }, event: function() { From 841080c8cf327e6862ec88da7fbcbc31495b8a04 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 28 Apr 2010 02:21:33 -0400 Subject: [PATCH 070/267] Easier way to compute beginning-of-day --- lib/aggregates.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/aggregates.js b/lib/aggregates.js index 7198fae..e6a1cf5 100644 --- a/lib/aggregates.js +++ b/lib/aggregates.js @@ -4,30 +4,31 @@ var TimeBucketers; if (!TimeBucketers) { TimeBucketers = {} }; TimeBucketers.closestSecondFor = function(floatApprox) { - // Truncate return parseInt(floatApprox / 1000) * 1000; } TimeBucketers.closestMinuteFor = function(floatApprox) { - return parseInt(floatApprox / 100000) * 100000; + var date = new Date(timestamp); + date.setSeconds(0); + date.setMilliseconds(0); + return date.getTime(); }; TimeBucketers.closestHourFor = function(floatApprox) { - // This function seems really inefficient - var date = new Date(parseInt(floatApprox / 100000) * 100000); - var minutes = date.getMinutes(); - var minutesInMilliseconds = minutes * 60 * 1000; - return (date - minutesInMilliseconds); + var date = new Date(timestamp); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + return date.getTime(); }; -TimeBucketers.closestDayFor = function(floatApprox) { - // Ditto - var date = new Date(parseInt(floatApprox / 100000) * 100000); - var minutes = date.getMinutes(); - var hours = date.getHours(); - var minutesInMilliseconds = minutes * 60 * 1000; - var hoursInMilliseconds = hours * 60 * 60 * 1000; - return (date - hoursInMilliseconds - minutesInMilliseconds); +TimeBucketers.closestDayFor = function(timestamp) { + var date = new Date(timestamp); + date.setMinutes(0); + date.setHours(0); + date.setSeconds(0); + date.setMilliseconds(0); + return date.getTime(); } Aggregates = function(collection) { @@ -85,3 +86,4 @@ Aggregates.prototype = { }; exports.Aggregates = Aggregates; +exports.TimeBucketers = TimeBucketers; \ No newline at end of file From 6278309cc6bd54514ff34d5605064278d1b12502 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 28 Apr 2010 15:57:55 -0400 Subject: [PATCH 071/267] Add metrics to mongo by minute instead of by metric interval --- lib/metric.js | 35 +++++++++++++++++++++++++---------- lib/metrics/all.js | 10 ++++++---- lib/metrics/sales.js | 12 +++++++----- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/lib/metric.js b/lib/metric.js index 238c599..25db4a1 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -6,12 +6,16 @@ var Metric = function(name, initialData, interval, db, addHandler) { } this.name = name; - this.initialData = this.data = initialData; + this.initialData = initialData; this.interval = interval; this.job = null; + this.minuteJob = null; this.clients = []; this.addHandler = addHandler; + this.resetMinuteData(); + this.resetData(); + var metric = this; db.createCollection('metrics', function(err, collection) { @@ -25,6 +29,7 @@ var Metric = function(name, initialData, interval, db, addHandler) { Metric.prototype = { run: function() { this.job = setInterval(this.runner, this.interval, this); + this.minuteJob = setInterval(this.minuteRunner, 60000, this); }, runner: function(metric) { @@ -38,22 +43,28 @@ Metric.prototype = { } }); - metric.insertData(); metric.resetData(); }, - addValue: function(view) { - this.addHandler(view); - }, + minuteRunner: function(metric) { + var timestamp = new Date(); + timestamp.setSeconds(0); - insertData: function() { var mongoData = { - data: this.data, - name: this.name, - timestamp: (new Date()).getTime() + data: metric.minuteData, + name: metric.name, + interval: 60, + timestamp: timestamp.getTime() }; - this.collection.insert(mongoData); + sys.log(JSON.stringify(mongoData, null, 2)); + + metric.collection.insert(mongoData); + metric.resetMinuteData(); + }, + + addValue: function(view) { + this.addHandler(view); }, removeClient: function(client) { @@ -68,6 +79,10 @@ Metric.prototype = { this.data = JSON.parse(JSON.stringify(this.initialData)); }, + resetMinuteData: function() { + this.minuteData = JSON.parse(JSON.stringify(this.initialData)); + }, + stop: function() { clearInterval(this.job); } diff --git a/lib/metrics/all.js b/lib/metrics/all.js index c461e5b..53d12dd 100644 --- a/lib/metrics/all.js +++ b/lib/metrics/all.js @@ -1,12 +1,14 @@ var AllViewsMetric = { - name: 'all_views', - defaultData: {total: 0, cartAdds: 0}, - interval: 50, - addValueCallback: function(view) { + name: 'all_views', + defaultData: {total: 0, cartAdds: 0}, + interval: 50, + addValueCallback: function(view) { this.data.total += 1; + this.minuteData.total += 1; if(view.event() && view.event() === "cart_add") { this.data.cartAdds += 1; + this.minuteData.cartAdds += 1; } } }; diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js index dca1932..ca61862 100644 --- a/lib/metrics/sales.js +++ b/lib/metrics/sales.js @@ -1,15 +1,17 @@ var SalesMetric = { - name: 'sales', - defaultData: {sales: {}}, - interval: 500, - addValueCallback: function(view) { + name: 'sales', + defaultData: {sales: {}}, + interval: 500, + addValueCallback: function(view) { if(view.urlKey()) { if(this.data.sales[view.urlKey()]) { this.data.sales[view.urlKey()] += 1; + this.minuteData.sales[view.urlKey()] += 1; } else { this.data.sales[view.urlKey()] = 1; + this.minuteData.sales[view.urlKey()] = 1; } - } + } } }; From 9836ca2cfc5e72c214edda23543255567e7633e8 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 28 Apr 2010 16:11:22 -0400 Subject: [PATCH 072/267] Switch metrics logging to single line mode --- lib/metric.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metric.js b/lib/metric.js index 25db4a1..3b4c5ff 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -57,7 +57,7 @@ Metric.prototype = { timestamp: timestamp.getTime() }; - sys.log(JSON.stringify(mongoData, null, 2)); + sys.log(JSON.stringify(mongoData)); metric.collection.insert(mongoData); metric.resetMinuteData(); From 24346b0dac334b4a0bda6d6ddb73b5af00ba959b Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 28 Apr 2010 16:14:19 -0400 Subject: [PATCH 073/267] Strip off url hash from url_keys --- lib/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/view.js b/lib/view.js index 50f15c5..cc2bd0a 100644 --- a/lib/view.js +++ b/lib/view.js @@ -39,6 +39,6 @@ View.prototype = { } }; -View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/)([^\/\?]+)\/?(product\/)?(\d+)?/); +View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/)([^\/\?\#]+)\/?(product\/)?(\d+)?/); exports.View = View; From faaf033028692fa24dcb89eb486dd71eed725e70 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 28 Apr 2010 16:24:33 -0400 Subject: [PATCH 074/267] Cleaner timestamps for metrics --- lib/metric.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/metric.js b/lib/metric.js index 3b4c5ff..0183cc0 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -47,14 +47,23 @@ Metric.prototype = { }, minuteRunner: function(metric) { - var timestamp = new Date(); - timestamp.setSeconds(0); + var time = new Date(); + var timestamp = time.getTime(); + + time.setMilliseconds(0); + + var timestampMinute = time.setSeconds(0); + var timestampHour = time.setMinutes(0); + var timestampDay = time.setHours(0); var mongoData = { data: metric.minuteData, name: metric.name, interval: 60, - timestamp: timestamp.getTime() + timestamp: timestamp, + minute: timestampMinute, + hour: timestampHour, + day: timestampDay }; sys.log(JSON.stringify(mongoData)); From eea67f5e9c4874de11dc223284e0be24167fe880 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 29 Apr 2010 23:08:52 -0400 Subject: [PATCH 075/267] css and copy tweaks --- public/css/main.css | 7 +++++-- public/index.html | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/public/css/main.css b/public/css/main.css index ccc84cd..1eb0aa5 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -35,6 +35,8 @@ div.hummingbird_graph div.axis_right { font-weight: bold; font-size: 0.8em; width: 30px; + position: relative; + top: -5px; } div.hummingbird_graph div.axis_left { @@ -74,7 +76,7 @@ div.hummingbird_graph div.axis_right { #sales div.sale div.hummingbird_graph div.req_s { position: absolute; top: 15px; - left: 0; + left: -10px; background-color: rgba(0, 0, 0, 0.8); color: #FFF; font-weight: bold; @@ -99,7 +101,8 @@ div.hummingbird_graph div.axis_right { #sales div.sale h2 { color: #CCC; font-size: 0.7em; - height: 1.8em; + height: 2.4em; + overflow: hidden; } #sales div.sale img.editorial { diff --git a/public/index.html b/public/index.html index 3e6f342..a761935 100644 --- a/public/index.html +++ b/public/index.html @@ -20,7 +20,7 @@

Hummingbird

-

Total Pageviews / Second

+

Pageviews / Second

@@ -32,7 +32,7 @@

Total Pageviews / Second

-

Total Cart Adds / Second

+

Cart Adds / Second

From 2d28a481152a02b3cffe31718d3712654b030d1c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 28 Apr 2010 15:49:57 -0400 Subject: [PATCH 076/267] Add a weekly json feed --- lib/static_assets.js | 35 ++++++++++------------------------- lib/weekly.js | 43 +++++++++++++++++++++++++++++++++++++++++++ server.js | 27 +++++++++++++++++++++++---- 3 files changed, 76 insertions(+), 29 deletions(-) create mode 100644 lib/weekly.js diff --git a/lib/static_assets.js b/lib/static_assets.js index edcc313..2d80140 100644 --- a/lib/static_assets.js +++ b/lib/static_assets.js @@ -1,33 +1,18 @@ var sys = require('sys'), paperboy = require('deps/node-paperboy'), - proxy = require('proxy'), - path = require('path'), - http = require('http'); + path = require('path'); var WEBROOT = path.join(path.dirname(__filename), '..', 'public'); -var serveStatic = function(port) { - try { - http.createServer(function(req, res) { - if(req.url.match(/\/sale_list/)) { - proxy.route("/sale_list", - "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); - } else { - paperboy.deliver(WEBROOT, req, res) - .addHeader('Content-Type', "text/plain") - .after(function(statCode) { - sys.log([statCode, - req.method, - req.url, - req.connection.remoteAddress].join(' ')); - }); - } - }).listen(port); - - sys.puts('Analytics server running at http://localhost:' + port + '/'); - } catch(e) { - sys.puts('Detected webserver already running on http://localhost:' + port + '.'); - } +var serveStatic = function(req, res) { + paperboy.deliver(WEBROOT, req, res) + .addHeader('Content-Type', "text/plain") + .after(function(statCode) { + sys.log([statCode, + req.method, + req.url, + req.connection.remoteAddress].join(' ')); + }); }; exports.serveStatic = serveStatic; diff --git a/lib/weekly.js b/lib/weekly.js new file mode 100644 index 0000000..b6f5c71 --- /dev/null +++ b/lib/weekly.js @@ -0,0 +1,43 @@ +var sys = require('sys'), + TimeBucketers = require('aggregates').TimeBucketers; + +var Weekly = {}; + +Weekly.serve = function(db, req, res) { + db.collection('visits', function(err, collection) { + var today = TimeBucketers.closestDayFor((new Date()).getTime()); + var counts = []; + var _oneDay = 1000 * 60 * 60 * 24; + + for(var i = 0; i < 7; i++) { + var startTime = today - (i + 1) * _oneDay; + var endTime = today - i * _oneDay; + var conditions = { + timestamp: { + $gt: startTime, + $lt: endTime + } + }; + Weekly.fetch(collection, conditions, startTime, endTime, counts, req, res); + } + }); +}; + +Weekly.fetch = function(collection, conditions, startTime, endTime, counts, req, res) { + collection.find(conditions, function(err, cursor) { + sys.log(JSON.stringify(cursor, null, 2)); + cursor.count(function(err, count) { + counts.push([startTime, count]); + sys.log(JSON.stringify(counts)); + + if(counts.length == 7) { + res.writeHead(200, {'Content-type': "text/plain"}); + res.write(JSON.stringify(counts, null, 2)); + res.close(); + } + }); + }); +}; + + +exports.serve = Weekly.serve; \ No newline at end of file diff --git a/server.js b/server.js index e28bcb4..af03f70 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,8 @@ require.paths.unshift(__dirname); var sys = require('sys'), http = require('http'), ws = require('deps/node-ws/ws'), + proxy = require('proxy'), + weekly = require('weekly'), mongo = require('deps/node-mongodb-native/lib/mongodb'), Hummingbird = require('hummingbird').Hummingbird; @@ -43,8 +45,25 @@ db.open(function(p_db) { sys.log("ws close"); }); }).listen(WEB_SOCKET_PORT); -}); -sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); -var staticAssets = require('static_assets'); -staticAssets.serveStatic(MONITOR_PORT); + sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); + var staticAssets = require('static_assets'); + + try { + http.createServer(function(req, res) { + if(req.url.match(/\/sale_list/)) { + proxy.route("/sale_list", + "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); + } else if(req.url.match(/\/week.json/)) { + weekly.serve(db, req, res); + } else { + staticAssets.serveStatic(req, res); + } + }).listen(MONITOR_PORT); + + sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); + } catch(e) { + sys.puts('Detected webserver already running on http://localhost:' + MONITOR_PORT + '.'); + } + +}); From 9c2c829533a75925a5579856f74eb96358ee5aa8 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 29 Apr 2010 23:08:32 -0400 Subject: [PATCH 077/267] Weekly stats url now working at /week.json --- lib/weekly.js | 55 ++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/lib/weekly.js b/lib/weekly.js index b6f5c71..2af65ee 100644 --- a/lib/weekly.js +++ b/lib/weekly.js @@ -3,41 +3,42 @@ var sys = require('sys'), var Weekly = {}; -Weekly.serve = function(db, req, res) { - db.collection('visits', function(err, collection) { - var today = TimeBucketers.closestDayFor((new Date()).getTime()); - var counts = []; - var _oneDay = 1000 * 60 * 60 * 24; - - for(var i = 0; i < 7; i++) { - var startTime = today - (i + 1) * _oneDay; - var endTime = today - i * _oneDay; - var conditions = { - timestamp: { - $gt: startTime, - $lt: endTime +Weekly.reducer = function(obj, prev) { + if(obj.name == 'all_views') { + prev.total += obj.data.total; prev.cartAdds += obj.data.cartAdds; + } else { + for(saleKey in obj.data.sales) { + if(obj.data.sales[saleKey] > 10) { + if(prev.sales[saleKey]) { + prev.sales[saleKey] += obj.data.sales[saleKey]; + } else { + prev.sales[saleKey] = obj.data.sales[saleKey]; } - }; - Weekly.fetch(collection, conditions, startTime, endTime, counts, req, res); + } } - }); + } }; -Weekly.fetch = function(collection, conditions, startTime, endTime, counts, req, res) { - collection.find(conditions, function(err, cursor) { - sys.log(JSON.stringify(cursor, null, 2)); - cursor.count(function(err, count) { - counts.push([startTime, count]); - sys.log(JSON.stringify(counts)); +Weekly.serve = function(db, req, res) { + db.collection('metrics', function(err, collection) { + var today = TimeBucketers.closestDayFor((new Date()).getTime()); + var counts = []; + var _oneDay = 1000 * 60 * 60 * 24; - if(counts.length == 7) { - res.writeHead(200, {'Content-type': "text/plain"}); - res.write(JSON.stringify(counts, null, 2)); - res.close(); + var result = collection.group(['day'], + {}, + { total: 0, cartAdds: 0, sales: {} }, + Weekly.reducer, + function(err, items) { + if(err) { + sys.log(JSON.stringify(err, null, 2)); } + + res.writeHead(200, {'Content-type': "text/plain"}); + res.write(JSON.stringify(items, null, 2)); + res.close(); }); }); }; - exports.serve = Weekly.serve; \ No newline at end of file From 40f49122d6a80d61307f995d2aee666aba87cba8 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 30 Apr 2010 02:10:46 -0400 Subject: [PATCH 078/267] Limit days to 1 week; sort weekly results; work around bug in mapreduce's initialize step by setting sales to null instead of empty object --- lib/weekly.js | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/weekly.js b/lib/weekly.js index 2af65ee..03afdfd 100644 --- a/lib/weekly.js +++ b/lib/weekly.js @@ -7,7 +7,9 @@ Weekly.reducer = function(obj, prev) { if(obj.name == 'all_views') { prev.total += obj.data.total; prev.cartAdds += obj.data.cartAdds; } else { - for(saleKey in obj.data.sales) { + if(!prev.sales) { prev.sales = {}; } + + for(var saleKey in obj.data.sales) { if(obj.data.sales[saleKey] > 10) { if(prev.sales[saleKey]) { prev.sales[saleKey] += obj.data.sales[saleKey]; @@ -22,18 +24,41 @@ Weekly.reducer = function(obj, prev) { Weekly.serve = function(db, req, res) { db.collection('metrics', function(err, collection) { var today = TimeBucketers.closestDayFor((new Date()).getTime()); - var counts = []; var _oneDay = 1000 * 60 * 60 * 24; var result = collection.group(['day'], - {}, - { total: 0, cartAdds: 0, sales: {} }, - Weekly.reducer, + {day: { $gte: today - _oneDay * 7 } }, + { total: 0, cartAdds: 0, sales: null}, + Weekly.reducer.toString(), function(err, items) { if(err) { sys.log(JSON.stringify(err, null, 2)); } + items = items.sort(function(a, b) { + if(a.day > b.day) { return -1; } else { return 1; } + }); + + // Turn the sales hash into an array, for sorting + items.each(function(item) { + item.tmpSales = item.sales; + item.sales = []; + for(sale in item.tmpSales) { + item.sales.push({url_key: sale, views: item.tmpSales[sale]}); + } + + // Sort by sale numbers descending + item.sales = item.sales.sort(function(a, b) { + if(a.views == b.views) { + return 0; + } else if(a.views > b.views) { + return -1; + } else { return 1; } + }); + + delete item.tmpSales; + }); + res.writeHead(200, {'Content-type': "text/plain"}); res.write(JSON.stringify(items, null, 2)); res.close(); From 1e8aa30c66e05154988f6bd518aa3176f418ee84 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 30 Apr 2010 02:11:10 -0400 Subject: [PATCH 079/267] Building out the weekly page --- public/css/weekly.css | 77 +++++++++++++++++++++++++++++++ public/index.html | 9 ++++ public/js/helpers.js | 11 +++++ public/js/sales.js | 8 +--- public/js/websocket.js | 6 +-- public/weekly.html | 102 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 201 insertions(+), 12 deletions(-) create mode 100644 public/css/weekly.css create mode 100644 public/weekly.html diff --git a/public/css/weekly.css b/public/css/weekly.css new file mode 100644 index 0000000..9af30c4 --- /dev/null +++ b/public/css/weekly.css @@ -0,0 +1,77 @@ +#days { + margin: 20px 58px; +} + +div.day { + color: #FFF; + border-top: 2px solid #666; +} + +div.day div.date_title { + color: #FFF; + text-transform: uppercase; + font-family: 'TitilliumText14L800wt', sans-serif; + font-size: 2.5em; +} + +div.day div.all_views_container, +div.day div.cart_adds_container { + float: right; + clear: right; + text-align: right; +} + +div.day div.all_views, +div.day div.cart_adds { + font-size: 2.5em; + font-weight: bold; + margin: 4px 0 0 10px; +} + +div.day div.all_views { + color: #5BC4B6; +} + +div.day div.all_views_container p, +div.day div.cart_adds_container p { + margin: 0 0 1em 0; + text-transform: uppercase; + font-size: 0.8em; + font-weight: bold; +} + +div.day div.sales { + margin: 0 10px 20px 0; +} + +div.day div.day_sale { + width: 180px; + float: left; + margin: 0 20px 10px 0; + position: relative; +} + +div.sale_container p { + margin: 10px 0 0 0; + text-transform: uppercase; + font-weight: bold; + font-size: 0.9em; +} + +div.day div.day_sale div.sale_views { + font-weight: bold; + padding: 4px; + background-color: #000; + float: right; + margin: 0 -5px 5px 5px; +} + +div.day div.day_sale div.sale_title { + font-size: 0.7em; + width: 180px; + margin: 5px 0 0 0; +} + +#day_template, #sale_template { + display: none; +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index a761935..1701893 100644 --- a/public/index.html +++ b/public/index.html @@ -10,6 +10,15 @@ + + Hummingbird diff --git a/public/js/helpers.js b/public/js/helpers.js index 6cc3806..d0b1949 100644 --- a/public/js/helpers.js +++ b/public/js/helpers.js @@ -23,6 +23,17 @@ Date.prototype.formattedTime = function() { return formattedDate; }; +Number.prototype.commify = function() { + var strArray = this.toString().split('').reverse(); + var commas = []; + for(var i = 0; i < strArray.length; i++) { + if(i > 0 && i % 3 == 0) { commas.push(','); } + commas.push(strArray[i]); + } + + return commas.reverse().join(''); +}; + // Custom sorting plugin (function($) { $.fn.sorted = function(customOptions) { diff --git a/public/js/sales.js b/public/js/sales.js index ff941b2..1b6321e 100644 --- a/public/js/sales.js +++ b/public/js/sales.js @@ -45,10 +45,4 @@ Hummingbird.resortSales = function() { $.each(sortedSales, function() { $(this).prependTo("div#sales"); }); -}; - -$(document).ready(function() { - Hummingbird.getSales(); - - setInterval(Hummingbird.resortSales, 3000); -}); \ No newline at end of file +}; \ No newline at end of file diff --git a/public/js/websocket.js b/public/js/websocket.js index ca3bf1a..917b772 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -59,8 +59,4 @@ Hummingbird.WebSocket.start = function() { console.log("socket started"); //alert("connected..."); }; -}; - -$(document).ready(function(){ - Hummingbird.WebSocket.start(); -}); +}; \ No newline at end of file diff --git a/public/weekly.html b/public/weekly.html new file mode 100644 index 0000000..990c1d2 --- /dev/null +++ b/public/weekly.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + Hummingbird + + + + + + +

Hummingbird

+ +
+ +
+ +
+
0
+

Page views

+
+ +
+
0
+

Cart adds

+
+ +
Monday
+ +
+

Top Sales:

+
+
+ +
+
+ +
+
+
+
+ +
+ + From 199a81689577770683d92342e03a004cc7d6d205 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 1 May 2010 14:49:12 -0700 Subject: [PATCH 080/267] After weekly stats page has loaded, update the most recent entry continually. Note: does not take the browser passing into a new day into account --- public/weekly.html | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/public/weekly.html b/public/weekly.html index 990c1d2..e6299e1 100644 --- a/public/weekly.html +++ b/public/weekly.html @@ -11,6 +11,9 @@ From e3b9360b22646714cc74d159a2e15b9a7fd3fdc8 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 1 May 2010 18:21:01 -0400 Subject: [PATCH 081/267] css tweaks for ipad --- public/css/weekly.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/css/weekly.css b/public/css/weekly.css index 9af30c4..0646b9f 100644 --- a/public/css/weekly.css +++ b/public/css/weekly.css @@ -41,14 +41,15 @@ div.day div.cart_adds_container p { } div.day div.sales { - margin: 0 10px 20px 0; + margin: 0 100px 20px 0; } div.day div.day_sale { width: 180px; float: left; - margin: 0 20px 10px 0; + margin: 0 20px 0 0; position: relative; + height: 130px; } div.sale_container p { From 32c305f7bfa47a2dfa5f98bfbe83bcb23bf7efdd Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Sun, 2 May 2010 00:25:24 +0000 Subject: [PATCH 082/267] Removing unmatched div tag --- public/weekly.html | 1 - 1 file changed, 1 deletion(-) diff --git a/public/weekly.html b/public/weekly.html index e6299e1..ac0629b 100644 --- a/public/weekly.html +++ b/public/weekly.html @@ -133,6 +133,5 @@

Hummingbird

-
From 5ff1a45b12000c7ca96f5a2aedab3a49c103120b Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Sun, 2 May 2010 01:52:19 +0000 Subject: [PATCH 083/267] Allowing weekly to pull from production --- public/weekly.html | 7 ++++++- server.js | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/public/weekly.html b/public/weekly.html index ac0629b..f7f25a9 100644 --- a/public/weekly.html +++ b/public/weekly.html @@ -24,7 +24,12 @@ sales[this.url_key] = this; }); - $.getJSON("/week.json", function(data) { + var weekJson = "/week.json"; + if(document.location.search.match(/use_prod/)) { + weekJson += "?use_prod"; + } + + $.getJSON(weekJson, function(data) { var dayTemplate = $("#day_template"); var saleTemplate = $("#sale_template"); diff --git a/server.js b/server.js index af03f70..3d3ce2e 100644 --- a/server.js +++ b/server.js @@ -55,7 +55,13 @@ db.open(function(p_db) { proxy.route("/sale_list", "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); } else if(req.url.match(/\/week.json/)) { - weekly.serve(db, req, res); + if(req.url.match(/use_prod/)) { + proxy.route("/week.json", + "http://hummingbird.giltrunway.com:8088/week.json", req, res); + } + else { + weekly.serve(db, req, res); + } } else { staticAssets.serveStatic(req, res); } From e5ff24f9658f7eadaa046aec054378c3f1992277 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Sun, 2 May 2010 02:17:16 +0000 Subject: [PATCH 084/267] Check if a sale exists before adding it to the top sales for a day * This happens when the sale no longer shows up in the pagegen response --- public/weekly.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/public/weekly.html b/public/weekly.html index f7f25a9..c588959 100644 --- a/public/weekly.html +++ b/public/weekly.html @@ -52,10 +52,13 @@ $.each(this.sales.slice(0, 4), function() { var saleDiv = saleTemplate.clone().attr('id', '').attr('style', ''); var sale = sales[this.url_key]; - saleDiv.prepend(""); - saleDiv.find('div.sale_title').text(sale.name); - saleDiv.find('div.sale_views').text(this.views); - dateDiv.find('div.sales').append(saleDiv); + + if (sale) { + saleDiv.prepend(""); + saleDiv.find('div.sale_title').text(sale.name); + saleDiv.find('div.sale_views').text(this.views); + dateDiv.find('div.sales').append(saleDiv); + } }); dateDiv.find('div.sales').append("
"); From 72bbe1d297c1a433f4005b01d39884596a1ca9b9 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Mon, 3 May 2010 17:25:49 +0000 Subject: [PATCH 085/267] Whitespace --- public/weekly.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/weekly.html b/public/weekly.html index c588959..d04693b 100644 --- a/public/weekly.html +++ b/public/weekly.html @@ -11,8 +11,8 @@ - - - - - - - - - Hummingbird - - - - - -

Hummingbird

- -
- -

Pageviews / Second

- -
- -
- -
- -
- -
- -

Cart Adds / Second

- -
- - - -
- -
- -
- -
- - - diff --git a/server.js b/server.js index 4b756f6..5207587 100644 --- a/server.js +++ b/server.js @@ -13,7 +13,7 @@ var TRACKING_PORT = 8000, WEB_SOCKET_PORT = 8080, MONITOR_PORT = 8888; -var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); +db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); db.open(function(p_db) { var hummingbird = new Hummingbird(db, function() { @@ -26,7 +26,7 @@ db.open(function(p_db) { }).listen(TRACKING_PORT); }); - sys.puts('Tracking server running at http://localhost:' + TRACKING_PORT + '/tracking_pixel.gif'); + sys.puts('Tracking server running at http://*:' + TRACKING_PORT + '/tracking_pixel.gif'); // Websocket TCP server ws.createServer(function (websocket) { @@ -46,30 +46,8 @@ db.open(function(p_db) { }); }).listen(WEB_SOCKET_PORT); - sys.puts('Web Socket server running at ws://localhost:' + WEB_SOCKET_PORT); + sys.puts('Web Socket server running at ws://*:' + WEB_SOCKET_PORT); var staticAssets = require('static_assets'); - try { - http.createServer(function(req, res) { - if(req.url.match(/\/sale_list/)) { - proxy.route("/sale_list", - "http://www.gilt.com/pagegen_service/sale/sale_list", req, res); - } else if(req.url.match(/\/week.json/)) { - if(req.url.match(/use_prod/)) { - proxy.route("/week.json", - "http://hummingbird.giltrunway.com:8088/week.json", req, res); - } - else { - weekly.serve(db, req, res); - } - } else { - staticAssets.serveStatic(req, res); - } - }).listen(MONITOR_PORT); - - sys.puts('Analytics server running at http://localhost:' + MONITOR_PORT + '/'); - } catch(e) { - sys.puts('Detected webserver already running on http://localhost:' + MONITOR_PORT + '.'); - } - + require('monitor'); }); diff --git a/views/index.html.ejs b/views/index.html.ejs new file mode 100644 index 0000000..a2bd5d3 --- /dev/null +++ b/views/index.html.ejs @@ -0,0 +1,30 @@ +

Hummingbird

+ +
+ +

Pageviews / Second

+ +
+ +
+ +
+ +
+ +
+ +

Cart Adds / Second

+ +
+ + + +
+ +
+ +
+ +
+ diff --git a/views/layout.html.ejs b/views/layout.html.ejs new file mode 100644 index 0000000..e77ae46 --- /dev/null +++ b/views/layout.html.ejs @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + Hummingbird + + + + + + <%= body %> + + From d4d115a53e11dd0e12e6efa9a7f8f8386a6379ce Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 5 May 2010 15:15:55 -0400 Subject: [PATCH 093/267] Fix sale_list json proxy --- lib/proxy.js | 11 ----------- lib/service_json.js | 4 ++-- monitor.js | 4 ++-- 3 files changed, 4 insertions(+), 15 deletions(-) delete mode 100644 lib/proxy.js diff --git a/lib/proxy.js b/lib/proxy.js deleted file mode 100644 index 8a580c7..0000000 --- a/lib/proxy.js +++ /dev/null @@ -1,11 +0,0 @@ -var services = require('./service_json'); -var sys = require('sys'); - -exports.route = function(path, remoteURL, req, res) { - sys.log("Routing " + path + " to " + remoteURL); - services.fetchJSON(remoteURL, function(data) { - res.writeHead(200, {'Content-type': "text/plain"}); - res.write(data); - res.close(); - }); -}; diff --git a/lib/service_json.js b/lib/service_json.js index 4c49307..90ea1dd 100644 --- a/lib/service_json.js +++ b/lib/service_json.js @@ -9,7 +9,7 @@ exports.fetchJSON = function(remoteURL, callback) { // TODO: remoteURL.search var request = pagegen.request('GET', remoteURL.pathname, {"host": remoteURL.hostname}); request.addListener('response', function(response) { - + response.setEncoding('binary'); response.client.responseBodyParts = ''; response.addListener('data', function(chunk) { @@ -20,5 +20,5 @@ exports.fetchJSON = function(remoteURL, callback) { callback(response.client.responseBodyParts); }); }); - request.close(); + request.end(); }; diff --git a/monitor.js b/monitor.js index 16322b5..96320f6 100644 --- a/monitor.js +++ b/monitor.js @@ -11,7 +11,7 @@ configure(function(){ set('pagegen_uri', "http://www.gilt.com/pagegen_service/sale/sale_list"); set('db', db); use(Static); - this.server.port = 8088;; + this.server.port = 8088; }); get('/', function(){ @@ -20,7 +20,7 @@ get('/', function(){ get('/sale_list', function() { var self = this; - svc.fetchJSON(Express.settings['pagegen_uri'], function(data) { + svc.fetchJSON(set('pagegen_uri'), function(data) { self.contentType('json'); self.respond(200, data); }); From 771a2549275d2bd9f9bee13415b63ba4cb76556f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 5 May 2010 16:43:15 -0400 Subject: [PATCH 094/267] Remove proxy require --- .gitmodules | 2 +- deps/node-ws | 2 +- server.js | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 172b80c..2bf92eb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ url = git://github.com/christkv/node-mongodb-native.git [submodule "deps/node-ws"] path = deps/node-ws - url = git://github.com/mnutt/node.ws.js + url = git://github.com/ncr/node.ws.js.git [submodule "deps/express"] path = deps/express url = git://github.com/visionmedia/express.git diff --git a/deps/node-ws b/deps/node-ws index 3cda892..148c1a1 160000 --- a/deps/node-ws +++ b/deps/node-ws @@ -1 +1 @@ -Subproject commit 3cda89274a7e2084f07a68820f09228be05fd077 +Subproject commit 148c1a19fe3a24fa5384ce625aa84ef480540346 diff --git a/server.js b/server.js index 5207587..28f959f 100644 --- a/server.js +++ b/server.js @@ -4,7 +4,6 @@ require.paths.unshift(__dirname); var sys = require('sys'), http = require('http'), ws = require('deps/node-ws/ws'), - proxy = require('proxy'), weekly = require('weekly'), mongo = require('deps/node-mongodb-native/lib/mongodb'), Hummingbird = require('hummingbird').Hummingbird; From 30118ec0143968a538b5b1f4a49057e07ddaccc6 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 5 May 2010 16:46:11 -0400 Subject: [PATCH 095/267] Upgrade mongodb-native and paperboy to latest versions --- .gitmodules | 2 +- deps/node-mongodb-native | 2 +- deps/node-paperboy | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 2bf92eb..13591fa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = git://github.com/caolan/nodeunit.git [submodule "deps/node-paperboy"] path = deps/node-paperboy - url = git://github.com/mnutt/node-paperboy + url = git://github.com/felixge/node-paperboy.git [submodule "deps/node-mongodb-native"] path = deps/node-mongodb-native url = git://github.com/christkv/node-mongodb-native.git diff --git a/deps/node-mongodb-native b/deps/node-mongodb-native index 921d13c..5401a62 160000 --- a/deps/node-mongodb-native +++ b/deps/node-mongodb-native @@ -1 +1 @@ -Subproject commit 921d13cd0696fbf3bafa718d54e16f55bc788f52 +Subproject commit 5401a62e7a139f9d0f379e46e6ad3107810f7c7c diff --git a/deps/node-paperboy b/deps/node-paperboy index f4e7ced..59345d1 160000 --- a/deps/node-paperboy +++ b/deps/node-paperboy @@ -1 +1 @@ -Subproject commit f4e7cedb816130dbc85dbd79b72d0585346bdbbc +Subproject commit 59345d119393630af5d429853540434cfeab1817 From 61eba869b1a98ae01606f8b8ce5c68b916105ec4 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 6 May 2010 11:23:35 -0400 Subject: [PATCH 096/267] Add private site-specific settings dir --- private/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 private/.gitkeep diff --git a/private/.gitkeep b/private/.gitkeep new file mode 100644 index 0000000..e69de29 From 69d1bb6bb5c4f935b78219cb55a5ed5b3744b376 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 6 May 2010 11:45:41 -0400 Subject: [PATCH 097/267] Fix weekly view to use express --- .gitignore | 2 + monitor.js | 6 +- public/js/weekly.js | 90 ++++++++++++++++++++++++++ public/weekly.html | 145 ------------------------------------------ views/index.html.ejs | 8 +++ views/layout.html.ejs | 11 +--- views/weekly.html.ejs | 40 ++++++++++++ 7 files changed, 147 insertions(+), 155 deletions(-) create mode 100644 .gitignore create mode 100644 public/js/weekly.js delete mode 100644 public/weekly.html create mode 100644 views/weekly.html.ejs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8afe420 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/private/* +!/private/.gitkeep diff --git a/monitor.js b/monitor.js index 96320f6..f62aeb1 100644 --- a/monitor.js +++ b/monitor.js @@ -18,6 +18,10 @@ get('/', function(){ this.render('index.html.ejs'); }); +get('/weekly', function() { + this.render('weekly.html.ejs'); +}); + get('/sale_list', function() { var self = this; svc.fetchJSON(set('pagegen_uri'), function(data) { @@ -26,7 +30,7 @@ get('/sale_list', function() { }); }); -get('/weekly.json', function() { +get('/week.json', function() { var self = this; weekly.findByDay(Express.settings['db'], function(data) { self.contentType('json'); diff --git a/public/js/weekly.js b/public/js/weekly.js new file mode 100644 index 0000000..e303634 --- /dev/null +++ b/public/js/weekly.js @@ -0,0 +1,90 @@ +if(!Hummingbird) { Hummingbird = {}; } + +Hummingbird.Weekly = {}; + +Hummingbird.Weekly.weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + +Hummingbird.Weekly.init = function() { + $.getJSON("/sale_list", function(saleData) { + saleData.data.active_sales.concat(saleData.data.upcoming_sales); + var sales = {}; + $.each(saleData.data.active_sales, function() { + sales[this.url_key] = this; + }); + + var weekJson = "/week.json"; + if(document.location.search.match(/use_prod/)) { + weekJson += "?use_prod"; + } + + $.getJSON(weekJson, function(data) { + var dayTemplate = $("#day_template"); + var saleTemplate = $("#sale_template"); + + var today = new Date(); + today.setUTCHours(0); today.setUTCMinutes(0); today.setUTCSeconds(0); today.setUTCMilliseconds(0); + + $.each(data, function() { + var day = new Date(this.day); + if(day.getTime() == today.getTime()) { + var weekDay = "Today"; + } else { + var weekDay = Hummingbird.Weekly.weekDays[day.getUTCDay()]; + } + + var dateDiv = dayTemplate.clone().attr('id', 'date_' + day.getTime()).attr('style', ''); + dateDiv.find('div.date_title').text(weekDay); + dateDiv.find('div.all_views').text(this.total.commify()).data('total', this.total); + dateDiv.find('div.cart_adds').text(this.cartAdds.commify()).data('cart_adds', this.cartAdds);; + + $.each(this.sales.slice(0, 4), function() { + var saleDiv = saleTemplate.clone().attr('id', '').attr('style', ''); + var sale = sales[this.url_key]; + + if (sale) { + saleDiv.prepend(""); + saleDiv.find('div.sale_title').text(sale.name); + saleDiv.find('div.sale_views').text(this.views); + dateDiv.find('div.sales').append(saleDiv); + } + }); + dateDiv.find('div.sales').append("
"); + + dateDiv.appendTo('#days'); + }); + }); + }); + + if(document.location.search.match(/use_prod/)) { + var wsServer = "ws://hummingbird.giltrunway.com:8080"; + } else { + var wsServer = "ws://" + document.location.hostname + ":8080"; + } + var ws = new WebSocket(wsServer); + ws.onmessage = function(evt) { + var data = JSON.parse(evt.data); + if(data.total && data.total > 0) { + var el = $("div.day:first-child div.all_views"); + var prevTotal = el.data("total"); + el.text((prevTotal + data.total).commify()).data('total', prevTotal + data.total); + } + if(data.cartAdds && data.cartAdds > 0) { + var el = $("div.day:first-child div.cart_adds"); + var prevCartAdds = el.data("cart_adds"); + el.text((prevCartAdds + data.cartAdds).commify()).data('cart_adds', prevCartAdds + data.cartAdds); + } + }; + ws.onclose = function() { + if(Hummingbird.WebSocket.state == "retrying") { + // Wait a while to try restarting + console.log("still no socket, retrying in 3 seconds"); + setTimeout(Hummingbird.WebSocket.start, 3000); + } else { + // First attempt at restarting, try immediately + Hummingbird.WebSocket.state = "retrying"; + console.log("socket lost, retrying immediately"); + setTimeout(Hummingbird.WebSocket.start, 200); + } + }; +}; + diff --git a/public/weekly.html b/public/weekly.html deleted file mode 100644 index 024b5d5..0000000 --- a/public/weekly.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - - - - - Hummingbird - - - - - - -

Hummingbird

- -
- -
- -
-
0
-

Page views

-
- -
-
0
-

Cart adds

-
- -
- -
-

Top Sales:

-
-
- -
-
- -
-
-
-
- - - diff --git a/views/index.html.ejs b/views/index.html.ejs index a2bd5d3..d010a71 100644 --- a/views/index.html.ejs +++ b/views/index.html.ejs @@ -28,3 +28,11 @@
+ diff --git a/views/layout.html.ejs b/views/layout.html.ejs index e77ae46..7cf797f 100644 --- a/views/layout.html.ejs +++ b/views/layout.html.ejs @@ -9,19 +9,12 @@ - - + Hummingbird + diff --git a/views/weekly.html.ejs b/views/weekly.html.ejs new file mode 100644 index 0000000..108e260 --- /dev/null +++ b/views/weekly.html.ejs @@ -0,0 +1,40 @@ +

Hummingbird

+ +
+ +
+ +
+
0
+

Page views

+
+ +
+
0
+

Cart adds

+
+ +
+ +
+

Top Sales:

+
+
+ +
+
+ +
+
+
+
+ + From 30b98392bbe9bde3d6cf7a5035b82a49652115cd Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 6 May 2010 11:53:33 -0400 Subject: [PATCH 098/267] Changing monitor port again, sorry (8888) --- monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitor.js b/monitor.js index f62aeb1..aa0468f 100644 --- a/monitor.js +++ b/monitor.js @@ -11,7 +11,7 @@ configure(function(){ set('pagegen_uri', "http://www.gilt.com/pagegen_service/sale/sale_list"); set('db', db); use(Static); - this.server.port = 8088; + this.server.port = 8888; }); get('/', function(){ From de8b47b72327bc4b2cc9fc43df27e02d00a31f95 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Fri, 7 May 2010 18:19:41 -0400 Subject: [PATCH 099/267] Breaking out the monitor into a standalone express app --- monitor.js | 66 ++++++++++++++++++++++++++++++------------------------ server.js | 3 --- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/monitor.js b/monitor.js index aa0468f..3654d50 100644 --- a/monitor.js +++ b/monitor.js @@ -1,41 +1,49 @@ -require.paths.unshift('deps/express/lib') -require('express'); -require('express/plugins'); +require.paths.unshift(__dirname + '/lib'); +require.paths.unshift(__dirname); +require.paths.unshift(__dirname + '/deps/express/lib') var sys = require('sys'), + mongo = require('deps/node-mongodb-native/lib/mongodb'), svc = require('service_json'), weekly = require('weekly'); -configure(function(){ - set('root', __dirname); - set('pagegen_uri', "http://www.gilt.com/pagegen_service/sale/sale_list"); - set('db', db); - use(Static); - this.server.port = 8888; -}); +require('express'); +require('express/plugins'); -get('/', function(){ - this.render('index.html.ejs'); -}); +db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); -get('/weekly', function() { - this.render('weekly.html.ejs'); -}); +db.open(function(p_db) { + configure(function(){ + set('root', __dirname); + set('pagegen_uri', "http://www.gilt.com/pagegen_service/sale/sale_list"); + set('db', db); + use(Static); + this.server.port = 8888; + }); -get('/sale_list', function() { - var self = this; - svc.fetchJSON(set('pagegen_uri'), function(data) { - self.contentType('json'); - self.respond(200, data); + get('/', function(){ + this.render('index.html.ejs'); }); -}); -get('/week.json', function() { - var self = this; - weekly.findByDay(Express.settings['db'], function(data) { - self.contentType('json'); - self.respond(200, data); + get('/weekly', function() { + this.render('weekly.html.ejs'); + }); + + get('/sale_list', function() { + var self = this; + svc.fetchJSON(set('pagegen_uri'), function(data) { + self.contentType('json'); + self.respond(200, data); + }); }); -}); -run(); + get('/week.json', function() { + var self = this; + weekly.findByDay(Express.settings['db'], function(data) { + self.contentType('json'); + self.respond(200, data); + }); + }); + + run(); +}); diff --git a/server.js b/server.js index 28f959f..6924a5f 100644 --- a/server.js +++ b/server.js @@ -46,7 +46,4 @@ db.open(function(p_db) { }).listen(WEB_SOCKET_PORT); sys.puts('Web Socket server running at ws://*:' + WEB_SOCKET_PORT); - var staticAssets = require('static_assets'); - - require('monitor'); }); From ac6ee7bd62904a100594fc71732998383ec22360 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Fri, 7 May 2010 18:27:41 -0400 Subject: [PATCH 100/267] Updating the README as well as converting it to GHF markdown --- README | 40 ----------------------------------- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 40 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index f614238..0000000 --- a/README +++ /dev/null @@ -1,40 +0,0 @@ -HUMMINGBIRD - -Site tracking and analytics storage - - -Description - -Hummingbird serves a 1x1 tracking pixel to users. In the browser's GET request it -sends back tracking data generated by javascript. - - -Requirements - - * node.js v0.1.33 - * mongodb - - -Installation - - git clone git://github.com/mnutt/hummingbird.git - cd hummingbird - git submodule update --init - mongod & (or start mongo some other way) - node server.js - - -Specs - - sudo gem install jspec - jspec run --node - - -Tips - - * To run the UI locally but get some production data, use the url http://localhost:8088/?use_prod - - -Known Issues - - * node-paperboy has issues with returning 304's that cause some weirdness in some browsers. Try shift-reload until it's fixed. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6994ed --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +HUMMINGBIRD +=========== + +Site tracking and analytics storage + + +Description +--------------- + +Hummingbird serves a 1x1 tracking pixel to users. In the browser's GET request it +sends back tracking data generated by javascript. + + +Requirements +------------------- + + * node.js v0.1.94 + * mongodb + + +Installation +-------------- + + git clone git://github.com/mnutt/hummingbird.git + cd hummingbird + git submodule update --init + + # Initialize the express submodules + cd deps/express; git submodule update --init; cd ../.. + + +Running Hummingbird +------------------------------ + +To start the analytics server, run the following: + + mongod & (or start mongo some other way) + node server.js + +To start the web monitor, run: + + node monitor.js + + +Specs +-------- + + sudo gem install jspec + jspec run --node + + +Tips +----- + + * To run the UI locally but get some production data, use the url http://localhost:8088/?use_prod + + +Known Issues +------------------- + + * node-paperboy has issues with returning 304's that cause some weirdness in some browsers. Try shift-reload until it's fixed. + From 1e19ffa760764705343d08a878cb7cc2b2975c39 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 8 May 2010 03:26:40 -0400 Subject: [PATCH 101/267] Properly clone date so that timestamps aren't wrong --- lib/metric.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/metric.js b/lib/metric.js index 44159da..86cda6c 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -48,16 +48,16 @@ Metric.prototype = { minuteRunner: function(metric) { var time = new Date(); - var timestamp = time; + var timestamp = new Date(time.getTime()); time.setMilliseconds(0); time.setSeconds(0); - var timestampMinute = time + var timestampMinute = new Date(time.getTime()); time.setMinutes(0); - var timestampHour = time + var timestampHour = new Date(time.getTime()); time.setHours(0); - var timestampDay = time + var timestampDay = new Date(time.getTime()); var mongoData = { data: metric.minuteData, From 24b8d32cbc484dbe08a53a9c0c9b14b686d5a554 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 8 May 2010 03:28:22 -0400 Subject: [PATCH 102/267] Fix sales metrics so that they're not accidentally reset --- lib/metrics/sales.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js index ca61862..9d1b77c 100644 --- a/lib/metrics/sales.js +++ b/lib/metrics/sales.js @@ -6,11 +6,16 @@ var SalesMetric = { if(view.urlKey()) { if(this.data.sales[view.urlKey()]) { this.data.sales[view.urlKey()] += 1; - this.minuteData.sales[view.urlKey()] += 1; } else { this.data.sales[view.urlKey()] = 1; + } + + if(this.minuteData.sales[view.urlKey()]) { + this.minuteData.sales[view.urlKey()] += 1; + } else { this.minuteData.sales[view.urlKey()] = 1; } + } } }; From 02cbad8f921f26911fb93d3e7c8259cb6e7d20a8 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 8 May 2010 15:38:16 -0400 Subject: [PATCH 103/267] Simplify incrementing --- lib/metrics/sales.js | 14 ++------------ lib/weekly.js | 8 +------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js index 9d1b77c..6e966e9 100644 --- a/lib/metrics/sales.js +++ b/lib/metrics/sales.js @@ -4,18 +4,8 @@ var SalesMetric = { interval: 500, addValueCallback: function(view) { if(view.urlKey()) { - if(this.data.sales[view.urlKey()]) { - this.data.sales[view.urlKey()] += 1; - } else { - this.data.sales[view.urlKey()] = 1; - } - - if(this.minuteData.sales[view.urlKey()]) { - this.minuteData.sales[view.urlKey()] += 1; - } else { - this.minuteData.sales[view.urlKey()] = 1; - } - + this.data.sales[view.urlKey()] = (this.data.sales[view.urlKey()] || 0) + 1; + this.minuteData.sales[view.urlKey()] = (this.minuteData.sales[view.urlKey()] || 0) + 1; } } }; diff --git a/lib/weekly.js b/lib/weekly.js index 55f4ed6..9fc46f8 100644 --- a/lib/weekly.js +++ b/lib/weekly.js @@ -10,13 +10,7 @@ Weekly.reducer = function(obj, prev) { if(!prev.sales) { prev.sales = {}; } for(var saleKey in obj.data.sales) { - if(obj.data.sales[saleKey] > 10) { - if(prev.sales[saleKey]) { - prev.sales[saleKey] += obj.data.sales[saleKey]; - } else { - prev.sales[saleKey] = obj.data.sales[saleKey]; - } - } + prev.sales[saleKey] = (prev.sales[saleKey] || 0) + obj.data.sales[saleKey]; } } }; From e7e57c4e3018f81f74001985e2e5c98936f54b13 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 8 May 2010 15:44:14 -0400 Subject: [PATCH 104/267] Reduce json output on the weekly page --- lib/weekly.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/weekly.js b/lib/weekly.js index 9fc46f8..54b644b 100644 --- a/lib/weekly.js +++ b/lib/weekly.js @@ -38,8 +38,10 @@ Weekly.findByDay = function(db, callback) { item.tmpSales = item.sales; item.sales = []; for(sale in item.tmpSales) { - item.sales.push({ url_key: sale, - views: item.tmpSales[sale] }); + if(item.tmpSales[sale] > 10) { + item.sales.push({ url_key: sale, + views: item.tmpSales[sale] }); + } } delete item.tmpSales; From 71ac0dd75a60931f938dea221687f2e1c9c53dd3 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 8 May 2010 22:54:03 -0400 Subject: [PATCH 105/267] interval explanation --- lib/metrics/all.js | 2 +- lib/metrics/sales.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/metrics/all.js b/lib/metrics/all.js index 53d12dd..a5e8108 100644 --- a/lib/metrics/all.js +++ b/lib/metrics/all.js @@ -1,7 +1,7 @@ var AllViewsMetric = { name: 'all_views', defaultData: {total: 0, cartAdds: 0}, - interval: 50, + interval: 50, // ms addValueCallback: function(view) { this.data.total += 1; this.minuteData.total += 1; diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js index 6e966e9..6109706 100644 --- a/lib/metrics/sales.js +++ b/lib/metrics/sales.js @@ -1,7 +1,7 @@ var SalesMetric = { name: 'sales', defaultData: {sales: {}}, - interval: 500, + interval: 500, // ms addValueCallback: function(view) { if(view.urlKey()) { this.data.sales[view.urlKey()] = (this.data.sales[view.urlKey()] || 0) + 1; From c9ab06e65516f7dcf2bedb013208ae48853297b9 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 02:35:31 -0400 Subject: [PATCH 106/267] Add node-microseconds for more granular profiling --- .gitmodules | 3 +++ deps/node-microseconds | 1 + lib/hummingbird.js | 1 + 3 files changed, 5 insertions(+) create mode 160000 deps/node-microseconds diff --git a/.gitmodules b/.gitmodules index 13591fa..4c41554 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "deps/express"] path = deps/express url = git://github.com/visionmedia/express.git +[submodule "deps/node-microseconds"] + path = deps/node-microseconds + url = http://github.com/tmpvar/node-microseconds.git diff --git a/deps/node-microseconds b/deps/node-microseconds new file mode 160000 index 0000000..79726d6 --- /dev/null +++ b/deps/node-microseconds @@ -0,0 +1 @@ +Subproject commit 79726d6daaf30e942023a2d148aa1562d1949a93 diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 2adfb20..5d26323 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -5,6 +5,7 @@ var sys = require('sys'), Aggregates = require('aggregates').Aggregates, path = require('path'), arrays = require('deps/arrays'), + milliseconds = require('deps/node-microseconds/lib/node-microseconds').milliseconds, querystring = require('querystring'); var Hummingbird = function(db, callback) { From 23b603fcee64fea27b4ec535cd368db13aa8f566 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 16:21:18 -0400 Subject: [PATCH 107/267] Refactor metrics to aggregate data in realtime with upserts rather than using mapreduce --- lib/hummingbird.js | 29 +++--------- lib/metric.js | 84 ++++++++++++++++++++++++----------- lib/metrics/all.js | 6 +-- lib/metrics/sales.js | 32 +++++++++++-- lib/weekly.js | 55 +++++++++-------------- public/js/weekly.js | 32 ++++++++----- spec/node.js | 6 ++- spec/unit/hummingbird_spec.js | 2 +- spec/unit/metric_spec.js | 15 ++++--- 9 files changed, 154 insertions(+), 107 deletions(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 5d26323..c66a610 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -3,9 +3,7 @@ var sys = require('sys'), View = require('view').View, Metric = require('metric').Metric, Aggregates = require('aggregates').Aggregates, - path = require('path'), arrays = require('deps/arrays'), - milliseconds = require('deps/node-microseconds/lib/node-microseconds').milliseconds, querystring = require('querystring'); var Hummingbird = function(db, callback) { @@ -34,25 +32,12 @@ Hummingbird.prototype = { }, addAllMetrics: function(db) { - var files = fs.readdirSync(path.join(__dirname, 'metrics')); - - for(var i = 0; i < files.length; i++) { - var file = files[i]; - var filename = file.replace(/\.js$/, ''); - - var m = require(path.join(__dirname, 'metrics', filename)); - - var metric = new Metric(m.name, - m.defaultData, - m.interval, - db, - m.addValueCallback); - this.metrics.push(metric); - } - }, + var self = this; - setCollection: function(collection) { - this.collection = collection; + Metric.allMetrics(function(metric) { + metric.init(db); + self.metrics.push(metric); + }); }, addClient: function(client) { @@ -79,10 +64,10 @@ Hummingbird.prototype = { env.url_key = view.urlKey(); env.product_id = view.productId(); - this.collection.insert(env); + this.collection.insertAll([env]); for(var i = 0; i < this.metrics.length; i++) { - this.metrics[i].addValue(view); + this.metrics[i].incrementCallback(view); } }, diff --git a/lib/metric.js b/lib/metric.js index 86cda6c..f80d897 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -1,32 +1,33 @@ -var sys = require('sys'); - -var Metric = function(name, initialData, interval, db, addHandler) { - if(!this instanceof Metric) { - return new Metric(name, initialData, interval, db, addHandler); - } - - this.name = name; - this.initialData = initialData; - this.interval = interval; +var sys = require('sys'), + path = require('path'), + fs = require('fs'); + +var Metric = function() { + this.name = null; + this.initialData = {}; + this.interval = 500; this.job = null; this.minuteJob = null; this.clients = []; - this.addHandler = addHandler; + this.incrementCallback = null; + this.aggregateCallback = null; this.resetMinuteData(); this.resetData(); - - var metric = this; - - db.createCollection('metrics', function(err, collection) { - db.collection('metrics', function(err, collection) { - metric.collection = collection; - metric.run(); - }); - }); } Metric.prototype = { + init: function(db) { + var metric = this; + + db.createCollection('metrics', function(err, collection) { + db.collection('metrics', function(err, collection) { + metric.collection = collection; + metric.run(); + }); + }); + }, + run: function() { this.job = setInterval(this.runner, this.interval, this); this.minuteJob = setInterval(this.minuteRunner, 60000, this); @@ -71,12 +72,20 @@ Metric.prototype = { sys.log(JSON.stringify(mongoData)); - metric.collection.insert(mongoData); - metric.resetMinuteData(); - }, + metric.collection.update({ minute: timestampMinute }, + { "$inc" : metric.minuteData }, + { upsert: true }, + function(err, result) {}); + metric.collection.update({ hour: timestampHour }, + { "$inc" : metric.minuteData }, + { upsert: true }, + function(err, result) {}); + metric.collection.update({ day: timestampDay }, + { "$inc" : metric.minuteData }, + { upsert: true }, + function(err, result) {}); - addValue: function(view) { - this.addHandler(view); + metric.resetMinuteData(); }, removeClient: function(client) { @@ -92,7 +101,7 @@ Metric.prototype = { }, resetMinuteData: function() { - this.minuteData = JSON.parse(JSON.stringify(this.initialData)); + this.minuteData = {}; }, stop: function() { @@ -100,4 +109,27 @@ Metric.prototype = { } }; +Metric.availableMetricPaths = function(callback) { + var files = fs.readdirSync(path.join(__dirname, 'metrics')); + + for(var i = 0; i < files.length; i++) { + var file = files[i]; + var filename = file.replace(/\.js$/, ''); + callback(path.join(__dirname, 'metrics', filename)); + } +}; + +Metric.allMetrics = function(callback) { + Metric.availableMetricPaths(function(metricPath) { + var m = require(metricPath); + + // Instantiate a new metric and use the settings from the custom metrics class + var metric = new Metric() + for(var key in m) { + metric[key] = m[key]; + } + callback(metric); + }); +}; + exports.Metric = Metric; \ No newline at end of file diff --git a/lib/metrics/all.js b/lib/metrics/all.js index a5e8108..5bd3cf9 100644 --- a/lib/metrics/all.js +++ b/lib/metrics/all.js @@ -1,10 +1,10 @@ var AllViewsMetric = { name: 'all_views', - defaultData: {total: 0, cartAdds: 0}, + initialData: {total: 0, cartAdds: 0}, interval: 50, // ms - addValueCallback: function(view) { + incrementCallback: function(view) { this.data.total += 1; - this.minuteData.total += 1; + this.minuteData.total = (this.minuteData.total || 0) + 1; if(view.event() && view.event() === "cart_add") { this.data.cartAdds += 1; diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js index 6109706..7c5e17b 100644 --- a/lib/metrics/sales.js +++ b/lib/metrics/sales.js @@ -1,13 +1,39 @@ var SalesMetric = { + name: 'sales', - defaultData: {sales: {}}, + + initialData: { sales: {} }, + interval: 500, // ms - addValueCallback: function(view) { + + incrementCallback: function(view) { if(view.urlKey()) { this.data.sales[view.urlKey()] = (this.data.sales[view.urlKey()] || 0) + 1; - this.minuteData.sales[view.urlKey()] = (this.minuteData.sales[view.urlKey()] || 0) + 1; + this.minuteData["sales."+view.urlKey()] = (this.minuteData["sales."+view.urlKey()] || 0) + 1; } + }, + + aggregateCallback: function(item) { + item.tmpSales = item.sales; + item.sales = []; + for(sale in item.tmpSales) { + if(item.tmpSales[sale] > 10) { + item.sales.push({ url_key: sale, + views: item.tmpSales[sale] }); + } + } + delete item.tmpSales; + + // Sort by sale numbers descending + item.sales = item.sales.sort(function(a, b) { + if(a.views == b.views) { + return 0; + } else if(a.views > b.views) { + return -1; + } else { return 1; } + }); } + }; for (var i in SalesMetric) diff --git a/lib/weekly.js b/lib/weekly.js index 54b644b..8350a3a 100644 --- a/lib/weekly.js +++ b/lib/weekly.js @@ -1,4 +1,5 @@ var sys = require('sys'), + Metric = require('metric').Metric, TimeBucketers = require('aggregates').TimeBucketers; var Weekly = {}; @@ -17,47 +18,35 @@ Weekly.reducer = function(obj, prev) { Weekly.findByDay = function(db, callback) { db.collection('metrics', function(err, collection) { + if(err) { + sys.log(JSON.stringify(err, null, 2)); + } + var today = TimeBucketers.closestDayFor((new Date()).getTime()); var _oneDay = 1000 * 60 * 60 * 24; - var result = collection.group(['day'], - { day: { $gte: new Date(today - _oneDay * 7) } }, - { total: 0, cartAdds: 0, sales: null}, - Weekly.reducer.toString(), - function(err, items) { - if(err) { - sys.log(JSON.stringify(err, null, 2)); - } + var result = collection.find({ day: { $gte: new Date(today - _oneDay * 7) } }, { sort: [['day', 'ascending']] }, function(err, cursor) { - items = items.sort(function(a, b) { - if(a.day > b.day) { return -1; } else { return 1; } - }); - - // Turn the sales hash into an array, for sorting - items.each(function(item) { - item.tmpSales = item.sales; - item.sales = []; - for(sale in item.tmpSales) { - if(item.tmpSales[sale] > 10) { - item.sales.push({ url_key: sale, - views: item.tmpSales[sale] }); - } + cursor.toArray(function(err, items) { + if(err) { + sys.log(JSON.stringify(err, null, 2)); } - delete item.tmpSales; - item.day = item.day.getTime(); + // Turn the sales hash into an array, for sorting + for(var i = 0; i < items.length; i++) { + var item = items[i]; - // Sort by sale numbers descending - item.sales = item.sales.sort(function(a, b) { - if(a.views == b.views) { - return 0; - } else if(a.views > b.views) { - return -1; - } else { return 1; } - }); - }); + item.day = item.day.getTime(); + delete item._id; - callback(JSON.stringify(items, null, 2)) + Metric.allMetrics(function(metric) { + if(metric.aggregateCallback) { metric.aggregateCallback(item); } + }); + + } + + callback(JSON.stringify(items, null, 2)) + }); }); }); }; diff --git a/public/js/weekly.js b/public/js/weekly.js index e303634..dde3ab4 100644 --- a/public/js/weekly.js +++ b/public/js/weekly.js @@ -34,20 +34,28 @@ Hummingbird.Weekly.init = function() { var dateDiv = dayTemplate.clone().attr('id', 'date_' + day.getTime()).attr('style', ''); dateDiv.find('div.date_title').text(weekDay); - dateDiv.find('div.all_views').text(this.total.commify()).data('total', this.total); - dateDiv.find('div.cart_adds').text(this.cartAdds.commify()).data('cart_adds', this.cartAdds);; + if(this.total) { + dateDiv.find('div.all_views').text(this.total.commify()).data('total', this.total); + } + + if(this.cartAdds) { + dateDiv.find('div.cart_adds').text(this.cartAdds.commify()).data('cart_adds', this.cartAdds); + } - $.each(this.sales.slice(0, 4), function() { - var saleDiv = saleTemplate.clone().attr('id', '').attr('style', ''); - var sale = sales[this.url_key]; + if(this.sales) { + $.each(this.sales.slice(0, 4), function() { + var saleDiv = saleTemplate.clone().attr('id', '').attr('style', ''); + var sale = sales[this.url_key]; + + if (sale) { + saleDiv.prepend(""); + saleDiv.find('div.sale_title').text(sale.name); + saleDiv.find('div.sale_views').text(this.views); + dateDiv.find('div.sales').append(saleDiv); + } + }); + } - if (sale) { - saleDiv.prepend(""); - saleDiv.find('div.sale_title').text(sale.name); - saleDiv.find('div.sale_views').text(this.views); - dateDiv.find('div.sales').append(saleDiv); - } - }); dateDiv.find('div.sales').append("
"); dateDiv.appendTo('#days'); diff --git a/spec/node.js b/spec/node.js index bb7d352..70ed4bd 100644 --- a/spec/node.js +++ b/spec/node.js @@ -46,8 +46,10 @@ MockCollection = function() { } MockCollection.prototype = { - insert: function(data) { - this.inserts.push(data) + insertAll: function(docs) { + for(var i = 0; i < docs.length; i++) { + this.inserts.push(docs[i]) + } } } diff --git a/spec/unit/hummingbird_spec.js b/spec/unit/hummingbird_spec.js index 9561853..b4e3d73 100644 --- a/spec/unit/hummingbird_spec.js +++ b/spec/unit/hummingbird_spec.js @@ -42,7 +42,7 @@ describe 'Hummingbird' var req = new MockRequest("http://localhost/t.gif?u=foobar") var res = new MockResponse() var collection = new MockCollection() - hummingbird.setCollection(collection) + hummingbird.collection = collection hummingbird.serveRequest(req, res) diff --git a/spec/unit/metric_spec.js b/spec/unit/metric_spec.js index 735ab6c..80780f0 100644 --- a/spec/unit/metric_spec.js +++ b/spec/unit/metric_spec.js @@ -1,11 +1,16 @@ describe 'Metric' describe '.addValue' - it 'calls the passed "addHandler" function' - var metric = new m.Metric('test', {foo: 0}, 100, db, function(view) { + it 'calls the passed "incrementCallback" function' + var metric = new m.Metric(); + metric.name = 'test'; + metric.initialData = {foo: 0}; + metric.interval = 100; + metric.db = db; + metric.incrementCallback = function(view) { this.data.foo = view; - }); + }; var view = 5; - metric.addValue(view); + metric.incrementCallback(view); metric.data.foo.should.equal 5 end @@ -17,7 +22,7 @@ describe 'Metric' this.data.foo = view; metric.insertData(); }); - + // metric.addValue(5); // TODO end From 1489ea193c14ba4e91f5b10e5bf21c753a0c451f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 16:22:26 -0400 Subject: [PATCH 108/267] ignore backups dir; don't use private dir anymore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8afe420..bf9a613 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -/private/* -!/private/.gitkeep +/backups From 2d83b17bf24c45aaa06e096d42c1d4d7480f8c3e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 16:24:18 -0400 Subject: [PATCH 109/267] Capistrano deploy scripts --- .gitignore | 1 + Capfile | 4 +++ config/app.json.sample | 8 +++++ config/deploy.rb | 69 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 Capfile create mode 100644 config/app.json.sample create mode 100644 config/deploy.rb diff --git a/.gitignore b/.gitignore index bf9a613..337756b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /backups +/config/app.json diff --git a/Capfile b/Capfile new file mode 100644 index 0000000..1a98f3c --- /dev/null +++ b/Capfile @@ -0,0 +1,4 @@ +load 'deploy' if respond_to?(:namespace) # cap2 differentiator +Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } + +load 'config/deploy' # remove this line to skip loading any of the default tasks diff --git a/config/app.json.sample b/config/app.json.sample new file mode 100644 index 0000000..c99053e --- /dev/null +++ b/config/app.json.sample @@ -0,0 +1,8 @@ +{ + "name" : "Hummingbird", + + "capistrano" : { + "repository" : "git://github.com/mnutt/hummingbird.git", + "hummingbird_host" : "hummingbird.your-host.com" + } +} diff --git a/config/deploy.rb b/config/deploy.rb new file mode 100644 index 0000000..6784ae9 --- /dev/null +++ b/config/deploy.rb @@ -0,0 +1,69 @@ +require 'json' + +settings = JSON.parse File.read(File.join(File.dirname(__FILE__), 'app.json')) + +set :application, "hummingbird" +set :scm, :git + +set :repository, settings['capistrano']['repository'] + +set :hummingbird_host, settings['capistrano']['hummingbird_host'] + +role :web, hummingbird_host +role :app, hummingbird_host +role :db, hummingbird_host + +depend :remote, :command, 'git' + +set :git_enable_submodules, 1 +set :deploy_to, "/var/www/#{application}" + +default_run_options[:pty] = true + +namespace :deploy do + task :restart, :roles => :app, :except => { :no_release => true } do + run "#{try_sudo} restart hummingbird" + run "#{try_sudo} restart hummingbird_monitor" + end + + task :pull_express_submodules, :roles => :app do + run "cd #{latest_release}/deps/express && git submodule update --init" + end +end + +desc 'Tail the production log' +task :tail, :roles => :app do + run "tail -100f #{shared_path}/log/hummingbird.log" +end + +desc 'Tail nginx error log' +task :tail_error, :roles => :app do + sudo "tail -100f /var/log/nginx/error.log" +end + +namespace :update do + desc 'Creates symlinks for shared resources' + task :symlink_shared do + symlinks = { 'log' => 'log' } + symlinks.each do |shared, current| + run "rm -rf #{latest_release}/#{current}" + run "ln -s #{shared_path}/#{shared} #{latest_release}/#{current}" + end + end +end + +desc "Backup the remote production database" +task :backup, :roles => :db do + filename = "#{application}.dump.#{Time.now.to_s.gsub(/[^0-9\-]/, '')}.bson" + file = "/tmp/hummingbird/metrics.bson" + on_rollback { run "rm #{file}" } + run "echo $PATH; mongodump -d hummingbird -c metrics -o /tmp" do |ch, stream, data| + puts data + end + `mkdir -p #{File.dirname(__FILE__)}/../backups/` + get file, "backups/#{filename}" + run "rm #{file}" +end + +after 'deploy:update_code', 'update:symlink_shared' +after 'deploy:update_code', 'deploy:pull_express_submodules' From d9e61c26d6b065d57af31bc1fe4a58ae2d1e4e8f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 17:09:54 -0400 Subject: [PATCH 110/267] Make websocket server configurable via url. Make server name configurable via app config file --- README.md | 12 ++++-------- config/app.json.sample | 1 + monitor.js | 12 +++++++++++- public/js/websocket.js | 9 +++++---- public/js/weekly.js | 4 +++- views/index.html.ejs | 2 +- views/layout.html.ejs | 2 +- views/weekly.html.ejs | 2 +- 8 files changed, 27 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index e6994ed..9fbf564 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ Installation # Initialize the express submodules cd deps/express; git submodule update --init; cd ../.. + # Copy the default configuration file + cp config/app.json.sample config/app.json + Running Hummingbird ------------------------------ @@ -52,11 +55,4 @@ Specs Tips ----- - * To run the UI locally but get some production data, use the url http://localhost:8088/?use_prod - - -Known Issues -------------------- - - * node-paperboy has issues with returning 304's that cause some weirdness in some browsers. Try shift-reload until it's fixed. - + * To run the UI locally but stream data from your production server, use the url http://localhost:8088/?ws_server=your-host.com&ws_port=12345 diff --git a/config/app.json.sample b/config/app.json.sample index c99053e..fc5f72d 100644 --- a/config/app.json.sample +++ b/config/app.json.sample @@ -1,5 +1,6 @@ { "name" : "Hummingbird", + "monitor_port" : 8888, "capistrano" : { "repository" : "git://github.com/mnutt/hummingbird.git", diff --git a/monitor.js b/monitor.js index 3654d50..59b7100 100644 --- a/monitor.js +++ b/monitor.js @@ -3,6 +3,7 @@ require.paths.unshift(__dirname); require.paths.unshift(__dirname + '/deps/express/lib') var sys = require('sys'), + fs = require('fs'), mongo = require('deps/node-mongodb-native/lib/mongodb'), svc = require('service_json'), weekly = require('weekly'); @@ -18,7 +19,16 @@ db.open(function(p_db) { set('pagegen_uri', "http://www.gilt.com/pagegen_service/sale/sale_list"); set('db', db); use(Static); - this.server.port = 8888; + + try { + var configJSON = fs.readFileSync(__dirname + "/config/app.json"); + } catch(e) { + sys.log("File config/app.json not found. Try: `cp config/app.json.sample config/app.json`"); + } + var config = JSON.parse(configJSON); + + this.server.port = config.monitor_port; + set('name', config.name); }); get('/', function(){ diff --git a/public/js/websocket.js b/public/js/websocket.js index 917b772..eab569d 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -4,7 +4,7 @@ Hummingbird.WebSocket = {}; Hummingbird.WebSocket.state = "stopped"; Hummingbird.WebSocket.start = function() { if(!("WebSocket" in window)) { - console.log("Sorry, the build of your browser does not support WebSockets. Please use latest Chrome or Webkit nightly"); + console.log("Sorry, the build of your browser does not support WebSockets. Please try latest Chrome or Webkit nightly"); return; } @@ -16,8 +16,10 @@ Hummingbird.WebSocket.start = function() { cartAdds.find('canvas').get(0).width = $(window).width() - 160; var cartAddsGraph = new Hummingbird.Graph(cartAdds, { ratePerSecond: 20 }); - if(document.location.search.match(/use_prod/)) { - var wsServer = "ws://hummingbird.giltrunway.com:8080"; + if(document.location.search.match(/ws_server/)) { + var wsServerParam = document.location.search.match(/ws_server=([^\&\#]+)/) || []; + var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; + var wsServer = "ws://" + wsServerParam[1] + ":" + (wsPortParam[1] || 8080); } else { var wsServer = "ws://" + document.location.hostname + ":8080"; } @@ -57,6 +59,5 @@ Hummingbird.WebSocket.start = function() { ws.onopen = function() { Hummingbird.WebSocket.state = "started"; console.log("socket started"); - //alert("connected..."); }; }; \ No newline at end of file diff --git a/public/js/weekly.js b/public/js/weekly.js index dde3ab4..fdbd5b7 100644 --- a/public/js/weekly.js +++ b/public/js/weekly.js @@ -64,7 +64,9 @@ Hummingbird.Weekly.init = function() { }); if(document.location.search.match(/use_prod/)) { - var wsServer = "ws://hummingbird.giltrunway.com:8080"; + var wsServerParam = document.location.search.match(/ws_server=([^\&\#]+)/) || []; + var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; + var wsServer = "ws://" + wsServerParam[1] + ":" + (wsPortParam[1] || 8080); } else { var wsServer = "ws://" + document.location.hostname + ":8080"; } diff --git a/views/index.html.ejs b/views/index.html.ejs index d010a71..71d5743 100644 --- a/views/index.html.ejs +++ b/views/index.html.ejs @@ -1,4 +1,4 @@ -

Hummingbird

+

<%= set('name') %>

diff --git a/views/layout.html.ejs b/views/layout.html.ejs index 7cf797f..958ea0f 100644 --- a/views/layout.html.ejs +++ b/views/layout.html.ejs @@ -11,7 +11,7 @@ - Hummingbird + <%= set('name') %> diff --git a/views/weekly.html.ejs b/views/weekly.html.ejs index 108e260..478c1d9 100644 --- a/views/weekly.html.ejs +++ b/views/weekly.html.ejs @@ -1,4 +1,4 @@ -

Hummingbird

+

<%= set('name') %>

From dc11adfb9a909f783ec11cfbe5ff61f63af21836 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 18:34:06 -0400 Subject: [PATCH 111/267] Add license --- LICENSE.md | 24 ++++++++++++++++++++++++ README.md | 13 +++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..a5fe035 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,24 @@ +The MIT License +=============== + +Copyright (c) 2010 Michael Nutt and others. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/README.md b/README.md index 9fbf564..3e2be08 100644 --- a/README.md +++ b/README.md @@ -56,3 +56,16 @@ Tips ----- * To run the UI locally but stream data from your production server, use the url http://localhost:8088/?ws_server=your-host.com&ws_port=12345 + + +Contributors +------------ + + * Michael Nutt + * Benny Wong + + +License +------- + +Hummingbird is licensed under the MIT License. (See LICENSE) From 2f2451f5736198a9f8e059a847df8ff8c371aea6 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 18:38:34 -0400 Subject: [PATCH 112/267] Add ubuntu upstart scripts for reference --- config/ubuntu/upstart/hummingbird.conf | 15 +++++++++++++++ config/ubuntu/upstart/hummingbird_monitor.conf | 14 ++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 config/ubuntu/upstart/hummingbird.conf create mode 100644 config/ubuntu/upstart/hummingbird_monitor.conf diff --git a/config/ubuntu/upstart/hummingbird.conf b/config/ubuntu/upstart/hummingbird.conf new file mode 100644 index 0000000..41dd757 --- /dev/null +++ b/config/ubuntu/upstart/hummingbird.conf @@ -0,0 +1,15 @@ +description "hummingbird node.js server" +author "Michael Nutt" + +start on startup +stop on shutdown + +script + # We found $HOME is needed. Without it, we ran into problems + export HOME="/home/web" + + cd /var/www/hummingbird/current + exec sudo -u web /usr/local/bin/node /var/www/hummingbird/current/server.js >> /var/www/hummingbird/current/log/hummingbird.log 2>&1 +end script +respawn + diff --git a/config/ubuntu/upstart/hummingbird_monitor.conf b/config/ubuntu/upstart/hummingbird_monitor.conf new file mode 100644 index 0000000..7e02210 --- /dev/null +++ b/config/ubuntu/upstart/hummingbird_monitor.conf @@ -0,0 +1,14 @@ +description "hummingbird node.js monitor" +author "Michael Nutt" + +start on startup +stop on shutdown + +script + # We found $HOME is needed. Without it, we ran into problems + export HOME="/home/web" + + cd /var/www/hummingbird/current + exec sudo -u web /usr/local/bin/node /var/www/hummingbird/current/monitor.js >> /var/www/hummingbird/current/log/hummingbird_monitor.log 2>&1 +end script +respawn From 10ab998fa2b6cac6bebb1e943c2ce36fda21378d Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 20:48:07 -0400 Subject: [PATCH 113/267] Upgrade node-mongodb-native to use buffers --- deps/node-mongodb-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/node-mongodb-native b/deps/node-mongodb-native index 5401a62..f019015 160000 --- a/deps/node-mongodb-native +++ b/deps/node-mongodb-native @@ -1 +1 @@ -Subproject commit 5401a62e7a139f9d0f379e46e6ad3107810f7c7c +Subproject commit f019015ea48fd90bc7fa006f507c1e92832cf599 From 1954115f107f0a46f6bbc19e5b0a981e7cb52183 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 9 May 2010 22:42:30 -0400 Subject: [PATCH 114/267] Use Buffer for serving tracking pixel --- lib/hummingbird.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index c66a610..18eb856 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -3,11 +3,15 @@ var sys = require('sys'), View = require('view').View, Metric = require('metric').Metric, Aggregates = require('aggregates').Aggregates, + Buffer = require('buffer').Buffer, arrays = require('deps/arrays'), querystring = require('querystring'); var Hummingbird = function(db, callback) { - this.pixel = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); + var pixelData = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); + this.pixel = new Buffer(43); + this.pixel.write(pixelData, 'binary', 0); + this.metrics = []; this.init(db, callback); }; @@ -75,8 +79,7 @@ Hummingbird.prototype = { res.writeHead(200, { 'Content-Type': 'image/gif', 'Content-Disposition': 'inline', 'Content-Length': '43' }); - res.write(this.pixel, 'binary'); - res.close(); + res.end(this.pixel); }, serveAggregates: function(client) { From aebbd5349e3fd5cf507d95f07755538dbf43ed2c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 10 May 2010 10:38:17 -0400 Subject: [PATCH 115/267] Fix cartAdds metric --- lib/metrics/all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metrics/all.js b/lib/metrics/all.js index 5bd3cf9..c103fa8 100644 --- a/lib/metrics/all.js +++ b/lib/metrics/all.js @@ -8,7 +8,7 @@ var AllViewsMetric = { if(view.event() && view.event() === "cart_add") { this.data.cartAdds += 1; - this.minuteData.cartAdds += 1; + this.minuteData.cartAdds = (this.minuteData.total || 0) + 1; } } }; From 56ed46525bfa165fa1bca754af860edb94aacbf2 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 10 May 2010 11:15:53 -0400 Subject: [PATCH 116/267] Typo in cartAdds --- lib/metrics/all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metrics/all.js b/lib/metrics/all.js index c103fa8..4f5ca4c 100644 --- a/lib/metrics/all.js +++ b/lib/metrics/all.js @@ -8,7 +8,7 @@ var AllViewsMetric = { if(view.event() && view.event() === "cart_add") { this.data.cartAdds += 1; - this.minuteData.cartAdds = (this.minuteData.total || 0) + 1; + this.minuteData.cartAdds = (this.minuteData.cartAdds || 0) + 1; } } }; From 751a7cb649e151287732745f0e10ebcdd38e87fb Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Mon, 10 May 2010 07:02:20 +0000 Subject: [PATCH 117/267] Adding regex for City url_keys --- lib/view.js | 2 +- spec/unit/view_spec.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/view.js b/lib/view.js index cc2bd0a..fe4064a 100644 --- a/lib/view.js +++ b/lib/view.js @@ -39,6 +39,6 @@ View.prototype = { } }; -View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/)([^\/\?\#]+)\/?(product\/)?(\d+)?/); +View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/|\/city\/offers?\/)([^\/\?\#]+)\/?(product\/)?(\d+)?/); exports.View = View; diff --git a/spec/unit/view_spec.js b/spec/unit/view_spec.js index 7c505bc..1a0ebc2 100644 --- a/spec/unit/view_spec.js +++ b/spec/unit/view_spec.js @@ -7,6 +7,12 @@ describe 'View' view.urlKey().should.equal "gucci" end + it 'extracts a url_key from a city offer url' + var env = { u: "http://newyork.gilt.com/city/offer/rougetomate" } + var view = new v.View(env) + view.urlKey().should.equal "rougetomate" + end + it 'extracts a url_key from a product url' var env = { u: "http://localhost/s/gucci/product/12345" } @@ -36,6 +42,12 @@ describe 'View' var view = new v.View(env) view.productId().should.equal 12345 end + + it 'should not extract a productId from a city offer url' + var env = { u: "http://newyork.gilt.com/city/offer/rougetomate" } + var view = new v.View(env) + isNaN(view.productId()).should.be_true + end end describe '.event()' From 1aa6e99286f4a905ceb03464b379915112a3f722 Mon Sep 17 00:00:00 2001 From: Benny Wong Date: Tue, 11 May 2010 03:07:33 +0000 Subject: [PATCH 118/267] Refactor Hummingbird.WebSocket to be inheritable * Two Hummingbird.WebSocket classes: Main and Weekly * Reuse connection retrying * Reuse WebSocket URI generator --- public/js/websocket.js | 132 ++++++++++++++++++++++++++++++++--------- public/js/weekly.js | 34 ----------- views/index.html.ejs | 4 +- views/weekly.html.ejs | 6 +- 4 files changed, 110 insertions(+), 66 deletions(-) diff --git a/public/js/websocket.js b/public/js/websocket.js index eab569d..a0ed678 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -1,12 +1,71 @@ if(!Hummingbird) { var Hummingbird = {}; } -Hummingbird.WebSocket = {}; -Hummingbird.WebSocket.state = "stopped"; -Hummingbird.WebSocket.start = function() { - if(!("WebSocket" in window)) { - console.log("Sorry, the build of your browser does not support WebSockets. Please try latest Chrome or Webkit nightly"); - return; +Hummingbird.WebSocket = function() { + this.state = "stopped"; +}; + +Hummingbird.WebSocket.prototype = { + // WebSocket callbacks + onclose: function() { + var self = this; + if(this.getState() == "retrying") { + // Wait a while to try restarting + console.log("still no socket, retrying in 3 seconds"); + setTimeout(function() { self.start() }, 3000); + } else { + // First attempt at restarting, try immediately + this.setState("retrying"); + console.log("socket lost, retrying immediately"); + setTimeout(function() { self.start() }, 200); + } + }, + + onopen: function() { + this.setState("started"); + console.log("socket started"); + }, + + // Hummingbird WebSocket functions + getState: function() { + return this.state; + }, + + setState: function(state) { + this.state = state; + }, + + start: function() { + console.log("start() not implemented"); + }, + + webSocketEnabled: function() { + if(!("WebSocket" in window)) { + console.log("Sorry, the build of your browser does not support WebSockets. Please try latest Chrome or Webkit nightly"); + return false; + } + return true; + }, + + webSocketURI: function() { + if(document.location.search.match(/ws_server/)) { + var wsServerParam = document.location.search.match(/ws_server=([^\&\#]+)/) || []; + var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; + var wsServer = "ws://" + wsServerParam[1] + ":" + (wsPortParam[1] || 8080); + } else { + var wsServer = "ws://" + document.location.hostname + ":8080"; + } + return wsServer; } +} + +// MAIN WEBSOCKET + +Hummingbird.WebSocket.Main = function() { } +Hummingbird.WebSocket.Main.prototype = new Hummingbird.WebSocket; + +Hummingbird.WebSocket.Main.prototype.start = function() { + if (!this.webSocketEnabled()) + return; var totalDiv = $("#log"); totalDiv.find('canvas').get(0).width = $(window).width() - 160; @@ -16,14 +75,11 @@ Hummingbird.WebSocket.start = function() { cartAdds.find('canvas').get(0).width = $(window).width() - 160; var cartAddsGraph = new Hummingbird.Graph(cartAdds, { ratePerSecond: 20 }); - if(document.location.search.match(/ws_server/)) { - var wsServerParam = document.location.search.match(/ws_server=([^\&\#]+)/) || []; - var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; - var wsServer = "ws://" + wsServerParam[1] + ":" + (wsPortParam[1] || 8080); - } else { - var wsServer = "ws://" + document.location.hostname + ":8080"; - } + var wsServer = this.webSocketURI(); var ws = new WebSocket(wsServer); + + var self = this; + ws.onmessage = function(evt) { var data = JSON.parse(evt.data); @@ -44,20 +100,40 @@ Hummingbird.WebSocket.start = function() { } } } - ws.onclose = function() { - if(Hummingbird.WebSocket.state == "retrying") { - // Wait a while to try restarting - console.log("still no socket, retrying in 3 seconds"); - setTimeout(Hummingbird.WebSocket.start, 3000); - } else { - // First attempt at restarting, try immediately - Hummingbird.WebSocket.state = "retrying"; - console.log("socket lost, retrying immediately"); - setTimeout(Hummingbird.WebSocket.start, 200); + + ws.onclose = function() { self.onclose(); } + ws.onopen = function() { self.onopen(); } +} + +// WEEKLY WEBSOCKET + +Hummingbird.WebSocket.Weekly = function() { } +Hummingbird.WebSocket.Weekly.prototype = new Hummingbird.WebSocket; + +Hummingbird.WebSocket.Weekly.prototype.start = function() { + if (!this.webSocketEnabled()) + return; + + var wsServer = this.webSocketURI(); + var ws = new WebSocket(wsServer); + + var self = this; + + ws.onmessage = function(evt) { + var data = JSON.parse(evt.data); + if(data.total && data.total > 0) { + var el = $("div.day:first-child div.all_views"); + var prevTotal = el.data("total"); + el.text((prevTotal + data.total).commify()).data('total', prevTotal + data.total); + } + if(data.cartAdds && data.cartAdds > 0) { + var el = $("div.day:first-child div.cart_adds"); + var prevCartAdds = el.data("cart_adds"); + el.text((prevCartAdds + data.cartAdds).commify()).data('cart_adds', prevCartAdds + data.cartAdds); } }; - ws.onopen = function() { - Hummingbird.WebSocket.state = "started"; - console.log("socket started"); - }; -}; \ No newline at end of file + + ws.onclose = function() { self.onclose(); } + ws.onopen = function() { self.onopen(); } +} + diff --git a/public/js/weekly.js b/public/js/weekly.js index fdbd5b7..4471a52 100644 --- a/public/js/weekly.js +++ b/public/js/weekly.js @@ -62,39 +62,5 @@ Hummingbird.Weekly.init = function() { }); }); }); - - if(document.location.search.match(/use_prod/)) { - var wsServerParam = document.location.search.match(/ws_server=([^\&\#]+)/) || []; - var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; - var wsServer = "ws://" + wsServerParam[1] + ":" + (wsPortParam[1] || 8080); - } else { - var wsServer = "ws://" + document.location.hostname + ":8080"; - } - var ws = new WebSocket(wsServer); - ws.onmessage = function(evt) { - var data = JSON.parse(evt.data); - if(data.total && data.total > 0) { - var el = $("div.day:first-child div.all_views"); - var prevTotal = el.data("total"); - el.text((prevTotal + data.total).commify()).data('total', prevTotal + data.total); - } - if(data.cartAdds && data.cartAdds > 0) { - var el = $("div.day:first-child div.cart_adds"); - var prevCartAdds = el.data("cart_adds"); - el.text((prevCartAdds + data.cartAdds).commify()).data('cart_adds', prevCartAdds + data.cartAdds); - } - }; - ws.onclose = function() { - if(Hummingbird.WebSocket.state == "retrying") { - // Wait a while to try restarting - console.log("still no socket, retrying in 3 seconds"); - setTimeout(Hummingbird.WebSocket.start, 3000); - } else { - // First attempt at restarting, try immediately - Hummingbird.WebSocket.state = "retrying"; - console.log("socket lost, retrying immediately"); - setTimeout(Hummingbird.WebSocket.start, 200); - } - }; }; diff --git a/views/index.html.ejs b/views/index.html.ejs index 71d5743..e3253c8 100644 --- a/views/index.html.ejs +++ b/views/index.html.ejs @@ -30,7 +30,9 @@ + + + + + + + + + <%= app.set('name') %> + + + + + + + <%- body %> + + diff --git a/views/layout.html.ejs b/views/layout.html.ejs deleted file mode 100644 index 958ea0f..0000000 --- a/views/layout.html.ejs +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - <%= set('name') %> - - - - - - - <%= body %> - - diff --git a/views/login.html.ejs b/views/login.ejs similarity index 100% rename from views/login.html.ejs rename to views/login.ejs diff --git a/views/weekly.html.ejs b/views/weekly.ejs similarity index 95% rename from views/weekly.html.ejs rename to views/weekly.ejs index 26a169a..f63d2f2 100644 --- a/views/weekly.html.ejs +++ b/views/weekly.ejs @@ -1,4 +1,4 @@ -

<%= set('name') %>

+

<%= app.set('name') %>

From 4e5ec12e3177c24657155260dae3f8e3a9f63f11 Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Mon, 30 Aug 2010 09:27:14 +0200 Subject: [PATCH 146/267] updated express plugin. --- deps/express | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/express b/deps/express index 6e25e18..02bcef7 160000 --- a/deps/express +++ b/deps/express @@ -1 +1 @@ -Subproject commit 6e25e18e98e98a845e26114a9da1fa68f942ca42 +Subproject commit 02bcef71dd9132e66795c2ba73d71fc35c24b0cd From 12b7316c4d5af72fb57956af788b5d712ffe918f Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Mon, 30 Aug 2010 10:43:46 +0200 Subject: [PATCH 147/267] added an id to the page views canvas. graph works but looks horrible. --- public/js/aggregates.js | 2 +- public/js/analytics.js | 5 +++-- views/index.ejs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/public/js/aggregates.js b/public/js/aggregates.js index e894d2d..3ab574d 100644 --- a/public/js/aggregates.js +++ b/public/js/aggregates.js @@ -9,7 +9,7 @@ Hummingbird.Aggregates.start = function() { } var lastHourDiv = $("#pageviews_last_hour"); - lastHourDiv.find('canvas').get(0).width = $(window).width() - 160; + lastHourDiv.find('page_views_canvas').width = $(window).width() - 160; var lastHourGraph = new Hummingbird.Graph(lastHourDiv, { ratePerSecond: 20, logDate: true }); var wsServer = "ws://" + document.location.hostname + ":8080/aggregates"; diff --git a/public/js/analytics.js b/public/js/analytics.js index 03b7dbd..70e134b 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -104,8 +104,9 @@ Hummingbird.Graph.prototype = { }, setupContext: function() { - if(this.canvas.getContext) { - this.context = this.canvas.getContext('2d'); + var canvas = document.getElementById('page_views_canvas') + if(canvas.getContext) { + this.context = canvas.getContext('2d'); } else { alert("Sorry, this browser doesn't support canvas"); } diff --git a/views/index.ejs b/views/index.ejs index 7c2c593..51b430d 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -5,7 +5,7 @@

Pageviews / Second

- +
From 330aa8c01588b42b424adb423378ee77513aa47c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 3 Sep 2010 01:11:34 -0400 Subject: [PATCH 148/267] Fix things to work with newest version of express --- deps/express | 2 +- monitor.js | 8 +++++--- public/css/main.css | 6 +++--- views/layout.ejs | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/deps/express b/deps/express index 02bcef7..20fae6e 160000 --- a/deps/express +++ b/deps/express @@ -1 +1 @@ -Subproject commit 02bcef71dd9132e66795c2ba73d71fc35c24b0cd +Subproject commit 20fae6e5122853164fa993da0ead7ad552dac0cb diff --git a/monitor.js b/monitor.js index 4919fa9..1ef3f06 100644 --- a/monitor.js +++ b/monitor.js @@ -1,11 +1,13 @@ require.paths.unshift(__dirname + '/lib'); require.paths.unshift(__dirname); -require.paths.unshift(__dirname + '/deps/express/lib') -require.paths.unshift(__dirname + '/deps/express/support') +require.paths.unshift(__dirname + '/deps'); +require.paths.unshift(__dirname + '/deps/express/support'); +require.paths.unshift(__dirname + '/deps/express/support/connect/lib'); +require.paths.unshift(__dirname + '/deps/node-mongodb-native/lib'); var sys = require('sys'), fs = require('fs'), - mongo = require('deps/node-mongodb-native/lib/mongodb'), + mongo = require('mongodb'), svc = require('service_json'), weekly = require('weekly'); diff --git a/public/css/main.css b/public/css/main.css index 8719f68..a2054de 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -112,7 +112,7 @@ div.hummingbird_graph div.axis_right { #login div.logo { - background: url(/public/images/logo.png) top left no-repeat; + background: url(/images/logo.png) top left no-repeat; width: 300px; height: 324px; margin: auto; @@ -158,6 +158,6 @@ div.hummingbird_graph div.axis_right { @font-face { font-family: 'TitilliumText14L800wt'; - src: url('/public/fonts/TitilliumText800wt.eot'); - src: local('TitilliumText14L'), local('TitilliumText14L-800wt'), url('/public/fonts/TitilliumText800wt.woff') format('woff'), url('/public/fonts/TitilliumText800wt.ttf') format('truetype'), url('/public/fonts/TitilliumText800wt.svg#TitilliumText14L-800wt') format('svg'); + src: url('/fonts/TitilliumText800wt.eot'); + src: local('TitilliumText14L'), local('TitilliumText14L-800wt'), url('/fonts/TitilliumText800wt.woff') format('woff'), url('/fonts/TitilliumText800wt.ttf') format('truetype'), url('/fonts/TitilliumText800wt.svg#TitilliumText14L-800wt') format('svg'); } diff --git a/views/layout.ejs b/views/layout.ejs index 97345dd..1aec1f9 100644 --- a/views/layout.ejs +++ b/views/layout.ejs @@ -14,8 +14,8 @@ <%= app.set('name') %> - - + + From a1edfb3558d88bf979810b6994cfecef3be2b1b8 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 7 Sep 2010 01:35:55 -0400 Subject: [PATCH 149/267] Upgrade server component to use latest versions; switch to socket.io for graceful degradation. Remove old cartAdds and sales. --- .gitmodules | 6 ++++ README.md | 6 ++-- config/app.json.sample | 1 - deps/node-socket.io | 1 + lib/hummingbird.js | 27 ++-------------- lib/metric.js | 2 +- monitor.js | 6 ++-- public/js/aggregates.js | 51 ----------------------------- public/js/analytics.js | 9 ++++-- public/js/websocket.js | 71 ++++++++++++++++------------------------- public/js/weekly.js | 29 ----------------- public/socket.io | 1 + server.js | 27 ++++++++++++---- views/index.ejs | 23 ++++--------- views/layout.ejs | 8 +++-- views/weekly.ejs | 15 --------- 16 files changed, 83 insertions(+), 200 deletions(-) create mode 160000 deps/node-socket.io delete mode 100644 public/js/aggregates.js create mode 160000 public/socket.io diff --git a/.gitmodules b/.gitmodules index d44d052..fdc4f6c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,9 @@ [submodule "deps/node-websocket-server"] path = deps/node-websocket-server url = http://github.com/mnutt/node-websocket-server.git +[submodule "deps/node-socket.io"] + path = deps/node-socket.io + url = http://github.com/LearnBoost/Socket.IO-node.git +[submodule "public/socket.io"] + path = public/socket.io + url = http://github.com/LearnBoost/Socket.IO.git diff --git a/README.md b/README.md index 734d3bd..6ca13a4 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,11 @@ Installation cd hummingbird # Update submodules - git submodule update --init - # If you are running an older version of git, you may have to run the following instead: + git submodule update --init --recursive + # If you are running a *really* old version of git, you may have to run the following instead: # git submodule init . && git submodule update . - # Initialize the express submodules + # If your version of git does not have the --recursive flag, initialize the express submodules cd deps/express; git submodule update --init; cd ../.. # build the native mongo db driver diff --git a/config/app.json.sample b/config/app.json.sample index 29e1cec..e77d1ce 100644 --- a/config/app.json.sample +++ b/config/app.json.sample @@ -3,7 +3,6 @@ "monitor_port" : 8888, "tracking_port" : 8000, - "websocket_port" : 8080, "username" : "admin", "password" : "change_this", diff --git a/deps/node-socket.io b/deps/node-socket.io new file mode 160000 index 0000000..84ee2d8 --- /dev/null +++ b/deps/node-socket.io @@ -0,0 +1 @@ +Subproject commit 84ee2d87882f53bcd6683b24729f786725687faf diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 7009210..0b98810 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -4,7 +4,7 @@ var sys = require('sys'), Metric = require('metric').Metric, Aggregates = require('aggregates').Aggregates, Buffer = require('buffer').Buffer, - ws = require('deps/node-websocket-server/lib/ws'), + io = require('deps/node-socket.io'), arrays = require('deps/arrays'), querystring = require('querystring'); @@ -28,10 +28,6 @@ Hummingbird.prototype = { this.setupDb(db, function() { callback(); }); - - this.setupWebSocket(); - - this.addAllMetrics(db); }, setupDb: function(db, callback) { @@ -44,29 +40,12 @@ Hummingbird.prototype = { }); }, - setupWebSocket: function() { - // Websocket TCP server - var wsServer = ws.createServer({log: false}); - wsServer.listen(config.websocket_port); - - wsServer.addListener("connection", function (conn) { - sys.log("ws connect: " + conn._id); - conn.addListener("close", function () { - sys.log("ws close: " + conn._id); - }); - }); - - this.wsServer = wsServer; - - sys.puts('Web Socket server running at ws://*:' + config.websocket_port); - }, - - addAllMetrics: function(db) { + addAllMetrics: function(socket, db) { var self = this; Metric.allMetrics(function(metric) { metric.init(db); - metric.wsServer = self.wsServer; + metric.socket = socket; self.metrics.push(metric); }); }, diff --git a/lib/metric.js b/lib/metric.js index ffdf239..a50474c 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -37,7 +37,7 @@ Metric.prototype = { runner: function(metric) { // NOTE: using 'metric' in place of 'this', since run from setInterval - metric.wsServer.broadcast(JSON.stringify(metric.data)); + metric.socket.broadcast(JSON.stringify(metric.data)); metric.resetData(); }, diff --git a/monitor.js b/monitor.js index 1ef3f06..16987f3 100644 --- a/monitor.js +++ b/monitor.js @@ -9,13 +9,11 @@ var sys = require('sys'), fs = require('fs'), mongo = require('mongodb'), svc = require('service_json'), - weekly = require('weekly'); + weekly = require('weekly'), + express = require('express'); -var express = require('express'); app = express.createServer(); -//require('express/plugins'); - db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); db.open(function(p_db) { diff --git a/public/js/aggregates.js b/public/js/aggregates.js deleted file mode 100644 index 3ab574d..0000000 --- a/public/js/aggregates.js +++ /dev/null @@ -1,51 +0,0 @@ -if(!Hummingbird) { var Hummingbird = {}; } - -Hummingbird.Aggregates = {}; -Hummingbird.Aggregates.state = "stopped"; -Hummingbird.Aggregates.start = function() { - if(!("WebSocket" in window)) { - console.log("Sorry, the build of your browser does not support WebSockets. Please use latest Chrome or Webkit nightly"); - return; - } - - var lastHourDiv = $("#pageviews_last_hour"); - lastHourDiv.find('page_views_canvas').width = $(window).width() - 160; - var lastHourGraph = new Hummingbird.Graph(lastHourDiv, { ratePerSecond: 20, logDate: true }); - - var wsServer = "ws://" + document.location.hostname + ":8080/aggregates"; - var ws = new WebSocket(wsServer); - - ws.onmessage = function(evt) { - var data = JSON.parse(evt.data); - - if (typeof(data.metric) != "undefined") { - var values = data.values; - $.each(values, function(idx, visit) { - lastHourGraph.drawLogPath(visit); - lastHourGraph.drawLogPath(visit); - lastHourGraph.drawLogPath(visit); - }); - } - } - ws.onclose = function() { - if(Hummingbird.Aggregates.state == "retrying") { - // Wait a while to try restarting - console.log("still no socket, retrying in 3 seconds"); - setTimeout(Hummingbird.Aggregates.start, 3000); - } else { - // First attempt at restarting, try immediately - Hummingbird.Aggregates.state = "retrying"; - console.log("socket lost, retrying immediately"); - setTimeout(Hummingbird.Aggregates.start, 200); - } - }; - ws.onopen = function() { - Hummingbird.Aggregates.state = "started"; - console.log("socket started"); - }; - Hummingbird.Aggregates.ws = ws; -}; - -$(document).ready(function(){ - Hummingbird.Aggregates.start(); -}); diff --git a/public/js/analytics.js b/public/js/analytics.js index 70e134b..531dcf1 100644 --- a/public/js/analytics.js +++ b/public/js/analytics.js @@ -100,7 +100,12 @@ Hummingbird.Graph.prototype = { }, shiftCanvas: function(x, y) { - this.context.putImageData(this.context.getImageData(x, y, this.canvas.width, this.canvas.height), 0, 0); + // Browser sniffing is bad, but each browser has different performance characteristics + if($.browser.mozilla) { + this.context.drawImage(this.context.canvas, -x, -y); + } else { + this.context.putImageData(this.context.getImageData(x, y, this.canvas.width - x, this.canvas.height - y), 0, 0); + } }, setupContext: function() { @@ -239,4 +244,4 @@ Hummingbird.Graph.prototype = { this.context.closePath(); } } -}; +}; \ No newline at end of file diff --git a/public/js/websocket.js b/public/js/websocket.js index 00382a7..ccafd28 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -50,11 +50,19 @@ Hummingbird.WebSocket.prototype = { if(document.location.search.match(/ws_server/)) { var wsServerParam = document.location.search.match(/ws_server=([^\&\#]+)/) || []; var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; - var wsServer = "ws://" + wsServerParam[1] + ":" + (wsPortParam[1] || 8080); + var wsServer = wsServerParam[1]; } else { - var wsServer = "ws://" + document.location.hostname + ":8080"; + var wsServer = document.location.hostname; } return wsServer; + }, + + webSocketPort: function() { + if(document.location.search.match(/ws_server/)) { + var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; + return wsPortParam; + } + return 8000; } } @@ -64,46 +72,26 @@ Hummingbird.WebSocket.Dashboard = function() { } Hummingbird.WebSocket.Dashboard.prototype = new Hummingbird.WebSocket; Hummingbird.WebSocket.Dashboard.prototype.start = function() { - if (!this.webSocketEnabled()) - return; + this.socket = new io.Socket(this.webSocketURI(), {port: this.webSocketPort()}); + this.socket.connect(); var totalDiv = $("#log"); totalDiv.find('canvas').get(0).width = $(window).width() - 160; var totalGraph = new Hummingbird.Graph(totalDiv, { ratePerSecond: 20, logDate: true }); - var cartAdds = $("#cart_adds");; - cartAdds.find('canvas').get(0).width = $(window).width() - 160; - var cartAddsGraph = new Hummingbird.Graph(cartAdds, { ratePerSecond: 20 }); - - var wsServer = this.webSocketURI(); - var ws = new WebSocket(wsServer); - var self = this; - ws.onmessage = function(evt) { - var data = JSON.parse(evt.data); - - if(typeof(data.sales) != "undefined") { - $.each(Hummingbird.saleGraphs, function(key) { - if(data.sales[key]) { - Hummingbird.saleGraphs[key].drawLogPath(data.sales[key]); - } else { - Hummingbird.saleGraphs[key].drawLogPath(0.0); - } - }); - } else if(typeof(data.total) != "undefined") { + this.socket.on('message', function(msg) { + var data = JSON.parse(msg); + + if(typeof(data.total) != "undefined") { totalGraph.drawLogPath(data.total); - if(data.cartAdds) { - cartAddsGraph.drawLogPath(data.cartAdds); - } else { - cartAddsGraph.drawLogPath(0.0); - } } - } + }) - ws.onclose = function() { self.onclose(); } - ws.onopen = function() { self.onopen(); } -} + this.socket.on('disconnect', function() { self.onclose(); }); + this.socket.on('connect', function() { self.onopen(); }); +}; // WEEKLY WEBSOCKET @@ -114,26 +102,21 @@ Hummingbird.WebSocket.Weekly.prototype.start = function() { if (!this.webSocketEnabled()) return; - var wsServer = this.webSocketURI(); - var ws = new WebSocket(wsServer); + this.socket = new io.Socket(this.webSocketURI(), {port: this.webSocketPort()}); + this.socket.connect(); var self = this; - ws.onmessage = function(evt) { - var data = JSON.parse(evt.data); + this.socket.on('message', function(msg) { + var data = JSON.parse(msg); if(data.total && data.total > 0) { var el = $("div.day:first-child div.all_views"); var prevTotal = el.data("total"); el.text((prevTotal + data.total).commify()).data('total', prevTotal + data.total); } - if(data.cartAdds && data.cartAdds > 0) { - var el = $("div.day:first-child div.cart_adds"); - var prevCartAdds = el.data("cart_adds"); - el.text((prevCartAdds + data.cartAdds).commify()).data('cart_adds', prevCartAdds + data.cartAdds); - } - }; + }); - ws.onclose = function() { self.onclose(); } - ws.onopen = function() { self.onopen(); } + this.socket.on('disconnect', function() { self.onclose(); }); + this.socket.on('open', function() { self.onopen(); }); } diff --git a/public/js/weekly.js b/public/js/weekly.js index 4471a52..5bcd87f 100644 --- a/public/js/weekly.js +++ b/public/js/weekly.js @@ -5,13 +5,6 @@ Hummingbird.Weekly = {}; Hummingbird.Weekly.weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; Hummingbird.Weekly.init = function() { - $.getJSON("/sale_list", function(saleData) { - saleData.data.active_sales.concat(saleData.data.upcoming_sales); - var sales = {}; - $.each(saleData.data.active_sales, function() { - sales[this.url_key] = this; - }); - var weekJson = "/week.json"; if(document.location.search.match(/use_prod/)) { weekJson += "?use_prod"; @@ -19,7 +12,6 @@ Hummingbird.Weekly.init = function() { $.getJSON(weekJson, function(data) { var dayTemplate = $("#day_template"); - var saleTemplate = $("#sale_template"); var today = new Date(); today.setUTCHours(0); today.setUTCMinutes(0); today.setUTCSeconds(0); today.setUTCMilliseconds(0); @@ -38,29 +30,8 @@ Hummingbird.Weekly.init = function() { dateDiv.find('div.all_views').text(this.total.commify()).data('total', this.total); } - if(this.cartAdds) { - dateDiv.find('div.cart_adds').text(this.cartAdds.commify()).data('cart_adds', this.cartAdds); - } - - if(this.sales) { - $.each(this.sales.slice(0, 4), function() { - var saleDiv = saleTemplate.clone().attr('id', '').attr('style', ''); - var sale = sales[this.url_key]; - - if (sale) { - saleDiv.prepend(""); - saleDiv.find('div.sale_title').text(sale.name); - saleDiv.find('div.sale_views').text(this.views); - dateDiv.find('div.sales').append(saleDiv); - } - }); - } - - dateDiv.find('div.sales').append("
"); - dateDiv.appendTo('#days'); }); }); - }); }; diff --git a/public/socket.io b/public/socket.io new file mode 160000 index 0000000..50f7e47 --- /dev/null +++ b/public/socket.io @@ -0,0 +1 @@ +Subproject commit 50f7e4704ee5e17533d662090e17c006d5853f3d diff --git a/server.js b/server.js index 46e7551..e0048f6 100644 --- a/server.js +++ b/server.js @@ -1,37 +1,50 @@ require.paths.unshift(__dirname + '/lib'); require.paths.unshift(__dirname); -var sys = require('sys'), - http = require('http'), +var http = require('http'), weekly = require('weekly'), fs = require('fs'), + io = require('deps/node-socket.io'), mongo = require('deps/node-mongodb-native/lib/mongodb'), Hummingbird = require('hummingbird').Hummingbird; try { var configJSON = fs.readFileSync(__dirname + "/config/app.json"); } catch(e) { - sys.log("File config/app.json not found. Try: `cp config/app.json.sample config/app.json`"); + console.log("File config/app.json not found. Try: `cp config/app.json.sample config/app.json`"); } var config = JSON.parse(configJSON.toString()); db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); db.addListener("error", function(error) { - sys.puts("Error connecting to mongo -- perhaps it isn't running?"); + console.log("Error connecting to mongo -- perhaps it isn't running?"); }); db.open(function(p_db) { var hummingbird = new Hummingbird(); hummingbird.init(db, function() { - http.createServer(function(req, res) { + var server = http.createServer(function(req, res) { try { hummingbird.serveRequest(req, res); } catch(e) { hummingbird.handleError(req, res, e); } - }).listen(config.tracking_port); + }); + server.listen(config.tracking_port, "127.0.0.1"); + + socket = io.listen(server); + + socket.on('connection', function(client){ + // new client is here! + client.on('disconnect', function(){ console.log("Lost ws client"); }) + }); + + hummingbird.socket = socket; + hummingbird.addAllMetrics(socket, db); + + console.log('Web Socket server running at ws://*:' + config.tracking_port); }); - sys.puts('Tracking server running at http://*:' + config.tracking_port + '/tracking_pixel.gif'); + console.log('Tracking server running at http://*:' + config.tracking_port + '/tracking_pixel.gif'); }); diff --git a/views/index.ejs b/views/index.ejs index 51b430d..6991ce9 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -12,29 +12,18 @@
-
- -

Cart Adds / Second

- -
- - - -
- -
- -
- -
+ diff --git a/views/layout.ejs b/views/layout.ejs index 1aec1f9..df8e4fd 100644 --- a/views/layout.ejs +++ b/views/layout.ejs @@ -4,11 +4,15 @@ + + + + - - diff --git a/views/weekly.ejs b/views/weekly.ejs index f63d2f2..d0481d8 100644 --- a/views/weekly.ejs +++ b/views/weekly.ejs @@ -9,26 +9,11 @@

Page views

-
-
0
-

Cart adds

-
-
-
-

Top Sales:

-
-
-
-
-
-
-
- + + + + + + + + + + + Hummingbird + + + + + + + +

Hummingbird

@@ -27,3 +53,6 @@

Pageviews / Second

}); }); + + + diff --git a/server.js b/server.js index e0048f6..09546ed 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,7 @@ require.paths.unshift(__dirname); var http = require('http'), weekly = require('weekly'), fs = require('fs'), + static = require('deps/node-static/lib/node-static'), io = require('deps/node-socket.io'), mongo = require('deps/node-mongodb-native/lib/mongodb'), Hummingbird = require('hummingbird').Hummingbird; @@ -48,3 +49,15 @@ db.open(function(p_db) { console.log('Tracking server running at http://*:' + config.tracking_port + '/tracking_pixel.gif'); }); + +if(config.enable_dashboard) { + var file = new(static.Server)('./public'); + + http.createServer(function (request, response) { + request.addListener('end', function () { + file.serve(request, response); + }); + }).listen(config.dashboard_port); + + console.log('Dashboard server running at http://*:' + config.dashboard_port); +} \ No newline at end of file diff --git a/views/layout.ejs b/views/layout.ejs deleted file mode 100644 index df8e4fd..0000000 --- a/views/layout.ejs +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - <%= app.set('name') %> - - - - - - - <%- body %> - - diff --git a/views/login.ejs b/views/login.ejs deleted file mode 100644 index 8e0cc32..0000000 --- a/views/login.ejs +++ /dev/null @@ -1,17 +0,0 @@ -
- -

Hummingbird

- -
-
- - -
-
- - -
- - -
-
diff --git a/views/weekly.ejs b/views/weekly.ejs deleted file mode 100644 index d0481d8..0000000 --- a/views/weekly.ejs +++ /dev/null @@ -1,25 +0,0 @@ -

<%= app.set('name') %>

- -
- -
- -
-
0
-

Page views

-
- -
- -
-
- - From dfbbdd8890f43e4cdd8b56f90eb2380bf1431727 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 23 Oct 2010 00:10:57 -0400 Subject: [PATCH 152/267] upgrade jspec --- spec/lib/jspec.jquery.js | 15 +++- spec/lib/jspec.js | 55 ++++++++---- spec/lib/jspec.timers.js | 182 ++++++++++++++++++++++++++------------- spec/lib/jspec.xhr.js | 4 +- 4 files changed, 175 insertions(+), 81 deletions(-) diff --git a/spec/lib/jspec.jquery.js b/spec/lib/jspec.jquery.js index 46422ec..6a50a81 100644 --- a/spec/lib/jspec.jquery.js +++ b/spec/lib/jspec.jquery.js @@ -60,9 +60,18 @@ JSpec }, have_event_handlers : function(actual, expected) { - return jQuery(actual).data('events') ? - jQuery(actual).data('events').hasOwnProperty(expected) : - false + if (jQuery(actual).data('events') && jQuery(actual).data('events').hasOwnProperty(expected)) { + return true; + } else if (jQuery(actual.context).data('events') && jQuery(actual.context).data('events').hasOwnProperty(expected)) { + var events = jQuery(actual.context).data('events')[expected]; + + for (index in events) { + if (events[index].selector === actual.selector) { + return true; + } + } + } + return false; }, 'be disabled selected checked' : function(attr) { diff --git a/spec/lib/jspec.js b/spec/lib/jspec.js index 79d7077..049b7b8 100644 --- a/spec/lib/jspec.js +++ b/spec/lib/jspec.js @@ -4,7 +4,7 @@ ;(function(){ JSpec = { - version : '4.2.1', + version : '4.3.3', assert : true, cache : {}, suites : [], @@ -1050,8 +1050,12 @@ if (object === false) return 'false' if (object.an_instance_of) return 'an instance of ' + object.an_instance_of.name if (object.jquery && object.selector.length > 0) return 'selector ' + puts(object.selector) - if (object.jquery) return object.get(0).outerHTML - if (object.nodeName) return object.outerHTML + if (object.jquery && object.get(0) && object.get(0).outerHTML) return object.get(0).outerHTML + if (object.jquery && object.get(0) && object.get(0).nodeType == 9) return 'jQuery(document)' + if (object.jquery && object.get(0)) return document.createElement('div').appendChild(object.get(0)).parentNode.innerHTML + if (object.jquery && object.length == 0) return 'jQuery()' + if (object.nodeName && object.outerHTML) return object.outerHTML + if (object.nodeName) return document.createElement('div').appendChild(object).parentNode.innerHTML switch (object.constructor) { case Function: return object.name || object case String: @@ -1272,12 +1276,13 @@ destub : function(object, method) { var captures if (method) { - if (object['__prototype__' + method]) + if (object.hasOwnProperty('__prototype__' + method)) delete object[method] - else + else if (object.hasOwnProperty('__original__' + method)) object[method] = object['__original__' + method] + delete object['__prototype__' + method] - delete object['__original____' + method] + delete object['__original__' + method] } else if (object) { for (var key in object) @@ -1302,9 +1307,13 @@ stub : function(object, method) { hook('stubbing', object, method) + + //unbind any stub already present on this method + JSpec.destub(object, method); JSpec.stubbed.push(object) var type = object.hasOwnProperty(method) ? '__original__' : '__prototype__' object[type + method] = object[method] + object[method] = function(){} return { and_return : function(value) { @@ -1749,10 +1758,20 @@ // --- Node.js support - if (typeof GLOBAL === 'object' && typeof exports === 'object') - quit = process.exit, - print = require('sys').puts, - readFile = require('fs').readFileSync + if (typeof GLOBAL === 'object' && typeof exports === 'object') { + var fs = require('fs') + quit = process.exit + print = require('sys').puts + readFile = function(file){ + return fs.readFileSync(file).toString('utf8') + } + } + + // --- envjsrb / johnson support + + if (typeof Johnson === 'object') { + quit = function () {} + } // --- Utility functions @@ -1872,17 +1891,17 @@ }, have_prop : function(actual, property, value) { - return actual[property] === undefined || - actual[property] instanceof Function ? false: - value === undefined ? true: - does(actual[property], 'eql', value) + var actualVal = actual[property], actualType = typeof actualVal + return (actualType == 'function' || actualType == 'undefined') ? false : + typeof value === 'undefined' || + does(actual[property],'eql',value) }, have_property : function(actual, property, value) { - return actual[property] === undefined || - actual[property] instanceof Function ? false: - value === undefined ? true: - value === actual[property] + var actualVal = actual[property], actualType = typeof actualVal + return (actualType == 'function' || actualType == 'undefined') ? false : + typeof value === 'undefined' || + value === actualVal } }) diff --git a/spec/lib/jspec.timers.js b/spec/lib/jspec.timers.js index c88d10b..f4f58cb 100644 --- a/spec/lib/jspec.timers.js +++ b/spec/lib/jspec.timers.js @@ -1,73 +1,122 @@ -// JSpec - Mock Timers - Copyright TJ Holowaychuk (MIT Licensed) +// Mock Timers - Copyright TJ Holowaychuk (MIT Licensed) ;(function(){ - /** - * Version. - */ - - mockTimersVersion = '1.0.2' - /** * Localized timer stack. */ + var timers = []; - var timers = [] + // nodejs, rhino don't have a window object + var global = this; - /** - * Set mock timeout with _callback_ and timeout of _ms_. - * - * @param {function} callback - * @param {int} ms - * @return {int} - * @api public - */ + // if they where mocked before this library is loaded - bad luck + var savedGlobals = { + setTimeout: global.setTimeout, + setInterval: global.setInterval, + clearInterval: global.clearInterval, + clearTimeout: global.clearTimeout, + + // those should not be globals, but are mocked none the less, so we save them + resetTimers: global.resetTimers, + tick: global.tick + }; + var hadResetTimers = 'resetTimers' in global; + var hadTick = 'tick' in global; - setTimeout = function(callback, ms) { - var id - return id = setInterval(function(){ - callback() - clearInterval(id) - }, ms) + function forEachProperty(anObject, aClosure) { + for (var key in anObject) { + if ( ! anObject.hasOwnProperty(key)) + continue; + + aClosure(key, anObject[key]); + } } - /** - * Set mock interval with _callback_ and interval of _ms_. - * - * @param {function} callback - * @param {int} ms - * @return {int} - * @api public - */ - - setInterval = function(callback, ms) { - callback.step = ms, callback.current = callback.last = 0 - return timers[timers.length] = callback, timers.length + global.MockTimers = { + + mockTimersVersion: '2.0.0', + + mockGlobalTimerFunctions: function() { + forEachProperty(this.mocks, function(aName, aFunction) { + global[aName] = aFunction; + }); + }, + + unmockGlobalTimerFunctions: function() { + forEachProperty(this.savedGlobals, function(aName, aFunction) { + global[aName] = aFunction; + }); + + if ( ! hadResetTimers) + delete global['resetTimers']; + if ( ! hadTick) + delete global['tick']; + + } + }; + + function clearTimer(id) { + return delete timers[--id]; } - /** - * Destroy timer with _id_. - * - * @param {int} id - * @return {bool} - * @api public - */ + var mocks = { + + /** + * Set mock timeout with _callback_ and timeout of _ms_. + * + * @param {function} callback + * @param {int} ms + * @return {int} + * @api public + */ + setTimeout: function(callback, ms) { + var id; + return id = setInterval(function(){ + callback(); + clearInterval(id); + }, ms); + }, - clearInterval = clearTimeout = function(id) { - return delete timers[--id] - } + + /** + * Set mock interval with _callback_ and interval of _ms_. + * + * @param {function} callback + * @param {int} ms + * @return {int} + * @api public + */ + setInterval: function(callback, ms) { + // REFACT: use wrapper object so callback is not changed -> state leak + callback.step = ms; + callback.current = callback.last = 0; + timers[timers.length] = callback; + return timers.length; + }, + + /** + * Destroy timer with _id_. + * + * @param {int} id + * @return {bool} + * @api public + */ + clearInterval: clearTimer, + clearTimeout: clearTimer + }; + // additional functions that are not originally in the global namespace /** * Reset timers. * * @return {array} * @api public */ - - resetTimers = function() { - return timers = [] - } + mocks.resetTimers = function() { + return timers = []; + }; /** * Increment each timers internal clock by _ms_. @@ -75,16 +124,31 @@ * @param {int} ms * @api public */ + mocks.tick = function(ms) { + for (var i = 0, len = timers.length; i < len; ++i) { + if ( ! timers[i] || ! (timers[i].current += ms)) + continue; + + if (timers[i].current - timers[i].last < timers[i].step) + continue; + + var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step); + var remainder = (timers[i].current - timers[i].last) % timers[i].step; + timers[i].last = timers[i].current - remainder; + while (times-- && timers[i]) + timers[i](); + } + }; - tick = function(ms) { - for (var i = 0, len = timers.length; i < len; ++i) - if (timers[i] && (timers[i].current += ms)) - if (timers[i].current - timers[i].last >= timers[i].step) { - var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step) - var remainder = (timers[i].current - timers[i].last) % timers[i].step - timers[i].last = timers[i].current - remainder - while (times-- && timers[i]) timers[i]() - } - } + // make them available publicly + MockTimers.mocks = mocks; -})() \ No newline at end of file + JSpec.include({ + beforeSpec: function(){ + MockTimers.mockGlobalTimerFunctions(); + }, + afterSpec : function() { + MockTimers.unmockGlobalTimerFunctions(); + } + }); +})(); \ No newline at end of file diff --git a/spec/lib/jspec.xhr.js b/spec/lib/jspec.xhr.js index 482a3c4..3b96310 100644 --- a/spec/lib/jspec.xhr.js +++ b/spec/lib/jspec.xhr.js @@ -34,7 +34,9 @@ */ getAllResponseHeaders : function(){ - return this.responseHeaders + return JSpec.inject(this.responseHeaders, '', function(buf, key, val){ + return buf + key + ': ' + val + '\r\n' + }) }, /** From f6ac93dec53b4339cd80b3eb4d05f402bc3d827e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 23 Oct 2010 00:13:29 -0400 Subject: [PATCH 153/267] remove all unused submodules --- .gitmodules | 15 --------------- deps/node-microseconds | 1 - deps/node-paperboy | 1 - deps/node-websocket-server | 1 - deps/nodeunit | 1 - 5 files changed, 19 deletions(-) delete mode 160000 deps/node-microseconds delete mode 160000 deps/node-paperboy delete mode 160000 deps/node-websocket-server delete mode 160000 deps/nodeunit diff --git a/.gitmodules b/.gitmodules index 8151fd7..3d9297a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,21 +1,6 @@ -[submodule "deps/nodeunit"] - path = deps/nodeunit - url = http://github.com/caolan/nodeunit.git -[submodule "deps/node-paperboy"] - path = deps/node-paperboy - url = http://github.com/felixge/node-paperboy.git [submodule "deps/node-mongodb-native"] path = deps/node-mongodb-native url = http://github.com/christkv/node-mongodb-native.git -[submodule "deps/node-ws"] - path = deps/node-ws - url = http://github.com/ncr/node.ws.js.git -[submodule "deps/node-microseconds"] - path = deps/node-microseconds - url = http://github.com/tmpvar/node-microseconds.git -[submodule "deps/node-websocket-server"] - path = deps/node-websocket-server - url = http://github.com/mnutt/node-websocket-server.git [submodule "deps/node-socket.io"] path = deps/node-socket.io url = http://github.com/LearnBoost/Socket.IO-node.git diff --git a/deps/node-microseconds b/deps/node-microseconds deleted file mode 160000 index 79726d6..0000000 --- a/deps/node-microseconds +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 79726d6daaf30e942023a2d148aa1562d1949a93 diff --git a/deps/node-paperboy b/deps/node-paperboy deleted file mode 160000 index 59345d1..0000000 --- a/deps/node-paperboy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 59345d119393630af5d429853540434cfeab1817 diff --git a/deps/node-websocket-server b/deps/node-websocket-server deleted file mode 160000 index 50468bf..0000000 --- a/deps/node-websocket-server +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 50468bf928f8b1eec9d1e3e54955e230fb21689f diff --git a/deps/nodeunit b/deps/nodeunit deleted file mode 160000 index daa9986..0000000 --- a/deps/nodeunit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit daa9986ee6a5266c2e02eae5e3a8bd6904bbcee8 From f42b6ef83c47abaf7229985d7a2cd7c299976caf Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 23 Oct 2010 00:19:19 -0400 Subject: [PATCH 154/267] remove some unused libs --- lib/service_json.js | 24 ------------------------ lib/static_assets.js | 18 ------------------ 2 files changed, 42 deletions(-) delete mode 100644 lib/service_json.js delete mode 100644 lib/static_assets.js diff --git a/lib/service_json.js b/lib/service_json.js deleted file mode 100644 index 90ea1dd..0000000 --- a/lib/service_json.js +++ /dev/null @@ -1,24 +0,0 @@ -var url = require('url'); -var http = require('http'); -var sys = require('sys'); - -exports.fetchJSON = function(remoteURL, callback) { - remoteURL = url.parse(remoteURL); - - var pagegen = http.createClient(remoteURL.port || 80, remoteURL.hostname); - // TODO: remoteURL.search - var request = pagegen.request('GET', remoteURL.pathname, {"host": remoteURL.hostname}); - request.addListener('response', function(response) { - response.setEncoding('binary'); - response.client.responseBodyParts = ''; - - response.addListener('data', function(chunk) { - response.client.responseBodyParts += chunk; - }); - - response.addListener('end', function() { - callback(response.client.responseBodyParts); - }); - }); - request.end(); -}; diff --git a/lib/static_assets.js b/lib/static_assets.js deleted file mode 100644 index 2d80140..0000000 --- a/lib/static_assets.js +++ /dev/null @@ -1,18 +0,0 @@ -var sys = require('sys'), - paperboy = require('deps/node-paperboy'), - path = require('path'); - -var WEBROOT = path.join(path.dirname(__filename), '..', 'public'); - -var serveStatic = function(req, res) { - paperboy.deliver(WEBROOT, req, res) - .addHeader('Content-Type', "text/plain") - .after(function(statCode) { - sys.log([statCode, - req.method, - req.url, - req.connection.remoteAddress].join(' ')); - }); -}; - -exports.serveStatic = serveStatic; From b4aef7b505a0dda294d62e050064ff9f4b2ea45e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 23 Oct 2010 00:23:11 -0400 Subject: [PATCH 155/267] update readme --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6ca13a4..4e03fa4 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,7 @@ Installation # Update submodules git submodule update --init --recursive # If you are running a *really* old version of git, you may have to run the following instead: - # git submodule init . && git submodule update . - # If your version of git does not have the --recursive flag, initialize the express submodules - cd deps/express; git submodule update --init; cd ../.. - # build the native mongo db driver cd deps/node-mongodb-native; make @@ -47,9 +43,9 @@ To start the analytics server, run the following: mongod & (or start mongo some other way) node server.js -To start the web monitor, run: - - node monitor.js +By default a dashboard will be run on port 8080. You can disable it for production use in +config/app.json. The dashboard is just html served out of public/; you can serve it using +any webserver. Specs @@ -62,7 +58,7 @@ Specs Tips ----- - * To run the UI locally but stream data from your production server, use the url http://localhost:8088/?ws_server=your-host.com&ws_port=12345 + * To run the UI locally but stream data from your production server, use the url http://localhost:8080/?ws_server=your-host.com&ws_port=12345 Contributors From f9b76017f926b14d2d46e9083b558f5d02a77faa Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 23 Oct 2010 22:40:49 -0400 Subject: [PATCH 156/267] Create widgets which are bound to specific properties on the websocket json data --- README.md | 1 - public/css/main.css | 2 +- public/index.html | 25 +++++++++++++--- public/js/websocket.js | 59 ++++++++++++++++++++++++++++++++----- public/js/widgets/base.js | 53 +++++++++++++++++++++++++++++++++ public/js/widgets/count.js | 28 ++++++++++++++++++ public/js/widgets/logger.js | 15 ++++++++++ 7 files changed, 170 insertions(+), 13 deletions(-) create mode 100644 public/js/widgets/base.js create mode 100644 public/js/widgets/count.js create mode 100644 public/js/widgets/logger.js diff --git a/README.md b/README.md index 4e03fa4..1bf19a0 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ Installation # Update submodules git submodule update --init --recursive - # If you are running a *really* old version of git, you may have to run the following instead: # build the native mongo db driver cd deps/node-mongodb-native; make diff --git a/public/css/main.css b/public/css/main.css index b1a1f2b..67680a5 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -12,7 +12,7 @@ h1 { margin-left: 58px; } -div.hummingbird_graph h2 { +h2.graph_title { color: #CCC; text-transform: uppercase; font-size: 0.9em; diff --git a/public/index.html b/public/index.html index b361ac0..135f54b 100644 --- a/public/index.html +++ b/public/index.html @@ -15,6 +15,9 @@ + + + Hummingbird @@ -26,9 +29,9 @@

Hummingbird

-
+

0 Pageviews / Second

-

Pageviews / Second

+
@@ -42,8 +45,22 @@

Pageviews / Second

+ - + + Hummingbird @@ -48,11 +49,11 @@

0 Pageviews / Second

hummingbirdSocket = new Hummingbird.WebSocket(); hummingbirdSocket.start(); - //$("#page_views_canvas").hummingbirdGraph(hummingbirdSocket, - // { - // data: { total: true }, - // rate: 30 - // }); + $("#log").hummingbirdGraph(hummingbirdSocket, + { + data: { total: true }, + rate: 30 + }); $("h2.graph_title span.value").hummingbirdCount(hummingbirdSocket, { diff --git a/public/js/jquery-1.4.2.js b/public/js/jquery-1.4.2.js new file mode 100644 index 0000000..fff6776 --- /dev/null +++ b/public/js/jquery-1.4.2.js @@ -0,0 +1,6240 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function( window, undefined ) { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, + + // Is it a simple selector + isSimple = /^.[^:#\[\.,]*$/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The functions to execute on DOM ready + readyList = [], + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwnProperty = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + indexOf = Array.prototype.indexOf; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context ) { + this.context = document; + this[0] = document.body; + this.selector = "body"; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + if ( elem ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $("TAG") + } else if ( !context && /^\w+$/.test( selector ) ) { + this.selector = selector; + this.context = document; + selector = document.getElementsByTagName( selector ); + return jQuery.merge( this, selector ); + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return jQuery( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.4.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = jQuery(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // If the DOM is already ready + if ( jQuery.isReady ) { + // Execute the function immediately + fn.call( document, jQuery ); + + // Otherwise, remember the function for later + } else if ( readyList ) { + // Add the function to the wait list + readyList.push( fn ); + } + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || jQuery(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging object literal values or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { + var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src + : jQuery.isArray(copy) ? [] : {}; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // Handle when the DOM is ready + ready: function() { + // Make sure that the DOM is not already loaded + if ( !jQuery.isReady ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 13 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If there are functions bound, to execute + if ( readyList ) { + // Execute all of them + var fn, i = 0; + while ( (fn = readyList[ i++ ]) ) { + fn.call( document, jQuery ); + } + + // Reset the list of functions + readyList = null; + } + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + return jQuery.ready(); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return toString.call(obj) === "[object Function]"; + }, + + isArray: function( obj ) { + return toString.call(obj) === "[object Array]"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor + && !hasOwnProperty.call(obj, "constructor") + && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwnProperty.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") + .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + noop: function() {}, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + + if ( jQuery.support.scriptEval ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + trim: function( text ) { + return (text || "").replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = []; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + if ( !inv !== !callback( elems[ i ], i ) ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + browser: {} +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch( error ) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +function evalScript( i, elem ) { + if ( elem.src ) { + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + } else { + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } +} + +// Mutifunctional method to get and set values to a collection +// The value/s can be optionally by executed if its a function +function access( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; +} + +function now() { + return (new Date).getTime(); +} +(function() { + + jQuery.support = {}; + + var root = document.documentElement, + script = document.createElement("script"), + div = document.createElement("div"), + id = "script" + now(); + + div.style.display = "none"; + div.innerHTML = "
a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return; + } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: div.getElementsByTagName("input")[0].value === "on", + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected, + + parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null, + + // Will be defined later + deleteExpando: true, + checkClone: false, + scriptEval: false, + noCloneEvent: true, + boxModel: null + }; + + script.type = "text/javascript"; + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + if ( window[ id ] ) { + jQuery.support.scriptEval = true; + delete window[ id ]; + } + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete script.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + + root.removeChild( script ); + + if ( div.attachEvent && div.fireEvent ) { + div.attachEvent("onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); + }); + div.cloneNode(true).fireEvent("onclick"); + } + + div = document.createElement("div"); + div.innerHTML = ""; + + var fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // Figure out if the W3C box model works as expected + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"); + div.style.width = div.style.paddingLeft = "1px"; + + document.body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + document.body.removeChild( div ).style.display = 'none'; + + div = null; + }); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + el = null; + + return isSupported; + }; + + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + root = script = div = all = a = null; +})(); + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; +var expando = "jQuery" + now(), uuid = 0, windowData = {}; + +jQuery.extend({ + cache: {}, + + expando:expando, + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + "object": true, + "applet": true + }, + + data: function( elem, name, data ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache; + + if ( !id && typeof name === "string" && data === undefined ) { + return null; + } + + // Compute a unique ID for the element + if ( !id ) { + id = ++uuid; + } + + // Avoid generating a new cache unless none exists and we + // want to manipulate it. + if ( typeof name === "object" ) { + elem[ expando ] = id; + thisCache = cache[ id ] = jQuery.extend(true, {}, name); + + } else if ( !cache[ id ] ) { + elem[ expando ] = id; + cache[ id ] = {}; + } + + thisCache = cache[ id ]; + + // Prevent overriding the named cache with undefined values + if ( data !== undefined ) { + thisCache[ name ] = data; + } + + return typeof name === "string" ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( thisCache ) { + // Remove the section of cache data + delete thisCache[ name ]; + + // If we've removed all the data, remove the element's cache + if ( jQuery.isEmptyObject(thisCache) ) { + jQuery.removeData( elem ); + } + } + + // Otherwise, we want to remove all of the element's data + } else { + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } + + // Completely remove the data cache + delete cache[ id ]; + } + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + if ( typeof key === "undefined" && this.length ) { + return jQuery.data( this[0] ); + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + } + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } else { + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { + jQuery.data( this, key, value ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i, elem ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + } +}); +var rclass = /[\n\t]/g, + rspace = /\s+/, + rreturn = /\r/g, + rspecialurl = /href|src|style/, + rtype = /(button|input)/i, + rfocusable = /(button|input|object|select|textarea)/i, + rclickable = /^(a|area)$/i, + rradiocheck = /radio|checkbox/; + +jQuery.fn.extend({ + attr: function( name, value ) { + return access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspace ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", setClass = elem.className; + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split(rspace); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, i = 0, self = jQuery(this), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery.data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery(option).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // Typecast each time if the value is a Function and the appended + // value is therefore different each time. + if ( typeof val === "number" ) { + val += ""; + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + // don't set attributes on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + if ( name in elem && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + elem[ name ] = value; + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + + // elem is actually elem.style ... set the style + // Using attr for specific style information is now deprecated. Use style instead. + return jQuery.style( elem, name, value ); + } +}); +var rnamespaces = /\.(.*)$/, + fcleanup = function( nm ) { + return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { + return "\\" + ch; + }); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery.data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events = elemData.events || {}, + eventHandle = elemData.handle, eventHandle; + + if ( !eventHandle ) { + elemData.handle = eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + handleObj.guid = handler.guid; + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for global triggering + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)") + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( var j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( var j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[expando] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + jQuery.each( jQuery.cache, function() { + if ( this.events && this.events[type] ) { + jQuery.event.trigger( event, data, this.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery.data( elem, "handle" ); + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var target = event.target, old, + isClick = jQuery.nodeName(target, "a") && type === "click", + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + + try { + if ( target[ type ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + type ]; + + if ( old ) { + target[ "on" + type ] = null; + } + + jQuery.event.triggered = true; + target[ type ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( old ) { + target[ "on" + type ] = old; + } + + jQuery.event.triggered = false; + } + } + }, + + handle: function( event ) { + var all, handlers, namespaces, namespace, events; + + event = arguments[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; + + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + var events = jQuery.data(this, "events"), handlers = events[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, arguments ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, body = document.body; + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { + event.which = event.charCode || event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); + }, + + remove: function( handleObj ) { + var remove = true, + type = handleObj.origType.replace(rnamespaces, ""); + + jQuery.each( jQuery.data(this, "events").live || [], function() { + if ( type === this.origType.replace(rnamespaces, "") ) { + remove = false; + return false; + } + }); + + if ( remove ) { + jQuery.event.remove( this, handleObj.origType, liveHandler ); + } + } + + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( this.setInterval ) { + this.onbeforeunload = eventHandle; + } + + return false; + }, + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +var removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + elem.removeEventListener( type, handle, false ); + } : + function( elem, type, handle ) { + elem.detachEvent( "on" + type, handle ); + }; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = now(); + + // Mark it as fixed + this[ expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + } + // otherwise set the returnValue property of the original event to false (IE) + e.returnValue = false; + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + return trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + return trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var formElems = /textarea|input|select/i, + + changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery.data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery.data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + return jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + return testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + return testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information/focus[in] is not needed anymore + beforeactivate: function( e ) { + var elem = e.target; + jQuery.data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return formElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return formElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; +} + +function trigger( type, elem, args ) { + args[0].type = type; + return jQuery.event.handle.apply( elem, args ); +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( type === "focus" || type === "blur" ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + context.each(function(){ + jQuery.event.add( this, liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + }); + + } else { + // unbind live handler + context.unbind( liveConvert( type, selector ), fn ); + } + } + + return this; + } +}); + +function liveHandler( event ) { + var stop, elems = [], selectors = [], args = arguments, + related, match, handleObj, elem, j, i, l, data, + events = jQuery.data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) + if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) { + return; + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( match[i].selector === handleObj.selector ) { + elem = match[i].elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) { + stop = false; + break; + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( fn ) { + return fn ? this.bind( name, fn ) : this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + +// Prevent memory leaks in IE +// Window isn't included so as not to unbind existing unload events +// More info: +// - http://isaacschlueter.com/2006/10/msie-memory-leaks/ +if ( window.attachEvent && !window.addEventListener ) { + window.attachEvent("onunload", function() { + for ( var id in jQuery.cache ) { + if ( jQuery.cache[ id ].handle ) { + // Try/Catch is to handle iframes being unloaded, see #4280 + try { + jQuery.event.remove( jQuery.cache[ id ].handle.elem ); + } catch(e) {} + } + } + }); +} +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var filter = Expr.filter[ type ], found, item, left = match[1]; + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = part.toLowerCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + return match[1].toLowerCase(); + }, + CHILD: function(match){ + if ( match[1] === "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 === i; + }, + eq: function(elem, i, match){ + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } else { + Sizzle.error( "Syntax error, unrecognized expression: " + name ); + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + if ( type === "first" ) { + return true; + } + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first === 0 ) { + return diff === 0; + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ + return "\\" + (num - 0 + 1); + })); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.compareDocumentPosition ? -1 : 1; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.sourceIndex ? -1 : 1; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.ownerDocument ? -1 : 1; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +function getText( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE + })(); +} + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return !!(a.compareDocumentPosition(b) & 16); +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = getText; +jQuery.isXMLDoc = isXML; +jQuery.contains = contains; + +return; + +window.Sizzle = Sizzle; + +})(); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + slice = Array.prototype.slice; + +// Implement the identical functionality for filter and not +var winnow = function( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + if ( jQuery.isArray( selectors ) ) { + var ret = [], cur = this[0], match, matches = {}, selector; + + if ( cur && selectors.length ) { + for ( var i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur }); + delete matches[selector]; + } + } + cur = cur.parentNode; + } + } + + return ret; + } + + var pos = jQuery.expr.match.POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + return this.map(function( i, cur ) { + while ( cur && cur.ownerDocument && cur !== context ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { + return cur; + } + cur = cur.parentNode; + } + return null; + }); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context || this.context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call(arguments).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], cur = elem[dir]; + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, + rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, + rtagName = /<([\w:]+)/, + rtbody = /"; + }, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and diff --git a/public/js/widgets/base.js b/public/js/widgets/base.js index f924ac1..e48c09a 100644 --- a/public/js/widgets/base.js +++ b/public/js/widgets/base.js @@ -4,6 +4,8 @@ Hummingbird.Base = function() {}; Hummingbird.Base.prototype = { + validMessageCount: 0, + initialize: function() { this.setFilter(); this.registerHandler(); @@ -20,7 +22,11 @@ Hummingbird.Base.prototype = { onData: function(fullData) { var message = this.extract(fullData); if(typeof(message) != "undefined") { - this.onMessage(message); + this.validMessageCount += 1; + + if((!this.options.every) || (this.validMessageCount % this.options.every == 0)) { + this.onMessage(message); + } } }, diff --git a/public/js/widgets/graph.js b/public/js/widgets/graph.js index 5fcfa2d..c5aa0a0 100644 --- a/public/js/widgets/graph.js +++ b/public/js/widgets/graph.js @@ -23,7 +23,8 @@ Hummingbird.Graph = function(element, socket, options) { showBackgroundBars: true, tickLineColor: '#666', bgLineColor: '#555', - barColor: null + barColor: null, + graphHeight: 216 } this.options = $.extend(defaults, options); @@ -64,7 +65,8 @@ $.extend(Hummingbird.Graph.prototype, { this.lineWidth = 3; - this.graphHeight = 216; // this.graph.height(); + this.graphHeight = this.options.graphHeight; // this.graph.height(); + this.graph.height(this.graphHeight); this.graphWidth = this.graph.width(); this.numPoints = Math.ceil(this.graphWidth / (this.lineWidth * 2)); diff --git a/public/js/widgets/logger.js b/public/js/widgets/logger.js index 612a792..2cbc9da 100644 --- a/public/js/widgets/logger.js +++ b/public/js/widgets/logger.js @@ -11,5 +11,5 @@ Hummingbird.Logger = function(element, socket, options) { Hummingbird.Logger.prototype = new Hummingbird.Base(); Hummingbird.Logger.prototype.onMessage = function(message) { - console.log(JSON.stringify(message)); + console.log("Logger: " + JSON.stringify(message)); }; From e338666a7ec0a97bb6937e2e13f3bce2a9d4fa6c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 24 Oct 2010 17:07:13 -0400 Subject: [PATCH 160/267] Move average stuff out of graph.js and into base; now any widgets can use averages --- public/js/widgets/base.js | 24 +++++++++++++++++++++++- public/js/widgets/count.js | 15 +++++++++++---- public/js/widgets/graph.js | 34 ++++++++++++---------------------- public/js/widgets/logger.js | 17 +++++++++++++---- 4 files changed, 59 insertions(+), 31 deletions(-) diff --git a/public/js/widgets/base.js b/public/js/widgets/base.js index e48c09a..f8bb6e9 100644 --- a/public/js/widgets/base.js +++ b/public/js/widgets/base.js @@ -6,7 +6,10 @@ Hummingbird.Base.prototype = { validMessageCount: 0, + messageRate: 20, + initialize: function() { + this.averageLog = []; this.setFilter(); this.registerHandler(); }, @@ -20,12 +23,16 @@ Hummingbird.Base.prototype = { }, onData: function(fullData) { + var average; var message = this.extract(fullData); if(typeof(message) != "undefined") { this.validMessageCount += 1; + // Calculate the average over N seconds if the averageOver option is set + if(this.options.averageOver) { average = this.addToAverage(message); } + if((!this.options.every) || (this.validMessageCount % this.options.every == 0)) { - this.onMessage(message); + this.onMessage(message, this.average()); } } }, @@ -54,6 +61,21 @@ Hummingbird.Base.prototype = { break; } } + }, + + addToAverage: function(newValue) { + var averageCount = this.options.averageOver * this.messageRate; + + this.averageLog.push(newValue); + if(this.averageLog.length > averageCount) { + this.averageLog.shift(); + } + }, + + average: function() { + if(this.averageLog.length == 0) { return 0; } + + return this.averageLog.sum() * 1.0 / this.averageLog.length * this.messageRate; } }; diff --git a/public/js/widgets/count.js b/public/js/widgets/count.js index f3f3060..1fa19eb 100644 --- a/public/js/widgets/count.js +++ b/public/js/widgets/count.js @@ -14,15 +14,22 @@ if(!Hummingbird) { var Hummingbird = {}; } Hummingbird.Count = function(element, socket, options) { this.element = element; this.socket = socket; - this.options = options; + var defaults = { + averageOver: 1, // second + ratePerSecond: 2, + decimalPlaces: 0 + }; + + this.options = $.extend(defaults, options); this.initialize(); }; Hummingbird.Count.prototype = new Hummingbird.Base(); $.extend(Hummingbird.Count.prototype, { - onMessage: function(message) { - this.element.text(message); - } + name: "Count", + onMessage: function(value, average) { + this.element.text(average.toFixed(this.options.decimalPlaces)); + }, }); diff --git a/public/js/widgets/graph.js b/public/js/widgets/graph.js index c5aa0a0..c51de94 100644 --- a/public/js/widgets/graph.js +++ b/public/js/widgets/graph.js @@ -19,12 +19,12 @@ Hummingbird.Graph = function(element, socket, options) { var defaults = { showLogDate: false, showMarkers: true, - ratePerSecond: 20, showBackgroundBars: true, tickLineColor: '#666', bgLineColor: '#555', barColor: null, - graphHeight: 216 + graphHeight: 216, + averageOver: 0.5 } this.options = $.extend(defaults, options); @@ -42,8 +42,11 @@ Hummingbird.Graph = function(element, socket, options) { Hummingbird.Graph.prototype = new Hummingbird.Base(); $.extend(Hummingbird.Graph.prototype, { - onMessage: function(message) { - this.drawLogPath(message); + + name: "Graph", + + onMessage: function(message, average) { + this.drawLogPath(average); }, createGraph: function() { @@ -101,8 +104,8 @@ $.extend(Hummingbird.Graph.prototype, { resetMarkerContainer(rightMarkerContainer, numMarkers, scale); var millisecsBeforeUpdating = 0; - if (this.lineWidth != null && this.options.ratePerSecond != null) { - var millisecsPerTick = 1000 / this.options.ratePerSecond; + if (this.lineWidth != null && this.messageRate != null) { + var millisecsPerTick = 1000 / this.messageRate; var ticksPerFrame = this.graphWidth / (this.lineWidth * 2.0); millisecsBeforeUpdating = millisecsPerTick * ticksPerFrame; } @@ -119,17 +122,6 @@ $.extend(Hummingbird.Graph.prototype, { } }, - addValue: function(value) { - this.trafficLog.push(value); - if(this.trafficLog.length > this.options.ratePerSecond) { - this.trafficLog.shift(); - } - }, - - runningAverage: function() { - return this.trafficLog.sum() * 1.0 / this.trafficLog.length; - }, - drawEmptyGraph: function() { var dataPoints = this.numPoints; @@ -180,15 +172,13 @@ $.extend(Hummingbird.Graph.prototype, { drawLogPath: function(value, isInitialFill) { this.tick++; - this.addValue(value); - - var average = this.runningAverage() * this.options.ratePerSecond; + var average = Math.round(value); var percent = average / this.scale; var height = Math.floor(percent * this.graphHeight); var color = this.options.barColor || this.lineColors[this.scale] || this.lineColors.def; var lineHeight = this.graphHeight - height; - if(this.tick % (this.options.ratePerSecond * 2) == 0) { // Every 2 seconds + if(this.tick % (this.messageRate * 2) == 0) { // Every 2 seconds this.element.attr('data-average', average); this.rescale(percent); @@ -199,7 +189,7 @@ $.extend(Hummingbird.Graph.prototype, { } var backgroundColor; - if(this.tick % this.options.ratePerSecond == 0) { + if(this.tick % this.messageRate == 0) { backgroundColor = this.options.tickLineColor; } else { backgroundColor = this.options.bgLineColor; diff --git a/public/js/widgets/logger.js b/public/js/widgets/logger.js index 2cbc9da..7d5614c 100644 --- a/public/js/widgets/logger.js +++ b/public/js/widgets/logger.js @@ -3,13 +3,22 @@ if(!Hummingbird) { var Hummingbird = {}; } Hummingbird.Logger = function(element, socket, options) { this.element = element; this.socket = socket; - this.options = options; + var defaults = { + averageOver: 60, // seconds + ratePerSecond: 1, + decimalPlaces: 1 + }; + + this.options = $.extend(defaults, options); this.initialize(); }; Hummingbird.Logger.prototype = new Hummingbird.Base(); -Hummingbird.Logger.prototype.onMessage = function(message) { - console.log("Logger: " + JSON.stringify(message)); -}; +$.extend(Hummingbird.Logger.prototype, { + name: "Logger", + onMessage: function(message, average) { + console.log("Minute Average: " + average.toFixed(this.options.decimalPlaces)); + } +}); From 1f264c32f309290fc8d752485c72f667a0803729 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 24 Oct 2010 17:07:34 -0400 Subject: [PATCH 161/267] favicon to shut webkit up --- public/images/favicon.png | Bin 0 -> 827 bytes public/index.html | 9 ++++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 public/images/favicon.png diff --git a/public/images/favicon.png b/public/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..e044db65fdb402a66f3f2787b80ed71f05fe919e GIT binary patch literal 827 zcmV-B1H}A^P)IV5g>IxY1rcmZg;Z)% zMOz96$8_w>3W;OJNxHu!XgP7-K1M2;{7+ znEX!7o+%sK=(-7lAU8KRmq~)Z`n8FjW2flrjLJu^qvdG`DTzMr{5*O9|ivb}8kb(X$`S+Yy_I6UG)V+Bjv6rG7G^=1W+=U|Bl zV@`eg86zVjqy=!_o+7qzzEl`s+tACTQyF|&{ZnT1U+pI=O}tbp(U!nkrNW_oV=O)_ zchqX+t<`Qni#J>SM7C{9i5A8-ELN)>og@IsUHn{}k&?FrQBT(E%fKWTWAx+8Czj+U zwmdO05&R!O!kT@-rOVhIR;?Ai{ex`y?GCWCTK`vo0RZ}9ATzIA`11e&002ovPDHLk FV1iIqk+uK; literal 0 HcmV?d00001 diff --git a/public/index.html b/public/index.html index 9051381..4d3bb4c 100644 --- a/public/index.html +++ b/public/index.html @@ -22,6 +22,8 @@ Hummingbird + + @@ -79,7 +81,12 @@

Cart Traffic:

every: 10 }); - new Hummingbird.Logger(window, hummingbirdSocket, { data: {cartAdds: true}, every: 20 }); + new Hummingbird.Logger(window, + hummingbirdSocket, + { + data: { cartAdds: true}, + every: 20 + }); $("#test_it").click(function(e) { e.preventDefault(); From ac8a6eb4997a129794396f2b6af1daf168138572 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 24 Oct 2010 19:44:15 -0400 Subject: [PATCH 162/267] scale down to 50 to start --- public/js/widgets/graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/widgets/graph.js b/public/js/widgets/graph.js index c51de94..6646dfa 100644 --- a/public/js/widgets/graph.js +++ b/public/js/widgets/graph.js @@ -29,7 +29,7 @@ Hummingbird.Graph = function(element, socket, options) { this.options = $.extend(defaults, options); - this.scale = 800; + this.scale = 50; this.element = element; this.socket = socket this.graph = this.element.find('div.graph'); From 21876e3de932a8549c95911d92c62829e3783394 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 26 Oct 2010 20:10:05 -0400 Subject: [PATCH 163/267] Update sample config; add customization notes to the readme, simplify sales view --- README.md | 31 +++++++++++++++++++++++++++++++ config/app.json.sample | 5 ++--- lib/hummingbird.js | 4 ++-- lib/metrics/sales.js | 34 ++++++++++------------------------ lib/view.js | 13 ------------- 5 files changed, 45 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 1bf19a0..3a9cbb1 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,37 @@ config/app.json. The dashboard is just html served out of public/; you can serv any webserver. +Architecture Overview +--------------------- + +Hummingbird is organized into two parts: a node.js-based tracking server that records user +activity via a tracking pixel, and a collection of javascript-based widgets that display that +activity. The server records all activity in MongoDB and broadcasts it to the clients using +WebSockets if possible, and falling back to Flash sockets if necessary. + +The Hummingbird.WebSocket object receives websocket events from the server in the form of JSON +objects. Individual widgets subscribe to a property in the JSON tree and register handler +functions to be called whenever that property is present. + + +Logging Customization +--------------------- + +Metrics are stored in lib/metrics and auto-loaded.. Each metric contains a handler function that is +called every time a new user event occurs. Metrics store data in the `data` object property which +gets emitted to clients in intervals specified by the metric. A basic example can be found in +lib/metrics/all.js. An example of how a metric can filter based on urls is in lib/metric/sales.js. + + +Display Customization +--------------------- + +Hummingbird comes with some stock widgets (Counter, Logger, Graph) that demonstrate how to hook into +the data provided by the node.js server. For the minimum amount required to create a widget, see +public/js/widgets/logger.js. A widget is an object whose prototype extends Hummingbird.Base and +implements onMessage. + + Specs -------- diff --git a/config/app.json.sample b/config/app.json.sample index e77d1ce..3d34289 100644 --- a/config/app.json.sample +++ b/config/app.json.sample @@ -1,11 +1,10 @@ { "name" : "Hummingbird", - "monitor_port" : 8888, "tracking_port" : 8000, + "dashboard_port" : 8080, - "username" : "admin", - "password" : "change_this", + "enable_dashboard" : true, "capistrano" : { "repository" : "git://github.com/mnutt/hummingbird.git", diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 0b98810..12483f5 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -59,8 +59,8 @@ Hummingbird.prototype = { var view = new View(env); - env.url_key = view.urlKey(); - env.product_id = view.productId(); + env.url_key = view.urlKey; + env.product_id = view.productId; this.collection.insertAll([env]); diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js index 7c5e17b..439009b 100644 --- a/lib/metrics/sales.js +++ b/lib/metrics/sales.js @@ -7,33 +7,19 @@ var SalesMetric = { interval: 500, // ms incrementCallback: function(view) { - if(view.urlKey()) { - this.data.sales[view.urlKey()] = (this.data.sales[view.urlKey()] || 0) + 1; - this.minuteData["sales."+view.urlKey()] = (this.minuteData["sales."+view.urlKey()] || 0) + 1; - } - }, - - aggregateCallback: function(item) { - item.tmpSales = item.sales; - item.sales = []; - for(sale in item.tmpSales) { - if(item.tmpSales[sale] > 10) { - item.sales.push({ url_key: sale, - views: item.tmpSales[sale] }); + if(view.env.u) { + var match = view.env.u.match(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/|\/city\/offers?\/)([^\/\?\#]+)\/?(product\/)?(\d+)?/); + if(match && match.length > 2) { + view.urlKey = match[2]; + view.productId = match[4]; } } - delete item.tmpSales; - - // Sort by sale numbers descending - item.sales = item.sales.sort(function(a, b) { - if(a.views == b.views) { - return 0; - } else if(a.views > b.views) { - return -1; - } else { return 1; } - }); - } + if(view.urlKey) { + this.data.sales[view.urlKey] = (this.data.sales[view.urlKey] || 0) + 1; + this.minuteData["sales."+view.urlKey] = (this.minuteData["sales."+view.urlKey] || 0) + 1; + } + }, }; for (var i in SalesMetric) diff --git a/lib/view.js b/lib/view.js index 56e65b4..c82503c 100644 --- a/lib/view.js +++ b/lib/view.js @@ -7,20 +7,9 @@ var View = function(env) { this.env = env; - if(this.env.u) { - var match = View.urlKeyRegexp.exec(this.env.u); - if(match && match.length > 2) { - this._urlKey = match[2]; - this._productId = match[4]; - } - } } View.prototype = { - urlKey: function() { - return this._urlKey; - }, - productId: function() { return this._productId; }, @@ -39,6 +28,4 @@ View.prototype = { } }; -View.urlKeyRegexp = new RegExp(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/|\/city\/offers?\/)([^\/\?\#]+)\/?(product\/)?(\d+)?/); - exports.View = View; From b02fddc978e26e43dcdbb7f9601733f6fe2511fb Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 27 Oct 2010 03:20:15 -0400 Subject: [PATCH 164/267] add map widget example --- lib/hummingbird.js | 1 + lib/metrics/hits.js | 16 + lib/metrics/locations.js | 50 + lib/view.js | 4 - public/css/map.css | 67 ++ public/index.html | 11 +- public/js/polymaps.js | 2409 ++++++++++++++++++++++++++++++++++++++ public/js/widgets/map.js | 63 + 8 files changed, 2616 insertions(+), 5 deletions(-) create mode 100644 lib/metrics/hits.js create mode 100644 lib/metrics/locations.js create mode 100644 public/css/map.css create mode 100755 public/js/polymaps.js create mode 100644 public/js/widgets/map.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 12483f5..103e259 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -57,6 +57,7 @@ Hummingbird.prototype = { env.timestamp = new Date(); // sys.log(JSON.stringify(env, null, 2)); + env.ip = req.connection.remoteAddress; var view = new View(env); env.url_key = view.urlKey; diff --git a/lib/metrics/hits.js b/lib/metrics/hits.js new file mode 100644 index 0000000..b8c47a5 --- /dev/null +++ b/lib/metrics/hits.js @@ -0,0 +1,16 @@ +var HitsMetric = { + name: 'Individual Hits', + initialData: [], + interval: 200, + incrementCallback: function(view) { + var value = { + url: view.env.u, + timestamp: view.env.timestamp, + ip: view.env.ip + }; + this.data.push(value); + } +} + +for (var i in HitsMetric) + exports[i] = HitsMetric[i]; \ No newline at end of file diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js new file mode 100644 index 0000000..bc74293 --- /dev/null +++ b/lib/metrics/locations.js @@ -0,0 +1,50 @@ +var http = require('http'); + +var LocationsMetric = { + name: 'Location', + initialData: {location: []}, + interval: 500, + + incrementCallback: function(view) { + var remoteAddress, + metric = this, + host = "ipinfodb.com", + client = http.createClient(80, host); + + if(view.env.ip === "127.0.0.1") { + remoteAddress = ""; + } else { + remoteAddress = view.env.ip; + } + + var request = client.request("GET", "/ip_query.php?ip=" + remoteAddress + "&timezone=false", {host: host}); + + request.end(); + + request.on('response', function(resp) { + var buffer = ''; + + resp.on('data', function(chunk) { buffer += chunk; }); + resp.on('end', function() { + var lat, lon, city; + + if(resp.statusCode < 300) { + lat = /([0-9\.\-]+)<\/Latitude>/.exec(buffer); + lon = /([0-9\.\-]+)<\/Longitude>/.exec(buffer); + city = /(.*)<\/City>/.exec(buffer); + } + + var location = { + latitude: lat ? lat[1] : 0, + longitude: lon ? lon[1] : 0, + city: city ? city[1] : "Unknown" + }; + + metric.data.location.push(location); + }); + }); + } +} + +for (var i in LocationsMetric) + exports[i] = LocationsMetric[i]; \ No newline at end of file diff --git a/lib/view.js b/lib/view.js index c82503c..cab3d2f 100644 --- a/lib/view.js +++ b/lib/view.js @@ -10,10 +10,6 @@ var View = function(env) { } View.prototype = { - productId: function() { - return this._productId; - }, - event: function() { if(this.env.events) { if(this.env.events.match(/scAdd/)) { diff --git a/public/css/map.css b/public/css/map.css new file mode 100644 index 0000000..a3aee31 --- /dev/null +++ b/public/css/map.css @@ -0,0 +1,67 @@ +.compass .back { + fill: #eee; + fill-opacity: .8; +} + +.compass .fore { + stroke: #999; + stroke-width: 1.5px; +} + +.compass rect.back.fore { + fill: #999; + fill-opacity: .3; + stroke: #eee; + stroke-width: 1px; + shape-rendering: crispEdges; +} + +.compass .direction { + fill: none; +} + +.compass .chevron { + fill: none; + stroke: #999; + stroke-width: 5px; +} + +.compass .zoom .chevron { + stroke-width: 4px; +} + +.compass .active .chevron, .compass .chevron.active { + stroke: #fff; +} + +.compass.active .active .direction { + fill: #999; +} + +circle.point { + fill-opacity: 1; + fill: #70AFC4; +} + +text.label { + font-size: 11px; + fill: #FFF; + font-weight: bold; + text-anchor: middle; + opacity: 0; +} + +path.label { + fill: #000; + stroke: #000; + opacity: 0; +} + +g.point:hover text.label, g.point:hover path.label { + opacity: 1.0; + -webkit-transition: opacity 0.2s linear; +} + +g.point:hover circle.point { + fill: #C90134; +} diff --git a/public/index.html b/public/index.html index 4d3bb4c..b3e9b7e 100644 --- a/public/index.html +++ b/public/index.html @@ -13,18 +13,21 @@ - + + + Hummingbird + @@ -59,6 +62,10 @@

Cart Traffic:

+
+ +
+ - + diff --git a/public/js/polymaps.js b/public/js/polymaps.js index 69f10cd..fc02500 100755 --- a/public/js/polymaps.js +++ b/public/js/polymaps.js @@ -1173,7 +1173,7 @@ po.geoJson = function(fetch) { a.setAttribute("begin", "indefinite"); a.setAttribute("type", "scale"); a.setAttribute("attributeName", "r"); - a.setAttribute("values", "0;10"); + a.setAttribute("values", "0;20;10"); a.setAttribute("fill", "freeze"); a.setAttribute("dur", "3s"); circle.appendChild(a); @@ -1186,22 +1186,53 @@ po.geoJson = function(fetch) { g.addEventListener("mouseover", function(e) { var el = e.target.parentNode; el.parentNode.appendChild(el); - }); + }, true); if(o.text) { var t = po.svg("text"); - var b = po.svg("path"); - b.setAttribute("d", "M351,269.5L346,264.5L334,264.5A5,5,0,0,1,329,259.5L329,257.5L329,252.5L329,247.5L329,245.5A5,5,0,0,1,334,240.5L346,240.5L351,240.5L356,240.5L368,240.5A5,5,0,0,1,373,245.5L373,247.5L373,252.5L373,257.5L373,259.5A5,5,0,0,1,368,264.5L356,264.5Z"); - b.setAttribute("class", "label"); - b.setAttribute("transform", "translate(" + (p.x - 351) + "," + (p.y - r - 273) + ")"); t.textContent = o.text; t.setAttribute("class", "label"); t.setAttribute("transform", "translate(" + p.x + "," + (p.y - r - 18) + ")"); - g.appendChild(b); g.appendChild(t); + + setTimeout(function() { + console.log(); + var b = po.svg("path"); + var textWidth = (t.getBBox().width / 2) + 6; + + var bg = ""; + bg += "M 0, 29"; + bg += "L -5, 24"; + bg += "L " + (-1 * (textWidth - 5)) + ", 24"; + bg += "A 5, 5, 0, 0, 1, " + (-1 * textWidth) + ", 19"; + bg += "L " + (-1 * textWidth) + ", 17"; + bg += "L " + (-1 * textWidth) + ", 12"; + bg += "L " + (-1 * textWidth) + ", 7"; + bg += "L " + (-1 * textWidth) + ", 5"; + bg += "A 5, 5, 0, 0, 1, " + (-1 * (textWidth - 5)) + ", 0"; + bg += "L 5, 0"; + bg += "L 0, 0"; + bg += "L 5, 0"; + bg += "L " + (textWidth - 5) + ", 0"; + bg += "A 5, 5, 0, 0, 1, " + textWidth + ", 5"; + bg += "L " + textWidth + ", 7"; + bg += "L " + textWidth + ", 12"; + bg += "L " + textWidth + ", 17"; + bg += "L " + textWidth + ", 19"; + bg += "A 5, 5, 0, 0, 1, " + (textWidth - 5) + ", 24"; + bg += "L 5, 24"; + bg += "Z"; + + b.setAttribute("d", bg); + b.setAttribute("class", "label"); + b.setAttribute("transform", "translate(" + (p.x) + "," + (p.y - r - 32) + ")"); + g.appendChild(b); + g.appendChild(t); + }, 5); + } - a.beginElement(); + if(a.beginElement) { a.beginElement(); } setTimeout(function() { var toRemove = g.parentNode.parentNode.parentNode; diff --git a/public/js/raphael.js b/public/js/raphael.js new file mode 100644 index 0000000..e5e7126 --- /dev/null +++ b/public/js/raphael.js @@ -0,0 +1,7 @@ +/* + * Raphael 1.5.2 - JavaScript Vector Library + * + * Copyright (c) 2010 Dmitry Baranovskiy (http://raphaeljs.com) + * Licensed under the MIT (http://raphaeljs.com/license.html) license. + */ +(function(){function a(){if(a.is(arguments[0],G)){var b=arguments[0],d=bV[m](a,b.splice(0,3+a.is(b[0],E))),e=d.set();for(var g=0,h=b[w];g";bg=bf.firstChild;bg.style.behavior="url(#default#VML)";if(!(bg&&typeof bg.adj=="object"))return a.type=null;bf=null}a.svg=!(a.vml=a.type=="VML");j[e]=a[e];k=j[e];a._id=0;a._oid=0;a.fn={};a.is=function(a,b){b=x.call(b);if(b=="finite")return!O[f](+a);return b=="null"&&a===null||b==typeof a||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||J.call(a).slice(8,-1).toLowerCase()==b};a.angle=function(b,c,d,e,f,g){{if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return((h<0)*180+y.atan(-i/-h)*180/D+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)}};a.rad=function(a){return a%360*D/180};a.deg=function(a){return a*180/D%360};a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,G)){var e=b.length;while(e--)if(B(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c};function bh(){var a=[],b=0;for(;b<32;b++)a[b]=(~(~(y.random()*16)))[H](16);a[12]=4;a[16]=(a[16]&3|8)[H](16);return"r-"+a[v]("")}a.setWindow=function(a){h=a;g=h.document};var bi=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write("");e.close();d=e.body}catch(a){d=createPopup().document.body}var f=d.createTextRange();bi=bm(function(a){try{d.style.color=r(a)[Y](c,p);var b=f.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b[H](16)).slice(-6)}catch(a){return"none"}})}else{var h=g.createElement("i");h.title="Raphaël Colour Picker";h.style.display="none";g.body[l](h);bi=bm(function(a){h.style.color=a;return g.defaultView.getComputedStyle(h,p).getPropertyValue("color")})}return bi(b)},bj=function(){return"hsb("+[this.h,this.s,this.b]+")"},bk=function(){return"hsl("+[this.h,this.s,this.l]+")"},bl=function(){return this.hex};a.hsb2rgb=function(b,c,d,e){if(a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b){d=b.b;c=b.s;b=b.h;e=b.o}return a.hsl2rgb(b,c,d/2,e)};a.hsl2rgb=function(b,c,d,e){if(a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b){d=b.l;c=b.s;b=b.h}if(b>1||c>1||d>1){b/=360;c/=100;d/=100}var f={},g=["r","g","b"],h,i,j,k,l,m;if(c){d<0.5?h=d*(1+c):h=d+c-d*c;i=2*d-h;for(var n=0;n<3;n++){j=b+1/3*-(n-1);j<0&&j++;j>1&&j--;j*6<1?f[g[n]]=i+(h-i)*6*j:j*2<1?f[g[n]]=h:j*3<2?f[g[n]]=i+(h-i)*(2/3-j)*6:f[g[n]]=i}}else f={r:d,g:d,b:d};f.r*=255;f.g*=255;f.b*=255;f.hex="#"+(16777216|f.b|f.g<<8|f.r<<16).toString(16).slice(1);a.is(e,"finite")&&(f.opacity=e);f.toString=bl;return f};a.rgb2hsb=function(b,c,d){if(c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b){d=b.b;c=b.g;b=b.r}if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r;c=e.g;d=e.b}if(b>1||c>1||d>1){b/=255;c/=255;d/=255}var f=z(b,c,d),g=A(b,c,d),h,i,j=f;{if(g==f)return{h:0,s:0,b:f,toString:bj};var k=f-g;i=k/f;b==f?h=(c-d)/k:c==f?h=2+(d-b)/k:h=4+(b-c)/k;h/=6;h<0&&h++;h>1&&h--}return{h:h,s:i,b:j,toString:bj}};a.rgb2hsl=function(b,c,d){if(c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b){d=b.b;c=b.g;b=b.r}if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r;c=e.g;d=e.b}if(b>1||c>1||d>1){b/=255;c/=255;d/=255}var f=z(b,c,d),g=A(b,c,d),h,i,j=(f+g)/2,k;if(g==f)k={h:0,s:0,l:j};else{var l=f-g;i=j<0.5?l/(f+g):l/(2-f-g);b==f?h=(c-d)/l:c==f?h=2+(d-b)/l:h=4+(b-c)/l;h/=6;h<0&&h++;h>1&&h--;k={h:h,s:i,l:j}}k.toString=bk;return k};a._path2string=function(){return this.join(",")[Y](ba,"$1")};function bm(a,b,c){function d(){var g=Array[e].slice.call(arguments,0),h=g[v]("►"),i=d.cache=d.cache||{},j=d.count=d.count||[];if(i[f](h))return c?c(i[h]):i[h];j[w]>=1000&&delete i[j.shift()];j[L](h);i[h]=a[m](b,g);return c?c(i[h]):i[h]}return d}a.getRGB=bm(function(b){if(!b||!(!((b=r(b)).indexOf("-")+1)))return{r:-1,g:-1,b:-1,hex:"none",error:1};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none"};!(_[f](b.toLowerCase().substring(0,2))||b.charAt()=="#")&&(b=bi(b));var c,d,e,g,h,i,j,k=b.match(N);if(k){if(k[2]){g=T(k[2].substring(5),16);e=T(k[2].substring(3,5),16);d=T(k[2].substring(1,3),16)}if(k[3]){g=T((i=k[3].charAt(3))+i,16);e=T((i=k[3].charAt(2))+i,16);d=T((i=k[3].charAt(1))+i,16)}if(k[4]){j=k[4][s]($);d=S(j[0]);j[0].slice(-1)=="%"&&(d*=2.55);e=S(j[1]);j[1].slice(-1)=="%"&&(e*=2.55);g=S(j[2]);j[2].slice(-1)=="%"&&(g*=2.55);k[1].toLowerCase().slice(0,4)=="rgba"&&(h=S(j[3]));j[3]&&j[3].slice(-1)=="%"&&(h/=100)}if(k[5]){j=k[5][s]($);d=S(j[0]);j[0].slice(-1)=="%"&&(d*=2.55);e=S(j[1]);j[1].slice(-1)=="%"&&(e*=2.55);g=S(j[2]);j[2].slice(-1)=="%"&&(g*=2.55);(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360);k[1].toLowerCase().slice(0,4)=="hsba"&&(h=S(j[3]));j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,g,h)}if(k[6]){j=k[6][s]($);d=S(j[0]);j[0].slice(-1)=="%"&&(d*=2.55);e=S(j[1]);j[1].slice(-1)=="%"&&(e*=2.55);g=S(j[2]);j[2].slice(-1)=="%"&&(g*=2.55);(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360);k[1].toLowerCase().slice(0,4)=="hsla"&&(h=S(j[3]));j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,g,h)}k={r:d,g:e,b:g};k.hex="#"+(16777216|g|e<<8|d<<16).toString(16).slice(1);a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1}},a);a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||0.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=0.075;if(b.h>1){b.h=0;b.s-=0.2;b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b})}return c.hex};a.getColor.reset=function(){delete this.start};a.parsePathString=bm(function(b){if(!b)return null;var c={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},d=[];a.is(b,G)&&a.is(b[0],G)&&(d=bo(b));d[w]||r(b)[Y](bb,function(a,b,e){var f=[],g=x.call(b);e[Y](bc,function(a,b){b&&f[L](+b)});if(g=="m"&&f[w]>2){d[L]([b][n](f.splice(0,2)));g="l";b=b=="m"?"l":"L"}while(f[w]>=c[g]){d[L]([b][n](f.splice(0,c[g])));if(!c[g])break}});d[H]=a._path2string;return d});a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=C(j,3)*a+C(j,2)*3*i*c+j*3*i*i*e+C(i,3)*g,l=C(j,3)*b+C(j,2)*3*i*d+j*3*i*i*f+C(i,3)*h,m=a+2*i*(c-a)+i*i*(e-2*c+a),n=b+2*i*(d-b)+i*i*(f-2*d+b),o=c+2*i*(e-c)+i*i*(g-2*e+c),p=d+2*i*(f-d)+i*i*(h-2*f+d),q=(1-i)*a+i*c,r=(1-i)*b+i*d,s=(1-i)*e+i*g,t=(1-i)*f+i*h,u=90-y.atan((m-o)/(n-p))*180/D;(m>o||n1){x=y.sqrt(x);c=x*c;d=x*d}var z=c*c,A=d*d,C=(f==g?-1:1)*y.sqrt(B((z*A-z*u*u-A*t*t)/(z*u*u+A*t*t))),E=C*c*u/d+(a+h)/2,F=C*-d*t/c+(b+i)/2,G=y.asin(((b-F)/d).toFixed(9)),H=y.asin(((i-F)/d).toFixed(9));G=aH&&(G=G-D*2);!g&&H>G&&(H=H-D*2)}var I=H-G;if(B(I)>k){var J=H,K=h,L=i;H=G+k*(g&&H>G?1:-1);h=E+c*y.cos(H);i=F+d*y.sin(H);m=bt(h,i,c,d,e,0,g,K,L,[H,J,E,F])}I=H-G;var M=y.cos(G),N=y.sin(G),O=y.cos(H),P=y.sin(H),Q=y.tan(I/4),R=4/3*c*Q,S=4/3*d*Q,T=[a,b],U=[a+R*N,b-S*M],V=[h+R*P,i-S*O],W=[h,i];U[0]=2*T[0]-U[0];U[1]=2*T[1]-U[1];{if(j)return[U,V,W][n](m);m=[U,V,W][n](m)[v]()[s](",");var X=[];for(var Y=0,Z=m[w];Y"1e12"&&(l=0.5);B(n)>"1e12"&&(n=0.5);if(l>0&&l<1){q=bu(a,b,c,d,e,f,g,h,l);p[L](q.x);o[L](q.y)}if(n>0&&n<1){q=bu(a,b,c,d,e,f,g,h,n);p[L](q.x);o[L](q.y)}i=f-2*d+b-(h-2*f+d);j=2*(d-b)-2*(f-d);k=b-d;l=(-j+y.sqrt(j*j-4*i*k))/2/i;n=(-j-y.sqrt(j*j-4*i*k))/2/i;B(l)>"1e12"&&(l=0.5);B(n)>"1e12"&&(n=0.5);if(l>0&&l<1){q=bu(a,b,c,d,e,f,g,h,l);p[L](q.x);o[L](q.y)}if(n>0&&n<1){q=bu(a,b,c,d,e,f,g,h,n);p[L](q.x);o[L](q.y)}return{min:{x:A[m](0,p),y:A[m](0,o)},max:{x:z[m](0,p),y:z[m](0,o)}}}),bw=bm(function(a,b){var c=bq(a),d=b&&bq(b),e={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1];b.Y=a[2];break;case"A":a=["C"][n](bt[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x));d=b.y+(b.y-(b.by||b.y));a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x));b.qy=b.y+(b.y-(b.qy||b.y));a=["C"][n](bs(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1];b.qy=a[2];a=["C"][n](bs(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](br(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](br(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](br(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](br(b.x,b.y,b.X,b.Y));break}return a},h=function(a,b){if(a[b][w]>7){a[b].shift();var e=a[b];while(e[w])a.splice(b++,0,["C"][n](e.splice(0,6)));a.splice(b,1);k=z(c[w],d&&d[w]||0)}},i=function(a,b,e,f,g){if(a&&b&&a[g][0]=="M"&&b[g][0]!="M"){b.splice(g,0,["M",f.x,f.y]);e.bx=0;e.by=0;e.x=a[g][1];e.y=a[g][2];k=z(c[w],d&&d[w]||0)}};for(var j=0,k=z(c[w],d&&d[w]||0);j0.5)*2-1;C(e-0.5,2)+C(f-0.5,2)>0.25&&(f=y.sqrt(0.25-C(e-0.5,2))*g+0.5)&&f!=0.5&&(f=f.toFixed(5)-0.00001*g)}return p});b=b[s](/\s*\-\s*/);if(d=="linear"){var i=b.shift();i=-S(i);if(isNaN(i))return null;var j=[0,0,y.cos(i*D/180),y.sin(i*D/180)],k=1/(z(B(j[2]),B(j[3]))||1);j[2]*=k;j[3]*=k;if(j[2]<0){j[0]=-j[2];j[2]=0}if(j[3]<0){j[1]=-j[3];j[3]=0}}var m=bx(b);if(!m)return null;var n=a.getAttribute(I);n=n.match(/^url\(#(.*)\)$/);n&&c.defs.removeChild(g.getElementById(n[1]));var o=bG(d+"Gradient");o.id=bh();bG(o,d=="radial"?{fx:e,fy:f}:{x1:j[0],y1:j[1],x2:j[2],y2:j[3]});c.defs[l](o);for(var q=0,t=m[w];q1?G.opacity/100:G.opacity});case"stroke":G=a.getRGB(o);h[R](n,G.hex);n=="stroke"&&G[f]("opacity")&&bG(h,{"stroke-opacity":G.opacity>1?G.opacity/100:G.opacity});break;case"gradient":(({circle:1,ellipse:1})[f](c.type)||r(o).charAt()!="r")&&bI(h,o,c.paper);break;case"opacity":i.gradient&&!i[f]("stroke-opacity")&&bG(h,{"stroke-opacity":o>1?o/100:o});case"fill-opacity":if(i.gradient){var H=g.getElementById(h.getAttribute(I)[Y](/^url\(#|\)$/g,p));if(H){var J=H.getElementsByTagName("stop");J[J[w]-1][R]("stop-opacity",o)}break}default:n=="font-size"&&(o=T(o,10)+"px");var K=n[Y](/(\-.)/g,function(a){return V.call(a.substring(1))});h.style[K]=o;h[R](n,o);break}}}bM(c,d);m?c.rotate(m.join(q)):S(j)&&c.rotate(j,true)},bL=1.2,bM=function(b,c){if(b.type!="text"||!(c[f]("text")||c[f]("font")||c[f]("font-size")||c[f]("x")||c[f]("y")))return;var d=b.attrs,e=b.node,h=e.firstChild?T(g.defaultView.getComputedStyle(e.firstChild,p).getPropertyValue("font-size"),10):10;if(c[f]("text")){d.text=c.text;while(e.firstChild)e.removeChild(e.firstChild);var i=r(c.text)[s]("\n");for(var j=0,k=i[w];jb.height&&(b.height=e.y+e.height-b.y);e.x+e.width-b.x>b.width&&(b.width=e.x+e.width-b.x)}}a&&this.hide();return b};bN[e].attr=function(b,c){if(this.removed)return this;if(b==null){var d={};for(var e in this.attrs)this.attrs[f](e)&&(d[e]=this.attrs[e]);this._.rt.deg&&(d.rotation=this.rotate());(this._.sx!=1||this._.sy!=1)&&(d.scale=this.scale());d.gradient&&d.fill=="none"&&(d.fill=d.gradient)&&delete d.gradient;return d}if(c==null&&a.is(b,F)){if(b=="translation")return cz.call(this);if(b=="rotation")return this.rotate();if(b=="scale")return this.scale();if(b==I&&this.attrs.fill=="none"&&this.attrs.gradient)return this.attrs.gradient;return this.attrs[b]}if(c==null&&a.is(b,G)){var g={};for(var h=0,i=b.length;h"));m.W=h.w=m.paper.span.offsetWidth;m.H=h.h=m.paper.span.offsetHeight;m.X=h.x;m.Y=h.y+Q(m.H/2);switch(h["text-anchor"]){case"start":m.node.style["v-text-align"]="left";m.bbx=Q(m.W/2);break;case"end":m.node.style["v-text-align"]="right";m.bbx=-Q(m.W/2);break;default:m.node.style["v-text-align"]="center";break}}};bI=function(a,b){a.attrs=a.attrs||{};var c=a.attrs,d,e="linear",f=".5 .5";a.attrs.gradient=b;b=r(b)[Y](bd,function(a,b,c){e="radial";if(b&&c){b=S(b);c=S(c);C(b-0.5,2)+C(c-0.5,2)>0.25&&(c=y.sqrt(0.25-C(b-0.5,2))*((c>0.5)*2-1)+0.5);f=b+q+c}return p});b=b[s](/\s*\-\s*/);if(e=="linear"){var g=b.shift();g=-S(g);if(isNaN(g))return null}var h=bx(b);if(!h)return null;a=a.shape||a.node;d=a.getElementsByTagName(I)[0]||cd(I);!d.parentNode&&a.appendChild(d);if(h[w]){d.on=true;d.method="none";d.color=h[0].color;d.color2=h[h[w]-1].color;var i=[];for(var j=0,k=h[w];j")}}catch(a){cd=function(a){return g.createElement("<"+a+" xmlns=\"urn:schemas-microsoft.com:vml\" class=\"rvml\">")}}bV=function(){var b=by[m](0,arguments),c=b.container,d=b.height,e,f=b.width,h=b.x,i=b.y;if(!c)throw new Error("VML container not found.");var k=new j,n=k.canvas=g.createElement("div"),o=n.style;h=h||0;i=i||0;f=f||512;d=d||342;f==+f&&(f+="px");d==+d&&(d+="px");k.width=1000;k.height=1000;k.coordsize=b_*1000+q+b_*1000;k.coordorigin="0 0";k.span=g.createElement("span");k.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";n[l](k.span);o.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d);if(c==1){g.body[l](n);o.left=h+"px";o.top=i+"px";o.position="absolute"}else c.firstChild?c.insertBefore(n,c.firstChild):c[l](n);bz.call(k,k,a.fn);return k};k.clear=function(){this.canvas.innerHTML=p;this.span=g.createElement("span");this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";this.canvas[l](this.span);this.bottom=this.top=null};k.remove=function(){this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]=bF(a);return true}}var ce=navigator.userAgent.match(/Version\\x2f(.*?)\s/);navigator.vendor=="Apple Computer, Inc."&&(ce&&ce[1]<4||navigator.platform.slice(0,2)=="iP")?k.safari=function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:"none"});h.setTimeout(function(){a.remove()})}:k.safari=function(){};var cf=function(){this.returnValue=false},cg=function(){return this.originalEvent.preventDefault()},ch=function(){this.cancelBubble=true},ci=function(){return this.originalEvent.stopPropagation()},cj=(function(){{if(g.addEventListener)return function(a,b,c,d){var e=o&&u[b]?u[b]:b,g=function(e){if(o&&u[f](b))for(var g=0,h=e.targetTouches&&e.targetTouches.length;g1&&(a=Array[e].splice.call(arguments,0,arguments[w]));return new cC(a)};k.setSize=bU;k.top=k.bottom=null;k.raphael=a;function co(){return this.x+q+this.y}bO.resetScale=function(){if(this.removed)return this;this._.sx=1;this._.sy=1;this.attrs.scale="1 1"};bO.scale=function(a,b,c,d){if(this.removed)return this;if(a==null&&b==null)return{x:this._.sx,y:this._.sy,toString:co};b=b||a;!(+b)&&(b=a);var e,f,g,h,i=this.attrs;if(a!=0){var j=this.getBBox(),k=j.x+j.width/2,l=j.y+j.height/2,m=B(a/this._.sx),o=B(b/this._.sy);c=+c||c==0?c:k;d=+d||d==0?d:l;var r=this._.sx>0,s=this._.sy>0,t=~(~(a/B(a))),u=~(~(b/B(b))),x=m*t,y=o*u,z=this.node.style,A=c+B(k-c)*x*(k>c==r?1:-1),C=d+B(l-d)*y*(l>d==s?1:-1),D=a*t>b*u?o:m;switch(this.type){case"rect":case"image":var E=i.width*m,F=i.height*o;this.attr({height:F,r:i.r*D,width:E,x:A-E/2,y:C-F/2});break;case"circle":case"ellipse":this.attr({rx:i.rx*m,ry:i.ry*o,r:i.r*D,cx:A,cy:C});break;case"text":this.attr({x:A,y:C});break;case"path":var G=bp(i.path),H=true,I=r?x:m,J=s?y:o;for(var K=0,L=G[w];Kr)p=n.data[r*l];else{p=a.findDotsAtSegment(b,c,d,e,f,g,h,i,r/l);n.data[r]=p}r&&(k+=C(C(o.x-p.x,2)+C(o.y-p.y,2),0.5));if(j!=null&&k>=j)return p;o=p}if(j==null)return k},cr=function(b,c){return function(d,e,f){d=bw(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;oe){if(c&&!l.start){m=cq(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);k+=["C",m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k;k=["M",m.x,m.y+"C",m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]][v]();n+=j;g=+i[5];h=+i[6];continue}if(!b&&!c){m=cq(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j;g=+i[5];h=+i[6]}k+=i}l.end=k;m=b?n:c?l:a.findDotsAtSegment(g,h,i[1],i[2],i[3],i[4],i[5],i[6],1);m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},cs=cr(1),ct=cr(),cu=cr(0,1);bO.getTotalLength=function(){if(this.type!="path")return;if(this.node.getTotalLength)return this.node.getTotalLength();return cs(this.attrs.path)};bO.getPointAtLength=function(a){if(this.type!="path")return;return ct(this.attrs.path,a)};bO.getSubpath=function(a,b){if(this.type!="path")return;if(B(this.getTotalLength()-b)<"1e-6")return cu(this.attrs.path,a).end;var c=cu(this.attrs.path,b,1);return a?cu(c,a).end:c};a.easing_formulas={linear:function(a){return a},"<":function(a){return C(a,3)},">":function(a){return C(a-1,3)+1},"<>":function(a){a=a*2;if(a<1)return C(a,3)/2;a-=2;return(C(a,3)+2)/2},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==0||a==1)return a;var b=0.3,c=b/4;return C(2,-10*a)*y.sin((a-c)*(2*D)/b)+1},bounce:function(a){var b=7.5625,c=2.75,d;if(a<1/c)d=b*a*a;else if(a<2/c){a-=1.5/c;d=b*a*a+0.75}else if(a<2.5/c){a-=2.25/c;d=b*a*a+0.9375}else{a-=2.625/c;d=b*a*a+0.984375}return d}};var cv=[],cw=function(){var b=+(new Date);for(var c=0;cd)return d;while(cf?c=e:d=e;e=(d-c)/2+c}return e}return n(a,1/(200*f))}bO.onAnimation=function(a){this._run=a||0;return this};bO.animate=function(c,d,e,g){var h=this;h.timeouts=h.timeouts||[];if(a.is(e,"function")||!e)g=e||null;if(h.removed){g&&g.call(h);return h}var i={},j={},k=false,l={};for(var m in c)if(c[f](m)){if(X[f](m)||h.paper.customAttributes[f](m)){k=true;i[m]=h.attr(m);i[m]==null&&(i[m]=W[m]);j[m]=c[m];switch(X[m]){case"along":var n=cs(c[m]),o=ct(c[m],n*!(!c.back)),p=h.getBBox();l[m]=n/d;l.tx=p.x;l.ty=p.y;l.sx=o.x;l.sy=o.y;j.rot=c.rot;j.back=c.back;j.len=n;c.rot&&(l.r=S(h.rotate())||0);break;case E:l[m]=(j[m]-i[m])/d;break;case"colour":i[m]=a.getRGB(i[m]);var q=a.getRGB(j[m]);l[m]={r:(q.r-i[m].r)/d,g:(q.g-i[m].g)/d,b:(q.b-i[m].b)/d};break;case"path":var t=bw(i[m],j[m]);i[m]=t[0];var u=t[1];l[m]=[];for(var v=0,x=i[m][w];v Date: Sat, 30 Oct 2010 01:52:37 -0400 Subject: [PATCH 171/267] just kidding, remove raphael. the integration with polymaps looks complicated --- public/index.html | 1 - public/js/raphael.js | 7 ------- public/js/widgets/map.js | 1 - 3 files changed, 9 deletions(-) delete mode 100644 public/js/raphael.js diff --git a/public/index.html b/public/index.html index dcda5d1..3015350 100644 --- a/public/index.html +++ b/public/index.html @@ -14,7 +14,6 @@ - diff --git a/public/js/raphael.js b/public/js/raphael.js deleted file mode 100644 index e5e7126..0000000 --- a/public/js/raphael.js +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Raphael 1.5.2 - JavaScript Vector Library - * - * Copyright (c) 2010 Dmitry Baranovskiy (http://raphaeljs.com) - * Licensed under the MIT (http://raphaeljs.com/license.html) license. - */ -(function(){function a(){if(a.is(arguments[0],G)){var b=arguments[0],d=bV[m](a,b.splice(0,3+a.is(b[0],E))),e=d.set();for(var g=0,h=b[w];g";bg=bf.firstChild;bg.style.behavior="url(#default#VML)";if(!(bg&&typeof bg.adj=="object"))return a.type=null;bf=null}a.svg=!(a.vml=a.type=="VML");j[e]=a[e];k=j[e];a._id=0;a._oid=0;a.fn={};a.is=function(a,b){b=x.call(b);if(b=="finite")return!O[f](+a);return b=="null"&&a===null||b==typeof a||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||J.call(a).slice(8,-1).toLowerCase()==b};a.angle=function(b,c,d,e,f,g){{if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return((h<0)*180+y.atan(-i/-h)*180/D+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)}};a.rad=function(a){return a%360*D/180};a.deg=function(a){return a*180/D%360};a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,G)){var e=b.length;while(e--)if(B(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c};function bh(){var a=[],b=0;for(;b<32;b++)a[b]=(~(~(y.random()*16)))[H](16);a[12]=4;a[16]=(a[16]&3|8)[H](16);return"r-"+a[v]("")}a.setWindow=function(a){h=a;g=h.document};var bi=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write("");e.close();d=e.body}catch(a){d=createPopup().document.body}var f=d.createTextRange();bi=bm(function(a){try{d.style.color=r(a)[Y](c,p);var b=f.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b[H](16)).slice(-6)}catch(a){return"none"}})}else{var h=g.createElement("i");h.title="Raphaël Colour Picker";h.style.display="none";g.body[l](h);bi=bm(function(a){h.style.color=a;return g.defaultView.getComputedStyle(h,p).getPropertyValue("color")})}return bi(b)},bj=function(){return"hsb("+[this.h,this.s,this.b]+")"},bk=function(){return"hsl("+[this.h,this.s,this.l]+")"},bl=function(){return this.hex};a.hsb2rgb=function(b,c,d,e){if(a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b){d=b.b;c=b.s;b=b.h;e=b.o}return a.hsl2rgb(b,c,d/2,e)};a.hsl2rgb=function(b,c,d,e){if(a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b){d=b.l;c=b.s;b=b.h}if(b>1||c>1||d>1){b/=360;c/=100;d/=100}var f={},g=["r","g","b"],h,i,j,k,l,m;if(c){d<0.5?h=d*(1+c):h=d+c-d*c;i=2*d-h;for(var n=0;n<3;n++){j=b+1/3*-(n-1);j<0&&j++;j>1&&j--;j*6<1?f[g[n]]=i+(h-i)*6*j:j*2<1?f[g[n]]=h:j*3<2?f[g[n]]=i+(h-i)*(2/3-j)*6:f[g[n]]=i}}else f={r:d,g:d,b:d};f.r*=255;f.g*=255;f.b*=255;f.hex="#"+(16777216|f.b|f.g<<8|f.r<<16).toString(16).slice(1);a.is(e,"finite")&&(f.opacity=e);f.toString=bl;return f};a.rgb2hsb=function(b,c,d){if(c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b){d=b.b;c=b.g;b=b.r}if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r;c=e.g;d=e.b}if(b>1||c>1||d>1){b/=255;c/=255;d/=255}var f=z(b,c,d),g=A(b,c,d),h,i,j=f;{if(g==f)return{h:0,s:0,b:f,toString:bj};var k=f-g;i=k/f;b==f?h=(c-d)/k:c==f?h=2+(d-b)/k:h=4+(b-c)/k;h/=6;h<0&&h++;h>1&&h--}return{h:h,s:i,b:j,toString:bj}};a.rgb2hsl=function(b,c,d){if(c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b){d=b.b;c=b.g;b=b.r}if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r;c=e.g;d=e.b}if(b>1||c>1||d>1){b/=255;c/=255;d/=255}var f=z(b,c,d),g=A(b,c,d),h,i,j=(f+g)/2,k;if(g==f)k={h:0,s:0,l:j};else{var l=f-g;i=j<0.5?l/(f+g):l/(2-f-g);b==f?h=(c-d)/l:c==f?h=2+(d-b)/l:h=4+(b-c)/l;h/=6;h<0&&h++;h>1&&h--;k={h:h,s:i,l:j}}k.toString=bk;return k};a._path2string=function(){return this.join(",")[Y](ba,"$1")};function bm(a,b,c){function d(){var g=Array[e].slice.call(arguments,0),h=g[v]("►"),i=d.cache=d.cache||{},j=d.count=d.count||[];if(i[f](h))return c?c(i[h]):i[h];j[w]>=1000&&delete i[j.shift()];j[L](h);i[h]=a[m](b,g);return c?c(i[h]):i[h]}return d}a.getRGB=bm(function(b){if(!b||!(!((b=r(b)).indexOf("-")+1)))return{r:-1,g:-1,b:-1,hex:"none",error:1};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none"};!(_[f](b.toLowerCase().substring(0,2))||b.charAt()=="#")&&(b=bi(b));var c,d,e,g,h,i,j,k=b.match(N);if(k){if(k[2]){g=T(k[2].substring(5),16);e=T(k[2].substring(3,5),16);d=T(k[2].substring(1,3),16)}if(k[3]){g=T((i=k[3].charAt(3))+i,16);e=T((i=k[3].charAt(2))+i,16);d=T((i=k[3].charAt(1))+i,16)}if(k[4]){j=k[4][s]($);d=S(j[0]);j[0].slice(-1)=="%"&&(d*=2.55);e=S(j[1]);j[1].slice(-1)=="%"&&(e*=2.55);g=S(j[2]);j[2].slice(-1)=="%"&&(g*=2.55);k[1].toLowerCase().slice(0,4)=="rgba"&&(h=S(j[3]));j[3]&&j[3].slice(-1)=="%"&&(h/=100)}if(k[5]){j=k[5][s]($);d=S(j[0]);j[0].slice(-1)=="%"&&(d*=2.55);e=S(j[1]);j[1].slice(-1)=="%"&&(e*=2.55);g=S(j[2]);j[2].slice(-1)=="%"&&(g*=2.55);(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360);k[1].toLowerCase().slice(0,4)=="hsba"&&(h=S(j[3]));j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,g,h)}if(k[6]){j=k[6][s]($);d=S(j[0]);j[0].slice(-1)=="%"&&(d*=2.55);e=S(j[1]);j[1].slice(-1)=="%"&&(e*=2.55);g=S(j[2]);j[2].slice(-1)=="%"&&(g*=2.55);(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360);k[1].toLowerCase().slice(0,4)=="hsla"&&(h=S(j[3]));j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,g,h)}k={r:d,g:e,b:g};k.hex="#"+(16777216|g|e<<8|d<<16).toString(16).slice(1);a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1}},a);a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||0.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=0.075;if(b.h>1){b.h=0;b.s-=0.2;b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b})}return c.hex};a.getColor.reset=function(){delete this.start};a.parsePathString=bm(function(b){if(!b)return null;var c={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},d=[];a.is(b,G)&&a.is(b[0],G)&&(d=bo(b));d[w]||r(b)[Y](bb,function(a,b,e){var f=[],g=x.call(b);e[Y](bc,function(a,b){b&&f[L](+b)});if(g=="m"&&f[w]>2){d[L]([b][n](f.splice(0,2)));g="l";b=b=="m"?"l":"L"}while(f[w]>=c[g]){d[L]([b][n](f.splice(0,c[g])));if(!c[g])break}});d[H]=a._path2string;return d});a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=C(j,3)*a+C(j,2)*3*i*c+j*3*i*i*e+C(i,3)*g,l=C(j,3)*b+C(j,2)*3*i*d+j*3*i*i*f+C(i,3)*h,m=a+2*i*(c-a)+i*i*(e-2*c+a),n=b+2*i*(d-b)+i*i*(f-2*d+b),o=c+2*i*(e-c)+i*i*(g-2*e+c),p=d+2*i*(f-d)+i*i*(h-2*f+d),q=(1-i)*a+i*c,r=(1-i)*b+i*d,s=(1-i)*e+i*g,t=(1-i)*f+i*h,u=90-y.atan((m-o)/(n-p))*180/D;(m>o||n1){x=y.sqrt(x);c=x*c;d=x*d}var z=c*c,A=d*d,C=(f==g?-1:1)*y.sqrt(B((z*A-z*u*u-A*t*t)/(z*u*u+A*t*t))),E=C*c*u/d+(a+h)/2,F=C*-d*t/c+(b+i)/2,G=y.asin(((b-F)/d).toFixed(9)),H=y.asin(((i-F)/d).toFixed(9));G=aH&&(G=G-D*2);!g&&H>G&&(H=H-D*2)}var I=H-G;if(B(I)>k){var J=H,K=h,L=i;H=G+k*(g&&H>G?1:-1);h=E+c*y.cos(H);i=F+d*y.sin(H);m=bt(h,i,c,d,e,0,g,K,L,[H,J,E,F])}I=H-G;var M=y.cos(G),N=y.sin(G),O=y.cos(H),P=y.sin(H),Q=y.tan(I/4),R=4/3*c*Q,S=4/3*d*Q,T=[a,b],U=[a+R*N,b-S*M],V=[h+R*P,i-S*O],W=[h,i];U[0]=2*T[0]-U[0];U[1]=2*T[1]-U[1];{if(j)return[U,V,W][n](m);m=[U,V,W][n](m)[v]()[s](",");var X=[];for(var Y=0,Z=m[w];Y"1e12"&&(l=0.5);B(n)>"1e12"&&(n=0.5);if(l>0&&l<1){q=bu(a,b,c,d,e,f,g,h,l);p[L](q.x);o[L](q.y)}if(n>0&&n<1){q=bu(a,b,c,d,e,f,g,h,n);p[L](q.x);o[L](q.y)}i=f-2*d+b-(h-2*f+d);j=2*(d-b)-2*(f-d);k=b-d;l=(-j+y.sqrt(j*j-4*i*k))/2/i;n=(-j-y.sqrt(j*j-4*i*k))/2/i;B(l)>"1e12"&&(l=0.5);B(n)>"1e12"&&(n=0.5);if(l>0&&l<1){q=bu(a,b,c,d,e,f,g,h,l);p[L](q.x);o[L](q.y)}if(n>0&&n<1){q=bu(a,b,c,d,e,f,g,h,n);p[L](q.x);o[L](q.y)}return{min:{x:A[m](0,p),y:A[m](0,o)},max:{x:z[m](0,p),y:z[m](0,o)}}}),bw=bm(function(a,b){var c=bq(a),d=b&&bq(b),e={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1];b.Y=a[2];break;case"A":a=["C"][n](bt[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x));d=b.y+(b.y-(b.by||b.y));a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x));b.qy=b.y+(b.y-(b.qy||b.y));a=["C"][n](bs(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1];b.qy=a[2];a=["C"][n](bs(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](br(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](br(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](br(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](br(b.x,b.y,b.X,b.Y));break}return a},h=function(a,b){if(a[b][w]>7){a[b].shift();var e=a[b];while(e[w])a.splice(b++,0,["C"][n](e.splice(0,6)));a.splice(b,1);k=z(c[w],d&&d[w]||0)}},i=function(a,b,e,f,g){if(a&&b&&a[g][0]=="M"&&b[g][0]!="M"){b.splice(g,0,["M",f.x,f.y]);e.bx=0;e.by=0;e.x=a[g][1];e.y=a[g][2];k=z(c[w],d&&d[w]||0)}};for(var j=0,k=z(c[w],d&&d[w]||0);j0.5)*2-1;C(e-0.5,2)+C(f-0.5,2)>0.25&&(f=y.sqrt(0.25-C(e-0.5,2))*g+0.5)&&f!=0.5&&(f=f.toFixed(5)-0.00001*g)}return p});b=b[s](/\s*\-\s*/);if(d=="linear"){var i=b.shift();i=-S(i);if(isNaN(i))return null;var j=[0,0,y.cos(i*D/180),y.sin(i*D/180)],k=1/(z(B(j[2]),B(j[3]))||1);j[2]*=k;j[3]*=k;if(j[2]<0){j[0]=-j[2];j[2]=0}if(j[3]<0){j[1]=-j[3];j[3]=0}}var m=bx(b);if(!m)return null;var n=a.getAttribute(I);n=n.match(/^url\(#(.*)\)$/);n&&c.defs.removeChild(g.getElementById(n[1]));var o=bG(d+"Gradient");o.id=bh();bG(o,d=="radial"?{fx:e,fy:f}:{x1:j[0],y1:j[1],x2:j[2],y2:j[3]});c.defs[l](o);for(var q=0,t=m[w];q1?G.opacity/100:G.opacity});case"stroke":G=a.getRGB(o);h[R](n,G.hex);n=="stroke"&&G[f]("opacity")&&bG(h,{"stroke-opacity":G.opacity>1?G.opacity/100:G.opacity});break;case"gradient":(({circle:1,ellipse:1})[f](c.type)||r(o).charAt()!="r")&&bI(h,o,c.paper);break;case"opacity":i.gradient&&!i[f]("stroke-opacity")&&bG(h,{"stroke-opacity":o>1?o/100:o});case"fill-opacity":if(i.gradient){var H=g.getElementById(h.getAttribute(I)[Y](/^url\(#|\)$/g,p));if(H){var J=H.getElementsByTagName("stop");J[J[w]-1][R]("stop-opacity",o)}break}default:n=="font-size"&&(o=T(o,10)+"px");var K=n[Y](/(\-.)/g,function(a){return V.call(a.substring(1))});h.style[K]=o;h[R](n,o);break}}}bM(c,d);m?c.rotate(m.join(q)):S(j)&&c.rotate(j,true)},bL=1.2,bM=function(b,c){if(b.type!="text"||!(c[f]("text")||c[f]("font")||c[f]("font-size")||c[f]("x")||c[f]("y")))return;var d=b.attrs,e=b.node,h=e.firstChild?T(g.defaultView.getComputedStyle(e.firstChild,p).getPropertyValue("font-size"),10):10;if(c[f]("text")){d.text=c.text;while(e.firstChild)e.removeChild(e.firstChild);var i=r(c.text)[s]("\n");for(var j=0,k=i[w];jb.height&&(b.height=e.y+e.height-b.y);e.x+e.width-b.x>b.width&&(b.width=e.x+e.width-b.x)}}a&&this.hide();return b};bN[e].attr=function(b,c){if(this.removed)return this;if(b==null){var d={};for(var e in this.attrs)this.attrs[f](e)&&(d[e]=this.attrs[e]);this._.rt.deg&&(d.rotation=this.rotate());(this._.sx!=1||this._.sy!=1)&&(d.scale=this.scale());d.gradient&&d.fill=="none"&&(d.fill=d.gradient)&&delete d.gradient;return d}if(c==null&&a.is(b,F)){if(b=="translation")return cz.call(this);if(b=="rotation")return this.rotate();if(b=="scale")return this.scale();if(b==I&&this.attrs.fill=="none"&&this.attrs.gradient)return this.attrs.gradient;return this.attrs[b]}if(c==null&&a.is(b,G)){var g={};for(var h=0,i=b.length;h"));m.W=h.w=m.paper.span.offsetWidth;m.H=h.h=m.paper.span.offsetHeight;m.X=h.x;m.Y=h.y+Q(m.H/2);switch(h["text-anchor"]){case"start":m.node.style["v-text-align"]="left";m.bbx=Q(m.W/2);break;case"end":m.node.style["v-text-align"]="right";m.bbx=-Q(m.W/2);break;default:m.node.style["v-text-align"]="center";break}}};bI=function(a,b){a.attrs=a.attrs||{};var c=a.attrs,d,e="linear",f=".5 .5";a.attrs.gradient=b;b=r(b)[Y](bd,function(a,b,c){e="radial";if(b&&c){b=S(b);c=S(c);C(b-0.5,2)+C(c-0.5,2)>0.25&&(c=y.sqrt(0.25-C(b-0.5,2))*((c>0.5)*2-1)+0.5);f=b+q+c}return p});b=b[s](/\s*\-\s*/);if(e=="linear"){var g=b.shift();g=-S(g);if(isNaN(g))return null}var h=bx(b);if(!h)return null;a=a.shape||a.node;d=a.getElementsByTagName(I)[0]||cd(I);!d.parentNode&&a.appendChild(d);if(h[w]){d.on=true;d.method="none";d.color=h[0].color;d.color2=h[h[w]-1].color;var i=[];for(var j=0,k=h[w];j")}}catch(a){cd=function(a){return g.createElement("<"+a+" xmlns=\"urn:schemas-microsoft.com:vml\" class=\"rvml\">")}}bV=function(){var b=by[m](0,arguments),c=b.container,d=b.height,e,f=b.width,h=b.x,i=b.y;if(!c)throw new Error("VML container not found.");var k=new j,n=k.canvas=g.createElement("div"),o=n.style;h=h||0;i=i||0;f=f||512;d=d||342;f==+f&&(f+="px");d==+d&&(d+="px");k.width=1000;k.height=1000;k.coordsize=b_*1000+q+b_*1000;k.coordorigin="0 0";k.span=g.createElement("span");k.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";n[l](k.span);o.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d);if(c==1){g.body[l](n);o.left=h+"px";o.top=i+"px";o.position="absolute"}else c.firstChild?c.insertBefore(n,c.firstChild):c[l](n);bz.call(k,k,a.fn);return k};k.clear=function(){this.canvas.innerHTML=p;this.span=g.createElement("span");this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";this.canvas[l](this.span);this.bottom=this.top=null};k.remove=function(){this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]=bF(a);return true}}var ce=navigator.userAgent.match(/Version\\x2f(.*?)\s/);navigator.vendor=="Apple Computer, Inc."&&(ce&&ce[1]<4||navigator.platform.slice(0,2)=="iP")?k.safari=function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:"none"});h.setTimeout(function(){a.remove()})}:k.safari=function(){};var cf=function(){this.returnValue=false},cg=function(){return this.originalEvent.preventDefault()},ch=function(){this.cancelBubble=true},ci=function(){return this.originalEvent.stopPropagation()},cj=(function(){{if(g.addEventListener)return function(a,b,c,d){var e=o&&u[b]?u[b]:b,g=function(e){if(o&&u[f](b))for(var g=0,h=e.targetTouches&&e.targetTouches.length;g1&&(a=Array[e].splice.call(arguments,0,arguments[w]));return new cC(a)};k.setSize=bU;k.top=k.bottom=null;k.raphael=a;function co(){return this.x+q+this.y}bO.resetScale=function(){if(this.removed)return this;this._.sx=1;this._.sy=1;this.attrs.scale="1 1"};bO.scale=function(a,b,c,d){if(this.removed)return this;if(a==null&&b==null)return{x:this._.sx,y:this._.sy,toString:co};b=b||a;!(+b)&&(b=a);var e,f,g,h,i=this.attrs;if(a!=0){var j=this.getBBox(),k=j.x+j.width/2,l=j.y+j.height/2,m=B(a/this._.sx),o=B(b/this._.sy);c=+c||c==0?c:k;d=+d||d==0?d:l;var r=this._.sx>0,s=this._.sy>0,t=~(~(a/B(a))),u=~(~(b/B(b))),x=m*t,y=o*u,z=this.node.style,A=c+B(k-c)*x*(k>c==r?1:-1),C=d+B(l-d)*y*(l>d==s?1:-1),D=a*t>b*u?o:m;switch(this.type){case"rect":case"image":var E=i.width*m,F=i.height*o;this.attr({height:F,r:i.r*D,width:E,x:A-E/2,y:C-F/2});break;case"circle":case"ellipse":this.attr({rx:i.rx*m,ry:i.ry*o,r:i.r*D,cx:A,cy:C});break;case"text":this.attr({x:A,y:C});break;case"path":var G=bp(i.path),H=true,I=r?x:m,J=s?y:o;for(var K=0,L=G[w];Kr)p=n.data[r*l];else{p=a.findDotsAtSegment(b,c,d,e,f,g,h,i,r/l);n.data[r]=p}r&&(k+=C(C(o.x-p.x,2)+C(o.y-p.y,2),0.5));if(j!=null&&k>=j)return p;o=p}if(j==null)return k},cr=function(b,c){return function(d,e,f){d=bw(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;oe){if(c&&!l.start){m=cq(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);k+=["C",m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k;k=["M",m.x,m.y+"C",m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]][v]();n+=j;g=+i[5];h=+i[6];continue}if(!b&&!c){m=cq(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j;g=+i[5];h=+i[6]}k+=i}l.end=k;m=b?n:c?l:a.findDotsAtSegment(g,h,i[1],i[2],i[3],i[4],i[5],i[6],1);m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},cs=cr(1),ct=cr(),cu=cr(0,1);bO.getTotalLength=function(){if(this.type!="path")return;if(this.node.getTotalLength)return this.node.getTotalLength();return cs(this.attrs.path)};bO.getPointAtLength=function(a){if(this.type!="path")return;return ct(this.attrs.path,a)};bO.getSubpath=function(a,b){if(this.type!="path")return;if(B(this.getTotalLength()-b)<"1e-6")return cu(this.attrs.path,a).end;var c=cu(this.attrs.path,b,1);return a?cu(c,a).end:c};a.easing_formulas={linear:function(a){return a},"<":function(a){return C(a,3)},">":function(a){return C(a-1,3)+1},"<>":function(a){a=a*2;if(a<1)return C(a,3)/2;a-=2;return(C(a,3)+2)/2},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==0||a==1)return a;var b=0.3,c=b/4;return C(2,-10*a)*y.sin((a-c)*(2*D)/b)+1},bounce:function(a){var b=7.5625,c=2.75,d;if(a<1/c)d=b*a*a;else if(a<2/c){a-=1.5/c;d=b*a*a+0.75}else if(a<2.5/c){a-=2.25/c;d=b*a*a+0.9375}else{a-=2.625/c;d=b*a*a+0.984375}return d}};var cv=[],cw=function(){var b=+(new Date);for(var c=0;cd)return d;while(cf?c=e:d=e;e=(d-c)/2+c}return e}return n(a,1/(200*f))}bO.onAnimation=function(a){this._run=a||0;return this};bO.animate=function(c,d,e,g){var h=this;h.timeouts=h.timeouts||[];if(a.is(e,"function")||!e)g=e||null;if(h.removed){g&&g.call(h);return h}var i={},j={},k=false,l={};for(var m in c)if(c[f](m)){if(X[f](m)||h.paper.customAttributes[f](m)){k=true;i[m]=h.attr(m);i[m]==null&&(i[m]=W[m]);j[m]=c[m];switch(X[m]){case"along":var n=cs(c[m]),o=ct(c[m],n*!(!c.back)),p=h.getBBox();l[m]=n/d;l.tx=p.x;l.ty=p.y;l.sx=o.x;l.sy=o.y;j.rot=c.rot;j.back=c.back;j.len=n;c.rot&&(l.r=S(h.rotate())||0);break;case E:l[m]=(j[m]-i[m])/d;break;case"colour":i[m]=a.getRGB(i[m]);var q=a.getRGB(j[m]);l[m]={r:(q.r-i[m].r)/d,g:(q.g-i[m].g)/d,b:(q.b-i[m].b)/d};break;case"path":var t=bw(i[m],j[m]);i[m]=t[0];var u=t[1];l[m]=[];for(var v=0,x=i[m][w];v Date: Sat, 30 Oct 2010 01:54:41 -0400 Subject: [PATCH 172/267] forgot to revert svg container --- public/js/widgets/map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index b8929cb..5ffaa3e 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -17,7 +17,7 @@ Hummingbird.Map = function(element, socket, options) { this.po = org.polymaps; this.map = this.po.map() - .container(this.element.find("svg").get(0)) + .container(this.element.get(0).appendChild(this.po.svg("svg"))) .center({lat: 39, lon: -96}) .zoom(4) .zoomRange([3, 9]) From 260f44cef41f5b6882bc36dbf1c12be0ee57e74c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 31 Oct 2010 19:27:24 -0400 Subject: [PATCH 173/267] Remove logging statement; fix bug in geoip caching --- lib/metrics/locations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index 8493848..564c0a9 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -20,8 +20,8 @@ var LocationsMetric = { } if(locationCache[remoteAddress]) { - console.log('cache hit'); metric.data.location.push(locationCache[remoteAddress]); + return; } client.on('error', function(exception) { From 42e0392b51da6059827ceb0a7d8134672f89453f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 31 Oct 2010 19:28:02 -0400 Subject: [PATCH 174/267] Upgrade to jquery 1.4.3 --- public/index.html | 2 +- public/js/jquery-1.4.2.min.js | 154 -- .../js/{jquery-1.4.2.js => jquery-1.4.3.js} | 2405 +++++++++++------ public/js/jquery-1.4.3.min.js | 166 ++ 4 files changed, 1691 insertions(+), 1036 deletions(-) delete mode 100644 public/js/jquery-1.4.2.min.js rename public/js/{jquery-1.4.2.js => jquery-1.4.3.js} (74%) create mode 100644 public/js/jquery-1.4.3.min.js diff --git a/public/index.html b/public/index.html index 3015350..c55c946 100644 --- a/public/index.html +++ b/public/index.html @@ -3,7 +3,7 @@ - + diff --git a/public/socket.io b/public/socket.io index 50f7e47..7a5197c 160000 --- a/public/socket.io +++ b/public/socket.io @@ -1 +1 @@ -Subproject commit 50f7e4704ee5e17533d662090e17c006d5853f3d +Subproject commit 7a5197c1e74d1f3a050b330e41e4b6e63afb209c From 394c8aa0205fbbf478a29af013c98f7e626f8874 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 3 Nov 2010 23:21:32 -0400 Subject: [PATCH 179/267] Fix map fullscreen bug; tweak map labels --- public/css/map.css | 4 ++++ public/js/polymaps.js | 4 ++-- public/js/widgets/.#map.js | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) delete mode 120000 public/js/widgets/.#map.js diff --git a/public/css/map.css b/public/css/map.css index cc3d3b0..99ce939 100644 --- a/public/css/map.css +++ b/public/css/map.css @@ -1,3 +1,7 @@ +#map_container svg.map { + background-color: #2F2C2B; +} + .compass .back { fill: #eee; fill-opacity: .8; diff --git a/public/js/polymaps.js b/public/js/polymaps.js index 31b9e44..43efc77 100755 --- a/public/js/polymaps.js +++ b/public/js/polymaps.js @@ -1192,7 +1192,7 @@ po.geoJson = function(fetch) { var t = po.svg("text"); t.textContent = o.text; t.setAttribute("class", "label"); - t.setAttribute("transform", "translate(" + p.x + "," + (p.y - r - 18) + ")"); + t.setAttribute("transform", "translate(" + p.x + "," + (p.y - r - 17) + ")"); g.appendChild(t); setTimeout(function() { @@ -1960,7 +1960,7 @@ po.fullscreen = function() { } else { container.css({ - position: null, + position: "relative", borderWidth: null, width: null, height: null, diff --git a/public/js/widgets/.#map.js b/public/js/widgets/.#map.js deleted file mode 120000 index 224823b..0000000 --- a/public/js/widgets/.#map.js +++ /dev/null @@ -1 +0,0 @@ -michael@Link.local.71613 \ No newline at end of file From 143f4ccdd31b05c6b337efa2d019e086e54ce05b Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Thu, 18 Nov 2010 13:16:36 +0100 Subject: [PATCH 180/267] Merge branch 'master', remote branch 'mnutt/master' From 99db006ba1622626a58640bb8367d91eb79517aa Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Thu, 18 Nov 2010 19:18:23 +0100 Subject: [PATCH 181/267] Merge branch 'master', remote branch 'mnutt/master' From c132010a4f11566180ae97c55dbcebfa874bf315 Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Thu, 18 Nov 2010 23:21:29 +0100 Subject: [PATCH 182/267] using npm to manage dependencies instead of submodules. --- .gitmodules | 9 --------- README.md | 8 +++----- deps/node-mongodb-native | 1 - deps/node-socket.io | 1 - deps/node-static | 1 - lib/hummingbird.js | 2 +- package.json | 12 ++++++++++++ server.js | 6 +++--- 8 files changed, 19 insertions(+), 21 deletions(-) delete mode 160000 deps/node-mongodb-native delete mode 160000 deps/node-socket.io delete mode 160000 deps/node-static create mode 100644 package.json diff --git a/.gitmodules b/.gitmodules index 3d9297a..93e17da 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,3 @@ -[submodule "deps/node-mongodb-native"] - path = deps/node-mongodb-native - url = http://github.com/christkv/node-mongodb-native.git -[submodule "deps/node-socket.io"] - path = deps/node-socket.io - url = http://github.com/LearnBoost/Socket.IO-node.git [submodule "public/socket.io"] path = public/socket.io url = http://github.com/LearnBoost/Socket.IO.git -[submodule "deps/node-static"] - path = deps/node-static - url = http://github.com/cloudhead/node-static.git diff --git a/README.md b/README.md index 3a9cbb1..8c96c90 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Requirements ------------------- * node.js v0.1.96 + * npm v0.2.4 * mongodb @@ -24,11 +25,8 @@ Installation git clone git://github.com/mnutt/hummingbird.git cd hummingbird - # Update submodules - git submodule update --init --recursive - - # build the native mongo db driver - cd deps/node-mongodb-native; make + # Use npm to install the dependencies + npm link . # Copy the default configuration file cp config/app.json.sample config/app.json diff --git a/deps/node-mongodb-native b/deps/node-mongodb-native deleted file mode 160000 index e271c50..0000000 --- a/deps/node-mongodb-native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e271c50a942e4a6e6435f8597bf37b6cc399d164 diff --git a/deps/node-socket.io b/deps/node-socket.io deleted file mode 160000 index 054e818..0000000 --- a/deps/node-socket.io +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 054e818bd981c4af28f55c55d409f412d86c63b8 diff --git a/deps/node-static b/deps/node-static deleted file mode 160000 index 8e15779..0000000 --- a/deps/node-static +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8e1577973154b8324966b1b28c62506c0dbc5458 diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 1ed3a1b..193b330 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -4,7 +4,7 @@ var sys = require('sys'), Metric = require('metric').Metric, Aggregates = require('aggregates').Aggregates, Buffer = require('buffer').Buffer, - io = require('deps/node-socket.io'), + io = require('socket.io'), arrays = require('deps/arrays'), querystring = require('querystring'); diff --git a/package.json b/package.json new file mode 100644 index 0000000..a0bc0b5 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ "name" : "hummingbird" + , "description" : "A node.js statistics server" + , "version" : "0.0.1" + , "dependencies": { + "mongodb": "0.7.9" + ,"socket.io": "0.6.1" + ,"node-static": "0.5.2" + } + , "repository" : { "type" : "git" + , "url" : "http://github.com/mnutt/hummingbird.git" } + , "engines" : { "node" : ">=0.2.4" } +} diff --git a/server.js b/server.js index 726c0c6..1bdc8a7 100644 --- a/server.js +++ b/server.js @@ -4,9 +4,9 @@ require.paths.unshift(__dirname); var http = require('http'), weekly = require('weekly'), fs = require('fs'), - static = require('deps/node-static/lib/node-static'), - io = require('deps/node-socket.io'), - mongo = require('deps/node-mongodb-native/lib/mongodb'), + static = require('node-static'), + io = require('socket.io'), + mongo = require('mongodb'), Hummingbird = require('hummingbird').Hummingbird; try { From 1b97c35a3f62332fe6d3f052d01862a4b4a41859 Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Fri, 19 Nov 2010 08:55:08 +0100 Subject: [PATCH 183/267] Since we are using npm need to bump the version of node up to 0.2.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c96c90..6576fe8 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ sends back tracking data generated by javascript. Requirements ------------------- - * node.js v0.1.96 + * node.js v0.2.0 * npm v0.2.4 * mongodb From ff233f57edbc2b8f2274e89b64ff7dd1c8051104 Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Fri, 19 Nov 2010 09:18:14 +0100 Subject: [PATCH 184/267] fix for tests to run don't pass yet though. --- scripts/gource.js | 2 +- spec/node.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/gource.js b/scripts/gource.js index de85c69..00dd6c3 100644 --- a/scripts/gource.js +++ b/scripts/gource.js @@ -2,7 +2,7 @@ require.paths.unshift(__dirname + "/.."); var sys = require('sys'), arrays = require('deps/arrays'), - mongo = require('deps/node-mongodb-native/lib/mongodb'); + mongo = require('mongodb'); var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); diff --git a/spec/node.js b/spec/node.js index 70ed4bd..7a56322 100644 --- a/spec/node.js +++ b/spec/node.js @@ -9,7 +9,7 @@ http = require('http'); v = require('view'); m = require('metric'); sys = require('sys'); -mongo = require('deps/node-mongodb-native/lib/mongodb'); +mongo = require('mongodb'); db = new mongo.Db('hummingbird_test', new mongo.Server('localhost', 27017, {}), {}); MockRequest = function(url) { From 99851b0298fda09ffe7857b85ad19c8edcbffe7f Mon Sep 17 00:00:00 2001 From: Brian Riddle Date: Fri, 19 Nov 2010 09:24:25 +0100 Subject: [PATCH 185/267] readded update submodules for public/socket.io --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 6576fe8..b7be0a9 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ Installation git clone git://github.com/mnutt/hummingbird.git cd hummingbird + # Update submodules + git submodule update --init --recursive + # Use npm to install the dependencies npm link . From 0c2cc4184694d63755991d07f996d91495e6899e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 21 Jan 2011 01:11:23 -0500 Subject: [PATCH 186/267] upgrade socket.io to latest --- deps/node-socket.io | 2 +- public/socket.io | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/node-socket.io b/deps/node-socket.io index 054e818..84ee2d8 160000 --- a/deps/node-socket.io +++ b/deps/node-socket.io @@ -1 +1 @@ -Subproject commit 054e818bd981c4af28f55c55d409f412d86c63b8 +Subproject commit 84ee2d87882f53bcd6683b24729f786725687faf diff --git a/public/socket.io b/public/socket.io index 7a5197c..50f7e47 160000 --- a/public/socket.io +++ b/public/socket.io @@ -1 +1 @@ -Subproject commit 7a5197c1e74d1f3a050b330e41e4b6e63afb209c +Subproject commit 50f7e4704ee5e17533d662090e17c006d5853f3d From a29bd26cf2176a1536462f3e5cae3ef28dee350f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 21 Jan 2011 01:14:20 -0500 Subject: [PATCH 187/267] fix css bug when switching from smaller axis to larger --- public/js/widgets/graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/widgets/graph.js b/public/js/widgets/graph.js index 6646dfa..313879b 100644 --- a/public/js/widgets/graph.js +++ b/public/js/widgets/graph.js @@ -174,7 +174,7 @@ $.extend(Hummingbird.Graph.prototype, { var average = Math.round(value); var percent = average / this.scale; - var height = Math.floor(percent * this.graphHeight); + var height = Math.min(Math.floor(percent * this.graphHeight), this.graphHeight); var color = this.options.barColor || this.lineColors[this.scale] || this.lineColors.def; var lineHeight = this.graphHeight - height; From 27bfcac7cb13a80a1c94dd18189a77ccb8dbd7e3 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 21 Jan 2011 01:17:52 -0500 Subject: [PATCH 188/267] ignore bundled npm packages --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e519b86..7f52690 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.swp /backups /config/app.json +/node_modules From a326d7285fe4b13ee5568665a3cd6ce555cdf809 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 21 Jan 2011 01:27:40 -0500 Subject: [PATCH 189/267] Switch to use socket.io's CDN so we can drop the submodule dependency --- public/index.html | 2 +- public/socket.io | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 160000 public/socket.io diff --git a/public/index.html b/public/index.html index 8c9eea9..9b7be39 100644 --- a/public/index.html +++ b/public/index.html @@ -5,7 +5,7 @@ - + diff --git a/public/socket.io b/public/socket.io deleted file mode 160000 index 50f7e47..0000000 --- a/public/socket.io +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 50f7e4704ee5e17533d662090e17c006d5853f3d From 6417c37d63c0404a12d58dfc57f29204b5cf7dd5 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 21 Jan 2011 01:27:52 -0500 Subject: [PATCH 190/267] Remove submodule instructions from readme --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index b7be0a9..8bde6f8 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,8 @@ Installation git clone git://github.com/mnutt/hummingbird.git cd hummingbird - # Update submodules - git submodule update --init --recursive - # Use npm to install the dependencies - npm link . + npm install # Copy the default configuration file cp config/app.json.sample config/app.json From 8369789a3fa8f11a7d51720e9080c85f42d6ec01 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 21 Jan 2011 03:37:48 -0500 Subject: [PATCH 191/267] switch back to serving socket.io locally; update readme --- README.md | 10 ++++++++++ public/index.html | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8bde6f8..0061ebb 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,16 @@ config/app.json. The dashboard is just html served out of public/; you can serv any webserver. +Deployment +---------- + +Make sure to properly secure the dashboard if you don't want outside people to see it. The dashboard +httpServer's 'listen' function takes a second argument that is the interface to bind; typically you +would choose "127.0.0.1" to only allow access from localhost, or "0.0.0.0" to listen on all +interfaces. In production you should change the instances of "localhost:8000" in public/index.html +to point to the server where you're hosting the dashboard. + + Architecture Overview --------------------- diff --git a/public/index.html b/public/index.html index 9b7be39..e9174db 100644 --- a/public/index.html +++ b/public/index.html @@ -5,9 +5,9 @@ - + From 321601770a3b42af4cf1e7439f6dd8dfdd6cf83d Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 22 Jan 2011 15:17:20 -0500 Subject: [PATCH 192/267] switch to geoip module instead of using an external service --- .gitignore | 1 + lib/metric.js | 6 +++ lib/metrics/locations.js | 60 ++++++++------------------ lib/metrics/sales.js | 5 +-- lib/metrics/{all.js => total_views.js} | 8 ++-- package.json | 1 + 6 files changed, 32 insertions(+), 49 deletions(-) rename lib/metrics/{all.js => total_views.js} (75%) diff --git a/.gitignore b/.gitignore index 7f52690..8a1303b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /backups /config/app.json /node_modules +/GeoLiteCity.dat diff --git a/lib/metric.js b/lib/metric.js index 8ae6733..e8d8165 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -120,6 +120,12 @@ Metric.availableMetricPaths = function(callback) { Metric.allMetrics = function(callback) { Metric.availableMetricPaths(function(metricPath) { var m = require(metricPath); + if(typeof(m.canLoad) == "function" && m.canLoad() == false) { + console.log("Skipping metric " + m.name + "."); + return; + } else { + console.log("Loading metric " + m.name + "."); + } // Instantiate a new metric and use the settings from the custom metrics class var metric = new Metric() diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index a75b029..b394670 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -1,4 +1,6 @@ var http = require('http'); +var geoip = require('geoip'); +var path = require('path'); var locationCache = {}; @@ -8,56 +10,32 @@ var LocationsMetric = { interval: 500, ignoreOnEmpty: true, // don't send any data if we don't get any hits + canLoad: function() { + var cityPath = path.normalize(__dirname + '/../../GeoLiteCity.dat'); + + try { + this.cities = geoip.open(cityPath); + return true; + } catch(e) { + return false; + } + }, + incrementCallback: function(view) { var remoteAddress, - metric = this, - host = "ipinfodb.com", - client = http.createClient(80, host); + locations, + metric = this; if(view.env.ip === "127.0.0.1") { - remoteAddress = ""; + remoteAddress = "8.8.8.8"; } else { remoteAddress = view.env.ip; } - if(locationCache[remoteAddress]) { - metric.data.location.push(locationCache[remoteAddress]); - return; + location = geoip.City.record_by_addr(this.cities, remoteAddress); + if(location.latitude) { + metric.data.location.push(location); } - - client.on('error', function(exception) { - console.log("IP Lookup exception:"); - console.log(JSON.stringify(exception, null, 2)); - }); - - var request = client.request("GET", "/ip_query.php?ip=" + remoteAddress + "&timezone=false", {host: host}); - - request.end(); - - request.on('response', function(resp) { - var buffer = ''; - - resp.on('data', function(chunk) { buffer += chunk; }); - resp.on('end', function() { - var lat, lon, city; - - if(resp.statusCode < 300) { - lat = /([0-9\.\-]+)<\/Latitude>/.exec(buffer); - lon = /([0-9\.\-]+)<\/Longitude>/.exec(buffer); - city = /(.*)<\/City>/.exec(buffer); - } - - var location = { - latitude: lat ? lat[1] : 0, - longitude: lon ? lon[1] : 0, - city: city ? city[1] : "Unknown" - }; - - locationCache[remoteAddress] = location; - - metric.data.location.push(location); - }); - }); } } diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js index 439009b..acea336 100644 --- a/lib/metrics/sales.js +++ b/lib/metrics/sales.js @@ -1,9 +1,6 @@ var SalesMetric = { - - name: 'sales', - + name: 'Sales', initialData: { sales: {} }, - interval: 500, // ms incrementCallback: function(view) { diff --git a/lib/metrics/all.js b/lib/metrics/total_views.js similarity index 75% rename from lib/metrics/all.js rename to lib/metrics/total_views.js index 4f5ca4c..04127d4 100644 --- a/lib/metrics/all.js +++ b/lib/metrics/total_views.js @@ -1,5 +1,5 @@ -var AllViewsMetric = { - name: 'all_views', +var TotalViewsMetric = { + name: 'Total Views', initialData: {total: 0, cartAdds: 0}, interval: 50, // ms incrementCallback: function(view) { @@ -13,5 +13,5 @@ var AllViewsMetric = { } }; -for (var i in AllViewsMetric) - exports[i] = AllViewsMetric[i]; \ No newline at end of file +for (var i in TotalViewsMetric) + exports[i] = TotalViewsMetric[i]; \ No newline at end of file diff --git a/package.json b/package.json index a0bc0b5..c566508 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "mongodb": "0.7.9" ,"socket.io": "0.6.1" ,"node-static": "0.5.2" + ,"geoip": "0.3.1-1" } , "repository" : { "type" : "git" , "url" : "http://github.com/mnutt/hummingbird.git" } From b02e3ff0f837f924de5cfee6245afeea791f71db Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 22 Jan 2011 15:36:59 -0500 Subject: [PATCH 193/267] Update readme for geoip --- README.md | 9 +++++++-- lib/metric.js | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0061ebb..118ab6f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ Installation # Copy the default configuration file cp config/app.json.sample config/app.json + # To use the map, download MaxMind's GeoIP database and extract to the root directory: + wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz + gunzip GeoLiteCity.dat.gz + Running Hummingbird ------------------------------ @@ -71,10 +75,11 @@ functions to be called whenever that property is present. Logging Customization --------------------- -Metrics are stored in lib/metrics and auto-loaded.. Each metric contains a handler function that is +Metrics are stored in lib/metrics and auto-loaded. Each metric contains a handler function that is called every time a new user event occurs. Metrics store data in the `data` object property which gets emitted to clients in intervals specified by the metric. A basic example can be found in -lib/metrics/all.js. An example of how a metric can filter based on urls is in lib/metric/sales.js. +lib/metrics/total_views.js. An example of how a metric can filter based on urls is in +lib/metric/sales.js. Display Customization diff --git a/lib/metric.js b/lib/metric.js index e8d8165..0e729c3 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -121,10 +121,10 @@ Metric.allMetrics = function(callback) { Metric.availableMetricPaths(function(metricPath) { var m = require(metricPath); if(typeof(m.canLoad) == "function" && m.canLoad() == false) { - console.log("Skipping metric " + m.name + "."); + sys.log("Skipping metric " + m.name + "."); return; } else { - console.log("Loading metric " + m.name + "."); + sys.log("Loading metric " + m.name + "."); } // Instantiate a new metric and use the settings from the custom metrics class From 25935591d0bacffca890f82000b657ee8caff59f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 18 Mar 2011 23:59:58 -0400 Subject: [PATCH 194/267] upgrade packages to latest --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c566508..3b27bcc 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,12 @@ , "description" : "A node.js statistics server" , "version" : "0.0.1" , "dependencies": { - "mongodb": "0.7.9" - ,"socket.io": "0.6.1" + "mongodb": "0.9.1" + ,"socket.io": "0.6.16" ,"node-static": "0.5.2" - ,"geoip": "0.3.1-1" + ,"geoip": "0.3.4-1" } , "repository" : { "type" : "git" , "url" : "http://github.com/mnutt/hummingbird.git" } - , "engines" : { "node" : ">=0.2.4" } + , "engines" : { "node" : ">=0.3.0" } } From 06cdbe9191fdcaab383500df93956d756b5f364c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 19 Mar 2011 00:02:26 -0400 Subject: [PATCH 195/267] recenter map --- public/js/widgets/map.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index 345d1ef..2343d58 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -18,9 +18,9 @@ Hummingbird.Map = function(element, socket, options) { this.map = this.po.map() .container(this.element.get(0).appendChild(this.po.svg("svg"))) - .center({lat: 39, lon: -96}) - .zoom(4) - .zoomRange([3, 9]) + .center({lat: 39, lon: 10}) + .zoom(2) + .zoomRange([2, 9]) .add(this.po.interact()); this.map.add(this.po.image() From fcb1a95b6266c04c4ce9ef4e78c5881a94f79ce1 Mon Sep 17 00:00:00 2001 From: Luis Bosque Date: Thu, 14 Apr 2011 19:16:05 +0800 Subject: [PATCH 196/267] Enables hummingbird to be used behind a proxy server (nginx, for example) --- lib/hummingbird.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 193b330..2c414c8 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -57,7 +57,7 @@ Hummingbird.prototype = { env.timestamp = new Date(); // sys.log(JSON.stringify(env, null, 2)); - env.ip = req.connection.remoteAddress; + env.ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; var view = new View(env); env.url_key = view.urlKey; From 7da2e5d75f22400f159af094a9eb1599d09f3369 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 16 Apr 2011 22:12:50 -0400 Subject: [PATCH 197/267] fix graph for average --- public/js/widgets/graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/widgets/graph.js b/public/js/widgets/graph.js index 313879b..e81fd8b 100644 --- a/public/js/widgets/graph.js +++ b/public/js/widgets/graph.js @@ -46,7 +46,7 @@ $.extend(Hummingbird.Graph.prototype, { name: "Graph", onMessage: function(message, average) { - this.drawLogPath(average); + this.drawLogPath(average * this.options.averageOver); }, createGraph: function() { From e3e85c827a2116bac3e20f9199d75a360a3cb761 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 15 Apr 2011 02:08:35 -0400 Subject: [PATCH 198/267] refactor insertData into its own function in preparation for udp support --- lib/hummingbird.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 2c414c8..d9bfd39 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -54,10 +54,13 @@ Hummingbird.prototype = { this.writePixel(res); var env = this.splitQuery(req.url.split('?')[1]); - env.timestamp = new Date(); - // sys.log(JSON.stringify(env, null, 2)); - env.ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; + + this.insertData(env); + }, + + insertData: function(env) { + env.timestamp = new Date(); var view = new View(env); env.url_key = view.urlKey; @@ -91,7 +94,7 @@ Hummingbird.prototype = { handleError: function(req, res, e) { res.writeHead(500, {}); res.write("Server error"); - res.close(); + res.end(); e.stack = e.stack.split('\n'); e.url = req.url; From d3eea95865d3f9970c6a4d17bd2481c4529ec911 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 15 Apr 2011 19:33:50 -0400 Subject: [PATCH 199/267] add support for receiving stats via udp --- client/file_watcher.js | 32 ++++++++++++++++++++++++++++++++ client/udp_client_sample.js | 18 ++++++++++++++++++ config/app.json.sample | 3 +++ server.js | 16 ++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 client/file_watcher.js create mode 100644 client/udp_client_sample.js diff --git a/client/file_watcher.js b/client/file_watcher.js new file mode 100644 index 0000000..185dc70 --- /dev/null +++ b/client/file_watcher.js @@ -0,0 +1,32 @@ +var dgram = require('dgram'); +var fs = require('fs'); + +function sendMessage(data) { + var message = new Buffer(JSON.stringify(data)); + var client = dgram.createSocket("udp4"); + client.send(message, 0, message.length, 8000, "localhost"); + client.close(); +} + +var filename = process.argv[1]; +if(!filename) { + console.log("No file specified"); + exit(1); +} +console.log("Watching " + filename); + +fs.watchFile(filename, function(curr, prev) { + console.log("HERE"); + if(prev.size > curr.size) return {clear:true}; + var stream = fs.createReadStream(filename, { start: prev.size, end: curr.size}); + stream.addListener("data", function(lines) { + console.log("GOT MESSAGE"); + lines.toString('utf-8').split("\n").forEach(function(line) { + var data = JSON.parse(line); + data.ip = data.remote_addr; + data.u = data.request_uri; + delete data.remote_addr; + delete data.request_uri; + }); + }); +}); diff --git a/client/udp_client_sample.js b/client/udp_client_sample.js new file mode 100644 index 0000000..b4c9602 --- /dev/null +++ b/client/udp_client_sample.js @@ -0,0 +1,18 @@ +var dgram = require('dgram'); + +function sendMessage(data) { + var message = new Buffer(JSON.stringify(data)); + var client = dgram.createSocket("udp4"); + client.send(message, 0, message.length, 8000, "localhost"); + client.close(); +} + +var msg = { + "ip" : "129.59.1.10", + "timestamp" : "Sat Oct 23 2010 21:39:35 GMT-0400 (EDT)", + "url_key" : 123, + "product_id" : 456 +}; + +sendMessage(msg); + diff --git a/config/app.json.sample b/config/app.json.sample index 00f8b73..3443119 100644 --- a/config/app.json.sample +++ b/config/app.json.sample @@ -7,6 +7,9 @@ "mongo_host" : "localhost", "mongo_port" : 27017, + "udp_address" : "127.0.0.1", + "udp_port" : 8000, + "enable_dashboard" : true, "capistrano" : { diff --git a/server.js b/server.js index 1bdc8a7..59da1fa 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,7 @@ require.paths.unshift(__dirname); var http = require('http'), weekly = require('weekly'), fs = require('fs'), + dgram = require('dgram'), static = require('node-static'), io = require('socket.io'), mongo = require('mongodb'), @@ -45,6 +46,21 @@ db.open(function(p_db) { hummingbird.addAllMetrics(socket, db); console.log('Web Socket server running at ws://*:' + config.tracking_port); + + if(config.udp_address) { + var udpServer = dgram.createSocket("udp4"); + + udpServer.on("message", function(message, rinfo) { + console.log("message from " + rinfo.address + " : " + rinfo.port); + + var data = JSON.parse(message); + hummingbird.insertData(data); + }); + + udpServer.bind(config.udp_port, config.udp_address); + + console.log('UDP server running on UDP port ' + config.udp_port); + } }); console.log('Tracking server running at http://*:' + config.tracking_port + '/tracking_pixel.gif'); From b68b7e2f38e7750a4287a2ad211d71738e8f0e39 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sat, 16 Apr 2011 22:32:26 -0400 Subject: [PATCH 200/267] upgrade polymaps --- public/js/polymaps.js | 239 +++++++++++++++++++++++++++++++++--------- 1 file changed, 188 insertions(+), 51 deletions(-) diff --git a/public/js/polymaps.js b/public/js/polymaps.js index 43efc77..2d75912 100755 --- a/public/js/polymaps.js +++ b/public/js/polymaps.js @@ -2,7 +2,7 @@ if (!org) var org = {}; if (!org.polymaps) org.polymaps = {}; (function(po){ - po.version = "2.3.0"; // semver.org + po.version = "2.5.0"; // semver.org var zero = {x: 0, y: 0}; po.ns = { @@ -40,7 +40,7 @@ po.transform = function(a, b, c, d, e, f) { transform.zoomFraction = function(x) { if (!arguments.length) return zoomFraction; zoomFraction = x; - zoomDelta = Math.floor(zoomFraction + Math.log(Math.sqrt(a * a + b * b + c * c + d * d)) / Math.log(2)); + zoomDelta = Math.floor(zoomFraction + Math.log(Math.sqrt(a * a + b * b + c * c + d * d)) / Math.LN2); k = Math.pow(2, -zoomDelta); return transform; }; @@ -182,12 +182,18 @@ po.cache = function(load, unload) { return cache; }; po.url = function(template) { - var hosts = []; + var hosts = [], + repeat = true; function format(c) { var max = c.zoom < 0 ? 1 : 1 << c.zoom, - column = c.column % max; - if (column < 0) column += max; + column = c.column; + if (repeat) { + column = c.column % max; + if (column < 0) column += max; + } else if ((column < 0) || (column >= max)) { + return null; + } return template.replace(/{(.)}/g, function(s, v) { switch (v) { case "S": return hosts[(Math.abs(c.zoom) + c.row + column) % hosts.length]; @@ -220,6 +226,12 @@ po.url = function(template) { return format; }; + format.repeat = function(x) { + if (!arguments.length) return repeat; + repeat = x; + return format; + }; + return format; }; po.dispatch = function(that) { @@ -613,7 +625,7 @@ po.map = function() { l = map.pointLocation({x: (bl.x + tr.x) / 2, y: (bl.y + tr.y) / 2}); // update the zoom level - zoom = zoom + zoomFraction - Math.log(k) / Math.log(2); + zoom = zoom + zoomFraction - Math.log(k) / Math.LN2; rezoom(); // set the new center @@ -671,10 +683,9 @@ resizer.remove = function(map) { } }; -if(window.addEventListener) { - // Note: assumes single window (no frames, iframes, etc.)! - window.addEventListener("resize", resizer, false); -} +// Note: assumes single window (no frames, iframes, etc.)! +window.addEventListener("resize", resizer, false); +window.addEventListener("load", resizer, false); // See http://wiki.openstreetmap.org/wiki/Mercator @@ -1100,16 +1111,22 @@ po.image = function() { if (typeof url == "function") { element.setAttribute("opacity", 0); - tile.request = po.queue.image(element, url(tile), function(img) { - delete tile.request; + var tileUrl = url(tile); + if (tileUrl != null) { + tile.request = po.queue.image(element, tileUrl, function(img) { + delete tile.request; + tile.ready = true; + tile.img = img; + element.removeAttribute("opacity"); + image.dispatch({type: "load", tile: tile}); + }); + } else { tile.ready = true; - tile.img = img; - element.removeAttribute("opacity"); image.dispatch({type: "load", tile: tile}); - }); + } } else { tile.ready = true; - if (url) element.setAttributeNS(po.ns.xlink, "href", url); + if (url != null) element.setAttributeNS(po.ns.xlink, "href", url); image.dispatch({type: "load", tile: tile}); } } @@ -1624,26 +1641,46 @@ po.wheel = function() { location = null; } + // mousewheel events are totally broken! + // https://bugs.webkit.org/show_bug.cgi?id=40441 + // not only that, but Chrome and Safari differ in re. to acceleration! + var inner = document.createElement("div"), + outer = document.createElement("div"); + outer.style.visibility = "hidden"; + outer.style.top = "0px"; + outer.style.height = "0px"; + outer.style.width = "0px"; + outer.style.overflowY = "scroll"; + inner.style.height = "2000px"; + outer.appendChild(inner); + document.body.appendChild(outer); + function mousewheel(e) { - var delta = (e.wheelDelta / 120 || -e.detail) * .1, + var delta = e.wheelDelta || -e.detail, point; - /* Detect fast & large wheel events on WebKit. */ - if (bug40441 < 0) { - var now = Date.now(), since = now - last; - if ((since > 9) && (Math.abs(e.wheelDelta) / since >= 50)) bug40441 = 1; - last = now; - } - if (bug40441 == 1) delta *= .03; + /* Detect the pixels that would be scrolled by this wheel event. */ + if (delta) { + if (smooth) { + try { + outer.scrollTop = 1000; + outer.dispatchEvent(e); + delta = 1000 - outer.scrollTop; + } catch (error) { + // Derp! Hope for the best? + } + delta *= .005; + } - /* If smooth zooming is disabled, batch events into unit steps. */ - if (!smooth && delta) { - var timeNow = Date.now(); - if (timeNow - timePrev > 200) { - delta = delta > 0 ? +1 : -1; - timePrev = timeNow; - } else { - delta = 0; + /* If smooth zooming is disabled, batch events into unit steps. */ + else { + var timeNow = Date.now(); + if (timeNow - timePrev > 200) { + delta = delta > 0 ? +1 : -1; + timePrev = timeNow; + } else { + delta = 0; + } } } @@ -1692,7 +1729,7 @@ po.wheel = function() { if (map) { container.removeEventListener("mousemove", move, false); container.removeEventListener("mousewheel", mousewheel, false); - container.removeEventListener("DOMMouseScroll", mousewheel, false); + container.removeEventListener("MozMousePixelScroll", mousewheel, false); container = null; map.off("move", move); } @@ -1701,16 +1738,13 @@ po.wheel = function() { container = map.container(); container.addEventListener("mousemove", move, false); container.addEventListener("mousewheel", mousewheel, false); - container.addEventListener("DOMMouseScroll", mousewheel, false); + container.addEventListener("MozMousePixelScroll", mousewheel, false); } return wheel; }; return wheel; }; - -// https://bugs.webkit.org/show_bug.cgi?id=40441 -var bug40441 = /WebKit\/533/.test(navigator.userAgent) ? -1 : 0; po.arrow = function() { var arrow = {}, key = {left: 0, right: 0, up: 0, down: 0}, @@ -1830,26 +1864,35 @@ po.hash = function() { lat = 90 - 1e-8, // allowable latitude range map; - function move() { + var parser = function(map, s) { + var args = s.split("/").map(Number); + if (args.length < 3 || args.some(isNaN)) return true; // replace bogus hash + else { + var size = map.size(); + map.zoomBy(args[0] - map.zoom(), + {x: size.x / 2, y: size.y / 2}, + {lat: Math.min(lat, Math.max(-lat, args[1])), lon: args[2]}); + } + }; + + var formatter = function(map) { var center = map.center(), zoom = map.zoom(), - precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)), - s1 = "#" + zoom.toFixed(2) + precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)); + return "#" + zoom.toFixed(2) + "/" + center.lat.toFixed(precision) + "/" + center.lon.toFixed(precision); + }; + + function move() { + var s1 = formatter(map); if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map! } function hashchange() { if (location.hash === s0) return; // ignore spurious hashchange events - var args = (s0 = location.hash).substring(1).split("/").map(Number); - if (args.length < 3 || args.some(isNaN)) move(); // replace bogus hash - else { - var size = map.size(); - map.zoomBy(args[0] - map.zoom(), - {x: size.x / 2, y: size.y / 2}, - {lat: Math.min(lat, Math.max(-lat, args[1])), lon: args[2]}); - } + if (parser(map, (s0 = location.hash).substring(1))) + move(); // replace bogus hash } hash.map = function(x) { @@ -1866,20 +1909,115 @@ po.hash = function() { return hash; }; + hash.parser = function(x) { + if (!arguments.length) return parser; + parser = x; + return hash; + }; + + hash.formatter = function(x) { + if (!arguments.length) return formatter; + formatter = x; + return hash; + }; + return hash; }; +po.touch = function() { + var touch = {}, + map, + container, + rotate = false, + last = 0, + zoom, + angle, + locations = {}; // touch identifier -> location + + window.addEventListener("touchmove", touchmove, false); + + function touchstart(e) { + var i = -1, + n = e.touches.length, + t = Date.now(); + + // doubletap detection + if ((n == 1) && (t - last < 300)) { + var z = map.zoom(); + map.zoomBy(1 - z + Math.floor(z), map.mouse(e.touches[0])); + e.preventDefault(); + } + last = t; + + // store original zoom & touch locations + zoom = map.zoom(); + angle = map.angle(); + while (++i < n) { + t = e.touches[i]; + locations[t.identifier] = map.pointLocation(map.mouse(t)); + } + } + + function touchmove(e) { + switch (e.touches.length) { + case 1: { // single-touch pan + var t0 = e.touches[0]; + map.zoomBy(0, map.mouse(t0), locations[t0.identifier]); + e.preventDefault(); + break; + } + case 2: { // double-touch pan + zoom + rotate + var t0 = e.touches[0], + t1 = e.touches[1], + p0 = map.mouse(t0), + p1 = map.mouse(t1), + p2 = {x: (p0.x + p1.x) / 2, y: (p0.y + p1.y) / 2}, // center point + c0 = po.map.locationCoordinate(locations[t0.identifier]), + c1 = po.map.locationCoordinate(locations[t1.identifier]), + c2 = {row: (c0.row + c1.row) / 2, column: (c0.column + c1.column) / 2, zoom: 0}, + l2 = po.map.coordinateLocation(c2); // center location + map.zoomBy(Math.log(e.scale) / Math.LN2 + zoom - map.zoom(), p2, l2); + if (rotate) map.angle(e.rotation / 180 * Math.PI + angle); + e.preventDefault(); + break; + } + } + } + + touch.rotate = function(x) { + if (!arguments.length) return rotate; + rotate = x; + return touch; + }; + + touch.map = function(x) { + if (!arguments.length) return map; + if (map) { + container.removeEventListener("touchstart", touchstart, false); + container = null; + } + if (map = x) { + container = map.container(); + container.addEventListener("touchstart", touchstart, false); + } + return touch; + }; + + return touch; +}; // Default map controls. po.interact = function() { var interact = {}, drag = po.drag(), wheel = po.wheel(), dblclick = po.dblclick(), + touch = po.touch(), arrow = po.arrow(); interact.map = function(x) { drag.map(x); wheel.map(x); dblclick.map(x); + touch.map(x); arrow.map(x); return interact; }; @@ -2180,9 +2318,8 @@ po.compass = function() { case "bottom-left": y = size.y - y; break; case "bottom-right": x = size.x - x; y = size.y - y; break; } - var tx = "translate(" + x + "," + y + ")"; - if (panContainer) panContainer.setAttribute("transform", tx); - if (zoomContainer) zoomContainer.setAttribute("transform", tx); + g.setAttribute("transform", "translate(" + x + "," + y + ")"); + dragRect.setAttribute("transform", "translate(" + -x + "," + -y + ")"); for (var i in ticks) { i == map.zoom() ? ticks[i].setAttribute("class", "active") From 0418c8998e4077cfa8b726c1753ca76fb70d0cd7 Mon Sep 17 00:00:00 2001 From: robertjwhitney Date: Tue, 17 May 2011 17:30:44 -0400 Subject: [PATCH 201/267] bumps node-static version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3b27bcc..e7c0302 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ , "dependencies": { "mongodb": "0.9.1" ,"socket.io": "0.6.16" - ,"node-static": "0.5.2" + ,"node-static": "0.5.6" ,"geoip": "0.3.4-1" } , "repository" : { "type" : "git" From 167a873b7dff8c177726f671704e869f45f71060 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 20 May 2011 23:31:36 -0400 Subject: [PATCH 202/267] clean up the api between frontend and backend --- lib/metric.js | 2 +- lib/metrics/hits.js | 2 +- lib/metrics/total_views.js | 2 +- public/index.html | 14 ++++--- public/js/websocket.js | 80 +++++++------------------------------- public/js/widgets/base.js | 14 ++++--- public/js/widgets/map.js | 1 + 7 files changed, 36 insertions(+), 79 deletions(-) diff --git a/lib/metric.js b/lib/metric.js index 0e729c3..9a1c90a 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -39,7 +39,7 @@ Metric.prototype = { // NOTE: using 'metric' in place of 'this', since run from setInterval if(metric.ignoreOnEmpty && !metric.isDirty) { return; } - metric.socket.broadcast(JSON.stringify(metric.data)); + metric.socket.broadcast(JSON.stringify({type: this.name, data: metric.data})); metric.resetData(); }, diff --git a/lib/metrics/hits.js b/lib/metrics/hits.js index b8c47a5..98a5217 100644 --- a/lib/metrics/hits.js +++ b/lib/metrics/hits.js @@ -1,5 +1,5 @@ var HitsMetric = { - name: 'Individual Hits', + name: 'hits', initialData: [], interval: 200, incrementCallback: function(view) { diff --git a/lib/metrics/total_views.js b/lib/metrics/total_views.js index 04127d4..85818de 100644 --- a/lib/metrics/total_views.js +++ b/lib/metrics/total_views.js @@ -1,5 +1,5 @@ var TotalViewsMetric = { - name: 'Total Views', + name: 'view_totals', initialData: {total: 0, cartAdds: 0}, interval: 50, // ms incrementCallback: function(view) { diff --git a/public/index.html b/public/index.html index e9174db..0e1a5f4 100644 --- a/public/index.html +++ b/public/index.html @@ -72,27 +72,31 @@

Cart Traffic:

$("#total").hummingbirdGraph(hummingbirdSocket, { - data: { total: true } + from: "view_totals", + filter: "total" }); $("#cart_adds").hummingbirdGraph(hummingbirdSocket, { - data: { cartAdds: true }, + from: "view_totals", + filter: "cartAdds", graphHeight: 100 }); $("#total h2.graph_title span.value").hummingbirdCount(hummingbirdSocket, { - data: { total: true }, + from: "view_totals", + filter: "total", every: 10 }); - $("#map_container").hummingbirdMap(hummingbirdSocket, { data: { location: true } }); + $("#map_container").hummingbirdMap(hummingbirdSocket, { from: "hits", filter: "location" }); new Hummingbird.Logger(window, hummingbirdSocket, { - data: { cartAdds: true}, + from: "view_totals", + filter: "cartAdds", every: 20 }); diff --git a/public/js/websocket.js b/public/js/websocket.js index f6242bd..ff02e75 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -27,13 +27,13 @@ Hummingbird.WebSocket.prototype = { }, onMessage: function(message) { - var data = JSON.parse(message); - var i = this.handlers.length; + message = JSON.parse(message); + var i = this.handlers[message.type].length; while(i--) { - var handler = this.handlers[i][0]; - var scope = this.handlers[i][1]; + var handler = this.handlers[message.type][i][0]; + var scope = this.handlers[message.type][i][1]; - handler.apply(scope, [data]); + handler.apply(scope, [message.data]); } }, @@ -79,15 +79,18 @@ Hummingbird.WebSocket.prototype = { return wsServer; }, - registerHandler: function(handler, object) { - this.handlers.push([handler, object]); + registerHandler: function(handler, scope, type) { + if(!this.handlers[type]) { this.handlers[type] = []; } + this.handlers[type].push([handler, scope]); }, unregisterHandler: function(handler) { - for(var i = 0; i < this.handlers.length; i++) { - if(this.handlers[i] === val) { - this.handlers.splice(i, 1); - break; + for(var type in this.handlers) { + for(var i = 0; i < this.handlers[type].length; i++) { + if(this.handlers[type][i] === val) { + this.handlers[type].splice(i, 1); + break; + } } } }, @@ -110,58 +113,3 @@ $.fn.hummingbirdGraph = function(socket, options) { return this; }; - -// DASHBOARD WEBSOCKET - -Hummingbird.WebSocket.Dashboard = function() { } -Hummingbird.WebSocket.Dashboard.prototype = new Hummingbird.WebSocket; - -Hummingbird.WebSocket.Dashboard.prototype.start = function() { - this.socket = new io.Socket(this.webSocketURI(), {port: this.webSocketPort()}); - this.socket.connect(); - - var totalDiv = $("#log"); - totalDiv.find('div.graph').width($(window).width() - 160); - var totalGraph = new Hummingbird.Graph(totalDiv, { ratePerSecond: 20, logDate: true }); - - var self = this; - - this.socket.on('message', function(msg) { - var data = JSON.parse(msg); - - if(typeof(data.total) != "undefined") { - totalGraph.drawLogPath(data.total); - } - }) - - this.socket.on('disconnect', function() { self.onClose(); }); - this.socket.on('connect', function() { self.onOpen(); }); -}; - -// WEEKLY WEBSOCKET - -Hummingbird.WebSocket.Weekly = function() { } -Hummingbird.WebSocket.Weekly.prototype = new Hummingbird.WebSocket; - -Hummingbird.WebSocket.Weekly.prototype.start = function() { - if (!this.webSocketEnabled()) - return; - - this.socket = new io.Socket(this.webSocketURI(), {port: this.webSocketPort()}); - this.socket.connect(); - - var self = this; - - this.socket.on('message', function(msg) { - var data = JSON.parse(msg); - if(data.total && data.total > 0) { - var el = $("div.day:first-child div.all_views"); - var prevTotal = el.data("total"); - el.text((prevTotal + data.total).commify()).data('total', prevTotal + data.total); - } - }); - - this.socket.on('disconnect', function() { self.onClose(); }); - this.socket.on('open', function() { self.onOpen(); }); -} - diff --git a/public/js/widgets/base.js b/public/js/widgets/base.js index f8bb6e9..a744f8f 100644 --- a/public/js/widgets/base.js +++ b/public/js/widgets/base.js @@ -15,7 +15,7 @@ Hummingbird.Base.prototype = { }, registerHandler: function() { - this.socket.registerHandler(this.onData, this); + this.socket.registerHandler(this.onData, this, this.from); }, onMessage: function(message) { @@ -25,6 +25,7 @@ Hummingbird.Base.prototype = { onData: function(fullData) { var average; var message = this.extract(fullData); + if(typeof(message) != "undefined") { this.validMessageCount += 1; @@ -43,24 +44,27 @@ Hummingbird.Base.prototype = { var obj = data; for(var i = 0, len = this.filter.length; i < len; i++) { obj = obj[this.filter[i]]; - if(typeof(obj) == "undefined") { return; } } return obj; }, setFilter: function() { - var obj = this.options.data; - this.filter = []; - while(typeof(obj) == "object") { + var obj = this.options.filter; + if(!obj) { return; } + + while(typeof(obj) != "string") { for(var i in obj) { + console.log(i); this.filter.push(i); obj = obj[i]; break; } } + this.filter.push(obj); + console.log(this.filter); }, addToAverage: function(newValue) { diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index 2343d58..77ee853 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -51,6 +51,7 @@ Hummingbird.Map.prototype = new Hummingbird.Base(); $.extend(Hummingbird.Map.prototype, { name: "Map", onMessage: function(value, average) { + console.log(value); if(value && value.length > 0) { for(var i in value) { var geo = value[i]; From 67d809cee348ff1f915ab598bd792c4ee77af288 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 20 May 2011 23:33:12 -0400 Subject: [PATCH 203/267] remove console.log; don't get into an infinite loop --- public/js/widgets/base.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/public/js/widgets/base.js b/public/js/widgets/base.js index a744f8f..476bdd5 100644 --- a/public/js/widgets/base.js +++ b/public/js/widgets/base.js @@ -55,16 +55,14 @@ Hummingbird.Base.prototype = { var obj = this.options.filter; if(!obj) { return; } - while(typeof(obj) != "string") { + while(obj && typeof(obj) != "string") { for(var i in obj) { - console.log(i); this.filter.push(i); obj = obj[i]; break; } } this.filter.push(obj); - console.log(this.filter); }, addToAverage: function(newValue) { From fdb97bb1feaf5745c332d09eab3154ec972f0630 Mon Sep 17 00:00:00 2001 From: Dan Thurman Date: Wed, 15 Jun 2011 16:33:52 +0000 Subject: [PATCH 204/267] Converted config to a module. Freeing the dependency on fs and the use of readFileSync. --- config/config.js | 19 +++++++++++++++++++ server.js | 9 +-------- 2 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 config/config.js diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000..a0da9da --- /dev/null +++ b/config/config.js @@ -0,0 +1,19 @@ +module.exports = config = { + "name" : "Hummingbird", + + "tracking_port" : 8000, + "dashboard_port" : 8080, + + "mongo_host" : "localhost", + "mongo_port" : 27017, + + "udp_address" : "127.0.0.1", + "udp_port" : 8000, + + "enable_dashboard" : true, + + "capistrano" : { + "repository" : "git://github.com/mnutt/hummingbird.git", + "hummingbird_host" : "hummingbird.your-host.com" + } +} diff --git a/server.js b/server.js index 59da1fa..9a06c2c 100644 --- a/server.js +++ b/server.js @@ -3,20 +3,13 @@ require.paths.unshift(__dirname); var http = require('http'), weekly = require('weekly'), - fs = require('fs'), + config = require('./config/app.json'), dgram = require('dgram'), static = require('node-static'), io = require('socket.io'), mongo = require('mongodb'), Hummingbird = require('hummingbird').Hummingbird; -try { - var configJSON = fs.readFileSync(__dirname + "/config/app.json"); -} catch(e) { - console.log("File config/app.json not found. Try: `cp config/app.json.sample config/app.json`"); -} -var config = JSON.parse(configJSON.toString()); - db = new mongo.Db('hummingbird', new mongo.Server(config.mongo_host, config.mongo_port, {}), {}); db.addListener("error", function(error) { From 023799b86792d8253581bd6c5938dafe1ca5d45a Mon Sep 17 00:00:00 2001 From: Dan Thurman Date: Wed, 15 Jun 2011 16:36:43 +0000 Subject: [PATCH 205/267] using the config module. --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 9a06c2c..482528c 100644 --- a/server.js +++ b/server.js @@ -3,7 +3,7 @@ require.paths.unshift(__dirname); var http = require('http'), weekly = require('weekly'), - config = require('./config/app.json'), + config = require('./config/config'), dgram = require('dgram'), static = require('node-static'), io = require('socket.io'), From ad879d7a8d1cf723f6495871f7c2fb11d15672dc Mon Sep 17 00:00:00 2001 From: Dan Thurman Date: Wed, 15 Jun 2011 18:09:20 +0000 Subject: [PATCH 206/267] missed reference in hummingbird.js --- lib/hummingbird.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/hummingbird.js b/lib/hummingbird.js index d9bfd39..33b3732 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -1,5 +1,6 @@ var sys = require('sys'), fs = require('fs'), + config = require('../config/config'), View = require('view').View, Metric = require('metric').Metric, Aggregates = require('aggregates').Aggregates, @@ -8,12 +9,6 @@ var sys = require('sys'), arrays = require('deps/arrays'), querystring = require('querystring'); -try { - var configJSON = fs.readFileSync(__dirname + "/../config/app.json"); -} catch(e) { - sys.log("File config/app.json not found. Try: `cp config/app.json.sample config/app.json`"); -} -var config = JSON.parse(configJSON.toString()); var Hummingbird = function(db, callback) { var pixelData = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); From c2e941a50b8681b6d23a31a92893fc3fb8546f95 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 7 Sep 2011 00:24:08 -0400 Subject: [PATCH 207/267] no more require.paths --- {deps => lib}/arrays.js | 0 lib/hummingbird.js | 8 ++++---- lib/weekly.js | 6 +++--- scripts/gource.js | 4 +--- server.js | 7 ++----- spec/node.js | 12 ++++-------- 6 files changed, 14 insertions(+), 23 deletions(-) rename {deps => lib}/arrays.js (100%) diff --git a/deps/arrays.js b/lib/arrays.js similarity index 100% rename from deps/arrays.js rename to lib/arrays.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 33b3732..45a0fe5 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -1,12 +1,12 @@ var sys = require('sys'), fs = require('fs'), config = require('../config/config'), - View = require('view').View, - Metric = require('metric').Metric, - Aggregates = require('aggregates').Aggregates, + View = require('./view').View, + Metric = require('./metric').Metric, + Aggregates = require('./aggregates').Aggregates, Buffer = require('buffer').Buffer, io = require('socket.io'), - arrays = require('deps/arrays'), + arrays = require('./arrays'), querystring = require('querystring'); diff --git a/lib/weekly.js b/lib/weekly.js index aa676aa..0030711 100644 --- a/lib/weekly.js +++ b/lib/weekly.js @@ -1,6 +1,6 @@ var sys = require('sys'), - Metric = require('metric').Metric, - TimeBucketers = require('aggregates').TimeBucketers; + Metric = require('./metric').Metric, + TimeBucketers = require('./aggregates').TimeBucketers; var Weekly = {}; @@ -51,4 +51,4 @@ Weekly.findByDay = function(db, callback) { }); }; -exports.findByDay = Weekly.findByDay; \ No newline at end of file +exports.findByDay = Weekly.findByDay; diff --git a/scripts/gource.js b/scripts/gource.js index 00dd6c3..3b5b7d0 100644 --- a/scripts/gource.js +++ b/scripts/gource.js @@ -1,7 +1,5 @@ -require.paths.unshift(__dirname + "/.."); - var sys = require('sys'), - arrays = require('deps/arrays'), + arrays = require('../lib/arrays'), mongo = require('mongodb'); var db = new mongo.Db('hummingbird', new mongo.Server('localhost', 27017, {}), {}); diff --git a/server.js b/server.js index 482528c..e96c3b4 100644 --- a/server.js +++ b/server.js @@ -1,14 +1,11 @@ -require.paths.unshift(__dirname + '/lib'); -require.paths.unshift(__dirname); - var http = require('http'), - weekly = require('weekly'), + weekly = require('./lib/weekly'), config = require('./config/config'), dgram = require('dgram'), static = require('node-static'), io = require('socket.io'), mongo = require('mongodb'), - Hummingbird = require('hummingbird').Hummingbird; + Hummingbird = require('./lib/hummingbird').Hummingbird; db = new mongo.Db('hummingbird', new mongo.Server(config.mongo_host, config.mongo_port, {}), {}); diff --git a/spec/node.js b/spec/node.js index 7a56322..515af85 100644 --- a/spec/node.js +++ b/spec/node.js @@ -1,13 +1,9 @@ -require.paths.unshift('spec', './spec/lib', 'lib') -require.paths.unshift(__dirname + '/../lib'); -require.paths.unshift(__dirname + '/..'); - require('jspec') -require('unit/spec.helper') -hb = require('hummingbird') +require('./unit/spec.helper') +hb = require('../lib/hummingbird') http = require('http'); -v = require('view'); -m = require('metric'); +v = require('../lib/view'); +m = require('../lib/metric'); sys = require('sys'); mongo = require('mongodb'); db = new mongo.Db('hummingbird_test', new mongo.Server('localhost', 27017, {}), {}); From 5c2d500bfdb9748d42a281083d993a8c1a50a38f Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 7 Sep 2011 01:20:07 -0400 Subject: [PATCH 208/267] upgrade mongodb to fix require.paths issue --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7c0302..d0b38cd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ , "description" : "A node.js statistics server" , "version" : "0.0.1" , "dependencies": { - "mongodb": "0.9.1" + "mongodb": "0.9.6-14" ,"socket.io": "0.6.16" ,"node-static": "0.5.6" ,"geoip": "0.3.4-1" From 52efc55ea43b77e9318b5c4c3f9c40cbdf5d1e32 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 7 Sep 2011 01:22:45 -0400 Subject: [PATCH 209/267] upgrade packages --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d0b38cd..8e028c4 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ , "dependencies": { "mongodb": "0.9.6-14" ,"socket.io": "0.6.16" - ,"node-static": "0.5.6" - ,"geoip": "0.3.4-1" + ,"node-static": "0.5.9" + ,"geoip": "0.4.3" } , "repository" : { "type" : "git" , "url" : "http://github.com/mnutt/hummingbird.git" } From 6c81795364d1e72da6b22d17db93c3b39381e86c Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 7 Sep 2011 03:16:54 -0400 Subject: [PATCH 210/267] upgrade socket.io to 0.8.4; rework client side pubsub --- lib/hummingbird.js | 5 ++-- lib/metric.js | 3 +-- lib/metrics/cart_adds.js | 14 +++++++++++ lib/metrics/locations.js | 12 +++++---- lib/metrics/total_views.js | 11 +++------ package.json | 2 +- public/index.html | 20 ++++++--------- public/js/websocket.js | 31 +---------------------- public/js/widgets/base.js | 50 +++++++++----------------------------- public/js/widgets/graph.js | 2 +- public/js/widgets/map.js | 1 - server.js | 14 ++++------- 12 files changed, 54 insertions(+), 111 deletions(-) create mode 100644 lib/metrics/cart_adds.js diff --git a/lib/hummingbird.js b/lib/hummingbird.js index 45a0fe5..c951cc1 100644 --- a/lib/hummingbird.js +++ b/lib/hummingbird.js @@ -5,7 +5,6 @@ var sys = require('sys'), Metric = require('./metric').Metric, Aggregates = require('./aggregates').Aggregates, Buffer = require('buffer').Buffer, - io = require('socket.io'), arrays = require('./arrays'), querystring = require('querystring'); @@ -35,12 +34,12 @@ Hummingbird.prototype = { }); }, - addAllMetrics: function(socket, db) { + addAllMetrics: function(io, db) { var self = this; Metric.allMetrics(function(metric) { metric.init(db); - metric.socket = socket; + metric.io = io; self.metrics.push(metric); }); }, diff --git a/lib/metric.js b/lib/metric.js index 9a1c90a..a2f6600 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -39,8 +39,7 @@ Metric.prototype = { // NOTE: using 'metric' in place of 'this', since run from setInterval if(metric.ignoreOnEmpty && !metric.isDirty) { return; } - metric.socket.broadcast(JSON.stringify({type: this.name, data: metric.data})); - + metric.io.sockets.volatile.emit(metric.name, metric.data); metric.resetData(); }, diff --git a/lib/metrics/cart_adds.js b/lib/metrics/cart_adds.js new file mode 100644 index 0000000..e817f74 --- /dev/null +++ b/lib/metrics/cart_adds.js @@ -0,0 +1,14 @@ +var CartAddsMetric = { + name: 'cart_adds', + initialData: 0, + interval: 50, // ms + incrementCallback: function(view) { + if(view.event() && view.event() === "cart_add") { + this.data += 1; + this.minuteData = (this.minuteData || 0) + 1; + } + } +} + +for (var i in CartAddsMetric) + exports[i] = CartAddsMetric[i]; diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index b394670..9bfe053 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -5,8 +5,8 @@ var path = require('path'); var locationCache = {}; var LocationsMetric = { - name: 'Location', - initialData: {location: []}, + name: 'location', + initialData: [], interval: 500, ignoreOnEmpty: true, // don't send any data if we don't get any hits @@ -14,9 +14,10 @@ var LocationsMetric = { var cityPath = path.normalize(__dirname + '/../../GeoLiteCity.dat'); try { - this.cities = geoip.open(cityPath); + this.cities = new geoip.City(cityPath); return true; } catch(e) { + console.log("Couldn't load geoip database."); return false; } }, @@ -32,9 +33,10 @@ var LocationsMetric = { remoteAddress = view.env.ip; } - location = geoip.City.record_by_addr(this.cities, remoteAddress); + location = this.cities.lookupSync(remoteAddress); + if(location.latitude) { - metric.data.location.push(location); + metric.data.push(location); } } } diff --git a/lib/metrics/total_views.js b/lib/metrics/total_views.js index 85818de..ad27ddc 100644 --- a/lib/metrics/total_views.js +++ b/lib/metrics/total_views.js @@ -1,15 +1,10 @@ var TotalViewsMetric = { name: 'view_totals', - initialData: {total: 0, cartAdds: 0}, + initialData: 0, interval: 50, // ms incrementCallback: function(view) { - this.data.total += 1; - this.minuteData.total = (this.minuteData.total || 0) + 1; - - if(view.event() && view.event() === "cart_add") { - this.data.cartAdds += 1; - this.minuteData.cartAdds = (this.minuteData.cartAdds || 0) + 1; - } + this.data += 1; + this.minuteData = (this.minuteData || 0) + 1; } }; diff --git a/package.json b/package.json index 8e028c4..f669084 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ , "version" : "0.0.1" , "dependencies": { "mongodb": "0.9.6-14" - ,"socket.io": "0.6.16" + ,"socket.io": "0.8.4" ,"node-static": "0.5.9" ,"geoip": "0.4.3" } diff --git a/public/index.html b/public/index.html index 0e1a5f4..3d4b1ee 100644 --- a/public/index.html +++ b/public/index.html @@ -70,33 +70,29 @@

Cart Traffic:

hummingbirdSocket = new Hummingbird.WebSocket(); hummingbirdSocket.start(); - $("#total").hummingbirdGraph(hummingbirdSocket, + $("#total").hummingbirdGraph(hummingbirdSocket.socket, { - from: "view_totals", - filter: "total" + from: "view_totals" }); - $("#cart_adds").hummingbirdGraph(hummingbirdSocket, + $("#cart_adds").hummingbirdGraph(hummingbirdSocket.socket, { - from: "view_totals", - filter: "cartAdds", + from: "cart_adds", graphHeight: 100 }); - $("#total h2.graph_title span.value").hummingbirdCount(hummingbirdSocket, + $("#total h2.graph_title span.value").hummingbirdCount(hummingbirdSocket.socket, { from: "view_totals", - filter: "total", every: 10 }); - $("#map_container").hummingbirdMap(hummingbirdSocket, { from: "hits", filter: "location" }); + $("#map_container").hummingbirdMap(hummingbirdSocket.socket, { from: "location" }); new Hummingbird.Logger(window, - hummingbirdSocket, + hummingbirdSocket.socket, { - from: "view_totals", - filter: "cartAdds", + from: "cart_adds", every: 20 }); diff --git a/public/js/websocket.js b/public/js/websocket.js index ff02e75..1e6cbe4 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -26,17 +26,6 @@ Hummingbird.WebSocket.prototype = { console.log("socket started"); }, - onMessage: function(message) { - message = JSON.parse(message); - var i = this.handlers[message.type].length; - while(i--) { - var handler = this.handlers[message.type][i][0]; - var scope = this.handlers[message.type][i][1]; - - handler.apply(scope, [message.data]); - } - }, - // Hummingbird WebSocket functions getState: function() { return this.state; @@ -50,12 +39,10 @@ Hummingbird.WebSocket.prototype = { // Functions that extract data and update UI elements this.handlers = []; - this.socket = new io.Socket(this.webSocketURI(), {port: this.webSocketPort()}); - this.socket.connect(); + this.socket = io.connect(this.webSocketURI(), {port: this.webSocketPort()}); var self = this; - this.socket.on('message', function(message) { self.onMessage(message); }); this.socket.on('disconnect', function() { self.onClose(); }); this.socket.on('connect', function() { self.onOpen(); }); }, @@ -79,22 +66,6 @@ Hummingbird.WebSocket.prototype = { return wsServer; }, - registerHandler: function(handler, scope, type) { - if(!this.handlers[type]) { this.handlers[type] = []; } - this.handlers[type].push([handler, scope]); - }, - - unregisterHandler: function(handler) { - for(var type in this.handlers) { - for(var i = 0; i < this.handlers[type].length; i++) { - if(this.handlers[type][i] === val) { - this.handlers[type].splice(i, 1); - break; - } - } - } - }, - webSocketPort: function() { if(document.location.search.match(/ws_server/)) { var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; diff --git a/public/js/widgets/base.js b/public/js/widgets/base.js index 476bdd5..48bdc24 100644 --- a/public/js/widgets/base.js +++ b/public/js/widgets/base.js @@ -4,67 +4,39 @@ Hummingbird.Base = function() {}; Hummingbird.Base.prototype = { - validMessageCount: 0, + messageCount: 0, messageRate: 20, initialize: function() { this.averageLog = []; - this.setFilter(); this.registerHandler(); }, registerHandler: function() { - this.socket.registerHandler(this.onData, this, this.from); + var self = this; + this.socket.on(this.options.from, function(data) { + self.onData.apply(self, [data]); + }); }, onMessage: function(message) { console.log("Base class says: " + JSON.stringify(message)); }, - onData: function(fullData) { + onData: function(message) { var average; - var message = this.extract(fullData); - if(typeof(message) != "undefined") { - this.validMessageCount += 1; + this.messageCount += 1; - // Calculate the average over N seconds if the averageOver option is set - if(this.options.averageOver) { average = this.addToAverage(message); } + // Calculate the average over N seconds if the averageOver option is set + if(this.options.averageOver && typeof(message) == "number") { average = this.addToAverage(message); } - if((!this.options.every) || (this.validMessageCount % this.options.every == 0)) { - this.onMessage(message, this.average()); - } + if((!this.options.every) || (this.messageCount % this.options.every == 0)) { + this.onMessage(message, this.average()); } }, - extract: function(data) { - if(typeof(data) == "undefined") { return; } - - var obj = data; - for(var i = 0, len = this.filter.length; i < len; i++) { - obj = obj[this.filter[i]]; - } - - return obj; - }, - - setFilter: function() { - this.filter = []; - - var obj = this.options.filter; - if(!obj) { return; } - - while(obj && typeof(obj) != "string") { - for(var i in obj) { - this.filter.push(i); - obj = obj[i]; - break; - } - } - this.filter.push(obj); - }, - addToAverage: function(newValue) { var averageCount = this.options.averageOver * this.messageRate; diff --git a/public/js/widgets/graph.js b/public/js/widgets/graph.js index e81fd8b..32b2fe7 100644 --- a/public/js/widgets/graph.js +++ b/public/js/widgets/graph.js @@ -31,7 +31,7 @@ Hummingbird.Graph = function(element, socket, options) { this.scale = 50; this.element = element; - this.socket = socket + this.socket = socket; this.graph = this.element.find('div.graph'); this.trafficLog = []; diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index 77ee853..2343d58 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -51,7 +51,6 @@ Hummingbird.Map.prototype = new Hummingbird.Base(); $.extend(Hummingbird.Map.prototype, { name: "Map", onMessage: function(value, average) { - console.log(value); if(value && value.length > 0) { for(var i in value) { var geo = value[i]; diff --git a/server.js b/server.js index e96c3b4..1a68c55 100644 --- a/server.js +++ b/server.js @@ -3,7 +3,7 @@ var http = require('http'), config = require('./config/config'), dgram = require('dgram'), static = require('node-static'), - io = require('socket.io'), + sio = require('socket.io'), mongo = require('mongodb'), Hummingbird = require('./lib/hummingbird').Hummingbird; @@ -25,15 +25,11 @@ db.open(function(p_db) { }); server.listen(config.tracking_port, "0.0.0.0"); - socket = io.listen(server); + io = sio.listen(server); + io.set('log level', 2); - socket.on('connection', function(client){ - // new client is here! - client.on('disconnect', function(){ console.log("Lost ws client"); }) - }); - - hummingbird.socket = socket; - hummingbird.addAllMetrics(socket, db); + hummingbird.io = io; + hummingbird.addAllMetrics(io, db); console.log('Web Socket server running at ws://*:' + config.tracking_port); From 5b23194f186b5ae514a4c513c8629e09685cc4c1 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 7 Sep 2011 03:30:06 -0400 Subject: [PATCH 211/267] update cap deploy script --- config/deploy.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/deploy.rb b/config/deploy.rb index 7ed755c..7ad6b26 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -26,8 +26,8 @@ run "#{try_sudo} restart hummingbird_monitor" end - task :pull_express_submodules, :roles => :app do - run "cd #{latest_release}/deps/express && git submodule update --init" + task :update_node_modules, :roles => :app do + run "cd #{latest_release}/#{current} && npm install" end end @@ -66,4 +66,4 @@ end after 'deploy:update_code', 'update:symlink_shared' -after 'deploy:update_code', 'deploy:pull_express_submodules' +after 'deploy:update_code', 'deploy:update_node_modules' From edfaec8cd993d17e40967234d60c20e0deb0c650 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 28 Oct 2011 02:28:49 -0400 Subject: [PATCH 212/267] extract out our polymaps changes --- public/index.html | 1 + public/js/polymaps-extras.js | 169 ++++++++++++++++++++++++ public/js/polymaps.js | 248 ++++++----------------------------- 3 files changed, 211 insertions(+), 207 deletions(-) create mode 100644 public/js/polymaps-extras.js diff --git a/public/index.html b/public/index.html index 3d4b1ee..2f052b6 100644 --- a/public/index.html +++ b/public/index.html @@ -14,6 +14,7 @@ + diff --git a/public/js/polymaps-extras.js b/public/js/polymaps-extras.js new file mode 100644 index 0000000..be1e639 --- /dev/null +++ b/public/js/polymaps-extras.js @@ -0,0 +1,169 @@ +(function(po) { +po.types.Marker = function(o, proj) { + var g = po.svg("g"), + c = o.coordinates, + p = proj(o.coordinates), + r = o.radius || 4.5, + circle = po.svg("circle"); + + circle.setAttribute("r", r); + circle.setAttribute("style", "fill: " + o.color + ";"); + circle.setAttribute("class", "point"); + circle.setAttribute("transform", "translate(" + p.x + "," + p.y + ")"); + g.appendChild(circle); + g.setAttribute("class", "point"); + g.setAttribute("id", o.id); + g.addEventListener("mouseover", function(e) { + var el = e.target.parentNode; + el.parentNode.appendChild(el); + }, true); + + if(o.text) { + var t = po.svg("text"); + t.textContent = o.text; + t.setAttribute("class", "label"); + t.setAttribute("transform", "translate(" + p.x + "," + (p.y - r - 17) + ")"); + g.appendChild(t); + + setTimeout(function() { + var b = po.svg("path"); + var textWidth = (t.getBBox().width / 2) + 6; + + var bg = ""; + bg += "M 0, 29"; + bg += "L -5, 24"; + bg += "L " + (-1 * (textWidth - 5)) + ", 24"; + bg += "A 5, 5, 0, 0, 1, " + (-1 * textWidth) + ", 19"; + bg += "L " + (-1 * textWidth) + ", 17"; + bg += "L " + (-1 * textWidth) + ", 12"; + bg += "L " + (-1 * textWidth) + ", 7"; + bg += "L " + (-1 * textWidth) + ", 5"; + bg += "A 5, 5, 0, 0, 1, " + (-1 * (textWidth - 5)) + ", 0"; + bg += "L 5, 0"; + bg += "L 0, 0"; + bg += "L 5, 0"; + bg += "L " + (textWidth - 5) + ", 0"; + bg += "A 5, 5, 0, 0, 1, " + textWidth + ", 5"; + bg += "L " + textWidth + ", 7"; + bg += "L " + textWidth + ", 12"; + bg += "L " + textWidth + ", 17"; + bg += "L " + textWidth + ", 19"; + bg += "A 5, 5, 0, 0, 1, " + (textWidth - 5) + ", 24"; + bg += "L 5, 24"; + bg += "Z"; + + b.setAttribute("d", bg); + b.setAttribute("class", "label"); + b.setAttribute("transform", "translate(" + (p.x) + "," + (p.y - r - 32) + ")"); + g.appendChild(b); + g.appendChild(t); + + }, 5); + + } + + return g; +}; + +po.fullscreen = function() { + var fullscreen = {}; + var svg = $(po.svg("svg")) + var circle = $(po.svg("circle")); + var arrow = $(po.svg("path")); + var map; + var container; + var isFullscreen = 0; + + svg.append(circle); + svg.append(arrow); + svg.click(goFullscreen); + $(window).bind("keydown",function(e){ + e.which == 27 && isFullscreen && goFullscreen(); + }); + + svg.css({ position: "absolute", + right: "4px", + top: "5px", + visibility: "visible", + cursor: "pointer" }); + + svg.get(0).setAttribute("width", "32"); + svg.get(0).setAttribute("height", "32"); + + circle.attr("fill", "#fff") + .attr("stroke", "#ccc") + .attr("stroke-width", "4"); + + circle.get(0).setAttribute("cx", "16"); + circle.get(0).setAttribute("cy", "16"); + circle.get(0).setAttribute("r", "14"); + + circle.append("Toggle Fullscreen. (ESC)"); + + arrow.attr("d", "M0,0L0,.5 2,.5 2,1.5 4,0 2,-1.5 2,-.5 0,-.5Z") + .attr("pointer-events", "none") + .attr("fill", "#aaa"); + + arrow.get(0).setAttribute("transform", "translate(16,16)rotate(-45)scale(5)translate(-1.85,0)") + + fullscreen.map = function(x) { + if (!arguments.length) return map; + + if (map = x) { + container = $(map.container()); + draw(); + } + + return map; + }; + + function goFullscreen() { + if(isFullscreen = !isFullscreen) { + container.css({ + position: "fixed", + borderWidth: 0, + width: "100%", + height: "100%", + top: 0, + left: 0 + }); + + svg.css({ + position: "fixed", + right: "16px", + top: "16px" + }); + + arrow.get(0).setAttribute("transform","translate(16,16) rotate(135) scale(5) translate(-1.85,0)"); + + } else { + container.css({ + position: "relative", + borderWidth: null, + width: null, + height: null, + top: null, + left: null + }); + + svg.css({ + position: "absolute", + right: "-16px", + top: "-16px" + }); + + arrow.get(0).setAttribute("transform","translate(16,16) rotate(-45) scale(5) translate(-1.85,0)"); + } + + map.resize() + }; + + function draw() { + container.parent().append(svg); + + return fullscreen; + }; + + return fullscreen; +}; +})(org.polymaps); \ No newline at end of file diff --git a/public/js/polymaps.js b/public/js/polymaps.js index 2d75912..849e8ec 100755 --- a/public/js/polymaps.js +++ b/public/js/polymaps.js @@ -1,7 +1,6 @@ if (!org) var org = {}; if (!org.polymaps) org.polymaps = {}; (function(po){ - po.version = "2.5.0"; // semver.org var zero = {x: 0, y: 0}; @@ -1143,115 +1142,21 @@ po.image = function() { return image; }; -po.geoJson = function(fetch) { - var geoJson = po.layer(load, unload), - container = geoJson.container(), - url, - clip = true, - clipId = "org.polymaps." + po.id(), - clipHref = "url(#" + clipId + ")", - clipPath = container.insertBefore(po.svg("clipPath"), container.firstChild), - clipRect = clipPath.appendChild(po.svg("rect")), - scale = "auto", - zoom = null, - features; - - container.setAttribute("fill-rule", "evenodd"); - clipPath.setAttribute("id", clipId); - - if (!arguments.length) fetch = po.queue.json; - - function projection(proj) { - var l = {lat: 0, lon: 0}; - return function(coordinates) { - l.lat = coordinates[1]; - l.lon = coordinates[0]; - var p = proj(l); - coordinates.x = p.x; - coordinates.y = p.y; - return p; - }; - } - function geometry(o, proj) { - return o && o.type in types && types[o.type](o, proj); - } +po.geometry = function (o, proj) { + return o && o.type in po.types && po.types[o.type](o, proj); +}; - var types = { +po.types = { Point: function(o, proj) { var p = proj(o.coordinates), - c = po.svg("circle"); + c = po.svg("circle"); c.setAttribute("r", 4.5); c.setAttribute("transform", "translate(" + p.x + "," + p.y + ")"); return c; }, - Marker: function(o, proj) { - var g = po.svg("g"), - c = o.coordinates, - p = proj(o.coordinates), - r = o.radius || 4.5, - circle = po.svg("circle"); - - circle.setAttribute("r", r); - circle.setAttribute("class", "point"); - circle.setAttribute("transform", "translate(" + p.x + "," + p.y + ")"); - g.appendChild(circle); - g.setAttribute("class", "point"); - g.setAttribute("id", o.id); - g.addEventListener("mouseover", function(e) { - var el = e.target.parentNode; - el.parentNode.appendChild(el); - }, true); - - if(o.text) { - var t = po.svg("text"); - t.textContent = o.text; - t.setAttribute("class", "label"); - t.setAttribute("transform", "translate(" + p.x + "," + (p.y - r - 17) + ")"); - g.appendChild(t); - - setTimeout(function() { - var b = po.svg("path"); - var textWidth = (t.getBBox().width / 2) + 6; - - var bg = ""; - bg += "M 0, 29"; - bg += "L -5, 24"; - bg += "L " + (-1 * (textWidth - 5)) + ", 24"; - bg += "A 5, 5, 0, 0, 1, " + (-1 * textWidth) + ", 19"; - bg += "L " + (-1 * textWidth) + ", 17"; - bg += "L " + (-1 * textWidth) + ", 12"; - bg += "L " + (-1 * textWidth) + ", 7"; - bg += "L " + (-1 * textWidth) + ", 5"; - bg += "A 5, 5, 0, 0, 1, " + (-1 * (textWidth - 5)) + ", 0"; - bg += "L 5, 0"; - bg += "L 0, 0"; - bg += "L 5, 0"; - bg += "L " + (textWidth - 5) + ", 0"; - bg += "A 5, 5, 0, 0, 1, " + textWidth + ", 5"; - bg += "L " + textWidth + ", 7"; - bg += "L " + textWidth + ", 12"; - bg += "L " + textWidth + ", 17"; - bg += "L " + textWidth + ", 19"; - bg += "A 5, 5, 0, 0, 1, " + (textWidth - 5) + ", 24"; - bg += "L 5, 24"; - bg += "Z"; - - b.setAttribute("d", bg); - b.setAttribute("class", "label"); - b.setAttribute("transform", "translate(" + (p.x) + "," + (p.y - r - 32) + ")"); - g.appendChild(b); - g.appendChild(t); - - }, 5); - - } - - return g; - }, - MultiPoint: function(o, proj) { var g = po.svg("g"), c = o.coordinates, @@ -1362,13 +1267,44 @@ po.geoJson = function(fetch) { n = c.length, x; while (++i < n) { - x = geometry(c[i], proj); + x = po.geometry(c[i], proj); if (x) g.appendChild(x); } return g; } - }; +}; + + +po.geoJson = function(fetch) { + var geoJson = po.layer(load, unload), + container = geoJson.container(), + url, + clip = true, + clipId = "org.polymaps." + po.id(), + clipHref = "url(#" + clipId + ")", + clipPath = container.insertBefore(po.svg("clipPath"), container.firstChild), + clipRect = clipPath.appendChild(po.svg("rect")), + scale = "auto", + zoom = null, + features; + + container.setAttribute("fill-rule", "evenodd"); + clipPath.setAttribute("id", clipId); + + if (!arguments.length) fetch = po.queue.json; + + function projection(proj) { + var l = {lat: 0, lon: 0}; + return function(coordinates) { + l.lat = coordinates[1]; + l.lon = coordinates[0]; + var p = proj(l); + coordinates.x = p.x; + coordinates.y = p.y; + return p; + }; + } function rescale(o, e, k) { return o.type in rescales && rescales[o.type](o, e, k); @@ -1413,18 +1349,18 @@ po.geoJson = function(fetch) { case "FeatureCollection": { for (var i = 0; i < data.features.length; i++) { var feature = data.features[i], - element = geometry(feature.geometry, proj); + element = po.geometry(feature.geometry, proj); if (element) updated.push({element: g.appendChild(element), data: feature}); } break; } case "Feature": { - var element = geometry(data.geometry, proj); + var element = po.geometry(data.geometry, proj); if (element) updated.push({element: g.appendChild(element), data: data}); break; } default: { - var element = geometry(data, proj); + var element = po.geometry(data, proj); if (element) updated.push({element: g.appendChild(element), data: {type: "Feature", geometry: data}}); break; } @@ -2025,108 +1961,6 @@ po.interact = function() { return interact; }; -po.fullscreen = function() { - var fullscreen = {}; - var svg = $(po.svg("svg")) - var circle = $(po.svg("circle")); - var arrow = $(po.svg("path")); - var map; - var container; - var isFullscreen = 0; - - svg.append(circle); - svg.append(arrow); - svg.click(goFullscreen); - $(window).bind("keydown",function(e){ - e.which == 27 && isFullscreen && goFullscreen(); - }); - - svg.css({ position: "absolute", - right: "-16px", - top: "-16px", - visibility: "visible", - cursor: "pointer" }); - - svg.get(0).setAttribute("width", "32"); - svg.get(0).setAttribute("height", "32"); - - circle.attr("fill", "#fff") - .attr("stroke", "#ccc") - .attr("stroke-width", "4"); - - circle.get(0).setAttribute("cx", "16"); - circle.get(0).setAttribute("cy", "16"); - circle.get(0).setAttribute("r", "14"); - - circle.append("Toggle Fullscreen. (ESC)"); - - arrow.attr("d", "M0,0L0,.5 2,.5 2,1.5 4,0 2,-1.5 2,-.5 0,-.5Z") - .attr("pointer-events", "none") - .attr("fill", "#aaa"); - - arrow.get(0).setAttribute("transform", "translate(16,16)rotate(-45)scale(5)translate(-1.85,0)") - - fullscreen.map = function(x) { - if (!arguments.length) return map; - - if (map = x) { - container = $(map.container()); - draw(); - } - - return map; - }; - - function goFullscreen() { - if(isFullscreen = !isFullscreen) { - container.css({ - position: "fixed", - borderWidth: 0, - width: "100%", - height: "100%", - top: 0, - left: 0 - }); - - svg.css({ - position: "fixed", - right: "16px", - top: "16px" - }); - - arrow.get(0).setAttribute("transform","translate(16,16) rotate(135) scale(5) translate(-1.85,0)"); - - } else { - container.css({ - position: "relative", - borderWidth: null, - width: null, - height: null, - top: null, - left: null - }); - - svg.css({ - position: "absolute", - right: "-16px", - top: "-16px" - }); - - arrow.get(0).setAttribute("transform","translate(16,16) rotate(-45) scale(5) translate(-1.85,0)"); - } - - map.resize() - }; - - function draw() { - container.parent().append(svg); - - return fullscreen; - }; - - return fullscreen; -}; - po.compass = function() { var compass = {}, g = po.svg("g"), From 1901cdaada442927b5ceb619e2abe6539f1f3fd6 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 28 Oct 2011 02:39:41 -0400 Subject: [PATCH 213/267] improvements in map markers --- public/js/widgets/map.js | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index 2343d58..f120280 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -18,9 +18,9 @@ Hummingbird.Map = function(element, socket, options) { this.map = this.po.map() .container(this.element.get(0).appendChild(this.po.svg("svg"))) - .center({lat: 39, lon: 10}) + .center({lat: 31, lon: 10}) .zoom(2) - .zoomRange([2, 9]) + .zoomRange([2, 8]) .add(this.po.interact()); this.map.add(this.po.image() @@ -41,6 +41,9 @@ Hummingbird.Map = function(element, socket, options) { decimalPlaces: 0 }; + this.colors = { + }; + this.options = $.extend(defaults, options); this.initialize(); }; @@ -56,12 +59,13 @@ $.extend(Hummingbird.Map.prototype, { var geo = value[i]; if(typeof(geo.latitude) == "undefined") { continue; } - this.addMarker(parseFloat(geo.longitude), parseFloat(geo.latitude), 10, geo.city); + var color = this.colors[geo.type] || "#3BA496"; + this.addMarker(parseFloat(geo.longitude), parseFloat(geo.latitude), 5, geo.city, color); } } }, - addMarker: function(lon, lat, radius, text) { + addMarker: function(lon, lat, radius, text, color) { var id = ("mark_" + lon + "_" + lat).replace(/[^0-9a-z_]/g, ''); var existing = $("#" + id); @@ -72,6 +76,7 @@ $.extend(Hummingbird.Map.prototype, { type: "Marker", id: id, radius: radius, + color: color, text: text || "" }; @@ -80,11 +85,24 @@ $.extend(Hummingbird.Map.prototype, { } else { // Stop the current animation queue and set opacity back to 1 existing.stop(true).stopDelay().css({ opacity: 1 }); + var radius = existing.find("circle").attr('r'); + var radiusValue = radius.baseVal.value; + radius.baseVal.value = radiusValue + 0.02 * ((30 - radiusValue) * Math.cos((radiusValue)/30 * (Math.PI/2))); } // After 4 seconds, fade marker out then remove the whole layer - existing.delay(4000).animate({ opacity: 0 }, 1000, function() { - $(this).parent().parent().parent().remove(); - }); + existing.delay(4000).animate({ opacity: 0 }, + { + duration: 1000, + step: function(now, fx) { + var radius = $(this).find("circle").attr('r'); + if(!radius.originalValue) { radius.originalValue = radius.baseVal.value; } + radius.baseVal.value = radius.originalValue * now; + }, + easing: "linear", + complete: function() { + $(this).parent().parent().parent().remove(); + } + }); } }); From 06cbe6e052707045259f0ef62bd3dca87a5a806a Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 28 Oct 2011 02:57:15 -0400 Subject: [PATCH 214/267] fix minuteData reporting --- lib/metric.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metric.js b/lib/metric.js index a2f6600..95d57f2 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -98,7 +98,7 @@ Metric.prototype = { }, resetMinuteData: function() { - this.minuteData = {}; + this.minuteData = JSON.parse(JSON.stringify(this.initialData)); }, stop: function() { From 8a2da13a2dfb3292fe3401409d0126a46295ad25 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 28 Oct 2011 02:57:46 -0400 Subject: [PATCH 215/267] show different color markers for different events --- lib/metrics/cart_adds.js | 2 +- lib/metrics/locations.js | 5 ++++- lib/view.js | 3 +++ public/js/widgets/map.js | 5 ++++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/metrics/cart_adds.js b/lib/metrics/cart_adds.js index e817f74..e8d18c8 100644 --- a/lib/metrics/cart_adds.js +++ b/lib/metrics/cart_adds.js @@ -5,7 +5,7 @@ var CartAddsMetric = { incrementCallback: function(view) { if(view.event() && view.event() === "cart_add") { this.data += 1; - this.minuteData = (this.minuteData || 0) + 1; + this.minuteData += 1; } } } diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index 9bfe053..ebd6745 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -36,7 +36,10 @@ var LocationsMetric = { location = this.cities.lookupSync(remoteAddress); if(location.latitude) { - metric.data.push(location); + metric.data.push({ city: location.city, + latitude: location.latitude, + longitude: location.longitude, + type: view.env.type }); } } } diff --git a/lib/view.js b/lib/view.js index cab3d2f..902b4f4 100644 --- a/lib/view.js +++ b/lib/view.js @@ -6,6 +6,9 @@ var View = function(env) { } this.env = env; + if(this.env.events == "scAdd") { + this.env.type = "cart_add"; + } } diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index f120280..c06480d 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -42,6 +42,7 @@ Hummingbird.Map = function(element, socket, options) { }; this.colors = { + cart_add: "#d84136" }; this.options = $.extend(defaults, options); @@ -85,7 +86,9 @@ $.extend(Hummingbird.Map.prototype, { } else { // Stop the current animation queue and set opacity back to 1 existing.stop(true).stopDelay().css({ opacity: 1 }); - var radius = existing.find("circle").attr('r'); + var circle = existing.find("circle") + var radius = circle.attr('r'); + circle.css({fill: color}); var radiusValue = radius.baseVal.value; radius.baseVal.value = radiusValue + 0.02 * ((30 - radiusValue) * Math.cos((radiusValue)/30 * (Math.PI/2))); } From 00b07690758d828d59bfe060dffb7001d35b1d10 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 28 Oct 2011 03:11:20 -0400 Subject: [PATCH 216/267] check to make sure geoip returned a location --- lib/metrics/locations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index ebd6745..94ad27a 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -35,7 +35,7 @@ var LocationsMetric = { location = this.cities.lookupSync(remoteAddress); - if(location.latitude) { + if(location && location.latitude) { metric.data.push({ city: location.city, latitude: location.latitude, longitude: location.longitude, From 792ed5991ac2f0e85dca00a0c957d12e45138e83 Mon Sep 17 00:00:00 2001 From: Thinkroth Date: Wed, 9 Nov 2011 13:53:38 -0500 Subject: [PATCH 217/267] Updated Dependancies Updated jQuery to 1.7 and socket.io to 0.8.7 --- package.json | 2 +- public/aggregates.html | 2 +- public/index.html | 2 +- public/js/jquery-1.4.3.js | 6883 ------------------------ public/js/jquery-1.4.3.min.js | 166 - public/js/jquery-1.7.js | 9300 +++++++++++++++++++++++++++++++++ public/js/jquery-1.7.min.js | 4 + 7 files changed, 9307 insertions(+), 7052 deletions(-) delete mode 100644 public/js/jquery-1.4.3.js delete mode 100644 public/js/jquery-1.4.3.min.js create mode 100755 public/js/jquery-1.7.js create mode 100755 public/js/jquery-1.7.min.js diff --git a/package.json b/package.json index f669084..f47dbf5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ , "version" : "0.0.1" , "dependencies": { "mongodb": "0.9.6-14" - ,"socket.io": "0.8.4" + ,"socket.io": "0.8.7" ,"node-static": "0.5.9" ,"geoip": "0.4.3" } diff --git a/public/aggregates.html b/public/aggregates.html index 1e23149..71522ed 100644 --- a/public/aggregates.html +++ b/public/aggregates.html @@ -3,7 +3,7 @@ - + diff --git a/public/index.html b/public/index.html index 2f052b6..be2d118 100644 --- a/public/index.html +++ b/public/index.html @@ -3,7 +3,7 @@ - + - + diff --git a/public/js/websocket.js b/public/js/websocket.js index 1e6cbe4..fefcdaf 100644 --- a/public/js/websocket.js +++ b/public/js/websocket.js @@ -71,7 +71,7 @@ Hummingbird.WebSocket.prototype = { var wsPortParam = document.location.search.match(/ws_port=([^\&\#]+)/) || []; return wsPortParam; } - return 8000; + return document.location.port; } } diff --git a/server.js b/server.js index 1a68c55..430639a 100644 --- a/server.js +++ b/server.js @@ -25,7 +25,25 @@ db.open(function(p_db) { }); server.listen(config.tracking_port, "0.0.0.0"); - io = sio.listen(server); + + if(config.enable_dashboard) { + var file = new(static.Server)('./public'); + + var dashboardServer = http.createServer(function (request, response) { + request.addListener('end', function () { + file.serve(request, response); + }); + }); + + dashboardServer.listen(config.dashboard_port); + + io = sio.listen(dashboardServer); + + console.log('Dashboard server running at http://*:' + config.dashboard_port); + } else { + io = sio.listen(server); + } + io.set('log level', 2); hummingbird.io = io; @@ -51,15 +69,3 @@ db.open(function(p_db) { console.log('Tracking server running at http://*:' + config.tracking_port + '/tracking_pixel.gif'); }); - -if(config.enable_dashboard) { - var file = new(static.Server)('./public'); - - http.createServer(function (request, response) { - request.addListener('end', function () { - file.serve(request, response); - }); - }).listen(config.dashboard_port); - - console.log('Dashboard server running at http://*:' + config.dashboard_port); -} From 5267069398586811bf1d831d118306ad36e2acf1 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 13 Sep 2012 02:02:01 -0400 Subject: [PATCH 221/267] split up hummingbird into a tracker and a dashboard; clean up metric api --- lib/dashboard.js | 37 +++++++++ lib/hummingbird.js | 99 ------------------------ lib/metric.js | 150 ++++++++++++------------------------- lib/metrics/cart_adds.js | 29 ++++--- lib/metrics/hits.js | 35 +++++---- lib/metrics/locations.js | 89 +++++++++++----------- lib/metrics/sales.js | 23 ------ lib/metrics/total_views.js | 25 ++++--- lib/pixel.js | 12 +++ lib/tracker.js | 48 ++++++++++++ package.json | 6 +- public/index.html | 4 +- server.js | 79 ++++--------------- 13 files changed, 264 insertions(+), 372 deletions(-) create mode 100644 lib/dashboard.js delete mode 100644 lib/hummingbird.js delete mode 100644 lib/metrics/sales.js create mode 100644 lib/pixel.js create mode 100644 lib/tracker.js diff --git a/lib/dashboard.js b/lib/dashboard.js new file mode 100644 index 0000000..d87a3f8 --- /dev/null +++ b/lib/dashboard.js @@ -0,0 +1,37 @@ +var socketio = require('socket.io'); +var static = require('node-static'); +var Metric = require('./metric'); + +var fileServer = new(static.Server)("./public"); + +var defaultHandler = function(request, response) { + console.log(" - " + request.url); + fileServer.serve(request, response); +}; + +var server = require('http').createServer(defaultHandler); +var io = socketio.listen(server); +io.set("log level", 1); + +if(config.origins) { + io.set("origins", config.origins); + console.log("Restricting dashboard websockets to " + config.origins + "."); +} + +setInterval(function() { + var userCount = Object.keys(io.sockets.sockets).length; + console.log(userCount + " users connected."); +}, 60 * 1000); + +Metric.loadMetrics(io); + +for(var metricName in Metric.all) { + var metric = Metric.all[metricName]; + metric.on('data', function(metricName, data) { + io.sockets.volatile.emit(metricName, data); + }); + + metric.start(); +} + +module.exports = server; diff --git a/lib/hummingbird.js b/lib/hummingbird.js deleted file mode 100644 index c951cc1..0000000 --- a/lib/hummingbird.js +++ /dev/null @@ -1,99 +0,0 @@ -var sys = require('sys'), - fs = require('fs'), - config = require('../config/config'), - View = require('./view').View, - Metric = require('./metric').Metric, - Aggregates = require('./aggregates').Aggregates, - Buffer = require('buffer').Buffer, - arrays = require('./arrays'), - querystring = require('querystring'); - - -var Hummingbird = function(db, callback) { - var pixelData = fs.readFileSync(__dirname + "/../images/tracking.gif", 'binary'); - this.pixel = new Buffer(43); - this.pixel.write(pixelData, 'binary', 0); - - this.metrics = []; -}; - -Hummingbird.prototype = { - init: function(db, callback) { - this.setupDb(db, function() { - callback(); - }); - }, - - setupDb: function(db, callback) { - var self = this; - db.createCollection('visits', function(err, collection) { - db.collection('visits', function(err, collection) { - self.collection = collection; - callback(); - }); - }); - }, - - addAllMetrics: function(io, db) { - var self = this; - - Metric.allMetrics(function(metric) { - metric.init(db); - metric.io = io; - self.metrics.push(metric); - }); - }, - - serveRequest: function(req, res) { - this.writePixel(res); - - var env = this.splitQuery(req.url.split('?')[1]); - env.ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; - - this.insertData(env); - }, - - insertData: function(env) { - env.timestamp = new Date(); - var view = new View(env); - - env.url_key = view.urlKey; - env.product_id = view.productId; - - this.collection.insertAll([env]); - - for(var i = 0; i < this.metrics.length; i++) { - this.metrics[i].incrementCallback(view); - this.metrics[i].isDirty = true; - } - }, - - splitQuery: function(query) { - var queryString = {}; - (query || "").replace( - new RegExp("([^?=&]+)(=([^&]*))?", "g"), - function($0, $1, $2, $3) { queryString[$1] = querystring.unescape($3.replace(/\+/g, ' ')); } - ); - - return queryString; - }, - - writePixel: function(res) { - res.writeHead(200, { 'Content-Type': 'image/gif', - 'Content-Disposition': 'inline', - 'Content-Length': '43' }); - res.end(this.pixel); - }, - - handleError: function(req, res, e) { - res.writeHead(500, {}); - res.write("Server error"); - res.end(); - - e.stack = e.stack.split('\n'); - e.url = req.url; - sys.log(JSON.stringify(e, null, 2)); - } -}; - -exports.Hummingbird = Hummingbird; diff --git a/lib/metric.js b/lib/metric.js index 95d57f2..a3b7db3 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -2,137 +2,83 @@ var sys = require('sys'), path = require('path'), fs = require('fs'); -var Metric = function() { - this.name = null; - this.initialData = {}; - this.interval = 500; - this.job = null; - this.minuteJob = null; - this.clients = []; - this.incrementCallback = null; - this.aggregateCallback = null; - - this.resetMinuteData(); - this.resetData(); -} +var Metric = function() {}; Metric.prototype = { - init: function(db) { - var metric = this; - - db.createCollection('metrics', function(err, collection) { - db.collection('metrics', function(err, collection) { - metric.collection = collection; - metric.resetData(); - metric.resetMinuteData(); - metric.run(); - }); - }); - }, + interval: 500, // ms + name: '', + initialData: {}, - run: function() { - this.job = setInterval(this.runner, this.interval, this); - this.minuteJob = setInterval(this.minuteRunner, 60000, this); + start: function() { + this.resetData(); + this.job = setInterval(this.run.bind(this), this.interval); }, - runner: function(metric) { - // NOTE: using 'metric' in place of 'this', since run from setInterval - if(metric.ignoreOnEmpty && !metric.isDirty) { return; } + run: function() { + if(this.ignoreOnEmpty && !this.hasChanged) { return; } + this.emit('data', this.name, this.data || this.initialData); - metric.io.sockets.volatile.emit(metric.name, metric.data); - metric.resetData(); + this.resetData(); }, - minuteRunner: function(metric) { - var time = new Date(); - var timestamp = new Date(time.getTime()); - - time.setMilliseconds(0); - - time.setSeconds(0); - var timestampMinute = new Date(time.getTime()); - time.setMinutes(0); - var timestampHour = new Date(time.getTime()); - time.setHours(0); - var timestampDay = new Date(time.getTime()); - - var mongoData = { - data: metric.minuteData, - name: metric.name, - interval: 60, - timestamp: timestamp, - minute: timestampMinute, - hour: timestampHour, - day: timestampDay - }; - - sys.log(JSON.stringify(mongoData)); - - metric.collection.update({ minute: timestampMinute }, - { "$inc" : metric.minuteData }, - { upsert: true }, - function(err, result) {}); - metric.collection.update({ hour: timestampHour }, - { "$inc" : metric.minuteData }, - { upsert: true }, - function(err, result) {}); - metric.collection.update({ day: timestampDay }, - { "$inc" : metric.minuteData }, - { upsert: true }, - function(err, result) {}); - - metric.resetMinuteData(); + resetData: function() { + this.data = this.prepareInitialData(); + this.hasChanged = false; }, - removeClient: function(client) { - this.clients.remove(client); + prepareInitialData: function() { + return JSON.parse(JSON.stringify(this.initialData)); }, - addClient: function(client) { - this.clients.push(client); + stop: function() { + clearInterval(this.job); }, - resetData: function() { - this.data = JSON.parse(JSON.stringify(this.initialData)); - this.isDirty = false; + // override if the metric needs to check if it can load + canLoad: function() { + return true; }, - resetMinuteData: function() { - this.minuteData = JSON.parse(JSON.stringify(this.initialData)); - }, + register: function() { + for(metric in Metric.all) { + if(this == Metric.all[metric]) { return; } + } + console.log("Loaded metric " + this.name); - stop: function() { - clearInterval(this.job); + Metric.all.push(this); } }; +// Inherit from EventEmitter +var events = Object.create(require('events').EventEmitter.prototype); +for(var o in events) { Metric.prototype[o] = events[o]; } + +Metric.all = []; + +Metric.loadMetrics = function() { + Metric.availableMetricPaths(function(path) { + var metric = require(path); + if(metric.canLoad()) { metric.register(); } + }); +}; + Metric.availableMetricPaths = function(callback) { var files = fs.readdirSync(path.join(__dirname, 'metrics')); for(var i = 0; i < files.length; i++) { var file = files[i]; - var filename = file.replace(/\.js$/, ''); + var filename = file.replace(/\.(js|coffee)$/, ''); callback(path.join(__dirname, 'metrics', filename)); } }; -Metric.allMetrics = function(callback) { - Metric.availableMetricPaths(function(metricPath) { - var m = require(metricPath); - if(typeof(m.canLoad) == "function" && m.canLoad() == false) { - sys.log("Skipping metric " + m.name + "."); - return; - } else { - sys.log("Loading metric " + m.name + "."); - } - - // Instantiate a new metric and use the settings from the custom metrics class - var metric = new Metric() - for(var key in m) { - metric[key] = m[key]; +Metric.insert = function(req) { + for(var i = 0, l = Metric.all.length; i < l; i++) { + var metric = Metric.all[i]; + if(metric.increment) { + metric.increment(req); } - callback(metric); - }); + } }; -exports.Metric = Metric; +module.exports = Metric; diff --git a/lib/metrics/cart_adds.js b/lib/metrics/cart_adds.js index e8d18c8..a80419f 100644 --- a/lib/metrics/cart_adds.js +++ b/lib/metrics/cart_adds.js @@ -1,14 +1,19 @@ -var CartAddsMetric = { - name: 'cart_adds', - initialData: 0, - interval: 50, // ms - incrementCallback: function(view) { - if(view.event() && view.event() === "cart_add") { - this.data += 1; - this.minuteData += 1; - } +// Cart adds +// +// Emits aggregates per interval for the number of requests +// with a query parameter ?event=cart_add + +var Metric = require('../metric'); + +var cartAdds = Object.create(Metric.prototype); + +cartAdds.name = 'cart_adds'; +cartAdds.initialData = 0; +cartAdds.interval = 50; // ms +cartAdds.increment = function(request) { + if(request.params.event === "cart_add") { + this.data += 1; } -} +}; -for (var i in CartAddsMetric) - exports[i] = CartAddsMetric[i]; +module.exports = cartAdds; diff --git a/lib/metrics/hits.js b/lib/metrics/hits.js index 98a5217..e42513d 100644 --- a/lib/metrics/hits.js +++ b/lib/metrics/hits.js @@ -1,16 +1,21 @@ -var HitsMetric = { - name: 'hits', - initialData: [], - interval: 200, - incrementCallback: function(view) { - var value = { - url: view.env.u, - timestamp: view.env.timestamp, - ip: view.env.ip - }; - this.data.push(value); - } -} +// Hits +// +// Send back individual hits. Warning: this will send +// a _lot_ of data if you have a high traffic site. -for (var i in HitsMetric) - exports[i] = HitsMetric[i]; \ No newline at end of file +var Metric = require('../metric'); + +var hits = Object.create(Metric.prototype); + +hits.name = 'hits'; +hits.initialData = []; +hits.interval = 200; // ms +hits.increment = function(request) { + this.data.push({ + url: request.headers.referer, + timestamp: new Date(), + ip: request.ip + }); +}; + +module.exports = hits; diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index 4fba0ca..f970257 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -1,48 +1,51 @@ -var http = require('http'); +// Locations +// +// Sends individual requests, geolocated using ip address + var geoip = require('geoip'); var path = require('path'); +var Metric = require('../metric'); + +var cities; + +var locations = Object.create(Metric.prototype); + +locations.name = 'location'; +locations.initialData = []; +locations.interval = 500; // ms +locations.ignoreOnEmpty = true; + +locations.canLoad = function() { + var cityPath = path.normalize(__dirname + '/../../GeoLiteCity.dat'); + + try { + cities = geoip.open(cityPath); + return true; + } catch(e) { + console.log("Couldn't load geoip database."); + return false; + } +}; + +locations.increment = function(request) { + var remoteAddress; + + if(request.ip === "127.0.0.1") { + remoteAddress = "8.8.8.8"; // Mountain View, CA + } else { + remoteAddress = request.ip; + } + + var location = geoip.City.record_by_addr(cities, remoteAddress); -var locationCache = {}; - -var LocationsMetric = { - name: 'location', - initialData: [], - interval: 500, - ignoreOnEmpty: true, // don't send any data if we don't get any hits - - canLoad: function() { - var cityPath = path.normalize(__dirname + '/../../GeoLiteCity.dat'); - - try { - this.cities = geoip.open(cityPath); - return true; - } catch(e) { - console.log("Couldn't load geoip database."); - return false; - } - }, - - incrementCallback: function(view) { - var remoteAddress, - locations, - metric = this; - - if(view.env.ip === "127.0.0.1") { - remoteAddress = "8.8.8.8"; - } else { - remoteAddress = view.env.ip; - } - - location = geoip.City.record_by_addr(this.cities, remoteAddress); - - if(location && location.latitude) { - metric.data.push({ city: location.city, - latitude: location.latitude, - longitude: location.longitude, - type: view.env.type }); - } + if(location && location.latitude) { + this.data.push({ + city: location.city, + latitude: location.latitude, + longitude: location.longitude, + type: request.params.type + }); } -} +}; -for (var i in LocationsMetric) - exports[i] = LocationsMetric[i]; +module.exports = locations; diff --git a/lib/metrics/sales.js b/lib/metrics/sales.js deleted file mode 100644 index acea336..0000000 --- a/lib/metrics/sales.js +++ /dev/null @@ -1,23 +0,0 @@ -var SalesMetric = { - name: 'Sales', - initialData: { sales: {} }, - interval: 500, // ms - - incrementCallback: function(view) { - if(view.env.u) { - var match = view.env.u.match(/^http:\/\/[^\/]+(\/s\/|\/sale\/splash\/|\/city\/offers?\/)([^\/\?\#]+)\/?(product\/)?(\d+)?/); - if(match && match.length > 2) { - view.urlKey = match[2]; - view.productId = match[4]; - } - } - - if(view.urlKey) { - this.data.sales[view.urlKey] = (this.data.sales[view.urlKey] || 0) + 1; - this.minuteData["sales."+view.urlKey] = (this.minuteData["sales."+view.urlKey] || 0) + 1; - } - }, -}; - -for (var i in SalesMetric) - exports[i] = SalesMetric[i]; \ No newline at end of file diff --git a/lib/metrics/total_views.js b/lib/metrics/total_views.js index ad27ddc..d92dede 100644 --- a/lib/metrics/total_views.js +++ b/lib/metrics/total_views.js @@ -1,12 +1,17 @@ -var TotalViewsMetric = { - name: 'view_totals', - initialData: 0, - interval: 50, // ms - incrementCallback: function(view) { - this.data += 1; - this.minuteData = (this.minuteData || 0) + 1; - } +// Total views +// +// Sends total count per interval of time for every +// request made + +var Metric = require('../metric'); + +var totalViews = Object.create(Metric.prototype); + +totalViews.name = 'view_totals'; +totalViews.initialData = 0; +totalViews.interval = 50; // ms +totalViews.increment = function(view) { + this.data += 1; }; -for (var i in TotalViewsMetric) - exports[i] = TotalViewsMetric[i]; \ No newline at end of file +module.exports = totalViews; diff --git a/lib/pixel.js b/lib/pixel.js new file mode 100644 index 0000000..7396a06 --- /dev/null +++ b/lib/pixel.js @@ -0,0 +1,12 @@ +var Buffer = require('buffer').Buffer; + +exports.data = new Buffer(42); +exports.data.write("GIF89a\u0001\u0000\u0001\u0000€\u0000\u0000\u0000\u0000\u0000ÿÿÿ!ù\u0004\u0001\u0000\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0001D\u0000;", 'binary'); +exports.size = 42; + +exports.headers = { + 'Content-Length': 42, + 'Content-Type': "image/gif", + 'Pragma': 'no-cache', + 'Cache-Control': "no-store, no-cache, must-revalidate, max-age=0,post-check=0,pre-check=0" +} diff --git a/lib/tracker.js b/lib/tracker.js new file mode 100644 index 0000000..a6377d8 --- /dev/null +++ b/lib/tracker.js @@ -0,0 +1,48 @@ +var http = require('http'); +var url = require('url'); +var Metric = require('./metric'); +var pixel = require('./pixel'); + +var pixelHandler = function(req, res) { + res.writeHead(200, pixel.headers); + res.end(pixel.data); + + req.params = url.parse(req.url, true).query; + + Metric.insert(req); +}; + +exports.listen = function(server, address) { + if(typeof(server) === "number") { + var port = server; + http.createServer(pixelHandler).listen(port, address); + } else { + // Attach to an existing server + var oldListeners = server.listeners('request'); + server.removeAllListeners('request'); + + server.on('request', function(req, res) { + if(req.url.match(/^\/tracking_pixel/)) { + pixelHandler(req, res); + } else { + for (var i = 0, l = oldListeners.length; i < l; i++) { + oldListeners[i].call(server, req, res); + } + } + }); + } +}; + +exports.listenUdp = function(port, address) { + var udpServer = dgram.createSocket("udp4"); + + udpServer.on("message", function(message, rinfo) { + try { + var data = JSON.parse(message); + } catch(e) { + console.log("Error parsing UDP message: " + e.message); + } + + Metric.insert({ip: data.ip, params: data}); + }); +}; diff --git a/package.json b/package.json index 5b1e6bd..39ef8b5 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "hummingbird", "description": "A node.js statistics server", - "version": "0.0.1-1", + "version": "0.0.1-4", "dependencies": { - "mongodb": "0.9.6-14", + "mongodb": "1.1.7", "socket.io": "0.8.7", "node-static": "0.5.9", "geoip": "0.3.4-1" @@ -19,4 +19,4 @@ "scripts": { "start": "server.js" } -} +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index a8856ec..1bf17b4 100644 --- a/public/index.html +++ b/public/index.html @@ -101,14 +101,14 @@

Cart Traffic:

e.preventDefault(); var img = document.createElement('img'); - img.src = "http://localhost:8000/tracking_pixel.gif?f=" + Math.ceil(Math.random() * 1000000) + img.src = "/tracking_pixel.gif?f=" + Math.ceil(Math.random() * 1000000) }); $("#test_cart").click(function(e) { e.preventDefault(); var img = document.createElement('img'); - img.src = "http://localhost:8000/tracking_pixel.gif?events=scAdd&f=" + Math.ceil(Math.random() * 1000000) + img.src = "/tracking_pixel.gif?events=scAdd&f=" + Math.ceil(Math.random() * 1000000) }); }); diff --git a/server.js b/server.js index 430639a..8761c2f 100644 --- a/server.js +++ b/server.js @@ -1,71 +1,24 @@ -var http = require('http'), - weekly = require('./lib/weekly'), - config = require('./config/config'), - dgram = require('dgram'), - static = require('node-static'), - sio = require('socket.io'), - mongo = require('mongodb'), - Hummingbird = require('./lib/hummingbird').Hummingbird; +config = require('./config/config'); -db = new mongo.Db('hummingbird', new mongo.Server(config.mongo_host, config.mongo_port, {}), {}); +var dashboard = require('./lib/dashboard'); +var tracker = require('./lib/tracker'); -db.addListener("error", function(error) { - console.log("Error connecting to mongo -- perhaps it isn't running?"); -}); -db.open(function(p_db) { - var hummingbird = new Hummingbird(); - hummingbird.init(db, function() { - var server = http.createServer(function(req, res) { - try { - hummingbird.serveRequest(req, res); - } catch(e) { - hummingbird.handleError(req, res, e); - } - }); - server.listen(config.tracking_port, "0.0.0.0"); +dashboard.listen(config.dashboard_port, config.dashboard_address); +console.log("Dashboard listening on http://" + (config.dashboard_address || '*') + ":" + config.dashboard_port + "."); - if(config.enable_dashboard) { - var file = new(static.Server)('./public'); +// Tracker should listen on the same port as the dashboard +tracker.listen(dashboard); +console.log("Tracker listening on http://" + (config.dashboard_address || '*') + ":" + config.dashboard_port + "/tracking_pixel.gif."); - var dashboardServer = http.createServer(function (request, response) { - request.addListener('end', function () { - file.serve(request, response); - }); - }); - dashboardServer.listen(config.dashboard_port); +// If you want to have the tracking pixel listen on a different port +// (for instance in order to password-protect your dashboard) you can +// uncomment this +// +// tracker.listen(8000, "0.0.0.0"); - io = sio.listen(dashboardServer); - - console.log('Dashboard server running at http://*:' + config.dashboard_port); - } else { - io = sio.listen(server); - } - - io.set('log level', 2); - - hummingbird.io = io; - hummingbird.addAllMetrics(io, db); - - console.log('Web Socket server running at ws://*:' + config.tracking_port); - - if(config.udp_address) { - var udpServer = dgram.createSocket("udp4"); - - udpServer.on("message", function(message, rinfo) { - console.log("message from " + rinfo.address + " : " + rinfo.port); - - var data = JSON.parse(message); - hummingbird.insertData(data); - }); - - udpServer.bind(config.udp_port, config.udp_address); - - console.log('UDP server running on UDP port ' + config.udp_port); - } - }); - - console.log('Tracking server running at http://*:' + config.tracking_port + '/tracking_pixel.gif'); -}); +// UDP tracking +// +// tracker.listenUdp(8000, "0.0.0.0"); From d9a3b8f27a8dcc4accea42c4b3ed380a5e945690 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 13 Sep 2012 02:02:08 -0400 Subject: [PATCH 222/267] update readme --- README.md | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 118ab6f..f0db9b0 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,7 @@ sends back tracking data generated by javascript. Requirements ------------------- - * node.js v0.2.0 - * npm v0.2.4 - * mongodb - + * node.js v0.8.0 Installation -------------- @@ -28,9 +25,6 @@ Installation # Use npm to install the dependencies npm install - # Copy the default configuration file - cp config/app.json.sample config/app.json - # To use the map, download MaxMind's GeoIP database and extract to the root directory: wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz gunzip GeoLiteCity.dat.gz @@ -41,22 +35,22 @@ Running Hummingbird To start the analytics server, run the following: - mongod & (or start mongo some other way) node server.js By default a dashboard will be run on port 8080. You can disable it for production use in -config/app.json. The dashboard is just html served out of public/; you can serve it using +config/config.js. The dashboard is just html served out of public/; you can serve it using any webserver. Deployment ---------- -Make sure to properly secure the dashboard if you don't want outside people to see it. The dashboard -httpServer's 'listen' function takes a second argument that is the interface to bind; typically you +Make sure to properly secure the dashboard if you don't want outside people to see it. This +typically means putting the dashboard behind nginx or apache using basic auth. The dashboard's +'listen' function takes a second argument that is the interface to bind; typically you would choose "127.0.0.1" to only allow access from localhost, or "0.0.0.0" to listen on all -interfaces. In production you should change the instances of "localhost:8000" in public/index.html -to point to the server where you're hosting the dashboard. +interfaces. You should then run the tracking pixel on a different port so that it is accessible +to the outside world. Architecture Overview @@ -64,12 +58,12 @@ Architecture Overview Hummingbird is organized into two parts: a node.js-based tracking server that records user activity via a tracking pixel, and a collection of javascript-based widgets that display that -activity. The server records all activity in MongoDB and broadcasts it to the clients using -WebSockets if possible, and falling back to Flash sockets if necessary. +activity. The server broadcasts all activity to the clients using Websockets if possible, and +falls back to Flash sockets or long polling if necessary. The Hummingbird.WebSocket object receives websocket events from the server in the form of JSON -objects. Individual widgets subscribe to a property in the JSON tree and register handler -functions to be called whenever that property is present. +objects. Individual widgets subscribe to a metric and register handler functions to be called +whenever that metric is present. Logging Customization @@ -78,8 +72,8 @@ Logging Customization Metrics are stored in lib/metrics and auto-loaded. Each metric contains a handler function that is called every time a new user event occurs. Metrics store data in the `data` object property which gets emitted to clients in intervals specified by the metric. A basic example can be found in -lib/metrics/total_views.js. An example of how a metric can filter based on urls is in -lib/metric/sales.js. +lib/metrics/total_views.js. An example of how a metric can filter based on query params is in +lib/metric/cart_adds.js. Display Customization From 044fc36157f828a31f2620c07e26aeaee6245e32 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Thu, 13 Sep 2012 02:09:50 -0400 Subject: [PATCH 223/267] update index.html to modify cart add request --- package.json | 3 +-- public/index.html | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 39ef8b5..8faaec1 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,8 @@ { "name": "hummingbird", "description": "A node.js statistics server", - "version": "0.0.1-4", + "version": "0.2.0-3", "dependencies": { - "mongodb": "1.1.7", "socket.io": "0.8.7", "node-static": "0.5.9", "geoip": "0.3.4-1" diff --git a/public/index.html b/public/index.html index 1bf17b4..832cc9c 100644 --- a/public/index.html +++ b/public/index.html @@ -108,7 +108,7 @@

Cart Traffic:

e.preventDefault(); var img = document.createElement('img'); - img.src = "/tracking_pixel.gif?events=scAdd&f=" + Math.ceil(Math.random() * 1000000) + img.src = "/tracking_pixel.gif?event=cart_add&f=" + Math.ceil(Math.random() * 1000000) }); }); From fe3c22a7ca384ebb69c484765d0e8dfa81728f14 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 14 Sep 2012 01:44:14 -0400 Subject: [PATCH 224/267] make metric loading asynchronous --- lib/dashboard.js | 7 +-- lib/metric.js | 17 ++++--- lib/metrics/locations.js | 91 +++++++++++++++++++++++++++++--------- lib/metrics/total_views.js | 2 +- public/index.html | 2 +- 5 files changed, 87 insertions(+), 32 deletions(-) diff --git a/lib/dashboard.js b/lib/dashboard.js index d87a3f8..cc58fa8 100644 --- a/lib/dashboard.js +++ b/lib/dashboard.js @@ -23,15 +23,12 @@ setInterval(function() { console.log(userCount + " users connected."); }, 60 * 1000); -Metric.loadMetrics(io); - -for(var metricName in Metric.all) { - var metric = Metric.all[metricName]; +Metric.loadMetrics(function(metric) { metric.on('data', function(metricName, data) { io.sockets.volatile.emit(metricName, data); }); metric.start(); -} +}); module.exports = server; diff --git a/lib/metric.js b/lib/metric.js index a3b7db3..c90ae79 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -34,9 +34,9 @@ Metric.prototype = { clearInterval(this.job); }, - // override if the metric needs to check if it can load - canLoad: function() { - return true; + // Override if the metric needs to check if it can load. + load: function(callback) { + callback(null); }, register: function() { @@ -55,10 +55,17 @@ for(var o in events) { Metric.prototype[o] = events[o]; } Metric.all = []; -Metric.loadMetrics = function() { +Metric.loadMetrics = function(callback) { Metric.availableMetricPaths(function(path) { var metric = require(path); - if(metric.canLoad()) { metric.register(); } + metric.load(function(err) { + if(err) { + console.log(err.message); + } else { + metric.register(); + if(callback) { callback(metric); } + } + }); }); }; diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index f970257..e8d392b 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -5,36 +5,23 @@ var geoip = require('geoip'); var path = require('path'); var Metric = require('../metric'); +var http = require('http'); +var zlib = require('zlib'); +var fs = require('fs'); + +var GEO_IP_DOWNLOAD = "http://hummingbird-data.s3.amazonaws.com/GeoLiteCity.dat.gz" var cities; var locations = Object.create(Metric.prototype); -locations.name = 'location'; +locations.name = 'locations'; locations.initialData = []; locations.interval = 500; // ms locations.ignoreOnEmpty = true; -locations.canLoad = function() { - var cityPath = path.normalize(__dirname + '/../../GeoLiteCity.dat'); - - try { - cities = geoip.open(cityPath); - return true; - } catch(e) { - console.log("Couldn't load geoip database."); - return false; - } -}; - locations.increment = function(request) { - var remoteAddress; - - if(request.ip === "127.0.0.1") { - remoteAddress = "8.8.8.8"; // Mountain View, CA - } else { - remoteAddress = request.ip; - } + var remoteAddress = this.ipFor(request); var location = geoip.City.record_by_addr(cities, remoteAddress); @@ -48,4 +35,68 @@ locations.increment = function(request) { } }; +locations.ipFor = function(request) { + var ip; + if(request.headers && request.headers['x-forwarded-for']) { + ip = request.headers['x-forwarded-for'].split(', ').shift(); + } else if(request.connection && request.connection.remoteAddress) { + ip = request.connection.remoteAddress; + } else if(request.params && request.params.ip) { + ip = request.params.ip; + } else { + ip = "127.0.0.1"; + } + + if(ip == "127.0.0.1") { + return "8.8.8.8"; // Mountain view, can be geolocated + } else { + return ip; + } +} + +// Try to load the binary geoip database. If it is not available, +// try to download it from MaxMind and unzip it. +locations.load = function(callback) { + var cityPath = path.normalize(__dirname + '/../../GeoLiteCity.dat'); + + function setupCities() { + try { + cities = geoip.open(cityPath); + return callback(null); + } catch(e) { + return callback(new Error("Couldn't load geoip database " + cityPath)); + } + } + + fs.stat(cityPath, function(notDownloaded) { + if(notDownloaded) { + console.log("Downloading GeoLiteCity.dat to " + cityPath); + locations.downloadGzipData(GEO_IP_DOWNLOAD, cityPath, function(err) { + if(err) { return callback(err); } + + setupCities(); + }); + } else { + setupCities(); + } + }); +}; + +locations.downloadGzipData = function(url, path, callback) { + http.get(url, function(res) { + if(res.statusCode != "200") { + return callback(new Error("HTTP error: " + res.statusCode)); + } + + var gunzip = zlib.createGunzip(); + var out = fs.createWriteStream(path); + + res.pipe(gunzip).pipe(out); + + gunzip.on('end', function(err) { + callback(err); + }); + }); +}; + module.exports = locations; diff --git a/lib/metrics/total_views.js b/lib/metrics/total_views.js index d92dede..602f354 100644 --- a/lib/metrics/total_views.js +++ b/lib/metrics/total_views.js @@ -10,7 +10,7 @@ var totalViews = Object.create(Metric.prototype); totalViews.name = 'view_totals'; totalViews.initialData = 0; totalViews.interval = 50; // ms -totalViews.increment = function(view) { +totalViews.increment = function(request) { this.data += 1; }; diff --git a/public/index.html b/public/index.html index 832cc9c..c985879 100644 --- a/public/index.html +++ b/public/index.html @@ -88,7 +88,7 @@

Cart Traffic:

every: 10 }); - $("#map_container").hummingbirdMap(hummingbirdSocket.socket, { from: "location" }); + $("#map_container").hummingbirdMap(hummingbirdSocket.socket, { from: "locations" }); new Hummingbird.Logger(window, hummingbirdSocket.socket, From a69eea36500ec017c6579fc0bb716a0d2c413a98 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 14 Sep 2012 01:44:34 -0400 Subject: [PATCH 225/267] don't require plugins to call this.hasChanged = true --- lib/metric.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/metric.js b/lib/metric.js index c90ae79..f9b1110 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -15,7 +15,7 @@ Metric.prototype = { }, run: function() { - if(this.ignoreOnEmpty && !this.hasChanged) { return; } + if(this.ignoreOnEmpty && this.data === this.initialData) { return; } this.emit('data', this.name, this.data || this.initialData); this.resetData(); @@ -23,7 +23,6 @@ Metric.prototype = { resetData: function() { this.data = this.prepareInitialData(); - this.hasChanged = false; }, prepareInitialData: function() { From e36075f73c8185e3479208498576a1c89435d448 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 14 Sep 2012 01:44:47 -0400 Subject: [PATCH 226/267] add hummingbird demo domain for nodejitsu --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8faaec1..d0ac306 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,15 @@ { "name": "hummingbird", "description": "A node.js statistics server", - "version": "0.2.0-3", + "version": "0.2.0-12", "dependencies": { "socket.io": "0.8.7", "node-static": "0.5.9", "geoip": "0.3.4-1" }, + "domains": [ + "demo.hummingbirdstats.com" + ], "repository": { "type": "git", "url": "http://github.com/mnutt/hummingbird.git" From 6fe207548f75b07bf17ff45fdd4adc0ff556adbc Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 17 Sep 2012 01:58:48 -0400 Subject: [PATCH 227/267] absolutely positioned elements; cooler greys --- public/css/login.css | 42 +++++++++++ public/css/main.css | 146 ++++++++++++--------------------------- public/css/map.css | 9 +++ public/index.html | 44 +++++------- public/js/widgets/map.js | 8 +-- 5 files changed, 113 insertions(+), 136 deletions(-) create mode 100644 public/css/login.css diff --git a/public/css/login.css b/public/css/login.css new file mode 100644 index 0000000..4a953ec --- /dev/null +++ b/public/css/login.css @@ -0,0 +1,42 @@ +#login div.logo { + background: url(/images/logo.png) top left no-repeat; + width: 300px; + height: 324px; + margin: auto; + padding-right: 50px; +} + +#login h1 { + margin: 0; +} + +#login form { + margin: auto; +} + +#login form label, +#login form input { + display: block; + width: 150px; + margin: auto; +} + +#login form label { + color: #FFF; + text-transform: uppercase; + font-size: 0.7em; + margin-bottom: 2px; +} + +#login form div { + margin-top: 10px; +} + +#login form #submit { + margin-top: 15px; +} + +#login { + margin: auto; + text-align: center; +} diff --git a/public/css/main.css b/public/css/main.css index 4975b67..e688b38 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -1,15 +1,55 @@ @charset "utf-8"; body { - background-color: #2F2C2B; + background-color: #211d29; font-family: "Lucida Grande", Helvetica, sans-serif; } -h1 { +div.topbar { + position: relative; + height: 100px; +} + +div.topbar div.header h1 { color: #FFF; text-transform: uppercase; + text-shadow: 0 2px 0 #000; + margin: 0; font-family: 'TitilliumText14L800wt', sans-serif; - margin-left: 58px; +} + +div.topbar div.header div.tagline { + color: #918e97; + font-style: italic; + font-family: Georgia, sans-serif; + font-size: 12px; + margin: 0 0 13px 3px; +} + +div.topbar #total { + position: absolute; + top: -10px; + right: 10px; + left: 265px; +} + +div.topbar #total div.graph { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 40px; + float: none; + width: auto; +} + +div.topbar #total div.axis_left { display: none; } +div.topbar #total div.axis_right { + float: none; + position: absolute; + top: 0; + right: 0; + width: 25px; } h2.graph_title { @@ -67,106 +107,6 @@ div.graph div.line { background-color: #F00; } -#sales { - margin-left: 60px; -} - -#sales div.sale { - float: left; - width: 180px; - height: 100px; - overflow: hidden; - padding: 10px 0; - position: relative; -} - -#sales div.sale div.hummingbird_graph { - position: absolute; - top: -6px; - left: 10px; - width: 180px; -} - -#sales div.sale div.hummingbird_graph div.req_s { - position: absolute; - top: 15px; - left: -10px; - background-color: rgba(0, 0, 0, 0.8); - color: #FFF; - font-weight: bold; - padding: 5px; - font-size: 0.6em; - -moz-border-radius-bottomright: 5px; - -webkit-border-bottom-right-radius: 5px; -} - -#sales div.sale img { - opacity: 0.5; -} - -#sales div.sale div.axis_right { - float: left; -} - -#sales div.sale div.axis_left { - display: none; -} - -#sales div.sale h2 { - color: #CCC; - font-size: 0.7em; - height: 2.4em; - overflow: hidden; -} - -#sales div.sale img.editorial { - width: 180px; -} - - -#login div.logo { - background: url(/images/logo.png) top left no-repeat; - width: 300px; - height: 324px; - margin: auto; - padding-right: 50px; -} - -#login h1 { - margin: 0; -} - -#login form { - margin: auto; -} - -#login form label, -#login form input { - display: block; - width: 150px; - margin: auto; -} - -#login form label { - color: #FFF; - text-transform: uppercase; - font-size: 0.7em; - margin-bottom: 2px; -} - -#login form div { - margin-top: 10px; -} - -#login form #submit { - margin-top: 15px; -} - -#login { - margin: auto; - text-align: center; -} - /* Fonts */ @font-face { diff --git a/public/css/map.css b/public/css/map.css index 99ce939..3ac4956 100644 --- a/public/css/map.css +++ b/public/css/map.css @@ -1,3 +1,12 @@ +#map_container { + position: absolute; + top: 110px; + left: 0; + right: 0; + bottom: 0; + border-top: 1px solid #000; +} + #map_container svg.map { background-color: #2F2C2B; } diff --git a/public/index.html b/public/index.html index c985879..aa5d4e0 100644 --- a/public/index.html +++ b/public/index.html @@ -33,38 +33,29 @@ -

Hummingbird

+
+
+

Hummingbird

-
+
Real time web stats
-

All Traffic: 0 Pageviews / Second

- -
-
-
- -
- -
- -
- -

Cart Traffic:

- -
-
-
+ + +
+
+
+
+
+
- -
-
+
+ @@ -55,14 +56,18 @@

Hummingbird

-
+
diff --git a/public/js/polymaps.js b/public/js/polymaps.js index 849e8ec..e7f4856 100755 --- a/public/js/polymaps.js +++ b/public/js/polymaps.js @@ -682,9 +682,11 @@ resizer.remove = function(map) { } }; -// Note: assumes single window (no frames, iframes, etc.)! -window.addEventListener("resize", resizer, false); -window.addEventListener("load", resizer, false); +if(window.addEventListener) { + // Note: assumes single window (no frames, iframes, etc.)! + window.addEventListener("resize", resizer, false); + window.addEventListener("load", resizer, false); +} // See http://wiki.openstreetmap.org/wiki/Mercator @@ -786,24 +788,30 @@ po.layer = function(load, unload) { } } - // set the layer transform - container.setAttribute("transform", - "translate(" + (mapSize.x / 2) + "," + (mapSize.y / 2) + ")" - + (mapAngle ? "rotate(" + mapAngle / Math.PI * 180 + ")" : "") - + (mapZoomFraction ? "scale(" + Math.pow(2, mapZoomFraction) + ")" : "") - + (transform ? transform.zoomFraction(mapZoomFraction) : "")); - // get the coordinates of the four corners var c0 = map.pointCoordinate(tileCenter, zero), c1 = map.pointCoordinate(tileCenter, {x: mapSize.x, y: 0}), c2 = map.pointCoordinate(tileCenter, mapSize), c3 = map.pointCoordinate(tileCenter, {x: 0, y: mapSize.y}); - // round to pixel boundary to avoid anti-aliasing artifacts - if (!mapZoomFraction && !mapAngle && !transform) { - tileCenter.column = (Math.round(tileSize.x * tileCenter.column) + (mapSize.x & 1) / 2) / tileSize.x; - tileCenter.row = (Math.round(tileSize.y * tileCenter.row) + (mapSize.y & 1) / 2) / tileSize.y; - } + var col = tileCenter.column, row = tileCenter.row; + tileCenter.column = Math.round((Math.round(tileSize.x * tileCenter.column) + (mapSize.x & 1) / 2) / tileSize.x); + tileCenter.row = Math.round((Math.round(tileSize.y * tileCenter.row) + (mapSize.y & 1) / 2) / tileSize.y); + col -= tileCenter.column; + row -= tileCenter.row; + + // set the layer transform + var roundedZoomFraction = roundZoom(Math.pow(2, mapZoomFraction)); + container.setAttribute("transform", + "translate(" + + Math.round(mapSize.x / 2 - col * tileSize.x * roundedZoomFraction) + + "," + + Math.round(mapSize.y / 2 - row * tileSize.y * roundedZoomFraction) + + ")" + + (mapAngle ? "rotate(" + mapAngle / Math.PI * 180 + ")" : "") + + (mapZoomFraction ? "scale(" + roundedZoomFraction + ")" : "") + + (transform ? transform.zoomFraction(mapZoomFraction) : "")); + // layer-specific coordinate transform if (transform) { @@ -923,13 +931,17 @@ po.layer = function(load, unload) { } } + function roundZoom(z) { + return Math.round(z * 256) / 256; + } + // position tiles for (var key in newLocks) { var t = newLocks[key], - k = Math.pow(2, t.level = t.zoom - tileCenter.zoom); + k = roundZoom(Math.pow(2, t.level = t.zoom - tileCenter.zoom)); t.element.setAttribute("transform", "translate(" - + (t.x = tileSize.x * (t.column - tileCenter.column * k)) + "," - + (t.y = tileSize.y * (t.row - tileCenter.row * k)) + ")"); + + Math.round(t.x = tileSize.x * (t.column - tileCenter.column * k)) + "," + + Math.round(t.y = tileSize.y * (t.row - tileCenter.row * k)) + ")"); } // remove tiles that are no longer visible @@ -1944,14 +1956,12 @@ po.touch = function() { po.interact = function() { var interact = {}, drag = po.drag(), - wheel = po.wheel(), dblclick = po.dblclick(), touch = po.touch(), arrow = po.arrow(); interact.map = function(x) { drag.map(x); - wheel.map(x); dblclick.map(x); touch.map(x); arrow.map(x); @@ -2107,6 +2117,7 @@ po.compass = function() { g = po.svg("g"), back = g.appendChild(po.svg("path")), dire = g.appendChild(po.svg("path")), + shadow = g.appendChild(po.svg("path")), chev = g.appendChild(po.svg("path")), fore = g.appendChild(po.svg("path")); back.setAttribute("class", "back"); @@ -2114,7 +2125,10 @@ po.compass = function() { dire.setAttribute("class", "direction"); dire.setAttribute("d", back.getAttribute("d")); chev.setAttribute("class", "chevron"); + shadow.setAttribute("class", "shadow"); chev.setAttribute("d", "M" + -y + "," + -x + "H" + y + (by > 0 ? "M0," + (-x - y) + "V" + -y : "")); + shadow.setAttribute("d", "M" + -y + "," + -x + "H" + y + (by > 0 ? "M0," + (-x - y) + "V" + -y : "")); + shadow.setAttribute("transform", (by > 0 ? "translate(2,2)" : "translate(-2,-2)")) fore.setAttribute("class", "fore"); fore.setAttribute("fill", "none"); fore.setAttribute("d", back.getAttribute("d")); @@ -2145,7 +2159,7 @@ po.compass = function() { } function move() { - var x = r + 6, y = x, size = map.size(); + var x = r - 4, y = x, size = map.size(); switch (position) { case "top-left": break; case "top-right": x = size.x - x; break; diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index a3469a6..703fef4 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -25,12 +25,12 @@ Hummingbird.Map = function(element, socket, options) { this.po = org.polymaps; - this.defaultZoom = $(window).height() > 860 ? 3 : 2; + this.defaultZoom = $(window).height() > 760 ? 3 : 2; this.map = this.po.map() .container(this.element.get(0).appendChild(this.po.svg("svg"))) .center({lat: 31, lon: 10}) - .zoom(2) + .zoom(this.defaultZoom) .zoomRange([1, 7]) .add(this.po.interact()); From dc1285c4f27139ac9e3066c4d34d056e2006da84 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 00:29:36 -0400 Subject: [PATCH 235/267] full size map in ff --- public/css/map.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/css/map.css b/public/css/map.css index 164341b..6052897 100644 --- a/public/css/map.css +++ b/public/css/map.css @@ -10,6 +10,8 @@ #map_container svg.map { background-color: #0d0022; + width: 100%; + height: 100%; } text.label { From 039b7775bd8a4b03e4eadb3fb7c14929799d838e Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 00:39:43 -0400 Subject: [PATCH 236/267] remove tracking pixel gif --- images/tracking.gif | Bin 43 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/tracking.gif diff --git a/images/tracking.gif b/images/tracking.gif deleted file mode 100644 index 8624666d94348cf14ec3425b5018e8d8d5e4d358..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43 ocmZ?wbhEHbWMp7uXkY+=|Ns9h{$v3&bwDIYhJlI6g^|G;0Kc9F_y7O^ From 03a33f318cb6908efc77716f935944321e589194 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 01:06:38 -0400 Subject: [PATCH 237/267] add demo mode for demo.hummingbirdstats.com --- config/config.js | 2 + lib/demo.js | 34 + log/sample_traffic.log | 2010 ++++++++++++++++++++++++++++++++++++++++ server.js | 5 + 4 files changed, 2051 insertions(+) create mode 100644 lib/demo.js create mode 100644 log/sample_traffic.log diff --git a/config/config.js b/config/config.js index a0da9da..b47c8fb 100644 --- a/config/config.js +++ b/config/config.js @@ -12,6 +12,8 @@ module.exports = config = { "enable_dashboard" : true, + "demo_mode": true, + "capistrano" : { "repository" : "git://github.com/mnutt/hummingbird.git", "hummingbird_host" : "hummingbird.your-host.com" diff --git a/lib/demo.js b/lib/demo.js new file mode 100644 index 0000000..513b1f4 --- /dev/null +++ b/lib/demo.js @@ -0,0 +1,34 @@ +// Demo mode +// +// Replays a sample traffic log to give an idea of what real traffic +// would look like + +var fs = require('fs'); +var Metric = require('./metric'); + +exports.run = function() { + fs.readFile(__dirname + "/../log/sample_traffic.log", function(err, logFile) { + if(err) { throw err; } + + var lines = logFile.toString().split("\n"); + + function submitLine(lines) { + var line = lines[0]; + if(!line) { + // start over + return submitLine(logFile.toString().split("\n")); + } + + var ip = line.split(" ")[0]; + var req = { params: {ip: ip}, headers: { referer: "/" } }; + if(Math.random() * 8 > 7) { req.params.event = "cart_add"; } + console.log(req); + Metric.insert(req); + setTimeout(function() { + submitLine(lines.slice(1)); + }, Math.random() * 500); + } + + submitLine(lines); + }); +}; diff --git a/log/sample_traffic.log b/log/sample_traffic.log new file mode 100644 index 0000000..596739b --- /dev/null +++ b/log/sample_traffic.log @@ -0,0 +1,2010 @@ +58.61.164.139 - - [31/Oct/2009:23:23:32 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +189.110.216.40 - - [02/Nov/2009:14:37:54 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; pt-BR; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 (.NET CLR 3.5.30729)" +91.203.168.159 - - [04/Nov/2009:16:45:27 +0000] "GET / HTTP/1.1" 200 6063 "-" "-" +59.63.20.20 - - [05/Nov/2009:02:58:09 +0000] "GET / HTTP/1.1" 200 6063 "http://www.baidu.com/s?tn=hintsoft_1_dg&bs=autosave%CF%C2%D4%D8&f=8&wd=http%3Awww.hid.im++" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; icafe8)" +67.194.203.57 - - [06/Nov/2009:01:13:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4" +67.194.203.57 - - [06/Nov/2009:01:14:26 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4" +67.194.203.57 - - [06/Nov/2009:01:15:33 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4" +80.236.123.91 - - [07/Nov/2009:14:46:34 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.fr/search?q=hid.im&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a" "Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 (.NET CLR 3.5.30729)" +88.234.174.123 - - [08/Nov/2009:03:13:48 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +58.61.164.141 - - [09/Nov/2009:00:13:53 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +121.162.214.87 - - [09/Nov/2009:04:36:05 +0000] "GET / HTTP/1.1" 304 0 "http://www.clubnex.co.kr/club/basic/bbs.php?pg_mode=view&list_count=0&clubid=clubwii&bbscode=121825369516613&list_scale=30&bbs_view_mode=0&start=0&idx=1453193" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.3; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2)" +59.16.117.7 - - [09/Nov/2009:04:50:30 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; IPMS/6B1DB034-14AF76A4242)" +130.237.161.37 - - [09/Nov/2009:21:23:11 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)" +188.54.111.96 - - [10/Nov/2009:06:50:26 +0000] "GET / HTTP/1.1" 200 6063 "http://www.blogsdna.com/4284/convert-torrent-file-into-a-regular-png-image-with-hidim.htm" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +83.163.113.227 - - [10/Nov/2009:19:01:19 +0000] "GET / HTTP/1.1" 200 6063 "http://www.nietnuttig.nl/2009/08/09/hidim-bit-torrents-nieuwe-stijl/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; InfoPath.2; .NET CLR 1.1.4322; .NET CLR 3.5.30729; OfficeLiveConnector.1.4; OfficeLivePatch.0.0; .NET CLR 3.0.30729)" +118.168.26.184 - - [11/Nov/2009:04:12:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 GTB5" +81.182.22.183 - - [11/Nov/2009:04:37:11 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.27 Safari/532.0" +24.93.98.172 - - [11/Nov/2009:15:29:02 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +203.141.45.241 - - [12/Nov/2009:01:46:14 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" +92.241.250.227 - - [12/Nov/2009:10:54:58 +0000] "GET / HTTP/1.1" 200 6063 "-" "-" +83.143.100.1 - - [12/Nov/2009:12:26:33 +0000] "GET / HTTP/1.1" 200 6063 "http://www.idg.pl/news/352432/Hidim.torrenty.w.obrazkach.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +88.220.181.15 - - [12/Nov/2009:12:34:35 +0000] "GET / HTTP/1.1" 200 6063 "http://www.idg.pl/news/352432/Hidim.torrenty.w.obrazkach.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +81.219.155.231 - - [12/Nov/2009:14:37:33 +0000] "GET / HTTP/1.1" 200 6063 "http://www.pcworld.pl/news/352432/Hidim.torrenty.w.obrazkach.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +92.28.165.63 - - [12/Nov/2009:17:35:59 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SU 3.24; SLCC1; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.5.30729; .NET CLR 3.0.30618)" +114.80.93.73 - - [12/Nov/2009:18:44:33 +0000] "GET / HTTP/1.1" 416 573 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +89.2.169.87 - - [12/Nov/2009:18:46:15 +0000] "GET / HTTP/1.1" 304 0 "http://www.odebi.org/forums/index.php/topic,1764.msg14371/topicseen.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 GTB5 (.NET CLR 3.5.30729)" +212.127.91.204 - - [12/Nov/2009:20:36:19 +0000] "GET / HTTP/1.1" 200 6063 "http://www.pcworld.pl/news/352432/7/Hidim.torrenty.w.obrazkach.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +98.170.239.204 - - [13/Nov/2009:03:56:37 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +96.246.12.147 - - [13/Nov/2009:05:17:09 +0000] "GET / HTTP/1.1" 200 3725 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4" +130.237.161.37 - - [13/Nov/2009:08:33:08 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)" +124.157.142.26 - - [13/Nov/2009:11:02:18 +0000] "GET / HTTP/1.1" 200 6063 "http://www.techfz.com/2009/07/18/hidim-%E0%B9%81%E0%B8%9B%E0%B8%A5%E0%B8%87%E0%B9%84%E0%B8%9F%E0%B8%A5%E0%B9%8C-torrent-to-png/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)" +212.93.100.167 - - [13/Nov/2009:23:16:12 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +90.53.11.52 - - [14/Nov/2009:02:08:05 +0000] "GET / HTTP/1.1" 200 6063 "http://www.pcinpact.com/actu/news/51974-hidim-torrent-fichier-image-dissimulation.htm" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; InfoPath.1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +99.12.241.85 - - [14/Nov/2009:09:18:34 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15" +24.30.54.238 - - [15/Nov/2009:01:42:09 +0000] "GET / HTTP/1.1" 206 4603 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +59.63.20.20 - - [15/Nov/2009:11:38:40 +0000] "GET / HTTP/1.1" 200 6063 "http://www.hid.im/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; icafe8; 360SE)" +87.205.37.196 - - [15/Nov/2009:19:13:56 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.pl/url?sa=t&source=web&ct=res&cd=1&ved=0CAcQFjAA&url=http%3A%2F%2Fwww.hid.im%2F&rct=j&q=hidim&ei=gUgAS-3RA47-_AbTl-2GCw&usg=AFQjCNFaT7O6AF0rjcfbralsOlblnMGYxQ" "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +95.160.211.135 - - [15/Nov/2009:20:09:27 +0000] "GET / HTTP/1.1" 200 6063 "http://pclab.pl/news39630.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.32 Safari/532.0" +212.59.229.133 - - [15/Nov/2009:20:21:53 +0000] "GET / HTTP/1.1" 200 6063 "http://pclab.pl/news39630.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4" +71.63.157.197 - - [15/Nov/2009:21:30:20 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +83.26.31.61 - - [16/Nov/2009:10:56:45 +0000] "GET / HTTP/1.0" 200 6063 "http://pclab.pl/news39630.html" "Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.2.15 Version/10.01" +88.199.162.10 - - [17/Nov/2009:09:03:47 +0000] "GET / HTTP/1.1" 200 6063 "http://pclab.pl/news39630.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +83.19.174.244 - - [17/Nov/2009:10:17:32 +0000] "GET / HTTP/1.1" 200 6063 "http://republika.onet.pl/39429,26,1,fabryka.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; OfficeLiveConnector.1.4; OfficeLivePatch.1.3)" +85.176.90.33 - - [18/Nov/2009:11:35:28 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 GTB5 (.NET CLR 3.5.30729)" +188.33.31.43 - - [18/Nov/2009:12:39:08 +0000] "GET / HTTP/1.0" 200 6063 "http://www.wykop.pl/search?phrase=torrent" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +84.115.136.183 - - [18/Nov/2009:13:11:41 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 GTB5 (.NET CLR 3.5.30729)" +80.195.173.120 - - [18/Nov/2009:16:16:12 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +64.219.241.210 - - [18/Nov/2009:16:50:41 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +69.205.19.181 - - [18/Nov/2009:20:05:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +84.71.44.15 - - [18/Nov/2009:20:17:24 +0000] "GET / HTTP/1.1" 206 4649 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +139.62.74.88 - - [18/Nov/2009:21:11:55 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +68.34.98.70 - - [18/Nov/2009:22:25:37 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +12.159.238.4 - - [19/Nov/2009:04:23:24 +0000] "GET / HTTP/1.1" 200 6063 "http://filepile.org/file/show/640383/torrent.png" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +209.249.53.52 - - [19/Nov/2009:12:31:35 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1 + FairShare-http://fairshare.cc)" +78.28.6.105 - - [19/Nov/2009:13:45:27 +0000] "GET / HTTP/1.1" 200 6063 "http://pclab.pl/news39630.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +192.198.151.36 - - [19/Nov/2009:14:44:06 +0000] "GET / HTTP/1.1" 200 6063 "http://cooler-online.ru/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +86.151.56.231 - - [19/Nov/2009:21:44:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/s/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.33 Safari/532.0" +95.56.39.100 - - [20/Nov/2009:01:36:56 +0000] "GET / HTTP/1.1" 200 6063 "http://user1.cooler-online.ru/blog/10415.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 (.NET CLR 3.5.30729) WebMoney Advisor" +212.17.21.100 - - [20/Nov/2009:05:09:22 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +89.209.83.59 - - [20/Nov/2009:08:32:49 +0000] "GET / HTTP/1.0" 200 6063 "http://user1.cooler-online.ru/blog/10415.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 GTB6" +84.49.133.195 - - [20/Nov/2009:10:28:31 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.2.15 Version/10.01" +94.253.47.195 - - [21/Nov/2009:07:53:02 +0000] "GET / HTTP/1.1" 200 6063 "http://user1.cooler-online.ru/blog/10415.html" "Opera/9.51 (Windows NT 5.1; U; ru)" +95.35.33.158 - - [21/Nov/2009:18:28:31 +0000] "GET / HTTP/1.1" 200 6063 "http://cooler-online.ru/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 GTB5" +68.206.62.55 - - [22/Nov/2009:17:46:55 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +76.169.29.58 - - [22/Nov/2009:18:13:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +88.192.56.83 - - [22/Nov/2009:18:42:37 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +66.193.4.25 - - [22/Nov/2009:21:50:57 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/r/technology/top/?count=50&t=year&after=t3_9f2nq" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +75.45.28.183 - - [23/Nov/2009:08:18:48 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729) FBSMTWB" +83.168.88.252 - - [23/Nov/2009:14:37:41 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +89.229.45.108 - - [23/Nov/2009:15:43:39 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.pl/search?client=opera&rls=pl&q=Hidim&sourceid=opera&ie=utf-8&oe=utf-8" "Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.2.15 Version/10.01" +95.28.201.229 - - [23/Nov/2009:19:12:02 +0000] "GET / HTTP/1.1" 200 6063 "http://cooler-online.ru/" "Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.01" +77.35.52.83 - - [24/Nov/2009:13:05:18 +0000] "GET / HTTP/1.1" 200 6063 "http://cooler-online.ru/" "Opera/9.64 (Windows NT 5.1; U; MRA 5.5 (build 02842); ru) Presto/2.1.1" +74.71.220.51 - - [24/Nov/2009:17:41:18 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +114.80.93.73 - - [24/Nov/2009:18:26:13 +0000] "GET / HTTP/1.1" 416 573 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +84.251.219.174 - - [25/Nov/2009:17:14:54 +0000] "GET / HTTP/1.1" 200 6063 "http://www.redferret.net/?p=17166" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fi; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +200.101.50.215 - - [25/Nov/2009:19:21:01 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +213.23.138.46 - - [26/Nov/2009:12:57:11 +0000] "GET / HTTP/1.1" 200 6063 "http://www.marklets.com/Bookmarklets/Decode+Hidim.aspx" "Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.2b3) Gecko/20091115 Firefox/3.6b3 FirePHP/0.3" +95.108.150.235 - - [27/Nov/2009:20:39:12 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +24.70.14.24 - - [27/Nov/2009:21:03:10 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/search?q=torrent&sort=top" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +67.195.111.57 - - [28/Nov/2009:06:12:23 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +173.45.114.178 - - [28/Nov/2009:16:49:05 +0000] "GET / HTTP/1.1" 200 6063 "-" "-" +89.231.104.203 - - [29/Nov/2009:11:08:22 +0000] "GET / HTTP/1.1" 200 6063 "http://di.com.pl/news/27605,0,Torrenty_udostepniane_jako_obrazki.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; FDM; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +87.18.29.151 - - [29/Nov/2009:14:21:56 +0000] "GET / HTTP/1.1" 200 6063 "http://www.computertrucchi.com/2009/07/nascondere-file-torrent-dentro-unimmagine/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5 (.NET CLR 3.5.30729) Creative ZENcast v2.00.13" +75.49.7.125 - - [30/Nov/2009:06:52:25 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/r/technology/top/?count=50&after=t3_748je" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +80.221.33.54 - - [30/Nov/2009:14:40:38 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.2.15 Version/10.10" +122.30.146.190 - - [01/Dec/2009:03:01:12 +0000] "GET / HTTP/1.1" 200 6063 "http://slashdot.jp/it/article.pl?sid=09/07/19/1058215" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +83.168.88.252 - - [01/Dec/2009:14:29:12 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +58.61.164.141 - - [01/Dec/2009:23:53:00 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +81.196.156.93 - - [02/Dec/2009:09:05:02 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/r/all/search?q=torrent&sort=top" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +193.233.4.2 - - [04/Dec/2009:17:59:36 +0000] "GET / HTTP/1.1" 200 6063 "http://cooler-online.ru/bydate/19-11-2009" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 WebMoney Advisor" +216.104.15.130 - - [05/Dec/2009:09:16:11 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +88.171.239.17 - - [05/Dec/2009:09:45:04 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6.3; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; FDM; Creative ZENcast v2.01.01)" +128.2.144.72 - - [06/Dec/2009:22:03:48 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/r/technology/comments/910sm/it_turns_a_torrent_into_a_regular_png_image/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)" +35.13.72.232 - - [07/Dec/2009:00:30:53 +0000] "GET / HTTP/1.1" 200 6063 "-" "iTunes/9.0.2 (Macintosh; Intel Mac OS X 10.4.11) AppleWebKit/531.9" +78.84.204.140 - - [07/Dec/2009:10:16:38 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; lv; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +218.104.96.134 - - [08/Dec/2009:02:53:59 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)" +79.232.93.38 - - [08/Dec/2009:11:18:33 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +35.11.147.89 - - [08/Dec/2009:15:32:46 +0000] "GET / HTTP/1.1" 200 6063 "-" "iTunes/9.0.2 (Macintosh; Intel Mac OS X 10.4.11) AppleWebKit/531.9" +76.188.208.72 - - [09/Dec/2009:04:49:16 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.1; .NET CLR 3.5.30729; .NET CLR 3.0.30729)" +113.57.142.130 - - [09/Dec/2009:11:03:47 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +195.23.32.2 - - [09/Dec/2009:13:15:50 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.33 Safari/532.0" +174.129.104.29 - - [10/Dec/2009:07:05:27 +0000] "GET / HTTP/1.1" 200 6063 "-" "Python-urllib/2.5" +94.23.51.159 - - [10/Dec/2009:07:17:10 +0000] "GET / HTTP/1.1" 200 6063 "http://real-url.org" "Mozilla/4.0 (compatible;MSIE 5.01; Windows -NT 5.0)" +208.84.47.48 - - [10/Dec/2009:23:29:49 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091105 Fedora/3.5.5-1.fc13 Firefox/3.5.5" +74.176.155.149 - - [12/Dec/2009:18:13:54 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +208.109.138.115 - - [13/Dec/2009:07:34:52 +0000] "GET / HTTP/1.0" 200 6063 "-" "980km (beta) (http://www.980km.com/ - email:tumbapi@980km.com)" +68.117.2.14 - - [13/Dec/2009:11:39:27 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" +117.136.1.134 - - [13/Dec/2009:15:13:59 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows Mobile; WCE; Opera Mobi/WMD-50286; U; en) Presto/2.4.13 Version/10.00" +83.149.199.54 - - [13/Dec/2009:15:35:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru-RU; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)" +219.78.197.207 - - [13/Dec/2009:18:55:15 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Foxy/1; Foxy/1; chromeframe; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; OfficeLiveConnector.1.4; OfficeLivePatch.1.3)" +95.108.150.235 - - [13/Dec/2009:21:32:56 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +89.110.59.65 - - [15/Dec/2009:23:02:45 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; ru-ru) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +62.159.136.5 - - [16/Dec/2009:12:06:19 +0000] "GET / HTTP/1.0" 200 6063 "-" "Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10" +72.174.32.21 - - [17/Dec/2009:08:09:20 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)" +95.108.150.235 - - [17/Dec/2009:11:03:01 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +89.149.14.172 - - [18/Dec/2009:18:30:31 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +216.24.142.45 - - [18/Dec/2009:19:15:31 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0 OneRiot/1.0 (http://www.oneriot.com)" +83.24.127.151 - - [22/Dec/2009:14:28:21 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)" +69.234.211.152 - - [23/Dec/2009:03:55:57 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +72.188.232.241 - - [23/Dec/2009:04:20:37 +0000] "GET / HTTP/1.1" 200 6063 "http://meneame.net/story/hid.im-convierte-torrents-imagenes-png-eng" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" +89.200.209.33 - - [23/Dec/2009:19:17:23 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.60 (Windows NT 5.1; U; pl) Presto/2.1.1" +208.80.193.43 - - [25/Dec/2009:03:09:58 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; America Online Browser 1.1; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)" +173.202.2.49 - - [25/Dec/2009:06:40:46 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 GTB6 (.NET CLR 3.5.30729) FBSMTWB" +99.16.7.181 - - [27/Dec/2009:03:53:49 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Ant.com Toolbar 1.5 Firefox/3.5.5 (.NET CLR 3.5.30729)" +67.204.21.61 - - [27/Dec/2009:07:08:35 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +68.9.190.164 - - [27/Dec/2009:08:23:03 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +83.9.31.160 - - [27/Dec/2009:14:43:05 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/search?phrase=torrent" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +95.108.150.235 - - [27/Dec/2009:18:42:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +98.183.209.207 - - [28/Dec/2009:05:03:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +89.200.209.33 - - [29/Dec/2009:21:37:12 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.60 (Windows NT 5.1; U; pl) Presto/2.1.1" +70.95.68.86 - - [02/Jan/2010:04:11:43 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +188.220.56.199 - - [02/Jan/2010:09:16:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.xmarks.com/site/http%3A//filesharefreak.com/trackers-list/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 GTB6 (.NET CLR 3.5.30729)" +90.209.100.51 - - [02/Jan/2010:15:57:37 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +61.222.140.99 - - [03/Jan/2010:14:50:00 +0000] "GET / HTTP/1.1" 200 3725 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +116.125.141.13 - - [03/Jan/2010:16:19:48 +0000] "GET / HTTP/1.1" 200 6063 "http://hid.im" "Mozilla/5.0 (compatible; Firefox compatible; MS IE compatible; not on Windows server; +http://cs.daum.net/faq/site/15.html) Daumoa-feedfetcher/2.0" +76.11.93.15 - - [03/Jan/2010:17:36:56 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2b6pre) Gecko/20100102 Namoroka/3.6b6pre" +90.151.107.182 - - [03/Jan/2010:20:52:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux armv6l; ru-RU; rv:1.9a6pre) Gecko/20080828 Firefox/3.0a1 Tablet browser 0.3.7 RX-34+RX-44+RX-48_DIABLO_5.2008.43-7" +208.80.193.26 - - [04/Jan/2010:00:32:58 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Ringo; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +195.50.218.242 - - [06/Jan/2010:15:09:11 +0000] "GET / HTTP/1.1" 200 6063 "http://www.facebook.com/posted.php?id=1502622485&start=1100&hash=8f4f7b9546781e7256a78ea0474569de" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; MS-RTC LM 8; InfoPath.2)" +98.88.164.106 - - [07/Jan/2010:09:58:29 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +82.67.191.183 - - [07/Jan/2010:14:18:48 +0000] "GET / HTTP/1.1" 200 6063 "http://hadopinfo.fr/cacher-un-fichier-torrent-dans-une-image-png/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +80.16.37.114 - - [07/Jan/2010:17:15:40 +0000] "GET / HTTP/1.0" 200 6063 "http://www.mondoinformatico.info/nascondere-file-torrent-in-unimmagine_post-16311.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 (.NET CLR 3.5.30729)" +173.169.90.103 - - [08/Jan/2010:02:36:18 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2" +121.111.231.47 - - [08/Jan/2010:09:23:25 +0000] "GET / HTTP/1.1" 200 6063 "http://slashdot.jp/article.pl?sid=09/07/19/1058215" "KDDI-KC3D UP.Browser/6.2.0.13.2 (GUI) MMP/2.0" +67.195.112.186 - - [11/Jan/2010:21:37:51 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +89.200.209.33 - - [12/Jan/2010:17:14:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.60 (Windows NT 5.1; U; pl) Presto/2.1.1" +77.88.26.26 - - [12/Jan/2010:19:46:51 +0000] "GET / HTTP/1.1" 304 0 "-" "Yandex/1.01.001 (compatible; Win16; I)" +89.74.105.29 - - [12/Jan/2010:22:25:10 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2) Gecko/20100105 Firefox/3.6" +83.225.119.172 - - [14/Jan/2010:21:33:24 +0000] "GET / HTTP/1.1" 200 6063 "http://www.navigaweb.net/2009/07/scaricare-tutto-senza-blocchi-e-anonimi.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.0.17) Gecko/2009122116 Firefox/3.0.17 (.NET CLR 3.5.30729)" +216.131.74.51 - - [15/Jan/2010:22:54:10 +0000] "GET / HTTP/1.0" 200 6063 "http://outgoing.mozilla.org/v1/02fca647400077b4f41b884cb8c5d83ad098414b/http%3A//hid.im" "Opera/9.80 (Windows NT 6.1; U; zh-tw) Presto/2.2.15 Version/10.10" +91.206.194.112 - - [16/Jan/2010:11:04:16 +0000] "GET / HTTP/1.1" 200 6063 "http://sirburuslan.com/blog-internet/1089/Transforma_un_fisier_torrent_intr-o_imagine_cu_hid.im/" "Opera/9.80 (Windows NT 5.1; U; ro) Presto/2.2.15 Version/10.10" +77.196.25.84 - - [16/Jan/2010:16:52:45 +0000] "GET / HTTP/1.1" 200 6063 "http://forum.downparadise.com/viewtopic.php?f=7&t=190208" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +68.229.128.89 - - [17/Jan/2010:01:50:23 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)" +80.33.138.192 - - [17/Jan/2010:12:35:29 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; ca; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +220.211.81.30 - - [17/Jan/2010:19:20:27 +0000] "GET / HTTP/1.1" 200 6063 "http://www.moongift.jp/2009/07/hid_im/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.49 Safari/532.5" +98.210.207.48 - - [18/Jan/2010:19:58:36 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +77.88.26.26 - - [20/Jan/2010:07:22:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Yandex/1.01.001 (compatible; Win16; I)" +71.176.58.204 - - [20/Jan/2010:23:55:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; SU 3.23; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 1.1.4322; .NET CLR 3.0.30729; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; MSN Optimized;US)" +24.85.247.22 - - [21/Jan/2010:01:05:24 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +41.140.32.20 - - [23/Jan/2010:12:20:46 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.38 Safari/532.0" +81.100.240.246 - - [23/Jan/2010:14:37:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +69.205.174.2 - - [24/Jan/2010:23:00:29 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" +67.168.202.202 - - [24/Jan/2010:23:11:41 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 4.0.20506)" +115.70.45.88 - - [25/Jan/2010:09:51:11 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +164.58.131.3 - - [26/Jan/2010:15:12:37 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.5.30729)" +64.233.172.20 - - [27/Jan/2010:11:23:22 +0000] "GET / HTTP/1.1" 200 6063 "-" "AppEngine-Google; (+http://code.google.com/appengine; appid: getfavicon)" +109.78.160.105 - - [29/Jan/2010:08:13:45 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +142.166.3.122 - - [30/Jan/2010:01:29:19 +0000] "GET / HTTP/1.1" 200 6063 "-" "R6_FeedFetcher(www.radian6.com/crawler)" +208.80.193.28 - - [30/Jan/2010:14:15:48 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8949F47D-9266-D2B2-E624-83AA60FCEB78})" +206.212.22.247 - - [30/Jan/2010:19:33:12 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +87.18.175.253 - - [30/Jan/2010:22:31:21 +0000] "GET / HTTP/1.1" 200 6063 "http://www.navigaweb.net/2009/07/scaricare-tutto-senza-blocchi-e-anonimi.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.78 Safari/532.5" +190.94.9.84 - - [31/Jan/2010:03:37:01 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; es-MX; rv:1.9.2.2pre) Gecko/20100129 Ubuntu/9.10 (karmic) Namoroka/3.6.2pre" +112.198.148.6 - - [31/Jan/2010:18:23:22 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +174.133.83.226 - - [02/Feb/2010:17:52:26 +0000] "GET / HTTP/1.1" 200 3725 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)" +77.253.117.132 - - [04/Feb/2010:02:51:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.2.15 Version/10.10" +95.108.142.138 - - [04/Feb/2010:13:38:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +109.93.75.5 - - [05/Feb/2010:01:43:22 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" +95.108.150.235 - - [05/Feb/2010:09:59:33 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +86.183.38.14 - - [05/Feb/2010:13:03:15 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +187.37.30.99 - - [05/Feb/2010:19:43:48 +0000] "GET / HTTP/1.1" 200 6063 "http://forum.darkside.com.br/vb/showthread.php?t=33630&page=3" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-BR; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +221.206.64.222 - - [06/Feb/2010:02:49:55 +0000] "GET / HTTP/1.1" 200 6063 "http://www.soft4fun.net/bbs/hidden-bt-torrent-download-url.htm" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" +218.231.189.151 - - [06/Feb/2010:02:59:23 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; GTB6.4; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Sleipnir/2.9.1)" +209.165.141.251 - - [06/Feb/2010:07:52:06 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.5.30729)" +151.71.214.181 - - [06/Feb/2010:19:41:46 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +212.108.204.4 - - [07/Feb/2010:20:09:22 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +69.162.115.173 - - [08/Feb/2010:03:46:46 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.1pre) Gecko/20100124 Ubuntu/10.04 (lucid) Namoroka/3.6.1pre" +77.46.205.32 - - [08/Feb/2010:20:20:19 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; sr; rv:1.9.2) Gecko/20100115 Firefox/3.6" +109.225.69.126 - - [09/Feb/2010:06:49:30 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE; rv:1.9.2) Gecko/20100115 Firefox/3.6" +84.24.22.160 - - [09/Feb/2010:11:08:08 +0000] "GET / HTTP/1.1" 200 6063 "http://digg.com/tech_news/The_Pirate_Bay_To_Be_Censored_in_Italy_Again" "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)" +58.110.148.247 - - [09/Feb/2010:11:52:37 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Mobile/7D11" +188.136.162.179 - - [09/Feb/2010:20:39:49 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?as_q=&hl=fa&num=10&btnG=%D8%AC%D8%B3%D8%AA%D8%AC%D9%88%D9%8A+Google&as_epq=www+hid+im&as_oq=&as_eq=&lr=&cr=&as_ft=i&as_filetype=&as_qdr=y&as_occt=any&as_dt=i&as_sitesearch=&as_rights=" "Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1" +195.189.80.25 - - [10/Feb/2010:06:43:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.10" +123.225.255.238 - - [10/Feb/2010:09:57:27 +0000] "GET / HTTP/1.0" 200 6063 "http://boards.4chan.org/t/" "Download Ninja 7.0" +115.238.86.178 - - [10/Feb/2010:11:22:35 +0000] "GET / HTTP/1.1" 200 6063 "-" "Nokia3108/1.0 (03.01) Profile/MIDP-1.0 Configuration/CLDC-1.0" +69.254.144.68 - - [12/Feb/2010:05:00:50 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +193.42.151.219 - - [12/Feb/2010:08:37:57 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/4.0.304.0 Safari/532.9" +82.233.217.204 - - [13/Feb/2010:19:10:14 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.3)" +78.46.43.100 - - [14/Feb/2010:13:21:59 +0000] "GET / HTTP/1.1" 200 6063 "" "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1)" +77.105.56.89 - - [14/Feb/2010:15:29:03 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +81.96.79.166 - - [15/Feb/2010:15:17:15 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 2.0.50727)" +212.141.48.2 - - [17/Feb/2010:15:02:45 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7" +121.210.226.178 - - [18/Feb/2010:04:37:21 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +195.66.81.4 - - [18/Feb/2010:11:16:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)" +81.7.90.162 - - [18/Feb/2010:13:04:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.lt/url?sa=t&source=web&ct=res&cd=2&ved=0CAwQFjAB&url=http%3A%2F%2Fwww.hid.im%2F&rct=j&q=hidim+decoder&ei=wTp9S9msIpSqmgO87YneBA&usg=AFQjCNFaT7O6AF0rjcfbralsOlblnMGYxQ" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +69.208.80.142 - - [19/Feb/2010:18:24:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8" +77.88.26.26 - - [19/Feb/2010:23:43:42 +0000] "GET / HTTP/1.1" 304 0 "-" "Yandex/1.01.001 (compatible; Win16; I)" +173.2.133.130 - - [20/Feb/2010:02:23:03 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +74.60.194.221 - - [20/Feb/2010:04:46:11 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)" +147.91.1.44 - - [20/Feb/2010:14:40:59 +0000] "GET / HTTP/1.0" 200 6063 "-" "Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10" +190.94.108.96 - - [21/Feb/2010:00:44:09 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.1.8pre) Gecko/20100128 Ubuntu/9.10 (karmic) Firefox/3.5.3" +67.174.139.94 - - [21/Feb/2010:17:31:29 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" +95.108.150.235 - - [22/Feb/2010:02:17:03 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +75.128.19.85 - - [22/Feb/2010:04:49:57 +0000] "GET / HTTP/1.1" 200 6063 "http://what.cd/forums.php?action=viewthread&threadid=83039&page=2" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8" +58.173.128.167 - - [22/Feb/2010:05:00:47 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.0) Gecko/20100115 SUSE/3.6.0-1.2 Firefox/3.6" +81.177.37.24 - - [22/Feb/2010:07:18:02 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?sourceid=navclient&ie=UTF-8&rls=ITVA,ITVA:2006-42,ITVA:en&q=%EA%EB%FE%F7" ";" +121.231.143.211 - - [22/Feb/2010:07:21:22 +0000] "GET / HTTP/1.1" 200 6063 "http://www.hid.im/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Foxy/1; TheWorld)" +94.78.180.224 - - [22/Feb/2010:22:29:41 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/ramka/210426/konwerter-plikow-torrent-do-png" "Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.2.15 Version/10.10" +217.108.34.13 - - [23/Feb/2010:18:35:03 +0000] "GET / HTTP/1.1" 200 6063 "http://www.pcinpact.com/actu/news/51974-hidim-torrent-fichier-image-dissimulation.htm" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.2) Gecko/20100115 Firefox/3.6" +64.56.78.10 - - [24/Feb/2010:04:04:58 +0000] "GET / HTTP/1.0" 200 6063 "-" "pt_viewer larbin2.6.3@unspecified.mail" +212.219.188.229 - - [25/Feb/2010:12:00:04 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)" +89.79.148.63 - - [25/Feb/2010:23:05:58 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2) Gecko/20100115 Firefox/3.6" +89.200.209.33 - - [26/Feb/2010:14:01:44 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.60 (Windows NT 5.1; U; pl) Presto/2.1.1" +109.93.160.29 - - [26/Feb/2010:16:19:16 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; OfficeLiveConnector.1.3; OfficeLivePatch.0.0; FDM; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +71.126.196.93 - - [26/Feb/2010:23:19:47 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729)" +83.109.146.173 - - [27/Feb/2010:12:53:11 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" +208.80.85.26 - - [27/Feb/2010:20:58:18 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8" +192.149.109.46 - - [28/Feb/2010:18:44:03 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729)" +190.94.8.115 - - [03/Mar/2010:04:17:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.1.8pre) Gecko/20100128 Ubuntu/9.10 (karmic) Firefox/3.5.3" +151.95.45.175 - - [04/Mar/2010:01:59:46 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTBDFff GTB7.0" +98.232.227.119 - - [04/Mar/2010:06:51:47 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729)" +71.229.244.117 - - [04/Mar/2010:08:14:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.5 NET_mmhpset (.NET CLR 3.5.30729)" +24.69.142.135 - - [04/Mar/2010:15:56:32 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.0.18) Gecko/2010020220 Firefox/3.0.18" +74.125.126.82 - - [04/Mar/2010:18:11:57 +0000] "GET / HTTP/1.1" 200 6063 "http://translate.google.co.kr/translate_p?hl=ko&ie=utf-8&langpair=auto%7Cko&u=http://www.hid.im/&tbb=1&twu=1&usg=ALkJrhi2uUqGLpuz1b4I86fjNy57xrmy8g" "Opera/9.80 (Windows NT 5.1; U; ko) Presto/2.2.15 Version/10.10,gzip(gfe) (via translate.google.com)" +95.104.244.10 - - [05/Mar/2010:13:34:05 +0000] "GET / HTTP/1.1" 200 6063 "http://simbirsk-ktv.ru/forum/viewtopic.php?t=22615" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.8) Gecko/20100202 MRA 5.5 (build 02842) Firefox/3.5.8 (.NET CLR 3.5.30729) sputnik 2.1.0.18" +84.0.198.54 - - [06/Mar/2010:07:03:13 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.9.2) Gecko/20100115 Firefox/3.6" +125.64.96.21 - - [06/Mar/2010:07:09:13 +0000] "GET / HTTP/1.0" 200 6063 "http://www.hid.im/" "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0 ; .NET CLR 2.0.50215; SL Commerce Client v1.0; Tablet PC 2.0" +117.200.131.56 - - [08/Mar/2010:06:29:54 +0000] "GET / HTTP/1.1" 200 6063 "http://www.makeuseof.com/tag/how-to-hide-your-torrent-files-inside-pictures/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8" +174.70.133.10 - - [09/Mar/2010:04:36:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.7) Gecko/20100106 Ubuntu/9.10 (karmic) Firefox/3.5.7 GTB6" +151.56.133.17 - - [09/Mar/2010:10:05:51 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.89 Safari/532.5" +217.131.117.27 - - [09/Mar/2010:20:41:45 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)" +96.30.32.12 - - [10/Mar/2010:02:10:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)" +77.39.53.1 - - [11/Mar/2010:14:30:30 +0000] "GET / HTTP/1.1" 200 6063 "http://mixa.su/news/internet/hid-im-preobrazuet-torrenty-v-izobrazheniya-png.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AskTB5.6)" +88.156.71.164 - - [11/Mar/2010:21:25:21 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/210426/konwerter-plikow-torrent-do-png/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729)" +79.38.7.150 - - [12/Mar/2010:09:49:28 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.89 Safari/532.5" +78.105.149.128 - - [14/Mar/2010:00:04:59 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 GTB6" +67.195.110.167 - - [15/Mar/2010:06:05:49 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +65.75.196.91 - - [15/Mar/2010:15:24:58 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" +78.0.84.83 - - [16/Mar/2010:06:42:05 +0000] "GET / HTTP/1.1" 200 6063 "http://www.doublebuffer.org/forum/viewtopic.php?f=23&t=530&view=unread" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.89 Safari/532.5" +71.205.150.96 - - [17/Mar/2010:01:24:32 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729)" +68.97.32.110 - - [17/Mar/2010:03:59:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" +123.151.90.133 - - [17/Mar/2010:20:28:50 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 1.7; TencentTraveler 4.0; CIBA; InfoPath.2; .NET CLR 2.0.50727" +69.251.212.3 - - [19/Mar/2010:01:17:57 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" +65.7.228.128 - - [20/Mar/2010:20:50:01 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)" +121.216.3.80 - - [21/Mar/2010:11:23:26 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?q=Hidim" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.359.0 Safari/533.3" +216.104.15.134 - - [23/Mar/2010:10:10:08 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +217.85.44.181 - - [23/Mar/2010:17:17:23 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2" +62.30.143.102 - - [23/Mar/2010:18:23:02 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2) Gecko/20100115 Firefox/3.6" +69.147.112.169 - - [23/Mar/2010:21:25:51 +0000] "GET / HTTP/1.1" 200 6063 "http://pipes.yahoo.com/pipes/pipe.info?_id=oFqDT3KB3RG8tyjP073fcQ" "Yahoo Pipes 1.0" +195.177.104.138 - - [24/Mar/2010:15:47:09 +0000] "GET / HTTP/1.1" 200 6063 "http://cooler-online.ru/bydate/19-11-2009" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 (.NET CLR 3.5.30729) WebMoney Advisor" +66.61.162.188 - - [27/Mar/2010:23:26:33 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2" +77.197.185.87 - - [28/Mar/2010:09:58:36 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 (.NET CLR 3.5.30729)" +74.222.4.219 - - [01/Apr/2010:02:57:22 +0000] "GET / HTTP/1.0" 200 6063 "http://hid.im/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)" +195.12.52.38 - - [01/Apr/2010:21:14:56 +0000] "GET / HTTP/1.1" 200 6063 "http://forum.paytv.ro/showthread.php?t=43752&highlight=norc.ro&page=16" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729)" +208.101.2.194 - - [02/Apr/2010:02:59:49 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.30729; .NET CLR 3.5.30729)" +202.160.178.203 - - [02/Apr/2010:10:03:07 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp China; http://misc.yahoo.com.cn/help.html)" +24.8.11.33 - - [03/Apr/2010:02:52:41 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8" +86.46.215.246 - - [03/Apr/2010:21:57:35 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.15) Gecko/2009101601 Firefox/3.0.15 (.NET CLR 3.5.30729)" +58.114.67.7 - - [04/Apr/2010:16:12:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.soft4fun.net/bbs/hidden-bt-torrent-download-url.htm" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.4; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.1; AskTB5.5)" +68.202.105.102 - - [05/Apr/2010:01:49:15 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +78.173.234.201 - - [07/Apr/2010:16:56:15 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; GTB6.4; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; OfficeLiveConnector.1.4; OfficeLivePatch.1.3)" +202.160.178.203 - - [09/Apr/2010:10:47:10 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp China; http://misc.yahoo.com.cn/help.html)" +59.156.29.210 - - [09/Apr/2010:14:35:32 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 BetterPrivacy-1.47 Firefox/3.6.3 Pathtraq/0.9 AutoPager/0.6.0.20 AutoPager/0.6.0.20" +95.118.218.80 - - [12/Apr/2010:11:43:38 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +208.215.25.131 - - [12/Apr/2010:19:02:21 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB6" +72.44.52.199 - - [12/Apr/2010:20:11:12 +0000] "GET / HTTP/1.0" 200 3725 "-" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16" +72.229.138.152 - - [13/Apr/2010:01:39:29 +0000] "GET / HTTP/1.1" 206 4603 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729)" +38.113.234.180 - - [13/Apr/2010:01:59:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "Voyager/1.0" +173.13.167.169 - - [13/Apr/2010:03:31:31 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)" +68.202.105.102 - - [14/Apr/2010:18:05:26 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +99.243.0.29 - - [15/Apr/2010:05:06:17 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +142.166.170.102 - - [16/Apr/2010:13:08:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "R6_FeedFetcher(www.radian6.com/crawler)" +67.14.202.30 - - [18/Apr/2010:02:42:02 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9" +76.112.75.252 - - [18/Apr/2010:03:31:57 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +65.92.142.100 - - [18/Apr/2010:05:20:32 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +95.108.150.235 - - [18/Apr/2010:09:22:03 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +95.108.150.235 - - [18/Apr/2010:09:22:04 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +184.73.66.203 - - [18/Apr/2010:21:20:49 +0000] "GET / HTTP/1.1" 301 185 "-" "Mozilla/5.0 (X11; U; Linux x86_64; pt-BR; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8" +75.92.10.153 - - [19/Apr/2010:20:45:42 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB6" +190.94.15.11 - - [20/Apr/2010:14:56:40 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; es-MX; rv:1.9.2.3) Gecko/20100407 Ubuntu/9.10 (karmic) Firefox/3.6.3" +92.250.243.172 - - [20/Apr/2010:18:58:03 +0000] "GET / HTTP/1.0" 200 6063 "http://nutt.im/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1" +66.183.132.57 - - [21/Apr/2010:23:22:17 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100407 Ubuntu/9.10 (karmic) Firefox/3.6.3" +71.197.235.39 - - [22/Apr/2010:00:07:36 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.1.249.1045 Safari/532.5" +67.195.112.109 - - [22/Apr/2010:13:01:19 +0000] "GET / HTTP/1.0" 200 3725 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +38.99.98.37 - - [23/Apr/2010:03:23:04 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; ScoutJet; +http://www.scoutjet.com/)" +72.30.161.230 - - [23/Apr/2010:17:18:42 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +88.160.206.196 - - [24/Apr/2010:19:19:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +91.38.198.14 - - [24/Apr/2010:21:55:24 +0000] "GET / HTTP/1.1" 200 6063 "http://nutt.im/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +38.104.134.114 - - [25/Apr/2010:20:32:32 +0000] "GET / HTTP/1.1" 200 6063 "-" "2" +144.118.200.57 - - [25/Apr/2010:20:50:26 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.10pre) Gecko/20100325 Ubuntu/9.10 (karmic) Firefox/3.5.9" +68.59.52.133 - - [27/Apr/2010:04:08:09 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729)" +68.202.105.102 - - [27/Apr/2010:10:53:37 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +95.108.150.235 - - [27/Apr/2010:11:52:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +78.147.216.181 - - [27/Apr/2010:18:29:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 (.NET CLR 3.5.30729)" +203.206.60.212 - - [28/Apr/2010:08:57:11 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com.au/search?sourceid=chrome&ie=UTF-8&q=hidim" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.9 Safari/533.2" +193.175.49.235 - - [28/Apr/2010:10:50:00 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; lt; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +78.105.160.215 - - [29/Apr/2010:07:46:20 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2" +79.85.107.154 - - [30/Apr/2010:17:26:52 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +65.25.76.51 - - [01/May/2010:18:45:25 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20100121 FireDownload/2.0.1 Firefox/3.5.6 Wyzo/3.5.6.1 FireTorrent/2.0.1" +38.99.97.11 - - [01/May/2010:20:17:21 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; ScoutJet; +http://www.scoutjet.com/)" +79.8.7.46 - - [01/May/2010:22:00:42 +0000] "GET / HTTP/1.1" 200 6063 "http://www.navigaweb.net/2009/07/scaricare-tutto-senza-blocchi-e-anonimi.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +95.108.151.244 - - [01/May/2010:23:14:06 +0000] "GET / HTTP/1.1" 200 3725 "-" "Yandex/1.01.001 (compatible; Win16; H)" +69.84.207.147 - - [02/May/2010:15:08:20 +0000] "GET / HTTP/1.1" 206 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0;Windows NT 5.1;.NET CLR 1.1.4322;.NET CLR 2.0.50727;.NET CLR 3.0.04506.30)" +194.57.169.173 - - [03/May/2010:19:23:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +95.108.150.235 - - [03/May/2010:23:46:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +79.1.201.194 - - [05/May/2010:06:33:38 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTBDFff GTB7.0 (.NET CLR 3.5.30729)" +199.17.197.52 - - [06/May/2010:07:04:28 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1" +174.129.151.220 - - [06/May/2010:17:55:50 +0000] "GET / HTTP/1.1" 200 3725 "-" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16" +71.123.243.250 - - [08/May/2010:08:33:08 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729)" +93.217.126.157 - - [08/May/2010:15:19:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +70.181.238.200 - - [08/May/2010:18:47:51 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729)" +121.214.96.84 - - [09/May/2010:03:27:32 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/search?q=torrent&sort=top" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; Trident/4.0; GTB6.4; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30618; Media Center PC 5.0; InfoPath.2)" +67.20.238.36 - - [09/May/2010:04:09:47 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 ( .NET CLR 3.5.30729)" +75.101.140.241 - - [09/May/2010:19:42:45 +0000] "GET / HTTP/1.1" 200 6063 "-" "http://advisor.wmtransfer.com/" +78.159.102.141 - - [10/May/2010:03:56:09 +0000] "GET / HTTP/1.0" 200 6063 "-" "igdeSpyder (compatible; igde.ru; +http://igde.ru/doc/tech.html)" +187.15.43.203 - - [10/May/2010:13:43:51 +0000] "GET / HTTP/1.1" 200 6063 "http://www.explorando.viamep.com/m/2009/07/site-converte-torrents-em-imagens" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Chrome/5.0.356.2 Safari/533.3" +24.215.141.120 - - [10/May/2010:20:02:22 +0000] "GET / HTTP/1.1" 200 6063 "http://nuttnet.net/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7" +87.196.95.203 - - [10/May/2010:20:30:38 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-PT; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +78.33.115.236 - - [10/May/2010:22:28:48 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +78.117.113.19 - - [11/May/2010:00:47:03 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +75.101.189.114 - - [11/May/2010:07:00:54 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0" +75.36.159.152 - - [11/May/2010:07:55:14 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/533.8 (KHTML, like Gecko) Chrome/5.0.396.0 Safari/533.8" +66.111.62.170 - - [11/May/2010:10:04:20 +0000] "GET / HTTP/1.1" 200 6063 "-" "Links (1.00pre19; OpenBSD 4.0 i386; 226x64)" +94.124.131.44 - - [11/May/2010:12:55:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100414 Iceweasel/3.5.9 (like Firefox/3.5.9)" +67.23.46.234 - - [12/May/2010:00:13:49 +0000] "GET / HTTP/1.1" 206 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-us; rv:1.9.0.2) Gecko/2008092313 Ubuntu/9.04 (jaunty) Firefox/3.5" +212.227.29.202 - - [12/May/2010:19:06:35 +0000] "GET / HTTP/1.1" 200 6063 "http://hid.im/" "SimplePie/1.1.3 (Feed Parser; http://simplepie.org; Allow like Gecko) Build/20081219" +90.227.88.187 - - [12/May/2010:19:21:09 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_3 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Mobile/7E18" +80.187.110.169 - - [12/May/2010:23:56:57 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; de-de) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7" +94.100.181.101 - - [13/May/2010:01:44:41 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mail.Ru/1.0" +84.189.89.200 - - [13/May/2010:02:35:04 +0000] "GET / HTTP/1.1" 200 6063 "http://delicious.com/nok/generator" "Opera/9.80 (X11; Linux i686; U; de) Presto/2.2.15 Version/10.10" +173.183.79.43 - - [14/May/2010:05:49:51 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729)" +95.108.142.138 - - [15/May/2010:03:36:19 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +208.80.193.39 - - [15/May/2010:15:47:53 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SIMBAR={FF5BBDF6-13F9-4F49-816E-58F618C18B47})" +95.108.155.252 - - [15/May/2010:16:44:22 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; I)" +70.232.166.159 - - [15/May/2010:21:34:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "iTunes/9.1.1 (Macintosh; Intel Mac OS X 10.4.11) AppleWebKit/531.22.7" +82.9.89.70 - - [16/May/2010:12:23:00 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100401 Ant.com Toolbar 2.0.1 Firefox/3.6.3" +66.182.202.27 - - [17/May/2010:23:44:48 +0000] "GET / HTTP/1.1" 206 4603 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +208.80.193.36 - - [21/May/2010:00:31:36 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0; .NET CLR 2.0.50727; InfoPath.1; IEMB3; IEMB3)" +122.29.78.146 - - [21/May/2010:13:56:29 +0000] "GET / HTTP/1.1" 200 6063 "http://www.moongift.jp/2009/07/hid_im/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.1.249.1064 Safari/532.5" +88.161.231.206 - - [21/May/2010:18:03:13 +0000] "GET / HTTP/1.1" 200 6063 "http://www.korben.info/cacher-un-torrent-dans-une-image.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2) Gecko/20100115 Firefox/3.6" +86.106.47.30 - - [23/May/2010:07:20:45 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +178.94.79.148 - - [23/May/2010:15:57:45 +0000] "GET / HTTP/1.1" 200 6063 "http://nuttnet.net/posts/8723-Announcing-Hid-im" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.1.249.1064 Safari/532.5" +178.94.79.148 - - [23/May/2010:16:18:24 +0000] "GET / HTTP/1.1" 304 0 "http://nuttnet.net/posts/8723-Announcing-Hid-im" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.1.249.1064 Safari/532.5" +184.73.9.64 - - [23/May/2010:17:13:55 +0000] "GET / HTTP/1.1" 200 6063 "-" "Python-urllib/2.5" +78.159.102.141 - - [24/May/2010:04:12:07 +0000] "GET / HTTP/1.0" 200 6063 "-" "igdeSpyder (compatible; igde.ru; +http://igde.ru/doc/tech.html)" +66.220.145.246 - - [24/May/2010:13:51:32 +0000] "GET / HTTP/1.1" 200 6063 "-" "facebookexternalhit/1.0 (+http://www.facebook.com/externalhit_uatext.php)" +62.101.81.68 - - [26/May/2010:14:33:31 +0000] "GET / HTTP/1.0" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0 ( .NET CLR 3.5.30729)" +188.3.215.9 - - [28/May/2010:18:51:25 +0000] "GET / HTTP/1.1" 200 6063 "http://www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; tr; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +91.81.140.91 - - [29/May/2010:07:02:14 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +77.37.137.115 - - [30/May/2010:03:35:12 +0000] "GET / HTTP/1.1" 200 6063 "http://luciddeep.ya.ru/replies.xml?item_no=1184" "Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53" +78.159.102.141 - - [01/Jun/2010:16:23:55 +0000] "GET / HTTP/1.0" 200 6063 "-" "igdeSpyder (compatible; igde.ru; +http://igde.ru/doc/tech.html)" +79.184.93.250 - - [02/Jun/2010:09:35:18 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3" +67.195.113.229 - - [03/Jun/2010:08:04:07 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +202.179.89.246 - - [05/Jun/2010:10:48:11 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.55 Safari/533.4" +59.177.0.95 - - [05/Jun/2010:18:09:46 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9" +190.94.10.76 - - [06/Jun/2010:05:01:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; es-MX; rv:1.9.2.3) Gecko/20100407 Ubuntu/9.10 (karmic) Firefox/3.6.3" +78.8.11.231 - - [07/Jun/2010:07:20:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +94.100.181.101 - - [07/Jun/2010:13:28:18 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mail.Ru/1.0" +76.111.197.136 - - [13/Jun/2010:23:40:40 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/url?sa=t&source=web&cd=1&ved=0CBsQFjAA&url=http%3A%2F%2Fwww.hid.im%2F&rct=j&q=hid.im&ei=c2wVTMS8MsL88AbVvISUCg&usg=AFQjCNFaT7O6AF0rjcfbralsOlblnMGYxQ" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0" +117.207.69.148 - - [14/Jun/2010:03:00:53 +0000] "GET / HTTP/1.1" 200 6063 "http://gallery.mobile9.com/f/866943/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +90.22.158.190 - - [14/Jun/2010:09:47:36 +0000] "GET / HTTP/1.1" 304 0 "http://www.korben.info/cacher-un-torrent-dans-une-image.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.427.0 Safari/534.1" +79.173.205.71 - - [15/Jun/2010:11:06:49 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4" +80.101.190.83 - - [15/Jun/2010:23:01:14 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Windows; U; Windows NT 6.1; nl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +94.163.4.183 - - [15/Jun/2010:23:21:00 +0000] "GET / HTTP/1.1" 200 6063 "http://ziogeek.com/nascondere-file-torrent/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +71.111.196.50 - - [16/Jun/2010:03:22:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 AutoPager/0.6.1.12 AutoPager/0.6.1.12" +190.94.99.183 - - [17/Jun/2010:02:19:18 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; es-MX; rv:1.9.2.3) Gecko/20100407 Ubuntu/9.10 (karmic) Firefox/3.6.3" +95.108.142.138 - - [17/Jun/2010:04:45:26 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +81.88.49.20 - - [17/Jun/2010:12:13:35 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +164.58.59.63 - - [17/Jun/2010:22:57:43 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +95.108.150.235 - - [18/Jun/2010:01:43:43 +0000] "GET / HTTP/1.1" 200 6063 "-" "Yandex/1.01.001 (compatible; Win16; H)" +99.249.93.52 - - [18/Jun/2010:03:12:09 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.19) Gecko/2010040119 Ubuntu/8.04 (hardy) Firefox/3.0.19" +66.235.124.57 - - [19/Jun/2010:15:36:41 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; Ask Jeeves/Teoma; +http://about.ask.com/en/docs/about/webmasters.shtml)" +150.70.66.183 - - [21/Jun/2010:21:56:42 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +94.100.181.101 - - [23/Jun/2010:17:27:38 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mail.Ru/1.0" +88.255.169.100 - - [24/Jun/2010:13:10:20 +0000] "GET / HTTP/1.1" 200 6063 "http://www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; tr; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4" +84.0.129.107 - - [24/Jun/2010:21:15:32 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4" +189.142.10.96 - - [25/Jun/2010:02:16:13 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4" +173.21.208.205 - - [25/Jun/2010:05:56:03 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4" +68.202.105.102 - - [25/Jun/2010:23:42:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 ( .NET CLR 3.5.30729; .NET4.0C)" +202.160.178.198 - - [27/Jun/2010:16:28:17 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp China; http://misc.yahoo.com.cn/help.html)" +203.206.74.238 - - [29/Jun/2010:08:44:03 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com.au/search?aq=f&sourceid=chrome&ie=UTF-8&q=hidim" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4" +134.106.137.68 - - [30/Jun/2010:07:11:55 +0000] "GET / HTTP/1.1" 200 6063 "http://news.ycombinator.com/item?id=702654" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4" +93.148.63.21 - - [30/Jun/2010:21:01:14 +0000] "GET / HTTP/1.1" 200 6063 "http://ziogeek.com/nascondere-file-torrent/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4" +149.169.60.253 - - [01/Jul/2010:00:42:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4" +216.239.124.44 - - [01/Jul/2010:21:03:19 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.18) Gecko/2010020220 Firefox/3.0.18" +86.184.172.219 - - [02/Jul/2010:23:52:50 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6" +82.38.177.174 - - [05/Jul/2010:21:38:54 +0000] "GET / HTTP/1.1" 206 4615 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3" +186.120.105.134 - - [06/Jul/2010:00:54:58 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; es-MX; rv:1.9.2.4) Gecko/20100621 Ubuntu/9.10 (karmic) Firefox/3.6.4" +119.12.206.61 - - [07/Jul/2010:12:00:09 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2) Gecko/20100115 Firefox/3.6" +208.85.24.247 - - [08/Jul/2010:22:34:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2" +183.5.36.172 - - [09/Jul/2010:06:07:28 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +208.80.193.34 - - [10/Jul/2010:01:14:51 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; LN; .NET CLR 1.1.4322; InfoPath.1)" +98.225.35.241 - - [10/Jul/2010:01:35:43 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 (.NET CLR 3.5.30729)" +119.245.57.154 - - [11/Jul/2010:03:00:02 +0000] "GET / HTTP/1.1" 304 0 "http://www.excite.co.jp/News/net_clm/20090719/Slashdot_09_07_19_1058215.html" "Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0C)" +67.165.230.118 - - [11/Jul/2010:08:29:41 +0000] "GET / HTTP/1.0" 200 6063 "http://www.reddit.com/r/Ubuntu/comments/co57o/i_made_a_glados_login_sound_please_feel_free_to/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6" +174.70.53.113 - - [11/Jul/2010:21:53:25 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729)" +71.101.129.174 - - [12/Jul/2010:02:01:17 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.3) Gecko/20091020 Ubuntu/9.10 (karmic) Firefox/3.5.3" +208.80.193.39 - - [12/Jul/2010:20:06:06 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {14716646-6BE7-494E-9004-D73A65136838}; InfoPath.1; .NET CLR 1.0.3705)" +70.83.1.11 - - [13/Jul/2010:18:13:04 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?q=bookmarklet%20hid.im" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6" +202.124.109.9 - - [14/Jul/2010:13:49:43 +0000] "GET / HTTP/1.1" 200 6063 "http://nzpug.org/MeetingsWellington" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6" +110.32.138.53 - - [15/Jul/2010:13:46:04 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4" +118.12.205.24 - - [17/Jul/2010:10:12:08 +0000] "GET / HTTP/1.1" 304 0 "http://www.google.co.jp/search?hl=ja&q=hid.im&lr=&aq=3&aqi=g5&aql=&oq=hid.&gs_rfai=" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)" +129.79.247.19 - - [17/Jul/2010:10:43:15 +0000] "GET / HTTP/1.1" 200 6063 "-" "Python-urllib/2.6" +97.82.255.13 - - [18/Jul/2010:06:40:31 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?q=Hid.im&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 (.NET CLR 3.5.30729)" +94.41.33.173 - - [20/Jul/2010:12:44:04 +0000] "GET / HTTP/1.1" 200 6063 "http://yandex.ru/yandsearch?text=hid.im&clid=14002&yasoft=barff&lr=172" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2) Gecko/20100115 Firefox/3.6" +68.202.105.102 - - [20/Jul/2010:19:08:16 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0C)" +174.34.147.83 - - [21/Jul/2010:15:57:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/2008103100 SUSE/3.0.4-4.6 Firefox/3.0.4" +64.56.66.178 - - [22/Jul/2010:17:38:12 +0000] "GET / HTTP/1.1" 200 6063 "-" "Wget/1.9+cvs-stable (Red Hat modified)" +95.67.205.193 - - [27/Jul/2010:15:11:35 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 6.1; U; YB/3.5.1; ru) Presto/2.6.30 Version/10.70" +83.237.32.220 - - [27/Jul/2010:22:31:57 +0000] "GET / HTTP/1.1" 200 6063 "http://habrahabr.ru/blogs/collaboration/100252/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4" +210.73.10.62 - - [30/Jul/2010:22:55:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.itpub.net/thread-1331753-1-1.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.4 (KHTML, like Gecko) Chrome/6.0.477.0 Safari/534.4" +123.124.17.51 - - [31/Jul/2010:01:40:34 +0000] "GET / HTTP/1.1" 200 6063 "http://www.itpub.net/thread-1331753-1-1.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)" +220.181.77.196 - - [31/Jul/2010:02:37:53 +0000] "GET / HTTP/1.1" 200 6063 "http://www.itpub.net/thread-1331753-1-1.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; baiduds; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +71.95.104.176 - - [01/Aug/2010:07:59:38 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C)" +92.28.159.188 - - [02/Aug/2010:10:35:52 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 ( .NET CLR 3.5.30729; .NET4.0C)" +93.184.35.45 - - [02/Aug/2010:17:26:16 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6" +64.56.64.57 - - [03/Aug/2010:06:39:00 +0000] "GET / HTTP/1.1" 200 6063 "-" "Wget/1.9+cvs-stable (Red Hat modified)" +70.241.17.162 - - [03/Aug/2010:20:23:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +93.87.0.181 - - [04/Aug/2010:21:13:13 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100701 Firefox/3.5.11" +84.203.74.244 - - [06/Aug/2010:01:47:31 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C)" +91.212.146.10 - - [06/Aug/2010:06:05:03 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.6.30 Version/10.60" +82.132.136.187 - - [07/Aug/2010:14:56:18 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.19) Gecko/2010040116 Ubuntu/9.04 (jaunty) Firefox/3.0.19 ( .NET CLR 3.5.30729)" +98.254.222.118 - - [09/Aug/2010:15:18:26 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729)" +202.238.96.133 - - [11/Aug/2010:09:59:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 5.1; U; ja) Presto/2.6.30 Version/10.60" +92.84.147.85 - - [13/Aug/2010:12:57:03 +0000] "GET / HTTP/1.1" 200 6063 "http://vertaler-nederlands.com" "Mozilla/5.0 (compatible; vertaler-nederlands/1.0; + http://vertaler-nederlands.com)" +83.30.9.224 - - [18/Aug/2010:20:47:35 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.6 (KHTML, like Gecko) Chrome/6.0.494.0 Safari/534.6" +219.1.208.6 - - [19/Aug/2010:00:51:12 +0000] "GET / HTTP/1.1" 200 6063 "http://www.hid.im/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; YTB730; GTB6.5; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30618)" +122.160.140.214 - - [19/Aug/2010:06:02:13 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +174.129.139.3 - - [19/Aug/2010:20:26:18 +0000] "GET / HTTP/1.1" 304 0 "-" "PostRank/2.0 (postrank.com; 1 subscribers)" +65.190.69.213 - - [20/Aug/2010:17:12:38 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C)" +174.60.105.4 - - [21/Aug/2010:00:52:16 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +187.142.26.23 - - [22/Aug/2010:04:36:11 +0000] "GET / HTTP/1.1" 304 0 "http://www.google.com.mx/search?hl=es&source=hp&q=Hidim&meta=&btnG=Buscar+con+Google" "Mozilla/5.0 (Windows; U; Windows NT 6.1; es-AR; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +68.202.105.102 - - [22/Aug/2010:19:38:25 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C)" +68.195.27.67 - - [23/Aug/2010:22:23:24 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.6 (KHTML, like Gecko) Chrome/6.0.497.0 Safari/534.6" +174.19.105.158 - - [24/Aug/2010:06:40:35 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729)" +69.115.24.69 - - [25/Aug/2010:18:43:11 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)" +92.193.49.251 - - [25/Aug/2010:23:25:40 +0000] "GET / HTTP/1.1" 200 6063 "http://famicoman.com/tag/thehiddentracker/" "Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8" +74.70.254.227 - - [26/Aug/2010:22:24:30 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 ( .NET CLR 3.5.30729)" +142.108.115.35 - - [27/Aug/2010:17:01:20 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 5.1; rv:2.0b4) Gecko/20100818 Firefox/4.0b4" +71.238.68.34 - - [28/Aug/2010:06:08:44 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100723 Ubuntu/9.10 (karmic) Firefox/3.6.8" +128.237.250.1 - - [28/Aug/2010:20:29:19 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?q=hidims&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +125.29.14.46 - - [29/Aug/2010:09:42:25 +0000] "GET / HTTP/1.1" 200 6063 "http://slashdot.jp/link.pl?url=http%3A%2F%2Fwww.hid.im%2F&ref=http%3A%2F%2Fslashdot.jp%2Fit%2F09%2F07%2F19%2F1058215.shtml" "Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.11) Gecko/20100701 Firefox/3.5.11" +190.94.9.73 - - [30/Aug/2010:04:04:16 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.8) Gecko/20100723 Linux Mint/9 (Isadora) Firefox/3.6.8" +96.255.142.201 - - [30/Aug/2010:07:20:59 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +38.108.107.34 - - [30/Aug/2010:18:19:39 +0000] "GET / HTTP/1.1" 200 6063 "http://nutt.im/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16" +126.121.14.106 - - [03/Sep/2010:06:59:42 +0000] "GET / HTTP/1.1" 200 6063 "http://slashdot.jp/link.pl?url=http%3A%2F%2Fwww.hid.im%2F&ref=http%3A%2F%2Fslashdot.jp%2Fit%2F09%2F07%2F19%2F1058215.shtml" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" +126.121.14.106 - - [03/Sep/2010:07:00:20 +0000] "GET / HTTP/1.1" 200 6063 "http://www.hid.im/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" +208.120.116.93 - - [04/Sep/2010:05:07:30 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 GTB7.1" +67.170.65.243 - - [04/Sep/2010:09:05:28 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +121.108.82.206 - - [05/Sep/2010:06:55:47 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.3a5pre) Gecko/20100608 Firefox/3.6.5" +71.238.68.34 - - [05/Sep/2010:11:47:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100723 Ubuntu/9.10 (karmic) Firefox/3.6.8" +98.149.221.251 - - [07/Sep/2010:03:33:08 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +68.202.105.102 - - [08/Sep/2010:19:51:01 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 ( .NET CLR 3.5.30729; .NET4.0C)" +122.122.128.226 - - [10/Sep/2010:16:15:36 +0000] "GET / HTTP/1.1" 200 6063 "http://www.soft4fun.net/bbs/hidden-bt-torrent-download-url.htm" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Foxy/1; Foxy/1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +202.224.154.223 - - [15/Sep/2010:17:39:40 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9" +75.101.195.195 - - [17/Sep/2010:09:06:23 +0000] "GET / HTTP/1.1" 304 0 "-" "PostRank/2.0 (postrank.com; 1 subscribers)" +86.76.98.12 - - [18/Sep/2010:22:56:34 +0000] "GET / HTTP/1.1" 200 6063 "http://hid.im/about/format" "Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.10) Gecko/20100915 Ubuntu/10.04 (lucid) Firefox/3.6.10 GTB7.1" +174.129.139.3 - - [20/Sep/2010:04:56:35 +0000] "GET / HTTP/1.1" 304 0 "-" "PostRank/2.0 (postrank.com; 1 subscribers)" +97.8.117.141 - - [23/Sep/2010:16:38:01 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" +190.94.13.135 - - [24/Sep/2010:22:40:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.8) Gecko/20100723 Linux Mint/9 (Isadora) Firefox/3.6.8" +67.242.173.176 - - [24/Sep/2010:23:04:20 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10" +198.1.37.1 - - [25/Sep/2010:20:53:48 +0000] "GET / HTTP/1.0" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10" +155.33.141.202 - - [28/Sep/2010:20:08:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.2; Media Center PC 6.0; .NET CLR 1.1.4322)" +69.208.36.43 - - [02/Oct/2010:04:39:41 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322)" +88.190.11.232 - - [02/Oct/2010:07:55:16 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 GTB7.1" +92.85.160.72 - - [03/Oct/2010:19:01:41 +0000] "GET / HTTP/1.1" 200 6063 "-" "Java/1.6.0_04" +208.118.60.157 - - [04/Oct/2010:09:21:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "-" +78.83.131.251 - - [04/Oct/2010:18:01:17 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.bg/search?q=hid&hl=bg&client=opera&hs=Uj&rls=bg&prmd=v&ei=PRaqTIaeHcSKswbUnvmrDA&start=20&sa=N" "Opera/9.80 (Windows NT 5.1; U; bg) Presto/2.6.30 Version/10.61" +35.13.248.241 - - [06/Oct/2010:03:13:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "iTunes/10.0 (Macintosh; Intel Mac OS X 10.6.4) AppleWebKit/533.18.1" +121.218.45.160 - - [06/Oct/2010:11:49:03 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3" +92.15.73.36 - - [07/Oct/2010:00:03:15 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +98.223.166.105 - - [07/Oct/2010:06:53:56 +0000] "GET / HTTP/1.1" 200 6063 "http://nuttnet.net/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.536.2 Safari/534.10" +145.48.234.151 - - [08/Oct/2010:08:46:22 +0000] "GET / HTTP/1.1" 200 6063 "http://www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; nl; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10" +67.195.114.24 - - [09/Oct/2010:08:50:21 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +95.95.118.150 - - [09/Oct/2010:10:30:44 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; pt-PT; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10" +190.94.15.49 - - [09/Oct/2010:17:45:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.8) Gecko/20100723 Linux Mint/9 (Isadora) Firefox/3.6.8" +149.132.118.92 - - [11/Oct/2010:08:14:56 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.2.10) Gecko/20100915 Ubuntu/10.04 (lucid) Firefox/3.6.10" +184.91.164.255 - - [14/Oct/2010:02:23:33 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.0 Safari/534.10" +210.212.205.135 - - [14/Oct/2010:07:18:10 +0000] "GET / HTTP/1.0" 200 6063 "http://www.makeuseof.com/dir/hid-im-hide-torrents/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10" +89.238.218.234 - - [14/Oct/2010:08:50:08 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.10) Gecko/20100915 Ubuntu/10.04 (lucid) Firefox/3.6.10 (.NET CLR 3.5.30729)" +75.101.195.195 - - [16/Oct/2010:11:33:28 +0000] "GET / HTTP/1.1" 304 0 "-" "PostRank/2.0 (postrank.com; 1 subscribers)" +93.35.60.249 - - [17/Oct/2010:13:21:56 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.2; it; rv:1.9.2) Gecko/20100115 Firefox/3.6 ( .NET CLR 3.5.30729)" +208.80.194.35 - - [19/Oct/2010:01:18:35 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; BT Openworld BB; .NET CLR 1.1.4322)" +208.80.194.53 - - [22/Oct/2010:20:21:53 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.2.0; BCD2000; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +173.45.109.18 - - [23/Oct/2010:16:08:33 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (.NET CLR 3.5.30729)" +152.17.55.60 - - [24/Oct/2010:20:26:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11 ( .NET CLR 3.5.30729; .NET4.0E)" +208.80.194.55 - - [25/Oct/2010:10:23:12 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; H010818; yie6; .NET CLR 1.1.4322)" +145.52.92.168 - - [25/Oct/2010:12:28:55 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.5" +38.97.94.34 - - [25/Oct/2010:17:27:14 +0000] "GET / HTTP/1.1" 200 3294 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 ( .NET CLR 3.5.30729; .NET4.0E)" +71.249.191.47 - - [25/Oct/2010:18:38:07 +0000] "GET / HTTP/1.1" 200 3294 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +99.136.93.181 - - [25/Oct/2010:18:52:24 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +98.207.22.129 - - [26/Oct/2010:04:38:53 +0000] "GET / HTTP/1.1" 200 3294 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.11 Safari/534.10" +92.230.245.179 - - [26/Oct/2010:08:24:52 +0000] "GET / HTTP/1.1" 200 3294 "http://news.ycombinator.com/item?id=1833276" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +83.8.112.166 - - [26/Oct/2010:08:51:25 +0000] "GET / HTTP/1.1" 200 3294 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +83.175.227.50 - - [26/Oct/2010:09:32:36 +0000] "GET / HTTP/1.1" 200 3294 "http://news.ycombinator.com/item?id=1833276" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +82.169.189.51 - - [26/Oct/2010:10:27:49 +0000] "GET / HTTP/1.1" 200 3294 "-" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0_1 like Mac OS X; nl-nl) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A306 Safari/6531.22.7" +193.203.207.241 - - [26/Oct/2010:10:30:34 +0000] "GET / HTTP/1.1" 200 3294 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.2 (KHTML, like Gecko) Chrome/6.0.451.0 Safari/534.2" +123.122.81.26 - - [26/Oct/2010:11:50:47 +0000] "GET / HTTP/1.1" 200 3294 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +74.68.115.87 - - [27/Oct/2010:07:28:52 +0000] "GET / HTTP/1.1" 200 3635 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +111.91.137.57 - - [27/Oct/2010:09:30:54 +0000] "GET / HTTP/1.1" 502 173 "http://rdelsalle.blogspot.com/2010/05/real-time-web-analytics-using-nodejs.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +88.177.191.216 - - [27/Oct/2010:11:16:08 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.11 Safari/534.10" +188.82.212.40 - - [27/Oct/2010:11:40:08 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3" +91.198.90.55 - - [27/Oct/2010:14:49:15 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/4.0 (compatible;)" +91.198.90.55 - - [27/Oct/2010:16:19:45 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows NT 5.1; rv:2.0b6) Gecko/20100101 Firefox/4.0b6" +74.68.115.87 - - [27/Oct/2010:16:32:07 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/534.10+ (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8" +74.68.115.87 - - [27/Oct/2010:16:34:54 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/534.10+ (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8" +86.184.61.86 - - [27/Oct/2010:21:41:47 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +188.126.80.59 - - [27/Oct/2010:21:58:53 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +24.30.80.65 - - [28/Oct/2010:02:06:04 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.11) Gecko/20101013 Ubuntu/10.04 (lucid) Firefox/3.6.11" +74.68.115.87 - - [28/Oct/2010:02:43:03 +0000] "GET / HTTP/1.1" 200 3635 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/534.10+ (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8" +74.68.115.87 - - [28/Oct/2010:06:39:28 +0000] "GET / HTTP/1.1" 200 3674 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/534.11+ (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8" +74.68.115.87 - - [28/Oct/2010:06:39:31 +0000] "GET / HTTP/1.1" 200 3674 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/534.11+ (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8" +58.49.254.171 - - [28/Oct/2010:07:56:30 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.6.30 Version/10.63" +86.136.228.129 - - [28/Oct/2010:18:17:06 +0000] "GET / HTTP/1.1" 200 3674 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +88.214.193.166 - - [29/Oct/2010:05:13:01 +0000] "GET / HTTP/1.1" 200 6063 "http://www.semrush.com/fr/info/hid.im" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +113.106.106.131 - - [29/Oct/2010:08:04:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; MAXTHON 2.0)" +87.212.192.125 - - [29/Oct/2010:13:17:45 +0000] "GET / HTTP/1.1" 200 3674 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +79.41.11.138 - - [29/Oct/2010:13:36:27 +0000] "GET / HTTP/1.1" 200 3674 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +70.89.24.113 - - [29/Oct/2010:20:13:33 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +81.100.240.246 - - [29/Oct/2010:23:31:02 +0000] "GET / HTTP/1.1" 502 173 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.36 Safari/534.3" +216.8.169.49 - - [30/Oct/2010:19:57:34 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +67.184.249.199 - - [31/Oct/2010:05:00:44 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +84.114.242.113 - - [31/Oct/2010:09:10:48 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +209.220.168.196 - - [31/Oct/2010:18:06:45 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +189.102.85.44 - - [01/Nov/2010:13:06:56 +0000] "GET / HTTP/1.1" 200 3673 "http://www.cocut.cn/scripts/4593-hummingbird-free-real-time-web-traffic-software-.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +77.206.7.145 - - [01/Nov/2010:14:24:36 +0000] "GET / HTTP/1.1" 200 3673 "http://www.clonestop.com/webmasters/analytics-clone/1605-hummingbird-free-real-time-web-traffic-software.html" "Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 ( .NET CLR 3.5.30729; .NET4.0C)" +68.169.158.241 - - [01/Nov/2010:15:15:19 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +189.221.0.2 - - [02/Nov/2010:04:04:21 +0000] "GET / HTTP/1.1" 200 3673 "http://cocut.cn/scripts/4593-hummingbird-free-real-time-web-traffic-software-.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +208.247.73.130 - - [02/Nov/2010:14:02:59 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +76.125.52.58 - - [02/Nov/2010:20:46:48 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +202.12.92.169 - - [03/Nov/2010:00:38:01 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +81.149.183.122 - - [03/Nov/2010:14:10:02 +0000] "GET / HTTP/1.1" 200 3673 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-gb) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8" +87.194.66.9 - - [03/Nov/2010:15:11:01 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +80.249.94.145 - - [03/Nov/2010:22:36:21 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +63.224.75.122 - - [04/Nov/2010:06:17:08 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +211.45.60.1 - - [04/Nov/2010:06:27:20 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB6.3; TCO_20101104152537; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322; .NET4.0C; .NET4.0E)" +81.136.192.108 - - [04/Nov/2010:14:01:09 +0000] "GET / HTTP/1.1" 200 3673 "http://www.clonestop.com/webmasters/analytics-clone/1605-hummingbird-free-real-time-web-traffic-software.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10" +116.247.127.226 - - [05/Nov/2010:05:05:41 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +198.145.116.13 - - [05/Nov/2010:17:05:56 +0000] "GET / HTTP/1.0" 200 3673 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" +193.226.219.57 - - [05/Nov/2010:17:13:48 +0000] "GET / HTTP/1.1" 200 3673 "http://www.cocut.cn/scripts/4593-hummingbird-free-real-time-web-traffic-software-.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +67.195.110.182 - - [06/Nov/2010:04:28:42 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)" +90.192.189.20 - - [06/Nov/2010:22:32:36 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.6.12" +152.65.80.92 - - [06/Nov/2010:23:52:38 +0000] "GET / HTTP/1.1" 200 3673 "http://www.clonestop.com/webmasters/analytics-clone/1605-hummingbird-free-real-time-web-traffic-software.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +174.88.23.160 - - [07/Nov/2010:05:06:10 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +82.198.106.32 - - [07/Nov/2010:12:55:50 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +76.241.138.25 - - [07/Nov/2010:17:11:11 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +93.156.77.27 - - [08/Nov/2010:18:45:15 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +72.148.195.118 - - [08/Nov/2010:22:26:50 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +95.17.11.186 - - [09/Nov/2010:00:06:49 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.28 Safari/534.10" +222.55.196.86 - - [09/Nov/2010:03:06:12 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +88.188.1.124 - - [09/Nov/2010:16:01:24 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; fr-fr) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +38.97.88.20 - - [09/Nov/2010:19:47:00 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +189.202.28.146 - - [09/Nov/2010:20:54:28 +0000] "GET / HTTP/1.1" 200 3673 "http://www.google.com.mx/url?sa=t&source=web&cd=6&ved=0CDQQFjAF&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=exceed%20hummingbird%20demo&ei=GrTZTN6bGsXflge3vOzzCA&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDC)" +77.2.25.232 - - [09/Nov/2010:22:45:48 +0000] "GET / HTTP/1.1" 200 3673 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +130.130.37.12 - - [09/Nov/2010:23:32:48 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6; en-au) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9" +67.185.163.231 - - [10/Nov/2010:03:40:52 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +58.1.228.208 - - [10/Nov/2010:06:42:15 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.11 (KHTML, like Gecko) Chrome/9.0.570.1 Safari/534.11" +212.18.129.79 - - [10/Nov/2010:09:11:15 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +94.85.30.130 - - [10/Nov/2010:14:41:13 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.33 Safari/530.5" +194.223.35.2 - - [10/Nov/2010:15:00:36 +0000] "GET / HTTP/1.1" 502 533 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648)" +121.45.119.134 - - [10/Nov/2010:15:31:41 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +24.10.239.160 - - [10/Nov/2010:17:21:41 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +86.220.177.78 - - [10/Nov/2010:18:22:38 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; fr; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +88.87.30.197 - - [10/Nov/2010:19:05:43 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.28 Safari/534.10" +91.209.51.61 - - [10/Nov/2010:21:01:31 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +93.152.131.39 - - [10/Nov/2010:21:45:43 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +188.86.0.126 - - [10/Nov/2010:21:47:04 +0000] "GET / HTTP/1.1" 502 173 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.6.12 GTB7.1" +99.38.250.226 - - [11/Nov/2010:03:34:05 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +202.3.77.219 - - [11/Nov/2010:06:41:14 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.12 (KHTML, like Gecko) Chrome/9.0.578.0 Safari/534.12" +76.169.79.42 - - [11/Nov/2010:07:20:26 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; U; CPU OS 3_2_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B500" +110.159.150.161 - - [11/Nov/2010:09:08:46 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13pre) Gecko/20101109 Ubuntu/10.04 (lucid) Firefox/3.6.9" +195.243.172.67 - - [11/Nov/2010:10:21:14 +0000] "GET / HTTP/1.0" 502 173 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +94.176.183.202 - - [11/Nov/2010:15:34:47 +0000] "GET / HTTP/1.1" 502 173 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +125.161.219.252 - - [11/Nov/2010:15:57:49 +0000] "GET / HTTP/1.1" 502 173 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +69.127.196.246 - - [12/Nov/2010:04:17:17 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +173.160.79.62 - - [12/Nov/2010:15:25:56 +0000] "GET / HTTP/1.1" 502 173 "http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=demo+hummingbird" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +115.186.145.151 - - [12/Nov/2010:15:43:20 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +70.168.157.254 - - [12/Nov/2010:17:22:17 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +212.251.177.52 - - [12/Nov/2010:20:24:10 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.200 Safari/534.10" +214.3.138.234 - - [12/Nov/2010:21:56:04 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 (.NET CLR 3.5.30729)" +84.152.7.215 - - [14/Nov/2010:17:57:20 +0000] "GET / HTTP/1.1" 502 173 "http://hummingbirdstats.com/" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; de-de) AppleWebKit/532.9 (KHTML, like Gecko) Mobile/8B117" +59.103.222.166 - - [14/Nov/2010:21:43:46 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTB6 (.NET CLR 3.5.30729) WebMoney Advisor" +72.230.135.225 - - [14/Nov/2010:22:07:40 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.200 Safari/534.10" +62.21.48.94 - - [15/Nov/2010:02:55:05 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; rv:2.0b8pre) Gecko/20101114 Firefox/4.0b8pre" +193.43.244.93 - - [15/Nov/2010:14:46:15 +0000] "GET / HTTP/1.0" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 (.NET CLR 3.5.30729)" +193.43.246.132 - - [15/Nov/2010:14:46:27 +0000] "GET / HTTP/1.0" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 (.NET CLR 3.5.30729)" +85.230.136.95 - - [15/Nov/2010:23:22:28 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +99.120.68.249 - - [16/Nov/2010:04:41:45 +0000] "GET / HTTP/1.1" 200 3673 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +184.72.46.160 - - [16/Nov/2010:09:20:49 +0000] "GET / HTTP/1.0" 200 6063 "-" "NING/1.0" +195.70.44.1 - - [16/Nov/2010:17:35:34 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; MS-RTC LM 8)" +95.18.86.181 - - [16/Nov/2010:18:21:27 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686; rv:2.0b8pre) Gecko/20101112 Firefox-4.0/4.0b8pre" +67.242.173.176 - - [17/Nov/2010:01:34:01 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +174.105.254.50 - - [17/Nov/2010:01:52:02 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +109.65.36.241 - - [17/Nov/2010:04:49:57 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 ( .NET CLR 3.5.30729)" +24.215.222.250 - - [17/Nov/2010:17:52:49 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +219.120.53.253 - - [17/Nov/2010:22:52:24 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +95.26.241.10 - - [18/Nov/2010:00:40:26 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:26 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:26 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:27 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:27 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:27 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:27 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:28 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:28 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:28 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:28 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:28 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:28 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:29 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:29 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:29 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:29 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:29 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:30 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:30 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:30 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:30 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:31 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:31 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:31 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:32 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:32 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:32 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:32 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:32 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:32 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:32 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:34 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:35 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:36 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:36 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:36 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:38 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:38 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:38 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:38 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:38 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:38 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:39 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:39 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:39 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:39 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:39 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:39 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:40 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:40 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:40 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:40 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:41 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:41 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:41 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:42 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:42 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:43 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:43 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:43 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:43 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:44 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:44 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:44 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:44 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:44 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:44 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:44 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:45 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:45 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:46 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:47 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:47 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +95.26.241.10 - - [18/Nov/2010:00:40:47 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +114.80.93.71 - - [18/Nov/2010:02:32:16 +0000] "GET / HTTP/1.1" 502 533 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +75.73.202.236 - - [18/Nov/2010:04:13:41 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.12 (KHTML, like Gecko) Chrome/9.0.576.0 Safari/534.12" +217.10.134.34 - - [18/Nov/2010:09:09:38 +0000] "GET / HTTP/1.1" 502 173 "http://www.webstockbox.com/web-tools/hummingbird-see-how-visitors-are-interacting-with-your-website-in-real-time/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+webstockbox+%28WebStockBox%29" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +75.150.171.169 - - [18/Nov/2010:17:01:41 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +93.21.145.208 - - [19/Nov/2010:18:45:02 +0000] "GET / HTTP/1.1" 200 6063 "http://deal.blog.mongenie.com/index.php?idblogp=883982" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +8.21.4.254 - - [19/Nov/2010:21:51:58 +0000] "GET / HTTP/1.1" 502 533 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +84.190.85.110 - - [20/Nov/2010:00:44:16 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; de-de) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +205.251.121.5 - - [20/Nov/2010:06:39:58 +0000] "GET / HTTP/1.1" 502 173 "-" "panscient.com" +82.225.249.125 - - [20/Nov/2010:10:09:07 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +187.65.91.199 - - [21/Nov/2010:13:53:20 +0000] "GET / HTTP/1.1" 502 173 "http://rdelsalle.blogspot.com/2010/05/real-time-web-analytics-using-nodejs.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +70.27.49.136 - - [21/Nov/2010:18:00:00 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +87.194.163.246 - - [21/Nov/2010:22:54:27 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +58.61.164.141 - - [22/Nov/2010:00:58:36 +0000] "GET / HTTP/1.1" 502 533 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +77.236.208.46 - - [22/Nov/2010:07:40:25 +0000] "GET / HTTP/1.1" 200 6063 "http://www.bauer-power.net/2010/08/hide-your-torrents-in-plain-site.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+Bauer-power+%28Bauer-Power%3A+Information+is+Power!%29" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.12) Gecko/20101031 Gentoo Firefox/3.6.12" +180.151.49.130 - - [22/Nov/2010:09:00:52 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +123.237.247.180 - - [22/Nov/2010:09:58:33 +0000] "GET / HTTP/1.1" 502 173 "http://www.webstockbox.com/web-tools/hummingbird-see-how-visitors-are-interacting-with-your-website-in-real-time/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 ( .NET CLR 3.5.30729; .NET4.0E)" +95.82.189.90 - - [22/Nov/2010:21:24:05 +0000] "GET / HTTP/1.1" 200 6063 "http://www.bauer-power.net/2010/08/hide-your-torrents-in-plain-site.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+Bauer-power+%28Bauer-Power%3A+Information+is+Power!%29" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6.6; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; AskTB5.4)" +63.146.69.17 - - [23/Nov/2010:02:27:59 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3" +89.143.244.182 - - [23/Nov/2010:12:36:19 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +193.235.142.2 - - [23/Nov/2010:16:00:13 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +79.27.94.107 - - [23/Nov/2010:23:09:45 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +208.80.194.70 - - [24/Nov/2010:08:18:10 +0000] "GET / HTTP/1.0" 502 533 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50728)" +184.75.39.118 - - [24/Nov/2010:18:35:19 +0000] "GET / HTTP/1.1" 200 3673 "http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CBcQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=hummingbird%20stats&ei=41rtTPnXKYP7lwfp5MyPAQ&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3" +58.61.164.141 - - [25/Nov/2010:03:42:54 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +75.154.87.103 - - [26/Nov/2010:03:33:23 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +64.13.159.80 - - [26/Nov/2010:04:52:53 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; ScoutJet; +http://www.scoutjet.com/)" +202.54.176.12 - - [26/Nov/2010:08:59:47 +0000] "GET / HTTP/1.1" 502 533 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.2; MS-RTC LM 8; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +123.236.174.51 - - [26/Nov/2010:10:03:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 (.NET CLR 3.5.30729)" +149.156.139.57 - - [26/Nov/2010:11:24:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +154.5.186.117 - - [26/Nov/2010:23:20:14 +0000] "GET / HTTP/1.1" 502 173 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +195.241.191.7 - - [27/Nov/2010:10:21:10 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +208.80.194.31 - - [27/Nov/2010:23:33:05 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.5.20404)" +173.192.81.150 - - [29/Nov/2010:01:23:05 +0000] "GET / HTTP/1.1" 502 173 "-" "-" +128.113.140.97 - - [30/Nov/2010:00:17:10 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +98.208.217.61 - - [30/Nov/2010:04:22:53 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.74 Chrome/7.0.517.44 Safari/534.7" +85.20.175.12 - - [01/Dec/2010:11:49:26 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.89 Safari/532.5" +82.226.75.197 - - [01/Dec/2010:14:00:33 +0000] "GET / HTTP/1.1" 502 173 "http://www.google.com/search?ie=UTF-8&oe=UTF-8&gfns=1&q=hummingbirdstats&qscrl=1" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.208 Safari/534.10" +38.96.131.10 - - [01/Dec/2010:18:18:22 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +24.13.90.110 - - [02/Dec/2010:06:06:20 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.0 Safari/534.13" +114.77.230.224 - - [02/Dec/2010:06:32:21 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.210 Safari/534.10" +94.137.243.254 - - [02/Dec/2010:06:41:32 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +74.93.41.2 - - [02/Dec/2010:16:57:57 +0000] "GET / HTTP/1.0" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +216.171.105.46 - - [02/Dec/2010:20:30:18 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.210 Safari/534.10" +92.231.241.236 - - [03/Dec/2010:00:56:15 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; de-de) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +80.70.52.5 - - [03/Dec/2010:14:56:37 +0000] "GET / HTTP/1.1" 502 173 "http://thechangelog.com/post/927103350/episode-0-3-1-websockets" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 (.NET CLR 3.5.30729)" +97.77.102.179 - - [03/Dec/2010:19:45:48 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7" +67.202.12.167 - - [03/Dec/2010:23:29:10 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; NetcraftSurveyAgent/1.0; +info@netcraft.com)" +4.53.128.194 - - [03/Dec/2010:23:31:31 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 FirePHP/0.5" +208.80.194.26 - - [04/Dec/2010:03:17:26 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; HbTools 4.8.7)" +72.188.60.37 - - [04/Dec/2010:22:06:09 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 ( .NET CLR 3.5.30729; .NET4.0C)" +24.167.216.25 - - [05/Dec/2010:08:21:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +201.80.177.148 - - [06/Dec/2010:20:20:19 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-BR; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +60.234.233.94 - - [07/Dec/2010:02:31:47 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/r/technology/top/?count=125&t=all&after=t3_buegc" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +58.61.164.139 - - [07/Dec/2010:06:00:39 +0000] "GET / HTTP/1.1" 502 533 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +83.145.241.82 - - [07/Dec/2010:09:10:57 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +208.240.243.170 - - [09/Dec/2010:00:09:22 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +209.20.69.196 - - [10/Dec/2010:05:27:19 +0000] "GET / HTTP/1.1" 200 6063 "-" "Python-urllib/2.6" +99.246.50.56 - - [10/Dec/2010:06:17:10 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +66.21.196.17 - - [10/Dec/2010:07:42:51 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 GTB7.1" +180.151.49.130 - - [10/Dec/2010:08:29:13 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +85.183.2.66 - - [10/Dec/2010:14:39:29 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.53 Safari/534.3" +24.60.249.255 - - [11/Dec/2010:20:18:11 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +88.235.18.144 - - [12/Dec/2010:18:15:51 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +220.181.32.24 - - [13/Dec/2010:00:26:25 +0000] "GET / HTTP/1.1" 502 533 "" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; baidu Transcoder;)" +66.235.124.20 - - [13/Dec/2010:04:40:29 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; Ask Jeeves/Teoma; +http://about.ask.com/en/docs/about/webmasters.shtml)" +194.247.89.14 - - [13/Dec/2010:14:01:35 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.16 Safari/534.13" +206.229.47.151 - - [14/Dec/2010:05:46:02 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; rv:2.0b7) Gecko/20100101 Firefox/4.0b7" +208.247.73.130 - - [14/Dec/2010:20:42:40 +0000] "GET / HTTP/1.1" 200 3673 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +80.87.205.250 - - [15/Dec/2010:15:55:30 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +24.213.77.173 - - [16/Dec/2010:03:56:08 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +75.101.56.240 - - [16/Dec/2010:21:04:14 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +217.69.134.177 - - [16/Dec/2010:22:13:37 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mail.Ru/1.0" +81.88.49.16 - - [16/Dec/2010:22:46:33 +0000] "GET / HTTP/1.0" 200 3673 "-" "-" +58.61.164.39 - - [17/Dec/2010:02:31:55 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322;TencentTraveler)" +70.162.60.187 - - [17/Dec/2010:04:39:58 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +128.30.52.95 - - [17/Dec/2010:15:10:32 +0000] "GET / HTTP/1.1" 200 3673 "-" "Jigsaw/2.2.5 W3C_CSS_Validator_JFouffa/2.0" +131.107.0.98 - - [18/Dec/2010:00:32:26 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:2.0b9pre) Gecko/20101216 Firefox-4.0/4.0b9pre" +50.9.13.140 - - [18/Dec/2010:22:57:21 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +114.80.93.71 - - [19/Dec/2010:06:01:47 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +184.72.148.87 - - [20/Dec/2010:02:38:43 +0000] "GET / HTTP/1.1" 200 6063 "-" "Python-urllib/2.6" +72.219.179.202 - - [20/Dec/2010:07:28:48 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8" +114.48.227.254 - - [20/Dec/2010:07:35:50 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +87.246.185.124 - - [20/Dec/2010:08:10:58 +0000] "GET / HTTP/1.1" 200 6063 "http://vruz.tumblr.com/post/141665097/a-hidim-turns-a-torrent-into-a-regular-png-image" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +90.191.106.117 - - [20/Dec/2010:19:11:10 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 AskTbFXTV5/3.9.1.14019 Firefox/3.6.13" +94.194.121.85 - - [21/Dec/2010:00:15:36 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/toolbar/litebar.php?device=chromebar&version=chromebar%202.9.8.1&ts=1292887244" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/11.04 Chromium/8.0.552.224 Chrome/8.0.552.224 Safari/534.10" +117.198.166.123 - - [21/Dec/2010:09:10:46 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +83.226.158.145 - - [21/Dec/2010:10:28:45 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +198.54.202.226 - - [21/Dec/2010:10:32:19 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +95.108.142.138 - - [21/Dec/2010:12:13:22 +0000] "GET / HTTP/1.1" 200 6063 "-" "-" +208.80.194.31 - - [22/Dec/2010:06:59:54 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V109|2015|S1411215282|dialno; SV1)" +114.80.93.73 - - [22/Dec/2010:21:56:10 +0000] "GET / HTTP/1.0" 200 3673 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322;TencentTraveler)" +208.80.194.31 - - [23/Dec/2010:18:52:55 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; sbcydsl 3.12; .NET CLR 1.0.3705; .NET CLR 2.0.50727)" +212.232.66.15 - - [24/Dec/2010:12:14:01 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +212.232.66.15 - - [24/Dec/2010:12:14:01 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +212.232.66.15 - - [24/Dec/2010:12:14:02 +0000] "GET / HTTP/1.0" 200 3673 "-" "ApacheBench/2.3" +99.238.60.203 - - [26/Dec/2010:05:04:12 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +79.227.178.236 - - [26/Dec/2010:15:00:15 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +65.185.126.156 - - [26/Dec/2010:16:28:40 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 AskTbFXTV5/3.9.1.14019 Firefox/3.6.13 QuizulousSearchToolbar/1.2" +84.197.34.223 - - [26/Dec/2010:16:45:33 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +99.68.224.186 - - [26/Dec/2010:22:07:30 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +84.109.238.65 - - [27/Dec/2010:08:52:48 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +121.55.99.157 - - [27/Dec/2010:14:30:34 +0000] "GET / HTTP/1.1" 499 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Chrome/10.0.614.0 Safari/534.15" +79.113.137.76 - - [27/Dec/2010:14:39:56 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +68.110.130.146 - - [27/Dec/2010:17:24:08 +0000] "GET / HTTP/1.1" 504 183 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.596.0 Safari/534.13" +208.80.194.27 - - [28/Dec/2010:05:11:41 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; SiteKiosk 6.0 Build 98)" +200.168.242.100 - - [28/Dec/2010:17:42:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b8) Gecko/20100101 Firefox/4.0b8" +75.190.155.236 - - [28/Dec/2010:21:15:19 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 GTB7.1" +67.195.114.224 - - [29/Dec/2010:15:50:56 +0000] "GET / HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +70.255.164.136 - - [29/Dec/2010:19:42:51 +0000] "GET / HTTP/1.1" 499 0 "http://thechangelog.com/post/927103350/episode-0-3-1-websockets" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +188.220.39.10 - - [29/Dec/2010:19:59:29 +0000] "GET / HTTP/1.1" 504 183 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +67.180.60.121 - - [29/Dec/2010:21:45:40 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +189.79.86.160 - - [30/Dec/2010:00:18:50 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +213.22.216.138 - - [30/Dec/2010:04:58:56 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +202.72.208.114 - - [30/Dec/2010:08:51:35 +0000] "GET / HTTP/1.1" 504 183 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.19 Safari/534.13" +188.220.37.242 - - [30/Dec/2010:12:16:38 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +148.87.19.214 - - [31/Dec/2010:10:15:05 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +78.55.220.31 - - [01/Jan/2011:13:21:43 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.11) Gecko/20101019 Conkeror/0.9.3" +114.80.93.71 - - [02/Jan/2011:08:53:17 +0000] "GET / HTTP/1.1" 499 0 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +220.133.118.167 - - [03/Jan/2011:04:10:55 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Chrome/10.0.612.3 Safari/534.15" +14.201.192.149 - - [03/Jan/2011:07:36:01 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +88.26.234.43 - - [03/Jan/2011:09:54:42 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +83.160.49.30 - - [03/Jan/2011:13:40:10 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +188.205.1.214 - - [03/Jan/2011:14:10:00 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +68.204.123.202 - - [03/Jan/2011:21:29:21 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +80.86.123.71 - - [04/Jan/2011:10:26:48 +0000] "GET / HTTP/1.1" 504 183 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +62.100.145.244 - - [04/Jan/2011:14:23:08 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +74.116.16.145 - - [04/Jan/2011:16:52:42 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +112.104.172.197 - - [05/Jan/2011:15:24:01 +0000] "GET / HTTP/1.1" 200 6063 "http://www.eyny.com/thread-3461496-1-6.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +74.94.185.249 - - [05/Jan/2011:15:53:54 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +2.208.4.178 - - [05/Jan/2011:16:52:48 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Linux; U; Android 2.1-update1; de-de; Milestone Build/SHOLS_U2_02.36.0) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17" +187.14.54.213 - - [06/Jan/2011:00:26:50 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.70 Safari/533.4" +173.57.21.192 - - [06/Jan/2011:15:14:34 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13 GTB7.1" +76.213.252.116 - - [07/Jan/2011:08:12:57 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +84.180.159.48 - - [07/Jan/2011:12:07:49 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +72.66.79.78 - - [09/Jan/2011:01:42:05 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +71.146.150.135 - - [09/Jan/2011:05:22:19 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +84.251.220.210 - - [09/Jan/2011:19:31:25 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +220.233.8.184 - - [10/Jan/2011:23:07:09 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.7.62 Version/11.00" +211.4.182.193 - - [11/Jan/2011:10:08:54 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/5.0 (Android; Linux armv7l; rv:2.0b8) Gecko/20101221 Firefox/4.0b8 Fennec/4.0b3" +189.89.102.158 - - [11/Jan/2011:17:04:28 +0000] "GET / HTTP/1.0" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +198.203.175.175 - - [11/Jan/2011:23:38:37 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +99.63.201.183 - - [12/Jan/2011:03:40:33 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +99.63.201.183 - - [12/Jan/2011:03:41:18 +0000] "GET / HTTP/1.1" 200 3673 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +195.141.76.130 - - [12/Jan/2011:14:14:33 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/10.04 Chromium/8.0.552.224 Chrome/8.0.552.224 Safari/534.10" +76.10.164.232 - - [12/Jan/2011:15:16:21 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +72.220.17.18 - - [12/Jan/2011:15:25:57 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +82.210.176.110 - - [12/Jan/2011:17:39:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.13) Gecko/20101203 FireDownload/2.0.1 Firefox/3.6.13" +69.255.227.225 - - [12/Jan/2011:19:54:40 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +87.201.142.62 - - [13/Jan/2011:04:33:39 +0000] "GET / HTTP/1.1" 200 6063 "http://wwwstumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Linux; U; Android 2.2; en-gb; Desire HD Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" +85.189.254.181 - - [13/Jan/2011:13:36:57 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +92.42.225.1 - - [13/Jan/2011:16:59:37 +0000] "GET / HTTP/1.0" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.634.0 Safari/534.16" +78.16.127.181 - - [13/Jan/2011:17:30:00 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +67.244.127.112 - - [14/Jan/2011:06:18:17 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +38.99.97.12 - - [15/Jan/2011:04:19:28 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; ScoutJet; +http://www.scoutjet.com/)" +89.173.50.42 - - [15/Jan/2011:10:44:27 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +187.20.140.99 - - [16/Jan/2011:14:22:29 +0000] "GET / HTTP/1.1" 200 3673 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +66.220.149.244 - - [17/Jan/2011:03:20:46 +0000] "GET / HTTP/1.1" 206 6063 "-" "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" +201.230.73.216 - - [17/Jan/2011:05:59:29 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +81.6.83.253 - - [17/Jan/2011:22:31:30 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +72.188.58.250 - - [18/Jan/2011:03:53:06 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729; .NET4.0C)" +71.250.239.234 - - [18/Jan/2011:05:46:33 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +71.162.124.18 - - [18/Jan/2011:12:49:04 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +189.97.17.33 - - [18/Jan/2011:17:20:52 +0000] "GET / HTTP/1.1" 200 3673 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +187.67.11.254 - - [18/Jan/2011:21:02:19 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +64.58.138.59 - - [18/Jan/2011:21:30:20 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +212.200.146.253 - - [19/Jan/2011:11:52:53 +0000] "GET / HTTP/1.1" 200 3673 "http://www.clonestop.com/webmasters/analytics-clone/1605-hummingbird-free-real-time-web-traffic-software.html" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/10.10 Chromium/8.0.552.215 Chrome/8.0.552.215 Safari/534.10" +78.115.117.138 - - [19/Jan/2011:22:17:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR, fr; rv:1.9.2.13) Gecko/20101211 Firefox/3.6.13" +188.27.105.202 - - [20/Jan/2011:00:16:22 +0000] "GET / HTTP/1.1" 200 3673 "http://www.clonestop.com/webmasters/analytics-clone/1605-hummingbird-free-real-time-web-traffic-software.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +210.143.35.11 - - [20/Jan/2011:02:48:42 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +221.250.87.66 - - [20/Jan/2011:09:40:57 +0000] "GET / HTTP/1.1" 200 3673 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +213.132.48.105 - - [20/Jan/2011:11:49:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729; .NET4.0E)" +204.28.122.20 - - [20/Jan/2011:19:52:17 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10" +169.139.222.5 - - [21/Jan/2011:00:13:39 +0000] "GET / HTTP/1.1" 200 6063 "http://wwwstumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; DROIDX Build/VZW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" +85.255.197.126 - - [21/Jan/2011:08:46:08 +0000] "GET / HTTP/1.1" 200 3633 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/10.10 Chromium/8.0.552.237 Chrome/8.0.552.237 Safari/534.10" +99.7.143.68 - - [21/Jan/2011:09:44:56 +0000] "GET / HTTP/1.1" 200 3633 "http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CCUQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=hummingbird%20stats&ei=fVU5TZPjDoyisAOw4f20Aw&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; HPNTDF; .NET4.0C; AskTbUT2V5/5.9.1.14019)" +188.174.15.220 - - [22/Jan/2011:00:20:25 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/10.04 Chromium/8.0.552.237 Chrome/8.0.552.237 Safari/534.10" +74.68.115.87 - - [22/Jan/2011:20:51:58 +0000] "GET / HTTP/1.1" 200 3707 "http://demo.hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/534.16+ (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8" +89.173.104.233 - - [23/Jan/2011:12:29:07 +0000] "GET / HTTP/1.1" 502 173 "http://hummingbirdstats.com/" "Opera/9.80 (X11; Linux i686; U; en) Presto/2.7.62 Version/11.00" +174.0.86.9 - - [23/Jan/2011:14:44:35 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +122.56.32.246 - - [24/Jan/2011:02:17:54 +0000] "GET / HTTP/1.1" 502 575 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +67.244.83.166 - - [24/Jan/2011:04:15:22 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +66.235.124.20 - - [24/Jan/2011:04:50:21 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; Ask Jeeves/Teoma; +http://about.ask.com/en/docs/about/webmasters.shtml)" +150.70.66.183 - - [24/Jan/2011:07:17:02 +0000] "GET / HTTP/1.0" 502 575 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +124.171.7.0 - - [24/Jan/2011:10:51:12 +0000] "GET / HTTP/1.1" 502 575 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +83.244.235.130 - - [24/Jan/2011:13:29:12 +0000] "GET / HTTP/1.1" 502 575 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.67 Safari/534.13" +209.7.44.100 - - [24/Jan/2011:14:38:32 +0000] "GET / HTTP/1.0" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729; .NET4.0E)" +109.255.58.9 - - [24/Jan/2011:23:09:33 +0000] "GET / HTTP/1.1" 502 575 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" +117.201.88.52 - - [25/Jan/2011:13:29:49 +0000] "GET / HTTP/1.1" 502 173 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b9) Gecko/20100101 Firefox/4.0b9" +24.253.199.254 - - [25/Jan/2011:14:43:56 +0000] "GET / HTTP/1.1" 502 575 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.67 Safari/534.13" +187.59.166.246 - - [25/Jan/2011:23:04:07 +0000] "GET / HTTP/1.1" 502 575 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +64.147.175.7 - - [27/Jan/2011:21:52:23 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +112.206.32.136 - - [27/Jan/2011:23:41:42 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +69.63.1.114 - - [29/Jan/2011:05:27:39 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +216.38.216.220 - - [29/Jan/2011:20:10:16 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; MSIE 7.0b; Windows NT 6.0)" +86.96.226.85 - - [30/Jan/2011:07:29:41 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +151.16.112.179 - - [30/Jan/2011:13:05:52 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.2.13) Gecko/20101203 SUSE/3.6.13-0.2.1 Firefox/3.6.13" +188.60.15.183 - - [30/Jan/2011:14:36:21 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +85.84.181.247 - - [30/Jan/2011:18:34:20 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +79.169.97.23 - - [30/Jan/2011:21:08:41 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; ms-office)" +142.1.250.6 - - [31/Jan/2011:00:06:48 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +71.63.233.89 - - [31/Jan/2011:04:51:36 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +186.223.197.12 - - [01/Feb/2011:13:46:35 +0000] "GET / HTTP/1.0" 200 3739 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b10) Gecko/20100101 Firefox/4.0b10 FirePHP/0.5" +217.119.144.130 - - [02/Feb/2011:09:15:24 +0000] "GET / HTTP/1.1" 200 3739 "http://www.fobec.com/CMS/web/webmaster/analyser-les-visites-sur-son-site_977.html" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; fr-fr) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +188.158.80.254 - - [02/Feb/2011:09:36:15 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100124 Ubuntu/9.10 (karmic) Firefox/3.6" +85.152.1.155 - - [02/Feb/2011:11:16:59 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.19 Safari/534.13" +88.161.244.241 - - [03/Feb/2011:12:44:15 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13) Gecko/20110103 Fedora/3.6.13-1.fc14 Firefox/3.6.13 FirePHP/0.5" +109.228.153.5 - - [04/Feb/2011:06:01:46 +0000] "GET / HTTP/1.1" 200 3739 "-" "LoadImpactRload/1.0 (Load Impact; http://loadimpact.com);" +92.81.102.8 - - [04/Feb/2011:16:20:06 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.11 Safari/534.16" +67.195.37.190 - - [04/Feb/2011:16:51:14 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +24.30.154.246 - - [04/Feb/2011:17:13:10 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.84 Safari/534.13" +67.195.114.215 - - [04/Feb/2011:22:07:58 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +68.12.156.184 - - [05/Feb/2011:05:59:02 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/10.04 Chromium/8.0.552.224 Chrome/8.0.552.224 Safari/534.10" +122.183.242.146 - - [05/Feb/2011:09:03:38 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +71.17.51.135 - - [06/Feb/2011:08:58:45 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +210.188.62.70 - - [06/Feb/2011:10:47:59 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20110129 Firefox/3.6.13" +84.226.102.240 - - [06/Feb/2011:17:27:01 +0000] "GET / HTTP/1.1" 200 3739 "http://zacklive.com/hummingbird-web-analytics-updates-20-times-per-second/2289/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.84 Safari/534.13" +121.98.81.61 - - [07/Feb/2011:03:06:42 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.co.nz/search?sourceid=chrome&ie=UTF-8&q=hidim" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.86 Safari/534.13" +216.189.208.114 - - [07/Feb/2011:14:40:51 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +99.231.177.44 - - [08/Feb/2011:02:56:53 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.84 Safari/534.13" +208.80.194.36 - - [08/Feb/2011:04:48:27 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; EKT-V3.0RRC; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2)" +122.164.30.21 - - [08/Feb/2011:06:31:08 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/list/javasitevvv9/Details.aspx" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +66.242.37.254 - - [09/Feb/2011:17:23:41 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16" +190.73.195.134 - - [09/Feb/2011:18:39:31 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.84 Safari/534.13" +202.171.184.127 - - [10/Feb/2011:02:08:53 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +70.187.180.82 - - [10/Feb/2011:06:28:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.94 Safari/534.13" +24.10.35.110 - - [11/Feb/2011:06:44:58 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.94 Safari/534.13" +206.15.98.168 - - [11/Feb/2011:18:10:59 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +83.58.150.18 - - [11/Feb/2011:18:51:28 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.94 Safari/534.13" +84.166.246.116 - - [13/Feb/2011:18:12:54 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-gb) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +216.226.131.181 - - [13/Feb/2011:23:58:59 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30;)" +62.24.252.133 - - [14/Feb/2011:11:04:54 +0000] "GET / HTTP/1.0" 200 6063 "http://www.hid.im/" "(compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR ; http://www.talktalk.co.uk/products/virus-alerts/)" +109.210.182.162 - - [15/Feb/2011:01:25:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +188.62.238.95 - - [15/Feb/2011:15:06:54 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.45 Safari/534.16" +70.62.126.162 - - [17/Feb/2011:16:19:21 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +82.22.69.148 - - [17/Feb/2011:17:01:39 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +70.42.129.157 - - [17/Feb/2011:19:30:02 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.21 (KHTML, like Gecko) Ubuntu/10.10 Chromium/11.0.673.0 Chrome/11.0.673.0 Safari/534.21" +213.60.86.165 - - [17/Feb/2011:19:33:49 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; es-ES; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 GTB7.1" +139.179.198.114 - - [17/Feb/2011:23:04:56 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; tr; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +80.229.137.89 - - [18/Feb/2011:07:35:07 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +70.190.216.104 - - [19/Feb/2011:02:40:42 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +81.200.10.74 - - [19/Feb/2011:19:03:58 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/default.aspx" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +67.168.131.173 - - [19/Feb/2011:23:57:58 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +77.86.4.34 - - [20/Feb/2011:14:01:05 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +150.101.126.242 - - [21/Feb/2011:03:14:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +190.163.49.54 - - [21/Feb/2011:07:34:45 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +46.1.52.93 - - [21/Feb/2011:12:56:55 +0000] "GET / HTTP/1.1" 304 0 "http://www.downloadjavascripts.com/default.aspx" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b11) Gecko/20100101 Firefox/4.0b11" +77.94.232.43 - - [21/Feb/2011:14:28:59 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.94 Safari/534.13" +158.121.22.130 - - [21/Feb/2011:16:43:53 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10" +173.72.78.233 - - [22/Feb/2011:13:12:08 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.84 Safari/534.13" +187.58.255.215 - - [22/Feb/2011:21:40:06 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +110.75.175.58 - - [23/Feb/2011:04:31:59 +0000] "GET / HTTP/1.1" 200 3739 "-" "Yahoo! Slurp China" +180.150.242.87 - - [23/Feb/2011:11:33:57 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/list/javasitevvv9/Details.aspx" "Mozilla/5.0 (Windows NT 6.1; rv:2.0b11) Gecko/20100101 Firefox/4.0b11" +189.20.216.235 - - [23/Feb/2011:18:51:19 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 ( .NET CLR 3.5.30729; .NET4.0E)" +189.20.216.235 - - [23/Feb/2011:18:51:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 ( .NET CLR 3.5.30729; .NET4.0E)" +81.88.49.3 - - [23/Feb/2011:23:39:06 +0000] "GET / HTTP/1.0" 200 3739 "-" "-" +81.88.49.24 - - [23/Feb/2011:23:39:09 +0000] "GET / HTTP/1.0" 200 3739 "-" "-" +64.231.153.79 - - [24/Feb/2011:05:31:40 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.114 Safari/534.16" +220.253.78.171 - - [24/Feb/2011:05:54:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.82 Safari/534.16" +75.72.241.109 - - [24/Feb/2011:06:06:17 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +208.80.70.128 - - [24/Feb/2011:06:13:29 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +150.101.196.122 - - [24/Feb/2011:06:19:33 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; U; Linux i686; en-AU; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13" +67.174.198.106 - - [24/Feb/2011:06:24:53 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.82 Safari/534.16" +208.57.136.115 - - [24/Feb/2011:06:31:29 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +83.245.192.194 - - [24/Feb/2011:06:38:39 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20" +145.253.32.51 - - [24/Feb/2011:06:50:39 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +24.6.200.120 - - [24/Feb/2011:07:25:03 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +84.92.32.174 - - [24/Feb/2011:07:30:22 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20" +111.69.253.236 - - [24/Feb/2011:07:48:47 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +94.200.129.162 - - [24/Feb/2011:07:57:31 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20" +62.236.54.98 - - [24/Feb/2011:07:58:51 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +89.172.204.212 - - [24/Feb/2011:08:01:23 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +76.173.73.94 - - [24/Feb/2011:08:05:05 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b11) Gecko/20100101 Firefox/4.0b11" +207.6.241.46 - - [24/Feb/2011:08:10:32 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.14) Gecko/20110207 Firefox/3.6.14" +74.68.154.186 - - [24/Feb/2011:08:14:17 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20" +68.225.252.108 - - [24/Feb/2011:08:23:16 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +213.112.231.49 - - [24/Feb/2011:09:15:59 +0000] "GET / HTTP/1.1" 200 3739 "-" "curl/7.16.4 (i386-apple-darwin9.0) libcurl/7.16.4 OpenSSL/0.9.7l zlib/1.2.3" +213.112.231.49 - - [24/Feb/2011:09:16:00 +0000] "GET / HTTP/1.1" 200 3739 "-" "curl/7.16.4 (i386-apple-darwin9.0) libcurl/7.16.4 OpenSSL/0.9.7l zlib/1.2.3" +213.112.231.49 - - [24/Feb/2011:09:16:06 +0000] "GET / HTTP/1.1" 200 3739 "-" "curl/7.16.4 (i386-apple-darwin9.0) libcurl/7.16.4 OpenSSL/0.9.7l zlib/1.2.3" +86.176.100.214 - - [24/Feb/2011:11:00:05 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +87.216.160.189 - - [24/Feb/2011:11:05:32 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +217.28.182.1 - - [24/Feb/2011:11:40:00 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.82 Safari/534.16" +74.112.128.60 - - [24/Feb/2011:11:43:19 +0000] "GET / HTTP/1.0" 200 3739 "-" "Mozilla/5.0 (compatible; Butterfly/1.0; +http://labs.topsy.com/butterfly/) Gecko/2009032608 Firefox/3.0.8" +90.220.101.34 - - [24/Feb/2011:11:43:26 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +95.45.230.102 - - [24/Feb/2011:11:44:39 +0000] "GET / HTTP/1.1" 200 3739 "http://twitter.com/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7 ( .NET CLR 3.5.30729; .NET4.0C)" +86.9.199.94 - - [24/Feb/2011:11:46:12 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +128.240.225.120 - - [24/Feb/2011:11:47:53 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729; .NET4.0E)" +93.83.53.214 - - [24/Feb/2011:11:54:28 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 (.NET CLR 3.5.30729)" +91.154.98.30 - - [24/Feb/2011:12:08:45 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.fi/search?source=ig&hl=fi&rlz=1R2HPNN_fiFI362&q=humingbird+viistokaiku+demo&aq=f&aqi=&aql=&oq=" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6.6; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)" +84.227.67.176 - - [24/Feb/2011:12:08:46 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +192.148.167.100 - - [24/Feb/2011:12:26:46 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0b11pre) Gecko/20110201 Firefox/4.0b11pre" +192.148.167.100 - - [24/Feb/2011:12:27:09 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +202.3.120.9 - - [24/Feb/2011:12:27:11 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686; rv:2.0b12pre) Gecko/20110223 Firefox/4.0b12pre" +121.242.198.2 - - [24/Feb/2011:12:45:19 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +91.155.190.174 - - [24/Feb/2011:12:49:03 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +210.210.41.202 - - [24/Feb/2011:13:00:41 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13" +201.87.96.181 - - [24/Feb/2011:13:26:55 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +18.111.114.34 - - [24/Feb/2011:13:30:14 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.82 Safari/534.16" +70.128.146.39 - - [24/Feb/2011:13:43:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +152.23.127.250 - - [24/Feb/2011:13:49:16 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20" +69.181.71.104 - - [24/Feb/2011:13:52:31 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +80.169.35.118 - - [24/Feb/2011:14:07:19 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +174.96.228.42 - - [24/Feb/2011:16:12:10 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)" +192.150.10.200 - - [24/Feb/2011:19:19:48 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +91.62.145.105 - - [24/Feb/2011:19:22:17 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.82 Safari/534.16" +78.25.39.76 - - [25/Feb/2011:16:07:30 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +89.191.147.123 - - [25/Feb/2011:20:28:19 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +87.162.80.37 - - [25/Feb/2011:20:52:15 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +199.181.135.135 - - [25/Feb/2011:23:41:48 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +70.42.188.130 - - [26/Feb/2011:00:12:02 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.94 Safari/534.13" +114.80.93.73 - - [26/Feb/2011:03:34:37 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322;TencentTraveler)" +88.214.193.166 - - [26/Feb/2011:05:32:45 +0000] "GET / HTTP/1.1" 200 6063 "http://www.whorush.com/search/?q=hid.im" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +80.198.253.204 - - [26/Feb/2011:21:39:07 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.nl/url?sa=t&source=web&cd=1&ved=0CBcQFjAA&url=http%3A%2F%2Fwww.hid.im%2F&rct=j&q=torrent%20into%20image&ei=-XJpTb7XB8boObPs7Z4L&usg=AFQjCNFaT7O6AF0rjcfbralsOlblnMGYxQ" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +83.217.178.230 - - [26/Feb/2011:23:39:07 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729)" +89.114.69.142 - - [27/Feb/2011:17:39:40 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.7.62 Version/11.01" +62.152.158.165 - - [27/Feb/2011:21:57:29 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/ramka/210426/konwerter-plikow-torrent-do-png/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +89.74.55.11 - - [28/Feb/2011:09:02:00 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/ramka/210426/konwerter-plikow-torrent-do-png/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 ( .NET CLR 3.5.30729; .NET4.0E)" +130.79.208.70 - - [28/Feb/2011:12:16:53 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +124.129.145.128 - - [28/Feb/2011:13:09:59 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0)" +62.245.168.190 - - [28/Feb/2011:13:50:26 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +87.152.214.221 - - [28/Feb/2011:18:23:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; de-de) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +66.211.104.160 - - [28/Feb/2011:20:38:26 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41 Safari/534.7" +91.115.61.37 - - [28/Feb/2011:21:50:55 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b12) Gecko/20100101 Firefox/4.0b12" +82.69.122.251 - - [28/Feb/2011:21:55:41 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.30 Safari/532.5" +124.108.98.216 - - [28/Feb/2011:22:21:03 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +130.166.42.233 - - [01/Mar/2011:02:18:47 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.114 Safari/534.16" +68.53.90.250 - - [01/Mar/2011:04:30:12 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5" +217.77.222.161 - - [01/Mar/2011:09:03:05 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +175.144.42.177 - - [01/Mar/2011:13:08:08 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +83.103.31.73 - - [01/Mar/2011:14:53:07 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +66.214.185.59 - - [01/Mar/2011:18:42:46 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +2.100.50.245 - - [01/Mar/2011:22:26:14 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 ( .NET CLR 3.5.30729; .NET4.0E)" +206.169.187.194 - - [02/Mar/2011:20:46:39 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.102 Safari/534.13" +65.75.63.29 - - [02/Mar/2011:21:56:34 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +216.178.40.20 - - [02/Mar/2011:22:21:34 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14" +88.115.32.12 - - [03/Mar/2011:15:01:22 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.14) Gecko/20110218 Firefox/3.6.14" +90.147.122.253 - - [03/Mar/2011:17:00:19 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.23 (KHTML, like Gecko) Ubuntu/10.04 Chromium/11.0.688.0 Chrome/11.0.688.0 Safari/534.23" +64.202.160.65 - - [03/Mar/2011:17:11:28 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13" +189.100.167.62 - - [04/Mar/2011:03:36:51 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/default.aspx" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +88.25.242.197 - - [04/Mar/2011:09:43:44 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.114 Safari/534.16" +24.155.144.5 - - [05/Mar/2011:00:07:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.23 (KHTML, like Gecko) Chrome/11.0.686.3 Safari/534.23" +83.85.185.179 - - [05/Mar/2011:01:24:17 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.14) Gecko/20110221 Ubuntu/10.10 (maverick) Firefox/3.6.14" +67.187.185.213 - - [05/Mar/2011:23:12:44 +0000] "GET / HTTP/1.1" 200 3739 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15" +124.158.79.172 - - [06/Mar/2011:05:37:56 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15" +119.19.6.186 - - [06/Mar/2011:09:19:02 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Chrome/10.0.612.3 Safari/534.15" +83.183.6.164 - - [06/Mar/2011:19:35:53 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +208.80.194.30 - - [07/Mar/2011:10:34:44 +0000] "GET / HTTP/1.0" 200 3739 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Comcast Install 1.0; FunWebProducts; .NET CLR 1.1.4322)" +201.13.136.231 - - [08/Mar/2011:01:34:20 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; pt-br) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +113.96.151.189 - - [08/Mar/2011:02:12:46 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6.4; CIBA; TheWorld)" +87.202.33.27 - - [08/Mar/2011:13:55:02 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)" +202.160.178.198 - - [09/Mar/2011:20:39:54 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp China; http://misc.yahoo.com.cn/help.html)" +184.73.249.120 - - [09/Mar/2011:22:43:02 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13" +180.151.49.130 - - [10/Mar/2011:06:59:50 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10" +97.76.110.210 - - [10/Mar/2011:17:12:41 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729)" +81.65.31.195 - - [10/Mar/2011:19:19:21 +0000] "GET / HTTP/1.1" 200 3739 "http://clonesdir.com/webmaster-clone-scripts/hummingbird-real-time-visitor-tracking/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 ( .NET CLR 3.5.30729)" +129.174.97.34 - - [11/Mar/2011:01:57:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13" +166.137.138.186 - - [11/Mar/2011:01:58:33 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7" +24.5.103.240 - - [11/Mar/2011:20:14:15 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127 Safari/534.16" +63.248.146.82 - - [12/Mar/2011:02:34:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +63.245.216.230 - - [12/Mar/2011:13:39:54 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; Linux i686; rv:2.0b13pre) Gecko/20100101 Firefox/4.0b13pre" +160.75.26.48 - - [12/Mar/2011:16:58:18 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.9.2.9) Gecko/20100913 Firefox/3.6.9 Java/1.6.0_24" +78.36.196.26 - - [12/Mar/2011:17:09:58 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/4.76 [en] (Win98; U)" +87.192.64.68 - - [13/Mar/2011:13:33:57 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15" +94.132.210.90 - - [13/Mar/2011:15:29:15 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; pt-pt) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16" +94.132.208.30 - - [14/Mar/2011:09:28:01 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; pt-pt) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16" +80.64.175.93 - - [14/Mar/2011:18:16:30 +0000] "GET / HTTP/1.1" 200 3739 "-" "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.01" +189.121.234.4 - - [14/Mar/2011:18:38:36 +0000] "GET / HTTP/1.0" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +67.191.204.200 - - [14/Mar/2011:20:24:04 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127 Safari/534.16" +192.155.59.22 - - [14/Mar/2011:20:45:00 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +89.155.216.199 - - [14/Mar/2011:23:22:27 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +174.129.120.222 - - [15/Mar/2011:19:24:47 +0000] "GET / HTTP/1.1" 200 6063 "-" "PostPost/1.0 (+http://postpo.st/crawlers)" +121.97.59.11 - - [16/Mar/2011:09:42:50 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; ICS)" +81.88.49.24 - - [17/Mar/2011:06:57:25 +0000] "GET / HTTP/1.0" 200 3739 "-" "-" +189.121.234.4 - - [17/Mar/2011:18:53:35 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +61.220.35.85 - - [18/Mar/2011:10:43:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.134 Safari/534.16" +69.241.82.132 - - [18/Mar/2011:14:31:09 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15" +95.167.119.216 - - [19/Mar/2011:11:52:59 +0000] "GET / HTTP/1.1" 304 0 "http://hid.im/about/bookmarklet" "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.01" +222.252.71.169 - - [19/Mar/2011:20:29:42 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16" +188.97.240.38 - - [20/Mar/2011:13:22:04 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16" +71.207.46.192 - - [21/Mar/2011:04:37:52 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +203.118.46.149 - - [21/Mar/2011:10:53:42 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +189.195.70.83 - - [21/Mar/2011:20:52:52 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/default.aspx" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.0.19) Gecko/2011012618 Firefox/3.0.19 Flock/2.6.2" +203.112.77.210 - - [22/Mar/2011:11:31:11 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +84.19.53.21 - - [22/Mar/2011:16:41:06 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.co.uk/search?sourceid=chrome&ie=UTF-8&q=hummingbird+stats" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.16 Safari/534.24" +208.80.194.28 - - [22/Mar/2011:16:56:20 +0000] "GET / HTTP/1.0" 200 3739 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts; .NET CLR 1.0.3705; SpamBlockerUtility 4.8.4; ZangoToolbar 4.8.2)" +77.220.131.217 - - [23/Mar/2011:05:28:27 +0000] "GET / HTTP/1.0" 200 6063 "www.saren .ru/" "Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9" +62.244.184.194 - - [23/Mar/2011:11:32:36 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.co.uk/url?sa=t&source=web&cd=1&ved=0CBYQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=hummingbird%20stats&ei=UdqJTcjqKsrLgQeRudC0DQ&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13" +213.61.58.210 - - [23/Mar/2011:15:15:19 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; de-de) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +84.92.26.220 - - [23/Mar/2011:16:26:58 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +204.128.192.33 - - [23/Mar/2011:18:04:16 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.com/url?sa=t&source=web&cd=1&ved=0CBQQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=hummingbird%20stats&ei=HDaKTbutJ5GtgQe-7vjBDQ&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0) Gecko/20100101 Firefox/4.0" +67.186.135.42 - - [23/Mar/2011:20:22:56 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10" +64.124.21.196 - - [23/Mar/2011:20:44:28 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +221.246.173.136 - - [24/Mar/2011:06:00:57 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0" +200.12.27.10 - - [24/Mar/2011:16:14:45 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.com/search?hl=en&client=safari&rls=en&q=hummingbird+stats&aq=f&aqi=g10&aql=&oq=" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; es-es) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +139.103.4.159 - - [24/Mar/2011:18:16:49 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +120.28.204.182 - - [25/Mar/2011:03:12:11 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com.ph/search?hl=tl&q=hid.im+files&aq=f&aqi=&aql=&oq=" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +125.2.133.32 - - [25/Mar/2011:08:43:17 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; U; CPU OS 4_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8F190 Safari/6533.18.5" +77.40.128.239 - - [25/Mar/2011:11:52:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; nn-NO; rv:1.9.2.15) Gecko/20110303 Ubuntu/10.04 (lucid) Firefox/3.6.15" +117.193.7.144 - - [25/Mar/2011:18:17:14 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/list/javasitevvv9/Details.aspx" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 GTB7.1 (.NET CLR 3.5.30729)" +80.216.162.40 - - [25/Mar/2011:23:41:12 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15" +174.129.120.222 - - [26/Mar/2011:01:12:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "PostPost/1.0 (+http://postpo.st/crawlers)" +76.121.96.114 - - [26/Mar/2011:03:30:56 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5" +79.175.77.116 - - [27/Mar/2011:21:03:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +114.160.1.194 - - [28/Mar/2011:03:29:52 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +203.126.164.205 - - [28/Mar/2011:06:45:41 +0000] "GET / HTTP/1.1" 200 3739 "-" "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.7.62 Version/11.01" +203.126.164.205 - - [28/Mar/2011:07:00:42 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +207.250.79.99 - - [28/Mar/2011:14:47:50 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0) Gecko/20100101 Firefox/4.0" +75.126.98.107 - - [28/Mar/2011:19:52:51 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" +113.34.90.1 - - [29/Mar/2011:01:29:56 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +220.255.1.79 - - [29/Mar/2011:02:59:52 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +113.34.90.1 - - [29/Mar/2011:09:57:16 +0000] "GET / HTTP/1.1" 304 0 "http://www.google.co.jp/search?q=humming+bird+demo&btnG=%E6%A4%9C%E7%B4%A2&hl=ja&client=firefox-a&hs=noS&rls=org.mozilla%3Aja%3Aofficial&sa=2" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15" +174.37.190.120 - - [29/Mar/2011:13:42:25 +0000] "GET / HTTP/1.1" 200 6063 "-" "curl/7.21.4 (i386-pc-win32) libcurl/7.21.4 OpenSSL/0.9.8g libssh2/1.2.7" +213.96.103.181 - - [29/Mar/2011:14:39:46 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +207.161.209.10 - - [29/Mar/2011:15:16:15 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +24.6.14.192 - - [29/Mar/2011:23:46:39 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +121.241.181.1 - - [30/Mar/2011:11:37:47 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15" +89.174.100.249 - - [31/Mar/2011:07:58:18 +0000] "GET / HTTP/1.0" 304 0 "http://www.google.pl/search?aq=f&sourceid=chrome&ie=UTF-8&q=hummingbird+stats" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +38.104.231.230 - - [31/Mar/2011:17:46:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +69.29.204.176 - - [01/Apr/2011:05:16:51 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +69.29.204.176 - - [01/Apr/2011:05:16:52 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +212.6.144.254 - - [01/Apr/2011:14:15:55 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +67.115.118.5 - - [02/Apr/2011:15:57:37 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)" +89.134.54.52 - - [03/Apr/2011:13:46:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)" +82.181.26.163 - - [03/Apr/2011:14:43:57 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.25 Safari/534.24" +72.188.58.250 - - [04/Apr/2011:00:40:06 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 ( .NET CLR 3.5.30729; .NET4.0C)" +175.157.167.1 - - [04/Apr/2011:04:24:42 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +201.81.110.220 - - [04/Apr/2011:11:18:36 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +109.105.186.114 - - [04/Apr/2011:13:40:41 +0000] "GET / HTTP/1.1" 200 6063 "http://wow-dark.ru/forum/viewtopic.php?t=2972&start=405" "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.7.62 Version/11.01" +58.61.164.139 - - [04/Apr/2011:13:55:01 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +71.88.126.169 - - [04/Apr/2011:14:43:47 +0000] "GET / HTTP/1.1" 200 3739 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +12.228.190.1 - - [04/Apr/2011:18:17:14 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +203.24.1.137 - - [05/Apr/2011:01:46:54 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27" +82.239.132.143 - - [05/Apr/2011:18:34:12 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.721.0 Safari/534.27" +122.166.117.130 - - [06/Apr/2011:08:38:32 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +94.251.185.19 - - [06/Apr/2011:15:24:02 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0" +217.153.99.42 - - [06/Apr/2011:15:32:57 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +77.237.20.129 - - [06/Apr/2011:15:36:27 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; rv:2.2a1pre) Gecko/20110405 Firefox/4.2a1pre" +178.218.224.3 - - [06/Apr/2011:16:18:27 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0" +212.4.142.66 - - [06/Apr/2011:16:25:49 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.7.62 Version/11.01" +89.74.157.166 - - [06/Apr/2011:16:35:59 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 GTB7.1" +91.90.61.89 - - [06/Apr/2011:16:51:45 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +66.211.104.160 - - [06/Apr/2011:17:09:28 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.94 Safari/534.13" +83.8.172.193 - - [06/Apr/2011:17:12:27 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +83.30.7.173 - - [06/Apr/2011:17:15:25 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +94.251.191.226 - - [06/Apr/2011:17:28:50 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +83.175.156.22 - - [06/Apr/2011:17:31:53 +0000] "GET / HTTP/1.0" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +83.24.229.46 - - [06/Apr/2011:17:37:06 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +77.252.157.43 - - [06/Apr/2011:17:55:55 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +83.29.78.203 - - [06/Apr/2011:18:01:53 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +85.221.135.200 - - [06/Apr/2011:18:19:23 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +91.206.210.241 - - [06/Apr/2011:18:40:58 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +150.254.145.96 - - [06/Apr/2011:19:01:57 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.7.62 Version/11.01" +78.8.216.131 - - [06/Apr/2011:19:05:13 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/powiazane/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +83.6.164.169 - - [06/Apr/2011:19:27:55 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +82.210.158.183 - - [06/Apr/2011:19:34:30 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0" +178.37.180.204 - - [06/Apr/2011:19:39:45 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0" +83.6.6.40 - - [06/Apr/2011:19:59:15 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +195.117.37.2 - - [06/Apr/2011:20:16:12 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +77.253.251.14 - - [06/Apr/2011:21:03:12 +0000] "GET / HTTP/1.1" 304 0 "http://www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +178.215.201.132 - - [06/Apr/2011:21:16:47 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +62.61.46.108 - - [06/Apr/2011:21:49:03 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +87.99.38.151 - - [06/Apr/2011:21:52:52 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.7.62 Version/11.01" +150.254.143.22 - - [06/Apr/2011:22:07:09 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +85.222.43.154 - - [06/Apr/2011:22:26:56 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.7.62 Version/11.01" +77.237.14.85 - - [07/Apr/2011:00:06:58 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +156.17.234.17 - - [07/Apr/2011:02:03:17 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +81.88.49.40 - - [07/Apr/2011:08:31:27 +0000] "GET / HTTP/1.0" 200 3739 "-" "-" +217.74.64.220 - - [07/Apr/2011:09:58:42 +0000] "GET / HTTP/1.1" 200 6063 "http://www.facebook.com/l.php?u=http%3A%2F%2Fhid.im%2F&h=f206f" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13" +81.64.201.91 - - [07/Apr/2011:14:00:33 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +91.150.220.27 - - [07/Apr/2011:15:14:26 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +189.179.123.104 - - [07/Apr/2011:17:55:16 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +89.72.27.77 - - [07/Apr/2011:19:48:44 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.9.2.13) Gecko/20101225 Firefox/3.6.13 (Swiftfox)" +94.254.80.130 - - [08/Apr/2011:00:09:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +72.188.58.250 - - [08/Apr/2011:00:43:29 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 ( .NET CLR 3.5.30729; .NET4.0C)" +210.24.172.163 - - [08/Apr/2011:04:35:23 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +115.193.189.87 - - [08/Apr/2011:12:14:44 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.04 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16" +147.31.105.181 - - [08/Apr/2011:14:11:46 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +67.195.110.152 - - [09/Apr/2011:05:17:35 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +65.122.12.41 - - [09/Apr/2011:07:56:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +122.117.177.77 - - [09/Apr/2011:12:02:34 +0000] "GET / HTTP/1.1" 200 6063 "http://www.soft4fun.net/bbs/hidden-bt-torrent-download-url.htm" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.6; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C)" +84.160.192.28 - - [09/Apr/2011:20:03:57 +0000] "GET / HTTP/1.1" 200 3739 "http://increaseyourgeek.wordpress.com/2010/06/30/more-node-js-awesomesauce/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +163.118.113.70 - - [09/Apr/2011:23:37:56 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.29+ (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +128.194.132.227 - - [10/Apr/2011:01:48:37 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +119.224.101.190 - - [10/Apr/2011:08:40:02 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/toolbar/litebar.php?device=chromebar&version=chromebar%202.9.8.1&ts=1302423371" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +78.84.113.185 - - [10/Apr/2011:12:50:19 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +141.209.230.104 - - [10/Apr/2011:22:01:46 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +206.248.206.4 - - [11/Apr/2011:15:32:55 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +217.18.21.2 - - [11/Apr/2011:16:33:58 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.16) Gecko/20110323 Ubuntu/9.10 (karmic) Firefox/3.6.16" +66.220.149.250 - - [12/Apr/2011:04:36:35 +0000] "GET / HTTP/1.1" 206 6063 "-" "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" +202.60.62.100 - - [12/Apr/2011:08:49:27 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4" +82.144.21.36 - - [12/Apr/2011:09:57:05 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +217.128.1.233 - - [12/Apr/2011:12:32:03 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +194.251.159.2 - - [12/Apr/2011:15:42:13 +0000] "GET / HTTP/1.1" 304 0 "http://webification.com/real-time-web-stats-hummingbird" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16" +95.223.241.69 - - [12/Apr/2011:19:24:57 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +76.182.240.209 - - [12/Apr/2011:23:02:24 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +195.205.87.25 - - [13/Apr/2011:11:33:31 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; pl-PL; rv:1.9.2.10) Gecko/20100915 Ubuntu/10.04 (lucid) Firefox/3.6.10" +85.74.225.156 - - [13/Apr/2011:12:22:29 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12" +154.5.186.117 - - [14/Apr/2011:04:11:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.43 Safari/534.24" +78.186.235.115 - - [14/Apr/2011:11:15:17 +0000] "GET / HTTP/1.1" 200 6063 "http://www.chip.com.tr/konu/png-dosyalari-icindeki-gizli-torrent-ler_14019.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +79.112.92.248 - - [14/Apr/2011:11:33:45 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +68.156.145.10 - - [14/Apr/2011:17:22:26 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +88.159.68.183 - - [14/Apr/2011:19:42:25 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.29 (KHTML, like Gecko) Chrome/12.0.733.0 Safari/534.29" +77.85.5.138 - - [14/Apr/2011:20:27:16 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +212.187.112.176 - - [15/Apr/2011:09:42:38 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Win64; x64; Trident/4.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)" +218.213.130.140 - - [16/Apr/2011:04:48:42 +0000] "GET / HTTP/1.1" 200 6063 "-" "ichiro/4.0 (http://help.goo.ne.jp/door/crawler.html)" +97.126.62.197 - - [17/Apr/2011:00:38:04 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +125.175.247.108 - - [17/Apr/2011:06:34:37 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +60.231.18.57 - - [17/Apr/2011:09:15:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +122.173.229.99 - - [18/Apr/2011:07:51:31 +0000] "GET / HTTP/1.1" 200 3739 "http://www.downloadjavascripts.com/a443cf60-4479-4c40-9c7c-41f86e925c54cad2fd8b-2c99-4b06-84c9-bb12214237db8760e9c4-2ccb-4137-a902-8c80b070d26e.aspx" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +210.251.250.1 - - [18/Apr/2011:11:47:11 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +72.76.158.233 - - [18/Apr/2011:12:25:38 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +113.67.92.215 - - [19/Apr/2011:12:35:31 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +71.228.19.24 - - [19/Apr/2011:16:06:52 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +86.96.226.85 - - [19/Apr/2011:18:26:10 +0000] "GET / HTTP/1.1" 200 3739 "http://www.clonestop.com/webmasters/analytics-clone/1605-hummingbird-free-real-time-web-traffic-software.html" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +8.7.228.252 - - [20/Apr/2011:05:29:04 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +118.137.2.40 - - [20/Apr/2011:06:56:05 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +67.224.89.202 - - [20/Apr/2011:15:48:38 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0) Gecko/20100101 Firefox/4.0" +216.145.71.254 - - [20/Apr/2011:17:18:28 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +140.107.10.62 - - [21/Apr/2011:02:42:49 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.0; rv:2.0) Gecko/20100101 Firefox/4.0" +77.196.141.121 - - [21/Apr/2011:05:35:06 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +114.91.202.218 - - [21/Apr/2011:14:42:11 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24" +87.111.149.73 - - [21/Apr/2011:22:45:01 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5" +71.61.56.77 - - [22/Apr/2011:04:31:28 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" +79.132.112.150 - - [22/Apr/2011:11:04:51 +0000] "GET / HTTP/1.1" 200 6063 "http://simbirsk-ktv.ru/forum/viewtopic.php?t=22615" "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.8.131 Version/11.10" +153.65.16.10 - - [22/Apr/2011:14:16:14 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +78.149.254.124 - - [22/Apr/2011:19:08:33 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +24.111.55.7 - - [23/Apr/2011:04:02:28 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/4.0" +109.188.238.158 - - [23/Apr/2011:13:00:08 +0000] "GET / HTTP/1.1" 200 6063 "http://cdn.pearltrees.com/s/prefetch/load?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13 ChromePlus/1.6.0.0" +72.19.68.76 - - [23/Apr/2011:14:14:24 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +69.254.43.70 - - [23/Apr/2011:20:44:50 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24" +76.168.175.210 - - [23/Apr/2011:20:54:06 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24" +58.37.213.6 - - [24/Apr/2011:05:48:18 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +24.220.184.63 - - [24/Apr/2011:06:51:44 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +66.108.110.177 - - [24/Apr/2011:15:13:24 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +80.222.21.145 - - [24/Apr/2011:15:14:48 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.fi/url?sa=t&source=web&cd=4&ved=0CEIQFjAD&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=humminbird%20demo&ei=WD60TdPhEcKVOte2_PII&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Windows; U; Windows NT 6.0; fi; rv:1.9.2.16) Gecko/20110319 AskTbLMW/3.11.3.15590 Firefox/3.6.16 (.NET CLR 3.5.30729)" +208.71.199.206 - - [25/Apr/2011:11:53:30 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.2; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +206.217.79.178 - - [25/Apr/2011:18:02:15 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.5 Safari/534.30" +69.196.186.123 - - [26/Apr/2011:03:21:21 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +93.114.47.254 - - [26/Apr/2011:04:56:59 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4" +94.112.16.172 - - [26/Apr/2011:08:35:30 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +83.227.173.251 - - [26/Apr/2011:15:03:45 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +156.34.227.71 - - [27/Apr/2011:00:32:44 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +125.55.5.64 - - [27/Apr/2011:01:33:07 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; YTB730; GTB6.6; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; (R1 1.6); msn Optimized IE build03;JP; Dealio Toolbar 3.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; msn Optimized IE build03;JP)" +188.244.99.217 - - [27/Apr/2011:07:31:29 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +178.29.11.159 - - [27/Apr/2011:12:04:11 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +206.217.79.178 - - [27/Apr/2011:18:23:34 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0" +66.183.77.136 - - [27/Apr/2011:20:38:01 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +187.78.115.152 - - [28/Apr/2011:15:14:15 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57 Safari/534.24" +216.166.0.66 - - [29/Apr/2011:20:58:47 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +64.236.138.3 - - [29/Apr/2011:22:18:49 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +63.209.137.11 - - [30/Apr/2011:04:33:56 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +123.192.49.219 - - [01/May/2011:12:11:21 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57 Safari/534.24" +213.93.189.68 - - [01/May/2011:14:02:08 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57 Safari/534.24" +93.79.162.2 - - [01/May/2011:20:06:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 sputnik 2.3.0.102" +196.15.16.20 - - [02/May/2011:08:33:30 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16" +124.171.224.247 - - [03/May/2011:07:39:21 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16" +212.187.112.176 - - [03/May/2011:10:00:04 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +99.226.45.18 - - [03/May/2011:11:31:55 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +82.67.230.154 - - [03/May/2011:17:36:22 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)" +189.203.146.76 - - [03/May/2011:19:01:54 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.04 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16" +88.175.210.174 - - [03/May/2011:20:01:21 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.1.16) Gecko/20110430 Iceweasel/3.5.16 (like Firefox/3.5.16) FirePHP/0.5" +64.160.161.107 - - [05/May/2011:23:24:00 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +24.255.244.231 - - [06/May/2011:04:29:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +216.239.73.15 - - [07/May/2011:01:07:00 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57 Safari/534.24" +189.35.78.241 - - [07/May/2011:11:02:51 +0000] "GET / HTTP/1.1" 304 0 "http://www.hid.im/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24" +67.195.115.156 - - [07/May/2011:23:25:49 +0000] "GET / HTTP/1.0" 200 3739 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +24.39.156.21 - - [08/May/2011:01:32:17 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17" +97.74.24.226 - - [08/May/2011:05:57:52 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +203.209.252.15 - - [08/May/2011:08:07:27 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp China; http://misc.yahoo.com.cn/help.html)" +221.170.25.185 - - [08/May/2011:18:12:14 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24" +207.46.204.157 - - [09/May/2011:04:38:04 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.1.4325; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30707; InfoPath.2)" +81.229.83.32 - - [09/May/2011:06:08:39 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57 Safari/534.24" +69.253.201.204 - - [10/May/2011:02:09:17 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +125.22.193.162 - - [10/May/2011:10:18:04 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +222.44.41.33 - - [11/May/2011:01:41:35 +0000] "GET / HTTP/1.0" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24" +71.232.112.106 - - [11/May/2011:03:52:30 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=hummingbirdstats&qscrl=1" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24" +80.153.47.157 - - [12/May/2011:12:03:55 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +81.110.93.13 - - [12/May/2011:15:06:36 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.0; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +77.100.70.22 - - [13/May/2011:16:05:14 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24" +98.202.143.212 - - [13/May/2011:20:05:10 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +59.161.25.110 - - [14/May/2011:04:07:32 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +64.233.172.18 - - [14/May/2011:17:49:00 +0000] "GET / HTTP/1.1" 200 6063 "-" "AppEngine-Google; (+http://code.google.com/appengine; appid: 239ch98rbvpy)" +83.105.22.35 - - [14/May/2011:19:36:58 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" +92.45.177.169 - - [15/May/2011:10:32:44 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +68.186.242.176 - - [15/May/2011:18:44:05 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/toolbar/litebar.php?device=chromebar&version=chromebar%202.9.8.1&ts=1305483291" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.35 (KHTML, like Gecko) Chrome/13.0.761.0 Safari/534.35" +70.232.160.130 - - [15/May/2011:19:52:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "iTunes/10.2.1 (Macintosh; Intel Mac OS X 10.6.7) AppleWebKit/533.20.25" +92.103.127.226 - - [16/May/2011:13:37:58 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27 JolicloudResolver/2.0" +95.78.151.61 - - [16/May/2011:18:30:11 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.53 Safari/534.30" +85.93.198.219 - - [17/May/2011:11:45:23 +0000] "GET / HTTP/1.1" 200 3739 "http://www.webstockbox.com/page/4/" "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +128.238.142.40 - - [17/May/2011:16:36:45 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +24.103.253.245 - - [17/May/2011:18:48:24 +0000] "GET / HTTP/1.1" 200 3739 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +209.71.202.61 - - [17/May/2011:19:22:50 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +77.220.131.217 - - [18/May/2011:00:28:24 +0000] "GET / HTTP/1.0" 200 6063 "http://www.fanfootball ru/" "Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9" +213.93.229.201 - - [18/May/2011:11:29:13 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +81.184.2.251 - - [18/May/2011:11:32:18 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +67.202.27.147 - - [19/May/2011:00:09:26 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/2.0.1" +78.109.82.93 - - [19/May/2011:16:26:33 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27 JolicloudResolver/2.0" +207.164.32.139 - - [19/May/2011:18:16:35 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +174.120.151.194 - - [20/May/2011:01:48:39 +0000] "GET / HTTP/1.1" 200 6063 "-" "-" +120.151.255.214 - - [20/May/2011:07:13:39 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:13:44 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:13:46 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:13:48 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:13:57 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:00 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:00 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:03 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:03 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:05 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:13 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:15 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:23 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:25 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +120.151.255.214 - - [20/May/2011:07:14:26 +0000] "GET / HTTP/1.1" 200 3739 "-" "JoeDog/1.00 [en] (X11; I; Siege 2.67)" +67.4.131.173 - - [20/May/2011:19:41:24 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +199.126.236.235 - - [21/May/2011:03:21:34 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +121.242.80.130 - - [22/May/2011:10:17:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" +67.161.91.161 - - [23/May/2011:11:05:51 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +207.239.107.3 - - [23/May/2011:23:56:31 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +178.236.40.236 - - [24/May/2011:12:47:05 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/4.0" +205.210.254.15 - - [24/May/2011:16:20:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27" +63.126.72.25 - - [24/May/2011:19:39:05 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +222.247.56.11 - - [25/May/2011:03:20:13 +0000] "GET / HTTP/1.1" 200 3739 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +83.137.191.1 - - [25/May/2011:12:41:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)" +78.86.205.83 - - [25/May/2011:14:17:23 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +89.240.197.172 - - [25/May/2011:16:08:06 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +77.255.15.186 - - [25/May/2011:21:23:03 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.71 Safari/534.24" +71.237.236.36 - - [25/May/2011:22:54:57 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.36 (KHTML, like Gecko) Ubuntu/11.04 Chromium/13.0.769.0 Chrome/13.0.769.0 Safari/534.36" +98.116.14.66 - - [25/May/2011:23:11:59 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +193.106.136.46 - - [26/May/2011:14:34:06 +0000] "GET / HTTP/1.0" 200 6063 "http://lookserial.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.6 (build 01425); MRSPUTNIK 1, 5, 0, 19 SW)" +66.235.124.20 - - [27/May/2011:06:08:57 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (compatible; Ask Jeeves/Teoma; +http://about.ask.com/en/docs/about/webmasters.shtml)" +94.227.57.248 - - [27/May/2011:08:30:42 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_1 like Mac OS X; nl-nl) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8G4 Safari/6533.18.5" +68.189.173.61 - - [27/May/2011:14:30:35 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/toolbar/litebar.php?device=chromebar&version=chromebar%203.5.18.1&ts=1306247102" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.60 Safari/534.30" +184.160.164.190 - - [27/May/2011:14:48:41 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +84.197.196.17 - - [27/May/2011:16:58:21 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30" +61.135.167.74 - - [27/May/2011:20:19:20 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +115.252.16.129 - - [27/May/2011:20:29:12 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/11.04 Chromium/11.0.696.68 Chrome/11.0.696.68 Safari/534.24" +92.41.79.213 - - [28/May/2011:07:39:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-gb) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5" +70.74.72.225 - - [29/May/2011:08:01:00 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +88.117.109.128 - - [29/May/2011:16:30:20 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +99.67.168.214 - - [29/May/2011:19:24:57 +0000] "GET / HTTP/1.1" 200 6063 "http://www.sitestouse.com/hid-im-hide-torrents-inside-an-image-file/" "Mozilla/5.0 (Linux; U; Android 2.1-update1; en-us; T-Mobile_Espresso Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17" +99.67.168.214 - - [29/May/2011:19:26:03 +0000] "GET / HTTP/1.1" 200 6063 "http://www.sitestouse.com/hid-im-hide-torrents-inside-an-image-file/" "Mozilla/5.0 (Linux; U; Android 2.1-update1; en-us; T-Mobile_Espresso Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17" +90.184.193.155 - - [29/May/2011:19:45:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +70.70.34.250 - - [29/May/2011:20:55:26 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http://www.hid.im/" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8C148" +91.44.89.118 - - [30/May/2011:13:56:25 +0000] "GET / HTTP/1.1" 200 3739 "http://demo.hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; de-de) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +219.78.197.39 - - [30/May/2011:14:03:23 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16" +183.3.249.54 - - [30/May/2011:14:15:15 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.8.131 Version/11.11" +67.183.68.36 - - [31/May/2011:13:48:33 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +80.220.79.86 - - [31/May/2011:18:28:06 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +72.233.2.104 - - [31/May/2011:21:48:09 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.71 Safari/534.24" +173.167.121.5 - - [01/Jun/2011:06:22:59 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +122.116.52.125 - - [01/Jun/2011:07:31:37 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +212.140.241.195 - - [01/Jun/2011:14:16:22 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.772.0 Safari/535.1" +58.11.98.171 - - [02/Jun/2011:16:49:11 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.71 Safari/534.24" +90.195.174.46 - - [02/Jun/2011:22:26:37 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +92.249.127.111 - - [02/Jun/2011:23:40:44 +0000] "GET / HTTP/1.0" 200 6063 "http://pincode.mobi/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT) ::ELNSB50::000061100320025802a00111000000000507000900000000" +70.52.114.26 - - [04/Jun/2011:22:19:27 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.71 Safari/534.24" +81.154.114.109 - - [05/Jun/2011:22:30:46 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.71 Safari/534.24" +217.243.205.226 - - [06/Jun/2011:11:09:21 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +98.250.50.25 - - [06/Jun/2011:14:37:29 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17" +187.78.119.32 - - [06/Jun/2011:21:22:10 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.71 Safari/534.24" +92.249.127.111 - - [07/Jun/2011:09:46:23 +0000] "GET / HTTP/1.0" 200 6063 "http://pincode.mobi/" "Mozilla/4.0 (compatible; Powermarks/3.5; Windows 95/98/2000/NT)" +92.249.127.111 - - [07/Jun/2011:22:46:41 +0000] "GET / HTTP/1.0" 200 6063 "http://site47.ru/" "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.1.4322)" +68.185.180.102 - - [07/Jun/2011:22:48:27 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +95.37.37.232 - - [08/Jun/2011:00:16:45 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.91 Safari/534.30" +70.90.117.211 - - [08/Jun/2011:18:09:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.77 Safari/534.24" +88.165.228.60 - - [08/Jun/2011:20:13:31 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +79.53.222.253 - - [08/Jun/2011:22:24:10 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; it-it) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5" +72.160.159.247 - - [09/Jun/2011:05:57:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.77 Safari/534.24" +115.238.86.179 - - [10/Jun/2011:00:33:43 +0000] "GET / HTTP/1.1" 200 6063 "-" "Nokia3108/1.0 (03.01) Profile/MIDP-1.0 Configuration/CLDC-1.0" +66.249.82.2 - - [10/Jun/2011:13:00:56 +0000] "GET / HTTP/1.1" 200 3739 "http://translate.googleusercontent.com/translate_c?hl=sk&prev=/search%3Fq%3Dhummingbird%26hl%3Dsk%26biw%3D1259%26bih%3D823%26prmd%3Divns&rurl=translate.google.sk&sl=en&u=http://projects.nuttnet.net/hummingbird/&usg=ALkJrhi0zSwlvIyNTN_Q80XZZYaXRzNoag" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6.3; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729),gzip(gfe) (via translate.google.com)" +84.92.165.189 - - [10/Jun/2011:19:43:49 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +193.106.136.49 - - [12/Jun/2011:04:10:17 +0000] "GET / HTTP/1.0" 200 6063 "http://hetraining.ru/news.php?readmore=390" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Deepnet Explorer)" +95.118.62.91 - - [12/Jun/2011:11:06:07 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20110516 Firefox/4.0.1" +82.47.5.64 - - [12/Jun/2011:16:16:17 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)" +78.167.147.122 - - [13/Jun/2011:06:33:01 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24" +121.243.227.98 - - [14/Jun/2011:09:41:31 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +109.206.103.2 - - [14/Jun/2011:18:28:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +67.138.234.46 - - [14/Jun/2011:22:15:17 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +193.106.136.40 - - [14/Jun/2011:23:22:33 +0000] "GET / HTTP/1.0" 200 6063 "http://sbrg.vndv.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)" +90.203.172.3 - - [14/Jun/2011:23:25:00 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7) AppleWebKit/534.42 (KHTML, like Gecko) Version/5.1 Safari/534.42" +98.223.183.149 - - [15/Jun/2011:06:15:18 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.91 Safari/534.30" +89.37.68.13 - - [15/Jun/2011:09:40:39 +0000] "GET / HTTP/1.1" 200 3739 "http://www.google.ro/url?sa=t&source=web&cd=1&sqi=2&ved=0CBcQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=hummingbird%20stats&ei=E374TZfuFY7Iswa_4uGKCQ&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +62.164.161.18 - - [15/Jun/2011:11:03:15 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +87.234.224.68 - - [15/Jun/2011:11:52:31 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.91 Safari/534.30" +193.106.136.56 - - [15/Jun/2011:21:26:07 +0000] "GET / HTTP/1.0" 200 6063 "http://pugachev.net/" "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95)" +92.249.127.111 - - [15/Jun/2011:22:13:01 +0000] "GET / HTTP/1.0" 200 6063 "http://warezsklad.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" +92.249.127.111 - - [16/Jun/2011:03:06:52 +0000] "GET / HTTP/1.0" 200 6063 "http://segol.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Update a; AOL 6.0; Windows 98)" +174.51.4.134 - - [16/Jun/2011:13:16:58 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +92.249.127.111 - - [16/Jun/2011:16:14:06 +0000] "GET / HTTP/1.0" 200 6063 "http://warezsklad.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT) ::ELNSB50::000061100320025802a00111000000000507000900000000" +69.248.189.36 - - [16/Jun/2011:23:32:59 +0000] "GET / HTTP/1.1" 200 6063 "http://nuttnet.net/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.91 Safari/534.30" +98.237.210.12 - - [16/Jun/2011:23:37:12 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.28 (KHTML, like Gecko) Chrome/12.0.725.0 Safari/534.28" +88.249.191.245 - - [17/Jun/2011:11:22:21 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +140.174.10.252 - - [17/Jun/2011:17:39:16 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.91 Safari/534.30" +201.216.254.193 - - [17/Jun/2011:21:53:05 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +92.228.62.178 - - [18/Jun/2011:01:24:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.773.0 Safari/535.1" +92.228.62.178 - - [18/Jun/2011:01:24:24 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.773.0 Safari/535.1" +89.176.249.254 - - [18/Jun/2011:08:36:20 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +86.130.19.174 - - [18/Jun/2011:17:30:51 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1" +70.176.105.10 - - [19/Jun/2011:05:56:03 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.2; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" +86.176.203.18 - - [19/Jun/2011:13:11:44 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +67.195.115.157 - - [20/Jun/2011:02:58:12 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +64.236.4.133 - - [21/Jun/2011:09:49:57 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +85.101.219.51 - - [21/Jun/2011:10:44:07 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +213.160.22.165 - - [21/Jun/2011:11:06:18 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +67.217.170.96 - - [21/Jun/2011:14:50:05 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" +69.221.171.92 - - [21/Jun/2011:16:51:40 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1" +94.175.97.184 - - [21/Jun/2011:21:45:49 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +67.84.156.172 - - [22/Jun/2011:03:30:23 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17" +76.190.236.239 - - [22/Jun/2011:12:54:24 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +208.97.59.52 - - [23/Jun/2011:21:29:41 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0" +69.163.208.189 - - [24/Jun/2011:07:27:18 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.32 Safari/535.1" +74.201.117.226 - - [24/Jun/2011:22:34:56 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1; StumbleUpon; noc@stumbleupon.com) Gecko/20100101 Firefox/4.0.1" +59.149.113.156 - - [25/Jun/2011:14:29:08 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11" +46.105.24.61 - - [25/Jun/2011:23:34:58 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +58.11.93.3 - - [26/Jun/2011:15:50:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +94.112.19.57 - - [27/Jun/2011:15:32:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)" +208.80.194.36 - - [27/Jun/2011:19:39:49 +0000] "GET / HTTP/1.0" 200 3739 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; sbcydsl 3.12; YPC 3.2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +98.189.74.36 - - [27/Jun/2011:23:15:36 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.32 Safari/535.1" +46.145.211.52 - - [28/Jun/2011:12:08:12 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +93.48.249.127 - - [29/Jun/2011:00:30:43 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.30 Safari/534.30" +217.172.180.18 - - [29/Jun/2011:03:15:58 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" +208.78.24.67 - - [29/Jun/2011:15:47:11 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/10.04 Chromium/12.0.742.91 Chrome/12.0.742.91 Safari/534.30" +67.18.217.74 - - [29/Jun/2011:17:44:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0" +84.32.45.97 - - [30/Jun/2011:21:21:16 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1" +79.117.149.172 - - [30/Jun/2011:21:21:42 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1" +173.75.26.249 - - [30/Jun/2011:22:59:11 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +212.87.32.10 - - [01/Jul/2011:15:01:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +74.199.102.139 - - [02/Jul/2011:01:16:53 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-US) AppleWebKit/534.21 (KHTML, like Gecko) Chrome/11.0.681.0 Safari/534.21" +218.213.136.254 - - [02/Jul/2011:12:11:06 +0000] "GET / HTTP/1.1" 200 3739 "-" "DoCoMo/2.0 P900i(c100;TB;W24H11) (compatible; ichiro/mobile goo; +http://help.goo.ne.jp/help/article/1142/)" +174.28.76.96 - - [02/Jul/2011:20:53:46 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" +78.144.221.37 - - [03/Jul/2011:08:26:16 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1" +67.195.111.230 - - [03/Jul/2011:12:56:37 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +71.231.192.223 - - [04/Jul/2011:14:53:36 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.0.2 Mobile/9A5248d Safari/6533.18.5" +46.105.24.61 - - [05/Jul/2011:00:50:54 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +189.83.92.215 - - [05/Jul/2011:01:01:24 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24" +24.23.164.181 - - [05/Jul/2011:06:59:42 +0000] "GET / HTTP/1.1" 200 6063 "http://forums.steampowered.com/forums/showthread.php?t=920892" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" +195.13.40.75 - - [05/Jul/2011:08:30:06 +0000] "GET / HTTP/1.0" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +209.234.229.21 - - [05/Jul/2011:17:36:47 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1" +88.88.131.128 - - [06/Jul/2011:10:59:23 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +173.172.71.65 - - [07/Jul/2011:04:35:01 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +149.157.1.180 - - [07/Jul/2011:14:31:47 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +193.106.136.58 - - [07/Jul/2011:14:45:55 +0000] "GET / HTTP/1.0" 200 6063 "http://stillaz.ya.ru/replies.xml?item_no=2" "Opera/8.01 (Windows NT 5.1)" +71.197.232.165 - - [08/Jul/2011:00:51:57 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/20100101 Firefox/5.0" +65.49.68.165 - - [08/Jul/2011:00:56:14 +0000] "GET / HTTP/1.0" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.77 Safari/534.24 ChromePlus/1.6.2.0" +92.26.144.193 - - [08/Jul/2011:12:18:28 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19 ( .NET CLR 3.5.30729; .NET4.0E)" +152.62.109.57 - - [08/Jul/2011:16:17:54 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +68.12.153.52 - - [08/Jul/2011:22:13:05 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/11.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30" +189.33.72.3 - - [09/Jul/2011:23:31:17 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +213.219.124.3 - - [10/Jul/2011:17:26:31 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5" +24.4.125.140 - - [11/Jul/2011:14:09:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +94.193.205.241 - - [11/Jul/2011:18:15:26 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30" +59.41.121.129 - - [12/Jul/2011:04:13:05 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com.mx/search?q=HID&hl=es&prmd=ivns&ei=_cYbTqGlL--dmQWs2ejLBw&start=60&sa=N" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)" +180.151.49.130 - - [12/Jul/2011:14:44:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0" +75.24.81.225 - - [12/Jul/2011:16:18:30 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" +190.2.40.166 - - [12/Jul/2011:21:00:20 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +46.105.24.61 - - [14/Jul/2011:16:45:13 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +200.80.198.7 - - [14/Jul/2011:21:42:17 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +80.11.94.212 - - [15/Jul/2011:07:22:03 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +108.80.118.198 - - [15/Jul/2011:07:59:26 +0000] "GET / HTTP/1.1" 200 3739 "http://www.delicious.com/tag/visualization?page=3" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +89.154.97.81 - - [15/Jul/2011:09:46:57 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +77.107.139.185 - - [15/Jul/2011:14:39:24 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.814.0 Safari/535.1" +174.47.83.122 - - [15/Jul/2011:15:01:05 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0" +190.26.38.51 - - [16/Jul/2011:03:16:25 +0000] "GET / HTTP/1.1" 200 6063 "http://zootool.com/watch/as5oh1/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +112.78.192.167 - - [16/Jul/2011:11:27:55 +0000] "GET / HTTP/1.0" 200 3739 "-" "lwp-trivial/1.35" +91.117.34.47 - - [17/Jul/2011:11:59:11 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +70.78.52.92 - - [18/Jul/2011:01:27:19 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +93.85.241.34 - - [18/Jul/2011:08:19:05 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +188.94.209.227 - - [18/Jul/2011:12:55:41 +0000] "GET / HTTP/1.0" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0" +95.147.140.157 - - [18/Jul/2011:21:58:06 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +110.168.120.248 - - [19/Jul/2011:07:35:27 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +188.177.142.170 - - [19/Jul/2011:13:00:29 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +200.121.140.213 - - [19/Jul/2011:14:57:04 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +89.182.2.211 - - [19/Jul/2011:15:55:56 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0.1) Gecko/20100101 Firefox/5.0.1" +199.89.103.11 - - [19/Jul/2011:18:59:44 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/2011050305 Firefox/3.6.17ms1" +88.234.234.99 - - [20/Jul/2011:10:53:33 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/20100101 Firefox/5.0" +83.22.253.104 - - [20/Jul/2011:12:07:36 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/ramka/210426/konwerter-plikow-torrent-do-png/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13" +46.105.24.61 - - [20/Jul/2011:15:09:20 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +174.47.83.122 - - [20/Jul/2011:15:25:30 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; MS-RTC LM 8; BRI/1)" +174.47.83.122 - - [20/Jul/2011:15:26:08 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; MS-RTC LM 8; BRI/1)" +98.169.65.87 - - [21/Jul/2011:00:43:15 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +202.7.107.76 - - [21/Jul/2011:03:00:48 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0" +110.168.105.146 - - [21/Jul/2011:09:52:30 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +113.166.44.3 - - [21/Jul/2011:10:14:42 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http://www.hid.im/" "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8C148" +216.213.24.11 - - [21/Jul/2011:15:22:34 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0" +2.60.48.34 - - [21/Jul/2011:20:38:57 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +95.175.128.20 - - [21/Jul/2011:21:57:28 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.124 Safari/534.30" +95.175.128.20 - - [21/Jul/2011:21:57:28 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.124 Safari/534.30" +72.46.217.195 - - [22/Jul/2011:00:22:20 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/search?q=torrent&sort=top" "Mozilla/5.0 (Windows NT 6.1; rv:2.0) Gecko/20100101 Firefox/4.0" +75.127.220.36 - - [22/Jul/2011:00:52:23 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1iwS7J/www.zeropaid.com/links/bittorrent" "Mozilla/5.0 (Windows NT 6.1; rv:5.0.1) Gecko/20100101 Firefox/5.0.1" +77.179.214.252 - - [23/Jul/2011:00:41:52 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +46.105.24.61 - - [23/Jul/2011:02:55:12 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +111.243.35.85 - - [23/Jul/2011:09:16:49 +0000] "GET / HTTP/1.1" 200 6063 "http://www.soft4fun.net/bbs/hidden-bt-torrent-download-url.htm" "Opera/9.80 (Windows NT 6.1; U; zh-tw) Presto/2.9.168 Version/11.50" +217.85.41.168 - - [24/Jul/2011:18:01:45 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/20100101 Firefox/5.0" +24.43.84.226 - - [25/Jul/2011:19:14:34 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.124 Safari/534.30" +113.108.3.83 - - [25/Jul/2011:23:21:27 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/4.0" +82.65.254.248 - - [26/Jul/2011:12:16:39 +0000] "GET / HTTP/1.1" 200 6063 "http://forum.korben.info/topic/5512-chiffrer-les-donnees-sur-une-base-de-donnee/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.834.0 Safari/535.1" +80.254.146.140 - - [26/Jul/2011:13:50:55 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30" +50.81.109.244 - - [26/Jul/2011:23:33:48 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_5) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +68.198.144.231 - - [27/Jul/2011:02:11:14 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.124 Safari/534.30" +148.80.255.152 - - [27/Jul/2011:15:16:17 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +68.19.214.157 - - [27/Jul/2011:17:14:28 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; rv:5.0.1) Gecko/20100101 Firefox/5.0.1" +130.225.31.205 - - [28/Jul/2011:09:46:07 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0.1) Gecko/20100101 Firefox/5.0.1" +173.246.3.19 - - [29/Jul/2011:00:11:45 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0.1) Gecko/20100101 Firefox/5.0.1" +75.110.20.249 - - [30/Jul/2011:16:29:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/4dnYBP/www.ericdsnider.com/snide/positive-buzz/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +98.199.207.113 - - [30/Jul/2011:19:12:09 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:09 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:09 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:10 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:10 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:10 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:11 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:12 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:12 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:12 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:13 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:13 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:14 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:14 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:15 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:15 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:15 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:27 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:27 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +98.199.207.113 - - [30/Jul/2011:19:12:27 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +74.125.152.86 - - [01/Aug/2011:07:52:02 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (en-us) AppleWebKit/534.14 (KHTML, like Gecko; Google Wireless Transcoder) Chrome/9.0.597 Safari/534.14" +174.17.36.28 - - [01/Aug/2011:16:59:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" +173.35.108.93 - - [02/Aug/2011:19:35:17 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.7; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" +84.153.54.22 - - [02/Aug/2011:22:39:29 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +74.94.139.34 - - [03/Aug/2011:03:24:22 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.124 Safari/534.30" +121.0.29.247 - - [03/Aug/2011:06:07:40 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +46.105.24.61 - - [03/Aug/2011:09:42:59 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +174.136.26.114 - - [04/Aug/2011:09:42:18 +0000] "GET / HTTP/1.0" 200 3739 "-" "Nutraspace/Nutch-1.2 (www.nutraspace.com)" +211.51.39.2 - - [05/Aug/2011:02:34:06 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C)" +82.230.77.30 - - [05/Aug/2011:15:36:58 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0" +116.237.15.42 - - [06/Aug/2011:09:17:56 +0000] "GET / HTTP/1.1" 200 6063 "http://www.3dch.net/read-htm-tid-187700.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)" +58.34.59.148 - - [07/Aug/2011:13:46:29 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +93.86.179.167 - - [07/Aug/2011:17:21:53 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0" +99.69.108.173 - - [07/Aug/2011:23:07:44 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/1J3ECE/www.hid.im/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Safari/530.17" +84.255.239.6 - - [08/Aug/2011:08:49:07 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +177.17.66.69 - - [08/Aug/2011:18:03:34 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +67.2.16.42 - - [09/Aug/2011:04:10:06 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.109 Safari/535.1" +89.167.25.76 - - [09/Aug/2011:05:10:47 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +208.247.73.130 - - [09/Aug/2011:15:46:25 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +218.13.31.2 - - [10/Aug/2011:06:45:54 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0" +74.207.235.38 - - [10/Aug/2011:20:16:33 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +175.177.23.18 - - [11/Aug/2011:00:10:59 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 (.NET CLR 3.5.30729)" +203.99.204.103 - - [11/Aug/2011:04:58:24 +0000] "GET / HTTP/1.1" 200 3739 "http://csocial.cognizant.com/pages/bba7c296df5bf4e5" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +207.7.178.236 - - [11/Aug/2011:05:35:32 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +112.216.97.126 - - [11/Aug/2011:06:51:39 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +89.75.48.36 - - [11/Aug/2011:15:43:06 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.68 Safari/534.24" +70.176.129.86 - - [11/Aug/2011:21:10:17 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7) AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 Safari/534.48.3" +202.146.7.239 - - [12/Aug/2011:06:57:38 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50" +63.249.46.77 - - [12/Aug/2011:18:53:12 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.0; rv:5.0.1) Gecko/20100101 Firefox/5.0.1" +72.52.96.9 - - [12/Aug/2011:19:03:53 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +112.119.82.222 - - [13/Aug/2011:11:20:06 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/15.0.849.1 Safari/535.1" +79.81.18.105 - - [13/Aug/2011:18:45:31 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +189.120.115.52 - - [13/Aug/2011:22:56:53 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +24.7.45.147 - - [14/Aug/2011:05:32:47 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +80.216.44.109 - - [14/Aug/2011:21:29:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" +115.176.200.159 - - [15/Aug/2011:05:07:22 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)" +124.65.199.2 - - [16/Aug/2011:06:57:35 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50" +109.156.104.244 - - [16/Aug/2011:20:30:03 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +188.40.124.153 - - [17/Aug/2011:12:25:59 +0000] "GET / HTTP/1.1" 200 6063 "-" "cmsworldmap.com" +38.112.210.2 - - [17/Aug/2011:19:07:32 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +203.235.61.126 - - [18/Aug/2011:05:08:09 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 Safari/534.48.3" +65.18.196.95 - - [18/Aug/2011:07:33:05 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:06 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:06 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:08 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:08 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:08 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:08 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:09 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:09 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:10 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:10 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:10 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:11 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:13 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:14 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:14 +0000] "GET / HTTP/1.0" 200 3739 "-" "ApacheBench/2.3" +65.18.196.95 - - [18/Aug/2011:07:33:15 +0000] "GET / HTTP/1.0" 499 0 "-" "ApacheBench/2.3" +141.100.244.48 - - [18/Aug/2011:15:30:28 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 Safari/534.48.3" +175.136.242.82 - - [19/Aug/2011:01:05:25 +0000] "GET / HTTP/1.0" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0" +202.174.61.196 - - [19/Aug/2011:05:10:13 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)" +98.165.221.211 - - [19/Aug/2011:07:17:48 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4" +217.91.122.116 - - [19/Aug/2011:09:17:47 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0" +217.91.122.116 - - [19/Aug/2011:09:17:48 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0" +217.91.122.116 - - [19/Aug/2011:09:17:49 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0" +196.23.187.135 - - [19/Aug/2011:14:39:37 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +107.20.61.146 - - [19/Aug/2011:18:11:10 +0000] "GET / HTTP/1.1" 200 6063 "-" "" +84.73.203.27 - - [19/Aug/2011:20:09:20 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +50.75.96.204 - - [19/Aug/2011:20:23:41 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/su/8nC99Q/www.metacafe.com/watch/718065/google_is_better_than_limewire_for_downloading_mp3s/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +187.58.108.150 - - [19/Aug/2011:22:27:58 +0000] "GET / HTTP/1.1" 200 3739 "http://news.ycombinator.net/item?id=1528247" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +190.30.1.125 - - [20/Aug/2011:20:36:47 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1" +186.136.25.39 - - [22/Aug/2011:04:26:38 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 5.1; rv:7.0) Gecko/20100101 Firefox/7.0" +196.210.162.74 - - [22/Aug/2011:16:40:07 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 Safari/534.48.3" +76.219.135.214 - - [23/Aug/2011:10:02:39 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?q=Hid.im&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a" "Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20100101 Firefox/6.0" +98.248.227.176 - - [23/Aug/2011:19:46:04 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +66.166.72.130 - - [23/Aug/2011:19:47:50 +0000] "GET / HTTP/1.1" 200 3739 "-" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)" +80.79.35.10 - - [24/Aug/2011:07:36:01 +0000] "GET / HTTP/1.1" 304 0 "http://www.google.nl/url?sa=t&source=web&cd=1&ved=0CBwQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=demo.hummingbrid.com&ei=_WdTTsViiOo55eDMnQY&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1" +173.162.202.89 - - [24/Aug/2011:15:08:42 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 5.1; rv:6.0) Gecko/20100101 Firefox/6.0" +111.184.11.60 - - [25/Aug/2011:02:30:11 +0000] "GET / HTTP/1.1" 200 6063 "http://www.soft4fun.net/bbs/hidden-bt-torrent-download-url.htm" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +77.85.132.231 - - [25/Aug/2011:08:56:38 +0000] "GET / HTTP/1.1" 200 3739 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0" +97.117.111.241 - - [25/Aug/2011:10:07:22 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:6.0) Gecko/20100101 Firefox/6.0" +92.249.127.111 - - [26/Aug/2011:10:12:22 +0000] "GET / HTTP/1.0" 200 6063 "http://linege.ixbb.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" +213.221.231.4 - - [26/Aug/2011:16:28:25 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.861.0 Safari/535.2" +89.167.25.76 - - [28/Aug/2011:09:10:37 +0000] "GET / HTTP/1.1" 304 0 "http://www.hid.im/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1" +208.80.194.26 - - [28/Aug/2011:11:04:07 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSDigitalLocker; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)" +83.145.205.160 - - [29/Aug/2011:08:49:45 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +92.249.127.111 - - [30/Aug/2011:13:09:37 +0000] "GET / HTTP/1.0" 200 6063 "http://delayreferat.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" +209.251.128.198 - - [31/Aug/2011:20:24:59 +0000] "GET / HTTP/1.1" 200 6063 "http://nuttnet.net/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.218 Safari/535.1" +98.209.131.132 - - [01/Sep/2011:02:43:18 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +96.19.8.1 - - [01/Sep/2011:06:49:38 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +78.41.136.12 - - [01/Sep/2011:12:39:24 +0000] "GET / HTTP/1.1" 200 3739 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.218 Safari/535.1" +213.16.179.240 - - [02/Sep/2011:08:52:54 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +208.80.194.26 - - [02/Sep/2011:18:46:07 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5; SV1; .NET CLR 1.1.4322)" +193.106.136.45 - - [03/Sep/2011:17:27:35 +0000] "GET / HTTP/1.0" 200 6063 "http://www.dverburg.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; XMPP Tiscali Communicator v.10.0.2; .NET CLR 2.0.50727)" +98.248.229.84 - - [04/Sep/2011:03:12:45 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +24.94.75.124 - - [04/Sep/2011:10:21:30 +0000] "GET / HTTP/1.1" 499 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +194.144.114.119 - - [05/Sep/2011:04:15:20 +0000] "GET / HTTP/1.1" 499 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (iPad; U; CPU OS 4_3_5 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5" +139.19.158.79 - - [05/Sep/2011:14:43:52 +0000] "GET / HTTP/1.1" 200 6063 "-" "Java/1.6.0_24" +74.68.115.87 - - [05/Sep/2011:23:40:38 +0000] "GET / HTTP/1.1" 200 45816 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1" +66.68.83.45 - - [06/Sep/2011:00:37:34 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/search?q=png&sort=top" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +208.80.194.26 - - [06/Sep/2011:01:14:55 +0000] "GET / HTTP/1.0" 200 45816 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; QS 4.1.2.2; YPC 3.2.0; PeoplePal 6.1; .NET CLR 1.1.4322; PeoplePal 3.0; yplus 5.6.04b)" +119.27.62.254 - - [06/Sep/2011:09:05:02 +0000] "GET / HTTP/1.1" 499 0 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" +161.253.142.215 - - [06/Sep/2011:12:25:31 +0000] "GET / HTTP/1.1" 499 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +50.23.30.149 - - [06/Sep/2011:19:15:56 +0000] "GET / HTTP/1.1" 200 45816 "-" "Mozilla/5.0 (Linux; en-US; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5" +207.67.117.170 - - [07/Sep/2011:05:58:38 +0000] "GET / HTTP/1.0" 200 45816 "-" "larbin_2.6.3 larbin2.6.3@unspecified.mail" +139.19.158.32 - - [07/Sep/2011:06:47:29 +0000] "GET / HTTP/1.1" 200 6063 "-" "Java/1.6.0_24" +122.217.239.146 - - [07/Sep/2011:11:38:06 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +96.246.150.212 - - [08/Sep/2011:00:55:20 +0000] "GET / HTTP/1.1" 200 45816 "-" "Reeder/1.5.1 CFNetwork/485.13.9 Darwin/11.0.0" +82.196.78.26 - - [08/Sep/2011:18:26:32 +0000] "GET / HTTP/1.1" 504 585 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +117.199.131.241 - - [08/Sep/2011:18:31:23 +0000] "GET / HTTP/1.1" 504 183 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 5.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +184.72.205.32 - - [09/Sep/2011:00:22:23 +0000] "GET / HTTP/1.1" 200 45816 "-" "EventMachine HttpClient" +98.247.217.142 - - [09/Sep/2011:04:23:24 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0" +122.177.40.25 - - [09/Sep/2011:07:16:21 +0000] "GET / HTTP/1.1" 200 45816 "-" "-" +80.149.229.120 - - [09/Sep/2011:09:11:27 +0000] "GET / HTTP/1.1" 504 585 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +68.194.16.247 - - [09/Sep/2011:18:18:25 +0000] "GET / HTTP/1.1" 504 585 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +76.26.227.57 - - [09/Sep/2011:22:05:31 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +211.246.71.234 - - [10/Sep/2011:14:51:16 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 Safari/534.48.3" +92.138.33.114 - - [10/Sep/2011:17:33:08 +0000] "GET / HTTP/1.1" 304 0 "http://hid.im/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +203.189.189.121 - - [10/Sep/2011:18:58:24 +0000] "GET / HTTP/1.1" 499 0 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +76.120.114.171 - - [10/Sep/2011:22:21:20 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +86.202.130.233 - - [10/Sep/2011:23:54:07 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +209.85.238.162 - - [11/Sep/2011:04:38:22 +0000] "GET / HTTP/1.1" 200 45812 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +119.82.96.130 - - [12/Sep/2011:05:44:28 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +213.249.204.130 - - [12/Sep/2011:11:03:19 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +212.251.176.145 - - [12/Sep/2011:17:07:31 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.50" +12.186.229.34 - - [12/Sep/2011:17:10:57 +0000] "GET / HTTP/1.1" 504 183 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +67.195.111.250 - - [12/Sep/2011:20:04:25 +0000] "GET / HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +86.150.218.90 - - [12/Sep/2011:21:59:30 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.5 Safari/535.2" +96.240.33.187 - - [13/Sep/2011:01:24:15 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +69.137.194.215 - - [13/Sep/2011:03:19:41 +0000] "GET / HTTP/1.1" 499 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.1) Gecko/20100101 Firefox/6.0.1" +78.41.136.12 - - [13/Sep/2011:12:34:13 +0000] "GET / HTTP/1.1" 499 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 5.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +78.105.213.244 - - [14/Sep/2011:10:29:59 +0000] "GET / HTTP/1.1" 200 6063 "-" "Safari/7534.48.3 CFNetwork/520.0.13 Darwin/11.1.0 (x86_64) (iMac10%2C1)" +195.191.106.90 - - [14/Sep/2011:12:06:23 +0000] "GET / HTTP/1.1" 499 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +110.132.88.115 - - [14/Sep/2011:12:27:48 +0000] "GET / HTTP/1.1" 200 6063 "http://it.slashdot.jp/story/09/07/19/1058215/Torrent%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E7%94%BB%E5%83%8F%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%80%8Chid.im%E3%80%8D" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; YTB730; BTRS26718; GTB7.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0E; .NET4.0C)" +67.195.112.186 - - [14/Sep/2011:12:40:54 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +2.12.15.19 - - [14/Sep/2011:13:08:11 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +84.208.176.65 - - [14/Sep/2011:17:51:28 +0000] "GET / HTTP/1.1" 504 183 "http://wiki.enonic.com/display/labs/Live+Portal+Trace+with+Ext+JS" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +14.223.94.95 - - [14/Sep/2011:20:38:50 +0000] "GET / HTTP/1.1" 504 585 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +68.199.77.192 - - [14/Sep/2011:23:06:51 +0000] "GET / HTTP/1.1" 200 45812 "-" "Reeder/1.5.1 CFNetwork/485.13.9 Darwin/11.0.0" +119.188.14.211 - - [15/Sep/2011:00:35:29 +0000] "GET / HTTP/1.1" 200 45812 "http://www.baidu.com/s?wd=a" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)" +92.249.127.111 - - [15/Sep/2011:05:01:54 +0000] "GET / HTTP/1.0" 200 6063 "http://millionsecrets.ru/" "Opera/9.0 (Windows NT 5.1; U; en)" +60.224.164.196 - - [16/Sep/2011:03:59:10 +0000] "GET / HTTP/1.1" 504 585 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +80.69.231.10 - - [16/Sep/2011:09:58:02 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +86.110.26.52 - - [16/Sep/2011:13:28:54 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +69.28.58.10 - - [16/Sep/2011:19:05:26 +0000] "GET / HTTP/1.1" 200 6063 "-" "Wget/1.9+cvs-stable (Red Hat modified)" +178.137.166.124 - - [17/Sep/2011:10:29:38 +0000] "GET / HTTP/1.0" 200 45812 "http://nuttnet.net/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; AMD64)" +85.176.111.104 - - [17/Sep/2011:14:23:18 +0000] "GET / HTTP/1.1" 504 585 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1" +173.13.160.189 - - [17/Sep/2011:23:57:36 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +67.195.111.250 - - [18/Sep/2011:03:32:16 +0000] "GET / HTTP/1.0" 499 0 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +119.152.100.102 - - [18/Sep/2011:14:36:10 +0000] "GET / HTTP/1.1" 504 183 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +86.44.20.231 - - [18/Sep/2011:16:24:39 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1" +90.224.209.141 - - [18/Sep/2011:16:51:02 +0000] "GET / HTTP/1.1" 504 585 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1" +124.115.1.66 - - [18/Sep/2011:18:31:19 +0000] "GET / HTTP/1.1" 200 45812 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +109.131.121.134 - - [18/Sep/2011:21:05:29 +0000] "GET / HTTP/1.1" 499 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Linux; U; Android 2.3.3; nl-nl; HTC_DesireHD_A9191 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" +84.110.5.143 - - [18/Sep/2011:21:50:33 +0000] "GET / HTTP/1.0" 200 45812 "http://nuttnet.net/" "Mozilla/4.0 (compatible; Powermarks/3.5; Windows 95/98/2000/NT)" +92.231.203.31 - - [18/Sep/2011:23:03:50 +0000] "GET / HTTP/1.1" 504 183 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +72.50.177.122 - - [19/Sep/2011:00:59:45 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; rv:7.0) Gecko/20100101 Firefox/7.0" +67.195.112.186 - - [19/Sep/2011:09:47:17 +0000] "GET / HTTP/1.0" 200 45812 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +220.181.106.54 - - [19/Sep/2011:15:46:01 +0000] "GET / HTTP/1.1" 200 3749 "http://stackoverflow.com/questions/5580776/monitoring-a-node-js-server" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; 360SE)" +178.59.113.220 - - [20/Sep/2011:02:15:15 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 ( .NET CLR 3.5.30729; .NET4.0E)" +212.205.51.2 - - [20/Sep/2011:10:06:17 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +173.165.89.131 - - [20/Sep/2011:14:14:43 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +74.125.46.84 - - [20/Sep/2011:23:17:05 +0000] "GET / HTTP/1.1" 200 45715 "-" "AppEngine-Google; (+http://code.google.com/appengine; appid: mobhook)" +69.140.112.82 - - [21/Sep/2011:01:56:38 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; Linux i686; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +72.14.199.2 - - [21/Sep/2011:06:03:19 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +72.14.199.2 - - [21/Sep/2011:09:03:26 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +208.75.140.69 - - [21/Sep/2011:15:29:32 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +207.138.251.2 - - [21/Sep/2011:19:16:56 +0000] "GET / HTTP/1.1" 200 3749 "http://stackoverflow.com/questions/5580776/monitoring-a-node-js-server" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22" +72.14.199.2 - - [21/Sep/2011:21:31:58 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +118.209.20.45 - - [22/Sep/2011:02:50:47 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +66.212.196.223 - - [22/Sep/2011:03:31:42 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (X11; Linux i686; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +93.133.250.40 - - [22/Sep/2011:18:45:27 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.1 CFNetwork/485.13.9 Darwin/11.0.0" +108.38.59.34 - - [22/Sep/2011:20:11:22 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.15 Safari/535.2" +78.60.37.78 - - [23/Sep/2011:02:59:53 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +204.112.30.204 - - [23/Sep/2011:04:52:47 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +141.228.106.151 - - [23/Sep/2011:09:31:10 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2)" +202.246.252.102 - - [23/Sep/2011:11:04:58 +0000] "GET / HTTP/1.0" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1" +24.193.144.203 - - [23/Sep/2011:15:32:42 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1" +190.239.197.172 - - [24/Sep/2011:01:49:56 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/toolbar/litebar.php?device=chromebar&version=chromebar%203.8.16.1&ts=1316801137662" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +62.31.185.16 - - [24/Sep/2011:05:58:11 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-gb) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8J3" +72.14.199.2 - - [24/Sep/2011:19:50:09 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +173.248.196.195 - - [26/Sep/2011:01:21:42 +0000] "GET / HTTP/1.1" 200 6063 "http://www.reddit.com/search?q=torrent&sort=top" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +68.199.77.192 - - [26/Sep/2011:02:55:09 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.1 CFNetwork/485.13.9 Darwin/11.0.0" +87.141.27.122 - - [26/Sep/2011:14:52:03 +0000] "GET / HTTP/1.1" 200 6063 "http://instant-thinking.de/tag/bittorrent/" "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" +216.81.57.102 - - [26/Sep/2011:23:20:05 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18) Gecko/20110628 Ubuntu/10.04 (lucid) Firefox/3.6.18" +68.199.77.192 - - [27/Sep/2011:03:48:32 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.1 CFNetwork/485.13.9 Darwin/11.0.0" +93.32.157.91 - - [27/Sep/2011:11:05:40 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +195.18.164.72 - - [27/Sep/2011:11:08:24 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +196.23.187.154 - - [27/Sep/2011:13:50:45 +0000] "GET / HTTP/1.0" 200 6063 "-" "-" +65.78.174.19 - - [28/Sep/2011:06:07:24 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0) Gecko/20100101 Firefox/7.0" +108.94.26.143 - - [28/Sep/2011:20:06:54 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +221.112.184.146 - - [29/Sep/2011:06:00:14 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +75.192.249.144 - - [29/Sep/2011:22:02:26 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +213.132.96.218 - - [30/Sep/2011:06:55:57 +0000] "GET / HTTP/1.1" 200 3749 "http://www.google.se/url?sa=t&source=web&cd=1&sqi=2&ved=0CBsQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&rct=j&q=hummingbird%20stats&ei=-meFTtzJCYL_4QTaoMDMDw&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +194.247.67.234 - - [30/Sep/2011:10:02:44 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.54 Safari/535.2" +209.85.238.148 - - [30/Sep/2011:10:29:58 +0000] "GET / HTTP/1.1" 200 45715 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +213.178.39.47 - - [30/Sep/2011:19:52:08 +0000] "GET / HTTP/1.1" 304 0 "http://www.hid.im/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +139.19.150.31 - - [30/Sep/2011:21:12:55 +0000] "GET / HTTP/1.1" 200 6063 "-" "Java/1.6.0_22" +213.141.144.63 - - [01/Oct/2011:11:59:37 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +209.85.238.87 - - [02/Oct/2011:13:32:28 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +87.171.96.33 - - [02/Oct/2011:19:29:47 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.187 Safari/535.1" +80.216.167.136 - - [02/Oct/2011:21:00:46 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +203.173.253.164 - - [02/Oct/2011:22:37:50 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +209.85.238.87 - - [03/Oct/2011:04:33:08 +0000] "GET / HTTP/1.1" 200 45715 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +71.183.212.254 - - [03/Oct/2011:08:28:24 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +121.84.174.111 - - [03/Oct/2011:14:59:59 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +81.156.8.220 - - [03/Oct/2011:22:31:31 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +93.32.183.136 - - [04/Oct/2011:09:39:14 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +81.57.75.205 - - [04/Oct/2011:12:01:56 +0000] "GET / HTTP/1.1" 200 3749 "http://blog.johanbleuzen.fr/hummingbird-outil-tracking-temps-reel-nodejs" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +194.239.142.252 - - [04/Oct/2011:13:36:12 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30" +93.32.183.136 - - [04/Oct/2011:16:45:16 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1" +62.212.72.40 - - [05/Oct/2011:10:32:34 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5" +141.117.182.92 - - [06/Oct/2011:15:08:17 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +72.14.199.20 - - [07/Oct/2011:11:30:52 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +187.65.125.253 - - [07/Oct/2011:20:35:41 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +209.85.238.72 - - [08/Oct/2011:02:31:55 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +83.25.141.17 - - [08/Oct/2011:18:59:44 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/ramka/210426/konwerter-plikow-torrent-do-png/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +92.113.132.239 - - [09/Oct/2011:11:10:11 +0000] "GET / HTTP/1.1" 200 3749 "http://habrahabr.ru/blogs/webdev/93514/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1" +86.126.110.222 - - [09/Oct/2011:11:43:53 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/11.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30" +67.195.112.186 - - [09/Oct/2011:23:37:26 +0000] "GET / HTTP/1.0" 200 45715 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +67.217.165.7 - - [10/Oct/2011:02:27:22 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" +95.27.25.216 - - [10/Oct/2011:03:30:46 +0000] "GET / HTTP/1.0" 200 45715 "http://yandex.ru/yandsearch?text=nuttnet.net" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" +178.37.236.147 - - [10/Oct/2011:12:31:24 +0000] "GET / HTTP/1.0" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +208.69.40.227 - - [10/Oct/2011:17:30:15 +0000] "GET / HTTP/1.0" 200 45715 "-" "-" +201.47.169.254 - - [10/Oct/2011:20:11:51 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +212.56.163.222 - - [11/Oct/2011:11:55:54 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +158.135.11.6 - - [11/Oct/2011:18:44:41 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.7; en-US; rv:1.9.2.23) Gecko/20110920 Firefox/3.6.23" +85.72.76.8 - - [12/Oct/2011:14:33:24 +0000] "GET / HTTP/1.1" 200 3749 "http://stackoverflow.com/questions/5580776/monitoring-a-node-js-server" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.83 Safari/535.2" +64.12.71.6 - - [12/Oct/2011:17:58:43 +0000] "GET / HTTP/1.1" 200 3749 "-" "Java/1.6.0_22" +122.181.11.106 - - [13/Oct/2011:05:10:48 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.124 Safari/534.30" +82.224.187.64 - - [13/Oct/2011:21:37:27 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; U; CPU OS 4_3_5 like Mac OS X; fr-fr) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5" +72.94.249.37 - - [14/Oct/2011:04:50:19 +0000] "GET / HTTP/1.1" 301 185 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" +212.126.160.26 - - [14/Oct/2011:11:08:39 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7) AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 Safari/534.48.3" +109.149.17.166 - - [14/Oct/2011:22:32:17 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22" +69.181.221.237 - - [16/Oct/2011:02:34:00 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1010.39.00 CFNetwork/520.2.5 Darwin/11.2.0 (x86_64) (iMac11%2C1)" +69.116.248.157 - - [16/Oct/2011:13:17:15 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.2 CFNetwork/548.0.3 Darwin/11.0.0" +108.27.21.97 - - [16/Oct/2011:19:20:04 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 FirePHP/0.6" +67.174.220.203 - - [16/Oct/2011:21:03:31 +0000] "GET / HTTP/1.1" 200 3749 "http://www.google.com/search?q=hummingbird+demo&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a" "Mozilla/5.0 (Windows NT 6.0; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +82.226.129.42 - - [16/Oct/2011:21:34:27 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/10.04 Chromium/14.0.835.202 Chrome/14.0.835.202 Safari/535.1" +76.15.193.120 - - [17/Oct/2011:01:40:14 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/2.5.2 CFNetwork/548.0.3 Darwin/11.0.0" +46.64.41.190 - - [18/Oct/2011:11:47:52 +0000] "GET / HTTP/1.1" 200 3749 "http://www.google.co.uk/search?q=hummingbird+stats&ie=UTF-8&oe=UTF-8&hl=en&client=safari" "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3" +78.12.251.164 - - [18/Oct/2011:12:40:53 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.04 Chromium/14.0.835.202 Chrome/14.0.835.202 Safari/535.1" +72.14.199.14 - - [18/Oct/2011:19:12:52 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +173.59.241.151 - - [20/Oct/2011:02:30:31 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +200.68.120.81 - - [20/Oct/2011:14:25:01 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +74.94.153.141 - - [20/Oct/2011:15:46:58 +0000] "GET / HTTP/1.1" 200 6063 "-" "PostPost/1.0 (+http://postpost.com/crawlers)" +74.94.153.141 - - [20/Oct/2011:15:47:09 +0000] "GET / HTTP/1.1" 200 6063 "-" "PostPost/1.0 (+http://postpost.com/crawlers)" +204.28.122.20 - - [20/Oct/2011:17:06:24 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +202.162.220.4 - - [21/Oct/2011:01:36:18 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +218.213.26.180 - - [22/Oct/2011:17:31:52 +0000] "GET / HTTP/1.1" 200 3749 "-" "DoCoMo/2.0 P900i(c100;TB;W24H11) (compatible; ichiro/mobile goo; +http://help.goo.ne.jp/help/article/1142/)" +178.177.149.87 - - [23/Oct/2011:05:24:45 +0000] "GET / HTTP/1.1" 200 3749 "http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CBkQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&ei=YqSjTqyfO8aA4gTVsfjcBA&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg&sig2=7q-hpXUHdEGCSaXHXXwV2A" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.7; ru; rv:1.9.2.23) Gecko/20110920 Firefox/3.6.23" +87.221.251.77 - - [23/Oct/2011:10:29:15 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +78.105.150.146 - - [23/Oct/2011:15:19:32 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +50.16.126.30 - - [23/Oct/2011:17:04:38 +0000] "GET / HTTP/1.1" 200 45715 "-" "EventMachine HttpClient" +72.94.169.146 - - [23/Oct/2011:22:23:21 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +72.14.199.14 - - [24/Oct/2011:09:04:41 +0000] "GET / HTTP/1.1" 200 45715 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +98.216.238.184 - - [24/Oct/2011:17:11:51 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +218.186.16.244 - - [24/Oct/2011:19:10:03 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +69.181.221.237 - - [25/Oct/2011:04:27:40 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.2 CFNetwork/548.0.3 Darwin/11.0.0" +67.169.12.175 - - [26/Oct/2011:04:26:14 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.102 Safari/535.2" +83.167.37.146 - - [26/Oct/2011:08:40:32 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/10.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30" +130.226.169.141 - - [26/Oct/2011:09:03:22 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.16) Gecko/20110929 Iceweasel/3.5.16 (like Firefox/3.5.16)" +184.74.179.42 - - [26/Oct/2011:15:28:27 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +173.228.116.136 - - [26/Oct/2011:17:44:40 +0000] "GET / HTTP/1.1" 200 3749 "http://news.ycombinator.com/item?id=1528247" "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.9.168 Version/11.51" +89.36.146.81 - - [26/Oct/2011:18:04:04 +0000] "GET / HTTP/1.1" 304 0 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +193.106.136.41 - - [27/Oct/2011:03:01:06 +0000] "GET / HTTP/1.0" 200 6063 "http://all-lasik-centers.com/NV/Lund.html" "Mozilla/4.0 (compatible; MSIE 4.01; Digital AlphaServer 1000A 4/233; Windows NT; Powered By 64-Bit Alpha Processor)" +92.249.127.111 - - [27/Oct/2011:03:28:10 +0000] "GET / HTTP/1.0" 200 6063 "http://www.tourclubfavorit.ru/" "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0 ; .NET CLR 2.0.50215; SL Commerce Client v1.0; Tablet PC 2.0" +85.224.105.175 - - [27/Oct/2011:08:10:55 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1" +200.157.33.226 - - [27/Oct/2011:10:42:04 +0000] "GET / HTTP/1.0" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16" +92.249.127.111 - - [27/Oct/2011:17:59:52 +0000] "GET / HTTP/1.0" 200 6063 "http://sdelatmebel.info/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) Babya Discoverer 8.0:" +90.185.40.173 - - [27/Oct/2011:18:20:59 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +69.116.248.157 - - [28/Oct/2011:00:02:44 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.2 CFNetwork/548.0.3 Darwin/11.0.0" +173.225.17.50 - - [28/Oct/2011:05:04:03 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" +92.249.127.111 - - [28/Oct/2011:09:36:32 +0000] "GET / HTTP/1.0" 200 6063 "http://www.tourclubfavorit.ru/" "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)" +77.57.213.187 - - [28/Oct/2011:13:16:17 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +198.45.19.95 - - [28/Oct/2011:14:24:45 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +193.106.136.41 - - [28/Oct/2011:17:32:40 +0000] "GET / HTTP/1.0" 200 6063 "http://www.unrealtech.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) NS8/0.9.6" +176.31.248.12 - - [29/Oct/2011:13:07:40 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +193.106.136.41 - - [30/Oct/2011:18:19:42 +0000] "GET / HTTP/1.0" 200 6063 "http://ball1.ru/" "Opera/8.01 (Windows NT 5.1)" +24.23.199.31 - - [31/Oct/2011:05:51:54 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22" +193.106.136.41 - - [31/Oct/2011:14:03:51 +0000] "GET / HTTP/1.0" 200 6063 "http://power1.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; WOW64; SV1; .NET CLR 2.0.50727)" +183.83.31.162 - - [31/Oct/2011:22:56:00 +0000] "GET / HTTP/1.1" 200 3749 "http://stackoverflow.com/questions/5580776/monitoring-a-node-js-server" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +89.216.22.216 - - [01/Nov/2011:13:49:28 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" +87.194.162.237 - - [01/Nov/2011:16:34:21 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +72.231.221.252 - - [02/Nov/2011:06:10:59 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +64.61.182.194 - - [02/Nov/2011:20:46:56 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +184.163.98.165 - - [02/Nov/2011:21:18:10 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +206.15.64.254 - - [02/Nov/2011:23:13:15 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.2 CFNetwork/548.0.3 Darwin/11.0.0" +110.66.178.41 - - [03/Nov/2011:13:35:56 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +67.21.63.18 - - [03/Nov/2011:17:18:56 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +209.85.238.246 - - [04/Nov/2011:11:57:04 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +173.160.119.249 - - [04/Nov/2011:21:51:51 +0000] "GET / HTTP/1.1" 200 3749 "http://thechangelog.com/search/performance" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.100 Safari/535.2" +119.242.231.126 - - [05/Nov/2011:12:35:09 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22" +96.31.79.130 - - [05/Nov/2011:20:39:14 +0000] "GET / HTTP/1.1" 200 33580 "http://www.intl-alliance.com/store" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6" +83.226.33.1 - - [07/Nov/2011:21:22:15 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +194.80.32.9 - - [08/Nov/2011:02:51:51 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +208.80.194.29 - - [08/Nov/2011:07:36:38 +0000] "GET / HTTP/1.0" 200 3749 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SIMBAR Enabled; Ringo; GameBar; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +201.189.123.201 - - [09/Nov/2011:01:57:46 +0000] "GET / HTTP/1.1" 200 3749 "http://www.google.cl/url?sa=t&rct=j&q=hummingbird%20demo&source=web&cd=1&ved=0CCAQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&ei=1d25TqiXGsK9twf00eGmBw&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +41.160.143.92 - - [09/Nov/2011:15:39:52 +0000] "GET / HTTP/1.0" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +190.52.150.224 - - [09/Nov/2011:19:22:41 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.04 Chromium/14.0.835.202 Chrome/14.0.835.202 Safari/535.1" +208.240.243.170 - - [09/Nov/2011:20:49:44 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +123.30.175.68 - - [10/Nov/2011:16:06:58 +0000] "GET / HTTP/1.0" 200 45715 "-" "itim" +98.144.109.241 - - [11/Nov/2011:00:34:34 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2" +174.143.152.33 - - [11/Nov/2011:02:46:18 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +194.80.32.8 - - [11/Nov/2011:02:55:11 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +178.217.102.225 - - [11/Nov/2011:11:19:00 +0000] "GET / HTTP/1.1" 200 6063 "-" "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.9.168 Version/11.52" +167.100.118.140 - - [11/Nov/2011:15:16:35 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22" +213.114.169.236 - - [11/Nov/2011:16:42:14 +0000] "GET / HTTP/1.1" 200 3749 "http://www.google.se/url?sa=t&rct=j&q=demo%20hummingbird&source=web&cd=1&ved=0CCkQFjAA&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&ei=ZFC9TpqkMpT74QTnj6GgBA&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2" +85.228.222.159 - - [11/Nov/2011:16:42:50 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0" +207.35.123.94 - - [11/Nov/2011:20:18:04 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; chromeframe/15.0.874.120; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; MS-RTC LM 8; Zune 4.7)" +76.198.128.121 - - [12/Nov/2011:01:57:57 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1" +50.23.23.81 - - [12/Nov/2011:06:16:35 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/5.0 (Linux; en-US; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5" +194.80.32.10 - - [15/Nov/2011:02:49:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +50.47.77.17 - - [15/Nov/2011:04:04:08 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2" +68.144.80.126 - - [15/Nov/2011:18:54:25 +0000] "GET / HTTP/1.1" 304 0 "http://www.hid.im/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +83.233.90.249 - - [15/Nov/2011:20:06:14 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:8.0) Gecko/20100101 Firefox/8.0" +213.238.60.136 - - [16/Nov/2011:14:12:54 +0000] "GET / HTTP/1.1" 200 3749 "-" "XING-contenttabreceiver/1.0" +188.241.102.24 - - [16/Nov/2011:14:19:07 +0000] "GET / HTTP/1.1" 200 3749 "http://adf.ly/504619/http://demo.hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0" +128.146.35.139 - - [16/Nov/2011:15:36:32 +0000] "GET / HTTP/1.1" 200 6063 "-" "iTunes/10.5 (Macintosh; Intel Mac OS X 10.6.8) AppleWebKit/534.50" +83.246.64.41 - - [17/Nov/2011:00:32:25 +0000] "GET / HTTP/1.1" 200 6063 "-" "Python-urllib/2.5" +87.218.15.251 - - [17/Nov/2011:04:15:28 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2" +78.46.71.147 - - [17/Nov/2011:12:19:21 +0000] "GET / HTTP/1.1" 200 45715 "" "rganalytics" +24.62.101.30 - - [17/Nov/2011:16:57:23 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)" +178.251.202.142 - - [18/Nov/2011:07:57:02 +0000] "GET / HTTP/1.1" 200 3749 "http://www.google.fr/url?sa=t&rct=j&q=hummingbird%20stats&source=web&cd=2&sqi=2&ved=0CCsQFjAB&url=http%3A%2F%2Fdemo.hummingbirdstats.com%2F&ei=yg_GTv6SOsiyhAe88_nLDw&usg=AFQjCNGMK2Tky2qz_I4dJQyp8mhe1dxiRg&sig2=i8u71dVCe5_sgUFIxG18iA&cad=rja" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2" +72.14.199.2 - - [18/Nov/2011:08:13:08 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +89.173.123.33 - - [18/Nov/2011:12:25:15 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0" +70.127.163.136 - - [18/Nov/2011:18:07:53 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (iPad; CPU OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3" +174.37.154.78 - - [18/Nov/2011:22:01:38 +0000] "GET / HTTP/1.0" 200 45715 "-" "Gist Server" +69.171.228.248 - - [19/Nov/2011:07:10:53 +0000] "GET / HTTP/1.1" 206 6063 "-" "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" +31.11.159.253 - - [19/Nov/2011:18:31:02 +0000] "GET / HTTP/1.1" 200 6063 "http://www.wykop.pl/link/693787/programowanie-w-ms-paint/" "Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.9.168 Version/11.52" +193.106.136.56 - - [20/Nov/2011:05:47:34 +0000] "GET / HTTP/1.0" 200 6063 "http://www.rospromtest.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1)" +125.89.75.100 - - [20/Nov/2011:18:33:08 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; MAXTHON 2.0)" +86.179.233.102 - - [20/Nov/2011:19:24:00 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Ubuntu/11.10 Chromium/14.0.835.202 Chrome/14.0.835.202 Safari/535.1" +69.181.221.237 - - [21/Nov/2011:01:53:29 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1010.49.00 CFNetwork/520.2.5 Darwin/11.2.0 (x86_64) (MacBookPro8%2C2)" +193.106.136.37 - - [21/Nov/2011:04:46:31 +0000] "GET / HTTP/1.0" 200 6063 "http://www.otvetnemail.ru/forumdisplay.php?f=422" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 4.3 (build 01218); .NET CLR 1.1.4322)" +72.14.199.113 - - [21/Nov/2011:05:02:48 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +202.143.76.251 - - [21/Nov/2011:09:05:07 +0000] "GET / HTTP/1.0" 200 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0" +180.70.97.5 - - [21/Nov/2011:09:21:23 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +24.141.10.70 - - [21/Nov/2011:10:09:12 +0000] "GET / HTTP/1.1" 200 3749 "http://stackoverflow.com/questions/5580776/monitoring-a-node-js-server" "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3" +83.149.38.119 - - [21/Nov/2011:17:09:44 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +126.124.105.89 - - [21/Nov/2011:17:24:49 +0000] "GET / HTTP/1.1" 304 0 "http://phpspot.org/blog/archives/2010/07/hummingbird.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; GTB7.1; YTB730; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30618; OfficeLiveConnector.1.5; OfficeLivePatch.1.3; .NET4.0C; .NET4.0E; YTB730)" +83.99.32.23 - - [21/Nov/2011:20:30:22 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +122.54.153.99 - - [22/Nov/2011:08:04:05 +0000] "GET / HTTP/1.0" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +107.20.23.163 - - [22/Nov/2011:10:06:55 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (FlipboardProxy/1.1; +http://flipboard.com/browserproxy)" +141.45.192.153 - - [22/Nov/2011:12:53:38 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +69.174.87.84 - - [22/Nov/2011:19:03:17 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +69.116.248.157 - - [23/Nov/2011:01:47:15 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +69.116.248.157 - - [23/Nov/2011:01:56:10 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +82.71.63.30 - - [23/Nov/2011:02:29:28 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.49.1 (KHTML, like Gecko) Version/5.1 Safari/534.49" +71.49.142.25 - - [23/Nov/2011:14:54:14 +0000] "GET / HTTP/1.1" 200 6063 "http://www.google.com/search?q=decode+hidim&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +46.4.221.189 - - [24/Nov/2011:14:57:31 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" +199.83.220.124 - - [25/Nov/2011:01:12:44 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.16 Safari/534.24" +180.234.102.173 - - [25/Nov/2011:10:50:09 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0" +64.233.182.82 - - [26/Nov/2011:04:41:45 +0000] "GET / HTTP/1.1" 200 3749 "http://translate.google.com.my/translate_p?hl=ms&prev=/search%3Fq%3Dhummingbird%26start%3D30%26hl%3Dms%26sa%3DN%26gbv%3D2%26biw%3D1024%26bih%3D667%26prmd%3Dimvns&sl=en&u=http://demo.hummingbirdstats.com/&usg=ALkJrhhPpDgJRhMz3UT5NkK60hK9v4NSjQ" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2,gzip(gfe) (via translate.google.com)" +49.134.211.28 - - [26/Nov/2011:09:30:23 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Linux; U; Android 3.2.1; ja-jp; Sony Tablet S Build/THMASU0035) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13" +178.137.5.109 - - [26/Nov/2011:19:12:44 +0000] "GET / HTTP/1.0" 200 6063 "http://wahforex.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +101.171.76.1 - - [27/Nov/2011:15:05:34 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +69.116.248.157 - - [28/Nov/2011:00:37:45 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +193.106.136.39 - - [28/Nov/2011:05:38:04 +0000] "GET / HTTP/1.0" 200 6063 "http://www.lovedbaby.ru/" "Opera/7.60 (Windows NT 5.2; U) [en] (IBM EVV/3.0/EAK01AG9/LE)" +208.80.194.28 - - [28/Nov/2011:05:56:35 +0000] "GET / HTTP/1.0" 301 185 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.2.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; yplus 5.3.03b)" +194.80.32.8 - - [29/Nov/2011:02:54:08 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +82.113.116.116 - - [29/Nov/2011:08:00:20 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +190.189.166.16 - - [29/Nov/2011:09:47:35 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +89.173.109.67 - - [29/Nov/2011:15:18:58 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64; rv:8.0.1) Gecko/20100101 Firefox/8.0.1" +77.56.120.38 - - [29/Nov/2011:23:07:45 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +78.86.146.56 - - [30/Nov/2011:10:03:09 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1010.49.00 CFNetwork/520.2.5 Darwin/11.2.0 (x86_64) (MacBookPro4%2C1)" +95.0.198.132 - - [30/Nov/2011:14:49:22 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +58.160.177.45 - - [30/Nov/2011:15:08:25 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +77.4.61.194 - - [30/Nov/2011:20:10:30 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +187.106.228.22 - - [01/Dec/2011:01:18:05 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Linux; U; Android 3.1; pt-br; MZ605 Build/H.6.3-28.6) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13" +69.203.147.217 - - [01/Dec/2011:04:51:10 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +49.98.10.160 - - [01/Dec/2011:12:13:22 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Linux; U; Android 2.3.3; ja-jp; SH-12C Build/S9300) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" +203.126.230.202 - - [02/Dec/2011:01:53:35 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +81.174.196.161 - - [02/Dec/2011:09:00:17 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +213.0.107.43 - - [02/Dec/2011:09:42:03 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +69.181.221.237 - - [02/Dec/2011:16:50:47 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1010.49.00 CFNetwork/520.2.5 Darwin/11.2.0 (x86_64) (iMac11%2C1)" +208.80.194.32 - - [02/Dec/2011:18:26:37 +0000] "GET / HTTP/1.0" 200 45715 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; Alexa Toolbar)" +72.14.199.113 - - [03/Dec/2011:00:49:54 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +72.30.161.241 - - [03/Dec/2011:18:32:07 +0000] "GET / HTTP/1.0" 200 45715 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" +208.80.194.30 - - [04/Dec/2011:03:30:28 +0000] "GET / HTTP/1.0" 200 45715 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; IEMB3; .NET CLR 2.0.50727; IEMB3)" +165.228.0.68 - - [05/Dec/2011:00:48:52 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.8 (KHTML, like Gecko) Chrome/17.0.942.0 Safari/535.8" +186.204.149.236 - - [05/Dec/2011:14:29:07 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" +69.181.221.237 - - [05/Dec/2011:18:00:09 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1010.49.00 CFNetwork/520.2.5 Darwin/11.2.0 (x86_64) (iMac11%2C1)" +193.106.136.34 - - [06/Dec/2011:08:00:56 +0000] "GET / HTTP/1.0" 200 6063 "http://www.tipkiller.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" +94.198.190.2 - - [06/Dec/2011:17:22:02 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +96.31.92.155 - - [07/Dec/2011:09:01:31 +0000] "GET / HTTP/1.1" 200 45715 "-" "-" +77.202.170.217 - - [07/Dec/2011:09:19:43 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +200.55.216.123 - - [07/Dec/2011:18:09:03 +0000] "GET / HTTP/1.0" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +92.39.51.73 - - [08/Dec/2011:19:52:41 +0000] "GET / HTTP/1.0" 200 45715 "http://nuttnet.net/" "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.0.2914)" +212.175.171.2 - - [09/Dec/2011:14:25:58 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +24.215.177.13 - - [09/Dec/2011:14:45:58 +0000] "GET / HTTP/1.1" 200 45715 "http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CEMQFjAA&url=http%3A%2F%2Fnuttnet.net%2F&ei=Ix_iTrDyJYbl0QHPtojjBQ&usg=AFQjCNHcdNmjLOAAQcksiOokaSd5I0WKfw&sig2=6pnRlAAG4hdGKbZ1fD5pTA" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:8.0.1) Gecko/20100101 Firefox/8.0.1" +72.14.199.113 - - [09/Dec/2011:18:59:44 +0000] "GET / HTTP/1.1" 200 45715 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +76.112.194.25 - - [11/Dec/2011:07:02:41 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +46.4.121.230 - - [11/Dec/2011:10:48:55 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13 BuiltWith/1.2" +208.80.194.29 - - [12/Dec/2011:16:31:30 +0000] "GET / HTTP/1.0" 200 3749 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D6EDF7C4-84F1-45C8-885B-28F5F48B27C5}; SV1; .NET CLR 1.1.4322)" +76.164.175.5 - - [12/Dec/2011:18:05:00 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +72.14.199.113 - - [12/Dec/2011:19:03:34 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +125.236.219.167 - - [12/Dec/2011:22:27:20 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.8 (KHTML, like Gecko) Ubuntu/11.10 Chromium/17.0.942.0 Chrome/17.0.942.0 Safari/535.8" +115.192.210.165 - - [13/Dec/2011:01:24:04 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2" +96.239.59.178 - - [13/Dec/2011:01:31:41 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +208.80.194.33 - - [13/Dec/2011:02:44:02 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322; HbTools 4.8.2; .NET CLR 2.0.50727)" +91.153.120.40 - - [13/Dec/2011:16:48:34 +0000] "GET / HTTP/1.1" 304 0 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +94.141.87.203 - - [14/Dec/2011:11:59:27 +0000] "GET / HTTP/1.0" 200 3749 "http://www.scriptcopy.com/out/2611/Demo" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +72.22.186.18 - - [14/Dec/2011:18:02:15 +0000] "GET / HTTP/1.1" 200 45715 "http://twitter.com/michaeln3" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +50.74.224.130 - - [14/Dec/2011:19:20:53 +0000] "GET / HTTP/1.1" 304 0 "http://news.ycombinator.com/item?id=1528247" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +87.93.143.219 - - [15/Dec/2011:14:45:25 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/531.21.11 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +216.129.65.170 - - [15/Dec/2011:18:09:22 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2" +69.58.178.57 - - [15/Dec/2011:19:56:46 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.3; ips-agent) Gecko/20090824 Fedora/1.0.7-1.1.fc4 Firefox/3.5.3" +202.32.86.104 - - [16/Dec/2011:08:05:45 +0000] "GET / HTTP/1.0" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +218.61.204.81 - - [16/Dec/2011:17:52:45 +0000] "GET / HTTP/1.1" 200 6063 "www.hid.im" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +128.30.52.70 - - [16/Dec/2011:21:27:17 +0000] "GET / HTTP/1.1" 200 6063 "-" "W3C_Validator/1.2" +188.40.124.153 - - [17/Dec/2011:15:46:00 +0000] "GET / HTTP/1.1" 200 3749 "-" "cmsworldmap.com" +178.63.63.5 - - [17/Dec/2011:15:56:46 +0000] "GET / HTTP/1.1" 200 45715 "http://nuttnet.net/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4308)" +87.93.143.219 - - [18/Dec/2011:12:05:42 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/531.21.11 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" +208.80.194.29 - - [19/Dec/2011:11:49:38 +0000] "GET / HTTP/1.0" 200 6063 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SIMBAR Enabled; SIMBAR={410E9075-B5E1-460a-998C-5A0B8CC7705A}; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" +96.31.79.130 - - [20/Dec/2011:15:26:15 +0000] "GET / HTTP/1.1" 200 33580 "http://www.intl-alliance.com/store" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6" +95.199.20.15 - - [20/Dec/2011:17:37:26 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3" +209.85.238.152 - - [20/Dec/2011:19:38:05 +0000] "GET / HTTP/1.1" 200 45715 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +86.145.113.36 - - [21/Dec/2011:10:06:49 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +83.213.127.188 - - [21/Dec/2011:19:03:36 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +193.106.136.45 - - [21/Dec/2011:19:26:09 +0000] "GET / HTTP/1.0" 200 6063 "http://www.linuxjournal.su/" "Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.00" +194.80.32.9 - - [24/Dec/2011:02:48:09 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11" +77.4.55.30 - - [24/Dec/2011:13:09:16 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/2.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +173.173.35.48 - - [25/Dec/2011:03:59:29 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +219.105.198.46 - - [25/Dec/2011:11:20:27 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Opera/9.80 (Windows NT 5.1; U; ja) Presto/2.10.229 Version/11.60" +77.4.45.175 - - [25/Dec/2011:16:25:35 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +184.107.233.98 - - [26/Dec/2011:15:34:10 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/5.0 (compatible; Firefox Addon; Windows XP 5.1)" +77.5.142.211 - - [26/Dec/2011:22:07:09 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; rv:8.0.1) Gecko/20100101 Firefox/8.0.1" +72.14.199.11 - - [27/Dec/2011:13:52:15 +0000] "GET / HTTP/1.1" 200 45715 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +204.153.88.2 - - [28/Dec/2011:21:41:15 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0" +204.153.88.2 - - [28/Dec/2011:21:41:15 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0" +122.179.19.63 - - [28/Dec/2011:21:57:32 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +67.169.116.81 - - [29/Dec/2011:04:43:11 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +95.51.101.186 - - [29/Dec/2011:09:42:38 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.15 Safari/535.2" +85.17.213.242 - - [29/Dec/2011:23:46:06 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)" +193.106.136.57 - - [30/Dec/2011:17:27:56 +0000] "GET / HTTP/1.0" 200 6063 "http://all4sensor.ru/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" +123.125.67.211 - - [31/Dec/2011:19:04:02 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/5.0 (Windows NT 5.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2" +85.152.205.241 - - [31/Dec/2011:19:22:26 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +61.155.149.228 - - [01/Jan/2012:12:38:09 +0000] "GET / HTTP/1.1" 200 6063 "http://www.baidu.com/s?wd=a" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)" +71.205.95.135 - - [01/Jan/2012:23:08:04 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +98.14.252.225 - - [02/Jan/2012:05:54:28 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +76.218.201.134 - - [02/Jan/2012:09:54:06 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.52.7 (KHTML, like Gecko) Version/5.1.2 Safari/534.52.7" +202.129.215.8 - - [02/Jan/2012:10:33:05 +0000] "GET / HTTP/1.0" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.25) Gecko/20111212 Firefox/3.6.25 ( .NET CLR 3.5.30729)" +174.110.175.255 - - [02/Jan/2012:18:33:43 +0000] "GET / HTTP/1.1" 200 3749 "http://www.search-results.com/web?l=dis&o=1928&q=hummingbird+demo&atb=sysid%3D406%3Aappid%3D113%3Auid%3D77007f2a7090790e%3Auc%3D1325529218%3Aq%3Dhummingbird+demo%3Asrc%3Dcrb%3Ao%3D1928" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +69.181.221.237 - - [02/Jan/2012:19:10:49 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +178.137.5.7 - - [03/Jan/2012:13:04:07 +0000] "GET / HTTP/1.0" 200 6063 "http://mamba.kiev.ua/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.0" +72.14.199.11 - - [03/Jan/2012:16:56:25 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +91.21.251.246 - - [03/Jan/2012:17:16:23 +0000] "GET / HTTP/1.1" 200 6063 "http://torrentfreak.com/hidim-converts-torrents-into-png-images-090714/" "Mozilla/5.0 (Windows; U; Windows NT 6.1; uk; rv:1.9.1.5; zb-hb-nigger) Gecko/20091102 Firefox/3.5.5" +209.41.118.2 - - [04/Jan/2012:17:55:01 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.52.7 (KHTML, like Gecko) Version/5.1.2 Safari/534.52.7" +206.15.64.254 - - [04/Jan/2012:21:42:15 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1010.49.00 CFNetwork/520.2.5 Darwin/11.2.0 (x86_64) (MacBookPro8%2C2)" +105.140.135.6 - - [04/Jan/2012:22:15:18 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +184.107.233.98 - - [05/Jan/2012:03:49:17 +0000] "GET / HTTP/1.1" 200 45715 "-" "Mozilla/5.0 (compatible; Firefox Addon; Windows XP 5.1)" +122.170.84.210 - - [05/Jan/2012:12:51:02 +0000] "GET / HTTP/1.1" 200 3749 "http://stackoverflow.com/questions/5580776/monitoring-a-node-js-server" "Mozilla/5.0 (Ubuntu; X11; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0" +194.73.99.134 - - [05/Jan/2012:16:46:17 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 5.1; rv:8.0.1) Gecko/20100101 Firefox/8.0.1" +71.95.239.140 - - [05/Jan/2012:21:16:58 +0000] "GET / HTTP/1.1" 200 6063 "http://www.stumbleupon.com/refer.php?url=http%3A%2F%2Fwww.hid.im%2F" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0" +122.211.73.82 - - [06/Jan/2012:06:42:14 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +67.159.149.114 - - [06/Jan/2012:09:08:49 +0000] "GET / HTTP/1.1" 200 3749 "http://stackoverflow.com/questions/5580776/monitoring-a-node-js-server" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +82.80.184.41 - - [06/Jan/2012:10:38:57 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +194.15.212.33 - - [06/Jan/2012:12:40:05 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)" +95.45.199.134 - - [06/Jan/2012:14:57:25 +0000] "GET / HTTP/1.1" 200 6063 "-" "Mozilla/5.0 (Windows NT 6.0; rv:9.0.1) Gecko/20100101 Firefox/9.0.1" +209.85.238.246 - - [06/Jan/2012:19:59:55 +0000] "GET / HTTP/1.1" 200 45715 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +31.192.104.159 - - [06/Jan/2012:23:50:04 +0000] "GET / HTTP/1.0" 200 45715 "http://nuttnet.net/" "Mozilla/4.79 [en] (Windows NT 5.0; U)" +79.40.136.98 - - [07/Jan/2012:11:08:26 +0000] "GET / HTTP/1.1" 200 6063 "http://www.misterwebby.com/nascondi-file-torrent-con-hid-im/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.52.7 (KHTML, like Gecko) Version/5.1.2 Safari/534.52.7" +174.29.76.252 - - [07/Jan/2012:19:38:59 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +69.181.221.237 - - [08/Jan/2012:04:10:52 +0000] "GET / HTTP/1.1" 200 45715 "-" "Reeder/1.5.4 CFNetwork/548.0.4 Darwin/11.0.0" +67.180.152.46 - - [08/Jan/2012:17:33:18 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +213.110.133.221 - - [08/Jan/2012:20:13:48 +0000] "GET / HTTP/1.1" 200 6063 "http://www.perevezem.kiev.ua/" "BlackBerry6230/4.0.0 Profile/MIDP-2.0 Configuration/CLDC-1.1" +83.102.10.66 - - [09/Jan/2012:15:23:46 +0000] "GET / HTTP/1.1" 200 6063 "http://news.ycombinator.com/item?id=3441924" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +24.67.116.161 - - [09/Jan/2012:15:43:57 +0000] "GET / HTTP/1.1" 200 6063 "http://news.ycombinator.com/item?id=3441924" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.26 Safari/535.11" +88.217.77.182 - - [09/Jan/2012:18:15:45 +0000] "GET / HTTP/1.1" 200 6063 "http://news.ycombinator.com/item?id=3441924" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7" +89.152.187.56 - - [09/Jan/2012:18:21:17 +0000] "GET / HTTP/1.1" 200 3749 "-" "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7" +88.114.98.206 - - [09/Jan/2012:18:36:19 +0000] "GET / HTTP/1.1" 200 6063 "http://news.ycombinator.com/item?id=3441924" "Opera/9.80 (Windows NT 6.1; U; fi) Presto/2.10.229 Version/11.60" +65.197.140.204 - - [09/Jan/2012:22:06:40 +0000] "GET / HTTP/1.1" 200 3749 "http://hummingbirdstats.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7" +72.14.199.11 - - [10/Jan/2012:11:05:35 +0000] "GET / HTTP/1.1" 304 0 "-" "Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 1 subscribers; feed-id=4870417677770210375)" +189.72.78.244 - - [10/Jan/2012:11:51:23 +0000] "GET / HTTP/1.1" 200 3749 "http://projects.nuttnet.net/hummingbird/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7" diff --git a/server.js b/server.js index 8761c2f..cd638cd 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,7 @@ config = require('./config/config'); var dashboard = require('./lib/dashboard'); var tracker = require('./lib/tracker'); +var demo = require('./lib/demo'); dashboard.listen(config.dashboard_port, config.dashboard_address); @@ -22,3 +23,7 @@ console.log("Tracker listening on http://" + (config.dashboard_address || '*') + // UDP tracking // // tracker.listenUdp(8000, "0.0.0.0"); + +if(config.demo_mode) { + demo.run(tracker); +} From 504ff6ff4a68fef76436177c4d5d7d1f0ce90a1b Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 01:06:54 -0400 Subject: [PATCH 238/267] protect against no headers being sent to tracker --- lib/metrics/hits.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metrics/hits.js b/lib/metrics/hits.js index e42513d..5236206 100644 --- a/lib/metrics/hits.js +++ b/lib/metrics/hits.js @@ -12,7 +12,7 @@ hits.initialData = []; hits.interval = 200; // ms hits.increment = function(request) { this.data.push({ - url: request.headers.referer, + url: request.headers && request.headers.referer, timestamp: new Date(), ip: request.ip }); From 3c5ad4c4e7b7cddbc9da4769d51bcf9ab5691a25 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 01:07:05 -0400 Subject: [PATCH 239/267] tweaking the green --- public/css/map.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/map.css b/public/css/map.css index 6052897..a10f6d6 100644 --- a/public/css/map.css +++ b/public/css/map.css @@ -94,7 +94,7 @@ div.hummingbird_map g.open circle { } div.hummingbird_map g.cart_add circle { - fill: #41c241; + fill: #16de16; } div.hummingbird_map text.label { From 03c8afd89ed8d9ff8682b7fbf8e0a25b8402b712 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 01:46:42 -0400 Subject: [PATCH 240/267] upgrade geoip to support iso-8859-1 city names --- lib/metrics/locations.js | 15 ++++++++------- package.json | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index 04b5094..07d9495 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -2,12 +2,13 @@ // // Sends individual requests, geolocated using ip address -var geoip = require('geoip'); -var path = require('path'); +var util = require('util'); +var geoip = require('geoip'); +var path = require('path'); var Metric = require('../metric'); -var http = require('http'); -var zlib = require('zlib'); -var fs = require('fs'); +var http = require('http'); +var zlib = require('zlib'); +var fs = require('fs'); var GEO_IP_DOWNLOAD = "http://hummingbird-data.s3.amazonaws.com/GeoLiteCity.dat.gz" @@ -23,7 +24,7 @@ locations.ignoreOnEmpty = true; locations.increment = function(request) { var remoteAddress = this.ipFor(request); - var location = geoip.City.record_by_addr(cities, remoteAddress); + var location = cities.lookupSync(remoteAddress); if(location && location.latitude) { this.data.push({ @@ -63,7 +64,7 @@ locations.load = function(callback) { function setupCities() { try { - cities = geoip.open(cityPath); + cities = new geoip.City(cityPath); return callback(null); } catch(e) { return callback(new Error("Couldn't load geoip database " + cityPath)); diff --git a/package.json b/package.json index 2bac2af..04b025f 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "hummingbird", "description": "A node.js statistics server", - "version": "0.2.0-12", + "version": "0.2.0-17", "dependencies": { "socket.io": "0.9.6", "node-static": "0.5.9", - "geoip": "0.3.4-1" + "geoip": "0.4.6" }, "domains": [ "demo.hummingbirdstats.com" @@ -15,7 +15,7 @@ "url": "http://github.com/mnutt/hummingbird.git" }, "engines": { - "node": ">=0.3.0" + "node": ">=0.6.0" }, "subdomain": "hummingbird", "scripts": { From 8715f6fb3c8ecd354608ba71165b4d9cb986070b Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 01:51:33 -0400 Subject: [PATCH 241/267] don't show markers with no city --- public/js/widgets/map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index 703fef4..acde6b1 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -80,7 +80,7 @@ $.extend(Hummingbird.Map.prototype, { if(value && value.length > 0) { for(var i in value) { var geo = value[i]; - if(typeof(geo.latitude) == "undefined" || geo.city == "") { continue; } + if(typeof(geo.latitude) == "undefined" || ! geo.city || geo.city == "") { continue; } geo.label = [geo.city, (geo.country == 'US') ? geo.region : geo.country].join(', '); // Remove duplicates From ee724b5dafc99318fa66554b5dce602699130916 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 02:20:28 -0400 Subject: [PATCH 242/267] move sample traffic log from log/ to data/ for nodejitsu --- {log => data}/sample_traffic.log | 0 lib/demo.js | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename {log => data}/sample_traffic.log (100%) diff --git a/log/sample_traffic.log b/data/sample_traffic.log similarity index 100% rename from log/sample_traffic.log rename to data/sample_traffic.log diff --git a/lib/demo.js b/lib/demo.js index 513b1f4..9e4a0f9 100644 --- a/lib/demo.js +++ b/lib/demo.js @@ -7,7 +7,7 @@ var fs = require('fs'); var Metric = require('./metric'); exports.run = function() { - fs.readFile(__dirname + "/../log/sample_traffic.log", function(err, logFile) { + fs.readFile(__dirname + "/../data/sample_traffic.log", function(err, logFile) { if(err) { throw err; } var lines = logFile.toString().split("\n"); @@ -22,7 +22,7 @@ exports.run = function() { var ip = line.split(" ")[0]; var req = { params: {ip: ip}, headers: { referer: "/" } }; if(Math.random() * 8 > 7) { req.params.event = "cart_add"; } - console.log(req); + Metric.insert(req); setTimeout(function() { submitLine(lines.slice(1)); From 559c52387f5246b0baff3603dd6d425c33d95244 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 19 Sep 2012 22:17:43 -0400 Subject: [PATCH 243/267] clean up head and switch to html5 doctype --- public/index.html | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/public/index.html b/public/index.html index 3ee54bb..b6f17a4 100644 --- a/public/index.html +++ b/public/index.html @@ -1,17 +1,22 @@ - - + + + + + Hummingbird + + + + + + + - - @@ -23,13 +28,7 @@ - Hummingbird - - - - - From ec1424fe4478b704abd8e8a91428c860396a45f1 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 23 Sep 2012 00:38:07 -0400 Subject: [PATCH 244/267] main background --- public/css/main.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/css/main.css b/public/css/main.css index 7d52f0e..d1fbe42 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -1,8 +1,7 @@ @charset "utf-8"; body { - background-color: #211d29; - background: url(/images/header-bg.png); + background: #211d29 url(/images/header-bg.png); font-family: "Lucida Grande", Helvetica, sans-serif; margin: 0; } From 23ad1a2672ac2b865c4772aa633962413cdda1ae Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 23 Sep 2012 00:38:34 -0400 Subject: [PATCH 245/267] fix zoomRange for retina displays --- public/js/widgets/map.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index acde6b1..526b477 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -27,22 +27,23 @@ Hummingbird.Map = function(element, socket, options) { this.defaultZoom = $(window).height() > 760 ? 3 : 2; + var zoomFactor = Math.log(window.devicePixelRatio || 1) / Math.LN2; + if(zoomFactor > 0) { + var doubleSize = "-2x"; + } else { + var doubleSize = ""; + } + this.map = this.po.map() .container(this.element.get(0).appendChild(this.po.svg("svg"))) .center({lat: 31, lon: 10}) .zoom(this.defaultZoom) - .zoomRange([1, 7]) + .zoomRange([1, 7 - zoomFactor]) .add(this.po.interact()); - if(window.devicePixelRatio >= 2) { - var doubleSize = "-2x"; - } else { - var doubleSize = ""; - } - this.map.add(this.po.image() .url(this.po.url("https://movableink-hummingbird-tiles.s3.amazonaws.com/hummingbird-dark" + doubleSize + "/{Z}/{X}/{Y}.png")) - .zoom(function(z) { return z + Math.log(window.devicePixelRatio || 1) / Math.LN2; return 2; })); + .zoom(function(z) { return z + zoomFactor; return 2; })); this.map.add(this.po.compass() .pan("none")); From bdc0f1b6cab6e64793f90c23cb1b55808bf03e46 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 23 Sep 2012 01:06:01 -0400 Subject: [PATCH 246/267] add legend to map --- public/css/map.css | 35 +++++++++++++++++++++++++++++++++++ public/js/widgets/map.js | 24 +++++++++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/public/css/map.css b/public/css/map.css index a10f6d6..f945a76 100644 --- a/public/css/map.css +++ b/public/css/map.css @@ -113,3 +113,38 @@ div.hummingbird_map path.label { div.hummingbird_map g.point:hover circle.point { fill: #C90134; } + +div.hummingbird_map div.legend { + position: absolute; + left: 10px; + bottom: 7px; + font-weight: bold; + font-size: 12px; + color: #FFF; + z-index: 60; + text-shadow: 2px 2px 0 #000; +} + +div.hummingbird_map div.legend div { + position: relative; + display: inline-block; + margin-right: 1em; +} + +div.hummingbird_map div.legend div span { + display: inline-block; + width: 11px; + height: 11px; + border-radius: 12px; + position: relative; + top: 1px; + margin-right: 3px; +} + +div.hummingbird_map div.legend div.open span { + background-color: #0395FE; +} + +div.hummingbird_map div.legend div.cart_add span { + background-color: #16de16; +} diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index 526b477..ee5ad3c 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -18,7 +18,8 @@ Hummingbird.Map = function(element, socket, options) { averageOver: 1, // second ratePerSecond: 2, decimalPlaces: 0, - maxPlaces: 100 + maxPlaces: 100, + defaultEvent: "open" }; this.options = $.extend(defaults, options); @@ -53,6 +54,7 @@ Hummingbird.Map = function(element, socket, options) { this.key = function(d) { return [d.latitude, d.longitude, d.type].join(','); }; this.data = []; + this.eventTypes = {}; this.layer = d3.select("svg.map").insert("svg:g", ".compass"); this.transform = function(d) { @@ -68,6 +70,9 @@ Hummingbird.Map = function(element, socket, options) { this.layer.selectAll("g").attr("transform", this.transform.bind(this)); }).bind(this)); + this.legend = $("
"); + this.element.append(this.legend); + this.initialize(options); }; @@ -79,6 +84,8 @@ $.extend(Hummingbird.Map.prototype, { onMessage: function(value, average) { if(value && value.length > 0) { + var self = this; + for(var i in value) { var geo = value[i]; if(typeof(geo.latitude) == "undefined" || ! geo.city || geo.city == "") { continue; } @@ -100,7 +107,6 @@ $.extend(Hummingbird.Map.prototype, { if(!this.pageIsVisible()) { // Don't render anything, but remove the object from this.data after 5s - var self = this; setTimeout(function() { if(!self.pageIsVisible()) { for(var i = 0, len = self.data.length; i < len; i++) { @@ -117,7 +123,11 @@ $.extend(Hummingbird.Map.prototype, { var elements = this.layer.selectAll("g").data(this.data, this.key); elements.enter() .append("svg:g") - .attr("class", function(d) { return d.event || "open"; }) + .attr("class", function(d) { + var event = d.event || self.options.defaultEvent; + self.addToLegend(event); + return event; + }) .attr("transform", this.transform.bind(this)) .call( function(newElement) { @@ -171,6 +181,14 @@ $.extend(Hummingbird.Map.prototype, { } }, + addToLegend: function(type) { + if(!this.eventTypes[type]) { + this.eventTypes[type] = true; + + $("
").addClass(type).append(type).appendTo(this.legend); + } + } + }); Hummingbird.Map.bubble = function(textWidth, textHeight, angle, notch, direction) { From d1277c27fe9117799120fdba39eb5ec1c577ab6b Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 5 Oct 2012 00:06:25 -0400 Subject: [PATCH 247/267] don't use reserved static keyword --- lib/dashboard.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dashboard.js b/lib/dashboard.js index cc58fa8..9630dfa 100644 --- a/lib/dashboard.js +++ b/lib/dashboard.js @@ -1,8 +1,8 @@ -var socketio = require('socket.io'); -var static = require('node-static'); -var Metric = require('./metric'); +var socketio = require('socket.io'); +var staticServer = require('node-static'); +var Metric = require('./metric'); -var fileServer = new(static.Server)("./public"); +var fileServer = new(staticServer.Server)("./public"); var defaultHandler = function(request, response) { console.log(" - " + request.url); From a0891caa06b79a7d4070fae9f22f513e20995512 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 25 Sep 2012 00:36:30 -0400 Subject: [PATCH 248/267] use relative asset paths to assist in using frontend under a subdirectory --- public/css/login.css | 2 +- public/css/main.css | 6 +++--- public/index.html | 32 ++++++++++++++++---------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/public/css/login.css b/public/css/login.css index 4a953ec..839a3fa 100644 --- a/public/css/login.css +++ b/public/css/login.css @@ -1,5 +1,5 @@ #login div.logo { - background: url(/images/logo.png) top left no-repeat; + background: url(../images/logo.png) top left no-repeat; width: 300px; height: 324px; margin: auto; diff --git a/public/css/main.css b/public/css/main.css index d1fbe42..becaa1c 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -1,7 +1,7 @@ @charset "utf-8"; body { - background: #211d29 url(/images/header-bg.png); + background: #211d29 url(../images/header-bg.png); font-family: "Lucida Grande", Helvetica, sans-serif; margin: 0; } @@ -115,6 +115,6 @@ div.graph div.line { @font-face { font-family: 'TitilliumText14L800wt'; - src: url('/fonts/TitilliumText800wt.eot'); - src: local('TitilliumText14L'), local('TitilliumText14L-800wt'), url('/fonts/TitilliumText800wt.woff') format('woff'), url('/fonts/TitilliumText800wt.ttf') format('truetype'), url('/fonts/TitilliumText800wt.svg#TitilliumText14L-800wt') format('svg'); + src: url('../fonts/TitilliumText800wt.eot'); + src: local('TitilliumText14L'), local('TitilliumText14L-800wt'), url('../fonts/TitilliumText800wt.woff') format('woff'), url('../fonts/TitilliumText800wt.ttf') format('truetype'), url('../fonts/TitilliumText800wt.svg#TitilliumText14L-800wt') format('svg'); } diff --git a/public/index.html b/public/index.html index b6f17a4..ae6614d 100644 --- a/public/index.html +++ b/public/index.html @@ -8,27 +8,27 @@ - - - + + + - + - + - - - - - + + + + + - - - - - + + + + + - + From 3452bf189a2cbf572dd5b6b7aeccb25c10cc54d3 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Fri, 5 Oct 2012 00:31:19 -0400 Subject: [PATCH 249/267] remove protocol from map tiles --- public/js/widgets/map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index ee5ad3c..c84adc1 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -43,7 +43,7 @@ Hummingbird.Map = function(element, socket, options) { .add(this.po.interact()); this.map.add(this.po.image() - .url(this.po.url("https://movableink-hummingbird-tiles.s3.amazonaws.com/hummingbird-dark" + doubleSize + "/{Z}/{X}/{Y}.png")) + .url(this.po.url("//movableink-hummingbird-tiles.s3.amazonaws.com/hummingbird-dark" + doubleSize + "/{Z}/{X}/{Y}.png")) .zoom(function(z) { return z + zoomFactor; return 2; })); this.map.add(this.po.compass() From e32cb750327e75f918677dd670bb88d7cffb34f6 Mon Sep 17 00:00:00 2001 From: Mark Willis Date: Mon, 26 Nov 2012 17:04:17 +0000 Subject: [PATCH 250/267] Updated UDP tracker to work. Mainly missing server.bind() but tidied up a bit too. Updated client/upd_client_sample.js to work with the changes - this fires a single event Added udpSocketInterval.js this fires a message every 100ms. --- client/udpSocketInterval.js | 23 +++++++++++++++++++++++ client/udp_client_sample.js | 21 +++++++++++++-------- lib/tracker.js | 22 +++++++++++++++++----- 3 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 client/udpSocketInterval.js diff --git a/client/udpSocketInterval.js b/client/udpSocketInterval.js new file mode 100644 index 0000000..4093461 --- /dev/null +++ b/client/udpSocketInterval.js @@ -0,0 +1,23 @@ + +var Buffer = require('buffer').Buffer; +var dgram = require('dgram'); + +var sock = dgram.createSocket("udp4"); + +var data = { + ip: '127.0.0.1', + // '141.101.99.4', + event: 'cart_add', + headers: '/' // this is the full url +}; + + + + +var buf = new Buffer(JSON.stringify(data)); + +console.log('buf:' + buf); + +setInterval(function() { + sock.send(buf, 0, buf.length, 8000, "0.0.0.0"); +},100); diff --git a/client/udp_client_sample.js b/client/udp_client_sample.js index b4c9602..e78aee1 100644 --- a/client/udp_client_sample.js +++ b/client/udp_client_sample.js @@ -1,18 +1,23 @@ +var Buffer = require('buffer').Buffer; var dgram = require('dgram'); -function sendMessage(data) { - var message = new Buffer(JSON.stringify(data)); - var client = dgram.createSocket("udp4"); - client.send(message, 0, message.length, 8000, "localhost"); - client.close(); -} +var sock = dgram.createSocket("udp4"); -var msg = { +var data = { "ip" : "129.59.1.10", "timestamp" : "Sat Oct 23 2010 21:39:35 GMT-0400 (EDT)", "url_key" : 123, "product_id" : 456 }; -sendMessage(msg); + + + +var buf = new Buffer(JSON.stringify(data)); + +console.log('buf:' + buf); + +setInterval(function() { + sock.send(buf, 0, buf.length, 8000, "0.0.0.0"); +},100); diff --git a/lib/tracker.js b/lib/tracker.js index a6377d8..b50aaeb 100644 --- a/lib/tracker.js +++ b/lib/tracker.js @@ -1,5 +1,6 @@ var http = require('http'); var url = require('url'); +var dgram = require('dgram'); var Metric = require('./metric'); var pixel = require('./pixel'); @@ -33,16 +34,27 @@ exports.listen = function(server, address) { } }; + exports.listenUdp = function(port, address) { - var udpServer = dgram.createSocket("udp4"); + var server = dgram.createSocket("udp4"); - udpServer.on("message", function(message, rinfo) { + server.on("message", function (message, rinfo) { + var data; try { - var data = JSON.parse(message); + data = JSON.parse(message.toString()); } catch(e) { - console.log("Error parsing UDP message: " + e.message); + return console.log("Error parsing UDP message: " + e.message); } Metric.insert({ip: data.ip, params: data}); }); -}; + + server.on("listening", function () { + var address = server.address(); + console.log("server listening " + + address.address + ":" + address.port); + }); + + server.bind(port, address); + +}; \ No newline at end of file From a6bc04b68fcd8ad42253b02af12bc4df6b129136 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 23 Dec 2012 11:54:49 -0600 Subject: [PATCH 251/267] clean up sample client js code and improve README --- README.md | 27 +++++++++++++++++++-------- client/hummingbird.js | 40 ++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f0db9b0..36ecac4 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,24 @@ interfaces. You should then run the tracking pixel on a different port so that to the outside world. +Setting Up Tracking +------------------- + +The file `client/hummingbird.js` contains a small script to trigger a hummingbird event. You +can either paste the contents of the file into the body of your webpage or you can upload it +to your server as a .js file and reference it with a ` From a70e39e443a8802826fd755715e3114569bf9c68 Mon Sep 17 00:00:00 2001 From: Csaba Okrona Date: Wed, 13 Feb 2013 11:16:44 +0100 Subject: [PATCH 253/267] Fixed an array keying error in the 'hummingbird.js' sample js tracker code --- client/hummingbird.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/hummingbird.js b/client/hummingbird.js index 94bc2bb..e306267 100644 --- a/client/hummingbird.js +++ b/client/hummingbird.js @@ -19,7 +19,7 @@ HummingbirdTracker = { var params = []; for(var key in env) { if(env.hasOwnProperty(key)) { - params.push(encodeURIComponent(i) + "=" + encodeURIComponent(env[i])); + params.push(encodeURIComponent(key) + "=" + encodeURIComponent(env[key])); } } From 7f3cb493f06c55167765e57125429d4c5cdeb8c0 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 10 Mar 2013 12:00:59 -0400 Subject: [PATCH 254/267] update geoip module to partially fix a memory leak --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 04b025f..e926bd0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "socket.io": "0.9.6", "node-static": "0.5.9", - "geoip": "0.4.6" + "geoip": "0.4.8" }, "domains": [ "demo.hummingbirdstats.com" From c6636b72fc273bd597421b926302034e0a530a63 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 10 Mar 2013 12:52:47 -0400 Subject: [PATCH 255/267] switch geoip to fork that fixes the memory leak. fixes #50 --- lib/metrics/locations.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index 07d9495..86afe2e 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -3,7 +3,7 @@ // Sends individual requests, geolocated using ip address var util = require('util'); -var geoip = require('geoip'); +var geoip = require('geoip-no-city-leak'); var path = require('path'); var Metric = require('../metric'); var http = require('http'); diff --git a/package.json b/package.json index e926bd0..cea0be4 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "socket.io": "0.9.6", "node-static": "0.5.9", - "geoip": "0.4.8" + "geoip-no-city-leak": "0.4.9-1" }, "domains": [ "demo.hummingbirdstats.com" From 48fc93f7d2b6608f10d690b76acd77c7f6b996b6 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 20 Mar 2013 22:51:16 -0400 Subject: [PATCH 256/267] ignore history data --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8a1303b..49e0abd 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /config/app.json /node_modules /GeoLiteCity.dat +/data/*.json From 83980fdd43d99a0616dc7a63efb435f8fb39fd11 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Sun, 17 Apr 2011 15:35:23 -0400 Subject: [PATCH 257/267] raw widget --- public/js/widgets/raw.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 public/js/widgets/raw.js diff --git a/public/js/widgets/raw.js b/public/js/widgets/raw.js new file mode 100644 index 0000000..68351ad --- /dev/null +++ b/public/js/widgets/raw.js @@ -0,0 +1,20 @@ +if(!Hummingbird) { var Hummingbird = {}; } + +Hummingbird.Raw = function(element, socket, callback) { + this.element = element; + this.socket = socket; + this.callback = callback; + + this.options = {}; + + this.initialize(); +}; + +Hummingbird.Raw.prototype = new Hummingbird.Base(); + +$.extend(Hummingbird.Raw.prototype, { + name: "Raw", + onMessage: function(message) { + this.callback(message); + }, +}); From 9a9ce7bcf9255545ae17e65e89d90570975e6b1d Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 25 Mar 2013 22:45:23 -0400 Subject: [PATCH 258/267] add list of contributors --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 36ecac4..d22d4fc 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,15 @@ Contributors * Michael Nutt * Benny Wong + * mikecampo + * caphrim007 + * brianjriddle + * lbosque + * robertjwhitney + * Dan Thurman + * thinkroth + * markwillis82 + * ochronus License From 0256789dc80c4bcf5dd01b067788b7389779a5f7 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 25 Mar 2013 23:38:30 -0400 Subject: [PATCH 259/267] merge dannyakakong's fixes for zoom level and configuration --- config/config.js | 35 +++++++++++++++++++++-------------- public/js/widgets/map.js | 2 +- server.js | 30 +++++++++++++++++------------- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/config/config.js b/config/config.js index b47c8fb..93952e5 100644 --- a/config/config.js +++ b/config/config.js @@ -1,21 +1,28 @@ module.exports = config = { - "name" : "Hummingbird", + "name" : "Hummingbird", - "tracking_port" : 8000, - "dashboard_port" : 8080, + // Replay some existing traffic logs to get an idea of what Hummingbird + // looks like. Change this to false when you're ready to actually use + // Hummingbird in production. + "demo_mode": true, - "mongo_host" : "localhost", - "mongo_port" : 27017, + // Port where the dashboard will be shown. Change it to false to disable + // the dashboard. (you might do this if you were integrating + // Hummingbird into an existing admin interface) + "dashboard_port" : 8080, - "udp_address" : "127.0.0.1", - "udp_port" : 8000, + // If you want to have the tracking pixel listen on a different port + // (for instance in order to password-protect your dashboard) you can + // specify the port to listen on (change from false to port number) + "tracking_port" : 8000, - "enable_dashboard" : true, + // Allow stats to be sent over UDP instead of HTTP. This works best for + // sending stats from backend servers within the same datacenter as + // Hummingbird. Change to false to disable. + "udp_tracking_port" : 8000, - "demo_mode": true, - - "capistrano" : { - "repository" : "git://github.com/mnutt/hummingbird.git", - "hummingbird_host" : "hummingbird.your-host.com" - } + // Interface to bind the UDP listener to. Use 127.0.0.1 to only allow + // other apps on your machine to connect, or 0.0.0.0 to bind to all + // interfaces and allow any machine to connect. + "udp_trackin_address" : "127.0.0.1" } diff --git a/public/js/widgets/map.js b/public/js/widgets/map.js index c84adc1..9ac8f43 100644 --- a/public/js/widgets/map.js +++ b/public/js/widgets/map.js @@ -28,7 +28,7 @@ Hummingbird.Map = function(element, socket, options) { this.defaultZoom = $(window).height() > 760 ? 3 : 2; - var zoomFactor = Math.log(window.devicePixelRatio || 1) / Math.LN2; + var zoomFactor = Math.round(Math.log(window.devicePixelRatio || 1) / Math.LN2); if(zoomFactor > 0) { var doubleSize = "-2x"; } else { diff --git a/server.js b/server.js index cd638cd..ec04545 100644 --- a/server.js +++ b/server.js @@ -5,25 +5,29 @@ var tracker = require('./lib/tracker'); var demo = require('./lib/demo'); +// Setup dashboard port listener dashboard.listen(config.dashboard_port, config.dashboard_address); -console.log("Dashboard listening on http://" + (config.dashboard_address || '*') + ":" + config.dashboard_port + "."); +console.log("Dashboard listening on http://" + (config.dashboard_address || "*") + ":" + config.dashboard_port + "."); -// Tracker should listen on the same port as the dashboard -tracker.listen(dashboard); -console.log("Tracker listening on http://" + (config.dashboard_address || '*') + ":" + config.dashboard_port + "/tracking_pixel.gif."); +// Setup tracker port listener... +if (typeof config.tracking_port != 'number') { + // Tracker should listen on the same port as the dashboard + tracker.listen(dashboard); +} else { + // Tracker should listen on specified port + tracker.listen(config.tracking_port, config.tracking_address); +} -// If you want to have the tracking pixel listen on a different port -// (for instance in order to password-protect your dashboard) you can -// uncomment this -// -// tracker.listen(8000, "0.0.0.0"); +console.log("Tracker listening on http://" + (config.tracking_address || "*") + ":" + (config.tracking_port || config.dashboard_port) + "/tracking_pixel.gif."); -// UDP tracking -// -// tracker.listenUdp(8000, "0.0.0.0"); +// Setup UDP tracking +if (typeof config.udp_tracking_port == 'number') { + tracker.listenUdp((config.udp_tracking_port || 8000), (config.udp_tracking_address || "0.0.0.0")); +} -if(config.demo_mode) { +// Run in demo mode +if (config.demo_mode) { demo.run(tracker); } From 5eccfcb81190a19ba8c3b413e4cc0e3148727122 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Mon, 25 Mar 2013 23:39:48 -0400 Subject: [PATCH 260/267] add dannyakakong as contributor --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d22d4fc..883d2cc 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ Contributors * thinkroth * markwillis82 * ochronus + * dannyakakong License From 040453056f1c0ea2b3ddeb858e46afeba2f37a08 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Tue, 26 Mar 2013 00:00:03 -0400 Subject: [PATCH 261/267] gitignore config and automatically copy from the sample if it doesn't exist --- .gitignore | 2 +- config/app.json.sample | 19 ------------------- config/{config.js => config.example.js} | 0 lib/config.js | 12 ++++++++++++ server.js | 2 +- 5 files changed, 14 insertions(+), 21 deletions(-) delete mode 100644 config/app.json.sample rename config/{config.js => config.example.js} (100%) create mode 100644 lib/config.js diff --git a/.gitignore b/.gitignore index 49e0abd..8c1c06d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ *.swp /backups -/config/app.json +/config/config.js /node_modules /GeoLiteCity.dat /data/*.json diff --git a/config/app.json.sample b/config/app.json.sample deleted file mode 100644 index 3443119..0000000 --- a/config/app.json.sample +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name" : "Hummingbird", - - "tracking_port" : 8000, - "dashboard_port" : 8080, - - "mongo_host" : "localhost", - "mongo_port" : 27017, - - "udp_address" : "127.0.0.1", - "udp_port" : 8000, - - "enable_dashboard" : true, - - "capistrano" : { - "repository" : "git://github.com/mnutt/hummingbird.git", - "hummingbird_host" : "hummingbird.your-host.com" - } -} diff --git a/config/config.js b/config/config.example.js similarity index 100% rename from config/config.js rename to config/config.example.js diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..539e6da --- /dev/null +++ b/lib/config.js @@ -0,0 +1,12 @@ +var fs = require('fs'); + +var configPath = __dirname + "/../config/config.js"; +var sampleConfigPath = __dirname + "/../config/config.example.js"; + +if(fs.existsSync(configPath)) { + module.exports = require(configPath); +} else { + console.log("config/config.js doesn't exist; creating it..."); + fs.createReadStream(sampleConfigPath).pipe(fs.createWriteStream(configPath)); + module.exports = require(sampleConfigPath); +} diff --git a/server.js b/server.js index ec04545..b0eecfd 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,4 @@ -config = require('./config/config'); +config = require('./lib/config'); var dashboard = require('./lib/dashboard'); var tracker = require('./lib/tracker'); From eecf4087d1a5c17864b45f304dd3a84c97009074 Mon Sep 17 00:00:00 2001 From: Zainan Victor Zhou Date: Thu, 11 Jul 2013 13:46:33 -0700 Subject: [PATCH 262/267] User new geoip --- lib/metrics/locations.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/metrics/locations.js b/lib/metrics/locations.js index 86afe2e..07d9495 100644 --- a/lib/metrics/locations.js +++ b/lib/metrics/locations.js @@ -3,7 +3,7 @@ // Sends individual requests, geolocated using ip address var util = require('util'); -var geoip = require('geoip-no-city-leak'); +var geoip = require('geoip'); var path = require('path'); var Metric = require('../metric'); var http = require('http'); diff --git a/package.json b/package.json index cea0be4..d3abb83 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "socket.io": "0.9.6", "node-static": "0.5.9", - "geoip-no-city-leak": "0.4.9-1" + "geoip": "0.4.10" }, "domains": [ "demo.hummingbirdstats.com" From 1a7133c89ee0c80d78815a6d1889d88aa938df44 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 4 Dec 2013 17:39:37 -0500 Subject: [PATCH 263/267] allow starting with 'npm start' --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d3abb83..7723e06 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,6 @@ }, "subdomain": "hummingbird", "scripts": { - "start": "server.js" + "start": "node server.js" } } From 5d6b24bcb938d142eb888b574536cf9f1e598a43 Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 4 Dec 2013 17:40:37 -0500 Subject: [PATCH 264/267] upgrade geoip to latest version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7723e06..fb63f61 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "socket.io": "0.9.6", "node-static": "0.5.9", - "geoip": "0.4.10" + "geoip": "0.4.12" }, "domains": [ "demo.hummingbirdstats.com" From 72d90e0865a87593e33927a125bd9c2b2db033bb Mon Sep 17 00:00:00 2001 From: Michael Nutt Date: Wed, 4 Dec 2013 17:42:10 -0500 Subject: [PATCH 265/267] update readme with node requirements and contributors --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 883d2cc..f62198c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ sends back tracking data generated by javascript. Requirements ------------------- - * node.js v0.8.0 + * node.js v0.8.0 or higher Installation -------------- @@ -124,6 +124,7 @@ Contributors * markwillis82 * ochronus * dannyakakong + * xinbenlv License From ae91d0316d8cb7f0d06f6d63267e66e9716f9d22 Mon Sep 17 00:00:00 2001 From: Frank Lemanschik Date: Mon, 14 Apr 2014 09:35:58 +0200 Subject: [PATCH 266/267] Checked out https://github.com/mnutt/hummingbird and deleted old useless code :D --- README | 6 - TODO | 5 - ft_client/form.html | 55 -- ft_client/index.html | 151 ------ ft_client/js/.htaccess | 21 - ft_client/js/freetale.js | 219 -------- ft_client/js/freetaleform.js | 238 -------- ft_client/js/index.php | 18 - ft_client/js/jquery-1.3.2.min.js | 19 - ft_client/js/jquery.cookie.js | 96 ---- ft_client/js/jquery.dimensions.js | 12 - ft_client/js/jquery.scrollTo-min.js | 11 - ft_client/js/jquery.scrollTo.js | 215 -------- ft_client/js/urlencode.js | 87 --- ft_server/admin/.htaccess | 3 - ft_server/admin/admin_db_view.php | 63 --- ft_server/admin/admin_form_view.php | 198 ------- ft_server/admin/admin_form_view_summary.php | 231 -------- ft_server/admin/admin_parse_log.php | 201 ------- ft_server/admin/admin_replay.php | 81 --- ft_server/admin/admin_replay_summary.php | 93 ---- ft_server/admin/auth_db.inc.php | 32 -- ft_server/admin/index.php | 48 -- ft_server/admin/login.php | 73 --- ft_server/admin/login_change.php | 85 --- ft_server/admin/login_change_do.php | 61 --- ft_server/admin/login_is.php | 45 -- ft_server/admin/login_out.php | 5 - ft_server/admin/makedb.php | 68 --- ft_server/cdot.png | Bin 856 -> 0 bytes ft_server/db/auth.sqlite | Bin 2048 -> 0 bytes ft_server/dot.png | Bin 812 -> 0 bytes ft_server/form_gif.php | 88 --- ft_server/gif.php | 92 ---- ft_server/includes/conf.inc.php | 73 --- ft_server/includes/db.inc.php | 571 -------------------- ft_server/includes/debug.inc.php | 65 --- ft_server/replay.php | 40 -- ft_server/replay_motion.php | 191 ------- ft_server/replay_summary.php | 20 - 40 files changed, 3580 deletions(-) delete mode 100644 README delete mode 100644 TODO delete mode 100644 ft_client/form.html delete mode 100644 ft_client/index.html delete mode 100644 ft_client/js/.htaccess delete mode 100644 ft_client/js/freetale.js delete mode 100644 ft_client/js/freetaleform.js delete mode 100644 ft_client/js/index.php delete mode 100644 ft_client/js/jquery-1.3.2.min.js delete mode 100644 ft_client/js/jquery.cookie.js delete mode 100644 ft_client/js/jquery.dimensions.js delete mode 100644 ft_client/js/jquery.scrollTo-min.js delete mode 100644 ft_client/js/jquery.scrollTo.js delete mode 100644 ft_client/js/urlencode.js delete mode 100644 ft_server/admin/.htaccess delete mode 100644 ft_server/admin/admin_db_view.php delete mode 100644 ft_server/admin/admin_form_view.php delete mode 100644 ft_server/admin/admin_form_view_summary.php delete mode 100644 ft_server/admin/admin_parse_log.php delete mode 100644 ft_server/admin/admin_replay.php delete mode 100644 ft_server/admin/admin_replay_summary.php delete mode 100644 ft_server/admin/auth_db.inc.php delete mode 100644 ft_server/admin/index.php delete mode 100644 ft_server/admin/login.php delete mode 100644 ft_server/admin/login_change.php delete mode 100644 ft_server/admin/login_change_do.php delete mode 100644 ft_server/admin/login_is.php delete mode 100644 ft_server/admin/login_out.php delete mode 100644 ft_server/admin/makedb.php delete mode 100644 ft_server/cdot.png delete mode 100644 ft_server/db/auth.sqlite delete mode 100644 ft_server/dot.png delete mode 100644 ft_server/form_gif.php delete mode 100644 ft_server/gif.php delete mode 100644 ft_server/includes/conf.inc.php delete mode 100644 ft_server/includes/db.inc.php delete mode 100644 ft_server/includes/debug.inc.php delete mode 100644 ft_server/replay.php delete mode 100644 ft_server/replay_motion.php delete mode 100644 ft_server/replay_summary.php diff --git a/README b/README deleted file mode 100644 index e38ad67..0000000 --- a/README +++ /dev/null @@ -1,6 +0,0 @@ -This is on github now, but unless you are a contributing developer, -you should run far, far away from this code. - -I use *nix, so i am using *nix style text files, if you open this in -notepad and it looks all funky, you know why. - diff --git a/TODO b/TODO deleted file mode 100644 index 931cab6..0000000 --- a/TODO +++ /dev/null @@ -1,5 +0,0 @@ -Many todos in the files, but this is like the "Meta" todo list, it is -not even remotely close to exhaustive. - -TODO: deal with urls with hash marks http://site.faux/index.php#whatever - diff --git a/ft_client/form.html b/ft_client/form.html deleted file mode 100644 index e93a700..0000000 --- a/ft_client/form.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - -FreeTale for Client with a Form - - - - - - - - - - - - - - - - -
- -
-
- -
-
-
- - - -
-
-
- - -
- - - diff --git a/ft_client/index.html b/ft_client/index.html deleted file mode 100644 index 04d35a6..0000000 --- a/ft_client/index.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - Example of FreeTale Client Page - - - - - - - - - - - - - - - - - - - - - - - -

- - This Page is Now Recording All your Mouse Motions, Scrolls and - Clicks to a database on a FreeTale Server. - -

- -
    - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • -
  • space
  • - -
- - -

- - Wow you scrolled all the way down here! - -

- -

- - You should click something too, even if its not clicky - -

- - - - diff --git a/ft_client/js/.htaccess b/ft_client/js/.htaccess deleted file mode 100644 index 8b46c72..0000000 --- a/ft_client/js/.htaccess +++ /dev/null @@ -1,21 +0,0 @@ -# -*- conf -*- -# @author: Victory -# @site: http://dfhu.org -# @copyright: dfhu.org -# @report_bugs: bugs(at)dfhu.org -# @feature_request: features(at)dfhu.org -# @file: scrollingheatmap/js/.htaccess -# @license: BSD -# -# @description: -# -# This file is great. -# -# $Date:: 2009-08-15 12:38:19 #$: -# $Rev:: 2 $: - - - -RewriteEngine On -RewriteRule !\.js$ - [F] - \ No newline at end of file diff --git a/ft_client/js/freetale.js b/ft_client/js/freetale.js deleted file mode 100644 index 374630e..0000000 --- a/ft_client/js/freetale.js +++ /dev/null @@ -1,219 +0,0 @@ -/* - -@author: Victory -@site: http://dfhu.org -@copyright: dfhu.org -@report_bugs: bugs(at)dfhu.org -@feature_request: features(at)dfhu.org -@file: -@license: BSD - -@description: - - This file is great. - -TODO: Remove mention of iseeyou the lame first name, its should be -called freetale - - -*/ -jQuery(function($){ - //alert($(document.body).height()); - - // do not record if we are in an iframe - if(window.top != window){ - return; - } - - var tic=now(); - var scrollMotion = new Array(); - scrollMotion[0] = lowestVisible(); - var mouseMotion = new Array(); - var mouseClicks = new Array(); - - var freetaleCookieName='freetale_id'; - - // store mouse movements - $(document).mousemove(function(e){ - mouseMotion[mouseMotion.length] = - mouseCoordinates(e); - }); - - // store scroll events - $(window).scroll(function(e){ - scrollMotion[scrollMotion.length] = - lowestVisible(); - }); - - // store click coordinates - $(document).click(function(e){ - - // e.button - mouseClicks[mouseClicks.length] = - mouseCoordinates(e); - }); - - function mouseCoordinates(e){ - // get X by Y coordinates of the mouse at event e - return e.pageX +'x'+ e.pageY; - } - - function lowestVisible(){ - // Get the lowest Visible point in the browser - return $(document).scrollTop()+$(window).height(); - } - - function now(){ - var now=new Date(); - return Math.floor(now.getTime()/100); - } - - - function conciseQuery(queryName,vals,maxLength){ - /* - - Create a &foo[]=132&foo[]=456&foo[]=784 type string from queryName - "foo" and vals which is an array of vals - - @param string queryName - the name of the variable as seen in the - query string - - @param array vals - array of values to append to query string - - @param int maxLength - the maximum number of values to append, if - vals.length > maxLength then we step through the array skiping - some vals - - */ - - // We set the step size to limit the length of query, this is just - // the number of values we will append. - var step=Math.ceil(vals.length/maxLength); - - var val=""; - // iterate over all the vals and ... - for(ii in vals){ - // ... if we are on step'th value, then .. - if( ii % step == 0){ - // ... append the &foo[]=123 type string - val=val + "&" + - queryName + "[]=" + - vals[ii]; - } - } - - // if we had no vals, then just send an empty var - if(val == ""){ - val="&" + queryName + "[]="; - } - return val; - } - - function getMotionQuery(){ - /* - - Create a query string from the recorded montions and clicks - - */ - - var maxLength=10; - var windowWidth = $(window).width(); - var windowHeight = $(window).height(); - var elapsedTime = now() - tic; - var bodyHeight = $(document.body).height(); - var q; - - q="?" + - "i=" + $.cookie(freetaleCookieName) + - "&r=" + urlencode(document.referrer) + - "&l=" + urlencode(window.location) + - "&w=" + windowWidth + - "&h=" + windowHeight + - "&b=" + bodyHeight + - "&t=" + elapsedTime + - conciseQuery("c",mouseClicks,maxLength) + - conciseQuery("m",mouseMotion,maxLength) + - conciseQuery("s",scrollMotion,maxLength); - - if(q.length > 1950){ - return ""; - } - - return q; - } - - function recordMotion(){ - /* - - Create a new Image, which has as its query string an encoding of - the mousemotions, clicks and scrolls if any such motions have - taken place. - - */ - - if(scrollMotion.length == 0 && - mouseMotion.length == 0 && - mouseClicks.length == 0){ - return; - } - - var q=getMotionQuery(); - var trackingImg = new Image(); - trackingImg.src = tracking_gif + q; - - //$('body').append(q + "

"); - - scrollMotion = new Array(); - mouseMotion = new Array(); - mouseClicks = new Array(); - } - - - function cookieCheck(){ - - // Session if, user - var freetale_id; - if(freetale_id=$.cookie(freetaleCookieName)){ - //alert(freetale_id); - - var bits=freetale_id.split("_"); - var tail=parseInt(bits[1])+1; - - freetale_id=bits[0] + "_" + tail; - - $.cookie(freetaleCookieName, - freetale_id, - {expires: 7}); - return; - } - - var rndId= - Math.floor(999999*Math.random()); - - $.cookie(freetaleCookieName, - rndId + "_1", - {expires: 7}); - - }; - cookieCheck(); - - /**/ - window.setInterval(recordMotion, - 500); - /**/ - - - /*************************************** - - - Begin logic for form analytics - - TODO: merg that code here - - ****************************************/ - - - - - -}); \ No newline at end of file diff --git a/ft_client/js/freetaleform.js b/ft_client/js/freetaleform.js deleted file mode 100644 index b90e224..0000000 --- a/ft_client/js/freetaleform.js +++ /dev/null @@ -1,238 +0,0 @@ -jQuery(function($){ - - - var blur=""; - var keyupCount=0; - var freetaleCookieName='freetaleform_id'; - - function cookieCheck(){ - - // if we already have a cookie, just use it - if(freetale_id=$.cookie(freetaleCookieName)){ - return; - } - // other wise we generate one - var rndId= - Math.floor(999999*Math.random()); - - $.cookie(freetaleCookieName, - rndId + "_1", - {expires: 7}); - - }; - cookieCheck(); - - - function now(){ - var now=new Date().getTime(); - return Math.ceil(now/1000); - } - function getParentFormId(o){ - var id=""; - id=o.parent("form").attr("id") - if(typeof(id) == 'undefined'){ - id=o.attr("id"); - } - return id; - } - function getName(o){ - return o.attr("name"); - } - - var initTime=-1; - function getElapsedTime(){ - /* - return the elapsed time since Init. initTime start on the first - keyup on an input/textarea element - */ - return now()-initTime; - } - function isClocking(){ - return initTime != -1; - } - function startClocking(){ - initTime=now(); - } - - function getClockString(thisObject){ - /* - - Returns Formated strings - - @param $(this) thisObject - element in a form - - @return string - something slike theform||firstname||30 - */ - return getParentFormId(thisObject) + - "||" + - getName(thisObject) + - "||" + - getElapsedTime(); - } - - function updateKeyupCount(name){ - keyupCount=keyupCount+1; - } - - function getKeyupCountString(){ - return keyupCount; - } - - function getBlurQuery(blur){ - var bits=blur.split("||"); - - var val = - "&f=" + urlencode(bits[0]) + - "&n=" + urlencode(bits[1]) + - "&c=" + bits[2]; - - return val; - } - - function getFormActionQuery(inputType){ - var q; - - q="?" + - "i=" + $.cookie(freetaleCookieName) + - "&r=" + urlencode(document.referrer) + - "&l=" + urlencode(window.location) + - "&t=" + inputType + - getBlurQuery(blur) + - "&k=" + keyupCount; - - return q; - } - - function inputFocus(){ - if(!isClocking()) - return; - startClocking(); - } - - function inputBlur(){ - if(!isClocking()) - return; - blur=getClockString($(this)); - - $('body').append("blur - " + getClockString($(this)) + "
"); - - // send for the form_gif.php - // TODO: need to fix this for textarea - storeActions($(this).attr('type')); - - } - - function inputKeyup(){ - - // If we haven't started clocking then ... - if(!isClocking()) - // ... its about time we start - startClocking(); - - // the JSON object uses the name to refrence. - var name=$(this).attr('name'); - - // a rose by any other name is still a rose, but a rose with - // an undefined name is a no good, dirty tramp. - if(typeof(name) == 'undefined') - return; - - // record the keyup event (just a counter) - updateKeyupCount(name); - - //$('body').append(getKeyupCountString(name) + "
"); - - } - - function bindActions(elements){ - for(ii in elements){ - - // We just brute force unbind all the elements, so we dont' - // windup doing multiple binds. Yes we call bindActions after - // every call to storeActions. Why? Well, because if your web - // 2.0 deally ads new elements to the form on some action like - // "choose state->choose town" then we need to pick up the new - // elements too. - $(elements[ii]).unbind('focus',inputFocus); - $(elements[ii]).unbind('blur',inputBlur); - $(elements[ii]).unbind('keyup',inputKeyup); - - // on focus we (re)start the clock, read the keyup comment too. - $(elements[ii]). - bind('focus',inputFocus); - - // when we blur we do a storeActions. - $(elements[ii]). - bind('blur',inputBlur); - - // We record the number of keyup events, for each named - // input/textarea on the page. Recoding of form action only - // starts when a named input starts getting input. We use this - // istead of the first on focus because, sometimes forms get - // focus before the user is ready to fill them out. - $(elements[ii]). - bind('keyup',inputKeyup); - - } - }// timeIt - - function storeActions(inputType){ - - var q=getFormActionQuery(inputType); - form_gif_location="http://site/FreeTale/ft_server/form_gif.php" - - var gifLocation=form_gif_location+q; - - var formGif=new Image(); - formGif.src = gifLocation; - - $('body').append("
" + gifLocation + "
"); - - blur=new Array(); - keyupCount=0; - - /* - - We rebind, incase the users action results in new form elements - being added. Like if the user selected "state" and so now there is - a "city" element. - - */ - bindActions(actionElements); - } - - - $("form").bind("submit",function(){ - var form_id=$(this).attr("id"); - var submit_name= - $("[input[type='submit']",this) - .attr("value"); - - blur=urlencode(form_id) + - "||" + - urlencode(submit_name) + - "||0"; - //inputBlur(); - storeActions('submit'); - }); - - - - - var actionElements= - new Array( - "textarea", - "select", - "input[type='text']", - "input[type='password']", - "input[type='file']", - "input[type='radio']", - "input[type='checkbox']"); - - bindActions(actionElements); - - // we start off with a faux blur just to say, "hey! i landed." I - // thought of the idea while standing in baggage reclaim. - storeActions('landing'); - -}); \ No newline at end of file diff --git a/ft_client/js/index.php b/ft_client/js/index.php deleted file mode 100644 index 7915db0..0000000 --- a/ft_client/js/index.php +++ /dev/null @@ -1,18 +0,0 @@ - \ No newline at end of file diff --git a/ft_client/js/jquery-1.3.2.min.js b/ft_client/js/jquery-1.3.2.min.js deleted file mode 100644 index b1ae21d..0000000 --- a/ft_client/js/jquery-1.3.2.min.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * jQuery JavaScript Library v1.3.2 - * http://jquery.com/ - * - * Copyright (c) 2009 John Resig - * Dual licensed under the MIT and GPL licenses. - * http://docs.jquery.com/License - * - * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) - * Revision: 6246 - */ -(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); -/* - * Sizzle CSS Selector Engine - v0.9.3 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/ft_client/js/jquery.cookie.js b/ft_client/js/jquery.cookie.js deleted file mode 100644 index 6df1fac..0000000 --- a/ft_client/js/jquery.cookie.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Cookie plugin - * - * Copyright (c) 2006 Klaus Hartl (stilbuero.de) - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * - */ - -/** - * Create a cookie with the given name and value and other optional parameters. - * - * @example $.cookie('the_cookie', 'the_value'); - * @desc Set the value of a cookie. - * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); - * @desc Create a cookie with all available options. - * @example $.cookie('the_cookie', 'the_value'); - * @desc Create a session cookie. - * @example $.cookie('the_cookie', null); - * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain - * used when the cookie was set. - * - * @param String name The name of the cookie. - * @param String value The value of the cookie. - * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. - * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. - * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. - * If set to null or omitted, the cookie will be a session cookie and will not be retained - * when the the browser exits. - * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). - * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). - * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will - * require a secure protocol (like HTTPS). - * @type undefined - * - * @name $.cookie - * @cat Plugins/Cookie - * @author Klaus Hartl/klaus.hartl@stilbuero.de - */ - -/** - * Get the value of a cookie with the given name. - * - * @example $.cookie('the_cookie'); - * @desc Get the value of a cookie. - * - * @param String name The name of the cookie. - * @return The value of the cookie. - * @type String - * - * @name $.cookie - * @cat Plugins/Cookie - * @author Klaus Hartl/klaus.hartl@stilbuero.de - */ -jQuery.cookie = function(name, value, options) { - if (typeof value != 'undefined') { // name and value given, set cookie - options = options || {}; - if (value === null) { - value = ''; - options.expires = -1; - } - var expires = ''; - if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { - var date; - if (typeof options.expires == 'number') { - date = new Date(); - date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); - } else { - date = options.expires; - } - expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE - } - // CAUTION: Needed to parenthesize options.path and options.domain - // in the following expressions, otherwise they evaluate to undefined - // in the packed version for some reason... - var path = options.path ? '; path=' + (options.path) : ''; - var domain = options.domain ? '; domain=' + (options.domain) : ''; - var secure = options.secure ? '; secure' : ''; - document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); - } else { // only name given, get cookie - var cookieValue = null; - if (document.cookie && document.cookie != '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = jQuery.trim(cookies[i]); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) == (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; - } -}; \ No newline at end of file diff --git a/ft_client/js/jquery.dimensions.js b/ft_client/js/jquery.dimensions.js deleted file mode 100644 index 552fd89..0000000 --- a/ft_client/js/jquery.dimensions.js +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net) - * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) - * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. - * - * $LastChangedDate: 2009-08-15 12:38:19 -0400 (Sat, 15 Aug 2009) $ - * $Rev: 2 $ - * - * Version: 1.2 - * - * Requires: jQuery 1.2+ - */ -(function($){$.dimensions={version:'1.2'};$.each(['Height','Width'],function(i,name){$.fn['inner'+name]=function(){if(!this[0])return;var torl=name=='Height'?'Top':'Left',borr=name=='Height'?'Bottom':'Right';return this.is(':visible')?this[0]['client'+name]:num(this,name.toLowerCase())+num(this,'padding'+torl)+num(this,'padding'+borr);};$.fn['outer'+name]=function(options){if(!this[0])return;var torl=name=='Height'?'Top':'Left',borr=name=='Height'?'Bottom':'Right';options=$.extend({margin:false},options||{});var val=this.is(':visible')?this[0]['offset'+name]:num(this,name.toLowerCase())+num(this,'border'+torl+'Width')+num(this,'border'+borr+'Width')+num(this,'padding'+torl)+num(this,'padding'+borr);return val+(options.margin?(num(this,'margin'+torl)+num(this,'margin'+borr)):0);};});$.each(['Left','Top'],function(i,name){$.fn['scroll'+name]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(name=='Left'?val:$(window)['scrollLeft'](),name=='Top'?val:$(window)['scrollTop']()):this['scroll'+name]=val;}):this[0]==window||this[0]==document?self[(name=='Left'?'pageXOffset':'pageYOffset')]||$.boxModel&&document.documentElement['scroll'+name]||document.body['scroll'+name]:this[0]['scroll'+name];};});$.fn.extend({position:function(){var left=0,top=0,elem=this[0],offset,parentOffset,offsetParent,results;if(elem){offsetParent=this.offsetParent();offset=this.offset();parentOffset=offsetParent.offset();offset.top-=num(elem,'marginTop');offset.left-=num(elem,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&$.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return $(offsetParent);}});function num(el,prop){return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;};})(jQuery); \ No newline at end of file diff --git a/ft_client/js/jquery.scrollTo-min.js b/ft_client/js/jquery.scrollTo-min.js deleted file mode 100644 index 73a3341..0000000 --- a/ft_client/js/jquery.scrollTo-min.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * jQuery.ScrollTo - Easy element scrolling using jQuery. - * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com - * Dual licensed under MIT and GPL. - * Date: 5/25/2009 - * @author Ariel Flesler - * @version 1.4.2 - * - * http://flesler.blogspot.com/2007/10/jqueryscrollto.html - */ -;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery); \ No newline at end of file diff --git a/ft_client/js/jquery.scrollTo.js b/ft_client/js/jquery.scrollTo.js deleted file mode 100644 index eec31e1..0000000 --- a/ft_client/js/jquery.scrollTo.js +++ /dev/null @@ -1,215 +0,0 @@ -/** - * jQuery.ScrollTo - * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com - * Dual licensed under MIT and GPL. - * Date: 5/25/2009 - * - * @projectDescription Easy element scrolling using jQuery. - * http://flesler.blogspot.com/2007/10/jqueryscrollto.html - * Works with jQuery +1.2.6. Tested on FF 2/3, IE 6/7/8, Opera 9.5/6, Safari 3, Chrome 1 on WinXP. - * - * @author Ariel Flesler - * @version 1.4.2 - * - * @id jQuery.scrollTo - * @id jQuery.fn.scrollTo - * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements. - * The different options for target are: - * - A number position (will be applied to all axes). - * - A string position ('44', '100px', '+=90', etc ) will be applied to all axes - * - A jQuery/DOM element ( logically, child of the element to scroll ) - * - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc ) - * - A hash { top:x, left:y }, x and y can be any kind of number/string like above. -* - A percentage of the container's dimension/s, for example: 50% to go to the middle. - * - The string 'max' for go-to-end. - * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead. - * @param {Object,Function} settings Optional set of settings or the onAfter callback. - * @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'. - * @option {Number} duration The OVERALL length of the animation. - * @option {String} easing The easing method for the animation. - * @option {Boolean} margin If true, the margin of the target element will be deducted from the final position. - * @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }. - * @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes. - * @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends. - * @option {Function} onAfter Function to be called after the scrolling ends. - * @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends. - * @return {jQuery} Returns the same jQuery object, for chaining. - * - * @desc Scroll to a fixed position - * @example $('div').scrollTo( 340 ); - * - * @desc Scroll relatively to the actual position - * @example $('div').scrollTo( '+=340px', { axis:'y' } ); - * - * @dec Scroll using a selector (relative to the scrolled element) - * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } ); - * - * @ Scroll to a DOM element (same for jQuery object) - * @example var second_child = document.getElementById('container').firstChild.nextSibling; - * $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){ - * alert('scrolled!!'); - * }}); - * - * @desc Scroll on both axes, to different values - * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } ); - */ -;(function( $ ){ - - var $scrollTo = $.scrollTo = function( target, duration, settings ){ - $(window).scrollTo( target, duration, settings ); - }; - - $scrollTo.defaults = { - axis:'xy', - duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1 - }; - - // Returns the element that needs to be animated to scroll the window. - // Kept for backwards compatibility (specially for localScroll & serialScroll) - $scrollTo.window = function( scope ){ - return $(window)._scrollable(); - }; - - // Hack, hack, hack :) - // Returns the real elements to scroll (supports window/iframes, documents and regular nodes) - $.fn._scrollable = function(){ - return this.map(function(){ - var elem = this, - isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1; - - if( !isWin ) - return elem; - - var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem; - - return $.browser.safari || doc.compatMode == 'BackCompat' ? - doc.body : - doc.documentElement; - }); - }; - - $.fn.scrollTo = function( target, duration, settings ){ - if( typeof duration == 'object' ){ - settings = duration; - duration = 0; - } - if( typeof settings == 'function' ) - settings = { onAfter:settings }; - - if( target == 'max' ) - target = 9e9; - - settings = $.extend( {}, $scrollTo.defaults, settings ); - // Speed is still recognized for backwards compatibility - duration = duration || settings.speed || settings.duration; - // Make sure the settings are given right - settings.queue = settings.queue && settings.axis.length > 1; - - if( settings.queue ) - // Let's keep the overall duration - duration /= 2; - settings.offset = both( settings.offset ); - settings.over = both( settings.over ); - - return this._scrollable().each(function(){ - var elem = this, - $elem = $(elem), - targ = target, toff, attr = {}, - win = $elem.is('html,body'); - - switch( typeof targ ){ - // A number will pass the regex - case 'number': - case 'string': - if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){ - targ = both( targ ); - // We are done - break; - } - // Relative selector, no break! - targ = $(targ,this); - case 'object': - // DOMElement / jQuery - if( targ.is || targ.style ) - // Get the real position of the target - toff = (targ = $(targ)).offset(); - } - $.each( settings.axis.split(''), function( i, axis ){ - var Pos = axis == 'x' ? 'Left' : 'Top', - pos = Pos.toLowerCase(), - key = 'scroll' + Pos, - old = elem[key], - max = $scrollTo.max(elem, axis); - - if( toff ){// jQuery / DOMElement - attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] ); - - // If it's a dom element, reduce the margin - if( settings.margin ){ - attr[key] -= parseInt(targ.css('margin'+Pos)) || 0; - attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0; - } - - attr[key] += settings.offset[pos] || 0; - - if( settings.over[pos] ) - // Scroll to a fraction of its width/height - attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos]; - }else{ - var val = targ[pos]; - // Handle percentage values - attr[key] = val.slice && val.slice(-1) == '%' ? - parseFloat(val) / 100 * max - : val; - } - - // Number or 'number' - if( /^\d+$/.test(attr[key]) ) - // Check the limits - attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max ); - - // Queueing axes - if( !i && settings.queue ){ - // Don't waste time animating, if there's no need. - if( old != attr[key] ) - // Intermediate animation - animate( settings.onAfterFirst ); - // Don't animate this axis again in the next iteration. - delete attr[key]; - } - }); - - animate( settings.onAfter ); - - function animate( callback ){ - $elem.animate( attr, duration, settings.easing, callback && function(){ - callback.call(this, target, settings); - }); - }; - - }).end(); - }; - - // Max scrolling position, works on quirks mode - // It only fails (not too badly) on IE, quirks mode. - $scrollTo.max = function( elem, axis ){ - var Dim = axis == 'x' ? 'Width' : 'Height', - scroll = 'scroll'+Dim; - - if( !$(elem).is('html,body') ) - return elem[scroll] - $(elem)[Dim.toLowerCase()](); - - var size = 'client' + Dim, - html = elem.ownerDocument.documentElement, - body = elem.ownerDocument.body; - - return Math.max( html[scroll], body[scroll] ) - - Math.min( html[size] , body[size] ); - - }; - - function both( val ){ - return typeof val == 'object' ? val : { top:val, left:val }; - }; - -})( jQuery ); \ No newline at end of file diff --git a/ft_client/js/urlencode.js b/ft_client/js/urlencode.js deleted file mode 100644 index 2c9066e..0000000 --- a/ft_client/js/urlencode.js +++ /dev/null @@ -1,87 +0,0 @@ -function urlencode (str) { - // URL-encodes string - // License MIT/GPL - // version: 908.406 - // discuss at: http://phpjs.org/functions/urlencode - // + original by: Philip Peterson - // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // + input by: AJ - // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // + improved by: Brett Zamir (http://brett-zamir.me) - // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // + input by: travc - // + input by: Brett Zamir (http://brett-zamir.me) - // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // + improved by: Lars Fischer - // + input by: Ratheous - - var hash_map = {}, unicodeStr='', hexEscStr=''; - var ret = (str+'').toString(); - - var replacer = function (search, replace, str) { - var tmp_arr = []; - tmp_arr = str.split(search); - return tmp_arr.join(replace); - }; - - // The hash_map is identical to the one in urldecode. - hash_map["'"] = '%27'; - hash_map['('] = '%28'; - hash_map[')'] = '%29'; - hash_map['*'] = '%2A'; - hash_map['~'] = '%7E'; - hash_map['!'] = '%21'; - hash_map['%20'] = '+'; - hash_map['\u00DC'] = '%DC'; - hash_map['\u00FC'] = '%FC'; - hash_map['\u00C4'] = '%D4'; - hash_map['\u00E4'] = '%E4'; - hash_map['\u00D6'] = '%D6'; - hash_map['\u00F6'] = '%F6'; - hash_map['\u00DF'] = '%DF'; - hash_map['\u20AC'] = '%80'; - hash_map['\u0081'] = '%81'; - hash_map['\u201A'] = '%82'; - hash_map['\u0192'] = '%83'; - hash_map['\u201E'] = '%84'; - hash_map['\u2026'] = '%85'; - hash_map['\u2020'] = '%86'; - hash_map['\u2021'] = '%87'; - hash_map['\u02C6'] = '%88'; - hash_map['\u2030'] = '%89'; - hash_map['\u0160'] = '%8A'; - hash_map['\u2039'] = '%8B'; - hash_map['\u0152'] = '%8C'; - hash_map['\u008D'] = '%8D'; - hash_map['\u017D'] = '%8E'; - hash_map['\u008F'] = '%8F'; - hash_map['\u0090'] = '%90'; - hash_map['\u2018'] = '%91'; - hash_map['\u2019'] = '%92'; - hash_map['\u201C'] = '%93'; - hash_map['\u201D'] = '%94'; - hash_map['\u2022'] = '%95'; - hash_map['\u2013'] = '%96'; - hash_map['\u2014'] = '%97'; - hash_map['\u02DC'] = '%98'; - hash_map['\u2122'] = '%99'; - hash_map['\u0161'] = '%9A'; - hash_map['\u203A'] = '%9B'; - hash_map['\u0153'] = '%9C'; - hash_map['\u009D'] = '%9D'; - hash_map['\u017E'] = '%9E'; - hash_map['\u0178'] = '%9F'; - - // Begin with encodeURIComponent, which most resembles PHP's encoding functions - ret = encodeURIComponent(ret); - - for (unicodeStr in hash_map) { - hexEscStr = hash_map[unicodeStr]; - ret = replacer(unicodeStr, hexEscStr, ret); // Custom replace. No regexing - } - - // Uppercase for full PHP compatibility - return ret.replace(/(\%([a-z0-9]{2}))/g, function (full, m1, m2) { - return "%"+m2.toUpperCase(); - }); -} diff --git a/ft_server/admin/.htaccess b/ft_server/admin/.htaccess deleted file mode 100644 index 2f1b1d4..0000000 --- a/ft_server/admin/.htaccess +++ /dev/null @@ -1,3 +0,0 @@ - -RewriteEngine On - diff --git a/ft_server/admin/admin_db_view.php b/ft_server/admin/admin_db_view.php deleted file mode 100644 index 451208c..0000000 --- a/ft_server/admin/admin_db_view.php +++ /dev/null @@ -1,63 +0,0 @@ -q($sql); - -// TODO: Really need to make this stop sucking so bad -$template=" -%id% %url% -Summary -
"; - -$db->while_row($template); - - -?> \ No newline at end of file diff --git a/ft_server/admin/admin_form_view.php b/ft_server/admin/admin_form_view.php deleted file mode 100644 index bf3d393..0000000 --- a/ft_server/admin/admin_form_view.php +++ /dev/null @@ -1,198 +0,0 @@ -$url_string -"; - return $url_link; - -} - -if(!preg_match("/freetaleform.sqlite/", - $_GET['db'])){ - - echo "BAD DATABSE"; - exit; -} -$db=new DBx(DB_DIR . $_GET['db']); - -$prepare_vars= - Array(':id'=>$_GET['id'], - ':url'=>$_GET['url']); -$sql=" -SELECT * FROM - actions -WHERE - id = :id - AND - url = :url -ORDER BY - unixtime -"; -$db->p($sql . " LIMIT 1"); -$db->exec($prepare_vars); -$meta_row=$db->f(); - -$url_link=anchor_link($meta_row['url']); -$referer_link=anchor_link($meta_row['referer']); - - - -$db->p($sql); -$db->exec($prepare_vars); - -?> - - - - - -Form Analytics - - - - - - - - - - - -

-
    - -
  • -
  • -
  • -
  • - -
- - - %form_id% - %input_name% - %input_type% - %key_ups% - %time_elapsed% - - -"; - -global $form_action_vars; -$vars= - array_map(create_function('$s', - 'return "%$s%";'), - $form_action_vars); - -ob_start(); -echo " - - - - - - - - - - - -"; -while($vals=$db->f()){ - - $vals=array_map('htmlentities', - $vals); - - if($vals['input_type'] != 'textarea' and - $vals['input_type'] != 'text'){ - $vals['key_ups'] = "N/A"; - } - - //TODO: Add Special Case for landing stats - - if($vals['input_type']=='landing'){ - $vals['input_name']=""; - $vals['key_ups']=""; - $vals['time_elapsed']=""; - - echo " -"; - - //continue; - } - - $te=intval($vals['time_elapsed']); - - if($te == 0){ - $time_length="null"; - }elseif($te < 3){ - $time_length="short"; - }elseif($te < 120){ - $time_length="medium"; - }else{ - $time_length="long"; - } - - $vars[]="%time_length%"; - $vals[]=$time_length; - - echo str_replace($vars,$vals,$template); - /** / - echo "
";
-  print_r($row);
-  echo "
"; - /**/ - -} -echo "
Form IdInput NameInput TypeKey UpsTime Elapsed (seconds)
- -Footnotes go here, possibly injected via javascript - -
"; -ob_end_flush(); - -?> - - - diff --git a/ft_server/admin/admin_form_view_summary.php b/ft_server/admin/admin_form_view_summary.php deleted file mode 100644 index e494c53..0000000 --- a/ft_server/admin/admin_form_view_summary.php +++ /dev/null @@ -1,231 +0,0 @@ -$url_string -"; - return $url_link; - -} - -if(!preg_match("/freetaleform.sqlite/", - $_GET['db'])){ - - echo "BAD DATABSE"; - exit; -} -$db=new DBx(DB_DIR . $_GET['db']); - - -$prepare_vars=Array(':url'=>$_GET['url']); -$sql=" -SELECT - * -FROM - actions -WHERE - url = :url - AND - input_type != 'landing' -GROUP BY - input_name -ORDER BY - unixtime -"; -$db->p($sql . " LIMIT 1"); -$db->exec($prepare_vars); -$meta_row=$db->f(); - -$url_link=anchor_link($meta_row['url']); -$referer_link=anchor_link($meta_row['referer']); - -$db->p($sql); -$db->exec($prepare_vars); -$input_names=Array(); -while($row=$db->f()){ - $input_names[]=$row['input_name']; -} - - -$sql=" -SELECT - input_type, - input_name, - key_ups, - form_id, - COUNT(*) AS count, - SUM(time_elapsed) AS total_time -FROM - actions -WHERE - input_name = :input_name -"; -$db->p($sql); - - -$form_time=0; -$time_stats=Array(); -foreach($input_names as $input_name){ - $db->exec(Array(":input_name"=>$input_name)); - $time_stat=$db->f(); - - $total_time=min($time_stat['total_time'],2*60); - $form_time+=$total_time/$time_stat['count']; - $average_key_ups=$time_stat['key_ups']/$time_stat['count']; - $average_time=$total_time/$time_stat['count']; - - $time_stat["form_time"]=sig_figs($form_time); - $time_stat["average_key_ups"]=sig_figs($average_key_ups); - $time_stat["average_time"]=sig_figs($average_time); - $time_stats[]=$time_stat; - - - -echo "
";
-print_r($time_stat);
-echo "
"; - -} - - - - -/** / -$db->p($sql); -$db->exec(); -/**/ - - -?> - - - - - -Form Analytics - - - - - - - - - - - - - %form_id% - %input_name% - %input_type% - %average_key_ups% - %total_time% - %form_time% - %average_time% - - -"; - -$vars= - array_map(create_function('$s', - 'return "%$s%";'), - array_keys($time_stats[0])); - -ob_start(); -echo " - - - - - - - - - - - -"; -foreach($time_stats as $time_stat){ - - - - /**/ - $vals=array_map('htmlentities', - $time_stat); - /**/ - - echo str_replace($vars,$vals,$template); - /** / - echo "
";
-  print_r($time_stat);
-  echo "
"; - /**/ - -} -echo "
Form IdInput NameInput TypeAverage Key UpsTime Elapsed (seconds)
- - Footnotes go here, possibly injected via javascript - -
"; -ob_end_flush(); - -?> - - - diff --git a/ft_server/admin/admin_parse_log.php b/ft_server/admin/admin_parse_log.php deleted file mode 100644 index 3b338c2..0000000 --- a/ft_server/admin/admin_parse_log.php +++ /dev/null @@ -1,201 +0,0 @@ -$var){ - $tic[$var]=$bits[$ii]; - } - - return $tic; -} - -function parse_motion_file($log_file_name){ - - $sqlite_db_name= - preg_replace("/.log$/", - ".sqlite", - $log_file_name); - - - $db=new DBx(DB_DIR . $sqlite_db_name, - "sqlite"); - - $sql="DROP TABLE IF EXISTS tics"; - $db->q($sql); - - $sql=" -CREATE TABLE tics ( - unixtime INT NOT NULL, - remote_addr CHAR(30), - user_agent TEXT, - id INT, - url TEXT NOT NULL, - referer TEXT, - - -- todo: make these more legit checks - - width INT CHECK(width < 4000), - height INT CHECK(height < 4000), - body_height INT CHECK(body_height < 10000), - time_elapsed INT, - clicks TEXT, - mouse_movements TEXT, - scroll TEXT -)"; - $db->q($sql); - - $sql=" -CREATE INDEX - tics_id - ON tics(id) -"; - $db->q($sql); - - global $tic_vars; - $contents=file_get_contents(DB_DIR . $log_file_name); - $lines=explode("\n",$contents); - // begin a transaction - $db->bt(); - - - foreach($lines as $line){ - if(strlen($line) == 0) - continue; - - $tic=parse_tic($line); - $db->set('tics',$tic); - - // todo add cleanup string - /** / - echo "
";
-    print_r($tic);
-    echo "
"; - /**/ - } - // commit the transaction - $db->c(); -} - -// TODO, refactor, because parse_tic is the same thing -function parse_form_action($action_string){ - - $form_action=Array(); - $bits=explode("\t",$action_string); - - // defined in ../includes/conf.inc.php - global $form_action_vars; - foreach($form_action_vars as $ii=>$var){ - $form_action[$var]=$bits[$ii]; - } - return $form_action; -} - - -function parse_form_file($log_file_name){ - - $sqlite_db_name= - preg_replace("/.log$/", - ".sqlite", - $log_file_name); - - - $db=new DBx(DB_DIR . $sqlite_db_name, - "sqlite"); - - $sql="DROP TABLE IF EXISTS actions"; - $db->q($sql); - - $sql=" -CREATE TABLE actions ( - unixtime INT NOT NULL, - remote_addr CHAR(30), - user_agent TEXT, - id INT, - url TEXT NOT NULL, - referer TEXT, - input_type TEXT, - form_id TEXT, - input_name TEXT, - time_elapsed TEXT, - key_ups INT -)"; - $db->q($sql); - - $sql=" -CREATE INDEX IF NOT EXISTS - actions_id - ON actions(id) -"; - $db->q($sql); - - global $form_actions; - $contents=file_get_contents(DB_DIR . $log_file_name); - $lines=explode("\n",$contents); - // begin a transaction - $db->bt(); - foreach($lines as $line){ - if(strlen($line) == 0) - continue; - - $tic=parse_form_action($line); - $db->set('actions',$tic); - - // todo add cleanup string - /** / - echo "
";
-    print_r($tic);
-    echo "
"; - /**/ - } - $db->c(); -} - - -echo "
";
-$d=dir(DB_DIR);
-// We are going to go through all the files in the dir ..
-while (false !== ($entry = $d->read())) {
-  // ... ignoring anything thats not a iseeyou logs.
-  if(!preg_match("/freetale(form)?.log$/",$entry)){
-    continue;
-  }
-
-  if(preg_match("/freetale.log$/",$entry)){
-    echo "
parseing motion log '$entry' ...

"; - parse_motion_file($entry); - } - - if(preg_match("/freetaleform.log$/",$entry)){ - echo "
parseing form log '$entry' ...

"; - parse_form_file($entry); - } - - // When we find and iseeyou log we are going to process it -} -echo "
"; -?> \ No newline at end of file diff --git a/ft_server/admin/admin_replay.php b/ft_server/admin/admin_replay.php deleted file mode 100644 index f6ddfda..0000000 --- a/ft_server/admin/admin_replay.php +++ /dev/null @@ -1,81 +0,0 @@ -p($sql); -$db->exec(Array(":id"=>$_GET['id'], - ":url"=>$_GET['url'])); - -$init=$db->f(); - -$_SESSION['id']=$_GET['id']; -$_SESSION['url']=$_GET['url']; -$_SESSION['db']=$_GET['db']; -$_SESSION['replay_motion']=1; -$_SESSION['replay_summary']=0; - -?> - - - - - -FreeTale Replay - - - - - - - - - -

replay

- -"; -?> - - - \ No newline at end of file diff --git a/ft_server/admin/admin_replay_summary.php b/ft_server/admin/admin_replay_summary.php deleted file mode 100644 index 73f2d97..0000000 --- a/ft_server/admin/admin_replay_summary.php +++ /dev/null @@ -1,93 +0,0 @@ -q($sql); - - - -function last_scroll($scroll){ - if($scroll == "") - return False; - $bits=explode("|",$scroll); - return $bits[count($bits) - 1]; -} - -$motions=Array(); -$this_id=False; -while($row=$db->f()){ - - if($this_id != $row['id']){ - $this_id=$row['id']; - $last_time=0; - $last_scroll=0; - } - - - - $motions[$row['id']][][0]=$row['time_elapsed']-$last_time; - $last_time=$row['time_elapsed']; - - $motions[$row['id']][count($motions[$row['id']])-1][1]=last_scroll($row['scroll']); - - /** / - echo "
";
-  print_r($row);
-  echo "
"; - /**/ - -} - - -/**/ -echo "
";
-print_r($motions);
-echo "
"; -/**/ - - - -// iterate over database, and find lowest point -?> - - diff --git a/ft_server/admin/auth_db.inc.php b/ft_server/admin/auth_db.inc.php deleted file mode 100644 index 6969fa8..0000000 --- a/ft_server/admin/auth_db.inc.php +++ /dev/null @@ -1,32 +0,0 @@ - diff --git a/ft_server/admin/index.php b/ft_server/admin/index.php deleted file mode 100644 index bc3cae1..0000000 --- a/ft_server/admin/index.php +++ /dev/null @@ -1,48 +0,0 @@ -read())) { - if(!preg_match("/\.sqlite$/",$entry) or - $entry == "auth.sqlite") - continue; - $db_name="$db_dir$entry"; - - // if this is an "action" db then ... - if(preg_match("/freetale.sqlite$/",$entry)){ - // ... link to the replayer - echo "$entry
"; - } - - // If this is a "form" db then ... - if(preg_match("/freetaleform.sqlite$/",$entry)){ - // ... link to the form displayer - echo "$entry - "; - } -} - -?> -

-logout -

\ No newline at end of file diff --git a/ft_server/admin/login.php b/ft_server/admin/login.php deleted file mode 100644 index 4453cb7..0000000 --- a/ft_server/admin/login.php +++ /dev/null @@ -1,73 +0,0 @@ - - - - - -Login To CCenter - - - - -
-

Login to CCenter

- -" . $_SESSION['flash'] . "

"; -$_SESSION['flash']=""; - - -//--> -?> - -
- - - - - - - - - - - -
Password:
- -
-

-q($sql); - -if($row=$auth_db->f()){ - echo "You are still using the default username password which is 'dfhu.org'"; - echo " This is a bad idea to leave as the default, you should "; -}else{ - echo "You may change "; -} -?> - change your Password. -

- - -
- - - - diff --git a/ft_server/admin/login_change.php b/ft_server/admin/login_change.php deleted file mode 100644 index 76e2b7a..0000000 --- a/ft_server/admin/login_change.php +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - -Change Password - - - - - - - - - - -
-

Change Password

- - -?> - -
- - - - - - - - - - - - - - - - - - - - - - - - -
Current Password:
New Password:
Retype New Password:
- -
- -

- Back to login page. -

- -
- - - - diff --git a/ft_server/admin/login_change_do.php b/ft_server/admin/login_change_do.php deleted file mode 100644 index ade4ac1..0000000 --- a/ft_server/admin/login_change_do.php +++ /dev/null @@ -1,61 +0,0 @@ - 32 ){ - $_POST['flash']="Sorry the new passwords is too short. It must be at least 8 chars long, but no greater than 32."; - header("Location: ./login_change.php"); - exit; -} - - -require("./auth_db.inc.php"); -$pass_sql=sha1($_POST['password']); -$sql=" -SELECT ROWID FROM `auth` - WHERE - pass_hash='$pass_sql'"; -$auth_db->q($sql); - -if(!$row=$auth_db->f()){ - $_SESSION['flash']="Sorry the old password is incorrect. The default password is -'ccenter_default_password'. This script requires cookies -enabled."; - header("Location: ./login_change.php"); - exit; -} - -$pw_sql=sha1($_POST['pw1']); -$sql="INSERT INTO `auth` (pass_hash) VALUES ('$pw_sql')"; -$auth_db->q($sql); - -$_SESSION['flash']="Password Succesfully Changed. You may now login."; -header("Location: ./login.php"); - - -//--> -?> diff --git a/ft_server/admin/login_is.php b/ft_server/admin/login_is.php deleted file mode 100644 index e50f639..0000000 --- a/ft_server/admin/login_is.php +++ /dev/null @@ -1,45 +0,0 @@ -q($sql); - if(!$row=$auth_db->f()){ - $_SESSION['flash']=" -Sorry the password is incorrect. -The default password is 'dfhu.org'. -This script requires cookies enabled. -"; - header("Location: ./login.php"); - exit; - } - -} - -if($_SESSION['logging_in'] == "1"){ - $_SESSION['logging_in']=""; - $_SESSION['logged_in']="true"; - - $token = md5(TOKEN_SALT . uniqid(mt_rand(), true)); - $_SESSION['CSRF_delete_do']=$token; - - header("Location: ./index.php"); -} - -?> \ No newline at end of file diff --git a/ft_server/admin/login_out.php b/ft_server/admin/login_out.php deleted file mode 100644 index 57cc8e4..0000000 --- a/ft_server/admin/login_out.php +++ /dev/null @@ -1,5 +0,0 @@ - \ No newline at end of file diff --git a/ft_server/admin/makedb.php b/ft_server/admin/makedb.php deleted file mode 100644 index 9a0e063..0000000 --- a/ft_server/admin/makedb.php +++ /dev/null @@ -1,68 +0,0 @@ -q($sql); - - -$sql=" -CREATE TRIGGER IF NOT EXISTS - only_one -BEFORE INSERT ON - `auth` -BEGIN - DELETE FROM `auth`; -END; -"; -$auth_db->q($sql); - - -/* -$sql=" -DELETE FROM `auth`; -"; -$auth_db->q($sql); -exit; -*/ - -$sql=" -SELECT COUNT(*) - AS count - FROM `auth` -"; -$auth_db->q($sql); -$row=$auth_db->f(); - -if((int)$row['count'] == 0){ - $pass_sql=sha1('dfhu.org'); - $sql=" -INSERT INTO `auth` - (pass_hash) - VALUES - ('$pass_sql') -"; - - $auth_db->q($sql); -} - -?> diff --git a/ft_server/cdot.png b/ft_server/cdot.png deleted file mode 100644 index 823b2469de49c7e3a9d68545c2ac2e2dc19424f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 zcmV-e1E>6nP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXV` z0xBImY)1_M000nlMObu0Z*6U5Zgc=-W@vRTZ*phjS*_my00O*8L_t(o!|m8jOw(W( z0N{4(+OB^aTec7*93+v032KI5ytumu4&MAhiE|@FuJgdzgIqDda0`k*HxC}XPfvm@ z>Jly{cmPAlmW{1{bZysqFecKj+v;f7C40|b`#t^o_Urq-0ML(q^uyKwJH0{X>RYfb zi-V#p4$Go2Sd#^^E=#bg)@SYoj4ZojlT#8H7>$1 z#bLA8l4NKPMetl=`+nJS@bfD#DVC?B99If;`gU+USR^ni`|!&>+7j@yOKanm%E86c z&P%`l%=bs%;@hVNUYmU7;@HX!jw^+&`j~J$SilMYhxq1Qr6X{9@{OCW7H{%Gg|vDH zz)(L!`9kkvo44ymV_dCn!ZM{PJFox%0K8BkS*A4AY)n(|(%5p8<;w$h?z1dk9#|S% zj+zFqM%IU_bYY|$KZhz^7+H<1519g2nd0?s{?Ux)ZwOwAWJV>CN4g1?L>^g*WJcQp z^IY|^6Y7RW4jni(u|XUQH0}iOu|VUgi4CGDSe9z%oK&4@J&-PUq}tg|CP?lqq}v_4 zc;QK`WiJ2mH6yuh=YF>(PNd9^{wRd1(f%^)yHcQiD?AXK9C2-YL9;;U$jB-4n!harJQpYIO_p_k~JXD{#5` zxi~YjiHnLdW|t%;<$x^#X=8#};RkyxCeP?lJfoRL_hVQ65W z$)yR(n~cm?7=UOLjE2By2n>S|&|+kYO-W2KNi;DtN={6%NHR?{Hcw1WO|>+!G_Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXV_ z04x=C+!Hwf000nlMObu0Z*6U5Zgc=-W@vRTZ*phjS*_my00NLnL_t(o!|m9;Z`wc< z0Ps6wFdqilB+yjl7@8qt)h0?SmY}Fx2Zjz=I`+@X*rh{<3|%8KBx<6hRWo!;2TWUv z6O6#d7=OGDl`7#6z$G?D;>{=D&(F_y?+&3=tYQ_R2A=l;r0^LdW3&OLRz~`81B_u7 znWF@oMFzi-gAQk5RylGy{=@N2WTcX@AMvVKXypz{g_ zonl}=Q##+q>HJ6GcE_3vOxCYr(Et4!v|cvw6@bb0arVIn;da~f8beKc2qnc57t$NaHm@{fkBm?Mxk$Tb2z|c?SchO&O`#N$r-YC!A=B&p*@aL zcV_p{juFPNG|vPL^WbpSvE|tNw^IlG^;~<`uEYJhDXmy#GU(JF~?k2AxTNkuBd zHjlH0shEWULJN-QxfYce^rXSS1Q*%&>}Zw<}L=esGHa64nYa3GL?aJkvdjAH4~p#q;HYs$C<(rW^(;7&;S76S}%V_{^qA)9vtc;OEC"; -print_r($_GET); -echo ""; -exit; -/**/ - -//TODO: Add filters - -/* -$filters= - Array( - 'l'=>FILTER_VALIDATE_URL, - 'r'=>FILTER_VALIDATE_URL, - 'w'=>FILTER_VALIDATE_INT, - 'h'=>FILTER_VALIDATE_INT, - 'k'=>FILTER_VALIDATE_INT - ); -filter_var_array($_GET,$filters); - -if(!preg_match("/^[0-9]+_[0-9]+$/", - $_GET['i'])){ - gif(); -} - -// TODO: Put in a proper filter, sticky because the name that input -// elements can have varies, like jquery doesn't like : or -// . but they are both valid. I will just remove the most obvious -// offenders. -$_GET['b']=trim($_GET['b']); -if(preg_match("/[\s<>\"\']/",$_GET['b'])){ - gif(); -} -*/ - - -$url_bits=parse_url($_GET['l']); - -$database_file= - "db/" . - date("ymd") . - "-{$url_bits['host']}-freetaleform.log"; - -$ua=preg_replace("/\t<>/","_",$_SERVER['HTTP_USER_AGENT']); - -$str=@date("U") . - "\t" . $_SERVER['REMOTE_ADDR'] . - "\t" . $ua . - "\t" . $_GET['i'] . // user id - "\t" . $_GET['l'] . // current page - "\t" . $_GET['r'] . // referer - "\t" . $_GET['t'] . // type of form (text,password,option,etc..) - "\t" . $_GET['f'] . // the form's id - "\t" . $_GET['n'] . // the name of the input - "\t" . $_GET['c'] . // the 'clock' time spent on the input - "\t" . $_GET['k'] . // number of keyup events - "\n"; -file_put_contents($database_file, $str, FILE_APPEND); - -function gif(){ - header("content-type: image/gif"); - //43byte 1x1 transparent pixel gif - - echo - base64_decode("R0lGODlhAQABAIAAAAAAAAAAACH5B" . - "AEAAAAALAAAAAABAAEAAAICRAEAOw=="); - exit; -} -gif(); -?> \ No newline at end of file diff --git a/ft_server/gif.php b/ft_server/gif.php deleted file mode 100644 index 914b190..0000000 --- a/ft_server/gif.php +++ /dev/null @@ -1,92 +0,0 @@ -FILTER_VALIDATE_URL, - 'r'=>FILTER_VALIDATE_URL, - 'w'=>FILTER_VALIDATE_INT, - 'h'=>FILTER_VALIDATE_INT, - 't'=>FILTER_VALIDATE_INT - ); -filter_var_array($_GET,$filters); - - -if(!preg_match("/^[0-9]+_[0-9]+$/",$_GET['i'])){ - gif(); -} - - -foreach($_GET['s'] as $s){ - if(!preg_match("/^(|[0-9]+)$/",$s)){ - gif(); - } -} - -function check_motion($vals){ - foreach($vals as $v){ - if(!preg_match("/^(|[0-9]+x[0-9]+)$/",$v)){ - gif(); - } - } -} -check_motion($_GET['c']); -check_motion($_GET['m']); -*/ - -$url_bits=parse_url($_GET['l']); - -$database_file= - "db/" . - date("ymd") . - "-{$url_bits['host']}-freetale.log"; - -$str=@date("U") . - "\t" . $_SERVER['REMOTE_ADDR'] . - "\t" . $_GET['i'] . - "\t" . $_GET['l'] . - "\t" . $_GET['r'] . - "\t" . $_GET['w'] . - "\t" . $_GET['h'] . - "\t" . $_GET['b'] . - "\t" . $_GET['t'] . - "\t" . implode("|",$_GET['c']) . - "\t" . implode("|",$_GET['m']) . - "\t" . implode("|",$_GET['s']) . - "\n"; - -file_put_contents($database_file, $str, FILE_APPEND); - - -function gif(){ - header("content-type: image/gif"); - //43byte 1x1 transparent pixel gif - - echo - base64_decode("R0lGODlhAQABAIAAAAAAAAAAACH5B" . - "AEAAAAALAAAAAABAAEAAAICRAEAOw=="); - exit; -} -gif(); - -?> diff --git a/ft_server/includes/conf.inc.php b/ft_server/includes/conf.inc.php deleted file mode 100644 index 81d9478..0000000 --- a/ft_server/includes/conf.inc.php +++ /dev/null @@ -1,73 +0,0 @@ - diff --git a/ft_server/includes/db.inc.php b/ft_server/includes/db.inc.php deleted file mode 100644 index 96df11a..0000000 --- a/ft_server/includes/db.inc.php +++ /dev/null @@ -1,571 +0,0 @@ -c is the connection - @var string $this->e is the engine - - @var string $this->name is name of the database - @var string $this->esc_func is the name string escape function - - - **/ - - var $e; // name of the engine - var $c; // connection - var $name; // name of the database - var $esc_func; // 'mysql_real_escape_string' or 'sqlite_escape' - var $stmt; // the statment - - function __construct($db_name=DB_NAME, - $db_engine=DB_ENGINE, - $die=True){ - /* - - @parama $die if True die if the sqlite db file can't be open. If - False try to create it - - Side Effects: - - @var string $this->name is name of the database - @var string $this->esc_func is the name string escape function - @var string $this->e name of the engine: 'sqlite' or 'mysql' - - */ - - // The database's autograph might be worth lots of money someday, - // so lets save it just in case. - $this->name=$db_name; - $engine=strtolower($db_engine); - $this->e=$engine; - - // Before we get all crazy and start PDO'ing stuff, make sure we - // are using a supported engine ... - if($engine != "sqlite" and - $engine != "mysql"){ - // ... if not, bitch and bail. - $this->_errpage( -"Supported Databases are sqlite and mysql. -Please Check your config and try again."); - } - - // If we are using sqlite ... - if($engine == "sqlite"){ - // ... save the sqlite escape function name. - $this->esc_func="sqlite_escape_string"; - - // Then try to ... - try{ - // ... open the database, ... - - $rel=($this->name[0] != "/") ? - "./" : ""; - - $this->c = new PDO("sqlite:$rel{$this->name}"); - // ... but if we can't open the database ... - }catch(Exception $e){ - // ... then check to see if we were told to $die=True when - // calling __construct() ... - if($die){ - // ... in which case bitch and bail. - $this->_errpage( -"Could not open sqlite database -'{$_SERVER['DOCUMENT_ROOT']}/{$this->name}' Make sure the file exists -and is writeable by the web server."); - } - // If we are still alive, try to create the database file now. - $this->_create_db_file(); - } - } - - // On the other hand, if we are using MySQL ... - if($engine == "mysql"){ - // ... save MySQL's RaPUNzel function (get it "escape string," - // like her hair, hehe ... oh whatever, you're no fun). - $this->esc_func="mysql_real_escape_string"; - - // Back to the plot, turn those globals into pretty string - // variables so that we can ... - $host=DB_HOST; - $user=DB_USER; - $pass=DB_PASS; - - // ... try to ... - try{ - // ... open up the mysql database, ... - $this->c = new PDO("mysql:host=$host;dbname={$this->name}", - $user, - $pass); - // ... but if we cant ... - }catch(Exception $e){ - // ... bitch and bail. - $this->_errpage("Error Opening MySQL Database: " . $e->getMessage()); - } - }// using mysql - - // Set it up so when PDO messes up or more likely when YOU messup, - // PDO throw's an exception. - $this->c->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); - }// And thus concludes the story of __construct(). - - function attach($name=CONFIG_DB_NAME, - $nickname="config"){ - - /* - - In SQLite you can ATTACH other databases to put them in global - scope. This is very handy for using config databases that you - upload to all your instances of the program. - - @param string $name - the complete path on the server to the - database file - @param string $nickname - what the database will be refrenced - AS. I.e. the initial dabase used to construct is by default - called 'main' - - */ - - // if not using sqlite ... - if($this->e != "sqlite") - // ... BAB. - $this->_errpage("You must Use SQLite if You wish to ATTACH"); - - // Now quote the database path ... - $name_sql=$this->quote($name); - // ... and escape the nickname. - $nickname_sql=$this->escape($nickname); - - // Finally, create the sql statement ... - $sql="ATTACH $name_sql AS $nickname_sql"; - // ... so that we can query the db with it. - $this->q($sql); - - }// attach - - function bt(){ - $this->c->beginTransaction(); - } - function c(){ - $this->c->commit(); - } - - function q($sql,$fetch_method=PDO::FETCH_ASSOC){ - // query - if($sql == "") - throw new Exception("Empty SQL Statement"); - $this->q = $this->stmt = null; - $this->q = $this->c->query($sql); - $this->q->setFetchMode($fetch_method); - } - - - function qf($sql,$fetch_method=PDO::FETCH_ASSOC){ - $this->q($sql,$fetch_method); - return $this->f(); - } - - function f($fetch_method=PDO::FETCH_ASSOC){ - // fetch one - if($this->q){ - return $this->q->fetch($fetch_method); - }elseif($this->stmt){ - return $this->stmt->fetch($fetch_method); - } - - throw new Exception("Neither $stmt nor $q is set"); - } - - function p($sql){ - // prepare a stateent - $this->q = $this->stmt = null; - $this->stmt = $this->c->prepare($sql); - } - - function quote($var){ - // quote a string i.e. for insert/where values - return $this->c->quote($var); - } - - function escape($var){ - // escape a string, for santizing table names, column names etc. - return call_user_func($this->esc_func,$var); - } - - function exec($vals){ - // @param array $vals - is an array of values to insert in the - // prepared statement - $this->stmt->execute($vals); - } - - private function _create_db_file(){ - /* Attempt to create the database for sqlite3. Then open it with - new PDO() */ - - $fp = @fopen("./" . $this->name, 'w'); - @fwrite($fp,""); - @fclose($fp); - - $this->__construct($die=True); - - } - - private function _errpage($msg, - $db_err="", - $title="Database Error"){ - ?> - <?php echo htmlentities($title) ?> - -

-

- - - fetch()){} loop - - @param string $template - a template string with delimiters (i.e - $templatate="%firstname% %lastname%"). The default delimiter - is '%' or it can be set $p['delimiter']='string' - - @param string $keys - Array("firstname","lastname") - - @named_params array $p - - - $p=array( - "before_each"=>"
  • ", // string default - "after_each"=>"
  • ", // string default - "before_all"=>"
      ", // string default - "after_all"=>"
    ", // string default - "delimiter"=>"%" // what vars in $str are seprated by. default - ); - - EXAMPLE: - - Using the values above - - $D->while_row($keys,$template,$p); - - Might give something like: - -
      -
    • Alice Sneaky
    • -
    • Bob Brown
    • -
    • Eve Zarko
    • -
    - - */ - - // set up the before each and after each tags - $be=isset($p['before_each']) ? $p['before_each'] : "
  • "; - $ae=isset($p['after_each']) ? $p['after_each'] : "
  • \n"; - // set up the delimiter for keys - $delimiter=isset($p['delimiter']) ? $p['delimiter'] : "%"; - - /* - // wrap the keys with the delimiter - $vars=array_map("DBx::_wrap_with", - $keys, - array_fill(0, - count($keys), - $delimiter)); - */ - - // buffer the output - ob_start(); - echo isset($p['before_all']) ? $p['before_all'] : "
      \n"; - $vars=False; - while($vals = $this->f()){ - - if(!$vars){ - // wrap the keys with the delimiter - $vars=array_map("DBx::_wrap_with", - array_keys($vals), - array_fill(0, - count($vals), - $delimiter)); - } - - echo $be; - echo str_replace($vars,$vals,$template); - echo $ae; - } - echo isset($p['after_all']) ? $p['after_all'] : "
    \n"; - // ok flush to the screen - ob_flush(); - - }// while_row - - - private function _show_tables_command(){ - - if($this->e == "sqlite"){ - $sql="select tbl_name from sqlite_master where type='table'"; - }elseif($this->e == "mysql"){ - throw new Exception("_show_tables Not Implemented for MySQL yet"); - $sql="SHOW TABLES"; - } - - return $sql; - } - function show_tables(){ - - $sql=$this->_show_tables_command(); - - $this->q($sql,PDO::FETCH_NUM); - - $p=Array(); - $template="%tbl_name%"; - $this->while_row($template); - }// show_tables - - - function tables(){ - // return an array with table names - - $sql=$this->_show_tables_command(); - $this->q($sql,PDO::FETCH_NUM); - - $tables=Array(); - while($r=$this->f()){ - - - $tables[]=$r['tbl_name']; - } - - return $tables; - } - - - - private function _append_vars($vars,$delimiter,$transform=False){ - /* - Makes var1,var2,var3 lists or var1 and var2 and var3 lists, - escaping with $transform which is a callable function such as - mysql_real_escape_string - */ - - if($transform and - !is_callable($transform,false,$callable)){ - throw new Exception("Function or Method does not exists $transform"); - } - - if(is_array($vars)){ - if($transform) - $v=implode($delimiter, array_map("$callable",$vars)); - else - $v=implode($delimiter, $vars); - - }elseif(is_string($vars)){ - if($transform) - $v=call_user_func("$callable",$vars); - else - $v=$vars; - - }else{ - throw new Exception("Must be string or array " . htmlentities("$vars")); - } - return $v; - } - - - function wheres($wheres,$and=True){ - /* - get the k='val' and k2='val2' and ... - style string. - */ - - if($and) - $conjunction=" AND "; - else - $conjunction=" OR "; - - $where=Array(); - $cnt=0; - foreach($wheres as $k=>$v){ - $cnt+=1; - - $k_sql=$this->escape($k); - $v_sql=$this->quote($v); - - $where[]="$k_sql=$v_sql"; - if($cnt != count($wheres)){ - $where[]=$conjunction; - } - } - return implode("\n",$where); - - }// wheres - - - - function update($table,$updates,$wheres=Array(), $and=True){ - /* - @param $table - the name of the table to work on - @param $updates - is new values as a key=>value array - @param $where - is the where clauses as key=>value array - @param $and - if True " and " else " OR "; - */ - - $table_sql=$this->escape($table); - - $updates=$this->wheres($updates); - - $wheres="where " . $this->wheres($wheres,$and); - - $sql="UPDATE $table_sql SET $updates $wheres"; - $this->q($sql); - - } - - - function set($table,$p){ - /* - -$p=Array("key"=>"value","key2"=>"value2"); - -or - -$p=Array(Array("key"=>"value0_0","key2=>"value1_0"), - Array("ignored"=>"value0_1","ignored","value1_1")...) - -This Function Ignores ON DUPLICATE. - - */ - - if(isset($p[0])){ - $kv=$p[0]; - $many=True; - }else{ - $kv=$p; - $many=False; - } - - $columns_sql=$this->_append_vars(array_keys($kv),", ",$this->esc_func); - - $setup=$this->_append_vars(array_fill(0,count($kv),"?"),", "); - - $table_sql=$this->escape($table); - - $sql="INSERT INTO $table_sql ($columns_sql) VALUES ($setup)"; - - $this->p($sql); - - if($many){ - foreach($p as $kv){ - $this->_ignore_duplicate($kv); - } - }else{ - $this->_ignore_duplicate($kv); - } - }//set - - private function _ignore_duplicate($kv){ - try { - $this->stmt->execute(array_values($kv)); - }catch(Exception $e){ - if(!preg_match("/(is not unique$|Duplicate entry '.*' for key)/",$e->getMessage())){ - throw $e; - } - } - }// _ignore_duplicate - - function get($table, // name of the table - $columns, // if array listed columns, if string one or * - $wheres=Array(), // array of key=>$value pairs - $limit=1, - $and=True // True = 'and' False = 'or' - ){ - /* - select $columns_sql from $table WHERE $wheres_sql limit $limit; - */ - - $columns_sql=$this->_append_vars($columns,", ",$this->esc_func); - - $table_sql=$this->escape($table); - - $limit=intval($limit); - - if(count($wheres) > 0) - $wheres_sql="WHERE " . $this->wheres($wheres, $and); - else - $wheres_sql=""; - - $sql="SELECT $columns_sql FROM $table_sql $wheres_sql LIMIT $limit"; - $this->q($sql); - - }// get - - function str_now(){ - if($this->e == "mysql"){ - return "NOW()"; - } - if($this->e == "sqlite"){ - return "DATETIME('NOW')"; - } - }// str_now - - function str_int_id(){ - /* - Helper function because auto increment integer id's are not - created the same in sqlite3 and mysql, granted they are - automagically created as ROWID in sqlite - */ - if($this->e == "sqlite"){ - return "`id` INTEGER PRIMARY KEY,"; - } - if($this->e == "mysql"){ - return "`id` INT PRIMARY KEY AUTO_INCREMENT,"; - } - }// str_int_id - -}// DBx - -class CRUD extends DBx{ - function __construct($db_name=DB_NAME){ - parent::__construct(); - } -} - -?> diff --git a/ft_server/includes/debug.inc.php b/ft_server/includes/debug.inc.php deleted file mode 100644 index 5073f8a..0000000 --- a/ft_server/includes/debug.inc.php +++ /dev/null @@ -1,65 +0,0 @@ -Sorry, maintenance\n" . - $e->getMessage() . - ""); - } - // Set the global excpetion handler - set_exception_handler('exceptionHandler'); - } - ini_set('display_errors', "Off"); -} - -if(DEBUG_LEVEL == 1){ - error_reporting(E_ALL|E_STRICT); - ini_set('display_errors', "Off"); -} - -if(DEBUG_LEVEL > 1){ - error_reporting(E_ALL|E_STRICT); - ini_set('display_errors', "On"); -} - -if(DEBUG_LEVEL >= 5){ - function here($msg="HERE"){ - echo - "\n
    " .
    -      "\nMesg: " . $msg .
    -      "\nStak: ";
    -    print_r(debug_backtrace());
    -    echo "\n
    "; - } -}else{ - function here($msg=""){}; -} - -function debug_say($msg,$debug_level){ - if($debug_level < DEBUG_LEVEL) - return; - echo "
    $msg
    "; -} - -?> \ No newline at end of file diff --git a/ft_server/replay.php b/ft_server/replay.php deleted file mode 100644 index ea9b5c7..0000000 --- a/ft_server/replay.php +++ /dev/null @@ -1,40 +0,0 @@ - - -if(top.location != document.location){ - -} diff --git a/ft_server/replay_motion.php b/ft_server/replay_motion.php deleted file mode 100644 index 9159bd9..0000000 --- a/ft_server/replay_motion.php +++ /dev/null @@ -1,191 +0,0 @@ -p($sql); -$db->exec(Array(":id"=>$_SESSION['id'], - ":url"=>$_SESSION['url'])); - - -function quote_extend(&$vals,$extend){ - foreach($extend as $e){ - $vals[]="'$e'"; - } -} - -function quote_dimensions($dim){ - $bits=explode("x",$dim); - return "Array('{$bits[0]}','{$bits[1]}')"; -} - -function quote_dim($dim){ - return "'$dim'"; -} - -function print_js_array($array_name,$vals){ - echo " var $array_name = Array("; - echo implode(",",$vals); - echo ");\n"; -} - - -$tics=array(); -$scrolls=array(); -$mouses=array(); -$clicks=array(); -while($row=$db->f()){ - $tics[]=$row['time_elapsed']; - $height=$row['height']; - - // TODO: refactor mouse/clicks - $tmp=explode("|",$row['mouse_movements']); - if(count($tmp) > 1){ - $mouses[]= - "Array(" . - implode(",", - array_map('quote_dimensions',$tmp)) . - ")"; - }else{ - $mouses[]=quote_dimensions($tmp[0]);; - } - - - $tmp=explode("|",$row['clicks']); - if(count($tmp) > 1){ - $clicks[]= - "Array(" . - implode(",", - array_map('quote_dimensions',$tmp)) . - ")"; - }else{ - $clicks[]=quote_dimensions($tmp[0]);; - } - - - $tmp= - array_map(create_function('$s','return max(0,$s -' . $height . ');'), - explode("|",$row['scroll'])); - if(count($tmp) > 1 ){ - $scrolls[]="Array(" . implode(",",$tmp) . ")"; - }else{ - $scrolls[]="{$tmp[0]}"; - } - -} - -?> - -jQuery(function($){ - $.scrollTo(0); - - $('body').append(""); - - - - function placeClick(pos){ - if(!pos[0] || !pos[1]) - return; - - // these corrections are just eyeballed - //pos[0]=(pos[0]*1)-35; - //pos[1]=(pos[1]*1)-12; - - $('body').append(""); - } - - function moveMouse(pos){ - if(!pos[0] || !pos[1]) - return; - - // these corrections are just eyeballed - //pos[0]=(pos[0]*1)-35; - //pos[1]=(pos[1]*1)-12; - - - $("#dfhu_dot") - .animate({ - left: pos[0] + "px", - top: pos[1] + "px"}, - 20); - - $("#dfhu_dot").css('left',pos[0] + "px"); - $("#dfhu_dot").css('top',pos[1] + "px"); - - return; - } - - - var tic=0; - var step=0; - function move(){ - - if(tic >= scrollMotion.length){ - return; - } - - // wait until the step time catches up to the current step - step=step+5; - if(tics[tic] > step){ - return; - } - - if(scrollMotion[tic] != 0){ - if(typeof(scrollMotion[tic]) == "object"){ - for(ii in scrollMotion[tic]){ - $.scrollTo(scrollMotion[tic][ii],20); - } - }else{ - $.scrollTo(scrollMotion[tic],20); - } - } - - if(typeof(mouseMotion[tic]) == "object"){ - for(ii in mouseMotion[tic]){ - moveMouse(mouseMotion[tic][ii]); - } - }else{ - moveMouse(mouseMotion[tic]); - } - - if(typeof(clicks[tic]) == "array"){ - for(ii in clicks[tic]){ - placeClick(clicks[tic][ii]); - } - }else{ - placeClick(clicks[tic]); - } - - tic=tic+1; - }// move() - - - setInterval(move,250); - -}); \ No newline at end of file diff --git a/ft_server/replay_summary.php b/ft_server/replay_summary.php deleted file mode 100644 index 1b66243..0000000 --- a/ft_server/replay_summary.php +++ /dev/null @@ -1,20 +0,0 @@ - \ No newline at end of file From d4d46aee63f7ef796a50f740f4a9cb7e6d1e0be5 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Tue, 8 Nov 2016 03:24:48 +0000 Subject: [PATCH 267/267] chore(package): update dependencies https://greenkeeper.io/ --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index fb63f61..f748691 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "description": "A node.js statistics server", "version": "0.2.0-17", "dependencies": { - "socket.io": "0.9.6", - "node-static": "0.5.9", - "geoip": "0.4.12" + "socket.io": "1.5.1", + "node-static": "0.7.9", + "geoip": "0.6.1" }, "domains": [ "demo.hummingbirdstats.com"