<commit_before>/*
 * Copyright 2014 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 */

const async = require('async');
const restUtils = require('./restUtils');
const statsRegistry = require('./../stats/statsRegistry');
const deviceService = require('./../devices/deviceService');
const intoTrans = require('../common/domain').intoTrans;
const logger = require('logops');
const errors = require('../../errors');
const _ = require('underscore');
const context = {
    op: 'IoTAgentNGSI.DeviceProvisioning'
};
const apply = async.apply;
let provisioningHandler;
let updatingHandler;
let removeDeviceHandler;
let updateDeviceTemplate;
let createDeviceTemplate;
const mandatoryHeaders = ['fiware-service', 'fiware-servicepath'];
let provisioningMiddlewares = [];
const provisioningAPITranslation = {
    /* jshint camelcase:false */

    name: 'id',
    apikey: 'apikey',
    service: 'service',
    service_path: 'subservice',
    entity_name: 'name',
    entity_type: 'type',
    timezone: 'timezone',
    timestamp: 'timestamp',
    protocol: 'protocol',
    transport: 'transport',
    endpoint: 'endpoint',
    polling: 'polling',
    attributes: 'active',
    commands: 'commands',
    lazy: 'lazy',
    internal_attributes: 'internalAttributes',
    static_attributes: 'staticAttributes',
    autoprovision: 'autoprovision',
    explicitAttrs: 'explicitAttrs',
    expressionLanguage: 'expressionLanguage',
    ngsiVersion: 'ngsiVersion'
};

/**
 * Load the templates for validating provisioning requests. The introduction of "Lax Mode" enables the addition of
 * characters which valid in the OPU-UA IoT Agent (e.g. semi-colons) but are usually forbidden by other IoT Agents
 */
function setConfiguration(config) {
    if (config.relaxTemplateValidation) {
        updateDeviceTemplate = require('../../templates/updateDeviceLax.json');
        createDeviceTemplate = require('../../templates/createDeviceLax.json');
    } else {
        updateDeviceTemplate = require('../../templates/updateDevice.json');
        createDeviceTemplate = require('../../templates/createDevice.json');
    }
}

/**
 * Express middleware to handle incoming device provisioning requests. Every request is validated and handled to the
 * NGSI Service for the registration.
 */
function handleProvision(req, res, next) {
    /* eslint-disable-next-line no-unused-vars */
    function handleProvisioningFinish(error, results) {
        if (error) {
            logger.debug(context, 'Device provisioning failed due to the following error: ', error.message);
            next(error);
        } else {
            logger.debug(context, 'Device provisioning request succeeded');
            res.status(201).json({});
        }
    }

    function applyProvisioningHandler(device, callback) {
        if (provisioningHandler) {
            provisioningHandler(device, callback);
        } else {
            callback(null, device);
        }
    }

    function applyProvisioningMiddlewares(device, callback) {
        if (provisioningMiddlewares.length > 0) {
            const firstMiddleware = provisioningMiddlewares.slice(0, 1)[0];
            const rest = provisioningMiddlewares.slice(1);
            let executingMiddlewares = [apply(firstMiddleware, device)];

            executingMiddlewares = executingMiddlewares.concat(rest);

            async.waterfall(executingMiddlewares, callback);
        } else {
            callback(null, device);
        }
    }

    function fillDeviceData(service, subservice, body, callback) {
        /* jshint sub: true */

        callback(null, {
            id: body.device_id,
            apikey: body.apikey,
            type: body.entity_type,
            name: body.entity_name,
            service,
            subservice,
            active: body.attributes,
            staticAttributes: body.static_attributes,
            lazy: body.lazy,
            commands: body.commands,
            timezone: body.timezone,
            timestamp: body.timestamp,
            endpoint: body.endpoint,
            internalAttributes: body.internal_attributes,
            protocol: body.protocol,
            transport: body.transport,
            internalId: null,
            autoprovision: body.autoprovision,
            explicitAttrs: body.explicitAttrs,
            expressionLanguage: body.expressionLanguage,
            ngsiVersion: body.ngsiVersion
        });
    }

    function provisionSingleDevice(device, callback) {
        async.waterfall(
            [
                apply(statsRegistry.add, 'deviceCreationRequests', 1),
                apply(restUtils.checkMandatoryQueryParams, ['device_id'], device),
                apply(fillDeviceData, req.headers['fiware-service'], req.headers['fiware-servicepath']),
                applyProvisioningMiddlewares,
                applyProvisioningHandler,
                deviceService.register
            ],
            callback
        );
    }

    function extractDevices() {
        return req.body.devices;
    }

    logger.debug(context, 'Handling device provisioning request.');
    async.map(extractDevices(), provisionSingleDevice, handleProvisioningFinish);
}

/**
 * Translate an attribute from the internal representaiton format to the one required by the Provisioning API.
 *
 * @param {Object} attribute                        Attribute in internal representation format.
 * @return {{object_id: *, name: *, type: *}}      Attribute in Device Provisioning API format.
 */
function attributeToProvisioningAPIFormat(attribute) {
    return {
        object_id: attribute.object_id,
        name: attribute.name,
        type: attribute.type,
        expression: attribute.expression,
        reverse: attribute.reverse,
        entity_name: attribute.entity_name,
        entity_type: attribute.entity_type,
        mqtt: attribute.mqtt,
        metadata: attribute.metadata
    };
}

/**
 * Translate between the inner model format to the external Device Provisioning API one.
 *
 * @param {Object} device           Device object coming from the registry.
 * @return {Object}                 Device object translated to Device Provisioning API format.
 */
function toProvisioningAPIFormat(device) {
    /* jshint camelcase:false */
    return {
        device_id: device.id,
        apikey: device.apikey,
        service: device.service,
        service_path: device.subservice,
        entity_name: device.name,
        entity_type: device.type,
        timezone: device.timezone,
        timestamp: device.timestamp,
        endpoint: device.endpoint,
        polling: device.polling,
        transport: device.transport,
        attributes: device.active ? device.active.map(attributeToProvisioningAPIFormat) : undefined,
        lazy: device.lazy ? device.lazy.map(attributeToProvisioningAPIFormat) : undefined,
        commands: device.commands ? device.commands.map(attributeToProvisioningAPIFormat) : undefined,
        static_attributes: device.staticAttributes,
        internal_attributes: device.internalAttributes,
        protocol: device.protocol,
        autoprovision: device.autoprovision,
        expressionLanguage: device.expressionLanguage,
        explicitAttrs: device.explicitAttrs,
        ngsiVersion: device.ngsiVersion
    };
}

/**
 * Express middleware that retrieves the complete set of provisioned devices (in JSON format).
 */
function handleListDevices(req, res, next) {
    deviceService.listDevices(
        req.headers['fiware-service'],
        req.headers['fiware-servicepath'],
        req.query.limit,
        req.query.offset,
        function handleListDevices(error, deviceList) {
            if (error) {
                next(error);
            } else {
                const response = deviceList;
                response.devices = deviceList.devices.map(toProvisioningAPIFormat);

                res.status(200).json(response);
            }
        }
    );
}

/**
 * This middleware gets the device specified in the deviceId parameter of the URL from the registry and returns it in
 * JSON format.
 */
function handleGetDevice(req, res, next) {
    deviceService.getDevice(
        req.params.deviceId,
        req.headers['fiware-service'],
        req.headers['fiware-servicepath'],
        function (error, device) {
            if (error) {
                next(error);
            } else if (device) {
                res.status(200).json(toProvisioningAPIFormat(device));
            } else {
                next(new errors.DeviceNotFound(req.params.deviceId));
            }
        }
    );
}

/**
 * This middleware handles the removal of a particular device specified with the deviceId.
 */
function handleRemoveDevice(req, res, next) {
    function getDevice(deviceId, service, subservice, callback) {
        deviceService.getDevice(deviceId, service, subservice, function (error, device) {
            if (error) {
                callback(error);
            } else if (device) {
                callback(null, device);
            } else {
                callback(new errors.DeviceNotFound(deviceId));
            }
        });
    }

    function applyRemoveDeviceHandler(device, callback) {
        if (removeDeviceHandler) {
            removeDeviceHandler(device, callback);
        } else {
            callback(null, device);
        }
    }

    function unregisterDevice(deviceId, service, subservice, device, callback) {
        return deviceService.unregister(deviceId, service, subservice, callback);
    }

    async.waterfall(
        [
            apply(statsRegistry.add, 'deviceRemovalRequests', 1),
            apply(getDevice, req.params.deviceId, req.headers['fiware-service'], req.headers['fiware-servicepath']),
            applyRemoveDeviceHandler,
            apply(
                unregisterDevice,
                req.params.deviceId,
                req.headers['fiware-service'],
                req.headers['fiware-servicepath']
            )
        ],
        function (error) {
            if (error && error.code !== 404) {
                next(error);
            } else if (error && error.code === 404) {
                next(new errors.DeviceNotFound(req.params.deviceId));
            } else {
                res.status(204).send();
            }
        }
    );
}

/**
 * This middleware handles updates in the provisioning devices. The only attribute
 */
function handleUpdateDevice(req, res, next) {
    function applyUpdatingHandler(device, callback) {
        if (updatingHandler) {
            updatingHandler(device, callback);
        } else {
            callback(null, device);
        }
    }

    if (req.body.device_id) {
        next(new errors.BadRequest("Can't change the ID of a preprovisioned device"));
    } else {
        deviceService.getDevice(
            req.params.deviceId,
            req.headers['fiware-service'],
            req.headers['fiware-servicepath'],
            function (error, device) {
                if (error) {
                    next(error);
                } else if (device) {
                    const pairs = _.pairs(req.body);
                    const newDevice = _.clone(device);

                    for (const i in pairs) {
                        newDevice[provisioningAPITranslation[pairs[i][0]]] = pairs[i][1];
                    }
                    var isTypeOrNameUpdated = false;
                    if (req.body.entity_name || req.body.entity_type) {
                        isTypeOrNameUpdated = true;
                    }
                    async.waterfall([apply(applyUpdatingHandler, newDevice)], function handleUpdating(
                        error,
                        newDeviceUpdated
                    ) {
                        deviceService.updateRegister(newDeviceUpdated, isTypeOrNameUpdated, function handleDeviceUpdate(
                            error
                        ) {
                            if (error) {
                                next(error);
                            } else {
                                res.status(204).json({});
                            }
                        });
                    });
                } else {
                    next(new errors.DeviceNotFound(req.params.deviceId));
                }
            }
        );
    }
}

/**
 * Load the routes related to device provisioning in the Express App.
 *
 * @param {Object} router      Express request router object.
 */
function loadContextRoutes(router) {
    router.post(
        '/iot/devices',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        restUtils.checkBody(createDeviceTemplate),
        handleProvision
    );

    router.get('/iot/devices', restUtils.checkRequestAttributes('headers', mandatoryHeaders), handleListDevices);

    router.get(
        '/iot/devices/:deviceId',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        handleGetDevice
    );

    router.put(
        '/iot/devices/:deviceId',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        restUtils.checkBody(updateDeviceTemplate),
        handleUpdateDevice
    );

    router.delete(
        '/iot/devices/:deviceId',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        handleRemoveDevice
    );
}

function setProvisioningHandler(newHandler) {
    provisioningHandler = newHandler;
}

function setUpdatingHandler(newHandler) {
    updatingHandler = newHandler;
}

function setRemoveDeviceHandler(newHandler) {
    removeDeviceHandler = newHandler;
}

function addDeviceProvisionMiddleware(newHandler) {
    provisioningMiddlewares.push(newHandler);
}

function clear(callback) {
    provisioningMiddlewares = [];
    provisioningHandler = null;
    callback();
}

exports.setConfiguration = setConfiguration;
exports.loadContextRoutes = intoTrans(context, loadContextRoutes);
exports.setProvisioningHandler = intoTrans(context, setProvisioningHandler);
exports.setUpdatingHandler = intoTrans(context, setUpdatingHandler);
exports.setRemoveDeviceHandler = intoTrans(context, setRemoveDeviceHandler);
exports.addDeviceProvisionMiddleware = addDeviceProvisionMiddleware;
exports.clear = clear;
<commit_msg>add pauloadType to attribute/commands model<commit_after>/*
 * Copyright 2014 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, see http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 */

const async = require('async');
const restUtils = require('./restUtils');
const statsRegistry = require('./../stats/statsRegistry');
const deviceService = require('./../devices/deviceService');
const intoTrans = require('../common/domain').intoTrans;
const logger = require('logops');
const errors = require('../../errors');
const _ = require('underscore');
const context = {
    op: 'IoTAgentNGSI.DeviceProvisioning'
};
const apply = async.apply;
let provisioningHandler;
let updatingHandler;
let removeDeviceHandler;
let updateDeviceTemplate;
let createDeviceTemplate;
const mandatoryHeaders = ['fiware-service', 'fiware-servicepath'];
let provisioningMiddlewares = [];
const provisioningAPITranslation = {
    /* jshint camelcase:false */

    name: 'id',
    apikey: 'apikey',
    service: 'service',
    service_path: 'subservice',
    entity_name: 'name',
    entity_type: 'type',
    timezone: 'timezone',
    timestamp: 'timestamp',
    protocol: 'protocol',
    transport: 'transport',
    endpoint: 'endpoint',
    polling: 'polling',
    attributes: 'active',
    commands: 'commands',
    lazy: 'lazy',
    internal_attributes: 'internalAttributes',
    static_attributes: 'staticAttributes',
    autoprovision: 'autoprovision',
    explicitAttrs: 'explicitAttrs',
    expressionLanguage: 'expressionLanguage',
    ngsiVersion: 'ngsiVersion'
};

/**
 * Load the templates for validating provisioning requests. The introduction of "Lax Mode" enables the addition of
 * characters which valid in the OPU-UA IoT Agent (e.g. semi-colons) but are usually forbidden by other IoT Agents
 */
function setConfiguration(config) {
    if (config.relaxTemplateValidation) {
        updateDeviceTemplate = require('../../templates/updateDeviceLax.json');
        createDeviceTemplate = require('../../templates/createDeviceLax.json');
    } else {
        updateDeviceTemplate = require('../../templates/updateDevice.json');
        createDeviceTemplate = require('../../templates/createDevice.json');
    }
}

/**
 * Express middleware to handle incoming device provisioning requests. Every request is validated and handled to the
 * NGSI Service for the registration.
 */
function handleProvision(req, res, next) {
    /* eslint-disable-next-line no-unused-vars */
    function handleProvisioningFinish(error, results) {
        if (error) {
            logger.debug(context, 'Device provisioning failed due to the following error: ', error.message);
            next(error);
        } else {
            logger.debug(context, 'Device provisioning request succeeded');
            res.status(201).json({});
        }
    }

    function applyProvisioningHandler(device, callback) {
        if (provisioningHandler) {
            provisioningHandler(device, callback);
        } else {
            callback(null, device);
        }
    }

    function applyProvisioningMiddlewares(device, callback) {
        if (provisioningMiddlewares.length > 0) {
            const firstMiddleware = provisioningMiddlewares.slice(0, 1)[0];
            const rest = provisioningMiddlewares.slice(1);
            let executingMiddlewares = [apply(firstMiddleware, device)];

            executingMiddlewares = executingMiddlewares.concat(rest);

            async.waterfall(executingMiddlewares, callback);
        } else {
            callback(null, device);
        }
    }

    function fillDeviceData(service, subservice, body, callback) {
        /* jshint sub: true */

        callback(null, {
            id: body.device_id,
            apikey: body.apikey,
            type: body.entity_type,
            name: body.entity_name,
            service,
            subservice,
            active: body.attributes,
            staticAttributes: body.static_attributes,
            lazy: body.lazy,
            commands: body.commands,
            timezone: body.timezone,
            timestamp: body.timestamp,
            endpoint: body.endpoint,
            internalAttributes: body.internal_attributes,
            protocol: body.protocol,
            transport: body.transport,
            internalId: null,
            autoprovision: body.autoprovision,
            explicitAttrs: body.explicitAttrs,
            expressionLanguage: body.expressionLanguage,
            ngsiVersion: body.ngsiVersion
        });
    }

    function provisionSingleDevice(device, callback) {
        async.waterfall(
            [
                apply(statsRegistry.add, 'deviceCreationRequests', 1),
                apply(restUtils.checkMandatoryQueryParams, ['device_id'], device),
                apply(fillDeviceData, req.headers['fiware-service'], req.headers['fiware-servicepath']),
                applyProvisioningMiddlewares,
                applyProvisioningHandler,
                deviceService.register
            ],
            callback
        );
    }

    function extractDevices() {
        return req.body.devices;
    }

    logger.debug(context, 'Handling device provisioning request.');
    async.map(extractDevices(), provisionSingleDevice, handleProvisioningFinish);
}

/**
 * Translate an attribute from the internal representaiton format to the one required by the Provisioning API.
 *
 * @param {Object} attribute                        Attribute in internal representation format.
 * @return {{object_id: *, name: *, type: *}}      Attribute in Device Provisioning API format.
 */
function attributeToProvisioningAPIFormat(attribute) {
    return {
        object_id: attribute.object_id,
        name: attribute.name,
        type: attribute.type,
        expression: attribute.expression,
        reverse: attribute.reverse,
        entity_name: attribute.entity_name,
        entity_type: attribute.entity_type,
        mqtt: attribute.mqtt,
        payloadType: attribute.payloadType,
        metadata: attribute.metadata
    };
}

/**
 * Translate between the inner model format to the external Device Provisioning API one.
 *
 * @param {Object} device           Device object coming from the registry.
 * @return {Object}                 Device object translated to Device Provisioning API format.
 */
function toProvisioningAPIFormat(device) {
    /* jshint camelcase:false */
    return {
        device_id: device.id,
        apikey: device.apikey,
        service: device.service,
        service_path: device.subservice,
        entity_name: device.name,
        entity_type: device.type,
        timezone: device.timezone,
        timestamp: device.timestamp,
        endpoint: device.endpoint,
        polling: device.polling,
        transport: device.transport,
        attributes: device.active ? device.active.map(attributeToProvisioningAPIFormat) : undefined,
        lazy: device.lazy ? device.lazy.map(attributeToProvisioningAPIFormat) : undefined,
        commands: device.commands ? device.commands.map(attributeToProvisioningAPIFormat) : undefined,
        static_attributes: device.staticAttributes,
        internal_attributes: device.internalAttributes,
        protocol: device.protocol,
        autoprovision: device.autoprovision,
        expressionLanguage: device.expressionLanguage,
        explicitAttrs: device.explicitAttrs,
        ngsiVersion: device.ngsiVersion
    };
}

/**
 * Express middleware that retrieves the complete set of provisioned devices (in JSON format).
 */
function handleListDevices(req, res, next) {
    deviceService.listDevices(
        req.headers['fiware-service'],
        req.headers['fiware-servicepath'],
        req.query.limit,
        req.query.offset,
        function handleListDevices(error, deviceList) {
            if (error) {
                next(error);
            } else {
                const response = deviceList;
                response.devices = deviceList.devices.map(toProvisioningAPIFormat);

                res.status(200).json(response);
            }
        }
    );
}

/**
 * This middleware gets the device specified in the deviceId parameter of the URL from the registry and returns it in
 * JSON format.
 */
function handleGetDevice(req, res, next) {
    deviceService.getDevice(
        req.params.deviceId,
        req.headers['fiware-service'],
        req.headers['fiware-servicepath'],
        function (error, device) {
            if (error) {
                next(error);
            } else if (device) {
                res.status(200).json(toProvisioningAPIFormat(device));
            } else {
                next(new errors.DeviceNotFound(req.params.deviceId));
            }
        }
    );
}

/**
 * This middleware handles the removal of a particular device specified with the deviceId.
 */
function handleRemoveDevice(req, res, next) {
    function getDevice(deviceId, service, subservice, callback) {
        deviceService.getDevice(deviceId, service, subservice, function (error, device) {
            if (error) {
                callback(error);
            } else if (device) {
                callback(null, device);
            } else {
                callback(new errors.DeviceNotFound(deviceId));
            }
        });
    }

    function applyRemoveDeviceHandler(device, callback) {
        if (removeDeviceHandler) {
            removeDeviceHandler(device, callback);
        } else {
            callback(null, device);
        }
    }

    function unregisterDevice(deviceId, service, subservice, device, callback) {
        return deviceService.unregister(deviceId, service, subservice, callback);
    }

    async.waterfall(
        [
            apply(statsRegistry.add, 'deviceRemovalRequests', 1),
            apply(getDevice, req.params.deviceId, req.headers['fiware-service'], req.headers['fiware-servicepath']),
            applyRemoveDeviceHandler,
            apply(
                unregisterDevice,
                req.params.deviceId,
                req.headers['fiware-service'],
                req.headers['fiware-servicepath']
            )
        ],
        function (error) {
            if (error && error.code !== 404) {
                next(error);
            } else if (error && error.code === 404) {
                next(new errors.DeviceNotFound(req.params.deviceId));
            } else {
                res.status(204).send();
            }
        }
    );
}

/**
 * This middleware handles updates in the provisioning devices. The only attribute
 */
function handleUpdateDevice(req, res, next) {
    function applyUpdatingHandler(device, callback) {
        if (updatingHandler) {
            updatingHandler(device, callback);
        } else {
            callback(null, device);
        }
    }

    if (req.body.device_id) {
        next(new errors.BadRequest("Can't change the ID of a preprovisioned device"));
    } else {
        deviceService.getDevice(
            req.params.deviceId,
            req.headers['fiware-service'],
            req.headers['fiware-servicepath'],
            function (error, device) {
                if (error) {
                    next(error);
                } else if (device) {
                    const pairs = _.pairs(req.body);
                    const newDevice = _.clone(device);

                    for (const i in pairs) {
                        newDevice[provisioningAPITranslation[pairs[i][0]]] = pairs[i][1];
                    }
                    var isTypeOrNameUpdated = false;
                    if (req.body.entity_name || req.body.entity_type) {
                        isTypeOrNameUpdated = true;
                    }
                    async.waterfall([apply(applyUpdatingHandler, newDevice)], function handleUpdating(
                        error,
                        newDeviceUpdated
                    ) {
                        deviceService.updateRegister(newDeviceUpdated, isTypeOrNameUpdated, function handleDeviceUpdate(
                            error
                        ) {
                            if (error) {
                                next(error);
                            } else {
                                res.status(204).json({});
                            }
                        });
                    });
                } else {
                    next(new errors.DeviceNotFound(req.params.deviceId));
                }
            }
        );
    }
}

/**
 * Load the routes related to device provisioning in the Express App.
 *
 * @param {Object} router      Express request router object.
 */
function loadContextRoutes(router) {
    router.post(
        '/iot/devices',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        restUtils.checkBody(createDeviceTemplate),
        handleProvision
    );

    router.get('/iot/devices', restUtils.checkRequestAttributes('headers', mandatoryHeaders), handleListDevices);

    router.get(
        '/iot/devices/:deviceId',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        handleGetDevice
    );

    router.put(
        '/iot/devices/:deviceId',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        restUtils.checkBody(updateDeviceTemplate),
        handleUpdateDevice
    );

    router.delete(
        '/iot/devices/:deviceId',
        restUtils.checkRequestAttributes('headers', mandatoryHeaders),
        handleRemoveDevice
    );
}

function setProvisioningHandler(newHandler) {
    provisioningHandler = newHandler;
}

function setUpdatingHandler(newHandler) {
    updatingHandler = newHandler;
}

function setRemoveDeviceHandler(newHandler) {
    removeDeviceHandler = newHandler;
}

function addDeviceProvisionMiddleware(newHandler) {
    provisioningMiddlewares.push(newHandler);
}

function clear(callback) {
    provisioningMiddlewares = [];
    provisioningHandler = null;
    callback();
}

exports.setConfiguration = setConfiguration;
exports.loadContextRoutes = intoTrans(context, loadContextRoutes);
exports.setProvisioningHandler = intoTrans(context, setProvisioningHandler);
exports.setUpdatingHandler = intoTrans(context, setUpdatingHandler);
exports.setRemoveDeviceHandler = intoTrans(context, setRemoveDeviceHandler);
exports.addDeviceProvisionMiddleware = addDeviceProvisionMiddleware;
exports.clear = clear;
<|endoftext|>


<commit_before>
	var cordova = require('cordova'),
		fileOpener2 = require('./FileOpener2');

	var schemes = [
        { protocol: 'ms-app', getFile: getFileFromApplicationUri },
        { protocol: 'cdvfile', getFile: getFileFromFileUri }    //protocol cdvfile
	]

	function nthIndex(str, pat, n) {
	    var L = str.length, i = -1;
	    while (n-- && i++ < L) {
	        i = str.indexOf(pat, i);
	        if (i < 0) break;
	    }
	    return i;
	}

	function getFileFromApplicationUri(uri) {
	    /* bad path from a file entry due to the last '//'
               example: ms-appdata:///local//path/to/file
            */
	    var index = nthIndex(uri, "//", 3);
	    var newUri = uri.substr(0, index) + uri.substr(index + 1);

	    var applicationUri = new Windows.Foundation.Uri(newUri);

	    return Windows.Storage.StorageFile.getFileFromApplicationUriAsync(applicationUri);
	}

	function getFileFromFileUri(uri) {
	    /* uri example:
               cdvfile://localhost/persistent|temporary|another-fs-root/path/to/file
            */
	    var indexFrom = nthIndex(uri, "/", 3) + 1;
	    var indexTo = nthIndex(uri, "/", 4);
	    var whichFolder = uri.substring(indexFrom, indexTo);
	    var filePath = uri.substr(indexTo + 1);
	    var path = "\\" + filePath;

	    if (whichFolder == "persistent") {
	        path = Windows.Storage.ApplicationData.current.localFolder.path + path;
	    }
	    else {  //temporary, note: no roaming management
	        path = Windows.Storage.ApplicationData.current.temporaryFolder.path + path;
	    }

	    return getFileFromNativePath(path);
	}

	function getFileFromNativePath(path) {
	    var nativePath = path.split("/").join("\\");

	    return Windows.Storage.StorageFile.getFileFromPathAsync(nativePath);
	}

	function getFileLoaderForScheme(path) {
	    var fileLoader = getFileFromNativePath;

	    schemes.some(function (scheme) {
	        return path.indexOf(scheme.protocol) === 0 ? ((fileLoader = scheme.getFile), true) : false;
	    });

	    return fileLoader;
	}

	module.exports = {

	    open: function (successCallback, errorCallback, args) {

	        var path = args[0];

	        var getFile = getFileLoaderForScheme(path);

	        getFile(path).then(function (file) {
	            var options = new Windows.System.LauncherOptions();

	            Windows.System.Launcher.launchFileAsync(file, options).done(function (success) {
	                successCallback();
	            }, function (error) {
	                errorCallback(error);
	            });

	        }, function (error) {
	            console.log("Error while opening the file: "+error);
		    errorCallback(error);
	        });
		}

	};

	require("cordova/exec/proxy").add("FileOpener2", module.exports);

<commit_msg>Update fileOpener2Proxy.js<commit_after>
	var cordova = require('cordova'),
		fileOpener2 = require('./FileOpener2');

	var schemes = [
        { protocol: 'ms-app', getFile: getFileFromApplicationUri },
        { protocol: 'cdvfile', getFile: getFileFromFileUri }    //protocol cdvfile
	]

	function nthIndex(str, pat, n) {
	    var L = str.length, i = -1;
	    while (n-- && i++ < L) {
	        i = str.indexOf(pat, i);
	        if (i < 0) break;
	    }
	    return i;
	}

	function getFileFromApplicationUri(uri) {
	    /* bad path from a file entry due to the last '//'
               example: ms-appdata:///local//path/to/file
            */
	    var index = nthIndex(uri, "//", 3);
	    var newUri = uri.substr(0, index) + uri.substr(index + 1);

	    var applicationUri = new Windows.Foundation.Uri(newUri);

	    return Windows.Storage.StorageFile.getFileFromApplicationUriAsync(applicationUri);
	}

	function getFileFromFileUri(uri) {
	    /* uri example:
               cdvfile://localhost/persistent|temporary|another-fs-root/path/to/file
            */
	    var indexFrom = nthIndex(uri, "/", 3) + 1;
	    var indexTo = nthIndex(uri, "/", 4);
	    var whichFolder = uri.substring(indexFrom, indexTo);
	    var filePath = uri.substr(indexTo + 1);
	    var path = "\\" + filePath;

	    if (whichFolder == "persistent") {
	        path = Windows.Storage.ApplicationData.current.localFolder.path + path;
	    }
	    else {  //temporary, note: no roaming management
	        path = Windows.Storage.ApplicationData.current.temporaryFolder.path + path;
	    }

	    return getFileFromNativePath(path);
	}

	function getFileFromNativePath(path) {
	    var nativePath = path.split("/").join("\\");

	    return Windows.Storage.StorageFile.getFileFromPathAsync(nativePath);
	}

	function getFileLoaderForScheme(path) {
	    var fileLoader = getFileFromNativePath;

	    schemes.some(function (scheme) {
	        return path.indexOf(scheme.protocol) === 0 ? ((fileLoader = scheme.getFile), true) : false;
	    });

	    return fileLoader;
	}

	module.exports = {

	    open: function (successCallback, errorCallback, args) {

	        var path = args[0];

	        var getFile = getFileLoaderForScheme(path);

	        getFile(path).then(function (file) {
	            var options = new Windows.System.LauncherOptions();

	            Windows.System.Launcher.launchFileAsync(file, options).then(function (success) {
	                successCallback();
	            }, function (error) {
	                errorCallback(error);
	            });

	        }, function (error) {
	            console.log("Error while opening the file: "+error);
		    errorCallback(error);
	        });
		}

	};

	require("cordova/exec/proxy").add("FileOpener2", module.exports);

<|endoftext|>


<commit_before>/*
https://en.wikipedia.org/wiki/Metric_prefix
			List of SI prefixes
		SI			1000^m			10^n
	Name	Symbol
	yotta	Y		1000^8			10^2
	zetta	Z		1000^7			10^2
	exa		E		1000^6			10^18
	peta	P		1000^5			10^15
	tera	T		1000^4			10^12
	giga	G		1000^3			10^9
	mega	M		1000^2			10^6
	kilo	k		1000^1			10^3
	hecto	h		1000^(2/3)		10^2
	deca	da		1000^(1/3)		10^1
					1000^0			10^0
	deci	d		1000^−(1/3)		10^−1
	centi	c		1000^−(2/3)		10^−2
	milli	m		1000^−1			10^−3
	micro	μ		1000^−2			10^−6
	nano	n		1000^−3			10^−9
	pico	p		1000^−4			10^−12
	femto	f		1000^−5			10^−15
	atto	a		1000^−6			10^-18
	zepto	z		1000^−7			10^−21
	yocto	y		1000^−8			10−^24
*/

/*
https://en.wikipedia.org/wiki/Binary_prefix
						List of Binary prefixes
		IEC					JEDEC			1024^m		2^n
	Name	Symbol		Name	Symbol
	kibi	Ki			kilo	K			1024^1		2^10
	mebi	Mi			mega	M			1024^2		2^20
	gibi	Gi			giga	G			1024^3		2^30
	tebi	Ti								1024^4		2^40
	pebi	Pi								1024^5		2^50
	exbi	Ei								1024^6		2^60
	zebi	Zi								1024^7		2^70
	yobi	Yi								1024^8		2^80
*/

var SCALE = 1, FIXED = 2;

var SI_PREFIXES = [
	{ "multiple": 1e24,		"symbol": "Y"  },
	{ "multiple": 1e21,		"symbol": "Z"  },
	{ "multiple": 1e18,		"symbol": "E"  },
	{ "multiple": 1e15,		"symbol": "P"  },
	{ "multiple": 1e12,		"symbol": "T"  },
	{ "multiple": 1e9,		"symbol": "G"  },
	{ "multiple": 1e6,		"symbol": "M"  },
	{ "multiple": 1e3,		"symbol": "k"  },
	{ "multiple": 1e2,		"symbol": "h"  },
	{ "multiple": 1e1,		"symbol": "da" },
	{ "multiple": 1,		"symbol": ""   },
	{ "multiple": 1e-1,		"symbol": "d"  },
	{ "multiple": 1e-2,		"symbol": "c"  },
	{ "multiple": 1e-3,		"symbol": "m"  },
	{ "multiple": 1e-6,		"symbol": "μ"  },
	{ "multiple": 1e-9,		"symbol": "n"  },
	{ "multiple": 1e-12,	"symbol": "p"  },
	{ "multiple": 1e-15,	"symbol": "f"  },
	{ "multiple": 1e-18,	"symbol": "a"  },
	{ "multiple": 1e-21,	"symbol": "z"  },
	{ "multiple": 1e-24,	"symbol": "y"  }
];

var BINARY_PREFIXES = [
	{ "multiple": Math.pow( 2, 80 ),	"symbol": "Yi" },
	{ "multiple": Math.pow( 2, 70 ),	"symbol": "Zi" },
	{ "multiple": Math.pow( 2, 60 ),	"symbol": "Ei" },
	{ "multiple": Math.pow( 2, 50 ),	"symbol": "Pi" },
	{ "multiple": Math.pow( 2, 40 ),	"symbol": "Ti" },
	{ "multiple": Math.pow( 2, 30 ),	"symbol": "Gi" },
	{ "multiple": Math.pow( 2, 20 ),	"symbol": "Mi" },
	{ "multiple": Math.pow( 2, 10 ),	"symbol": "Ki" }
];

function toTrimmedFixed( f, n ) {
	"use strict";

	return f.toFixed( n ).replace( /0+$/, "" ).replace( /\.$/, "" );
};

function addPrefix( n, prefixes ) {
	"use strict";

	var i, prefix, multiple;

	for ( i = 0; i < prefixes.length; i += 1 ) {
		prefix = prefixes[ i ];
		multiple = prefix.multiple;

		if ( n >= SCALE * multiple ) {
			return toTrimmedFixed( n / multiple, FIXED ) + prefix.symbol;
		}
	}

	return n.toString();
};<commit_msg>fix(addPrefix.js):<commit_after>/*
https://en.wikipedia.org/wiki/Metric_prefix
			List of SI prefixes
		SI			1000^m			10^n
	Name	Symbol
	yotta	Y		1000^8			10^2
	zetta	Z		1000^7			10^2
	exa		E		1000^6			10^18
	peta	P		1000^5			10^15
	tera	T		1000^4			10^12
	giga	G		1000^3			10^9
	mega	M		1000^2			10^6
	kilo	k		1000^1			10^3
	hecto	h		1000^(2/3)		10^2
	deca	da		1000^(1/3)		10^1
					1000^0			10^0
	deci	d		1000^−(1/3)		10^−1
	centi	c		1000^−(2/3)		10^−2
	milli	m		1000^−1			10^−3
	micro	μ		1000^−2			10^−6
	nano	n		1000^−3			10^−9
	pico	p		1000^−4			10^−12
	femto	f		1000^−5			10^−15
	atto	a		1000^−6			10^-18
	zepto	z		1000^−7			10^−21
	yocto	y		1000^−8			10−^24
*/

/*
https://en.wikipedia.org/wiki/Binary_prefix
						List of Binary prefixes
		IEC					JEDEC			1024^m		2^n
	Name	Symbol		Name	Symbol
	kibi	Ki			kilo	K			1024^1		2^10
	mebi	Mi			mega	M			1024^2		2^20
	gibi	Gi			giga	G			1024^3		2^30
	tebi	Ti								1024^4		2^40
	pebi	Pi								1024^5		2^50
	exbi	Ei								1024^6		2^60
	zebi	Zi								1024^7		2^70
	yobi	Yi								1024^8		2^80
*/

var SCALE = 1, FIXED = 2;

var SI_PREFIXES = [
	{ "multiple": 1e24,		"symbol": "Y"  },
	{ "multiple": 1e21,		"symbol": "Z"  },
	{ "multiple": 1e18,		"symbol": "E"  },
	{ "multiple": 1e15,		"symbol": "P"  },
	{ "multiple": 1e12,		"symbol": "T"  },
	{ "multiple": 1e9,		"symbol": "G"  },
	{ "multiple": 1e6,		"symbol": "M"  },
	{ "multiple": 1e3,		"symbol": "k"  },
	{ "multiple": 1e2,		"symbol": "h"  },
	{ "multiple": 1e1,		"symbol": "da" },
	{ "multiple": 1,		"symbol": ""   },
	{ "multiple": 1e-1,		"symbol": "d"  },
	{ "multiple": 1e-2,		"symbol": "c"  },
	{ "multiple": 1e-3,		"symbol": "m"  },
	{ "multiple": 1e-6,		"symbol": "μ"  },
	{ "multiple": 1e-9,		"symbol": "n"  },
	{ "multiple": 1e-12,	"symbol": "p"  },
	{ "multiple": 1e-15,	"symbol": "f"  },
	{ "multiple": 1e-18,	"symbol": "a"  },
	{ "multiple": 1e-21,	"symbol": "z"  },
	{ "multiple": 1e-24,	"symbol": "y"  }
];

var BINARY_PREFIXES = [
	{ "multiple": Math.pow( 2, 80 ),	"symbol": "Yi" },
	{ "multiple": Math.pow( 2, 70 ),	"symbol": "Zi" },
	{ "multiple": Math.pow( 2, 60 ),	"symbol": "Ei" },
	{ "multiple": Math.pow( 2, 50 ),	"symbol": "Pi" },
	{ "multiple": Math.pow( 2, 40 ),	"symbol": "Ti" },
	{ "multiple": Math.pow( 2, 30 ),	"symbol": "Gi" },
	{ "multiple": Math.pow( 2, 20 ),	"symbol": "Mi" },
	{ "multiple": Math.pow( 2, 10 ),	"symbol": "Ki" }
];

function toTrimmedFixed( f, n ) {
	"use strict";

	return f.toFixed( n ).replace( /0+$/, "" ).replace( /\.$/, "" );
};

function addPrefix( n, prefixes ) {
	"use strict";

	var i, prefix, multiple;

	for ( i = 0; i < prefixes.length; i += 1 ) {
		prefix = prefixes[ i ];
		multiple = prefix.multiple;

		if ( n >= SCALE * multiple ) {
			return toTrimmedFixed( n / multiple, FIXED ) + prefix.symbol;
		}
	}

	return toTrimmedFixed( n, FIXED );
};<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var stylesInDom = {},
	memoize = function(fn) {
		var memo;
		return function () {
			if (typeof memo === "undefined") memo = fn.apply(this, arguments);
			return memo;
		};
	},
	isOldIE = memoize(function() {
		return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
	}),
	getHeadElement = memoize(function () {
		return document.head || document.getElementsByTagName("head")[0];
	}),
	singletonElement = null,
	singletonCounter = 0;

module.exports = function(list, options) {
	if(typeof DEBUG !== "undefined" && DEBUG) {
		if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
	}

	options = options || {};
	// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
	// tags it will allow on a page
	if (typeof options.singleton === "undefined") options.singleton = isOldIE();

	// By default, add <style> tags to the bottom of <head>.
	if (options.insertAt !== "top" && options.insertAt !== "bottom") options.insertAt = "bottom";

	var styles = listToStyles(list);
	addStylesToDom(styles, options);

	return function update(newList) {
		var mayRemove = [];
		for(var i = 0; i < styles.length; i++) {
			var item = styles[i];
			var domStyle = stylesInDom[item.id];
			domStyle.refs--;
			mayRemove.push(domStyle);
		}
		if(newList) {
			var newStyles = listToStyles(newList);
			addStylesToDom(newStyles, options);
		}
		for(var i = 0; i < mayRemove.length; i++) {
			var domStyle = mayRemove[i];
			if(domStyle.refs === 0) {
				for(var j = 0; j < domStyle.parts.length; j++)
					domStyle.parts[j]();
				delete stylesInDom[domStyle.id];
			}
		}
	};
}

function addStylesToDom(styles, options) {
	for(var i = 0; i < styles.length; i++) {
		var item = styles[i];
		var domStyle = stylesInDom[item.id];
		if(domStyle) {
			domStyle.refs++;
			for(var j = 0; j < domStyle.parts.length; j++) {
				domStyle.parts[j](item.parts[j]);
			}
			for(; j < item.parts.length; j++) {
				domStyle.parts.push(addStyle(item.parts[j], options));
			}
		} else {
			var parts = [];
			for(var j = 0; j < item.parts.length; j++) {
				parts.push(addStyle(item.parts[j], options));
			}
			stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
		}
	}
}

function listToStyles(list) {
	var styles = [];
	var newStyles = {};
	for(var i = 0; i < list.length; i++) {
		var item = list[i];
		var id = item[0];
		var css = item[1];
		var media = item[2];
		var sourceMap = item[3];
		var part = {css: css, media: media, sourceMap: sourceMap};
		if(!newStyles[id])
			styles.push(newStyles[id] = {id: id, parts: [part]});
		else
			newStyles[id].parts.push(part);
	}
	return styles;
}

function createStyleElement(options) {
	var styleElement = document.createElement("style");
	var head = getHeadElement();
	styleElement.type = "text/css";
	if (options.insertAt === "top") {
		head.insertBefore(styleElement, head.firstChild);
	} else if (options.insertAt === "bottom") {
		head.appendChild(styleElement);
	} else {
		throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
	}
	return styleElement;
}

function createLinkElement() {
	var linkElement = document.createElement("link");
	var head = getHeadElement();
	linkElement.rel = "stylesheet";
	head.appendChild(linkElement);
	return linkElement;
}

function addStyle(obj, options) {
	var styleElement, update, remove;

	if (options.singleton) {
		var styleIndex = singletonCounter++;
		styleElement = singletonElement || (singletonElement = createStyleElement(options));
		update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
		remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
	} else if(obj.sourceMap &&
		typeof URL === "function" &&
		typeof URL.createObjectURL === "function" &&
		typeof URL.revokeObjectURL === "function" &&
		typeof Blob === "function" &&
		typeof btoa === "function") {
		styleElement = createLinkElement();
		update = updateLink.bind(null, styleElement);
		remove = function() {
			styleElement.parentNode.removeChild(styleElement);
			if(styleElement.href)
				URL.revokeObjectURL(styleElement.href);
		};
	} else {
		styleElement = createStyleElement(options);
		update = applyToTag.bind(null, styleElement);
		remove = function() {
			styleElement.parentNode.removeChild(styleElement);
		};
	}

	update(obj);

	return function updateStyle(newObj) {
		if(newObj) {
			if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)
				return;
			update(obj = newObj);
		} else {
			remove();
		}
	};
}

var replaceText = (function () {
	var textStore = [];

	return function (index, replacement) {
		textStore[index] = replacement;
		return textStore.filter(Boolean).join('\n');
	};
})();

function applyToSingletonTag(styleElement, index, remove, obj) {
	var css = remove ? "" : obj.css;

	if (styleElement.styleSheet) {
		styleElement.styleSheet.cssText = replaceText(index, css);
	} else {
		var cssNode = document.createTextNode(css);
		var childNodes = styleElement.childNodes;
		if (childNodes[index]) styleElement.removeChild(childNodes[index]);
		if (childNodes.length) {
			styleElement.insertBefore(cssNode, childNodes[index]);
		} else {
			styleElement.appendChild(cssNode);
		}
	}
}

function applyToTag(styleElement, obj) {
	var css = obj.css;
	var media = obj.media;
	var sourceMap = obj.sourceMap;

	if(media) {
		styleElement.setAttribute("media", media)
	}

	if(styleElement.styleSheet) {
		styleElement.styleSheet.cssText = css;
	} else {
		while(styleElement.firstChild) {
			styleElement.removeChild(styleElement.firstChild);
		}
		styleElement.appendChild(document.createTextNode(css));
	}
}

function updateLink(linkElement, obj) {
	var css = obj.css;
	var media = obj.media;
	var sourceMap = obj.sourceMap;

	if(sourceMap) {
		// http://stackoverflow.com/a/26603875
		css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
	}

	var blob = new Blob([css], { type: "text/css" });

	var oldSrc = linkElement.href;

	linkElement.href = URL.createObjectURL(blob);

	if(oldSrc)
		URL.revokeObjectURL(oldSrc);
}
<commit_msg>Set insertAt parameter to default only when it is undefined.<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var stylesInDom = {},
	memoize = function(fn) {
		var memo;
		return function () {
			if (typeof memo === "undefined") memo = fn.apply(this, arguments);
			return memo;
		};
	},
	isOldIE = memoize(function() {
		return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
	}),
	getHeadElement = memoize(function () {
		return document.head || document.getElementsByTagName("head")[0];
	}),
	singletonElement = null,
	singletonCounter = 0;

module.exports = function(list, options) {
	if(typeof DEBUG !== "undefined" && DEBUG) {
		if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
	}

	options = options || {};
	// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
	// tags it will allow on a page
	if (typeof options.singleton === "undefined") options.singleton = isOldIE();

	// By default, add <style> tags to the bottom of <head>.
	if (typeof options.insertAt === "undefined") options.insertAt = "bottom";

	var styles = listToStyles(list);
	addStylesToDom(styles, options);

	return function update(newList) {
		var mayRemove = [];
		for(var i = 0; i < styles.length; i++) {
			var item = styles[i];
			var domStyle = stylesInDom[item.id];
			domStyle.refs--;
			mayRemove.push(domStyle);
		}
		if(newList) {
			var newStyles = listToStyles(newList);
			addStylesToDom(newStyles, options);
		}
		for(var i = 0; i < mayRemove.length; i++) {
			var domStyle = mayRemove[i];
			if(domStyle.refs === 0) {
				for(var j = 0; j < domStyle.parts.length; j++)
					domStyle.parts[j]();
				delete stylesInDom[domStyle.id];
			}
		}
	};
}

function addStylesToDom(styles, options) {
	for(var i = 0; i < styles.length; i++) {
		var item = styles[i];
		var domStyle = stylesInDom[item.id];
		if(domStyle) {
			domStyle.refs++;
			for(var j = 0; j < domStyle.parts.length; j++) {
				domStyle.parts[j](item.parts[j]);
			}
			for(; j < item.parts.length; j++) {
				domStyle.parts.push(addStyle(item.parts[j], options));
			}
		} else {
			var parts = [];
			for(var j = 0; j < item.parts.length; j++) {
				parts.push(addStyle(item.parts[j], options));
			}
			stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
		}
	}
}

function listToStyles(list) {
	var styles = [];
	var newStyles = {};
	for(var i = 0; i < list.length; i++) {
		var item = list[i];
		var id = item[0];
		var css = item[1];
		var media = item[2];
		var sourceMap = item[3];
		var part = {css: css, media: media, sourceMap: sourceMap};
		if(!newStyles[id])
			styles.push(newStyles[id] = {id: id, parts: [part]});
		else
			newStyles[id].parts.push(part);
	}
	return styles;
}

function createStyleElement(options) {
	var styleElement = document.createElement("style");
	var head = getHeadElement();
	styleElement.type = "text/css";
	if (options.insertAt === "top") {
		head.insertBefore(styleElement, head.firstChild);
	} else if (options.insertAt === "bottom") {
		head.appendChild(styleElement);
	} else {
		throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
	}
	return styleElement;
}

function createLinkElement() {
	var linkElement = document.createElement("link");
	var head = getHeadElement();
	linkElement.rel = "stylesheet";
	head.appendChild(linkElement);
	return linkElement;
}

function addStyle(obj, options) {
	var styleElement, update, remove;

	if (options.singleton) {
		var styleIndex = singletonCounter++;
		styleElement = singletonElement || (singletonElement = createStyleElement(options));
		update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
		remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
	} else if(obj.sourceMap &&
		typeof URL === "function" &&
		typeof URL.createObjectURL === "function" &&
		typeof URL.revokeObjectURL === "function" &&
		typeof Blob === "function" &&
		typeof btoa === "function") {
		styleElement = createLinkElement();
		update = updateLink.bind(null, styleElement);
		remove = function() {
			styleElement.parentNode.removeChild(styleElement);
			if(styleElement.href)
				URL.revokeObjectURL(styleElement.href);
		};
	} else {
		styleElement = createStyleElement(options);
		update = applyToTag.bind(null, styleElement);
		remove = function() {
			styleElement.parentNode.removeChild(styleElement);
		};
	}

	update(obj);

	return function updateStyle(newObj) {
		if(newObj) {
			if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)
				return;
			update(obj = newObj);
		} else {
			remove();
		}
	};
}

var replaceText = (function () {
	var textStore = [];

	return function (index, replacement) {
		textStore[index] = replacement;
		return textStore.filter(Boolean).join('\n');
	};
})();

function applyToSingletonTag(styleElement, index, remove, obj) {
	var css = remove ? "" : obj.css;

	if (styleElement.styleSheet) {
		styleElement.styleSheet.cssText = replaceText(index, css);
	} else {
		var cssNode = document.createTextNode(css);
		var childNodes = styleElement.childNodes;
		if (childNodes[index]) styleElement.removeChild(childNodes[index]);
		if (childNodes.length) {
			styleElement.insertBefore(cssNode, childNodes[index]);
		} else {
			styleElement.appendChild(cssNode);
		}
	}
}

function applyToTag(styleElement, obj) {
	var css = obj.css;
	var media = obj.media;
	var sourceMap = obj.sourceMap;

	if(media) {
		styleElement.setAttribute("media", media)
	}

	if(styleElement.styleSheet) {
		styleElement.styleSheet.cssText = css;
	} else {
		while(styleElement.firstChild) {
			styleElement.removeChild(styleElement.firstChild);
		}
		styleElement.appendChild(document.createTextNode(css));
	}
}

function updateLink(linkElement, obj) {
	var css = obj.css;
	var media = obj.media;
	var sourceMap = obj.sourceMap;

	if(sourceMap) {
		// http://stackoverflow.com/a/26603875
		css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
	}

	var blob = new Blob([css], { type: "text/css" });

	var oldSrc = linkElement.href;

	linkElement.href = URL.createObjectURL(blob);

	if(oldSrc)
		URL.revokeObjectURL(oldSrc);
}
<|endoftext|>


<commit_before>const expect = require('chai').expect;
const std = require('../../src/index');

//WIP
describe('工作時間、休息、休假', () => {

  describe('工作時間', () => {
    it('一勞工於一天內工作十個小時，其中八個小時是正常工時，兩個小時為加班', () => {
      let result = std.validateWorkingHours(std.DAILY_WORKING_HOURS, 10);
      expect(result.status).eq(std.LEGAL);
      expect(result.value.regular).eq(8);
      expect(result.value.overtime).eq(2);
    });

    it('一勞工於一天內工作十二個小時，其中八個小時是正常工時，四個小時為加班', () => {
      let result = std.validateWorkingHours(std.DAILY_WORKING_HOURS, 12);
      expect(result.status).eq(std.LEGAL);
      expect(result.value.regular).eq(8);
      expect(result.value.overtime).eq(4);
    });

    it('一勞工於一天內工作十五個小時，其中八個小時是正常工時，七個小時為加班並且違反勞基法 32 條', () => {
      let result = std.validateWorkingHours(std.DAILY_WORKING_HOURS, 15);
      expect(result.status).eq(std.ILLEGAL);
      expect(result.value.regular).eq(8);
      expect(result.value.overtime).eq(7);
      expect(result.fines[0].according).eq('LSA-79');
      expect(result.fines[0].min).eq(20000);
      expect(result.fines[0].max).eq(1000000);
    });

    it('勞工於一個月內的連續三週（十五天）每天工作十二個小時，此違反勞基法 32 條一個月不能超過 46 小時', () => {
      let hours = Array.apply(null, Array(15)).map(Number.prototype.valueOf, 12);
      // this array will be [12, 12, 12, 12, ...] with 15 items;
      let total = hours
                    .map(h => std.validateWorkingHours(std.DAILY_WORKING_HOURS, h))
                    .reduce((a, b) => a + b);
      let result = std.validateWorkingHours(std.MONTHLY_WORKING_HOURS, total);
      expect(result.status).eq(std.ILLEGAL);
      expect(result.value.regular).eq(120);
      expect(result.value.overtime).eq(60);
      expect(result.fines[0].according).eq('LSA-79');
      expect(result.fines[0].min).eq(20000);
      expect(result.fines[0].max).eq(1000000);
    });
  });

  describe('休假', () => {
    describe('特休', () => {
    });

    describe('事假', () => {
    });

    describe('產假', () => {

    });

    describe('陪產假', () => {

    });

    describe('病假', () => {

    });
  });
})
<commit_msg>Added std.REGULAR_WORKING_HOURS to test cases<commit_after>const expect = require('chai').expect;
const std = require('../../src/index');

//WIP
describe('工作時間、休息、休假', () => {

  describe('工作時間', () => {
    it('正常工時情況下，一勞工於一天內工作十個小時，其中八個小時是正常工時，兩個小時為加班', () => {
      let result = std.validateWorkingHours(std.DAILY_WORKING_HOURS, std.REGULAR_WORKING_HOURS, 10);
      expect(result.status).eq(std.LEGAL);
      expect(result.value.regular).eq(8);
      expect(result.value.overtime).eq(2);
    });

    it('正常工時情況下，一勞工於一天內工作十二個小時，其中八個小時是正常工時，四個小時為加班', () => {
      let result = std.validateWorkingHours(std.DAILY_WORKING_HOURS, std.REGULAR_WORKING_HOURS, 12);
      expect(result.status).eq(std.LEGAL);
      expect(result.value.regular).eq(8);
      expect(result.value.overtime).eq(4);
    });

    it('正常工時情況下，一勞工於一天內工作十五個小時，其中八個小時是正常工時，七個小時為加班並且違反勞基法 32 條', () => {
      let result = std.validateWorkingHours(std.DAILY_WORKING_HOURS, std.REGULAR_WORKING_HOURS, 15);
      expect(result.status).eq(std.ILLEGAL);
      expect(result.value.regular).eq(8);
      expect(result.value.overtime).eq(7);
      expect(result.fines[0].according).eq('LSA-79');
      expect(result.fines[0].min).eq(20000);
      expect(result.fines[0].max).eq(1000000);
    });

    it('正常工時情況下，勞工於一個月內的連續三週（十五天）每天工作十二個小時，此違反勞基法 32 條一個月不能超過 46 小時', () => {
      let hours = Array.apply(null, Array(15)).map(Number.prototype.valueOf, 12);
      // this array will be [12, 12, 12, 12, ...] with 15 items;
      let total = hours
                    .map(h => std.validateWorkingHours(std.DAILY_WORKING_HOURS, std.REGULAR_WORKING_HOURS, h))
                    .reduce((a, b) => a + b);
      let result = std.validateWorkingHours(std.MONTHLY_WORKING_HOURS, std.REGULAR_WORKING_HOURS, total);
      expect(result.status).eq(std.ILLEGAL);
      expect(result.value.regular).eq(120);
      expect(result.value.overtime).eq(60);
      expect(result.fines[0].according).eq('LSA-79');
      expect(result.fines[0].min).eq(20000);
      expect(result.fines[0].max).eq(1000000);
    });
  });

  describe('休假', () => {
    describe('特休', () => {
    });

    describe('事假', () => {
    });

    describe('產假', () => {

    });

    describe('陪產假', () => {

    });

    describe('病假', () => {

    });
  });
})
<|endoftext|>


<commit_before>/*
 * grunt-shopify-theme-settings
 * https://github.com/discolabs/grunt-shopify-theme-settings
 *
 * Copyright (c) 2014 Gavin Ballard
 * Licensed under the MIT license.
 */

'use strict';
var swig = require('swig');
var tidy = require('htmltidy').tidy;

module.exports = function(grunt) {

  grunt.registerMultiTask('shopify_theme_settings', 'Grunt plugin to build a settings.html file for Shopify themes.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      docType: 'strict',
      outputXhtml: true,
      indent: true,
      indentSpaces: 4,
      wrap: 0,
      showBodyOnly: true
    });

    // Mark this task as asynchronous.
    var done = this.async();

    // Iterate over all specified file targets.
    this.files.forEach(function(f) {

      // Test each source YAML file for existence, then reduce the parsed YAML into a single sections object.
      var sections = f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).reduce(function(sections, filepath) {
        // Parse source file.
        var parsed = grunt.file.readYAML(filepath);

        // Add the sections from the parsed source file to our existing sections.
        for(var key in parsed) {
          if(parsed.hasOwnProperty(key)) {
            sections[key] = parsed[key];
          }
        }

        return sections;
      }, {});

      // Compile and render using Swig.
      var settingsTemplate = swig.compileFile(__dirname + '/templates/settings.html');
      var output = settingsTemplate({
        sections: sections
      });

      // Tidy using HTMLTidy.
      tidy(output, options, function(err, tidiedOutput) {
        // Write the destination file.
        grunt.file.write(f.dest, tidiedOutput);

        // Print a success message.
        grunt.log.writeln('File "' + f.dest + '" created.');

        // Mark asynchronous task as done.
        done();
      });
    });
  });

};<commit_msg>Don’t drop empty elements, to allow generation of empty <option> tags.<commit_after>/*
 * grunt-shopify-theme-settings
 * https://github.com/discolabs/grunt-shopify-theme-settings
 *
 * Copyright (c) 2014 Gavin Ballard
 * Licensed under the MIT license.
 */

'use strict';
var swig = require('swig');
var tidy = require('htmltidy').tidy;

module.exports = function(grunt) {

  grunt.registerMultiTask('shopify_theme_settings', 'Grunt plugin to build a settings.html file for Shopify themes.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      docType: 'strict',
      outputXhtml: true,
      indent: true,
      indentSpaces: 4,
      wrap: 0,
      showBodyOnly: true,
      dropEmptyElements: false
    });

    // Mark this task as asynchronous.
    var done = this.async();

    // Iterate over all specified file targets.
    this.files.forEach(function(f) {

      // Test each source YAML file for existence, then reduce the parsed YAML into a single sections object.
      var sections = f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).reduce(function(sections, filepath) {
        // Parse source file.
        var parsed = grunt.file.readYAML(filepath);

        // Add the sections from the parsed source file to our existing sections.
        for(var key in parsed) {
          if(parsed.hasOwnProperty(key)) {
            sections[key] = parsed[key];
          }
        }

        return sections;
      }, {});

      // Compile and render using Swig.
      var settingsTemplate = swig.compileFile(__dirname + '/templates/settings.html');
      var output = settingsTemplate({
        sections: sections
      });

      // Tidy using HTMLTidy.
      tidy(output, options, function(err, tidiedOutput) {
        // Write the destination file.
        grunt.file.write(f.dest, tidiedOutput);

        // Print a success message.
        grunt.log.writeln('File "' + f.dest + '" created.');

        // Mark asynchronous task as done.
        done();
      });
    });
  });

};
<|endoftext|>


<commit_before>const {resMsg} = require('$routeLib');

/**
 * Delete Connection Controller
 *
 * @param req
 * @param res
 * @param next
 */
module.exports = async ({query}, res, next) => {
  resMsg.tokenClear(res);
};
<commit_msg>[create] 로그아웃 controller 구현<commit_after>const {resMsg} = require('$routeLib');

/**
 * Delete Connection Controller
 *
 * @param req
 * @param res
 * @param next
 */
module.exports = (body, res) => {
  resMsg.tokenClear(res);
};
<|endoftext|>


<commit_before>/* Copyright (C) 2011  Lincoln de Sousa <lincoln@comum.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

avl.extend('player', function (e, o, disableAsync) {
    function Player (element, opts) {
        opts = opts || {};
        this.sources = opts.sources;
        this.width = opts.width || 480;
        this.height = opts.height || 270;

        /* Configuring the target element */
        this.$element = $(element);
        this.$element.addClass('video-js-box');

        /* Let's build the player */
        this.player();
    }

    Player.prototype = {
        player: function () {
            var $video = $('<video>');
            var uid = 'player-' + (new Date()).getTime();
            var flv = null;
            var rtmp = false;
            for (var i = 0; i < this.sources.length; i++) {
                if (this.sources[i].content_type === 'video/x-flv') {
                    flv = this.sources[i].url;
                    if (this.sources[i].url.substr(0, 4) === 'rtmp') {
                        rtmp = true;
                    }
                }

                var attrs = {
                    src: this.sources[i].url,
                    type: this.sources[i].content_type
                };
                $video.append($('<source>').attr(attrs));
            }

            var $playerContainer = $('<div>').attr('id', uid);
            $playerContainer.css({width: this.width, height: this.height});

            var ie9 = navigator.userAgent.indexOf("Trident/5") > -1;

            /* There's only one source, a flash one. So, we'll not setup
             * the video tag. Another condition is we have flash and
             * it's IE9. */
            if ((this.sources.length === 1 && flv) || (flv && ie9)) {
                $playerContainer.appendTo(this.$element);
            } else {
                $video.attr({width: this.width, height: this.height});
                $video.addClass('video-js');
                $video.append($playerContainer);
                $video.appendTo(this.$element);
            }

            /* Setting up video js in the just added player. It will not
             * until we add it to the dom structure */
            VideoJS.setup($('video', this.$element)[0]);

            /* We need to setup flash too */
            if (flv != null) {
                var cfg = {
                    clip: {
                        url: flv,
                        autoPlay: true
                    }
                };

                /* We also need to support flash streaming */
                if (rtmp) {

                    /* Handling requests in all styles, including akamai
                     * ones.
                     *
                     * Don't know why they just don't use another
                     * mimetype once they're not actually providing flv
                     * content in the first request... */
                    var result = /^(.+)\/([^\/]+)$/.exec(flv);
                    var netConnectionUrl = result[1];
                    var clipUrl = result[0]

                    cfg.clip.url = clipUrl;
                    cfg.clip.live = true;
                    cfg.clip.provider = 'influxis';
                    cfg.plugins = {
                        influxis: {
                            url: 'http://releases.flowplayer.org/swf/flowplayer.rtmp-3.2.3.swf',
                            netConnectionUrl: netConnectionUrl
                        }
                    };
                }

                $f(uid, "http://releases.flowplayer.org/swf/flowplayer-3.2.7.swf", cfg);
            }
            return $video;
        }
    };

    /* We shall want to call this API with the video object already
     * loaded */
    if (disableAsync === true) {
        return new Player(e, o);
    }

    /* Ok, let's proced with the async call */
    $.getJSON(this.api_url + '/' + o.id + '/?callback=?', function (video) {
        new Player(e, video);
    });
});
<commit_msg>Some changes to make the player work on more browsers<commit_after>/* Copyright (C) 2011  Lincoln de Sousa <lincoln@comum.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

avl.extend('player', function (e, o, disableAsync) {
    function Player (element, opts) {
        opts = opts || {};
        this.sources = opts.sources;
        this.width = opts.width || 480;
        this.height = opts.height || 270;

        /* Configuring the target element */
        this.$element = $(element);
        this.$element.addClass('video-js-box');

        /* Let's build the player */
        this.player();
    }

    Player.prototype = {
        player: function () {
            var $video = $('<video>');
            var uid = 'player-' + (new Date()).getTime();
            var flv = null;
            var rtmp = false;
            for (var i = 0; i < this.sources.length; i++) {
                if (this.sources[i].content_type === 'video/x-flv') {
                    flv = this.sources[i].url;
                    if (this.sources[i].url.substr(0, 4) === 'rtmp') {
                        rtmp = true;
                    }
                }

                var attrs = {
                    src: this.sources[i].url,
                    type: this.sources[i].content_type
                };
                $video.append($('<source>').attr(attrs));
            }

            var $playerContainer = $('<div>').attr('id', uid);
            $playerContainer.css({width: this.width, height: this.height});

            /* Let's the hammer play around
             *
             * There are some special conditions that we have to
             * consider before using the video tag and the flash stuff.
             *
             * I know that these rules are quite basic, and that safari
             * (and other mac stuff) accepts the video tag but not
             * ogg. Here they are:
             *
             *  - (flv && sources.length === 1)
             *  - (flv && ie9)
             *  - (flv && !ogg)
             */
            var videoTag = !!document.createElement('video').canPlayType;
            var ie9 = navigator.userAgent.indexOf("Trident/5") > -1;
            var ogg = document.createElement("video")
                .canPlayType('video/ogg; codecs="theora, vorbis"');
            if ((this.sources.length === 1 && flv) ||
                (flv && ie9) ||
                (flv && !ogg)) {
                $playerContainer.appendTo(this.$element);
            } else {
                $video.attr({width: this.width, height: this.height});
                $video.addClass('video-js');
                $video.append($playerContainer);
                $video.appendTo(this.$element);
            }

            /* Setting up video js in the just added player. It will not
             * until we add it to the dom structure */
            VideoJS.setup($('video', this.$element)[0]);

            /* We need to setup flash too */
            if (flv != null) {
                var cfg = {
                    clip: {
                        url: flv,
                        autoPlay: true
                    }
                };

                /* We also need to support flash streaming */
                if (rtmp) {

                    /* Handling requests in all styles, including akamai
                     * ones.
                     *
                     * Don't know why they just don't use another
                     * mimetype once they're not actually providing flv
                     * content in the first request... */
                    var result = /^(.+)\/([^\/]+)$/.exec(flv);
                    var netConnectionUrl = result[1];
                    var clipUrl = result[0]

                    cfg.clip.url = clipUrl;
                    cfg.clip.live = true;
                    cfg.clip.provider = 'influxis';
                    cfg.plugins = {
                        influxis: {
                            url: 'http://releases.flowplayer.org/swf/flowplayer.rtmp-3.2.3.swf',
                            netConnectionUrl: netConnectionUrl
                        }
                    };
                }

                $f(uid, "http://releases.flowplayer.org/swf/flowplayer-3.2.7.swf", cfg);
            }
            return $video;
        }
    };

    /* We shall want to call this API with the video object already
     * loaded */
    if (disableAsync === true) {
        return new Player(e, o);
    }

    /* Ok, let's proced with the async call */
    $.getJSON(this.api_url + '/' + o.id + '/?callback=?', function (video) {
        new Player(e, video);
    });
});
<|endoftext|>


<commit_before>'use strict';

var syncStyle    = require('dom-ext/html-element/#/sync-style')
  , isMobileView = require('../utils/is-mobile-view')
  , syncHeight   = require('../utils/sync-height')
  , db           = require('mano').db
  , reject       = require('./_reject')

  , user = db.User.prototype;

exports['sub-main'] = function () {
	var source,
	target,
	elem;

	section(
		{ class: 'submitted-main table-responsive-container' },
		table(
			{ class: 'submitted-user-data-table submitted-current-user-data-table', responsive: true },
			thead(
				tr(
					th("Status"),
					th("Application number"),
					th("Application date"),
					th("Requested registrations"),
					th("")
				)
			),
			tbody(
				tr(
					td("Pending for revision"),
					td("4068-50001-N-2013"),
					td("23/07/2014 18:09:22"),
					td(
						span({ class: 'label-reg' }, "Brela"),
						span({ class: 'label-reg' }, "Tinc"),
						span({ class: 'label-reg' }, "Vat"),
						span({ class: 'label-reg' }, "Gepf"),
						span({ class: 'label-reg' }, "Nssf"),
						span({ class: 'label-reg' }, "Lapf")
					),
					td(
						a({ class: 'hint-optional hint-optional-left', 'data-hint': 'Download status' },
							span({ class: 'fa fa-download' }, "Download"))
					)
				)
			)
		)
	);
	section(
		{ class: 'section-primary' },
		h2({ class: 'container-with-nav' }, "Application history",
			a(
				{ class: 'hint-optional hint-optional-left',
					'data-hint': 'Print history of application',
					href: '/user-submitted/history-print/' },
				span({ class: 'fa fa-print' }, "Print")
			)),
		table(
			{ class: 'submitted-user-history' },
			tbody(
				tr(
					th(
						div("User")
					),
					td(
						div("John Watson (4068-50001-N-2013)")
					),
					td(
						div("24/07/2014 10:09:22")
					),
					td(
						div("Required modifications sent by user")
					)
				),
				tr(
					th(
						div("File sent")
					),
					td(
						div("John Watson (4068-50001-N-2013)")
					),
					td(
						div("24/07/2014 13:09:22")
					),
					td(
						div("File sent")
					)
				),
				tr(
					th(
						div("Official")
					),
					td(
						div("Sherlock Holmes (4068-50001-N-2013)")
					),
					td(
						div("24/07/2014 16:19:22")
					),
					td(
						div("Document accepted")
					)
				)
			)
		)
	);
	section(
		{ class: 'section-primary' },
		insert(reject),
		h2("Application revision"),
		div({ class: 'official-submission-toolbar' },
			postButton({ buttonClass: 'button-main button-main-success', value: "Approve file" }),
			postButton({ buttonClass: 'button-main', value: "Send for corrections" }),
			a({ href: '#reject', class: 'button-main button-main-error' }, "Reject file")),
		hr(),
		h3("Required documents"),
		ol({ class: 'submitted-documents-list' },
			li(
				a("Memorandum and articles of association")
			),
			li(
				a("Proof of identity for director 1")
			),
			li(
				a("Proof of identity for director 2")
			),
			li(
				a("Registered title deed")
			)),
		h3("Received documents"),
		ol({ class: 'submitted-documents-thumbs' },
			li(
				a(span({ class: 'submitted-documents-thumbs-status ' +
						'submitted-documents-thumbs-success fa fa-check ' }),
					img({ src: '/uploads/docASubFile2.thumb.idoc.png.jpg' }))
			),
			li(
				a(span({ class: 'submitted-documents-thumbs-status' +
						' submitted-documents-thumbs-success fa fa-check ' }),
					img({ src: '/uploads/docASubFile1.thumb.idoc.jpg' }))
			),
			li(
				a(span({ class: 'submitted-documents-thumbs-status ' +
						'submitted-documents-thumbs-error fa fa-exclamation ' }),
					img({ src: '/uploads/docBSubFile1.thumb.idoc.jpg' }))
			),
			li(
				a(span({ class: 'submitted-documents-thumbs-status ' +
						'submitted-documents-thumbs-success fa fa-check ' }),
					img({ src: '/uploads/docASubFile2.thumb.idoc.png.jpg' }))
			))
	);
	section(
		{ class: 'submitted-preview' },
		source = div(
			{ class: 'section-primary submitted-preview-document' },
			div({ class: 'container-with-nav' },
				h3(i({ class: 'submitted-preview-item-number' }, "1"),
					"Memorandum and articles of association")),
			elem = div({ class: 'submitted-preview-image-placeholder' },
				img({ zoomOnHover: true, src: '/uploads/docASubFile2.idoc.png.jpg' })),
			form(
				{ class: 'submitted-preview-form' },
				ul(
					{ class: 'form-elements' },
					li(
						input({ dbjs: user._isValidated })
					),
					li(
						div(
							{ class: 'dbjs-input-component' },
							label("Reject document: "),
							div(
								{ class: 'input official-form-document-revision-reject-reason' },
								select(
									option("Choose rejection reason: "),
									option("Document is not readable."),
									option("The document is not acurate or does not match the data of the form."),
									option("Other")
								),
								textarea()
							)
						)
					)
				),
				p(input({ type: 'submit' }, "Save"))
			)
		),
		target = div({ class: 'section-primary submitted-preview-user-data entity-data-section-side' },
			h2({ class: 'container-with-nav' }, "Application form",
				a(
					{ class: 'hint-optional hint-optional-left',
						'data-hint': 'Print Your application form',
						href: '/user-submitted/data-print/' },
					span({ class: 'fa fa-print' }, "Print")
				)),

			section(
				{ class: 'entity-data-section' },
				h3("Proposed company name"),
				table(
					tbody(
						tr(
							td("Blink IT Solutions")
						)
					)
				)
			),
			section(
				{ class: 'entity-data-section' },
				h3("Business activity"),
				table(
					tbody(
						tr(
							th("Activity"),
							td("Air chater agent")
						),
						tr(
							th("Activity starting date"),
							td("7/30/2014")
						),
						tr(
							th("Date of account year end"),
							td("12/31/2014")
						),
						tr(
							th("Does the company have branches?"),
							td("Yes")
						)
					)
				)
			),
			section(
				{ class: 'entity-data-section' },
				h3("Company secretary"),
				section(
					{ class: 'entity-data-section-sub' },
					h4("Basic secretary data"),
					table(
						tbody(
							tr(
								th("Title"),
								td("Mr")
							),
							tr(
								th("First Name"),
								td("Andrei")
							),
							tr(
								th("Middle Name"),
								td("Mihai")
							),
							tr(
								th("Surname"),
								td("Balan")
							)
						)
					)
				),
				section(
					{ class: 'entity-data-section-sub' },
					h4("Residential address"),
					table(
						tbody(
							tr(
								th("Plot"),
								td("1")
							),
							tr(
								th("Block"),
								td("1")
							),
							tr(
								th("Street or location"),
								td("Nicolae Filipescu")
							),
							tr(
								th("City, district or town"),
								td("Bucharest")
							),
							tr(
								th("P.O. box"),
								td("1")
							),
							tr(
								th("Country"),
								td("Romania")
							)
						)
					)
				)
			),
			section(
				{ class: 'entity-data-section' },
				h3("Applicants"),
				ul(
					{ class: 'entity-data-section-entities' },
					li(
						h4("Marko Zagola"),
						section(
							{ class: 'entity-data-section' },
							h5("Personal data"),
							section(
								{ class: 'entity-data-section-sub' },
								h6("Basic data"),
								table(
									tbody(
										tr(
											th("Name"),
											td("Marko")
										),
										tr(
											th("Surname"),
											td("Zagalo")
										)
									)
								)
							),
							section(
								{ class: 'entity-data-section-sub' },
								h6("Additional data"),
								table(
									tbody(
										tr(
											th("Document type"),
											td("X")
										),
										tr(
											th("Document number"),
											td("123")
										),
										tr(
											th("Marital status"),
											td("")
										),
										tr(
											th("Date of birth"),
											td("25-06-1991")
										),
										tr(
											th("Nationality"),
											td("Romanian")
										),
										tr(
											th("E-mail"),
											td("andrei.balan@blink-it.ro")
										)
									)
								)
							),
							section(
								{ class: 'entity-data-section-sub' },
								h6("Address"),
								table(
									tbody(
										tr(
											th("Address"),
											td("XXX")
										),
										tr(
											th("Number"),
											td("1")
										),
										tr(
											th("Postal code"),
											td("X")
										),
										tr(
											th("City"),
											td("Bucharest")
										),
										tr(
											th("Country"),
											td("Romania")
										)
									)
								)
							)
						)
					),
					li(
						h4("Frank Grozel"),
						section(
							{ class: 'entity-data-section' },
							h5("Additional data"),
							table(
								tbody(
									tr(
										th("Document type"),
										td("X")
									),
									tr(
										th("Document number"),
										td("123")
									),
									tr(
										th("Marital status"),
										td("")
									),
									tr(
										th("Date of birth"),
										td("25-06-1991")
									),
									tr(
										th("Nationality"),
										td("Romanian")
									),
									tr(
										th("E-mail"),
										td("andrei.balan@blink-it.ro")
									)
								)
							)
						)
					)
				)
			)
			)
	);
	syncStyle.call(target, source, 'height', isMobileView);
	syncHeight(elem);
};
<commit_msg>Added user-history wrapper where missed. #299<commit_after>'use strict';

var syncStyle    = require('dom-ext/html-element/#/sync-style')
  , isMobileView = require('../utils/is-mobile-view')
  , syncHeight   = require('../utils/sync-height')
  , db           = require('mano').db
  , reject       = require('./_reject')

  , user = db.User.prototype;

exports['sub-main'] = function () {
	var source,
	target,
	elem;

	section(
		{ class: 'submitted-main table-responsive-container' },
		table(
			{ class: 'submitted-user-data-table submitted-current-user-data-table', responsive: true },
			thead(
				tr(
					th("Status"),
					th("Application number"),
					th("Application date"),
					th("Requested registrations"),
					th("")
				)
			),
			tbody(
				tr(
					td("Pending for revision"),
					td("4068-50001-N-2013"),
					td("23/07/2014 18:09:22"),
					td(
						span({ class: 'label-reg' }, "Brela"),
						span({ class: 'label-reg' }, "Tinc"),
						span({ class: 'label-reg' }, "Vat"),
						span({ class: 'label-reg' }, "Gepf"),
						span({ class: 'label-reg' }, "Nssf"),
						span({ class: 'label-reg' }, "Lapf")
					),
					td(
						a({ class: 'hint-optional hint-optional-left', 'data-hint': 'Download status' },
							span({ class: 'fa fa-download' }, "Download"))
					)
				)
			)
		)
	);
	section(
		{ class: 'section-primary' },
		h2({ class: 'container-with-nav' }, "Application history",
			a(
				{ class: 'hint-optional hint-optional-left',
					'data-hint': 'Print history of application',
					href: '/user-submitted/history-print/' },
				span({ class: 'fa fa-print' }, "Print")
			)),
		div(
			{ class: 'submitted-user-history-wrapper' },
			table(
				{ class: 'submitted-user-history' },
				tbody(
					tr(
						th(div("User")),
						td(div("24/07/2014 10:09:22")),
						td(div("Required modifications sent by user"))
					),
					tr(
						th(div("File sent")),
						td(div("24/07/2014 13:09:22")),
						td(div("File sent"))
					),
					tr(
						th(div("Official")),
						td(div("24/07/2014 16:19:22")),
						td(div("Document accepted"))
					),
					tr(
						th(div("User")),
						td(div("24/07/2014 10:09:22")),
						td(div("Required modifications sent by user"))
					),
					tr(
						th(div("File sent")),
						td(div("24/07/2014 13:09:22")),
						td(div("File sent"))
					),
					tr(
						th(div("Official")),
						td(div("24/07/2014 16:19:22")),
						td(div("Document accepted"))
					),
					tr(
						th(div("User")),
						td(div("24/07/2014 10:09:22")),
						td(div("Required modifications sent by user"))
					),
					tr(
						th(div("File sent")),
						td(div("24/07/2014 13:09:22")),
						td(div("File sent"))
					),
					tr(
						th(div("Official")),
						td(div("24/07/2014 16:19:22")),
						td(div("Document accepted"))
					)
				)
			)
		)
	);
	section(
		{ class: 'section-primary' },
		insert(reject),
		h2("Application revision"),
		div({ class: 'official-submission-toolbar' },
			postButton({ buttonClass: 'button-main button-main-success', value: "Approve file" }),
			postButton({ buttonClass: 'button-main', value: "Send for corrections" }),
			a({ href: '#reject', class: 'button-main button-main-error' }, "Reject file")),
		hr(),
		h3("Required documents"),
		ol({ class: 'submitted-documents-list' },
			li(
				a("Memorandum and articles of association")
			),
			li(
				a("Proof of identity for director 1")
			),
			li(
				a("Proof of identity for director 2")
			),
			li(
				a("Registered title deed")
			)),
		h3("Received documents"),
		ol({ class: 'submitted-documents-thumbs' },
			li(
				a(span({ class: 'submitted-documents-thumbs-status ' +
						'submitted-documents-thumbs-success fa fa-check ' }),
					img({ src: '/uploads/docASubFile2.thumb.idoc.png.jpg' }))
			),
			li(
				a(span({ class: 'submitted-documents-thumbs-status' +
						' submitted-documents-thumbs-success fa fa-check ' }),
					img({ src: '/uploads/docASubFile1.thumb.idoc.jpg' }))
			),
			li(
				a(span({ class: 'submitted-documents-thumbs-status ' +
						'submitted-documents-thumbs-error fa fa-exclamation ' }),
					img({ src: '/uploads/docBSubFile1.thumb.idoc.jpg' }))
			),
			li(
				a(span({ class: 'submitted-documents-thumbs-status ' +
						'submitted-documents-thumbs-success fa fa-check ' }),
					img({ src: '/uploads/docASubFile2.thumb.idoc.png.jpg' }))
			))
	);
	section(
		{ class: 'submitted-preview' },
		source = div(
			{ class: 'section-primary submitted-preview-document' },
			div({ class: 'container-with-nav' },
				h3(i({ class: 'submitted-preview-item-number' }, "1"),
					"Memorandum and articles of association")),
			elem = div({ class: 'submitted-preview-image-placeholder' },
				img({ zoomOnHover: true, src: '/uploads/docASubFile2.idoc.png.jpg' })),
			form(
				{ class: 'submitted-preview-form' },
				ul(
					{ class: 'form-elements' },
					li(
						input({ dbjs: user._isValidated })
					),
					li(
						div(
							{ class: 'dbjs-input-component' },
							label("Reject document: "),
							div(
								{ class: 'input official-form-document-revision-reject-reason' },
								select(
									option("Choose rejection reason: "),
									option("Document is not readable."),
									option("The document is not acurate or does not match the data of the form."),
									option("Other")
								),
								textarea()
							)
						)
					)
				),
				p(input({ type: 'submit' }, "Save"))
			)
		),
		target = div({ class: 'section-primary submitted-preview-user-data entity-data-section-side' },
			h2({ class: 'container-with-nav' }, "Application form",
				a(
					{ class: 'hint-optional hint-optional-left',
						'data-hint': 'Print Your application form',
						href: '/user-submitted/data-print/' },
					span({ class: 'fa fa-print' }, "Print")
				)),

			section(
				{ class: 'entity-data-section' },
				h3("Proposed company name"),
				table(
					tbody(
						tr(
							td("Blink IT Solutions")
						)
					)
				)
			),
			section(
				{ class: 'entity-data-section' },
				h3("Business activity"),
				table(
					tbody(
						tr(
							th("Activity"),
							td("Air chater agent")
						),
						tr(
							th("Activity starting date"),
							td("7/30/2014")
						),
						tr(
							th("Date of account year end"),
							td("12/31/2014")
						),
						tr(
							th("Does the company have branches?"),
							td("Yes")
						)
					)
				)
			),
			section(
				{ class: 'entity-data-section' },
				h3("Company secretary"),
				section(
					{ class: 'entity-data-section-sub' },
					h4("Basic secretary data"),
					table(
						tbody(
							tr(
								th("Title"),
								td("Mr")
							),
							tr(
								th("First Name"),
								td("Andrei")
							),
							tr(
								th("Middle Name"),
								td("Mihai")
							),
							tr(
								th("Surname"),
								td("Balan")
							)
						)
					)
				),
				section(
					{ class: 'entity-data-section-sub' },
					h4("Residential address"),
					table(
						tbody(
							tr(
								th("Plot"),
								td("1")
							),
							tr(
								th("Block"),
								td("1")
							),
							tr(
								th("Street or location"),
								td("Nicolae Filipescu")
							),
							tr(
								th("City, district or town"),
								td("Bucharest")
							),
							tr(
								th("P.O. box"),
								td("1")
							),
							tr(
								th("Country"),
								td("Romania")
							)
						)
					)
				)
			),
			section(
				{ class: 'entity-data-section' },
				h3("Applicants"),
				ul(
					{ class: 'entity-data-section-entities' },
					li(
						h4("Marko Zagola"),
						section(
							{ class: 'entity-data-section' },
							h5("Personal data"),
							section(
								{ class: 'entity-data-section-sub' },
								h6("Basic data"),
								table(
									tbody(
										tr(
											th("Name"),
											td("Marko")
										),
										tr(
											th("Surname"),
											td("Zagalo")
										)
									)
								)
							),
							section(
								{ class: 'entity-data-section-sub' },
								h6("Additional data"),
								table(
									tbody(
										tr(
											th("Document type"),
											td("X")
										),
										tr(
											th("Document number"),
											td("123")
										),
										tr(
											th("Marital status"),
											td("")
										),
										tr(
											th("Date of birth"),
											td("25-06-1991")
										),
										tr(
											th("Nationality"),
											td("Romanian")
										),
										tr(
											th("E-mail"),
											td("andrei.balan@blink-it.ro")
										)
									)
								)
							),
							section(
								{ class: 'entity-data-section-sub' },
								h6("Address"),
								table(
									tbody(
										tr(
											th("Address"),
											td("XXX")
										),
										tr(
											th("Number"),
											td("1")
										),
										tr(
											th("Postal code"),
											td("X")
										),
										tr(
											th("City"),
											td("Bucharest")
										),
										tr(
											th("Country"),
											td("Romania")
										)
									)
								)
							)
						)
					),
					li(
						h4("Frank Grozel"),
						section(
							{ class: 'entity-data-section' },
							h5("Additional data"),
							table(
								tbody(
									tr(
										th("Document type"),
										td("X")
									),
									tr(
										th("Document number"),
										td("123")
									),
									tr(
										th("Marital status"),
										td("")
									),
									tr(
										th("Date of birth"),
										td("25-06-1991")
									),
									tr(
										th("Nationality"),
										td("Romanian")
									),
									tr(
										th("E-mail"),
										td("andrei.balan@blink-it.ro")
									)
								)
							)
						)
					)
				)
			)
			)
	);
	syncStyle.call(target, source, 'height', isMobileView);
	syncHeight(elem);
};
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

"use strict";

var tabs = require("sdk/tabs");

const { Trace, TraceError } = require("../core/trace.js").get(module.id);
const { ActionButton } = require("sdk/ui/button/action");
const { Cu } = require("chrome");
const { getMostRecentBrowserWindow } = require("sdk/window/utils");

// Import 'devtools' object
Cu.import("resource://gre/modules/devtools/Loader.jsm")

// xxxHonza: this object should slowly turn into Firebug start button.
var button = ActionButton({
  id: "helloWorld-link",
  label: "Visit Mozilla",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick
});

function handleClick(state) {
  let browser = getMostRecentBrowserWindow();
  let currentTab = browser.gBrowser.mCurrentTab;
  let target = devtools.TargetFactory.forTab(currentTab);

  // Open the toolbox with default panel selected.
  browser.gDevTools.showToolbox(target);
}
<commit_msg>Removing ActionButton usage (see also bug 1053704)<commit_after>/* See license.txt for terms of usage */

"use strict";

var tabs = require("sdk/tabs");

const { Trace, TraceError } = require("../core/trace.js").get(module.id);

// xxxHonza: this object should slowly turn into Firebug start button.
// xxxHonza: the ActionButton doesn't seem to be properly unregistered
// when the extension is disabled. This causes the following exception:
// JavaScript error: chrome://browser/content/tabbrowser.xml,
// line 1097: can't access dead object
// See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1053704
//const { ActionButton } = require("sdk/ui/button/action");

const { Cu } = require("chrome");
const { getMostRecentBrowserWindow } = require("sdk/window/utils");

// Import 'devtools' object
Cu.import("resource://gre/modules/devtools/Loader.jsm")

/*var button = ActionButton({
  id: "helloWorld-link",
  label: "Visit Mozilla",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick
});
*/

function handleClick(state) {
  let browser = getMostRecentBrowserWindow();
  let currentTab = browser.gBrowser.mCurrentTab;
  let target = devtools.TargetFactory.forTab(currentTab);

  // Open the toolbox with default panel selected.
  browser.gDevTools.showToolbox(target);
}
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  up: function(migration, DataTypes) {
    return [
      migration.changeColumn('memberships', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'CASCADE'
        }
      ),
      migration.changeColumn('artifacts', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'CASCADE'
        }
      ),
      migration.changeColumn('messages', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'CASCADE'
        }
      )
    ]
  },

  down: function(migration, DataTypes) {
    return [
      migration.changeColumn('memberships', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'NO ACTION'
        }
      ),
      ,
      migration.changeColumn('artifacts', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'NO ACTION'
        }
      ),
      migration.changeColumn('messages', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'NO ACTION'
        }
      )
    ]
  }
};
<commit_msg>fix migration 01<commit_after>'use strict';

module.exports = {
  up: function(migration, DataTypes) {
    return Promise.all([
      migration.changeColumn('memberships', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'CASCADE'
        }
      ),
      migration.changeColumn('artifacts', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'CASCADE'
        }
      ),
      migration.changeColumn('messages', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'CASCADE'
        }
      )
    ])
  },

  down: function(migration, DataTypes) {
    return Promise.all([
      migration.changeColumn('memberships', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'NO ACTION'
        }
      ),
      migration.changeColumn('artifacts', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'NO ACTION'
        }
      ),
      migration.changeColumn('messages', 'space_id',
        {
          type: DataTypes.STRING,
          references: {
            model: 'spaces',
            key: '_id'
          },
          onDelete: 'CASCADE',
          onUpdate: 'NO ACTION'
        }
      )
    ])
  }
}
<|endoftext|>