<commit_before>const omxp = require('omxplayer-controll');

module.exports = function(RED) {
    function omxControl(config) {
        RED.nodes.createNode(this, config);
        var node = this;

        node.filename = config.filename;
        node.audiooutput = config.audiooutput;
        node.blackbackground = config.blackbackground;
        node.disablekeys = config.disablekeys;
        node.disableosd = config.disableosd;
        node.disableghostbox = config.disableghostbox;
        node.subtitlepath = config.subtitlepath;

        var opts = {
            'audioOutput': node.audiooutput || 'hdmi',
            'blackBackground': node.blackbackground,
            'disableKeys': node.disablekeys,
            'disableOnScreenDisplay': node.disableosd,
            'disableGhostbox': node.disableghostbox,
            'subtitlePath': node.subtitlepath || '',
            'startAt': 0,
            'startVolume': 0.8,
            'closeOtherPlayers': true //Should close other players if necessary
        };

        node.on('input', function(msg) {
            var filename = node.filename || msg.filename || "";

            if (msg.payload == 'open') {
                if (filename == ""){
                    node.warn('No filename provided.');
                    return;
                } else {
                    omxp.open(filename, opts);
                }
            }
            if (msg.payload == 'playpause') {
                omxp.playPause(function(err){
                    if (err){
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'pause') {
                omxp.pause(function(err){
                    if (err) {
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'stop') {
                omxp.stop(function(err){
                    if (err) {
                        node.error(err, msg);
                    } else {
                        node.status({fill:"red",shape:"dot",text:"Stopped"});
                    }
                });
            }
            if (msg.payload == 'volumeup') {
                omxp.volumeUp(function(err){
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'volumedown') {
                omxp.volumeDown(function(err){
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'getduration') {
                omxp.getDuration(function(err, duration){
                    node.warn(duration);
                });
            }
            if (msg.payload == 'getstatus') {
                omxp.getStatus(function(err, status){
                    if (status) node.warn(status);
                });
            }
            if (msg.payload == 'getvolume') {
                omxp.getVolume(function(err, volume){
                    node.warn(volume);
                });
            }
        });

        function updateStatus() {
            omxp.getStatus(function(err, status){
                if (status) {
                    switch (status) {
                        case 'Playing':
                            node.status({fill:"green",shape:"dot",text:"Playing"});
                            break;
                        case 'Stopped':
                            node.status({fill:"red",shape:"dot",text:"Stopped"});
                            break;
                        case 'Paused':
                            node.status({fill:"gray",shape:"dot",text:"Paused"});
                            break;
                    }
                }

            });
        }

        omxp.on('changeStatus',function(status) {
            switch (status.status) {
                case 'Playing':
                    node.status({fill:"green",shape:"dot",text:"Playing"});
                    break;
                case 'Stopped':
                    node.status({fill:"red",shape:"dot",text:"Stopped"});
                    break;
                case 'Paused':
                    node.status({fill:"gray",shape:"dot",text:"Paused"});
                    break;
            }
        });

        omxp.on('finish', function() {
            node.warn('============= Finished =============');
            node.status({fill:"red",shape:"dot",text:"Stopped"});
        });

        node.on('close', function() {
            omxp.removeAllListeners('finish');
        });
    }
    RED.nodes.registerType("rpi-omxplayer", omxControl);
};
<commit_msg>Add setvolume<commit_after>const omxp = require('omxplayer-controll');

module.exports = function(RED) {
    function omxControl(config) {
        RED.nodes.createNode(this, config);
        var node = this;

        node.filename = config.filename;
        node.audiooutput = config.audiooutput;
        node.blackbackground = config.blackbackground;
        node.disablekeys = config.disablekeys;
        node.disableosd = config.disableosd;
        node.disableghostbox = config.disableghostbox;
        node.subtitlepath = config.subtitlepath;

        var opts = {
            'audioOutput': node.audiooutput || 'hdmi',
            'blackBackground': node.blackbackground,
            'disableKeys': node.disablekeys,
            'disableOnScreenDisplay': node.disableosd,
            'disableGhostbox': node.disableghostbox,
            'subtitlePath': node.subtitlepath || '',
            'startAt': 0,
            'startVolume': 0.8,
            'closeOtherPlayers': true //Should close other players if necessary
        };

        node.on('input', function(msg) {
            var filename = node.filename || msg.filename || "";

            if (msg.payload == 'open') {
                if (filename == ""){
                    node.warn('No filename provided.');
                    return;
                } else {
                    omxp.open(filename, opts);
                }
            }
            if (msg.payload == 'playpause') {
                omxp.playPause(function(err){
                    if (err){
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'pause') {
                omxp.pause(function(err){
                    if (err) {
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'stop') {
                omxp.stop(function(err){
                    if (err) {
                        node.error(err, msg);
                    } else {
                        node.status({fill:"red",shape:"dot",text:"Stopped"});
                    }
                });
            }
            if (msg.payload == 'volumeup') {
                omxp.volumeUp(function(err){
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'volumedown') {
                omxp.volumeDown(function(err){
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'getduration') {
                omxp.getDuration(function(err, duration){
                    node.warn(duration);
                });
            }
            if (msg.payload == 'getstatus') {
                omxp.getStatus(function(err, status){
                    if (status) node.warn(status);
                });
            }
            if (msg.payload == 'getvolume') {
                omxp.getVolume(function(err, volume){
                    node.warn(volume);
                });
            }
            if (msg.payload.startsWith('setvolume')) {
                var volume = parseFloat(msg.payload.split()[1]);
                if (volume > 1) volume = 1;
                if (volume < 0) volume = 0;
                omxp.setVolume(volume, function(err, volume){
                    node.error(err);
                });
            }
        });

        function updateStatus() {
            omxp.getStatus(function(err, status){
                if (status) {
                    switch (status) {
                        case 'Playing':
                            node.status({fill:"green",shape:"dot",text:"Playing"});
                            break;
                        case 'Stopped':
                            node.status({fill:"red",shape:"dot",text:"Stopped"});
                            break;
                        case 'Paused':
                            node.status({fill:"gray",shape:"dot",text:"Paused"});
                            break;
                    }
                }

            });
        }

        omxp.on('changeStatus',function(status) {
            switch (status.status) {
                case 'Playing':
                    node.status({fill:"green",shape:"dot",text:"Playing"});
                    break;
                case 'Stopped':
                    node.status({fill:"red",shape:"dot",text:"Stopped"});
                    break;
                case 'Paused':
                    node.status({fill:"gray",shape:"dot",text:"Paused"});
                    break;
            }
        });

        omxp.on('finish', function() {
            node.warn('============= Finished =============');
            node.status({fill:"red",shape:"dot",text:"Stopped"});
        });

        node.on('close', function() {
            omxp.removeAllListeners('finish');
        });
    }
    RED.nodes.registerType("rpi-omxplayer", omxControl);
};
<|endoftext|>


<commit_before>export const ANIMATION = true;

export const ARRANGE_METRICS = [];

export const CELL_SIZE = 6;

export const CELL_SIZE_HALF = CELL_SIZE / 2;

export const CELL_THRESHOLD = 0.0;  // only cells above are shown

export const COLOR_LOW_QUALITY = [1, 0.890196078, 0.835294118];

export const COLOR_PRIMARY = 0xff5500;

/**
 * External config to initialize fragments.
 *
 * @description
 * The config is different from the visual state of the app.
 *
 * @type  {Object}
 */
export const CONFIG = {};

export const DIAGONAL_VALUE = 0.11;

export const DURATION = 500;

export const FONT_URL = 'src/assets/fonts/rubik-regular.json';

export const FPS = 25;

export const HIGHLIGHT_FRAME_LINE_WIDTH = 5;

export const LABEL_DIST = 60;

export const LABEL_WIDTH = 130;

export const LABEL_TEXT_SPEC = {
  size: 6,
  height: 1,
  curveSegments: 3
};

export const LETTER_SPACE = 6;

export const MARGIN_BOTTOM = 2;

export const MARGIN_LEFT = 2;

export const MARGIN_RIGHT = 2;

export const MARGIN_TOP = 2;

export const MATRIX_GAP_HORIZONTAL = 10;

export const MATRIX_GAP_VERTICAL = 20;

export const METRIC_DIST_DIAG = 'distToDiag';

export const METRIC_NOISE = 'noise';

export const METRIC_SHARPNESS = 'sharpness';

export const METRIC_SIZE = 'size';

export const MODE_BARCHART = 1;

export const MODE_DIFFERENCE = 4;

export const MODE_DIRECT_DIFFERENCE = 5;

/**
 * Harmonic Mean
 *
 * @type  {Number}
 */
export const MODE_MEAN = 0;

/**
 * Not sure
 *
 * @type  {Number}
 */
export const MODE_TREND = 2;

/**
 * Statistical variance
 *
 * @type  {Number}
 */
export const MODE_VARIANCE = 3;

export const ORDER_DATA = 0;

export const ORDER_GLOBAL = 1;

export const ORDER_LOCAL = 2;

export const PILING_DIRECTION = 'horizontal';

export const PREVIEW_SIZE = 3;

export const SHADER_ATTRIBUTES = {
  customColor: { type: 'c', value: [] }
};

export const SHOW_MATRICES = 1000;

export const SHOW_SPECIAL_CELLS = false;

export const SVG_MENU_HEIGHT = 30;

export const TIMELINE_HEIGHT = 130;

/**
 * Three.js's WebGL config
 *
 * @type  {Object}
 */
export const WEB_GL_CONFIG = {
  alpha: true,
  antialias: true
};

export default {
  CELL_SIZE,
  CELL_SIZE_HALF,
  CELL_THRESHOLD,
  CONFIG,
  DIAGONAL_VALUE,
  DURATION,
  FONT_URL,
  FPS,
  LABEL_DIST,
  LABEL_TEXT_SPEC,
  LABEL_WIDTH,
  LETTER_SPACE,
  MARGIN_BOTTOM,
  MARGIN_LEFT,
  MARGIN_RIGHT,
  MARGIN_TOP,
  MATRIX_GAP_HORIZONTAL,
  MATRIX_GAP_VERTICAL,
  MODE_BARCHART,
  MODE_DIFFERENCE,
  MODE_DIRECT_DIFFERENCE,
  MODE_MEAN,
  MODE_TREND,
  MODE_VARIANCE,
  ORDER_DATA,
  ORDER_GLOBAL,
  ORDER_LOCAL,
  PILING_DIRECTION,
  PREVIEW_SIZE,
  SHADER_ATTRIBUTES,
  SHOW_MATRICES,
  SVG_MENU_HEIGHT,
  TIMELINE_HEIGHT,
  WEB_GL_CONFIG
};
<commit_msg>Remove unused cover matrix display modes<commit_after>export const ANIMATION = true;

export const ARRANGE_METRICS = [];

export const CELL_SIZE = 6;

export const CELL_SIZE_HALF = CELL_SIZE / 2;

export const CELL_THRESHOLD = 0.0;  // only cells above are shown

export const COLOR_LOW_QUALITY = [1, 0.890196078, 0.835294118];

export const COLOR_PRIMARY = 0xff5500;

/**
 * External config to initialize fragments.
 *
 * @description
 * The config is different from the visual state of the app.
 *
 * @type  {Object}
 */
export const CONFIG = {};

export const DIAGONAL_VALUE = 0.11;

export const DURATION = 500;

export const FONT_URL = 'src/assets/fonts/rubik-regular.json';

export const FPS = 25;

export const HIGHLIGHT_FRAME_LINE_WIDTH = 5;

export const LABEL_DIST = 60;

export const LABEL_WIDTH = 130;

export const LABEL_TEXT_SPEC = {
  size: 6,
  height: 1,
  curveSegments: 3
};

export const LETTER_SPACE = 6;

export const MARGIN_BOTTOM = 2;

export const MARGIN_LEFT = 2;

export const MARGIN_RIGHT = 2;

export const MARGIN_TOP = 2;

export const MATRIX_GAP_HORIZONTAL = 10;

export const MATRIX_GAP_VERTICAL = 20;

export const METRIC_DIST_DIAG = 'distToDiag';

export const METRIC_NOISE = 'noise';

export const METRIC_SHARPNESS = 'sharpness';

export const METRIC_SIZE = 'size';

/**
 * Harmonic Mean
 *
 * @type {Number}
 */
export const MODE_MEAN = 0;

/**
 * Not sure
 *
 * @type {Number}
 */
export const MODE_TREND = 1;

/**
 * Statistical variance
 *
 * @type {Number}
 */
export const MODE_VARIANCE = 2;

/**
 * Stuff
 *
 * @type {Number}
 */
export const MODE_DIFFERENCE = 3;

export const ORDER_DATA = 0;

export const ORDER_GLOBAL = 1;

export const ORDER_LOCAL = 2;

export const PILING_DIRECTION = 'horizontal';

export const PREVIEW_SIZE = 3;

export const SHADER_ATTRIBUTES = {
  customColor: { type: 'c', value: [] }
};

export const SHOW_MATRICES = 1000;

export const SHOW_SPECIAL_CELLS = false;

export const SVG_MENU_HEIGHT = 30;

export const TIMELINE_HEIGHT = 130;

/**
 * Three.js's WebGL config
 *
 * @type  {Object}
 */
export const WEB_GL_CONFIG = {
  alpha: true,
  antialias: true
};

export default {
  CELL_SIZE,
  CELL_SIZE_HALF,
  CELL_THRESHOLD,
  CONFIG,
  DIAGONAL_VALUE,
  DURATION,
  FONT_URL,
  FPS,
  LABEL_DIST,
  LABEL_TEXT_SPEC,
  LABEL_WIDTH,
  LETTER_SPACE,
  MARGIN_BOTTOM,
  MARGIN_LEFT,
  MARGIN_RIGHT,
  MARGIN_TOP,
  MATRIX_GAP_HORIZONTAL,
  MATRIX_GAP_VERTICAL,
  MODE_DIFFERENCE,
  MODE_MEAN,
  MODE_TREND,
  MODE_VARIANCE,
  ORDER_DATA,
  ORDER_GLOBAL,
  ORDER_LOCAL,
  PILING_DIRECTION,
  PREVIEW_SIZE,
  SHADER_ATTRIBUTES,
  SHOW_MATRICES,
  SVG_MENU_HEIGHT,
  TIMELINE_HEIGHT,
  WEB_GL_CONFIG
};
<|endoftext|>


<commit_before>var users = {};
var x = d3.scaleTime();
var y = d3.scaleLinear();

var svg = d3.select('#tableChart');
var width = 1000;
var height = 500;
var margin_left = 40;
var margin_bottom = 70;
var line_func = d3.line().x(function(d) { return x(d.date); }).y(function(d) { return y(d.v); });
var draw_line = function(chart_data, color) {
    svg.append('path')
        .attr('d', line_func(chart_data))
        .attr('stroke', color)
        .attr('stroke-width', '2')
        .attr('fill', 'none')
        .on('mouseover', function() {
            d3.select(this).attr('stroke-width', '3').attr('stroke', d3.color(color).brighter(3));
        })
        .on('mouseout', function() {
            d3.select(this).attr('stroke-width', '2').attr('stroke', color);
        });
};

var process_chart_data = function(selection, key) {
    selection.select(function() {
        var wdate = d3.timeParse("%Y-%m-%d")(this.getAttribute('data-wdate'));
        var wuserid = this.getAttribute('data-wuserid');
        var v = this.innerHTML;
        if (!users[wuserid]) {
            users[wuserid] = { classic: [], twentyfour: [] };
        }
        users[wuserid][key].push({date: wdate, v: v});
    });
}

process_chart_data(d3.selectAll('.chart-data .classic span'), 'classic');
process_chart_data(d3.selectAll('.chart-data .twentyfour span'), 'twentyfour');
var first_date = d3.timeParse("%Y-%m-%d")(d3.select('.chart-data').attr('data-first-date'));
var last_date = d3.timeParse("%Y-%m-%d")(d3.select('.chart-data').attr('data-last-date'));

var mdata = [];
for (wuserid in users) {
    var muser = d3.merge([users[wuserid]['classic'], users[wuserid]['twentyfour']]);
    mdata = d3.merge([mdata, muser]);
}
mdata = mdata.filter(function(d) { return (d.date >= first_date) && (d.date <= last_date); });
x
    .range([margin_left,width])
    .domain([first_date, last_date]);
    //.domain(d3.extent(mdata, function(d) { return d.date; }));
y
    .range([height-margin_bottom,margin_bottom])
    .domain(d3.extent(mdata, function(d) { return d.v; }));

for (wuserid in users) {
    draw_line(users[wuserid]['classic'], 'blue');
    draw_line(users[wuserid]['twentyfour'], 'green');
}

var xAxis = d3.axisBottom(x).ticks(d3.timeMonday.every(1)).tickFormat(d3.timeFormat("%Y.%m.%d"));
yticks = Math.round(y.domain()[1] - y.domain()[0])*2
var yAxis = d3.axisLeft(y).ticks(yticks);

var draw_grid = function(selection, orientation) {
    console.log('draw_grid %o', selection);
    selection.selectAll("g.tick").select(function() {
        var dthis = d3.select(this);
        if (orientation == "horizontal") {
            svg.insert('line', ':first-child')
                .attr('stroke', 'lightgrey')
                .attr('x1', 0)
                .attr('y1', height-margin_bottom)
                .attr('x2', 0)
                .attr('y2', 0)
                .attr('opacity', 0.4)
                .attr('transform', dthis.attr('transform'));
        } else if (orientation == "vertical") {
            svg.insert('line', ':first-child')
                .attr('stroke', 'lightgrey')
                .attr('x1', margin_left)
                .attr('y1', 0)
                .attr('x2', width)
                .attr('y2', 0)
                .attr('opacity', 0.4)
                .attr('transform', dthis.attr('transform'));
        }
    });
};

svg.append('g').attr('transform', 'translate(0, '+(height-margin_bottom)+')').call(xAxis).call(draw_grid, "horizontal").call(function(selection) { selection.selectAll("g.tick text").attr('transform', 'rotate(90) translate(35, -14)'); });
svg.append('g').attr('transform', 'translate('+margin_left+', 0)').call(yAxis).call(draw_grid, "vertical");
<commit_msg>niech ta siatka nie wychodzi ponad linie pionowej osi, tak jak jest w poziomie<commit_after>var users = {};
var x = d3.scaleTime();
var y = d3.scaleLinear();

var svg = d3.select('#tableChart');
var width = 1000;
var height = 500;
var margin_left = 40;
var margin_bottom = 70;
var line_func = d3.line().x(function(d) { return x(d.date); }).y(function(d) { return y(d.v); });
var draw_line = function(chart_data, color) {
    svg.append('path')
        .attr('d', line_func(chart_data))
        .attr('stroke', color)
        .attr('stroke-width', '2')
        .attr('fill', 'none')
        .on('mouseover', function() {
            d3.select(this).attr('stroke-width', '3').attr('stroke', d3.color(color).brighter(3));
        })
        .on('mouseout', function() {
            d3.select(this).attr('stroke-width', '2').attr('stroke', color);
        });
};

var process_chart_data = function(selection, key) {
    selection.select(function() {
        var wdate = d3.timeParse("%Y-%m-%d")(this.getAttribute('data-wdate'));
        var wuserid = this.getAttribute('data-wuserid');
        var v = this.innerHTML;
        if (!users[wuserid]) {
            users[wuserid] = { classic: [], twentyfour: [] };
        }
        users[wuserid][key].push({date: wdate, v: v});
    });
}

process_chart_data(d3.selectAll('.chart-data .classic span'), 'classic');
process_chart_data(d3.selectAll('.chart-data .twentyfour span'), 'twentyfour');
var first_date = d3.timeParse("%Y-%m-%d")(d3.select('.chart-data').attr('data-first-date'));
var last_date = d3.timeParse("%Y-%m-%d")(d3.select('.chart-data').attr('data-last-date'));

var mdata = [];
for (wuserid in users) {
    var muser = d3.merge([users[wuserid]['classic'], users[wuserid]['twentyfour']]);
    mdata = d3.merge([mdata, muser]);
}
mdata = mdata.filter(function(d) { return (d.date >= first_date) && (d.date <= last_date); });
x
    .range([margin_left,width])
    .domain([first_date, last_date]);
    //.domain(d3.extent(mdata, function(d) { return d.date; }));
y
    .range([height-margin_bottom,0])
    .domain(d3.extent(mdata, function(d) { return d.v; }));

for (wuserid in users) {
    draw_line(users[wuserid]['classic'], 'blue');
    draw_line(users[wuserid]['twentyfour'], 'green');
}

var xAxis = d3.axisBottom(x).ticks(d3.timeMonday.every(1)).tickFormat(d3.timeFormat("%Y.%m.%d"));
yticks = Math.round(y.domain()[1] - y.domain()[0])*2
var yAxis = d3.axisLeft(y).ticks(yticks);

var draw_grid = function(selection, orientation) {
    console.log('draw_grid %o', selection);
    selection.selectAll("g.tick").select(function() {
        var dthis = d3.select(this);
        if (orientation == "horizontal") {
            svg.insert('line', ':first-child')
                .attr('stroke', 'lightgrey')
                .attr('x1', 0)
                .attr('y1', height-margin_bottom)
                .attr('x2', 0)
                .attr('y2', 0)
                .attr('opacity', 0.4)
                .attr('transform', dthis.attr('transform'));
        } else if (orientation == "vertical") {
            svg.insert('line', ':first-child')
                .attr('stroke', 'lightgrey')
                .attr('x1', margin_left)
                .attr('y1', 0)
                .attr('x2', width)
                .attr('y2', 0)
                .attr('opacity', 0.4)
                .attr('transform', dthis.attr('transform'));
        }
    });
};

svg.append('g').attr('transform', 'translate(0, '+(height-margin_bottom)+')').call(xAxis).call(draw_grid, "horizontal").call(function(selection) { selection.selectAll("g.tick text").attr('transform', 'rotate(90) translate(35, -14)'); });
svg.append('g').attr('transform', 'translate('+margin_left+', 0)').call(yAxis).call(draw_grid, "vertical");
<|endoftext|>


<commit_before>//Load local build if in local environment.
if (window.origin !== 'https://rhoinc.github.io') {
    var head = document.getElementsByTagName('head')[0];

  //...load local build.
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = '../webcodebook.js';
    head.appendChild(script);

  //...load local stylesheet.
    for (var i = 0; i < document.styleSheets.length; i++) {
        var styleSheet = document.styleSheets[i];
        if (styleSheet.href.indexOf('webcodebook') > -1)
            styleSheet.disabled = true;
    }
    var link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.href = '../../css/webcodebook.css';
    head.appendChild(link);   head.appendChild(script);
}

function initExplorer(fileList){
  console.log(fileList)
  var metaFiles = ["AE","DM","LB"] //list of files to add meta data
  d3.csv("https://rawgit.com/RhoInc/viz-library/master/data/safetyData/variableMetaData.csv",function(error,meta){
    meta.forEach(function(f){
      f.file = f.Form+".csv"
    })
    var fileList_clean = fileList.map(function(f){
  		f.path = "https://rawgit.com/RhoInc/viz-library/master"+f.rel_path.slice(1);
      f.shortname = f.filename.replace(/\.[^/.]+$/, "")
      if(metaFiles.indexOf(f.shortname)>-1){
        f.meta = meta.filter(m=>m.Form == f.shortname)
        .map(function(m){
          m.value_col = m.Variable;
          return m;
        })
        f["Metadata included?"] = "Yes"
      }else{
        f["Metadata included?"] = "No"
      }
  		return f;
  	})

  	var settings = {
  		labelColumn:"filename",
  		ignoredColumns: ["local_path","rel_path","path"],
  		files:fileList_clean,
      meta:meta
  	};
  	var explorer = webcodebook.createExplorer("#container", settings).init();
  })

}

initExplorer(dataFiles)
<commit_msg>update explorer example<commit_after>//Load local build if in local environment.
if (window.origin !== 'https://rhoinc.github.io') {
    var head = document.getElementsByTagName('head')[0];

  //...load local build.
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = '../webcodebook.js';
    head.appendChild(script);

  //...load local stylesheet.
    for (var i = 0; i < document.styleSheets.length; i++) {
        var styleSheet = document.styleSheets[i];
        if (styleSheet.href.indexOf('webcodebook') > -1)
            styleSheet.disabled = true;
    }
    var link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.href = '../../css/webcodebook.css';
    head.appendChild(link);   head.appendChild(script);
}

function initExplorer(fileList){
  console.log(fileList)
  var metaFiles = ["AE","DM","LB"] //list of files to add meta data
  d3.csv("https://rawgit.com/RhoInc/viz-library/master/data/safetyData/variableMetaData.csv",function(error,meta){
    meta.forEach(function(f){
      f.file = f.Form+".csv"
      f.label = f.Label
      console.log(f)
    })
    var fileList_clean = fileList.map(function(f){
  		f.path = "https://rawgit.com/RhoInc/viz-library/master"+f.rel_path.slice(1);
      f.shortname = f.filename.replace(/\.[^/.]+$/, "")
      if(metaFiles.indexOf(f.shortname)>-1){
        f.meta = meta.filter(m=>m.Form == f.shortname)
        .map(function(m){
          m.value_col = m.Variable;
          return m;
        })
        f["Metadata included?"] = "Yes"
      }else{
        f["Metadata included?"] = "No"
      }
  		return f;
  	})

  	var settings = {
  		labelColumn:"filename",
  		ignoredColumns: ["local_path","rel_path","path"],
  		files:fileList_clean,
      meta:meta
  	};
  	var explorer = webcodebook.createExplorer("#container", settings).init();
  })

}

initExplorer(dataFiles)
<|endoftext|>


<commit_before>'use babel';
import {
  CompositeDisposable,
  Point,
} from 'atom';

import minimapCodeglanceElement from './minimap-codeglance-element.js';

import {
  addEventListener,
  addEventListenerOnce,
} from './utils.js';

var prototype = {
  initialize() {
    this.element = minimapCodeglanceElement();

    this.disposables = new CompositeDisposable(
      atom.config.observe('minimap-codeglance.numberOfLines', numberOfLines =>
        this.numberOfLines = numberOfLines
      ),
      atom.config.observe('minimap-codeglance.showLineNumbers', showLineNumbers =>
        showLineNumbers ? this.element.showLineNumbers() : this.element.hideLineNumbers()
      ),
      atom.config.observe('minimap-codeglance.codeHighlighting', codeHighlighting =>
        this.codeHighlighting = codeHighlighting
      ),
      atom.config.observe('minimap-codeglance.softWrap', softWrapMode =>
        this.softWrapMode = softWrapMode
      ),
    );
  },

  destroy() {
    this.detachElement();
    this.element.destroy();
    this.disposables.dispose();
    [this.element, this.disposables, this.minimap] = [];
  },

  disabled: false,

  disableDuringMouseDown() {
    if(this.disabled) return;
    this.disabled = true;
    this.detachElement();
    addEventListenerOnce(document.body, 'mouseup', () => {
      this.disabled = false;
      this.attachElement();
      this.element.hide();
    });
  },

  addMinimap(minimap) {
    var minimapView = atom.views.getView(minimap);

    var minimapDisposable = new CompositeDisposable(
      addEventListener(minimapView, 'mouseenter', () =>
        this.setCurrentMinimap(minimap)
      ),
      addEventListener(minimapView, 'mousemove', event =>
        this.scrollToMousePosition(event)
      ),
      addEventListener(minimapView, 'mouseleave', () =>
        this.detachElement()
      ),
      addEventListener(minimapView, 'mousedown', () =>
        this.disableDuringMouseDown()
      ),
      addEventListener(atom.views.getView(minimap.getTextEditor()), 'mousedown', () =>
        this.disableDuringMouseDown()
      ),
      minimap.onDidDestroy(() => {
        this.disposables.remove(minimapDisposable);
        minimapDisposable.dispose();
        minimapDisposable = null;
      }),
    );

    this.disposables.add(minimapDisposable);
  },

  setCurrentMinimap(minimap) {
    this.minimap = minimap;
    this.attachElement();
    this.updateNumberOfLines();
    this.updateSoftWrapped();

    if(this.getTextEditor().getText() == this.element.getText()) return;

    this.element.setText('');
    this.updateGrammar();
    this.updateText();
  },

  getTextEditor() {
    return this.minimap.getTextEditor();
  },

  getTextEditorRoot() {
    var textEditorView = atom.views.getView(this.getTextEditor());
    return textEditorView.shadowRoot || textEditorView;
  },

  attachElement() {
    var textEditorRoot = this.getTextEditorRoot();
    textEditorRoot.querySelector('.editor-contents--private').appendChild(this.element);
  },

  detachElement() {
    this.element.remove();
  },

  updateNumberOfLines() {
    this.element.setNumberOfLines(this.numberOfLines);
  },

  updateSoftWrapped() {
    this.element.setSoftWrapped(this.getSoftWrapped());
  },

  getSoftWrapped() {
    switch(this.softWrapMode.split(' ')[0]) {
      default:
      case 'editor':
        return this.getTextEditor().isSoftWrapped();
      case 'always':
        return true;
      case 'never':
        return false;
    }
  },

  updateGrammar() {
    this.element.setGrammar(
      this.codeHighlighting ?
        this.getTextEditor().getGrammar() :
        atom.grammars.grammarForScopeName('text.plain.null-grammar')
    );
  },

  updateText() {
    this.element.setText(this.getTextEditor().getText());
  },

  scrollToMousePosition({offsetX, offsetY}) {
    if(this.disabled || !this.minimap) return;
    var screenPosition = this.screenPositionForOffset({offsetX, offsetY});

    if(screenPosition.row > this.getTextEditor().getLastScreenRow()) {
      return void this.element.hide();
    }

    this.element.show();
    this.element.scrollToBufferPosition(
      this.getTextEditor().bufferPositionForScreenPosition(screenPosition)
    );
    this.element.translateY(offsetY);
  },

  screenPositionForOffset({offsetX, offsetY}) {
    var firstVisibleScreenRow = this.minimap.getFirstVisibleScreenRow();
    var lineHeight = this.minimap.charHeight + this.minimap.interline;
    var row = firstVisibleScreenRow + Math.floor(offsetY / lineHeight);
    var columnWidth = this.minimap.charWidth;
    var column = Math.floor(offsetX / columnWidth);
    return new Point(row, column);
  },
};

export default function minimapCodeglance() {
  return Object.create(prototype);
}
<commit_msg>fix crash (#8)<commit_after>'use babel';
import {
  CompositeDisposable,
  Point,
} from 'atom';

import minimapCodeglanceElement from './minimap-codeglance-element.js';

import {
  addEventListener,
  addEventListenerOnce,
} from './utils.js';

var prototype = {
  initialize() {
    this.element = minimapCodeglanceElement();

    this.disposables = new CompositeDisposable(
      atom.config.observe('minimap-codeglance.numberOfLines', numberOfLines =>
        this.numberOfLines = numberOfLines
      ),
      atom.config.observe('minimap-codeglance.showLineNumbers', showLineNumbers =>
        showLineNumbers ? this.element.showLineNumbers() : this.element.hideLineNumbers()
      ),
      atom.config.observe('minimap-codeglance.codeHighlighting', codeHighlighting =>
        this.codeHighlighting = codeHighlighting
      ),
      atom.config.observe('minimap-codeglance.softWrap', softWrapMode =>
        this.softWrapMode = softWrapMode
      ),
    );
  },

  destroy() {
    this.detachElement();
    this.element.destroy();
    this.disposables.dispose();
    [this.element, this.disposables, this.minimap] = [];
  },

  disabled: false,

  disableDuringMouseDown() {
    if(this.disabled) return;
    this.disabled = true;
    this.detachElement();
    addEventListenerOnce(document.body, 'mouseup', () => {
      this.disabled = false;
      this.attachElement();
      this.element.hide();
    });
  },

  addMinimap(minimap) {
    var minimapView = atom.views.getView(minimap);

    var minimapDisposable = new CompositeDisposable(
      atom.workspace.observeActivePaneItem(paneItem => {
        if(paneItem == minimap.getTextEditor()) {
          this.setCurrentMinimap(minimap);
          this.element.hide();
        }
      }),
      addEventListener(minimapView, 'mouseenter', () =>
        this.setCurrentMinimap(minimap)
      ),
      addEventListener(minimapView, 'mousemove', event =>
        this.scrollToMousePosition(event)
      ),
      addEventListener(minimapView, 'mouseleave', () =>
        this.detachElement()
      ),
      addEventListener(minimapView, 'mousedown', () =>
        this.disableDuringMouseDown()
      ),
      addEventListener(atom.views.getView(minimap.getTextEditor()), 'mousedown', () =>
        this.disableDuringMouseDown()
      ),
      minimap.onDidDestroy(() => {
        this.disposables.remove(minimapDisposable);
        minimapDisposable.dispose();
        minimapDisposable = null;
      }),
    );

    this.disposables.add(minimapDisposable);
  },

  setCurrentMinimap(minimap) {
    this.minimap = minimap;
    this.attachElement();
    this.updateNumberOfLines();
    this.updateSoftWrapped();

    if(this.getTextEditor().getText() == this.element.getText()) return;

    this.element.setText('');
    this.updateGrammar();
    this.updateText();
  },

  getTextEditor() {
    return this.minimap.getTextEditor();
  },

  getTextEditorRoot() {
    var textEditorView = atom.views.getView(this.getTextEditor());
    return textEditorView.shadowRoot || textEditorView;
  },

  attachElement() {
    var textEditorRoot = this.getTextEditorRoot();
    textEditorRoot.querySelector('.editor-contents--private').appendChild(this.element);
  },

  detachElement() {
    this.element.remove();
  },

  updateNumberOfLines() {
    this.element.setNumberOfLines(this.numberOfLines);
  },

  updateSoftWrapped() {
    this.element.setSoftWrapped(this.getSoftWrapped());
  },

  getSoftWrapped() {
    switch(this.softWrapMode.split(' ')[0]) {
      default:
      case 'editor':
        return this.getTextEditor().isSoftWrapped();
      case 'always':
        return true;
      case 'never':
        return false;
    }
  },

  updateGrammar() {
    this.element.setGrammar(
      this.codeHighlighting ?
        this.getTextEditor().getGrammar() :
        atom.grammars.grammarForScopeName('text.plain.null-grammar')
    );
  },

  updateText() {
    this.element.setText(this.getTextEditor().getText());
  },

  scrollToMousePosition({offsetX, offsetY}) {
    if(this.disabled || !this.minimap) return;
    var screenPosition = this.screenPositionForOffset({offsetX, offsetY});

    if(screenPosition.row > this.getTextEditor().getLastScreenRow()) {
      return void this.element.hide();
    }

    this.element.show();
    this.element.scrollToBufferPosition(
      this.getTextEditor().bufferPositionForScreenPosition(screenPosition)
    );
    this.element.translateY(offsetY);
  },

  screenPositionForOffset({offsetX, offsetY}) {
    var firstVisibleScreenRow = this.minimap.getFirstVisibleScreenRow();
    var lineHeight = this.minimap.charHeight + this.minimap.interline;
    var row = firstVisibleScreenRow + Math.floor(offsetY / lineHeight);
    var columnWidth = this.minimap.charWidth;
    var column = Math.floor(offsetX / columnWidth);
    return new Point(row, column);
  },
};

export default function minimapCodeglance() {
  return Object.create(prototype);
}
<|endoftext|>


<commit_before>/**************************************
 *
 *   Module for generating
 *   random passwords
 *
 *   Created by
 *   Aleksandr Filatov (c)
 *
 * ***********************************/
var Password = (function() {

	var _digits              = "0123456789";
	var _alphabet            = "abcdefghijklmnopqrstuvwxyz";
	var _alphabetCapitalized = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	var _spec                = "-_!@#$%^&*()+/{[]}|\;:'<>?";

	var _randInt = function(min, max){
		return Math.floor(Math.random() * (max - min + 1)) + min;
	};

	var _agregateChars = function(useDigits, useAlphabet, useAlphabetCapitalized, useSpec) {
		var chars = "";

		if (useDigits)
			chars += _digits;
		if (useAlphabet)
			chars += _alphabet;
		if (useAlphabetCapitalized)
			chars += _alphabetCapitalized;
		if (useSpec)
			chars += _spec;

		return chars;
	};

	/***************************************
	*   Private method
	*   for generating random one password
	* *************************************/
	var _generateOne = function(config, chars) {
		var password = "";

		for(var i = 0; i < config.length; i++){
			// generate a random position in
			// possible character string
			var randomPos = _randInt(0, chars.length - 1);

			// get the char at this position from
			// possible character string
			var c = chars.charAt(randomPos);

			// append character to already
			// generated string
			password += c;
		}

		// return the password
		return password;
	};

	return {

		/***************************************
		*    Common config settings
		* *************************************/
		config: {
			useDigits 				: true,
			useAlphabet 			: true,
			useAlphabetCapitalized  : true,
			useSpec 				: true,

			numberOfPasswords 		: 1,
			length 					: 5
		},

		/***************************************
		*    Public common method
		*    for generating passwords
		* *************************************/
		generate: function(){
			var config = this.config;

			var chars = _agregateChars(
				config.useDigits,
				config.useAlphabet,
				config.useAlphabetCapitalized,
				config.useSpec
			);

			var passwordArray = [];
			for (i = 0; i < config.numberOfPasswords; i++) {
				passwordArray.push({
						"key"  : i,
						"pass" : _generateOne(config, chars)
					}
				);
			}

			return JSON.stringify(passwordArray);
		}
	}
}());

<commit_msg>fix spaces<commit_after>/**************************************
 *
 *   Module for generating
 *   random passwords
 *
 *   Created by
 *   Aleksandr Filatov (c)
 *
 * ***********************************/
var Password = (function() {

	var _digits              = "0123456789";
	var _alphabet            = "abcdefghijklmnopqrstuvwxyz";
	var _alphabetCapitalized = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	var _spec                = "-_!@#$%^&*()+/{[]}|\;:'<>?";

	var _randInt = function(min, max){
		return Math.floor(Math.random() * (max - min + 1)) + min;
	};

	var _agregateChars = function(useDigits, useAlphabet, useAlphabetCapitalized, useSpec) {
		var chars = "";

		if (useDigits)
			chars += _digits;
		if (useAlphabet)
			chars += _alphabet;
		if (useAlphabetCapitalized)
			chars += _alphabetCapitalized;
		if (useSpec)
			chars += _spec;

		return chars;
	};

	/***************************************
	*   Private method
	*   for generating random one password
	* *************************************/
	var _generateOne = function(config, chars) {
		var password = "";

		for(var i = 0; i < config.length; i++){
			// generate a random position in
			// possible character string
			var randomPos = _randInt(0, chars.length - 1);

			// get the char at this position from
			// possible character string
			var c = chars.charAt(randomPos);

			// append character to already
			// generated string
			password += c;
		}

		// return the password
		return password;
	};

	return {

		/***************************************
		*    Common config settings
		* *************************************/
		config: {
			useDigits               : true,
			useAlphabet             : true,
			useAlphabetCapitalized  : true,
			useSpec 				: true,

			numberOfPasswords       : 1,
			length                  : 5
		},

		/***************************************
		*    Public common method
		*    for generating passwords
		* *************************************/
		generate: function(){
			var config = this.config;

			var chars = _agregateChars(
				config.useDigits,
				config.useAlphabet,
				config.useAlphabetCapitalized,
				config.useSpec
			);

			var passwordArray = [];
			for (i = 0; i < config.numberOfPasswords; i++) {
				passwordArray.push({
						"key"  : i,
						"pass" : _generateOne(config, chars)
					}
				);
			}

			return JSON.stringify(passwordArray);
		}
	}
}());

<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var passport = require('passport'),
	SamlStrategy = require('passport-saml').Strategy,
  fs = require('fs'),
	User = require('mongoose').model('User'),
  pvk = fs.readFileSync('./config/keys/mykey.key', 'utf-8');

// Set in global scope, so it can be used again for the metadata route
global.SAMLStrategy = new SamlStrategy({
      path: '/login/callback',
      entryPoint: 'https://engine.surfconext.nl/authentication/idp/single-sign-on',
      issuer: 'https://goalsetting.ihatestatistics.com/metadata',
      decryptionPvk: pvk,
      cert: 'MIID3zCCAsegAwIBAgIJAMVC9xn1ZfsuMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYDVQQGEwJOTDEQMA4GA1UECAwHVXRyZWNodDEQMA4GA1UEBwwHVXRyZWNodDEVMBMGA1UECgwMU1VSRm5ldCBCLlYuMRMwEQYDVQQLDApTVVJGY29uZXh0MSYwJAYDVQQDDB1lbmdpbmUuc3VyZmNvbmV4dC5ubCAyMDE0MDUwNTAeFw0xNDA1MDUxNDIyMzVaFw0xOTA1MDUxNDIyMzVaMIGFMQswCQYDVQQGEwJOTDEQMA4GA1UECAwHVXRyZWNodDEQMA4GA1UEBwwHVXRyZWNodDEVMBMGA1UECgwMU1VSRm5ldCBCLlYuMRMwEQYDVQQLDApTVVJGY29uZXh0MSYwJAYDVQQDDB1lbmdpbmUuc3VyZmNvbmV4dC5ubCAyMDE0MDUwNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKthMDbB0jKHefPzmRu9t2h7iLP4wAXr42bHpjzTEk6gttHFb4l/hFiz1YBI88TjiH6hVjnozo/YHA2c51us+Y7g0XoS7653lbUN/EHzvDMuyis4Xi2Ijf1A/OUQfH1iFUWttIgtWK9+fatXoGUS6tirQvrzVh6ZstEp1xbpo1SF6UoVl+fh7tM81qz+Crr/Kroan0UjpZOFTwxPoK6fdLgMAieKSCRmBGpbJHbQ2xxbdykBBrBbdfzIX4CDepfjE9h/40ldw5jRn3e392jrS6htk23N9BWWrpBT5QCk0kH3h/6F1Dm6TkyG9CDtt73/anuRkvXbeygI4wml9bL3rE8CAwEAAaNQME4wHQYDVR0OBBYEFD+Ac7akFxaMhBQAjVfvgGfY8hNKMB8GA1UdIwQYMBaAFD+Ac7akFxaMhBQAjVfvgGfY8hNKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAC8L9D67CxIhGo5aGVu63WqRHBNOdo/FAGI7LURDFeRmG5nRw/VXzJLGJksh4FSkx7aPrxNWF1uFiDZ80EuYQuIv7bDLblK31ZEbdg1R9LgiZCdYSr464I7yXQY9o6FiNtSKZkQO8EsscJPPy/Zp4uHAnADWACkOUHiCbcKiUUFu66dX0Wr/v53Gekz487GgVRs8HEeT9MU1reBKRgdENR8PNg4rbQfLc3YQKLWK7yWnn/RenjDpuCiePj8N8/80tGgrNgK/6fzM3zI18sSywnXLswxqDb/J+jgVxnQ6MrsTf1urM8MnfcxG/82oHIwfMh/sXPCZpo+DTLkhQxctJ3M=',
      identifierFormat: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
      callbackUrl: 'https://goalsetting.ihatestatistics.com/login/callback'
    },
    function(profile, done) {
      User.findOne({
        studentNumber: profile.studentNumber
      }, function(err, user) {
        if (err) {
          return done(err);
        }
        if (!user) {
          return done(null, false, {
            message: 'Unknown user or invalid password'
          });
        }
        if (!user.authenticate(profile.password)) {
          return done(null, false, {
            message: 'Unknown user or invalid password'
          });
        }

        return done(null, user);
      });
    }
);

module.exports = function() {
  var samlStrategy = global.SAMLStrategy;

  // Use SAML strategy for Surfconext
  passport.use(samlStrategy);
};<commit_msg>Changed issuer back to old value, else surfconext doesnt recognize service<commit_after>'use strict';

/**
 * Module dependencies.
 */
var passport = require('passport'),
	SamlStrategy = require('passport-saml').Strategy,
  fs = require('fs'),
	User = require('mongoose').model('User'),
  pvk = fs.readFileSync('./config/keys/mykey.key', 'utf-8');

// Set in global scope, so it can be used again for the metadata route
global.SAMLStrategy = new SamlStrategy({
      path: '/login/callback',
      entryPoint: 'https://engine.surfconext.nl/authentication/idp/single-sign-on',
      issuer: 'goalsetting.ihatestatistics.com',
      decryptionPvk: pvk,
      cert: 'MIID3zCCAsegAwIBAgIJAMVC9xn1ZfsuMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYDVQQGEwJOTDEQMA4GA1UECAwHVXRyZWNodDEQMA4GA1UEBwwHVXRyZWNodDEVMBMGA1UECgwMU1VSRm5ldCBCLlYuMRMwEQYDVQQLDApTVVJGY29uZXh0MSYwJAYDVQQDDB1lbmdpbmUuc3VyZmNvbmV4dC5ubCAyMDE0MDUwNTAeFw0xNDA1MDUxNDIyMzVaFw0xOTA1MDUxNDIyMzVaMIGFMQswCQYDVQQGEwJOTDEQMA4GA1UECAwHVXRyZWNodDEQMA4GA1UEBwwHVXRyZWNodDEVMBMGA1UECgwMU1VSRm5ldCBCLlYuMRMwEQYDVQQLDApTVVJGY29uZXh0MSYwJAYDVQQDDB1lbmdpbmUuc3VyZmNvbmV4dC5ubCAyMDE0MDUwNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKthMDbB0jKHefPzmRu9t2h7iLP4wAXr42bHpjzTEk6gttHFb4l/hFiz1YBI88TjiH6hVjnozo/YHA2c51us+Y7g0XoS7653lbUN/EHzvDMuyis4Xi2Ijf1A/OUQfH1iFUWttIgtWK9+fatXoGUS6tirQvrzVh6ZstEp1xbpo1SF6UoVl+fh7tM81qz+Crr/Kroan0UjpZOFTwxPoK6fdLgMAieKSCRmBGpbJHbQ2xxbdykBBrBbdfzIX4CDepfjE9h/40ldw5jRn3e392jrS6htk23N9BWWrpBT5QCk0kH3h/6F1Dm6TkyG9CDtt73/anuRkvXbeygI4wml9bL3rE8CAwEAAaNQME4wHQYDVR0OBBYEFD+Ac7akFxaMhBQAjVfvgGfY8hNKMB8GA1UdIwQYMBaAFD+Ac7akFxaMhBQAjVfvgGfY8hNKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAC8L9D67CxIhGo5aGVu63WqRHBNOdo/FAGI7LURDFeRmG5nRw/VXzJLGJksh4FSkx7aPrxNWF1uFiDZ80EuYQuIv7bDLblK31ZEbdg1R9LgiZCdYSr464I7yXQY9o6FiNtSKZkQO8EsscJPPy/Zp4uHAnADWACkOUHiCbcKiUUFu66dX0Wr/v53Gekz487GgVRs8HEeT9MU1reBKRgdENR8PNg4rbQfLc3YQKLWK7yWnn/RenjDpuCiePj8N8/80tGgrNgK/6fzM3zI18sSywnXLswxqDb/J+jgVxnQ6MrsTf1urM8MnfcxG/82oHIwfMh/sXPCZpo+DTLkhQxctJ3M=',
      identifierFormat: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
      callbackUrl: 'https://goalsetting.ihatestatistics.com/login/callback'
    },
    function(profile, done) {
      User.findOne({
        studentNumber: profile.studentNumber
      }, function(err, user) {
        if (err) {
          return done(err);
        }
        if (!user) {
          return done(null, false, {
            message: 'Unknown user or invalid password'
          });
        }
        if (!user.authenticate(profile.password)) {
          return done(null, false, {
            message: 'Unknown user or invalid password'
          });
        }

        return done(null, user);
      });
    }
);

module.exports = function() {
  var samlStrategy = global.SAMLStrategy;

  // Use SAML strategy for Surfconext
  passport.use(samlStrategy);
};<|endoftext|>


<commit_before>var portal = angular.module('portal', [
  'ngAnimate',
  'ngRoute',
  'templates',
  'restangular',
  'portal.config',
  'portal.services',
  'portal.directives',
  'portal.controllers',
  'portal.home',
  'portal.levels',
  'portal.organizations',
  'portal.users',
  'portal.news',
  'portal.crud'
  ]);

portal.config(function($locationProvider, $urlRouterProvider, RestangularProvider, ApiConfig) {

  $locationProvider.html5Mode(ApiConfig.html5Mode);
  $urlRouterProvider.otherwise('/');

  if (ApiConfig.port)
    ApiConfig.endpoint = '//'+document.domain+':'+ApiConfig.port;

  RestangularProvider.setBaseUrl(ApiConfig.endpoint);

  RestangularProvider.setRestangularFields({
    id: "_id"
  });

  RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {

    if (operation == 'getList') {
      if (what == '/')
        data._items = data._links.child;
      data._items.meta = data._meta;
      return data._items;
    }
    return response;

  });

  RestangularProvider.addFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) {

    if (operation == 'patch') {
      headers['If-Match'] = element._etag;
      delete element._etag;
    }

    return {
      element: element,
      headers: headers,
      params: params,
      httpConfig: httpConfig
    };

  });

});

portal.run(function ($rootScope, CurrentUserService, Restangular) {

  $rootScope.$on('$stateChangeStart', function (event, toState) {
    $rootScope.state = toState.name;
  });

  $rootScope.setCurrentUser = function(user) {
    $rootScope.currentUser = user;
  };

  CurrentUserService.restore().then(function(user) {

    $rootScope.setCurrentUser(user);

    if (CurrentUserService.isAuthentificated()) {
      var token = CurrentUserService.getAuthToken();
      var basic = 'Basic '+window.btoa(token+':');

      Restangular.setDefaultHeaders({ Authorization: basic });

      //FIX ME: LoadUserInfo should not require argument
      CurrentUserService.loadUserInfo(user.user._id).then(function(user) {
        $rootScope.setCurrentUser(user);
      });
    }

  });

});
<commit_msg>WIP of client side access control<commit_after>var portal = angular.module('portal', [
  'ngAnimate',
  'ngRoute',
  'templates',
  'restangular',
  'portal.config',
  'portal.services',
  'portal.directives',
  'portal.controllers',
  'portal.home',
  'portal.levels',
  'portal.organizations',
  'portal.users',
  'portal.news',
  'portal.crud'
  ]);

portal.config(function($locationProvider, $urlRouterProvider, RestangularProvider, ApiConfig) {

  $locationProvider.html5Mode(ApiConfig.html5Mode);
  $urlRouterProvider.otherwise('/');

  if (ApiConfig.port)
    ApiConfig.endpoint = '//'+document.domain+':'+ApiConfig.port;

  RestangularProvider.setBaseUrl(ApiConfig.endpoint);

  RestangularProvider.setRestangularFields({
    id: "_id"
  });

  RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {

    if (operation == 'getList') {
      if (what == '/')
        data._items = data._links.child;
      data._items.meta = data._meta;
      return data._items;
    }
    return response;

  });

  RestangularProvider.addFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) {

    if (operation == 'patch') {
      headers['If-Match'] = element._etag;
      delete element._etag;
    }

    return {
      element: element,
      headers: headers,
      params: params,
      httpConfig: httpConfig
    };

  });

});

portal.run(function ($rootScope, $location, $state, CurrentUserService, Restangular) {

  $rootScope.setCurrentUser = function(user) {
    $rootScope.currentUser = user;
  };

  CurrentUserService.restore().then(function(user) {

    $rootScope.setCurrentUser(user);

    if (CurrentUserService.isAuthentificated()) {
      var token = CurrentUserService.getAuthToken();
      var basic = 'Basic '+window.btoa(token+':');

      Restangular.setDefaultHeaders({ Authorization: basic });

      //FIX ME: LoadUserInfo should not require argument
      CurrentUserService.loadUserInfo(user.user._id).then(function(user) {
        $rootScope.setCurrentUser(user);
      });
    }

  });

  $rootScope.$on('$stateChangeStart', function (event, toState) {
    $rootScope.state = toState.name;

    // TODO: State Based access definition
    if (toState.name != 'login' && !CurrentUserService.isAuthentificated()) {
      event.preventDefault();
      $state.transitionTo('login');
    }
  });

});
<|endoftext|>


<commit_before>// Copyright (c) 2020, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Number Card', {
	refresh: function(frm) {
		if (!frappe.boot.developer_mode && frm.doc.is_standard) {
			frm.disable_form();
		}
		frm.set_df_property("filters_section", "hidden", 1);
		frm.set_df_property("dynamic_filters_section", "hidden", 1);
		frm.trigger('set_options');

		if (!frm.doc.type) {
			frm.set_value('type', 'Document Type');
		}

		if (frm.doc.type == 'Report' && frm.doc.report_name) {
			frm.trigger('set_report_filters');
		}

		if (frm.doc.type == 'Custom') {
			if (!frappe.boot.developer_mode) {
				frm.disable_form();
			}
			frm.filters = eval(frm.doc.filters_config);
			frm.trigger('set_filters_description');
		}
	},

	before_save: function(frm) {
		let dynamic_filters = JSON.parse(frm.doc.dynamic_filters_json || 'null');
		let static_filters = JSON.parse(frm.doc.filters_json || 'null');
		static_filters =
			frappe.dashboard_utils.remove_common_static_filter_values(static_filters, dynamic_filters);

		frm.set_value('filters_json', JSON.stringify(static_filters));
		frm.trigger('render_filters_table');
	},

	is_standard: function(frm) {
		frm.trigger('render_dynamic_filters_table');
		frm.set_df_property("dynamic_filters_section", "hidden", 1);
	},

	set_filters_description: function(frm) {
		if (frm.doc.type == 'Custom') {
			frm.fields_dict.filters_config.set_description(`
		Set the filters here. For example:

[{
	fieldname: "company",
	label: __("Company"),
	fieldtype: "Link",
	options: "Company",
	default: frappe.defaults.get_user_default("Company"),
	reqd: 1
},
{
	fieldname: "account",
	label: __("Account"),
	fieldtype: "Link",
	options: "Account",
	reqd: 1
}]

`);
		}
	},

	type: function(frm) {
		frm.trigger('set_filters_description');
		if (frm.doc.type == 'Report') {
			frm.set_query('report_name', () => {
				return {
					filters: {
						'report_type': ['!=', 'Report Builder']
					}
				};
			});
		}

	},

	report_name: function(frm) {
		frm.set_value('filters_json', '{}');
		frm.set_value('dynamic_filters_json', '{}');
		frm.set_df_property('report_field', 'options', []);
		frm.trigger('set_report_filters');
	},

	filters_config: function(frm) {
		frm.filters = eval(frm.doc.filters_config);
		const filter_values = frappe.report_utils.get_filter_values(frm.filters);
		frm.set_value('filters_json', JSON.stringify(filter_values));
		frm.trigger('render_filters_table');
	},

	document_type: function(frm) {
		frm.set_query('document_type', function() {
			return {
				filters: {
					'issingle': false
				}
			};
		});
		frm.set_value('filters_json', '[]');
		frm.set_value('dynamic_filters_json', '[]');
		frm.set_value('aggregate_function_based_on', '');
		frm.trigger('set_options');
	},

	set_options: function(frm) {
		if (frm.doc.type !== 'Document Type') {
			return;
		}

		let aggregate_based_on_fields = [];
		const doctype = frm.doc.document_type;

		if (doctype) {
			frappe.model.with_doctype(doctype, () => {
				frappe.get_meta(doctype).fields.map(df => {
					if (frappe.model.numeric_fieldtypes.includes(df.fieldtype)) {
						if (df.fieldtype == 'Currency') {
							if (!df.options || df.options !== 'Company:company:default_currency') {
								return;
							}
						}
						aggregate_based_on_fields.push({label: df.label, value: df.fieldname});
					}
				});

				frm.set_df_property('aggregate_function_based_on', 'options', aggregate_based_on_fields);
			});
			frm.trigger('render_filters_table');
		}
	},

	set_report_filters: function(frm) {
		const report_name = frm.doc.report_name;
		if (report_name) {
			frappe.report_utils.get_report_filters(report_name).then(filters => {
				if (filters) {
					frm.filters = filters;
					const filter_values = frappe.report_utils.get_filter_values(filters);
					if (frm.doc.filters_json.length <= 2) {
						frm.set_value('filters_json', JSON.stringify(filter_values));
					}
				}
				frm.trigger('render_filters_table');
				frm.trigger('set_report_field_options');
				frm.trigger('render_dynamic_filters_table');
			});
		}
	},

	set_report_field_options: function(frm) {
		let filters = frm.doc.filters_json.length > 2 ? JSON.parse(frm.doc.filters_json) : null;
		frappe.xcall(
			'frappe.desk.query_report.run',
			{
				report_name: frm.doc.report_name,
				filters: filters,
				ignore_prepared_report: 1
			}
		).then(data => {
			if (data.result.length) {
				frm.field_options = frappe.report_utils.get_field_options_from_report(data.columns, data);
				frm.set_df_property('report_field', 'options', frm.field_options.numeric_fields);
				if (!frm.field_options.numeric_fields.length) {
					frappe.msgprint(__(`Report has no numeric fields, please change the Report Name`));
				}
			} else {
				frappe.msgprint(__('Report has no data, please modify the filters or change the Report Name'));
			}
		});
	},

	render_filters_table: function(frm) {
		frm.set_df_property("filters_section", "hidden", 0);
		let is_document_type = frm.doc.type == 'Document Type';
		let is_dynamic_filter = f => ['Date', 'DateRange'].includes(f.fieldtype) && f.default;

		let wrapper = $(frm.get_field('filters_json').wrapper).empty();
		let table = $(`

					${__('Filter')}
					${__('Condition')}
					${__('Value')}

`).appendTo(wrapper);
		$(`<p class="text-muted small">${__("Click table to edit")}</p>`).appendTo(wrapper);

		let filters = JSON.parse(frm.doc.filters_json || '[]');
		let filters_set = false;

		// Set dynamic filters for reports
		if (frm.doc.type == 'Report') {
			let set_filters = false;
			frm.filters.forEach(f => {
				if (is_dynamic_filter(f)) {
					filters[f.fieldname] = f.default;
					set_filters = true;
				}
			});
			set_filters && frm.set_value('filters_json', JSON.stringify(filters));
		}

		let fields;
		if (is_document_type) {
			fields = [
				{
					fieldtype: 'HTML',
					fieldname: 'filter_area',
				}
			];

			if (filters.length) {
				filters.forEach(filter => {
					const filter_row =
						$(`

							${filter[1]}
							${filter[2] || ""}
							${filter[3]}

`);

					table.find('tbody').append(filter_row);
				});
				filters_set = true;
			}
		} else if (frm.filters.length) {
			filters_set = true;
			fields = frm.filters.filter(f => f.fieldname);
			fields.map(f => {
				if (filters[f.fieldname]) {
					let condition = '=';
					const filter_row =
						$(`

							${f.label}
							${condition}
							${filters[f.fieldname] || ""}

`);

					table.find('tbody').append(filter_row);
				}
			});
		}

		if (!filters_set) {
			const filter_row = $(`

				${__("Click to Set Filters")}
`);
			table.find('tbody').append(filter_row);
		}

		table.on('click', () => {
			let dialog = new frappe.ui.Dialog({
				title: __('Set Filters'),
				fields: fields.filter(f => !is_dynamic_filter(f)),
				primary_action: function() {
					let values = this.get_values();
					if (values) {
						this.hide();
						if (is_document_type) {
							let filters = frm.filter_group.get_filters();
							frm.set_value('filters_json', JSON.stringify(filters));
						} else {
							frm.set_value('filters_json', JSON.stringify(values));
						}
						frm.trigger('render_filters_table');
					}
				},
				primary_action_label: "Set"
			});

			if (is_document_type) {
				frm.filter_group = new frappe.ui.FilterGroup({
					parent: dialog.get_field('filter_area').$wrapper,
					doctype: frm.doc.document_type,
					on_change: () => {},
				});
				filters && frm.filter_group.add_filters_to_filter_group(filters);
			}

			dialog.show();

			if (frm.doc.type == 'Report') {
				//Set query report object so that it can be used while fetching filter values in the report
				frappe.query_report = new frappe.views.QueryReport({'filters': dialog.fields_list});
				frappe.query_reports[frm.doc.report_name]
					&& frappe.query_reports[frm.doc.report_name].onload
						&& frappe.query_reports[frm.doc.report_name].onload(frappe.query_report);
			}

			dialog.set_values(filters);
		});

	},

	render_dynamic_filters_table(frm) {
		if (!frappe.boot.developer_mode || !frm.doc.is_standard) {
			return
		}

		frm.set_df_property("dynamic_filters_section", "hidden", 0);

		let is_document_type = frm.doc.type == 'Document Type';

		let wrapper = $(frm.get_field('dynamic_filters_json').wrapper).empty();

		frm.dynamic_filter_table = $(`

					${__('Filter')}
					${__('Condition')}
					${__('Value')}

`).appendTo(wrapper);

		frm.dynamic_filters = frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2
			? JSON.parse(frm.doc.dynamic_filters_json)
			: null;

		frm.trigger('set_dynamic_filters_in_table');

		let filters = JSON.parse(frm.doc.filters_json || '[]');

		let fields = frappe.dashboard_utils.get_fields_for_dynamic_filter_dialog(
			is_document_type, filters, frm.dynamic_filters
		);

		frm.dynamic_filter_table.on('click', () => {
			let dialog = new frappe.ui.Dialog({
				title: __('Set Dynamic Filters'),
				fields: fields,
				primary_action: () => {
					let values = dialog.get_values();
					dialog.hide();
					let dynamic_filters = [];
					for (let key of Object.keys(values)) {
						if (is_document_type) {
							let [doctype, fieldname] = key.split(':');
							dynamic_filters.push([doctype, fieldname, '=', values[key]]);
						}
					}

					if (is_document_type) {
						frm.set_value('dynamic_filters_json', JSON.stringify(dynamic_filters));
					} else {
						frm.set_value('dynamic_filters_json', JSON.stringify(values));
					}
					frm.trigger('set_dynamic_filters_in_table');
				},
				primary_action_label: "Set"
			});

			dialog.show();
			dialog.set_values(frm.dynamic_filters);
		});
	},

	set_dynamic_filters_in_table: function(frm) {
		frm.dynamic_filters =  frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2
			? JSON.parse(frm.doc.dynamic_filters_json)
			: null;

		if (!frm.dynamic_filters) {
			const filter_row = $(`

				${__("Click to Set Dynamic Filters")}
`);
			frm.dynamic_filter_table.find('tbody').html(filter_row);
		} else {
			let filter_rows = '';
			if ($.isArray(frm.dynamic_filters)) {
				frm.dynamic_filters.forEach(filter => {
					filter_rows +=
						`

							${filter[1]}
							${filter[2] || ""}
							${filter[3]}

`;
				});
			} else {
				let condition = '=';
				for (let [key, val] of Object.entries(frm.dynamic_filters)) {
					filter_rows +=
						`

							${key}
							${condition}
							${val || ""}

`
					;
				}
			}

			frm.dynamic_filter_table.find('tbody').html(filter_rows);
		}
	}

});
<commit_msg>feat: add to dashboard button in number card form<commit_after>// Copyright (c) 2020, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Number Card', {
	refresh: function(frm) {
		if (!frappe.boot.developer_mode && frm.doc.is_standard) {
			frm.disable_form();
		}
		frm.set_df_property("filters_section", "hidden", 1);
		frm.set_df_property("dynamic_filters_section", "hidden", 1);
		frm.trigger('set_options');

		if (!frm.doc.type) {
			frm.set_value('type', 'Document Type');
		}

		if (frm.doc.type == 'Report' && frm.doc.report_name) {
			frm.trigger('set_report_filters');
		}

		if (frm.doc.type == 'Custom') {
			if (!frappe.boot.developer_mode) {
				frm.disable_form();
			}
			frm.filters = eval(frm.doc.filters_config);
			frm.trigger('set_filters_description');
		}
		frm.trigger('create_add_to_dashboard_button');
	},

	create_add_to_dashboard_button: function(frm) {
		frm.add_custom_button('Add Card to Dashboard', () => {
			const d = new frappe.ui.Dialog({
				title: __('Add to Dashboard'),
				fields: [
					{
						label: __('Select Dashboard'),
						fieldtype: 'Link',
						fieldname: 'dashboard',
						options: 'Dashboard',
					}
				],
				primary_action: (values) => {
					values.name = frm.doc.name;
					frappe.xcall(
						'frappe.desk.doctype.number_card.number_card.add_card_to_dashboard',
						{
							args: values
						}
					).then(()=> {
						let dashboard_route_html =
							`<a href = "#dashboard/${values.dashboard}">${values.dashboard}</a>`;
						let message =
							__(`Number Card ${values.name} add to Dashboard ` + dashboard_route_html);

						frappe.msgprint(message);
					});

					d.hide();
				}
			});

			if (!frm.doc.name) {
				frappe.msgprint(__('Please create Card first'));
			} else {
				d.show();
			}
		});
	},

	before_save: function(frm) {
		let dynamic_filters = JSON.parse(frm.doc.dynamic_filters_json || 'null');
		let static_filters = JSON.parse(frm.doc.filters_json || 'null');
		static_filters =
			frappe.dashboard_utils.remove_common_static_filter_values(static_filters, dynamic_filters);

		frm.set_value('filters_json', JSON.stringify(static_filters));
		frm.trigger('render_filters_table');
		frm.trigger('render_dynamic_filters_table');
	},

	is_standard: function(frm) {
		frm.trigger('render_dynamic_filters_table');
		frm.set_df_property("dynamic_filters_section", "hidden", 1);
	},

	set_filters_description: function(frm) {
		if (frm.doc.type == 'Custom') {
			frm.fields_dict.filters_config.set_description(`
		Set the filters here. For example:

[{
	fieldname: "company",
	label: __("Company"),
	fieldtype: "Link",
	options: "Company",
	default: frappe.defaults.get_user_default("Company"),
	reqd: 1
},
{
	fieldname: "account",
	label: __("Account"),
	fieldtype: "Link",
	options: "Account",
	reqd: 1
}]

`);
		}
	},

	type: function(frm) {
		frm.trigger('set_filters_description');
		if (frm.doc.type == 'Report') {
			frm.set_query('report_name', () => {
				return {
					filters: {
						'report_type': ['!=', 'Report Builder']
					}
				};
			});
		}

	},

	report_name: function(frm) {
		frm.set_value('filters_json', '{}');
		frm.set_value('dynamic_filters_json', '{}');
		frm.set_df_property('report_field', 'options', []);
		frm.trigger('set_report_filters');
	},

	filters_config: function(frm) {
		frm.filters = eval(frm.doc.filters_config);
		const filter_values = frappe.report_utils.get_filter_values(frm.filters);
		frm.set_value('filters_json', JSON.stringify(filter_values));
		frm.trigger('render_filters_table');
	},

	document_type: function(frm) {
		frm.set_query('document_type', function() {
			return {
				filters: {
					'issingle': false
				}
			};
		});
		frm.set_value('filters_json', '[]');
		frm.set_value('dynamic_filters_json', '[]');
		frm.set_value('aggregate_function_based_on', '');
		frm.trigger('set_options');
	},

	set_options: function(frm) {
		if (frm.doc.type !== 'Document Type') {
			return;
		}

		let aggregate_based_on_fields = [];
		const doctype = frm.doc.document_type;

		if (doctype) {
			frappe.model.with_doctype(doctype, () => {
				frappe.get_meta(doctype).fields.map(df => {
					if (frappe.model.numeric_fieldtypes.includes(df.fieldtype)) {
						if (df.fieldtype == 'Currency') {
							if (!df.options || df.options !== 'Company:company:default_currency') {
								return;
							}
						}
						aggregate_based_on_fields.push({label: df.label, value: df.fieldname});
					}
				});

				frm.set_df_property('aggregate_function_based_on', 'options', aggregate_based_on_fields);
			});
			frm.trigger('render_filters_table');
			frm.trigger('render_dynamic_filters_table');
		}
	},

	set_report_filters: function(frm) {
		const report_name = frm.doc.report_name;
		if (report_name) {
			frappe.report_utils.get_report_filters(report_name).then(filters => {
				if (filters) {
					frm.filters = filters;
					const filter_values = frappe.report_utils.get_filter_values(filters);
					if (frm.doc.filters_json.length <= 2) {
						frm.set_value('filters_json', JSON.stringify(filter_values));
					}
				}
				frm.trigger('render_filters_table');
				frm.trigger('set_report_field_options');
				frm.trigger('render_dynamic_filters_table');
			});
		}
	},

	set_report_field_options: function(frm) {
		let filters = frm.doc.filters_json.length > 2 ? JSON.parse(frm.doc.filters_json) : null;
		if (frm.doc.dynamic_filters_json.length > 2) {
			filters = {...filters, ...JSON.parse(frm.doc.dynamic_filters_json)};
		}
		frappe.xcall(
			'frappe.desk.query_report.run',
			{
				report_name: frm.doc.report_name,
				filters: filters,
				ignore_prepared_report: 1
			}
		).then(data => {
			if (data.result.length) {
				frm.field_options = frappe.report_utils.get_field_options_from_report(data.columns, data);
				frm.set_df_property('report_field', 'options', frm.field_options.numeric_fields);
				if (!frm.field_options.numeric_fields.length) {
					frappe.msgprint(__(`Report has no numeric fields, please change the Report Name`));
				}
			} else {
				frappe.msgprint(__('Report has no data, please modify the filters or change the Report Name'));
			}
		});
	},

	render_filters_table: function(frm) {
		frm.set_df_property("filters_section", "hidden", 0);
		let is_document_type = frm.doc.type == 'Document Type';
		let is_dynamic_filter = f => ['Date', 'DateRange'].includes(f.fieldtype) && f.default;

		let wrapper = $(frm.get_field('filters_json').wrapper).empty();
		let table = $(`

					${__('Filter')}
					${__('Condition')}
					${__('Value')}

`).appendTo(wrapper);
		$(`<p class="text-muted small">${__("Click table to edit")}</p>`).appendTo(wrapper);

		let filters = JSON.parse(frm.doc.filters_json || '[]');
		let filters_set = false;

		// Set dynamic filters for reports
		if (frm.doc.type == 'Report') {
			let set_filters = false;
			frm.filters.forEach(f => {
				if (is_dynamic_filter(f)) {
					filters[f.fieldname] = f.default;
					set_filters = true;
				}
			});
			set_filters && frm.set_value('filters_json', JSON.stringify(filters));
		}

		let fields;
		if (is_document_type) {
			fields = [
				{
					fieldtype: 'HTML',
					fieldname: 'filter_area',
				}
			];

			if (filters.length) {
				filters.forEach(filter => {
					const filter_row =
						$(`

							${filter[1]}
							${filter[2] || ""}
							${filter[3]}

`);

					table.find('tbody').append(filter_row);
				});
				filters_set = true;
			}
		} else if (frm.filters.length) {
			filters_set = true;
			fields = frm.filters.filter(f => f.fieldname);
			fields.map(f => {
				if (filters[f.fieldname]) {
					let condition = '=';
					const filter_row =
						$(`

							${f.label}
							${condition}
							${filters[f.fieldname] || ""}

`);

					table.find('tbody').append(filter_row);
				}
			});
		}

		if (!filters_set) {
			const filter_row = $(`

				${__("Click to Set Filters")}
`);
			table.find('tbody').append(filter_row);
		}

		table.on('click', () => {
			let dialog = new frappe.ui.Dialog({
				title: __('Set Filters'),
				fields: fields.filter(f => !is_dynamic_filter(f)),
				primary_action: function() {
					let values = this.get_values();
					if (values) {
						this.hide();
						if (is_document_type) {
							let filters = frm.filter_group.get_filters();
							frm.set_value('filters_json', JSON.stringify(filters));
						} else {
							frm.set_value('filters_json', JSON.stringify(values));
						}
						frm.trigger('render_filters_table');
					}
				},
				primary_action_label: "Set"
			});

			if (is_document_type) {
				frm.filter_group = new frappe.ui.FilterGroup({
					parent: dialog.get_field('filter_area').$wrapper,
					doctype: frm.doc.document_type,
					on_change: () => {},
				});
				filters && frm.filter_group.add_filters_to_filter_group(filters);
			}

			dialog.show();

			if (frm.doc.type == 'Report') {
				//Set query report object so that it can be used while fetching filter values in the report
				frappe.query_report = new frappe.views.QueryReport({'filters': dialog.fields_list});
				frappe.query_reports[frm.doc.report_name]
					&& frappe.query_reports[frm.doc.report_name].onload
						&& frappe.query_reports[frm.doc.report_name].onload(frappe.query_report);
			}

			dialog.set_values(filters);
		});

	},

	render_dynamic_filters_table(frm) {
		if (!frappe.boot.developer_mode || !frm.doc.is_standard) {
			return
		}

		frm.set_df_property("dynamic_filters_section", "hidden", 0);

		let is_document_type = frm.doc.type == 'Document Type';

		let wrapper = $(frm.get_field('dynamic_filters_json').wrapper).empty();

		frm.dynamic_filter_table = $(`

					${__('Filter')}
					${__('Condition')}
					${__('Value')}

`).appendTo(wrapper);

		frm.dynamic_filters = frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2
			? JSON.parse(frm.doc.dynamic_filters_json)
			: null;

		frm.trigger('set_dynamic_filters_in_table');

		let filters = JSON.parse(frm.doc.filters_json || '[]');

		let fields = frappe.dashboard_utils.get_fields_for_dynamic_filter_dialog(
			is_document_type, filters, frm.dynamic_filters
		);

		frm.dynamic_filter_table.on('click', () => {
			let dialog = new frappe.ui.Dialog({
				title: __('Set Dynamic Filters'),
				fields: fields,
				primary_action: () => {
					let values = dialog.get_values();
					dialog.hide();
					let dynamic_filters = [];
					for (let key of Object.keys(values)) {
						if (is_document_type) {
							let [doctype, fieldname] = key.split(':');
							dynamic_filters.push([doctype, fieldname, '=', values[key]]);
						}
					}

					if (is_document_type) {
						frm.set_value('dynamic_filters_json', JSON.stringify(dynamic_filters));
					} else {
						frm.set_value('dynamic_filters_json', JSON.stringify(values));
					}
					frm.trigger('set_dynamic_filters_in_table');
				},
				primary_action_label: "Set"
			});

			dialog.show();
			dialog.set_values(frm.dynamic_filters);
		});
	},

	set_dynamic_filters_in_table: function(frm) {
		frm.dynamic_filters =  frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2
			? JSON.parse(frm.doc.dynamic_filters_json)
			: null;

		if (!frm.dynamic_filters) {
			const filter_row = $(`

				${__("Click to Set Dynamic Filters")}
`);
			frm.dynamic_filter_table.find('tbody').html(filter_row);
		} else {
			let filter_rows = '';
			if ($.isArray(frm.dynamic_filters)) {
				frm.dynamic_filters.forEach(filter => {
					filter_rows +=
						`

							${filter[1]}
							${filter[2] || ""}
							${filter[3]}

`;
				});
			} else {
				let condition = '=';
				for (let [key, val] of Object.entries(frm.dynamic_filters)) {
					filter_rows +=
						`

							${key}
							${condition}
							${val || ""}

`
					;
				}
			}

			frm.dynamic_filter_table.find('tbody').html(filter_rows);
		}
	}

});
<|endoftext|>


<commit_before>/*    Copyright 2019-2021 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

'use strict';

const log = require("../../net2/logger.js")(__filename, "info");

const util = require('util');

const f = require('../../net2/Firewalla.js');
const logFolder = f.getLogFolder();

const config = require("../../net2/config.js").getConfig();

const df = util.promisify(require('node-df'))

const os = require('../../vendor_lib/osutils.js');

const exec = require('child-process-promise').exec;
const { execSync } = require('child_process')

const rclient = require('../../util/redis_manager.js').getRedisClient()

const platformLoader = require('../../platform/PlatformLoader.js');
const platform = platformLoader.getPlatform();

const rateLimit = require('../../extension/ratelimit/RateLimit.js');

const fs = require('fs');

let cpuUsage = 0;
let realMemUsage = 0;
let usedMem = 0;
let allMem = 0;
let curTemp = 0;
let peakTemp = 0;

let conn = 0;
let peakConn = 0;

let rateLimitInfo = null;

let redisMemory = 0;

let updateFlag = 0;

let updateInterval = 600 * 1000; // every 10 minutes

let threadInfo = {};

let diskInfo = null;

let ethInfo = {};

let intelQueueSize = 0;

let multiProfileSupport = false;

let no_auto_upgrade = false;

let uptimeInfo = {};
let updateTime = null;

let maxPid = 0;
let activeContainers = 0;

getMultiProfileSupportFlag();

async function update() {
  await Promise.all([
    // this takes 10s
    os.cpuUsage().then((v) => cpuUsage = v),

    // Redis
    getRedisMemoryUsage()
      .then(getConns)
      .then(getIntelQueueSize)
      .then(getRateLimitInfo),

    // bash
    getRealMemoryUsage()
      .then(getTemp)
      .then(getThreadInfo)
      .then(getDiskInfo)
      .then(getMultiProfileSupportFlag)
      .then(getAutoUpgrade)
      .then(getUptimeInfo)
      .then(getMaxPid)
      .then(getActiveContainers)
      .then(getEthernetInfo)
  ]);

  if(updateFlag) {
    setTimeout(() => { update(); }, updateInterval);
  }
}

function startUpdating() {
  updateFlag = 1;
  update();
}

function stopUpdating() {
  updateFlag = 0;
}

async function getThreadInfo() {
  try {
    const count = await exec("ps -Haux | wc -l", {encoding: 'utf8'});
    const mainCount = await exec("ps -Haux | grep Fi[r]eMain | wc -l", {encoding: 'utf8'});
    const apiCount = await exec("ps -Haux | grep Fi[r]eApi | wc -l", {encoding: 'utf8'});
    const monitorCount = await exec("ps -Haux | grep Fi[r]eMon | wc -l", {encoding: 'utf8'});
    threadInfo.count = count.stdout.replace("\n", "");
    threadInfo.mainCount = mainCount.stdout.replace("\n", "");
    threadInfo.apiCount = apiCount.stdout.replace("\n", "");
    threadInfo.monitorCount = monitorCount.stdout.replace("\n", "");
  } catch(err) {
    log.error("Failed to get thread info", err);
  }
}

async function getUptimeInfo() {
  try {
    uptimeInfo.fireMain = 0;
    uptimeInfo.FireApi = 0;
    uptimeInfo.FireMon = 0;
    uptimeInfo.bitbridge6 = 0;
    uptimeInfo.bitbridge7 = 0;
    uptimeInfo.dnscrypt = 0;
    uptimeInfo.dnsmasq = 0;
    uptimeInfo.openvpn = 0;

    const cmdResult = await exec("ps -eo etimes,cmd | awk '{print $1, $2}'", {encoding: 'utf8'});
    let lines = cmdResult.stdout.split("\n");
    lines.shift();
    lines.pop();
    updateTime = Date.now() / 1000;
    for (const line of lines) {
      let contents = line.split(' ');
      if (contents[1] == "FireMain") {
        uptimeInfo.fireMain = Number(contents[0])
      } else if (contents[1] == "FireApi") {
        uptimeInfo.FireApi = Number(contents[0])
      } else if (contents[1] == "FireMon") {
        uptimeInfo.FireMon = Number(contents[0])
      } else if (contents[1].indexOf("bitbridge6") > -1) {
        uptimeInfo.bitbridge6 = Number(contents[0])
      } else if (contents[1].indexOf("bitbridge7") > -1) {
        uptimeInfo.bitbridge7 = Number(contents[0])
      } else if (contents[1].indexOf("dnscrypt") > -1) {
        uptimeInfo.dnscrypt = Number(contents[0])
      } else if (contents[1].indexOf("dnsmasq") > -1) {
        uptimeInfo.dnsmasq = Number(contents[0])
      } else if (contents[1].indexOf("openvpn") > -1) {
        uptimeInfo.openvpn = Number(contents[0])
      }
    }
  } catch(err) {
    log.error("Failed to get uptime info", err);
  }
}

async function getRateLimitInfo() {
  rateLimitInfo = await rateLimit.getLastTS();
}

async function getDiskInfo() {
  try {
    const response = await df()
    const disks = response.filter(entry => ["/dev/mmc", "overlay"].some(x => entry.filesystem.startsWith(x)));
    diskInfo = disks;
  } catch(err) {
    log.error("Failed to get disk info", err);
  }
}

function getAutoUpgrade() {
  return new Promise((resolve, reject) => {
    fs.exists("/home/pi/.firewalla/config/.no_auto_upgrade", function(exists) {
      no_auto_upgrade = exists;
      resolve(no_auto_upgrade);
    });
  })
}

async function getMultiProfileSupportFlag() {
  const cmd = "sudo bash -c 'test -e /etc/openvpn/easy-rsa/keys2/ta.key'"
  try {
    await exec(cmd);
    multiProfileSupport = false;
  } catch(err) {
    multiProfileSupport = true;
  }
}

async function getIntelQueueSize() {
  intelQueueSize = await rclient.zcountAsync("ip_set_to_be_processed", "-inf", "+inf");
}

async function getRealMemoryUsage() {
  try {
    const res = await exec('free');
    var lines = res.stdout.split(/\n/g);
    for(var i = 0; i < lines.length; i++) {
      lines[i] = lines[i].split(/\s+/);
    }

    usedMem = parseInt(lines[1][2]);
    allMem = parseInt(lines[1][1]);
    realMemUsage = 1.0 * usedMem / allMem;
    log.debug("Memory Usage: ", usedMem, " ", allMem, " ", realMemUsage);
  } catch (err) {
    log.error("Failed to get memory usuage:", err);
  }
}

async function getTemp() {
  try {
    curTemp = await platform.getCpuTemperature();
    if (Array.isArray(curTemp)) curTemp = curTemp[0]
    log.debug("Current Temp: ", curTemp);
    peakTemp = peakTemp > curTemp ? peakTemp : curTemp;
  } catch(err) {
    log.debug("Failed getting CPU temperature", err);
    curTemp = -1;
  }
}

function getUptime() {
  return process.uptime();
}

function getOSUptime() {
  return require('os').uptime();
}

function getTimestamp() {
  return new Date();
}

async function getConns() {
  // get conns in last 24 hours
  try {
    const keys = await rclient.keysAsync('flow:conn:*');

    let results = await Promise.all(
      keys.map(key => rclient.zcountAsync(key, '-inf', '+inf'))
    );

    if(results.length > 0) {
      conn = results.reduce((a,b) => (a + b));
      peakConn = peakConn > conn ? peakConn : conn;
    }
  } catch(err) {
    log.error("Failed getting connections in 24 hrs", err);
    conn = -1;
    return;
  }
}

async function getRedisMemoryUsage() {
  const cmd = "redis-cli info | grep used_memory: | awk -F: '{print $2}'";
  try {
    const res = await exec(cmd);
    redisMemory = res.stdout.replace(/\r?\n$/,'');
  } catch(err) {
    log.error("Error getting Redis memory usage", err);
  }
}

function getCategoryStats() {
  try {
    const output = execSync(`${f.getFirewallaHome()}/scripts/category_blocking_stats.sh`, {encoding: 'utf8'})
    const lines = output.split("\n");

    let stats = {};
    lines.forEach((line) => {
      const entries = line.split(" ");
      const category = entries[0];
      const num = entries[1];
      stats[category] = num;
    })

    return stats;

  } catch(err) {
    return {};
  }
}

async function getMaxPid() {
  try {
    const cmd = await exec('echo $$')
    const pid = Number(cmd.stdout)
    if (pid < maxPid) {
      log.debug(`maxPid decresed. max: ${maxPid}, now: ${pid}`)
    } else {
      maxPid = pid
    }
  } catch(err) {
    log.error("Error getting max pid", err)
  }
}

async function getActiveContainers() {
  try {
    if (! platform.isDockerSupported()) { return; }
    const cmd = await exec('sudo docker container ls -q | wc -l')
    activeContainers = Number(cmd.stdout)
    log.info(`active docker containers count = ${activeContainers}`);
  } catch(err) {
    log.error("failed to get number of active docker containers", err)
  }
}

function getSysInfo() {
  let sysinfo = {
    cpu: cpuUsage,
    mem: 1 - os.freememPercentage(),
    realMem: realMemUsage,
    totalMem: os.totalmem(),
    load1: os.loadavg(1),
    load5: os.loadavg(5),
    load15: os.loadavg(15),
    curTemp: curTemp + "",
    peakTemp: peakTemp + "",
    timestamp: getTimestamp(),
    uptime: getUptime(),
    osUptime: getOSUptime(),
    conn: conn + "",
    peakConn: peakConn + "",
    redisMem: redisMemory,
    releaseType: f.getReleaseType(),
    threadInfo: threadInfo,
    intelQueueSize: intelQueueSize,
    nodeVersion: process.version,
    diskInfo: diskInfo,
    //categoryStats: getCategoryStats(),
    multiProfileSupport: multiProfileSupport,
    no_auto_upgrade: no_auto_upgrade,
    maxPid: maxPid,
    ethInfo
  }

  let newUptimeInfo = {};
  Object.keys(uptimeInfo).forEach((uptimeName) => {
    if (uptimeInfo[uptimeName] > 0 ) {
      newUptimeInfo[uptimeName] = uptimeInfo[uptimeName] + Date.now() / 1000 - updateTime; // add time difference between update and getSysInfo()
    } else {
      newUptimeInfo[uptimeName] = 0;
    }
  });
  sysinfo.uptimeInfo = newUptimeInfo;

  if(rateLimitInfo) {
    sysinfo.rateLimitInfo = rateLimitInfo;
  }

  if (platform.isDockerSupported()) {
    sysinfo.activeContainers = activeContainers;
  }

  return sysinfo;
}

async function getRecentLogs() {
  const logFiles = ["api.log", "kickui.log", "main.log", "monitor.log", "dns.log"].map((name) => logFolder + "/" + name);

  const tailNum = config.sysInfo.tailNum || 100; // default 100

  let results = await Promise.all(logFiles.map(async file => {
    // ignore all errors
    try {
      let res = await exec(util.format('tail -n %d %s', tailNum, file))
      return { file: file, content: res.stdout }
    } catch(err) {
      return { file: file, content: "" }
    }
  }));

  return results
}

function getTopStats() {
  return execSync("top -b -n 1 -o %MEM | head -n 20").toString('utf-8').split("\n");
}

async function getTop5Flows() {
  let flows = await rclient.keysAsync("flow:conn:*");

  let stats = await Promise.all(flows.map(async (flow) => {
    let count = await rclient.zcountAsync(flow, "-inf", "+inf")
    return {name: flow, count: count};
  }))

  return stats.sort((a, b) => b.count - a.count).slice(0, 5);
}

async function getPerfStats() {
  return {
    top: getTopStats(),
    sys: getSysInfo(),
    perf: await getTop5Flows()
  }
}

function getHeapDump(file, callback) {
  callback(null);
  // let heapdump = require('heapdump');
  // heapdump.writeSnapshot(file, callback);
}

async function getEthernetInfo() {
  const localEthInfo = {};
  const eth0_crc = await exec("ethtool -S eth0 | fgrep rx_crc_errors: | awk '{print $2}'").catch((err) => -1); // return -1 when err
  localEthInfo.eth0_crc = eth0_crc;
  ethInfo = localEthInfo;
}

module.exports = {
  getSysInfo: getSysInfo,
  startUpdating: startUpdating,
  stopUpdating: stopUpdating,
  getRealMemoryUsage:getRealMemoryUsage,
  getRecentLogs: getRecentLogs,
  getPerfStats: getPerfStats,
  getHeapDump: getHeapDump
};
<commit_msg>add purple limit<commit_after>/*    Copyright 2019-2021 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

'use strict';

const log = require("../../net2/logger.js")(__filename, "info");

const util = require('util');

const f = require('../../net2/Firewalla.js');
const logFolder = f.getLogFolder();

const config = require("../../net2/config.js").getConfig();

const df = util.promisify(require('node-df'))

const os = require('../../vendor_lib/osutils.js');

const exec = require('child-process-promise').exec;
const { execSync } = require('child_process')

const rclient = require('../../util/redis_manager.js').getRedisClient()

const platformLoader = require('../../platform/PlatformLoader.js');
const platform = platformLoader.getPlatform();

const rateLimit = require('../../extension/ratelimit/RateLimit.js');

const fs = require('fs');

let cpuUsage = 0;
let realMemUsage = 0;
let usedMem = 0;
let allMem = 0;
let curTemp = 0;
let peakTemp = 0;

let conn = 0;
let peakConn = 0;

let rateLimitInfo = null;

let redisMemory = 0;

let updateFlag = 0;

let updateInterval = 600 * 1000; // every 10 minutes

let threadInfo = {};

let diskInfo = null;

let ethInfo = {};

let intelQueueSize = 0;

let multiProfileSupport = false;

let no_auto_upgrade = false;

let uptimeInfo = {};
let updateTime = null;

let maxPid = 0;
let activeContainers = 0;

getMultiProfileSupportFlag();

async function update() {
  await Promise.all([
    // this takes 10s
    os.cpuUsage().then((v) => cpuUsage = v),

    // Redis
    getRedisMemoryUsage()
      .then(getConns)
      .then(getIntelQueueSize)
      .then(getRateLimitInfo),

    // bash
    getRealMemoryUsage()
      .then(getTemp)
      .then(getThreadInfo)
      .then(getDiskInfo)
      .then(getMultiProfileSupportFlag)
      .then(getAutoUpgrade)
      .then(getUptimeInfo)
      .then(getMaxPid)
      .then(getActiveContainers)
      .then(getEthernetInfo)
  ]);

  if(updateFlag) {
    setTimeout(() => { update(); }, updateInterval);
  }
}

function startUpdating() {
  updateFlag = 1;
  update();
}

function stopUpdating() {
  updateFlag = 0;
}

async function getThreadInfo() {
  try {
    const count = await exec("ps -Haux | wc -l", {encoding: 'utf8'});
    const mainCount = await exec("ps -Haux | grep Fi[r]eMain | wc -l", {encoding: 'utf8'});
    const apiCount = await exec("ps -Haux | grep Fi[r]eApi | wc -l", {encoding: 'utf8'});
    const monitorCount = await exec("ps -Haux | grep Fi[r]eMon | wc -l", {encoding: 'utf8'});
    threadInfo.count = count.stdout.replace("\n", "");
    threadInfo.mainCount = mainCount.stdout.replace("\n", "");
    threadInfo.apiCount = apiCount.stdout.replace("\n", "");
    threadInfo.monitorCount = monitorCount.stdout.replace("\n", "");
  } catch(err) {
    log.error("Failed to get thread info", err);
  }
}

async function getUptimeInfo() {
  try {
    uptimeInfo.fireMain = 0;
    uptimeInfo.FireApi = 0;
    uptimeInfo.FireMon = 0;
    uptimeInfo.bitbridge6 = 0;
    uptimeInfo.bitbridge7 = 0;
    uptimeInfo.dnscrypt = 0;
    uptimeInfo.dnsmasq = 0;
    uptimeInfo.openvpn = 0;

    const cmdResult = await exec("ps -eo etimes,cmd | awk '{print $1, $2}'", {encoding: 'utf8'});
    let lines = cmdResult.stdout.split("\n");
    lines.shift();
    lines.pop();
    updateTime = Date.now() / 1000;
    for (const line of lines) {
      let contents = line.split(' ');
      if (contents[1] == "FireMain") {
        uptimeInfo.fireMain = Number(contents[0])
      } else if (contents[1] == "FireApi") {
        uptimeInfo.FireApi = Number(contents[0])
      } else if (contents[1] == "FireMon") {
        uptimeInfo.FireMon = Number(contents[0])
      } else if (contents[1].indexOf("bitbridge6") > -1) {
        uptimeInfo.bitbridge6 = Number(contents[0])
      } else if (contents[1].indexOf("bitbridge7") > -1) {
        uptimeInfo.bitbridge7 = Number(contents[0])
      } else if (contents[1].indexOf("dnscrypt") > -1) {
        uptimeInfo.dnscrypt = Number(contents[0])
      } else if (contents[1].indexOf("dnsmasq") > -1) {
        uptimeInfo.dnsmasq = Number(contents[0])
      } else if (contents[1].indexOf("openvpn") > -1) {
        uptimeInfo.openvpn = Number(contents[0])
      }
    }
  } catch(err) {
    log.error("Failed to get uptime info", err);
  }
}

async function getRateLimitInfo() {
  rateLimitInfo = await rateLimit.getLastTS();
}

async function getDiskInfo() {
  try {
    const response = await df()
    const disks = response.filter(entry => ["/dev/mmc", "overlay"].some(x => entry.filesystem.startsWith(x)));
    diskInfo = disks;
  } catch(err) {
    log.error("Failed to get disk info", err);
  }
}

function getAutoUpgrade() {
  return new Promise((resolve, reject) => {
    fs.exists("/home/pi/.firewalla/config/.no_auto_upgrade", function(exists) {
      no_auto_upgrade = exists;
      resolve(no_auto_upgrade);
    });
  })
}

async function getMultiProfileSupportFlag() {
  const cmd = "sudo bash -c 'test -e /etc/openvpn/easy-rsa/keys2/ta.key'"
  try {
    await exec(cmd);
    multiProfileSupport = false;
  } catch(err) {
    multiProfileSupport = true;
  }
}

async function getIntelQueueSize() {
  intelQueueSize = await rclient.zcountAsync("ip_set_to_be_processed", "-inf", "+inf");
}

async function getRealMemoryUsage() {
  try {
    const res = await exec('free');
    var lines = res.stdout.split(/\n/g);
    for(var i = 0; i < lines.length; i++) {
      lines[i] = lines[i].split(/\s+/);
    }

    usedMem = parseInt(lines[1][2]);
    allMem = parseInt(lines[1][1]);
    realMemUsage = 1.0 * usedMem / allMem;
    log.debug("Memory Usage: ", usedMem, " ", allMem, " ", realMemUsage);
  } catch (err) {
    log.error("Failed to get memory usuage:", err);
  }
}

async function getTemp() {
  try {
    curTemp = await platform.getCpuTemperature();
    if (Array.isArray(curTemp)) curTemp = curTemp[0]
    log.debug("Current Temp: ", curTemp);
    peakTemp = peakTemp > curTemp ? peakTemp : curTemp;
  } catch(err) {
    log.debug("Failed getting CPU temperature", err);
    curTemp = -1;
  }
}

function getUptime() {
  return process.uptime();
}

function getOSUptime() {
  return require('os').uptime();
}

function getTimestamp() {
  return new Date();
}

async function getConns() {
  // get conns in last 24 hours
  try {
    const keys = await rclient.keysAsync('flow:conn:*');

    let results = await Promise.all(
      keys.map(key => rclient.zcountAsync(key, '-inf', '+inf'))
    );

    if(results.length > 0) {
      conn = results.reduce((a,b) => (a + b));
      peakConn = peakConn > conn ? peakConn : conn;
    }
  } catch(err) {
    log.error("Failed getting connections in 24 hrs", err);
    conn = -1;
    return;
  }
}

async function getRedisMemoryUsage() {
  const cmd = "redis-cli info | grep used_memory: | awk -F: '{print $2}'";
  try {
    const res = await exec(cmd);
    redisMemory = res.stdout.replace(/\r?\n$/,'');
  } catch(err) {
    log.error("Error getting Redis memory usage", err);
  }
}

function getCategoryStats() {
  try {
    const output = execSync(`${f.getFirewallaHome()}/scripts/category_blocking_stats.sh`, {encoding: 'utf8'})
    const lines = output.split("\n");

    let stats = {};
    lines.forEach((line) => {
      const entries = line.split(" ");
      const category = entries[0];
      const num = entries[1];
      stats[category] = num;
    })

    return stats;

  } catch(err) {
    return {};
  }
}

async function getMaxPid() {
  try {
    const cmd = await exec('echo $$')
    const pid = Number(cmd.stdout)
    if (pid < maxPid) {
      log.debug(`maxPid decresed. max: ${maxPid}, now: ${pid}`)
    } else {
      maxPid = pid
    }
  } catch(err) {
    log.error("Error getting max pid", err)
  }
}

async function getActiveContainers() {
  try {
    if (! platform.isDockerSupported()) { return; }
    const cmd = await exec('sudo docker container ls -q | wc -l')
    activeContainers = Number(cmd.stdout)
    log.info(`active docker containers count = ${activeContainers}`);
  } catch(err) {
    log.error("failed to get number of active docker containers", err)
  }
}

function getSysInfo() {
  let sysinfo = {
    cpu: cpuUsage,
    mem: 1 - os.freememPercentage(),
    realMem: realMemUsage,
    totalMem: os.totalmem(),
    load1: os.loadavg(1),
    load5: os.loadavg(5),
    load15: os.loadavg(15),
    curTemp: curTemp + "",
    peakTemp: peakTemp + "",
    timestamp: getTimestamp(),
    uptime: getUptime(),
    osUptime: getOSUptime(),
    conn: conn + "",
    peakConn: peakConn + "",
    redisMem: redisMemory,
    releaseType: f.getReleaseType(),
    threadInfo: threadInfo,
    intelQueueSize: intelQueueSize,
    nodeVersion: process.version,
    diskInfo: diskInfo,
    //categoryStats: getCategoryStats(),
    multiProfileSupport: multiProfileSupport,
    no_auto_upgrade: no_auto_upgrade,
    maxPid: maxPid,
    ethInfo
  }

  let newUptimeInfo = {};
  Object.keys(uptimeInfo).forEach((uptimeName) => {
    if (uptimeInfo[uptimeName] > 0 ) {
      newUptimeInfo[uptimeName] = uptimeInfo[uptimeName] + Date.now() / 1000 - updateTime; // add time difference between update and getSysInfo()
    } else {
      newUptimeInfo[uptimeName] = 0;
    }
  });
  sysinfo.uptimeInfo = newUptimeInfo;

  if(rateLimitInfo) {
    sysinfo.rateLimitInfo = rateLimitInfo;
  }

  if (platform.isDockerSupported()) {
    sysinfo.activeContainers = activeContainers;
  }

  return sysinfo;
}

async function getRecentLogs() {
  const logFiles = ["api.log", "kickui.log", "main.log", "monitor.log", "dns.log"].map((name) => logFolder + "/" + name);

  const tailNum = config.sysInfo.tailNum || 100; // default 100

  let results = await Promise.all(logFiles.map(async file => {
    // ignore all errors
    try {
      let res = await exec(util.format('tail -n %d %s', tailNum, file))
      return { file: file, content: res.stdout }
    } catch(err) {
      return { file: file, content: "" }
    }
  }));

  return results
}

function getTopStats() {
  return execSync("top -b -n 1 -o %MEM | head -n 20").toString('utf-8').split("\n");
}

async function getTop5Flows() {
  let flows = await rclient.keysAsync("flow:conn:*");

  let stats = await Promise.all(flows.map(async (flow) => {
    let count = await rclient.zcountAsync(flow, "-inf", "+inf")
    return {name: flow, count: count};
  }))

  return stats.sort((a, b) => b.count - a.count).slice(0, 5);
}

async function getPerfStats() {
  return {
    top: getTopStats(),
    sys: getSysInfo(),
    perf: await getTop5Flows()
  }
}

function getHeapDump(file, callback) {
  callback(null);
  // let heapdump = require('heapdump');
  // heapdump.writeSnapshot(file, callback);
}

async function getEthernetInfo() {
  const localEthInfo = {};
  if(platform.getName() == "purple") {
    const eth0_crc = await exec("ethtool -S eth0 | fgrep mmc_rx_crc_error: | awk '{print $2}'").catch((err) => -1); // return -1 when err
    localEthInfo.eth0_crc = eth0_crc;
  }
  ethInfo = localEthInfo;
}

module.exports = {
  getSysInfo: getSysInfo,
  startUpdating: startUpdating,
  stopUpdating: stopUpdating,
  getRealMemoryUsage:getRealMemoryUsage,
  getRecentLogs: getRecentLogs,
  getPerfStats: getPerfStats,
  getHeapDump: getHeapDump
};
<|endoftext|>