Initial commit
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
class DoubleLinkedListNode {
|
||||
constructor(key, value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.next = null;
|
||||
this.prev = null;
|
||||
};
|
||||
};
|
||||
|
||||
class DoubleLinkedList {
|
||||
constructor() {
|
||||
this.map = new Map();
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
};
|
||||
|
||||
getElement(id) {
|
||||
const element = this.map.get(id);
|
||||
if (!element) return;
|
||||
|
||||
return element.value;
|
||||
}
|
||||
|
||||
hasElement(id) {
|
||||
return this.map.has(id);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.head === null;
|
||||
}
|
||||
|
||||
addFirst(key, value) {
|
||||
if (this.map.has(key)) this.removeItem(key);
|
||||
|
||||
const newNode = new DoubleLinkedListNode(key, value);
|
||||
|
||||
const oldHead = this.head;
|
||||
this.head = newNode;
|
||||
this.head.prev = null;
|
||||
|
||||
if (oldHead) {
|
||||
oldHead.prev = newNode;
|
||||
this.head.next = oldHead;
|
||||
};
|
||||
|
||||
this.map.set(key, {
|
||||
value,
|
||||
node: newNode
|
||||
});
|
||||
};
|
||||
|
||||
accumulateItem(key, value) {
|
||||
if (isNaN(value)) return;
|
||||
|
||||
const entry = this.map.get(key);
|
||||
const updatedValue = entry ? entry.value + value : value;
|
||||
|
||||
this.addItem(key, updatedValue);
|
||||
}
|
||||
|
||||
addItem(key, value) {
|
||||
if (this.map.has(key)) this.removeItem(key);
|
||||
|
||||
const temp = new DoubleLinkedListNode(key, value);
|
||||
|
||||
if (!this.head) {
|
||||
this.head = temp;
|
||||
this.tail = temp;
|
||||
} else {
|
||||
this.tail.next = temp;
|
||||
temp.prev = this.tail;
|
||||
this.tail = this.tail.next;
|
||||
};
|
||||
|
||||
this.map.set(key, {
|
||||
value,
|
||||
node: temp
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
removeItem(key) {
|
||||
const entry = this.map.get(key);
|
||||
if (!entry) return;
|
||||
|
||||
const node = entry.node;
|
||||
if (node.prev) node.prev.next = node.next;
|
||||
if (node.next) node.next.prev = node.prev;
|
||||
|
||||
if (node === this.head) this.head = node.next;
|
||||
if (node === this.tail) this.tail = node.prev;
|
||||
|
||||
this.map.delete(key);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
each(cb) {
|
||||
if (this.isEmpty()) return;
|
||||
if (!cb) return;
|
||||
|
||||
let isRunning = true;
|
||||
let current = this.head;
|
||||
|
||||
while (current && (isRunning === undefined || isRunning)) { // I'm afraid this would backfire one day
|
||||
isRunning = cb(current.key, current.value);
|
||||
|
||||
current = current.next;
|
||||
};
|
||||
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
clearEach(cb) {
|
||||
if (this.isEmpty()) return;
|
||||
if (!cb) return;
|
||||
|
||||
let current = this.head;
|
||||
while (current) {
|
||||
cb(current.key, current.value);
|
||||
|
||||
current.prev = null;
|
||||
current = current.next;
|
||||
};
|
||||
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
|
||||
this.map.clear();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DoubleLinkedList;
|
||||
@@ -0,0 +1,73 @@
|
||||
class LinkedListNode {
|
||||
constructor(key, value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.next = null;
|
||||
};
|
||||
};
|
||||
|
||||
class LinkedList {
|
||||
constructor() {
|
||||
this.map = new Map();
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
};
|
||||
|
||||
getElement(id) {
|
||||
const element = this.map.get(id);
|
||||
if (!element) return;
|
||||
|
||||
return element.value;
|
||||
}
|
||||
|
||||
hasElement(id) {
|
||||
return this.map.has(id);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.head === null;
|
||||
}
|
||||
|
||||
addItem(key, value) {
|
||||
const temp = new LinkedListNode(key, value);
|
||||
|
||||
if (!this.head) {
|
||||
this.head = temp;
|
||||
this.tail = temp;
|
||||
} else {
|
||||
this.tail.next = temp;
|
||||
this.tail = temp;
|
||||
};
|
||||
|
||||
this.map.set(key, temp);
|
||||
}
|
||||
|
||||
each(cb) {
|
||||
if (this.isEmpty()) return;
|
||||
|
||||
let current = this.head;
|
||||
while (current) {
|
||||
cb(current.key, current.value);
|
||||
|
||||
current = current.next;
|
||||
};
|
||||
}
|
||||
|
||||
clearEach(cb) {
|
||||
if (this.isEmpty()) return;
|
||||
|
||||
let current = this.head;
|
||||
while (current) {
|
||||
cb(current.key, current.value);
|
||||
|
||||
current = current.next;
|
||||
};
|
||||
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
|
||||
this.map.clear();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = LinkedList;
|
||||
@@ -0,0 +1,30 @@
|
||||
class PriorityQueue {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
};
|
||||
|
||||
enqueue(item, priority) {
|
||||
const element = { item, priority };
|
||||
let added = false;
|
||||
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
if (priority < this.items[i].priority) {
|
||||
this.items.splice(i, 0, element);
|
||||
added = true;
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
if (!added) this.items.push(element);
|
||||
}
|
||||
|
||||
dequeue() {
|
||||
return this.isEmpty() ? null : this.items.shift().item;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.items.length === 0;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PriorityQueue;
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var defaultcomparator = function (a, b) {
|
||||
return a < b;
|
||||
};
|
||||
|
||||
// the provided comparator function should take a, b and return *true* when a < b
|
||||
function FastPriorityQueue(comparator) {
|
||||
if (!(this instanceof FastPriorityQueue)) return new FastPriorityQueue(comparator);
|
||||
this.array = [];
|
||||
this.size = 0;
|
||||
this.compare = comparator || defaultcomparator;
|
||||
}
|
||||
|
||||
// copy the priority queue into another, and return it. Queue items are shallow-copied.
|
||||
// Runs in `O(n)` time.
|
||||
FastPriorityQueue.prototype.clone = function() {
|
||||
var fpq = new FastPriorityQueue(this.compare);
|
||||
fpq.size = this.size;
|
||||
fpq.array = this.array.slice(0, this.size);
|
||||
return fpq;
|
||||
};
|
||||
|
||||
// Add an element into the queue
|
||||
// runs in O(log n) time
|
||||
FastPriorityQueue.prototype.add = function(value, obj) {
|
||||
var i = this.size;
|
||||
this.array[this.size] = { value, obj };
|
||||
this.size += 1;
|
||||
|
||||
var p;
|
||||
var ap;
|
||||
|
||||
while (i > 0) {
|
||||
p = (i - 1) >> 1;
|
||||
ap = this.array[p];
|
||||
if (!this.compare(value, ap.value)) break;
|
||||
|
||||
this.array[i] = ap;
|
||||
i = p;
|
||||
};
|
||||
|
||||
this.array[i] = { value, obj };
|
||||
};
|
||||
|
||||
// replace the content of the heap by provided array and "heapify it"
|
||||
FastPriorityQueue.prototype.heapify = function(arr) {
|
||||
this.array = arr;
|
||||
this.size = arr.length;
|
||||
var i;
|
||||
for (i = this.size >> 1; i >= 0; i--) {
|
||||
this._percolateDown(i);
|
||||
}
|
||||
};
|
||||
|
||||
// for internal use
|
||||
FastPriorityQueue.prototype._percolateUp = function(i, force) {
|
||||
var myval = this.array[i];
|
||||
var p;
|
||||
var ap;
|
||||
while (i > 0) {
|
||||
p = (i - 1) >> 1;
|
||||
ap = this.array[p];
|
||||
// force will skip the compare
|
||||
if (!force && !this.compare(myval.value, ap.value)) {
|
||||
break;
|
||||
}
|
||||
this.array[i] = ap;
|
||||
i = p;
|
||||
}
|
||||
this.array[i] = myval;
|
||||
};
|
||||
|
||||
// for internal use
|
||||
FastPriorityQueue.prototype._percolateDown = function(i) {
|
||||
var size = this.size;
|
||||
var hsize = this.size >>> 1;
|
||||
var ai = this.array[i];
|
||||
var l;
|
||||
var r;
|
||||
var bestc;
|
||||
while (i < hsize) {
|
||||
l = (i << 1) + 1;
|
||||
r = l + 1;
|
||||
bestc = this.array[l];
|
||||
if (r < size) {
|
||||
if (this.compare(this.array[r].value, bestc.value)) {
|
||||
l = r;
|
||||
bestc = this.array[r];
|
||||
}
|
||||
}
|
||||
if (!this.compare(bestc.value, ai.value)) {
|
||||
break;
|
||||
}
|
||||
this.array[i] = bestc;
|
||||
i = l;
|
||||
}
|
||||
this.array[i] = ai;
|
||||
};
|
||||
|
||||
// internal
|
||||
// _removeAt(index) will remove the item at the given index from the queue,
|
||||
// retaining balance. returns the removed item, or undefined if nothing is removed.
|
||||
FastPriorityQueue.prototype._removeAt = function(index) {
|
||||
if (index > this.size - 1 || index < 0) return undefined;
|
||||
|
||||
// impl1:
|
||||
//this.array.splice(index, 1);
|
||||
//this.heapify(this.array);
|
||||
// impl2:
|
||||
this._percolateUp(index, true);
|
||||
return this.poll();
|
||||
};
|
||||
|
||||
// remove(myval) will remove an item matching the provided value from the
|
||||
// queue, checked for equality by using the queue's comparator.
|
||||
// return true if removed, false otherwise.
|
||||
FastPriorityQueue.prototype.remove = function(myval) {
|
||||
for (var i = 0; i < this.size; i++) {
|
||||
if (!this.compare(this.array[i], myval) && !this.compare(myval, this.array[i])) {
|
||||
// items match, comparator returns false both ways, remove item
|
||||
this._removeAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// removeOne(callback) will execute the callback function for each item of the queue
|
||||
// and will remove the first item for which the callback will return true.
|
||||
// return the removed item, or undefined if nothing is removed.
|
||||
FastPriorityQueue.prototype.removeOne = function(callback) {
|
||||
if (typeof callback !== "function") {
|
||||
return undefined;
|
||||
}
|
||||
for (var i = 0; i < this.size; i++) {
|
||||
if (callback(this.array[i])) {
|
||||
return this._removeAt(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// remove(callback[, limit]) will execute the callback function for each item of
|
||||
// the queue and will remove each item for which the callback returns true, up to
|
||||
// a max limit of removed items if specified or no limit if unspecified.
|
||||
// return an array containing the removed items.
|
||||
// The callback function should be a pure function.
|
||||
FastPriorityQueue.prototype.removeMany = function(callback, limit) {
|
||||
// Skip unnecessary processing for edge cases
|
||||
if (typeof callback !== "function" || this.size < 1) {
|
||||
return [];
|
||||
}
|
||||
limit = limit ? Math.min(limit, this.size) : this.size;
|
||||
|
||||
// Prepare the results container to hold up to the results limit
|
||||
var resultSize = 0;
|
||||
var result = new Array(limit);
|
||||
|
||||
// Prepare a temporary array to hold items we'll traverse through and need to keep
|
||||
var tmpSize = 0;
|
||||
var tmp = new Array(this.size);
|
||||
|
||||
while (resultSize < limit && !this.isEmpty()) {
|
||||
// Dequeue items into either the results or our temporary array
|
||||
var item = this.poll();
|
||||
if (callback(item)) {
|
||||
result[resultSize++] = item;
|
||||
} else {
|
||||
tmp[tmpSize++] = item;
|
||||
}
|
||||
}
|
||||
// Update the result array with the exact number of results
|
||||
result.length = resultSize;
|
||||
|
||||
// Re-add all the items we can keep
|
||||
var i = 0;
|
||||
while (i < tmpSize) {
|
||||
const elem = tmp[i++];
|
||||
this.add(elem.value, elem.obj);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Look at the top of the queue (one of the smallest elements) without removing it
|
||||
// executes in constant time
|
||||
//
|
||||
// Calling peek on an empty priority queue returns
|
||||
// the "undefined" value.
|
||||
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/undefined
|
||||
//
|
||||
FastPriorityQueue.prototype.peek = function() {
|
||||
if (this.size == 0) return undefined;
|
||||
return this.array[0];
|
||||
};
|
||||
|
||||
// remove the element on top of the heap (one of the smallest elements)
|
||||
// runs in logarithmic time
|
||||
//
|
||||
// If the priority queue is empty, the function returns the
|
||||
// "undefined" value.
|
||||
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/undefined
|
||||
//
|
||||
// For long-running and large priority queues, or priority queues
|
||||
// storing large objects, you may want to call the trim function
|
||||
// at strategic times to recover allocated memory.
|
||||
FastPriorityQueue.prototype.poll = function() {
|
||||
if (this.size == 0) return undefined;
|
||||
var ans = this.array[0];
|
||||
|
||||
if (this.size > 1) {
|
||||
this.array[0] = this.array[--this.size];
|
||||
this._percolateDown(0);
|
||||
} else {
|
||||
this.size -= 1;
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
|
||||
// This function adds the provided value to the heap, while removing
|
||||
// and returning one of the smallest elements (like poll). The size of the queue
|
||||
// thus remains unchanged.
|
||||
FastPriorityQueue.prototype.replaceTop = function(myval) {
|
||||
if (this.size == 0) return undefined;
|
||||
var ans = this.array[0];
|
||||
this.array[0] = myval;
|
||||
this._percolateDown(0);
|
||||
return ans;
|
||||
};
|
||||
|
||||
// recover unused memory (for long-running priority queues)
|
||||
FastPriorityQueue.prototype.trim = function() {
|
||||
this.array = this.array.slice(0, this.size);
|
||||
};
|
||||
|
||||
// Check whether the heap is empty
|
||||
FastPriorityQueue.prototype.isEmpty = function() {
|
||||
return this.size === 0;
|
||||
};
|
||||
|
||||
FastPriorityQueue.prototype.forEach = function(callback) {
|
||||
if (this.isEmpty() || typeof callback != 'function') return;
|
||||
var i = 0;
|
||||
var fpq = this.clone();
|
||||
let isRunning = true;
|
||||
|
||||
while (!fpq.isEmpty() && isRunning) {
|
||||
isRunning = callback(fpq.poll(), i++);
|
||||
}
|
||||
};
|
||||
|
||||
// return the k 'smallest' elements of the queue as an array,
|
||||
// runs in O(k log k) time, the elements are not removed
|
||||
// from the priority queue.
|
||||
FastPriorityQueue.prototype.kSmallest = function(k) {
|
||||
if ((this.size == 0) || (k<=0)) return [];
|
||||
k = Math.min(this.size, k);
|
||||
const newSize = Math.min(this.size, (2 ** (k - 1)) + 1);
|
||||
if (newSize < 2) { return [this.peek()] }
|
||||
|
||||
const fpq = new FastPriorityQueue(this.compare);
|
||||
fpq.size = newSize;
|
||||
fpq.array = this.array.slice(0, newSize);
|
||||
|
||||
const smallest = new Array(k);
|
||||
for (let i = 0; i < k; i++) {
|
||||
smallest[i] = fpq.poll();
|
||||
}
|
||||
return smallest;
|
||||
}
|
||||
|
||||
module.exports = FastPriorityQueue;
|
||||
@@ -0,0 +1,71 @@
|
||||
class Router {
|
||||
constructor(base) {
|
||||
this.routes = [];
|
||||
this.base = base;
|
||||
};
|
||||
|
||||
addRoute(method, path, handler) {
|
||||
const paramNames = [];
|
||||
const regexPath = path
|
||||
.replace(/:([^/]+)/g, (match, paramName) => {
|
||||
paramNames.push(paramName);
|
||||
return '([^/]+)';
|
||||
})
|
||||
.replace(/\*/g, '.*');
|
||||
|
||||
this.routes.push({
|
||||
method,
|
||||
path,
|
||||
regex: new RegExp(`^${regexPath}$`),
|
||||
paramNames,
|
||||
handler
|
||||
});
|
||||
}
|
||||
|
||||
get(path, handler) {
|
||||
this.addRoute("GET", this.base ? this.base + path : path, handler);
|
||||
console.info(this.base ? this.base + path : path)
|
||||
}
|
||||
|
||||
post(path, handler) {
|
||||
this.addRoute("POST", this.base ? this.base + path : path, handler);
|
||||
console.info("POST", this.base ? this.base + path : path)
|
||||
|
||||
}
|
||||
|
||||
put(path, handler) {
|
||||
this.addRoute("PUT", this.base ? this.base + path : path, handler);
|
||||
}
|
||||
|
||||
delete(path, handler) {
|
||||
this.addRoute("DELETE", this.base ? this.base + path : path, handler);
|
||||
}
|
||||
|
||||
handle(res, req) {
|
||||
const method = req.getMethod().toUpperCase();
|
||||
const urlPrepare = req.getUrl().split("/");
|
||||
const urlRelevant = urlPrepare.slice(2, urlPrepare.length);
|
||||
const url = "/" + urlRelevant.join("/");
|
||||
console.info("hm?", method)
|
||||
for (const route of this.routes) {
|
||||
if (route.method === method) {
|
||||
const match = url.match(route.regex);
|
||||
console.info(url, route, method)
|
||||
if (!match) continue;
|
||||
|
||||
const params = {};
|
||||
route.paramNames.forEach((name, index) => params[name] = match[index + 1]);
|
||||
|
||||
req.params = params;
|
||||
|
||||
return route.handler(res, req);
|
||||
};
|
||||
};
|
||||
|
||||
res
|
||||
.writeStatus("404 Not Found")
|
||||
.end("Invalid route");
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Router;
|
||||
@@ -0,0 +1,15 @@
|
||||
function chooseWeightedRandom(items, weights) {
|
||||
let i;
|
||||
let length = weights.length;
|
||||
weights = [...weights];
|
||||
|
||||
for (i = 0; i < length; i++) weights[i] += weights[i - 1] || 0;
|
||||
|
||||
const random = Math.random() * weights[length - 1];
|
||||
|
||||
for (i = 0; i < length; i++) if (weights[i] > random) break;
|
||||
|
||||
return items[i];
|
||||
};
|
||||
|
||||
module.exports = chooseWeightedRandom;
|
||||
@@ -0,0 +1,76 @@
|
||||
function extractBehaviourFeatures(actions) {
|
||||
if (!actions || actions.length < 2) return null;
|
||||
|
||||
const actionCounts = {};
|
||||
const idleThreshold = 5000;
|
||||
const windowSize = 5;
|
||||
const intervals = [];
|
||||
const sequenceBuffer = [];
|
||||
let totalInterval = 0;
|
||||
let minInterval = Infinity;
|
||||
let maxInterval = -Infinity;
|
||||
let idleTimeCount = 0;
|
||||
let idleTimeTotal = 0;
|
||||
let lastTimestamp = actions[0].timestamp;
|
||||
let prevAction = actions[0].opcode;
|
||||
let sequenceMap = {};
|
||||
|
||||
for (let i = 1; i < actions.length; i++) {
|
||||
const current = actions[i];
|
||||
const interval = current.timestamp - lastTimestamp;
|
||||
lastTimestamp = current.timestamp;
|
||||
|
||||
intervals.push(interval);
|
||||
|
||||
totalInterval += interval;
|
||||
minInterval = Math.min(minInterval, interval);
|
||||
maxInterval = Math.max(maxInterval, interval);
|
||||
|
||||
actionCounts[current.opcode] = (actionCounts[current.opcode] || 0) + 1;
|
||||
|
||||
if (interval > idleThreshold) {
|
||||
idleTimeCount++;
|
||||
idleTimeTotal += interval;
|
||||
};
|
||||
|
||||
sequenceBuffer.push(current.opcode);
|
||||
if (sequenceBuffer.length === windowSize) {
|
||||
const key = sequenceBuffer.join(",");
|
||||
sequenceMap[key] = (sequenceMap[key] || 0) + 1;
|
||||
|
||||
sequenceBuffer.shift();
|
||||
};
|
||||
|
||||
prevAction = current.opcode;
|
||||
};
|
||||
|
||||
const meanInterval = totalInterval / intervals.length;
|
||||
const stdDevInterval = Math.sqrt(intervals.reduce((sum, val) => sum + (val - meanInterval) ** 2, 0) / intervals.length);
|
||||
|
||||
const uniqueActionsCount = Object.keys(actionCounts).length;
|
||||
const idleTimeRatio = idleTimeCount / (actions.length - 1);
|
||||
const maxSequenceRepeats = Math.max(...Object.values(sequenceMap)) || 0;
|
||||
|
||||
const totalActions = actions.length;
|
||||
let entropy = 0;
|
||||
|
||||
for (const count of Object.values(actionCounts)) {
|
||||
const p = count / totalActions;
|
||||
entropy -= p * Math.log2(p);
|
||||
};
|
||||
|
||||
return {
|
||||
timestamp: new Date(),
|
||||
timestampStart: null,
|
||||
meanInterval,
|
||||
stdDevInterval,
|
||||
minInterval,
|
||||
maxInterval,
|
||||
uniqueActionsCount,
|
||||
actionEntropy: entropy,
|
||||
maxSequenceRepeats,
|
||||
idleTimeRatio
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = extractBehaviourFeatures;
|
||||
@@ -0,0 +1,5 @@
|
||||
function getFixedDate(seconds) {
|
||||
return Date.now() - (Date.now() % (seconds * 1000) - seconds * 1000);
|
||||
};
|
||||
|
||||
module.exports = getFixedDate;
|
||||
@@ -0,0 +1,36 @@
|
||||
const redis = require("../Miscellaneous/redis");
|
||||
|
||||
async function isAuthenticated(res, req) {
|
||||
const cookieHeader = req.getHeader("cookie");
|
||||
const cookie = cookieHeader.split("ps=")[1];
|
||||
if (!cookie) {
|
||||
res.cork(() => res
|
||||
.writeStatus("400")
|
||||
.end("Unauthenticated"));
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const formattedCookie = cookie.split(".")[0].slice(4);
|
||||
const cookieInDB = await redis.get(`sess:${formattedCookie}`);
|
||||
if (!cookieInDB) {
|
||||
res.cork(() => res
|
||||
.writeStatus("400")
|
||||
.end("Unauthenticated"));
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const parsedCookie = JSON.parse(cookieInDB);
|
||||
if (!parsedCookie.isAdmin) {
|
||||
res.cork(() => res
|
||||
.writeStatus("400")
|
||||
.end("Unauthorized"));
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
module.exports = isAuthenticated;
|
||||
@@ -0,0 +1,131 @@
|
||||
(function(w) {
|
||||
|
||||
/**
|
||||
* The main constructor function.
|
||||
* @constructor
|
||||
* @param {Function} onTick The tick function.
|
||||
* @param {Number} interval The tick duration.
|
||||
* @returns {Timer} The instance of timer.
|
||||
*/
|
||||
var Timer = function(onTick, interval) {
|
||||
this.setInterval(interval);
|
||||
this.setOnTick(onTick);
|
||||
|
||||
this._timer = null;
|
||||
this._active = false;
|
||||
|
||||
this._startTime = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Start the timer.
|
||||
* The tick function is called with one argument, the drift amount (int).
|
||||
* @returns {Timer} this.
|
||||
*/
|
||||
Timer.prototype.start = function() {
|
||||
|
||||
let drift = 0,
|
||||
actual = 0,
|
||||
ideal = 0,
|
||||
counter = 0,
|
||||
time = 0,
|
||||
that = this,
|
||||
now = performance.now;
|
||||
|
||||
|
||||
function onTick() {
|
||||
that._onTick(drift);
|
||||
|
||||
++counter;
|
||||
|
||||
ideal = that._interval * counter;
|
||||
actual = now() - that._startTime;
|
||||
drift = actual - ideal;
|
||||
time = that._interval - drift;
|
||||
|
||||
|
||||
|
||||
if (that._active) setTimeout(onTick, time);
|
||||
}
|
||||
|
||||
that._active = true;
|
||||
that._startTime = now();
|
||||
that._timer = setTimeout(onTick, that._interval);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stop the timer.
|
||||
* @returns {Timer} this.
|
||||
*/
|
||||
Timer.prototype.stop = function() {
|
||||
this._active = false;
|
||||
clearTimeout(this._timer);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the tick duration. Can be called whilst timer is running.
|
||||
* @param {Number} ms The tick duration.
|
||||
* @returns {Timer} this.
|
||||
*/
|
||||
Timer.prototype.setInterval = function(ms) {
|
||||
if(isNaN(ms)) {
|
||||
throw new Error('Timer.setInterval requires a number');
|
||||
}
|
||||
else if(ms < 10) {
|
||||
ms = 10;
|
||||
}
|
||||
|
||||
this._interval = ms;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow for replacement of the tick function, even whilst the timer
|
||||
* is running.
|
||||
* @param {Function} onTick The new tick function to be called on each cycle.
|
||||
* @returns {Timer} this.
|
||||
*/
|
||||
Timer.prototype.setOnTick = function(onTick) {
|
||||
this._onTick = onTick;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allow the `Timer` constructor to be used as a replacement for
|
||||
* setInterval.
|
||||
* @param {Function} tick The tick function to call every `interval` ms.
|
||||
* @param {Number} interval The tick duration.
|
||||
* @returns {Timer} A new instance of the `Timer` constructor.
|
||||
*/
|
||||
var setTimer = function(tick, interval) {
|
||||
var timer = new Timer(tick, interval);
|
||||
timer.start();
|
||||
return timer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Imitate the clearTimeout method...
|
||||
* @param {Timer}
|
||||
*/
|
||||
var clearTimer = function(timer) {
|
||||
timer.stop();
|
||||
};
|
||||
|
||||
|
||||
|
||||
w.Timer = Timer;
|
||||
w.setTimer = setTimer;
|
||||
|
||||
|
||||
|
||||
|
||||
}(global));
|
||||
Reference in New Issue
Block a user