<commit_before>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
"use strict";

var utils   = require(__dirname + '/lib/utils'); // Get common adapter utils
var path    = require('path');
var dataDir = path.normalize(utils.controllerDir + '/' + require(utils.controllerDir + '/lib/tools').getDefaultDataDir());
var fs      = require('fs');

var history = {};

var adapter = utils.adapter({

    name: 'history',

    objectChange: function (id, obj) {
        if (obj && obj.common && obj.common.history && obj.common.history[adapter.namespace]) {
            history[id] = obj.common.history;
            adapter.log.info('enabled logging of ' + id);
        } else {
            if (history[id]) {
                adapter.log.info('disabled logging of ' + id);
                delete history[id];
            }
        }
    },

    stateChange: function (id, state) {
        pushHistory(id, state);
    },

    unload: function (callback) {
        finish(callback);
    },

    ready: function () {
        main();
    },

    message: function (obj) {
        processMessage(obj);
    }
});

process.on('SIGINT', function () {
    if (adapter && adapter.setState) {
        finish();
    }
});

function finish(callback) {
    for (var id in history) {
        if (history[id][adapter.namespace].list && history[id][adapter.namespace].list.length) {
            adapter.log.debug('Store th rest for ' + id);
            appendFile(id, history[id][adapter.namespace].list);
        }
    }
    if (callback) callback();
}

function processMessage(msg) {
    if (msg.command == 'getHistory') {
        getHistory(msg);
    }
}

function main() {
    adapter.config.storeDir = adapter.config.storeDir || 'history';
    adapter.config.storeDir = adapter.config.storeDir.replace(/\\/g, '/');
    // remove last /
    if (adapter.config.storeDir[adapter.config.storeDir.length - 1] == '/') {
        adapter.config.storeDir = adapter.config.storeDir.substring(0, adapter.config.storeDir.length - 1);
    }

    if (adapter.config.storeDir[0] !== '/' && !adapter.config.storeDir.match(/^\w:\//)) {
        adapter.config.storeDir = dataDir + adapter.config.storeDir;
    }
    adapter.config.storeDir += '/';

    adapter.objects.getObjectView('history', 'state', {}, function (err, doc) {
        if (doc && doc.rows) {
            for (var i = 0, l = doc.rows.length; i < l; i++) {
                if (doc.rows[i].value) {
                    history[doc.rows[i].id] = doc.rows[i].value;
                    // convert old value
                    if (history[doc.rows[i].id].enabled !== undefined) {
                        history[doc.rows[i].id] = history[doc.rows[i].id].enabled ? {'history.0': history[doc.rows[i].id]} : {};
                    }
                    if (!history[doc.rows[i].id][adapter.namespace] || history[doc.rows[i].id][adapter.namespace].enabled === false) {
                        delete history[doc.rows[i].id];
                    } else {
                        adapter.log.info('enabled logging of ' + doc.rows[i].id);
                        history[doc.rows[i].id][adapter.namespace].maxLength = parseInt(history[doc.rows[i].id][adapter.namespace].maxLength || adapter.config.maxLength, 10);
                    }
                }
            }
        }
    });

    adapter.subscribeForeignStates('*');
    adapter.subscribeForeignObjects('*');
}

function pushHistory(id, state) {
    // Push into redis
    if (history[id]) {
        var settings = history[id][adapter.namespace];

        if (!settings || !state) return;

        if (history[id].state && settings.changesOnly && (state.ts !== state.lc)) return;

        history[id].state = state;

        // Do not store values ofter than 1 second
        if (!history[id].timeout) {

            history[id].timeout = setTimeout(function (_id) {
                if (!history[_id]) return;
                var _settings = history[_id][adapter.namespace];
                // if it was not deleted in this time
                if (_settings) {
                    history[_id].timeout = null;
                    history[_id].list = history[_id].list || [];
                    history[_id].list.push(history[_id].state);

                    if (history[id].list.length > _settings.maxLength) {
                        adapter.log.info('moving ' + history[id].list.length + ' entries to file');
                        appendFile(_id, history[_id].list);
                    }
                }
            }, settings.debounce || 1000, id);
        }
    }
}

function appendFile(id, states) {

    var day = ts2day(states[states.length - 1].ts);

    var file = adapter.config.storeDir + day + '/history.' + id + '.json';
    var data;

    var i;
    for (i = states.length - 1; i >= 0; i--) {
        if (!states[i]) continue;
        if (ts2day(states[i].ts) !== day) {
            break
        }
    }
    data = states.splice(i - states.length + 1);

    if (fs.existsSync(file)) {
        try {
            data = JSON.parse(fs.readFileSync(file)).concat(data);
        } catch (err) {
            adapter.log.error('Cannot read file ' + file + ': ' + err);
        }
    }

    try {
        // create directory
        if (!fs.existsSync(adapter.config.storeDir + day)) {
            fs.mkdirSync(adapter.config.storeDir + day);
        }
        fs.writeFileSync(file, JSON.stringify(data, null, 2));
    } catch (ex) {
        adapter.log.error('Cannot store file ' + file + ': ' + ex);
    }

    if (states.length) {
        appendFile(id, states);
    }

    /*adapter.getForeignObject(cid, function (err, res) {
        var obj;
        if (err || !res) {
            obj = {
                type: 'history',
                common: {
                    source: id,
                    day: day,
                    data: []
                },
                native: {}
            };
        } else {
            obj = res;
        }

        if (!obj.common) {
            adapter.log.error('invalid object ' + id);
            return;
        }

        if (!obj.common.data) obj.common.data = [];

        for (var i = states.length - 1; i >= 0; i--) {
            if (!states[i]) continue;
            if (ts2day(states[i].ts) === day) {
                obj.common.data.unshift(states[i]);
            } else {
                break;
            }
        }

        adapter.setForeignObject(cid, obj, function () {
            adapter.log.info('store ' + states.length + ' history datapoints from RAM history.' + id + ' to file ' + cid);
        });

        if (i >= 0) {
            adapter.log.info((i + 1) + ' remaining datapoints of history.' + id);
            appendFile(id, states.slice(0, (i + 1)));
        }
    });*/
}

function getCachedData(id, options, callback) {
    var res = history[id].list;
    var cache = [];
    if (res) {
        var iProblemCount = 0;
        for (var i = res.length - 1; i >= 0 ; i--) {
            if (!res[i]) {
                iProblemCount++;
                continue;
            }
            if (options.start && res[i].ts < options.start) {
                break;
            } else if (res[i].ts > options.end) {
                continue;
            }
            cache.unshift(res[i]);

            if (!options.start && cache.length >= options.count) {
                break;
            }
        }
        if (iProblemCount) adapter.log.warn('got null states ' + iProblemCount + ' times for ' + id);

        adapter.log.debug('got ' + res.length + ' datapoints for ' + id);
    } else {
        if (err != 'Not exists') {
            adapter.log.error(err);
        } else {
            adapter.log.debug('datapoints for ' + id + ' do not yet exist');
        }
    }
    options.length = cache.length;
    callback(cache, !options.start && cache.length >= options.count);
}

function getFileData(id, options, callback) {

    var day_start = options.start ? ts2day(options.start) : null;
    var day_end = ts2day(options.end);
    var data = [];

    // get list of directories
    var day_list = getDirectories(adapter.config.storeDir).sort(function (a, b) {
        return a - b;
    });

    // get all files in directory
    for (var i = day_list.length - 1; i >= 0; i--) {
        var day = parseInt(day_list[i]);

        if (day_start && day < day_start) {
            break;
        } else
        if ((!day_start || day >= day_start) && day <= day_end) {
            var file = adapter.config.storeDir + day_list[i].toString() + '/history.' + id + '.json';
            if (fs.existsSync(file)) {
                try {
                    data = data.concat(JSON.parse(fs.readFileSync(file)));
                } catch (e) {
                    adapter.log.error('Cannot parse file ' + file + ': ' + e.message);
                }
                // if we need "count" entries
                if (!day_start && (options.length + data.length > options.count)) {
                    break;
                }
            }
        }
    }

    callback(data);
}

function aggregate(data, options) {
    if (data && data.length) {
        var start = new Date(options.start * 1000);
        var end   = new Date(options.end * 1000);

        var step = 1; // 1 Step is 1 second
        if (options.step) {
            step = options.step;
        } else{
            step = Math.round((options.end - options.start) / options.count) ;
        }

        // Limit 2000
        if ((options.end - options.start) / step > options.limit){
            step = Math.round((options.end - options.start)/ options.limit);
        }

        var stepEnd;
        var i = 0;
        var result = [];
        var iStep = 0;
        options.aggregate = options.aggregate || 'max';

        while (i < data.length && new Date(data[i].ts * 1000) < end) {
            stepEnd = new Date(start);
            var x = stepEnd.getSeconds();
            stepEnd.setSeconds(x + step);

            if (stepEnd < start) {
                // Summer time
                stepEnd.setHours(start.getHours() + 2);
            }

            // find all entries in this time period
            var value = null;
            var count = 0;

            while (i < data.length && new Date(data[i].ts * 1000) < stepEnd) {
                if (options.aggregate == 'max') {
                    // Find max
                    if (value === null || data[i].val > value) value = data[i].val;
                } else if (options.aggregate == 'min') {
                    // Find min
                    if (value === null || data[i].val < value) value = data[i].val;
                } else if (options.aggregate == 'average') {
                    if (value === null) value = 0;
                    value += data[i].val;
                    count++;
                } else if (options.aggregate == 'total') {
                    // Find sum
                    if (value === null) value = 0;
                    value += parseFloat(data[i].val);
                }
                i++;
            }

            if (options.aggregate == 'average') {
                if (!count) {
                    value = null;
                } else {
                    value /= count;
                    value = Math.round(value * 100) / 100;
                }
            }
            if (value || options.getNull ) {
                result[iStep] = {ts: stepEnd.getTime() / 1000};
                result[iStep].val = value;
                iStep++;
            }

            start = stepEnd;
        }

        return {result: result, step: step, sourceLength: data.length};
    } else {
        return {result: [], step: 0, sourceLength: 0};
    }
}

function sortByTs(a, b) {
    var aTs = a.ts;
    var bTs = b.ts;
    return ((aTs < bTs) ? -1 : ((aTs > bTs) ? 1 : 0));
}

function sendResponse(msg, options, data, startTime) {
    var aggregateData;
    data = data.sort(sortByTs);
    if (options.count && !options.start && data.length > options.count) {
        data.splice(0, data.length - options.count);
    }

    options.start = options.start || data[0].ts;

    if (!options.aggregate || options.aggregate === 'none') {
        aggregateData = {result: data, step: 0, sourceLength: data.length};
    } else {
        aggregateData = aggregate(data, options);
    }

    adapter.log.info('Send: ' + aggregateData.result.length + ' of: ' + aggregateData.sourceLength + ' in: ' + (new Date().getTime() - startTime) + 'ms');
    adapter.sendTo(msg.from, msg.command, {result: aggregateData.result, step: aggregateData.step, error: null}, msg.callback);

}

function getHistory(msg) {
    var startTime = new Date().getTime();
    var id = msg.message.id;
    var options = {
        start:      msg.message.options.start,
        end:        msg.message.options.end || Math.round((new Date()).getTime() / 1000) + 5000,
        step:       parseInt(msg.message.options.step) || null,
        count:      parseInt(msg.message.options.count) || 500,
        getNull:    msg.message.options.getNull,
        aggregate:  msg.message.options.aggregate || 'average', // One of: max, min, average, total
        limit:      msg.message.options.limit || adapter.config.limit || 2000
    };

    if (options.start > options.end){
        var _end = options.end;
        options.end   = options.start;
        options.start =_end;
    }

    if (!options.start && !options.count) {
        options.start = Math.round((new Date()).getTime() / 1000) - 5030; // - 1 year
    }

    getCachedData(id, options, function (cacheData, isFull) {
        // if all data read
        if (isFull && cacheData.length) {
            sendResponse(msg, options, cacheData, startTime);
        } else {
            getFileData(id, options, function (fileData) {
                sendResponse(msg, options, cacheData.concat(fileData), startTime);
            });
        }
    });
}

function getDirectories(path) {
    return fs.readdirSync(path).filter(function (file) {
        return fs.statSync(path + '/' + file).isDirectory();
    });
}

function ts2day(ts) {
    var dateObj = new Date(ts * 1000);

    var text = dateObj.getFullYear().toString();
    var v = dateObj.getMonth() + 1;
    if (v < 10) text += '0';
    text += v.toString();

    v = dateObj.getDate();
    if (v < 10) text += '0';
    text += v.toString();

    return text;
}

<commit_msg>(bluefox) handle strings and booleans<commit_after>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
"use strict";

var utils   = require(__dirname + '/lib/utils'); // Get common adapter utils
var path    = require('path');
var dataDir = path.normalize(utils.controllerDir + '/' + require(utils.controllerDir + '/lib/tools').getDefaultDataDir());
var fs      = require('fs');

var history = {};

var adapter = utils.adapter({

    name: 'history',

    objectChange: function (id, obj) {
        if (obj && obj.common && obj.common.history && obj.common.history[adapter.namespace]) {
            history[id] = obj.common.history;
            adapter.log.info('enabled logging of ' + id);
        } else {
            if (history[id]) {
                adapter.log.info('disabled logging of ' + id);
                delete history[id];
            }
        }
    },

    stateChange: function (id, state) {
        pushHistory(id, state);
    },

    unload: function (callback) {
        finish(callback);
    },

    ready: function () {
        main();
    },

    message: function (obj) {
        processMessage(obj);
    }
});

process.on('SIGINT', function () {
    if (adapter && adapter.setState) {
        finish();
    }
});

function finish(callback) {
    for (var id in history) {
        if (history[id][adapter.namespace].list && history[id][adapter.namespace].list.length) {
            adapter.log.debug('Store th rest for ' + id);
            appendFile(id, history[id][adapter.namespace].list);
        }
    }
    if (callback) callback();
}

function processMessage(msg) {
    if (msg.command == 'getHistory') {
        getHistory(msg);
    }
}

function main() {
    adapter.config.storeDir = adapter.config.storeDir || 'history';
    adapter.config.storeDir = adapter.config.storeDir.replace(/\\/g, '/');
    // remove last /
    if (adapter.config.storeDir[adapter.config.storeDir.length - 1] == '/') {
        adapter.config.storeDir = adapter.config.storeDir.substring(0, adapter.config.storeDir.length - 1);
    }

    if (adapter.config.storeDir[0] !== '/' && !adapter.config.storeDir.match(/^\w:\//)) {
        adapter.config.storeDir = dataDir + adapter.config.storeDir;
    }
    adapter.config.storeDir += '/';

    adapter.objects.getObjectView('history', 'state', {}, function (err, doc) {
        if (doc && doc.rows) {
            for (var i = 0, l = doc.rows.length; i < l; i++) {
                if (doc.rows[i].value) {
                    history[doc.rows[i].id] = doc.rows[i].value;
                    // convert old value
                    if (history[doc.rows[i].id].enabled !== undefined) {
                        history[doc.rows[i].id] = history[doc.rows[i].id].enabled ? {'history.0': history[doc.rows[i].id]} : {};
                    }
                    if (!history[doc.rows[i].id][adapter.namespace] || history[doc.rows[i].id][adapter.namespace].enabled === false) {
                        delete history[doc.rows[i].id];
                    } else {
                        adapter.log.info('enabled logging of ' + doc.rows[i].id);
                        history[doc.rows[i].id][adapter.namespace].maxLength = parseInt(history[doc.rows[i].id][adapter.namespace].maxLength || adapter.config.maxLength, 10);
                    }
                }
            }
        }
    });

    adapter.subscribeForeignStates('*');
    adapter.subscribeForeignObjects('*');
}

function pushHistory(id, state) {
    // Push into redis
    if (history[id]) {
        var settings = history[id][adapter.namespace];

        if (!settings || !state) return;

        if (history[id].state && settings.changesOnly && (state.ts !== state.lc)) return;

        history[id].state = state;

        // Do not store values ofter than 1 second
        if (!history[id].timeout) {

            history[id].timeout = setTimeout(function (_id) {
                if (!history[_id]) return;
                var _settings = history[_id][adapter.namespace];
                // if it was not deleted in this time
                if (_settings) {
                    history[_id].timeout = null;
                    history[_id].list = history[_id].list || [];
                    if (typeof history[_id].state.val === 'string') {
                        var f = parseFloat(history[_id].state.val);
                        if (f.toString() == history[_id].state.val) history[_id].state.val = f;
                    }
                    history[_id].list.push(history[_id].state);

                    if (history[id].list.length > _settings.maxLength) {
                        adapter.log.info('moving ' + history[id].list.length + ' entries to file');
                        appendFile(_id, history[_id].list);
                    }
                }
            }, settings.debounce || 1000, id);
        }
    }
}

function appendFile(id, states) {
    // todo check retention time
    var day = ts2day(states[states.length - 1].ts);

    var file = adapter.config.storeDir + day + '/history.' + id + '.json';
    var data;

    var i;
    for (i = states.length - 1; i >= 0; i--) {
        if (!states[i]) continue;
        if (ts2day(states[i].ts) !== day) {
            break
        }
    }
    data = states.splice(i - states.length + 1);

    if (fs.existsSync(file)) {
        try {
            data = JSON.parse(fs.readFileSync(file)).concat(data);
        } catch (err) {
            adapter.log.error('Cannot read file ' + file + ': ' + err);
        }
    }

    try {
        // create directory
        if (!fs.existsSync(adapter.config.storeDir + day)) {
            fs.mkdirSync(adapter.config.storeDir + day);
        }
        fs.writeFileSync(file, JSON.stringify(data, null, 2));
    } catch (ex) {
        adapter.log.error('Cannot store file ' + file + ': ' + ex);
    }

    if (states.length) {
        appendFile(id, states);
    }
}

function getCachedData(id, options, callback) {
    var res = history[id].list;
    var cache = [];
    // todo canbe optimized
    if (res) {
        var iProblemCount = 0;
        for (var i = res.length - 1; i >= 0 ; i--) {
            if (!res[i]) {
                iProblemCount++;
                continue;
            }
            if (options.start && res[i].ts < options.start) {
                break;
            } else if (res[i].ts > options.end) {
                continue;
            }
            cache.unshift(res[i]);

            if (!options.start && cache.length >= options.count) {
                break;
            }
        }
        if (iProblemCount) adapter.log.warn('got null states ' + iProblemCount + ' times for ' + id);

        adapter.log.debug('got ' + res.length + ' datapoints for ' + id);
    } else {
        if (err != 'Not exists') {
            adapter.log.error(err);
        } else {
            adapter.log.debug('datapoints for ' + id + ' do not yet exist');
        }
    }
    options.length = cache.length;
    callback(cache, !options.start && cache.length >= options.count);
}

function getFileData(id, options, callback) {

    var day_start = options.start ? ts2day(options.start) : null;
    var day_end = ts2day(options.end);
    var data = [];

    // get list of directories
    var day_list = getDirectories(adapter.config.storeDir).sort(function (a, b) {
        return a - b;
    });

    // get all files in directory
    for (var i = day_list.length - 1; i >= 0; i--) {
        var day = parseInt(day_list[i]);

        if (day_start && day < day_start) {
            break;
        } else
        if ((!day_start || day >= day_start) && day <= day_end) {
            var file = adapter.config.storeDir + day_list[i].toString() + '/history.' + id + '.json';
            if (fs.existsSync(file)) {
                try {
                    data = data.concat(JSON.parse(fs.readFileSync(file)));
                } catch (e) {
                    adapter.log.error('Cannot parse file ' + file + ': ' + e.message);
                }
                // if we need "count" entries
                if (!day_start && (options.length + data.length > options.count)) {
                    break;
                }
            }
        }
    }

    callback(data);
}

function aggregate(data, options) {
    if (data && data.length) {
        if (typeof data[0].val !== 'number') {
            return {result: data, step: 0, sourceLength: data.length};
        }
        var start = new Date(options.start * 1000);
        var end   = new Date(options.end * 1000);

        var step = 1; // 1 Step is 1 second
        if (options.step) {
            step = options.step;
        } else{
            step = Math.round((options.end - options.start) / options.count) ;
        }

        // Limit 2000
        if ((options.end - options.start) / step > options.limit){
            step = Math.round((options.end - options.start)/ options.limit);
        }

        var stepEnd;
        var i = 0;
        var result = [];
        var iStep = 0;
        options.aggregate = options.aggregate || 'max';

        while (i < data.length && new Date(data[i].ts * 1000) < end) {
            stepEnd = new Date(start);
            var x = stepEnd.getSeconds();
            stepEnd.setSeconds(x + step);

            if (stepEnd < start) {
                // Summer time
                stepEnd.setHours(start.getHours() + 2);
            }

            // find all entries in this time period
            var value = null;
            var count = 0;

            while (i < data.length && new Date(data[i].ts * 1000) < stepEnd) {
                if (options.aggregate == 'max') {
                    // Find max
                    if (value === null || data[i].val > value) value = data[i].val;
                } else if (options.aggregate == 'min') {
                    // Find min
                    if (value === null || data[i].val < value) value = data[i].val;
                } else if (options.aggregate == 'average') {
                    if (value === null) value = 0;
                    value += data[i].val;
                    count++;
                } else if (options.aggregate == 'total') {
                    // Find sum
                    if (value === null) value = 0;
                    value += parseFloat(data[i].val);
                }
                i++;
            }

            if (options.aggregate == 'average') {
                if (!count) {
                    value = null;
                } else {
                    value /= count;
                    value = Math.round(value * 100) / 100;
                }
            }
            if (value !== null || !options.ignoreNull) {
                result[iStep] = {ts: stepEnd.getTime() / 1000};
                result[iStep].val = value;
                iStep++;
            }

            start = stepEnd;
        }

        return {result: result, step: step, sourceLength: data.length};
    } else {
        return {result: [], step: 0, sourceLength: 0};
    }
}

function sortByTs(a, b) {
    var aTs = a.ts;
    var bTs = b.ts;
    return ((aTs < bTs) ? -1 : ((aTs > bTs) ? 1 : 0));
}

function sendResponse(msg, options, data, startTime) {
    var aggregateData;
    data = data.sort(sortByTs);
    if (options.count && !options.start && data.length > options.count) {
        data.splice(0, data.length - options.count);
    }

    options.start = options.start || data[0].ts;

    if (!options.aggregate || options.aggregate === 'none') {
        aggregateData = {result: data, step: 0, sourceLength: data.length};
    } else {
        aggregateData = aggregate(data, options);
    }

    adapter.log.info('Send: ' + aggregateData.result.length + ' of: ' + aggregateData.sourceLength + ' in: ' + (new Date().getTime() - startTime) + 'ms');
    adapter.sendTo(msg.from, msg.command, {result: aggregateData.result, step: aggregateData.step, error: null}, msg.callback);

}

function getHistory(msg) {
    var startTime = new Date().getTime();
    var id = msg.message.id;
    var options = {
        start:      msg.message.options.start,
        end:        msg.message.options.end || Math.round((new Date()).getTime() / 1000) + 5000,
        step:       parseInt(msg.message.options.step) || null,
        count:      parseInt(msg.message.options.count) || 500,
        ignoreNull: msg.message.options.ignoreNull,
        aggregate:  msg.message.options.aggregate || 'average', // One of: max, min, average, total
        limit:      msg.message.options.limit || adapter.config.limit || 2000
    };

    if (options.start > options.end){
        var _end = options.end;
        options.end   = options.start;
        options.start =_end;
    }

    if (!options.start && !options.count) {
        options.start = Math.round((new Date()).getTime() / 1000) - 5030; // - 1 year
    }

    getCachedData(id, options, function (cacheData, isFull) {
        // if all data read
        if (isFull && cacheData.length) {
            sendResponse(msg, options, cacheData, startTime);
        } else {
            getFileData(id, options, function (fileData) {
                sendResponse(msg, options, cacheData.concat(fileData), startTime);
            });
        }
    });
}

function getDirectories(path) {
    return fs.readdirSync(path).filter(function (file) {
        return fs.statSync(path + '/' + file).isDirectory();
    });
}

function ts2day(ts) {
    var dateObj = new Date(ts * 1000);

    var text = dateObj.getFullYear().toString();
    var v = dateObj.getMonth() + 1;
    if (v < 10) text += '0';
    text += v.toString();

    v = dateObj.getDate();
    if (v < 10) text += '0';
    text += v.toString();

    return text;
}

<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var expect = require('chai').expect;
var settings = require('../settings');
var classes = require('../utils/classes');
var EntitySpecification = require('./EntitySpecification');
var errors = require('./errors');

module.exports = Entity;

/**
 * Base class for entities.
 * @constructor
 * @memberof module:back4app/entity/models
 * @example
 * var entity = new Entity();
 */
function Entity() {
  /**
   * This is a read-only property to get the Entity Class of an instance.
   * @type {!Class}
   * @readonly
   * @example
   * var entity = new Entity();
   * console.log(entity.Entity == Entity); // Logs "true"
   */
  this.Entity = null;
  /**
   * This is a read-only property to get the general Entity Class of an
   * instance. This is just an alias to this.Entity.General.
   * @type {!Class}
   * @readonly
   * @example
   * var MyEntity = Entity.specify();
   * var myEntity = new MyEntity();
   * console.log(myEntity.General == Entity); // Logs "true"
   */
  this.General = null;

  expect(arguments).to.have.length(
    0,
    'Invalid arguments length when creating an Entity (it has not to be ' +
    'passed any argument)');

  Object.defineProperty(this, 'Entity', {
    value: Entity,
    enumerable: false,
    writable: false,
    configurable: true
  });

  Object.defineProperty(this, 'General', {
    get: function () {
      return this.Entity.General;
    },
    set: function () {
      throw new Error(
        'General property of an Entity instance cannot be changed'
      );
    },
    enumerable: false,
    configurable: true
  });
}

/**
 * This is a read-only property to get the general Entity Class of the current
 * Entity Class.
 * @type {?Class}
 * @readonly
 * @example
 * var generalAttributes = SpecificEntity.General.attributes;
 */
Entity.General = null;
/**
 * This is the specification of the current Entity Class.
 * @type {!module:back4app/entity/models.EntitySpecification}
 * @readonly
 * @example
 * var entitySpecification = Entity.specification;
 */
Entity.specification = null;
/**
 * This is a dictionary with a consolidation of the Entity's attributes.
 * @type
 * {!Object.<!string, !module:back4app/entity/models/attributes.Attribute>}
 * @readonly
 * @example
 * var consolidatedAttributes = Entity.attributes;
 */
Entity.attributes = null;
/**
 * This is a dictionary with a consolidation of the Entity's methods.
 * @type {!Object.<!string, !module:back4app/entity/models/methods.Method>}
 * @readonly
 * @example
 * var consolidatedMethods = Entity.methods;
 */
Entity.methods = null;

Entity.specify = null;
Entity.new = null;

Object.defineProperty(Entity, 'General', {
  value: null,
  enumerable: true,
  writable: false,
  configurable: false
});

Object.defineProperty(Entity, 'specification', {
  value: new EntitySpecification(),
  enumerable: true,
  writable: false,
  configurable: false
});

Object.defineProperty(Entity, 'attributes', {
  value: {},
  enumerable: true,
  writable: false,
  configurable: false
});

Object.defineProperty(Entity, 'methods', {
  value: {},
  enumerable: true,
  writable: false,
  configurable: false
});

/**
 * Private function used to get the specify function specific for the current
 * Entity class.
 * @name module:back4app/entity/models.Entity~_getSpecifyFunction
 * @function
 * @param {!Class} CurrentEntity The currentEntity for which the specify
 * function will be got.
 * @returns {function} The specify function.
 * @private
 * @example
 * Entity.specify = _getSpecifyFunction(Entity);
 */
var _getSpecifyFunction = function (CurrentEntity) {
  return function () {
    expect(arguments).to.have.length.below(
      3,
      'Invalid arguments length when specifying an Entity (it has to be ' +
      'passed less than 3 arguments)'
    );

    function SpecificEntity() {
      CurrentEntity.call(this);

      Object.defineProperty(this, 'Entity', {
        value: SpecificEntity,
        enumerable: false,
        writable: false,
        configurable: true
      });
    }

    classes.generalize(CurrentEntity, SpecificEntity);

    Object.defineProperty(SpecificEntity, 'General', {
      value: CurrentEntity,
      enumerable: true,
      writable: false,
      configurable: false
    });

    var _specificEntitySpecification = null;

    if (arguments.length === 1 && arguments[0]) {
      var specification = arguments[0];

      expect(specification).to.be.an(
        'object',
        'Invalid argument type when specifying an Entity'
      );

      if (specification instanceof EntitySpecification) {
        _specificEntitySpecification = specification;
      } else {
        _specificEntitySpecification = new EntitySpecification(specification);
      }
    } else if (arguments.length > 1) {
      var attributes = arguments[0];
      var methods = arguments[1];

      if (attributes) {
        expect(typeof attributes).to.equal(
          'object',
          'Invalid property "attributes" when specifying an Entity (it has ' +
          'to be an object)'
        );
      }

      if (methods) {
        expect(methods).to.be.an(
          'object',
          'Invalid property "methods" when specifying an Entity (it has to ' +
          'be an object)'
        );
      }

      _specificEntitySpecification = new EntitySpecification(
        attributes,
        methods
      );
    } else {
      _specificEntitySpecification = new EntitySpecification();
    }

    Object.defineProperty(SpecificEntity, 'specification', {
      get: function () {
        return _specificEntitySpecification;
      },
      set: function () {
        throw  new Error('Specification cannot be changed');
      },
      enumerable: true
    });

    Object.defineProperty(SpecificEntity, 'attributes', {
      get: function () {
        var attributes = {};

        var visitedEntities = [];
        var CurrentEntity = SpecificEntity;
        while (CurrentEntity && visitedEntities.indexOf(CurrentEntity) === -1) {
          for (var attribute in CurrentEntity.specification.attributes) {
            if (!attributes.hasOwnProperty(attribute)) {
              attributes[attribute] =
                CurrentEntity.specification.attributes[attribute];
            }
          }

          visitedEntities.push(CurrentEntity);
          CurrentEntity = CurrentEntity.General;
        }

        return attributes;
      },
      set: function () {
        throw  new Error('Attributes cannot be changed');
      },
      enumerable: true
    });

    Object.defineProperty(SpecificEntity, 'methods', {
      get: function () {
        var methods = {};

        var visitedEntities = [];
        var CurrentEntity = SpecificEntity;
        while (CurrentEntity && visitedEntities.indexOf(CurrentEntity) === -1) {
          for (var method in CurrentEntity.specification.methods) {
            if (!methods.hasOwnProperty(method)) {
              methods[method] =
                CurrentEntity.specification.methods[method];
            }
          }

          visitedEntities.push(CurrentEntity);
          CurrentEntity = CurrentEntity.General;
        }

        return methods;
      },
      set: function () {
        throw  new Error('Methods cannot be changed');
      },
      enumerable: true
    });

    SpecificEntity.specify = _getSpecifyFunction(SpecificEntity);
    SpecificEntity.new = _getNewFunction(SpecificEntity);

    return SpecificEntity;
  };
};

/**
 * Creates a new Entity Class by specifying a general one.
 * @memberof module:back4app/entity/models.Entity
 * @name specify
 * @function
 * @param {?module:back4app/entity/models.EntitySpecification} [specification]
 * The new Entity specification.
 * @returns {Class} The new Entity Class.
 */
/**
 * Creates a new Entity Class by specifying a general one.
 * @memberof module:back4app/entity/models.Entity
 * @name specify
 * @function
 * @param
 * {?(module:back4app/entity/models/attributes.AttributeCollection|
 * module:back4app/entity/models/attributes.Attribute[]|
 * Object.<!string, !(module:back4app/entity/models/attributes.Attribute|
 * Object)>)}
 * attributes The new entity specification attributes. It can be given as an
 * instance of
 * {@link module:back4app/entity/models/attributes.AttributeCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/attributes.AttributeCollection}.
 * @param
 * {?(module:back4app/entity/models/methods.MethodCollection|
 * Object.<!string, !function>)}
 * methods The new entity specification methods. It can be given as an instance
 * of
 * {@link module:back4app/entity/models/methods.MethodCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/methods.MethodCollection}.
 * @returns {Class} The new Entity Class.
 */
/**
 * Creates a new Entity Class by specifying a general one.
 * @memberof module:back4app/entity/models.Entity
 * @name specify
 * @function
 * @param {?Object} [specification] The new Entity specification.
 * @param
 * {?(module:back4app/entity/models/attributes.AttributeCollection|
 * module:back4app/entity/models/attributes.Attribute[]|
 * Object.<!string, !(module:back4app/entity/models/attributes.Attribute|
 * Object)>)}
 * [specification.attributes] The new entity specification attributes. It can be
 * given as an instance of
 * {@link module:back4app/entity/models/attributes.AttributeCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/attributes.AttributeCollection}.
 * @param
 * {?(module:back4app/entity/models/methods.MethodCollection|
 * Object.<!string, !function>)}
 * [specification.methods] The new entity specification methods. It can be
 * given as an instance of
 * {@link module:back4app/entity/models/methods.MethodCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/methods.MethodCollection}.
 * @returns {Class} The new Entity Class.
 */
Entity.specify = _getSpecifyFunction(Entity);

/**
 * Private function used to get the new function specific for the current Entity
 * class.
 * @name module:back4app/entity/models.Entity~_getNewFunction
 * @function
 * @param {!Class} CurrentEntity The current entity class for which the new
 * function will be created.
 * @returns {function} The new function.
 * @private
 * @example
 * Entity.new = _getNewFunction(Entity);
 */
var _getNewFunction = function (CurrentEntity) {
  return function (entity) {
    expect(arguments).to.have.length.below(
      2,
      'Invalid arguments length when creating a new Entity function (it has ' +
      'to be passed less than 2 arguments)'
    );

    var EntityClass = CurrentEntity;
    if (entity) {
      expect(entity).to.be.a(
        'string',
        'Invalid argument when creating a new Entity function (it has to be ' +
        'a string'
      );
      try {
        EntityClass = require(path.join(settings.ENTITIESPATH, entity));
      }
      catch (e) {
        throw new errors.EntityNotFoundError(
          entity,
          e
        );
      }
    }

    return function () {
      return new EntityClass();
    };
  };
};

/**
 * Returns a function that creates new instances of an Entity Class.
 * @function
 * @param {?string} [entity] The Entity Class of which the new instances will be
 * created. If the parameter is not given, the function will create instances of
 * the current Entity Class.
 * @returns {function}
 * @example
 * var c1NewFunction = Entity.new('C1');
 * var c1 = c1NewFunction();
 */
Entity.new = _getNewFunction(Entity);
<commit_msg>Improvement of Entity.specify<commit_after>'use strict';

var path = require('path');
var expect = require('chai').expect;
var settings = require('../settings');
var classes = require('../utils/classes');
var EntitySpecification = require('./EntitySpecification');
var AttributeCollection = require('./attributes').AttributeCollection;
var MethodCollection = require('./methods').MethodCollection;
var errors = require('./errors');

module.exports = Entity;

/**
 * Base class for entities.
 * @constructor
 * @memberof module:back4app/entity/models
 * @example
 * var entity = new Entity();
 */
function Entity() {
  /**
   * This is a read-only property to get the Entity Class of an instance.
   * @type {!Class}
   * @readonly
   * @example
   * var entity = new Entity();
   * console.log(entity.Entity == Entity); // Logs "true"
   */
  this.Entity = null;
  /**
   * This is a read-only property to get the general Entity Class of an
   * instance. This is just an alias to this.Entity.General.
   * @type {!Class}
   * @readonly
   * @example
   * var MyEntity = Entity.specify();
   * var myEntity = new MyEntity();
   * console.log(myEntity.General == Entity); // Logs "true"
   */
  this.General = null;

  expect(arguments).to.have.length(
    0,
    'Invalid arguments length when creating an Entity (it has not to be ' +
    'passed any argument)');

  Object.defineProperty(this, 'Entity', {
    value: Entity,
    enumerable: false,
    writable: false,
    configurable: true
  });

  Object.defineProperty(this, 'General', {
    get: function () {
      return this.Entity.General;
    },
    set: function () {
      throw new Error(
        'General property of an Entity instance cannot be changed'
      );
    },
    enumerable: false,
    configurable: true
  });
}

/**
 * This is a read-only property to get the general Entity Class of the current
 * Entity Class.
 * @type {?Class}
 * @readonly
 * @example
 * var generalAttributes = SpecificEntity.General.attributes;
 */
Entity.General = null;
/**
 * This is the specification of the current Entity Class.
 * @type {!module:back4app/entity/models.EntitySpecification}
 * @readonly
 * @example
 * var entitySpecification = Entity.specification;
 */
Entity.specification = null;
/**
 * This is a dictionary with a consolidation of the Entity's attributes.
 * @type
 * {!Object.<!string, !module:back4app/entity/models/attributes.Attribute>}
 * @readonly
 * @example
 * var consolidatedAttributes = Entity.attributes;
 */
Entity.attributes = null;
/**
 * This is a dictionary with a consolidation of the Entity's methods.
 * @type {!Object.<!string, !module:back4app/entity/models/methods.Method>}
 * @readonly
 * @example
 * var consolidatedMethods = Entity.methods;
 */
Entity.methods = null;

Entity.specify = null;
Entity.new = null;

Object.defineProperty(Entity, 'General', {
  value: null,
  enumerable: true,
  writable: false,
  configurable: false
});

Object.defineProperty(Entity, 'specification', {
  value: new EntitySpecification(),
  enumerable: true,
  writable: false,
  configurable: false
});

Object.defineProperty(Entity, 'attributes', {
  value: {},
  enumerable: true,
  writable: false,
  configurable: false
});

Object.defineProperty(Entity, 'methods', {
  value: {},
  enumerable: true,
  writable: false,
  configurable: false
});

/**
 * Private function used to get the specify function specific for the current
 * Entity class.
 * @name module:back4app/entity/models.Entity~_getSpecifyFunction
 * @function
 * @param {!Class} CurrentEntity The currentEntity for which the specify
 * function will be got.
 * @returns {function} The specify function.
 * @private
 * @example
 * Entity.specify = _getSpecifyFunction(Entity);
 */
var _getSpecifyFunction = function (CurrentEntity) {
  return function () {
    expect(arguments).to.have.length.below(
      3,
      'Invalid arguments length when specifying an Entity (it has to be ' +
      'passed less than 3 arguments)'
    );

    function SpecificEntity() {
      CurrentEntity.call(this);

      Object.defineProperty(this, 'Entity', {
        value: SpecificEntity,
        enumerable: false,
        writable: false,
        configurable: true
      });
    }

    classes.generalize(CurrentEntity, SpecificEntity);

    Object.defineProperty(SpecificEntity, 'General', {
      value: CurrentEntity,
      enumerable: true,
      writable: false,
      configurable: false
    });

    var _specificEntitySpecification = null;

    if (arguments.length === 1 && arguments[0]) {
      var specification = arguments[0];

      expect(specification).to.be.an(
        'object',
        'Invalid argument type when specifying an Entity'
      );

      if (specification instanceof EntitySpecification) {
        _specificEntitySpecification = specification;
      } else {
        _specificEntitySpecification = new EntitySpecification(specification);
      }
    } else if (arguments.length > 1) {
      var attributes = arguments[0];
      var methods = arguments[1];

      if (attributes) {
        expect(typeof attributes).to.equal(
          'object',
          'Invalid property "attributes" when specifying an Entity (it has ' +
          'to be an object)'
        );
      }

      if (methods) {
        expect(methods).to.be.an(
          'object',
          'Invalid property "methods" when specifying an Entity (it has to ' +
          'be an object)'
        );
      }

      _specificEntitySpecification = new EntitySpecification(
        attributes,
        methods
      );
    } else {
      _specificEntitySpecification = new EntitySpecification();
    }

    Object.defineProperty(SpecificEntity, 'specification', {
      value: _specificEntitySpecification,
      enumerable: true,
      writable: false,
      configurable: false
    });

    Object.defineProperty(SpecificEntity, 'attributes', {
      get: function () {
        var attributesObject = {};

        var visitedEntities = [];
        var CurrentEntity = SpecificEntity;
        while (CurrentEntity && visitedEntities.indexOf(CurrentEntity) === -1) {
          for (var attribute in CurrentEntity.specification.attributes) {
            if (!attributesObject.hasOwnProperty(attribute)) {
              attributesObject[attribute] =
                CurrentEntity.specification.attributes[attribute];
            }
          }

          visitedEntities.push(CurrentEntity);
          CurrentEntity = CurrentEntity.General;
        }

        return new AttributeCollection(attributesObject);
      },
      set: function () {
        throw new Error('Attributes of an Entity cannot be changed');
      },
      enumerable: true,
      configurable: false
    });

    Object.defineProperty(SpecificEntity, 'methods', {
      get: function () {
        var methodsObject = {};

        var visitedEntities = [];
        var CurrentEntity = SpecificEntity;
        while (CurrentEntity && visitedEntities.indexOf(CurrentEntity) === -1) {
          for (var method in CurrentEntity.specification.methods) {
            if (!methodsObject.hasOwnProperty(method)) {
              methodsObject[method] =
                CurrentEntity.specification.methods[method];
            }
          }

          visitedEntities.push(CurrentEntity);
          CurrentEntity = CurrentEntity.General;
        }

        return new MethodCollection(methodsObject);
      },
      set: function () {
        throw new Error('Methods of an Entity cannot be changed');
      },
      enumerable: true,
      configurable: false
    });

    SpecificEntity.specify = _getSpecifyFunction(SpecificEntity);
    SpecificEntity.new = _getNewFunction(SpecificEntity);

    return SpecificEntity;
  };
};

/**
 * Creates a new Entity Class by specifying a general one.
 * @memberof module:back4app/entity/models.Entity
 * @name specify
 * @function
 * @param {?module:back4app/entity/models.EntitySpecification} [specification]
 * The new Entity specification.
 * @returns {Class} The new Entity Class.
 */
/**
 * Creates a new Entity Class by specifying a general one.
 * @memberof module:back4app/entity/models.Entity
 * @name specify
 * @function
 * @param
 * {?(module:back4app/entity/models/attributes.AttributeCollection|
 * module:back4app/entity/models/attributes.Attribute[]|
 * Object.<!string, !(module:back4app/entity/models/attributes.Attribute|
 * Object)>)}
 * attributes The new entity specification attributes. It can be given as an
 * instance of
 * {@link module:back4app/entity/models/attributes.AttributeCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/attributes.AttributeCollection}.
 * @param
 * {?(module:back4app/entity/models/methods.MethodCollection|
 * Object.<!string, !function>)}
 * methods The new entity specification methods. It can be given as an instance
 * of
 * {@link module:back4app/entity/models/methods.MethodCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/methods.MethodCollection}.
 * @returns {Class} The new Entity Class.
 */
/**
 * Creates a new Entity Class by specifying a general one.
 * @memberof module:back4app/entity/models.Entity
 * @name specify
 * @function
 * @param {?Object} [specification] The new Entity specification.
 * @param
 * {?(module:back4app/entity/models/attributes.AttributeCollection|
 * module:back4app/entity/models/attributes.Attribute[]|
 * Object.<!string, !(module:back4app/entity/models/attributes.Attribute|
 * Object)>)}
 * [specification.attributes] The new entity specification attributes. It can be
 * given as an instance of
 * {@link module:back4app/entity/models/attributes.AttributeCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/attributes.AttributeCollection}.
 * @param
 * {?(module:back4app/entity/models/methods.MethodCollection|
 * Object.<!string, !function>)}
 * [specification.methods] The new entity specification methods. It can be
 * given as an instance of
 * {@link module:back4app/entity/models/methods.MethodCollection} or an
 * object, as specified in
 * {@link module:back4app/entity/models/methods.MethodCollection}.
 * @returns {Class} The new Entity Class.
 */
Entity.specify = _getSpecifyFunction(Entity);

/**
 * Private function used to get the new function specific for the current Entity
 * class.
 * @name module:back4app/entity/models.Entity~_getNewFunction
 * @function
 * @param {!Class} CurrentEntity The current entity class for which the new
 * function will be created.
 * @returns {function} The new function.
 * @private
 * @example
 * Entity.new = _getNewFunction(Entity);
 */
var _getNewFunction = function (CurrentEntity) {
  return function (entity) {
    expect(arguments).to.have.length.below(
      2,
      'Invalid arguments length when creating a new Entity function (it has ' +
      'to be passed less than 2 arguments)'
    );

    var EntityClass = CurrentEntity;
    if (entity) {
      expect(entity).to.be.a(
        'string',
        'Invalid argument when creating a new Entity function (it has to be ' +
        'a string'
      );
      try {
        EntityClass = require(path.join(settings.ENTITIESPATH, entity));
      }
      catch (e) {
        throw new errors.EntityNotFoundError(
          entity,
          e
        );
      }
    }

    return function () {
      return new EntityClass();
    };
  };
};

/**
 * Returns a function that creates new instances of an Entity Class.
 * @function
 * @param {?string} [entity] The Entity Class of which the new instances will be
 * created. If the parameter is not given, the function will create instances of
 * the current Entity Class.
 * @returns {function}
 * @example
 * var c1NewFunction = Entity.new('C1');
 * var c1 = c1NewFunction();
 */
Entity.new = _getNewFunction(Entity);
<|endoftext|>


<commit_before>this.addEventListener("install", function (event) {
    event.waitUntil(
        caches.open('v10').then(function (cache) {
         return cache.addAll(['/html/',
          '/html/index.html',
          '/html/manifest.json',
          '/html/emergency.html',
          '/html/js/911.js',
          '/html/js/all_scr.js',
          '/html/js/app.js',
          '/html/js/bootstrap.min.js',
          '/html/js/emergency.js',
          '/html/js/wow.min.js',
          '/html/rs-plugin/js/jquery.themepunch.tools.min.js',
          '/html/rs-plugin/js/jquery.themepunch.revolution.min.js',
          '/html/rs-plugin/assets/timer.png',
          '/html/js/jquery.min.js',
          '/html/js/jquery.parallax-0.2-min.js',
          '/html/css/adaptive.css',
          '/html/css/animate.css',
          '/html/css/bootstrap.css',
          '/html/css/main.css',
          '/html/css/pushy.css',
          '/html/css/font-awesome.css',
          '/html/rs-plugin/css/settings.css',
          '/html/img/trapped_lady.jpg',
          '/html/img/screaming.jpg',
          '/html/img/location4.jpg',
          '/html/img/embrace3.jpg',
          '/html/img/start/bg.jpg',
          '/html/font/fontawesome-webfont.woff?v=4.3.0',
          '/html/font/fontawesome-webfont.woff2?v=4.3.0',
          '/html/rs-plugin/font/revicons.woff?5510888',
          '/html/rs-plugin/font/revicons.ttf?5510888',
          '/html/font/fontawesome-webfont.ttf?v=4.3.0',
          '/html/img/wmb_128x128.png',
          '/html/img/wmb_144x144.png',
          '/html/img/wmb_152x152.png',
          '/html/img/wmb_192x192.png',
          '/html/img/wmb_256x256.png'
          ]);
        })
        );
    });

this.addEventListener('activate', function(event) {
  var cacheWhitelist = ['v10'];

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheWhitelist.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});

this.addEventListener('fetch', function (event) {
	event.respondWith(
    caches.match(event.request)
    );
});

this.addEventListener('push', event => {
   event.waitUntil(() => {
     if (event.data) {
      return Promise.resolve(event.data);
     }
     return fetch("demo_sse.php").then(response => response.json());
}).then(data => {
 return this.registration.showNotification(title, {
    body : 'help me',
    icon : 'screaming.jpg',
    vibrate: [200, 100, 200, 100, 400],
    tag : 'request',
    actions : [
    { action : 'track', title : "wacth", icon : "fa fa-thumb-up"},
    { action : "Ignore", title : "Ignore", icon : "fa fa-thumb-down"} ]
  })
});

this.addEventListener('notificationclick', event => {
event.waitUntil(() =>
   event.notification.close();
  )

});<commit_msg>version 10<commit_after>this.addEventListener("install", function (event) {
    event.waitUntil(
        caches.open('v10').then(function (cache) {
         return cache.addAll(['/html/',
          '/html/index.html',
          '/html/manifest.json',
          '/html/emergency.html',
          '/html/js/911.js',
          '/html/js/all_scr.js',
          '/html/js/app.js',
          '/html/js/bootstrap.min.js',
          '/html/js/emergency.js',
          '/html/js/wow.min.js',
          '/html/rs-plugin/js/jquery.themepunch.tools.min.js',
          '/html/rs-plugin/js/jquery.themepunch.revolution.min.js',
          '/html/rs-plugin/assets/timer.png',
          '/html/js/jquery.min.js',
          '/html/js/jquery.parallax-0.2-min.js',
          '/html/css/adaptive.css',
          '/html/css/animate.css',
          '/html/css/bootstrap.css',
          '/html/css/main.css',
          '/html/css/pushy.css',
          '/html/css/font-awesome.css',
          '/html/rs-plugin/css/settings.css',
          '/html/img/trapped_lady.jpg',
          '/html/img/screaming.jpg',
          '/html/img/location4.jpg',
          '/html/img/embrace3.jpg',
          '/html/img/start/bg.jpg',
          '/html/font/fontawesome-webfont.woff?v=4.3.0',
          '/html/font/fontawesome-webfont.woff2?v=4.3.0',
          '/html/rs-plugin/font/revicons.woff?5510888',
          '/html/rs-plugin/font/revicons.ttf?5510888',
          '/html/font/fontawesome-webfont.ttf?v=4.3.0',
          '/html/img/wmb_128x128.png',
          '/html/img/wmb_144x144.png',
          '/html/img/wmb_152x152.png',
          '/html/img/wmb_192x192.png',
          '/html/img/wmb_256x256.png'
          ]);
        })
        );
    });

this.addEventListener('activate', function(event) {
  var cacheWhitelist = ['v10'];

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheWhitelist.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});

this.addEventListener('fetch', function (event) {
	event.respondWith(
    caches.match(event.request)
    );
});

this.addEventListener('push', event => {
   event.waitUntil(() => {
     if (event.data) {
      return Promise.resolve(event.data);
     }
     return fetch("demo_sse.php").then(response => response.json());
}).then(data => {
 return this.registration.showNotification(title, {
    body : 'help me',
    icon : 'screaming.jpg',
    vibrate: [200, 100, 200, 100, 400],
    tag : 'request',
    actions : [
    { action : 'track', title : "wacth", icon : "fa fa-thumb-up"},
    { action : "Ignore", title : "Ignore", icon : "fa fa-thumb-down"} ]
  })
});

this.addEventListener('notificationclick', event => {
event.waitUntil(() =>
   event.notification.close();
  )

});<|endoftext|>


<commit_before>/*!
 * Tracking JS
 *
 * This is a self-executing script that initialises the Google Analytics
 * tracking code without having to include any inline scripts.
 *
 * Copyright 2014 James Angus
 * Released under the MIT license
 * http://jquery.org/license
 */
( function( window, document, undefined ) {
	var metas = document.getElementsByTagName( "meta" ) || [];

	function meta( key ) {
		for ( var i = 0; i < metas.length; i++ ) {
			if ( metas[i].getAttribute( "name" ) === key ) {
				return metas[i].getAttribute( "content" );
			}
		}
		return "";
	}

	function metaslike( key ) {
		var metalre = new RegExp( "^" + key + ".*" );
		var returns = [];
		for ( var i = 0; i < metas.length; i++ ) {
			if ( metas[i].getAttribute( "name" ).match( metalre ) ) {
				returns.push( metas[i] );
			}
		}
		return returns;
	}

	function gaProtocol() {
		var proto = "https:";
		if ( window.location.protocol === "http:") {
			proto = "http:";
		}
		return proto;
	}

	var analyticsUrl = "//www.google-analytics.com/analytics.js",
		analyticsDebugUrl = "//www.google-analytics.com/analytics_debug.js",
		trackingId = meta( "ga-trackingid" ) || null,
		requires = meta( "ga-requires" ).split( "," ) || [],
		debug = meta( "ga-debug" ) || false,
		trace = meta( "ga-trace" ) || false,
		campaignFields = [ "campaignName", "campaignSource", "campaignMedium", "campaignContent", "campaignKeyword" ],
		dimensions = metaslike( "ga-dimension" ),
		userId = meta( "ga-userid" );

	if ( trackingId !== null && trackingId.length > 0 ) {
		if ( debug && debug === "true" ) {
			analyticsUrl = analyticsDebugUrl;
		}

		if ( trace && trace === "true" ) {
			window.ga_debug = { trace: true };
		}

		analyticsUrl = gaProtocol() + analyticsUrl;

		(function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
		(i[r].q=i[r].q||[]).push(arguments);},i[r].l=1*new Date();a=s.createElement(o),
		m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m);
		})(window,document,"script",analyticsUrl,"ga");

		if ( typeof(ga) !== "function" ) {
			console.log("Tracking-JS failed. Google Analytics Object not loaded.");
			return;
		}

		ga( "create", trackingId, "auto" );

		if ( requires.indexOf( "displayfeatures" ) > -1 ) {
			ga( "require", "displayfeatures" );
		}

		if ( requires.indexOf( "linkid" ) > -1 ) {
			ga( "require", "linkid", "linkid.js" );
		}

		for ( var i = 0; i < campaignFields.length; i++ ) {
			if ( meta( campaignFields[i] ) ) {
				ga( "set", campaignFields[i], meta( campaignFields[i] ) );
			}
		}

		for ( var j = 0; j < dimensions.length; j++ ) {
			if ( meta( dimensions[i] ) ) {
				ga( "set", dimensions[i], meta( dimensions[i] ) );
			}
		}

		if ( userId.length > 0 ) {
			ga( "set", "&uid", userId );
		}

		ga( "send", "pageview" );
	}
} ) ( window, document );
<commit_msg>Fix issue with linkid URL<commit_after>/*!
 * Tracking JS
 *
 * This is a self-executing script that initialises the Google Analytics
 * tracking code without having to include any inline scripts.
 *
 * Copyright 2014 James Angus
 * Released under the MIT license
 * http://jquery.org/license
 */
( function( window, document, undefined ) {
	var metas = document.getElementsByTagName( "meta" ) || [];

	function meta( key ) {
		for ( var i = 0; i < metas.length; i++ ) {
			if ( metas[i].getAttribute( "name" ) === key ) {
				return metas[i].getAttribute( "content" );
			}
		}
		return "";
	}

	function metaslike( key ) {
		var metalre = new RegExp( "^" + key + ".*" );
		var returns = [];
		for ( var i = 0; i < metas.length; i++ ) {
			if ( metas[i].getAttribute( "name" ).match( metalre ) ) {
				returns.push( metas[i] );
			}
		}
		return returns;
	}

	function gaProtocol() {
		var proto = "https:";
		if ( window.location.protocol === "http:") {
			proto = "http:";
		}
		return proto;
	}

	var analyticsUrl = "//www.google-analytics.com/analytics.js",
		analyticsDebugUrl = "//www.google-analytics.com/analytics_debug.js",
		linkidUrl = "//www.google-analytics.com/plugins/ua/linkid.js",
		trackingId = meta( "ga-trackingid" ) || null,
		requires = meta( "ga-requires" ).split( "," ) || [],
		debug = meta( "ga-debug" ) || false,
		trace = meta( "ga-trace" ) || false,
		campaignFields = [ "campaignName", "campaignSource", "campaignMedium", "campaignContent", "campaignKeyword" ],
		dimensions = metaslike( "ga-dimension" ),
		userId = meta( "ga-userid" );

	if ( trackingId !== null && trackingId.length > 0 ) {
		if ( debug && debug === "true" ) {
			analyticsUrl = analyticsDebugUrl;
		}

		if ( trace && trace === "true" ) {
			window.ga_debug = { trace: true };
		}

		analyticsUrl = gaProtocol() + analyticsUrl;

		(function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
		(i[r].q=i[r].q||[]).push(arguments);},i[r].l=1*new Date();a=s.createElement(o),
		m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m);
		})(window,document,"script",analyticsUrl,"ga");

		if ( typeof(ga) !== "function" ) {
			console.log("Tracking-JS failed. Google Analytics Object not loaded.");
			return;
		}

		ga( "create", trackingId, "auto" );

		if ( requires.indexOf( "displayfeatures" ) > -1 ) {
			ga( "require", "displayfeatures" );
		}

		if ( requires.indexOf( "linkid" ) > -1 ) {
			linkidUrl = gaProtocol() + linkidUrl;
			ga( "require", "linkid",  linkidUrl );
		}

		for ( var i = 0; i < campaignFields.length; i++ ) {
			if ( meta( campaignFields[i] ) ) {
				ga( "set", campaignFields[i], meta( campaignFields[i] ) );
			}
		}

		for ( var j = 0; j < dimensions.length; j++ ) {
			if ( meta( dimensions[i] ) ) {
				ga( "set", dimensions[i], meta( dimensions[i] ) );
			}
		}

		if ( userId.length > 0 ) {
			ga( "set", "&uid", userId );
		}

		ga( "send", "pageview" );
	}
} ) ( window, document );
<|endoftext|>


<commit_before>import { ViewEngine } from 'grind-view'

import './CacheManager'
import './Compiler'
import './HtmlString'
import './StoneLoop'
import './Watcher'
import './Support/escape'

export class StoneEngine extends ViewEngine {
	cacheManager = null
	compiler = null
	watcher = null

	context = {
		escape: escape,
		HtmlString: HtmlString,
		StoneLoop: StoneLoop,
		stringify: JSON.stringify
	}

	constructor(app, view) {
		super(app, view)

		this.cacheManager = new CacheManager(app, this)
		this.compiler = new Compiler(this)
	}

	async bootstrap() {
		const engine = this

		function StoneExpressView(name) {
			this.template = name
			this.name = name
			this.path = name
		}

		StoneExpressView.prototype.render = function(context, callback) {
			let template = null

			try {
				template = engine._render(this.template, context)
			} catch(err) {
				return callback(err)
			}

			callback(null, template)
		}

		this.app.express.set('view', StoneExpressView)

		if(this.app.config.get('view.watch', this.app.debug)) {
			this.watcher = new Watcher(this, this.view.viewPath)
			this.watcher.start()
		}

		if(await this.cacheManager.exists()) {
			await this.cacheManager.load()
		}
	}

	shutdown() {
		if(this.watcher.isNil) {
			return
		}

		return this.watcher.stop()
	}

	share(name, value) {
		this.context[name] = value
	}

	extend(name, extension) {
		this.compiler.directives[name] = extension
	}

	render(template, context) {
		return Promise.resolve(this._render(template, context))
	}

	_render(template, context) {
		const compiled = this.compiler.compile(this.resolve(template))
		const rendered = compiled({
			...this.context,
			...context,
			$engine: this,
			$compiler: this.compiler
		})

		return rendered
	}

	renderString(template, context) {
		const compiled = this.compiler.compileString(template)
		const rendered = compiled({
			...this.context,
			...context,
			$engine: this,
			$compiler: this.compiler
		})

		return rendered
	}

	resolve(template) {
		return `${this.view.viewPath}/${template.replace(/\./g, '/')}.stone`
	}

	_extends(template, context, sections) {
		return (this.compiler.compile(this.resolve(template)))(context, sections)
	}

	_include(context, sections, template, extra) {
		if(extra) {
			context = { ...context, ...extra }
		}

		const compiled = this.compiler.compile(this.resolve(template))

		if(compiled.isLayout) {
			// Don’t pass through sections if including another layout
			return compiled(context)
		}

		return compiled(context, sections)
	}

	writeCache() {
		return this.cacheManager.write()
	}

	clearCache() {
		return this.cacheManager.clear()
	}

	toHtmlString(html) {
		return new HtmlString(html)
	}

	isHtmlString(html) {
		return html instanceof HtmlString
	}

}
<commit_msg>Removed duplicate code in StoneEngine<commit_after>import { ViewEngine } from 'grind-view'

import './CacheManager'
import './Compiler'
import './HtmlString'
import './StoneLoop'
import './Watcher'
import './Support/escape'

export class StoneEngine extends ViewEngine {
	cacheManager = null
	compiler = null
	watcher = null

	context = {
		escape: escape,
		HtmlString: HtmlString,
		StoneLoop: StoneLoop,
		stringify: JSON.stringify
	}

	constructor(app, view) {
		super(app, view)

		this.cacheManager = new CacheManager(app, this)
		this.compiler = new Compiler(this)
	}

	async bootstrap() {
		const engine = this

		function StoneExpressView(name) {
			this.template = name
			this.name = name
			this.path = name
		}

		StoneExpressView.prototype.render = function(context, callback) {
			let template = null

			try {
				template = engine._render(this.template, context)
			} catch(err) {
				return callback(err)
			}

			callback(null, template)
		}

		this.app.express.set('view', StoneExpressView)

		if(this.app.config.get('view.watch', this.app.debug)) {
			this.watcher = new Watcher(this, this.view.viewPath)
			this.watcher.start()
		}

		if(await this.cacheManager.exists()) {
			await this.cacheManager.load()
		}
	}

	shutdown() {
		if(this.watcher.isNil) {
			return
		}

		return this.watcher.stop()
	}

	share(name, value) {
		this.context[name] = value
	}

	extend(name, extension) {
		this.compiler.directives[name] = extension
	}

	render(template, context) {
		return Promise.resolve(this._render(template, context))
	}

	_render(template, context) {
		return this._renderCompiled(this.compiler.compile(this.resolve(template)), context)
	}

	renderString(template, context) {
		return this._renderCompiled(this.compiler.compileString(template), context)
	}

	_renderCompiled(compiled, context) {
		return compiled({
			...this.context,
			...context,
			$engine: this,
			$compiler: this.compiler
		})
	}

	resolve(template) {
		return `${this.view.viewPath}/${template.replace(/\./g, '/')}.stone`
	}

	_extends(template, context, sections) {
		return (this.compiler.compile(this.resolve(template)))(context, sections)
	}

	_include(context, sections, template, extra) {
		if(extra) {
			context = { ...context, ...extra }
		}

		const compiled = this.compiler.compile(this.resolve(template))

		if(compiled.isLayout) {
			// Don’t pass through sections if including another layout
			return compiled(context)
		}

		return compiled(context, sections)
	}

	writeCache() {
		return this.cacheManager.write()
	}

	clearCache() {
		return this.cacheManager.clear()
	}

	toHtmlString(html) {
		return new HtmlString(html)
	}

	isHtmlString(html) {
		return html instanceof HtmlString
	}

}
<|endoftext|>