<commit_before>//*****************************************************************************
// Copyright (c) 2015 Auto-ID Lab. Japan
//
// Contributors:
//  Iori MIZUTANI (iori.mizutani@gmail.com)
//*****************************************************************************
// Make Intel Edison's BLE module for connecting a Texas Instruments SenstorTag CC2451
var async = require("async"), fs = require("fs"), getmac = require("getmac"), mqtt = require("mqtt"), nconf = require("nconf"), SensorTag = require("sensortag"), spawn = require("child_process").spawn;

// constants
var configFile = "/var/local/config.json";

var sensorMacFile = "/var/local/SENSOR_TAG";

var pidFile = "/var/local/iot.pid";

var mosquittoHost = "test.mosquitto.org";

var mosquittoPort = 1883;

var defaultTopic = "gif-iot";

var defaultInterval = 1e3;

// globals
var mqttHost, mqttPort, mqttTopic, mqttInterbal, sensorInterval;

// mqttClient
var mqttClient = null;

// tagData object
var tagData = {};

tagData.payload = {};

tagData.payload.deviceMac = null;

tagData.payload.sensorMac = undefined;

tagData.toJson = function() {
    return JSON.stringify(this.payload);
};

tagData.toBluemixJson = function() {
    return JSON.stringify({
        d: {
            myName: undefined,
            objectTemp: this.payload.objectTemp,
            ambientTemp: this.payload.ambientTemp,
            accelX: this.payload.accelX,
            accelY: this.payload.accelY,
            accelZ: this.payload.accelZ,
            humidity: this.payload.humidity,
            temp: this.payload.temp,
            magX: this.payload.magX,
            magY: this.payload.magY,
            magZ: this.payload.magZ,
            pressure: this.payload.pressure,
            gyroX: this.payload.gyroX,
            gyroY: this.payload.gyroY,
            gyroZ: this.payload.gyroZ,
            latitude: 35.621465,
            longitude: 139.748531
        }
    });
};

tagData.publish = function(sensorMac) {
    mqttClient.publish(mqttTopic + "/data/" + sensorMac, tagData.toJson());
    if (bluemix) {
        bluemixClient.publish("iot-2/evt/sample/fmt/json", tagData.toBluemixJson());
        console.log(tagData.toBluemixJson());
    }
};

// mac address to discover
var macToDiscover = undefined;

// pending notifier pid
var pendingNotifier = null;

// bluemixOption
var bluemix = false;

// bluemixClient
var bluemixClient = null;

// read the config file
function readConfig() {
    nconf.argv().file({
        file: configFile
    });
    if (nconf.get("bluemix")) bluemix = true;
    mqttHost = nconf.get("mqtt:host") || mosquittoHost;
    mqttPort = nconf.get("mqtt:port") || mosquittoPort;
    mqttTopic = nconf.get("mqtt:topic") || defaultTopic;
    mqttInterval = nconf.get("mqtt:interval") || defaultInterval;
    sensorInterval = nconf.get("sensor:interval") || mqttInterval;
    if (!tagData.payload.sensorMac && nconf.get("sensor:mac")) {
        tagData.payload.sensorMac = nconf.get("sensor:mac");
    }
    if (tagData.payload.sensorMac) {
        macToDiscover = tagData.payload.sensorMac.replace(/:/g, "").toLowerCase();
    }
    console.log("Press the side button on the SensorTag (" + tagData.payload.sensorMac + ") to connect");
}

// save the config to disk
function saveConfig(ignoreMac) {
    nconf.set("mqtt:host", mqttHost);
    nconf.set("mqtt:port", mqttPort);
    nconf.set("mqtt:topic", mqttTopic);
    nconf.set("mqtt:interval", mqttInterval);
    nconf.set("sensor:interval", sensorInterval);
    if (!ignoreMac) nconf.set("sensor:mac", tagData.payload.sensorMac.toUpperCase().replace(/(.)(?=(..)+$)/g, "$1:"));
    nconf.save(function(err) {
        fs.readFile(configFile, function(err, data) {
            console.dir(JSON.parse(data.toString()));
        });
        if (!ignoreMac) {
            fs.writeFile(sensorMacFile, nconf.get("sensor:mac"), function(err) {
                if (err) console.log(err);
            });
        }
    });
}

// delete config file from the disk
function deleteConfig() {
    fs.unlink(sensorMacFile, function(err) {
        if (err) throw err;
    });
    fs.unlink(configFile, function(err) {
        if (err) throw err;
    });
    saveConfig(true);
}

// called on message received
function doCommand(topic, message, packet) {
    console.log("received command: " + topic + " msg: " + message);
    var topics = topic.split("/");
    switch (topics[3]) {
      case "ping":
        var payload = JSON.parse(message);
        break;

      default:
        console.log("Unxpected Command: " + topics[3]);
    }
}

// cycle thru obx1 led color
function toggleRainbowLED() {
    spawn("bash", [ "/var/local/rainbow.sh" ], {
        stdio: "ignore",
        detached: true
    }).unref();
}

// write PID to file
function savePID() {
    fs.writeFile(pidFile, process.pid, function(err) {
        if (err) console.log(err);
    });
}

// graceful shutdown
function gracefulShutdown() {
    // delete PID file
    fs.unlink(pidFile, function(err) {
        if (err) throw err;
    });
    // reset LED
    toggleRainbowLED();
    if (mqttClient) {
        var ipmac = JSON.stringify({
            ip: nconf.get("ip"),
            sensorMac: nconf.get("sensor:mac"),
            deviceMac: tagData.payload.deviceMac,
            nodeStatus: "down"
        });
        mqttClient.publish("gif-iot/ip", ipmac);
        console.log("*** [gif-iot/ip] " + ipmac);
        mqttClient.end();
    }
    if (bluemixClient) bluemixClient.end();
    process.exit(0);
}

//*****************************************************************************
/* node */
//*****************************************************************************
process.on("exit", function(code) {
    console.log("*** Exiting with code: " + code);
});

var signals = [ "SIGINT", "SIGTERM", "SIGQUIT" ];

for (i in signals) {
    process.on(signals[i], function() {
        console.log("\n" + signals[i]);
        gracefulShutdown();
    });
}

async.series([ function(callback) {
    fs.readFile(sensorMacFile, "utf8", function(err, data) {
        // if (err) throw err; // just skip if file not found
        tagData.payload.sensorMac = data;
    });
    callback();
}, function(callback) {
    readConfig();
    callback();
}, function(callback) {
    // get device mac address
    getmac.getMac(function(err, mac) {
        if (err) throw err;
        tagData.payload.deviceMac = mac.toUpperCase();
    });
    callback();
}, function(callback) {
    // create MQTT client
    console.log("*** [MQTT] Connect to the mqtt broker: " + mqttHost);
    mqttClient = mqtt.connect({
        port: mqttPort,
        host: mqttHost,
        keepalive: 30
    });
    if (bluemix) {
        bluemixClient = mqtt.connect({
            port: "1883",
            host: "quickstart.messaging.internetofthings.ibmcloud.com",
            keepalive: 30,
            clientId: "d:quickstart:iotsample-ti-bbst:" + macToDiscover
        });
    }
    callback();
}, function(callback) {
    if (nconf.get("ip") != undefined) {
        pendingNotifier = setInterval(function(tag) {
            var ipmac = JSON.stringify({
                ip: nconf.get("ip"),
                sensorMac: nconf.get("sensor:mac"),
                deviceMac: tagData.payload.deviceMac,
                nodeStatus: "pending"
            });
            mqttClient.publish("gif-iot/ip", ipmac);
            console.log("*** [gif-iot/ip] " + ipmac);
        }, 5e3);
    }
    callback();
}, function(callback) {
    toggleRainbowLED();
    callback();
} ]);

SensorTag.discover(function(sensorTag) {
    sensorTag.on("disconnect", function() {
        console.log("*** SensorTag disconnected");
        gracefulShutdown();
    });
    // asynchronous functions in series
    async.series([ function(callback) {
        // save pid
        savePID();
        if (pendingNotifier) clearInterval(pendingNotifier);
        callback();
    }, function(callback) {
        // stop rainbowLED
        toggleRainbowLED();
        callback();
    }, function(callback) {
        // connect to the sensor tag
        console.log("*** [SensorTag] connect");
        sensorTag.connect(callback);
    }, function(callback) {
        // discover services and characteristics
        console.log("*** [SensorTag] discover services and characteristics");
        sensorTag.discoverServicesAndCharacteristics(callback);
    }, function(callback) {
        // get and save MAC address of the sensor tag
        console.log("*** [SensorTag] get MAC address");
        tagData.payload.sensorMac = sensorTag.uuid;
        callback();
    }, function(callback) {
        // save config with new MAC address
        saveConfig();
        if (nconf.get("ip") != undefined) {
            // get device mac address
            var ipmac = JSON.stringify({
                ip: nconf.get("ip"),
                sensorMac: nconf.get("sensor:mac"),
                deviceMac: tagData.payload.deviceMac
            });
            mqttClient.publish("gif-iot/ip", ipmac);
            console.log("*** [gif-iot/ip] " + ipmac);
        } else {
            console.log("*** [Option] IP address not provided");
        }
        callback();
    }, function(callback) {
        // irTemperature
        console.log("*** [SensorTag] Enabling irTemperature");
        sensorTag.enableIrTemperature(callback);
    }, function(callback) {
        sensorTag.on("irTemperatureChange", function(objectTemperature, ambientTemperature) {
            tagData.payload.objectTemp = parseFloat(objectTemperature.toFixed(1));
            tagData.payload.ambientTemp = parseFloat(ambientTemperature.toFixed(1));
        });
        sensorTag.notifyIrTemperature(callback);
    }, function(callback) {
        // accelerometer
        console.log("*** [SensorTag] Enabling accelerometer");
        sensorTag.enableAccelerometer(callback);
    }, function(callback) {
        sensorTag.setAccelerometerPeriod(sensorInterval, callback);
    }, function(callback) {
        sensorTag.on("accelerometerChange", function(x, y, z) {
            tagData.payload.accelX = parseFloat(x.toFixed(4));
            tagData.payload.accelY = parseFloat(y.toFixed(4));
            tagData.payload.accelZ = parseFloat(z.toFixed(4));
        });
        sensorTag.notifyAccelerometer(callback);
    }, function(callback) {
        // humidity
        console.log("*** [SensorTag] Enabling humidity");
        sensorTag.enableHumidity(callback);
    }, function(callback) {
        sensorTag.on("humidityChange", function(temperature, humidity) {
            tagData.payload.humidity = parseFloat(humidity.toFixed(1));
            tagData.payload.temp = parseFloat(temperature.toFixed(1));
        });
        sensorTag.notifyHumidity(callback);
    }, function(callback) {
        // magnetometer
        console.log("*** [SensorTag] Enabling magnetometer");
        sensorTag.enableMagnetometer(callback);
    }, function(callback) {
        sensorTag.setMagnetometerPeriod(sensorInterval, callback);
    }, function(callback) {
        sensorTag.on("magnetometerChange", function(x, y, z) {
            tagData.payload.magX = parseFloat(x.toFixed(1));
            tagData.payload.magY = parseFloat(y.toFixed(1));
            tagData.payload.magZ = parseFloat(z.toFixed(1));
        });
        sensorTag.notifyMagnetometer(callback);
    }, function(callback) {
        // barometricPressure
        console.log("*** [SensorTag] Enabling barometricPressure");
        sensorTag.enableBarometricPressure(callback);
    }, function(callback) {
        sensorTag.on("barometricPressureChange", function(pressure) {
            tagData.payload.pressure = parseFloat(pressure.toFixed(1));
        });
        sensorTag.notifyBarometricPressure(callback);
    }, function(callback) {
        // gyroscope
        console.log("*** [SensorTag] Enabling gyroscope");
        sensorTag.enableGyroscope(callback);
    }, function(callback) {
        sensorTag.on("gyroscopeChange", function(x, y, z) {
            tagData.payload.gyroX = parseFloat(x.toFixed(1));
            tagData.payload.gyroY = parseFloat(y.toFixed(1));
            tagData.payload.gyroZ = parseFloat(z.toFixed(1));
        });
        sensorTag.notifyGyroscope(callback);
    }, function(callback) {
        // simleKey
        sensorTag.on("simpleKeyChange", function(left, right) {
            tagData.payload.left = left;
            tagData.payload.right = right;
            if (left && right) deleteConfig();
        });
        sensorTag.notifySimpleKey(callback);
    }, function(callback) {
        // MQTT subscribe to cmd topic
        console.log("*** [MQTT] Subscribe to " + mqttTopic + "/cmd/" + nconf.get("sensor:mac"));
        mqttClient.subscribe(mqttTopic + "/cmd/" + nconf.get("sensor:mac"));
        mqttClient.on("message", doCommand);
        callback();
    }, function(callback) {
        // MQTT publish sensor data
        console.log("*** [MQTT] Publish to " + mqttTopic + "/data/" + nconf.get("sensor:mac"));
        setInterval(function(tag) {
            tag.publish(nconf.get("sensor:mac"));
        }, mqttInterval, tagData);
    }, function(callback) {
        // disconnect from the sensor tag
        sensorTag.disconnect(callback);
    } ]);
}, macToDiscover);
<commit_msg>file removal exception<commit_after>//*****************************************************************************
// Copyright (c) 2015 Auto-ID Lab. Japan
//
// Contributors:
//  Iori MIZUTANI (iori.mizutani@gmail.com)
//*****************************************************************************
// Make Intel Edison's BLE module for connecting a Texas Instruments SenstorTag CC2451
var async = require("async"), fs = require("fs"), getmac = require("getmac"), mqtt = require("mqtt"), nconf = require("nconf"), SensorTag = require("sensortag"), spawn = require("child_process").spawn;

// constants
var configFile = "/var/local/config.json";

var sensorMacFile = "/var/local/SENSOR_TAG";

var pidFile = "/var/local/iot.pid";

var mosquittoHost = "lain.sfc.wide.ad.jp";

var mosquittoPort = 1883;

var defaultTopic = "gif-iot";

var defaultInterval = 1e3;

// globals
var mqttHost, mqttPort, mqttTopic, mqttInterbal, sensorInterval;

// mqttClient
var mqttClient = null;

// tagData object
var tagData = {};

tagData.payload = {};

tagData.payload.deviceMac = null;

tagData.payload.sensorMac = undefined;

tagData.toJson = function() {
    return JSON.stringify(this.payload);
};

tagData.toBluemixJson = function() {
    return JSON.stringify({
        d: {
            myName: undefined,
            objectTemp: this.payload.objectTemp,
            ambientTemp: this.payload.ambientTemp,
            accelX: this.payload.accelX,
            accelY: this.payload.accelY,
            accelZ: this.payload.accelZ,
            humidity: this.payload.humidity,
            temp: this.payload.temp,
            magX: this.payload.magX,
            magY: this.payload.magY,
            magZ: this.payload.magZ,
            pressure: this.payload.pressure,
            gyroX: this.payload.gyroX,
            gyroY: this.payload.gyroY,
            gyroZ: this.payload.gyroZ,
            latitude: 35.621465,
            longitude: 139.748531
        }
    });
};

tagData.publish = function(sensorMac) {
    mqttClient.publish(mqttTopic + "/data/" + sensorMac, tagData.toJson());
    if (bluemix) {
        bluemixClient.publish("iot-2/evt/sample/fmt/json", tagData.toBluemixJson());
        console.log(tagData.toBluemixJson());
    }
};

// mac address to discover
var macToDiscover = undefined;

// pending notifier pid
var pendingNotifier = null;

// bluemixOption
var bluemix = false;

// bluemixClient
var bluemixClient = null;

// read the config file
function readConfig() {
    nconf.argv().file({
        file: configFile
    });
    if (nconf.get("bluemix")) bluemix = true;
    mqttHost = nconf.get("mqtt:host") || mosquittoHost;
    mqttPort = nconf.get("mqtt:port") || mosquittoPort;
    mqttTopic = nconf.get("mqtt:topic") || defaultTopic;
    mqttInterval = nconf.get("mqtt:interval") || defaultInterval;
    sensorInterval = nconf.get("sensor:interval") || mqttInterval;
    if (!tagData.payload.sensorMac && nconf.get("sensor:mac")) {
        tagData.payload.sensorMac = nconf.get("sensor:mac");
    }
    if (tagData.payload.sensorMac) {
        macToDiscover = tagData.payload.sensorMac.replace(/:/g, "").toLowerCase();
    }
    console.log("Press the side button on the SensorTag (" + tagData.payload.sensorMac + ") to connect");
}

// save the config to disk
function saveConfig(ignoreMac) {
    nconf.set("mqtt:host", mqttHost);
    nconf.set("mqtt:port", mqttPort);
    nconf.set("mqtt:topic", mqttTopic);
    nconf.set("mqtt:interval", mqttInterval);
    nconf.set("sensor:interval", sensorInterval);
    if (!ignoreMac) nconf.set("sensor:mac", tagData.payload.sensorMac.toUpperCase().replace(/(.)(?=(..)+$)/g, "$1:"));
    nconf.save(function(err) {
        fs.readFile(configFile, function(err, data) {
            console.dir(JSON.parse(data.toString()));
        });
        if (!ignoreMac) {
            fs.writeFile(sensorMacFile, nconf.get("sensor:mac"), function(err) {
                if (err) console.log(err);
            });
        }
    });
}

// delete config file from the disk
function deleteConfig() {
    fs.unlink(sensorMacFile, function(err) {
    });
    fs.unlink(configFile, function(err) {
    });
    saveConfig(true);
}

// called on message received
function doCommand(topic, message, packet) {
    console.log("received command: " + topic + " msg: " + message);
    var topics = topic.split("/");
    switch (topics[3]) {
      case "ping":
        var payload = JSON.parse(message);
        break;

      default:
        console.log("Unxpected Command: " + topics[3]);
    }
}

// cycle thru obx1 led color
function toggleRainbowLED() {
    spawn("bash", [ "/var/local/rainbow.sh" ], {
        stdio: "ignore",
        detached: true
    }).unref();
}

// write PID to file
function savePID() {
    fs.writeFile(pidFile, process.pid, function(err) {
        if (err) console.log(err);
    });
}

// graceful shutdown
function gracefulShutdown() {
    // delete PID file
    fs.unlink(pidFile, function(err) {
        if (err) throw err;
    });
    // reset LED
    toggleRainbowLED();
    if (mqttClient) {
        var ipmac = JSON.stringify({
            ip: nconf.get("ip"),
            sensorMac: nconf.get("sensor:mac"),
            deviceMac: tagData.payload.deviceMac,
            nodeStatus: "down"
        });
        mqttClient.publish("gif-iot/ip", ipmac);
        console.log("*** [gif-iot/ip] " + ipmac);
        mqttClient.end();
    }
    if (bluemixClient) bluemixClient.end();
    process.exit(0);
}

//*****************************************************************************
/* node */
//*****************************************************************************
process.on("exit", function(code) {
    console.log("*** Exiting with code: " + code);
});

var signals = [ "SIGINT", "SIGTERM", "SIGQUIT" ];

for (i in signals) {
    process.on(signals[i], function() {
        console.log("\n" + signals[i]);
        gracefulShutdown();
    });
}

async.series([ function(callback) {
    fs.readFile(sensorMacFile, "utf8", function(err, data) {
        // if (err) throw err; // just skip if file not found
        tagData.payload.sensorMac = data;
    });
    callback();
}, function(callback) {
    readConfig();
    callback();
}, function(callback) {
    // get device mac address
    getmac.getMac(function(err, mac) {
        if (err) throw err;
        tagData.payload.deviceMac = mac.toUpperCase();
    });
    callback();
}, function(callback) {
    // create MQTT client
    console.log("*** [MQTT] Connect to the mqtt broker: " + mqttHost);
    mqttClient = mqtt.connect({
        port: mqttPort,
        host: mqttHost,
        keepalive: 30
    });
    if (bluemix) {
        bluemixClient = mqtt.connect({
            port: "1883",
            host: "quickstart.messaging.internetofthings.ibmcloud.com",
            keepalive: 30,
            clientId: "d:quickstart:iotsample-ti-bbst:" + macToDiscover
        });
    }
    callback();
}, function(callback) {
    if (nconf.get("ip") != undefined) {
        pendingNotifier = setInterval(function(tag) {
            var ipmac = JSON.stringify({
                ip: nconf.get("ip"),
                sensorMac: nconf.get("sensor:mac"),
                deviceMac: tagData.payload.deviceMac,
                nodeStatus: "pending"
            });
            mqttClient.publish("gif-iot/ip", ipmac);
            console.log("*** [gif-iot/ip] " + ipmac);
        }, 5e3);
    }
    callback();
}, function(callback) {
    toggleRainbowLED();
    callback();
} ]);

SensorTag.discover(function(sensorTag) {
    sensorTag.on("disconnect", function() {
        console.log("*** SensorTag disconnected");
        gracefulShutdown();
    });
    // asynchronous functions in series
    async.series([ function(callback) {
        // save pid
        savePID();
        if (pendingNotifier) clearInterval(pendingNotifier);
        callback();
    }, function(callback) {
        // stop rainbowLED
        toggleRainbowLED();
        callback();
    }, function(callback) {
        // connect to the sensor tag
        console.log("*** [SensorTag] connect");
        sensorTag.connect(callback);
    }, function(callback) {
        // discover services and characteristics
        console.log("*** [SensorTag] discover services and characteristics");
        sensorTag.discoverServicesAndCharacteristics(callback);
    }, function(callback) {
        // get and save MAC address of the sensor tag
        console.log("*** [SensorTag] get MAC address");
        tagData.payload.sensorMac = sensorTag.uuid;
        callback();
    }, function(callback) {
        // save config with new MAC address
        saveConfig();
        if (nconf.get("ip") != undefined) {
            // get device mac address
            var ipmac = JSON.stringify({
                ip: nconf.get("ip"),
                sensorMac: nconf.get("sensor:mac"),
                deviceMac: tagData.payload.deviceMac
            });
            mqttClient.publish("gif-iot/ip", ipmac);
            console.log("*** [gif-iot/ip] " + ipmac);
        } else {
            console.log("*** [Option] IP address not provided");
        }
        callback();
    }, function(callback) {
        // irTemperature
        console.log("*** [SensorTag] Enabling irTemperature");
        sensorTag.enableIrTemperature(callback);
    }, function(callback) {
        sensorTag.on("irTemperatureChange", function(objectTemperature, ambientTemperature) {
            tagData.payload.objectTemp = parseFloat(objectTemperature.toFixed(1));
            tagData.payload.ambientTemp = parseFloat(ambientTemperature.toFixed(1));
        });
        sensorTag.notifyIrTemperature(callback);
    }, function(callback) {
        // accelerometer
        console.log("*** [SensorTag] Enabling accelerometer");
        sensorTag.enableAccelerometer(callback);
    }, function(callback) {
        sensorTag.setAccelerometerPeriod(sensorInterval, callback);
    }, function(callback) {
        sensorTag.on("accelerometerChange", function(x, y, z) {
            tagData.payload.accelX = parseFloat(x.toFixed(4));
            tagData.payload.accelY = parseFloat(y.toFixed(4));
            tagData.payload.accelZ = parseFloat(z.toFixed(4));
        });
        sensorTag.notifyAccelerometer(callback);
    }, function(callback) {
        // humidity
        console.log("*** [SensorTag] Enabling humidity");
        sensorTag.enableHumidity(callback);
    }, function(callback) {
        sensorTag.on("humidityChange", function(temperature, humidity) {
            tagData.payload.humidity = parseFloat(humidity.toFixed(1));
            tagData.payload.temp = parseFloat(temperature.toFixed(1));
        });
        sensorTag.notifyHumidity(callback);
    }, function(callback) {
        // magnetometer
        console.log("*** [SensorTag] Enabling magnetometer");
        sensorTag.enableMagnetometer(callback);
    }, function(callback) {
        sensorTag.setMagnetometerPeriod(sensorInterval, callback);
    }, function(callback) {
        sensorTag.on("magnetometerChange", function(x, y, z) {
            tagData.payload.magX = parseFloat(x.toFixed(1));
            tagData.payload.magY = parseFloat(y.toFixed(1));
            tagData.payload.magZ = parseFloat(z.toFixed(1));
        });
        sensorTag.notifyMagnetometer(callback);
    }, function(callback) {
        // barometricPressure
        console.log("*** [SensorTag] Enabling barometricPressure");
        sensorTag.enableBarometricPressure(callback);
    }, function(callback) {
        sensorTag.on("barometricPressureChange", function(pressure) {
            tagData.payload.pressure = parseFloat(pressure.toFixed(1));
        });
        sensorTag.notifyBarometricPressure(callback);
    }, function(callback) {
        // gyroscope
        console.log("*** [SensorTag] Enabling gyroscope");
        sensorTag.enableGyroscope(callback);
    }, function(callback) {
        sensorTag.on("gyroscopeChange", function(x, y, z) {
            tagData.payload.gyroX = parseFloat(x.toFixed(1));
            tagData.payload.gyroY = parseFloat(y.toFixed(1));
            tagData.payload.gyroZ = parseFloat(z.toFixed(1));
        });
        sensorTag.notifyGyroscope(callback);
    }, function(callback) {
        // simleKey
        sensorTag.on("simpleKeyChange", function(left, right) {
            tagData.payload.left = left;
            tagData.payload.right = right;
            if (left && right) deleteConfig();
        });
        sensorTag.notifySimpleKey(callback);
    }, function(callback) {
        // MQTT subscribe to cmd topic
        console.log("*** [MQTT] Subscribe to " + mqttTopic + "/cmd/" + nconf.get("sensor:mac"));
        mqttClient.subscribe(mqttTopic + "/cmd/" + nconf.get("sensor:mac"));
        mqttClient.on("message", doCommand);
        callback();
    }, function(callback) {
        // MQTT publish sensor data
        console.log("*** [MQTT] Publish to " + mqttTopic + "/data/" + nconf.get("sensor:mac"));
        setInterval(function(tag) {
            tag.publish(nconf.get("sensor:mac"));
        }, mqttInterval, tagData);
    }, function(callback) {
        // disconnect from the sensor tag
        sensorTag.disconnect(callback);
    } ]);
}, macToDiscover);
<|endoftext|>


<commit_before>var async = require('async'),
	keystone = require('keystone');

var Meetup = keystone.list('Meetup'),
	RSVP = keystone.list('RSVP'),
	User = keystone.list('User'),
	Post = keystone.list('Post');

exports = module.exports = function(req, res) {

	var stats = {};

	async.parallel([

		function(next) {

			Meetup.model.findOne()
				.where('date').lt(moment().startOf('day').toDate())
				.where('state', 'published')
				.sort('-date')
				.exec(function(err, meetup) {

					RSVP.model.count({
						meetup: meetup,
						attending: true
					})
					.exec(function(err, count) {
						stats.rsvps = count;
						return next();
					});

				});

		},

		function(next) {

			User.model.count()
				.exec(function(err, count) {
					stats.members = count;
					return next();
				});

		},

		function(next) {

			Post.model.count()
				.exec(function(err, count) {
					stats.posts = count;
					return next();
				});

		}

	], function(err) {

		return res.apiResponse(stats);

	});

}
<commit_msg>Loading the correct meet up.<commit_after>var async = require('async'),
	keystone = require('keystone');

var Meetup = keystone.list('Meetup'),
	RSVP = keystone.list('RSVP'),
	User = keystone.list('User'),
	Post = keystone.list('Post');

exports = module.exports = function(req, res) {

	var stats = {};

	async.parallel([

		function(next) {

			Meetup.model.findOne()
				.where('date').gte(moment().startOf('day').toDate())
				.where('state', 'published')
				.sort('date')
				.exec(function(err, meetup) {

					RSVP.model.count({
						meetup: meetup,
						attending: true
					})
					.exec(function(err, count) {
						stats.rsvps = count;
						return next();
					});

				});

		},

		function(next) {

			User.model.count()
				.exec(function(err, count) {
					stats.members = count;
					return next();
				});

		},

		function(next) {

			Post.model.count()
				.exec(function(err, count) {
					stats.posts = count;
					return next();
				});

		}

	], function(err) {

		return res.apiResponse(stats);

	});

}
<|endoftext|>


<commit_before>function PerformanceDashboard(executionId, measurementType, entity) {

	var widgetsArray = [];
	var entityName = '';
	if(measurementType && measurementType === 'keyword'){
		entityName = 'Keyword';
	}else{
		entityName = 'Custom Transaction';
	}

	//addLastMeasurements(widgetsArray);
	addAggregatesOverTimeTpl(widgetsArray, entityName);
	addLastMeasurementsTpl(widgetsArray, entityName);
	addAggregatesSummaryTpl(widgetsArray, entityName);
	//TODO:addMeasurementExplorer(widgetsArray) //with paging
	//TODO:addAggregatesSummaryOptzTpl(widgetsArray);
	var dashboardObject = new Dashboard(
			entityName + ' Performance',
			new DashboardState(
					new GlobalSettings(
							[new Placeholder("__eId__", executionId, false), new Placeholder("__measurementType__", measurementType, false)],
							false,
							false,
							'Global Settings',
							3000
					),
					widgetsArray,
					entityName + ' Dashboard',
					'aggregated',
					new DefaultDashboardGui()
			)
	);

	dashboardObject.oid = "perfDashboardId";
	return dashboardObject;
};

function RTMAggBaseQueryTmpl(metric, transform){
	return new AsyncQuery(
			null,
			new Service(//service
					"/rtm/rest/aggregate/get", "Post",
					"",//templated
					new Preproc("function(requestFragment, workData){var newRequestFragment = requestFragment;for(i=0;i<workData.length;i++){newRequestFragment = newRequestFragment.replace(workData[i].key, workData[i].value);}return newRequestFragment;}"),
					new Postproc("", "",[], "function(response){if(!response.data.payload){console.log('No payload ->' + JSON.stringify(response)); return null;}return [{ placeholder : '__streamedSessionId__', value : response.data.payload.streamedSessionId, isDynamic : false }];}", "")
			),
			new Service(//callback
					"/rtm/rest/aggregate/refresh", "Post",
					"{\"streamedSessionId\": \"__streamedSessionId__\"}",
					new Preproc("function(requestFragment, workData){var newRequestFragment = requestFragment;for(i=0;i<workData.length;i++){newRequestFragment = newRequestFragment.replace(workData[i].placeholder, workData[i].value);}return newRequestFragment;}"),
					new Postproc("function(response){return response.data.payload.stream.complete;}", transform ,[{"key" : "metric", "value" : metric, "isDynamic" : false}], {}, ""))
	);
};

function RTMAggBaseTemplatedQueryTmpl(metric, pGranularity, transform){
	return new TemplatedQuery(
			"Template",
			new RTMAggBaseQueryTmpl(metric, transform),
			new DefaultPaging(),
			new Controls(
					new Template(
							"{ \"selectors1\": [{ \"textFilters\": [{ \"key\": \"eId\", \"value\": \"__eId__\", \"regex\": \"false\" }, { \"key\": \"type\", \"value\": \"__measurementType__\", \"regex\": \"false\" }], \"numericalFilters\": [] }], \"serviceParams\": { \"measurementService.nextFactor\": \"0\", \"aggregateService.sessionId\": \"defaultSid\", \"aggregateService.granularity\": \"__granularity__\", \"aggregateService.groupby\": \"name\", \"aggregateService.cpu\": \"1\", \"aggregateService.partition\": \"8\", \"aggregateService.timeout\": \"600\" } }",
							"",
							[new Placeholder("__granularity__", pGranularity, false)]
					)
			)
	);
};

var addAggregatesSummaryTpl = function(widgetsArray, entityName){
	var summaryTransform = "function (response) {\r\n    //var metrics = response.data.payload.metricList;\r\n    var metrics = [\"cnt\",\"avg\", \"min\", \"max\", \"tpm\", \"tps\", \"90th pcl\"];\r\n    var retData = [], series = {};\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    if (payload && payloadKeys.length > 0) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[0]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            for (i = 0; i < metrics.length; i++) {\r\n                var metric = metrics[i];\r\n                if (payload[payloadKeys[0]][serieskeys[j]][metric]) {\r\n                    retData.push({\r\n                        x: metric,\r\n                        y: Math.round(payload[payloadKeys[0]][serieskeys[j]][metric]),\r\n                        z: serieskeys[j]\r\n                    });\r\n                }\r\n            }\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var standalone = new Widget(getUniqueId(), new DefaultWidgetState(), new DashletState(entityName + " stats summary", false, 0, {}, new ChartOptions('seriesTable'), new Config('Off', false, false, ''), new RTMAggBaseTemplatedQueryTmpl("sum", "max", summaryTransform), new DefaultGuiClosed(), new DefaultInfo()));
	widgetsArray.push(standalone);
};

var addAggregatesOverTimeTpl = function(widgetsArray, entityName){
	var overtimeTransform = "function (response, args) {\r\n    var metric = args.metric;\r\n    var retData = [], series = {};\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            retData.push({\r\n                x: payloadKeys[i],\r\n                y: payload[payloadKeys[i]][serieskeys[j]][metric],\r\n                z: serieskeys[j]\r\n            });\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var overtimeFillBlanksTransform = "function (response, args) {\r\n    var metric = args.metric;\r\n    var retData = [], series = [];\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            if(!series.includes(serieskeys[j])){\r\n                series.push(serieskeys[j]);\r\n            }\r\n        }\r\n    }\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < series.length; j++) {\r\n            var yval;\r\n            if(payload[payloadKeys[i]][serieskeys[j]] && payload[payloadKeys[i]][serieskeys[j]][metric]){\r\n              yval = payload[payloadKeys[i]][serieskeys[j]][metric];\r\n            }else{\r\n              //console.log('missing dot: x=' + payloadKeys[i] + '; series=' + series[j]);\r\n              yval = 0;\r\n            }\r\n            retData.push({\r\n                x: payloadKeys[i],\r\n                y: yval,\r\n                z: series[j]\r\n            });\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var config = getMasterSlaveConfig("raw", "Average "+entityName+" Duration (ms)", "Nb " + entityName + " per second");

	var master = new Widget(config.masterid, new DefaultWidgetState(), new DashletState(config.mastertitle, false, 0, {}, new ChartOptions('lineChart'), config.masterconfig, new RTMAggBaseTemplatedQueryTmpl("avg", "auto", overtimeTransform), new DefaultGuiClosed(), new DefaultInfo()));
	//var slave = new Widget(config.slaveid, new DefaultWidgetState(), new DashletState(config.slavetitle, false, 0, {}, new ChartOptions('lineChart'), config.slaveconfig, new RTMAggBaseTemplatedQueryTmpl("cnt", "auto", overtimeTransform), new DefaultGuiClosed(), new DefaultInfo()));
	var slave = new Widget(config.slaveid, new DefaultWidgetState(), new DashletState(config.slavetitle, false, 0, {}, new ChartOptions('stackedAreaChart', false, true), config.slaveconfig, new RTMAggBaseTemplatedQueryTmpl("tps", "auto", overtimeFillBlanksTransform), new DefaultGuiClosed(), new DefaultInfo()));

	widgetsArray.push(master);
	widgetsArray.push(slave);
};

//No paging: FACTOR 100 via template
var addLastMeasurementsTpl = function(widgetsArray, entityName){
	function RTMLatestMeasurementBaseQueryTmpl(){
		return new SimpleQuery(
				"Raw", new Service(
						"/rtm/rest/measurement/latest", "Post",
						"",
						new Preproc("function(requestFragment, workData){var newRequestFragment = requestFragment;for(i=0;i<workData.length;i++){newRequestFragment = newRequestFragment.replace(workData[i].key, workData[i].value);}return newRequestFragment;}"),
						new Postproc("", "function (response, args) {\r\n    var x = 'begin', y = 'value', z = 'name';\r\n    var retData = [], index = {};\r\n    var payload = response.data.payload;\r\n    for (var i = 0; i < payload.length; i++) {\r\n        retData.push({\r\n            x: payload[i][x],\r\n            y: payload[i][y],\r\n            z: payload[i][z]\r\n        });\r\n    }\r\n    return retData;\r\n}",
								[], {}, "")
				)
		);
	};

	function RTMLatestMeasurementTemplatedQuery(){
		return new TemplatedQuery(
				"Template",
				new RTMLatestMeasurementBaseQueryTmpl(),
				new DefaultPaging(),
				//new Paging("On", new Offset("__FACTOR__", "return 0;", "return value + 1;", "if(value > 0){return value - 1;} else{return 0;}"), null),
				new Controls(
						new Template(
								"{ \"selectors1\": [{ \"textFilters\": [{ \"key\": \"eId\", \"value\": \"__eId__\", \"regex\": \"false\" }, { \"key\": \"type\", \"value\": \"__measurementType__\", \"regex\": \"false\" }], \"numericalFilters\": [] }], \"serviceParams\": { \"measurementService.nextFactor\": \"__FACTOR__\", \"aggregateService.sessionId\": \"defaultSid\", \"aggregateService.granularity\": \"auto\", \"aggregateService.groupby\": \"name\", \"aggregateService.cpu\": \"1\", \"aggregateService.partition\": \"8\", \"aggregateService.timeout\": \"600\" } }",
								"",
								[new Placeholder("__FACTOR__", "100", false)]
						)
				)
		);
	};

	var config = getMasterSlaveConfig("transformed", "Last 100 " + entityName +"s - Individual duration (ms)", "Last 100 "+entityName+"s - Value table (ms)");

	var master = new Widget(config.masterid, new DefaultWidgetState(), new DashletState(config.mastertitle, false, 0, {}, new ChartOptions('scatterChart'), config.masterconfig, new RTMLatestMeasurementTemplatedQuery(), new DefaultGuiClosed(), new DefaultInfo()) );
	var slave = new Widget(config.slaveid, new DefaultWidgetState(), new DashletState(config.slavetitle, false, 0, {}, new ChartOptions('seriesTable'), config.slaveconfig, new RTMLatestMeasurementTemplatedQuery(), new DefaultGuiClosed(), new DefaultInfo()) );

	widgetsArray.push(master);
	//widgetsArray.push(slave);
};

var getMasterSlaveConfig = function(rawOrTransformed, masterTitle, slaveTitle){
	var masterId, slaveId, masterTitle, slaveTitle, masterConfig, slaveConfig, datatype;

	if(rawOrTransformed === 'raw'){
		datatype = 'state.data.rawresponse';
	}else{
		datatype = 'state.data.transformed';
	}

	var random = getUniqueId();
	masterId = random + "-master";
	slaveId = random + "-slave";

	masterConfig = new Config('Off', true, false, 'unnecessaryAsMaster');
	slaveConfig = new Config('Off', false, true, datatype);
	slaveConfig.currentmaster = {
			oid: masterId,
			title: masterTitle
	};

	return {masterid: masterId, slaveid: slaveId, mastertitle: masterTitle, slavetitle: slaveTitle, masterconfig : masterConfig, slaveconfig: slaveConfig};
};

function StaticPresets() {
	return {
		queries: [],
		controls: {
			templates: []
		},
		configs: []
	};
}<commit_msg>Adding error stats to perf dashboard<commit_after>function PerformanceDashboard(executionId, measurementType, entity) {

	var widgetsArray = [];
	var entityName = '';
	if(measurementType && measurementType === 'keyword'){
		entityName = 'Keyword';
	}else{
		entityName = 'Custom Transaction';
	}

	//addLastMeasurements(widgetsArray);
	addAggregatesOverTimeTpl(widgetsArray, entityName);
	addErrorsOverTimeTpl(widgetsArray, entityName);
	addErrorsSummary(widgetsArray, entityName);
	addLastMeasurementsTpl(widgetsArray, entityName);
	addAggregatesSummaryTpl(widgetsArray, entityName);
	//TODO:addMeasurementExplorer(widgetsArray) //with paging
	//TODO:addAggregatesSummaryOptzTpl(widgetsArray);
	var dashboardObject = new Dashboard(
			entityName + ' Performance',
			new DashboardState(
					new GlobalSettings(
							[new Placeholder("__eId__", executionId, false), new Placeholder("__measurementType__", measurementType, false)],
							false,
							false,
							'Global Settings',
							3000
					),
					widgetsArray,
					entityName + ' Dashboard',
					'aggregated',
					new DefaultDashboardGui()
			)
	);

	dashboardObject.oid = "perfDashboardId";
	return dashboardObject;
};

function RTMAggBaseQueryTmpl(metric, transform){
	return new AsyncQuery(
			null,
			new Service(//service
					"/rtm/rest/aggregate/get", "Post",
					"",//templated
					new Preproc("function(requestFragment, workData){var newRequestFragment = requestFragment;for(i=0;i<workData.length;i++){newRequestFragment = newRequestFragment.replace(workData[i].key, workData[i].value);}return newRequestFragment;}"),
					new Postproc("", "",[], "function(response){if(!response.data.payload){console.log('No payload ->' + JSON.stringify(response)); return null;}return [{ placeholder : '__streamedSessionId__', value : response.data.payload.streamedSessionId, isDynamic : false }];}", "")
			),
			new Service(//callback
					"/rtm/rest/aggregate/refresh", "Post",
					"{\"streamedSessionId\": \"__streamedSessionId__\"}",
					new Preproc("function(requestFragment, workData){var newRequestFragment = requestFragment;for(i=0;i<workData.length;i++){newRequestFragment = newRequestFragment.replace(workData[i].placeholder, workData[i].value);}return newRequestFragment;}"),
					new Postproc("function(response){return response.data.payload.stream.complete;}", transform ,[{"key" : "metric", "value" : metric, "isDynamic" : false}], {}, ""))
	);
};

function RTMAggBaseTemplatedQueryTmpl(metric, pGranularity, transform, groupby){
	return new TemplatedQuery(
			"Template",
			new RTMAggBaseQueryTmpl(metric, transform),
			new DefaultPaging(),
			new Controls(
					new Template(
							"{ \"selectors1\": [{ \"textFilters\": [{ \"key\": \"eId\", \"value\": \"__eId__\", \"regex\": \"false\" }, { \"key\": \"type\", \"value\": \"__measurementType__\", \"regex\": \"false\" }], \"numericalFilters\": [] }], \"serviceParams\": { \"measurementService.nextFactor\": \"0\", \"aggregateService.sessionId\": \"defaultSid\", \"aggregateService.granularity\": \"__granularity__\", \"aggregateService.groupby\": \""+groupby+"\", \"aggregateService.cpu\": \"1\", \"aggregateService.partition\": \"8\", \"aggregateService.timeout\": \"600\" } }",
							"",
							[new Placeholder("__granularity__", pGranularity, false)]
					)
			)
	);
};

var addAggregatesSummaryTpl = function(widgetsArray, entityName){
	var summaryTransform = "function (response) {\r\n    //var metrics = response.data.payload.metricList;\r\n    var metrics = [\"cnt\",\"avg\", \"min\", \"max\", \"tpm\", \"tps\", \"90th pcl\"];\r\n    var retData = [], series = {};\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    if (payload && payloadKeys.length > 0) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[0]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            for (i = 0; i < metrics.length; i++) {\r\n                var metric = metrics[i];\r\n                if (payload[payloadKeys[0]][serieskeys[j]][metric]) {\r\n                    retData.push({\r\n                        x: metric,\r\n                        y: Math.round(payload[payloadKeys[0]][serieskeys[j]][metric]),\r\n                        z: serieskeys[j]\r\n                    });\r\n                }\r\n            }\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var standalone = new Widget(getUniqueId(), new DefaultWidgetState(), new DashletState(entityName + " stats summary", false, 0, {}, new ChartOptions('seriesTable'), new Config('Off', false, false, ''), new RTMAggBaseTemplatedQueryTmpl("sum", "max", summaryTransform, "name"), new DefaultGuiClosed(), new DefaultInfo()));
	widgetsArray.push(standalone);
};

var addErrorsSummary = function(widgetsArray, entityName){
	var summaryTransform = "function (response) {\r\n    //var metrics = response.data.payload.metricList;\r\n    var metrics = [\"cnt\"];\r\n    var retData = [], series = {};\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    if (payload && payloadKeys.length > 0) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[0]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            for (i = 0; i < metrics.length; i++) {\r\n                var metric = metrics[i];\r\n                if (payload[payloadKeys[0]][serieskeys[j]][metric]) {\r\n                    retData.push({\r\n                        x: metric,\r\n                        y: Math.round(payload[payloadKeys[0]][serieskeys[j]][metric]),\r\n                        z: '\u0020' + serieskeys[j].split('_')[0]\r\n                    });\r\n                }\r\n            }\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var standalone = new Widget(getUniqueId(), new DefaultWidgetState(), new DashletState(entityName + " status summary", false, 0, {}, new ChartOptions('singleValueTable'), new Config('Off', false, false, ''), new RTMAggBaseTemplatedQueryTmpl("cnt", "max", summaryTransform, "rnStatus"), new DefaultGuiClosed(), new DefaultInfo()));
	widgetsArray.push(standalone);
};

var addAggregatesOverTimeTpl = function(widgetsArray, entityName){
	var overtimeTransform = "function (response, args) {\r\n    var metric = args.metric;\r\n    var retData = [], series = {};\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            retData.push({\r\n                x: payloadKeys[i],\r\n                y: payload[payloadKeys[i]][serieskeys[j]][metric],\r\n                z: serieskeys[j]\r\n            });\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var overtimeFillBlanksTransform = "function (response, args) {\r\n    var metric = args.metric;\r\n    var retData = [], series = [];\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            if(!series.includes(serieskeys[j])){\r\n                series.push(serieskeys[j]);\r\n            }\r\n        }\r\n    }\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < series.length; j++) {\r\n            var yval;\r\n            if(payload[payloadKeys[i]][serieskeys[j]] && payload[payloadKeys[i]][serieskeys[j]][metric]){\r\n              yval = payload[payloadKeys[i]][serieskeys[j]][metric];\r\n            }else{\r\n              //console.log('missing dot: x=' + payloadKeys[i] + '; series=' + series[j]);\r\n              yval = 0;\r\n            }\r\n            retData.push({\r\n                x: payloadKeys[i],\r\n                y: yval,\r\n                z: series[j]\r\n            });\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var config = getMasterSlaveConfig("raw", "Average "+entityName+" Duration (ms)", "Nb " + entityName + " per second");

	var master = new Widget(config.masterid, new DefaultWidgetState(), new DashletState(config.mastertitle, false, 0, {}, new ChartOptions('lineChart'), config.masterconfig, new RTMAggBaseTemplatedQueryTmpl("avg", "auto", overtimeTransform, "name"), new DefaultGuiClosed(), new DefaultInfo()));
	//var slave = new Widget(config.slaveid, new DefaultWidgetState(), new DashletState(config.slavetitle, false, 0, {}, new ChartOptions('lineChart'), config.slaveconfig, new RTMAggBaseTemplatedQueryTmpl("cnt", "auto", overtimeTransform), new DefaultGuiClosed(), new DefaultInfo()));
	var slave = new Widget(config.slaveid, new DefaultWidgetState(), new DashletState(config.slavetitle, false, 0, {}, new ChartOptions('stackedAreaChart', false, true), config.slaveconfig, new RTMAggBaseTemplatedQueryTmpl("tps", "auto", overtimeFillBlanksTransform, "name"), new DefaultGuiClosed(), new DefaultInfo()));

	widgetsArray.push(master);
	widgetsArray.push(slave);
};

var addErrorsOverTimeTpl = function(widgetsArray, entityName){
	var summaryTransform = "function (response, args) {\r\n    var metric = args.metric;\r\n    var retData = [], series = [];\r\n\r\n    var payload = response.data.payload.stream.streamData;\r\n    var payloadKeys = Object.keys(payload);\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < serieskeys.length; j++) {\r\n            if(!serieskeys[j].includes(';PASSED') && !series.includes(serieskeys[j])){\r\n                series.push(serieskeys[j]);\r\n            }\r\n        }\r\n    }\r\n\r\n    for (i = 0; i < payloadKeys.length; i++) {\r\n        var serieskeys = Object.keys(payload[payloadKeys[i]])\r\n        for (j = 0; j < series.length; j++) {\r\n            var yval;\r\n            if(payload[payloadKeys[i]][serieskeys[j]] && payload[payloadKeys[i]][serieskeys[j]][metric]){\r\n              yval = payload[payloadKeys[i]][serieskeys[j]][metric];\r\n            }else{\r\n              //console.log('missing dot: x=' + payloadKeys[i] + '; series=' + series[j]);\r\n              yval = 0;\r\n            }\r\n            retData.push({\r\n                x: payloadKeys[i],\r\n                y: yval,\r\n                z: series[j]\r\n            });\r\n        }\r\n    }\r\n    return retData;\r\n}";
	var standalone = new Widget(getUniqueId(), new DefaultWidgetState(), new DashletState(entityName + " errors per minute", false, 0, {}, new ChartOptions('stackedAreaChart', false, true), new Config('Off', false, false, ''), new RTMAggBaseTemplatedQueryTmpl("tpm", "auto", summaryTransform, "name;rnStatus"), new DefaultGuiClosed(), new DefaultInfo()));
	widgetsArray.push(standalone);
};

//No paging: FACTOR 100 via template
var addLastMeasurementsTpl = function(widgetsArray, entityName){
	function RTMLatestMeasurementBaseQueryTmpl(){
		return new SimpleQuery(
				"Raw", new Service(
						"/rtm/rest/measurement/latest", "Post",
						"",
						new Preproc("function(requestFragment, workData){var newRequestFragment = requestFragment;for(i=0;i<workData.length;i++){newRequestFragment = newRequestFragment.replace(workData[i].key, workData[i].value);}return newRequestFragment;}"),
						new Postproc("", "function (response, args) {\r\n    var x = 'begin', y = 'value', z = 'name';\r\n    var retData = [], index = {};\r\n    var payload = response.data.payload;\r\n    for (var i = 0; i < payload.length; i++) {\r\n        retData.push({\r\n            x: payload[i][x],\r\n            y: payload[i][y],\r\n            z: payload[i][z]\r\n        });\r\n    }\r\n    return retData;\r\n}",
								[], {}, "")
				)
		);
	};

	function RTMLatestMeasurementTemplatedQuery(){
		return new TemplatedQuery(
				"Template",
				new RTMLatestMeasurementBaseQueryTmpl(),
				new DefaultPaging(),
				//new Paging("On", new Offset("__FACTOR__", "return 0;", "return value + 1;", "if(value > 0){return value - 1;} else{return 0;}"), null),
				new Controls(
						new Template(
								"{ \"selectors1\": [{ \"textFilters\": [{ \"key\": \"eId\", \"value\": \"__eId__\", \"regex\": \"false\" }, { \"key\": \"type\", \"value\": \"__measurementType__\", \"regex\": \"false\" }], \"numericalFilters\": [] }], \"serviceParams\": { \"measurementService.nextFactor\": \"__FACTOR__\", \"aggregateService.sessionId\": \"defaultSid\", \"aggregateService.granularity\": \"auto\", \"aggregateService.groupby\": \"name\", \"aggregateService.cpu\": \"1\", \"aggregateService.partition\": \"8\", \"aggregateService.timeout\": \"600\" } }",
								"",
								[new Placeholder("__FACTOR__", "100", false)]
						)
				)
		);
	};

	var config = getMasterSlaveConfig("transformed", "Last 100 " + entityName +"s - Individual duration (ms)", "Last 100 "+entityName+"s - Value table (ms)");

	var master = new Widget(config.masterid, new DefaultWidgetState(), new DashletState(config.mastertitle, false, 0, {}, new ChartOptions('scatterChart'), config.masterconfig, new RTMLatestMeasurementTemplatedQuery(), new DefaultGuiClosed(), new DefaultInfo()) );
	var slave = new Widget(config.slaveid, new DefaultWidgetState(), new DashletState(config.slavetitle, false, 0, {}, new ChartOptions('seriesTable'), config.slaveconfig, new RTMLatestMeasurementTemplatedQuery(), new DefaultGuiClosed(), new DefaultInfo()) );

	widgetsArray.push(master);
	//widgetsArray.push(slave);
};

var getMasterSlaveConfig = function(rawOrTransformed, masterTitle, slaveTitle){
	var masterId, slaveId, masterTitle, slaveTitle, masterConfig, slaveConfig, datatype;

	if(rawOrTransformed === 'raw'){
		datatype = 'state.data.rawresponse';
	}else{
		datatype = 'state.data.transformed';
	}

	var random = getUniqueId();
	masterId = random + "-master";
	slaveId = random + "-slave";

	masterConfig = new Config('Off', true, false, 'unnecessaryAsMaster');
	slaveConfig = new Config('Off', false, true, datatype);
	slaveConfig.currentmaster = {
			oid: masterId,
			title: masterTitle
	};

	return {masterid: masterId, slaveid: slaveId, mastertitle: masterTitle, slavetitle: slaveTitle, masterconfig : masterConfig, slaveconfig: slaveConfig};
};

function StaticPresets() {
	return {
		queries: [],
		controls: {
			templates: []
		},
		configs: []
	};
}<|endoftext|>


<commit_before>var gulp = require('gulp');

gulp.task('default', [
<% if (includeReact) { %>'babel',<% } %>
'less',
'lint',
'jscs'
])<commit_msg>babel task is default for all frameworks<commit_after>var gulp = require('gulp');

gulp.task('default', ['babel', 'less', 'lint', 'jscs'])<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Ember from 'ember';

export default Ember.Component.extend({
  classNames: ['list-filter'],
  header: '',
  subHeader: '',
  items: [],
  filterText: '',
  emptyFilterText: Ember.computed('filterText', function() {
    return this.get('filterText').length === 0;
  }),
  filteredItems: Ember.computed('filterText', 'items.@each', function() {
    return this.get('items').filter((item) => {
      return item.get('name').indexOf(this.get('filterText')) !== -1;
    });
  }),

  actions: {
    enableFilter() {
      this.$('input').focus();
    },

    disableFilter() {
      this.set('filterText', '');
    }
  }
});
<commit_msg>AMBARI-20087. HiveView 2.0: Table search is case sensitive, show table only if name match exactly. (dipayanb)<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Ember from 'ember';

export default Ember.Component.extend({
  classNames: ['list-filter'],
  header: '',
  subHeader: '',
  caseInsensitive: true,
  items: [],
  filterText: '',
  emptyFilterText: Ember.computed('filterText', function() {
    return this.get('filterText').length === 0;
  }),
  filteredItems: Ember.computed('filterText', 'items.@each', function() {
    return this.get('items').filter((item) => {
      let filterText = this.get('caseInsensitive') ? this.get('filterText').toLowerCase() : this.get('filterText');
      let itemName = this.get('caseInsensitive') ? item.get('name').toLowerCase() : item.get('name')
      return itemName.indexOf(filterText) !== -1;
    });
  }),

  actions: {
    enableFilter() {
      this.$('input').focus();
    },

    disableFilter() {
      this.set('filterText', '');
    }
  }
});
<|endoftext|>


<commit_before>var solfege = require('solfegejs');

/**
 * A request
 *
 * @param   {Object}    serverRequest       The original request
 */
var Request = solfege.util.Class.create(function(serverRequest)
{
    // Save the original request
    this.serverRequest = serverRequest;

    // Copy some informations
    this.url = serverRequest.url;

    // Initialize the parameters
    this.parameters = {};

}, 'solfege.bundle.server.Request');
var proto = Request.prototype;

/**
 * The original request
 *
 * @type {Object}
 * @api public
 */
proto.serverRequest;

/**
 * The parameters
 *
 * @type {Object}
 * @api private
 */
proto.parameters;

/**
 * The request URL
 *
 * @type {String}
 * @api public
 */
proto.url;

/**
 * The method of the request
 *
 * @type {String}
 * @api public
 */
Object.defineProperty(proto, 'method',
{
    get: function()
    {
        return this.serverRequest.method;
    }
});

/**
 * Get a parameter value
 *
 * @param   {String}    name    The parameter name
 * @return  {any}               The parameter value
 */
proto.getParameter = function(name)
{
    return this.parameters[name];
};

/**
 * Set a parameter value
 *
 * @param   {String}    name    The parameter name
 * @param   {any}               The parameter value
 */
proto.setParameter = function(name, value)
{
    this.parameters[name] = value;
};

module.exports = Request;
<commit_msg>Add the ability to get a header from the request<commit_after>var solfege = require('solfegejs');

/**
 * A request
 *
 * @param   {Object}    serverRequest       The original request
 */
var Request = solfege.util.Class.create(function(serverRequest)
{
    // Save the original request
    this.serverRequest = serverRequest;

    // Copy some informations
    this.url = serverRequest.url;

    // Initialize the parameters
    this.parameters = {};

}, 'solfege.bundle.server.Request');
var proto = Request.prototype;

/**
 * The original request
 *
 * @type {Object}
 * @api public
 */
proto.serverRequest;

/**
 * The parameters
 *
 * @type {Object}
 * @api private
 */
proto.parameters;

/**
 * The request URL
 *
 * @type {String}
 * @api public
 */
proto.url;

/**
 * The method of the request
 *
 * @type {String}
 * @api public
 */
Object.defineProperty(proto, 'method',
{
    get: function()
    {
        return this.serverRequest.method;
    }
});

/**
 * Get a header
 *
 * @param   {String}    name    The header name
 * @return  {String}            The header value
 */
proto.getHeader = function(name)
{
    name = name.toLowerCase();
    return this.serverRequest.headers[name];
};

/**
 * Get a parameter value
 *
 * @param   {String}    name    The parameter name
 * @return  {any}               The parameter value
 */
proto.getParameter = function(name)
{
    return this.parameters[name];
};

/**
 * Set a parameter value
 *
 * @param   {String}    name    The parameter name
 * @param   {any}               The parameter value
 */
proto.setParameter = function(name, value)
{
    this.parameters[name] = value;
};

module.exports = Request;
<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Play pause button for starting/stopping the sim.  Often appears at the bottom center of the screen.
 * Generated programmatically using RoundPushButton (as opposed to using raster images).
 *
 * @author Sam Reid
 */

define( function( require ) {
  'use strict';

  // imports
  var inherit = require( 'PHET_CORE/inherit' );
  var BooleanRoundToggleButton = require( 'SUN/buttons/BooleanRoundToggleButton' );
  var ToggleNode = require( 'SUN/ToggleNode' );
  var Shape = require( 'KITE/Shape' );
  var Path = require( 'SCENERY/nodes/Path' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );

  var DEFAULT_RADIUS = 28;

  /*
   * PlayPauseButton constructor
   *
   * @param {Property<Boolean>} runningProperty property that represents whether the sim is paused or not
   * @param {object} options node options
   * @constructor
   */
  function PlayPauseButton( runningProperty, options ) {

    options = _.extend( {
      radius: DEFAULT_RADIUS
    }, options );

    //Overall scaling factor for individual elements (without scaling the entire node)
    var elementScale = options.radius / DEFAULT_RADIUS;

    var triangleHeight = 24.48 * elementScale;
    var triangleWidth = triangleHeight * elementScale * 0.6885;
    var barWidth = 7.65 * elementScale;
    var barHeight = triangleHeight;

    var playPath = new Path( new Shape().moveTo( 0, triangleHeight / 2 ).lineTo( triangleWidth, 0 ).lineTo( 0, -triangleHeight / 2 ).close(), {fill: 'black', stroke: '#bbbbbb', lineWidth: 1} );
    var bar = function() { return new Rectangle( 0, 0, barWidth, barHeight, {fill: 'black', stroke: '#bbbbbb', lineWidth: 1} ); };
    var bar1 = bar();
    var bar2 = bar();
    var pausePath = new HBox( {children: [ bar1, bar2], spacing: elementScale * 1.53} );

    //Shift the triangle to the right a bit
    playPath.center = pausePath.center.plusXY( 1.5, 0 );

    BooleanRoundToggleButton.call( this, pausePath, playPath, runningProperty, options );
  }

  return inherit( BooleanRoundToggleButton, PlayPauseButton );
} );<commit_msg>Fixed jshint [L16:C17] W098: 'ToggleNode' is defined but never used.<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Play pause button for starting/stopping the sim.  Often appears at the bottom center of the screen.
 * Generated programmatically using RoundPushButton (as opposed to using raster images).
 *
 * @author Sam Reid
 */

define( function( require ) {
  'use strict';

  // imports
  var inherit = require( 'PHET_CORE/inherit' );
  var BooleanRoundToggleButton = require( 'SUN/buttons/BooleanRoundToggleButton' );
  var Shape = require( 'KITE/Shape' );
  var Path = require( 'SCENERY/nodes/Path' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );

  var DEFAULT_RADIUS = 28;

  /*
   * PlayPauseButton constructor
   *
   * @param {Property<Boolean>} runningProperty property that represents whether the sim is paused or not
   * @param {object} options node options
   * @constructor
   */
  function PlayPauseButton( runningProperty, options ) {

    options = _.extend( {
      radius: DEFAULT_RADIUS
    }, options );

    //Overall scaling factor for individual elements (without scaling the entire node)
    var elementScale = options.radius / DEFAULT_RADIUS;

    var triangleHeight = 24.48 * elementScale;
    var triangleWidth = triangleHeight * elementScale * 0.6885;
    var barWidth = 7.65 * elementScale;
    var barHeight = triangleHeight;

    var playPath = new Path( new Shape().moveTo( 0, triangleHeight / 2 ).lineTo( triangleWidth, 0 ).lineTo( 0, -triangleHeight / 2 ).close(), {fill: 'black', stroke: '#bbbbbb', lineWidth: 1} );
    var bar = function() { return new Rectangle( 0, 0, barWidth, barHeight, {fill: 'black', stroke: '#bbbbbb', lineWidth: 1} ); };
    var bar1 = bar();
    var bar2 = bar();
    var pausePath = new HBox( {children: [ bar1, bar2], spacing: elementScale * 1.53} );

    //Shift the triangle to the right a bit
    playPath.center = pausePath.center.plusXY( 1.5, 0 );

    BooleanRoundToggleButton.call( this, pausePath, playPath, runningProperty, options );
  }

  return inherit( BooleanRoundToggleButton, PlayPauseButton );
} );<|endoftext|>


<commit_before>// Example webpack configuration with asset fingerprinting in production.
'use strict';

const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OfflinePlugin = require('offline-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');

// set NODE_ENV=production on the environment to add asset fingerprints
const currentEnv = process.env.NODE_ENV || 'development';
const isProduction = currentEnv === 'production';

const preScripts = {
  development: [],
  production: []
};

const preScriptsEnv = isProduction ?
  preScripts['production'] :
  preScripts['development'];

const cssLoaders = [
  MiniCssExtractPlugin.loader,
  {
    loader: 'css-loader',
    options: {
      modules: false,
      minimize: isProduction,
      sourceMap: true
    }
  },
  {
    loader: 'postcss-loader',
    options: {
      sourceMap: true,
      plugins: function() {
        return [
          require('postcss-import')({
            addDependencyTo: webpack
          }),
          require('postcss-url')(),
          require('lost')({
            flexbox: 'flex'
          }),
          require('rucksack-css')(),
          require('postcss-cssnext')({
            browsers: [
              'last 2 version'
            ],
            features: {
              rem: false,
              customProperties: {
                strict: false,
                warnings: false,
                preserve: true
              }
            }
          }),
          require('postcss-browser-reporter')(),
          require('postcss-reporter')()
        ];
      }
    }
  }
];

const config = {
  target: 'web',
  mode: currentEnv,
  performance: {
    hints: false
  },
  entry: {
    'app': preScriptsEnv.concat(['./webpack/app.js'])
  },

  output: {
    // Build assets directly in to public/webpack/, let webpack know
    // that all webpacked assets start with webpack/

    // must match config.webpack.output_dir
    path: path.join(__dirname, '.tmp', 'dist'),
    publicPath: '/',
    filename: isProduction ? '[name]-[chunkhash].js' : '[name].js'
  },

  resolve: {
    modules: [
      path.join(__dirname, 'webpack'),
      path.join(__dirname, 'node_modules')
    ],
    extensions: ['.js', '.jsx', '.json']
  },

  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: [
          'babel-loader'
        ]
      },
      {
        test: /\.(gif|jpg|png|woff|woff2|eot|ttf|svg|ico)$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 10000,
            outputPath: 'assets/'
          }
        }]
      },
      {
        test: /\.scss$/,
        use: cssLoaders.concat({
          loader: 'sass-loader',
          options: {
            indentedSyntax: false,
            sourceMap:      true,
            includePaths:   [path.join(__dirname, 'webpack', 'css')]
          }
        })
      },
      {
        test: /\.sass$/,
        use: cssLoaders.concat({
          loader: 'sass-loader',
          options: {
            indentedSyntax: true,
            sourceMap:      true,
            includePaths:   [path.join(__dirname, 'webpack', 'css')]
          }
        })
      }
    ]
  },

  plugins: [
    new MiniCssExtractPlugin({
      filename: isProduction ? '[name]-[hash].css' : '[name].css'
    })
  ],

  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        }
      }
    }
  }
};

if (isProduction) {
  config.plugins.push(
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env': {NODE_ENV: JSON.stringify('production')}
    }),
    new webpack.optimize.ModuleConcatenationPlugin()
  );
  config.optimization = config.optimization || {};
  config.optimization.minimizer = [
    new UglifyJSPlugin({
      cache: true,
      parallel: 2,
      sourceMap: true,
      uglifyOptions: {
        compressor: {warnings: false},
        mangle: true
      }
    })
  ];
  // Source maps
  config.devtool = 'source-map';
} else {
  config.plugins.push(
    new webpack.NamedModulesPlugin()
  );
  // Source maps
  config.devtool = 'inline-source-map';
}

config.plugins.push(
  new OfflinePlugin({
    cache: {
      main: [
        '*.js',
        '*.css',
        '*.png',
        '*.svg'
      ],
    },
    excludes: [
      '**/.*',
      '**/*.map',
      '**/*.gz'
    ],
    externals: [
      '/'
    ],
    name: 'mp-cache',
    version: '[hash]',
    responseStrategy: 'cache-first',
    prefetchRequest: {
      credentials: 'include'
    },
    ServiceWorker: {
      events: true,
      scope: '/',
      minify: isProduction
    },
    AppCache: null
  }),
  new ManifestPlugin({
    fileName: 'assets-manifest.json',
    publicPath: config.output.publicPath,
    writeToFileEmit: process.env.NODE_ENV !== 'test'
  })
)

module.exports = config;
<commit_msg>use mini-css-extract-plugin with contenthash<commit_after>// Example webpack configuration with asset fingerprinting in production.
'use strict';

const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OfflinePlugin = require('offline-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');

// set NODE_ENV=production on the environment to add asset fingerprints
const currentEnv = process.env.NODE_ENV || 'development';
const isProduction = currentEnv === 'production';

const preScripts = {
  development: [],
  production: []
};

const preScriptsEnv = isProduction ?
  preScripts['production'] :
  preScripts['development'];

const cssLoaders = [
  MiniCssExtractPlugin.loader,
  {
    loader: 'css-loader',
    options: {
      modules: false,
      minimize: isProduction,
      sourceMap: true
    }
  },
  {
    loader: 'postcss-loader',
    options: {
      sourceMap: true,
      plugins: function() {
        return [
          require('postcss-import')({
            addDependencyTo: webpack
          }),
          require('postcss-url')(),
          require('lost')({
            flexbox: 'flex'
          }),
          require('rucksack-css')(),
          require('postcss-cssnext')({
            browsers: [
              'last 2 version'
            ],
            features: {
              rem: false,
              customProperties: {
                strict: false,
                warnings: false,
                preserve: true
              }
            }
          }),
          require('postcss-browser-reporter')(),
          require('postcss-reporter')()
        ];
      }
    }
  }
];

const config = {
  target: 'web',
  mode: currentEnv,
  performance: {
    hints: false
  },
  entry: {
    'app': preScriptsEnv.concat(['./webpack/app.js'])
  },

  output: {
    // Build assets directly in to public/webpack/, let webpack know
    // that all webpacked assets start with webpack/

    // must match config.webpack.output_dir
    path: path.join(__dirname, '.tmp', 'dist'),
    publicPath: '/',
    filename: isProduction ? '[name]-[chunkhash].js' : '[name].js'
  },

  resolve: {
    modules: [
      path.join(__dirname, 'webpack'),
      path.join(__dirname, 'node_modules')
    ],
    extensions: ['.js', '.jsx', '.json']
  },

  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: [
          'babel-loader'
        ]
      },
      {
        test: /\.(gif|jpg|png|woff|woff2|eot|ttf|svg|ico)$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 10000,
            outputPath: 'assets/'
          }
        }]
      },
      {
        test: /\.scss$/,
        use: cssLoaders.concat({
          loader: 'sass-loader',
          options: {
            indentedSyntax: false,
            sourceMap:      true,
            includePaths:   [path.join(__dirname, 'webpack', 'css')]
          }
        })
      },
      {
        test: /\.sass$/,
        use: cssLoaders.concat({
          loader: 'sass-loader',
          options: {
            indentedSyntax: true,
            sourceMap:      true,
            includePaths:   [path.join(__dirname, 'webpack', 'css')]
          }
        })
      }
    ]
  },

  plugins: [
    new MiniCssExtractPlugin({
      filename: isProduction ? '[name]-[contenthash].css' : '[name].css'
    })
  ],

  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        }
      }
    }
  }
};

if (isProduction) {
  config.plugins.push(
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env': {NODE_ENV: JSON.stringify('production')}
    }),
    new webpack.optimize.ModuleConcatenationPlugin()
  );
  config.optimization = config.optimization || {};
  config.optimization.minimizer = [
    new UglifyJSPlugin({
      cache: true,
      parallel: 2,
      sourceMap: true,
      uglifyOptions: {
        compressor: {warnings: false},
        mangle: true
      }
    })
  ];
  // Source maps
  config.devtool = 'source-map';
} else {
  config.plugins.push(
    new webpack.NamedModulesPlugin()
  );
  // Source maps
  config.devtool = 'inline-source-map';
}

config.plugins.push(
  new OfflinePlugin({
    cache: {
      main: [
        '*.js',
        '*.css',
        '*.png',
        '*.svg'
      ],
    },
    excludes: [
      '**/.*',
      '**/*.map',
      '**/*.gz'
    ],
    externals: [
      '/'
    ],
    name: 'mp-cache',
    version: '[hash]',
    responseStrategy: 'cache-first',
    prefetchRequest: {
      credentials: 'include'
    },
    ServiceWorker: {
      events: true,
      scope: '/',
      minify: isProduction
    },
    AppCache: null
  }),
  new ManifestPlugin({
    fileName: 'assets-manifest.json',
    publicPath: config.output.publicPath,
    writeToFileEmit: process.env.NODE_ENV !== 'test'
  })
)

module.exports = config;
<|endoftext|>