<commit_before>const {ipcRenderer} = require('electron');
const data_logs = require('./data_logs');
data_logs.loadLogs();
let nodeMap = data_logs.getLogsMap();
require('./chart_styles');

// vars
let previousIndex = 0;
let pointIndex = 0;
let currentNode = '';

// network load color array for use in order of 10
// order is from red to green for modulo purpose
// var colorArray = [
// "#F33B3B",
// "#D9473A",
// "#C05439",
// "#A76139",
// "#8D6E38",
// "#747A38",
// "#5B8737",
// "#419437",
// "#28A136",
// "#0FAE36"
// ]

// var colorArray = [
// "#CC3333",
// "#FF9933",
// "#66CC33"
// ]

var colorArray = [
"red",
"orange",
"green"
];

// update and highlight functions
$(document).ready(function() {
    updateCurrentNode('overall');
    // print to our console
    data_logs.getLogsMap().forEach(function(value, key) {
        // ipcRenderer.send('main', key + ': ' + value);
        ipcRenderer.send('main', 'name: ' + value.get('name'));
        ipcRenderer.send('main', 'numOfPorts: ' + value.get('numOfPorts'));
        let portNames = value.get('portNames');
        ipcRenderer.send('main', 'portNames: ' + portNames);
        portNames.forEach(function(currentValue, index, array) {
            ipcRenderer.send('main', 'port: ' + currentValue);
            ipcRenderer.send('main', 'input: ' + value.get('ports').get(currentValue).get('input'));
            ipcRenderer.send('main', 'output: ' + value.get('ports').get(currentValue).get('output'));
            ipcRenderer.send('main', 'port total: ' + value.get('ports').get(currentValue).get('total'));
        });
        ipcRenderer.send('main', 'total: ' + value.get('total'));
    });
});

function updateCurrentNode(node) {
    $("#currentNodeLabel").text(node);
    currentNode = node;
    updateDataSources();
    update();
    showHideCharts();
}

function updateDataSources() {
    if (nodeMap.has(currentNode)) {
        networkChart.data.datasets[0].data = nodeMap.get(currentNode).get('total');
        let numOfPorts = nodeMap.get(currentNode).get('numOfPorts');
        networkChart.options.scales.yAxes[0].ticks.max = 2500000 * numOfPorts;
        for (i = 0; i < numOfPorts; i++) {
            let portName = nodeMap.get(currentNode).get('portNames')[i];
            portCharts[i].options.title.text = portName;
            portCharts[i].data.datasets[0].data = nodeMap.get(currentNode).get('ports').get(portName).get('input');
            portCharts[i].data.datasets[1].data = nodeMap.get(currentNode).get('ports').get(portName).get('output');
            portCharts[i].update();
        }
    } else {
        networkChart.data.datasets[0].data = networkData_overall;
        networkChart.options.scales.yAxes[0].ticks.max = 125000000;
    }
    networkChart.update();
    cpuChart.data.datasets[0].data = cpuData_overall;
    cpuChart.update();
}

function update() {
    updateHighlights();
    $("#currentTimeLabel").text(pointIndex);
}

function updateHighlights() {
    highlightPointOnCharts();
    highlightOverallNetworkLoad();
    highlightNetworkLoad();
}

function highlightPointOnCharts() {
    var cpuMeta = cpuChart.getDatasetMeta(0);
    var networkMeta = networkChart.getDatasetMeta(0);

    // Reset previous point
    var cpuOldPoint = cpuMeta.data[previousIndex];
    cpuOldPoint.custom = cpuOldPoint.custom || {};
    cpuOldPoint.custom.backgroundColor = "#fff";
    cpuOldPoint.custom.radius = 3;
    var networkOldPoint = networkMeta.data[previousIndex];
    networkOldPoint.custom = networkOldPoint.custom || {};
    networkOldPoint.custom.backgroundColor = "#fff";
    networkOldPoint.custom.radius = 3;

    //Get point object and change the radius/color
    var cpuPoint = cpuMeta.data[pointIndex];
    cpuPoint.custom = cpuPoint.custom || {};
    cpuPoint.custom.backgroundColor = "#828282";
    cpuPoint.custom.radius = 7;
    var networkPoint = networkMeta.data[pointIndex];
    networkPoint.custom = networkPoint.custom || {};
    networkPoint.custom.backgroundColor = "#828282";
    networkPoint.custom.radius = 7;

    // first parameter to update is the animation duration.
    // if none is specified, the config animation duration
    // is used. Using 0 here will do the draw immediately.
    cpuChart.update();
    networkChart.update();

    if (nodeMap.has(currentNode)) {
        for (i = 0; i < nodeMap.get(currentNode).get('numOfPorts'); i++) {
            var portMeta1 = portCharts[i].getDatasetMeta(0);
            var portMeta2 = portCharts[i].getDatasetMeta(1);

            // Reset previous point
            var portOldPoint1 = portMeta1.data[previousIndex];
            var portOldPoint2 = portMeta2.data[previousIndex];
            portOldPoint1.custom = portOldPoint1.custom || {};
            portOldPoint2.custom = portOldPoint2.custom || {};
            portOldPoint1.custom.backgroundColor = "#fff";
            portOldPoint2.custom.backgroundColor = "#fff";
            portOldPoint1.custom.radius = 3;
            portOldPoint2.custom.radius = 3;

            //Get point object and change the radius/color
            var portPoint1 = portMeta1.data[pointIndex];
            var portPoint2 = portMeta2.data[pointIndex];
            portPoint1.custom = portPoint1.custom || {};
            portPoint2.custom = portPoint2.custom || {};
            portPoint1.custom.backgroundColor = "#828282";
            portPoint2.custom.backgroundColor = "#828282";
            portPoint1.custom.radius = 7;
            portPoint2.custom.radius = 7;

            portCharts[i].update();
        }
    }

    previousIndex = pointIndex;
}

function highlightNetworkLoad() {
    if (nodeMap.has(currentNode)) {
        cy.nodes().style({ 'background-color':'gray' });

        // colour nodes based on cpu load
        // if (cpuData[currentNode][pointIndex] > 70) {
        //     cy.nodes('#' + nodes[currentNode]).style({ 'background-color':'red' });
        // } else if (cpuData[currentNode][pointIndex] > 40) {
        //     cy.nodes('#' + nodes[currentNode]).style({ 'background-color':'orange' });
        // } else {
        //     cy.nodes('#' + nodes[currentNode]).style({ 'background-color':'green' });
        // }

        // colour nodes based on network load
        let networkLoad = nodeMap.get(currentNode).get('total')[pointIndex];
        if (networkLoad > 400000) {
            cy.nodes('#' + currentNode).style({ 'background-color':'red' });
        } else if (networkLoad > 200000) {
            cy.nodes('#' + currentNode).style({ 'background-color':'orange' });
        } else {
            cy.nodes('#' + currentNode).style({ 'background-color':'green' });
        }

        cy.edges().style({ 'line-color':'gray' });
        let portsMap = nodeMap.get(currentNode).get('ports');
        let portNum = 0;
        portsMap.forEach(function (value, key) {
            let bandwidth = value.get('total')[pointIndex];
            if (bandwidth > 400000) {
                cy.elements('edge[source = "' + nodeMap.get(currentNode).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'red' });
            } else if (bandwidth > 200000) {
                cy.elements('edge[source = "' + nodeMap.get(currentNode).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'orange' });
            } else {
                cy.elements('edge[source = "' + nodeMap.get(currentNode).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'green' });
            }
            portNum++;
        });
    }
}

function highlightOverallNetworkLoad() {
    if (!nodeMap.has(currentNode)) {
        let nodes = data_logs.getNodes();
        for (i = 0; i < nodes.length; i++) {
            // color nodes based on network data
            let node = nodes[i];
            let networkLoad = nodeMap.get(node).get('total')[pointIndex];
            let nodeColorIndex = 2;
            if (networkLoad > 400000) {
                nodeColorIndex = 0;
            } else if (networkLoad > 200000) {
                nodeColorIndex = 1;
            }
            cy.nodes('#' + nodes[i]).style({'background-color': colorArray[nodeColorIndex]});

            let portsMap = nodeMap.get(node).get('ports');
            let portNum = 0;
            portsMap.forEach(function (value, key) {
                let bandwidth = value.get('total')[pointIndex];
                if (bandwidth > 400000) {
                    cy.elements('edge[source = "' + nodeMap.get(node).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'red' });
                } else if (bandwidth > 200000) {
                    cy.elements('edge[source = "' + nodeMap.get(node).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'orange' });
                } else {
                    cy.elements('edge[source = "' + nodeMap.get(node).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'green' });
                }
                portNum++;
            });
        }
    }
}

// reset nodes and edges colors for mouse click on cy container
function resetNodesAndEdgesColors() {
    cy.nodes().style({ 'background-color':'gray' });
    cy.edges().style({ 'line-color':'gray' });
}

function showHideCharts() {
    if (nodeMap.has(currentNode)) {
        for (i = 1; i <= portCharts.length; i++) {
            if (i <= nodeMap.get(currentNode).get('numOfPorts')) {
                if ($('#placeholder-row' + i).hasClass("no-visibility")) {
                    $('#placeholder-row' + i).removeClass("no-visibility");
                }
            } else {
                if (!$('#placeholder-row' + i).hasClass("no-visibility")) {
                    $('#placeholder-row' + i).addClass("no-visibility");
                }
            }
        }
    } else {
        for (i = 1; i <= portCharts.length; i++) {
            if (!$('#placeholder-row' + i).hasClass("no-visibility")) {
                $('#placeholder-row' + i).addClass("no-visibility");
            }
        }
    }
}

// button functions
$('#startButton').on('click', function () {
    pointIndex = $('#ex1').slider('getAttribute', 'min');
    $('#ex1').slider('setValue', pointIndex);
    update();
});
$('#endButton').on('click', function () {
    pointIndex = $('#ex1').slider('getAttribute', 'max');
    $('#ex1').slider('setValue', pointIndex);
    update();
});
var isPlaying = false;
$('#playPauseButton').on('click', function () {
    if (isPlaying) {
        isPlaying = false;
        $('#playPauseIcon').removeClass('glyphicon-pause').addClass('glyphicon-play');
    } else {
        isPlaying = true;
        $('#playPauseIcon').removeClass('glyphicon-play').addClass('glyphicon-pause');
        if (pointIndex == $('#ex1').slider('getAttribute', 'max')) {
            pointIndex = $('#ex1').slider('getAttribute', 'min');
            $('#ex1').slider('setValue', pointIndex);
            update();
            window.setTimeout(playbackTicker, 100);
        } else {
            playbackTicker();
        }
    }
});
function playbackTicker() {
    if (isPlaying && pointIndex < $('#ex1').slider('getAttribute', 'max')) {
        pointIndex++;
        $('#ex1').slider('setValue', pointIndex);
        update();
        window.setTimeout(playbackTicker, 100);
    } else if (isPlaying && pointIndex >= $('#ex1').slider('getAttribute', 'max')) {
        isPlaying = false;
        $('#playPauseIcon').removeClass('glyphicon-pause').addClass('glyphicon-play');
    }
}

// slider
$('#ex1').slider({
    formatter: function(value) {
        return 'Current time: ' + value;
    }
});
$("#ex1").on("slide", function(slideEvt) {
    pointIndex = slideEvt.value;
    update();
});
$("#ex1").on("slideStop", function(slideEvt) {
    pointIndex = slideEvt.value;
    update();
});

// topology
var cy = cytoscape({
    container: $('#cy'),
    elements: dataset,

    boxSelectionEnabled: false,
    autounselectify: true,

    layout: {
        name: 'cose-bilkent',
        randomize: true,
        nodeRepulsion: 400000
    },
    style: cyStyle
});
cy.on('mouseover', 'node', function(event) {
    var node = event.cyTarget;
    // node.qtip({
    //     content: this.data('label'),
    //     show: {
    //         event: event.type,
    //         ready: true
    //     },
    //     hide: {
    //         event: 'mouseout unfocus'
    //     }
    // }, event);
});
cy.on('click', function(event) {
    var node = event.cyTarget;
    if (node === cy) {
        updateCurrentNode('overall');
        resetNodesAndEdgesColors();
    } else {
        updateCurrentNode(node.id());
    }
});

// cpu chart
var cpuCanvas = document.getElementById("cpu-chart");
cpuCanvas.width = parseInt($('#well1').css('width'), 10);
cpuCanvas.height = parseInt($('#well1').css('height'), 10);
var cpuChart = new Chart(cpuCanvas, {
    type: 'line',
    data: cpuChartStyle,
    options: {}
});

// network chart
var networkCanvas = document.getElementById("network-chart");
networkCanvas.width = parseInt($('#well2').css('width'), 10);
networkCanvas.height = parseInt($('#well2').css('height'), 10);
var networkChart = new Chart(networkCanvas, {
    type: 'line',
    data: networkChartStyle,
    options: networkChartOptions
});

// port charts
var portCanvas1 = document.getElementById("port-chart1");
portCanvas1.width = parseInt($('#well3').css('width'), 10);
portCanvas1.height = parseInt($('#well3').css('height'), 10);
var portChart1 = new Chart(portCanvas1, {
    type: "line",
    data: portChartStyle1,
    options: {
        title: {
            display: true,
            text: 'Port [0]'
        },
        scales: portChartScales
    }
});

var portCanvas2 = document.getElementById("port-chart2");
portCanvas2.width = parseInt($('#well4').css('width'), 10);
portCanvas2.height = parseInt($('#well4').css('height'), 10);
var portChart2 = new Chart(portCanvas2, {
    type: "line",
    data: portChartStyle2,
    options: {
        title: {
            display: true,
            text: 'Port [1]'
        },
        scales: portChartScales
    }
});

portCharts = [
    portChart1,
    portChart2];
<commit_msg>try out gradient for nodes<commit_after>const {ipcRenderer} = require('electron');
const data_logs = require('./data_logs');
data_logs.loadLogs();
let nodeMap = data_logs.getLogsMap();
require('./chart_styles');

// vars
let previousIndex = 0;
let pointIndex = 0;
let currentNode = '';

// network load color array for use in order of 10
// order is from red to green for modulo purpose
// var colorArray = [
// "#F33B3B",
// "#D9473A",
// "#C05439",
// "#A76139",
// "#8D6E38",
// "#747A38",
// "#5B8737",
// "#419437",
// "#28A136",
// "#0FAE36"
// ]

// var colorArray = [
// "#CC3333",
// "#FF9933",
// "#66CC33"
// ]

var colorArray = [
"red",
"orange",
"green"
];

var colorArray = [
"#fb2754",
"#8d1f8f",
"#2d2997",
"#2171b0",
"#0fb2f3",
"#0cc1f8"
]

// update and highlight functions
$(document).ready(function() {
    updateCurrentNode('overall');
    // print to our console
    data_logs.getLogsMap().forEach(function(value, key) {
        // ipcRenderer.send('main', key + ': ' + value);
        ipcRenderer.send('main', 'name: ' + value.get('name'));
        ipcRenderer.send('main', 'numOfPorts: ' + value.get('numOfPorts'));
        let portNames = value.get('portNames');
        ipcRenderer.send('main', 'portNames: ' + portNames);
        portNames.forEach(function(currentValue, index, array) {
            ipcRenderer.send('main', 'port: ' + currentValue);
            ipcRenderer.send('main', 'input: ' + value.get('ports').get(currentValue).get('input'));
            ipcRenderer.send('main', 'output: ' + value.get('ports').get(currentValue).get('output'));
            ipcRenderer.send('main', 'port total: ' + value.get('ports').get(currentValue).get('total'));
        });
        ipcRenderer.send('main', 'total: ' + value.get('total'));
    });
});

function updateCurrentNode(node) {
    $("#currentNodeLabel").text(node);
    currentNode = node;
    updateDataSources();
    update();
    showHideCharts();
}

function updateDataSources() {
    if (nodeMap.has(currentNode)) {
        networkChart.data.datasets[0].data = nodeMap.get(currentNode).get('total');
        let numOfPorts = nodeMap.get(currentNode).get('numOfPorts');
        networkChart.options.scales.yAxes[0].ticks.max = 2500000 * numOfPorts;
        for (i = 0; i < numOfPorts; i++) {
            let portName = nodeMap.get(currentNode).get('portNames')[i];
            portCharts[i].options.title.text = portName;
            portCharts[i].data.datasets[0].data = nodeMap.get(currentNode).get('ports').get(portName).get('input');
            portCharts[i].data.datasets[1].data = nodeMap.get(currentNode).get('ports').get(portName).get('output');
            portCharts[i].update();
        }
    } else {
        networkChart.data.datasets[0].data = networkData_overall;
        networkChart.options.scales.yAxes[0].ticks.max = 125000000;
    }
    networkChart.update();
    cpuChart.data.datasets[0].data = cpuData_overall;
    cpuChart.update();
}

function update() {
    updateHighlights();
    $("#currentTimeLabel").text(pointIndex);
}

function updateHighlights() {
    highlightPointOnCharts();
    highlightOverallNetworkLoad();
    highlightNetworkLoad();
}

function highlightPointOnCharts() {
    var cpuMeta = cpuChart.getDatasetMeta(0);
    var networkMeta = networkChart.getDatasetMeta(0);

    // Reset previous point
    var cpuOldPoint = cpuMeta.data[previousIndex];
    cpuOldPoint.custom = cpuOldPoint.custom || {};
    cpuOldPoint.custom.backgroundColor = "#fff";
    cpuOldPoint.custom.radius = 3;
    var networkOldPoint = networkMeta.data[previousIndex];
    networkOldPoint.custom = networkOldPoint.custom || {};
    networkOldPoint.custom.backgroundColor = "#fff";
    networkOldPoint.custom.radius = 3;

    //Get point object and change the radius/color
    var cpuPoint = cpuMeta.data[pointIndex];
    cpuPoint.custom = cpuPoint.custom || {};
    cpuPoint.custom.backgroundColor = "#828282";
    cpuPoint.custom.radius = 7;
    var networkPoint = networkMeta.data[pointIndex];
    networkPoint.custom = networkPoint.custom || {};
    networkPoint.custom.backgroundColor = "#828282";
    networkPoint.custom.radius = 7;

    // first parameter to update is the animation duration.
    // if none is specified, the config animation duration
    // is used. Using 0 here will do the draw immediately.
    cpuChart.update();
    networkChart.update();

    if (nodeMap.has(currentNode)) {
        for (i = 0; i < nodeMap.get(currentNode).get('numOfPorts'); i++) {
            var portMeta1 = portCharts[i].getDatasetMeta(0);
            var portMeta2 = portCharts[i].getDatasetMeta(1);

            // Reset previous point
            var portOldPoint1 = portMeta1.data[previousIndex];
            var portOldPoint2 = portMeta2.data[previousIndex];
            portOldPoint1.custom = portOldPoint1.custom || {};
            portOldPoint2.custom = portOldPoint2.custom || {};
            portOldPoint1.custom.backgroundColor = "#fff";
            portOldPoint2.custom.backgroundColor = "#fff";
            portOldPoint1.custom.radius = 3;
            portOldPoint2.custom.radius = 3;

            //Get point object and change the radius/color
            var portPoint1 = portMeta1.data[pointIndex];
            var portPoint2 = portMeta2.data[pointIndex];
            portPoint1.custom = portPoint1.custom || {};
            portPoint2.custom = portPoint2.custom || {};
            portPoint1.custom.backgroundColor = "#828282";
            portPoint2.custom.backgroundColor = "#828282";
            portPoint1.custom.radius = 7;
            portPoint2.custom.radius = 7;

            portCharts[i].update();
        }
    }

    previousIndex = pointIndex;
}

function highlightNetworkLoad() {
    if (nodeMap.has(currentNode)) {
        cy.nodes().style({ 'background-color':'gray' });

        // colour nodes based on cpu load
        // if (cpuData[currentNode][pointIndex] > 70) {
        //     cy.nodes('#' + nodes[currentNode]).style({ 'background-color':'red' });
        // } else if (cpuData[currentNode][pointIndex] > 40) {
        //     cy.nodes('#' + nodes[currentNode]).style({ 'background-color':'orange' });
        // } else {
        //     cy.nodes('#' + nodes[currentNode]).style({ 'background-color':'green' });
        // }

        // colour nodes based on network load
        let networkLoad = nodeMap.get(currentNode).get('total')[pointIndex];
        if (networkLoad > 400000) {
            cy.nodes('#' + currentNode).style({ 'background-color':'red' });
        } else if (networkLoad > 200000) {
            cy.nodes('#' + currentNode).style({ 'background-color':'orange' });
        } else {
            cy.nodes('#' + currentNode).style({ 'background-color':'green' });
        }

        cy.edges().style({ 'line-color':'gray' });
        let portsMap = nodeMap.get(currentNode).get('ports');
        let portNum = 0;
        portsMap.forEach(function (value, key) {
            let bandwidth = value.get('total')[pointIndex];
            if (bandwidth > 400000) {
                cy.elements('edge[source = "' + nodeMap.get(currentNode).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'red' });
            } else if (bandwidth > 200000) {
                cy.elements('edge[source = "' + nodeMap.get(currentNode).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'orange' });
            } else {
                cy.elements('edge[source = "' + nodeMap.get(currentNode).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'green' });
            }
            portNum++;
        });
    }
}

function highlightOverallNetworkLoad() {
    if (!nodeMap.has(currentNode)) {
        let nodes = data_logs.getNodes();
        for (i = 0; i < nodes.length; i++) {
            // color nodes based on network data
            let node = nodes[i];
            let networkLoad = nodeMap.get(node).get('total')[pointIndex];
            console.log(networkLoad);
            let nodeColorIndex = 2;
            if (networkLoad > 700000) {
                nodeColorIndex = 0;
            } else if (networkLoad > 600000) {
                nodeColorIndex = 1;
            } else if (networkLoad > 400000) {
                nodeColorIndex = 2;
            } else if (networkLoad > 260000) {
                nodeColorIndex = 3;
            } else if (networkLoad > 200000) {
                nodeColorIndex = 4;
            }
            cy.nodes('#' + nodes[i]).style({'background-color': colorArray[nodeColorIndex]});

            let portsMap = nodeMap.get(node).get('ports');
            let portNum = 0;
            portsMap.forEach(function (value, key) {
                let bandwidth = value.get('total')[pointIndex];
                if (bandwidth > 400000) {
                    cy.elements('edge[source = "' + nodeMap.get(node).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'red' });
                } else if (bandwidth > 200000) {
                    cy.elements('edge[source = "' + nodeMap.get(node).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'orange' });
                } else {
                    cy.elements('edge[source = "' + nodeMap.get(node).get('name') + '"][sPort = ' + portNum + ']').style({ 'line-color':'green' });
                }
                portNum++;
            });
        }
    }
}

// reset nodes and edges colors for mouse click on cy container
function resetNodesAndEdgesColors() {
    cy.nodes().style({ 'background-color':'gray' });
    cy.edges().style({ 'line-color':'gray' });
}

function showHideCharts() {
    if (nodeMap.has(currentNode)) {
        for (i = 1; i <= portCharts.length; i++) {
            if (i <= nodeMap.get(currentNode).get('numOfPorts')) {
                if ($('#placeholder-row' + i).hasClass("no-visibility")) {
                    $('#placeholder-row' + i).removeClass("no-visibility");
                }
            } else {
                if (!$('#placeholder-row' + i).hasClass("no-visibility")) {
                    $('#placeholder-row' + i).addClass("no-visibility");
                }
            }
        }
    } else {
        for (i = 1; i <= portCharts.length; i++) {
            if (!$('#placeholder-row' + i).hasClass("no-visibility")) {
                $('#placeholder-row' + i).addClass("no-visibility");
            }
        }
    }
}

// button functions
$('#startButton').on('click', function () {
    pointIndex = $('#ex1').slider('getAttribute', 'min');
    $('#ex1').slider('setValue', pointIndex);
    update();
});
$('#endButton').on('click', function () {
    pointIndex = $('#ex1').slider('getAttribute', 'max');
    $('#ex1').slider('setValue', pointIndex);
    update();
});
var isPlaying = false;
$('#playPauseButton').on('click', function () {
    if (isPlaying) {
        isPlaying = false;
        $('#playPauseIcon').removeClass('glyphicon-pause').addClass('glyphicon-play');
    } else {
        isPlaying = true;
        $('#playPauseIcon').removeClass('glyphicon-play').addClass('glyphicon-pause');
        if (pointIndex == $('#ex1').slider('getAttribute', 'max')) {
            pointIndex = $('#ex1').slider('getAttribute', 'min');
            $('#ex1').slider('setValue', pointIndex);
            update();
            window.setTimeout(playbackTicker, 100);
        } else {
            playbackTicker();
        }
    }
});
function playbackTicker() {
    if (isPlaying && pointIndex < $('#ex1').slider('getAttribute', 'max')) {
        pointIndex++;
        $('#ex1').slider('setValue', pointIndex);
        update();
        window.setTimeout(playbackTicker, 100);
    } else if (isPlaying && pointIndex >= $('#ex1').slider('getAttribute', 'max')) {
        isPlaying = false;
        $('#playPauseIcon').removeClass('glyphicon-pause').addClass('glyphicon-play');
    }
}

// slider
$('#ex1').slider({
    formatter: function(value) {
        return 'Current time: ' + value;
    }
});
$("#ex1").on("slide", function(slideEvt) {
    pointIndex = slideEvt.value;
    update();
});
$("#ex1").on("slideStop", function(slideEvt) {
    pointIndex = slideEvt.value;
    update();
});

// topology
var cy = cytoscape({
    container: $('#cy'),
    elements: dataset,

    boxSelectionEnabled: false,
    autounselectify: true,

    layout: {
        name: 'cose-bilkent',
        randomize: true,
        nodeRepulsion: 400000
    },
    style: cyStyle
});
cy.on('mouseover', 'node', function(event) {
    var node = event.cyTarget;
    // node.qtip({
    //     content: this.data('label'),
    //     show: {
    //         event: event.type,
    //         ready: true
    //     },
    //     hide: {
    //         event: 'mouseout unfocus'
    //     }
    // }, event);
});
cy.on('click', function(event) {
    var node = event.cyTarget;
    if (node === cy) {
        updateCurrentNode('overall');
        resetNodesAndEdgesColors();
    } else {
        updateCurrentNode(node.id());
    }
});

// cpu chart
var cpuCanvas = document.getElementById("cpu-chart");
cpuCanvas.width = parseInt($('#well1').css('width'), 10);
cpuCanvas.height = parseInt($('#well1').css('height'), 10);
var cpuChart = new Chart(cpuCanvas, {
    type: 'line',
    data: cpuChartStyle,
    options: {}
});

// network chart
var networkCanvas = document.getElementById("network-chart");
networkCanvas.width = parseInt($('#well2').css('width'), 10);
networkCanvas.height = parseInt($('#well2').css('height'), 10);
var networkChart = new Chart(networkCanvas, {
    type: 'line',
    data: networkChartStyle,
    options: networkChartOptions
});

// port charts
var portCanvas1 = document.getElementById("port-chart1");
portCanvas1.width = parseInt($('#well3').css('width'), 10);
portCanvas1.height = parseInt($('#well3').css('height'), 10);
var portChart1 = new Chart(portCanvas1, {
    type: "line",
    data: portChartStyle1,
    options: {
        title: {
            display: true,
            text: 'Port [0]'
        },
        scales: portChartScales
    }
});

var portCanvas2 = document.getElementById("port-chart2");
portCanvas2.width = parseInt($('#well4').css('width'), 10);
portCanvas2.height = parseInt($('#well4').css('height'), 10);
var portChart2 = new Chart(portCanvas2, {
    type: "line",
    data: portChartStyle2,
    options: {
        title: {
            display: true,
            text: 'Port [1]'
        },
        scales: portChartScales
    }
});

portCharts = [
    portChart1,
    portChart2];
<|endoftext|>


<commit_before>var config = require('./config');
var fetch  = require('./fetcher');
var notify = require('./notifier');

function error(err) {
  console.error(err);
}

fetch(config.consulateUrls, function callback(err, data) {
  if (err) return error(err);
  console.log(JSON.stringify(data, null, 2));
  return notify('available-dates-summary', data, 7438652);
});<commit_msg>Add config object description and example<commit_after>/**
 * Config object, import as JSON
 * @type {Object}
 *
 * @example
 * {
 *   "consulateUrls": {
 *     "country": "https://example.com/countries.php",
 *     "consulate": "https://example.com/consulates.php",
 *     "agenda": "https://example.com/agenda.xhtml"
 *   },
 *   "telegram": {
 *     "baseUrl": "https://api.telegram.org/bot<bot-token>/"
 *   }
 * }
 */
var config = require('./config');
var fetch  = require('./fetcher');
var notify = require('./notifier');

function error(err) {
  console.error(err);
}

fetch(config.consulateUrls, function callback(err, data) {
  if (err) return error(err);
  console.log(JSON.stringify(data, null, 2));
  return notify('available-dates-summary', data, 7438652);
});<|endoftext|>


<commit_before>'use strict';

var util = require('./lib/util');

exports = module.exports = Parth;

function Parth(){
  if(!(this instanceof Parth)){
    return new Parth();
  }

  this.store = {children: {}};
  this.regex = [];
  this.regex.master = /(?:[])/;
}

// ## parth.add(path)
// > path to regex classification
// > TODO: give support for regexp input
//
// arguments
//  - path, type `string`
//  - options, type `object` optional with all extra information
//
// returns
//  - null for non-supported types
//  - regular expression from the path
//
var noParamRE = /(^|[/. ]+)(\([^?].+?\)+)/g;
var paramRE = /(^|[ /.]):([A-Za-z0-9_]+)(\([^)]+?\)+)?/g;

Parth.prototype.add = function(path, opt){
  var o = util.boil(path, opt); if(!o){ return null; }

  // find groups without parameters and label them
  var index = -1;
  o.path = o.path.replace(noParamRE, function($0, $1, $2){
    return $1 + ':' + (++index) + $2;
  });

  var sep, parsed = '^' + o.path.replace(/\S+/g, function(stem){
      sep = (stem.match(/\//) || stem.match(/\./) || ' ')[0].trim();
      return stem.replace(paramRE, function($0, $1, $2, $3){
        return $1 + ($3 || '([^'+sep+' ]+)');
      });
      // now escape separation tokens outside parens
    }).replace(/(.*?)(?:\(.+?\)+|$)/g, function($0, $1){
      return $0.replace($1, util.escapeRegExp);
    });

  parsed = new RegExp(parsed);
  parsed.path = o.path;
  parsed.depth = util.boil.argv(o.path).length;

  // avoid mutation of main object
  if(this.store.children[o.path]){
    return parsed;
  }

  this.regex.push(parsed);

  // ## order regexes according to
  // - depth (number of separation tokens, [ /.])
  // - if that fails, use localCompare

  this.regex.sort(function(x, y){
    return (y.depth - x.depth) || y.path.localeCompare(x.path);
  });

  // ## sum up all learned
  // - void groups all groups first
  // - make a giant regex

  this.regex.master = new RegExp(
    '(' + this.regex.map(util.voidRE).join(')|(') + ')'
  );

  this.store.children[o.path] = o;
  return parsed;
};

// ## parth.match(path[, options])
// > take a string or array, return the matching path
//
// arguments
//  - path, type `string`
//  - options, type `object` optional holding all extra information
//
// return
//  - null for non-supported types or not matching path
//  - regex with for the matching path
//
Parth.prototype.match = function(path, opt){
  var o = opt || { }; o.notFound = true;
  o = util.boil(path, o); if(!o){ return null; }

  var found = this.regex.master.exec(o.path);
  if(!found){ return null; }

  o.match = found[0].trim();
  var regex = this.regex[found.indexOf(found.shift())];
  if(!opt){ return regex; }

  var index = -1;
  o.params = {_: o.path.match(regex).slice(1)};
  regex.path.replace(paramRE, function($0, $1, $2){
    o.params[$2] = o.params._[++index];
    o.params._[index] = $2;
  });

  o.notFound = o.path.replace(o.match, '') || false;
  return regex;
};
<commit_msg>support change in flag begin and end of regex<commit_after>'use strict';

var util = require('./lib/util');

exports = module.exports = Parth;

function Parth(){
  if(!(this instanceof Parth)){
    return new Parth();
  }

  this.store = {children: {}};
  this.regex = [];
  this.regex.master = /(?:[])/;
}

// ## parth.add(path)
// > path to regex classification
// > TODO: give support for regexp input
//
// arguments
//  - path, type `string`
//  - options, type `object` optional with all extra information
//
// returns
//  - null for non-supported types
//  - regular expression from the path
//
var noParamRE = /(^|[/. ]+)(\([^?].+?\)+)/g;
var paramRE = /(^|[ /.]):([A-Za-z0-9_]+)(\([^)]+?\)+)?/g;

Parth.prototype.add = function(path, opt){
  var o = util.boil(path, opt); if(!o){ return null; }

  // avoid mutation of main object
  if(this.store.children[o.path]){
    return this.store.children[o.path];
  }

  var sep, index = -1;

  // find groups without parameters and label them
  o.path = o.path.replace(noParamRE, function($0, $1, $2){
    return $1 + ':' + (++index) + $2;
  });

  o.end = util.type(o.end).string || '';
  o.flag = util.type(o.flag).string || '';
  o.begin = util.type(o.begin).string || '^';

  var parsed = new RegExp(o.begin + o.path.replace(/\S+/g, function(stem){
      sep = (stem.match(/\//) || stem.match(/\./) || ' ')[0].trim();
      return stem.replace(paramRE, function($0, $1, $2, $3){
        return $1 + ($3 || '([^'+sep+' ]+)');
      });
      // now escape separation tokens outside parens
    }).replace(/(.*?)(?:\(.+?\)+|$)/g, function($0, $1){
      return $0.replace($1, util.escapeRegExp);
    }) + o.end, o.flag);

  parsed.path = o.path;
  parsed.depth = util.boil.argv(o.path).length;

  this.regex.push(parsed);

  // ## order regexes according to
  // - depth (number of separation tokens, [ /.])
  // - if that fails, use localCompare

  this.regex.sort(function(x, y){
    return (y.depth - x.depth) || y.path.localeCompare(x.path);
  });

  // ## sum up all learned
  // - void all groups
  // - make a giant regex

  this.regex.master = new RegExp(
    '(' + this.regex.map(util.voidRE).join(')|(') + ')'
  );

  this.store.children[o.path] = o;
  return parsed;
};

// ## parth.match(path[, options])
// > take a string or array, return the matching path
//
// arguments
//  - path, type `string`
//  - options, type `object` optional holding all extra information
//
// return
//  - null for non-supported types or not matching path
//  - regex with for the matching path
//
Parth.prototype.match = function(path, opt){
  var o = opt || { }; o.notFound = true;
  o = util.boil(path, o); if(!o){ return null; }

  var found = this.regex.master.exec(o.path);
  if(!found){ return null; }

  o.match = found[0].trim();
  var regex = this.regex[found.indexOf(found.shift())];
  if(!opt){ return regex; }

  var index = -1;
  o.params = {_: o.path.match(regex).slice(1)};
  regex.path.replace(paramRE, function($0, $1, $2){
    o.params[$2] = o.params._[++index];
    o.params._[index] = $2;
  });

  o.notFound = o.path.replace(o.match, '') || false;
  return regex;
};
<|endoftext|>


<commit_before>global.async = require('asyncawait/async');
global.await = require('asyncawait/await');

const express = require('express');

module.exports = (args) => {
    var app = args ? args.app : null;
    var config = {};

    var defaultVal = (val, defaultVal) => {
        if (val == undefined) {
            return defaultVal;
        }

        return val;
    }

    config.debug = defaultVal(args.debug, true);

    config.cfg = {};
    config.cfg = {};

    config.cfg.controller = args.apppath + '/controller';
    config.cfg.view = args.apppath + '/view';
    config.cfg.minifyRemoveLineBreakWhitespace = defaultVal(args.minifyRemoveLineBreakWhitespace, true);

    config.delegate = {};
    config.delegate.error = args.error || undefined;

    if (!app) {
        app = express();
    }

    config.app = app;
    config.view = require('./lib/view')(config);

    if (args.logging) {
        app.use(require('morgan')('short', {}));
    }

    if (args.static) {
        var paths = args.static;

        if (typeof(paths) != 'object') {
            paths = [paths]
        }

        paths.forEach((e) => {
            app.use(express.static(args.apppath + '/' + e))
        })
    }

    const listen = (port) => {
        console.log('Listening .. ' + port);
        app.listen(port);
    }

    if (args.port) {
        listen(args.port);
    }

    return {
        app: app,
        listen: listen,
        router: require('./lib/router')(config)
    }
}
<commit_msg>add options description.<commit_after>global.async = require('asyncawait/async');
global.await = require('asyncawait/await');

const express = require('express');

/*
|*
|* @param {Object} [options] {
|         app: Object, Express App.
|         apppath: String, Application Absolute Path [Required]
|         port: Int, Binding port, If specified, will bind automatically.
|         debug: Boolean, Debug Mode, Default is false.
|         minifyRemoveLineBreakWhitespace: Boolean, Whether if remove line break whitespace or not, Default is true.
|         error: Function, Error Handler.
|         logging: Boolean, Logging enabled, Default is false.
|         static: [String], Static file paths.
|       }
|*
*/
module.exports = (options) => {
    var app = options ? options.app : null;
    var config = {};

    var defaultVal = (val, defaultVal) => {
        if (val == undefined) {
            return defaultVal;
        }

        return val;
    }

    config.debug = defaultVal(options.debug, false);

    config.cfg = {};
    config.cfg = {};

    config.cfg.controller = options.apppath + '/controller';
    config.cfg.view = options.apppath + '/view';
    config.cfg.minifyRemoveLineBreakWhitespace = defaultVal(options.minifyRemoveLineBreakWhitespace, true);

    config.delegate = {};
    config.delegate.error = options.error || undefined;

    if (!app) {
        app = express();
    }

    config.app = app;
    config.view = require('./lib/view')(config);

    if (options.logging) {
        app.use(require('morgan')('short', {}));
    }

    if (options.static) {
        var paths = options.static;

        if (typeof(paths) != 'object') {
            paths = [paths]
        }

        paths.forEach((e) => {
            app.use(express.static(options.apppath + '/' + e))
        })
    }

    const listen = (port) => {
        console.log('Listening .. ' + port);
        app.listen(port);
    }

    if (options.port) {
        listen(options.port);
    }

    return {
        app: app,
        listen: listen,
        router: require('./lib/router')(config)
    }
}
<|endoftext|>


<commit_before>var builtins = require('builtins')
var through = require('through')
var resolve = require('resolve')
var flatten = require('flatten')
var duplex = require('duplexer')
var pluck = require('plucker')
var uniq = require('uniq')

var commondir = require('commondir')
var fileTree = require('file-tree')
var path = require('path')
var fs = require('fs')
var bl = require('bl')

var versions = require('./lib/versions')

module.exports = createStream
createStream.json = json
createStream.bundle = bundle

function createStream(opts) {
  opts = opts || {}

  var buffer = bl(function(err, content) {
    if (err) return stream.emit('error', err)

    bundle(content, opts, function(err, html) {
      if (err) return stream.emit('error', err)

      output.queue(html)
      output.queue(null)
    })
  })

  var output = through()
  var stream = duplex(buffer, output)

  return stream
}

function json(bundles, callback) {
  var modules = flatten(bundles
    .map(String)
    .map(JSON.parse)
    .map(function(json) {
      return json.modules
    })
  )

  modules = modules.filter(function(module) {
    return !isEmpty(module)
  })

  // var browserifyModules = modules.filter(fromBrowserify(true))
  // var otherModules = modules.filter(function(module) {
  //   if (path.basename(module.id) === '_empty.js') return false
  //   if (browserifyModules.indexOf(module) === -1) return true
  // })

  // var root = commondir(otherModules.map(pluck('id')))

  // browserifyModules.forEach(function(module) {
  //   var regex = /^.+\/node_modules\/browserify\/(?:node_modules\/)(.+)$/g

  //   module.id = module.id.replace(regex, function(_, subpath) {
  //     return path.resolve(root, 'browserify-core/' + subpath)
  //   })

  //   return module
  // })

  // uniq(modules, function(a, b) {
  //   return a.id === b.id ? 0 : 1
  // }, true)

  var root = commondir(modules.map(pluck('identifier')))
  var main = path.basename(root)

  var byid = modules.reduce(function(memo, mod) {
    memo[mod.identifier] = mod
    return memo
  }, {})

  fileTree(Object.keys(byid), function(id, next) {
    var row = byid[id]
    if (!row) console.log(id)

    next(null, {
        size: row.size
      , deps: Object.keys(row.reasons).length
      , path: row.name
    })
  }, function(err, tree) {
    if (err) return callback(err)

    tree = { name: main, children: tree }
    dirsizes(tree)
    versions(tree)
    callback(null, tree)
  })
}

function bundle(bundles, opts, callback) {
  bundles = Array.isArray(bundles)
    ? bundles
    : bundles ? [bundles] : []

  if (typeof opts === 'function') {
    callback = opts
    opts = {}
  }

  opts = opts || {}
  callback = callback || noop

  var header = opts.header || opts.button || ''
  var footer = opts.footer || ''

  return json(bundles, function(err, data) {
    if (err) return callback(err)

    data.mode = opts.mode || 'size'
    data = '<script type="text/javascript">'
      + ';window.disc = ('
      + JSON.stringify(data)
      + ');</script>'

    var script = '<script type="text/javascript">'
      + bundled().replace(/\/script/gi, '\\/script')
      + '</script>'

    callback(null, template()({
        scripts: script
      , styles: styles()
      , markdown: footer
      , header: header
      , data: data
    }))
  })
}

function toarray(arg) {
  if (typeof arg === 'undefined' || arg === null) return []
  return Array.isArray(arg) ? arg : [arg]
}

function template() {
  if (template.text) return template.text
  return template.text = require('./lib/lazy-template')(
    fs.readFileSync(__dirname + '/src/base.html', 'utf8')
  )
}

function styles() {
  if (styles.text) return styles.text
  return styles.text = fs.readFileSync(__dirname + '/build/style.css', 'utf8')
}

function bundled() {
  if (bundled.text) return bundled.text
  return bundled.text = fs.readFileSync(__dirname + '/build/bundle.js', 'utf8')
}

function dirsizes(child) {
  return child.size = "size" in child ? child.size : child.children.reduce(function(size, child) {
    return size + ("size" in child ? child.size : dirsizes(child))
  }, 0)
}

function submodule(parent, child) {
  parent = require.resolve(parent)
  return resolve.sync(child, {
    basedir: path.dirname(parent)
  })
}

function sortById(a, b) {
  var aid = a.id
  var bid = b.id

  return aid > bid
    ? -1 : aid < bid
    ? +1 : 0
}

function noop(){}

function fromBrowserify(yes) {
  var existsCache = {}
  var no = !yes

  return function(module) {
    var search = '/node_modules/browserify'
    var idx  = module.id.indexOf(search)
    var from = idx !== -1

    if (!from) return no

    // special case for process.js
    // from insert-module-globals
    if (
      module.id.indexOf('insert-module-globals') !== -1 &&
      module.id.split(path.sep).slice(-2).join('/') === 'process/browser.js'
    ) return yes

    // Look up browserify's builtins file to
    // determine if this file is part of browserify
    // core.
    var builtinFile = (
      module.id.slice(0, idx + search.length) +
      '/lib/builtins.js'
    )

    if (!(builtinFile in existsCache)) {
      existsCache[builtinFile] = values(
        fs.existsSync(builtinFile) &&
        require(builtinFile) || {}
      )
    }

    var localBuiltins = existsCache[builtinFile]
    var bidx = localBuiltins.indexOf(module.id)

    if (bidx !== -1) return yes

    // Guess remaining helper files based on module
    // name: this should probably be improved in the
    // future.
    var split = module.id.split(path.sep)
    var j = split.length - 1

    while (split[--j] !== 'node_modules');;

    var dir = split.slice(j + 1)[0].replace(/\-(?:browser(?:ify)?|es3)$/g, '')
    if (dir === 'Base64') return yes
    if (dir === 'base64-js') return yes
    if (dir === 'inherits') return yes
    if (dir === 'process') return yes
    if (dir === 'ieee754') return yes
    if (builtins.indexOf(dir) !== -1) return yes

    return no
  }
}

function values(object) {
  return Object.keys(object).map(function(key) {
    return object[key]
  })
}

function isEmpty(module) {
  return (
    path.basename(module.id) === '_empty.js' &&
  (!fs.existsSync(module.id) || !fs.statSync(module.id).size)
  )
}
<commit_msg>Filter out 'cjs require context' modules<commit_after>var builtins = require('builtins')
var through = require('through')
var resolve = require('resolve')
var flatten = require('flatten')
var duplex = require('duplexer')
var pluck = require('plucker')
var uniq = require('uniq')

var commondir = require('commondir')
var fileTree = require('file-tree')
var path = require('path')
var fs = require('fs')
var bl = require('bl')

var versions = require('./lib/versions')

module.exports = createStream
createStream.json = json
createStream.bundle = bundle

function createStream(opts) {
  opts = opts || {}

  var buffer = bl(function(err, content) {
    if (err) return stream.emit('error', err)

    bundle(content, opts, function(err, html) {
      if (err) return stream.emit('error', err)

      output.queue(html)
      output.queue(null)
    })
  })

  var output = through()
  var stream = duplex(buffer, output)

  return stream
}

function json(bundles, callback) {
  var modules = flatten(bundles
    .map(String)
    .map(JSON.parse)
    .map(function(json) {
      return json.modules
    })
  )

  modules = modules.filter(function(module) {
    return !isEmpty(module)
  })

  // var browserifyModules = modules.filter(fromBrowserify(true))
  // var otherModules = modules.filter(function(module) {
  //   if (path.basename(module.id) === '_empty.js') return false
  //   if (browserifyModules.indexOf(module) === -1) return true
  // })

  // var root = commondir(otherModules.map(pluck('id')))

  // browserifyModules.forEach(function(module) {
  //   var regex = /^.+\/node_modules\/browserify\/(?:node_modules\/)(.+)$/g

  //   module.id = module.id.replace(regex, function(_, subpath) {
  //     return path.resolve(root, 'browserify-core/' + subpath)
  //   })

  //   return module
  // })

  // uniq(modules, function(a, b) {
  //   return a.id === b.id ? 0 : 1
  // }, true)

  modules = modules.filter(function(mod) {
    return !mod.reasons.some(function(reason) {
      return reason.type === 'cjs require context';
    });
  });

  var root = commondir(modules.map(pluck('identifier')))
  var main = path.basename(root)

  var byid = modules.reduce(function(memo, mod) {
    memo[mod.identifier] = mod
    return memo
  }, {})

  fileTree(Object.keys(byid), function(id, next) {
    var row = byid[id]
    if (!row) console.log(id)

    next(null, {
        size: row.size
      , deps: Object.keys(row.reasons).length
      , path: row.name
    })
  }, function(err, tree) {
    if (err) return callback(err)

    tree = { name: main, children: tree }
    dirsizes(tree)
    versions(tree)
    callback(null, tree)
  })
}

function bundle(bundles, opts, callback) {
  bundles = Array.isArray(bundles)
    ? bundles
    : bundles ? [bundles] : []

  if (typeof opts === 'function') {
    callback = opts
    opts = {}
  }

  opts = opts || {}
  callback = callback || noop

  var header = opts.header || opts.button || ''
  var footer = opts.footer || ''

  return json(bundles, function(err, data) {
    if (err) return callback(err)

    data.mode = opts.mode || 'size'
    data = '<script type="text/javascript">'
      + ';window.disc = ('
      + JSON.stringify(data)
      + ');</script>'

    var script = '<script type="text/javascript">'
      + bundled().replace(/\/script/gi, '\\/script')
      + '</script>'

    callback(null, template()({
        scripts: script
      , styles: styles()
      , markdown: footer
      , header: header
      , data: data
    }))
  })
}

function toarray(arg) {
  if (typeof arg === 'undefined' || arg === null) return []
  return Array.isArray(arg) ? arg : [arg]
}

function template() {
  if (template.text) return template.text
  return template.text = require('./lib/lazy-template')(
    fs.readFileSync(__dirname + '/src/base.html', 'utf8')
  )
}

function styles() {
  if (styles.text) return styles.text
  return styles.text = fs.readFileSync(__dirname + '/build/style.css', 'utf8')
}

function bundled() {
  if (bundled.text) return bundled.text
  return bundled.text = fs.readFileSync(__dirname + '/build/bundle.js', 'utf8')
}

function dirsizes(child) {
  return child.size = "size" in child ? child.size : child.children.reduce(function(size, child) {
    return size + ("size" in child ? child.size : dirsizes(child))
  }, 0)
}

function submodule(parent, child) {
  parent = require.resolve(parent)
  return resolve.sync(child, {
    basedir: path.dirname(parent)
  })
}

function sortById(a, b) {
  var aid = a.id
  var bid = b.id

  return aid > bid
    ? -1 : aid < bid
    ? +1 : 0
}

function noop(){}

function fromBrowserify(yes) {
  var existsCache = {}
  var no = !yes

  return function(module) {
    var search = '/node_modules/browserify'
    var idx  = module.id.indexOf(search)
    var from = idx !== -1

    if (!from) return no

    // special case for process.js
    // from insert-module-globals
    if (
      module.id.indexOf('insert-module-globals') !== -1 &&
      module.id.split(path.sep).slice(-2).join('/') === 'process/browser.js'
    ) return yes

    // Look up browserify's builtins file to
    // determine if this file is part of browserify
    // core.
    var builtinFile = (
      module.id.slice(0, idx + search.length) +
      '/lib/builtins.js'
    )

    if (!(builtinFile in existsCache)) {
      existsCache[builtinFile] = values(
        fs.existsSync(builtinFile) &&
        require(builtinFile) || {}
      )
    }

    var localBuiltins = existsCache[builtinFile]
    var bidx = localBuiltins.indexOf(module.id)

    if (bidx !== -1) return yes

    // Guess remaining helper files based on module
    // name: this should probably be improved in the
    // future.
    var split = module.id.split(path.sep)
    var j = split.length - 1

    while (split[--j] !== 'node_modules');;

    var dir = split.slice(j + 1)[0].replace(/\-(?:browser(?:ify)?|es3)$/g, '')
    if (dir === 'Base64') return yes
    if (dir === 'base64-js') return yes
    if (dir === 'inherits') return yes
    if (dir === 'process') return yes
    if (dir === 'ieee754') return yes
    if (builtins.indexOf(dir) !== -1) return yes

    return no
  }
}

function values(object) {
  return Object.keys(object).map(function(key) {
    return object[key]
  })
}

function isEmpty(module) {
  return (
    path.basename(module.id) === '_empty.js' &&
  (!fs.existsSync(module.id) || !fs.statSync(module.id).size)
  )
}
<|endoftext|>


<commit_before>module.exports = createTorrent
module.exports.parseInput = parseInput

module.exports.announceList = [
  [ 'udp://tracker.openbittorrent.com:80' ],
  [ 'udp://tracker.internetwarriors.net:1337' ],
  [ 'udp://tracker.leechers-paradise.org:6969' ],
  [ 'udp://tracker.coppersurfer.tk:6969' ],
  [ 'udp://exodus.desync.com:6969' ],
  [ 'wss://tracker.webtorrent.io' ] // For WebRTC peers (see: WebTorrent.io)
]

var bencode = require('bencode')
var BlockStream = require('block-stream2')
var calcPieceLength = require('piece-length')
var corePath = require('path')
var dezalgo = require('dezalgo')
var FileReadStream = require('filestream/read')
var flatten = require('flatten')
var fs = require('fs')
var isFile = require('is-file')
var junk = require('junk')
var MultiStream = require('multistream')
var once = require('once')
var parallel = require('run-parallel')
var sha1 = require('simple-sha1')
var stream = require('stream')

/**
 * Create a torrent.
 * @param  {string|File|FileList|Buffer|Stream|Array.<string|File|Buffer|Stream>} input
 * @param  {Object} opts
 * @param  {string=} opts.name
 * @param  {Date=} opts.creationDate
 * @param  {string=} opts.comment
 * @param  {string=} opts.createdBy
 * @param  {boolean|number=} opts.private
 * @param  {number=} opts.pieceLength
 * @param  {Array.<Array.<string>>=} opts.announceList
 * @param  {Array.<string>=} opts.urlList
 * @param  {function} cb
 * @return {Buffer} buffer of .torrent file data
 */
function createTorrent (input, opts, cb) {
  if (typeof opts === 'function') {
    cb = opts
    opts = {}
  }
  if (!opts) opts = {}
  parseInput(input, opts, function (err, files, singleFileTorrent) {
    if (err) return cb(err)
    opts.singleFileTorrent = singleFileTorrent
    onFiles(files, opts, cb)
  })
}

function parseInput (input, opts, cb) {
  if (typeof opts === 'function') {
    cb = opts
    opts = {}
  }
  if (!opts) opts = {}
  cb = dezalgo(cb)

  if (Array.isArray(input) && input.length === 0) throw new Error('invalid input type')

  if (isFileList(input)) input = Array.prototype.slice.call(input)
  if (!Array.isArray(input)) input = [ input ]

  // If there's just one file, allow the name to be set by `opts.name`
  if (input.length === 1 && typeof input[0] !== 'string' && !input[0].name) input[0].name = opts.name

  var commonPrefix = null
  input.forEach(function (item, i) {
    if (typeof item === 'string') return

    var path = item.fullPath || item.name
    if (!path) throw new Error('missing required `fullPath` or `name` property on input')

    item.path = path.split('/')

    if (!item.path[0]) item.path.shift() // Remove initial slash

    if (item.path.length < 2) { // No real prefix
      commonPrefix = null
    } else if (i === 0) { // The first file has a prefix
      commonPrefix = item.path[0]
    } else if (item.path[0] !== commonPrefix) { // The prefix doesn't match
      commonPrefix = null
    }
  })

  // remove junk files
  input = input.filter(function (item) {
    if (typeof item === 'string') return true
    var filename = item.path[item.path.length - 1]
    return notHidden(filename) && junk.not(filename)
  })

  if (commonPrefix) {
    input.forEach(function (item) {
      if (typeof item === 'string') return
      item.path.shift()
    })
  }

  if (!opts.name && commonPrefix) opts.name = commonPrefix
  if (!opts.name && input[0] && input[0].name) opts.name = input[0].name
  if (!opts.name && typeof input[0] === 'string') opts.name = corePath.basename(input[0])

  if (opts.name === undefined) {
    throw new Error('missing option \'name\' and unable to infer it from input[0].name')
  }

  var numPaths = input.reduce(function (sum, item) {
    return sum + Number(typeof item === 'string')
  }, 0)

  var isSingleFileTorrent = (input.length === 1)

  if (input.length === 1 && typeof input[0] === 'string') {
    if (typeof fs.stat !== 'function') {
      throw new Error('filesystem paths do not work in the browser')
    }
    // If there's a single path, verify it's a file before deciding this is a single
    // file torrent
    isFile(input[0], function (err, pathIsFile) {
      if (err) return cb(err)
      isSingleFileTorrent = pathIsFile
      processInput()
    })
  } else {
    processInput()
  }

  function processInput () {
    parallel(input.map(function (item) {
      return function (cb) {
        var file = {}

        if (isBlob(item)) {
          file.getStream = getBlobStream(item)
          file.length = item.size
        } else if (Buffer.isBuffer(item)) {
          file.getStream = getBufferStream(item)
          file.length = item.length
        } else if (isReadable(item)) {
          if (!opts.pieceLength) {
            throw new Error('must specify `pieceLength` option if input is Stream')
          }
          file.getStream = getStreamStream(item, file)
          file.length = 0
        } else if (typeof item === 'string') {
          if (typeof fs.stat !== 'function') {
            throw new Error('filesystem paths do not work in the browser')
          }
          var keepRoot = numPaths > 1 || isSingleFileTorrent
          getFiles(item, keepRoot, cb)
          return // early return!
        } else {
          throw new Error('invalid input type')
        }
        file.path = item.path
        cb(null, file)
      }
    }), function (err, files) {
      if (err) return cb(err)
      files = flatten(files)
      cb(null, files, isSingleFileTorrent)
    })
  }
}

function getFiles (path, keepRoot, cb) {
  traversePath(path, getFileInfo, function (err, files) {
    if (err) return cb(err)

    if (Array.isArray(files)) files = flatten(files)
    else files = [ files ]

    path = corePath.normalize(path)
    if (keepRoot) {
      path = path.slice(0, path.lastIndexOf(corePath.sep) + 1)
    }
    if (path[path.length - 1] !== corePath.sep) path += corePath.sep

    files.forEach(function (file) {
      file.getStream = getFilePathStream(file.path)
      file.path = file.path.replace(path, '').split(corePath.sep)
    })
    cb(null, files)
  })
}

function getFileInfo (path, cb) {
  cb = once(cb)
  fs.stat(path, function (err, stat) {
    if (err) return cb(err)
    var info = {
      length: stat.size,
      path: path
    }
    cb(null, info)
  })
}

function traversePath (path, fn, cb) {
  fs.readdir(path, function (err, entries) {
    if (err && err.code === 'ENOTDIR') {
      // this is a file
      fn(path, cb)
    } else if (err) {
      // real error
      cb(err)
    } else {
      // this is a folder
      parallel(entries.filter(notHidden).filter(junk.not).map(function (entry) {
        return function (cb) {
          traversePath(corePath.join(path, entry), fn, cb)
        }
      }), cb)
    }
  })
}

function notHidden (file) {
  return file[0] !== '.'
}

function getPieceList (files, pieceLength, cb) {
  cb = once(cb)
  var pieces = []
  var length = 0

  var streams = files.map(function (file) {
    return file.getStream
  })

  var remainingHashes = 0
  var pieceNum = 0
  var ended = false

  var multistream = new MultiStream(streams)
  var blockstream = new BlockStream(pieceLength, { zeroPadding: false })

  multistream.on('error', onError)

  multistream
    .pipe(blockstream)
    .on('data', onData)
    .on('end', onEnd)
    .on('error', onError)

  function onData (chunk) {
    length += chunk.length

    var i = pieceNum
    sha1(chunk, function (hash) {
      pieces[i] = hash
      remainingHashes -= 1
      maybeDone()
    })
    remainingHashes += 1
    pieceNum += 1
  }

  function onEnd () {
    ended = true
    maybeDone()
  }

  function onError (err) {
    cleanup()
    cb(err)
  }

  function cleanup () {
    multistream.removeListener('error', onError)
    blockstream.removeListener('data', onData)
    blockstream.removeListener('end', onEnd)
    blockstream.removeListener('error', onError)
  }

  function maybeDone () {
    if (ended && remainingHashes === 0) {
      cleanup()
      cb(null, new Buffer(pieces.join(''), 'hex'), length)
    }
  }
}

function onFiles (files, opts, cb) {
  var announceList = opts.announceList

  if (!announceList) {
    if (typeof opts.announce === 'string') announceList = [ [ opts.announce ] ]
    else if (Array.isArray(opts.announce)) {
      announceList = opts.announce.map(function (u) { return [ u ] })
    }
  }

  if (!announceList) announceList = []

  if (global.WEBTORRENT_ANNOUNCE) {
    if (typeof global.WEBTORRENT_ANNOUNCE === 'string') {
      announceList.push([ [ global.WEBTORRENT_ANNOUNCE ] ])
    } else if (Array.isArray(global.WEBTORRENT_ANNOUNCE)) {
      announceList = announceList.concat(global.WEBTORRENT_ANNOUNCE.map(function (u) {
        return [ u ]
      }))
    }
  }

  // When no trackers specified, use some reasonable defaults
  if (opts.announce === undefined && opts.announceList === undefined) {
    announceList = announceList.concat(module.exports.announceList)
  }

  if (typeof opts.urlList === 'string') opts.urlList = [ opts.urlList ]

  var torrent = {
    info: {
      name: opts.name
    },
    'creation date': Number(opts.creationDate) || Date.now(),
    encoding: 'UTF-8'
  }

  if (announceList.length !== 0) {
    torrent.announce = announceList[0][0]
    torrent['announce-list'] = announceList
  }

  if (opts.comment !== undefined) torrent.comment = opts.comment

  if (opts.createdBy !== undefined) torrent['created by'] = opts.createdBy

  if (opts.private !== undefined) torrent.info.private = Number(opts.private)

  // "ssl-cert" key is for SSL torrents, see:
  //   - http://blog.libtorrent.org/2012/01/bittorrent-over-ssl/
  //   - http://www.libtorrent.org/manual-ref.html#ssl-torrents
  //   - http://www.libtorrent.org/reference-Create_Torrents.html
  if (opts.sslCert !== undefined) torrent.info['ssl-cert'] = opts.sslCert

  if (opts.urlList !== undefined) torrent['url-list'] = opts.urlList

  var pieceLength = opts.pieceLength || calcPieceLength(files.reduce(sumLength, 0))
  torrent.info['piece length'] = pieceLength

  getPieceList(files, pieceLength, function (err, pieces, torrentLength) {
    if (err) return cb(err)
    torrent.info.pieces = pieces

    files.forEach(function (file) {
      delete file.getStream
    })

    if (opts.singleFileTorrent) {
      torrent.info.length = torrentLength
    } else {
      torrent.info.files = files
    }

    cb(null, bencode.encode(torrent))
  })
}

/**
 * Accumulator to sum file lengths
 * @param  {number} sum
 * @param  {Object} file
 * @return {number}
 */
function sumLength (sum, file) {
  return sum + file.length
}

/**
 * Check if `obj` is a W3C `Blob` object (which `File` inherits from)
 * @param  {*} obj
 * @return {boolean}
 */
function isBlob (obj) {
  return typeof Blob !== 'undefined' && obj instanceof Blob
}

/**
 * Check if `obj` is a W3C `FileList` object
 * @param  {*} obj
 * @return {boolean}
 */
function isFileList (obj) {
  return typeof FileList === 'function' && obj instanceof FileList
}

/**
 * Check if `obj` is a node Readable stream
 * @param  {*} obj
 * @return {boolean}
 */
function isReadable (obj) {
  return typeof obj === 'object' && typeof obj.pipe === 'function'
}

/**
 * Convert a `File` to a lazy readable stream.
 * @param  {File|Blob} file
 * @return {function}
 */
function getBlobStream (file) {
  return function () {
    return new FileReadStream(file)
  }
}

/**
 * Convert a `Buffer` to a lazy readable stream.
 * @param  {Buffer} buffer
 * @return {function}
 */
function getBufferStream (buffer) {
  return function () {
    var s = new stream.PassThrough()
    s.end(buffer)
    return s
  }
}

/**
 * Convert a file path to a lazy readable stream.
 * @param  {string} path
 * @return {function}
 */
function getFilePathStream (path) {
  return function () {
    return fs.createReadStream(path)
  }
}

/**
 * Convert a readable stream to a lazy readable stream. Adds instrumentation to track
 * the number of bytes in the stream and set `file.length`.
 *
 * @param  {Stream} stream
 * @param  {Object} file
 * @return {function}
 */
function getStreamStream (readable, file) {
  return function () {
    var counter = new stream.Transform()
    counter._transform = function (buf, enc, done) {
      file.length += buf.length
      this.push(buf)
      done()
    }
    readable.pipe(counter)
    return counter
  }
}
<commit_msg>Added βTorrent tracker<commit_after>module.exports = createTorrent
module.exports.parseInput = parseInput

module.exports.announceList = [
  [ 'udp://tracker.openbittorrent.com:80' ],
  [ 'udp://tracker.internetwarriors.net:1337' ],
  [ 'udp://tracker.leechers-paradise.org:6969' ],
  [ 'udp://tracker.coppersurfer.tk:6969' ],
  [ 'udp://exodus.desync.com:6969' ],
  [ 'wss://tracker.webtorrent.io' ], // For WebRTC peers (see: WebTorrent.io)
  [ 'wss://tracker.btorrent.xyz' ] // For WebRTC peers (see: btorrent.xyz)
]

var bencode = require('bencode')
var BlockStream = require('block-stream2')
var calcPieceLength = require('piece-length')
var corePath = require('path')
var dezalgo = require('dezalgo')
var FileReadStream = require('filestream/read')
var flatten = require('flatten')
var fs = require('fs')
var isFile = require('is-file')
var junk = require('junk')
var MultiStream = require('multistream')
var once = require('once')
var parallel = require('run-parallel')
var sha1 = require('simple-sha1')
var stream = require('stream')

/**
 * Create a torrent.
 * @param  {string|File|FileList|Buffer|Stream|Array.<string|File|Buffer|Stream>} input
 * @param  {Object} opts
 * @param  {string=} opts.name
 * @param  {Date=} opts.creationDate
 * @param  {string=} opts.comment
 * @param  {string=} opts.createdBy
 * @param  {boolean|number=} opts.private
 * @param  {number=} opts.pieceLength
 * @param  {Array.<Array.<string>>=} opts.announceList
 * @param  {Array.<string>=} opts.urlList
 * @param  {function} cb
 * @return {Buffer} buffer of .torrent file data
 */
function createTorrent (input, opts, cb) {
  if (typeof opts === 'function') {
    cb = opts
    opts = {}
  }
  if (!opts) opts = {}
  parseInput(input, opts, function (err, files, singleFileTorrent) {
    if (err) return cb(err)
    opts.singleFileTorrent = singleFileTorrent
    onFiles(files, opts, cb)
  })
}

function parseInput (input, opts, cb) {
  if (typeof opts === 'function') {
    cb = opts
    opts = {}
  }
  if (!opts) opts = {}
  cb = dezalgo(cb)

  if (Array.isArray(input) && input.length === 0) throw new Error('invalid input type')

  if (isFileList(input)) input = Array.prototype.slice.call(input)
  if (!Array.isArray(input)) input = [ input ]

  // If there's just one file, allow the name to be set by `opts.name`
  if (input.length === 1 && typeof input[0] !== 'string' && !input[0].name) input[0].name = opts.name

  var commonPrefix = null
  input.forEach(function (item, i) {
    if (typeof item === 'string') return

    var path = item.fullPath || item.name
    if (!path) throw new Error('missing required `fullPath` or `name` property on input')

    item.path = path.split('/')

    if (!item.path[0]) item.path.shift() // Remove initial slash

    if (item.path.length < 2) { // No real prefix
      commonPrefix = null
    } else if (i === 0) { // The first file has a prefix
      commonPrefix = item.path[0]
    } else if (item.path[0] !== commonPrefix) { // The prefix doesn't match
      commonPrefix = null
    }
  })

  // remove junk files
  input = input.filter(function (item) {
    if (typeof item === 'string') return true
    var filename = item.path[item.path.length - 1]
    return notHidden(filename) && junk.not(filename)
  })

  if (commonPrefix) {
    input.forEach(function (item) {
      if (typeof item === 'string') return
      item.path.shift()
    })
  }

  if (!opts.name && commonPrefix) opts.name = commonPrefix
  if (!opts.name && input[0] && input[0].name) opts.name = input[0].name
  if (!opts.name && typeof input[0] === 'string') opts.name = corePath.basename(input[0])

  if (opts.name === undefined) {
    throw new Error('missing option \'name\' and unable to infer it from input[0].name')
  }

  var numPaths = input.reduce(function (sum, item) {
    return sum + Number(typeof item === 'string')
  }, 0)

  var isSingleFileTorrent = (input.length === 1)

  if (input.length === 1 && typeof input[0] === 'string') {
    if (typeof fs.stat !== 'function') {
      throw new Error('filesystem paths do not work in the browser')
    }
    // If there's a single path, verify it's a file before deciding this is a single
    // file torrent
    isFile(input[0], function (err, pathIsFile) {
      if (err) return cb(err)
      isSingleFileTorrent = pathIsFile
      processInput()
    })
  } else {
    processInput()
  }

  function processInput () {
    parallel(input.map(function (item) {
      return function (cb) {
        var file = {}

        if (isBlob(item)) {
          file.getStream = getBlobStream(item)
          file.length = item.size
        } else if (Buffer.isBuffer(item)) {
          file.getStream = getBufferStream(item)
          file.length = item.length
        } else if (isReadable(item)) {
          if (!opts.pieceLength) {
            throw new Error('must specify `pieceLength` option if input is Stream')
          }
          file.getStream = getStreamStream(item, file)
          file.length = 0
        } else if (typeof item === 'string') {
          if (typeof fs.stat !== 'function') {
            throw new Error('filesystem paths do not work in the browser')
          }
          var keepRoot = numPaths > 1 || isSingleFileTorrent
          getFiles(item, keepRoot, cb)
          return // early return!
        } else {
          throw new Error('invalid input type')
        }
        file.path = item.path
        cb(null, file)
      }
    }), function (err, files) {
      if (err) return cb(err)
      files = flatten(files)
      cb(null, files, isSingleFileTorrent)
    })
  }
}

function getFiles (path, keepRoot, cb) {
  traversePath(path, getFileInfo, function (err, files) {
    if (err) return cb(err)

    if (Array.isArray(files)) files = flatten(files)
    else files = [ files ]

    path = corePath.normalize(path)
    if (keepRoot) {
      path = path.slice(0, path.lastIndexOf(corePath.sep) + 1)
    }
    if (path[path.length - 1] !== corePath.sep) path += corePath.sep

    files.forEach(function (file) {
      file.getStream = getFilePathStream(file.path)
      file.path = file.path.replace(path, '').split(corePath.sep)
    })
    cb(null, files)
  })
}

function getFileInfo (path, cb) {
  cb = once(cb)
  fs.stat(path, function (err, stat) {
    if (err) return cb(err)
    var info = {
      length: stat.size,
      path: path
    }
    cb(null, info)
  })
}

function traversePath (path, fn, cb) {
  fs.readdir(path, function (err, entries) {
    if (err && err.code === 'ENOTDIR') {
      // this is a file
      fn(path, cb)
    } else if (err) {
      // real error
      cb(err)
    } else {
      // this is a folder
      parallel(entries.filter(notHidden).filter(junk.not).map(function (entry) {
        return function (cb) {
          traversePath(corePath.join(path, entry), fn, cb)
        }
      }), cb)
    }
  })
}

function notHidden (file) {
  return file[0] !== '.'
}

function getPieceList (files, pieceLength, cb) {
  cb = once(cb)
  var pieces = []
  var length = 0

  var streams = files.map(function (file) {
    return file.getStream
  })

  var remainingHashes = 0
  var pieceNum = 0
  var ended = false

  var multistream = new MultiStream(streams)
  var blockstream = new BlockStream(pieceLength, { zeroPadding: false })

  multistream.on('error', onError)

  multistream
    .pipe(blockstream)
    .on('data', onData)
    .on('end', onEnd)
    .on('error', onError)

  function onData (chunk) {
    length += chunk.length

    var i = pieceNum
    sha1(chunk, function (hash) {
      pieces[i] = hash
      remainingHashes -= 1
      maybeDone()
    })
    remainingHashes += 1
    pieceNum += 1
  }

  function onEnd () {
    ended = true
    maybeDone()
  }

  function onError (err) {
    cleanup()
    cb(err)
  }

  function cleanup () {
    multistream.removeListener('error', onError)
    blockstream.removeListener('data', onData)
    blockstream.removeListener('end', onEnd)
    blockstream.removeListener('error', onError)
  }

  function maybeDone () {
    if (ended && remainingHashes === 0) {
      cleanup()
      cb(null, new Buffer(pieces.join(''), 'hex'), length)
    }
  }
}

function onFiles (files, opts, cb) {
  var announceList = opts.announceList

  if (!announceList) {
    if (typeof opts.announce === 'string') announceList = [ [ opts.announce ] ]
    else if (Array.isArray(opts.announce)) {
      announceList = opts.announce.map(function (u) { return [ u ] })
    }
  }

  if (!announceList) announceList = []

  if (global.WEBTORRENT_ANNOUNCE) {
    if (typeof global.WEBTORRENT_ANNOUNCE === 'string') {
      announceList.push([ [ global.WEBTORRENT_ANNOUNCE ] ])
    } else if (Array.isArray(global.WEBTORRENT_ANNOUNCE)) {
      announceList = announceList.concat(global.WEBTORRENT_ANNOUNCE.map(function (u) {
        return [ u ]
      }))
    }
  }

  // When no trackers specified, use some reasonable defaults
  if (opts.announce === undefined && opts.announceList === undefined) {
    announceList = announceList.concat(module.exports.announceList)
  }

  if (typeof opts.urlList === 'string') opts.urlList = [ opts.urlList ]

  var torrent = {
    info: {
      name: opts.name
    },
    'creation date': Number(opts.creationDate) || Date.now(),
    encoding: 'UTF-8'
  }

  if (announceList.length !== 0) {
    torrent.announce = announceList[0][0]
    torrent['announce-list'] = announceList
  }

  if (opts.comment !== undefined) torrent.comment = opts.comment

  if (opts.createdBy !== undefined) torrent['created by'] = opts.createdBy

  if (opts.private !== undefined) torrent.info.private = Number(opts.private)

  // "ssl-cert" key is for SSL torrents, see:
  //   - http://blog.libtorrent.org/2012/01/bittorrent-over-ssl/
  //   - http://www.libtorrent.org/manual-ref.html#ssl-torrents
  //   - http://www.libtorrent.org/reference-Create_Torrents.html
  if (opts.sslCert !== undefined) torrent.info['ssl-cert'] = opts.sslCert

  if (opts.urlList !== undefined) torrent['url-list'] = opts.urlList

  var pieceLength = opts.pieceLength || calcPieceLength(files.reduce(sumLength, 0))
  torrent.info['piece length'] = pieceLength

  getPieceList(files, pieceLength, function (err, pieces, torrentLength) {
    if (err) return cb(err)
    torrent.info.pieces = pieces

    files.forEach(function (file) {
      delete file.getStream
    })

    if (opts.singleFileTorrent) {
      torrent.info.length = torrentLength
    } else {
      torrent.info.files = files
    }

    cb(null, bencode.encode(torrent))
  })
}

/**
 * Accumulator to sum file lengths
 * @param  {number} sum
 * @param  {Object} file
 * @return {number}
 */
function sumLength (sum, file) {
  return sum + file.length
}

/**
 * Check if `obj` is a W3C `Blob` object (which `File` inherits from)
 * @param  {*} obj
 * @return {boolean}
 */
function isBlob (obj) {
  return typeof Blob !== 'undefined' && obj instanceof Blob
}

/**
 * Check if `obj` is a W3C `FileList` object
 * @param  {*} obj
 * @return {boolean}
 */
function isFileList (obj) {
  return typeof FileList === 'function' && obj instanceof FileList
}

/**
 * Check if `obj` is a node Readable stream
 * @param  {*} obj
 * @return {boolean}
 */
function isReadable (obj) {
  return typeof obj === 'object' && typeof obj.pipe === 'function'
}

/**
 * Convert a `File` to a lazy readable stream.
 * @param  {File|Blob} file
 * @return {function}
 */
function getBlobStream (file) {
  return function () {
    return new FileReadStream(file)
  }
}

/**
 * Convert a `Buffer` to a lazy readable stream.
 * @param  {Buffer} buffer
 * @return {function}
 */
function getBufferStream (buffer) {
  return function () {
    var s = new stream.PassThrough()
    s.end(buffer)
    return s
  }
}

/**
 * Convert a file path to a lazy readable stream.
 * @param  {string} path
 * @return {function}
 */
function getFilePathStream (path) {
  return function () {
    return fs.createReadStream(path)
  }
}

/**
 * Convert a readable stream to a lazy readable stream. Adds instrumentation to track
 * the number of bytes in the stream and set `file.length`.
 *
 * @param  {Stream} stream
 * @param  {Object} file
 * @return {function}
 */
function getStreamStream (readable, file) {
  return function () {
    var counter = new stream.Transform()
    counter._transform = function (buf, enc, done) {
      file.length += buf.length
      this.push(buf)
      done()
    }
    readable.pipe(counter)
    return counter
  }
}
<|endoftext|>


<commit_before>/**
 *  Kache
 *  Kache - A Simple Memory Cache
 *  Version 0.0.2
 *  https://github.com/lemoncreative/kache/
 */

/**
 *  Module Dependencies
 */
var EventEmitter = require('events').EventEmitter
  , inherits     = require('inherits')
  , debug        = require('debug')('cache')
  , _            = require('underscore');

/**
 * Kasch Constructor
 *
 * @param {Object} options Options
 * @param {Array}  payload An array of Objects to preload the cache with.
 * @constructor
 * @api   public
 */
var Kache = function(options, payload) {
  Kache.super.apply(this);

  // Instance options & defaults
  options       = options || {};
  options.start = options.start || true;

  this.lru      = options.lru || false;
  this.max      = _.isNumber(options.max) ? options.max : Infinity;
  this.interval = _.isNumber(options.interval) ? (options.interval * 1000) : 300000;

  // Cache storage
  this.cache   = {};
  this.length  = 0;
  this.hits    = 0;
  this.misses  = 0;

  // Add payload to cache
  // @todo

  // Start scanner
  if(options.start)
    this.start();
};

inherits(Kache, EventEmitter);

/**
 * Item Constructor
 *
 * @param {Object} value Contents of cached item
 * @param {Number} ttl   Number of seconds to store this Item in the cache
 * @constructor
 * @api   public
 */
var Item = function(value, ttl) {
  var now = Date.now();
  this.createdAt = now;
  this.lastGet   = now;
  this.value     = value;
  this.ttl       = _.isNumber(ttl) ? (ttl * 1000) : Infinity;
};

/**
 * Add or replace an item in the cache
 *
 * @param {String} key   Key
 * @param {Mixed}  value Value
 * @param {Number} ttl   Number of seconds to store this Item in the cache
 * @api   public
 */
Kache.prototype.set = function set(key, value, ttl) {
    debug('Set: %s = %j (TTL: %s)', key, value, (_.isNumber(ttl) ? ttl : 'None'));
    if(!this.has(key))
      this.length++;
    this.cache[key] = new Item(value, ttl);

    // Return the value so we can do:
    // var name = cache.get('name') || cache.set('name', 'James', 3600);
    return value;
};

/**
 * Get an item from the cache
 *
 * @param  {String}   key      Key
 * @param  {Mixed}    def      Default Value to return
 * @param  {Function} callback Optional callback with err and value parameters
 * @return {Mixed}             Either callback(err, value|def|null) or value|def|null
 * @api    public
 */
Kache.prototype.get = function get(key, def, callback) {
  if(this.valid(key)) {
    this.hits++;
    if(this.lru)
      this.cache[key].lastGet = Date.now();
    return _.isFunction(callback) ? callback(null, this.cache[key].value) : this.cache[key].value;
  }
  this.misses++;
  return _.isFunction(callback) ? callback(null, def || def) : def || null;
};

/**
 * Remove an Item from the cache
 *
 * @param {String} key  Key
 * @api   public
 */
Kache.prototype.del = function remove(key) {
  if(!this.has(key)) return this;
  debug('Del: %s',key);
  delete this.cache[key];
  this.emit('remove', key);
  this.length--;
  return this;
};

/**
 * Check if an item has expired
 *
 * @param  {String} key Key
 * @return {Boolean}    Whether or not the item has expired
 * @api    public
 */
Kache.prototype.expired = function expired(key) {
  return this.cache[key].expired === true || (this.cache[key].expired = (Date.now() - this.cache[key].createdAt) > this.cache[key].ttl);
};

/**
 * Check if an item exists in the cache
 *
 * @param  {String}   key  Key
 * @return {Boolean}       Whether or not the item exists
 * @api public
 */
Kache.prototype.has = function check(key) {
  return this.cache.hasOwnProperty(key);
};

/**
 * Returns true if the item exists and has not expired
 *
 * @param  {String}   key  Key
 * @return {Boolean}       Whether or not the item is valid
 * @api public
 */
Kache.prototype.valid = function valid(key) {
  return this.has(key) && !this.expired(key);
};

/**
 * Returns true if the item doesn't exist or has expired
 *
 * @param  {String}   key  Key
 * @return {Boolean}       Whether or not the item is invalid
 * @api public
 */
Kache.prototype.invalid = function invalid(key) {
  return !this.valid(key);
};

/**
 * Returns an Array containing all the keys in the cache
 *
 * @return {Array} Keys of items currently in the cache
 * @api public
 */
Kache.prototype.keys = function keys() {
  return Object.keys(this.cache);
};

/**
 * Returns an Array containing keys of items which have expired
 *
 * @return {Array} Keys of items which have expired
 * @api public
 */
Kache.prototype.expiredKeys = function keys() {
  return this.keys().filter(function(key) {
    return this.expired(key);
  }, this);
};

/**
 * Returns an Array containing all the values in the cache
 *
 * @return {Array} All values from the cache
 * @api public
 */
Kache.prototype.values = function values() {
  return _.chain(this.cache)
    .values()
    .map(function(item) {
      return item.value;
    })
    .value();
};

/**
 * Returns a list of `[key, value]` pairs
 *
 * @return {Array} An Array containing `[key, value]` pairs for every item in the cache
 * @api public
 */
Kache.prototype.pairs = function pairs() {
  // @todo
};

/**
 * Iterate over each item in the cache excluding expired items.
 * Same API as `Array.prototype.forEach`
 *
 * @param  {Function} callback Callback Function
 * @param  {Object}   thisArg  The value to set this to
 * @return {Object}            The entire cache
 * @api public
 */
Kache.prototype.each = function each(callback, thisArg) {
  thisArg = thisArg || this;

  return this.keys().forEach(function(key) {
    if(this.expired(key)) return;
    callback.call(thisArg, key, this.cache[key].value, this.cache[key].ttl);
  }, this);
};

/**
 * Empty the entire cache
 *
 * @api public
 */
Kache.prototype.empty = function removeAll() {
  this.cache = {};
  this.length = 0;
  return this;
};

/**
 * Scan the cache and remove old items
 *
 * @api public
 */
Kache.prototype.scan = function scan() {
  debug('Scanning Cache');
  this.purgeExpired();
  this.purgeOldest();

  return this;
};

/**
 * Reduce the size of the cache to the maximum allowed size
 * by removing the oldest items.
 *
 * @api public
 */
Kache.prototype.purgeOldest = function purgeOldest() {
  if(!this.max || this.length < this.max) return;

  // @todo: Find and delete the oldest items from the cache
  return this;
};

/**
 * Checks the entire cache for expired objects
 *
 * @api public
 */
Kache.prototype.purgeExpired = function purgeExpired() {
  this.expiredKeys().forEach(function(key) {
    debug('Expired: %s', key);
    this.del(key);
  }, this);
  return this;
};

Kache.prototype.start = function start() {
  if(this.worker) this.stop();
  this.worker = setInterval(this.scan.bind(this), this.interval);
  return this;
};

Kache.prototype.stop = function stop() {
  if (this.worker)
    clearInterval(this.worker);
  return this;
};

function createCache(options) {
  return new Kache(options);
}

module.exports = createCache;<commit_msg>Fix typo<commit_after>/**
 *  Kache - A Simple Memory Cache
 *  Version 0.0.2
 *  https://github.com/lemoncreative/kache/
 */

/**
 *  Module Dependencies
 */
var EventEmitter = require('events').EventEmitter
  , inherits     = require('inherits')
  , debug        = require('debug')('cache')
  , _            = require('underscore');

/**
 * Kache Constructor
 *
 * @param {Object} options Options
 * @param {Array}  payload An array of Objects to preload the cache with.
 * @constructor
 * @api   public
 */
var Kache = function(options, payload) {
  Kache.super.apply(this);

  // Instance options & defaults
  options       = options || {};
  options.start = options.start || true;

  this.lru      = options.lru || false;
  this.max      = _.isNumber(options.max) ? options.max : Infinity;
  this.interval = _.isNumber(options.interval) ? (options.interval * 1000) : 300000;

  // Cache storage
  this.cache   = {};
  this.length  = 0;
  this.hits    = 0;
  this.misses  = 0;

  // Add payload to cache
  // @todo

  // Start scanner
  if(options.start)
    this.start();
};

inherits(Kache, EventEmitter);

/**
 * Item Constructor
 *
 * @param {Object} value Contents of cached item
 * @param {Number} ttl   Number of seconds to store this Item in the cache
 * @constructor
 * @api   public
 */
var Item = function(value, ttl) {
  var now = Date.now();
  this.createdAt = now;
  this.lastGet   = now;
  this.value     = value;
  this.ttl       = _.isNumber(ttl) ? (ttl * 1000) : Infinity;
};

/**
 * Add or replace an item in the cache
 *
 * @param {String} key   Key
 * @param {Mixed}  value Value
 * @param {Number} ttl   Number of seconds to store this Item in the cache
 * @api   public
 */
Kache.prototype.set = function set(key, value, ttl) {
    debug('Set: %s = %j (TTL: %s)', key, value, (_.isNumber(ttl) ? ttl : 'None'));
    if(!this.has(key))
      this.length++;
    this.cache[key] = new Item(value, ttl);

    // Return the value so we can do:
    // var name = cache.get('name') || cache.set('name', 'James', 3600);
    return value;
};

/**
 * Get an item from the cache
 *
 * @param  {String}   key      Key
 * @param  {Mixed}    def      Default Value to return
 * @param  {Function} callback Optional callback with err and value parameters
 * @return {Mixed}             Either callback(err, value|def|null) or value|def|null
 * @api    public
 */
Kache.prototype.get = function get(key, def, callback) {
  if(this.valid(key)) {
    this.hits++;
    if(this.lru)
      this.cache[key].lastGet = Date.now();
    return _.isFunction(callback) ? callback(null, this.cache[key].value) : this.cache[key].value;
  }
  this.misses++;
  return _.isFunction(callback) ? callback(null, def || def) : def || null;
};

/**
 * Remove an Item from the cache
 *
 * @param {String} key  Key
 * @api   public
 */
Kache.prototype.del = function remove(key) {
  if(!this.has(key)) return this;
  debug('Del: %s',key);
  delete this.cache[key];
  this.emit('remove', key);
  this.length--;
  return this;
};

/**
 * Check if an item has expired
 *
 * @param  {String} key Key
 * @return {Boolean}    Whether or not the item has expired
 * @api    public
 */
Kache.prototype.expired = function expired(key) {
  return this.cache[key].expired === true || (this.cache[key].expired = (Date.now() - this.cache[key].createdAt) > this.cache[key].ttl);
};

/**
 * Check if an item exists in the cache
 *
 * @param  {String}   key  Key
 * @return {Boolean}       Whether or not the item exists
 * @api public
 */
Kache.prototype.has = function check(key) {
  return this.cache.hasOwnProperty(key);
};

/**
 * Returns true if the item exists and has not expired
 *
 * @param  {String}   key  Key
 * @return {Boolean}       Whether or not the item is valid
 * @api public
 */
Kache.prototype.valid = function valid(key) {
  return this.has(key) && !this.expired(key);
};

/**
 * Returns true if the item doesn't exist or has expired
 *
 * @param  {String}   key  Key
 * @return {Boolean}       Whether or not the item is invalid
 * @api public
 */
Kache.prototype.invalid = function invalid(key) {
  return !this.valid(key);
};

/**
 * Returns an Array containing all the keys in the cache
 *
 * @return {Array} Keys of items currently in the cache
 * @api public
 */
Kache.prototype.keys = function keys() {
  return Object.keys(this.cache);
};

/**
 * Returns an Array containing keys of items which have expired
 *
 * @return {Array} Keys of items which have expired
 * @api public
 */
Kache.prototype.expiredKeys = function keys() {
  return this.keys().filter(function(key) {
    return this.expired(key);
  }, this);
};

/**
 * Returns an Array containing all the values in the cache
 *
 * @return {Array} All values from the cache
 * @api public
 */
Kache.prototype.values = function values() {
  return _.chain(this.cache)
    .values()
    .map(function(item) {
      return item.value;
    })
    .value();
};

/**
 * Returns a list of `[key, value]` pairs
 *
 * @return {Array} An Array containing `[key, value]` pairs for every item in the cache
 * @api public
 */
Kache.prototype.pairs = function pairs() {
  // @todo
};

/**
 * Iterate over each item in the cache excluding expired items.
 * Same API as `Array.prototype.forEach`
 *
 * @param  {Function} callback Callback Function
 * @param  {Object}   thisArg  The value to set this to
 * @return {Object}            The entire cache
 * @api public
 */
Kache.prototype.each = function each(callback, thisArg) {
  thisArg = thisArg || this;

  return this.keys().forEach(function(key) {
    if(this.expired(key)) return;
    callback.call(thisArg, key, this.cache[key].value, this.cache[key].ttl);
  }, this);
};

/**
 * Empty the entire cache
 *
 * @api public
 */
Kache.prototype.empty = function removeAll() {
  this.cache = {};
  this.length = 0;
  return this;
};

/**
 * Scan the cache and remove old items
 *
 * @api public
 */
Kache.prototype.scan = function scan() {
  debug('Scanning Cache');
  this.purgeExpired();
  this.purgeOldest();

  return this;
};

/**
 * Reduce the size of the cache to the maximum allowed size
 * by removing the oldest items.
 *
 * @api public
 */
Kache.prototype.purgeOldest = function purgeOldest() {
  if(!this.max || this.length < this.max) return;

  // @todo: Find and delete the oldest items from the cache
  return this;
};

/**
 * Checks the entire cache for expired objects
 *
 * @api public
 */
Kache.prototype.purgeExpired = function purgeExpired() {
  this.expiredKeys().forEach(function(key) {
    debug('Expired: %s', key);
    this.del(key);
  }, this);
  return this;
};

Kache.prototype.start = function start() {
  if(this.worker) this.stop();
  this.worker = setInterval(this.scan.bind(this), this.interval);
  return this;
};

Kache.prototype.stop = function stop() {
  if (this.worker)
    clearInterval(this.worker);
  return this;
};

function createCache(options) {
  return new Kache(options);
}

module.exports = createCache;<|endoftext|>


<commit_before>/*!
  Knockout Modal
  By: Brian M Hunt
  License: MIT
 */
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['knockout', 'jquery'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('knockout'), require('jquery'));
  } else {
    root.KnockoutModal = factory(root.ko, root.jQuery);
  }
}(this, function (ko, $) {
  var stack, at;
  var $html = $("html");
  var TRANSITION_END = "webkitTransitionEnd oTransitionEnd otransitionend " +
    "transitionend msTransitionEnd";
  var KnockoutModal = (function() {
    var KM = function KnockoutModal(template, data, options) {
      var self = this;
      this.template = null;
      this.options = options || {};
      this.pop = this.options.pop || function () { at(at() - 1); };
      var on_hide = this.options.on_hide || null;
      var on_show = this.options.on_show || null;

      this.is_active = ko.computed(function () { return this.index() == at() }, this);

      if (on_hide || on_show) {
        this.is_active.subscribe(function (is_active) {
          is_active ? (on_show ? on_show(this) : null) : (on_hide ? on_hide(this) : null);
        }, this);
      }

      this.css = ko.pureComputed(function () {
        var classes = this.options.classes || '';
        return classes + ' ' + (this.index() == at() ? 'kom-show' : 'kom-hide');
      }, this);

      stack.splice(at() + 1);
      at(at() + 1);

      this.render_future = Promise.resolve(data)
        .then(this.render.bind(this, template))
        .catch(console.error.bind(console))
    }

    KM.at = at = ko.observable(-1);
    KM.stack = stack = ko.observableArray();

    KM.prototype.index = function () { return stack.indexOf(this); }
    KM.prototype.on_close_click = function() { this.pop(); }
    KM.prototype.render = function (template, data) {
      this.data = data;
      this.template = template;
      stack.push(this);
    }

    // Add kom-active to <html>
    at.subscribe(function(at_) { $html.toggleClass('kom-active', at_ >= 0) });

    return KM;
  })();

  function on_close_click(vm, evt) {
    var kom;
    if (evt.target.classList.contains('kom-modal') ||
        evt.target.classList.contains('kom-box')) {
      kom = KnockoutModal.stack()[at()];
      if (kom) { kom.pop(); }
    }
  }

  function animate_blur(node, idx, kom) {
    node.parentNode.removeChild(node);
    if (typeof kom.options.on_blur == 'function') { kom.options.on_blur(kom); }
  };

  var bh = ko.bindingHandlers;
  var foreach_data = { data: stack, beforeRemove: animate_blur };
  bh.KnockoutModal = {
    init: function (e, va, a, vm, c) {
      bh.foreach.init(e, function () { return foreach_data }, a, vm, c);
      bh.click.init(e, function () { return on_close_click }, a, vm, c);
    },
    update: function (e, va, a, vm, c) {
      bh.foreach.update(e, function () { return foreach_data }, a, vm, c);
    }
  };

  // Globals
  KnockoutModal.$container = $(document.body);
  KnockoutModal.template = $("#kom-template").html();
  return KnockoutModal;
}));
<commit_msg>Remove unused blur animation/beforeRemove handler<commit_after>/*!
  Knockout Modal
  By: Brian M Hunt
  License: MIT
 */
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['knockout', 'jquery'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('knockout'), require('jquery'));
  } else {
    root.KnockoutModal = factory(root.ko, root.jQuery);
  }
}(this, function (ko, $) {
  var stack, at;
  var $html = $("html");
  var TRANSITION_END = "webkitTransitionEnd oTransitionEnd otransitionend " +
    "transitionend msTransitionEnd";
  var KnockoutModal = (function() {
    var KM = function KnockoutModal(template, data, options) {
      this.template = null;
      this.options = options || {};
      this.pop = this.options.pop || function () { at(at() - 1); };
      var on_hide = this.options.on_hide || null;
      var on_show = this.options.on_show || null;

      this.is_active = ko.computed(function () { return this.index() == at() }, this);

      if (on_hide || on_show) {
        this.is_active.subscribe(function (is_active) {
          is_active ? (on_show ? on_show(this) : null) : (on_hide ? on_hide(this) : null);
        }, this);
      }

      this.css = ko.pureComputed(function () {
        var classes = this.options.classes || '';
        return classes + ' ' + (this.index() == at() ? 'kom-show' : 'kom-hide');
      }, this);

      stack.splice(at() + 1);
      at(at() + 1);

      this.render_future = Promise.resolve(data)
        .then(this.render.bind(this, template))
        .catch(console.error.bind(console))
    }

    KM.at = at = ko.observable(-1);
    KM.stack = stack = ko.observableArray();

    KM.prototype.index = function () { return stack.indexOf(this); }
    KM.prototype.on_close_click = function() { this.pop(); }
    KM.prototype.render = function (template, data) {
      this.data = data;
      this.template = template;
      stack.push(this);
    }

    // Add kom-active to <html>
    at.subscribe(function(at_) { $html.toggleClass('kom-active', at_ >= 0) });

    return KM;
  })();

  function on_close_click(vm, evt) {
    var kom;
    if (evt.target.classList.contains('kom-modal') ||
        evt.target.classList.contains('kom-box')) {
      kom = KnockoutModal.stack()[at()];
      if (kom) { kom.pop(); }
    }
  }

  var bh = ko.bindingHandlers;
  bh.KnockoutModal = {
    init: function (e, va, a, vm, c) {
      bh.foreach.init(e, function () { return {data: stack} }, a, vm, c);
      bh.click.init(e, function () { return on_close_click }, a, vm, c);
    },
    update: function (e, va, a, vm, c) {
      bh.foreach.update(e, function () { return {data: stack} }, a, vm, c);
    }
  };

  // Globals
  KnockoutModal.$container = $(document.body);
  KnockoutModal.template = $("#kom-template").html();
  return KnockoutModal;
}));
<|endoftext|>