2 var root
, crypto
, net
= false;
4 if (typeof window
=== "undefined") {
7 root
= window
.utils
= {};
10 if (typeof require
=== "function") {
11 crypto
= require("crypto");
15 var Set = function (items
) {
18 if (items
instanceof Array
)
19 items
.forEach(function (it
) { self
.add(it
); });
22 Set
.prototype.contains = function (what
) {
23 return (what
in this._items
);
26 Set
.prototype.add = function (what
) {
27 this._items
[what
] = true;
30 Set
.prototype.remove = function (what
) {
31 if (what
in this._items
)
32 delete this._items
[what
];
35 Set
.prototype.clear = function () {
39 Set
.prototype.forEach = function (fn
) {
40 for (var k
in this._items
) {
47 root
.isValidChannelName = function (name
) {
48 return name
.match(/^[\w-]{1,30}$/);
51 root
.isValidUserName = function (name
) {
52 return name
.match(/^[\w-]{1,20}$/);
55 root
.isValidEmail = function (email
) {
56 if (email
.length
> 255) {
60 if (!email
.match(/^[^@]+?@[^@]+$/)) {
64 if (email
.match(/^[^@]+?@(localhost|127\.0\.0\.1)$/)) {
71 root
.randomSalt = function (length
) {
72 var chars
= "abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
73 + "0123456789!@#$%^&*_+=~";
75 for(var i
= 0; i
< length
; i
++) {
76 salt
.push(chars
[parseInt(Math
.random()*chars
.length
)]);
81 root
.getIPRange = function (ip
) {
83 return root
.expandIPv6(ip
)
84 .replace(/((?:[0-9a-f]{4}:){3}[0-9a-f]{4}):(?:[0-9a-f]{4}:){3}[0-9a-f]{4}/, "$1");
86 return ip
.replace(/((?:[0-9]+\.){2}[0-9]+)\.[0-9]+/, "$1");
90 root
.getWideIPRange = function (ip
) {
92 return root
.expandIPv6(ip
)
93 .replace(/((?:[0-9a-f]{4}:){2}[0-9a-f]{4}):(?:[0-9a-f]{4}:){4}[0-9a-f]{4}/, "$1");
95 return ip
.replace(/([0-9]+\.[0-9]+)\.[0-9]+\.[0-9]+/, "$1");
99 root
.expandIPv6 = function (ip
) {
100 var result
= "0000:0000:0000:0000:0000:0000:0000:0000".split(":");
101 var parts
= ip
.split("::");
102 var left
= parts
[0].split(":");
104 left
.forEach(function (block
) {
105 while (block
.length
< 4) {
111 if (parts
.length
> 1) {
112 var right
= parts
[1].split(":");
114 right
.forEach(function (block
) {
115 while (block
.length
< 4) {
122 return result
.join(":");
125 root
.formatTime = function (sec
) {
129 sec
= Math
.floor(+sec
);
130 var h
= "", m
= "", s
= "";
133 h
= "" + Math
.floor(sec
/ 3600);
139 m
= "" + Math
.floor(sec
/ 60);
148 return [m
, s
].join(":");
150 return [h
, m
, s
].join(":");
153 root
.parseTime = function (time
) {
154 var parts
= time
.split(":").reverse();
156 switch (parts
.length
) {
158 seconds
+= parseInt(parts
[2]) * 3600;
160 seconds
+= parseInt(parts
[1]) * 60;
162 seconds
+= parseInt(parts
[0]);
170 root
.newRateLimiter = function () {
174 throttle: function (opts
) {
175 if (typeof opts
=== "undefined")
178 var burst
= +opts
.burst
,
179 sustained
= +opts
.sustained
,
180 cooldown
= +opts
.cooldown
;
185 if (isNaN(sustained
))
189 cooldown
= burst
/ sustained
;
191 // Cooled down, allow and clear buffer
192 if (this.lastTime
< Date
.now() - cooldown
*1000) {
194 this.lastTime
= Date
.now();
198 // Haven't reached burst cap yet, allow
199 if (this.count
< burst
) {
201 this.lastTime
= Date
.now();
205 var diff
= Date
.now() - this.lastTime
;
206 if (diff
< 1000/sustained
)
209 this.lastTime
= Date
.now();
215 root
.formatLink = function (id
, type
) {
218 return "http://youtu.be/" + id
;
220 return "http://vimeo.com/" + id
;
222 return "http://dailymotion.com/video/" + id
;
226 return "http://livestream.com/" + id
;
228 return "http://twitch.tv/" + id
;
234 return "http://imgur.com/a/" + id
;
236 return "http://ustream.tv/" + id
;
238 return "https://docs.google.com/file/d/" + id
;
242 return "http://hitbox.tv/" + id
;
248 root
.isLive = function (type
) {
264 root
.sha1 = function (data
) {
268 var shasum
= crypto
.createHash("sha1");
270 return shasum
.digest("hex");
273 root
.cloakIP = function (ip
) {
274 if (ip
.match(/\d+\.\d+(\.\d+)?(\.\d+)?/)) {
275 return cloakIPv4(ip
);
276 } else if (ip
.match(/([0-9a-f]{1,4}\:){1,7}[0-9a-f]{1,4}/)) {
277 return cloakIPv6(ip
);
282 function iphash(data
, len
) {
283 var md5
= crypto
.createHash("md5");
285 return md5
.digest("base64").substring(0, len
);
288 function cloakIPv4(ip
) {
289 var parts
= ip
.split(".");
290 var accumulator
= "";
292 parts
= parts
.map(function (segment
, i
) {
293 if (i
< 2) return segment
;
295 var part
= iphash(accumulator
+ segment
+ i
, 3);
296 accumulator
+= segment
;
300 while (parts
.length
< 4) parts
.push("*");
301 return parts
.join(".");
304 function cloakIPv6(ip
) {
305 var parts
= ip
.split(":");
307 var accumulator
= "";
309 parts
= parts
.map(function (segment
, i
) {
310 if (i
< 2) return segment
;
312 var part
= iphash(accumulator
+ segment
+ i
, 4);
313 accumulator
+= segment
;
317 while (parts
.length
< 4) parts
.push("*");
318 return parts
.join(":");