<commit_before>(function($, window, document, undefined) {

    var pluginName = "jqueryVideoLightning",
        defaults = {
            id: "y-dQw4w9WgXcQ",
            width: "640px",
            height: "390px",
            autoplay: 0,
            autohide: 2,
            controls: 1,
            iv_load_policy: 1,
            loop: 0,
            modestbranding: 0,
            playlist: "",
            related: 0,
            showinfo: 1,
            start_time: 0,
            theme: "dark",
            color: "",
            byline: 1,
            portrait: 1,
            effect_in: "fadeIn",
            ease_in: 300,
            ease_out: 0,
            backdrop_color: "#000",
            backdrop_opacity: 1,
            glow: 0,
            glow_color: "#fff"
        };

    function JQVideoLightning ( element, options ) {
        this.element = element;
        this.settings = $.extend( {}, defaults, options );
        this._defaults = defaults;
        this._name = pluginName;
        this.init();
    }

    JQVideoLightning.prototype = {
        init: function () {
            var void_target, void_elements, target, target_class;
            void_elements = [ "AREA", "BASE", "BR", "COL", "COMMAND", "EMBED", "HR", "IMG", "INPUT", "KEYGEN", "LINK", "META", "PARAM", "SOURCE", "TRACK", "WBR" ];
            void_target = 0;
            target_class = ".video-target";

            $(this.element).css( "cursor", "pointer" );

            if (($.inArray($(this.element).prop('tagName'), void_elements)) == -1) {
                target = $(this.element);
                target.addClass("video-target");
            }
            else {
                $("body").append('
' + '
');
                target = $(target_class);
                void_target = 1;
            }

            function callPlayer() {
                $(this.player(target, $(this).settings), void_target);
            }

            $(this.element).on( "click", $.proxy(callPlayer, this));
        },

        player: function ( target, settings, void_target ) {
            var id, video_autohide, video_autoplay, video_byline, video_color, video_controls, video_height, video_id, video_iv_load_policy, video_loop, video_modestbranding, video_playlist, video_portrait, video_related, video_showinfo, video_start_time, video_theme, video_vendor, video_width, vimeo_player, youtube_player, ease_in, glow, glow_color, backdrop_color, backdrop_opacity, red, green, blue;

            if (target.find(".video-wrapper").is(':visible')) {
                target.find(".video").remove();
                target.find(".video-wrapper").hide(((this.settings).easeOut));
                target.find(".video-wrapper").remove();
                if (void_target == 1){target.remove()}
                return $(this).destroy;
            } else {
                id = (typeof target.data("videoId") === 'undefined') ? (this.settings).id : target.data("videoId");
                video_vendor = id.split("-")[0];
                if ((video_vendor === "v") || (video_vendor === "V")) {
                    video_vendor = "Vimeo";
                } else {
                    video_vendor = "Youtube";
                }
                video_id = id.split("-")[1]; // Youtube: "y-XbTtgr8J8uU" Vimeo: "v-32187194"
                video_width = target.data("videoWidth") || (this.settings).width; // Y&V: video width in px
                video_height = target.data("videoHeight") || (this.settings).height; // Y&V: video height in px
                video_autoplay = target.data("videoAutoplay") || (this.settings).autoplay; // Y&V: start playback immediately (0,1)
                video_autohide = target.data("videoAutohide") || (this.settings).autohide; // Y: auto hide controls after video load (0,1,2)
                video_controls = target.data("videoControls") || (this.settings).controls; // Y: display controls (0,1,2)
                video_iv_load_policy = target.data("videoIvLoadPolicy") || (this.settings).iv_load_policy; // Y: display annotations (1,3)
                video_loop = target.data("videoLoop") || (this.settings).loop; // Y&V: loop video playback (0,1)
                video_modestbranding = target.data("videoModestbranding") || (this.settings).modestbranding; // Y: hide large Youtube logo (0,1)
                video_playlist = target.data("videoPlaylist") || (this.settings).playlist; // Y: comma-separated list of video IDs to play
                video_related = target.data("videoRelated") || (this.settings).related; // Y: show related videos when playback id finished (0,1)
                video_showinfo = target.data("videoShowinfo") || (this.settings).showinfo; // Y: display title, uploader (0,1)  V: display title (0,1)
                video_start_time = target.data("videoStartTime") || (this.settings).start_time; // Y: playback start position in seconds (ex. "132" starts at 2mins, 12secs)
                video_theme = target.data("videoTheme") || (this.settings).theme; // Y: player theme ("dark","light")
                if (video_vendor == "Vimeo"){
                    video_color = target.data("videoColor") || prepHex((this.settings).color); // V: player controls color (hex code minus the "#", default is "00adef")
                } else {
                    video_color = target.data("videoColor") || (this.settings).color; // Y: player controls color ("red","white")
                }
                video_byline = target.data("videoByline") || (this.settings).byline; // V: display byline (0,1)
                video_portrait = target.data("videoPortrait") || (this.settings).portrait; // V: display user's portrait (0,1)
                youtube_player = $("<embed src=\"https://www.youtube.com/embed/" + video_id + "?autoplay=" + video_autoplay + "&autohide=" + video_autohide + "&controls=" + video_controls + "&iv_load_policy=" + video_iv_load_policy + "&loop=" + video_loop + "&modestbranding=" + video_modestbranding + "&playlist=" + video_playlist + "&rel=" + video_related + "&showinfo=" + video_showinfo + "&start=" + video_start_time + "&theme=" + video_theme + "&color=" + video_color + "\" width=\"" + video_width + "\" height=\"" + video_height + "\" frameborder=\"0\" allowfullscreen></embed>");
                vimeo_player = $("");
                ease_in = (this.settings).ease_in;
                glow = (this.settings).glow;
                glow_color = (this.settings).glow_color;
                backdrop_color = (this.settings).backdrop_color;
                backdrop_opacity = (this.settings).backdrop_opacity;

                function colorConverter(hex){
                    red = parseInt((prepHex(hex)).substring(0,2),16);
                    blue = parseInt((prepHex(hex)).substring(2,4),16);
                    green = parseInt((prepHex(hex)).substring(4,6),16);
                    return {
                        red: red,
                        blue: blue,
                        green: green
                    };
                }

                function fullHex(hex){
                    hex = "#" + prepHex(hex);
                    return hex;
                }

                function prepHex(hex){
                    hex = (hex.charAt(0)=="#") ? hex.split("#")[1]:hex;
                    if (hex.length == 3){
                        hex = hex + hex;
                    }
                    return hex;
                }

                target.append('

');
                target.find(".video-wrapper").css({
                    backgroundColor: "rgba(" + colorConverter(backdrop_color).red + "," + colorConverter(backdrop_color).blue + "," + colorConverter(backdrop_color).green + "," + backdrop_opacity + ")"
                });
                target.find(".video-frame").css({
                    width:  video_width,
                    height: video_height,
                    marginTop: '-' + ((video_height.split("p")[0])/2) + 'px',
                    marginLeft: '-' + ((video_width.split("p")[0])/2) + 'px',
                    boxShadow: '0px 0px ' + glow + 'px ' + (glow/5) + 'px ' + fullHex(glow_color)
                });
                target.find(".video-wrapper").fadeIn(ease_in);
                if (video_vendor === "Vimeo") {
                    return target.find(".video").append(vimeo_player);
                } else {
                    return target.find(".video").append(youtube_player);
                }
            }
        },

        destroy: function () {
            $(this).off();
            $(this).removeData();
        }
    };

    $.fn[ pluginName ] = function ( options ) {
        return this.each(function() {
            if ( !$.data( this, "plugin_" + pluginName ) ) {
                $.data( this, "plugin_" + pluginName, new JQVideoLightning( this, options ) );
            }
        });
    };

    return this;

})( jQuery, window, document );<commit_msg>some minor cleanup<commit_after>(function($, window, document, undefined) {

    var pluginName = "jqueryVideoLightning",
        defaults = {
            id: "y-dQw4w9WgXcQ",
            width: "640px",
            height: "390px",
            autoplay: 0,
            autohide: 2,
            controls: 1,
            iv_load_policy: 1,
            loop: 0,
            modestbranding: 0,
            playlist: "",
            related: 0,
            showinfo: 1,
            start_time: 0,
            theme: "dark",
            color: "",
            byline: 1,
            portrait: 1,
            effect_in: "fadeIn",
            ease_in: 300,
            ease_out: 0,
            backdrop_color: "#000",
            backdrop_opacity: 1,
            glow: 0,
            glow_color: "#fff"
        };

    function JQVideoLightning ( element, options ) {
        this.element = element;
        this.settings = $.extend( {}, defaults, options );
        this._defaults = defaults;
        this._name = pluginName;
        this.init();
    }

    JQVideoLightning.prototype = {
        init: function () {
            var void_target, void_elements, target, target_class;
            void_elements = [ "AREA", "BASE", "BR", "COL", "COMMAND", "EMBED", "HR", "IMG", "INPUT", "KEYGEN", "LINK", "META", "PARAM", "SOURCE", "TRACK", "WBR" ];
            void_target = 0;
            target_class = ".video-target";

            $(this.element).css( "cursor", "pointer" );

            if (($.inArray($(this.element).prop('tagName'), void_elements)) == -1) {
                target = $(this.element);
                target.addClass("video-target");
            }
            else {
                $("body").append('
' + '
');
                target = $(target_class);
                void_target = 1;
            }

            function callPlayer() {
                $(this.player(target, $(this).settings), void_target);
            }

            $(this.element).on( "click", $.proxy(callPlayer, this));
        },

        player: function ( target, settings, void_target ) {
            var id, video_autohide, video_autoplay, video_byline, video_color, video_controls, video_height, video_id, video_iv_load_policy, video_loop, video_modestbranding, video_playlist, video_portrait, video_related, video_showinfo, video_start_time, video_theme, video_vendor, video_width, vimeo_player, youtube_player, ease_in, glow, glow_color, backdrop_color, backdrop_opacity, red, green, blue, effect_in;

            settings = this.settings;

            if (target.find(".video-wrapper").is(':visible')) {
                target.find(".video").remove();
                target.find(".video-wrapper").hide((settings.easeOut));
                target.find(".video-wrapper").remove();
                if (void_target == 1){target.remove()}
                return $(this).destroy;
            } else {
                id = (typeof target.data("videoId") === 'undefined') ? settings.id : target.data("videoId");
                video_vendor = id.split("-")[0];
                if ((video_vendor === "v") || (video_vendor === "V")) {
                    video_vendor = "Vimeo";
                } else {
                    video_vendor = "Youtube";
                }
                video_id = id.split("-")[1]; // Youtube: "y-XbTtgr8J8uU" Vimeo: "v-32187194"
                video_width = target.data("videoWidth") || settings.width; // Y&V: video width in px
                video_height = target.data("videoHeight") || settings.height; // Y&V: video height in px
                video_autoplay = target.data("videoAutoplay") || settings.autoplay; // Y&V: start playback immediately (0,1)
                video_autohide = target.data("videoAutohide") || settings.autohide; // Y: auto hide controls after video load (0,1,2)
                video_controls = target.data("videoControls") || settings.controls; // Y: display controls (0,1,2)
                video_iv_load_policy = target.data("videoIvLoadPolicy") || settings.iv_load_policy; // Y: display annotations (1,3)
                video_loop = target.data("videoLoop") || settings.loop; // Y&V: loop video playback (0,1)
                video_modestbranding = target.data("videoModestbranding") || settings.modestbranding; // Y: hide large Youtube logo (0,1)
                video_playlist = target.data("videoPlaylist") || settings.playlist; // Y: comma-separated list of video IDs to play
                video_related = target.data("videoRelated") || settings.related; // Y: show related videos when playback id finished (0,1)
                video_showinfo = target.data("videoShowinfo") || settings.showinfo; // Y: display title, uploader (0,1)  V: display title (0,1)
                video_start_time = target.data("videoStartTime") || settings.start_time; // Y: playback start position in seconds (ex. "132" starts at 2mins, 12secs)
                video_theme = target.data("videoTheme") || settings.theme; // Y: player theme ("dark","light")
                if (video_vendor == "Vimeo"){
                    video_color = target.data("videoColor") || prepHex(settings.color); // V: player controls color (hex code minus the "#", default is "00adef")
                } else {
                    video_color = target.data("videoColor") || settings.color; // Y: player controls color ("red","white")
                }
                video_byline = target.data("videoByline") || settings.byline; // V: display byline (0,1)
                video_portrait = target.data("videoPortrait") || settings.portrait; // V: display user's portrait (0,1)
                youtube_player = $("<embed src=\"https://www.youtube.com/embed/" + video_id + "?autoplay=" + video_autoplay + "&autohide=" + video_autohide + "&controls=" + video_controls + "&iv_load_policy=" + video_iv_load_policy + "&loop=" + video_loop + "&modestbranding=" + video_modestbranding + "&playlist=" + video_playlist + "&rel=" + video_related + "&showinfo=" + video_showinfo + "&start=" + video_start_time + "&theme=" + video_theme + "&color=" + video_color + "\" width=\"" + video_width + "\" height=\"" + video_height + "\" frameborder=\"0\" allowfullscreen></embed>");
                vimeo_player = $("");
                effect_in = settings.effect_in;
                ease_in = settings.ease_in;
                glow = settings.glow;
                glow_color = settings.glow_color;
                backdrop_color = settings.backdrop_color;
                backdrop_opacity = settings.backdrop_opacity;

                function colorConverter(hex){
                    red = parseInt((prepHex(hex)).substring(0,2),16);
                    blue = parseInt((prepHex(hex)).substring(2,4),16);
                    green = parseInt((prepHex(hex)).substring(4,6),16);
                    return {
                        red: red,
                        blue: blue,
                        green: green
                    };
                }

                function fullHex(hex){
                    hex = "#" + prepHex(hex);
                    return hex;
                }

                function prepHex(hex){
                    hex = (hex.charAt(0)=="#") ? hex.split("#")[1]:hex;
                    if (hex.length == 3){
                        hex = hex + hex;
                    }
                    return hex;
                }

                target.append('

');
                target.find(".video-wrapper").css({
                    backgroundColor: "rgba(" + colorConverter(backdrop_color).red + "," + colorConverter(backdrop_color).blue + "," + colorConverter(backdrop_color).green + "," + backdrop_opacity + ")"
                });
                target.find(".video-frame").css({
                    width:  video_width,
                    height: video_height,
                    marginTop: '-' + ((video_height.split("p")[0])/2) + 'px',
                    marginLeft: '-' + ((video_width.split("p")[0])/2) + 'px',
                    boxShadow: '0px 0px ' + glow + 'px ' + (glow/5) + 'px ' + fullHex(glow_color)
                });
                target.find(".video-wrapper")[effect_in](ease_in);
                if (video_vendor === "Vimeo") {
                    return target.find(".video").append(vimeo_player);
                } else {
                    return target.find(".video").append(youtube_player);
                }
            }
        },

        destroy: function () {
            $(this).off();
            $(this).removeData();
        }
    };

    $.fn[ pluginName ] = function ( options ) {
        return this.each(function() {
            if ( !$.data( this, "plugin_" + pluginName ) ) {
                $.data( this, "plugin_" + pluginName, new JQVideoLightning( this, options ) );
            }
        });
    };

    return this;

})( jQuery, window, document );<|endoftext|>


<commit_before>import assert from 'assert';

import electron from 'electron';
const { BrowserWindow, ipcMain } = electron;

function jews(url) {
    return new Promise((resolve, reject) => {
        let window = new BrowserWindow({
            show: process.env.JEWS_SHOW_ELECTRON_WINDOW === 'show'
        });
        ipcMain.on('jews-done', (event, result) => resolve(result));
        ipcMain.on('jews-error', (event, err) => reject(err));
        window.loadURL(url);
        window.webContents.executeJavaScript(`
            try {
                eval(require('fs').readFileSync('dist/jews.user.js', 'utf-8'));
            } catch (e) {
                require('electron').ipcRenderer.sendSync('jews-error', e);
            }
        `);
    });
}

describe('파싱 중에 에러가 나면 안됨', function () {
    this.timeout(0);
    it('한겨레', async () => {
        await jews('http://www.hani.co.kr/arti/society/schooling/718916.html'); // #211
    });
});

async function testTimestampParsing(url) {
    let jewsResult = await jews(url);
    let t = jewsResult.timestamp;
    if (t) {
        if (t.created === 'Invalid Date') throw new Error('잘못된 작성일');
        if (t.lastModified === 'Invalid Date') throw new Error('잘못된 마지막 수정일');
    }
}

describe('날짜 파싱에 실패하면 안됨', function () {
    this.timeout(0);
    it('마이데일리', async () => {
        await testTimestampParsing('http://www.mydaily.co.kr/new_yk/html/read.php?newsid=201511192101592220&ext=na'); // #208
    });
});
<commit_msg>more test #208<commit_after>import assert from 'assert';

import electron from 'electron';
const { BrowserWindow, ipcMain } = electron;

function jews(url) {
    return new Promise((resolve, reject) => {
        if (jews.cache[url]) return resolve(jews.cache[url]);
        let window = new BrowserWindow({
            show: process.env.JEWS_SHOW_ELECTRON_WINDOW === 'show'
        });
        ipcMain.on('jews-done', (event, result) => {
            jews.cache[url] = result;
            resolve(result);
        });
        ipcMain.on('jews-error', (event, err) => reject(err));
        window.loadURL(url);
        window.webContents.executeJavaScript(`
            try {
                eval(require('fs').readFileSync('dist/jews.user.js', 'utf-8'));
            } catch (e) {
                require('electron').ipcRenderer.sendSync('jews-error', e);
            }
        `);
    });
}
jews.cache = {};

describe('파싱 중에 에러가 나면 안됨', function () {
    this.timeout(0);
    it('한겨레', async () => {
        await jews('http://www.hani.co.kr/arti/society/schooling/718916.html'); // #211
    });
});

async function testTimestampParsing(url) {
    let jewsResult = await jews(url);
    let t = jewsResult.timestamp;
    if (t) {
        if (t.created === 'Invalid Date') throw new Error('잘못된 작성일');
        if (t.lastModified === 'Invalid Date') throw new Error('잘못된 마지막 수정일');
    }
}

describe('날짜 파싱에 실패하면 안됨', function () {
    this.timeout(0);
    it('마이데일리', async () => {
        await testTimestampParsing('http://www.mydaily.co.kr/new_yk/html/read.php?newsid=201511192101592220&ext=na'); // #208
    });
});

async function testTitleParsing(url) {
    let jewsResult = await jews(url);
    switch (jewsResult.title) {
    case undefined: throw new Error('제목이 undefined');
    case '': throw new Error('제목이 비어있음');
    }
}

describe('제목이 비어있으면 안됨', function () {
    this.timeout(0);
    it('마이데일리', async () => {
        await testTitleParsing('http://www.mydaily.co.kr/new_yk/html/read.php?newsid=201511192101592220&ext=na'); // #208
    });
});
<|endoftext|>


<commit_before>/* Copyright (c) 2011 by MapQuery Contributors (see AUTHORS for
 * full list of contributors). Published under the MIT license.
 * See https://github.com/mapquery/mapquery/blob/master/LICENSE for the
 * full text of the license. */

/**
#jquery.mapquery.legend.js
A plugin on mapquery.core to add a legend to a layer. It will check if the layer
is within a valid extent and zoom range. And if not will return an error message.
 */

(function($, MQ) {
$.extend( $.fn.mapQuery.defaults.layer.all, {
    legend: {
        url: '',
        msg: ''
        }
});
//possible error messages to display in the legend
LEGEND_ERRORS= ['E_ZOOMOUT', 'E_ZOOMIN', 'E_OUTSIDEBOX'];
$.extend(MQ.Layer.prototype, {
/**
###**layer**.`legend([options])`
_version added 0.1_
####**Description**: get/set the legend of a layer

**options** url:url the url to the legend image

>Returns: {url:url, msg:'E\_ZOOMOUT' | 'E\_ZOOMIN' | 'E\_OUTSIDEBOX' | ''}

The `.legend()` function allows us to attach a legend image to a layer. It will
also check if the layer is not visible due to wrong extent or zoom level. It will
return an error message which can be used to notify the user.

     var legend = layer.legend();  //get the current legend
     layer.legend({url:'legendimage.png'}) //set the legend url to legendimage.png

 */
    //get/set the legend object
    legend: function(options) {
        //get the legend object
        var goto = this.map.goto();
        if (arguments.length===0) {
            this._checkZoom(goto);
            //if zoom = ok, check box
            if(this.options.legend.msg==''){
                this._checkBox(goto);
            };
            return this.options.legend;
        }
        //set the legend url
        if (options.url!==undefined) {
            this.options.legend.url = options.url;
            return this.options.legend;
        }
    },
    //Check if the layer has a maximum box set and if the current box
    //is outside these settings, set the legend.msg accordingly
    _checkBox: function(goto){
        var maxExtent = this.options.maxExtent;
        if(maxExtent!==undefined) {
            var mapBounds = new OpenLayers.Bounds(goto.box[0],goto.box[1],goto.box[2],goto.box[3]);
            var layerBounds = new OpenLayers.Bounds(maxExtent[0],maxExtent[1],maxExtent[2],maxExtent[3]);
            var inside = layerBounds.containsBounds(mapBounds, true);
            inside?this.options.legend.msg='':this.options.legend.msg=LEGEND_ERRORS[2];
        };
    },
    //Check if the layer has a minimum or maximum zoom set and if the current zoom
    //is outside these settings, set the legend.msg accordingly
    _checkZoom: function(goto){
        var zoom = goto.zoom;
        var maxZoom = this.options.maxZoom;
        var minZoom = this.options.minZoom;
        (maxZoom!==undefined&&maxZoom<zoom)? this.options.legend.msg=LEGEND_ERRORS[0]:this.options.legend.msg='';
        (minZoom!==undefined&&minZoom>zoom)? this.options.legend.msg=LEGEND_ERRORS[1]:this.options.legend.msg='';
    }

});

})(jQuery, $.MapQuery);
<commit_msg>parsed through jslint<commit_after>/* Copyright (c) 2011 by MapQuery Contributors (see AUTHORS for
 * full list of contributors). Published under the MIT license.
 * See https://github.com/mapquery/mapquery/blob/master/LICENSE for the
 * full text of the license. */

/**
#jquery.mapquery.legend.js
A plugin on mapquery.core to add a legend to a layer. It will check if the layer
is within a valid extent and zoom range. And if not will return an error message.
 */

(function($, MQ) {
$.extend( $.fn.mapQuery.defaults.layer.all, {
    legend: {
        url: '',
        msg: ''
        }
});
//possible error messages to display in the legend
LEGEND_ERRORS= ['E_ZOOMOUT', 'E_ZOOMIN', 'E_OUTSIDEBOX'];
$.extend(MQ.Layer.prototype, {
/**
###**layer**.`legend([options])`
_version added 0.1_
####**Description**: get/set the legend of a layer

**options** url:url the url to the legend image

>Returns: {url:url, msg:'E\_ZOOMOUT' | 'E\_ZOOMIN' | 'E\_OUTSIDEBOX' | ''}

The `.legend()` function allows us to attach a legend image to a layer. It will
also check if the layer is not visible due to wrong extent or zoom level. It will
return an error message which can be used to notify the user.

     var legend = layer.legend();  //get the current legend
     layer.legend({url:'legendimage.png'}) //set the legend url to legendimage.png

 */
    //get/set the legend object
    legend: function(options) {
        //get the legend object
        var goto = this.map.goto();
        if (arguments.length===0) {
            this._checkZoom(goto);
            //if zoom = ok, check box
            if(this.options.legend.msg==''){
                this._checkBox(goto);
            }
            return this.options.legend;
        }
        //set the legend url
        if (options.url!==undefined) {
            this.options.legend.url = options.url;
            return this.options.legend;
        }
    },
    //Check if the layer has a maximum box set and if the current box
    //is outside these settings, set the legend.msg accordingly
    _checkBox: function(goto){
        var maxExtent = this.options.maxExtent;
        if(maxExtent!==undefined) {
            var mapBounds = new OpenLayers.Bounds(goto.box[0],goto.box[1],goto.box[2],goto.box[3]);
            var layerBounds = new OpenLayers.Bounds(maxExtent[0],maxExtent[1],maxExtent[2],maxExtent[3]);
            var inside = layerBounds.containsBounds(mapBounds, true);
            this.options.legend.msg = inside?'':LEGEND_ERRORS[2];
        }
    },
    //Check if the layer has a minimum or maximum zoom set and if the current zoom
    //is outside these settings, set the legend.msg accordingly
    _checkZoom: function(goto){
        var zoom = goto.zoom;
        var maxZoom = this.options.maxZoom;
        var minZoom = this.options.minZoom;
        this.options.legend.msg=(maxZoom!==undefined&&maxZoom<zoom)? LEGEND_ERRORS[0]:'';
        this.options.legend.msg=(minZoom!==undefined&&minZoom>zoom)? LEGEND_ERRORS[1]:'';
    }

});

})(jQuery, $.MapQuery);
<|endoftext|>


<commit_before>/*! jquery-responsive-image
 * Copyright (c) 2015 Jan Rembold <janrembold@gmail.com>; License: MIT */

(function ( $, window, document, undefined ) {
    'use strict';

    // Create the defaults
    var pluginName = 'responsiveImage',
        defaults = {
            source:             '> span',
            sourcePrefix:       '',
            container:          null,

            minWidthDefault:    0,
            maxWidthDefault:    Number.MAX_VALUE,
            minDprDefault:      1,

            attributes:         ['title', 'alt', 'class', 'width', 'height'],
            resizeEvent:        'resize',
            preload:            false,
            autoDpr:            false,

            onGetWidth:         null,
            onLoadSources:      null
        };

    // The actual plugin constructor
    function Plugin ( element, options ) {
        var self = this;
        self.$element = $(element);
        self.options = $.extend( {}, defaults, options );

        self.sources = [];
        self.dpr = self.getDpr();
        self.attributeCount = self.options.attributes.length;

        if( typeof( self.$element.data('source-prefix') ) !== 'undefined' ) {
            self.options.sourcePrefix = self.$element.data('source-prefix');
        }

        self.init();
    }

    // Avoid Plugin.prototype conflicts
    $.extend(Plugin.prototype, {
        init: function () {
            var self = this;

            // load sources
            self.sources = self.loadSources();
            if(self.sources.length === 0) {
                return;
            }

            // check container or viewport support - data-container overrides default setting
            var containerSelector = self.$element.attr('data-container') || self.options.container;
            if(containerSelector) {
                self.$container = self.$element.parents(containerSelector);
            }

            // load responsive image
            self.loadResponsiveImage();

            // init resize event with jquery-debouncedwidth support: https://github.com/janrembold/jquery-debouncedwidth
            self.initResizeEvent();
        },

        loadSources: function(){
            var self = this;
            var sources = [];

            if( $.isFunction( self.options.onLoadSources ) ) {

                // use injected source loader
                sources = self.options.onLoadSources( self );
            } else {

                // prepare all necessary image data
                self.$element.find(self.options.source).each(function(){
                    var $source = $(this);

                    // only use images with source
                    if($source.data('src')) {
                        var data = {
                            'src':      self.options.sourcePrefix + $source.data('src'),
                            'minWidth': $source.data('min-width') || self.options.minWidthDefault,
                            'maxWidth': $source.data('max-width') || self.options.maxWidthDefault,
                            'minDpr':   $source.data('min-dpr') || self.options.minDprDefault
                        };

                        // prepare all attributes
                        for(var i=0; i<self.attributeCount; i++) {
                            var attribute = self.options.attributes[i];
                            data[attribute] = $source.data(attribute) || self.$element.data(attribute);
                        }

                        sources.push(data);
                    }
                });
            }

            // sort sources desc by minWidth, maxWidth and minDpr -> largest files first
            sources.sort(function(a, b) {
                if(b.minWidth === a.minWidth) {
                    if(b.maxWidth === a.maxWidth) {
                        return b.minDpr - a.minDpr;
                    }
                    return b.maxWidth - a.maxWidth;
                }
                return b.minWidth - a.minWidth;
            });

            return sources;
        },

        loadResponsiveImage: function () {
            var self = this;
            var newSource;
            var targetWidth = self.getWidth();
            var sourceCount = self.sources.length;

            // search for best image source
            for (var i=0; i<sourceCount; i++) {
                if( self.sources[i].minWidth <= targetWidth &&
                    self.sources[i].maxWidth > targetWidth &&
                    self.sources[i].minDpr <= self.dpr
                ) {
                    newSource = self.sources[i];
                    break;
                }
            }

            // check if image is already loaded
            if(newSource === self.$currentSource) {
                return;
            }

            // set new source
            self.$currentSource = newSource;

            // create new image
            var $image = self.createImageWithAttributes(newSource);

            // append responsive image immediately to target element
            if( !self.options.preload ) {
                self.setNewSource( $image );
            }

        },

        setNewSource: function( $image ) {
            var self = this;

            // set new image to html
            self.$element.html( $image );

            // trigger new source event
            self.$element.trigger('new.source.'+pluginName);
        },

        getWidth: function(){
            var self = this;
            var width;

            if($.isFunction(self.options.onGetWidth)) {

                // get width from custom function
                width = self.options.onGetWidth.call(this);
            } else if(self.$container) {

                // get width from container
                width = self.$container.width();
            } else {

                // get window width
                width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
            }

            // multiply width with dpr
            if( self.options.autoDpr ) {
                width *= self.dpr;
            }

            return width;
        },

        getDpr: function(){
            var dpr = 1;

            if (window.screen.systemXDPI !== undefined && window.screen.logicalXDPI !== undefined && window.screen.systemXDPI > window.screen.logicalXDPI) {
                dpr = window.screen.systemXDPI / window.screen.logicalXDPI;
            }

            if (window.devicePixelRatio !== undefined) {
                dpr = window.devicePixelRatio;
            }

            // return only dpr >= 1, because zoomed pages (>100%) return dpr values smaller than 1
            return dpr >= 1 ? dpr : 1;
        },

        createImageWithAttributes: function(source){
            // create default image
            var self = this;
            var $image = $('<img/>');

            // append all given attributes
            for(var i=0; i<self.attributeCount; i++) {
                var attribute = self.options.attributes[i];
                if(typeof(source[attribute]) !== 'undefined' && source[attribute] !== '') {
                    $image.attr(attribute, source[attribute]);
                }
            }

            // add load event listener and set image source
            $image.one('load', function() {
                self.$element.trigger('load.source.responsiveImage');

                // append responsive image to target element after preload
                if( self.options.preload ) {
                    self.setNewSource( $image );
                }
            })
            .attr('src', source.src);

            // check if image is already completed, maybe from browser cache
            if( $image.get(0).complete ) {
                $image.trigger('load');
            }

            return $image;
        },

        initResizeEvent: function(){
            var self = this;

            // attach resize event handler
            if( self.options.resizeEvent !== '' ) {
                $(window).on(self.options.resizeEvent, $.proxy(self.loadResponsiveImage, self));
            }
        }
    });

    $.fn[ pluginName ] = function ( options ) {
        return this.each(function() {
            if ( !$.data( this, 'plugin_' + pluginName ) ) {
                $.data( this, 'plugin_' + pluginName, new Plugin( this, options ) );
                $(this).trigger('ready.'+pluginName);
            }
            $(window).trigger('all.ready.'+pluginName);
        });
    };

})( jQuery, window, document );<commit_msg>Update jquery.responsiveImage.js<commit_after>/*! jquery-responsive-image
 * Copyright (c) 2015 Jan Rembold <janrembold@gmail.com>; License: MIT */

(function ( $, window, document, undefined ) {
    'use strict';

    // Create the defaults
    var pluginName = 'responsiveImage',
        defaults = {
            source:             '> span',
            sourcePrefix:       '',
            container:          null,

            minWidthDefault:    0,
            maxWidthDefault:    Number.MAX_VALUE,
            minDprDefault:      1,

            attributes:         ['title', 'alt', 'class', 'width', 'height'],
            resizeEvent:        'resize',
            preload:            false,
            autoDpr:            false,

            onGetWidth:         null,
            onLoadSources:      null
        };

    // The actual plugin constructor
    function Plugin ( element, options ) {
        var self = this;
        self.$element = $(element);
        self.options = $.extend( {}, defaults, options );

        self.sources = [];
        self.dpr = self.getDpr();
        self.attributeCount = self.options.attributes.length;

        if( typeof( self.$element.data('source-prefix') ) !== 'undefined' ) {
            self.options.sourcePrefix = self.$element.data('source-prefix');
        }

        self.init();
    }

    // Avoid Plugin.prototype conflicts
    $.extend(Plugin.prototype, {
        init: function () {
            var self = this;

            // load sources
            self.sources = self.loadSources();
            if(self.sources.length === 0) {
                return;
            }

            // check container or viewport support - data-container overrides default setting
            var containerSelector = self.$element.attr('data-container') || self.options.container;
            if(containerSelector) {
                self.$container = self.$element.parents(containerSelector);
            }

            // load responsive image
            self.loadResponsiveImage();

            // init resize event with jquery-debouncedwidth support: https://github.com/janrembold/jquery-debouncedwidth
            self.initResizeEvent();
        },

        loadSources: function(){
            var self = this;
            var sources = [];

            if( $.isFunction( self.options.onLoadSources ) ) {

                // use injected source loader
                sources = self.options.onLoadSources( self );
            } else {

                // prepare all necessary image data
                self.$element.find(self.options.source).each(function(){
                    var $source = $(this);

                    // only use images with source
                    if($source.data('src')) {
                        var data = {
                            'src':      self.options.sourcePrefix + $source.data('src'),
                            'minWidth': $source.data('min-width') || self.options.minWidthDefault,
                            'maxWidth': $source.data('max-width') || self.options.maxWidthDefault,
                            'minDpr':   $source.data('min-dpr') || self.options.minDprDefault
                        };

                        // prepare all attributes
                        for(var i=0; i<self.attributeCount; i++) {
                            var attribute = self.options.attributes[i];
                            data[attribute] = $source.data(attribute) || self.$element.data(attribute);
                        }

                        sources.push(data);
                    }
                });
            }

            // sort sources desc by minWidth, maxWidth and minDpr -> largest files first
            sources.sort(function(a, b) {
                if(b.minWidth === a.minWidth) {
                    if(b.maxWidth === a.maxWidth) {
                        return b.minDpr - a.minDpr;
                    }
                    return b.maxWidth - a.maxWidth;
                }
                return b.minWidth - a.minWidth;
            });

            return sources;
        },

        loadResponsiveImage: function () {
            var self = this;
            var newSource;
            var targetWidth = self.getWidth();
            var sourceCount = self.sources.length;

            // search for best image source
            for (var i=0; i<sourceCount; i++) {
                if( self.sources[i].minWidth <= targetWidth &&
                    self.sources[i].maxWidth > targetWidth &&
                    self.sources[i].minDpr <= self.dpr
                ) {
                    newSource = self.sources[i];
                    break;
                }
            }

            // check if image is already loaded
            if(newSource === self.$currentSource) {
                return;
            }

            // set new source
            self.$currentSource = newSource;

            // create new image
            var $image = self.createImageWithAttributes(newSource);

            // append responsive image immediately to target element
            if( !self.options.preload ) {
                self.setNewSource( $image );
            }

        },

        setNewSource: function( $image ) {
            var self = this;

            // set new image to html
            self.$element.html( $image );

            // trigger new source event
            self.$element.trigger('new.source.'+pluginName);
        },

        getWidth: function(){
            var self = this;
            var width;

            if($.isFunction(self.options.onGetWidth)) {

                // get width from custom function
                width = self.options.onGetWidth.call(this);
            } else if(self.$container) {

                // get width from container
                width = self.$container.width();
            } else {

                // get window width
                width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
            }

            // multiply width with dpr
            if( self.options.autoDpr ) {
                width *= self.dpr;
            }

            return width;
        },

        getDpr: function(){
            var dpr = 1;

            if (window.screen.systemXDPI !== undefined && window.screen.logicalXDPI !== undefined && window.screen.systemXDPI > window.screen.logicalXDPI) {
                dpr = window.screen.systemXDPI / window.screen.logicalXDPI;
            } else if (window.devicePixelRatio !== undefined) {
                dpr = window.devicePixelRatio;
            }

            // return only dpr >= 1, because zoomed pages (>100%) return dpr values smaller than 1
            return dpr >= 1 ? dpr : 1;
        },

        createImageWithAttributes: function(source){
            // create default image
            var self = this;
            var $image = $('<img/>');

            // append all given attributes
            for(var i=0; i<self.attributeCount; i++) {
                var attribute = self.options.attributes[i];
                if(typeof(source[attribute]) !== 'undefined' && source[attribute] !== '') {
                    $image.attr(attribute, source[attribute]);
                }
            }

            // add load event listener and set image source
            $image.one('load', function() {
                self.$element.trigger('load.source.responsiveImage');

                // append responsive image to target element after preload
                if( self.options.preload ) {
                    self.setNewSource( $image );
                }
            })
            .attr('src', source.src);

            // check if image is already completed, maybe from browser cache
            if( $image.get(0).complete ) {
                $image.trigger('load');
            }

            return $image;
        },

        initResizeEvent: function(){
            var self = this;

            // attach resize event handler
            if( self.options.resizeEvent !== '' ) {
                $(window).on(self.options.resizeEvent, $.proxy(self.loadResponsiveImage, self));
            }
        }
    });

    $.fn[ pluginName ] = function ( options ) {
        return this.each(function() {
            if ( !$.data( this, 'plugin_' + pluginName ) ) {
                $.data( this, 'plugin_' + pluginName, new Plugin( this, options ) );
                $(this).trigger('ready.'+pluginName);
            }
            $(window).trigger('all.ready.'+pluginName);
        });
    };

})( jQuery, window, document );
<|endoftext|>


<commit_before>/**
 * Created by JetBrains WebStorm.
 * User: saar
 * Date: 13/05/12
 * Time: 13:19
 * To change this template use File | Settings | File Templates.
 */
var SEND_MAIL_NOTIFICATION = true;

var models = require('../models'),
    async = require('async'),
    notificationResource = require('./NotificationResource'),
    templates = require('../lib/templates'),
    mail = require('../lib/mail'),
    config = require('../config'),
    _ = require('underscore');

exports.create_user_notification = create_user_notification = function (notification_type, entity_id, user_id, notificatior_id, sub_entity, url, no_mail, callback) {

    if(typeof no_mail === 'function' && typeof callback !== 'function'){
        callback = no_mail;
        no_mail = null;
    }

    var single_notification_arr = [
        "new_discussion",
        "approved_change_suggestion_you_created",
        "approved_change_suggestion_on_discussion_you_are_part_of",
        "new_information_item_on_subject_you_are_part_of",
        "new_discussion_in_subject_you_are_part_of"
    ];

    var multi_notification_arr = [
        'comment_on_discussion_you_are_part_of',
        "comment_on_discussion_you_created",
        "comment_on_subject_you_are_part_of",
        "comment_on_your_forum_post",
        "comment_on_your_discussion_post",
        "comment_on_change_suggestion_i_created",
        "change_suggestion_on_discussion_you_created",
        "change_suggestion_on_discussion_you_are_part_of"
    ];

    if (notificatior_id && _.indexOf(single_notification_arr, notification_type) == -1) {

        async.waterfall([
            //find existing notification
            function (cbk) {
                notification_type = notification_type + "";
                if (_.contains(multi_notification_arr, notification_type) && sub_entity) {
                    models.Notification.findOne({type:notification_type, 'notificators.sub_entity_id':sub_entity, user_id:user_id, visited: false}, function (err, obj) {
                        cbk(err, obj);
                    });
                }
                else if (entity_id)
                    models.Notification.findOne({type:notification_type, entity_id:entity_id, user_id:user_id}, function (err, obj) {
                        cbk(err, obj);
                    });
                else
                    models.Notification.findOne({type:notification_type, user_id:user_id}, function (err, obj) {
                        cbk(err, obj);
                    });
            },
            function(noti, cbk){
                //check if mail needs to be sent
                if(noti){
                    if(noti.visited)
                        cbk(null, noti, true);
                    else
                        cbk(null, noti, false);
                } else {
                    cbk(null, noti, true);
                }
            },
            function (noti, send_mail, cbk) {
                if (noti) {
                    noti.seen = false;
                    noti.visited = false;
                    noti.update_date = Date.now();

                    var new_notificator = {
                            notificator_id:notificatior_id,
                            sub_entity_id:sub_entity
                        },
                        notificator_exists = _.any(noti.notificators, function (notificator) {
                            return notificator.notificator_id + "" == notificatior_id + ""
                        });

                    if(notificator_exists) {
                        if(_.contains(multi_notification_arr, notification_type)) {
                            noti.notificators.push(new_notificator);
                        }
                    } else {
                        noti.notificators.push(new_notificator);
                    }

                    noti.save(function(err, obj){
                        if(!err && send_mail) {
                            sendNotificationToUser(obj);
                        }
                        cbk(err, obj);
                    });

                } else {
                    create_new_notification(notification_type, entity_id, user_id, notificatior_id, sub_entity, url, !send_mail, function (err, obj) {
                        cbk(err, obj);
                    });
                }
            }
        ],
        function (err, obj) {
            callback(err, obj);
        });
    } else {
        create_new_notification(notification_type, entity_id, user_id, notificatior_id, sub_entity, url, no_mail,function (err, obj) {
            callback(err, obj);
        });
    }
};

var create_new_notification = function (notification_type, entity_id, user_id, notificatior_id, sub_entity_id, url, no_mail, callback) {

    if(typeof no_mail === 'function' && typeof callback !== 'function'){
        callback = no_mail;
        no_mail = null;
    }

    var notification = new models.Notification();
    var notificator = {
        notificator_id:notificatior_id ? notificatior_id : null,
        sub_entity_id:sub_entity_id
    };

    notification.user_id = user_id;
    notification.notificators = notificator;
    notification.type = notification_type;
    notification.entity_id = entity_id;
    notification.url = url;
    notification.seen = false;
    notification.update_date = new Date();
    notification.visited = false;

    notification.save(function (err, obj) {
        if (err)
            console.error(err);
        callback(null, obj || notification);
        if (!err && obj && !no_mail)
            sendNotificationToUser(obj);
    });
};

/***
 * Send notification to user through mail or other external API
 * Checks if user should receive notification according to settings
 * @param notification
 * Notification object
 * @param last_update_date
 * notification last update date, or null if the notification is new
 * @param callback
 * function(err)
 */
var sendNotificationToUser = function (notification) {
    /**
     * Waterfall:
     * 1) Get user email
     * 2) Check user mail configuration
     * 3) create text message
     * 4) send message
     */

    var email;
    var  uru_group = [
        /*'saarsta@gmail.com',*/
        'themarianne@gmail.com',
        'maria@empeeric.com'
    ];

    if (SEND_MAIL_NOTIFICATION)
        async.waterfall([
            // 1) Get user email
            function (cbk) {
                models.User.findById(notification.user_id._doc ? notification.user_id.id : notification.user_id, cbk);
            },

            // 2) Check user mail configuration
            function(user, cbk){
                if(user.mail_notification_configuration['get_alert_of_' + notification.type] && user.mail_notification_configuration.get_mails){
                    cbk(null, user);
                } else {
                    console.log('User should not receive mail because of his mail configuration');
                    cbk('break');
                }
            },

            // 3.1) create text message
            function(user, cbk){
                // notification populate references by notification type
                email = user.email;
                notificationResource.populateNotifications({objects:[notification]}, user.id, function(err, result){
                    cbk(err, result);
                });
            },

            // 3.2) create text message
            function (results, cbk) {
                var notification = results.objects[0];

                notification.entity_name = notification.name || '';
                notification.description_of_notificators = notification.description_of_notificators || '';
                notification.message_of_notificators = notification.message_of_notificators || '';
                templates.renderTemplate('notifications/' + notification.type, notification, function(err, result){
                    cbk(err, result);
                });
            },
            // 4) send message
            function (message, cbk) {
                mail.sendMailFromTemplate(email, message, cbk);
            }
        ],
            // Final
            function (err) {
                if (err) {
                    if (err != 'break') {
                        /*console.error('failed sending notification to user');
                        console.error(err);
                        console.trace();*/
                    }
                }
                else {
                    console.log('email ' + notification.type + ' sent to ' + email);
                    notification.visited = false;
                    notification.mail_was_sent = true;

                    notification.save(function (err) {
                        if (err) {
                            console.error('saving notification flag failed');
                        }
                    });
                }
            });
};

exports.update_user_notification = function (notification_type, obj_id, user, callback) {

};

exports.updateVisited = function (user, url) {
    models.Notification.update({user_id:user._id, url:url}, {$set:{visited:true}}, {multi:true}, function (err, count) {
        if (err) {
            console.error('failed setting notification visited to true', err);
        }
    })
};

function updateNotificationToSendMail(noti){
    models.Notification.update({_id: noti._id}, {$set: {mail_was_sent: false}}, function(err, num){
        if(err){
            console.error("could not set notification mail_was_sent flag to false");
            console.error(err);
        }
    })
}

models.InformationItem.onPreSave(function(next){
    var self = this;

    if(self.isNew) {
        async.each(self.subjects, function(subject_id, callback){
            models.User.find().where('subjects', subject_id).exec(function(err, users){
                if(err) next();
                async.each(users, function(user, cbk){
                    create_user_notification("new_information_item_on_subject_you_are_part_of", self._id, user._id, user._id, subject_id, "/discussions/subject/" + subject_id, function (err, results) {
                        cbk(err, results);
                    });
                }, function(err){
                    callback(err);
                });
            });
        } ,function(err){
            next();
        });
    } else {
        next();
    }
});

models.Discussion.onPreSave(function(next){
    var self = this;

    if(self.isNew) {
        models.User.find().where('subjects', self.subject_id).exec(function(err, users){
            if(err) next();
            async.each(users, function(user, cbk){
                create_user_notification("new_discussion_in_subject_you_are_part_of", self._id, user._id, self.creator_id, self.subject_id, "/discussions/" + self._id.toString(), function (err, results) {
                    cbk(err, results);
                });
            }, function(err){
                next();
            });
        });
    } else {
        next();
    }
});

//approved_info_item_i_created
if (/notifications\.js/.test(process.argv[1])) {
    var app = require('../app');

    console.log('testing');
    //function(notification_type, entity_id, user_id, notificatior_id, sub_entity_id, callback){
    //4f90064e360b9b01000000ac --info item
    //4fcdf7180a381201000005b3 --disc

    //a_dicussion_created_with_info_item_that_you_created
    //  sub //4fce400ccdd0570100000216

    //501fcef1e6ae520017000662 --הצעה לשינוי שהתקבלה
    setTimeout(function () {
        create_new_notification('comment_on_discussion_you_created',
            '4fcdf7180a381201000005b3', '4ff1b29aabf64e440f00013a', '4f45145968766b0100000002', '501fcef1e6ae520017000662', function (err) {
                console.log(err);
            });

    }, 1000);
}<commit_msg>add aharon to uru group<commit_after>/**
 * Created by JetBrains WebStorm.
 * User: saar
 * Date: 13/05/12
 * Time: 13:19
 * To change this template use File | Settings | File Templates.
 */
var SEND_MAIL_NOTIFICATION = true;

var models = require('../models'),
    async = require('async'),
    notificationResource = require('./NotificationResource'),
    templates = require('../lib/templates'),
    mail = require('../lib/mail'),
    config = require('../config'),
    _ = require('underscore');

exports.create_user_notification = create_user_notification = function (notification_type, entity_id, user_id, notificatior_id, sub_entity, url, no_mail, callback) {

    if(typeof no_mail === 'function' && typeof callback !== 'function'){
        callback = no_mail;
        no_mail = null;
    }

    var single_notification_arr = [
        "new_discussion",
        "approved_change_suggestion_you_created",
        "approved_change_suggestion_on_discussion_you_are_part_of",
        "new_information_item_on_subject_you_are_part_of",
        "new_discussion_in_subject_you_are_part_of"
    ];

    var multi_notification_arr = [
        'comment_on_discussion_you_are_part_of',
        "comment_on_discussion_you_created",
        "comment_on_subject_you_are_part_of",
        "comment_on_your_forum_post",
        "comment_on_your_discussion_post",
        "comment_on_change_suggestion_i_created",
        "change_suggestion_on_discussion_you_created",
        "change_suggestion_on_discussion_you_are_part_of"
    ];

    if (notificatior_id && _.indexOf(single_notification_arr, notification_type) == -1) {

        async.waterfall([
            //find existing notification
            function (cbk) {
                notification_type = notification_type + "";
                if (_.contains(multi_notification_arr, notification_type) && sub_entity) {
                    models.Notification.findOne({type:notification_type, 'notificators.sub_entity_id':sub_entity, user_id:user_id, visited: false}, function (err, obj) {
                        cbk(err, obj);
                    });
                }
                else if (entity_id)
                    models.Notification.findOne({type:notification_type, entity_id:entity_id, user_id:user_id}, function (err, obj) {
                        cbk(err, obj);
                    });
                else
                    models.Notification.findOne({type:notification_type, user_id:user_id}, function (err, obj) {
                        cbk(err, obj);
                    });
            },
            function(noti, cbk){
                //check if mail needs to be sent
                if(noti){
                    if(noti.visited)
                        cbk(null, noti, true);
                    else
                        cbk(null, noti, false);
                } else {
                    cbk(null, noti, true);
                }
            },
            function (noti, send_mail, cbk) {
                if (noti) {
                    noti.seen = false;
                    noti.visited = false;
                    noti.update_date = Date.now();

                    var new_notificator = {
                            notificator_id:notificatior_id,
                            sub_entity_id:sub_entity
                        },
                        notificator_exists = _.any(noti.notificators, function (notificator) {
                            return notificator.notificator_id + "" == notificatior_id + ""
                        });

                    if(notificator_exists) {
                        if(_.contains(multi_notification_arr, notification_type)) {
                            noti.notificators.push(new_notificator);
                        }
                    } else {
                        noti.notificators.push(new_notificator);
                    }

                    noti.save(function(err, obj){
                        if(!err && send_mail) {
                            sendNotificationToUser(obj);
                        }
                        cbk(err, obj);
                    });

                } else {
                    create_new_notification(notification_type, entity_id, user_id, notificatior_id, sub_entity, url, !send_mail, function (err, obj) {
                        cbk(err, obj);
                    });
                }
            }
        ],
        function (err, obj) {
            callback(err, obj);
        });
    } else {
        create_new_notification(notification_type, entity_id, user_id, notificatior_id, sub_entity, url, no_mail,function (err, obj) {
            callback(err, obj);
        });
    }
};

var create_new_notification = function (notification_type, entity_id, user_id, notificatior_id, sub_entity_id, url, no_mail, callback) {

    if(typeof no_mail === 'function' && typeof callback !== 'function'){
        callback = no_mail;
        no_mail = null;
    }

    var notification = new models.Notification();
    var notificator = {
        notificator_id:notificatior_id ? notificatior_id : null,
        sub_entity_id:sub_entity_id
    };

    notification.user_id = user_id;
    notification.notificators = notificator;
    notification.type = notification_type;
    notification.entity_id = entity_id;
    notification.url = url;
    notification.seen = false;
    notification.update_date = new Date();
    notification.visited = false;

    notification.save(function (err, obj) {
        if (err)
            console.error(err);
        callback(null, obj || notification);
        if (!err && obj && !no_mail)
            sendNotificationToUser(obj);
    });
};

/***
 * Send notification to user through mail or other external API
 * Checks if user should receive notification according to settings
 * @param notification
 * Notification object
 * @param last_update_date
 * notification last update date, or null if the notification is new
 * @param callback
 * function(err)
 */
var sendNotificationToUser = function (notification) {
    /**
     * Waterfall:
     * 1) Get user email
     * 2) Check user mail configuration
     * 3) create text message
     * 4) send message
     */

    var email;
    var  uru_group = [
        'saarsta@gmail.com',
        'themarianne@gmail.com',
        'maria@empeeric.com',
        'aharon.porath@gmail.com',
        'aharon@uru.org.il'
    ];

    if (SEND_MAIL_NOTIFICATION)
        async.waterfall([
            // 1) Get user email
            function (cbk) {
                models.User.findById(notification.user_id._doc ? notification.user_id.id : notification.user_id, cbk);
            },

            // 2) Check user mail configuration
            function(user, cbk){
                if(user.mail_notification_configuration['get_alert_of_' + notification.type] && user.mail_notification_configuration.get_mails){
                    cbk(null, user);
                } else {
                    console.log('User should not receive mail because of his mail configuration');
                    cbk('break');
                }
            },

            // 3.1) create text message
            function(user, cbk){
                // notification populate references by notification type
                email = user.email;
                notificationResource.populateNotifications({objects:[notification]}, user.id, function(err, result){
                    cbk(err, result);
                });
            },

            // 3.2) create text message
            function (results, cbk) {
                var notification = results.objects[0];

                notification.entity_name = notification.name || '';
                notification.description_of_notificators = notification.description_of_notificators || '';
                notification.message_of_notificators = notification.message_of_notificators || '';
                templates.renderTemplate('notifications/' + notification.type, notification, function(err, result){
                    cbk(err, result);
                });
            },
            // 4) send message
            function (message, cbk) {
                mail.sendMailFromTemplate(email, message, cbk);
            }
        ],
            // Final
            function (err) {
                if (err) {
                    if (err != 'break') {
                        /*console.error('failed sending notification to user');
                        console.error(err);
                        console.trace();*/
                    }
                }
                else {
                    console.log('email ' + notification.type + ' sent to ' + email);
                    notification.visited = false;
                    notification.mail_was_sent = true;

                    notification.save(function (err) {
                        if (err) {
                            console.error('saving notification flag failed');
                        }
                    });
                }
            });
};

exports.update_user_notification = function (notification_type, obj_id, user, callback) {

};

exports.updateVisited = function (user, url) {
    models.Notification.update({user_id:user._id, url:url}, {$set:{visited:true}}, {multi:true}, function (err, count) {
        if (err) {
            console.error('failed setting notification visited to true', err);
        }
    })
};

function updateNotificationToSendMail(noti){
    models.Notification.update({_id: noti._id}, {$set: {mail_was_sent: false}}, function(err, num){
        if(err){
            console.error("could not set notification mail_was_sent flag to false");
            console.error(err);
        }
    })
}

models.InformationItem.onPreSave(function(next){
    var self = this;

    if(self.isNew) {
        async.each(self.subjects, function(subject_id, callback){
            models.User.find().where('subjects', subject_id).exec(function(err, users){
                if(err) next();
                async.each(users, function(user, cbk){
                    create_user_notification("new_information_item_on_subject_you_are_part_of", self._id, user._id, user._id, subject_id, "/discussions/subject/" + subject_id, function (err, results) {
                        cbk(err, results);
                    });
                }, function(err){
                    callback(err);
                });
            });
        } ,function(err){
            next();
        });
    } else {
        next();
    }
});

models.Discussion.onPreSave(function(next){
    var self = this;

    if(self.isNew) {
        models.User.find().where('subjects', self.subject_id).exec(function(err, users){
            if(err) next();
            async.each(users, function(user, cbk){
                create_user_notification("new_discussion_in_subject_you_are_part_of", self._id, user._id, self.creator_id, self.subject_id, "/discussions/" + self._id.toString(), function (err, results) {
                    cbk(err, results);
                });
            }, function(err){
                next();
            });
        });
    } else {
        next();
    }
});

//approved_info_item_i_created
if (/notifications\.js/.test(process.argv[1])) {
    var app = require('../app');

    console.log('testing');
    //function(notification_type, entity_id, user_id, notificatior_id, sub_entity_id, callback){
    //4f90064e360b9b01000000ac --info item
    //4fcdf7180a381201000005b3 --disc

    //a_dicussion_created_with_info_item_that_you_created
    //  sub //4fce400ccdd0570100000216

    //501fcef1e6ae520017000662 --הצעה לשינוי שהתקבלה
    setTimeout(function () {
        create_new_notification('comment_on_discussion_you_created',
            '4fcdf7180a381201000005b3', '4ff1b29aabf64e440f00013a', '4f45145968766b0100000002', '501fcef1e6ae520017000662', function (err) {
                console.log(err);
            });

    }, 1000);
}<|endoftext|>


<commit_before>import isBrowser from './isBrowser';

const isIE = isBrowser ? !!document.documentElement.currentStyle : false;

const HIDDEN_TEXTAREA_STYLE = {
  'min-height': '0',
  'max-height': 'none',
  height: '0',
  visibility: 'hidden',
  overflow: 'hidden',
  position: 'absolute',
  'z-index': '-1000',
  top: '0',
  right: '0',
};

const SIZING_STYLE = [
  'letter-spacing',
  'line-height',
  'font-family',
  'font-weight',
  'font-size',
  'font-style',
  'tab-size',
  'text-rendering',
  'text-transform',
  'width',
  'text-indent',
  'padding-top',
  'padding-right',
  'padding-bottom',
  'padding-left',
  'border-top-width',
  'border-right-width',
  'border-bottom-width',
  'border-left-width',
  'box-sizing',
];

let computedStyleCache = {};
const hiddenTextarea = isBrowser && document.createElement('textarea');

const forceHiddenStyles = node => {
  Object.keys(HIDDEN_TEXTAREA_STYLE).forEach(key => {
    node.style.setProperty(key, HIDDEN_TEXTAREA_STYLE[key], 'important');
  });
};

if (isBrowser) {
  forceHiddenStyles(hiddenTextarea);
}

export default function calculateNodeHeight(
  uiTextNode,
  uid,
  useCache = false,
  minRows = null,
  maxRows = null,
) {
  if (hiddenTextarea.parentNode === null) {
    document.body.appendChild(hiddenTextarea);
  }

  // Copy all CSS properties that have an impact on the height of the content in
  // the textbox
  const nodeStyling = calculateNodeStyling(uiTextNode, uid, useCache);

  if (nodeStyling === null) {
    return null;
  }

  const { paddingSize, borderSize, boxSizing, sizingStyle } = nodeStyling;

  // Need to have the overflow attribute to hide the scrollbar otherwise
  // text-lines will not calculated properly as the shadow will technically be
  // narrower for content
  Object.keys(sizingStyle).forEach(key => {
    hiddenTextarea.style[key] = sizingStyle[key];
  });
  forceHiddenStyles(hiddenTextarea);
  hiddenTextarea.value = uiTextNode.value || uiTextNode.placeholder || 'x';

  let minHeight = -Infinity;
  let maxHeight = Infinity;
  let height = hiddenTextarea.scrollHeight;

  if (boxSizing === 'border-box') {
    // border-box: add border, since height = content + padding + border
    height = height + borderSize;
  } else if (boxSizing === 'content-box') {
    // remove padding, since height = content
    height = height - paddingSize;
  }

  // measure height of a textarea with a single row
  hiddenTextarea.value = 'x';
  const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;

  if (minRows !== null || maxRows !== null) {
    if (minRows !== null) {
      minHeight = singleRowHeight * minRows;
      if (boxSizing === 'border-box') {
        minHeight = minHeight + paddingSize + borderSize;
      }
      height = Math.max(minHeight, height);
    }
    if (maxRows !== null) {
      maxHeight = singleRowHeight * maxRows;
      if (boxSizing === 'border-box') {
        maxHeight = maxHeight + paddingSize + borderSize;
      }
      height = Math.min(maxHeight, height);
    }
  }

  const rowCount = Math.floor(height / singleRowHeight);

  return { height, minHeight, maxHeight, rowCount };
}

function calculateNodeStyling(node, uid, useCache = false) {
  if (useCache && computedStyleCache[uid]) {
    return computedStyleCache[uid];
  }

  const style = window.getComputedStyle(node);

  if (style === null) {
    return null;
  }

  let sizingStyle = SIZING_STYLE.reduce((obj, name) => {
    obj[name] = style.getPropertyValue(name);
    return obj;
  }, {});

  const boxSizing = sizingStyle['box-sizing'];

  // probably node is detached from DOM, can't read computed dimensions
  if (boxSizing === '') {
    return null;
  }

  // IE (Edge has already correct behaviour) returns content width as computed width
  // so we need to add manually padding and border widths
  if (isIE && boxSizing === 'border-box') {
    sizingStyle.width =
      parseFloat(sizingStyle.width) +
      parseFloat(style['border-right-width']) +
      parseFloat(style['border-left-width']) +
      parseFloat(style['padding-right']) +
      parseFloat(style['padding-left']) +
      'px';
  }

  const paddingSize =
    parseFloat(sizingStyle['padding-bottom']) +
    parseFloat(sizingStyle['padding-top']);

  const borderSize =
    parseFloat(sizingStyle['border-bottom-width']) +
    parseFloat(sizingStyle['border-top-width']);

  const nodeInfo = {
    sizingStyle,
    paddingSize,
    borderSize,
    boxSizing,
  };

  if (useCache) {
    computedStyleCache[uid] = nodeInfo;
  }

  return nodeInfo;
}

export const purgeCache = uid => delete computedStyleCache[uid];
<commit_msg>Removed doubled condition logic<commit_after>import isBrowser from './isBrowser';

const isIE = isBrowser ? !!document.documentElement.currentStyle : false;

const HIDDEN_TEXTAREA_STYLE = {
  'min-height': '0',
  'max-height': 'none',
  height: '0',
  visibility: 'hidden',
  overflow: 'hidden',
  position: 'absolute',
  'z-index': '-1000',
  top: '0',
  right: '0',
};

const SIZING_STYLE = [
  'letter-spacing',
  'line-height',
  'font-family',
  'font-weight',
  'font-size',
  'font-style',
  'tab-size',
  'text-rendering',
  'text-transform',
  'width',
  'text-indent',
  'padding-top',
  'padding-right',
  'padding-bottom',
  'padding-left',
  'border-top-width',
  'border-right-width',
  'border-bottom-width',
  'border-left-width',
  'box-sizing',
];

let computedStyleCache = {};
const hiddenTextarea = isBrowser && document.createElement('textarea');

const forceHiddenStyles = node => {
  Object.keys(HIDDEN_TEXTAREA_STYLE).forEach(key => {
    node.style.setProperty(key, HIDDEN_TEXTAREA_STYLE[key], 'important');
  });
};

if (isBrowser) {
  forceHiddenStyles(hiddenTextarea);
}

export default function calculateNodeHeight(
  uiTextNode,
  uid,
  useCache = false,
  minRows = null,
  maxRows = null,
) {
  if (hiddenTextarea.parentNode === null) {
    document.body.appendChild(hiddenTextarea);
  }

  // Copy all CSS properties that have an impact on the height of the content in
  // the textbox
  const nodeStyling = calculateNodeStyling(uiTextNode, uid, useCache);

  if (nodeStyling === null) {
    return null;
  }

  const { paddingSize, borderSize, boxSizing, sizingStyle } = nodeStyling;

  // Need to have the overflow attribute to hide the scrollbar otherwise
  // text-lines will not calculated properly as the shadow will technically be
  // narrower for content
  Object.keys(sizingStyle).forEach(key => {
    hiddenTextarea.style[key] = sizingStyle[key];
  });
  forceHiddenStyles(hiddenTextarea);
  hiddenTextarea.value = uiTextNode.value || uiTextNode.placeholder || 'x';

  let minHeight = -Infinity;
  let maxHeight = Infinity;
  let height = hiddenTextarea.scrollHeight;

  if (boxSizing === 'border-box') {
    // border-box: add border, since height = content + padding + border
    height = height + borderSize;
  } else if (boxSizing === 'content-box') {
    // remove padding, since height = content
    height = height - paddingSize;
  }

  // measure height of a textarea with a single row
  hiddenTextarea.value = 'x';
  const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;

  if (minRows !== null) {
    minHeight = singleRowHeight * minRows;
    if (boxSizing === 'border-box') {
      minHeight = minHeight + paddingSize + borderSize;
    }
    height = Math.max(minHeight, height);
  }

  if (maxRows !== null) {
    maxHeight = singleRowHeight * maxRows;
    if (boxSizing === 'border-box') {
      maxHeight = maxHeight + paddingSize + borderSize;
    }
    height = Math.min(maxHeight, height);
  }

  const rowCount = Math.floor(height / singleRowHeight);

  return { height, minHeight, maxHeight, rowCount };
}

function calculateNodeStyling(node, uid, useCache = false) {
  if (useCache && computedStyleCache[uid]) {
    return computedStyleCache[uid];
  }

  const style = window.getComputedStyle(node);

  if (style === null) {
    return null;
  }

  let sizingStyle = SIZING_STYLE.reduce((obj, name) => {
    obj[name] = style.getPropertyValue(name);
    return obj;
  }, {});

  const boxSizing = sizingStyle['box-sizing'];

  // probably node is detached from DOM, can't read computed dimensions
  if (boxSizing === '') {
    return null;
  }

  // IE (Edge has already correct behaviour) returns content width as computed width
  // so we need to add manually padding and border widths
  if (isIE && boxSizing === 'border-box') {
    sizingStyle.width =
      parseFloat(sizingStyle.width) +
      parseFloat(style['border-right-width']) +
      parseFloat(style['border-left-width']) +
      parseFloat(style['padding-right']) +
      parseFloat(style['padding-left']) +
      'px';
  }

  const paddingSize =
    parseFloat(sizingStyle['padding-bottom']) +
    parseFloat(sizingStyle['padding-top']);

  const borderSize =
    parseFloat(sizingStyle['border-bottom-width']) +
    parseFloat(sizingStyle['border-top-width']);

  const nodeInfo = {
    sizingStyle,
    paddingSize,
    borderSize,
    boxSizing,
  };

  if (useCache) {
    computedStyleCache[uid] = nodeInfo;
  }

  return nodeInfo;
}

export const purgeCache = uid => delete computedStyleCache[uid];
<|endoftext|>


<commit_before>/*    Copyright 2016 Firewalla LLC
 *
 *    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';

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

let express = require('express');
let router = express.Router();
const passport = require('passport')

let SysManager = require('../../net2/SysManager.js');
let sysManager = new SysManager('info');

let sysInfo = require('../../extension/sysinfo/SysInfo.js');

let zlib = require('zlib');

let redis = require('redis');

let Firewalla = require('../../net2/Firewalla.js');

let Promise = require('bluebird');

let NetBotTool = require('../../net2/NetBotTool');
let netBotTool = new NetBotTool();

let flowTool = require('../../net2/FlowTool')();

let async = require('asyncawait/async');
let await = require('asyncawait/await');

/* system api */
router.get('/info',
//    passport.authenticate('bearer', { session: false }),
           function(req, res, next) {
             res.json({
               ip_address: sysManager.myIp(),
               mac_address: sysManager.myMAC(),
               gateway: sysManager.myGateway(),
               subnet: sysManager.mySubnet(),
               dns: sysManager.myDNS(),
               ddns: sysManager.myDDNS(),
               info: sysInfo.getSysInfo()
             });
           });

router.get('/status',
           (req, res, next) => {
             let HostManager = require('../../net2/HostManager.js');
             let hm = new HostManager('system_api', 'client', 'info');
             let compressed = req.query.compressed;

             hm.toJson(true, (err, json) => {
               if(err) {
                 res.status(500).send({error: err});
                 return;
               }

               if(compressed) {
                 let jsonString = JSON.stringify(json);
                 zlib.deflate(new Buffer(jsonString, 'utf8'), (err, output) => {
                   if(err) {
                     res.status(500).send({error: err});
                     return;
                   }

                   res.json({
                     payload: output.toString('base64')
                   });
                 });
               } else {
                 res.json(json);
               }

             });
           });

router.get('/flow',
    function(req, res, next) {

    });

router.get('/topDownload',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};
    netBotTool.prepareTopDownloadFlows(json, {
      begin: begin,
      end: end
    }).then(() => {
      res.json(json);
    }).catch((err) => {
      res.status(500).send({error: err});
    })
  }
);

router.get('/topUpload',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};
    netBotTool.prepareTopUploadFlows(json, {
      begin: begin,
      end: end
    }).then(() => {
      res.json(json);
    }).catch((err) => {
      res.status(500).send({error: err});
    })
  }
);

router.get('/recent',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};
    flowTool.prepareRecentFlows(json, {
      begin: begin,
      end: end
    }).then(() => {
      res.json(json);
    }).catch((err) => {
      res.status(500).send({error: err});
    })
  }
);

router.get('/apps',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};

    async(() => {
      await (netBotTool.prepareAppActivitiesFlows(json, {
        begin: begin,
        end: end
      }))
      await (netBotTool.prepareDetailedAppFlows(json, {
        begin: begin,
        end: end
      }))
      res.json(json)
    })().catch((err) => {
      log.error("Failed to process /apps: ", err, err.stack, {})
      res.status(500).send({error: err});
    })
  }
);

router.get('/perfstat',
          function(req, res, next) {
            sysInfo.getPerfStats((err, stat) => {
              if(err) {
                res.status(500);
                res.send('server error');
                return;
              }

              res.json(stat);
            });
          });

router.get('/heapdump',
  (req, res, next) => {
    let process = req.query.process;

    process = process || "FireApi";

    let file = Firewalla.getTempFolder() + "/" + process + "-heapdump-" + new Date() /1000 + ".heapsnapshot";

    switch(process) {
      case "FireApi":
        sysInfo.getHeapDump(file, (err, file) => {
          if(err) {
            res.status(500);
            res.send('server error: ' + err);
            return;
          }

          res.download(file);
        });

        break;
      case "FireMain":
      case "FireMon":
        let rclient = redis.createClient();
        let sclient = redis.createClient();

        rclient.on("message", (channel, message) => {
          if(channel === "heapdump_done" && message ) {
            try {
              let msg = JSON.parse(message);
              let file = msg.file;
              let title = msg.title;
              if(title === process) {
                res.download(file);
              }
            } catch (err) {
              log.error("Failed to parse payload of heapdump_done message: ", message, err, {});
            }
          }
        });
        rclient.subscribe("heapdump_done");
        sclient.publish("heapdump", JSON.stringify({
          title: process,
          file: file
        }));

        break;
      default:
        res.status(404).send("");
    }

  });

module.exports = router;
<commit_msg>add api for categories<commit_after>/*    Copyright 2016 Firewalla LLC
 *
 *    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';

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

let express = require('express');
let router = express.Router();
const passport = require('passport')

let SysManager = require('../../net2/SysManager.js');
let sysManager = new SysManager('info');

let sysInfo = require('../../extension/sysinfo/SysInfo.js');

let zlib = require('zlib');

let redis = require('redis');

let Firewalla = require('../../net2/Firewalla.js');

let Promise = require('bluebird');

let NetBotTool = require('../../net2/NetBotTool');
let netBotTool = new NetBotTool();

let flowTool = require('../../net2/FlowTool')();

let async = require('asyncawait/async');
let await = require('asyncawait/await');

/* system api */
router.get('/info',
//    passport.authenticate('bearer', { session: false }),
           function(req, res, next) {
             res.json({
               ip_address: sysManager.myIp(),
               mac_address: sysManager.myMAC(),
               gateway: sysManager.myGateway(),
               subnet: sysManager.mySubnet(),
               dns: sysManager.myDNS(),
               ddns: sysManager.myDDNS(),
               info: sysInfo.getSysInfo()
             });
           });

router.get('/status',
           (req, res, next) => {
             let HostManager = require('../../net2/HostManager.js');
             let hm = new HostManager('system_api', 'client', 'info');
             let compressed = req.query.compressed;

             hm.toJson(true, (err, json) => {
               if(err) {
                 res.status(500).send({error: err});
                 return;
               }

               if(compressed) {
                 let jsonString = JSON.stringify(json);
                 zlib.deflate(new Buffer(jsonString, 'utf8'), (err, output) => {
                   if(err) {
                     res.status(500).send({error: err});
                     return;
                   }

                   res.json({
                     payload: output.toString('base64')
                   });
                 });
               } else {
                 res.json(json);
               }

             });
           });

router.get('/flow',
    function(req, res, next) {

    });

router.get('/topDownload',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};
    netBotTool.prepareTopDownloadFlows(json, {
      begin: begin,
      end: end
    }).then(() => {
      res.json(json);
    }).catch((err) => {
      res.status(500).send({error: err});
    })
  }
);

router.get('/topUpload',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};
    netBotTool.prepareTopUploadFlows(json, {
      begin: begin,
      end: end
    }).then(() => {
      res.json(json);
    }).catch((err) => {
      res.status(500).send({error: err});
    })
  }
);

router.get('/recent',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};
    flowTool.prepareRecentFlows(json, {
      begin: begin,
      end: end
    }).then(() => {
      res.json(json);
    }).catch((err) => {
      res.status(500).send({error: err});
    })
  }
);

router.get('/apps',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};

    async(() => {
      await (netBotTool.prepareAppActivitiesFlows(json, {
        begin: begin,
        end: end
      }))
      await (netBotTool.prepareDetailedAppFlows(json, {
        begin: begin,
        end: end
      }))
      res.json(json)
    })().catch((err) => {
      log.error("Failed to process /apps: ", err, err.stack, {})
      res.status(500).send({error: err});
    })
  }
);

router.get('/categories',
  (req, res, next) => {
    let now = new Date() / 1000;
    let end = Math.floor(now / 3600) * 3600;
    let begin = end - 3600;
    let json = {};

    async(() => {
      await (netBotTool.prepareCategoryActivitiesFlows(json, {
        begin: begin,
        end: end
      }))
      await (netBotTool.prepareDetailedCategoryFlows(json, {
        begin: begin,
        end: end
      }))
      res.json(json)
    })().catch((err) => {
      log.error("Failed to process /categories: ", err, err.stack, {})
      res.status(500).send({error: err});
    })
  }
);

router.get('/perfstat',
          function(req, res, next) {
            sysInfo.getPerfStats((err, stat) => {
              if(err) {
                res.status(500);
                res.send('server error');
                return;
              }

              res.json(stat);
            });
          });

router.get('/heapdump',
  (req, res, next) => {
    let process = req.query.process;

    process = process || "FireApi";

    let file = Firewalla.getTempFolder() + "/" + process + "-heapdump-" + new Date() /1000 + ".heapsnapshot";

    switch(process) {
      case "FireApi":
        sysInfo.getHeapDump(file, (err, file) => {
          if(err) {
            res.status(500);
            res.send('server error: ' + err);
            return;
          }

          res.download(file);
        });

        break;
      case "FireMain":
      case "FireMon":
        let rclient = redis.createClient();
        let sclient = redis.createClient();

        rclient.on("message", (channel, message) => {
          if(channel === "heapdump_done" && message ) {
            try {
              let msg = JSON.parse(message);
              let file = msg.file;
              let title = msg.title;
              if(title === process) {
                res.download(file);
              }
            } catch (err) {
              log.error("Failed to parse payload of heapdump_done message: ", message, err, {});
            }
          }
        });
        rclient.subscribe("heapdump_done");
        sclient.publish("heapdump", JSON.stringify({
          title: process,
          file: file
        }));

        break;
      default:
        res.status(404).send("");
    }

  });

module.exports = router;
<|endoftext|>